A game engine in Rust built for the long haul, and built to be operated rather than merely used. The simulation core is deterministic by construction: same build, same seed, same inputs, same result, bit for bit.
renew is an open-source game engine written in Rust. Every capability is a library with a command-line face and machine-readable output, so a person, a script, or an agent drives the engine through exactly the same surface.
Status: early development. Pre-0.1. APIs are unstable, modules are still moving through the maturity ladder, and this is not yet ready to build a game on. What is here is real, tested, and honest about what it is.
Fixed timestep over integer nanoseconds, Q47.16 fixed point, no wall-clock reads, no unseeded randomness, no iteration-order-dependent state. Replay and lockstep are a foundation rather than a retrofit.
Build, test, benchmark, asset work, running samples, all headless. Every command
takes --json and emits a schema-versioned document. A GUI, when it
arrives, is a client of the same APIs.
Twenty-seven engine crates, five of them core. Everything else is optional and removable behind an explicit interface, enforced by CI rather than by good intentions.
Performance claims arrive with numbers and the configuration that produced them. The steady-state frame loop is held to zero heap allocations through the engine's allocators, counted in dev builds.
hello-engine is the current proof of life. A fixed-timestep accumulator
driven through 60 frames of deliberately uneven frame times, reading no clocks at all:
$ cargo run --bin hello-engine
hello-engine 0.1.1
fixed timestep: 16666667 ns
frames simulated: 60
time submitted: 1245000015 ns
ticks executed: 74
time pending: 11666657 ns
Run it twice. Run it on another machine, or another OS. Every byte is identical, and that is the property everything else in the engine is built to preserve.
Making a simulation reproduce bit-for-bit on three platforms sets out what that property costs in practice: why the arithmetic is fixed point rather than floating, why the frame loop cannot read a clock, and why a digest compared against a committed constant proves nothing about a second machine.
Requires stable Rust 1.97 or newer.
git clone https://github.com/renew-engine/renew
cd renew
cargo build --workspace
cargo test --workspace
cargo run --bin hello-engine
One binary drives the workspace the same way for people, scripts, and CI:
cargo run --bin renew -- help
configure, build, test, bench,
run, record, replay, lint,
check, coverage, modules,
asset-pack, asset-inspect, determinism,
doctor.
Every module is independently buildable, testable, and, outside the minimal core, removable. CI proves the last part on every commit, one crate at a time.
| Crate | What it does | Maturity |
|---|---|---|
renew-diag | Log records, severity levels, and the sink interface the engine reports through | internal, core |
renew-event | The event vocabulary (key codes, pointer buttons, event shapes) as plain data | internal, core |
renew-math | Vec2/3/4, Mat4, Quat, Aabb3, with documented layout and branchless kernels | internal, core |
renew-memory | LinearArena, a generation-checked Pool<T>, and a counting global allocator | internal, core |
renew-platform | The engine's only doorway to the OS: clock, files, named threads, window | internal, core |
renew-fixed | Q47.16 fixed-point arithmetic, the number type the simulation is written in | bootstrap |
renew-frame | The fixed-timestep loop: an accumulator over integer nanoseconds, clock passed in | bootstrap |
renew-ecs | Sparse-set storage with a defined iteration order | bootstrap |
renew-jobs | A fixed-size worker pool with a deterministic-chunk parallel_for | bootstrap |
renew-rng | Seeded, reproducible random numbers: PCG32 with derived per-domain streams | bootstrap |
renew-input | Input state and mapping, over the event vocabulary | bootstrap |
renew-replay | Input traces as files: record a run, replay it, compare the digests | bootstrap |
renew-trace | Simulation digests, the hash the cross-platform determinism lane compares | bootstrap |
renew-physics2d | Bodies, shapes, broadphase, SAT narrowphase, raycasts, sweeps, slide resolution | bootstrap |
renew-physics3d | The same surface in three dimensions, axis-aligned only | bootstrap |
renew-scene | Local placements, parenting, and a propagation pass composing them over entity storage | bootstrap |
renew-rhi | The GPU doorway: Vulkan through ash, behind an interface naming no Vulkan type | bootstrap |
renew-render2d | Sprites from an atlas, one instanced draw | bootstrap |
renew-render3d | Indexed geometry, depth-tested, in submission order | bootstrap |
renew-camera | Look-at view, reversed-depth perspective, and a blend between ticks | bootstrap |
renew-snapshot | Two captures of one slot space blended by the interpolation factor | bootstrap |
renew-particles | A fixed-capacity particle pool stepped at the simulation's cadence | bootstrap |
renew-ui | A widget tree solved in fixed point inside the simulation | bootstrap |
renew-ui-render | Retained snapshots blended at display rate, clipped on the CPU, emitted as sprites | bootstrap |
renew-audio | Mixing and playback, behind the platform's device seam | bootstrap |
renew-asset | Content-addressed asset packs, every entry verifiable against its digest | bootstrap |
renew-png | PNG encoding with no dependencies: pixels in, the bytes of a file out | bootstrap |
Maturity runs bootstrap, then internal, then
stable. A module never claims a level it has not earned, and nothing
here is stable yet.
Every commit on main clears all of these, on Windows, Linux, and macOS:
| Gate | Enforced by |
|---|---|
| Format and lints, zero warnings | rustfmt and clippy with a strict deny-set |
| Tests, debug and release | cargo test across the three-platform matrix |
| Line coverage | 100% of every line not individually exempted, each exemption naming its lines and its reason |
| No panicking shortcuts | unwrap, expect, panic, todo, dbg! denied outside tests |
unsafe denied by default | Workspace-wide unsafe_code = "deny", and every opted-in block states the invariant that keeps it sound |
| Module graph is a DAG | Crate manifest and dependency-graph check (renew check) |
| Optional modules stay removable | One configuration per optional crate, each excluding that crate and its dependents, all built and tested |
| Licenses and advisories | cargo-deny, over the full dependency tree |
| Sanitizers and Miri | Scheduled nightly runs (ASan, TSan, Miri) |
Every capability is headless, scriptable, and emits schema-versioned JSON beside its human-readable output, so nothing about the engine requires a person in front of a screen. It does not mean the engine ships AI features. It means the machine-operable surface is the primary one, and the GUI, when it arrives, will be a client of it like everything else.