Launching hikari-editor without --project boots a full-screen project selector: the engine brand mark, an Open Project… action, and Exit.
hikari-editor # boots the project selector
hikari-editor --project=<path> # opens the project directly (unchanged)Flow
-
No project argument. The native frontends (
src/hikari/src/native_frontends/macOS/main.mm,src/hikari/src/native_frontends/Windows/main.cpp) pass an empty project path through the frontend ABI instead of rejecting the launch. -
Selector boot.
src/hikari/src/application/editor_application.zigmaps the empty path to a nullProject. It skips the game-module compile worker and bootsEditorApplicationwithboot_select_project = trueand null project roots (all project inputs were already optional). The window uses a fixedEditor1280×800 config since there is no project descriptor to read one from. Sessionscene_pathis still anchored at staged<exe_dir>/data/untitled.jsonsocontent_rootis productdata/— renderer device-init loads_engine/shadersfrom that tree even before a game project is open. A bare relativeuntitled.jsonwould derivecontent_root="."and crash on shader load. -
Selection. Open Project… opens the platform's native folder dialog —
NSOpenPanelon macOS,IFileOpenDialogwithFOS_PICKFOLDERSon Windows (src/hikari/src/platform/dialogs.zig). The dialog is modal; cancelling returns to the selector. -
Validation. The chosen folder is opened with
Project.open(src/hikari/src/editor/project.zig), the same code path a normal launch uses:hikari.project.jsonmust exist and becom.hikari.projectversion5with a required durable UUIDid(identity only — session policy lives inconfigs/*.json).engine_sdkmay be a relative path,"bundled", or omitted (<exe_dir>/sdkif present, else walk parents forhikari/sdk). Failures surface as an inline message on the selector:Failure Message descriptor missing That folder has no hikari.project.json wrong kind / version / malformed JSON hikari.project.json is not a valid project descriptor engine SDK missing Engine SDK not found ( <exe>/sdk, ancestorhikari/sdk, or setengine_sdk)anything else Could not open the project — see the console log -
Editor version check. The editor compares
current.version.numberfrom its global identity (src/hikari/src/version.zig) tolast_editor_versioninhikari.project.json. Missing field = first open (no warning). A mismatch shows an Editor Version Changed alert (Open Anyway / Cancel). Cancel returns to the selector; Continue records the new version and proceeds. -
Open. On success the editor writes
last_editor_version, spawns a freshhikari-editor --project=<path>process, and closes itself. A session is composed around one project for its whole lifetime (asset roots, caches, the game-module build), so a process hand-off is the entire "open" implementation — the new process goes through the exact launch path a direct--projectstart uses, including the project's own window config. A direct--project=launch runs the same version check after boot (Cancel closes back to the selector).
Zig toolchain discovery
Game-module compile needs a Zig 0.16 toolchain. Before spawning zig build game-module, the editor runs a discovery phase (resolveZigExecutable in src/hikari/src/editor/project/zig_toolchain.zig) and picks the first usable candidate:
| Order | Source | Notes |
|---|---|---|
| 1 | HIKARI_ZIG_EXECUTABLE | Explicit full path override |
| 2 | <editor_exe_dir>/tools/zig/zig (.exe on Windows) | Bundled SDK only if Kaji staged it via --vendor:zig=…bundle… |
| 3 | PATH | Scan for zig / zig.exe |
| 4 | Platform fallbacks | macOS: /opt/homebrew/bin, /usr/local/bin; Linux: /usr/local/bin, /usr/bin, Homebrew; Windows: C:\Zig, C:\Program Files\Zig |
If none succeed, compile fails with guidance to rebuild with --vendor:zig=fetch+bundle, install Zig 0.16, or set HIKARI_ZIG_EXECUTABLE.
The winner is logged as Zig discovery: <source> plus Using <path> on the compile splash BUILD OUTPUT, and as std.log.info (Zig discovery: <source> → <path>) on the editor console / stderr / --log= file. Sources: HIKARI_ZIG_EXECUTABLE, tools/zig (bundled), PATH, platform fallback.
Packaged .app / Start Menu launches often have a stripped PATH (and no HOME). Shipping a self-contained editor means opting into --vendor:zig=bundle (usually fetch+bundle) at package time so step 2 hits. Without that flag, the editor still builds and packages — it just relies on discovery steps 1/3/4 at runtime. Zig caches are pinned under <project>/.engine/cache/game/zig/{local,global} so GUI launches do not hit AppDataDirUnavailable.
The game-module build also forwards the host product profile so GameModule validation matches the editor binary: -Doptimize=<builtin.mode> (Debug from --config=debug, ReleaseFast from --config=release) and the same -Dprofiler-timing / -Dprofiler-timing-markers / -Dprofiler-timing-pix / -Dprofiler-timing-xcode values baked into hikari_build_options when Kaji built the editor. Those flags appear on the compile splash as Profile …. Game modules compile against the thin hikari_game SDK only (no shared Entity/World layout). Editor recompile always adds -Deditor-contrib=true so projects may export registerEditor / hi.editor; standalone kaji game products leave that flag off (default false) so editor extension code is not compiled in. Details: Game editor SDK.
Where to read logs
| Surface | What it shows |
|---|---|
| Compile splash BUILD OUTPUT | Zig discovery source + path, then live Zig game-module compile lines (also the failure reason) |
| Editor console (bottom dock) | Engine std.log after the splash closes |
| stderr | Same engine log stream — visible when launching from a terminal |
--log=<path> / HIKARI_LOG_FILE | Redirect engine NDJSON log file (default with project: .engine/logs/editor-latest.json; no file on selector-only boot) |
Finder-launched .app bundles have no terminal; use the splash BUILD OUTPUT or relaunch with --log=….
Closing a project
When a project is open, File → Close Project relaunches the editor with no --project argument, landing back in the selector — the same hand-off as opening, in reverse. If the scene document has unsaved changes, the standard unsaved-changes dialog (Save / Discard / Cancel) runs first. The action is a no-op when the editor booted without a project.
Code map
| Piece | Location |
|---|---|
| Selector screen (retained UI) | src/hikari/src/editor/project_selector.zig |
| Boot flag + action handling | src/hikari/src/editor/editor_app/app.zig (boot_select_project); open/relaunch in editor_app/project_lifecycle.zig |
| Optional-project frontend | src/hikari/src/application/editor_application.zig |
| Native folder dialog facade | src/hikari/src/platform/dialogs.zig |
| macOS dialog | src/hikari/src/native/macOS/src/services/Dialogs.m (engineDarwinPickFolder) |
| Windows dialog | src/hikari/src/native/Windows/src/services/Dialogs.cpp (engineWindowsPickFolder) |
The selector follows the compile-splash pattern: a full-screen retained-UI overlay owned by EditorApplication, updated at the top of tick, which early-returns while open so no editor chrome logic runs behind it. Linux has no native frontend yet; dialogs.pickFolder reports no selection there. Folder pick lives in the platform library (engineDarwinPickFolder / engineWindowsPickFolder).