Build digital infrastructure. Find the bottleneck. Scale the network.
Nodustry is a deterministic, high-performance 2D automation game about routing data from where it is produced to where it is needed. Build a network, measure throughput and latency, fix the limiting constraint, then discover the next one.
Written in Zig. Rendering via raylib. Simulation runs headless.
Foundation Preview — pre-alpha. The first vertical slice runs: a source feeds a router, which splits across two processors that merge into a destination, with packets in transit and live throughput / latency / loss metrics.
What exists today:
- fixed-timestep, integer-only simulation kernel;
- source, router, processor, and sink nodes;
- link travel time, capacity, backpressure, TTL, and packet-pool limits;
- live throughput, latency, loss, and buffer metrics;
- interactive desktop demo plus headless tests and benchmark.
Not yet included: in-game building/editor, saves or schematics, progression, multiplayer, and mod-authored behavior code.
- Zig 0.16.0 (exact; the build declares it as the minimum and the raylib bindings require it)
- Linux or Windows desktop. On Linux the client needs X11 development headers
(
libx11,libxrandr,libxinerama,libxi,libxcursor) and OpenGL. The headless targets need none of that.
zig build run # the game client (fetches and builds raylib)
zig build test # headless simulation + content tests, no graphics stack
zig build bench # headless throughput benchmark
zig build fmt-check # formatting gateraylib is declared as a lazy dependency, so zig build test and
zig build bench never fetch or compile it. That is deliberate: the simulation
must stay buildable and testable on a machine with no GPU and no display server.
zig build bench -Doptimize=ReleaseFast -- --lanes=700 --batch=16 --ticks=900 --packets=2097152Options: --shape=lanes|fanin, --lanes, --sources, --processors,
--ticks, --batch, --packets.
lanes measures the uncontended path; fanin measures backpressure, saturated
links and buffer overflow.
src/sim/ simulation kernel — depends on std and nothing else
src/content/ content identity and the node kind registry
src/scenario/ the external boundary: JSON -> validated -> World
src/render/ drawing; read-only with respect to the simulation
src/main.zig client: window, input, fixed-timestep driver
src/bench.zig headless benchmark
scenarios/ example scenario documents
The dependency arrow only ever points one way: render and main may read the
simulation; the simulation may not know they exist.
A network is described by a versioned JSON document. Nodes name their type by a
stable content id (nodustry:router), never by an internal index, and refer
to each other by instance id:
{
"format_version": 1,
"simulation": { "tick_rate": 60, "packet_capacity": 65536, "seed": 0 },
"nodes": [
{ "id": "src", "kind": "nodustry:source", "position": { "x": -8, "y": 0 },
"source": { "interval_ticks": 2, "batch": 1, "ttl": 8 } },
{ "id": "dst", "kind": "nodustry:destination", "position": { "x": 10, "y": 0 } }
],
"links": [
{ "from": "src", "to": "dst", "travel_ticks": 30, "capacity": 64 }
]
}A scenario describes a network before it runs. It is not a savegame: it holds
no tick counter, no packets and no buffer contents, and always starts at tick 0.
Every document is size-checked, parsed, version-checked, validated and resolved
before any simulation exists — see src/scenario/.
The schema is strict on purpose. Numbers must be written as JSON numbers:
"tick_rate": 60 is valid, "tick_rate": "60" is not. Unknown and duplicate
fields are refused rather than ignored, and documents larger than 64 MiB are
rejected before parsing begins.
See scenarios/demo.json for the network the client ships with.
| Key / input | Action |
|---|---|
Space |
Pause / resume |
R |
Reset the network |
| Mouse drag | Pan |
| Mouse wheel | Zoom |
The central design constraint is that simulation remains headless and deterministic while rendering stays a read-only client. This is what keeps replays, large simulations, debugging, and eventual multiplayer feasible.
Nodustry is licensed under the GNU General Public License v3.0.