Design rules
- No shared TypeScript union of game keys.
GameKeyisstring. - No new Expo Router file per game. Engine games share
app/(tabs)/locker-room/games/[gameKey].tsx. - The playfield does not score, award Rep, or decide win/loss.
- The playfield does not render chrome, HUD, or safe-area wrappers.
- Session games do not include a game loop, remote game logic, or realtime. Physics stays outside engine core.
locker-singularityis the exception: progression is the idle ledger, not a UTC day slot.
Add a game on native
1
Create the folder
Add
lib/games/<slug>/ with index.ts, the playfield component, parse.ts, and styles/*.styles.ts.2
Register the definition
Call
registerGame({ key, parseConfig, parseScenario, Component, presentOutcome? }) from that index.ts. Side-effect import the folder from lib/games/index.ts.3
Keep the playfield thin
Accept
presentation: "modal" | "screen". Use makeStyles plus useTheme / useCommonStyles. Haptics go through hooks/use-haptics.ts only.4
Optional catalog copy
Add static title/art in
constants/games.constants.ts with routeKey equal to the registry key. Engine games also launch through resolveGame, so a GAME_ROUTES entry is optional.5
Test the registry
Colocate
bun test files. Keep the registry multi-game. Do not let a new import replace Pick’em or Trivia.Add the same key on the server
- Insert a
Gamerow whosekeymatches the native slug. - Ship
configJson,rewardJson, andminClientVersion. - Enable the game per team (
TeamGame). - If the game uses prompts (Pick’em / Trivia style), store them server-side. Never send the answer in
scenario.
X-Client-Version on every engine call. Raise minClientVersion when the binary cannot parse a new config shape. The catalog then returns playable: false with reason: UPDATE_REQUIRED instead of omitting the tile.
Expandability
A catalog key with no registry entry is Not in this build. A catalog row whose
minClientVersion is newer than the binary is Update required. Both are valid, visible states.
Content verticals (for example sport-themed dailies) should registerGame on the same engine. Do not start a second shell or a second session API.
What v1 is not
- Daily Spin and Guess the Player already write live rewards on
/api/games/*. They are not engine games yet. - Live arena (
/api/games/live/*) is a separate session model. - Game Center (
/api/events/*) is sports-event UX, not a mini-game playfield. - Pack opening is commerce, not the engine.
