Programming in Zig
Turian is written in Zig and your game scripts are written in Zig too — the same language, the same compiler, no bindings or DSLs to learn.
Compatible editors
Zig has editor support via Zig Language Server (zls):
| Editor | Setup |
|---|---|
| Zed | Built-in Zig support — install the Zig binary and Zed detects it automatically. |
| VS Code | Install the ziglang.vscode-zig extension. |
| Neovim | Use zls with your LSP configuration. |
| Helix | Built-in Zig support. |
| IntelliJ | The Zig plugin provides language support. |
The same zls powers all of them, so you get autocompletion, go-to-definition,
hover types, and inline errors regardless of which editor you choose.
Zig basics
Zig is a general-purpose systems programming language with no hidden control flow, no hidden memory allocations, and no garbage collector. Key concepts you will encounter:
Structs as the building block
There are no classes. A component is a plain struct:
pub const Health = struct {
pub const is_component = true;
max: f32 = 100.0,
current: f32 = 100.0,
};
The pub const is_component = true; marker is what tells the engine to
consider this struct as a component that can be attached to scene nodes.
Without it, the struct is just a regular Zig type — useful for internal data but
invisible to the editor and the component system.
Comptime
Zig blurs the line between compile-time and run-time. The comptime keyword lets
you run arbitrary code during compilation — Turian uses it for component discovery,
GUID resolution, and zero-cost abstractions.
No hidden allocations
std.heap.GeneralPurposeAllocator, arenas, stack allocators — you choose. The
engine supplies allocators through the Frame context so scripts can allocate
without guessing.
Error handling
Errors are values, not exceptions. Functions return tagged unions:
const file = try std.fs.cwd().openFile("config.json", .{});
defer file.close();
Zig in Turian scripts
Your game code lives inside .zig files in your project's assets/ folder. Each
file can export one or more component structs. The editor parses your source
(not a regex) to discover pub const is_component = true markers — only structs
with this marker are considered components.
The engine is imported as a single module:
const engine = @import("engine");
This gives you access to engine.Vec3, engine.Time, engine.Frame,
engine.GameObjectRef, and all built-in types — exactly the same API the engine
itself uses. There is no abstraction layer between user code and engine code.
See the Tutorial for a walkthrough of writing your first component.