Game move
The game move page is the core gameplay UI.
Routes
| Route | Behaviour |
|---|---|
/move/:metaGame/:cbits/:gameID |
Primary play page; optional ?layout=classic|strip|card|narrative |
/move-beta/:metaGame/:cbits/:gameID |
Legacy preview URL → redirects to /move/... preserving ?layout= |
Layout resolution (see layoutPreference.js):
- Valid
?layout=in the URL → use for this visit (shareable deep links); persisted to localStorage localStoragekeygameMoveLayout(migrated fromgameMoveBetaLayout)- Site default: strip
Preferences are localStorage only (per browser/device). No account setting.
Layouts
| ID | Component | Summary |
|---|---|---|
classic |
GameMoveClassicLayout.js |
Original full-page layout |
strip |
GameMoveStripLayout.js |
Board hero, sticky dock, tabbed drawer (default) |
card |
GameMoveCardLayout.js |
Queue card for playing through your inbox |
narrative |
GameMoveNarrativeLayout.js |
Story column beside the board |
All four layouts are available to anonymous and logged-in users.
Key files
| File | Role |
|---|---|
GameMoveWrapper.js |
Route wrapper; /move-beta/ redirect |
GameMoveShell.js |
Unified shell: layout switch, picker modal, session load |
useGameMoveLayout.js |
layoutId + resolvedFrom from URL / localStorage / default |
layoutPreference.js |
Layout IDs, paths, localStorage read/write, hint helpers |
layoutTracking.js |
Fire-and-forget layout analytics emitter |
useGameMoveSession.js |
Game load, moves, chats, modals |
GameMove/Board.js |
SVG board via renderer |
GameMove/MoveEntry.js |
Move input UI |
GameMove/GameMoves.js |
Move history list |
GameMove/UserChats.js |
In-game chat |
Discoverability
- Layout picker — header trigger (
LayoutPickerTrigger) on all four layouts opens a modal (LayoutPickerModal) with descriptions for each layout (LayoutSwitcher). - First-visit hint — on strip when the user has no saved layout and no
?layout=URL, a dismissible notice (LayoutHint) offers “Change layout”. Dismissal is stored ingameMoveLayoutHintDismissed.
There is no permanent floating layout bar.
Analytics
layoutTracking.js emits:
| Event | When |
|---|---|
session_start |
After game load when layout is resolved (GameMoveShell) |
layout_switch |
User picks another layout in the switcher (LayoutSwitcher) |
Logged-in users call auth log_gamemove_layout_event. Anonymous users call the public query with a per-page sessionId and a 25 events / UTC day client cap. Server-side limits and storage are documented in Game Move layout analytics.
Data flow
- Load game — open query
get_gamewithmetaGame,cbits,gameID. - Instantiate rules —
GameFactoryfrom@abstractplay/gameslibbuilds the game object from stored state. - Render board — game
render()produces JSON;@abstractplay/rendererrender()produces SVG. - Submit move — auth query (e.g.
submit_move) viacallAuthApi. - Real-time updates — WebSocket messages refresh game state when opponent moves.
Backend semantics: Games and moves.
Move entry
MoveEntry handles click/tap input, legal move highlighting, and validation through gameslib before submission. Game-specific flags in gameinfo (e.g. pie, check, no-moves) affect UI behaviour — see Gameslib flags.
Exploration
Private and public move exploration (what-if analysis) lives in exploration.js. Users can branch from historical positions, comment on nodes, and publish exploration trees.
Settings and display
settings.js manages colour schemes, display variants, and renderer options. Session overrides persist across reloads via sessionDisplay.js.
Themes
Colour context from Zustand and user customizations feed into renderer via setRendererColourOpts and setGlyphMapOpt. See Customize & themes.
Lab integration
Games supported in the Lab can be opened from the game move page. See isLabSupportedGame and Lab.