In this guide
- Entities & componentsWhat an entity is, how components attach, and hierarchy rules.
- Prefabs & instancesReusable compositions, overrides, and ID expansion.
- Assets & stable IDsURI schemes, conventional paths, and why IDs never change.
- Source vs generatedWhat to edit, what to ignore, and where saves live.
Projects, scenes, entities, components, prefabs, assets, and packages.
Core concepts
DemiEngine games are readable, versioned documents. The editor and the CLI read the same source; nothing required to ship a game lives in editor-only state.
Concept map
| Concept | Purpose | Identity |
|---|---|---|
| Project | Game-wide settings, scene list, input, physics layers, build metadata | demi.project.json |
| Scene | A set of entities loaded together | scene://game/main |
| Entity | An object with a stable ID and components | player, wall_north |
| Component | Data describing one capability on an entity | Transform3D, MeshRenderer, Sprite |
| Prefab | Reusable entity composition with per-instance overrides | prefab://doorway |
| HUD / UI prefab | Screen-space interface tree / reusable UI subtree | *.hud.json, ui-prefab://button |
| Asset | Imported resource referenced by stable identity | asset://textures/brick |
| Package | Installable Lua modules or assets shared across projects | demi.gameplay.health |
| Script | Lua gameplay attached to an entity | script://scripts/player.lua |
Stable identity and URIs
Every durable document keeps format_version. References use URI schemes, never array positions or editor-only handles:
scene://namespace/main→scenes/main.scene.jsonprefab://characters/player→prefabs/characters/player.prefab.jsonui-prefab://controls/menu_button→ui/controls/menu_button.ui.prefab.jsonasset://textures/brick→assets/textures/brick.asset.jsonasset-group://level_one→assets/level_one.asset-group.jsonscript://scripts/player.lua→scripts/player.lua
Project scene entries may omit path when the conventional path can be inferred from the scene ID. Explicit paths remain valid.
Entities and hierarchy
Entities carry a stable document-wide ID, optional name/tags/layer, and a components object. Prefer children arrays for visually meaningful local hierarchies:
{
"id": "house",
"components": { "Transform3D": { "position": [0, 0, 0] } },
"children": [
{ "id": "roof", "components": { "Transform3D": { "position": [0, 2, 0] } } }
]
}
IDs stay document-wide; nesting is not an ID namespace. Keep explicit transform parent for cross-prefab or cross-scene relationships that cannot be nested in the authored document.
Transform parents must share a dimensional domain: Transform2D, Transform3D, or IsoTransform. Mixed domains and conflicting explicit parents are validation errors. Maximum nesting depth is 128.
Components, not frameworks
A component is authored JSON data for one capability on an entity. Examples: Sprite, SpriteAnimator2D, Tilemap2D, Camera2D, Rigidbody2D, MeshRenderer, AnimationPlayer3D, CharacterController3D, Fracture3D, AudioSource, LuaScript.
Fields you omit use the component’s defaults, so newly authored JSON stays short. Write only the values that differ from the default. Existing explicit values are preserved as-is.
Assets contain resources; entities use them. A model asset does not itself have health, collision, or game logic. Add those components or scripts to the entity that renders the model, then save the composition as a prefab.
Lua gameplay
Gameplay rules live in Lua. Import the services you need and call them through the returned table:
local Input = require("demi.input")
local Transform3D = require("demi.transform3d")
local x, y = Input.vector("move") -- -1 … 1 per axis
local px, py, pz = Transform3D.get_position("player")
Optional gameplay packages install Lua modules under dotted namespaces such as demi.gameplay.health or demi.network.session.
See Lua scripting and the Lua API reference.
Source, generated, and writable data
- Source — scenes, prefabs, scripts, asset manifests, data, project files. You edit these.
- Generated — cook output, imported generated sources, fracture geometry, installed packages under
.demi/. Never hand-edit; never commit build outputs. - Writable — game saves and caches use platform user-data/cache directories, never the application or cooked source directory.
Determinism
Simulation uses a project-fixed timestep (default 1/60) with a capped number of fixed steps per frame. Randomness is seeded from the project. Physics contacts are dispatched in a stable order. Input can be recorded and replayed. These rules make runs, replays, and E2E tests comparable.
Where to continue
- Project & file formats — concrete JSON shapes.
- Capabilities — what is stable versus experimental.
- Packages — reusable gameplay and assets.