@indiegems/gem-web-sdk 14.0.0 → 14.0.2

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +2 -2
  3. package/brand/ticket-hero-128.png +0 -0
  4. package/brand/ticket-hero-256.png +0 -0
  5. package/brand/ticket-hero-384.png +0 -0
  6. package/brand/ticket-hero-512.png +0 -0
  7. package/brand/ticket-hero-768.png +0 -0
  8. package/brand/ticket-icon-20-1.5x.png +0 -0
  9. package/brand/ticket-icon-20-1x.png +0 -0
  10. package/brand/ticket-icon-20-2x.png +0 -0
  11. package/brand/ticket-icon-20-3x.png +0 -0
  12. package/brand/ticket-icon-32-1.5x.png +0 -0
  13. package/brand/ticket-icon-32-1x.png +0 -0
  14. package/brand/ticket-icon-32-2x.png +0 -0
  15. package/brand/ticket-icon-32-3x.png +0 -0
  16. package/dist/gem-web-sdk.esm.js +1 -1
  17. package/dist/gem-web-sdk.function.js +1 -1
  18. package/dist/gem-web-sdk.game.js +2 -2
  19. package/dist/gem-web-sdk.min.js +2 -2
  20. package/dist/gem-web-sdk.sdk.js +2 -2
  21. package/dist/gem-web-sdk.server.js +1 -1
  22. package/docs/achievements.md +2 -2
  23. package/docs/api/api-reference-function.md +3 -3
  24. package/docs/api/api-reference-game.md +65 -32
  25. package/docs/api/api-reference-server.md +1 -1
  26. package/docs/api/reference.json +21 -21
  27. package/docs/arcade-avatars.md +3 -3
  28. package/docs/arcade-economy.md +37 -36
  29. package/docs/brand-art.md +31 -30
  30. package/docs/changelog.md +12 -0
  31. package/docs/daily-challenges.md +1 -1
  32. package/docs/game-economy-tutorial.md +14 -14
  33. package/docs/getting-started.md +3 -3
  34. package/docs/inventory-and-catalogs.md +29 -29
  35. package/docs/manifest.json +32 -32
  36. package/docs/platform-rules.md +2 -2
  37. package/docs/rewarded-ads.md +1 -1
  38. package/docs/saving-player-progress.md +1 -1
  39. package/docs/server-bundles.md +2 -2
  40. package/docs/serverless-functions.md +2 -2
  41. package/docs/trading-and-gifting.md +1 -1
  42. package/docs/what-a-game-must-do.md +57 -36
  43. package/package.json +1 -1
  44. package/schema/bridge.v1.json +7 -7
@@ -2,7 +2,7 @@
2
2
  "schema_version": 2,
3
3
  "source": {
4
4
  "repo": "IndieGems/gem-web-sdk",
5
- "version": "14.0.0"
5
+ "version": "14.0.2"
6
6
  },
7
7
  "entries": [
8
8
  {
@@ -5242,7 +5242,7 @@
5242
5242
  "group": "player",
5243
5243
  "signature": "interface PlayerBoost",
5244
5244
  "documented": true,
5245
- "summary": "The player's Boost — **for display only**.\n\nReached as `gem.player.boost`, and always present on a `gem.player`: when\nthe arcade has not said (an older arcade, a backend without boosts, a read\nthat has not landed), it reads as not boosted — `active: false`, no\nmultipliers — which is exactly what an unboosted player's reads as too.\n\n```js\nconst tickets = gem.player?.boost.multipliers.find((m) => m.currencySlug === 'ARCADE_TICKETS');\nif (tickets && tickets.multiplier > 1) showBadge(`${tickets.multiplier}x`);\n```\n\n⚠️ **Show it; never gate on it.** A \"2x\" badge on a reward screen is what\nthis is for. Content, difficulty, matchmaking, prices and power must be the\nsame for a boosted and an unboosted player: the value is advisory, may lag,\nand can be forged inside your own page. The platform applies the real\nmultiplier when it pays, whatever you render.",
5245
+ "summary": "The player's Boost — **for display only**.\n\nReached as `gem.player.boost`, and always present on a `gem.player`: when\nthe arcade has not said (an older arcade, a backend without boosts, a read\nthat has not landed), it reads as not boosted — `active: false`, no\nmultipliers — which is exactly what an unboosted player's reads as too.\n\n```js\nconst coins = gem.player?.boost.multipliers.find((m) => m.currencySlug === 'ARCADE_TICKETS');\nif (coins && coins.multiplier > 1) showBadge(`${coins.multiplier}x`);\n```\n\n⚠️ **Show it; never gate on it.** A \"2x\" badge on a reward screen is what\nthis is for. Content, difficulty, matchmaking, prices and power must be the\nsame for a boosted and an unboosted player: the value is advisory, may lag,\nand can be forged inside your own page. The platform applies the real\nmultiplier when it pays, whatever you render.",
5246
5246
  "deprecated": null,
5247
5247
  "params": [],
5248
5248
  "returns": null,
@@ -6482,7 +6482,7 @@
6482
6482
  "group": "platform",
6483
6483
  "signature": "currencySlug: string",
6484
6484
  "documented": true,
6485
- "summary": "The platform currency's slug, as `gem.platform.currencies.get()` lists it —\n`GEMS` or `ARCADE_TICKETS`. It decides what flies — gems or tickets — and\nwhich of the player's totals the payout moves.",
6485
+ "summary": "The platform currency's slug, as `gem.platform.currencies.get()` lists it —\n`GEMS` or `ARCADE_TICKETS`. It decides what flies — gems or coins — and\nwhich of the player's totals the payout moves.",
6486
6486
  "deprecated": null,
6487
6487
  "params": [],
6488
6488
  "returns": null,
@@ -6514,7 +6514,7 @@
6514
6514
  "group": "platform",
6515
6515
  "signature": "origin?: { x: number; y: number }",
6516
6516
  "documented": true,
6517
- "summary": "Where the flight starts, in CSS px of YOUR viewport: the centre of the\ncurrency's icon (or hero) your screen draws beside the reward — the gem\nfor Gems, the ticket for Tickets. Measure that element's own box, not a\nrow or panel around it. Leave it out and the Gem Arcade flies the payout\nfrom the middle of your frame once the platform confirms it.",
6517
+ "summary": "Where the flight starts, in CSS px of YOUR viewport: the centre of the\ncurrency's icon (or hero) your screen draws beside the reward — the gem\nfor Gems, the coin for Coins. Measure that element's own box, not a\nrow or panel around it. Leave it out and the Gem Arcade flies the payout\nfrom the middle of your frame once the platform confirms it.",
6518
6518
  "deprecated": null,
6519
6519
  "params": [],
6520
6520
  "returns": null,
@@ -8449,7 +8449,7 @@
8449
8449
  "group": "gameSettings",
8450
8450
  "signature": "readonly icon?: GemGameSettingIcon",
8451
8451
  "documented": true,
8452
- "summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.",
8452
+ "summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.\n\nIn the Gem Arcade the icon also fills its fixed quick row (Music, Sound,\nColor, Vibration): the first **toggle** with `'music'` is the Music slot\nand the first toggle with `'eye'` is the Color slot. Give those two icons\nto your music on/off and colour-help toggles, and to no other setting.",
8453
8453
  "deprecated": null,
8454
8454
  "params": [],
8455
8455
  "returns": null,
@@ -8513,7 +8513,7 @@
8513
8513
  "group": "gameSettings",
8514
8514
  "signature": "readonly icon?: GemGameSettingIcon",
8515
8515
  "documented": true,
8516
- "summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.",
8516
+ "summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.\n\nIn the Gem Arcade the icon also fills its fixed quick row (Music, Sound,\nColor, Vibration): the first **toggle** with `'music'` is the Music slot\nand the first toggle with `'eye'` is the Color slot. Give those two icons\nto your music on/off and colour-help toggles, and to no other setting.",
8517
8517
  "deprecated": null,
8518
8518
  "params": [],
8519
8519
  "returns": null,
@@ -8561,7 +8561,7 @@
8561
8561
  "group": "gameSettings",
8562
8562
  "signature": "readonly quick?: boolean",
8563
8563
  "documented": true,
8564
- "summary": "Ask for this toggle in the menu's quick row, beside the Arcade's own Sound\nand Vibration. The first two toggles that ask get it; a third is shown only\nin the settings list.",
8564
+ "summary": "**Ignored by the Gem Arcade**, whose quick row is fixed — Music, Sound,\nColor, Vibration — and filled by [GemGameSettingBase.icon](api-reference-game.md#gemgamesettingbase-icon)\n(`'music'`, `'eye'`), not by this flag. Kept for other embedders, which\nmay show the first two toggles that ask in a quick row of their own;\nleaving it out is fine.",
8565
8565
  "deprecated": null,
8566
8566
  "params": [],
8567
8567
  "returns": null,
@@ -8625,7 +8625,7 @@
8625
8625
  "group": "gameSettings",
8626
8626
  "signature": "readonly icon?: GemGameSettingIcon",
8627
8627
  "documented": true,
8628
- "summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.",
8628
+ "summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.\n\nIn the Gem Arcade the icon also fills its fixed quick row (Music, Sound,\nColor, Vibration): the first **toggle** with `'music'` is the Music slot\nand the first toggle with `'eye'` is the Color slot. Give those two icons\nto your music on/off and colour-help toggles, and to no other setting.",
8629
8629
  "deprecated": null,
8630
8630
  "params": [],
8631
8631
  "returns": null,
@@ -8817,7 +8817,7 @@
8817
8817
  "group": "gameSettings",
8818
8818
  "signature": "readonly icon?: GemGameSettingIcon",
8819
8819
  "documented": true,
8820
- "summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.",
8820
+ "summary": "One of the Arcade's icon codes; a code this SDK does not know is left out\n(with a warning) and the setting is kept with the generic glyph.\n\nIn the Gem Arcade the icon also fills its fixed quick row (Music, Sound,\nColor, Vibration): the first **toggle** with `'music'` is the Music slot\nand the first toggle with `'eye'` is the Color slot. Give those two icons\nto your music on/off and colour-help toggles, and to no other setting.",
8821
8821
  "deprecated": null,
8822
8822
  "params": [],
8823
8823
  "returns": null,
@@ -8945,7 +8945,7 @@
8945
8945
  "group": "gameSettings",
8946
8946
  "signature": "interface GameSettingsApi",
8947
8947
  "documented": true,
8948
- "summary": "`gem.settings` — mirror up to eight of your game's own settings into the\nArcade's Gem menu. Your own settings button and screen stay: this is a\nsecond door to a few of the same settings, never the only one.",
8948
+ "summary": "`gem.settings` — mirror your game's own settings, up to eight, into the\nArcade's Gem menu. Your own settings button and screen stay: this is a\nsecond door to the same settings, never the only one.",
8949
8949
  "deprecated": null,
8950
8950
  "params": [],
8951
8951
  "returns": null,
@@ -8961,7 +8961,7 @@
8961
8961
  "group": "gameSettings",
8962
8962
  "signature": "declare(settings: readonly GemGameSetting[]): boolean",
8963
8963
  "documented": true,
8964
- "summary": "Show up to eight of your settings in the Arcade's menu, in this order — the\nwhole list each time, the latest call winning. `declare([])` takes them\nall back out.\n\n```js\ngem.settings.declare([\n { id: 'music', label: t('Music'), kind: 'toggle', value: music.on, quick: true, icon: 'music' },\n { id: 'speed', label: t('Game speed'), kind: 'slider', value: speed, min: 0.5, max: 2, step: 0.25 },\n]);\n```\n\n**Keep your own settings button and screen** — top-right, on every screen.\nThis mirrors a few of those settings; it never replaces them, and an\nembedder that draws no game settings shows none of it.\n\n**Declare again whenever your own screen changes a value**, so the menu\nnever shows a stale one. Mark at most two toggles `quick` (good ones:\nMusic, Sound effects, Color help). **Never declare the Arcade's own\nsettings** — master volume or mute, vibration, graphics quality, controls:\nthe Arcade already has them and they reach you as `gem.prefs`.\n\nAn entry that breaks a rule is left out, with a warning through your\n`log`; nothing throws.",
8964
+ "summary": "Show up to eight of your settings in the Arcade's menu, in this order — the\nwhole list each time, the latest call winning. `declare([])` takes them\nall back out.\n\n```js\ngem.settings.declare([\n { id: 'music', label: t('Music'), kind: 'toggle', value: music.on, icon: 'music' },\n { id: 'colors', label: t('Color help'), kind: 'toggle', value: colorHelp, icon: 'eye' },\n { id: 'speed', label: t('Game speed'), kind: 'slider', value: speed, min: 0.5, max: 2, step: 0.25 },\n]);\n```\n\n**Keep your own settings button and screen** — top-right, on every screen.\nThis mirrors those settings; it never replaces them, and an embedder that\ndraws no game settings shows none of it.\n\nThe Gem Arcade's Settings screen lists **every** setting you declare, so\ndeclare all of yours. Its quick row is fixed — Music, Sound, Color and\nVibration (phones and tablets), with the Arcade's own labels: your first\ntoggle with `icon: 'music'` fills Music, your first with `icon: 'eye'`\nfills Color, and a slot you do not fill stays greyed. It ignores `quick`.\n\n**Declare again whenever your own screen changes a value**, so the menu\nnever shows a stale one. **Never declare a second mute or vibration\nswitch** — the quick row has the Arcade's own. Your game's own volume,\nmusic and sound-effects levels are yours to declare; graphics quality and\nthe controls defaults stay the Arcade's and reach you as\n`gem.prefs.recommended`.\n\nAn entry that breaks a rule is left out, with a warning through your\n`log`; nothing throws.",
8965
8965
  "deprecated": null,
8966
8966
  "params": [
8967
8967
  {
@@ -9556,7 +9556,7 @@
9556
9556
  "group": "player",
9557
9557
  "signature": "readonly boost: PlayerBoost",
9558
9558
  "documented": true,
9559
- "summary": "The player's Boost — how much faster they earn Gems and Tickets right now,\nand for how many more days. **For display only.**\n\nAlways present: when the arcade has not said, it reads as not boosted\n(`active: false`, no multipliers).\n\n```js\nconst gems = gem.player?.boost.multipliers.find((m) => m.currencySlug === 'GEMS');\nif (gems && gems.multiplier > 1) rewardScreen.showBadge(`${gems.multiplier}x Gems`);\n```\n\n⚠️ **Show it; never gate on it** — no content, difficulty, matchmaking,\nprice or power may depend on it. It is advisory, may lag, and can be\nforged inside your own page; the platform applies the real multiplier\nwhen it pays. See [PlayerBoost](api-reference-game.md#playerboost).",
9559
+ "summary": "The player's Boost — how much faster they earn Gems and Coins right now,\nand for how many more days. **For display only.**\n\nAlways present: when the arcade has not said, it reads as not boosted\n(`active: false`, no multipliers).\n\n```js\nconst gems = gem.player?.boost.multipliers.find((m) => m.currencySlug === 'GEMS');\nif (gems && gems.multiplier > 1) rewardScreen.showBadge(`${gems.multiplier}x Gems`);\n```\n\n⚠️ **Show it; never gate on it** — no content, difficulty, matchmaking,\nprice or power may depend on it. It is advisory, may lag, and can be\nforged inside your own page; the platform applies the real multiplier\nwhen it pays. See [PlayerBoost](api-reference-game.md#playerboost).",
9560
9560
  "deprecated": null,
9561
9561
  "params": [],
9562
9562
  "returns": null,
@@ -10429,7 +10429,7 @@
10429
10429
  "group": "platform",
10430
10430
  "signature": "readonly only?: readonly string[]",
10431
10431
  "documented": true,
10432
- "summary": "While shown, show ONLY these: platform currency slugs as\n`gem.platform.currencies.get()` lists them (`GEMS`, `ARCADE_TICKETS`),\nmatched exactly, and the literal `'score'` for the achievement score. Only\nfor a screen about one currency, such as a ticket store; leave it out and\nevery wallet shows, which is always safe. The Gem Arcade draws no wallet\nover a game, so it has nothing to narrow and ignores it.",
10432
+ "summary": "While shown, show ONLY these: platform currency slugs as\n`gem.platform.currencies.get()` lists them (`GEMS`, `ARCADE_TICKETS`),\nmatched exactly, and the literal `'score'` for the achievement score. Only\nfor a screen about one currency, such as a Coins store; leave it out and\nevery wallet shows, which is always safe. The Gem Arcade draws no wallet\nover a game, so it has nothing to narrow and ignores it.",
10433
10433
  "deprecated": null,
10434
10434
  "params": [],
10435
10435
  "returns": null,
@@ -11055,7 +11055,7 @@
11055
11055
  "group": "start",
11056
11056
  "signature": "readonly settings: GameSettingsApi",
11057
11057
  "documented": true,
11058
- "summary": "Mirror up to eight of your game's own settings — Music, Color help, Game\nspeed — into the Arcade's Gem menu, and hear when the player changes one\nthere. Up to two toggles can sit in the menu's quick row.\n\n```js\ngem.settings.declare([\n { id: 'music', label: t('Music'), kind: 'toggle', value: music.on, quick: true, icon: 'music' },\n]);\ngem.settings.onChange(({ id, value }) => {\n if (id === 'music') setMusic(value === true); // even while paused\n});\n```\n\n**A mirror, never a replacement: your game still draws its own settings\nbutton and screen**, and every setting you declare is on that screen too.\nDeclare again whenever your screen changes a value. Never declare the\nArcade's own settings — master volume or mute, vibration, graphics,\ncontrols; they reach you as `gem.prefs`.\n\nSee the guide's \"Game settings\" section.",
11058
+ "summary": "Mirror your game's own settings, up to eight — Music, Color help, Game\nspeed — into the Arcade's Gem menu, and hear when the player changes one\nthere. The Arcade's Settings screen lists every one; its fixed quick row\ntakes your first toggle with `icon: 'music'` as Music and your first with\n`icon: 'eye'` as Color (`quick` is ignored by the Gem Arcade).\n\n```js\ngem.settings.declare([\n { id: 'music', label: t('Music'), kind: 'toggle', value: music.on, icon: 'music' },\n]);\ngem.settings.onChange(({ id, value }) => {\n if (id === 'music') setMusic(value === true); // even while paused\n});\n```\n\n**A mirror, never a replacement: your game still draws its own settings\nbutton and screen**, and every setting you declare is on that screen too.\nDeclare again whenever your screen changes a value. Never declare a\nsecond mute or vibration switch — the Arcade's quick row has them; your\nown volume and music or sound-effects levels are fine, and graphics and\ncontrols defaults stay the Arcade's (`gem.prefs.recommended`).\n\nSee the guide's \"Game settings\" section.",
11059
11059
  "deprecated": null,
11060
11060
  "params": [],
11061
11061
  "returns": null,
@@ -11161,7 +11161,7 @@
11161
11161
  "group": "start",
11162
11162
  "signature": "readonly platform: PlatformApi",
11163
11163
  "documented": true,
11164
- "summary": "The player's standing in PLATFORM currencies (Gems, Tickets): their\nbalances, `gem.platform.currencies.get()`, and how much more this game can\ngrant them, `gem.platform.earnAllowance.get()` (display only).\n\nA player surface only. In a context with no player — a game server — the\nplatform refuses the read.",
11164
+ "summary": "The player's standing in PLATFORM currencies (Gems, Coins): their\nbalances, `gem.platform.currencies.get()`, and how much more this game can\ngrant them, `gem.platform.earnAllowance.get()` (display only).\n\nA player surface only. In a context with no player — a game server — the\nplatform refuses the read.",
11165
11165
  "deprecated": null,
11166
11166
  "params": [],
11167
11167
  "returns": null,
@@ -11365,7 +11365,7 @@
11365
11365
  "group": "start",
11366
11366
  "signature": "cueReward(cue: RewardCue): boolean",
11367
11367
  "documented": true,
11368
- "summary": "Tell the arcade a platform-currency reward is on its way, so it **shows it\nlanding**: in the Gem Arcade the currency flies from `origin` into the Gem\nbutton, wherever on your frame it sits, which pops as each mark lands, and\nthe player's total moves once the platform confirms the grant. The Gem\nArcade draws no wallet over your game: the player sees their Gems and\nTickets in the Gem menu. A payout you do not cue still flies, from the\nmiddle of your frame, so cue the ones the player earns on screen.\n\nCall it the moment your game decides to award — when your server has moved\n(or is about to move) the progression mapped onto a platform currency —\nand pass the centre of that currency's icon (or hero) on your screen, so\nthe flight starts from the mark the player is looking at:\n\n```js\nconst { x, y, width, height } = rewardGem.getBoundingClientRect(); // the gem's own box\ngem.cueReward({\n currencySlug: 'GEMS', // or 'ARCADE_TICKETS', from the ticket\n expected: 15,\n origin: { x: x + width / 2, y: y + height / 2 },\n});\n```\n\n**This is the platform-currency animation, and the only one.** The display\nof every platform currency — Gems and Tickets alike — belongs to the\narcade: a game draws no flight or celebration of its own for one and keeps\nno counter of one. **If this returns `false`, do nothing** — there is no\nfallback celebration.\n\n**The arcade never takes your word for the amount.** What lands, and the\nplayer's new total, come from the platform itself; `expected` is drawn as\nprovisional, and a cue the platform never confirms fades on its own — a\ngrant clamped to zero, say, or one the receipt reports `suppressed`. So\nthe cue can only ever make the wallet move for a reward that really\nlanded — which it does on every channel, dev and test included.",
11368
+ "summary": "Tell the arcade a platform-currency reward is on its way, so it **shows it\nlanding**: in the Gem Arcade the currency flies from `origin` into the Gem\nbutton, wherever on your frame it sits, which pops as each mark lands, and\nthe player's total moves once the platform confirms the grant. The Gem\nArcade draws no wallet over your game: the player sees their Gems and\nCoins in the Gem menu. A payout you do not cue still flies, from the\nmiddle of your frame, so cue the ones the player earns on screen.\n\nCall it the moment your game decides to award — when your server has moved\n(or is about to move) the progression mapped onto a platform currency —\nand pass the centre of that currency's icon (or hero) on your screen, so\nthe flight starts from the mark the player is looking at:\n\n```js\nconst { x, y, width, height } = rewardGem.getBoundingClientRect(); // the gem's own box\ngem.cueReward({\n currencySlug: 'GEMS', // or 'ARCADE_TICKETS', from the coin\n expected: 15,\n origin: { x: x + width / 2, y: y + height / 2 },\n});\n```\n\n**This is the platform-currency animation, and the only one.** The display\nof every platform currency — Gems and Coins alike — belongs to the\narcade: a game draws no flight or celebration of its own for one and keeps\nno counter of one. **If this returns `false`, do nothing** — there is no\nfallback celebration.\n\n**The arcade never takes your word for the amount.** What lands, and the\nplayer's new total, come from the platform itself; `expected` is drawn as\nprovisional, and a cue the platform never confirms fades on its own — a\ngrant clamped to zero, say, or one the receipt reports `suppressed`. So\nthe cue can only ever make the wallet move for a reward that really\nlanded — which it does on every channel, dev and test included.",
11369
11369
  "deprecated": null,
11370
11370
  "params": [
11371
11371
  {
@@ -11388,7 +11388,7 @@
11388
11388
  "group": "start",
11389
11389
  "signature": "setWalletVisible(visible: boolean, options?: WalletVisibleOptions): boolean",
11390
11390
  "documented": true,
11391
- "summary": "Show or hide the player's wallets — Gems, Tickets, the achievement score —\nthat an embedder draws over your game.\n\n**The Gem Arcade draws no wallet over a game** (since 2026-10-11): the\nplayer sees their balances in the Gem menu, and payouts fly into the Gem\nbutton. So under the Gem Arcade this changes nothing on screen — it is\naccepted and harmless, and a game that already calls it keeps working.\nCall it for an embedder that does draw wallets over your game: hide them\nwhile you play, show them on your menus.\n\n```js\nlevel.onStart = () => gem.setWalletVisible(false);\nmenu.onOpen = () => gem.setWalletVisible(true);\n```\n\n**It is screen state, not a toggle.** Each call is the whole answer and\nreplaces the last. Where an embedder draws wallets, shown ones arrive as\nrectangles in `gem.viewport.reserved` and hiding them gives that space\nback; the Gem Arcade sends none for wallets. `only` narrows what shows,\nwhere an embedder honours it; the Gem Arcade does not.\n\n**Never draw a platform balance yourself**, and never show a pending state\nfor one: the arcade takes every figure from the platform. If this returns\n`false`, do nothing in its place.",
11391
+ "summary": "Show or hide the player's wallets — Gems, Coins, the achievement score —\nthat an embedder draws over your game.\n\n**The Gem Arcade draws no wallet over a game** (since 2026-10-11): the\nplayer sees their balances in the Gem menu, and payouts fly into the Gem\nbutton. So under the Gem Arcade this changes nothing on screen — it is\naccepted and harmless, and a game that already calls it keeps working.\nCall it for an embedder that does draw wallets over your game: hide them\nwhile you play, show them on your menus.\n\n```js\nlevel.onStart = () => gem.setWalletVisible(false);\nmenu.onOpen = () => gem.setWalletVisible(true);\n```\n\n**It is screen state, not a toggle.** Each call is the whole answer and\nreplaces the last. Where an embedder draws wallets, shown ones arrive as\nrectangles in `gem.viewport.reserved` and hiding them gives that space\nback; the Gem Arcade sends none for wallets. `only` narrows what shows,\nwhere an embedder honours it; the Gem Arcade does not.\n\n**Never draw a platform balance yourself**, and never show a pending state\nfor one: the arcade takes every figure from the platform. If this returns\n`false`, do nothing in its place.",
11392
11392
  "deprecated": null,
11393
11393
  "params": [
11394
11394
  {
@@ -13795,7 +13795,7 @@
13795
13795
  "group": "platform",
13796
13796
  "signature": "readonly balance: number",
13797
13797
  "documented": true,
13798
- "summary": "The player's exact balance, as of this read.\n\nA snapshot: the player can earn or spend this currency elsewhere at any\nmoment, so it is a figure to compare a price against, never a promise that\na purchase will go through. The platform re-checks at spend time.\n\n**Do not draw it as a counter.** Platform-currency display belongs to the\narcade: its wallet is the one place a player's Gems or Tickets total is\nshown, and a game keeps no balance of either on screen.",
13798
+ "summary": "The player's exact balance, as of this read.\n\nA snapshot: the player can earn or spend this currency elsewhere at any\nmoment, so it is a figure to compare a price against, never a promise that\na purchase will go through. The platform re-checks at spend time.\n\n**Do not draw it as a counter.** Platform-currency display belongs to the\narcade: its wallet is the one place a player's Gems or Coins total is\nshown, and a game keeps no balance of either on screen.",
13799
13799
  "deprecated": null,
13800
13800
  "params": [],
13801
13801
  "returns": null,
@@ -13875,7 +13875,7 @@
13875
13875
  "group": "platform",
13876
13876
  "signature": "get(options?: PlatformCurrencyReadOptions): Promise<readonly PlatformCurrency[]>",
13877
13877
  "documented": true,
13878
- "summary": "Read the player's balance of every active platform currency.\n\n```js\nconst gems = (await gem.platform.currencies.get()).find((c) => c.slug === 'GEMS');\nbuyButton.disabled = !gems || gems.balance < price;\n```\n\nUse it to decide whether the player can afford a price. Do not show it as\na Gems or Tickets total: the arcade's wallet already does, and is the only\nplace one is shown.\n\nIt is a snapshot, and a balance can change while your game is paused. If\nyou keep anything worked out from it — a greyed-out Buy button — read it\nagain on every `onPause(false)`; nothing tells your game that it changed.",
13878
+ "summary": "Read the player's balance of every active platform currency.\n\n```js\nconst gems = (await gem.platform.currencies.get()).find((c) => c.slug === 'GEMS');\nbuyButton.disabled = !gems || gems.balance < price;\n```\n\nUse it to decide whether the player can afford a price. Do not show it as\na Gems or Coins total: the arcade's wallet already does, and is the only\nplace one is shown.\n\nIt is a snapshot, and a balance can change while your game is paused. If\nyou keep anything worked out from it — a greyed-out Buy button — read it\nagain on every `onPause(false)`; nothing tells your game that it changed.",
13879
13879
  "deprecated": null,
13880
13880
  "params": [
13881
13881
  {
@@ -35056,7 +35056,7 @@
35056
35056
  "group": "platform",
35057
35057
  "signature": "readonly balance: number",
35058
35058
  "documented": true,
35059
- "summary": "The player's exact balance, as of this read.\n\nA snapshot: the player can earn or spend this currency elsewhere at any\nmoment, so it is a figure to compare a price against, never a promise that\na purchase will go through. The platform re-checks at spend time.\n\n**Do not draw it as a counter.** Platform-currency display belongs to the\narcade: its wallet is the one place a player's Gems or Tickets total is\nshown, and a game keeps no balance of either on screen.",
35059
+ "summary": "The player's exact balance, as of this read.\n\nA snapshot: the player can earn or spend this currency elsewhere at any\nmoment, so it is a figure to compare a price against, never a promise that\na purchase will go through. The platform re-checks at spend time.\n\n**Do not draw it as a counter.** Platform-currency display belongs to the\narcade: its wallet is the one place a player's Gems or Coins total is\nshown, and a game keeps no balance of either on screen.",
35060
35060
  "deprecated": null,
35061
35061
  "params": [],
35062
35062
  "returns": null,
@@ -35136,7 +35136,7 @@
35136
35136
  "group": "platform",
35137
35137
  "signature": "get(options?: PlatformCurrencyReadOptions): Promise<readonly PlatformCurrency[]>",
35138
35138
  "documented": true,
35139
- "summary": "Read the player's balance of every active platform currency.\n\n```js\nconst gems = (await gem.platform.currencies.get()).find((c) => c.slug === 'GEMS');\nbuyButton.disabled = !gems || gems.balance < price;\n```\n\nUse it to decide whether the player can afford a price. Do not show it as\na Gems or Tickets total: the arcade's wallet already does, and is the only\nplace one is shown.\n\nIt is a snapshot, and a balance can change while your game is paused. If\nyou keep anything worked out from it — a greyed-out Buy button — read it\nagain on every `onPause(false)`; nothing tells your game that it changed.",
35139
+ "summary": "Read the player's balance of every active platform currency.\n\n```js\nconst gems = (await gem.platform.currencies.get()).find((c) => c.slug === 'GEMS');\nbuyButton.disabled = !gems || gems.balance < price;\n```\n\nUse it to decide whether the player can afford a price. Do not show it as\na Gems or Coins total: the arcade's wallet already does, and is the only\nplace one is shown.\n\nIt is a snapshot, and a balance can change while your game is paused. If\nyou keep anything worked out from it — a greyed-out Buy button — read it\nagain on every `onPause(false)`; nothing tells your game that it changed.",
35140
35140
  "deprecated": null,
35141
35141
  "params": [
35142
35142
  {
@@ -274,7 +274,7 @@ renders the item, and the command waits until it is `ready`.
274
274
 
275
275
  ## 5. Sell it
276
276
 
277
- An avatar is for sale only when you put it on sale, priced in Tickets, Gems or both:
277
+ An avatar is for sale only when you put it on sale, priced in Coins, Gems or both:
278
278
 
279
279
  ```sh
280
280
  gemctl item sell red-knight --tickets 50 --gems 300
@@ -329,7 +329,7 @@ const offers = await gem.avatars3d.offers(); // what is on sale, priced by the p
329
329
  for (const offer of offers) {
330
330
  const tile = shop.addTile(offer.displayName, platformIconUrl(offer.iconUrl));
331
331
  for (const { currencySlug, price } of offer.prices) {
332
- tile.addButton(`${price} ${currencySlug === 'GEMS' ? 'Gems' : 'Tickets'}`, async () => {
332
+ tile.addButton(`${price} ${currencySlug === 'GEMS' ? 'Gems' : 'Coins'}`, async () => {
333
333
  const result = await gem.avatars3d.purchase({ itemId: offer.itemId, currencySlug });
334
334
  if (result.outcome === 'declined' && result.reason === 'already_owned') {
335
335
  gem.openAvatarPicker({ tab: '3d' }); // they have it: let them put it on
@@ -370,7 +370,7 @@ up, or under an Arcade that does not sell 3D avatars, it resolves `unavailable`
370
370
  platform with your game's token, so a shop can show what is on sale.
371
371
 
372
372
  **Purchases are real on every channel.** On `dev` and `test` a purchase spends the player's real
373
- Gems or Tickets and grants a real avatar they keep, exactly as on `release`. Test with your
373
+ Gems or Coins and grants a real avatar they keep, exactly as on `release`. Test with your
374
374
  organization's test accounts.
375
375
 
376
376
  ## 7. Read the worn avatar, and load it at runtime
@@ -1,9 +1,9 @@
1
- # Gems, Tickets and Achievement Points
1
+ # Gems, Coins and Achievement Points
2
2
 
3
3
  The arcade runs three things across every game, and a player should be able to tell them apart at
4
4
  a glance:
5
5
 
6
- > **Gems = progress. Tickets = cosmetics. Achievement Points = prestige.**
6
+ > **Gems = progress. Coins = cosmetics. Achievement Points = prestige.**
7
7
 
8
8
  You do not have to use any of them. A game with no platform currency and no achievements is a
9
9
  complete game, and the currencies your core loop runs on — gold, XP, energy, materials, cards — are
@@ -14,7 +14,7 @@ most of them are enforced at upload, so a design that ignores them is refused ra
14
14
 
15
15
  ## 1. The three, side by side
16
16
 
17
- | | **Gems** (`GEMS`) | **Tickets** (`ARCADE_TICKETS`) | **Achievement Points** |
17
+ | | **Gems** (`GEMS`) | **Coins** (`ARCADE_TICKETS`) | **Achievement Points** |
18
18
  | ------------------ | ------------------------------------------------------ | ----------------------------------------------- | --------------------------------------------------------- |
19
19
  | What it is | the arcade's progression currency | the arcade's cosmetics currency | permanent prestige: the **Achievement Score** |
20
20
  | Which games pay it | any game with a server or a serverless function | any game with a server or a serverless function | an achievement, from any game with a server or a function |
@@ -23,7 +23,7 @@ most of them are enforced at upload, so a design that ignores them is refused ra
23
23
  | A Boost raises it | yes — the grants and the caps | yes — the grants and the caps | never |
24
24
 
25
25
  A player earns Gems across the arcade's games and spends them on progress anywhere: upgrades, unlocks,
26
- extra attempts, resources, characters, cards. A player earns Tickets by playing almost anything and
26
+ extra attempts, resources, characters, cards. A player earns Arcade Coins by playing almost anything and
27
27
  spends them on how they look: skins, outfits, visual effects, decorations, emotes, profile
28
28
  cosmetics. Achievement points are what a player has done, summed across every game into the
29
29
  Achievement Score; they are never bought, boosted or spent, and nothing takes them away except the
@@ -41,15 +41,15 @@ platform-wide currency of your own:
41
41
  | If your design has… | Use |
42
42
  | ----------------------------------------------------------------------------------------- | --------------------------------------------------------- |
43
43
  | a premium or meta currency that speeds up or unlocks progress | **Gems**: price that progress in `GEMS` |
44
- | a cosmetics currency, or a shop of skins | **Tickets**: price the cosmetics in `ARCADE_TICKETS` |
44
+ | a cosmetics currency, or a shop of skins | **Coins**: price the cosmetics in `ARCADE_TICKETS` |
45
45
  | a trophy count, a mastery rank or a completion percentage that says "this player is good" | **achievements**, whose points join the Achievement Score |
46
46
 
47
- ⚠️ **Do not build a second Gems or a second Tickets.** A game-local premium or cosmetic
47
+ ⚠️ **Do not build a second Gems or a second Coins.** A game-local premium or cosmetic
48
48
  meta-currency — "Crystals" that buy your upgrades, "Shards" that buy your skins, earned and hoarded
49
49
  the way a player would earn and hoard the arcade's — competes with the arcade's own, splits the
50
50
  player between two wallets that mean the same thing, and sidesteps every rule on this page: the Gem
51
51
  Source approval, the cosmetics-only line and the platform's caps. The release review checks for one.
52
- A currency that is part of play is fine: coins picked up in a level and spent in that run's shop,
52
+ A currency that is part of play is fine: gold picked up in a level and spent in that run's shop,
53
53
  energy that paces a session, materials a crafting tree consumes.
54
54
 
55
55
  ## 3. Which kind of game is yours
@@ -64,7 +64,7 @@ There are four shapes:
64
64
  | **No-Gem** | no | no | a game that stays out of Gems entirely |
65
65
 
66
66
  The shapes describe what a game does, not what it may do: a Gem Source that starts pricing its own
67
- progress in Gems is Balanced. Every shape may pay Tickets, price its cosmetics in Tickets and carry
67
+ progress in Gems is Balanced. Every shape may pay Coins, price its cosmetics in Coins and carry
68
68
  achievements. **Gems can be your game's soft currency** — award them for play and price your
69
69
  progression in them.
70
70
 
@@ -85,7 +85,7 @@ What may move it:
85
85
  - **Your game server** — a platform-allocated dedicated server, through the progression add and max
86
86
  routes.
87
87
  - **Your serverless function**, called by the player it pays, on a progression that sets
88
- `function_may_grant: true`. It may pay Gems and Tickets and unlock achievements for **that player
88
+ `function_may_grant: true`. It may pay Gems and Coins and unlock achievements for **that player
89
89
  only**, and never for a guest. A function a player calls may also change only that player's own
90
90
  state — any write it aims at another player is refused. Opting in makes the function's own checks
91
91
  the only thing deciding a reward was earned, so read
@@ -97,7 +97,7 @@ So a browser-only game with neither a server nor a function pays nothing platfor
97
97
  rule read strictly, not a gap: a browser credential is public, and anything it could pay, a modified
98
98
  client could pay itself.
99
99
 
100
- **How much to pay: about 500 Tickets an hour.** A game pays about **500 Tickets per hour of ordinary
100
+ **How much to pay: about 500 Coins an hour.** A game pays about **500 Coins per hour of ordinary
101
101
  play**, unboosted, averaged over a typical session of its repeatable loop — runs, levels, matches,
102
102
  to-dos. A one-time prize, such as finishing the tutorial or a first-time milestone, comes on top and
103
103
  stays modest. Work the rate out from what each firing pays and how often a player fires it, and keep
@@ -122,29 +122,29 @@ currency may price is a platform setting on that currency, its **spend scope**:
122
122
 
123
123
  - **Gems — `any`.** Price progress in `GEMS`: an extra life, an upgrade, a character, a pack of
124
124
  cards, another attempt.
125
- - **Tickets — `cosmetic_only`.** A Tickets price is accepted only on an item your config declares
126
- `category: cosmetic`, or on a recipe that grants cosmetic items and nothing else. A Tickets price
125
+ - **Coins — `cosmetic_only`.** A Coins price is accepted only on an item your config declares
126
+ `category: cosmetic`, or on a recipe that grants cosmetic items and nothing else. A Coins price
127
127
  on anything that grants a currency, moves a progression, grants a non-cosmetic item, opens into
128
128
  other items (a bundle or a loot box) or rolls a loot table is refused at upload — a loot table
129
129
  even when every entry in it is cosmetic.
130
130
 
131
- So a Tickets price on an item is always the pair `currency: ARCADE_TICKETS` and
131
+ So a Coins price on an item is always the pair `currency: ARCADE_TICKETS` and
132
132
  `category: cosmetic`; on a recipe, every item it grants declares `category: cosmetic`.
133
133
 
134
- **How much to charge: 500 Tickets is worth about $1.** Price a Tickets cosmetic at what it would be
135
- worth in dollars, times 500: a $1 emote is 500 Tickets, a $3 outfit 1,500, a $10 skin 5,000. At the
134
+ **How much to charge: 500 Coins is worth about $1.** Price a Coins cosmetic at what it would be
135
+ worth in dollars, times 500: a $1 emote is 500 Coins, a $3 outfit 1,500, a $10 skin 5,000. At the
136
136
  earn rate in [§4](#4-earning-needs-server-authority), that is about an hour of play for each dollar.
137
- Tickets are never sold for money, so the dollar is your yardstick only: never show a dollar figure
138
- beside a Tickets price. The release review lists every Tickets price with its dollar value and hours
139
- of play, and a price under 100 or over 10,000 Tickets blocks release unless the creator has approved
137
+ Coins are never sold for money, so the dollar is your yardstick only: never show a dollar figure
138
+ beside a Coins price. The release review lists every Coins price with its dollar value and hours
139
+ of play, and a price under 100 or over 10,000 Coins blocks release unless the creator has approved
140
140
  it for that game.
141
141
 
142
142
  **`category` defaults to `progression`**, so an item is a cosmetic only because you said so. The
143
143
  platform takes that at your word and the release review checks it: an item that changes what a
144
- player can do, labelled `cosmetic` so it can sell for Tickets, breaks platform policy.
144
+ player can do, labelled `cosmetic` so it can sell for Coins, breaks platform policy.
145
145
 
146
146
  **A cosmetic can still wait for progress.** "Reach level 10 to unlock the dragon skin" is a recipe
147
- with a prerequisite and a Tickets price, and the platform refuses a locked player with
147
+ with a prerequisite and a Coins price, and the platform refuses a locked player with
148
148
  `recipe_locked` before it takes anything ([game-economy-tutorial.md](game-economy-tutorial.md)).
149
149
 
150
150
  **Take the scope from the refusal, not from this page.** The platform owns each currency's scope and
@@ -152,10 +152,10 @@ can change it. A refusal names the scope that applied, and `gemctl platform conf
152
152
  currencies your game may price in at all. A scope changed after you published stops the prices it
153
153
  no longer admits: the purchase is refused and the price leaves the catalog, with nothing charged.
154
154
 
155
- **The arcade sells cosmetics of its own for Tickets, and never sells prestige.** Besides your game's
156
- shop, the arcade has a Tickets shop of its own profile cosmetics. Every arcade item is either a
157
- **shop** item — a cosmetic priced in Tickets — or **earned**: a default, a free claim, an achievement
158
- or Achievement Score reward. An earned item can never be given a price, in Tickets, Gems or anything
155
+ **The arcade sells cosmetics of its own for Coins, and never sells prestige.** Besides your game's
156
+ shop, the arcade has a Coins shop of its own profile cosmetics. Every arcade item is either a
157
+ **shop** item — a cosmetic priced in Coins — or **earned**: a default, a free claim, an achievement
158
+ or Achievement Score reward. An earned item can never be given a price, in Coins, Gems or anything
159
159
  else, so what a player shows off for what they did cannot be bought.
160
160
 
161
161
  ## 6. Every number is the platform's, and it moves
@@ -195,14 +195,14 @@ player got.
195
195
 
196
196
  ## 7. What a player buys with money: Gems and Boosts
197
197
 
198
- Nothing sells Tickets or achievement points, alone or in a bundle. The arcade's own store sells
198
+ Nothing sells Coins or achievement points, alone or in a bundle. The arcade's own store sells
199
199
  Gems, and the Gems a player bought there spend in your game exactly as the ones they earned do: your
200
200
  game cannot tell the two apart and prices nothing differently for either. Your game sells neither,
201
201
  and never sends a player to the store. The real-money
202
202
  product that changes what your game pays is a **Boost**, which a player buys from the arcade, never
203
203
  from your game:
204
204
 
205
- - **It multiplies what Gems and Tickets grants pay, and the ceilings with them.** A player on a 2×
205
+ - **It multiplies what Gems and Coins grants pay, and the ceilings with them.** A player on a 2×
206
206
  Boost earns twice as much per grant, may earn twice as much per window and per day, and may hold
207
207
  more. When it ends, what they earned stays theirs.
208
208
  - **It never touches achievement points.** An unlock credits the same points for every player.
@@ -211,7 +211,7 @@ from your game:
211
211
  - **None is on sale yet.** The first Boost, `booster_x2_30d`, is inactive until the arcade launches
212
212
  it, so today every player earns at the unboosted rate. Design for both.
213
213
 
214
- ⚠️ **Show a Boost; never gate on one.** Your game may tell a player they are boosted — "2× Tickets"
214
+ ⚠️ **Show a Boost; never gate on one.** Your game may tell a player they are boosted — "2× Coins"
215
215
  beside a reward, from `gem.player.boost`
216
216
  ([what-a-game-must-do.md](what-a-game-must-do.md#the-signed-in-players-boost-show-it-never-gate-on-it))
217
217
  — and must never make content, difficulty, power, access, prices, matchmaking or odds depend on
@@ -222,7 +222,7 @@ rule is [platform-rules.md](platform-rules.md#8-a-players-boost-is-for-display-n
222
222
  ## 8. The arcade owns the display of every platform currency
223
223
 
224
224
  The arcade draws the player's platform currencies in its own chrome while your game runs, and
225
- animates every payout into the right total. Gems and Tickets follow the same rules:
225
+ animates every payout into the right total. Gems and Coins follow the same rules:
226
226
 
227
227
  - **No counter.** Keep no balance, running total or wallet of a platform currency on any screen of
228
228
  yours. Read `gem.platform.currencies.get()` to decide whether a price is affordable, never to draw
@@ -230,17 +230,17 @@ animates every payout into the right total. Gems and Tickets follow the same rul
230
230
  `onPause(false)` if you keep anything worked out from it, such as a greyed-out Buy button.
231
231
  - **No celebration of your own.** At a payout, cue the arcade's wallet with `gem.cueReward`, naming
232
232
  the currency that paid — `currencySlug: 'GEMS'` from the gem on your reward screen,
233
- `'ARCADE_TICKETS'` from the ticket. If it returns `false`, do nothing
233
+ `'ARCADE_TICKETS'` from the coin. If it returns `false`, do nothing
234
234
  ([inventory-and-catalogs.md](inventory-and-catalogs.md#showing-the-reward-land-in-the-arcades-wallet)).
235
235
  - **No "daily max" of your own making.** Your game cannot see what every other game paid the player,
236
236
  and must not compute a maximum. To show how much more your game can pay, read
237
237
  `gem.platform.earnAllowance.get()` (one consolidated figure, display only); the arcade still tells
238
238
  the player when they reach the maximum.
239
- - **No top-up or payment screen of your own.** Never draw a "get more Gems" or "buy Tickets" offer,
239
+ - **No top-up or payment screen of your own.** Never draw a "get more Gems" or "buy Coins" offer,
240
240
  a checkout, a wallet top-up, or anything shaped like the arcade's purchase sheet: a game screen
241
241
  that looks like platform payment chrome is an imitation of it, and players cannot tell the two
242
242
  apart. Your shop's own Buy button is yours. When a purchase is refused for
243
- `insufficient_funds`, say so in your shop's own words ("Not enough Tickets") and stop there.
243
+ `insufficient_funds`, say so in your shop's own words ("Not enough Coins") and stop there.
244
244
  - **No amount at all when you are not connected to the arcade.** Hide every platform price and
245
245
  reward unless `gem.awaitBridge()` settled `connected`.
246
246
  - **Draw a currency with the art the SDK ships**: the icon beside an amount, the hero only on a
@@ -251,11 +251,12 @@ never computes the score, restates it, or turns it into a currency of its own.
251
251
 
252
252
  ## 9. What the arcade does not have
253
253
 
254
- - **No Stars, Coins, Tokens or Supporter Seals.** All four are retired. None of them can be
254
+ - **No Stars, Tokens or Supporter Seals, and not the old `COINS` currency** (retired; not today's
255
+ Coins, `ARCADE_TICKETS`). All four are retired. None of them can be
255
256
  granted, priced in or bought: a config naming one is refused at upload, and a mapping onto one
256
257
  that is still live reads `suppressed`. The Achievement Score is the arcade's measure of prestige.
257
- - **No Gems or Tickets for money from a game**, alone or in a bundle. Only the arcade's own store
258
- sells Gems, and nothing sells Tickets.
258
+ - **No Gems or Coins for money from a game**, alone or in a bundle. Only the arcade's own store
259
+ sells Gems, and nothing sells Coins.
259
260
  - **No achievement points or earned items for anything a player pays for.**
260
261
  - **No content behind a Boost.** A Boost is shown, never checked.
261
262
 
@@ -265,7 +266,7 @@ never computes the score, restates it, or turns it into a currency of its own.
265
266
  | ---------------------------------------------------------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
266
267
  | a mapping refused, naming the currencies your game may pay | the platform does not let your game grant that currency | target one it lists — `gemctl platform config` has the current set |
267
268
  | a receipt `suppressed`, reason `not_allowlisted…` | the platform stopped letting your game grant that currency | target a currency `gemctl platform config` lists; paid balances stay |
268
- | a price refused, naming the spend scope `cosmetic_only` | a Tickets price on something that is not a cosmetic | price it in `GEMS`, or mark the item `category: cosmetic` if it changes only looks |
269
+ | a price refused, naming the spend scope `cosmetic_only` | a Coins price on something that is not a cosmetic | price it in `GEMS`, or mark the item `category: cosmetic` if it changes only looks |
269
270
  | a receipt `suppressed`, reason `functions_not_opted_in` | your function wrote a paying progression that has not opted in | read [serverless-functions.md](serverless-functions.md), then set `function_may_grant: true` |
270
271
  | a receipt `suppressed`, reason `function_gems_not_enabled` | an older receipt, from before functions could pay Gems | nothing — a function pays Gems now, so its next firing pays |
271
272
  | `403 function_foreign_entity_write` | a function a player called wrote another player | take the player from the call's context, never its input |
@@ -277,7 +278,7 @@ never computes the score, restates it, or turns it into a currency of its own.
277
278
  - [`inventory-and-catalogs.md`](inventory-and-catalogs.md) — platform grants (§13) and selling for a
278
279
  platform currency (§16), in full.
279
280
  - [`game-economy-tutorial.md`](game-economy-tutorial.md) — a shop, step by step, including a
280
- cosmetic sold for Tickets.
281
+ cosmetic sold for Coins.
281
282
  - [`daily-challenges.md`](daily-challenges.md) — the commonest thing that pays a platform currency.
282
283
  - [`achievements.md`](achievements.md) — achievements, their points and the Achievement Score.
283
284
  - [`serverless-functions.md`](serverless-functions.md) — paying a player from a game with no
package/docs/brand-art.md CHANGED
@@ -1,20 +1,21 @@
1
- # The Gems, Tickets and trophy art
1
+ # The Gems, Coins and trophy art
2
2
 
3
- The SDK ships the platform's own art for its two currencies, **Gems** and **Tickets**, and for
4
- **trophies**. You need it only if your game draws Gems, Tickets or a trophy on its own screens. Read
3
+ The SDK ships the platform's own art for its two currencies, **Gems** and **Coins**, and for
4
+ **trophies**. You need it only if your game draws Gems, Coins or a trophy on its own screens. Read
5
5
  §1 before you pick a file: each currency has two kinds of art, and which one you use depends on what
6
6
  the screen is for.
7
7
 
8
- **Currency display belongs to the arcade.** The arcade draws the player's Gems and Tickets totals in
8
+ **Currency display belongs to the arcade.** The arcade draws the player's Gems and Coins totals in
9
9
  its own chrome while your game runs, and it animates every payout of either into its total. Your game
10
- draws Gems or Tickets only in the three places §5 allows — an amount on offer or just paid, a reward
10
+ draws Gems or Coins only in the three places §5 allows — an amount on offer or just paid, a reward
11
11
  screen, and how much more your game can still pay (the earn allowance) — and never a balance of its
12
12
  own. §5 is the creator's ruling and is not optional.
13
13
 
14
- > **The Tickets art is generated art, open to a designer pass.** It was generated on 2026-09-28
15
- > (gemforge asset `e540c7ac-850c-4ef0-9b9c-f11227098ce6`): a solid tangerine ticket with a vertical
16
- > gradient, so it never reads as the rainbow gem or the gold trophy. It replaced the first art of
17
- > 2026-09-27, a ticket cut from the gem's rainbow glass. If a designer redraws it, the new art
14
+ > **The Coins art is a 3D render, open to a designer pass.** Since the currency was renamed from
15
+ > Tickets to Coins (2026-10-21) it is a solid tangerine coin — a raised rim, a cream ring and an
16
+ > embossed gem-cut, with one vertical gradient — so it never reads as the rainbow gem or the gold
17
+ > trophy. It replaced the tangerine ticket of 2026-09-28. The files keep their `ticket-*` names, as
18
+ > the currency keeps its slug `ARCADE_TICKETS`. If a designer redraws it, the new art
18
19
  > replaces these files **under the same names** in a later SDK release, so a game that imports them
19
20
  > picks it up on its next SDK update. Lay your screens out from the sizes on this page, not from the
20
21
  > drawing.
@@ -25,8 +26,8 @@ own. §5 is the creator's ruling and is not optional.
25
26
  | --------------- | --- | -------- |
26
27
  | Gems **inline**, beside a number: a price, a "+15" reward label, a small chip | the **icon**, `gem-icon-20-*` or `gem-icon-32-*` | 16–40 CSS px |
27
28
  | Gems as **the subject of a reward presentation**: a victory or reward screen where the gem is what the player looks at, such as a victory overlay with a sunburst behind the reward | the **hero**, `gem-hero-*` | 64–256 CSS px |
28
- | Tickets **inline**, beside a number | the **icon**, `ticket-icon-20-*` or `ticket-icon-32-*` | 16–40 CSS px |
29
- | Tickets as **the subject of a reward presentation** | the **hero**, `ticket-hero-*` | 64–256 CSS px |
29
+ | Coins **inline**, beside a number | the **icon**, `ticket-icon-20-*` or `ticket-icon-32-*` | 16–40 CSS px |
30
+ | Coins as **the subject of a reward presentation** | the **hero**, `ticket-hero-*` | 64–256 CSS px |
30
31
 
31
32
  The role decides first and the size follows from it. A price tag is inline even if you make it
32
33
  large; a reward screen is a presentation even on a small phone.
@@ -40,8 +41,8 @@ large; a reward screen is a presentation even on a small phone.
40
41
 
41
42
  The **trophy** comes only as a hero (§3). There is no trophy icon.
42
43
 
43
- The Gems and Tickets marks differ in **shape** — a faceted gem, and a ticket with a notch in each
44
- end — as well as colour, so a player can tell the two apart without seeing colour. Keep the currency's
44
+ The Gems and Coins marks differ in **shape** — a wide faceted gem, and a round coin with a ring
45
+ inside its rim — as well as colour, so a player can tell the two apart without seeing colour. Keep the currency's
45
46
  name beside or behind every amount (in words, or for a screen reader) all the same.
46
47
 
47
48
  ## 2. The Gems icon
@@ -89,12 +90,12 @@ every quality setting and moved a 20 px icon's facet colours visibly. The render
89
90
  and the pipeline lives with the platform's art sources; if the gem changes, the platform re-renders
90
91
  both sizes and a new SDK release ships them. Never edit the files by hand.
91
92
 
92
- ### The Tickets icon
93
+ ### The Coins icon
93
94
 
94
- The same two renditions and four ratios, under the same rules: the ticket spans the full width of its
95
- box, with clear rows above and below it (more of them than the gem, because a ticket is wider than it
96
- is tall), and each size is drawn on its own grid with its own outline weight — 1.5 px at 20, 2 px at
97
- 32.
95
+ The same two renditions and four ratios, under the same rules, except that the coin is about as tall
96
+ as it is wide: it is centred with clear rows above and below it (about a twelfth of the box each, so
97
+ it carries the same weight as the wide, low gem), and each size is drawn on its own grid with its own
98
+ outline weight — 1.5 px at 20, 2 px at 32.
98
99
 
99
100
  | Rendition | For a CSS box of | File | Pixels |
100
101
  | --------- | ---------------- | ---- | ------ |
@@ -107,14 +108,14 @@ is tall), and each size is drawn on its own grid with its own outline weight —
107
108
  | | | `ticket-icon-32-2x.png` | 64 × 64 |
108
109
  | | | `ticket-icon-32-3x.png` | 96 × 96 |
109
110
 
110
- It is the hero's ticket — solid tangerine, a notch in each end and a perforated stub (see the note at
111
- the top of this page) — downscaled onto each file's own pixel grid, inside the gem icon's violet
112
- outline. The arcade's wallet draws the same ticket from the same master, and a simplified vector
111
+ It is the hero's coin — solid tangerine, turned a little so its edge shows, a cream ring and an
112
+ embossed gem-cut (see the note at the top of this page) — downscaled onto each file's own pixel grid,
113
+ inside the gem icon's violet outline. The arcade's wallet draws the same coin from the same master, and a simplified vector
113
114
  version of it at 16–20 px.
114
115
 
115
116
  ## 3. The hero art
116
117
 
117
- Three marks — the gem, the ticket and the trophy — each at five sizes. Every file is a square PNG with a
118
+ Three marks — the gem, the coin and the trophy — each at five sizes. Every file is a square PNG with a
118
119
  transparent background, no outline, and the mark centred with a small margin, so the files swap for
119
120
  one another at any size without moving your layout.
120
121
 
@@ -274,11 +275,11 @@ an engine or a tool that cannot bundle files and needs to ask the platform what
274
275
  **A bundled game should prefer the renditions in this package**: they come in two sizes and four
275
276
  densities, and they cost no request at play time.
276
277
 
277
- ## 5. The rules: Gems and Tickets display belongs to the arcade
278
+ ## 5. The rules: Gems and Coins display belongs to the arcade
278
279
 
279
- The creator's ruling (2026-09-24): **"Gems display belongs to the arcade."** Tickets, the platform's
280
- second currency, is held to the same ruling: read every rule below about Gems as a rule about Tickets
281
- too, with the ticket in place of the gem. Amended 2026-09-30 for the earn allowance (the platform's
280
+ The creator's ruling (2026-09-24): **"Gems display belongs to the arcade."** Coins, the platform's
281
+ second currency, is held to the same ruling: read every rule below about Gems as a rule about Coins
282
+ too, with the coin in place of the gem. Amended 2026-09-30 for the earn allowance (the platform's
282
283
  decision of that date); the ruling's other rules are unchanged. In rules:
283
284
 
284
285
  - **Keep no Gems counter.** Your game shows no Gems balance, running total or wallet of its own, on
@@ -306,8 +307,8 @@ decision of that date); the ruling's other rules are unchanged. In rules:
306
307
  the flight leaves from the gem the player is looking at. On a canvas, convert from canvas pixels
307
308
  with the canvas's `getBoundingClientRect()`.
308
309
 
309
- A Tickets payout is cued the same way, from the ticket, with `currencySlug: 'ARCADE_TICKETS'`. The
310
- slug decides what flies — gems or tickets — and which total the platform moves. In the Gem Arcade
310
+ A Coins payout is cued the same way, from the coin, with `currencySlug: 'ARCADE_TICKETS'`. The
311
+ slug decides what flies — gems or coins — and which total the platform moves. In the Gem Arcade
311
312
  every payout flies into the Gem button, in whichever corner of your frame it sits; no wallet is
312
313
  drawn over your game.
313
314
  - **If `cueReward` returns `false`, do nothing.** There is no fallback celebration. `false` means the
@@ -323,8 +324,8 @@ decision of that date); the ruling's other rules are unchanged. In rules:
323
324
  `gem.platform.earnAllowance.get()` ("40 Gems left to earn today"). The icon may sit beside that
324
325
  figure. It is still not a balance, a counter or a running total, and it is never a number your game
325
326
  computes. Your server's order response is the receipt, not your screen.
326
- - **The ticket means Tickets, the platform's cosmetics currency** — never your own currency, and
327
- never a raffle, an entry or a pass. The gem rule above applies to it word for word.
327
+ - **The coin means Coins, the platform's cosmetics currency** — never your own currency (a game's
328
+ own gold or coins included: draw those with your own art), and never a token, a chip or a pass. The gem rule above applies to it word for word.
328
329
  - **The trophy means an achievement**: use it where your game shows what a player has earned.
329
330
  Whether the trophy also becomes the mark of the player's Achievement Score — the sum of their
330
331
  achievement points, which the arcade now shows — is an open design question; until it is answered,