Game router
The game-router skill (templates/crescent-game/.claude/skills/game-router/SKILL.md) is the first thing an agent reads for any request that makes a game or changes what kind of game it is. It does two things before any code is written: it classifies the request into a genre, and it picks the route that builds that genre best. Then the agent reads only the skill and doc that route names.
A route is one of four kinds:
| Route kind | Means |
|---|---|
module:<name> | The genre is a config object for a genre module: defineRaceGame, defineShooterGame, definePuzzleGame or defineKingdomGame. See Game modules. |
foundation:character | A game on the engine's character controller, cameras, bots and combat kit, copied from an example and changed. |
kit:turns | A turn-based board game on the turns kit (TurnRules, useOpponent, useTurnRoom). See Turns. |
scratch | Written in src/game/ with engine primitives: the 2D layer for flat games, EngineCanvas for 3D. |
Before routing, the skill reads GDD.md. If the game has one, its genre and rules hold. A change request keeps the current genre unless it names another one: "turn my race into a space game" is still racing; "add enemies that chase me" to a parkour game is parkour plus bots on the same route; "make it a card game" is a new route with the same title.
1. Classify
Players often name a well-known game as shorthand; the skill matches those names too. This table describes them by genre instead.
| Player says (any of) | Genre |
|---|---|
| race, racing, kart, drift, lap, circuit, car, F1, rally, highway, drive | racing |
| parkour, obby, platformer, jump over gaps, rooftops, lava floor, checkpoints, speedrun course, climb | parkour |
| arena, brawl, fight in a ring, knock off, sumo, dodgeball, sword duel (no guns) | arena |
| tag, chase, hide and seek, cops and robbers, catch me, zombies that chase, infected | tag |
| stealth, sneak, guards, steal, heist, escape the asylum, backrooms, monster hunts you, horror, flashlight | stealth |
| top-down, dungeon, survivors, horde, waves of enemies, twin-stick, bullet heaven | top-down |
| side-scroller, 2D-ish, a classic run-and-jump platformer, run right and jump, endless runner | side-view |
| shooter, gun, FPS, deathmatch, team deathmatch, capture the flag, king of the hill (with guns), gun game, paintball, snipers, aim, shoot the bots | shooter |
| block puzzle, drag blocks to clear lines, wood blocks on a grid, number merge, merge, match three, gems, pop the groups, tap to blast groups, water sort, ball sort, colour tubes, potions, pour | puzzle |
| chess, checkers, draughts, connect four, reversi, othello, tic-tac-toe, gomoku, dots and boxes, mancala, "play against the computer", a turn-based duel on a board | board |
| cards, deck, dice, poker, memory, trivia, quiz | cards / menu |
| kingdom, village I build and defend, a town builder with hero sorties, a survival city in the snow, a farm game with crops and orders, farm with a story, crops and raids, castle and army, samurai province, colony | kingdom |
| builder, city, idle, tycoon, tower defense, resources, upgrade timers (no story, no sorties) | strategy |
| darts, bowling, golf, basketball, flick, swipe to throw | sports minigame |
2. Route
What each genre maps to, where the agent starts, and what it reads next.
| Genre | Route | Start from | Then read |
|---|---|---|---|
| racing | module:racing: a defineRaceGame config | src/game/index.tsx as shipped (Sunset Sprint) | car-race-game, docs/racing-module.md |
| parkour | foundation:character | copy examples/rooftop-hop/index.tsx | character-game, docs/character-controller.md |
| arena | foundation:character | copy examples/lantern-tag/index.tsx, replace lanterns with the arena rule (knock-off, king of the hill) | character-game, docs/bots.md (health, knockback, swords: docs/combat.md) |
| tag | foundation:character | copy examples/lantern-tag/index.tsx | character-game, docs/bots.md |
| stealth / horror | foundation:character | copy examples/lantern-tag/index.tsx, corridors preset, dark theme, fog | character-game, docs/bots.md |
| top-down | foundation:character | copy examples/lantern-tag/index.tsx with the top camera and look: false | character-game |
| side-view | 2D platformer (flat, the default) or foundation:character (3D seen from the side) | copy examples/sky-runner/index.tsx (the platformer-2d skill), or examples/rooftop-hop/index.tsx with the side camera | character-game |
| shooter | module:shooter: a defineShooterGame config (modes ffa, tdm, gun-game, ctf, koth) | copy examples/flag-rush/index.tsx; for a rule no mode covers (waves, bomb defusal) copy examples/pulse-arena/index.tsx and use the combat kit directly | shooter-game, docs/shooter-module.md (weapons: docs/combat.md) |
| puzzle | module:puzzle: a definePuzzleGame config (2D, no 3D) | copy examples/moon-blocks/index.tsx (block) or examples/moonrise/index.tsx (merge, drawn tiles) | puzzle-game, docs/puzzle-module.md |
| board | kit:turns: the game as TurnRules, useOpponent, useTurnRoom, drawn on the 2D layer | chess: copy examples/moon-chess/index.tsx and change its look, rivals and names; another board game: keep that file's screens and flow, swap in your own TurnRules | crescent-game-change, docs/turns.md, docs/2d-layer.md |
| cards / menu | scratch on the 2D layer (GameCanvas2D), no 3D | a new src/game/index.tsx (examples/tap-pop/ shows the layer) | crescent-game-change, docs/2d-layer.md |
| kingdom | module:kingdom: a defineKingdomGame config | copy examples/oath-of-ashvale/index.tsx | kingdom-game, docs/kingdom-module.md, cutout-art for portraits and icons |
| strategy | scratch: tap UI, top camera if 3D | a new src/game/index.tsx | crescent-game-change and saves (buildings as upgrades, currencies, offline earnings) |
| sports minigame | scratch with EngineCanvas (3D), or the 2D layer for a flat game | a new src/game/index.tsx | crescent-game-change, touch-controls, docs/2d-layer.md |
The docs/... paths are the template's own agent docs, inside the game repo.
Camera, controls and bots per genre
The same table in the skill also fixes the defaults, so every game of a genre starts from choices that work on a phone.
| Genre | Camera | Controls | Bots |
|---|---|---|---|
| racing | the module's chase cam | steer + gas + brake (controls.layout) | AI cars (opponents) |
| parkour | third (offer side for a 2D feel) | stick + look + Jump | none, or 1 to 2 cowards as moving hazards |
| arena | third | stick + look + Jump (+ a for the action) | guard / hunter, 2 to 5, roster fill |
| tag | third | stick + look + Jump | hunter 2 to 4 (or the player hunts cowards) |
| stealth / horror | first (horror) or third | stick + look (+ Jump) | guard 2 to 3 on patrol routes or one hunter, hard hearing |
| top-down | top | stick + buttons (a, b) | hunters in waves (roster to spawn) |
| side-view | 2D camera follow / side | stick (x only) + Jump, look: false | walkers on the 2D bodies, or coward / guard |
| shooter | third (the module's over-the-shoulder rig) or first | the module's: stick + look + FIRE + Jump (+ SWAP) | the module's (seats, bots.difficulty) |
| puzzle | none (2D board) | one thumb: drag (block), swipe (merge), tap (match, sort) | none (the dev AUTO plays the solver) |
| board | none (2D board) | tap a piece then a square, or drag it | three rivals (easy, medium, hard) with personalities that talk through the backend's model; the search plays alone offline |
| cards / menu | none | taps and drags (onPointer) | TurnRules + useOpponent for a turn-based duel; otherwise an AI you write |
| kingdom | the module's 3/4 town camera (drag to pan) and top-down sortie rig | tap lots and buttons in the village; the floating <Joystick> on sorties | the module's squads and camps |
| strategy | top or none | taps | none |
| sports minigame | fixed camera | swipe / flick (GameCanvas2D swipes, or one manual gesture) | optional |
Online and saved by default
Every route gets the online default from the realtime-backend skill when a backend is available: a leaderboard (time or score), presence ("N playing now"), and rooms where the genre is versus or co-op (racing ghosts; tag, arena and shooter rooms with bot fill; the shooter module runs its own rooms; board games get a friend's room from a link through useTurnRoom and the talking opponent on /ai/turn). Single-player genres (parkour, puzzle, cards) get a leaderboard and presence only.
Every route that keeps anything between sessions keeps it with the saves skill: runners a shop and upgrades, survivors permanent upgrades, idle games offline earnings, RPGs XP and gear. See Backend.
What the router says is not possible yet
The skill's section 3 lists the limits and the closest thing to build instead. In short:
- Shooters: bomb defusal, escort and waves are not modes; build them on a copy of
ShooterGame.tsxor onpulse-arenaand call it a first version. Multiplayer is up to 8 per room, hosted by the oldest player's phone. - Hordes: waves of 8 bots or fewer.
- Puzzles: mechanics beyond block, merge, match and sort (screws, parking jam, hexa boards, word puzzles) get the closest pack.
- Board games: chess is built in (
chessRules); others need theirTurnRuleswritten. No turns across days and no notifications; a room keeps its game for 30 minutes after both players leave. - Kingdoms: no alliances, gacha heroes, PvP, shared world map or tower placement.
- Shared worlds: a Durable Object in the game's backend; without one, the world stays on the device.
Worked examples
These rows are from the skill.
| Request | Route | Start | Next read |
|---|---|---|---|
| "A night race through a neon city with 5 rivals" | module:racing | Sunset Sprint config | car-race-game |
| "A parkour game on rooftops, make the jumps hard" | foundation:character / parkour | rooftop-hop (course preset, jumpHeight 1.4, gaps near 3 m) | character-game |
| "Sneak through a dark maze, guards hear your steps, first person" | foundation:character / stealth | lantern-tag (corridors preset, first camera, 3 guards hard, loud footsteps) | character-game + docs/bots.md |
| "Capture the flag with my friends, neon, bots when nobody's on" | module:shooter | flag-rush (mode: 'ctf', neon theme, seats: 6) | shooter-game |
| "Tag with my friends, bots fill in when nobody's online" | foundation:character / tag | lantern-tag (rooms + createRoster fill, hunters) | character-game + realtime-backend |
| "A memory card game with a leaderboard" | scratch (Skia) | a new src/game/index.tsx | crescent-game-change + realtime-backend |
| "Chess I can play with my friends or against a cheeky computer" | kit:turns / board | moon-chess (rename the rivals, cheeky personas) | docs/turns.md + realtime-backend |
| "Connect four against the computer" | kit:turns / board | moon-chess's screens and flow, a 7 by 6 board, connect-four TurnRules | docs/turns.md |
Writing the route down
The agent puts the route on its own line in the commit message (Route: foundation:character / stealth) and keeps anything it tells the player about the game, not the route.
Adding a route
A new module or foundation is one row in the Route table (genre, route, what to copy, camera, controls, bots, docs), its trigger words in Classify, and its limit removed from section 3. See Writing a module.