What you need for a new game package the editor and Kaji can open. The sample under src/games/example/ is the reference layout.
Deep reference: Project file, Build and packaging, Frontends and drivers.
Layout
my_game/
hikari.project.json # identity only (kind, version, id, name, source, assets, content_dirs)
configs/
game.json # window + startup.scene
render.json # render pipeline
drivers.json # driver recipe
editor.json # editor recipe
packaging.json # kaji --package identity
input_actions.json # authored actions + default bindings (config://)
packaging/
icon.png # used by kaji --package (optional macos.icon = Icon Composer .icon)
src/
root.zig # exports config, content_manifest, optional GameSubsystem
config.zig # ProjectConfig Zig defaults
entities/ # conventional; any .zig under src/ is discovered
*.zig # defineActor / defineComponent exports
scenes/
main.json
assets/
materials/ models/ textures/ scripts/ shaders/ …hikari.project.json is identity only — durable id (UUID), source, assets, optional content_dirs, optional engine_sdk (omit or "bundled" → packaged SDK or parent walk). Zig ProjectConfig supplies defaults; present fields in configs/*.json win. Shipping identity is configs/packaging.json (optional nested editor for project-bound editor packages). The standalone editor (kaji editor with no --project) uses engine-owned src/hikari/editor.project.json (Project file).
Minimal project descriptor (match sample src/games/example/hikari.project.json):
{
"kind": "com.hikari.project",
"version": "5",
"id": "b0d18223-4b45-4611-b17f-fcf4175a51b7",
"name": "My Game",
"source": "src",
"assets": "."
}Minimum Zig exports
// root.zig
pub const config = @import("config.zig").config;
pub const content_manifest = @import("content_manifest.gen.zig");
// optional:
// pub const GameSubsystem = @import("session.zig").GameSubsystem;// config.zig — Zig defaults (solo configs/*.json override field-by-field)
const hi = @import("hikari_game");
pub const config: hi.ProjectConfig = .{
.game = .{
.window = .{ .title = "My Game", .width = 1280, .height = 720 },
.render = .{ .look = .{ .tonemap = .aces } },
.drivers = .{ .physics = "tenkai3d", .scripting = "kawa", .game_ui = "hikari" },
},
// Editor viewport render/drivers inherit the game recipe at compose —
// author those on `.game` (or configs/render.json / drivers.json), not here.
.editor = .{
.window = .{ .title = "My Game Editor", .width = 1600, .height = 1000 },
},
.startup = .{
.scene = "scenes/main", // extension-free stem (no .json / .shinscene)
},
};Optional override in configs/game.json (JSON wins when present):
{
"kind": "com.hikari.config.game",
"version": 1,
"startup": { "scene": "scenes/demo" }
}Copy configs/input_actions.json and a tiny scene from the sample, plus one *_entity.zig (even empty).
Build and open
bin/kaji/kaji editor --workspace="$PWD" --project=/path/to/my_game --type=dynamic --config=debug --runOr open the editor without --project and use the project selector. Generated editor state lands in my_game/.engine/ — do not commit it.
Gotchas
- Prefer
--project=(never rely on a bare positional path through Kaji). - Author under the project assets root — never into packaged
bin/.../data/scenes. - After changing
Entity/Worldlayouts in the engine, fully rebuild the editor for dynamic games (not only Recompile). See Dynamic editor recompile.