diff --git a/MODULES.md b/MODULES.md
index 3c527c4d..ce956897 100644
--- a/MODULES.md
+++ b/MODULES.md
@@ -430,8 +430,11 @@ api.onInput((kind, code) => {}); // 'down'/'up' events; returns unsubscri
// pause the HOST's use of an input scope while your module drives:
// 'keys' — WASD camera fly + play-mode movement
// 'locomotion' — VR left-stick locomotion
+// 'sticks' — (1.19) BOTH VR sticks: left-stick move, right-stick snap/smooth turn + teleport
+// (a held thing reeled on Y and scaled on X, the way an Edit grab does)
api.claimInput('keys'); // ALWAYS release when your mode ends
api.releaseInput('keys');
+const sticksOk = api.claimInput('sticks') === true; // true = this core knows the scope (older: undefined)
// reading a keydown YOURSELF (a toolbox's own handler)? resolve the key the way the
// editor does — `event.key` when it is an ASCII letter/digit, the physical
@@ -693,6 +696,8 @@ api.game.addSetting?.({
onChange: (v) => setBoard(v)
});
setBoard(api.game.setting?.('board') ?? 'globe'); // the stored choice at load
+// (1.19) a CHOICE that decides which levels you see: `onLevels: true` also draws it as tabs
+// above the Levels page's grid (desktop + headset) — Untangle's Board [Globe] [2D board]
api.game.setSetting?.('board', '2d'); // your in-game button writes the same row
api.game.onSettingsChange?.((values) => console.log(values.board, values.sfx));
```
diff --git a/src/components/hud/GameShellMenu.svelte b/src/components/hud/GameShellMenu.svelte
index b4614ca5..609c53ac 100644
--- a/src/components/hud/GameShellMenu.svelte
+++ b/src/components/hud/GameShellMenu.svelte
@@ -21,6 +21,7 @@
shellMenuAvailable,
shellMenuItems,
shellSettingViews,
+ shellLevelTabs,
shellPageTitle,
shellGameName,
shellHelpLines,
@@ -43,6 +44,9 @@
const items = $derived(itemsFor($gameLevels));
const viewsFor = (/** @type {any[]} */ ..._deps) => shellSettingViews({ vr: false });
const settings = $derived(viewsFor($gameSettingValues, $gameSettingRows));
+ // 33 (G3): a game's level-picking choice (Untangle's Board) as tabs above the grid
+ const tabsFor = (/** @type {any[]} */ ..._deps) => shellLevelTabs();
+ const levelTabs = $derived(tabsFor($gameSettingValues, $gameSettingRows));
const vrViewsFor = (/** @type {any[]} */ ..._deps) => shellSettingViews({ vr: true }).filter((/** @type {any} */ r) => r.vrOnly);
const vrSettings = $derived(vrViewsFor($gameSettingValues));
const helpFor = (/** @type {any[]} */ ..._deps) => shellHelpLines({ vr: false });
@@ -150,6 +154,22 @@
{/each}
{:else if page === 'levels'}
+ {#each levelTabs as tab (tab.id)}
+
+ {tab.label}
+ {#each tab.options as option (option.value)}
+
+ {/each}
+
+ {/each}
{#each $gameLevels?.list ?? [] as level (level.id)}