Builtin Library
README.md
scene
Work with the live scene across its whole lifecycle: start one from a template, understand its structure, reshape its player, clean it, and set it as the world's entry point.
The player model
A scene is either playerless ("none") or spawns a player per
joining user ("spawns"). The player is defined by a PlayerPrototype
subtree — a body (the avatar a joining user becomes) and a camera rig. Zero
is like Roblox here: the default character is a socket a joining player's
own avatar replaces, so reuse the canonical player setup rather than
hand-rolling one — a divergent player breaks multiplayer. scene.summary
and scene.tree always report the scene's player intent, so you can see a
scene's type without knowing this tool exists.
Start a scene
- create — create a NEW scene from a typed template (
empty,flat,player,menu) and load it. Omit the template to get the catalog of what each contains.opts.startup = truealso makes it the world's entry scene. The starting point is a choice, not a scene handed to you silently. - setStartup — make the currently active scene the world's startup scene, so it survives world reloads. No argument, no clear.
Understand a scene
- tree — the entity hierarchy as an indented tree, led by a one-line player-state header. The quick "what is the current structure" view.
- find — the single entity-discovery tool over the whole live
population. Search by
name,component, orattribute(each a list), scope by hierarchy or scene, and add projections withinclude:transform(position,rotation,eulerAngles,scaleas arrays, readposition[1]),componentValues(each component's live field values),attributes,scriptComponents. Every match carriescomponents(the component names) without one. Returns{ matches, total, truncated, searchedAxes }. - summary: entity + root counts, the top-level rows (at most
limit, 20 when omitted), the active camera, the player setup (intent + counts + the verb to change it), and the world's startup scene.underscopes the counts and rows to the subtrees of named entities, andfieldskeeps only the named fields, so{ fields = { "entityCount" } }answers the count alone. - list — the SCENES you can load, so you find one by name instead of
guessing.
scopefiltersworld(default, this world's own scenes),library(builtin@builtin::templates / demos / canonical setups), orall; each entry says whether it is currently loaded / active. - loadedLayers — the scene LAYERS composing the live scene right now:
the root scene plus any additive overlays (editor UI, effect passes),
each with its backing scene, status, visibility, and additive flag. A
layer whose load produced failures reads
status = "partial".
See what a load did, and what a scene costs
- observe — what every load did and what each loaded scene costs.
lastLoadis the last load's report: what it produced, the root it replaced and the overlays that went with it, the entity counts on each side, the milliseconds each phase took, and every failure with the entity, component or lifecycle hook it is about.layerscounts what the engine attributes to each layer,costis each layer's per-frame entrypoint tick summed across the windowwindowreports. - whyPartial — why a layer is not whole: the nearest cause from a closed set, the engine's own words for it, and the full failure list. The answer to "the scene loaded but something in it is missing".
- cost — which loaded scene is eating the frame time, ranked by what
each layer's entrypoint tick costs. A scene entrypoint's per-frame
update/editorUpdateruns on the scheduler rather than as a component, soprofiler.scriptsdoes not list it; this does. Passtrueto open a fresh window, let frames pass, then call again.
Reshape the player
-
player — read the setup, flip the typed intent between
"spawns"and"none", and reshape:bodyadopts an entity or an avatar asset ref,camerawires an entity carrying a Camera,behaviorsets the player camera's behavior to anycameraBehaviorcomponent."none"removes the prototype and spawns;"spawns"authors the canonical setup when missing. -
spawns — the spawn POINTS: where joining players arrive, as opposed to
player, which decides whether they arrive at all and what they become. No argument reports every PlayerSpawn with its transform, the prototype it instantiates (and whether that reference still resolves), and its team / role / maxPlayers / spawnPolicy / placement."add"places one,"set"reconfigures one (omitted fields keep their value),"remove"deletes one;opts.spawnpicks WHICH when the scene has several. A spawn's transform is where a body lands and its forward axis is the heading it faces — the edit-mode overlay draws that ring, arrow and standing capsule.
Change the content
- clean — clear the scene down to a protected keep-set. By default only
the player setup survives (never orphaned);
keepprotects ascene.findselection (e.g.{ component = { "Light" } });keepPlayer = falsewipes the player too;dryRunpreviews. Only the active scene layer is touched. - remove — delete entities by name, id, array, or a
scene.findquery, subtree-deep. The default floor is the entity namedground. - save — save a loaded scene back to its own
scene.json; a no-arg call reuses the last scene name. - load — load a scene snapshot into the live world.
- reload — re-run a loaded scene's build after editing its entrypoint.
loadof an already-loaded, unchanged scene is an idempotent no-op; this rebuilds it, in edit mode. Omit the name to reload the active scene. A rebuild saves the scene, as a write tobuild.luaudoes, soscene.jsonholds what the reload built and the next play loads it. A library scene (under/libs/) is rebuilt in the live scene alone. - replace — replace a loaded scene's content with another scene's
content, keeping the target's identity. Supports
dryRun.
Maintenance
- migrate_v6_to_v7 — convert a v6 scene's
scene.jsonto the v7 format in place. User-initiated only.
World mode (play/edit) and additive layers are wld; accepting or
rejecting play-mode changes is sceneAuthoring.