Components

A component is a plain Zig struct that opts into editor discovery. There is no base class to inherit and no registration boilerplate — a single marker is enough.


Marking a struct as a component

pub const Health = struct {
    pub const is_component = true;

    max: f32 = 100.0,
    current: f32 = 100.0,
};
  • pub const is_component = true; marks the struct for discovery. Set it to false to temporarily opt out without deleting the struct.
  • The editor parses real Zig source (not a regex), so the marker works regardless of formatting, comments, or conditional compilation.
  • The struct must be pub and its name must start with a capital letter.
  • Component type names must be unique across the project. Duplicates are reported and the second definition is ignored.

User scripts live in your project's assets/ folder. After adding or editing a script, click Refresh in the Asset Browser to re-scan.


Supported field types

Public fields with a default value become editable controls in the Inspector.

Type Inspector control
f32 number field
i32 integer field
bool checkbox
engine.Vec3 three-axis vector field
engine.GameObjectRef drop target — drag an object from the Hierarchy
engine.ComponentRef drop target — reference another component
engine.AssetRef drop target — reference an asset

Fields prefixed with _ (e.g. _timer) are treated as private runtime state and are not shown in the Inspector.


Node lifecycle

Every node in a scene follows a deterministic lifecycle from the moment it is loaded until it is destroyed. Components attached to the node receive lifecycle callbacks at each stage.

Loading and activation order

When a scene is loaded, nodes are processed in depth-first traversal order. For each node, the engine:

  1. Constructs the node and all its components (zero-initialised).
  2. Calls awake on every component — the component knows it exists and can set up internal state, but should not assume other nodes are ready.
  3. Calls enable on every component — the component becomes active. If the node starts disabled, enable is deferred until the node is enabled.
  4. Once all nodes are loaded and enabled, calls start on every component in the same depth-first order — at this point every node in the scene exists and every component has been awakened.

Per-frame update

After start, the engine enters the update loop. Each frame:

  1. Calls update on every enabled component — this is where gameplay logic runs (movement, input, spawning). The update order within a frame is deterministic but unspecified; do not rely on one component updating before another in the same frame.

Deactivation and destruction

  1. disable — called when a node is deactivated (e.g. visibility off, parent disabled), either immediately or at the end of the current frame.
  2. destroy — called when a node is removed from the scene. After destroy returns, the component's memory is reclaimed.

Summary

Construct → awake → enable → start → [update × frames] → disable → destroy

Lifecycle hooks

All hooks are optional — implement only the ones you need.

Hook Called when
awake(self) or awake(self, frame: engine.Frame) Object is first loaded — use for self-setup that does not depend on other objects
enable(self) or enable(self, frame: engine.Frame) Object becomes active — good for subscribing to events or starting timers
start(self) or start(self, frame: engine.Frame) Scene starts running — every node in the scene is ready; safe to resolve object references
update(self, frame: engine.Frame) Every frame (preferred) — main gameplay logic
update(self, time: engine.Time) Every frame (legacy)
disable(self) or disable(self, frame: engine.Frame) Object becomes inactive — unsubscribe from events, pause timers
destroy(self) or destroy(self, frame: engine.Frame) Object is destroyed — final cleanup, release resources

The engine.Frame context bundles everything a script needs: frame.time, frame.input, frame.transform, frame.objects, and frame.services. See the Input System page for a full field reference.

engine.Time

Field Type Meaning
.delta f32 seconds since the last frame
.elapsed f32 total seconds since the scene started
.frame u64 frame counter

Built-in components

Built-in components ship with the engine and require no script. Add them via Add Component ▾ in the Inspector. Authoring your own built-in is a contributor task — see Building from Source.


Next steps

  • Follow the Tutorial for a hands-on walkthrough.
  • See the CLI Reference to build and package without the editor.

← All docs Edit this page