Skip to content
hikari
RenderingEditorAIToolchainDocumentation
GitHub
hikari

© 2026 Flying Rat Studio.
All rights reserved.

Explore the engineDocumentationContributorsLicenseBack to top
Documentation / Tutorials
Browse docs
Overview
Tutorials16
OverviewFirst game projectFirst entityAuthored user_data and the inspectorFirst mesh and materialFirst physics body and triggerFirst character controllerFirst session servicesFirst UIFirst input actionFirst messagesPlay, Edit, and scenesFirst runtime spawnFirst motionFirst skeletal animationAssets in Play (soft refs and hot reload)Dynamic editor recompile
Guides16
OverviewDevelopment guideGameplay APIChoosing component storageBuild and packagingProject filePluginsHikari Plugin APIData-driven content, JSON, and pathsScripting with KawaShader authoringTime of dayUser interfaceUI layoutUI widgetsMigration from Unity / UnrealActor and component lifecycle
Systems28
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 governorGPU particlesVisual ZonesVolumetric mediaInputAudioPhysicsMotion KitTemporal KitAssets and ShinraPrefabsAsset residencyAsset formats (Shinra pipeline)UI and editorEditor asset hot reloadEditor Project Selector
Language reference2
OverviewAkari language referenceKawa language reference
Engine overview
Start exploring
  • No matching sections. Try fewer words or another topic.
NavigateEnter Openesc Close
Overview
Tutorials16
OverviewFirst game projectFirst entityAuthored user_data and the inspectorFirst mesh and materialFirst physics body and triggerFirst character controllerFirst session servicesFirst UIFirst input actionFirst messagesPlay, Edit, and scenesFirst runtime spawnFirst motionFirst skeletal animationAssets in Play (soft refs and hot reload)Dynamic editor recompile
Guides16
OverviewDevelopment guideGameplay APIChoosing component storageBuild and packagingProject filePluginsHikari Plugin APIData-driven content, JSON, and pathsScripting with KawaShader authoringTime of dayUser interfaceUI layoutUI widgetsMigration from Unity / UnrealActor and component lifecycle
Systems28
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 governorGPU particlesVisual ZonesVolumetric mediaInputAudioPhysicsMotion KitTemporal KitAssets and ShinraPrefabsAsset residencyAsset formats (Shinra pipeline)UI and editorEditor asset hot reloadEditor Project Selector
Language reference2
OverviewAkari language referenceKawa language reference
Engine overview
Tutorials3 min read

Tutorial: first runtime spawn

On this page
On this pageLayer membershipSpawn from a descriptorVerifyNext Back to top

Scene JSON is not the only way to create actors. Spawn at runtime from session code or an entity when content is dynamic (pickups, VFX hosts, debug helpers).

Deep reference: Session services — layer membership. Related: First session services.

Layer membership

APILayerSurvives additive unload?
Scene-authored actorLoading scene’s layerNo
w.spawn with .layer = .loosenull (loose)Yes (until replace unload / destroy)
w.spawn with .layer = .{ .layer = key }Named layerNo
w.spawn with .layer = .{ .inherit = id }Copied from parentDepends

In Play, the hierarchy Global group lists loose entities (layer_key == null).

Spawn from a descriptor

Game modules spawn through hi.world().spawn with a SpawnDesc. The host returns an ActorRef (EntityId is the same type — prefer ActorRef).

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

const cube_mesh = hi.AssetRef.must(.model, "asset://./models/cube");
const pickup_material = hi.AssetRef.must(.material, "asset://./materials/cube");
const pickup_script = hi.AssetRef.must(.script, "asset://./scripts/pickup");

const w = hi.world();
const id = try w.spawn(&.{
    .archetype = "cube",
    .id = "pickup_01",
    .name = "Pickup",
    .active = true,
    .transform = .{ .position = .{ 0, 1, 0 } },
    .components = .{
        .physics = .{
            .body_type = .dynamic,
            .collider_shape = .sphere,
            .collider_radius = 0.35,
            .mass = 0.5,
        },
        .render = .{
            .geometry = cube_mesh,
            .material = pickup_material,
        },
    },
    .script = .{
        .mode = .override,
        .asset = pickup_script,
        .params_json = "{\"respawn_seconds\":5}",
    },
    .user_data_json = "{\"score\":100}",
    .layer = .loose,
});
_ = id;

Omit id (or pass "") to let the host generate a unique scene id. Prefer stable unique ids when you will look the actor up later — additive loads reject duplicates across layers.

The request can initialize parent, active state, transform, render, physics, camera, light, visual zone, audio, script parameters, and authored component fields. An override is accepted only when the archetype declares that capability. Asset references, JSON, component values, parent/layer handles, and the scene id are validated before the entity is published.

awake and start observe the complete initial state. A failed request is rolled back; it does not leave a partially configured entity in the world. Script mode defaults to the archetype script; use .none to suppress it or .override to replace it.

Kawa uses the same pipeline:

kawa
let pickup = World.spawn({
    archetype = "cube",
    id = "pickup_02",
    position = [2, 1, 0],
    user_data_json = "{\"score\":100}",
    components = {
        physics = { body_type = "dynamic", collider_shape = "sphere", collider_radius = 0.35, mass = 0.5 },
        render = { mesh = "asset://./models/cube", material = "asset://./materials/cube" }
    },
    script = { asset = "asset://./scripts/pickup", params_json = "{\"respawn_seconds\":5}" },
    layer = "loose"
});

Kawa returns an actor ref or nil when validation or spawning fails. script: nil suppresses the archetype default script. parent and inherit_layer accept actor refs; layer accepts "loose" or a loaded layer key.

Open scenes/runtime_spawn_showcase.json for a side-by-side executable example. The red group is spawned by spawn_showcase_zig_entity.zig; the blue group is spawned by assets/scripts/spawn_showcase_kawa.kawa. Each path creates a parented configured prop, a dynamic physics sphere, a runtime light, initial component data, and a configured child script.

scenes/runtime_spawn_showcase inherits the scene-placed anchor’s layer (inherit_layer / .layer = .{ .inherit = anchor }); step through the scene tour on the session HUD to reach it. Use .layer = .loose when the actor must survive additive unload.

Keep cross-scene policy on the subsystem; do not re-place a “manager” actor in every scene JSON.

Verify

  1. Spawn a loose cube from a button or onSceneLoaded.
  2. Additive-load then unload a layer — loose actor remains; layer actors disappear.
  3. requestSceneLoad (replace) — loose actors are torn down with the world rebuild.

Next

  • Play, Edit, and scenes
  • First physics
PreviousTutorial: Play, Edit, and scenesNext Tutorial: first motion

Documentation follows the current engine checkout.

Snapshot cc148c75Source docs/tutorials/first-runtime-spawn.md
On this pageLayer membershipSpawn from a descriptorVerifyNext Back to top