# Quickstart

> Clone the repository, install the game template, run the starter game Sunset Sprint in a browser with npm run web, make a static web build, run an example, and find the steps for iOS and Android.

This page gets the starter game, **Sunset Sprint**, running in your browser. It takes one clone, one install and one command. Then it shows how to make a static web build, swap in an example game, and where to go for phones.

Everything here is plain Expo. You do not need the Moonspell app or any Moonspell account. This is the "engine only" path; the other one is below ([What is open and what is private](https://docs.moonspell.app/start/open-source.md#two-ways-to-build-a-game)).

## Prerequisites

- **Node 24 and npm.** Tested with Node 24.18.0 and npm 11.16.0.
- **Git.**
- **A browser with WebGPU.** Tested in Google Chrome 157 on macOS. The engine asks players for "the latest Chrome, Edge or Safari"; those other browsers, Firefox, Windows and Linux have not been tested yet. There is no WebGL fallback: a browser without WebGPU shows a notice instead of the game.

## 1. Get the code

```bash
git clone https://github.com/<org>/moonspell.git
cd moonspell/templates/crescent-game
```

`templates/crescent-game/` is the game template: the engine in `src/engine/`, the starter game in `src/game/`, eleven example games in `examples/`. Every command on this page runs from that folder.

## 2. Install

```bash
npm install
```

Use a real install in this folder. A `node_modules` that is symlinked from somewhere else, or left over from an older checkout, breaks the web bundle (see [Troubleshooting](https://docs.moonspell.app/start/quickstart.md#troubleshooting)).

## 3. Run it in the browser

```bash
npm run web
```

This copies Skia's WebAssembly file (`canvaskit.wasm`) into `public/`, then starts Expo's dev server on `http://localhost:8081`. Open that URL. The first bundle takes about 15 seconds; later reloads are faster. To use another port, pass it through: `npm run web -- --port 8790`.

You should see Sunset Sprint: a coastal circuit at sunset, your car and three rivals, and a HUD with the lap, your position, your best lap and your speed.

Drive it:

| Input | Gas | Brake | Steer |
| --- | --- | --- | --- |
| Mouse or touch | hold **GAS** | hold **BRAKE** | hold the left and right arrow buttons |
| Keyboard | W or Up | S, Down or Space | A and D, or Left and Right |

The keyboard works because the engine's touch controls also listen to keys in a browser ([Input](https://docs.moonspell.app/engine/input.md)). The dev server also shows development extras that production builds hide: an **AUTO** button that drives the car for you, and a telemetry line.

Edit `src/game/index.tsx` and save: the page reloads with your change. Try `laps: 1`, or `timeOfDay: 'night'` in `theme`.

## 4. Make a static web build

```bash
npm run export:web
```

This writes a static site to `dist/`: `index.html`, one JavaScript bundle under `_expo/static/js/web/`, the game's assets, and `canvaskit.wasm`. Serve it with any static server and open it:

```bash
cd dist
python3 -m http.server 8765 --bind 127.0.0.1
# open http://127.0.0.1:8765/
```

The production build has no AUTO button and no telemetry line. Two things to know before you host it:

- The build uses absolute URLs (`/_expo/...`, `/assets/...`), so serve `dist/` at the root of a domain or subdomain.
- Serve `.wasm` files as `application/wasm`.

Hosting, sub-paths and browser support are on [Web](https://docs.moonspell.app/platforms/web.md).

## 5. Run it on a phone

```bash
npm run ios       # expo run:ios
npm run android   # expo run:android
```

Each makes a normal Expo development build of the game: Expo generates the native project, builds it and starts Metro. You need Xcode and CocoaPods for iOS, Android Studio and a JDK for Android, and you should first change the app ids in `app.json` (`expo.ios.bundleIdentifier` and `expo.android.package`) to your own.

These two commands are configured and the generated native projects were checked, but a build on a simulator or a device has not been run by the maintainers yet. The full steps and what is known are on [iOS](https://docs.moonspell.app/platforms/ios.md) and [Android](https://docs.moonspell.app/platforms/android.md).

## 6. Run an example

An example runs by becoming the game. Copy its file over `src/game/index.tsx`:

```bash
cp examples/tap-pop/index.tsx src/game/index.tsx
npm run web
```

Tap Pop is a 2D game: tap the drifting dots before the 30 seconds run out. To put Sunset Sprint back:

```bash
git checkout src/game/index.tsx
```

Tap Pop has been run in a browser; the other ten examples type-check with the template (`npm run typecheck` includes `examples/`) but have not all been run on the web. The list of examples and what each one shows is on [Examples](https://docs.moonspell.app/examples.md).

## Check your work

```bash
npm run typecheck    # tsc --noEmit
npm test             # the engine's unit tests (Node's test runner)
npm run export:web   # the build players get; a Metro error here means the game will not open
```

Metro does not stop on type errors, so run `npm run typecheck` as well as the build.

## Troubleshooting

| What you see | Why | Fix |
| --- | --- | --- |
| "This browser can't run this game yet. Try the latest Chrome, Edge or Safari." | The browser has no `navigator.gpu`, or it returns no adapter | Use a current Chrome. Headless Chrome needs `--enable-unsafe-webgpu` |
| `Unable to resolve "react-native-web/dist/exports/..."` | `node_modules` is stale or symlinked from another folder | Delete `node_modules` and run `npm install` in this folder |
| `setup-skia-web` prints "Metro bundler not detected. Assuming the project is using Webpack." | Skia's setup script guesses the bundler | Nothing: the scripts pass the folder (`public`) explicitly |
| `npx expo-doctor` reports packages that do not match the SDK | The template pins exact versions on purpose ([The game contract](https://docs.moonspell.app/start/game-contract.md)) | Leave them as they are |
| A `404` for `/favicon.ico` | There is no favicon | Nothing, or add one to `public/` |

## Want your game in the Moonspell app?

The steps above never touch Moonspell. To publish a game to the Moonspell app on iPhone and Android and to the web, start from the starter instead: `npx https://moonspell.app/api/dev/cli/latest.tgz init my-game` downloads it with the built `crescent` CLI, and you sign in with a Moonspell account. See [Publish to the Moonspell app](https://docs.moonspell.app/start/publish-to-moonspell.md).

## Next steps

- [Your first game](https://docs.moonspell.app/start/first-game.md): build a small 3D game from scratch in `src/game/`.
- [How it works](https://docs.moonspell.app/start/how-it-works.md): what happens between `npm run web` and a frame on screen.
- [Project structure](https://docs.moonspell.app/start/project-structure.md): what is in the folder you ran, and what to rename before you make it your own.
- [Build with AI](https://docs.moonspell.app/ai/overview.md): open the folder in Claude Code and ask for a game.
