@indiegems/gem-web-sdk 9.0.0 → 9.1.1

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.
@@ -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/v9.0.0/gem-web-sdk.tgz
84
- curl -fsSL https://downloads.gemarcade.com/sdk/v9.0.0/gem-web-sdk.tgz.sri
83
+ curl -fsSL -O https://downloads.gemarcade.com/sdk/v9.1.1/gem-web-sdk.tgz
84
+ curl -fsSL https://downloads.gemarcade.com/sdk/v9.1.1/gem-web-sdk.tgz.sri
85
85
  openssl dgst -sha384 -binary gem-web-sdk.tgz | openssl base64 -A
86
86
  ```
87
87
 
@@ -528,7 +528,10 @@ credit for it until you say so.
528
528
  inventory and dialog operable on the standard gamepad mapping with the pointer unused, and a focus
529
529
  cue thicker than a hairline — a 1px outline disappears at ten feet. TV remotes arrive as
530
530
  **keyboard-class events** (arrows, Enter, Back), so a game that calls itself a keyboard game is a
531
- D-pad game on a TV whether it planned to be or not.
531
+ D-pad game on a TV whether it planned to be or not. One control a gamepad cannot work: a
532
+ rewarded-ad button. Browsers do not count gamepad input as a press, so a rewarded ask made from
533
+ one is refused ([`rewarded-ads.md` §3](rewarded-ads.md#3-ask-from-the-press-then-re-read)). A
534
+ remote's keys do count. Keep the ordinary way on beside the button working.
532
535
  - **Title-safe layout.** HUD and critical UI inset at least ~5% of the frame — roughly 48–96px at
533
536
  1080p. `env(safe-area-inset-*)` resolves to **0 on every TV**: overscan is a hardware crop the
534
537
  browser cannot see, so no platform can hand you the number and your game must apply its own
@@ -540,6 +543,12 @@ credit for it until you say so.
540
543
  - **Text entry the on-screen keyboard can serve.** Focusing a field summons the TV's OSK, so keep
541
544
  entry fields few and ordinary — and never gate first play behind one. A player made to type on a
542
545
  remote before they may play mostly does not.
546
+
547
+ The same fields have a rule that is not about televisions at all: **give every focusable text
548
+ field a font size of at least 16px**, on every device. Below that, iOS Safari zooms the page in
549
+ when the field takes focus and does not zoom back out, so the game is left cropped off the side of
550
+ the screen until the player pinches it back. A 14px lobby-code box is enough to do it.
551
+
543
552
  - **A TV performance budget.** TV-browser SoCs are weak next to any desktop: ship a player-settable
544
553
  render-scale option (render at DPR 1 and upscale), bound memory, assume a fixed frame — 16:9, or
545
554
  a centred 9:16 column when your store page makes you
@@ -1122,15 +1131,15 @@ player (`gem.player`), room members, leaderboard rows, friends, profiles, showca
1122
1131
  async opponent you read through the raw client, once you pass the row through `mapIdentity`. One
1123
1132
  renderer serves all of them.
1124
1133
 
1125
- | Field | What it is | Type |
1126
- | --------------- | ------------------------------------------------------------------------------------------- | ------------ |
1127
- | `playerId` | The player's id. **Absent on an anonymous row** | `string` |
1128
- | `displayName` | The name the player chose | `PlayerText` |
1129
- | `discriminator` | The digits that tell two same-named players apart — `0001`, no `#` | `string` |
1130
- | `displayTag` | The precomposed `Name#0001` | `PlayerText` |
1131
- | `avatarIconId` | The portrait item's id | `string` |
1132
- | `avatarIconUrl` | The portrait's thumbnail | `string` |
1133
- | `badges` | Equipped badges, at most two, in the player's order, each `{ itemId, iconUrl }` | array |
1134
+ | Field | What it is | Type |
1135
+ | --------------- | ------------------------------------------------------------------------------- | ------------ |
1136
+ | `playerId` | The player's id. **Absent on an anonymous row** | `string` |
1137
+ | `displayName` | The name the player chose | `PlayerText` |
1138
+ | `discriminator` | The digits that tell two same-named players apart — `0001`, no `#` | `string` |
1139
+ | `displayTag` | The precomposed `Name#0001` | `PlayerText` |
1140
+ | `avatarIconId` | The portrait item's id | `string` |
1141
+ | `avatarIconUrl` | The portrait's thumbnail | `string` |
1142
+ | `badges` | Equipped badges, at most two, in the player's order, each `{ itemId, iconUrl }` | array |
1134
1143
 
1135
1144
  **A player chooses what they wear**: a portrait and up to two badges, each an icon they own — one
1136
1145
  an achievement in your game or any other may have awarded them ([achievements.md](achievements.md)
@@ -1283,8 +1292,10 @@ nothing, so a reward must never be handed out on the strength of it.
1283
1292
  [`cross-promotion.md`](cross-promotion.md) is the page.
1284
1293
 
1285
1294
  A button the player presses for a reward — a revive, an extra attempt — is the same call with
1286
- `format: 'rewarded'`. Your game config declares what each such button grants, the platform writes
1287
- the reward into your game's inventory, and your game reads it there rather than from the answer.
1295
+ `format: 'rewarded'`, made from that press itself. The button says it is an ad and names the
1296
+ reward, and the Arcade starts the ad as soon as the ask arrives. Your game config declares what
1297
+ each such button grants, the platform writes the reward into your game's inventory, and your game
1298
+ reads it there rather than from the answer.
1288
1299
  [`rewarded-ads.md`](rewarded-ads.md) is that page.
1289
1300
 
1290
1301
  ## An account upsell, if your game has something to offer one
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indiegems/gem-web-sdk",
3
- "version": "9.0.0",
3
+ "version": "9.1.1",
4
4
  "description": "postMessage bridge contract between gem-web and browser-playable games",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -3203,9 +3203,21 @@
3203
3203
  "",
3204
3204
  " RENDER IT IN YOUR OWN CHROME. Labelled as a promotion, dismissible, and",
3205
3205
  " focus-trapped over the paused game. Nothing in this message is rendered.",
3206
- " For `rewarded`, the player pressed the game's button, and the game's",
3207
- " label is not the disclosure: paint an offer sheet that says it is an ad",
3208
- " and what the player gets, with a way to decline, BEFORE anything plays.",
3206
+ " For `rewarded`, the player pressed the game's button, and THAT PRESS IS",
3207
+ " THE OPT-IN: the game's label says it is an ad and names the reward, so",
3208
+ " start the ad without a prompt of your own. Label it as an ad for as long",
3209
+ " as it plays, and let the player close it; closing early is a skip and",
3210
+ " pays nothing. Where no ad could play and nothing was granted, say so",
3211
+ " briefly in your own chrome ('No ad available right now').",
3212
+ "",
3213
+ " DO NOT RELY ON THE FRAME HAVING CHECKED FOR A PRESS. SDK releases after",
3214
+ " 9.0.0 send a rewarded ask only while the frame holds user activation,",
3215
+ " where the browser reports it. Every SDK from 5.1.0 to 9.0.0 sends one",
3216
+ " with no such check, so a game pinned to one of those can ask from a",
3217
+ " timer and start an ad with no press, and a hostile frame posts on the",
3218
+ " port directly. Even the check cannot say which press caused an ask:",
3219
+ " activation belongs to the whole frame for a few seconds, so an ask from",
3220
+ " the game's jump button passes it too.",
3209
3221
  "",
3210
3222
  " PAUSE WITH `gem.pause`. That message already means 'stop running and stop",
3211
3223
  " making noise', which is exactly what is wanted while a panel is up. Do",
@@ -3285,8 +3297,8 @@
3285
3297
  " no; a game reads it identically to `no_ad`.",
3286
3298
  "",
3287
3299
  "AFTER A `rewarded` ASK the player pressed a button, so two of those",
3288
- "readings change. `shown` means an offer sheet was painted and has",
3289
- "closed, whatever the player chose inside it, and still grants nothing.",
3300
+ "readings change. `shown` means the parent painted something for the ask",
3301
+ "and it has closed - the ad, however it ended - and still grants nothing.",
3290
3302
  "`no_ad` can arrive with the reward already granted - where no ad serves",
3291
3303
  "and the game's config says to grant without one, for one - so a game",
3292
3304
  "reads its own inventory, never the outcome, to learn whether a reward",