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.


← All docs Edit this page