---
name: simengine-create-project
description: Create a new SimEngine project (a scene, a scenario and a project.json) from the first_scene example, check it against the engine build, run it headless, capture it offscreen to PNG and verify the result. Use when the user asks to start, create or scaffold a SimEngine scene, project or "first game", or to check that their SimEngine build can run one.
---

# Create a SimEngine project

This skill ships with the SimEngine `first_scene` example. It drives only
SimEngine's public tools: the `simengine_host` scenario CLI, the `simengine_capture`
offscreen renderer and the example driver `examples/first_scene/first_scene.py`, which
calls those two executables in separate processes and verifies what they write.

## Compatible versions

Written for, and verified against, a SimEngine build that reports:

| Interface | Version | Where it is reported |
| --- | --- | --- |
| Scenario schema `simengine.scenario` | `schema_version` 1 | `simengine_host --capabilities` → `capabilities.scenario_schema.schema_version` |
| Capability document `simengine.capabilities` | 1 | `capabilities.schema_version` |
| Scene state `simengine.scene_state` | 1 | `capabilities.state_schema.schema_version` |
| Simulation (module extension) contract | 1 | `capabilities.simulation_contract_version` |
| Module contract | 1 | `simengine_host --report` → `runtime.modules.registry.contract_version` |
| Scene / asset text formats | `simengine_scene 1`, `simengine_asset 1` | first line of `.sescene` / `.seasset` files |
| Capture manifest `simengine.capture.manifest` | 1 | `simengine_capture --version` |
| Example driver / project file | driver 1, `simengine.example_project` 1 | `first_scene.py`, `project.json` |

The driver checks every one of these before it runs anything and stops with
`incompatible_engine` (exit 21) on a mismatch. Do not work around that: the skill is
out of date for that engine.

## What SimEngine can do today (and what it cannot)

Can: run a deterministic, seeded, headless scenario of point entities in one Cartesian
frame (positions in meters, yaw orientations, scheduled `simengine.entity.set_position`
commands, seeded `scatter_box` placement, end-of-run expectations), and render a static
scene offscreen with a small PBR material subset to a PNG plus a JSON manifest.

Cannot (do not promise or attempt it): a window or interactive camera, keyboard/mouse
input, physics, collisions or contacts, audio, a game loop, textures or normal maps,
glTF import, local lights or shadows. Motion without the optional `point_mass` module
is a sequence of scheduled teleports.

## Before you start

You need a built SimEngine checkout. If `build/linux-release/apps/host/simengine_host`
does not exist yet, run the setup script first (`./tools/setup.sh` on Linux,
`tools/setup.ps1` on Windows) and report its result.

The commands below use three variables. Shell tools often do not keep variables between
calls: prefix each command with the assignments, or substitute absolute paths.

```text
SIMENGINE_ROOT=/absolute/path/to/SimEngine          # the checkout
SIMENGINE_BUILD=$SIMENGINE_ROOT/build/linux-release  # what tools/setup.sh builds
PROJECT=/absolute/path/to/my_first_scene             # a NEW directory, outside the checkout
```

Use `python` instead of `python3` where that is the Python 3 interpreter (Windows).

## Steps

1. Discover what this build can do. Read `capabilities.commands`, `capabilities.components`
   and `capabilities.modules`: a core-only build has one command
   (`simengine.entity.set_position`) and no components or modules.

```sh
"$SIMENGINE_BUILD/apps/host/simengine_host" --capabilities > "$SIMENGINE_BUILD/capabilities.json"
python3 -c "import json,sys; c=json.load(open(sys.argv[1]))['capabilities']; print('scenario schema', c['scenario_schema']['schema_version'], '| commands', [x['id'] for x in c['commands']], '| modules', [m['id'] for m in c['modules']])" "$SIMENGINE_BUILD/capabilities.json"
```

2. Create the project. `new` copies the example scene, scenarios, assets and these
   skills (into `$PROJECT/.claude/skills/`) and prints one JSON line (`outcome`,
   `files`, `next`).

```sh
python3 "$SIMENGINE_ROOT/examples/first_scene/first_scene.py" new "$PROJECT"
```

3. Check it without a GPU: engine compatibility, scene import path, scenario validation.
   Expect `"outcome": "PASS"` and exit code 0.

```sh
python3 "$SIMENGINE_ROOT/examples/first_scene/first_scene.py" check --project "$PROJECT" --build "$SIMENGINE_BUILD"
```

4. Run the whole journey: two deterministic runs, the scene posed from the initial and
   final simulation states, three offscreen captures (two viewpoints), verification and
   `manifest.json` under `$PROJECT/runs/main-NNN/`.

```sh
python3 "$SIMENGINE_ROOT/examples/first_scene/first_scene.py" run --project "$PROJECT" --build "$SIMENGINE_BUILD"
```

5. Verify it independently from the files it wrote (hashes, PNG decode, sidecars).

```sh
python3 "$SIMENGINE_ROOT/examples/first_scene/first_scene.py" verify --project "$PROJECT"
```

## Verify what you produced

Report these to the user, from the `run` and `verify` JSON lines, not from memory:

- `outcome` is `PASS` and the exit code is 0 for `check`, `run` and `verify`;
- `expectations`: 3 passed, 0 failed; `final_state_sha256` (64 hex characters);
- `checks.deterministic_repeat` and `checks.motion_visible` are `PASS`;
- three PNGs under `runs/main-NNN/captures/` (`initial-front`, `final-front`,
  `final-side`). Open `final-front` and look at it: a table with a red ball on it, two
  stacked crates, three barrels on a checkered ground.

If the exit code is 77 (`BLOCKED_ENVIRONMENT`), the machine has no usable Vulkan device:
the simulation was verified but nothing was rendered. Say so; it is not a pass.

## On failure

The driver prints `failure.code`, `failure.step`, `failure.message` and a `failure.hint`.
Quote them verbatim. Then:

| Exit | `failure.code` | Do this |
| --- | --- | --- |
| 20 | `build_not_found` | Run the setup script, or pass the build directory that contains `apps/host` and `apps/capture`. |
| 21 | `incompatible_engine` | Stop. Host and capture come from different builds, or the engine changed a version this skill was written for. Report it. |
| 22 | `module_missing` | The scenario needs an optional module. Use a build configured with `-DSIMENGINE_MODULES=<id>` or pick a core-only scenario. |
| 23 | `scenario_invalid` | Use `simengine-modify-scene`: fix each `failure.detail.errors[]` entry at its JSON pointer `path`. |
| 24 | `scene_invalid` | Fix the `.sescene`/`.seasset` line in `failure.detail` (`code`, `file`, `line`). |
| 31 | `project_invalid` | `$PROJECT` already exists and is not empty, or `project.json` is malformed. Choose a new directory. |
| other | see `simengine-run-capture-diagnose` | |

Never edit engine sources, tests or the example's files under `$SIMENGINE_ROOT` to make
a journey pass; change only the project.
