@indiegems/gem-web-sdk 13.4.3 → 14.0.0
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/CHANGELOG.md +13 -0
- package/dist/game.d.ts +66 -1
- package/dist/gem-web-sdk.bridge.js +2 -2
- package/dist/gem-web-sdk.esm.js +3 -3
- package/dist/gem-web-sdk.function.js +3 -3
- package/dist/gem-web-sdk.game.js +3 -3
- package/dist/gem-web-sdk.min.js +3 -3
- package/dist/gem-web-sdk.sdk.js +3 -3
- package/dist/gem-web-sdk.server.js +2 -2
- package/dist/index.d.ts +38 -4
- package/dist/sdk.d.ts +66 -1
- package/docs/api/api-reference-function.md +1 -1
- package/docs/api/api-reference-game.md +518 -1
- package/docs/api/api-reference-server.md +1 -1
- package/docs/api/reference.json +682 -1
- package/docs/changelog.md +13 -0
- package/docs/getting-started.md +3 -2
- package/docs/manifest.json +8 -8
- package/docs/server-bundles.md +2 -2
- package/docs/what-a-game-must-do.md +93 -4
- package/package.json +1 -1
- package/schema/bridge.v1.json +199 -0
- package/schema/capabilities.public.json +7 -0
package/docs/changelog.md
CHANGED
|
@@ -16,6 +16,19 @@ Its entries are grouped under up to five headings:
|
|
|
16
16
|
- **Rebuild**: a type changed. Recompile against the new version; code that compiles today keeps compiling unless the entry says otherwise.
|
|
17
17
|
- **New capability**: something a game can now do. Nothing changes unless you use it.
|
|
18
18
|
|
|
19
|
+
## 14.0.0
|
|
20
|
+
|
|
21
|
+
Upgrading from 13.4.3. Impact: required.
|
|
22
|
+
|
|
23
|
+
### Rebuild
|
|
24
|
+
|
|
25
|
+
- The message name lists, the frame and parent message unions, and the capability union each gained new members for game settings (the gameSettings capability among them). Recompiling is enough for most games. If your code switches exhaustively over message kinds or capability names, add handling for the new members.
|
|
26
|
+
|
|
27
|
+
### New capability
|
|
28
|
+
|
|
29
|
+
- A game can now mirror up to eight of its own settings into the Arcade's in-game menu using Gem.settings. A setting is a toggle, a slider or a choice. The Arcade shows up to two game toggles in the quick row next to its own sound and vibration controls, and lists the game's settings at the top of its settings screen. The game receives a change whenever the player alters one of them, but only for a setting it declared and only with a value of that setting's kind. Slider values are clamped and stepped. Keep drawing your own settings button and screen, because the declaration only mirrors a few settings. Do not declare the Arcade's own settings such as master volume, mute, vibration, graphics or controls.
|
|
30
|
+
- A game that talks to the Arcade through the frame object directly can now declare its settings with GemFrame.declareSettings and receive player changes through the onSettingChange option or callback. The declaration is held until the connection is ready and re-sent after each handshake. Updates are paced to about two per second.
|
|
31
|
+
|
|
19
32
|
## 13.4.3
|
|
20
33
|
|
|
21
34
|
Upgrading from 13.4.2. Impact: none.
|
package/docs/getting-started.md
CHANGED
|
@@ -50,7 +50,7 @@ either way.
|
|
|
50
50
|
```jsonc
|
|
51
51
|
// package.json
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@indiegems/gem-web-sdk": "
|
|
53
|
+
"@indiegems/gem-web-sdk": "14.0.0"
|
|
54
54
|
}
|
|
55
55
|
```
|
|
56
56
|
|
|
@@ -178,7 +178,8 @@ And draw a settings button of your own — top-right, with your Back button just
|
|
|
178
178
|
([the top of the screen](what-a-game-must-do.md#the-top-of-the-screen)) — whose values start from
|
|
179
179
|
the player's Arcade-wide defaults, `gem.prefs.recommended`, until the player chooses their own
|
|
180
180
|
([what a game must do](what-a-game-must-do.md#game-settings)). The Arcade's menu does not open
|
|
181
|
-
your settings
|
|
181
|
+
your settings screen; you may also mirror a few of your settings into it with
|
|
182
|
+
`gem.settings.declare`, but never instead of your own button. Outside the Arcade there is no Arcade menu at all, so also give players a way out — a
|
|
182
183
|
control that calls `gem.exit()`. A game a player cannot leave is one they leave by closing the tab.
|
|
183
184
|
|
|
184
185
|
## 6. Play it
|
package/docs/manifest.json
CHANGED
|
@@ -38,8 +38,8 @@
|
|
|
38
38
|
},
|
|
39
39
|
{
|
|
40
40
|
"file": "changelog.md",
|
|
41
|
-
"sha256": "
|
|
42
|
-
"updated": "2026-10-
|
|
41
|
+
"sha256": "3ccaf70d80a6164736920b4df6f817d600b2a80287d4a14783f72fbb470863f6",
|
|
42
|
+
"updated": "2026-10-21T13:51:48Z"
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
"file": "daily-challenges.md",
|
|
@@ -68,8 +68,8 @@
|
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
70
|
"file": "getting-started.md",
|
|
71
|
-
"sha256": "
|
|
72
|
-
"updated": "2026-10-
|
|
71
|
+
"sha256": "dbda9199712f4112bfe316b7af6e63a11fcce6842e778672459e1532947cf21f",
|
|
72
|
+
"updated": "2026-10-21T13:51:48Z"
|
|
73
73
|
},
|
|
74
74
|
{
|
|
75
75
|
"file": "inventory-and-catalogs.md",
|
|
@@ -128,8 +128,8 @@
|
|
|
128
128
|
},
|
|
129
129
|
{
|
|
130
130
|
"file": "server-bundles.md",
|
|
131
|
-
"sha256": "
|
|
132
|
-
"updated": "2026-10-
|
|
131
|
+
"sha256": "2312a25bb11ce29f50b97b0737c708b31f6e0290f99fe2520179a9dbac67fb8c",
|
|
132
|
+
"updated": "2026-10-21T13:51:48Z"
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
"file": "serverless-functions-js.md",
|
|
@@ -153,8 +153,8 @@
|
|
|
153
153
|
},
|
|
154
154
|
{
|
|
155
155
|
"file": "what-a-game-must-do.md",
|
|
156
|
-
"sha256": "
|
|
157
|
-
"updated": "2026-10-
|
|
156
|
+
"sha256": "3a9c0e307b78cfb8b959c7b47a1ad0349699be944903a24834ee785c3823b402",
|
|
157
|
+
"updated": "2026-10-21T13:31:36Z"
|
|
158
158
|
}
|
|
159
159
|
]
|
|
160
160
|
}
|
package/docs/server-bundles.md
CHANGED
|
@@ -80,8 +80,8 @@ To check the download yourself: the package npm serves is, byte for byte, the fi
|
|
|
80
80
|
also publishes on its download host, with the hash beside it:
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
|
-
curl -fsSL -O https://downloads.gemarcade.com/sdk/
|
|
84
|
-
curl -fsSL https://downloads.gemarcade.com/sdk/
|
|
83
|
+
curl -fsSL -O https://downloads.gemarcade.com/sdk/v14.0.0/gem-web-sdk.tgz
|
|
84
|
+
curl -fsSL https://downloads.gemarcade.com/sdk/v14.0.0/gem-web-sdk.tgz.sri
|
|
85
85
|
openssl dgst -sha384 -binary gem-web-sdk.tgz | openssl base64 -A
|
|
86
86
|
```
|
|
87
87
|
|
|
@@ -1016,10 +1016,13 @@ This is the whole model, and every other page that mentions settings links here:
|
|
|
1016
1016
|
|
|
1017
1017
|
- **The Arcade's settings are the player's Arcade-wide defaults for this device.** Your game reads
|
|
1018
1018
|
them from `gem.prefs.recommended` (and `muted` and `reducedMotion` from `gem.prefs`) and applies
|
|
1019
|
-
them again on `onPrefs`. The Arcade never asks your game anything about them
|
|
1020
|
-
anything your game says.
|
|
1019
|
+
them again on `onPrefs`. The Arcade never asks your game anything about them.
|
|
1021
1020
|
- **Every game draws its own settings button, top-right ([the top of the
|
|
1022
1021
|
screen](#the-top-of-the-screen)), and its own settings screen.** The Arcade's menu never opens it.
|
|
1022
|
+
- **A game may also mirror up to eight of its own settings into the Arcade's menu**, with
|
|
1023
|
+
`gem.settings.declare` — a second way to reach a few of them, never the only one, and never a
|
|
1024
|
+
setting the Arcade already has ([mirror a few settings into the Arcade's
|
|
1025
|
+
menu](#mirror-a-few-settings-into-the-arcades-menu-gemsettings)).
|
|
1023
1026
|
- **A setting starts from `recommended` until the player changes it in your game, and then the
|
|
1024
1027
|
player's choice in your game wins.** Save only what the player chose, never a recommended value.
|
|
1025
1028
|
- **Where a choice is kept.** Device configuration — volume, graphics quality, look sensitivity, a
|
|
@@ -1135,6 +1138,90 @@ owns — starts from `recommended` the same way and is kept in `gem.me.settings`
|
|
|
1135
1138
|
([sound](#sound-your-own-mute-control-and-the-arcades)), and `reducedMotion` is the player's
|
|
1136
1139
|
accessibility setting, which your game honours.
|
|
1137
1140
|
|
|
1141
|
+
### Mirror a few settings into the Arcade's menu: `gem.settings`
|
|
1142
|
+
|
|
1143
|
+
Optional. The Arcade's Gem menu can show a few of your game's own settings beside the player's
|
|
1144
|
+
Arcade-wide ones: in its Settings screen, in a group named for your game above the player's
|
|
1145
|
+
defaults for all games, and — for up to two toggles — in the menu's quick row, next to the
|
|
1146
|
+
Arcade's own Sound and Vibration buttons. A player who opens the menu mid-game can turn your music
|
|
1147
|
+
off without hunting for your settings screen.
|
|
1148
|
+
|
|
1149
|
+
**It is a mirror, never a replacement: keep your own settings button and screen**, with every
|
|
1150
|
+
setting you declare on it too. An embedder that draws no game settings shows none of this, and the
|
|
1151
|
+
Arcade may leave an entry out when it is short of room — your own screen is what remains. A game
|
|
1152
|
+
that dropped its button because the Arcade's menu had its settings would have settings nobody can
|
|
1153
|
+
reach.
|
|
1154
|
+
|
|
1155
|
+
```js
|
|
1156
|
+
// Built from the same state your own settings screen shows.
|
|
1157
|
+
const declared = () => [
|
|
1158
|
+
{ id: 'music', label: t('Music'), kind: 'toggle', value: music.on, quick: true, icon: 'music' },
|
|
1159
|
+
{ id: 'sfx', label: t('Sound effects'), kind: 'toggle', value: sfx.on, quick: true, icon: 'sfx' },
|
|
1160
|
+
{ id: 'colors', label: t('Color help'), kind: 'toggle', value: colorHelp, icon: 'eye' },
|
|
1161
|
+
{ id: 'speed', label: t('Game speed'), kind: 'slider', value: speed, min: 0.5, max: 2, step: 0.25 },
|
|
1162
|
+
{
|
|
1163
|
+
id: 'difficulty',
|
|
1164
|
+
label: t('Difficulty'),
|
|
1165
|
+
kind: 'choice',
|
|
1166
|
+
value: difficulty,
|
|
1167
|
+
options: [
|
|
1168
|
+
{ id: 'easy', label: t('Easy') },
|
|
1169
|
+
{ id: 'normal', label: t('Normal') },
|
|
1170
|
+
{ id: 'hard', label: t('Hard') },
|
|
1171
|
+
],
|
|
1172
|
+
},
|
|
1173
|
+
];
|
|
1174
|
+
|
|
1175
|
+
gem.settings.declare(declared());
|
|
1176
|
+
|
|
1177
|
+
// The player changed one in the Arcade's menu. Your game is usually paused: apply it anyway.
|
|
1178
|
+
gem.settings.onChange(({ id, value }) => {
|
|
1179
|
+
if (id === 'music') setMusic(value === true);
|
|
1180
|
+
if (id === 'sfx') setSfx(value === true);
|
|
1181
|
+
if (id === 'colors') setColorHelp(value === true);
|
|
1182
|
+
if (id === 'speed') setSpeed(value);
|
|
1183
|
+
if (id === 'difficulty') setDifficulty(value);
|
|
1184
|
+
keepChoice(id, value); // where your own screen keeps the same choice
|
|
1185
|
+
});
|
|
1186
|
+
|
|
1187
|
+
// Your own screen changed one: declare again, so the menu never shows a stale value.
|
|
1188
|
+
musicToggle.onchange = () => {
|
|
1189
|
+
setMusic(musicToggle.checked);
|
|
1190
|
+
keepChoice('music', musicToggle.checked);
|
|
1191
|
+
gem.settings.declare(declared());
|
|
1192
|
+
};
|
|
1193
|
+
```
|
|
1194
|
+
|
|
1195
|
+
- **Three kinds, up to eight settings, shown in your order.** A `toggle`'s `value` is `true` or
|
|
1196
|
+
`false`; a `slider`'s is a number from `min` to `max` on `step` (defaults `0`, `100`, `1`); a
|
|
1197
|
+
`choice` has two to four `options` and its `value` is one of their ids. `id` is your own name
|
|
1198
|
+
for the setting, 1 to 40 of `A-Z a-z 0-9 _ -`, unique. An entry that breaks a rule is left out
|
|
1199
|
+
with a warning on the console, and nothing throws.
|
|
1200
|
+
- **Mark at most two toggles `quick`** — the ones a player reaches for mid-game: Music, Sound
|
|
1201
|
+
effects, Color help. A third that asks is shown only in the list. `icon` is optional: `music`,
|
|
1202
|
+
`sfx`, `voice`, `eye`, `text`, `hint`, `speed`, `bright`, `controls` or `star`.
|
|
1203
|
+
- **Labels are already in the player's language** (`gem.prefs.locale`): the Arcade does not
|
|
1204
|
+
translate them, and cuts them at 40 characters. Declare again when the language changes.
|
|
1205
|
+
- **Never declare a setting the Arcade already has.** Master volume and mute, vibration, graphics
|
|
1206
|
+
quality and the controls defaults (look sensitivity, invert, touch stick, keyboard layout,
|
|
1207
|
+
confirm button) are in the Arcade's own settings and reach you as `gem.prefs` and
|
|
1208
|
+
`gem.prefs.recommended`. A "Vibration", "Volume" or "Mute" of yours beside them is a second
|
|
1209
|
+
switch for the same thing, and the player cannot tell which one wins. Your own music and
|
|
1210
|
+
sound-effect levels are yours to declare.
|
|
1211
|
+
- **It is screen state, not a toggle.** Each call is the whole list and replaces the last;
|
|
1212
|
+
`gem.settings.declare([])` takes them all back out. **Declare again whenever your own screen
|
|
1213
|
+
changes a value**, so the menu never shows a stale one. Before the Arcade connects the list is
|
|
1214
|
+
held and sent when it does, and again after any reconnect; a burst — a slider being dragged — is
|
|
1215
|
+
sent at most twice a second, always ending on the last value.
|
|
1216
|
+
- **Apply a change at once, even while paused.** The Arcade's menu holds your game paused
|
|
1217
|
+
(`onPause(true)`) while it is open, and a player who turns Music off expects the music to stop
|
|
1218
|
+
while the menu is still open. The change is the player's own choice, exactly as if they had made
|
|
1219
|
+
it on your screen: keep it where you keep that setting (device settings or `gem.me.settings`,
|
|
1220
|
+
[above](#game-settings)). The SDK has already written it into your declaration, so you do not
|
|
1221
|
+
need to declare again for it.
|
|
1222
|
+
- **`declare` returns `false`** before the Arcade connects (the list is held) and under an
|
|
1223
|
+
embedder that draws no game settings. Do nothing differently: your own screen has them all.
|
|
1224
|
+
|
|
1138
1225
|
## Camera and look controls
|
|
1139
1226
|
|
|
1140
1227
|
If your game turns a camera — a drag on a phone, a mouse under pointer lock, a gamepad's right
|
|
@@ -1289,8 +1376,10 @@ gem.setMenu({
|
|
|
1289
1376
|
});
|
|
1290
1377
|
```
|
|
1291
1378
|
|
|
1292
|
-
- **Your settings
|
|
1293
|
-
Arcade's menu never opens
|
|
1379
|
+
- **Your settings screen is not in it.** It opens from [your own button](#game-settings), and the
|
|
1380
|
+
Arcade's menu never opens it. A few of your settings can also appear in the Arcade's menu, with
|
|
1381
|
+
[`gem.settings`](#mirror-a-few-settings-into-the-arcades-menu-gemsettings) — a mirror of your
|
|
1382
|
+
screen, never a replacement for it.
|
|
1294
1383
|
- **`items` are up to four entries of your own**, shown in a group below the Arcade's. `id` is your
|
|
1295
1384
|
name for the entry (1 to 32 characters); `label` is what the player reads, **already in their
|
|
1296
1385
|
language** (`gem.prefs.locale`) — the Arcade does not translate it, cuts it at 40 characters, and
|
package/package.json
CHANGED
package/schema/bridge.v1.json
CHANGED
|
@@ -3076,6 +3076,205 @@
|
|
|
3076
3076
|
"rateLimit": { "perMinute": 12 }
|
|
3077
3077
|
},
|
|
3078
3078
|
|
|
3079
|
+
{
|
|
3080
|
+
"type": "gem.settingsDeclare",
|
|
3081
|
+
"direction": "frameToParent",
|
|
3082
|
+
"transport": "port",
|
|
3083
|
+
"$comment": [
|
|
3084
|
+
"A few of the game's OWN settings, mirrored into the arcade's menu - in",
|
|
3085
|
+
"the Gem Arcade, a group headed with the game's name in its Settings",
|
|
3086
|
+
"screen (\"only this game\"), above the player's Arcade-wide defaults,",
|
|
3087
|
+
"and up to two toggles in the menu's quick row beside the arcade's own",
|
|
3088
|
+
"Sound and Vibration (owner decision 2026-10-21).",
|
|
3089
|
+
"",
|
|
3090
|
+
"A MIRROR, NEVER A REPLACEMENT. A game that declares settings still draws",
|
|
3091
|
+
"its own settings button and the screen it opens, and every one of these",
|
|
3092
|
+
"settings is on that screen too. That is the answer to why the earlier",
|
|
3093
|
+
"game-to-arcade settings channels (`gem.controlsDeclare`, `gem.menu`'s",
|
|
3094
|
+
"`settings` flag) were withdrawn: games hid their own button, and their",
|
|
3095
|
+
"settings became unreachable wherever the arcade showed nothing. A parent may",
|
|
3096
|
+
"draw none of this - any embedder that did not advertise `gameSettings`,",
|
|
3097
|
+
"a parent short of room - and the game's own screen is what remains.",
|
|
3098
|
+
"",
|
|
3099
|
+
" settings 0..8 entries, in the order the game wants them shown;",
|
|
3100
|
+
" empty means the game shows none",
|
|
3101
|
+
"",
|
|
3102
|
+
"Each entry is one of three kinds:",
|
|
3103
|
+
"",
|
|
3104
|
+
" toggle `value` a boolean",
|
|
3105
|
+
" slider `value` a number in [min, max], on `step` from `min`;",
|
|
3106
|
+
" `min`, `max` and `step` default to 0, 100 and 1",
|
|
3107
|
+
" choice `value` one of `options`' ids; 2..4 options",
|
|
3108
|
+
"",
|
|
3109
|
+
"`id` is the game's own name for the setting, 1..40 characters of",
|
|
3110
|
+
"A-Z a-z 0-9 _ -, and is what comes back in `gem.settingChange`;",
|
|
3111
|
+
"unique within one message, and the parent keeps the first of a",
|
|
3112
|
+
"repeated id. `label` (and each option's) is what the player reads,",
|
|
3113
|
+
"1..40 characters, ALREADY IN THE PLAYER'S LANGUAGE (`gem.prefs.locale`):",
|
|
3114
|
+
"the parent does not translate it. A parent drops an entry whose id,",
|
|
3115
|
+
"kind, value or options break these rules rather than guessing; the SDK",
|
|
3116
|
+
"never sends one.",
|
|
3117
|
+
"",
|
|
3118
|
+
"`quick` asks for a toggle in the menu's quick row. A parent honours it",
|
|
3119
|
+
"on the first two toggles that ask, in order, and ignores it on any other",
|
|
3120
|
+
"kind. `icon` is a CODE, not an enum: one of music, sfx, voice, eye,",
|
|
3121
|
+
"text, hint, speed, bright, controls, star - and a parent draws its",
|
|
3122
|
+
"generic glyph for one it does not know, so the vocabulary can grow",
|
|
3123
|
+
"without an older parent refusing the message. The SDK drops a code it",
|
|
3124
|
+
"does not know before sending.",
|
|
3125
|
+
"",
|
|
3126
|
+
"NOT THE ARCADE'S OWN SETTINGS. Master volume and mute, vibration,",
|
|
3127
|
+
"graphics and the controls defaults are the arcade's, reaching the game",
|
|
3128
|
+
"as `gem.prefs` and `gem.prefs.recommended`, and a game declares none of",
|
|
3129
|
+
"them.",
|
|
3130
|
+
"",
|
|
3131
|
+
"A LABEL IS UNTRUSTED TEXT IN THE PARENT'S CHROME. A parent renders it as",
|
|
3132
|
+
"text and never as markup, in the game's own group and never among its",
|
|
3133
|
+
"own entries, truncated to fit, and may decline to show an entry at all.",
|
|
3134
|
+
"",
|
|
3135
|
+
"SCREEN STATE, NOT A TOGGLE, like `gem.menu`. Each message is the whole",
|
|
3136
|
+
"answer and the latest one wins; nothing accumulates. The SDK holds it",
|
|
3137
|
+
"from before the bridge is up and re-sends it after every handshake; a",
|
|
3138
|
+
"game declares again whenever its own screen changes a value, and the",
|
|
3139
|
+
"SDK writes a `gem.settingChange` into the declaration it holds, so a",
|
|
3140
|
+
"reconnect never shows a stale value. A declaration is per game",
|
|
3141
|
+
"session: the parent forgets it when the game is left.",
|
|
3142
|
+
"",
|
|
3143
|
+
"A PRESENTATION REQUEST ONLY, and not an authorization control. It",
|
|
3144
|
+
"carries no player data and changes nothing but what the parent draws;",
|
|
3145
|
+
"a change the player makes there reaches the game as",
|
|
3146
|
+
"`gem.settingChange` and does nothing else.",
|
|
3147
|
+
"",
|
|
3148
|
+
"Gated by `gameSettings`: sent only to a parent that advertised it. To",
|
|
3149
|
+
"any other, `gem.settings.declare` returns false."
|
|
3150
|
+
],
|
|
3151
|
+
"fields": {
|
|
3152
|
+
"settings": {
|
|
3153
|
+
"kind": "array",
|
|
3154
|
+
"maxItems": 8,
|
|
3155
|
+
"items": {
|
|
3156
|
+
"kind": "object",
|
|
3157
|
+
"fields": {
|
|
3158
|
+
"id": {
|
|
3159
|
+
"kind": "string",
|
|
3160
|
+
"maxLength": 40,
|
|
3161
|
+
"$comment": "The game's own name for the setting, 1..40 characters of A-Z a-z 0-9 _ -, echoed in `gem.settingChange`."
|
|
3162
|
+
},
|
|
3163
|
+
"label": {
|
|
3164
|
+
"kind": "string",
|
|
3165
|
+
"maxLength": 40,
|
|
3166
|
+
"$comment": "What the player reads, 1..40 characters, already translated. Untrusted text: rendered as text only."
|
|
3167
|
+
},
|
|
3168
|
+
"kind": {
|
|
3169
|
+
"kind": "enum",
|
|
3170
|
+
"values": ["toggle", "slider", "choice"]
|
|
3171
|
+
},
|
|
3172
|
+
"value": {
|
|
3173
|
+
"kind": "scalar",
|
|
3174
|
+
"maxLength": 40,
|
|
3175
|
+
"min": -1000000,
|
|
3176
|
+
"max": 1000000,
|
|
3177
|
+
"$comment": "The setting's current value: a boolean for a toggle, a number in [min, max] for a slider, one of `options`' ids for a choice."
|
|
3178
|
+
},
|
|
3179
|
+
"quick": {
|
|
3180
|
+
"kind": "boolean",
|
|
3181
|
+
"optional": true,
|
|
3182
|
+
"$comment": "Toggles only: ask to appear in the menu's quick row. A parent honours the first two that ask."
|
|
3183
|
+
},
|
|
3184
|
+
"icon": {
|
|
3185
|
+
"kind": "string",
|
|
3186
|
+
"maxLength": 16,
|
|
3187
|
+
"format": "code",
|
|
3188
|
+
"optional": true,
|
|
3189
|
+
"$comment": "A code: music, sfx, voice, eye, text, hint, speed, bright, controls or star. Unknown means the parent's generic glyph."
|
|
3190
|
+
},
|
|
3191
|
+
"min": {
|
|
3192
|
+
"kind": "number",
|
|
3193
|
+
"min": -1000000,
|
|
3194
|
+
"max": 1000000,
|
|
3195
|
+
"optional": true,
|
|
3196
|
+
"$comment": "Sliders only: the lowest value, 0 when absent. Below `max`."
|
|
3197
|
+
},
|
|
3198
|
+
"max": {
|
|
3199
|
+
"kind": "number",
|
|
3200
|
+
"min": -1000000,
|
|
3201
|
+
"max": 1000000,
|
|
3202
|
+
"optional": true,
|
|
3203
|
+
"$comment": "Sliders only: the highest value, 100 when absent. Above `min`."
|
|
3204
|
+
},
|
|
3205
|
+
"step": {
|
|
3206
|
+
"kind": "number",
|
|
3207
|
+
"min": 0,
|
|
3208
|
+
"max": 1000000,
|
|
3209
|
+
"optional": true,
|
|
3210
|
+
"$comment": "Sliders only: the increment from `min`, 1 when absent. Greater than 0."
|
|
3211
|
+
},
|
|
3212
|
+
"options": {
|
|
3213
|
+
"kind": "array",
|
|
3214
|
+
"maxItems": 4,
|
|
3215
|
+
"optional": true,
|
|
3216
|
+
"$comment": "Choices only: 2..4 options, ids unique, each with the same id and label rules as a setting.",
|
|
3217
|
+
"items": {
|
|
3218
|
+
"kind": "object",
|
|
3219
|
+
"fields": {
|
|
3220
|
+
"id": { "kind": "string", "maxLength": 40 },
|
|
3221
|
+
"label": { "kind": "string", "maxLength": 40 }
|
|
3222
|
+
}
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
},
|
|
3229
|
+
"rateLimit": { "perMinute": 120 }
|
|
3230
|
+
},
|
|
3231
|
+
|
|
3232
|
+
{
|
|
3233
|
+
"type": "gem.settingChange",
|
|
3234
|
+
"direction": "parentToFrame",
|
|
3235
|
+
"transport": "port",
|
|
3236
|
+
"$comment": [
|
|
3237
|
+
"The player changed one of the game's declared settings in the arcade's",
|
|
3238
|
+
"own chrome: the setting with this `id`, now at `value`.",
|
|
3239
|
+
"",
|
|
3240
|
+
"Sent only for an id the frame's LATEST `gem.settingsDeclare` holds,",
|
|
3241
|
+
"with a value of that setting's kind - a boolean for a toggle, a slider's",
|
|
3242
|
+
"number clamped into [min, max] and onto its step, one of a choice's",
|
|
3243
|
+
"option ids - and only to a frame that advertised `gameSettings`. A",
|
|
3244
|
+
"parent coalesces a drag: it sends a slider's value when the player",
|
|
3245
|
+
"lets go, or at most a few times a second while they hold it.",
|
|
3246
|
+
"",
|
|
3247
|
+
"THE GAME IS USUALLY PAUSED when this arrives - the menu holds the",
|
|
3248
|
+
"`gem.pause` it opened with - and applies the change anyway, so the",
|
|
3249
|
+
"player hears the music stop while the menu is still open. A frame",
|
|
3250
|
+
"that hears an id it no longer declares ignores it: the menu may have",
|
|
3251
|
+
"been open across a change.",
|
|
3252
|
+
"",
|
|
3253
|
+
"The SDK writes the new value into the declaration it holds before the",
|
|
3254
|
+
"game's handlers run, so the next handshake re-sends what the player",
|
|
3255
|
+
"chose rather than what the game last said.",
|
|
3256
|
+
"",
|
|
3257
|
+
"A PRESENTATION EVENT, NOT AN AUTHORIZATION CONTROL. It tells the game",
|
|
3258
|
+
"what the player picked in a mirror of the game's own screen, and",
|
|
3259
|
+
"nothing else; the game keeps the choice where it keeps any other."
|
|
3260
|
+
],
|
|
3261
|
+
"fields": {
|
|
3262
|
+
"id": {
|
|
3263
|
+
"kind": "string",
|
|
3264
|
+
"maxLength": 40,
|
|
3265
|
+
"$comment": "The setting's id, from the latest `gem.settingsDeclare`."
|
|
3266
|
+
},
|
|
3267
|
+
"value": {
|
|
3268
|
+
"kind": "scalar",
|
|
3269
|
+
"maxLength": 40,
|
|
3270
|
+
"min": -1000000,
|
|
3271
|
+
"max": 1000000,
|
|
3272
|
+
"$comment": "The new value, of the setting's kind."
|
|
3273
|
+
}
|
|
3274
|
+
},
|
|
3275
|
+
"rateLimit": { "perMinute": 120 }
|
|
3276
|
+
},
|
|
3277
|
+
|
|
3079
3278
|
{
|
|
3080
3279
|
"type": "gem.requestShare",
|
|
3081
3280
|
"direction": "frameToParent",
|