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
Tutorials3 min read

Tutorial: first session services

On this page
On this pageWhat people mean by “global”Minimal GameSubsystemSession Kawa scriptLoose runtime spawn (optional)VerifyNext Back to top

The engine has no “global entity” archetype. Cross-scene state and HUD belong on the optional GameSubsystem, which outlives scene replace. Scene JSON is for placeable content only.

Deep reference: Session services.

What people mean by “global”

IntentCorrect seam
HUD / progress / settings that survive Scene.loadGameSubsystem (+ optional session Kawa script)
Runtime actor not bound to an additive layerw.spawn(&.{ .layer = .loose, … }) — shows under Play hierarchy Global group
Fields not editable in the inspectorbehaviour metadata = .{ .runtime_only = true } (still placeable in scenes)

Do not duplicate a “GameManager” actor into every scene JSON.


Minimal GameSubsystem

Export from the game root (sample already does):

zig
// hikari-games/example/src/root.zig
pub const config = @import("config.zig").config;
pub const content_manifest = @import("content_manifest.gen.zig");
pub const GameSubsystem = @import("session.zig").GameSubsystem;

Skeleton (hooks are optional beyond create / destroy; call sites use hi.world() / hi.ui() — do not store a World pointer):

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

pub const GameSubsystem = struct {
    allocator: std.mem.Allocator,
    score: i32 = 0,

    pub fn create(allocator: std.mem.Allocator) !*GameSubsystem {
        const self = try allocator.create(GameSubsystem);
        self.* = .{ .allocator = allocator };
        return self;
    }

    pub fn destroy(self: *GameSubsystem) void {
        self.allocator.destroy(self);
    }

    pub fn onLaunch(self: *GameSubsystem) void {
        _ = self;
        // Register one-time session providers/resources.
    }

    /// Runs once per World — the initial one, and every disposable Play copy.
    /// One subsystem instance serves them all, so key per-World state by
    /// `scope.id` instead of assuming there is only ever one.
    pub fn onWorldAttach(self: *GameSubsystem, scope: hi.WorldScope) void {
        _ = self;
        _ = scope;
        // Reserve UI capacity and install world-local script natives.
    }

    pub fn onTick(self: *GameSubsystem) void {
        _ = self;
        // Draw cross-scene HUD; tick session Kawa if attached.
        // hi.world().updateSessionScript();
    }

    pub fn onSceneLoaded(self: *GameSubsystem, info: hi.SceneInfo) void {
        _ = self;
        _ = info;
    }

    pub fn onSceneWillUnload(_: *GameSubsystem) void {}
    pub fn onTerminate(_: *GameSubsystem) void {}
};

Useful hooks: onLaunch / onTerminate for the session, onWorldAttach / onWorldDetach for each initial or disposable Play World, onTick, onPlayEnded (editor Stop — clear play-ephemeral HUD here, not in unload), onSceneWillUnload / onSceneLoaded, onSceneLayerLoaded / onSceneLayerReady (a manual layer is loaded but not yet shown) / onSceneLayerWillUnload, onSceneReadyStage (none → entities → assets → gpu → world all).

onSceneLoaded means actors spawned only. For a loading screen, wait until hi.world().sceneLoadSnapshot().ready_stage == .all (or handle onSceneReadyStage), then fade out. Stage table: Session services — readiness.

Editor Stop is immediate because the authoring world is retained while a disposable Play world runs. Stop switches back before returning, then retires Play invisibly in bounded slices. Keep expensive shared resources on the subsystem — session-owned resources. Play/Edit rules: Play, Edit, and scenes.

Sample implementation: hikari-games/example/src/session.zig + session_ui.zig (session card, settings, Next Scene / Reload).


Session Kawa script

Attach once the asset store is ready (sample retries from onTick until bytecode is live):

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

const w = hi.world();
const script = hi.AssetRef.must(.script, "asset://./scripts/session");
w.attachSessionScript(script) catch |err| {
    std.log.info("session script: {any}", .{err});
};

Session scripts have no Actor.* — they are not entity scripts. Tick them from onTick via hi.world().updateSessionScript() (no-op outside a play tick; see sample).


Loose runtime spawn (optional)

When you need a live actor that is not authored in the current scene and should not die with an additive layer unload, call hi.world().spawn with .layer = .loose — see First runtime spawn.

Replace scene unload still tears down live world entities; only GameSubsystem state survives. For HUD that must persist across replace, draw from onTick, not from a scene actor.


Verify

  1. Rebuild and Play.
  2. Use the sample HUD “Next Scene” (or your own hi.world().requestSceneLoad) and confirm subsystem fields persist.
  3. Stop in the editor — the document scene returns; session services tear down only on session shutdown.

Next

  • First UI — draw the HUD
  • Play, Edit, and scenes — load rules and Stop semantics
PreviousTutorial: first character controllerNext Tutorial: first UI

Documentation follows the current engine checkout.

Snapshot 86f12d68Source docs/tutorials/first-session-services.md
On this pageWhat people mean by “global”Minimal GameSubsystemSession Kawa scriptLoose runtime spawn (optional)VerifyNext Back to top