25 shipped, 4 in progress and 13 planned. Each feature is marked from the roadmap's ticks at 0cba65f, so the list moves as the tasks land.
Quality // Shipped
No third-party crates
The game is built from this workspace's crates alone: its OS bindings, OpenGL backend, math, ECS, codecs and tools are written here, and beyond Rust's standard library it calls only the system's own libraries, such as Xlib, EGL and OpenGL. The build fails if the lock file gains a package from outside the workspace, and each crate may use only the crates the architecture's dependency matrix allows.
Quality // Shipped
Guardrails on every push
Each push is formatted, linted with warnings as errors, tested, and checked for dependencies, layering and unsafe code on Windows, macOS and Linux. Unsafe code is allowed in three crates only, and the audit fails any unsafe block without a SAFETY comment.
Quality // Shipped
Fuzzing and benchmarks
A mutation fuzzer of our own runs each parser of the codec crate in CI, with a hang watchdog, and saves an input that panics or hangs one. A benchmark harness reports medians and 95th percentiles against a recorded baseline.
Core // Shipped
Math, color and geometry
Vectors, 3 × 3 matrices, 2D affine transforms, rectangles, and colors with sRGB conversions, checked by property tests such as inverse round trips and symmetric intersections.
Core // Shipped
Handles, hashing and random numbers
Generational arenas and typed handles that catch a stale reference, FNV-1a, a fast hasher for maps, CRC-32 and the PCG32 generator, each checked against reference values.
Core // Shipped
Logging, time and test tools
Log macros with rotating files and an in-memory ring, calendar time without the OS, a command-line parser, profile scopes, and a property-test helper that prints the seed of a failure so that it can be run again.
Content // Shipped
JSON and JSONC
A parser and writer for JSON, with comments and trailing commas allowed in JSONC. Bad input gets an error with its line and column, never a panic, and limits on depth, sizes and counts keep a hostile file from exhausting memory.
Platform // In progress
Native windows on every desktop
Windows, keys, mouse, focus, resizing, DPI scaling and borderless fullscreen through each system's own API, declared by hand. Linux, through X11 loaded at run time, is done. The Win32 and Cocoa versions build and pass CI, and will be done once they are checked by hand on Windows and macOS.
Simulation // Shipped
Fixed-tick main loop
The simulation steps exactly 60 times a second whatever the frame rate, and each frame draws between the last two ticks, so motion is smooth at 60, 144 or uncapped frames a second. A tap between two ticks still counts, and a long stall is clamped instead of spiraling into catch-up ticks.
Platform // In progress
Log files and fatal errors
On Linux the game finds its folders where the system expects them, writes each run's log there and keeps the last three, and logs and reports an error that ends the game before it exits. Windows and macOS will follow, with their windows.
Graphics // In progress
OpenGL 3.3 on every desktop
An OpenGL 3.3 core context with vsync through EGL on Linux, and an offscreen context that the tests and these recordings draw with. WGL on Windows and NSOpenGL on macOS will follow.
Graphics // Shipped
A small graphics interface
A thin layer over OpenGL 3.3 core: textures, buffers, render targets, pipelines, instanced draws, scissor and readback, with a state cache. Using a destroyed resource is an error rather than a wrong frame, and a shader that fails to compile reports the driver's log.
Quality // Shipped
Golden-image tests
Scenes of the renderer are drawn offscreen on Mesa's software renderer in CI and compared with committed reference images within a small tolerance. A scene that differs uploads what it drew and an image of where.
Graphics // Shipped
Sprites, y-sorting and a pixel-perfect camera
Sprites are sorted by layer and by where their feet are, so what stands lower on screen is drawn in front, then packed into instanced batches. A 2D camera draws at a fixed virtual resolution and scales it up by whole numbers, letterboxed, so every pixel stays square.
Graphics // Shipped
10,000 sprites with no allocation
The stress scene draws 10,203 sprites in 1 batch, all from one page of the cooked atlas. A test counts every allocation the engine makes through Rust's allocator in the real loop and finds none in 100 steady frames, and sorting and batching such a frame takes about 0.74 ms on an i7-11800H.
Simulation // Shipped
Input actions
Keys and mouse buttons map to named actions, buttons or 2D axes such as WASD, latched once a tick so that nothing pressed between ticks is lost. A text mode mutes the game's bindings while a text field has the keyboard, and the actions can be recorded for replays.
Content // Shipped
Asset loading
Typed handles to assets loaded from files: the same path gives the same handle, and a development build shows a placeholder for anything missing. Worker threads read and decode the files while the game runs, and each frame makes the decoded ones within a budget of 2 ms: asked for a thousand at once, an optimized build spends under 4 ms of any frame on them. Assets load in scopes, global, level or transient, and unloading a scope frees what no other scope holds, GPU textures included.
Simulation // Shipped
Entity component system
Generational entities with sparse-set storage, resources, events, deferred commands and a schedule of stages with run conditions; a borrow conflict names the system that caused it. The engine's own systems move, collide, animate and draw entities.
Simulation // Shipped
Reflection
Macros describe structs and enums as dynamic values and back, with a registry of types and warnings for unknown fields. Asset handles are written as their files' paths and loaded again when read, and the engine's sprites, colliders and animators are reflected too: a sprite can name a frame of a cooked atlas, a collider its layers by name, an animator its clip. The determinism tests hash worlds through it.
Simulation // Shipped
Collision and sliding movement
Boxes and circles, tile grids and a spatial hash, with move-and-slide in up to 16 substeps so that movers follow their path and slide along walls without snagging, plus sweeps, triggers and queries. 5,000 colliding entities tick in about 2.4 ms on an i7-11800H.
Graphics // Shipped
Tilemaps
Tile layers drawn a chunk at a time from a cache, culled to the view, with animated tiles. Tall tiles become y-sorted sprites, and the same map gives the collision grid: the field in the demo is one.
Graphics // Shipped
Sprite animation
Clips of frames that loop, or play once and send an event at the end, played by an Animator component and mirrored by the way the entity faces.
Quality // Shipped
Deterministic replays
The input is recorded tick by tick and played back with no window. A test replays a stored recording and compares a hash of the reflected world with the stored sequence, so a change that makes the simulation nondeterministic fails it. The hash leaves out what animation rewrites each frame, a sprite's frame and the way it faces.
Content // Shipped
QOI and PNG images
QOI encoding and decoding for the game's textures, and a PNG decoder, with an inflate and Adler-32 of its own, for the asset cooker. Each has hand-made test vectors and a fuzz target.
Content // Shipped
Compression, binary JSON, fonts and WAV
KLZ, an LZ4-style block compression, and KBJ, a binary JSON with one encoding per value, both of which round-trip; and readers for BMFont's text format, as AngelCode, Hiero and other tools write it, and for WAV. All four reject malformed input and run under the fuzzer.
Tools // Shipped
Asset cooking
An offline pipeline packs each folder's PNG images, Aseprite sprite sheet exports and bitmap fonts into an atlas: it trims each frame and glyph to its pixels, packs them into square pages with padding and extruded edges, keeps tile sets as pages of their own, and writes QOI pages with a file of where each frame went and the animation clips of the exports' tags, which it checks with the game's own reader, and a file of each font's glyphs. Data files become KBJ. The same files cook to the same bytes, and an incremental cache cooks again only what changed. The game loads an atlas before its first frame and finds its sprites and clips by name, each trimmed frame placed, and mirrored, where its whole cell would be: the demo's walking person comes from an export in Aseprite's format, written by hand, drawn pixel for pixel as before.
Content // Shipped
Levels and prefabs
Prefabs inherit from one another: a prefab's components apply over its base's, and a level's overrides over both, onto one value, and a cycle, a chain of more than 16, an unknown component or a value that does not fit is refused, naming the file and the field, with no entity left behind. A level's entities spawn through their prefabs. The engine reads LDtk 1.5.3's projects and level files, and its own level and prefab files, strictly and under the fuzzer: a project saved by another version of LDtk is refused with the version to save it with, and every refusal names where in the file it is. The cook turns each level of an LDtk project into a level file, by conventions for what LDtk has no notion of: animated and tall tiles from a tile set's custom data, the grid from the Collision layer, and each entity the prefab of its name, its fields overriding the prefab's. What a level file cannot hold, such as a translucent layer or two tiles in one cell, is refused, naming the file and the member. A level loads whole, in place of the last: the engine draws its tile layers over its background, collides with its grid, spawns its tall tiles and its entities, and removes what it made when the next comes. The demo's field is an LDtk project, cooked to the map it was built from, cell for cell, with its trees and rocks as prefabs, and the game now draws it from its level file, frame for frame as it drew the map it built by hand.
Content // Shipped
Pack files
The cook writes every file it cooks into one pack, each file of the same bytes stored once, aligned, and compressed where that makes it smaller, and reads it back with the game's reader before writing it. The engine reads packs strictly and under the fuzzer, through the same virtual file system as loose files: a header and a table of contents checked against their CRC-32 and the limits before anything is allocated, each file found by a binary search of its path's hash, and each file's bytes checked against their CRC-32 as it is read, so that a damaged one is refused, naming its path. Release builds read the pack alone, and the release files and the download ship nothing else; a pack that does not open fails every load with its error, and development builds read the loose files.
Tools // In progress
Hot reload
While the cook watches the assets, one saved is cooked again in about a fifth of a second for the sandbox's, by a cook built once, and the cook rewrites only the files whose bytes changed, each atlas page before the file that names it. The running game will reload what changed, textures, data, levels and shaders, behind the handles it holds, within a second of the save.
Audio // Planned
Audio mixer
A mixer of our own will play WAV and QOA-compressed sound through voices and buses, with constant-power panning, positional attenuation, fades and streaming, and a soak test will count underruns.
Platform // Planned
Audio output on every desktop
Sound will go out through ALSA on Linux, WASAPI on Windows and AudioUnit on macOS, and recover when a device is unplugged or plugged back in.
Graphics // Planned
Bitmap text
Text will be drawn from bitmap fonts, with wrapping, alignment, kerning and color markup.
Tools // Planned
Developer tools
An immediate-mode debug UI will carry a stats overlay, a profiler that exports traces, an entity inspector, a console, debug drawing and time controls, all left out of release builds.
Platform // Planned
Gamepads
Gamepads will work through evdev, XInput and GameController.framework, with hotplugging, deadzones, bindings, and button prompts that follow the device in use.
Simulation // Planned
Game states, menus and settings
A state machine will run the game's screens and level transitions, menus will work with keys, mouse or gamepad, and a settings file will keep what it does not understand.
Content // Planned
Saves
Saves will be written atomically with a backup and a checksum, and migrated from older versions.
Simulation // Planned
Pathfinding and enemy AI
A* with a budget and path smoothing, and flow fields, will steer the sandbox's enemies.
Release // Planned
Crash reports
Every panic will leave a report, and on Windows a native crash will leave a minidump, with symbols archived to read them.
Release // Planned
A complete level
One finished level of the real game will be built with the content pipeline, and played through by someone outside the team on each system.
Graphics // Planned
Metal on macOS
A Metal backend will sit behind the same graphics interface, with every shader in MSL, match the OpenGL golden images, and become the default on macOS.
Release // Planned
Signed packages for every desktop
Packages for Windows, macOS and Linux will be signed and notarized in CI, and smoke-tested from the package before each release.
Release // Planned
Release readiness
Every performance budget will be measured on a min-spec machine, the parsers will get a security pass, players will get documentation, and a release-candidate dry run will walk the release checklist.