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):

  1. Valid ?layout= in the URL → use for this visit (shareable deep links); persisted to localStorage
  2. localStorage key gameMoveLayout (migrated from gameMoveBetaLayout)
  3. 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

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

  1. Load game — open query get_game with metaGame, cbits, gameID.
  2. Instantiate rules — GameFactory from @abstractplay/gameslib builds the game object from stored state.
  3. Render board — game render() produces JSON; @abstractplay/renderer render() produces SVG.
  4. Submit move — auth query (e.g. submit_move) via callAuthApi.
  5. 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.

Related