@bountyboard/arcade-sdk 1.4.3 → 1.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +3 -2
- package/CHANGELOG.md +12 -0
- package/docs/game-design-playbook.md +168 -53
- package/docs/llms.txt +2 -2
- package/package.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -51,7 +51,7 @@ lockToHost() → init() → [getPlayer()] → gameLoadingFinished()
|
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
`gameplayStart`/`gameplayStop` bracket ACTIVE play only (not menus). They drive playtime
|
|
54
|
-
analytics
|
|
54
|
+
analytics (feed ranking counts play sessions and ratings, not these calls), so missing `gameplayStop` on pause inflates numbers and will look
|
|
55
55
|
anomalous. WebXR games must call `xrSessionStart()`/`xrSessionEnd()` around immersive sessions
|
|
56
56
|
or their playtime flatlines while the headset hides the page.
|
|
57
57
|
|
|
@@ -91,4 +91,5 @@ the safe/default experience the alphabetically-first name. Don't re-randomize cl
|
|
|
91
91
|
## Design intent (read docs/game-design-playbook.md before building a NEW game)
|
|
92
92
|
|
|
93
93
|
Leaderboard shape, daily-seed modes, session length, and ad-placement etiquette are design
|
|
94
|
-
decisions, not integration details. The playbook
|
|
94
|
+
decisions, not integration details. The playbook separates platform facts (enforced by the SDK and
|
|
95
|
+
host) from design guidance backed by cited public sources.
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @bountyboard/arcade-sdk
|
|
2
2
|
|
|
3
|
+
## 1.4.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7a75783: Restyle the arcade player frame's controls on the Design Kit, and keep the CSS pseudo-fullscreen overlay above the site sidebar.
|
|
8
|
+
|
|
9
|
+
## 1.4.4
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Host the official Spotify embedded player beside build-backed arcade games, and let embedded-player popups escape the game iframe's sandbox.
|
|
14
|
+
|
|
3
15
|
## 1.4.3
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
|
@@ -1,75 +1,190 @@
|
|
|
1
1
|
# Bounty Board game design playbook (the "design brain")
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
decide whether the game earns plays, retention, and revenue.
|
|
3
|
+
Read this BEFORE designing a new game or porting one in. The SDK wiring is the easy part; the
|
|
4
|
+
choices below shape how a run feels, how the leaderboards behave, and how ads land.
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
How to read it. Two kinds of statement live here, and each one says which it is:
|
|
7
|
+
|
|
8
|
+
- **Platform fact.** Behavior the SDK or the Bounty Board host enforces in code. These are
|
|
9
|
+
checkable in this package and in the host, and they change only with a release.
|
|
10
|
+
- **Guidance.** Design advice. Where public research or another platform's published developer
|
|
11
|
+
docs back it, the source is cited as [n] (see Sources at the end). Guidance without a citation
|
|
12
|
+
is a design judgment, not a measured result. Nothing in this file is a claim about how games
|
|
13
|
+
perform on Bounty Board; we have not published that data.
|
|
8
14
|
|
|
9
15
|
## Session shape
|
|
10
16
|
|
|
11
|
-
- **
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
- **Guidance: keep a full run short.** A complete arc (start, tension, payoff) in roughly one to
|
|
18
|
+
three minutes suits players who arrive while browsing and keeps a restart cheap. This range is
|
|
19
|
+
our judgment, not a measured threshold. Longer games should checkpoint through cloud saves
|
|
20
|
+
(see Platform fit).
|
|
21
|
+
- **Guidance: get to the first input fast.** Poki's developer docs note that players tend to move
|
|
22
|
+
to another game when loading takes more than 10 seconds [1], and recommend an initial download
|
|
23
|
+
of no more than 5MB and 8MB in total [2]. CrazyGames puts attention starting to wander at 10
|
|
24
|
+
seconds of waiting [3]. Aim well under that: defer heavy assets past the first playable moment.
|
|
25
|
+
- **Platform fact: `gameLoadingFinished()` means "the player can start now".** It is an alias of
|
|
26
|
+
`ready()` and tells the host the game has loaded and is playable. Call it at that moment, not at
|
|
27
|
+
script load and not after a menu the player must click through.
|
|
28
|
+
- **Guidance: make restart instant.** Game over to a new run should be one input and under a
|
|
29
|
+
second. Super Meat Boy's postmortem names this directly: "Remove lives, reduce respawn time, keep
|
|
30
|
+
the levels short and keep the goal always in sight" [4].
|
|
18
31
|
|
|
19
32
|
## Score design (this is leaderboard design)
|
|
20
33
|
|
|
21
|
-
- **
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
- **Platform fact: scores are positive integers with a per game ceiling.** The SDK truncates
|
|
35
|
+
fractional scores, the submit endpoint accepts only positive integers up to the 32 bit limit,
|
|
36
|
+
and a score above the game's cap is rejected. Unless Bounty Board sets a per game cap, that
|
|
37
|
+
ceiling is 10,000,000; games scored by time survived can instead get a per second allowance.
|
|
38
|
+
Keep a great run comfortably inside the range, and tell the reviewer what a top score looks like.
|
|
39
|
+
- **Guidance: let skill show up in the score.** A great run should clearly beat a lucky one. If
|
|
40
|
+
score grows mainly with time played rather than with skill, long sessions crowd the top of the
|
|
41
|
+
board. Reward risk and precision; cap or decay pure survival scoring. This is design judgment;
|
|
42
|
+
we found no public study that sets a target spread.
|
|
43
|
+
- **Guidance: show players how close they came.** In a gambling study, near misses raised the
|
|
44
|
+
desire to keep playing when the player had some control over the outcome [5]. Research on goal
|
|
45
|
+
proximity finds effort rises as people near a goal: café customers bought coffee more often as
|
|
46
|
+
they approached a free one [6]. Both findings come from outside score chasing games, so treat
|
|
47
|
+
them as a reason to try this, not a promised lift. In your own UI, show the player's best and
|
|
48
|
+
the gap to it.
|
|
49
|
+
- **Platform fact: the host already shows a near miss.** After a run that sets no personal best
|
|
50
|
+
but lands just below a top three spot, the game page shows how many points short the player was.
|
|
51
|
+
Your in game UI can add finer detail (the gap to their own best, the next rank).
|
|
52
|
+
- **Platform fact: the Today board resets at midnight UTC.** Every submitted score lands on both
|
|
53
|
+
the all time board and the Today board. A run counts toward the UTC day its play session
|
|
54
|
+
started, so a run that crosses midnight stays on the day it began.
|
|
55
|
+
- **Daily mode.** If your game has procedural content, a shared seed daily run gives every player
|
|
56
|
+
the same level, so the board compares like with like. Spelunky's Daily Challenge is a well known
|
|
57
|
+
example: one attempt per day on a shared level, with a leaderboard [7]. Platform fact: submit
|
|
58
|
+
those runs with `{ mode: 'daily' }` on `submitScore()` / `gameOver()` so the Today board can mark
|
|
59
|
+
them.
|
|
30
60
|
|
|
31
61
|
## Multiplayer design (for room based games)
|
|
32
62
|
|
|
33
|
-
- **
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
63
|
+
- **Platform fact: clients send inputs; the room authority simulates.** On a Bounty Board hosted
|
|
64
|
+
module or a registered external server, the server runs the rules and validates every input.
|
|
65
|
+
If your design needs a client to decide who got tagged, move that rule to the server. Gambetta's
|
|
66
|
+
guide states the same principle: the server is the only authority, and you should assume
|
|
67
|
+
players will try to cheat [8].
|
|
68
|
+
- **Guidance: prefer latency tolerant mechanics.** Other players are normally drawn slightly in
|
|
69
|
+
the past between snapshots (entity interpolation) [9]; Valve's Source engine defaults to 20
|
|
70
|
+
snapshots per second and a 100 ms interpolation delay [10]. That delay suits movement based
|
|
71
|
+
play (chase, tag, social deduction) and makes instant hit duels hard: when you aim at a target
|
|
72
|
+
drawn 100 ms in the past, precise hits need server side lag compensation [9][10]. Momentum,
|
|
73
|
+
grid steps, and proximity rules forgive latency better than frame perfect hits.
|
|
74
|
+
- **Platform fact: tick and snapshot rates are set per module.** A hosted module's simulation
|
|
75
|
+
runs at 1 to 60 Hz, and its snapshot rate can be lower than its tick rate. The reference hide
|
|
76
|
+
and seek module ticks at 12 Hz; relay rooms batch messages at 20 Hz.
|
|
77
|
+
- **Platform fact: hosted modules filter state per viewer.** Every snapshot goes through the
|
|
78
|
+
module's per viewer serializer, so a player receives only what they are allowed to know. In the
|
|
79
|
+
reference hide and seek module, the seeker's snapshot simply does not contain unfound hiders,
|
|
80
|
+
so a modified client has nothing to reveal. Riot uses the same idea against wallhacks in
|
|
81
|
+
VALORANT: do not send an enemy's position until it could be seen [11]. This holds for refereed
|
|
82
|
+
modules and external authorities you build that way. Relay rooms do not interpret game payloads,
|
|
83
|
+
so their outcomes are client trusted and never feed results or leaderboards.
|
|
84
|
+
- **Platform fact: rooms fill by share code or quick match.** `joinRoom()` can create a room with
|
|
85
|
+
a share code, join a friend's code, or quick match into the game's open public room. Guidance:
|
|
86
|
+
plan for players arriving mid round. The reference hide and seek module runs a 5 second
|
|
87
|
+
countdown, 10 seconds of hiding, and 90 seconds of seeking, and late joiners spectate until the
|
|
88
|
+
next round.
|
|
43
89
|
|
|
44
90
|
## Monetization etiquette (rewarded ads)
|
|
45
91
|
|
|
46
|
-
- **
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
- **
|
|
53
|
-
|
|
92
|
+
- **Guidance: make the ad a trade the player chooses, never a toll.** Google's AdMob policy
|
|
93
|
+
requires rewarded ads to be served only after the user opts in, and says declining must not
|
|
94
|
+
interfere with normal use of the app [12]. CrazyGames recommends stating the reward on the button
|
|
95
|
+
("Watch Ad for +50 Gems"), offering it at natural pauses, and suggests revives ("Respawn now",
|
|
96
|
+
"Keep your score", capped at once per session) and doubled end of level rewards [13]. A cosmetic
|
|
97
|
+
item also fits. Never gate core progression.
|
|
98
|
+
- **Guidance: one placement at a natural fail state beats several interruptions.** Prepare one
|
|
99
|
+
rewarded placement where the run ends and offer it once. Cap anything that repeats [13].
|
|
100
|
+
- **Platform fact: ads are host gated.** Rewarded ads run only when Bounty Board has enabled them
|
|
101
|
+
for the game (or in local test mode). Otherwise preparation returns `'unavailable'`, so the
|
|
102
|
+
game must be complete and fair without ads.
|
|
103
|
+
- **Platform fact: the Watch Ad click must show directly.** Enable it only after
|
|
104
|
+
`prepareRewardedAd()` returns ready, then call the retained `show()` before any `await`,
|
|
105
|
+
microtask, timer, or other work. Browsers grant a short lived "transient activation" after a
|
|
106
|
+
click, and it expires after a timeout [14]; the SDK checks for it and fails closed with
|
|
107
|
+
`'direct_user_action_required'` when it is gone.
|
|
108
|
+
- **Platform fact: always pause audio/game in `onStart`** and grant only when the final status
|
|
109
|
+
is `'viewed'`. A raw provider `breakStatus`, dismissal, timeout, or error never earns the reward.
|
|
54
110
|
|
|
55
111
|
## Platform fit
|
|
56
112
|
|
|
57
|
-
- **
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
113
|
+
- **Guidance: design for touch first.** One thumb controls, generous hit targets, no hover
|
|
114
|
+
dependence, portrait friendly if possible. Keyboard is the enhancement. WCAG sets 24 by 24 CSS
|
|
115
|
+
pixels as the minimum target size and 44 by 44 as the enhanced level [15]. Platform fact: a game
|
|
116
|
+
listed without touch support shows touch device players a desktop only notice, and only games
|
|
117
|
+
with touch support list "mobile and tablet browser" under supported devices.
|
|
118
|
+
- **Guidance: budget for 60fps on a mid range phone.** A frame at 60fps has about 16 ms, and
|
|
119
|
+
web.dev's RAIL model advises producing each animation frame in 10 ms or less because the browser
|
|
120
|
+
needs the rest [16]. Render into a smaller back buffer when you need speed (cap the
|
|
121
|
+
devicePixelRatio you honor) [17], and pool objects to keep garbage collection pauses out of play
|
|
122
|
+
[18]. Avoid layout thrash.
|
|
123
|
+
- **Platform fact: the SDK stays inert off platform.** Off Bounty Board the fire and forget calls do
|
|
124
|
+
nothing, `save()` / `load()` reject fast with `'unsupported'`, and `getPlayer()` resolves null.
|
|
125
|
+
Ship one bundle that runs standalone and on the arcade; don't fork builds.
|
|
126
|
+
- **Platform fact: hosted builds have no native localStorage.** Bounty Board hosted uploads run in
|
|
127
|
+
an opaque origin sandbox where reading `localStorage` throws. Cloud saves (`save()` / `load()`)
|
|
128
|
+
work for hosted uploads with a logged in player: load on boot, save on checkpoint and game over,
|
|
129
|
+
and greet returning players with their progress (`getPlayer()` gives the display name, or null
|
|
130
|
+
for guests). Engine exports that need synchronous storage can use the SDK's cloud backed
|
|
131
|
+
`storage` shim instead; the script tag installs it automatically, module builds call
|
|
132
|
+
`storage.install()` before boot. Wire this early, not as a retrofit.
|
|
66
133
|
|
|
67
134
|
## Ship checklist (design, not code)
|
|
68
135
|
|
|
69
|
-
- [ ] A stranger
|
|
70
|
-
- [ ]
|
|
71
|
-
- [ ]
|
|
72
|
-
- [ ]
|
|
73
|
-
- [ ]
|
|
74
|
-
- [ ]
|
|
136
|
+
- [ ] A stranger understands the goal within the first few seconds of play
|
|
137
|
+
- [ ] Loading reaches a playable screen well under 10 seconds [1][3]
|
|
138
|
+
- [ ] A full run is short; restart is one input
|
|
139
|
+
- [ ] The score of a great run clearly beats the score of a lucky run, inside the score cap
|
|
140
|
+
- [ ] Daily mode if content is procedural, submitted with `{ mode: 'daily' }`
|
|
141
|
+
- [ ] Rewarded placement is a trade the player initiates, and the game is complete without it
|
|
142
|
+
- [ ] Playable one thumb on a phone, aiming for 60fps
|
|
75
143
|
- [ ] Boots and plays with the SDK fully offline
|
|
144
|
+
|
|
145
|
+
## Sources
|
|
146
|
+
|
|
147
|
+
Platform facts are backed by the code in this package (`src/types.ts`, `src/core.ts`,
|
|
148
|
+
`src/storage.ts`, `src/multiplayer.ts`), the room server (`packages/arcade-mp-server`), and the
|
|
149
|
+
Bounty Board host, not by the links below.
|
|
150
|
+
|
|
151
|
+
[1] Poki Developer Docs, "Requirements".
|
|
152
|
+
https://developers.poki.com/guide/requirements-quality
|
|
153
|
+
[2] Poki Developer Docs, "Choosing your web game engine".
|
|
154
|
+
https://developers.poki.com/guide/web-engine
|
|
155
|
+
[3] CrazyGames Docs, "Game loading tips".
|
|
156
|
+
https://docs.crazygames.com/resources/getting-to-the-first-frame/
|
|
157
|
+
[4] Edmund McMillen, "Postmortem: Team Meat's Super Meat Boy", Game Developer, 2011.
|
|
158
|
+
https://www.gamedeveloper.com/audio/postmortem-team-meat-s-i-super-meat-boy-i-
|
|
159
|
+
[5] Clark, Lawrence, Astley-Jones and Gray, "Gambling near-misses enhance motivation to gamble
|
|
160
|
+
and recruit win-related brain circuitry", Neuron 61(3), 2009. doi:10.1016/j.neuron.2008.12.031
|
|
161
|
+
https://pmc.ncbi.nlm.nih.gov/articles/PMC2658737/
|
|
162
|
+
[6] Kivetz, Urminsky and Zheng, "The Goal-Gradient Hypothesis Resurrected", Journal of Marketing
|
|
163
|
+
Research 43(1), 2006. doi:10.1509/jmkr.43.1.39
|
|
164
|
+
https://journals.sagepub.com/doi/abs/10.1509/jmkr.43.1.39
|
|
165
|
+
[7] Mossmouth, "The Spelunky Daily Challenge".
|
|
166
|
+
https://spelunkyworld.com/dailychallenge/
|
|
167
|
+
[8] Gabriel Gambetta, "Fast-Paced Multiplayer (Part I): Client-Server Game Architecture".
|
|
168
|
+
https://www.gabrielgambetta.com/client-server-game-architecture.html
|
|
169
|
+
[9] Gabriel Gambetta, "Fast-Paced Multiplayer (Part III): Entity Interpolation".
|
|
170
|
+
https://www.gabrielgambetta.com/entity-interpolation.html
|
|
171
|
+
[10] Valve Developer Community, "Source Multiplayer Networking".
|
|
172
|
+
https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
|
|
173
|
+
[11] Riot Games, "Demolishing Wallhacks with VALORANT's Fog of War", 2020.
|
|
174
|
+
https://www.riotgames.com/en/news/demolishing-wallhacks-valorants-fog-war
|
|
175
|
+
[12] Google AdMob Help, "Policies for ad units that offer rewards".
|
|
176
|
+
https://support.google.com/admob/answer/7313578
|
|
177
|
+
[13] CrazyGames Docs, "Mastering Rewarded Ads: A Deep Dive".
|
|
178
|
+
https://docs.crazygames.com/resources/rewarded-ads-deep-dive/
|
|
179
|
+
[14] MDN Web Docs, "User activation".
|
|
180
|
+
https://developer.mozilla.org/en-US/docs/Web/Security/User_activation
|
|
181
|
+
[15] W3C, "Understanding SC 2.5.8 Target Size (Minimum)" and "Understanding SC 2.5.5 Target Size
|
|
182
|
+
(Enhanced)", WCAG 2.2.
|
|
183
|
+
https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html
|
|
184
|
+
https://www.w3.org/WAI/WCAG22/Understanding/target-size-enhanced.html
|
|
185
|
+
[16] web.dev, "Measure performance with the RAIL model".
|
|
186
|
+
https://web.dev/articles/rail
|
|
187
|
+
[17] MDN Web Docs, "WebGL best practices".
|
|
188
|
+
https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices
|
|
189
|
+
[18] web.dev, "Static Memory JavaScript with Object Pools".
|
|
190
|
+
https://web.dev/speed-static-mem-pools/
|
package/docs/llms.txt
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Human guide: https://www.bountyboard.gg/arcade/sdk
|
|
4
4
|
Package: @bountyboard/arcade-sdk (https://www.npmjs.com/package/@bountyboard/arcade-sdk)
|
|
5
|
-
Stable npm release: 1.4.
|
|
5
|
+
Stable npm release: 1.4.5
|
|
6
6
|
Wire protocol: 1
|
|
7
7
|
|
|
8
8
|
This file is the complete integration contract for coding agents integrating an
|
|
9
9
|
HTML5 game. The package TypeScript declarations remain the exact public type
|
|
10
|
-
reference. npm 1.4.
|
|
10
|
+
reference. npm 1.4.5, the /arcade-sdk/v1.js browser artifact, and repository
|
|
11
11
|
source all expose the same surface. Rooms open on all three approved rails:
|
|
12
12
|
Bounty shared service referee modules, Bounty shared service relay rooms, and
|
|
13
13
|
host routed registered external authorities. code/create works on every rail;
|
package/package.json
CHANGED