Skip to content
hikari
RenderingEditorAIToolchainDocumentation
Download

© 2026 Flying Rat Studio.
All rights reserved.

Explore the engineDocumentationContributorsDownloadLicenseBack to top
Documentation / Guides
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
Guides6 min read

Hikari Plugin API

On this page
On this pageOne product name; three domainsComposition in one pageChoose your domainEditorChromeScene transactionsGameplayPackage settings (hi.settings)Open components and the inspectorTyped plugin-to-plugin dependenciesRenderingThreading and lifetimeRelated docs Back to top

Product front door for author-facing plugin contracts. Composition (manifests, roles, packaging) lives in Plugins.

One product name; three domains

There is no runtime hi.plugin mega-vtable. Plugins compose into the game module, then call typed SDK surfaces:

DomainSurfaceThreadingLifetime
Editorhi.editorEditor main / UI thread onlyGame-module generation; chrome frozen after freezeChrome
Gameplayhikari_game + lifecycle Plugin + hi.settingsGame thread (and existing component rules)Process / scene as today
Renderinghi.render()Register on game thread (onLaunch); frame callbacks on render threadRegistration for module generation; frame resources frame-scoped
text
                    Hikari Plugin API  (product name + docs)
                    ┌─────────────────────────────────────┐
                    │  Source composition (unchanged)     │
                    │  hikari.plugins.json / plugin.json  │
                    └──────────────┬──────────────────────┘
           ┌───────────────────────┼───────────────────────┐
           ▼                       ▼                       ▼
     hi.editor              hikari_game               hi.render
      Editor                 Gameplay                 Rendering

Composition in one page

  1. Enable a package in project hikari.plugins.json.
  2. Package hikari.plugin.json declares modules by role (runtime, editor, developer, third_party).
  3. Build composes Zig sources into the game module; native link and staging inputs come from generated hikari-plugin-artifacts.json only.
  4. No runtime Zig package loader.

Full steps and composition rules: Plugins guide.

Choose your domain

NeedStart here
Actions, menus, panels, scene editsEditor · UI and editor SDK
Entities, tick, libraries, settings, open componentsGameplay
Temporal reconstruction; typed post-process slotsRendering · Rendering system

Editor

Chrome

In an editor role module, export registerEditor and always call api.check() first:

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

pub fn registerEditor(api: *const editor.Api) void {
    api.check() catch return;
    // registerAction / menus / toolbar / panels / surfaces …
}

ActionDesc.invoke always receives host-filled ActionContext (playing, has_project, can_author, …). There is no register_command / CommandFn path.

Working sample: hikari-games/example/plugins/example_capability/editor/root.zig.

Scene transactions

Main-thread only. Use hi.editor.scene() → buffer-until-commit EditTransaction → shared host applyBatch (one undo label). Do not hold raw SceneDocument* / EditorApp*.

Builtin-only sketch (matches the example plugin demo):

zig
fn onCreateDemoLight(user: ?*anyopaque, ctx: *const editor.ActionContext) callconv(.c) void {
    _ = user;
    if (ctx.playing or !ctx.has_project or !ctx.can_author) return;
    const scene = editor.scene() orelse return;

    var edit = scene.beginEdit(.{
        .label = "Create Demo Light",
        .expected_revision = scene.revision(),
    }) catch return;
    defer edit.cancel(); // no-op after successful commit

    const actor = edit.createActor(.{
        .name = "Demo Light",
        .archetype = "light", // engine ids are lowercase ("light", "empty", …)
    }) catch return;

    edit.setField(actor, "light.intensity", 0, .{ .number = 5.0 }) catch return;
    edit.setTransform(actor, .{ .position = .{ 0, 3, 0 } }) catch return;
    edit.commit() catch return;

    // Selection is not an undoable document op — post-commit side effect only.
    scene.setSelection(&.{actor}) catch {};
}
RuleBehavior
Live documentUnchanged until successful commit
OpsBuffered until commit; max 64 (shared with MCP)
Mid-tx readsSee committed state only
setSelectionPost-commit side effect; not in the undo stack
Archetype idsCatalog ids ("light"), never UI labels ("Light")

Shared mutation plane with MCP: Editor MCP.

Gameplay

Plugins use the same hikari_game surface as project game code:

  • Lifecycle methods on Plugin (create / destroy / onLaunch / onTick / scene hooks) via compose glue — see Lifecycle hooks.
  • Entities and components under runtime modules (entities / components paths on the runtime module).
  • Explicit native shared libraries via hi.shared_lib when declared as stage-only middleware.
  • Optional compile-time deps via hikari_plugin_options.
  • Package settings via hi.settings (below).

Working open-component sample: hikari-games/example/plugins/example_capability/ registers example_marker (attachable) with document-backed inspector fields (mutation plane / undo). Canonical skeleton: hikari-games/example/plugins/_template/.

Package settings (hi.settings)

Project-owned values for enabled packages, authored in the editor and shipped with the product. Game code reads them; it never writes them. Does not dirty hikari.project.json.

ItemValue
Path<project>/configs/plugin_settings.json (com.hikari.config.plugin_settings v1), staged to the product's data/configs/ with the other configs
AuthoringProject Settings → Plugins and MCP plugins_edit (immediate write)
APIhi.settings — read-only; not hi.plugin_* (no service bus)
Valuespackages.<package_id>.<key>: bool / number / string
BoundaryTyped host API; plugin code never receives filesystem access
json
{
  "kind": "com.hikari.config.plugin_settings",
  "version": 1,
  "packages": {
    "com.hikari.example_capability": { "radius": 8.0, "enabled_feature": true }
  }
}
zig
const package_id = "com.hikari.example_capability";
const radius = hi.settings.getFloat(package_id, "radius") orelse 5.0;
const enabled = hi.settings.getBool(package_id, "enabled_feature") orelse true;
// Strings: getStringAlloc(allocator, …) returns an owned copy.

Absent values return null, so the manifest default belongs at the call site. Per-player preferences are not package settings; store them through hi.config (writable user layer).

Optional schema in the package manifest (drives Project Settings → Plugins package-settings rows when present):

json
{
  "settings": {
    "schema_version": 1,
    "keys": [
      { "key": "enabled_feature", "type": "bool", "default": true, "label": "Enable feature" },
      { "key": "radius", "type": "float", "default": 5.0, "min": 0.1, "max": 100.0 }
    ]
  }
}

Runtime reads do not require the schema. Schema keys and keys already present in configs/plugin_settings.json both surface in Project Settings (immediate write; does not dirty Save / hikari.project.json). A running game module sees an editor write on its next hi.settings read.

Open components and the inspector

Attachable components from game/plugin *_component.zig files register by name. Authors Add Component by registry name; defineComponent reflects supported Data fields into the same normalized authoring schema used by engine components. Data.metadata.properties supplies optional labels, tooltips, ranges, ordering, visibility, and widget overrides. Numeric scalars/vectors of any supported arity, booleans, colors, text, ordinary/optional enums, and typed resources all use the generic inspector path. Resource fields share picker, typed-path, remove, and drag/drop behavior. Runtime field offsets remain a separate generated table for fast live access.

  • One write path (undoable): inspector rows, hi.editor.scene(), and MCP set_field all use component.field paths through the shared mutation plane (scene_mutation → document payload). No live-column / localScalar poke for open-component fields.
  • Live world: document apply re-spawns the actor so decode reloads the new payload; save also runs syncOpenComponentPayloads as a safety net for any other column drift.
  • Undo: begin/write/commit on inspector widgets joins one history transaction (same as builtins).
  • Policy: hidden, read_only, field kind/arity, enum tags, and numeric bounds are enforced at the shared mutation boundary, not only by disabled inspector controls.
  • Runtime cost: schema rows are static per component declaration. There is no per-instance property storage, allocation, lookup map, or tick work; standalone gameplay still uses typed rows and generated offset accessors.

Automated place → edit → save for open components: document tests in editor/scene_document/tests.zig (place edit save open component document round-trip); binding undo in editor/property_binding.zig.

Typed plugin-to-plugin dependencies

Already legal via module deps + @import. Rules:

RuleDetail
Import nameDependents @import the module import name from hikari.plugin.json (e.g. hikari_plugin_example), never package id strings at runtime
Optional"optional": true on a dep + compile-time hikari_plugin_options.enabled("…")
Visibility"public": true|false follows the resolver — private deps are not re-exported
RolesRuntime may depend on runtime / third_party only; editor may depend on runtime / editor / third_party

Package id is for enablement, settings storage, and packaging — not a runtime service lookup key.

Rendering

ExtensionStatusRegister
Temporal reconstructionShipped (native escape hatch)hi.render().registerReconstructionProvider in onLaunch
Typed post-process passesAvailable — five fixed slots + host tinthi.render().registerPostProcessPass in onLaunch

Samples: metalfx_temporal (macOS), fsr4 (Windows), host_tint (after_tonemap host fullscreen tint). Details: dual resolution, plugin post-process.

Threading and lifetime

Call siteThreadNotes
registerEditor, action invoke, panel update, SceneApi / EditTransactionEditor UI / mainNever from game or render thread
Lifecycle onTick / scene hooksGameSame rules as game subsystems
registerReconstructionProvider / registerPostProcessPassGame (onLaunch)
Reconstruction / PP frame callbacksRenderFrame-scoped opaque resources only
show_message / setControl*Editor UICopy api.* during registerEditor; do not keep the registration stack pointer

Game-module reload rebinds callbacks; structural chrome does not change after freezeChrome.

Related docs

DocRole
PluginsComposition, manifests, lifecycle, surfaces table
UI and editorhi.editor ABI table
RenderingReconstruction and PP
PreviousPluginsNext Data-driven content, JSON, and paths

Documentation follows the current engine checkout.

Snapshot 86f12d68Source docs/guides/plugin-api.md
On this pageOne product name; three domainsComposition in one pageChoose your domainEditorChromeScene transactionsGameplayPackage settings (hi.settings)Open components and the inspectorTyped plugin-to-plugin dependenciesRenderingThreading and lifetimeRelated docs Back to top