renew is a game engine in Rust, built to be operated.
Every capability is a library with a command-line face and machine-readable output. Building,
testing, packing assets, recording a play session, replaying it, benchmarking, and running any
sample all happen from one binary, headless, with --json on every command. A person, a script,
and an agent drive the engine through exactly the same surface, because there is only one. That is
what AI-first means here: the machine-operable surface is the primary one, not an export from
something else.
Underneath it, the simulation is bit-deterministic by construction. Same build, same seed, same inputs, same result, down to the byte, on every platform the engine targets.
Important
Early development. The crates are published at 0.1.1, but APIs change without notice and no
module has reached stable maturity, so this is not something to start a shipping game on today.
Everything described below exists, runs, and is covered by tests. Nothing here is a plan.
Every picture below was produced by the sample under it and is committed in this repository.
Six samples ship with the engine. The four simulation samples run headless and answer with a digest:
$ cargo run -p renew-sample-cube --bin cube
cube script=stand source=script ticks=600 digest=0xcbc2871e466a6bfc solids=5012 broken=0 placed=0 grounded=true
$ cargo run -p renew-sample-leap --bin leap
leap script=stand ticks=600 digest=0xd7058b85479adeb4 grounded=true wall=false
$ cargo run -p renew-sample-glide --bin glide -- --frames 600
renew-frame sample=glide seed=7 source=soar frames=600 ticks=600 dropped=0 score=3 alive=1 schedule_hash=0x55ce27c8dcb97c4d state_hash=0xe8f68645bf927702Run any of those again, on any machine, on any supported operating system, and the digest does not
move. The other two samples, hello_triangle and input_echo, open a window and exist to exercise
the renderer and the input path.
Stable Rust 1.97 or newer. That is all the engine and its headless samples need. Opening a window or playing audio on Linux additionally wants the usual desktop development packages, the same ones any Rust graphics project asks for.
git clone https://github.com/renew-engine/renew
cd renew
cargo run --bin renew -- build
cargo run --bin renew -- testThen pick something to look at:
# a 3D voxel world, drawn to a window
cargo run --bin renew -- --features window run cube -- --window
# the same world, headless, answered with one line
cargo run -p renew-sample-cube --bin cube -- --script patrol --ticks 2000
# chess, counting every legal game four plies deep
cargo run -p renew-sample-chess --bin chessMost engines treat reproducibility as a feature you bolt on for netcode or for replays. Here it is the constraint everything else is built around, and the parts that make it possible are not optional extras:
- the simulation runs on a fixed timestep over integer nanoseconds, and the frame loop is handed its clock rather than reading one
- simulation arithmetic is Q47.16 fixed point, so no floating-point mode or instruction selection can change a result
- storage has a defined iteration order, because an undefined one is a determinism bug waiting for a rehash
- randomness is seeded and explicit, with no thread-local state and no entropy a caller did not ask for
The engine can prove it about itself. One command runs a pinned set of simulations and writes what they produced:
$ cargo run --bin renew -- determinism --emit windows.json
wrote 15 digests for windows/x86_64 to windows.jsonOn every commit, CI produces that file on five targets and holds them against each other. Windows, Linux and macOS on the desktop, an Android emulator, and an iOS simulator. A digest that differs anywhere fails the build. Comparing against a value committed in the repository would prove only that one machine agrees with its own past; comparing targets against each other is what actually establishes the claim.
| Target | CI compiles | Test suite runs | Simulation digests match | Draws a frame |
|---|---|---|---|---|
| Windows, Linux, macOS | yes | yes | yes | yes |
| Android | yes, and lints | no, the pinned simulations only | yes, on an emulator | not yet in CI |
| iOS | yes, and lints | no, the pinned simulations only | yes, on a simulator | yes, on a simulator |
Graphics go through an internal interface backed by Vulkan through ash,
with MoltenVK on Apple platforms. Windowing and input go through winit.
No Vulkan type appears in the rendering interface's public API, so the backend stays replaceable.
An emulator is not a phone and a simulator is not a device, so the table says which was used. Android rendering is held back by the emulator topping out at Vulkan 1.2 while the renderer requires 1.3, not by anything missing in the engine.
$ cargo run --bin renew -- help| Commands | What they cover |
|---|---|
build test bench lint check |
the workspace, with one canonical command each |
run record replay |
start a sample, capture the input it saw, play it back and compare |
determinism |
emit this target's digests, or compare several targets' |
asset-pack asset-inspect ui-compile |
content, built and verified from the command line |
coverage modules doctor configure |
the state of the tree and the machine it is on |
Every one of them accepts --json and answers with a single document carrying a schema_version,
so tooling can build against a stable contract while the human-readable output stays free to
change. This is what "built to be operated" means in practice: no capability is reachable only by
clicking, and the editor, when it arrives, will be one more client of these APIs.
Twenty-nine engine crates, five of them core. Everything outside the core is optional and removable, and CI proves it one crate at a time: twenty-four configurations, each excluding one optional crate and everything that depends on it, every one built and tested. A twenty-fifth builds the minimal core alone and checks that no optional crate reached its graph.
| Group | Crates |
|---|---|
| Core | diag logging and sinks · event the input vocabulary · math vectors, matrices, quaternions · memory arenas, pools, a counting allocator · platform the only doorway to the OS |
| Simulation and runtime | fixed Q47.16 arithmetic · frame the fixed-timestep loop · ecs sparse-set storage · scene transform hierarchies · physics2d and physics3d · volume chunked voxels · particles · ui layout solved in fixed point · input state and mapping · rng · jobs |
| Rendering | rhi the GPU doorway · render2d sprites · render3d indexed geometry · camera views and projections · snapshot interpolation between ticks · ui-render |
| Content and IO | asset content-addressed packs · png encoding with no dependencies · audio mixing and playback · net lockstep datagrams · replay record a run and play it back · trace the recorded-input file format |
Twenty-seven of the twenty-nine are published on crates.io
at 0.1.1. cargo run --bin renew -- modules prints the live list with each crate's declared
maturity, read from its manifest, so it stays correct as this table ages. Maturity runs bootstrap to internal
to stable, and nothing has reached stable yet.
Every commit on main clears all of this. The test suite runs on all three desktop platforms;
the rest run once, on Linux:
| Gate | What it enforces |
|---|---|
| Format and lints | rustfmt, and clippy with warnings denied |
| Tests | the workspace suite on Windows, Linux and macOS, plus a release build |
| Coverage | every line of engine code covered, or individually exempted with a written reason. The gate fails in both directions, so an exemption that becomes covered again is also an error |
| No panicking shortcuts | unwrap, expect and panic denied outside tests; todo, unimplemented and dbg! denied everywhere |
unsafe denied by default |
denied workspace-wide; three crates opt in (memory, jobs, rhi), and every block must document the invariant that makes it sound |
| Module graph is a DAG | manifests are checked against the real dependency graph |
| Optional crates stay removable | one build and test per crate removed, plus the minimal core alone |
| Licenses and advisories | cargo-deny across the whole tree, dev-dependencies included |
| Determinism | five targets compared against each other |
| Sanitizers, Miri, fuzzing | on a schedule, against the parsers and the threaded code |
Performance claims arrive with numbers and the configuration that produced them, or they are not made. The steady-state frame loop is held to zero heap allocations through the engine's allocators, counted in development builds.
Issues and pull requests are welcome. CONTRIBUTING.md has the workflow and the bar a change is held to. The short version: a change arrives with its tests, its documentation, and evidence that it works.
Apache-2.0. Contributions are accepted under the same license.
Brand assets live in
assets/brand/.



{ "schema_version": 1, "os": "windows", "arch": "x86_64", "toolchain": "rustc 1.97.1 (8bab26f4f 2026-07-14)", "digests": { "chess/play-60/digest": "0x6bf0be22d95711ee", "cube/build-900/digest": "0xce632722e5698fa1", "cube/patrol-600/digest": "0x29559b5af5e634d2" // 12 more, in key order } }