Skip to main content
Euca has three ways to persist and rebuild a world, and the most important thing to know is that they are lossy in different amounts. The mental model: each path serializes a subset of an entity’s components and restores a subset of what it wrote — so a saved world is an authoring artifact, not a byte-exact snapshot. This page saves a world, changes it, reloads it, and reads back exactly what survives, for each path. Every command is real and runnable against a local server, with output captured from one. Run it as a single session, top to bottom: each section resets the world, but the tick and entity generation carry forward (which is why later sections show higher numbers). The three paths, thinnest restore first:
  • Scene (/scene/save, /scene/load) — restores transform + physics body only.
  • Scenario (POST/GET /scenario) — restores transform + health + team; reassigns ids.
  • Level (/level/save, /level/load) — saves a rich file, but the save and load formats don’t match, so a saved level reloads zero entities.

Scene round-trip — what survives

Reset (a fresh server holds one component-less bootstrap entity), spawn a rich entity (position, health, team, role, gold, a dynamic physics body), step once so the transform propagates, and read it back. health is reported as [current, max]:
Now save the scene, load it straight back (load wipes the world first, then restores), and step once so the restored transform propagates:
The position ([5, 0.997, -2]), scale, and physics body round-tripped. Everything else is gone — no health, team, gold, level, role, or velocity. The save file contains those fields, but scene/load only reads transform.position, transform.scale, and physics_body back. The generation bumped (here 12) because load wipes and re-spawns.

Scenario round-trip — richer, but still partial

A scenario is one document for a complete setup (templates, entities, rules, assertions, camera, game config). GET /scenario exports the current world; POST /scenario wipes and rebuilds from a document. Reset, spawn a unit, step, and export it:
Re-applying that export rebuilds the world. health and team survive (scene/load drops both), but role and gold are still lost, and ids are reassigned:
The world→scenario extractor reconstructs position, scale, health, and team from each entity’s components — that’s the full set it knows how to round-trip. role, gold, color, mesh, and the combat/AI fields are read as null even when the components are present, so they’re dropped on re-apply. Entities are inlined with no id, so applying assigns fresh ids.

Level save/load — a saved level reloads zero entities

POST /level/save writes a level file, and POST /level/load reads one. But they speak different shapes, so a level you saved cannot be reloaded. Reset, spawn a unit, step, then save and reload it:
level/save writes the same rich per-entity record as /observe (with health as a [current, max] array). But level/load parses each entity as a spawn request, where health is a single number. The array shape fails to deserialize, and the loader silently falls back to an empty entity list — so entities_created is 0, with no error. The loader itself works fine; it’s the save format that’s incompatible. A hand-authored level (with scalar health) loads correctly:

Behavior and gotchas

The things you only find out by running it:
  • Restore depth differs by path. Scene keeps transform + physics body; scenario keeps transform + health + team; level save→load keeps nothing (format mismatch). No path keeps role, gold, color, velocity, or ability/AI state. None is byte-exact.
  • Step after a load to see positions. Load writes the local transform; the world-space transform /observe reports propagates on the next tick. Read immediately after a load and a dynamic body still shows [0,0,0] until you /step.
  • scene/load and POST /scenario wipe the world first; level/load appends. Loading a scene or applying a scenario despawns everything, then rebuilds. level/load adds to whatever is already there.
  • A saved level file does not reload (entities_created:0, silently). Use a scenario for a save→reload round-trip, or hand-author level files in the spawn-request shape (scalar health).
  • Paths are sandboxed and relative. Absolute paths and .. are rejected; files resolve against the server’s working directory.

Endpoints

For exact, byte-comparable reproducibility, use the structured state and digest on Datasets — scene/scenario/level files are for authoring and layout.

Status

  • Shipped — scene save/load, scenario apply/export (including into forks), level save/load with format auto-detect and a procedural MOBA map. All headless.
  • Partial — every save/load path is a subset round-trip. Scene keeps transform + physics body; scenario keeps transform + health + team; a saved level file currently reloads zero entities (the save format is the /observe record, which the loader doesn’t accept).

Scene & scenario endpoints

Scenario, level, and scene endpoints with request and response schemas.