Skip to content

Writ

Native speed. Familiar syntax. Scripting for games.

Statically typed

Catch mistakes at compile time, not during a play session. No runtime type errors.

Clean Rust interop

Derive WritObject on any Rust struct. Pass it straight into scripts — no wrappers, no copying.

Sandboxed by default

Scripts get zero access until you register it. File I/O, networking, syscalls — all opt-in.

Hot reload

Swap script bytecode mid-session without restarting. VM state and live coroutines survive.

Coroutines

yield suspends a function and resumes it next tick — no threads, no callbacks, no state machines.

Familiar syntax

Classes, structs, traits, enums, and when — if you know C# or GDScript, you’ll feel at home in minutes.

struct Vec2 {
x: float
y: float
func length() -> float {
return sqrt(x * x + y * y)
}
}
class Player extends Entity {
public health: float = 100.0
set(value) { field = clamp(value, 0.0, 100.0) }
public func takeDamage(amount: float) {
health -= amount
if health <= 0 { die() }
}
func respawn() {
yield seconds(3.0) // wait without blocking the host
health = 100.0
setActive(true)
}
}
use writ::Writ;
let mut vm = Writ::new(); // create a sandboxed VM
vm.set_tick_source(|| engine.delta_time()); // drive coroutine timers from your engine
vm.load("scripts/game.writ").unwrap(); // compile and load a script
vm.call("onStart", &[]).unwrap(); // call any top-level function by name