# Project structure

> What is in a Moonspell game repo, as an annotated tree of the game template, which files you edit, which you leave alone, the placeholders a copied template must replace, and where the docs and skills for coding agents live.

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

```text
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](https://docs.moonspell.app/engine/overview.md).

## What you edit

| File | What you change |
| --- | --- |
| `src/game/index.tsx` | The game. Start from the starter, an example, or an empty file ([Your first game](https://docs.moonspell.app/start/first-game.md)). 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.json` | `expo.name` (the window and app name, "Sunset Sprint" in the template), `expo.slug`, `expo.ios.bundleIdentifier` and `expo.android.package` |
| `src/theme.ts` | The colours the HUD chrome (`TopBar`, `FinishCard`, `RoundButton`) uses |
| `src/engine/net/config.ts` | `GAME_BACKEND_URL` once you deploy a backend ([Backend](https://docs.moonspell.app/backend/overview.md)), and `GAME_ID` (below) |
| `GDD.md` | The 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](https://docs.moonspell.app/ai/game-design-doc.md)) |
| `playtest.json` | The 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

| File | Why |
| --- | --- |
| `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](https://docs.moonspell.app/engine/platform-layer.md)) |
| `index.ts`, `index.web.ts`, `src/App.tsx` | The entry chain. `index.web.ts` must keep loading CanvasKit before the game; keep `"main": "./index"` in `package.json` |
| `metro.config.js`, `babel.config.js` | They make `three` the WebGPU build and compile TypeGPU shaders. Without them the engine does not build |
| Dependency versions in `package.json` | They are pinned to what the Moonspell app compiles in. See [The game contract](https://docs.moonspell.app/start/game-contract.md#dependencies-and-native-code) |
| `"crescent"` block in `package.json` | Metadata 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:

| Placeholder | Where | Replace with |
| --- | --- | --- |
| `__GAME_SLUG__` | `name` in `package.json`, twice in `package-lock.json`, `GAME_ID` in `src/engine/net/config.ts` | Your game's slug, such as `orb-hunt` |
| `__GAME_TITLE__` | The first line of `CLAUDE.md` and `AGENTS.md` | Your game's title |
| `__PREFIX__`, `__D1_DATABASE_ID__` | `.claude/skills/realtime-backend/scaffold/backend/wrangler.jsonc` | Nothing 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](https://docs.moonspell.app/engine/saves.md)).

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:

```bash
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:

| Where | What |
| --- | --- |
| `CLAUDE.md` | What 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.md` | The 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.md` | What 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](https://docs.moonspell.app/ai/overview.md) and [Skills](https://docs.moonspell.app/ai/skills.md) say which, and what to do instead.
