# Engine overview

> The map of src/engine, what each folder and file does, how a game imports from the engine, and what belongs in src/game versus src/engine.

The engine is the folder `src/engine/` inside every game repo made from the template (`templates/crescent-game/`). It is plain TypeScript and React Native: a game imports what it needs from `@/engine` and composes it in `src/game/`. There is no npm package; each game carries its own copy of the engine.

This page is the map. Each folder has its own page with examples and reference tables.

## How a game imports from the engine

`@/` is a path alias for `src/` (set in the template's `tsconfig.json`), so `@/engine` is `src/engine/index.ts`. Almost everything comes from there:

```tsx
import React from 'react';
import { View } from 'react-native';
import { EngineCanvas, Environment, TopBar, type GameDefinition, type GameScreenProps } from '@/engine';

const Screen = ({ onExit }: GameScreenProps) => (
  <View style={{ flex: 1 }}>
    <EngineCanvas camera={{ position: [0, 3, 8] }}>
      <Environment preset="day" />
      <mesh position={[0, 1, 0]} castShadow>
        <boxGeometry args={[1, 1, 1]} />
        <meshStandardMaterial color="#E8ECF4" />
      </mesh>
    </EngineCanvas>
    <View style={{ position: 'absolute', left: 0, right: 0, top: 0 }} pointerEvents="box-none">
      <TopBar title="My game" status="Ready" onExit={onExit} />
    </View>
  </View>
);

const game: GameDefinition = {
  id: 'my-game',
  title: 'My game',
  description: 'A box in the sun.',
  Component: Screen,
};

export default game;
```

Three other entry points are imported by path, not from `@/engine`:

| Import | What it is | Page |
| --- | --- | --- |
| `@/engine/ui` | The game UI kit: `Icon`, `Counter`, `PressScale`, motion helpers, `SheetImage` | [HUD and UI](https://docs.moonspell.app/engine/hud-and-ui.md) |
| `@/engine/ui/fonts/<face>` | One bundled font face per module (`@/engine/ui/fonts/nunitoBlack`) | [HUD and UI](https://docs.moonspell.app/engine/hud-and-ui.md) |
| `@/engine/modules/<name>` | A whole genre from a config: `racing`, `shooter`, `puzzle`, `kingdom` | [Game modules](https://docs.moonspell.app/modules/overview.md) |

Fonts and modules stay out of `@/engine` on purpose: a game's bundle carries only the faces and modules it imports.

## The map of `src/engine`

### Top-level files

| File | What it does | Page |
| --- | --- | --- |
| `index.ts` | The public API: everything `@/engine` exports | this page |
| `math.ts` | `clamp`, `lerp`, `damp`, `angleDelta`, `TAU`, `formatTime`, `makeRng` | [Utilities](https://docs.moonspell.app/engine/utilities.md) |
| `shell.ts` | `exitToShell`, `onShellClosed`, `isShellActive`, `onShellActive`, `useShellActive`: the game's side of the app around it | [Platform layer](https://docs.moonspell.app/engine/platform-layer.md) |
| `shellModule.ts` | What the app gives the game on phones (an optional native module, absent in plain Expo) | [Platform layer](https://docs.moonspell.app/engine/platform-layer.md) |
| `shellModule.web.ts` | The same contract in a browser, over `postMessage` with the page that frames the game | [Platform layer](https://docs.moonspell.app/engine/platform-layer.md) |

### Folders

| Folder | What it does | Page |
| --- | --- | --- |
| `render/` | `EngineCanvas` (the 3D surface), the WebGPU renderer, `Environment` (sky, sun, fog), `PostFX` (bloom, grade), `glow`, `Water` | [Canvas and rendering](https://docs.moonspell.app/engine/canvas-and-rendering.md) |
| `core/` | `GameDefinition`, `GameScreenProps` and `EngineErrorBoundary` | [Canvas and rendering](https://docs.moonspell.app/engine/canvas-and-rendering.md) |
| `input/` | `TouchControls` (racing), `Joystick`, `CharacterControls`, input state objects, the web keyboard | [Input](https://docs.moonspell.app/engine/input.md) |
| `hud/` | `Gauge` (a Skia speedometer) and HUD chrome: `TopBar`, `RoundButton`, `FinishCard`, `Banner`, `DebugRow` | [HUD and UI](https://docs.moonspell.app/engine/hud-and-ui.md) |
| `ui/` | The game UI kit (`@/engine/ui`): SF Symbol icons, bundled fonts, rolling counters, press and pop motion | [HUD and UI](https://docs.moonspell.app/engine/hud-and-ui.md) |
| `audio/` | `AudioMixer` and `useAudioMixer` (buses, positional sound, ducking, music), `RaceAudio` | [Audio](https://docs.moonspell.app/engine/audio.md) |
| `physics/` | Rigid bodies on cannon-es, triggers, joints, rays, `Vehicle`, GPU `Debris` | [Physics](https://docs.moonspell.app/engine/physics.md) |
| `models/` | `Model` (bundled `.glb` with a fallback), `Scenery` (one model placed many times), `Billboard`, animation graph and IK | [Models and scenery](https://docs.moonspell.app/engine/models-and-scenery.md) |
| `gpu/` | TypeGPU on three's device: `Particles`, `Trail`, `Grass`, `LivelyGround`, `GpuStrip`, the root for your own compute | [GPU effects](https://docs.moonspell.app/engine/gpu-effects.md) |
| `feel/` | Camera shake, hit-stop, slow motion, flash, squash and stretch, tweens, `juice` presets | [Game feel](https://docs.moonspell.app/engine/game-feel.md) |
| `2d/` | `GameCanvas2D` and the 2D kit: stage units, pointer, loop, sprites, tile maps, platformer bodies, haptics, one-shot sounds | [The 2D layer](https://docs.moonspell.app/engine/2d.md) |
| `character/` | The character controller, cameras, `CharacterMesh`, ripples and flocks | [Character and cameras](https://docs.moonspell.app/engine/character-and-cameras.md) |
| `level/` | Levels of boxes, pieces (ramps, stairs, arches), grid maps, `LevelMeshes`, `Extruded`, `Lathed` | [Character and cameras](https://docs.moonspell.app/engine/character-and-cameras.md) |
| `combat/` | Health, weapons, hitscan, projectiles, aim assist, statuses, combat HUD | [Combat](https://docs.moonspell.app/engine/combat.md) |
| `bots/` | Nav grid, pathfinding, senses, steering, `BotSquad`, roster fill | [Bots](https://docs.moonspell.app/engine/bots.md) |
| `save/` | Versioned saves, progression, shop, settings, share card | [Saves](https://docs.moonspell.app/engine/saves.md) |
| `net/` | Leaderboards, presence, rooms, launch links, the game backend URL | [Net](https://docs.moonspell.app/engine/net.md) |
| `story/` | Dialogue with portraits, choices, objectives, chapters | [Story](https://docs.moonspell.app/engine/story.md) |
| `turns/` | `TurnRules`, chess, search, `useOpponent`, `useTurnRoom` | [Turns](https://docs.moonspell.app/engine/turns.md) |
| `paths/` | Curves in metres, followers, moving platforms, camera dollies, path meshes | [Utilities](https://docs.moonspell.app/engine/utilities.md) |
| `zones/` | Trigger zones without physics, and typed signals (an event bus) | [Utilities](https://docs.moonspell.app/engine/utilities.md) |
| `debug/` | The development readout: fps, frame time, draw calls, module lines | [Utilities](https://docs.moonspell.app/engine/utilities.md) |
| `web/` | The browser boot (`bootWeb`) and Skia's font fallback for CanvasKit | [Platform layer](https://docs.moonspell.app/engine/platform-layer.md) |
| `modules/` | Genre modules: `racing`, `shooter`, `puzzle`, `kingdom` | [Game modules](https://docs.moonspell.app/modules/overview.md) |

## What goes in `src/game` and what goes in `src/engine`

The entry chain is fixed: `index.ts` (phones) or `index.web.ts` (browser) registers `src/App.tsx`, and `App.tsx` renders the `Component` of the `GameDefinition` that `src/game/index.tsx` default-exports. Keep that contract.

Put in `src/game/`:

- Everything about this game: its rules, level data, palette, fonts, HUD screens, sounds list and the `GameDefinition`.
- Code that only this game needs, even if it is large.

Change `src/engine/` only when:

- The game needs something the engine does not have and it would be useful to any game (a new control scheme, a new effect). Add it as a new export and keep existing exports working.
- Something differs per platform. Platform differences live in the engine (`*.web.ts` files, `Platform.OS` checks), never in a game. See [Platform layer](https://docs.moonspell.app/engine/platform-layer.md).

Rules that keep a game working everywhere:

- Read per-frame values from mutable objects inside `useFrame` (input state, character state), not from React state. React state is for things that change a few times a second at most.
- Take input through the engine's controls or react-native-gesture-handler, so a keyboard and mouse work in a desktop browser too.
- Load every asset with `require()` and the engine's loaders. Do not build file paths or URLs by hand.
- Draw 3D through `EngineCanvas`. There is no WebGL path.

## Gotchas

- `src/engine/index.ts` re-exports whole folders with `export *`. Two folders exporting the same name would clash, so engine additions use distinct names.
- Inside the hosted Moonspell app, the template's engine files are refreshed in existing games when a new version runs, unless the game changed them. In your own repo nothing refreshes them: copy engine changes from the template yourself.
- Tests for the pure parts of the engine run with `npm test` (Node's test runner over `src/engine/**/*.test.ts`). Type errors do not stop Metro, so also run `npm run typecheck`.
