Skip to main content
The simulation is a fixed-timestep loop: each tick (1/60 s) runs the shared schedule — physics, combat, status effects, abilities, AI, rules — over the world table. Nothing happens between calls; you advance it explicitly with /step, or hand control to the free-running loop with /play and /pause. Stepping is deterministic: the same seed and inputs produce a bit-identical trajectory. This page drives the loop and a match by hand; every command is real and runnable against a local server, with output captured from one.

Drive the loop and run a match

1. Check the clock. GET / reports the engine rollup, including the current tick.
(entity_count and tick reflect the loaded project the headless host boots, so your numbers will differ.) 2. Spawn, then step. /step advances N ticks and reports the new tick and live entity count. The tick is 1/60 s, so 60 ticks is one second.
A single /step is capped at 10,000 ticks per call — ask for more and it advances 10,000 and reports the real count:
3. Free-run with play / pause. These toggle the background loop instead of stepping by hand.
4. Reset the scene. /reset despawns every non-Persistent entity and reports how many it removed — and crucially leaves the tick counter alone. It clears the scene, not the clock.
5. Run a match lifecycle. /game/create starts a match; /game/state reports the phase (lobbycountdownplayingpost_match), elapsed time, and per-entity scores. Elapsed advances as you step.

Behavior and gotchas

The things you only learn by running it:
  • /reset does not zero the tick. The message above reports Tick: 10060 after the reset, and GET / confirms the clock is unchanged. Reset clears entities, not time.
  • /reset keeps Persistent entities and clears the rest. Ground and lights a project marks Persistent survive a reset; everything else is removed. How many entities remain depends on the served project — a world that marks nothing persistent drops to entity_count: 0. Use POST /observe as the authoritative read of what the scene holds after a reset — GET /entities/{id} may still answer 200 with a bare {"id","generation"} for an index that previously held an entity.
  • /step is capped at 10,000 ticks per call. Larger ticks are clamped; ticks_advanced tells you what actually ran. Loop the call to go further.
  • /game/state before /game/create is an error, not an empty match. It returns {"error":"No game state. Use POST /game/create first."}. Create the match first.
  • Entity transforms read [0,0,0] until the first /step. GlobalTransform propagates on a tick, so step once after spawning before reading positions.

Endpoints

What runs each tick

Physics integration, collision and the impulse solver, combat (damage / projectiles), status-effect ticks, ability cooldowns, AI steering, navigation, and rule evaluation — all in a fixed, deterministic order. See Engine internals for the schedule and Determinism for the reproducibility guarantee.

Status

  • Shipped, all headless — manual /step with the 10,000-tick cap, the free-running play/pause loop, scene reset that preserves Persistent entities and leaves the clock untouched, and the match lifecycle (create + phase/elapsed/score state). Stepping is deterministic.

Simulation endpoints

Step, play, pause, reset, and match-lifecycle endpoints, with request and response schemas.