⚡Zig talks to null0 with no glue at all - its extern declarations are the wasm imports. Manual memory, comptime, and a very small cart.
- Template: cart_zig - press "Use this template" and you have a working game.
- Docker image:
ghcr.io/notnullgames/null0-cart-zig:latest - Your code:
cart/main.zig, compiled with zig, wasm32-wasi - Bindings:
carts/zig/null0.zig(baked into the docker image for you) - WASI is available, so ordinary file and stdio calls work.
- See carts made with Zig
- API docs for Zig
building
You do not install zig, wasm32-wasi - the docker image has it, and the current null0 bindings, baked in. There is nothing in your project to keep in sync with the engine.
docker run --rm --user $(id -u):$(id -g) \
-v ./cart:/src -v ./webroot:/out \
ghcr.io/notnullgames/null0-cart-zig:latest mygameThe template wraps that in npm start, which also serves the result and rebuilds when you save.
Zig notes
- wasm32-wasi executables need a
main, even though null0 never uses it. Keep it empty.
a cart, in Zig
This is carts/zig/simple/main.zig in the engine repo - the same file CI builds into the cart below, so it always compiles.
const null0 = @import("null0.zig");
// zig needs an entry-point for wasm32-wasi executables
pub fn main() void {}
export fn load() void {
null0.clear(null0.BLUE);
null0.draw_circle(100, 100, 50, null0.RED);
null0.draw_text(null0.FONT_DEFAULT, "hello from Zig", 170, 92, null0.WHITE);
}
// callbacks (optional - implement as needed)
// export fn update() void {}
// export fn unload() void {}
carts/zig/simple/main.zigThis toolchain needs an entry point to exist even though null0 never uses it for gameplay. Leave it empty: pub fn main() void {}
callbacks
A cart implements the callbacks it cares about. In Zig they look like this:
export fn load() void {}See anatomy of a cart for the full list and what each one is passed.