A deterministic, tick-based, scriptable multi-agent simulation engine on a 2D grid, written in Rust. The engine itself defines no game content — every block type, entity type, and behavior is supplied at runtime as a scenario (JSON) plus a set of scripts (Lua) that implement entity AI, functional-block handlers, and scheduled events.
Given the same scenario and scripts, the engine produces byte-identical output on every run, on any machine. That output is a single, self-contained log file — a full tick-by-tick snapshot of world state — sufficient on its own to drive a separate visualization or analysis tool without ever re-running the simulation.
All engine milestones are complete: world model, blocks/items, entities,
ticking, the Lua scripting runtime and action API, the scenario/log file
formats, determinism verification, and the spec's worked example as a golden
integration test. The visualization application at viewer/
(React + TypeScript + Vite + PixiJS) is also complete — it replays a log
file's playback, lifecycle, perception/line-of-sight, and communication
data, with inspection, filtering, and search over any tick. See
viewer/README.md for its features and commands, and
specification/ImplementationPlan.md
for the full milestone history and design decisions.
- You write a scenario file (JSON): world dimensions, tunable constants, block/entity class definitions, the initial placement of blocks/items/entities, and any predefined scheduled events.
- You write Lua scripts for entity AI and functional-block behavior, referenced by path from the scenario.
swarm-simloads the scenario, resolves and compiles the scripts, and runs the simulation for a fixed number of ticks. Each tick, in strict order, it: decays item stacks, fires due scheduled events, ticks functional blocks, then ticks entities — all in ascending-ID order for determinism.- The engine writes a single JSON log file containing the input scenario verbatim plus a complete snapshot of every tick, which can be replayed, diffed, or visualized without touching the simulation again.
Entities and functional blocks perceive the world through a sensors table
(a windowed, line-of-sight-filtered view) and act through an api.*
surface exposing major actions (move, attack, break_block, place,
spawn — one per tick) and free actions (eat, pick_up, drop,
send_message, pop_message, random, random_int). Scripts run in a
locked-down Lua sandbox: no OS/file access, no wall-clock, no unseeded
randomness, and a hard instruction budget — a script that errors or exceeds
its budget only kills the instance that ran it.
crates/
swarm-core/ the engine library — world/tick/scripting logic, no I/O
src/
world.rs world grid, coordinates, border (spec ch. 3)
block.rs block classes, categories, breaking, loot (spec ch. 4)
item.rs items, item stacks, pickup/drop, despawn (spec ch. 5)
entity.rs entities, adjacency, hunger/health, perception (spec ch. 6)
tick.rs the tick executor and phase order (spec ch. 7)
ids.rs monotonic ID counters (spec ch. 8)
scripting/ Lua sandbox, calling conventions, action API (spec ch. 9)
scenario.rs scenario JSON deserialization & validation (spec ch. 10)
log.rs output log JSON format (spec ch. 11)
rng.rs shared deterministic RNG (SplitMix64)
swarm-cli/ the `swarm-sim` binary — thin CLI wiring over swarm-core
tests/
worked_example.rs golden integration test (spec Appendix A)
determinism.rs repeated-run determinism regression test
specification/
swarm-simulator-spec.tex the authoritative formal spec (source of truth)
swarm-simulator-spec.pdf rendered copy of the above
draft-summary.md informal precursor design notes
brainstorm.md original raw brainstorm (historical only)
ImplementationPlan.md milestone plan, decisions log, and rationale
FeatureDescription_visualization_application.md viewer/ requirements
viewer/
the visualization app — a standalone npm project (React + TypeScript +
Vite + PixiJS) that replays a log file; see viewer/README.md
scenarios/
ready-to-run example scenarios (JSON + Lua scripts) — see "Sample
scenarios" below
The formal specification (specification/swarm-simulator-spec.tex) is the
single source of truth for engine behavior. Its chapter order — World
Model, Blocks, Items, Entities, Ticking, IDs, Scripting Runtime, Scenario
Format, Log Format, Determinism, Visualization Contract, Worked Example — is
also the intended build order, tracked milestone-by-milestone in
specification/ImplementationPlan.md.
Requires a Rust toolchain (stable) and no other system dependencies — Lua
5.4 is vendored via mlua.
cargo build --workspace
cargo test --workspace
cargo run -p swarm-cli -- <scenario.json> <output.json> <ticks> [--memory] [--messages]<scenario.json>— path to a scenario file (seecrates/swarm-cli/tests/fixtures/worked_example/scenario.jsonfor a complete worked example, or spec ch. 10 for the format).<output.json>— where to write the tick-by-tick log.<ticks>— number of ticks to simulate.--memory— optionally include each entity's/functional block's private memory table in the log (omitted by default).--messages— optionally include each messages sent between entities in the log (omitted by default).
scenarios/ holds ready-to-run example scenarios, each a
self-contained directory with its own scenario.json and scripts/:
foraging-ants— three ants wander a 6x6 grid scattered with berry bushes; each ant moves onto an adjacent bush when it sees one (silently eating it, spec §4.3), otherwise takes a random step.rock-miners— two miners hunt a 7x7 grid for rocks, breaking each one they find adjacent (spec §4.2's loot-table roll), stepping onto the cleared tile, and picking up the dropped pebbles, before resuming the hunt.
Both exhaust their world's food/ore within ~30-40 ticks, after which entities (having no more food source) slowly starve — run for around 40 ticks to see the interesting behavior:
cargo run -p swarm-cli -- scenarios/foraging-ants/scenario.json foraging.output.json 40 --memory
cargo run -p swarm-cli -- scenarios/rock-miners/scenario.json mining.output.json 40 --memory| Command | Purpose |
|---|---|
cargo build --workspace |
build everything |
cargo test --workspace |
run all unit and integration tests |
cargo test -p swarm-core <test_name> |
run a single test |
cargo fmt --all |
format (runs automatically on file edit via a Claude Code hook) |
cargo clippy --workspace --all-targets -- -D warnings |
lint; must be clean before any milestone is considered done |
Determinism is a hard requirement, not an aspiration: all simulation state
that affects output is stored in ID-ordered structures (never raw HashMap
iteration), all randomness — both script-driven (api.random) and
engine-driven (loot table rolls) — is drawn from one shared seeded RNG
stream, and the instruction-budget sandbox never depends on wall-clock
timing. crates/swarm-cli/tests/determinism.rs runs a fixture scenario
five times end-to-end through the real binary and asserts byte-identical
logs.
MIT — see LICENSE.