@indiegems/gem-web-sdk 13.0.0 → 13.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 +14 -0
- package/dist/function.d.ts +1 -1
- package/dist/game.d.ts +15 -2
- package/dist/gem-web-sdk.bridge.js +1 -1
- package/dist/gem-web-sdk.esm.js +2 -2
- package/dist/gem-web-sdk.function.js +1 -1
- package/dist/gem-web-sdk.game.js +2 -2
- package/dist/gem-web-sdk.min.js +2 -2
- package/dist/gem-web-sdk.sdk.js +2 -2
- package/dist/gem-web-sdk.server.js +1 -1
- package/dist/index.d.ts +15 -4
- package/dist/sdk.d.ts +15 -2
- package/docs/api/api-reference-function.md +13 -5
- package/docs/api/api-reference-game.md +190 -11
- package/docs/api/api-reference-server.md +1 -1
- package/docs/api/reference.json +184 -10
- package/docs/arcade-avatars.md +194 -26
- package/docs/brand-art.md +3 -3
- package/docs/changelog.md +14 -0
- package/docs/getting-started.md +3 -2
- package/docs/inventory-and-catalogs.md +1 -1
- package/docs/manifest.json +14 -14
- package/docs/server-bundles.md +2 -2
- package/docs/what-a-game-must-do.md +97 -57
- package/package.json +4 -2
- package/rigs/adult_human.glb +0 -0
- package/schema/bridge.v1.json +53 -6
- package/schema/capabilities.public.json +6 -0
|
@@ -708,46 +708,54 @@ the `var()` above, or read `gem.viewport`. The release checklist looks for the b
|
|
|
708
708
|
The Arcade keeps **one control of its own over every game**, on every device — a phone's full-bleed
|
|
709
709
|
game, a framed or full-window game on a desktop, a tablet or a TV in native fullscreen:
|
|
710
710
|
|
|
711
|
-
- **The Gem button**, the Gem Arcade's gem,
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
711
|
+
- **The Gem button**, the Gem Arcade's gem, always there (a touch target, about 50px across), in
|
|
712
|
+
the **top-left corner** unless your game [asks for another](#moving-the-gem-gemsetgemcorner). It
|
|
713
|
+
opens [the Arcade's menu](#the-arcades-menu): Return to the Arcade, the player's Gems, Tickets and
|
|
714
|
+
achievement score, mute, the player's Arcade-wide settings and the rest. Not your settings: those
|
|
715
|
+
are [your own button](#game-settings).
|
|
715
716
|
- **Nothing else.** The player's wallets (Gems, Tickets, their achievement score) are **not** drawn
|
|
716
717
|
over your game: the player opens the Gem menu to see them, and every platform-currency payout
|
|
717
718
|
flies into the Gem button ([the Arcade's wallet](#the-arcades-wallet-in-the-gem-menu-never-drawn-by-you)).
|
|
718
719
|
When the player switches the frame-rate readout on, it sits beside the gem and is reserved the
|
|
719
720
|
same way.
|
|
720
721
|
|
|
721
|
-
|
|
722
|
+
### The top of the screen
|
|
722
723
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
| **Top-left corner** | the Arcade's | Its Gem button. Nothing of yours under it. |
|
|
726
|
-
| **Top-left, right of the Gem** | yours | Your **Home / Back** buttons, drawn when a screen needs them, level with the Gem and just to its right. They move around _inside_ your game — back to your level select or title screen — and never leave it. |
|
|
727
|
-
| **Centre of the top row** | yours | Your **information**: score, moves, a timer, a level name. |
|
|
728
|
-
| **Top-right** | yours | Your **settings** button ([Game settings](#game-settings)). |
|
|
724
|
+
**The top of the screen has one layout, in every game, wherever the Gem sits.** A player learns
|
|
725
|
+
where "back" and "settings" are once, across every game:
|
|
729
726
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
727
|
+
| Where | Whose | What goes there |
|
|
728
|
+
| ------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
729
|
+
| **The Gem's corner** | the Arcade's | Its Gem button — top-left unless you [ask for another corner](#moving-the-gem-gemsetgemcorner). Nothing of yours under it. |
|
|
730
|
+
| **Top-right** | yours | Your **settings** button ([Game settings](#game-settings)) at the end of the row, and your **Back / Home** button just to its left, level with it and about 16px apart, so a fingertip lands on one and not the other. |
|
|
731
|
+
| **Centre of the top row** | yours | Your **information**: a title, score, moves, a timer, a level name. |
|
|
733
732
|
|
|
734
|
-
**
|
|
735
|
-
|
|
736
|
-
|
|
733
|
+
- **Back / Home is drawn when a screen needs it, always in that spot.** It moves around _inside_
|
|
734
|
+
your game — back to your level select or title screen — and never leaves it: leaving is the
|
|
735
|
+
Arcade's menu, so a player always knows which control does which.
|
|
736
|
+
- **Whichever of your controls shares the Gem's corner sits level with the Gem, on the side toward
|
|
737
|
+
the centre.** With the Gem top-left, nothing of yours does. With the Gem top-right, your Back and
|
|
738
|
+
settings sit just left of it.
|
|
739
|
+
- **Your settings button is there on every screen.** It goes top-right even where no Arcade control
|
|
740
|
+
is: another embedder may keep one in that corner, so place it from the reserved areas below and it
|
|
741
|
+
moves aside for whatever is there.
|
|
737
742
|
|
|
738
|
-
|
|
739
|
-
them. **Never hard-code their size or position.** They
|
|
740
|
-
|
|
743
|
+
The parts of your frame under the Gem and any other Arcade control are **reserved**: keep
|
|
744
|
+
essential UI and every touch target out of them. **Never hard-code their size or position.** They
|
|
745
|
+
differ by phone, orientation and mode. The Gem sits at the edge of the safe area and never rises
|
|
746
|
+
into the camera band, but that edge is somewhere else on every device — read them, as below.
|
|
741
747
|
|
|
742
748
|
An inset cannot say that — as a left or top inset, a button a few dozen pixels wide would take a whole
|
|
743
749
|
strip of your screen. So `gem.viewport` also carries the rectangles, in the same CSS pixels of your
|
|
744
750
|
frame, measured from its top-left corner — one for the Gem button, and one for the frame-rate
|
|
745
|
-
readout while the player shows it
|
|
751
|
+
readout while the player shows it. Each is grown out to the frame edges it sits nearest, because the
|
|
752
|
+
sliver between the Gem and the edge is no place for a button either. On a notched phone in portrait,
|
|
753
|
+
with the Gem top-left:
|
|
746
754
|
|
|
747
755
|
```json
|
|
748
756
|
{
|
|
749
757
|
"insets": { "top": 47, "right": 0, "bottom": 34, "left": 0 },
|
|
750
|
-
"reserved": [{ "x":
|
|
758
|
+
"reserved": [{ "x": 0, "y": 0, "width": 60, "height": 99 }]
|
|
751
759
|
}
|
|
752
760
|
```
|
|
753
761
|
|
|
@@ -755,35 +763,37 @@ readout while the player shows it:
|
|
|
755
763
|
`--gem-safe-*` before anything else hears the push: `--gem-reserved-tl-width` and
|
|
756
764
|
`--gem-reserved-tl-height`, and the same pair for `tr`, `bl` and `br` — how far that corner's
|
|
757
765
|
reserved rectangles reach in from its two edges. A rectangle belongs to the corner its centre lies
|
|
758
|
-
nearest to.
|
|
766
|
+
nearest to. Lay the top row out between the two top corners, and it is right wherever the Gem is:
|
|
759
767
|
|
|
760
768
|
```css
|
|
761
|
-
/*
|
|
762
|
-
#
|
|
769
|
+
/* The top row: clear of whatever the Arcade reserves in either top corner */
|
|
770
|
+
#top-row {
|
|
771
|
+
position: absolute;
|
|
763
772
|
top: var(--gem-safe-top, env(safe-area-inset-top, 0px));
|
|
764
773
|
left: max(var(--gem-safe-left, 0px), var(--gem-reserved-tl-width, 0px));
|
|
774
|
+
right: max(var(--gem-safe-right, 0px), var(--gem-reserved-tr-width, 0px));
|
|
775
|
+
display: flex;
|
|
776
|
+
align-items: center;
|
|
777
|
+
gap: 16px;
|
|
765
778
|
}
|
|
766
|
-
/* your information
|
|
767
|
-
#info {
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
var(--gem-reserved-tr-height, 0px)
|
|
771
|
-
);
|
|
772
|
-
left: max(var(--gem-safe-left, 0px), var(--gem-reserved-tl-width, 0px));
|
|
773
|
-
right: var(--gem-safe-right, 0px);
|
|
779
|
+
/* your information takes the middle; Back, then settings, at the right end */
|
|
780
|
+
#top-row .info {
|
|
781
|
+
flex: 1;
|
|
782
|
+
text-align: center;
|
|
774
783
|
}
|
|
775
784
|
```
|
|
776
785
|
|
|
777
786
|
The per-corner properties say how far a corner's rectangles reach, not how much room is left beside
|
|
778
|
-
them. To know whether
|
|
779
|
-
script: the room
|
|
780
|
-
edge among them.
|
|
787
|
+
them. To know whether your top row fits between the Arcade's controls, read the rectangles from
|
|
788
|
+
script: the room is what lies between the top rectangles on the left and those on the right.
|
|
781
789
|
|
|
782
790
|
```js
|
|
783
|
-
const
|
|
784
|
-
const
|
|
785
|
-
const
|
|
786
|
-
|
|
791
|
+
const w = window.innerWidth;
|
|
792
|
+
const top = (gem.viewport?.reserved ?? []).filter((r) => r.y === 0);
|
|
793
|
+
const isLeft = (r) => r.x + r.width / 2 < w / 2;
|
|
794
|
+
const from = Math.max(0, ...top.filter(isLeft).map((r) => r.x + r.width));
|
|
795
|
+
const to = Math.min(w, ...top.filter((r) => !isLeft(r)).map((r) => r.x));
|
|
796
|
+
row.classList.toggle('below-arcade-row', to - from < row.scrollWidth + 8);
|
|
787
797
|
```
|
|
788
798
|
|
|
789
799
|
All eight properties are written on every push, `0px` for a clear corner, so a rotation never leaves
|
|
@@ -791,8 +801,39 @@ a stale value; they are never set under an embedder that sends no viewport, whic
|
|
|
791
801
|
fallback is for. `gem.viewport.reserved` is `[]` when nothing is covered.
|
|
792
802
|
|
|
793
803
|
**Lay out against it whenever it changes.** The Gem button's rectangle is there for the whole
|
|
794
|
-
session, and it moves with a rotation, a resize
|
|
795
|
-
only the one
|
|
804
|
+
session, and it moves with a rotation, a resize, the frame-rate readout and a change of corner. Read
|
|
805
|
+
every corner, not only the one you asked for: a layout that honours all four is right under any
|
|
806
|
+
embedder.
|
|
807
|
+
|
|
808
|
+
### Moving the Gem: `gem.setGemCorner`
|
|
809
|
+
|
|
810
|
+
**Leave the Gem top-left unless your own HUD needs that corner.** If it does, ask for another:
|
|
811
|
+
|
|
812
|
+
```js
|
|
813
|
+
// This game's minimap needs the top-left, so the Gem goes bottom-left.
|
|
814
|
+
gem.setGemCorner('bottom-left'); // 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
|
|
815
|
+
```
|
|
816
|
+
|
|
817
|
+
- **One corner per game**, at most one per orientation (one in portrait, another in landscape).
|
|
818
|
+
Call it once at boot, and again on a rotation if the two differ. A Gem that moves from screen to
|
|
819
|
+
screen is a way out the player has to look for.
|
|
820
|
+
- **In landscape the bottom corners are where a player's thumbs hold the sticks.** Ask for one only
|
|
821
|
+
if your controls do not live there.
|
|
822
|
+
- **Lay out around the reserved rectangles you receive, never around the corner you asked for.**
|
|
823
|
+
The Arcade moves the Gem on its own terms: not while the player is using it or its menu is open,
|
|
824
|
+
no more often than every few seconds, and a corner the player chooses for themselves, should the
|
|
825
|
+
Arcade ever offer that, wins over yours. The rectangles — and the `--gem-reserved-*` properties —
|
|
826
|
+
say where the Gem is now; a game that reads them is right whatever the Arcade decided, and a game
|
|
827
|
+
that assumed its corner is not.
|
|
828
|
+
- **The top row does not change.** Back and settings stay top-right and information top-centre,
|
|
829
|
+
wherever the Gem goes ([the top of the screen](#the-top-of-the-screen)).
|
|
830
|
+
- **It is screen state, not a toggle**: each call is the whole answer, held before the Arcade
|
|
831
|
+
connects and sent again after any reconnect. A value that is not one of the four corners is
|
|
832
|
+
ignored, with a warning on the console.
|
|
833
|
+
|
|
834
|
+
`gem.setGemCorner` returns `true` when the Arcade was told, and `false` before it connects and
|
|
835
|
+
under an embedder that cannot move its Gem. On `false` the Gem stays where the embedder puts it,
|
|
836
|
+
and the rectangles say where that is: there is nothing else to do.
|
|
796
837
|
|
|
797
838
|
**Older SDKs get it folded into the top inset.** A game on an SDK from before reserved areas cannot
|
|
798
839
|
read the rectangles, so the arcade sends it none and instead raises `insets.top` — and so
|
|
@@ -900,8 +941,8 @@ This is the whole model, and every other page that mentions settings links here:
|
|
|
900
941
|
them from `gem.prefs.recommended` (and `muted` and `reducedMotion` from `gem.prefs`) and applies
|
|
901
942
|
them again on `onPrefs`. The Arcade never asks your game anything about them, and never shows
|
|
902
943
|
anything your game says.
|
|
903
|
-
- **Every game draws its own settings button, top-right
|
|
904
|
-
Arcade's menu never opens it.
|
|
944
|
+
- **Every game draws its own settings button, top-right ([the top of the
|
|
945
|
+
screen](#the-top-of-the-screen)), and its own settings screen.** The Arcade's menu never opens it.
|
|
905
946
|
- **A setting starts from `recommended` until the player changes it in your game, and then the
|
|
906
947
|
player's choice in your game wins.** Save only what the player chose, never a recommended value.
|
|
907
948
|
- **Where a choice is kept.** Device configuration — volume, graphics quality, look sensitivity, a
|
|
@@ -914,17 +955,15 @@ This is the whole model, and every other page that mentions settings links here:
|
|
|
914
955
|
while `gem.vibration.available` ([vibration](vibration.md)).
|
|
915
956
|
|
|
916
957
|
**The button goes in the top-right corner**, the same corner in every game, so a player never has
|
|
917
|
-
to look for it
|
|
918
|
-
control
|
|
958
|
+
to look for it, with your Back button just to its left when a screen has one. Place it with the
|
|
959
|
+
reserved-area properties so it never sits under an Arcade control: if the Gem is in that corner, the
|
|
960
|
+
button sits level with it, just inside it.
|
|
919
961
|
|
|
920
962
|
```css
|
|
921
963
|
#settings-button {
|
|
922
964
|
position: absolute;
|
|
923
|
-
top:
|
|
924
|
-
|
|
925
|
-
var(--gem-reserved-tr-height, 0px)
|
|
926
|
-
);
|
|
927
|
-
right: var(--gem-safe-right, 0px);
|
|
965
|
+
top: var(--gem-safe-top, env(safe-area-inset-top, 0px));
|
|
966
|
+
right: max(var(--gem-safe-right, 0px), var(--gem-reserved-tr-width, 0px));
|
|
928
967
|
}
|
|
929
968
|
```
|
|
930
969
|
|
|
@@ -1143,7 +1182,8 @@ What it does, so you know what to expect:
|
|
|
1143
1182
|
|
|
1144
1183
|
## The Arcade's menu
|
|
1145
1184
|
|
|
1146
|
-
The Arcade keeps one button over every game, on every device: the Gem,
|
|
1185
|
+
The Arcade keeps one button over every game, on every device: the Gem, top-left unless your game
|
|
1186
|
+
[asks for another corner](#moving-the-gem-gemsetgemcorner). Its menu is
|
|
1147
1187
|
how a player leaves (**Return to the Arcade**), sees their Gems, Tickets and achievement score, mutes,
|
|
1148
1188
|
goes fullscreen, reports a problem and changes their Arcade-wide settings — the ones that reach you as [`gem.prefs.recommended`](#game-settings). You can add up to
|
|
1149
1189
|
four entries of your own:
|
|
@@ -1175,9 +1215,9 @@ gem.setMenu({
|
|
|
1175
1215
|
settings button is there either way; what such a game also needs is a way out of its own, a control
|
|
1176
1216
|
that calls `gem.exit()`.
|
|
1177
1217
|
|
|
1178
|
-
Your own **back or home** button — the one that moves around inside your game — goes **top-
|
|
1179
|
-
|
|
1180
|
-
leaving is the Arcade's menu, so a player always knows which control does which.
|
|
1218
|
+
Your own **back or home** button — the one that moves around inside your game — goes **top-right,
|
|
1219
|
+
just left of your settings button** ([the top of the screen](#the-top-of-the-screen)). It never
|
|
1220
|
+
leaves the game: leaving is the Arcade's menu, so a player always knows which control does which.
|
|
1181
1221
|
|
|
1182
1222
|
## Sound: your own mute control, and the Arcade's
|
|
1183
1223
|
|
|
@@ -1267,8 +1307,8 @@ belong to the Arcade. **Your game never draws one**, and never shows a pending s
|
|
|
1267
1307
|
Arcade takes every figure from the platform and shows them itself.
|
|
1268
1308
|
|
|
1269
1309
|
**The Gem Arcade draws no wallet over your game** (since 2026-10-11). Nothing of it sits in your top
|
|
1270
|
-
row, at rest or when a balance moves. The player opens the Gem menu — the Gem button
|
|
1271
|
-
|
|
1310
|
+
row, at rest or when a balance moves. The player opens the Gem menu — the Gem button, in whichever
|
|
1311
|
+
corner it sits — to see their Gems, Tickets and achievement score, and every payout
|
|
1272
1312
|
[`gem.cueReward`](inventory-and-catalogs.md#showing-the-reward-land-in-the-arcades-wallet) announces
|
|
1273
1313
|
flies into the Gem button. A payout you do not cue flies too, from the middle of your frame, so cue
|
|
1274
1314
|
the ones the player earns on screen and the flight starts where they are looking.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@indiegems/gem-web-sdk",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.1.0",
|
|
4
4
|
"description": "postMessage bridge contract between gem-web and browser-playable games",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -40,7 +40,8 @@
|
|
|
40
40
|
"import": "./dist/gem-web-sdk.quality.js"
|
|
41
41
|
},
|
|
42
42
|
"./schema": "./schema/bridge.v1.json",
|
|
43
|
-
"./brand/*": "./brand/*"
|
|
43
|
+
"./brand/*": "./brand/*",
|
|
44
|
+
"./rigs/*": "./rigs/*"
|
|
44
45
|
},
|
|
45
46
|
"files": [
|
|
46
47
|
"bin",
|
|
@@ -50,6 +51,7 @@
|
|
|
50
51
|
"schema/bridge.v1.json",
|
|
51
52
|
"schema/capabilities.public.json",
|
|
52
53
|
"brand/*.png",
|
|
54
|
+
"rigs/*.glb",
|
|
53
55
|
"docs/*.md",
|
|
54
56
|
"docs/manifest.json",
|
|
55
57
|
"docs/api/*.md",
|
|
Binary file
|
package/schema/bridge.v1.json
CHANGED
|
@@ -684,9 +684,9 @@
|
|
|
684
684
|
"optional": true,
|
|
685
685
|
"$comment": [
|
|
686
686
|
"Every 3D character the player WEARS, one per RIG FAMILY (gem-api",
|
|
687
|
-
"`avatars_3d`). A family is a rig contract —",
|
|
688
|
-
"`
|
|
689
|
-
"
|
|
687
|
+
"`avatars_3d`). A family is a rig contract — `small_human` and",
|
|
688
|
+
"`adult_human` today — and a player wears at most one character per",
|
|
689
|
+
"family, so a game that accepts several families reads the one it",
|
|
690
690
|
"draws by `family`.",
|
|
691
691
|
"",
|
|
692
692
|
"THE FLAT FIELDS STAY, AND THEY ARE ONE OF THESE. `avatar3dId`,",
|
|
@@ -720,7 +720,7 @@
|
|
|
720
720
|
"family": {
|
|
721
721
|
"kind": "string",
|
|
722
722
|
"maxLength": 32,
|
|
723
|
-
"$comment": "The rig family (gem-api `family`), e.g. `small_human`. A lowercase code, checked by the frame rather than by a format here, so one family name this frame does not recognise costs the entry and never the message."
|
|
723
|
+
"$comment": "The rig family (gem-api `family`), e.g. `small_human` or `adult_human`. A lowercase code, checked by the frame rather than by a format here, so one family name this frame does not recognise costs the entry and never the message."
|
|
724
724
|
},
|
|
725
725
|
"id": {
|
|
726
726
|
"kind": "string",
|
|
@@ -2681,8 +2681,8 @@
|
|
|
2681
2681
|
"moved (or is about to move) a progression mapped onto a platform currency,",
|
|
2682
2682
|
"and the game would like the arcade to show it landing: the currency flying",
|
|
2683
2683
|
"from `origin` into the arcade's chrome — in the Gem Arcade, into its Gem",
|
|
2684
|
-
"button
|
|
2685
|
-
"confirms the grant.",
|
|
2684
|
+
"button, in whichever corner of the frame it sits — and the total moving",
|
|
2685
|
+
"when the platform confirms the grant.",
|
|
2686
2686
|
"",
|
|
2687
2687
|
"A PRESENTATION CUE, NOT A CLAIM. Nothing here is trusted as a number. The",
|
|
2688
2688
|
"amount that lands and the player's new total reach the parent from gem-api",
|
|
@@ -3008,6 +3008,53 @@
|
|
|
3008
3008
|
"rateLimit": { "perMinute": 60 }
|
|
3009
3009
|
},
|
|
3010
3010
|
|
|
3011
|
+
{
|
|
3012
|
+
"type": "gem.gemCorner",
|
|
3013
|
+
"direction": "frameToParent",
|
|
3014
|
+
"transport": "port",
|
|
3015
|
+
"$comment": [
|
|
3016
|
+
"The corner of the frame the game would like the arcade's own control",
|
|
3017
|
+
"over it to sit in - in the Gem Arcade, the Gem button that opens its",
|
|
3018
|
+
"menu. With no message at all it sits top-left, which is also the",
|
|
3019
|
+
"recommendation: a game asks for another corner only when its own HUD",
|
|
3020
|
+
"needs that one.",
|
|
3021
|
+
"",
|
|
3022
|
+
"SCREEN STATE, NOT A TOGGLE, like `gem.menu`. Each message is the whole",
|
|
3023
|
+
"answer and the latest one wins. The SDK holds it from before the bridge",
|
|
3024
|
+
"is up and re-sends it after every handshake, so a parent that reconnects",
|
|
3025
|
+
"puts the control where the game had asked.",
|
|
3026
|
+
"",
|
|
3027
|
+
"A REQUEST, APPLIED ON THE PARENT'S TERMS. The parent holds a move while",
|
|
3028
|
+
"the player is using the control or one of its surfaces is open, keeps a",
|
|
3029
|
+
"minimum dwell between moves and applies only the latest request after",
|
|
3030
|
+
"one, and puts a player's own choice of corner, should it ever offer one,",
|
|
3031
|
+
"above the game's. So a game never lays out around the corner it asked",
|
|
3032
|
+
"for: it lays out around the rectangles `gem.viewport` sends in",
|
|
3033
|
+
"`reserved`, which say where the control actually is.",
|
|
3034
|
+
"",
|
|
3035
|
+
"ONE ENUM, AND IT ONLY GROWS. A later anchor is a new value behind a",
|
|
3036
|
+
"capability of its own, sent only to a parent that advertised that",
|
|
3037
|
+
"capability, so `v` does not move; a parent that advertised only",
|
|
3038
|
+
"`gemCorner` is only ever sent these four.",
|
|
3039
|
+
"",
|
|
3040
|
+
"A PRESENTATION REQUEST ONLY, and not an authorization control. The game",
|
|
3041
|
+
"picks one of four places the parent defines, never a coordinate, a size,",
|
|
3042
|
+
"a visibility or a look; the parent's dwell and holds, not this rate",
|
|
3043
|
+
"limit, are what keep a game from making the control run away.",
|
|
3044
|
+
"",
|
|
3045
|
+
"Gated by `gemCorner`: sent only to a parent that advertised it. To any",
|
|
3046
|
+
"other, `gem.setGemCorner` returns false."
|
|
3047
|
+
],
|
|
3048
|
+
"fields": {
|
|
3049
|
+
"corner": {
|
|
3050
|
+
"kind": "enum",
|
|
3051
|
+
"values": ["top-left", "top-right", "bottom-left", "bottom-right"],
|
|
3052
|
+
"$comment": "Physical, not logical: `left` is the frame's left edge in every language, so a right-to-left locale never mirrors a game's choice."
|
|
3053
|
+
}
|
|
3054
|
+
},
|
|
3055
|
+
"rateLimit": { "perMinute": 12 }
|
|
3056
|
+
},
|
|
3057
|
+
|
|
3011
3058
|
{
|
|
3012
3059
|
"type": "gem.requestShare",
|
|
3013
3060
|
"direction": "frameToParent",
|