@indiegems/gem-web-sdk 7.9.0 → 7.9.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.
@@ -571,73 +571,117 @@ the `var()` above, or read `gem.viewport`. The release checklist looks for the b
571
571
 
572
572
  ### The arcade's own controls: reserved areas
573
573
 
574
- On a phone your game is full-bleed, and the arcade keeps one cluster of its own over it, in the
575
- **top-right corner**:
574
+ On a phone your game is full-bleed, and the arcade keeps one row of its own over the top of it:
576
575
 
577
- - **The menu button**, in the corner itself, always there. It opens
576
+ - **The menu button**, in the **top-right corner**, always there. It opens
578
577
  [the Arcade's menu](#the-arcades-menu-your-settings-live-in-it): Return to the Arcade, your
579
578
  settings, mute and the rest.
580
- - **The player's wallets** (Gems, Tickets, their achievement score), to the left of it, while your
581
- screen [shows them](#the-arcades-wallet-show-it-never-draw-it). When gameplay hides them with
582
- `gem.setWalletVisible(false)`, the cluster shrinks to the menu button alone.
579
+ - **The player's wallets** (Gems, Tickets, their achievement score), in the **middle of the row**,
580
+ [always there](#the-arcades-wallet-always-shown-never-drawn), during play as well as on your
581
+ menus. They are translucent, so your game shows through them — but they are still the Arcade's,
582
+ and still taps the Arcade takes.
583
583
 
584
- **The top-left corner is yours.** Put your own back or home button there — the one that moves around
585
- _inside_ your game, back to your level select or your title screen. **Put no settings, pause-menu or
586
- burger button of your own top-right**: your settings open from the Arcade's menu, and a second
587
- button under the Arcade's would mean something else in every game.
584
+ **The top of the screen has one layout, in every game:**
585
+
586
+ | Where | Whose | What goes there |
587
+ | -------------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
588
+ | **Top-left** | yours | Your **Home / Back** buttons, drawn when a screen needs them, in the space to the left of the wallets. They move around _inside_ your game — back to your level select or title screen — and never leave it. |
589
+ | **Middle and top-right** | the Arcade's | Its wallets and its menu button. Nothing of yours. |
590
+ | **Centre and right, below the Arcade's row** | yours | Your **information**: score, moves, a timer, a level name. It starts under the bottom of the Arcade's row, never beside it or under it. |
591
+
592
+ Keep the left for Home / Back even on a screen that has neither today: a player learns where "back"
593
+ is once, across every game, and information that sits there on one screen teaches them the wrong
594
+ thing on the next.
595
+
596
+ **Put no settings, pause-menu or burger button of your own top-right**: your settings open from the
597
+ Arcade's menu, and a second button under the Arcade's would mean something else in every game.
598
+
599
+ **How much room the top-left has.** The menu button is about 48px across — the size of a Home or
600
+ Back button. With every wallet shown, the narrowest phones (360px wide) leave roughly 68px to the
601
+ left of the wallets: room for **one** button. Two buttons, or a wide one, go on their own row below
602
+ the Arcade's. Do not copy those numbers — read the space, as below.
588
603
 
589
604
  Those rectangles of your frame are **reserved**: keep essential UI and every touch target out of
590
605
  them. **Never hard-code their size or height.** They differ by phone, and in native fullscreen the
591
606
  whole row may rise into the camera band — read them, as below.
592
607
 
593
- An inset cannot say that — as a top inset, a tab a few dozen pixels wide would take your whole top
608
+ An inset cannot say that — as a top inset, a button a few dozen pixels wide would take your whole top
594
609
  strip. So `gem.viewport` also carries the rectangles, in the same CSS pixels of your frame, measured
595
- from its top-left corner:
610
+ from its top-left corner — one per wallet shown, and one for the menu button:
596
611
 
597
612
  ```json
598
613
  {
599
614
  "insets": { "top": 47, "right": 0, "bottom": 34, "left": 0 },
600
- "reserved": [{ "x": 8, "y": 51, "width": 104, "height": 34 }]
615
+ "reserved": [
616
+ { "x": 68, "y": 51, "width": 72, "height": 28 },
617
+ { "x": 144, "y": 51, "width": 72, "height": 28 },
618
+ { "x": 220, "y": 51, "width": 72, "height": 28 },
619
+ { "x": 304, "y": 51, "width": 48, "height": 48 }
620
+ ]
601
621
  }
602
622
  ```
603
623
 
604
624
  **The SDK turns them into one pair of custom properties per corner**, written beside
605
625
  `--gem-safe-*` before anything else hears the push: `--gem-reserved-tl-width` and
606
626
  `--gem-reserved-tl-height`, and the same pair for `tr`, `bl` and `br` — how far that corner's
607
- reserved rectangles reach in from its two edges. Push the corner's UI clear of it:
627
+ reserved rectangles reach in from its two edges. A rectangle belongs to the corner its centre lies
628
+ nearest to.
629
+
630
+ ⚠️ **The wallets sit in the middle, so they count toward BOTH top corners.** A wallet left of
631
+ centre is a top-left rectangle, one right of centre a top-right one. While wallets are shown,
632
+ `--gem-reserved-tl-height` is the bottom of the wallets and `--gem-reserved-tl-width` reaches to the
633
+ middle of the screen — even though the corner itself, left of the first wallet, is clear. So:
608
634
 
609
635
  ```css
610
- /* your back button in the top-left corner, which the arcade leaves clear */
636
+ /* your information — score, moves, a timer — below the WHOLE of the arcade's row: the taller of
637
+ the two top corners. It moves up by itself when gameplay hides the wallets. */
638
+ #info {
639
+ top: max(
640
+ var(--gem-safe-top, env(safe-area-inset-top, 0px)),
641
+ var(--gem-reserved-tl-height, 0px),
642
+ var(--gem-reserved-tr-height, 0px)
643
+ );
644
+ right: var(--gem-safe-right, 0px);
645
+ }
646
+ /* ONE Home or Back button, level with the arcade's row, in the clear corner to the wallets' left */
611
647
  #back {
612
648
  top: var(--gem-safe-top, env(safe-area-inset-top, 0px));
613
649
  left: var(--gem-safe-left, 0px);
614
650
  }
615
- /* a score in the top-right corner, below the arcade's cluster */
616
- #score {
617
- top: max(var(--gem-safe-top, env(safe-area-inset-top, 0px)), var(--gem-reserved-tr-height, 0px));
618
- right: var(--gem-safe-right, 0px);
619
- }
620
- /* or a row along the top, stopping short of it */
621
- #top-bar {
622
- padding-left: var(--gem-reserved-tl-width, 0px);
623
- padding-right: var(--gem-reserved-tr-width, 0px);
651
+ /* a ROW of your own buttons does not fit beside the wallets: start it below the arcade's row,
652
+ like your information */
653
+ #nav {
654
+ top: max(
655
+ var(--gem-safe-top, env(safe-area-inset-top, 0px)),
656
+ var(--gem-reserved-tl-height, 0px),
657
+ var(--gem-reserved-tr-height, 0px)
658
+ );
624
659
  }
625
660
  ```
626
661
 
627
- All eight are written on every push, `0px` for a clear corner, so a rotation never leaves a stale
628
- value; they are never set under an embedder that sends no viewport, which is what the `0px`
629
- fallback is for. A rectangle belongs to the corner its centre lies nearest to. For a HUD laid out
630
- from script, read `gem.viewport.reserved` — `[]` when nothing is covered.
662
+ The per-corner properties cannot say how wide the clear corner is — only that the corner's
663
+ rectangles reach in to the middle. To know whether your button fits beside the wallets, read the
664
+ rectangles from script: the clear width at the top-left is the smallest `x` among
665
+ `gem.viewport.reserved` (the whole width when the list is empty).
631
666
 
632
- **Lay out against it whenever it changes.** Shown wallets widen the top-right rectangle; hiding them
633
- shrinks it to the menu button alone. A wallet the arcade pops up for a moment while they are hidden
634
- never reserves anything — it floats over your game and moves nothing. Read every corner, not only the
635
- one this page names today: `--gem-reserved-tl-*` is `0px` now, and a layout that honours it anyway
636
- is right under any embedder.
667
+ ```js
668
+ const reserved = gem.viewport?.reserved ?? [];
669
+ const clearLeft = reserved.length ? Math.min(...reserved.map((r) => r.x)) : window.innerWidth;
670
+ nav.classList.toggle('below-arcade-row', clearLeft < nav.offsetWidth + 8);
671
+ ```
672
+
673
+ All eight properties are written on every push, `0px` for a clear corner, so a rotation never leaves
674
+ a stale value; they are never set under an embedder that sends no viewport, which is what the `0px`
675
+ fallback is for. `gem.viewport.reserved` is `[]` when nothing is covered.
676
+
677
+ **Lay out against it whenever it changes.** The wallets' rectangles are there for the whole
678
+ session on the Arcade's phone layout, and their number and width can change as the player's
679
+ balances and currencies do. Read every corner, not only the ones this page names today: a layout that honours
680
+ all four is right under any embedder.
637
681
 
638
682
  **Older SDKs get it folded into the top inset.** A game on an SDK from before reserved areas cannot
639
683
  read the rectangles, so the arcade sends it none and instead raises `insets.top` — and so
640
- `--gem-safe-top` — past the bottom of the cluster. That game keeps working, at the cost of a full-width
684
+ `--gem-safe-top` — past the bottom of the row. That game keeps working, at the cost of a full-width
641
685
  band; upgrading gives the band back.
642
686
 
643
687
  ## Which store-page experiment brought this player in: cohorts
@@ -854,38 +898,25 @@ its music out than cut it, say. The Arcade still shows its button for your game
854
898
  so this is a promise: your `onPrefs` handler must go quiet on `muted: true` and come back on `false`,
855
899
  and the release checklist checks that it does.
856
900
 
857
- ## The Arcade's wallet: show it, never draw it
901
+ ## The Arcade's wallet: always shown, never drawn
858
902
 
859
903
  The player's platform balances — Gems, Tickets (`ARCADE_TICKETS`) and their achievement score —
860
904
  belong to the Arcade. **Your game never draws one**, and never shows a pending state for one: the
861
- Arcade takes every figure from the platform and draws the wallets itself, beside its menu button in
862
- the top-right corner of your frame on a phone.
863
-
864
- **They are shown unless your game hides them.** A game that does nothing has every wallet on show
865
- the whole time. The one rule: **hide them during gameplay, show them on your menus.**
866
-
867
- ```js
868
- level.onStart = () => gem.setWalletVisible(false);
869
- pauseMenu.onOpen = () => gem.setWalletVisible(true);
870
- ```
871
-
872
- - **While hidden, the Arcade still pops a wallet up** for a moment when something happens to it —
873
- a reward you cued with `gem.cueReward`, a spend, a landing, a daily-maximum note, a score change
874
- — then hides it again. Your state never cancels that, so a reward mid-level still shows.
875
- - **It is screen state, not a toggle.** Each call is the whole answer and replaces the last. Call it
876
- as often as you like: before the Arcade connects the state is held and sent when it does, and
877
- again after any reconnect; a repeat of the current state is not re-sent.
878
- - **Shown wallets take space; a pop does not.** Shown, they widen the top-right
879
- [reserved area](#the-arcades-own-controls-reserved-areas) beside the menu button, so lay your
880
- screen out against `--gem-reserved-tr-*`; hidden, it shrinks back to the button alone. A pop floats
881
- over your game and never moves its layout.
882
- - **Narrowing is optional.** On a screen that sells in one currency — a ticket store — you may show
883
- only that one: `gem.setWalletVisible(true, { only: ['ARCADE_TICKETS'] })`, with `'score'` for the
884
- achievement score. Use it only there; leaving it out shows every wallet, which is always safe.
885
- - **Where the Arcade docks its wallets beside your frame** — a desktop page — they are always on
886
- show, and this changes nothing. Call it anyway; the same code is right everywhere.
887
- - **`false` means nobody is listening** — no connection yet, or an embedder that draws no wallet.
888
- Do nothing in its place.
905
+ Arcade takes every figure from the platform and draws the wallets itself, in the middle of the row
906
+ across the top of your frame on a phone, with its menu button at the right end.
907
+
908
+ **The Arcade shows every wallet the whole time, during play too** (since 2026-10-04). They are
909
+ small, translucent chips in the middle of the top row, and they are
910
+ [reserved rectangles](#the-arcades-own-controls-reserved-areas): lay every screen out below both
911
+ `--gem-reserved-tl-height` and `--gem-reserved-tr-height`, gameplay included. There is nothing for
912
+ your game to call.
913
+
914
+ ⚠️ **`gem.setWalletVisible` no longer hides anything in the Arcade.** It was how a game hid the
915
+ wallets for gameplay and showed them on its menus, and narrowed them to one currency on a store
916
+ screen. The Arcade still accepts the call — it returns `true`, and existing games need no change —
917
+ but the wallets stay up whatever it is told. **Do not design a screen around the top row being
918
+ clear during play**: it is not. Another embedder may still honour the call, so leaving it in is
919
+ harmless; new code does not need it.
889
920
 
890
921
  ## No accidental text selection
891
922
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indiegems/gem-web-sdk",
3
- "version": "7.9.0",
3
+ "version": "7.9.1",
4
4
  "description": "postMessage bridge contract between gem-web and browser-playable games",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",