🦉Odin is a modern take on C, aimed squarely at games. Explicit, data-oriented, and pleasant to read.
- Template: cart_odin - press "Use this template" and you have a working game.
- Docker image:
ghcr.io/notnullgames/null0-cart-odin:latest - Your code:
cart/main.odin, compiled with odin, freestanding wasm32 - Bindings:
carts/odin/null0/null0.odin(baked into the docker image for you) - WASI is available, so ordinary file and stdio calls work.
- See carts made with Odin
- API docs for Odin
building
You do not install odin, freestanding wasm32 - 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-odin:latest mygameThe template wraps that in npm start, which also serves the result and rebuilds when you save.
Odin notes
import null0 "null0".
a cart, in Odin
This is carts/odin/simple/main.odin in the engine repo - the same file CI builds into the cart below, so it always compiles.
package main
import null0 "null0"
@(export)
load :: proc "c" () {
null0.clear(null0.BLUE)
null0.draw_circle(100, 100, 50, null0.RED)
null0.draw_text(null0.FONT_DEFAULT, "hello from Odin", 170, 92, null0.WHITE)
}
// callbacks (optional - implement as needed)
//
// @(export)
// update :: proc "c" () {}
carts/odin/simple/main.odincallbacks
A cart implements the callbacks it cares about. In Odin they look like this:
@(export) load :: proc "c" () {}See anatomy of a cart for the full list and what each one is passed.