Skip to main content

Project structure

Every Moonspell game is its own repo, and every repo starts as a copy of the game template, templates/crescent-game/. This page is a map of that folder: what each file is for, what you change to make a game, and what you rename when you copy it.

The tree​

templates/crescent-game/
package.json scripts and the pinned dependency set; "main": "./index"
package-lock.json
app.json Expo config: name, slug, orientation, iOS and Android ids, plugins
index.ts phone entry: registerRootComponent(App)
index.web.ts browser entry: bootWeb, then the same App
metro.config.js three -> its WebGPU build, R3F -> its web build, .glb as assets
babel.config.js babel-preset-expo + the TypeGPU plugin ('use gpu' -> WGSL)
tsconfig.json strict; @/* -> src/*; includes examples/
.gitignore node_modules, dist, .expo, public/canvaskit.wasm, ...
playtest.json a scripted run of the game with real touches
CLAUDE.md standing instructions for Claude Code
AGENTS.md the same for other coding agents (an exact copy)
.claude/
settings.json Claude Code permissions for the repo's checks
skills/ 24 skills, one folder each with a SKILL.md
realtime-backend/
scaffold/backend/ the game's Cloudflare Worker, copied to backend/ when it goes online
docs/ agent-facing references: engine-api.md, games-contract.md,
one file per module and engine piece, cloudflare.md
src/
App.tsx mounts the game, wires exit and close, shows "Play" after an exit
theme.ts colours, radii and spacing used by the HUD chrome
game/
index.tsx THE GAME: default-exports a GameDefinition (starter: Sunset Sprint)
engine/ the engine, this game's own copy
index.ts everything @/engine exports
render/ core/ input/ hud/ ui/ audio/ physics/ models/ gpu/ feel/
2d/ character/ level/ combat/ bots/ save/ net/ story/ turns/
paths/ zones/ debug/ web/
modules/ racing/ puzzle/ shooter/ kingdom/
shell.ts shellModule.ts shellModule.web.ts math.ts
examples/ eleven complete games, one index.tsx each, plus README.md
assets/
icon.png
audio/ Sunset Sprint's engine loops and music, Ashvale's sounds
sfx/ short effects (pop.wav, the puzzle module's sounds)
models/ .glb models (KayKit's CC0 adventurers, Ashvale's buildings)
sprites/ sprite sheets for the examples

Folders that appear when you run things, all ignored by git: node_modules/, dist/ (from npm run export:web), public/canvaskit.wasm (copied by npm run web and npm run export:web), .expo/, and ios/ and android/ if you run npm run ios or npm run android.

Every folder of src/engine/ has its own page; the map with one line per folder is the engine overview.

What you edit​

FileWhat you change
src/game/index.tsxThe game. Start from the starter, an example, or an empty file (Your first game). Split it into more files in src/game/ when it grows
assets/Sounds, models, images and fonts, loaded with require(). Keep the total small: players download every version
app.jsonexpo.name (the window and app name, "Sunset Sprint" in the template), expo.slug, expo.ios.bundleIdentifier and expo.android.package
src/theme.tsThe colours the HUD chrome (TopBar, FinishCard, RoundButton) uses
src/engine/net/config.tsGAME_BACKEND_URL once you deploy a backend (Backend), and GAME_ID (below)
GDD.mdThe game's design document. It is not in the template: you or your agent create it with the first change (GDD.md and playtest.json)
playtest.jsonThe scripted test. The template's drives Sunset Sprint, so rewrite it when your controls or labels differ

The examples can go once you have picked a starting point; nothing imports them. Deleting examples/ also removes them from npm run typecheck.

What you normally leave alone​

FileWhy
src/engine/It is a library that happens to live in your repo. Change it when your game needs something the engine lacks, or to fix a bug, and keep its exports working. A platform difference goes here, never in the game (Platform layer)
index.ts, index.web.ts, src/App.tsxThe entry chain. index.web.ts must keep loading CanvasKit before the game; keep "main": "./index" in package.json
metro.config.js, babel.config.jsThey make three the WebGPU build and compile TypeGPU shaders. Without them the engine does not build
Dependency versions in package.jsonThey are pinned to what the Moonspell app compiles in. See The game contract
"crescent" block in package.jsonMetadata for the Moonspell pipeline. Harmless outside it

Each game owns its copy of the engine. Inside the Moonspell app, engine files a game never changed are refreshed from the template on the game's next build. In your own repo nothing refreshes them: copy engine changes from a newer template yourself.

Placeholders to replace​

The Moonspell pipeline fills these in when it creates a game repo. When you copy the template yourself, replace them:

PlaceholderWhereReplace with
__GAME_SLUG__name in package.json, twice in package-lock.json, GAME_ID in src/engine/net/config.tsYour game's slug, such as orb-hunt
__GAME_TITLE__The first line of CLAUDE.md and AGENTS.mdYour game's title
__PREFIX__, __D1_DATABASE_ID__.claude/skills/realtime-backend/scaffold/backend/wrangler.jsoncNothing yet. The realtime-backend skill fills them in its copy in backend/ when you set up the backend

GAME_ID matters more than it looks: it names the game's on-device storage (saves, settings, local leaderboards). Two games with the same id on one phone, or on one web origin, share their saves (Saves).

Also change the ids in app.json (com.rofi.crescentmoon.game in the template) to your own before you build for a phone.

A quick way to start a new game from a clone of the repository:

cp -R moonspell/templates/crescent-game orb-hunt
cd orb-hunt
git init
npm install

Then replace the placeholders above and commit once, so every later change is a diff you can read.

Docs and skills for agents​

A game repo carries its own instructions, so a coding agent opened in it knows the engine without these docs:

WhereWhat
CLAUDE.mdWhat can be built and with which engine piece, the rules every game keeps, how to finish a task. Its section "Outside the Moonspell app" says which commands to use without the Moonspell CLI
AGENTS.mdThe same instructions for agents that look for that name. It is an exact copy of CLAUDE.md
.claude/skills/24 skills: game-router first, then one per genre, engine piece, art, audio, backend and the playtest
docs/Short references the skills point to for every field and range
examples/README.mdWhat each example shows and which route uses it

Some skills and some lines in CLAUDE.md assume the Moonspell pipeline (the crescent CLI, generated art, live push to the app). Build with AI and Skills say which, and what to do instead.