wasmcart
Write games in Rust. Ship the smallest carts there are.
Freestanding wasm32-unknown-unknown: no runtime to embed, no JS glue, no wasm-bindgen. Just structs, constants and one macro.
Small enough that the number is the reason to pick it:
examples/hello 7,677 bytes wasm 1 import (env.wc_log)
examples/hello_gl 1,905 bytes wasm 22 imports (env.wc_log + 21 gl.*)
The GL cart is under 2 KB because there is nothing to carry: no interpreter, no garbage collector, no standard library it did not ask for.
Everything below lives in wasmcart/wasmcart-rust.
rustup target add wasm32-unknown-unknown
cargo add wasmcart
Then in Cargo.toml. The release profile is what keeps carts small, so it is worth copying as-is:
[lib]
crate-type = ["cdylib"]
[profile.release]
opt-level = "z"
lto = true
panic = "abort"
strip = true
codegen-units = 1
Not an excerpt. This is the entire program:
#![no_std]
use wasmcart::*;
wc_cart!(320, 240);
#[no_mangle]
pub extern "C" fn wc_init() {
wc_log("hello from rust");
}
#[no_mangle]
pub extern "C" fn wc_render() {
let buf = fb();
for (i, px) in buf.iter_mut().enumerate() {
*px = 0xFF00_0000 | (i as u32 & 0xFFFF);
}
}
wc_cart!(w, h) declares every buffer the ABI needs, the live wc_info_t, wc_get_info, and a panic handler. You write wc_init and wc_render. Notably, a cart author writes no unsafe around a mutable static.
cargo build --release --target wasm32-unknown-unknown
npx wasmcart pack --wasm target/wasm32-unknown-unknown/release/my_game.wasm \
--name my-game --width 320 --height 240 -o my-game.wasc
npx wasmcart my-game.wasc
#![no_std] and a freestanding target. Nothing is embedded, nothing is shimmed, and the wasm contains only what your code reached for.
The macro owns the mutable statics the ABI requires, so the buffers reach your code as ordinary slices. Writing a cart takes no unsafe.
GL entry points are plain WASM imports, declared at compile time as the ABI requires. The GL example draws through them in under 2 KB.
Your code is the cart. There is no interpreter between the game loop and the host, which is the whole trade the compiled path makes.