@indiegems/gem-web-sdk 17.0.0 → 18.1.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 +21 -0
- package/dist/function.d.ts +4 -0
- package/dist/game.d.ts +11 -1
- package/dist/gem-web-sdk.bridge.js +2 -2
- package/dist/gem-web-sdk.conformance.js +3 -3
- 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 +17 -3
- package/dist/sdk.d.ts +11 -1
- package/docs/analytics.md +15 -8
- package/docs/api/api-reference-function.md +16 -5
- package/docs/api/api-reference-game.md +109 -5
- package/docs/api/api-reference-server.md +6 -2
- package/docs/api/reference.json +102 -8
- package/docs/changelog.md +21 -0
- package/docs/getting-started.md +1 -1
- package/docs/manifest.json +10 -10
- package/docs/server-bundles.md +2 -2
- package/docs/what-a-game-must-do.md +29 -0
- package/package.json +1 -1
- package/schema/bridge.v1.json +58 -0
- package/schema/capabilities.public.json +6 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The function surface — API reference
|
|
2
2
|
|
|
3
|
-
Generated from `@indiegems/gem-web-sdk/function`
|
|
3
|
+
Generated from `@indiegems/gem-web-sdk/function` v18.1.0, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
|
|
4
4
|
|
|
5
5
|
`@indiegems/gem-web-sdk/function` exports exactly the symbols on this page and nothing else.
|
|
6
6
|
|
|
@@ -23,7 +23,11 @@ type AnalyticsValue = string | number
|
|
|
23
23
|
A value attached to an event.
|
|
24
24
|
|
|
25
25
|
A **string** is a dimension and a **number** is a measure, and which one a
|
|
26
|
-
key is was decided in your game config, not here.
|
|
26
|
+
key is was decided in your game config, not here. The one exception, in a
|
|
27
|
+
browser game, is a key your config declares as an integer `range`
|
|
28
|
+
dimension: there a number is that dimension's value, sent as its decimal. A
|
|
29
|
+
dedicated server and a serverless function read no config, so there a
|
|
30
|
+
range dimension goes as its decimal string. Dimensions are closed sets
|
|
27
31
|
declared ahead of time — that is the whole reason there is no free-text
|
|
28
32
|
property — and measures are the numbers the platform sums, averages and
|
|
29
33
|
takes the min and max of.
|
|
@@ -267,7 +271,10 @@ track(name: string, props?: Readonly<Record<string, AnalyticsValue>>): void
|
|
|
267
271
|
Record an event. Synchronous, and it never throws.
|
|
268
272
|
|
|
269
273
|
String values become dimensions and numbers become measures, matched
|
|
270
|
-
against your `analytics_events` declaration server-side.
|
|
274
|
+
against your `analytics_events` declaration server-side. A number on a key
|
|
275
|
+
that declaration makes an integer `range` dimension is that dimension's
|
|
276
|
+
value instead — `level: 7` against `level: { range: { min: 1, max: 50 } }`
|
|
277
|
+
— and so is its decimal string, `level: '7'`. Nothing is sent
|
|
271
278
|
yet: the event joins a queue that goes out on a timer, at 50 events, and
|
|
272
279
|
on the way out of the page.
|
|
273
280
|
|
|
@@ -275,12 +282,16 @@ on the way out of the page.
|
|
|
275
282
|
a name starting `gem_` is refused here rather than sent and rejected
|
|
276
283
|
there.
|
|
277
284
|
|
|
285
|
+
⚠️ In a serverless function the SDK holds no config, so a number there is
|
|
286
|
+
always a measure: pass a range dimension as its decimal string.
|
|
287
|
+
|
|
278
288
|
| Parameter | Type | Description |
|
|
279
289
|
| --- | --- | --- |
|
|
280
290
|
| `name` | `string` | A declared event id — the `id` of an entry in your config's
|
|
281
291
|
`analytics_events`. |
|
|
282
|
-
| `props` | `Readonly<Record<string, AnalyticsValue>>` | Dimensions (strings
|
|
283
|
-
whatever [AnalyticsApi.setContext](#analyticsapi-setcontext)
|
|
292
|
+
| `props` | `Readonly<Record<string, AnalyticsValue>>` | Dimensions (strings, or a number on a `range` dimension) and
|
|
293
|
+
measures (numbers), merged over whatever [AnalyticsApi.setContext](#analyticsapi-setcontext)
|
|
294
|
+
holds. |
|
|
284
295
|
|
|
285
296
|
<a id="analyticsapi-setcontext"></a>
|
|
286
297
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The browser surface — API reference
|
|
2
2
|
|
|
3
|
-
Generated from `@indiegems/gem-web-sdk/sdk`
|
|
3
|
+
Generated from `@indiegems/gem-web-sdk/sdk` v18.1.0, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
|
|
4
4
|
|
|
5
5
|
`@indiegems/gem-web-sdk/sdk` is the one import a game writes, wherever its code runs. `@indiegems/gem-web-sdk/game` exports exactly the symbols on this page and nothing else, for a build that wants only this half.
|
|
6
6
|
|
|
@@ -3430,7 +3430,11 @@ type AnalyticsValue = string | number
|
|
|
3430
3430
|
A value attached to an event.
|
|
3431
3431
|
|
|
3432
3432
|
A **string** is a dimension and a **number** is a measure, and which one a
|
|
3433
|
-
key is was decided in your game config, not here.
|
|
3433
|
+
key is was decided in your game config, not here. The one exception, in a
|
|
3434
|
+
browser game, is a key your config declares as an integer `range`
|
|
3435
|
+
dimension: there a number is that dimension's value, sent as its decimal. A
|
|
3436
|
+
dedicated server and a serverless function read no config, so there a
|
|
3437
|
+
range dimension goes as its decimal string. Dimensions are closed sets
|
|
3434
3438
|
declared ahead of time — that is the whole reason there is no free-text
|
|
3435
3439
|
property — and measures are the numbers the platform sums, averages and
|
|
3436
3440
|
takes the min and max of.
|
|
@@ -3674,7 +3678,10 @@ track(name: string, props?: Readonly<Record<string, AnalyticsValue>>): void
|
|
|
3674
3678
|
Record an event. Synchronous, and it never throws.
|
|
3675
3679
|
|
|
3676
3680
|
String values become dimensions and numbers become measures, matched
|
|
3677
|
-
against your `analytics_events` declaration server-side.
|
|
3681
|
+
against your `analytics_events` declaration server-side. A number on a key
|
|
3682
|
+
that declaration makes an integer `range` dimension is that dimension's
|
|
3683
|
+
value instead — `level: 7` against `level: { range: { min: 1, max: 50 } }`
|
|
3684
|
+
— and so is its decimal string, `level: '7'`. Nothing is sent
|
|
3678
3685
|
yet: the event joins a queue that goes out on a timer, at 50 events, and
|
|
3679
3686
|
on the way out of the page.
|
|
3680
3687
|
|
|
@@ -3682,12 +3689,16 @@ on the way out of the page.
|
|
|
3682
3689
|
a name starting `gem_` is refused here rather than sent and rejected
|
|
3683
3690
|
there.
|
|
3684
3691
|
|
|
3692
|
+
⚠️ In a serverless function the SDK holds no config, so a number there is
|
|
3693
|
+
always a measure: pass a range dimension as its decimal string.
|
|
3694
|
+
|
|
3685
3695
|
| Parameter | Type | Description |
|
|
3686
3696
|
| --- | --- | --- |
|
|
3687
3697
|
| `name` | `string` | A declared event id — the `id` of an entry in your config's
|
|
3688
3698
|
`analytics_events`. |
|
|
3689
|
-
| `props` | `Readonly<Record<string, AnalyticsValue>>` | Dimensions (strings
|
|
3690
|
-
whatever [AnalyticsApi.setContext](#analyticsapi-setcontext)
|
|
3699
|
+
| `props` | `Readonly<Record<string, AnalyticsValue>>` | Dimensions (strings, or a number on a `range` dimension) and
|
|
3700
|
+
measures (numbers), merged over whatever [AnalyticsApi.setContext](#analyticsapi-setcontext)
|
|
3701
|
+
holds. |
|
|
3691
3702
|
|
|
3692
3703
|
<a id="analyticsapi-setcontext"></a>
|
|
3693
3704
|
|
|
@@ -6969,6 +6980,37 @@ A corner of your frame, for `gem.setGemCorner`: where you would like the
|
|
|
6969
6980
|
arcade's Gem button to sit. `'top-left'` is where it sits unless you ask.
|
|
6970
6981
|
Physical corners: `'top-left'` is the top-left in every language.
|
|
6971
6982
|
|
|
6983
|
+
<a id="menustyle"></a>
|
|
6984
|
+
|
|
6985
|
+
## MenuStyle
|
|
6986
|
+
|
|
6987
|
+
```ts
|
|
6988
|
+
interface MenuStyle
|
|
6989
|
+
```
|
|
6990
|
+
|
|
6991
|
+
Two colours for the arcade's own screens over your game, for
|
|
6992
|
+
`gem.setMenuStyle`: each exactly `#rrggbb`. The arcade works out the rest.
|
|
6993
|
+
|
|
6994
|
+
<a id="menustyle-ground"></a>
|
|
6995
|
+
|
|
6996
|
+
## MenuStyle.ground
|
|
6997
|
+
|
|
6998
|
+
```ts
|
|
6999
|
+
readonly ground: string
|
|
7000
|
+
```
|
|
7001
|
+
|
|
7002
|
+
The colour the arcade's surfaces are built on, such as `'#1b2a4a'`.
|
|
7003
|
+
|
|
7004
|
+
<a id="menustyle-accent"></a>
|
|
7005
|
+
|
|
7006
|
+
## MenuStyle.accent
|
|
7007
|
+
|
|
7008
|
+
```ts
|
|
7009
|
+
readonly accent: string
|
|
7010
|
+
```
|
|
7011
|
+
|
|
7012
|
+
The one highlight, at least 3:1 against `ground`, such as `'#ffb300'`.
|
|
7013
|
+
|
|
6972
7014
|
<a id="framestate"></a>
|
|
6973
7015
|
|
|
6974
7016
|
## FrameState
|
|
@@ -7346,6 +7388,29 @@ its control.
|
|
|
7346
7388
|
up, for an arcade that cannot move its control, for a value that is not
|
|
7347
7389
|
one of the four corners, and past this frame's own limit.
|
|
7348
7390
|
|
|
7391
|
+
<a id="gemframe-setmenustyle"></a>
|
|
7392
|
+
|
|
7393
|
+
## GemFrame.setMenuStyle
|
|
7394
|
+
|
|
7395
|
+
```ts
|
|
7396
|
+
setMenuStyle(style: MenuStyle | null): boolean
|
|
7397
|
+
```
|
|
7398
|
+
|
|
7399
|
+
Give the arcade's own screens over your game two colours to wear, or
|
|
7400
|
+
`null` to hand them back to the player's style: the whole answer each
|
|
7401
|
+
time, the latest one winning.
|
|
7402
|
+
|
|
7403
|
+
Prefer `gem.setMenuStyle`, which checks the colours and holds them across
|
|
7404
|
+
a reconnect. This one sends only while connected, and only to an arcade
|
|
7405
|
+
that can wear them.
|
|
7406
|
+
|
|
7407
|
+
| Parameter | Type |
|
|
7408
|
+
| --- | --- |
|
|
7409
|
+
| `style` | `MenuStyle \| null` |
|
|
7410
|
+
|
|
7411
|
+
**Returns.** whether the message left the frame: `false` before the bridge is
|
|
7412
|
+
up, for an arcade that cannot wear them, and past this frame's own limit.
|
|
7413
|
+
|
|
7349
7414
|
<a id="gemframe-requestshare"></a>
|
|
7350
7415
|
|
|
7351
7416
|
## GemFrame.requestShare
|
|
@@ -12019,6 +12084,45 @@ with a warning on the console, and changes nothing.
|
|
|
12019
12084
|
up (the corner is held and sent when it connects), under an embedder that
|
|
12020
12085
|
cannot move its control, and for a value that is not a corner.
|
|
12021
12086
|
|
|
12087
|
+
<a id="gem-setmenustyle"></a>
|
|
12088
|
+
|
|
12089
|
+
## Gem.setMenuStyle
|
|
12090
|
+
|
|
12091
|
+
```ts
|
|
12092
|
+
setMenuStyle(style: MenuStyle | null): boolean
|
|
12093
|
+
```
|
|
12094
|
+
|
|
12095
|
+
Give the arcade's own screens over your game your colours, so they match
|
|
12096
|
+
it: on the Gem Arcade, the burger button, the Gem menu and its pages, and
|
|
12097
|
+
every Arcade pop-up over the running game.
|
|
12098
|
+
|
|
12099
|
+
```js
|
|
12100
|
+
gem.setMenuStyle({ ground: '#1b2a4a', accent: '#ffb300' });
|
|
12101
|
+
gem.setMenuStyle(null); // back to the player's own style
|
|
12102
|
+
```
|
|
12103
|
+
|
|
12104
|
+
**Colours only.** `ground` is what the arcade's surfaces are built on and
|
|
12105
|
+
`accent` its one highlight; the arcade works out the text, rims, button
|
|
12106
|
+
shapes and fonts, so its screens stay readable on any ground.
|
|
12107
|
+
|
|
12108
|
+
**The Arcade refuses colours it cannot use.** Each must be exactly
|
|
12109
|
+
`#rrggbb`, and `accent` must reach 3:1 contrast against `ground`. Anything
|
|
12110
|
+
else is ignored, with a warning on the console giving the measured ratio:
|
|
12111
|
+
the last colours stand, nothing is sent, and this returns `false`.
|
|
12112
|
+
|
|
12113
|
+
**Your colours win over the player's chosen style while your game runs**,
|
|
12114
|
+
and the player's style comes back when it ends. It is screen state, not a
|
|
12115
|
+
toggle: each call is the whole answer, so you may change it between levels.
|
|
12116
|
+
Call it at boot, so your colours arrive with the first screen.
|
|
12117
|
+
|
|
12118
|
+
| Parameter | Type | Description |
|
|
12119
|
+
| --- | --- | --- |
|
|
12120
|
+
| `style` | `MenuStyle \| null` | The two colours, or `null` to hand back to the player's style. |
|
|
12121
|
+
|
|
12122
|
+
**Returns.** `true` when the arcade was told now; `false` before the bridge is
|
|
12123
|
+
up (the colours are held and sent when it connects), under an embedder
|
|
12124
|
+
that cannot wear them, and for colours it would refuse.
|
|
12125
|
+
|
|
12022
12126
|
<a id="gem-reportframe"></a>
|
|
12023
12127
|
|
|
12024
12128
|
## Gem.reportFrame
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The server surface — API reference
|
|
2
2
|
|
|
3
|
-
Generated from `@indiegems/gem-web-sdk/sdk`
|
|
3
|
+
Generated from `@indiegems/gem-web-sdk/sdk` v18.1.0, the version of the package this file ships in. Every symbol below carries an explicit anchor, its `anchor` in `reference.json` beside this file.
|
|
4
4
|
|
|
5
5
|
`@indiegems/gem-web-sdk/sdk` is the one import a game writes, wherever its code runs. `@indiegems/gem-web-sdk/server` exports exactly the symbols on this page and nothing else, for a build that wants only this half.
|
|
6
6
|
|
|
@@ -21,7 +21,11 @@ type AnalyticsValue = string | number
|
|
|
21
21
|
A value attached to an event.
|
|
22
22
|
|
|
23
23
|
A **string** is a dimension and a **number** is a measure, and which one a
|
|
24
|
-
key is was decided in your game config, not here.
|
|
24
|
+
key is was decided in your game config, not here. The one exception, in a
|
|
25
|
+
browser game, is a key your config declares as an integer `range`
|
|
26
|
+
dimension: there a number is that dimension's value, sent as its decimal. A
|
|
27
|
+
dedicated server and a serverless function read no config, so there a
|
|
28
|
+
range dimension goes as its decimal string. Dimensions are closed sets
|
|
25
29
|
declared ahead of time — that is the whole reason there is no free-text
|
|
26
30
|
property — and measures are the numbers the platform sums, averages and
|
|
27
31
|
takes the min and max of.
|
package/docs/api/reference.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"schema_version": 2,
|
|
3
3
|
"source": {
|
|
4
4
|
"repo": "IndieGems/gem-web-sdk",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "18.1.0"
|
|
6
6
|
},
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -4147,7 +4147,7 @@
|
|
|
4147
4147
|
"group": "analytics",
|
|
4148
4148
|
"signature": "type AnalyticsValue = string | number",
|
|
4149
4149
|
"documented": true,
|
|
4150
|
-
"summary": "A value attached to an event.\n\nA **string** is a dimension and a **number** is a measure, and which one a\nkey is was decided in your game config, not here. Dimensions are closed sets\ndeclared ahead of time — that is the whole reason there is no free-text\nproperty — and measures are the numbers the platform sums, averages and\ntakes the min and max of.",
|
|
4150
|
+
"summary": "A value attached to an event.\n\nA **string** is a dimension and a **number** is a measure, and which one a\nkey is was decided in your game config, not here. The one exception, in a\nbrowser game, is a key your config declares as an integer `range`\ndimension: there a number is that dimension's value, sent as its decimal. A\ndedicated server and a serverless function read no config, so there a\nrange dimension goes as its decimal string. Dimensions are closed sets\ndeclared ahead of time — that is the whole reason there is no free-text\nproperty — and measures are the numbers the platform sums, averages and\ntakes the min and max of.",
|
|
4151
4151
|
"deprecated": null,
|
|
4152
4152
|
"params": [],
|
|
4153
4153
|
"returns": null,
|
|
@@ -4424,7 +4424,7 @@
|
|
|
4424
4424
|
"group": "analytics",
|
|
4425
4425
|
"signature": "track(name: string, props?: Readonly<Record<string, AnalyticsValue>>): void",
|
|
4426
4426
|
"documented": true,
|
|
4427
|
-
"summary": "Record an event. Synchronous, and it never throws.\n\nString values become dimensions and numbers become measures, matched\nagainst your `analytics_events` declaration server-side. Nothing is sent\nyet: the event joins a queue that goes out on a timer, at 50 events, and\non the way out of the page.\n\n⚠️ `gem_` IS RESERVED. The SDK emits the platform's own events itself, so\na name starting `gem_` is refused here rather than sent and rejected\nthere.",
|
|
4427
|
+
"summary": "Record an event. Synchronous, and it never throws.\n\nString values become dimensions and numbers become measures, matched\nagainst your `analytics_events` declaration server-side. A number on a key\nthat declaration makes an integer `range` dimension is that dimension's\nvalue instead — `level: 7` against `level: { range: { min: 1, max: 50 } }`\n— and so is its decimal string, `level: '7'`. Nothing is sent\nyet: the event joins a queue that goes out on a timer, at 50 events, and\non the way out of the page.\n\n⚠️ `gem_` IS RESERVED. The SDK emits the platform's own events itself, so\na name starting `gem_` is refused here rather than sent and rejected\nthere.\n\n⚠️ In a serverless function the SDK holds no config, so a number there is\nalways a measure: pass a range dimension as its decimal string.",
|
|
4428
4428
|
"deprecated": null,
|
|
4429
4429
|
"params": [
|
|
4430
4430
|
{
|
|
@@ -4437,7 +4437,7 @@
|
|
|
4437
4437
|
"name": "props",
|
|
4438
4438
|
"type": "Readonly<Record<string, AnalyticsValue>>",
|
|
4439
4439
|
"optional": false,
|
|
4440
|
-
"summary": "Dimensions (strings) and
|
|
4440
|
+
"summary": "Dimensions (strings, or a number on a `range` dimension) and\n measures (numbers), merged over whatever [AnalyticsApi.setContext](api-reference-game.md#analyticsapi-setcontext)\n holds."
|
|
4441
4441
|
}
|
|
4442
4442
|
],
|
|
4443
4443
|
"returns": null,
|
|
@@ -8304,6 +8304,54 @@
|
|
|
8304
8304
|
"defaultValue": null,
|
|
8305
8305
|
"guides": []
|
|
8306
8306
|
},
|
|
8307
|
+
{
|
|
8308
|
+
"id": "MenuStyle",
|
|
8309
|
+
"name": "MenuStyle",
|
|
8310
|
+
"anchor": "menustyle",
|
|
8311
|
+
"group": "frame",
|
|
8312
|
+
"signature": "interface MenuStyle",
|
|
8313
|
+
"documented": true,
|
|
8314
|
+
"summary": "Two colours for the arcade's own screens over your game, for\n`gem.setMenuStyle`: each exactly `#rrggbb`. The arcade works out the rest.",
|
|
8315
|
+
"deprecated": null,
|
|
8316
|
+
"params": [],
|
|
8317
|
+
"returns": null,
|
|
8318
|
+
"throws": null,
|
|
8319
|
+
"example": null,
|
|
8320
|
+
"defaultValue": null,
|
|
8321
|
+
"guides": []
|
|
8322
|
+
},
|
|
8323
|
+
{
|
|
8324
|
+
"id": "MenuStyle.ground",
|
|
8325
|
+
"name": "ground",
|
|
8326
|
+
"anchor": "menustyle-ground",
|
|
8327
|
+
"group": "frame",
|
|
8328
|
+
"signature": "readonly ground: string",
|
|
8329
|
+
"documented": true,
|
|
8330
|
+
"summary": "The colour the arcade's surfaces are built on, such as `'#1b2a4a'`.",
|
|
8331
|
+
"deprecated": null,
|
|
8332
|
+
"params": [],
|
|
8333
|
+
"returns": null,
|
|
8334
|
+
"throws": null,
|
|
8335
|
+
"example": null,
|
|
8336
|
+
"defaultValue": null,
|
|
8337
|
+
"guides": []
|
|
8338
|
+
},
|
|
8339
|
+
{
|
|
8340
|
+
"id": "MenuStyle.accent",
|
|
8341
|
+
"name": "accent",
|
|
8342
|
+
"anchor": "menustyle-accent",
|
|
8343
|
+
"group": "frame",
|
|
8344
|
+
"signature": "readonly accent: string",
|
|
8345
|
+
"documented": true,
|
|
8346
|
+
"summary": "The one highlight, at least 3:1 against `ground`, such as `'#ffb300'`.",
|
|
8347
|
+
"deprecated": null,
|
|
8348
|
+
"params": [],
|
|
8349
|
+
"returns": null,
|
|
8350
|
+
"throws": null,
|
|
8351
|
+
"example": null,
|
|
8352
|
+
"defaultValue": null,
|
|
8353
|
+
"guides": []
|
|
8354
|
+
},
|
|
8307
8355
|
{
|
|
8308
8356
|
"id": "FrameState",
|
|
8309
8357
|
"name": "FrameState",
|
|
@@ -8684,6 +8732,29 @@
|
|
|
8684
8732
|
"defaultValue": null,
|
|
8685
8733
|
"guides": []
|
|
8686
8734
|
},
|
|
8735
|
+
{
|
|
8736
|
+
"id": "GemFrame.setMenuStyle",
|
|
8737
|
+
"name": "setMenuStyle",
|
|
8738
|
+
"anchor": "gemframe-setmenustyle",
|
|
8739
|
+
"group": "frame",
|
|
8740
|
+
"signature": "setMenuStyle(style: MenuStyle | null): boolean",
|
|
8741
|
+
"documented": true,
|
|
8742
|
+
"summary": "Give the arcade's own screens over your game two colours to wear, or\n`null` to hand them back to the player's style: the whole answer each\ntime, the latest one winning.\n\nPrefer `gem.setMenuStyle`, which checks the colours and holds them across\na reconnect. This one sends only while connected, and only to an arcade\nthat can wear them.",
|
|
8743
|
+
"deprecated": null,
|
|
8744
|
+
"params": [
|
|
8745
|
+
{
|
|
8746
|
+
"name": "style",
|
|
8747
|
+
"type": "MenuStyle | null",
|
|
8748
|
+
"optional": false,
|
|
8749
|
+
"summary": null
|
|
8750
|
+
}
|
|
8751
|
+
],
|
|
8752
|
+
"returns": "whether the message left the frame: `false` before the bridge is\n up, for an arcade that cannot wear them, and past this frame's own limit.",
|
|
8753
|
+
"throws": null,
|
|
8754
|
+
"example": null,
|
|
8755
|
+
"defaultValue": null,
|
|
8756
|
+
"guides": []
|
|
8757
|
+
},
|
|
8687
8758
|
{
|
|
8688
8759
|
"id": "GemFrame.requestShare",
|
|
8689
8760
|
"name": "requestShare",
|
|
@@ -13364,6 +13435,29 @@
|
|
|
13364
13435
|
"defaultValue": null,
|
|
13365
13436
|
"guides": []
|
|
13366
13437
|
},
|
|
13438
|
+
{
|
|
13439
|
+
"id": "Gem.setMenuStyle",
|
|
13440
|
+
"name": "setMenuStyle",
|
|
13441
|
+
"anchor": "gem-setmenustyle",
|
|
13442
|
+
"group": "start",
|
|
13443
|
+
"signature": "setMenuStyle(style: MenuStyle | null): boolean",
|
|
13444
|
+
"documented": true,
|
|
13445
|
+
"summary": "Give the arcade's own screens over your game your colours, so they match\nit: on the Gem Arcade, the burger button, the Gem menu and its pages, and\nevery Arcade pop-up over the running game.\n\n```js\ngem.setMenuStyle({ ground: '#1b2a4a', accent: '#ffb300' });\ngem.setMenuStyle(null); // back to the player's own style\n```\n\n**Colours only.** `ground` is what the arcade's surfaces are built on and\n`accent` its one highlight; the arcade works out the text, rims, button\nshapes and fonts, so its screens stay readable on any ground.\n\n**The Arcade refuses colours it cannot use.** Each must be exactly\n`#rrggbb`, and `accent` must reach 3:1 contrast against `ground`. Anything\nelse is ignored, with a warning on the console giving the measured ratio:\nthe last colours stand, nothing is sent, and this returns `false`.\n\n**Your colours win over the player's chosen style while your game runs**,\nand the player's style comes back when it ends. It is screen state, not a\ntoggle: each call is the whole answer, so you may change it between levels.\nCall it at boot, so your colours arrive with the first screen.",
|
|
13446
|
+
"deprecated": null,
|
|
13447
|
+
"params": [
|
|
13448
|
+
{
|
|
13449
|
+
"name": "style",
|
|
13450
|
+
"type": "MenuStyle | null",
|
|
13451
|
+
"optional": false,
|
|
13452
|
+
"summary": "The two colours, or `null` to hand back to the player's style."
|
|
13453
|
+
}
|
|
13454
|
+
],
|
|
13455
|
+
"returns": "`true` when the arcade was told now; `false` before the bridge is\n up (the colours are held and sent when it connects), under an embedder\n that cannot wear them, and for colours it would refuse.",
|
|
13456
|
+
"throws": null,
|
|
13457
|
+
"example": null,
|
|
13458
|
+
"defaultValue": null,
|
|
13459
|
+
"guides": []
|
|
13460
|
+
},
|
|
13367
13461
|
{
|
|
13368
13462
|
"id": "Gem.reportFrame",
|
|
13369
13463
|
"name": "reportFrame",
|
|
@@ -24289,7 +24383,7 @@
|
|
|
24289
24383
|
"group": "analytics",
|
|
24290
24384
|
"signature": "type AnalyticsValue = string | number",
|
|
24291
24385
|
"documented": true,
|
|
24292
|
-
"summary": "A value attached to an event.\n\nA **string** is a dimension and a **number** is a measure, and which one a\nkey is was decided in your game config, not here. Dimensions are closed sets\ndeclared ahead of time — that is the whole reason there is no free-text\nproperty — and measures are the numbers the platform sums, averages and\ntakes the min and max of.",
|
|
24386
|
+
"summary": "A value attached to an event.\n\nA **string** is a dimension and a **number** is a measure, and which one a\nkey is was decided in your game config, not here. The one exception, in a\nbrowser game, is a key your config declares as an integer `range`\ndimension: there a number is that dimension's value, sent as its decimal. A\ndedicated server and a serverless function read no config, so there a\nrange dimension goes as its decimal string. Dimensions are closed sets\ndeclared ahead of time — that is the whole reason there is no free-text\nproperty — and measures are the numbers the platform sums, averages and\ntakes the min and max of.",
|
|
24293
24387
|
"deprecated": null,
|
|
24294
24388
|
"params": [],
|
|
24295
24389
|
"returns": null,
|
|
@@ -29538,7 +29632,7 @@
|
|
|
29538
29632
|
"group": "analytics",
|
|
29539
29633
|
"signature": "type AnalyticsValue = string | number",
|
|
29540
29634
|
"documented": true,
|
|
29541
|
-
"summary": "A value attached to an event.\n\nA **string** is a dimension and a **number** is a measure, and which one a\nkey is was decided in your game config, not here. Dimensions are closed sets\ndeclared ahead of time — that is the whole reason there is no free-text\nproperty — and measures are the numbers the platform sums, averages and\ntakes the min and max of.",
|
|
29635
|
+
"summary": "A value attached to an event.\n\nA **string** is a dimension and a **number** is a measure, and which one a\nkey is was decided in your game config, not here. The one exception, in a\nbrowser game, is a key your config declares as an integer `range`\ndimension: there a number is that dimension's value, sent as its decimal. A\ndedicated server and a serverless function read no config, so there a\nrange dimension goes as its decimal string. Dimensions are closed sets\ndeclared ahead of time — that is the whole reason there is no free-text\nproperty — and measures are the numbers the platform sums, averages and\ntakes the min and max of.",
|
|
29542
29636
|
"deprecated": null,
|
|
29543
29637
|
"params": [],
|
|
29544
29638
|
"returns": null,
|
|
@@ -29815,7 +29909,7 @@
|
|
|
29815
29909
|
"group": "analytics",
|
|
29816
29910
|
"signature": "track(name: string, props?: Readonly<Record<string, AnalyticsValue>>): void",
|
|
29817
29911
|
"documented": true,
|
|
29818
|
-
"summary": "Record an event. Synchronous, and it never throws.\n\nString values become dimensions and numbers become measures, matched\nagainst your `analytics_events` declaration server-side. Nothing is sent\nyet: the event joins a queue that goes out on a timer, at 50 events, and\non the way out of the page.\n\n⚠️ `gem_` IS RESERVED. The SDK emits the platform's own events itself, so\na name starting `gem_` is refused here rather than sent and rejected\nthere.",
|
|
29912
|
+
"summary": "Record an event. Synchronous, and it never throws.\n\nString values become dimensions and numbers become measures, matched\nagainst your `analytics_events` declaration server-side. A number on a key\nthat declaration makes an integer `range` dimension is that dimension's\nvalue instead — `level: 7` against `level: { range: { min: 1, max: 50 } }`\n— and so is its decimal string, `level: '7'`. Nothing is sent\nyet: the event joins a queue that goes out on a timer, at 50 events, and\non the way out of the page.\n\n⚠️ `gem_` IS RESERVED. The SDK emits the platform's own events itself, so\na name starting `gem_` is refused here rather than sent and rejected\nthere.\n\n⚠️ In a serverless function the SDK holds no config, so a number there is\nalways a measure: pass a range dimension as its decimal string.",
|
|
29819
29913
|
"deprecated": null,
|
|
29820
29914
|
"params": [
|
|
29821
29915
|
{
|
|
@@ -29828,7 +29922,7 @@
|
|
|
29828
29922
|
"name": "props",
|
|
29829
29923
|
"type": "Readonly<Record<string, AnalyticsValue>>",
|
|
29830
29924
|
"optional": false,
|
|
29831
|
-
"summary": "Dimensions (strings) and
|
|
29925
|
+
"summary": "Dimensions (strings, or a number on a `range` dimension) and\n measures (numbers), merged over whatever [AnalyticsApi.setContext](api-reference-function.md#analyticsapi-setcontext)\n holds."
|
|
29832
29926
|
}
|
|
29833
29927
|
],
|
|
29834
29928
|
"returns": null,
|
package/docs/changelog.md
CHANGED
|
@@ -16,6 +16,27 @@ 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
|
+
## 18.1.0
|
|
20
|
+
|
|
21
|
+
Upgrading from 18.0.0. Impact: recommended.
|
|
22
|
+
|
|
23
|
+
### New capability
|
|
24
|
+
|
|
25
|
+
- A number sent for an analytics dimension that your game config declares as a range is now delivered as that dimension, written as its decimal. Previously such events went out as a measure and were refused as missing a dimension. If your game dropped, skipped or worked around these events, you can send the number directly. Numbers on other fields remain measures, and events your config does not declare are sent as before. The analytics options also gain a declarations field, which the SDK fills in from your game config, so you normally do not set it. Code that runs on a server or in a function should still send a range as its decimal string.
|
|
26
|
+
|
|
27
|
+
## 18.0.0
|
|
28
|
+
|
|
29
|
+
Upgrading from 17.0.0. Impact: required.
|
|
30
|
+
|
|
31
|
+
### Rebuild
|
|
32
|
+
|
|
33
|
+
- The set of capability names a game can query has a new member, menuStyle. Recompiling is enough, but if your code handles every capability name exhaustively, add a case for the new one.
|
|
34
|
+
- The frame message type has a new member for menu style, and the list of messages a game frame sends to the Arcade now includes gem.menuStyle. Recompiling is enough, but code that handles every message exhaustively needs a case for the new message.
|
|
35
|
+
|
|
36
|
+
### New capability
|
|
37
|
+
|
|
38
|
+
- A game can now hand the Arcade its own colours for the Arcade menu by calling Gem.setMenuStyle with a MenuStyle value. Check for the menuStyle capability first, since an older Arcade will not act on it. The same call is also available on the frame object.
|
|
39
|
+
|
|
19
40
|
## 17.0.0
|
|
20
41
|
|
|
21
42
|
*Written from the API facts alone; no summary was generated for this release.*
|
package/docs/getting-started.md
CHANGED
package/docs/manifest.json
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"file": "analytics.md",
|
|
16
|
-
"sha256": "
|
|
17
|
-
"updated": "2026-10-
|
|
16
|
+
"sha256": "42f3d0d3360e1a6066c21015bd4925475b4336a53611bf04acb773a7c6084e62",
|
|
17
|
+
"updated": "2026-10-30T16:54:41Z"
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"file": "arcade-and-store.md",
|
|
@@ -48,8 +48,8 @@
|
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"file": "changelog.md",
|
|
51
|
-
"sha256": "
|
|
52
|
-
"updated": "2026-10-
|
|
51
|
+
"sha256": "75530d611c02d513b1789d787e83a219392cfa92bfa70b1995aaa46bd233fbbd",
|
|
52
|
+
"updated": "2026-10-30T18:08:09Z"
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
"file": "daily-challenges.md",
|
|
@@ -78,8 +78,8 @@
|
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
80
|
"file": "getting-started.md",
|
|
81
|
-
"sha256": "
|
|
82
|
-
"updated": "2026-10-
|
|
81
|
+
"sha256": "cefcb0179415e448ac16b5e7e23be35c48745aa1b4ac5e23e7375f58b3c8890c",
|
|
82
|
+
"updated": "2026-10-30T18:08:09Z"
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
85
|
"file": "inventory-and-catalogs.md",
|
|
@@ -138,8 +138,8 @@
|
|
|
138
138
|
},
|
|
139
139
|
{
|
|
140
140
|
"file": "server-bundles.md",
|
|
141
|
-
"sha256": "
|
|
142
|
-
"updated": "2026-10-
|
|
141
|
+
"sha256": "a5bdf1ca63a3c5f9f3ca8b123cc569135779960934c74176453f2596a22da7f4",
|
|
142
|
+
"updated": "2026-10-30T18:08:09Z"
|
|
143
143
|
},
|
|
144
144
|
{
|
|
145
145
|
"file": "serverless-functions-js.md",
|
|
@@ -163,8 +163,8 @@
|
|
|
163
163
|
},
|
|
164
164
|
{
|
|
165
165
|
"file": "what-a-game-must-do.md",
|
|
166
|
-
"sha256": "
|
|
167
|
-
"updated": "2026-10-
|
|
166
|
+
"sha256": "8faa9ef2cef2a5eb73cf95d7c52af914325c2bc26834625c9cb4b5748eecc616",
|
|
167
|
+
"updated": "2026-10-30T14:09:09Z"
|
|
168
168
|
}
|
|
169
169
|
]
|
|
170
170
|
}
|
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/v18.1.0/gem-web-sdk.tgz
|
|
84
|
+
curl -fsSL https://downloads.gemarcade.com/sdk/v18.1.0/gem-web-sdk.tgz.sri
|
|
85
85
|
openssl dgst -sha384 -binary gem-web-sdk.tgz | openssl base64 -A
|
|
86
86
|
```
|
|
87
87
|
|
|
@@ -971,6 +971,35 @@ read the rectangles, so the arcade sends it none and instead raises `insets.top`
|
|
|
971
971
|
`--gem-safe-top` — past the bottom of the row. That game keeps working, at the cost of a full-width
|
|
972
972
|
band; upgrading gives the band back.
|
|
973
973
|
|
|
974
|
+
### Matching the Arcade to your game: `gem.setMenuStyle`
|
|
975
|
+
|
|
976
|
+
The burger button and everything the Arcade draws over your game wear the player's Arcade style
|
|
977
|
+
until you say otherwise. To make them match your game, give the Arcade two colours:
|
|
978
|
+
|
|
979
|
+
```js
|
|
980
|
+
gem.setMenuStyle({ ground: '#1b2a4a', accent: '#ffb300' }); // at boot, with your first screen
|
|
981
|
+
gem.setMenuStyle(null); // back to the player's own style
|
|
982
|
+
```
|
|
983
|
+
|
|
984
|
+
- **Colours only.** `ground` is what the Arcade's surfaces are built on and `accent` is its one
|
|
985
|
+
highlight. The Arcade works out the text, rims, button shapes and fonts, so its screens stay
|
|
986
|
+
readable on any ground.
|
|
987
|
+
- **What the Arcade refuses.** Each colour must be exactly `#rrggbb`, and `accent` must reach 3:1
|
|
988
|
+
contrast against `ground`. Anything else is ignored, with a warning on the console giving the
|
|
989
|
+
measured ratio: the last colours stand, nothing is sent, and the call returns `false`.
|
|
990
|
+
- **What wears your colours.** The burger button, the Gem menu and its pages, and every Arcade
|
|
991
|
+
pop-up over your running game, purchase sheets included. They do not reach the Arcade's other
|
|
992
|
+
screens.
|
|
993
|
+
- **Your colours win while your game runs.** They replace the style the player chose, and that
|
|
994
|
+
style comes back when your game ends.
|
|
995
|
+
- **It is screen state, not a toggle**: each call is the whole answer, held before the Arcade
|
|
996
|
+
connects and sent again after any reconnect, so you may change it between levels. A change the
|
|
997
|
+
Arcade receives while its menu or a pop-up is open waits until that closes.
|
|
998
|
+
|
|
999
|
+
`gem.setMenuStyle` returns `true` when the Arcade was told, and `false` before it connects, under an
|
|
1000
|
+
embedder that cannot wear your colours, and for colours it would refuse. On `false` from an embedder
|
|
1001
|
+
there is nothing else to do: never draw a look-alike of its menu.
|
|
1002
|
+
|
|
974
1003
|
## Which store-page experiment brought this player in: cohorts
|
|
975
1004
|
|
|
976
1005
|
**You need this only if you run an A/B experiment on your store page and want the game to match
|
package/package.json
CHANGED
package/schema/bridge.v1.json
CHANGED
|
@@ -3145,6 +3145,64 @@
|
|
|
3145
3145
|
"rateLimit": { "perMinute": 12 }
|
|
3146
3146
|
},
|
|
3147
3147
|
|
|
3148
|
+
{
|
|
3149
|
+
"type": "gem.menuStyle",
|
|
3150
|
+
"direction": "frameToParent",
|
|
3151
|
+
"transport": "port",
|
|
3152
|
+
"$comment": [
|
|
3153
|
+
"The colours the game would like the arcade's own screens over it to wear,",
|
|
3154
|
+
"so they match the game: in the Gem Arcade, the burger button, the Gem menu",
|
|
3155
|
+
"and its pages, and every Arcade pop-up over the running game. With no",
|
|
3156
|
+
"message at all those screens wear the player's own Arcade style.",
|
|
3157
|
+
"",
|
|
3158
|
+
"TWO COLOURS, BOTH OR NEITHER. `ground` is the colour the arcade's surfaces",
|
|
3159
|
+
"are built on and `accent` its one highlight. A message with neither hands",
|
|
3160
|
+
"the arcade back to the player's own style; a message with only one is",
|
|
3161
|
+
"refused by the parent. The parent works out everything else, text, rims,",
|
|
3162
|
+
"button shapes and fonts, so a game can never make its screens unreadable.",
|
|
3163
|
+
"",
|
|
3164
|
+
"SCREEN STATE, NOT A TOGGLE, like `gem.gemCorner`. Each message is the whole",
|
|
3165
|
+
"answer and the latest one wins, so a game may change it between levels.",
|
|
3166
|
+
"The SDK holds it from before the bridge is up and re-sends it after every",
|
|
3167
|
+
"handshake, so a parent that reconnects wears what the game had asked.",
|
|
3168
|
+
"",
|
|
3169
|
+
"THE PARENT DECIDES, AND IT CHECKS AGAIN. The frame is untrusted, so a",
|
|
3170
|
+
"parent checks both values itself before a byte of them reaches a style:",
|
|
3171
|
+
"exactly `#` and six hexadecimal digits, and at least 3:1 WCAG contrast",
|
|
3172
|
+
"between `accent` and `ground`. On failure it keeps the screens as they",
|
|
3173
|
+
"are and tells the game nothing; the SDK refuses the same values on the",
|
|
3174
|
+
"game's side, where a developer sees why. A format of its own is not used",
|
|
3175
|
+
"for the hex, because a parent built on an older contract refuses a format",
|
|
3176
|
+
"it does not know.",
|
|
3177
|
+
"",
|
|
3178
|
+
"ON THE PARENT'S TERMS. In the Gem Arcade the game's colours win over the",
|
|
3179
|
+
"player's chosen style for as long as that game runs, a change that arrives",
|
|
3180
|
+
"while one of the arcade's surfaces is open waits for it to close, and the",
|
|
3181
|
+
"player's own style comes back when the game ends.",
|
|
3182
|
+
"",
|
|
3183
|
+
"A PRESENTATION REQUEST ONLY, and not an authorization control. Cosmetic:",
|
|
3184
|
+
"nothing may key a trust decision on it.",
|
|
3185
|
+
"",
|
|
3186
|
+
"Gated by `menuStyle`: sent only to a parent that advertised it. To any",
|
|
3187
|
+
"other, `gem.setMenuStyle` returns false."
|
|
3188
|
+
],
|
|
3189
|
+
"fields": {
|
|
3190
|
+
"ground": {
|
|
3191
|
+
"kind": "string",
|
|
3192
|
+
"maxLength": 7,
|
|
3193
|
+
"optional": true,
|
|
3194
|
+
"$comment": "`#rrggbb`, the colour the arcade's surfaces are built on. Absent with `accent` to clear."
|
|
3195
|
+
},
|
|
3196
|
+
"accent": {
|
|
3197
|
+
"kind": "string",
|
|
3198
|
+
"maxLength": 7,
|
|
3199
|
+
"optional": true,
|
|
3200
|
+
"$comment": "`#rrggbb`, the one highlight, at least 3:1 against `ground`. Absent with `ground` to clear."
|
|
3201
|
+
}
|
|
3202
|
+
},
|
|
3203
|
+
"rateLimit": { "perMinute": 12 }
|
|
3204
|
+
},
|
|
3205
|
+
|
|
3148
3206
|
{
|
|
3149
3207
|
"type": "gem.settingsDeclare",
|
|
3150
3208
|
"direction": "frameToParent",
|