@indiegems/gem-web-sdk 10.2.0 → 10.3.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.
@@ -2,7 +2,7 @@
2
2
  "schema_version": 2,
3
3
  "source": {
4
4
  "repo": "IndieGems/gem-web-sdk",
5
- "version": "10.2.0"
5
+ "version": "10.3.1"
6
6
  },
7
7
  "entries": [
8
8
  {
@@ -65,6 +65,10 @@
65
65
  "key": "vibration",
66
66
  "title": "Vibrating the device"
67
67
  },
68
+ {
69
+ "key": "controls",
70
+ "title": "Camera and look controls"
71
+ },
68
72
  {
69
73
  "key": "config",
70
74
  "title": "Your published config"
@@ -5385,6 +5389,572 @@
5385
5389
  "defaultValue": null,
5386
5390
  "guides": []
5387
5391
  },
5392
+ {
5393
+ "id": "GemLookSpeed",
5394
+ "name": "GemLookSpeed",
5395
+ "anchor": "gemlookspeed",
5396
+ "group": "controls",
5397
+ "signature": "interface GemLookSpeed",
5398
+ "documented": true,
5399
+ "summary": "A look speed per axis, in radians: per CSS px for a pointer, per second at\nfull tilt for a stick.",
5400
+ "deprecated": null,
5401
+ "params": [],
5402
+ "returns": null,
5403
+ "throws": null,
5404
+ "example": null,
5405
+ "defaultValue": null,
5406
+ "guides": []
5407
+ },
5408
+ {
5409
+ "id": "GemLookSpeed.yaw",
5410
+ "name": "yaw",
5411
+ "anchor": "gemlookspeed-yaw",
5412
+ "group": "controls",
5413
+ "signature": "readonly yaw: number",
5414
+ "documented": true,
5415
+ "summary": "Across: radians of yaw.",
5416
+ "deprecated": null,
5417
+ "params": [],
5418
+ "returns": null,
5419
+ "throws": null,
5420
+ "example": null,
5421
+ "defaultValue": null,
5422
+ "guides": []
5423
+ },
5424
+ {
5425
+ "id": "GemLookSpeed.pitch",
5426
+ "name": "pitch",
5427
+ "anchor": "gemlookspeed-pitch",
5428
+ "group": "controls",
5429
+ "signature": "readonly pitch: number",
5430
+ "documented": true,
5431
+ "summary": "Up/down: radians of pitch.",
5432
+ "deprecated": null,
5433
+ "params": [],
5434
+ "returns": null,
5435
+ "throws": null,
5436
+ "example": null,
5437
+ "defaultValue": null,
5438
+ "guides": []
5439
+ },
5440
+ {
5441
+ "id": "GemLookBase",
5442
+ "name": "GemLookBase",
5443
+ "anchor": "gemlookbase",
5444
+ "group": "controls",
5445
+ "signature": "interface GemLookBase",
5446
+ "documented": true,
5447
+ "summary": "The shape of `gem.controls.LOOK_BASE`: Roblox's base look speeds and the\nstick and touch shaping constants `gem.controls.look()` applies.",
5448
+ "deprecated": null,
5449
+ "params": [],
5450
+ "returns": null,
5451
+ "throws": null,
5452
+ "example": null,
5453
+ "defaultValue": null,
5454
+ "guides": []
5455
+ },
5456
+ {
5457
+ "id": "GemLookBase.touch",
5458
+ "name": "touch",
5459
+ "anchor": "gemlookbase-touch",
5460
+ "group": "controls",
5461
+ "signature": "readonly touch: GemLookSpeed",
5462
+ "documented": true,
5463
+ "summary": "Radians per CSS px, for touch and pen: 1° across, 0.66° up/down.",
5464
+ "deprecated": null,
5465
+ "params": [],
5466
+ "returns": null,
5467
+ "throws": null,
5468
+ "example": null,
5469
+ "defaultValue": null,
5470
+ "guides": []
5471
+ },
5472
+ {
5473
+ "id": "GemLookBase.mouse",
5474
+ "name": "mouse",
5475
+ "anchor": "gemlookbase-mouse",
5476
+ "group": "controls",
5477
+ "signature": "readonly mouse: GemLookSpeed",
5478
+ "documented": true,
5479
+ "summary": "Radians per CSS px, for a mouse: 0.5° across, 0.385° up/down.",
5480
+ "deprecated": null,
5481
+ "params": [],
5482
+ "returns": null,
5483
+ "throws": null,
5484
+ "example": null,
5485
+ "defaultValue": null,
5486
+ "guides": []
5487
+ },
5488
+ {
5489
+ "id": "GemLookBase.stick",
5490
+ "name": "stick",
5491
+ "anchor": "gemlookbase-stick",
5492
+ "group": "controls",
5493
+ "signature": "readonly stick: GemLookSpeed",
5494
+ "documented": true,
5495
+ "summary": "Radians per second at full tilt, for a gamepad stick: 240° across, 184.8° up/down.",
5496
+ "deprecated": null,
5497
+ "params": [],
5498
+ "returns": null,
5499
+ "throws": null,
5500
+ "example": null,
5501
+ "defaultValue": null,
5502
+ "guides": []
5503
+ },
5504
+ {
5505
+ "id": "GemLookBase.stickDeadzone",
5506
+ "name": "stickDeadzone",
5507
+ "anchor": "gemlookbase-stickdeadzone",
5508
+ "group": "controls",
5509
+ "signature": "readonly stickDeadzone: number",
5510
+ "documented": true,
5511
+ "summary": "A stick axis below this magnitude turns nothing: 0.1.",
5512
+ "deprecated": null,
5513
+ "params": [],
5514
+ "returns": null,
5515
+ "throws": null,
5516
+ "example": null,
5517
+ "defaultValue": null,
5518
+ "guides": []
5519
+ },
5520
+ {
5521
+ "id": "GemLookBase.stickCurve",
5522
+ "name": "stickCurve",
5523
+ "anchor": "gemlookbase-stickcurve",
5524
+ "group": "controls",
5525
+ "signature": "readonly stickCurve: number",
5526
+ "documented": true,
5527
+ "summary": "The stick curve's curvature `k` in `(e^(k·d) − 1) / (e^k − 1)`: 2.",
5528
+ "deprecated": null,
5529
+ "params": [],
5530
+ "returns": null,
5531
+ "throws": null,
5532
+ "example": null,
5533
+ "defaultValue": null,
5534
+ "guides": []
5535
+ },
5536
+ {
5537
+ "id": "GemLookBase.touchPitchMin",
5538
+ "name": "touchPitchMin",
5539
+ "anchor": "gemlookbase-touchpitchmin",
5540
+ "group": "controls",
5541
+ "signature": "readonly touchPitchMin: number",
5542
+ "documented": true,
5543
+ "summary": "The least fraction of the pitch speed a touch drag keeps straight up or down: 0.25.",
5544
+ "deprecated": null,
5545
+ "params": [],
5546
+ "returns": null,
5547
+ "throws": null,
5548
+ "example": null,
5549
+ "defaultValue": null,
5550
+ "guides": []
5551
+ },
5552
+ {
5553
+ "id": "GemLookOptions",
5554
+ "name": "GemLookOptions",
5555
+ "anchor": "gemlookoptions",
5556
+ "group": "controls",
5557
+ "signature": "interface GemLookOptions",
5558
+ "documented": true,
5559
+ "summary": "The game's own overrides for `gem.controls.look()` — what the player chose in\nYOUR settings screen. Each one wins over the Arcade's value; leave one out to\nfollow the Arcade.",
5560
+ "deprecated": null,
5561
+ "params": [],
5562
+ "returns": null,
5563
+ "throws": null,
5564
+ "example": null,
5565
+ "defaultValue": null,
5566
+ "guides": []
5567
+ },
5568
+ {
5569
+ "id": "GemLookOptions.sensitivity",
5570
+ "name": "sensitivity",
5571
+ "anchor": "gemlookoptions-sensitivity",
5572
+ "group": "controls",
5573
+ "signature": "readonly sensitivity?: number",
5574
+ "documented": true,
5575
+ "summary": "The player's own look speed for touch, mouse and pen, as a multiplier\n(`1` = the base speed). Wins over `gem.prefs.recommended.lookSensitivity`.",
5576
+ "deprecated": null,
5577
+ "params": [],
5578
+ "returns": null,
5579
+ "throws": null,
5580
+ "example": null,
5581
+ "defaultValue": null,
5582
+ "guides": []
5583
+ },
5584
+ {
5585
+ "id": "GemLookOptions.gamepadSensitivity",
5586
+ "name": "gamepadSensitivity",
5587
+ "anchor": "gemlookoptions-gamepadsensitivity",
5588
+ "group": "controls",
5589
+ "signature": "readonly gamepadSensitivity?: number",
5590
+ "documented": true,
5591
+ "summary": "The player's own look speed for a gamepad stick, as a multiplier. Wins\nover `gem.prefs.recommended.gamepadLookSensitivity`.",
5592
+ "deprecated": null,
5593
+ "params": [],
5594
+ "returns": null,
5595
+ "throws": null,
5596
+ "example": null,
5597
+ "defaultValue": null,
5598
+ "guides": []
5599
+ },
5600
+ {
5601
+ "id": "GemLookOptions.invertY",
5602
+ "name": "invertY",
5603
+ "anchor": "gemlookoptions-inverty",
5604
+ "group": "controls",
5605
+ "signature": "readonly invertY?: boolean",
5606
+ "documented": true,
5607
+ "summary": "The player's own inverted up/down look. Wins over\n`gem.prefs.recommended.invertLookY`.",
5608
+ "deprecated": null,
5609
+ "params": [],
5610
+ "returns": null,
5611
+ "throws": null,
5612
+ "example": null,
5613
+ "defaultValue": null,
5614
+ "guides": []
5615
+ },
5616
+ {
5617
+ "id": "GemLookDelta",
5618
+ "name": "GemLookDelta",
5619
+ "anchor": "gemlookdelta",
5620
+ "group": "controls",
5621
+ "signature": "interface GemLookDelta",
5622
+ "documented": true,
5623
+ "summary": "A turn to apply to your camera, in radians to ADD: `yaw` positive turns\nright (clockwise seen from above), `pitch` positive looks up.",
5624
+ "deprecated": null,
5625
+ "params": [],
5626
+ "returns": null,
5627
+ "throws": null,
5628
+ "example": null,
5629
+ "defaultValue": null,
5630
+ "guides": []
5631
+ },
5632
+ {
5633
+ "id": "GemLookDelta.yaw",
5634
+ "name": "yaw",
5635
+ "anchor": "gemlookdelta-yaw",
5636
+ "group": "controls",
5637
+ "signature": "readonly yaw: number",
5638
+ "documented": true,
5639
+ "summary": "Radians to add to the camera's yaw; positive turns right.",
5640
+ "deprecated": null,
5641
+ "params": [],
5642
+ "returns": null,
5643
+ "throws": null,
5644
+ "example": null,
5645
+ "defaultValue": null,
5646
+ "guides": []
5647
+ },
5648
+ {
5649
+ "id": "GemLookDelta.pitch",
5650
+ "name": "pitch",
5651
+ "anchor": "gemlookdelta-pitch",
5652
+ "group": "controls",
5653
+ "signature": "readonly pitch: number",
5654
+ "documented": true,
5655
+ "summary": "Radians to add to the camera's pitch; positive looks up.",
5656
+ "deprecated": null,
5657
+ "params": [],
5658
+ "returns": null,
5659
+ "throws": null,
5660
+ "example": null,
5661
+ "defaultValue": null,
5662
+ "guides": []
5663
+ },
5664
+ {
5665
+ "id": "GemLook",
5666
+ "name": "GemLook",
5667
+ "anchor": "gemlook",
5668
+ "group": "controls",
5669
+ "signature": "interface GemLook",
5670
+ "documented": true,
5671
+ "summary": "The look helper `gem.controls.look()` returns. Pure math: it listens to\nnothing and moves no camera — feed it the deltas your input code already\nhas and add what it returns to your camera's yaw and pitch, then clamp the\npitch as you always do.",
5672
+ "deprecated": null,
5673
+ "params": [],
5674
+ "returns": null,
5675
+ "throws": null,
5676
+ "example": null,
5677
+ "defaultValue": null,
5678
+ "guides": []
5679
+ },
5680
+ {
5681
+ "id": "GemLook.fromPointer",
5682
+ "name": "fromPointer",
5683
+ "anchor": "gemlook-frompointer",
5684
+ "group": "controls",
5685
+ "signature": "fromPointer(dx: number, dy: number, pointerType: string, pitch?: number): GemLookDelta",
5686
+ "documented": true,
5687
+ "summary": "A pointer move — a touch drag, a mouse move (under pointer lock,\n`movementX` / `movementY`) or a pen — turned into a look turn.",
5688
+ "deprecated": null,
5689
+ "params": [
5690
+ {
5691
+ "name": "dx",
5692
+ "type": "number",
5693
+ "optional": false,
5694
+ "summary": "The move across, in CSS px, right positive."
5695
+ },
5696
+ {
5697
+ "name": "dy",
5698
+ "type": "number",
5699
+ "optional": false,
5700
+ "summary": "The move down the screen, in CSS px, DOWN positive (as\n `PointerEvent` reports it). Dragging up looks up."
5701
+ },
5702
+ {
5703
+ "name": "pointerType",
5704
+ "type": "string",
5705
+ "optional": false,
5706
+ "summary": "The event's `pointerType`: `'touch'` and `'pen'` take\n the touch speeds, anything else the mouse speeds."
5707
+ },
5708
+ {
5709
+ "name": "pitch",
5710
+ "type": "number",
5711
+ "optional": true,
5712
+ "summary": "The camera's current pitch in radians (0 = the horizon,\n positive = looking up), for the touch slowdown near straight up or\n down. Leave it out to skip the slowdown."
5713
+ }
5714
+ ],
5715
+ "returns": null,
5716
+ "throws": null,
5717
+ "example": null,
5718
+ "defaultValue": null,
5719
+ "guides": []
5720
+ },
5721
+ {
5722
+ "id": "GemLook.fromStick",
5723
+ "name": "fromStick",
5724
+ "anchor": "gemlook-fromstick",
5725
+ "group": "controls",
5726
+ "signature": "fromStick(x: number, y: number, dt: number): GemLookDelta",
5727
+ "documented": true,
5728
+ "summary": "A right stick turned into a look turn over one frame.",
5729
+ "deprecated": null,
5730
+ "params": [
5731
+ {
5732
+ "name": "x",
5733
+ "type": "number",
5734
+ "optional": false,
5735
+ "summary": "The stick's horizontal axis as the Gamepad API reports it,\n −1..1, right positive."
5736
+ },
5737
+ {
5738
+ "name": "y",
5739
+ "type": "number",
5740
+ "optional": false,
5741
+ "summary": "The stick's vertical axis as the Gamepad API reports it, −1..1,\n DOWN positive. Pushing up looks up."
5742
+ },
5743
+ {
5744
+ "name": "dt",
5745
+ "type": "number",
5746
+ "optional": false,
5747
+ "summary": "The frame's duration in seconds."
5748
+ }
5749
+ ],
5750
+ "returns": null,
5751
+ "throws": null,
5752
+ "example": null,
5753
+ "defaultValue": null,
5754
+ "guides": []
5755
+ },
5756
+ {
5757
+ "id": "GemLook.set",
5758
+ "name": "set",
5759
+ "anchor": "gemlook-set",
5760
+ "group": "controls",
5761
+ "signature": "set(options: GemLookOptions): void",
5762
+ "documented": true,
5763
+ "summary": "Change your game's overrides — call it when the player changes a setting\nin your settings screen. Each key you pass replaces that override; a key\npassed as `undefined` removes it, so that input follows the Arcade again;\na key you leave out is unchanged.",
5764
+ "deprecated": null,
5765
+ "params": [
5766
+ {
5767
+ "name": "options",
5768
+ "type": "GemLookOptions",
5769
+ "optional": false,
5770
+ "summary": null
5771
+ }
5772
+ ],
5773
+ "returns": null,
5774
+ "throws": "TypeError when a sensitivity is not a finite number above 0, or\n `invertY` is not a boolean.",
5775
+ "example": null,
5776
+ "defaultValue": null,
5777
+ "guides": []
5778
+ },
5779
+ {
5780
+ "id": "ControlsApi",
5781
+ "name": "ControlsApi",
5782
+ "anchor": "controlsapi",
5783
+ "group": "controls",
5784
+ "signature": "interface ControlsApi",
5785
+ "documented": true,
5786
+ "summary": "`gem.controls` — the player's camera and controls settings: tell the Arcade\nwhich ones your game leaves to the player, and turn look input into a camera\nturn at the player's sensitivity.",
5787
+ "deprecated": null,
5788
+ "params": [],
5789
+ "returns": null,
5790
+ "throws": null,
5791
+ "example": null,
5792
+ "defaultValue": null,
5793
+ "guides": [
5794
+ {
5795
+ "slug": "what-a-game-must-do",
5796
+ "anchor": null
5797
+ }
5798
+ ]
5799
+ },
5800
+ {
5801
+ "id": "ControlsApi.declare",
5802
+ "name": "declare",
5803
+ "anchor": "controlsapi-declare",
5804
+ "group": "controls",
5805
+ "signature": "declare(uses: GemControlsDeclaration): boolean",
5806
+ "documented": true,
5807
+ "summary": "Tell the Arcade which of the player's camera and controls settings your\ngame uses, and for each one who decides it: `'player'` — you apply the\nArcade's value from `gem.prefs.recommended` (or the player's own choice\nin your settings, which wins) — or `'game'` — you decide it yourself, and\nthe Arcade's Settings shows that row as \"Set by this game\". Leave out a\nsetting your game does not use.\n\n```js\ngem.controls.declare({\n lookSensitivity: 'player',\n gamepadLookSensitivity: 'player',\n invertLookY: 'player',\n touchMovement: 'game', // this game always uses a fixed stick\n});\n```\n\n**It is screen state, not a toggle.** Each call is the whole answer and\nreplaces the last. The SDK holds it and sends it again after every\nreconnect, so call it once at boot, and again only when the answer\nchanges. Any other key or value is dropped.",
5808
+ "deprecated": null,
5809
+ "params": [
5810
+ {
5811
+ "name": "uses",
5812
+ "type": "GemControlsDeclaration",
5813
+ "optional": false,
5814
+ "summary": null
5815
+ }
5816
+ ],
5817
+ "returns": "`true` when the Arcade was told now; `false` before the bridge is\n up (the declaration is held and sent when it connects), outside the\n Arcade, and under an embedder that does not show these settings. Never\n throws.",
5818
+ "throws": null,
5819
+ "example": null,
5820
+ "defaultValue": null,
5821
+ "guides": []
5822
+ },
5823
+ {
5824
+ "id": "ControlsApi.look",
5825
+ "name": "look",
5826
+ "anchor": "controlsapi-look",
5827
+ "group": "controls",
5828
+ "signature": "look(options?: GemLookOptions): GemLook",
5829
+ "documented": true,
5830
+ "summary": "Make a look helper: Roblox's camera-input math at the player's look\nsensitivity and invert. Make one and keep it.\n\n```js\nconst look = gem.controls.look();\n// A mouse under pointer lock; for touch, pass the change in clientX/clientY.\ncanvas.addEventListener('pointermove', (e) => {\n if (document.pointerLockElement !== canvas) return;\n const t = look.fromPointer(e.movementX, e.movementY, e.pointerType, camera.pitch);\n camera.yaw += t.yaw;\n camera.pitch = clamp(camera.pitch + t.pitch, -1.4, 1.4);\n});\n```\n\nThe sensitivity and invert are read **live** on every call: the Arcade's\n`gem.prefs.recommended` values, unless `options` (or a later\n[GemLook.set](api-reference-game.md#gemlook-set)) gives your game's own, which win.",
5831
+ "deprecated": null,
5832
+ "params": [
5833
+ {
5834
+ "name": "options",
5835
+ "type": "GemLookOptions",
5836
+ "optional": true,
5837
+ "summary": null
5838
+ }
5839
+ ],
5840
+ "returns": null,
5841
+ "throws": "TypeError when an option is malformed, as [GemLook.set](api-reference-game.md#gemlook-set).",
5842
+ "example": null,
5843
+ "defaultValue": null,
5844
+ "guides": []
5845
+ },
5846
+ {
5847
+ "id": "ControlsApi.LOOK_BASE",
5848
+ "name": "LOOK_BASE",
5849
+ "anchor": "controlsapi-look_base",
5850
+ "group": "controls",
5851
+ "signature": "readonly LOOK_BASE: GemLookBase",
5852
+ "documented": true,
5853
+ "summary": "The base speeds `look` applies at 1×, in radians. Frozen.",
5854
+ "deprecated": null,
5855
+ "params": [],
5856
+ "returns": null,
5857
+ "throws": null,
5858
+ "example": null,
5859
+ "defaultValue": null,
5860
+ "guides": []
5861
+ },
5862
+ {
5863
+ "id": "GemControlChoice",
5864
+ "name": "GemControlChoice",
5865
+ "anchor": "gemcontrolchoice",
5866
+ "group": "controls",
5867
+ "signature": "type GemControlChoice = \"player\" | \"game\"",
5868
+ "documented": true,
5869
+ "summary": "Who decides one camera or controls setting: `'player'` — your game applies\nthe Arcade's value, or the player's own in-game choice, which wins — or\n`'game'` — your game decides it itself, and the Arcade's Settings shows the\nrow as \"Set by this game\".",
5870
+ "deprecated": null,
5871
+ "params": [],
5872
+ "returns": null,
5873
+ "throws": null,
5874
+ "example": null,
5875
+ "defaultValue": null,
5876
+ "guides": []
5877
+ },
5878
+ {
5879
+ "id": "GemControlsDeclaration",
5880
+ "name": "GemControlsDeclaration",
5881
+ "anchor": "gemcontrolsdeclaration",
5882
+ "group": "controls",
5883
+ "signature": "interface GemControlsDeclaration",
5884
+ "documented": true,
5885
+ "summary": "What `gem.controls.declare` takes: for each of the player's camera and\ncontrols settings your game uses, who decides it. Leave a setting out when\nyour game does not use it at all — the Arcade then says \"This game doesn't\nuse this\" beside that row.",
5886
+ "deprecated": null,
5887
+ "params": [],
5888
+ "returns": null,
5889
+ "throws": null,
5890
+ "example": null,
5891
+ "defaultValue": null,
5892
+ "guides": []
5893
+ },
5894
+ {
5895
+ "id": "GemControlsDeclaration.lookSensitivity",
5896
+ "name": "lookSensitivity",
5897
+ "anchor": "gemcontrolsdeclaration-looksensitivity",
5898
+ "group": "controls",
5899
+ "signature": "readonly lookSensitivity?: GemControlChoice",
5900
+ "documented": true,
5901
+ "summary": "Look speed for touch, mouse and pen — `gem.prefs.recommended.lookSensitivity`.",
5902
+ "deprecated": null,
5903
+ "params": [],
5904
+ "returns": null,
5905
+ "throws": null,
5906
+ "example": null,
5907
+ "defaultValue": null,
5908
+ "guides": []
5909
+ },
5910
+ {
5911
+ "id": "GemControlsDeclaration.gamepadLookSensitivity",
5912
+ "name": "gamepadLookSensitivity",
5913
+ "anchor": "gemcontrolsdeclaration-gamepadlooksensitivity",
5914
+ "group": "controls",
5915
+ "signature": "readonly gamepadLookSensitivity?: GemControlChoice",
5916
+ "documented": true,
5917
+ "summary": "Look speed for a gamepad stick — `gem.prefs.recommended.gamepadLookSensitivity`.",
5918
+ "deprecated": null,
5919
+ "params": [],
5920
+ "returns": null,
5921
+ "throws": null,
5922
+ "example": null,
5923
+ "defaultValue": null,
5924
+ "guides": []
5925
+ },
5926
+ {
5927
+ "id": "GemControlsDeclaration.invertLookY",
5928
+ "name": "invertLookY",
5929
+ "anchor": "gemcontrolsdeclaration-invertlooky",
5930
+ "group": "controls",
5931
+ "signature": "readonly invertLookY?: GemControlChoice",
5932
+ "documented": true,
5933
+ "summary": "Inverted up/down look — `gem.prefs.recommended.invertLookY`.",
5934
+ "deprecated": null,
5935
+ "params": [],
5936
+ "returns": null,
5937
+ "throws": null,
5938
+ "example": null,
5939
+ "defaultValue": null,
5940
+ "guides": []
5941
+ },
5942
+ {
5943
+ "id": "GemControlsDeclaration.touchMovement",
5944
+ "name": "touchMovement",
5945
+ "anchor": "gemcontrolsdeclaration-touchmovement",
5946
+ "group": "controls",
5947
+ "signature": "readonly touchMovement?: GemControlChoice",
5948
+ "documented": true,
5949
+ "summary": "The touch movement thumbstick, floating or fixed — `gem.prefs.recommended.touchMovement`.",
5950
+ "deprecated": null,
5951
+ "params": [],
5952
+ "returns": null,
5953
+ "throws": null,
5954
+ "example": null,
5955
+ "defaultValue": null,
5956
+ "guides": []
5957
+ },
5388
5958
  {
5389
5959
  "id": "DEVICE_SETTINGS_MAX_BYTES",
5390
5960
  "name": "DEVICE_SETTINGS_MAX_BYTES",
@@ -5582,7 +6152,7 @@
5582
6152
  "group": "platform",
5583
6153
  "signature": "interface RewardCue",
5584
6154
  "documented": true,
5585
- "summary": "A platform-currency reward on its way to the arcade's wallet — what\n`gem.cueReward` takes.",
6155
+ "summary": "A platform-currency reward on its way to the arcade — in the Gem Arcade, a\nflight into the Gem button at the top-left of your frame — what\n`gem.cueReward` takes.",
5586
6156
  "deprecated": null,
5587
6157
  "params": [],
5588
6158
  "returns": null,
@@ -5598,7 +6168,7 @@
5598
6168
  "group": "platform",
5599
6169
  "signature": "currencySlug: string",
5600
6170
  "documented": true,
5601
- "summary": "The platform currency's slug, as `gem.platform.currencies.get()` lists it —\n`GEMS` or `ARCADE_TICKETS`. It decides which total in the arcade's wallet\nthe payout flies into.",
6171
+ "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.",
5602
6172
  "deprecated": null,
5603
6173
  "params": [],
5604
6174
  "returns": null,
@@ -5630,7 +6200,7 @@
5630
6200
  "group": "platform",
5631
6201
  "signature": "origin?: { x: number; y: number }",
5632
6202
  "documented": true,
5633
- "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 arcade animates at its wallet\nalone.",
6203
+ "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.",
5634
6204
  "deprecated": null,
5635
6205
  "params": [],
5636
6206
  "returns": null,
@@ -5914,7 +6484,7 @@
5914
6484
  "group": "frame",
5915
6485
  "signature": "cueReward(cue: RewardCue): boolean",
5916
6486
  "documented": true,
5917
- "summary": "Tell the arcade a platform-currency reward is on its way, so its wallet can\nshow it landing — a pending state now and, once the platform confirms the\ngrant, the currency flying from `origin` into the wallet.\n\nPrefer `gem.cueReward`, which says what the arcade does with it. This one\nsends only while connected, and only to an arcade that draws a wallet.",
6487
+ "summary": "Tell the arcade a platform-currency reward is on its way, so it can show it\nlanding — in the Gem Arcade, the currency flying from `origin` into the Gem\nbutton, the total moving once the platform confirms the grant.\n\nPrefer `gem.cueReward`, which says what the arcade does with it. This one\nsends only while connected, and only to an arcade that draws a wallet.",
5918
6488
  "deprecated": null,
5919
6489
  "params": [
5920
6490
  {
@@ -5982,6 +6552,29 @@
5982
6552
  "defaultValue": null,
5983
6553
  "guides": []
5984
6554
  },
6555
+ {
6556
+ "id": "GemFrame.declareControls",
6557
+ "name": "declareControls",
6558
+ "anchor": "gemframe-declarecontrols",
6559
+ "group": "frame",
6560
+ "signature": "declareControls(uses: GemControlsDeclaration): boolean",
6561
+ "documented": true,
6562
+ "summary": "Tell the arcade which of the player's camera and controls settings your\ngame leaves to the player and which it decides itself — the whole answer\neach time, the latest one winning.\n\nPrefer `gem.controls.declare`, which holds the declaration across a\nreconnect. This one sends only while connected, and only to an arcade\nthat shows these settings.",
6563
+ "deprecated": null,
6564
+ "params": [
6565
+ {
6566
+ "name": "uses",
6567
+ "type": "GemControlsDeclaration",
6568
+ "optional": false,
6569
+ "summary": null
6570
+ }
6571
+ ],
6572
+ "returns": "whether the message left the frame — `false` before the bridge is\n up, for an arcade that does not show these settings, and past this\n frame's own limit.",
6573
+ "throws": null,
6574
+ "example": null,
6575
+ "defaultValue": null,
6576
+ "guides": []
6577
+ },
5985
6578
  {
5986
6579
  "id": "GemFrame.setMenu",
5987
6580
  "name": "setMenu",
@@ -8109,7 +8702,7 @@
8109
8702
  "group": "player",
8110
8703
  "signature": "readonly recommended: GemRecommendedSettings | null",
8111
8704
  "documented": true,
8112
- "summary": "The player's Arcade-wide defaults for this device — a volume, battery\nsaver, a keyboard layout, the gamepad's confirm button and vibration — or\n`null` when the Arcade did not send them.\n\n**Recommendations only; the player's own choice in your game wins.** Start\na setting from here while the player has made no choice of their own for\nit, and never overwrite one they made because this changed:\n\n```js\nconst saved = gem.deviceSettings.current ?? {};\nconst volume = saved.volume ?? gem.prefs?.recommended?.volume ?? 100;\n```\n\nUnlike `muted` and `reducedMotion`, nothing here is applied for you, and\nnothing obliges you to use it. See the guide's \"Game settings\" section.",
8705
+ "summary": "The player's Arcade-wide defaults for this device — a volume, battery\nsaver, a keyboard layout, the gamepad's confirm button, vibration, and the\ncamera and controls settings (look sensitivity, gamepad look sensitivity,\ninvert look, touch movement) — or `null` when the Arcade did not send them.\n\n**Recommendations only; the player's own choice in your game wins.** Start\na setting from here while the player has made no choice of their own for\nit, and never overwrite one they made because this changed:\n\n```js\nconst saved = gem.deviceSettings.current ?? {};\nconst volume = saved.volume ?? gem.prefs?.recommended?.volume ?? 100;\n```\n\nUnlike `muted` and `reducedMotion`, nothing here is applied for you, and\nnothing obliges you to use it. See the guide's \"Game settings\" section.",
8113
8706
  "deprecated": null,
8114
8707
  "params": [],
8115
8708
  "returns": null,
@@ -8219,6 +8812,70 @@
8219
8812
  "defaultValue": null,
8220
8813
  "guides": []
8221
8814
  },
8815
+ {
8816
+ "id": "GemRecommendedSettings.lookSensitivity",
8817
+ "name": "lookSensitivity",
8818
+ "anchor": "gemrecommendedsettings-looksensitivity",
8819
+ "group": "player",
8820
+ "signature": "readonly lookSensitivity: number",
8821
+ "documented": true,
8822
+ "summary": "The player's look speed for touch, mouse and pen, as a percentage of the\nbase speeds: `100` is 1×, from `20` (0.2×) to `400` (4×). `100` when the\nArcade did not say. `gem.controls.look()` applies it for you.",
8823
+ "deprecated": null,
8824
+ "params": [],
8825
+ "returns": null,
8826
+ "throws": null,
8827
+ "example": null,
8828
+ "defaultValue": null,
8829
+ "guides": []
8830
+ },
8831
+ {
8832
+ "id": "GemRecommendedSettings.gamepadLookSensitivity",
8833
+ "name": "gamepadLookSensitivity",
8834
+ "anchor": "gemrecommendedsettings-gamepadlooksensitivity",
8835
+ "group": "player",
8836
+ "signature": "readonly gamepadLookSensitivity: number",
8837
+ "documented": true,
8838
+ "summary": "The player's look speed for a gamepad stick, as a percentage: `100` is 1×,\nfrom `20` to `400`. `100` when the Arcade did not say.\n`gem.controls.look()` applies it for you.",
8839
+ "deprecated": null,
8840
+ "params": [],
8841
+ "returns": null,
8842
+ "throws": null,
8843
+ "example": null,
8844
+ "defaultValue": null,
8845
+ "guides": []
8846
+ },
8847
+ {
8848
+ "id": "GemRecommendedSettings.invertLookY",
8849
+ "name": "invertLookY",
8850
+ "anchor": "gemrecommendedsettings-invertlooky",
8851
+ "group": "player",
8852
+ "signature": "readonly invertLookY: boolean",
8853
+ "documented": true,
8854
+ "summary": "Whether the player wants up/down look inverted: pushing up or dragging up\nlooks down. Flips pitch only, never yaw. `false` when the Arcade did not\nsay. `gem.controls.look()` applies it for you.",
8855
+ "deprecated": null,
8856
+ "params": [],
8857
+ "returns": null,
8858
+ "throws": null,
8859
+ "example": null,
8860
+ "defaultValue": null,
8861
+ "guides": []
8862
+ },
8863
+ {
8864
+ "id": "GemRecommendedSettings.touchMovement",
8865
+ "name": "touchMovement",
8866
+ "anchor": "gemrecommendedsettings-touchmovement",
8867
+ "group": "player",
8868
+ "signature": "readonly touchMovement: \"floating\" | \"fixed\"",
8869
+ "documented": true,
8870
+ "summary": "On a touch screen, the movement thumbstick the player wants: `'floating'`\nappears where the thumb lands, `'fixed'` stays in one place. `'floating'`\nwhen the Arcade did not say. Your game draws the stick.",
8871
+ "deprecated": null,
8872
+ "params": [],
8873
+ "returns": null,
8874
+ "throws": null,
8875
+ "example": null,
8876
+ "defaultValue": null,
8877
+ "guides": []
8878
+ },
8222
8879
  {
8223
8880
  "id": "GemCohort",
8224
8881
  "name": "GemCohort",
@@ -8412,7 +9069,7 @@
8412
9069
  "group": "player",
8413
9070
  "signature": "readonly reserved: readonly GemReservedArea[]",
8414
9071
  "documented": true,
8415
- "summary": "Rectangles of your frame the arcade's own controls cover — its menu button\nin the top-right corner, and the wallets in the middle of the top row while they are shown (see\n`setWalletVisible`). Keep essential UI and touch targets out of them. Empty\nwhen the arcade covers nothing.\n\nA stylesheet reads the per-corner custom properties the SDK stamps from\nthese instead — `--gem-reserved-tl-height` and friends.",
9072
+ "summary": "Rectangles of your frame the arcade's own controls cover — in the Gem\nArcade, its Gem button in the top-left corner, and the frame-rate readout\nbeside it while the player shows it; an embedder that draws wallets over\nyour game adds theirs (see `setWalletVisible`). Keep essential UI and touch\ntargets out of them. Empty when the arcade covers nothing.\n\nA stylesheet reads the per-corner custom properties the SDK stamps from\nthese instead — `--gem-reserved-tl-height` and friends.",
8416
9073
  "deprecated": null,
8417
9074
  "params": [],
8418
9075
  "returns": null,
@@ -8524,7 +9181,7 @@
8524
9181
  "group": "platform",
8525
9182
  "signature": "readonly only?: readonly string[]",
8526
9183
  "documented": true,
8527
- "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 ignores it and\nshows every wallet while shown.",
9184
+ "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.",
8528
9185
  "deprecated": null,
8529
9186
  "params": [],
8530
9187
  "returns": null,
@@ -9099,6 +9756,22 @@
9099
9756
  }
9100
9757
  ]
9101
9758
  },
9759
+ {
9760
+ "id": "Gem.controls",
9761
+ "name": "controls",
9762
+ "anchor": "gem-controls",
9763
+ "group": "start",
9764
+ "signature": "readonly controls: ControlsApi",
9765
+ "documented": true,
9766
+ "summary": "The player's camera and controls settings — look sensitivity, gamepad look\nsensitivity, invert look and touch movement, which arrive in\n`gem.prefs.recommended`. Two things to do with them:\n\n```js\n// 1. Tell the Arcade which ones your game leaves to the player.\ngem.controls.declare({ lookSensitivity: 'player', invertLookY: 'player' });\n\n// 2. Turn look input into a camera turn at the player's sensitivity.\nconst look = gem.controls.look();\n// dx, dy: the pointer's move in CSS px since the last event.\nconst t = look.fromPointer(dx, dy, e.pointerType, camera.pitch);\ncamera.yaw += t.yaw;\ncamera.pitch += t.pitch;\n```\n\nSee the guide's \"Camera and look controls\" section.",
9767
+ "deprecated": null,
9768
+ "params": [],
9769
+ "returns": null,
9770
+ "throws": null,
9771
+ "example": null,
9772
+ "defaultValue": null,
9773
+ "guides": []
9774
+ },
9102
9775
  {
9103
9776
  "id": "Gem.analytics",
9104
9777
  "name": "analytics",
@@ -9384,7 +10057,7 @@
9384
10057
  "group": "start",
9385
10058
  "signature": "cueReward(cue: RewardCue): boolean",
9386
10059
  "documented": true,
9387
- "summary": "Tell the arcade a platform-currency reward is on its way, so its **wallet\nshows it landing**: a pending state right away and, once the platform\nconfirms the grant, the currency flying from `origin` into the wallet with\na bounce as the total moves.\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.",
10060
+ "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 at the top-left of your frame, 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.",
9388
10061
  "deprecated": null,
9389
10062
  "params": [
9390
10063
  {
@@ -9407,7 +10080,7 @@
9407
10080
  "group": "start",
9408
10081
  "signature": "setWalletVisible(visible: boolean, options?: WalletVisibleOptions): boolean",
9409
10082
  "documented": true,
9410
- "summary": "Show or hide the player's wallets — Gems, Tickets, the achievement score —\nthat an embedder draws over your game.\n\n**Shown unless you hide them.** Call nothing and the Gem Arcade shows\nevery wallet the whole time, during play too. A game that wants the top\nrow for gameplay hides them while it plays and shows them again on its\nmenus (the Gem Arcade honours this again since 2026-10-08, on a phone,\nwhere the wallets sit over your game; where they sit beside the frame it\nchanges nothing).\n\n```js\nlevel.onStart = () => gem.setWalletVisible(false);\nmenu.onOpen = () => gem.setWalletVisible(true);\n```\n\nThe Gem Arcade does NOT act on `only`: a shown wallet there is every\nwallet. Another embedder may honour it.\n\n**It is screen state, not a toggle.** Each call is the whole answer and\nreplaces the last. While hidden, the arcade still pops a wallet up for a\nmoment when something happens to it — a reward you cued, a spend, a\nlanding — and your state never cancels that. Shown wallets cover the\nmiddle of your frame's top row, each arriving as a rectangle in\n`gem.viewport.reserved`; hiding them gives that space back. A wallet the\narcade pops up for a moment floats over your game and moves nothing.\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.",
10083
+ "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.",
9411
10084
  "deprecated": null,
9412
10085
  "params": [
9413
10086
  {