DEMIENGINEDOCUMENTATION Everything is free
Project & file formats · Start here

Entities, children, instances, and the full scene document.

Scene files

A scene is one place your game can be in: a level, a menu screen, a boss arena. It is a JSON file that lists the objects that exist there and how they are set up. When the game starts — or when you ask it to change levels — a scene file is what gets loaded and turned into a running world. This page explains every part of a scene document from the ground up.

What is in a scene

Three words cover almost everything:

  • Entity — one thing in the world. A player, a crate, a light, a camera. An entity is an identity with a name and a list of abilities; it is not a picture or a physics body by itself.
  • Component — one ability attached to an entity. A transform (where it is), a sprite (how it looks), a collider (what it bumps into), a script (what it does). An entity is a plain identity; components give it behavior.
  • Scene — the file that holds ordinary entities and prefab placements together, plus an optional heads-up display (the on-screen UI).

Why split things this way? Because you reuse abilities. Ten crates can each have their own transform but share the same sprite component settings, and one player entity can combine a transform, a collider, and a script without any of those knowing about each other.

Every scene document starts with format_version. Documents without it are rejected — the engine needs to know which shape of file it is reading.

A minimal scene

This is the smallest useful scene: one box sitting at the origin.

{
  "format_version": 1,
  "id": "scene://game/main",
  "name": "Main",
  "entities": [
    {
      "id": "crate",
      "components": {
        "Transform2D": { "position": [0, 0] }
      }
    }
  ]
}

What each field means:

FieldMeaning
format_versionAlways required. Declares which document shape this file uses.
idThe scene's stable identity, written as a scene:// URI. The project file and other documents refer to scenes by this ID, never by file path.
nameHuman-readable label shown in the editor and tooling.
entitiesRequired. A shared list of ordinary entities and prefab placements. It may be empty.

The scene ID maps to a conventional file location: scene://game/main lives at scenes/main.scene.json inside the project (here, games/my_game). The project can also give the scene an explicit path. See demi.project.json for how scenes are registered.

Entities

Each entry in entities is one entity:

{
  "id": "player",
  "name": "Hero",
  "enabled": true,
  "persistent": false,
  "tags": ["hero", "saveable"],
  "layer": "player",
  "components": {
    "Transform2D": { "position": [2, 1] }
  },
  "children": []
}
FieldRequiredMeaning
idyesStable identity for this entity inside the document. Scripts, overrides, and parent links all use it. It must be unique in the scene.
namenoDisplay label for editors and debugging. Does not affect gameplay.
enablednoDefaults to true. A disabled entity is kept in the scene but skipped while running — useful for temporarily switching things off without deleting them.
persistentnoDefaults to false. A persistent entity survives when the game moves to another scene, instead of being torn down with the old one.
tagsnoA list of free-form labels. Gameplay code can search for "all entities tagged enemy" without knowing their IDs.
layernoNames a physics layer this entity belongs to, matching a name from the project's physics layers. See Physics layers.
componentsnoAn object whose keys are component names and whose values are that component's settings. See below.
childrennoNested entities. See the hierarchy section.

Components

components is a plain object, not a list. Each key names one component type; the value is that component's authored fields:

"components": {
  "Transform2D": { "position": [4, 2], "rotation": 0, "scale": [1, 1] },
  "Sprite": { "texture": "asset://textures/brick" },
  "BoxCollider2D": { "size": [1, 1] }
}
  • Keys are component type names, such as Transform2D, Sprite, BoxCollider2D, Rigidbody2D, or LuaScript.
  • Values hold only the fields you care about. Any field you leave out uses that component's normal default — you do not have to write every setting.
  • Collider shape comes from the component type (BoxCollider2D, CircleCollider2D, CapsuleCollider2D, …), not from a shape field. Sprite has its own shape field for masking (rectangle, circle, triangle); colliders do not.
  • Reference fields use URI strings. A texture is asset://textures/brick, which points at assets/textures/brick.asset.json. See Asset manifests.

A component's fields belong to that component alone: one entity can carry a transform, a sprite, and a script, and each object is edited independently.

Children hierarchy

Terrain3D stores its authored recipe, including biome regions and sculpt edits. Scene loading, editor scene previews, and prefab previews generate the same terrain surface from that recipe. Generated surface entities use IDs below <owner>/__terrain/ and inherit the terrain transform and ancestor visibility. They remain transient: saving a scene or prefab keeps the recipe, without writing generated meshes into the document or asset folders. Each chunk groups triangles by biome tint while sharing the generator's blended heights and normals; static triangle collision uses the same geometry. Smooth material-surface blending and biome texture references are follow-up capabilities.

Entities can contain other entities in a children array. Children inherit the movement of their parent: when the parent moves, rotates, or scales, the children follow. This is how you build a character out of parts — a body with a weapon and a shadow attached.

{
  "id": "player",
  "components": {
    "Transform2D": { "position": [2, 1] }
  },
  "children": [
    {
      "id": "body",
      "components": {
        "Transform2D": { "position": [0, 0] },
        "Sprite": { "texture": "asset://textures/hero" }
      },
      "children": [
        {
          "id": "weapon",
          "components": {
            "Transform2D": { "position": [0.5, 0] }
          }
        }
      ]
    }
  ]
}

Reading this example:

  • player is the root entity of this little tree.
  • body is a child of player. Its position is local to the player: [0, 0] means "exactly where the player is".
  • weapon is a child of body, half a unit to the right of the body. Move the player and the whole stack moves with it.

Nesting is recursive — a child may have its own children. IDs stay unique across the whole document; nesting is not a naming scope.

Children versus parent. Prefer the children array whenever the objects share the same kind of transform and belong together visually. An explicit parent field on a component is for links that cannot be written as nesting — for example, pointing one prefab's transform at an entity outside it. Same-domain groups belong in children.

Instances and overrides

An instance places a prefab into the scene. A prefab is a reusable template of entities (see Prefab files). Instead of copying a hero's entity tree into every level, you write one small instance entry.

{
  "format_version": 1,
  "id": "scene://game/main",
  "name": "Main",
  "entities": [
    {
      "id": "player",
      "prefab": "prefab://characters/player",
      "overrides": {
        "body.Transform2D.position": [3, 2]
      }
    }
  ]
}
FieldMeaning
idName this placement in the scene. Prefab entity IDs are prefixed with it (see below).
prefabWhich prefab to place, as a prefab:// URI.
overridesOptional per-field changes applied after the prefab expands. Fields you do not override keep the prefab's values.

Ordinary entities and prefab placements share the entities array; placements can also appear under an entity's children. The separate top-level instances form remains accepted, but new authoring should use the unified list.

The placement above expands to player/body and any other prefab-local entities prefixed with player/. The placement ID itself does not create an extra runtime entity. The dotted override changes that body's position; other fields remain inherited. See Prefab files for nested-merge and exact-field override rules.

Entity presets and shorthand

Presets are ready-made entity shapes. You name a preset and give only what differs; the engine expands it into a full entity before the scene is parsed.

{
  "id": "wall",
  "preset": "static_box_3d",
  "size": [4, 1, 0.5]
}

Available presets and their shorthand fields:

PresetWhat it createsShorthand
static_box_3dA solid 3D box that does not move.size — box dimensions.
trigger_sphere_3dAn invisible 3D sphere that reports overlaps.radius — sphere radius.
prop_2dA flat 2D prop with a sprite.texture — asset:// texture to show.
character_3dA 3D character setup (body shape and movement pieces).None — it only expands components.

Shorthand fields are conveniences: size, radius, and texture fill in the matching component fields for the preset that accepts them. If you write an explicit component field yourself, your value wins over the preset's. Use presets when a shape is ordinary; write full components when you need fine control.

The hud field

A scene can name the on-screen UI that belongs with it:

"hud": "main.hud.json"
  • The value is a relative file path to a *.hud.json document, resolved beside the scene file. "hud": "main.hud.json" next to scenes/main.scene.json points at scenes/main.hud.json.
  • When the scene loads, that HUD document becomes the visible interface — health bars, menus, touch sticks.
  • Omit the field when the scene has no interface.

HUD documents are trees of interface nodes in their own file format. ui-prefab:// URIs are a different thing: they name reusable UI prefab trees placed inside a HUD. See HUD files.

Tags, layer, enabled, persistent in practice

{
  "id": "checkpoint",
  "tags": ["checkpoint"],
  "layer": "trigger",
  "enabled": true,
  "persistent": true,
  "components": {
    "Transform2D": { "position": [10, 0] }
  }
}
  • Tags group entities for queries: every entity tagged checkpoint can be found at once. Tags do nothing on their own.
  • Layer assigns the entity to a named physics layer, so collision rules can say "the player collides with world but not with trigger solids".
  • Enabled keeps the entity present but inactive. Flip it at runtime to turn something off and on again without rebuilding the scene.
  • Persistent keeps the entity alive across a scene change. Use it sparingly — most entities belong to one scene.

Validating a scene

From the project root (games/my_game):

demi validate games/my_game

Validation checks the scene and everything it references: prefab URIs, asset URIs, script paths, and child nesting. Fix reported errors before running. For deterministic runs and seeded simulation, see Simulation & seeds.