Skip to content
hikari
RenderingEditorAIToolchainDocumentation
Download

© 2026 Flying Rat Studio.
All rights reserved.

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

Document schemas

On this page
On this pageWhat existsThe envelopeWho checks whatWhere shapes liveAdding a kindChanging a shapeGame data Back to top

Every JSON file the engine, editor, Shinra or Kaji read is a document kind: a file with a kind tag (com.hikari.material), an integer version, and a shape described by a JSON Schema (draft 2020-12) rendered from the Zig type that parses it. The rendered files live in src/hikari/schemas/ and are staged into every project as <project>/.engine/schemas/ by the editor when it opens the project (the folder is derived output under the ignored .engine/; a fresh clone has it after the first editor open). Read the schema before writing a document by hand or from an agent; the editor, the cook and the MCP tools all check against it.

What exists

FilePurpose
schemas/document_kinds.jsonThe registry: every kind's tag, how a file is recognised (compound suffix such as .material.json, a fixed project path such as configs/render.json, or the kind tag of a bare .json), current version, whether the envelope may be implied, the cooked companion suffix, and the schema file name.
schemas/<tag>.v<N>.schema.jsonOne current schema per kind. $id is urn:hikari:schema:<tag>:v<N>. Nested shapes are $defs; every object is additionalProperties: false unless the type says otherwise (game components under components, free-form slot maps).

Kinds today: scene, prefab, material (with the embedded material graph), model document, particle system, animation graph, sprite atlas, UI document, localization catalog, import-settings sidecar (.shinmeta.json), project descriptor, plugin package and project plugins, gameplay tags, and the nine configs/*.json documents.

The envelope

An envelope fragment (add the document-specific fields):

json
{
  "$schema": "../../.engine/schemas/com.hikari.material.v1.schema.json",
  "kind": "com.hikari.material",
  "version": 1
}
  • kind and version are required. version is a positive integer matching the registry’s current version. Older and newer versions are refused.
  • $schema is a hint the editor stamps (relative path to the staged copy). Every reader ignores it.
  • Two kinds allow an implied envelope as part of their authoring format: localization catalogs and .shinmeta.json sidecars read as version 1 when the envelope is absent, and the editor stamps it on save.
  • The sidecar's wire shape is assets/meta/sidecar_json.zig, mirroring what Shinra reads. The inspector's field table is a projection of it: a comptime lock refuses a row that names no wire field and a wire leaf with no row (or waiver), and a Shinra test validates what serde writes against the schema. An inspector save overlays its rows onto the file as it is on disk, so hand-authored blocks it does not model (material_overrides, spatial_clusters) survive.

Who checks what

ReaderBehaviour
Editor (EditorContent.readText, Config.load, scene open)Checks the current (or implied) envelope, validates against the schema and logs each issue as a warning with its path ($.material.params.metalic: unknown property 'metalic' (did you mean 'metallic'?)). A document with a typo still opens; the next save writes it canonical.
Editor writes (EditorContent.writeText, Config.write, project settings)Stamp $schema, kind and the current integer version first, keep every other key and number token as written. A file that names another kind is written untouched.
Shinra cook and watchRefuse a document whose envelope is not current (or implied) or that fails the schema, naming the path. shinra validate <file-or-dir>… runs the same check from the command line; fixed project files (configs/*.json, hikari.project.json) classify by where they sit, and a file named on the command line that matches no kind fails rather than being skipped.
KajiReads configs/layout.json, configs/packaging.json and hikari.project.json and takes their versions from the registry. Kaji never touches .engine/schemas/; the editor stages it on project open.
MCPdocument_schema_get lists kinds or returns one schema; hikari://schema/documents is the same list as a resource. asset_document_get / asset_document_edit report schema_issues and refuse a patch that breaks the shape.

Where shapes live

The Zig struct std.json parses is the schema. Reflection turns fields into properties, a field without a default into a required property, ?T into an optional-or-null property, enums into enum lists and [N]T into fixed-length arrays. Three declarations add what reflection cannot see:

zig
pub const Document = struct {
    kind: []const u8,
    version: u32,
    capacity: u32 = 65_536,
    emitters: []const Emitter,

    pub const schema_doc = "GPU particle system.";                       // object description
    pub const schema_additional_properties = false;                        // default; true allows extra keys
    pub const schema_meta = .{                                             // per-field constraints
        .capacity = .{ .description = "Total particles.", .minimum = 1 },
        .texture = .{ .format = "asset-ref" },
    };
};

A type with its own jsonParse provides pub fn jsonSchema(arena) !std.json.Value. A table-driven shape (the import-settings sidecar, the UI node vocabulary) builds its body from the same table the editor uses. Every document struct must be named: an anonymous struct's type name is numbered per compilation and would make the rendered file unstable.

KindZig shape
scene, prefabscene/scene_json_loader/json_types.zig (SceneJsonRoot, PrefabJsonRoot)
materialassets/material_asset.zig (MaterialJsonRoot; node kinds from editor/material_graph/nodes.schema.json)
model documentassets/formats/model_doc_json.zig
particle systemassets/formats/particle_json.zig (Shinra's serde structs are the parser; a Shinra test holds the two to one field set)
animation graphassets/formats/animation_graph_json.zig
sprite atlasassets/formats/sprite_atlas_json.zig
UI documentui/document/document_json.zig (node vocabulary rendered from ui/document/spec.zig)
localizationassets/formats/localization_json.zig
import sidecarassets/meta/schema.zig (Document.jsonSchema from the field table)
project descriptorproject_descriptor.zig
plugin manifestssdk/src/plugins/manifest_json.zig (import-free; the build-side parser is held to it by fixtures/full_manifest.json)
gameplay tagsscene/world/world_tags.zig (CatalogJson)
configssdk/src/project_config/*.zig and input/input_*_json.zig

The binding table is src/hikari/src/assets/document_schemas.zig; the registry is sdk/src/document_schema/registry.zig. Shinra embeds the rendered files through its build.rs and classifies with shinra::schema; Kaji reads them through DocumentKinds.

Adding a kind

  1. Add a registry row (sdk/src/document_schema/registry.zig): tag, suffix / fixed file / bare tag, current = 1, envelope policy, cooked suffix if Shinra cooks it.
  2. Bind it (assets/document_schemas.zig): the Zig struct, optional extra_defs.
  3. Render: from src/hikari, zig build generate-document-schemas, and commit schemas/.
  4. If Shinra cooks it, add the AuthoringKind variant and its cook; the schema::tests bijection test refuses a mismatch. If the editor lists it, map it in editor_content.diskKindOf.

The tests refuse a registry row without a binding, a stale rendered file, an anonymous document struct, and a Shinra kind set that differs from the registry's cooked rows.

Changing a shape

  • Adding an optional field with a default keeps the version. Re-render; the stale-file test tells you when.
  • Removing, renaming or retyping a property bumps current. Update authored documents and regenerate the schema in the same change. Every reader accepts only the current version (or an implied envelope where allowed); there is no migration chain or compatibility range.

Game data

Game tables read through hi.json are not registry kinds, but hi.json.schema(T, allocator, .{ .id, .title }) renders the same JSON Schema for a game's own table type, so a project can publish shapes for its content://…json files the same way.

PreviousAsset formats (Shinra pipeline)Next UI and editor

Documentation follows the current engine checkout.

Snapshot 86f12d68Source docs/systems/document-schemas.md
On this pageWhat existsThe envelopeWho checks whatWhere shapes liveAdding a kindChanging a shapeGame data Back to top