Skip to content
hikari
RenderingEditorAIToolchainDocumentation
Download

© 2026 Flying Rat Studio.
All rights reserved.

Explore the engineDocumentationContributorsDownloadLicenseBack to top
Documentation / Tutorials
Browse docs
Overview
Tutorials17
OverviewPlay, Edit, and scenesFirst UI documentFirst game projectFirst entityComponent properties and the inspectorFirst mesh and materialFirst physics body and triggerFirst character controllerFirst session servicesFirst UIFirst input actionFirst messagesFirst runtime spawnFirst motionFirst skeletal animationAssets in Play (soft refs and hot reload)Dynamic editor recompile
Guides25
OverviewWorking in the editorDevelopment guideGameplay APIActor and component lifecycleThreads, jobs, events, and routinesGameplay AI tasksGame AI: perception and movement playgroundBrain assetsBrain execution for swarm populationsLocalizationGame cursorsChoosing component storageBuild and packagingProject filePluginsHikari Plugin APIData-driven content, JSON, and pathsScripting with KawaShader authoringChoosing and scaling shadowsTime of dayUser interfaceUI layoutUI widgetsMigration from Unity / Unreal
Systems32
OverviewArchitectureApplication lifecycleFrontends and driversPlatforms and supportSession services and cross-scene stateScenes and gameplayActor communication (hi.actors)Game-facing refsSave / replication wire versionCoordinate space and camera conventionsRenderingRenderer architecture mapFrame governorPipeline compilationSkeletal animationGPU particlesVisual ZonesVolumetric mediaInputAudioPhysicsMotion KitTemporal KitUI documentsAssets and ShinraPrefabsAsset residencyAsset formats (Shinra pipeline)Document schemasUI and editorEditor asset hot reloadEditor Project Selector
Language reference3
OverviewAkari GPU ABIAkari language referenceKawa language reference
Engine overview
Start exploring
  • No matching sections. Try fewer words or another topic.
NavigateEnter Openesc Close
Overview
Tutorials17
OverviewPlay, Edit, and scenesFirst UI documentFirst game projectFirst entityComponent properties and the inspectorFirst mesh and materialFirst physics body and triggerFirst character controllerFirst session servicesFirst UIFirst input actionFirst messagesFirst runtime spawnFirst motionFirst skeletal animationAssets in Play (soft refs and hot reload)Dynamic editor recompile
Guides25
OverviewWorking in the editorDevelopment guideGameplay APIActor and component lifecycleThreads, jobs, events, and routinesGameplay AI tasksGame AI: perception and movement playgroundBrain assetsBrain execution for swarm populationsLocalizationGame cursorsChoosing component storageBuild and packagingProject filePluginsHikari Plugin APIData-driven content, JSON, and pathsScripting with KawaShader authoringChoosing and scaling shadowsTime of dayUser interfaceUI layoutUI widgetsMigration from Unity / Unreal
Systems32
OverviewArchitectureApplication lifecycleFrontends and driversPlatforms and supportSession services and cross-scene stateScenes and gameplayActor communication (hi.actors)Game-facing refsSave / replication wire versionCoordinate space and camera conventionsRenderingRenderer architecture mapFrame governorPipeline compilationSkeletal animationGPU particlesVisual ZonesVolumetric mediaInputAudioPhysicsMotion KitTemporal KitUI documentsAssets and ShinraPrefabsAsset residencyAsset formats (Shinra pipeline)Document schemasUI and editorEditor asset hot reloadEditor Project Selector
Language reference3
OverviewAkari GPU ABIAkari language referenceKawa language reference
Engine overview
Tutorials5 min read

Tutorial: first entity

On this page
On this pageSetup checklistZig-onlyActive / enableKawa-only (script-primary)Scripted componentMixed Zig + KawaVerifyNext Back to top

An entity is an archetype (string id) plus a tuple of components. Engine capabilities (hi.ComponentRender, hi.ComponentPhysics, …) and game logic (defineComponent) are listed together. The build recursively imports every .zig under the project src/ into content_manifest.gen.zig; comptime registration picks out defineActor / defineComponent types — you do not maintain a hand registry, and files may live in any subdirectory.

Deep reference: Scenes and gameplay, Scripting with Kawa. API reference: Gameplay API.

Setup checklist

  1. Add a .zig file under the project src/ (any folder; entities/ is conventional, not required).
  2. Export a defineActor value with a unique .archetype string (and any defineComponent types the archetype needs).
  3. Rebuild the game/editor so content_manifest.gen.zig picks the file up.
  4. Place an actor in scene JSON with the same "archetype" and a "components" map (scene document "version": 1).
  5. Cameras look local −Z. Identity rotation at +Z looks at the origin; yaw 180 at +Z looks away. Copy scenes/messaging.json ([0, 5, -14], yaw 180) — see coordinate space.
  6. Press Play in the editor (or run the standalone game) to run component update / scripts.

If the archetype is missing from the manifest, scene load soft-fails to a _missing host instead of aborting. Components listed by an exported entity may remain private declarations: defineActor publishes their types to content discovery, which registers them before the archetype. Export a component separately only when other source files need to import it or when it is not referenced by an entity (for example, a purely instance-addable component).


Zig-only

Minimal marker (sample: empty-style archetypes):

zig
const hi = @import("hikari_game");

pub const BeaconEntity = hi.defineActor(.{
    .archetype = "beacon",
});

With engine capabilities and game logic as components:

zig
const hi = @import("hikari_game");

const BeaconLogic = hi.defineComponent(.{
    .name = "beacon_logic",
    .data = struct {
        speed: f32 = 1,
        state: struct { spin: f32 = 0 } = .{},

        pub fn update(self: *@This(), _: hi.ActorContext, tick: *const hi.TickContext) void {
            self.state.spin += self.speed * tick.dt;
        }
    },
});

pub const BeaconEntity = hi.defineActor(.{
    .archetype = "beacon",
    .components = .{ hi.ComponentRender, BeaconLogic },
});

Components default to .attachable: they work in archetypes and in the editor's Add Component menu. Use explicit .embedded only for fixed composition; it has the same authored fields but cannot be added to arbitrary actors. Populations without actor identity use defineSwarm. See Gameplay API.

Optional lifecycle methods on the logic component data struct: awake, start, update, lateUpdate, fixedUpdate, onCollision, onMessage, onChanged, onDestroy, deinit.

Cross-actor talk and name-keyed fields: hi.actors / Actors.*. Same-actor typed siblings in Zig: ActorContext.get / require. See Actor communication and First messages.

Built-in capability components (engine):

SymbolCapability
hi.ComponentRenderMesh / material draw
hi.ComponentPhysicsBody / collider
hi.ComponentCameraCamera
hi.ComponentLightLight
hi.ComponentAudioAudio source
hi.ComponentVisualZoneVisual zone
hi.ComponentTransformExplicit transform (always present on live entities; rarely listed)

Scene actor (com.hikari.scene document version 1). Capabilities live under "components", not top-level "render" / "physics":

json
{
  "id": "beacon_01",
  "name": "Beacon",
  "archetype": "beacon",
  "transform": {
    "position": [0, 1, 0],
    "rotation_euler": [0, 0, 0],
    "scale": [1, 1, 1]
  },
  "components": {
    "render": {
      "mesh": "asset://./models/cube",
      "material": "asset://./materials/cube"
    }
  }
}

Scene document root uses numeric "version": 1, with actors at the top level. Shinra cooks .shinscene from the same form.

Sample Zig actors to copy: floor_entity.zig, cube_entity.zig, disco_light_entity.zig.

Active / enable

Active / enable trio on the live actor (defaults all on):

SwitchSceneRuntime
Entity"active": falsehi.world().setActive(id, false) — stops update/scripts/messages; gates physics + render
Physics"components": { "physics": { "is_active": false } }hi.world().setPhysicsActive(id, false) — body out of sim
Render"components": { "render": { "is_visible": false } }hi.render().setVisible(id, false) — skip draw

Full rules: Scenes and gameplay — Active / enable trio.


Kawa-only (script-primary)

Declare capabilities and a default script; put game logic in the script only:

zig
const hi = @import("hikari_game");

pub const BannerEntity = hi.defineActor(.{
    .archetype = "banner",
    .components = .{hi.ComponentRender},
    .script = "asset://./scripts/banner",
});

Script (assets/scripts/banner.kawa — extension-free stem in the ref):

kawa
fn start() {
    Debug.log("banner ready: " + Actor.get_scene_id());
}

fn update(dt, total_time) {
    _ = dt;
    _ = total_time;
}

Entity script hooks: start, update, late_update, on_collision, on_message. Scripts do not run in Edit mode — enter Play.

Sample: message_kawa_door_entity.zig + assets/scenes/messaging/scripts/message_door.kawa.

A scene actor may also override the script without changing the archetype:

json
{
  "script": { "path": "asset://./scripts/collision_logger" }
}

(cube_00 in scenes/physics_playground.json does this.)


Scripted component

A script can also live on a component instead of the archetype. The component keeps typed Zig fields (inspector-editable, serialized under "components"), and the script sees them as data:

zig
const hi = @import("hikari_game");

pub const Patrol = hi.defineComponent(.{
    .name = "patrol",
    .script = "asset://./scripts/patrol",
    .data = struct {
        speed: f32 = 2.0,
        radius: f32 = 12.0,
    },
});

pub const GuardEntity = hi.defineActor(.{
    .archetype = "guard",
    .components = .{ hi.ComponentRender, Patrol },
});

One script slot attaches per component instance; an actor with two scripted components plus an entity .script has three slots. A scene actor overrides a component's script inside that component's block:

json
{
  "components": {
    "patrol": { "speed": 3.0, "script": { "path": "asset://./scripts/patrol_aggressive" } }
  }
}

Engine capability builtins and .swarm components reject .script at comptime. Detail: Scripting with Kawa. Working sample: hikari-games/example/scenes/script_interop.json (reactor = Zig data + component script + entity script on one actor).


Mixed Zig + Kawa

Engine builtins already provide bare empty / light / camera. Genre cameras layer logic + script on a new archetype name (sample fly_camera):

zig
const hi = @import("hikari_game");

const FlyCameraLogic = hi.defineComponent(.{
    .name = "fly_camera_logic",
    .data = struct {
        move_speed: f32 = 14,
        // Add authored fields here. Revise the script to read the same fields.
    },
});

pub const FlyCameraEntity = hi.defineActor(.{
    .archetype = "fly_camera",
    .components = .{ hi.ComponentCamera, FlyCameraLogic },
    .script = "asset://./scripts/camera_controller",
});

Scene user_data / component properties seed Zig fields; Kawa can read the same data. Do not redefine host builtins (empty / light / camera / visual_zone).

ModeLogic component(s).scriptAuthored schema
Zig-onlyyesnofrom supported data fields; optional metadata customizes them
Hybridyesyesfrom supported data fields
Script-primarynoyesnone (or inspector-only)
Scripted componentyes (defineComponent.script)per componentfrom that component's fields

Verify

  1. Rebuild: bin/kaji/kaji editor --workspace=$PWD --project=$PWD/../hikari-games/example --type=dynamic --config=debug --run (or your usual product command).
  2. Open the scene, confirm the actor appears in the hierarchy.
  3. Enter Play — component update and Kawa hooks run; entity timing (Profiler → Entity timing) can confirm costs.

Next

  • Cross-scene HUD / state → First session services
  • Draw widgets from an entity → First UI
  • Wire a key → First input action
PreviousTutorial: first game projectNext Tutorial: component properties and the inspector

Documentation follows the current engine checkout.

Snapshot 86f12d68Source docs/tutorials/first-entity.md
On this pageSetup checklistZig-onlyActive / enableKawa-only (script-primary)Scripted componentMixed Zig + KawaVerifyNext Back to top