Rendered actors need an explicit mesh and material in scene JSON when the archetype lists hi.ComponentRender. Paths use asset:// URIs (hi.AssetRef at runtime).
- Unscoped:
asset://./models/cube(catalog → pack; pack must be retained) - Explicit pack:
asset://shared/models/cube
See Game-facing refs and Asset URIs and packs. Mesh / material / texture refs are extension-free stems (no .shinmodel / .png). Scene "model" placeables must end with .model.json (validator).
Deep reference: Assets and Shinra, Shinra asset formats.
1. Entity with render
const hi = @import("hikari_game");
pub const CrateEntity = hi.defineActor(.{
.archetype = "crate",
.components = .{hi.ComponentRender},
});Rebuild so the archetype is in the manifest.
2. Material JSON
Sample: src/games/example/assets/materials/cube.material.json
{
"kind": "com.hikari.material",
"version": "1",
"id": "cube",
"material": {
"name": "cube_material",
"shader": {
"name": "DeferredGeometry",
"package": "_engine/gbuffer",
"entry_points": { "vertex": "gbuffer_vertex", "fragment": "gbuffer_fragment" }
},
"textures": { "albedo": "asset://./textures/crate" },
"params": { "base_color": [1, 1, 1, 1] }
}
}Shinra turns source textures/models into .shintexture / .shinmodel (and packs). Point materials at logical stems, not raw .png.
3. Scene actor
Scene document is flat version 1. Capability blocks live under "components". The scene must list every retained pack in packs:
{
"kind": "com.hikari.scene",
"version": 1,
"id": "…",
"name": "My Level",
"packs": ["my_level", "shared"],
"actors": [{
"id": "crate_01",
"archetype": "crate",
"transform": {
"position": [0, 0.5, 0],
"rotation_euler": [0, 0, 0],
"scale": [1, 1, 1]
},
"components": {
"render": {
"mesh": "asset://./models/cube",
"material": "asset://./materials/cube"
}
}
}]
}List shared (or whatever pack holds cube art) in packs. Put exclusive level art in the primary pack via configs/layout.json includes. Sample: scenes/physics_playground.json.
Multi-material models (placeable)
Cook merges glTF primitives that share a material into one slot, then emits companions with unscoped refs (asset://./…). Place the model with a single actor:
{
"id": "prop",
"name": "MosquitoInAmber",
"archetype": "empty",
"transform": { "position": [0, 1, 0], "rotation_euler": [0, 0, 0], "scale": [1, 1, 1] },
"components": {
"render": {
"model": "asset://./scenes/mosquito_in_amber/models/MosquitoInAmber.model.json"
}
},
"script": { "path": "asset://./scripts/cinematic_prop_rotate" }
}One entity submits N draws (one per material slot). Optional components.render.materials[] overrides slot materials. Samples: scenes/material_samples.json (both Khronos multi-slot models side by side).
Soft failures (expected)
| Missing / failed | Placeholder |
|---|---|
| Mesh | Error cube |
| Material / shader | Pink error_material |