---
title: "layers"
description: "The layers namespace — the engine's Luau API reference for layers."
section: "API Reference"
slug: "api-layers"
canonical: "https://origozero.ai/docs/api-layers"
updated: "2026-09-05T23:13:46.619403124+00:00"
tags: ["api", "reference"]
---

# layers

The `layers` namespace — 85 functions.

## globals/layers/active {#globals-layers-active}

```lua
layers.active -> any
```

The root scene's proxy, re-resolved on every read.

**Returns** `any`

## globals/layers/active/clearDirty {#globals-layers-active-cleardirty}

```lua
layers.active:clearDirty(opts?) -> boolean
```

Discard this layer's unsaved edits and respawn the live scene from canonical. Must run in a coroutine.

**Parameters**

- `opts` `table` _(optional)_ — Options

**Returns** `boolean` — True if overlay state was removed.

## globals/layers/active/hasDirty {#globals-layers-active-hasdirty}

```lua
layers.active:hasDirty(opts?) -> boolean
```

True iff any unsaved dirty state exists for this layer — the manifest or at least one per-entity overlay file.

**Parameters**

- `opts` `table` _(optional)_ — Options

**Returns** `boolean` — True when unsaved dirty state exists.

## globals/layers/active/load_additive {#globals-layers-active-load-additive}

```lua
layers.active:load_additive(ref) -> SceneProxy
```

Load a scene as an additive overlay on top of this one, routed through the canonical load path (v6 player/camera config, lighting, entrypoint discovery).

**Parameters**

- `ref` `string` — Scene asset reference to overlay

**Returns** `SceneProxy` — The new overlay layer's proxy.

## globals/layers/active/offReady {#globals-layers-active-offready}

```lua
layers.active:offReady(handle) -> boolean
```

Remove an onReady subscription by its handle.

**Parameters**

- `handle` `number` — Handle returned by onReady

**Returns** `boolean` — True if the subscription was removed.

## globals/layers/active/off_edit_load {#globals-layers-active-off-edit-load}

```lua
layers.active:off_edit_load(handle) -> boolean
```

Remove an on_edit_load subscription by its handle.

**Parameters**

- `handle` `number` — Handle returned by on_edit_load

**Returns** `boolean` — True if the subscription was removed.

## globals/layers/active/off_load {#globals-layers-active-off-load}

```lua
layers.active:off_load(handle) -> boolean
```

Remove an on_load subscription by its handle.

**Parameters**

- `handle` `number` — Handle returned by on_load

**Returns** `boolean` — True if the subscription was removed.

## globals/layers/active/off_load_play {#globals-layers-active-off-load-play}

```lua
layers.active:off_load_play(handle) -> boolean
```

Remove an on_load_play subscription by its handle.

**Parameters**

- `handle` `number` — Handle returned by on_load_play

**Returns** `boolean` — True if the subscription was removed.

## globals/layers/active/off_unload {#globals-layers-active-off-unload}

```lua
layers.active:off_unload(handle) -> boolean
```

Remove an on_unload subscription by its handle.

**Parameters**

- `handle` `number` — Handle returned by on_unload

**Returns** `boolean` — True if the subscription was removed.

## globals/layers/active/onReady {#globals-layers-active-onready}

```lua
layers.active:onReady(cb) -> number
```

Subscribe to this scene reaching the 'ready' state. LATCHED — a callback registered after the scene is already ready fires immediately.

**Parameters**

- `cb` `function` — Called with the SceneProxy once the scene is ready

**Returns** `number` — Subscription handle for offReady.

## globals/layers/active/on_edit_load {#globals-layers-active-on-edit-load}

```lua
layers.active:on_edit_load(cb) -> number
```

Subscribe to THIS scene's load, firing only when it loads with engine.mode == "edit".

**Parameters**

- `cb` `function` — Called when this scene loads in edit mode

**Returns** `number` — Subscription handle for off_edit_load.

## globals/layers/active/on_load {#globals-layers-active-on-load}

```lua
layers.active:on_load(cb) -> number
```

Subscribe to THIS scene's load event (fires only for this layer, unlike the global layers.onLoad).

**Parameters**

- `cb` `function` — Called on this scene's load

**Returns** `number` — Subscription handle for off_load.

## globals/layers/active/on_load_play {#globals-layers-active-on-load-play}

```lua
layers.active:on_load_play(cb) -> number
```

Subscribe to THIS scene's load, firing only when it loads with engine.mode == "play".

**Parameters**

- `cb` `function` — Called when this scene loads in play mode

**Returns** `number` — Subscription handle for off_load_play.

## globals/layers/active/on_unload {#globals-layers-active-on-unload}

```lua
layers.active:on_unload(cb) -> number
```

Subscribe to THIS scene's unload event (fires only for this layer).

**Parameters**

- `cb` `function` — Called on this scene's unload

**Returns** `number` — Subscription handle for off_unload.

## globals/layers/active/promoteDirty {#globals-layers-active-promotedirty}

```lua
layers.active:promoteDirty(opts?) -> string?
```

Promote the dirty overlay to canonical — compose canonical + overlay, write canonical, then clear the dirty state. Raises when the canonical write is refused, leaving the overlay holding this session's edits.

**Parameters**

- `opts` `table` — { to?

**Returns** `string` — Canonical path on success; nil when nothing to promote.

## globals/layers/active/reload {#globals-layers-active-reload}

```lua
layers.active:reload(opts?) -> SceneBuildReport?
```

Round-trip reload — unload then reload the same scene ref, firing the full unload / before-load / load lifecycle, and running the scene's build.luau against what it resolves now. Must run in a coroutine.

**Parameters**

- `opts` `table` — { rebuild?

**Returns** `table` — What the scene's build.luau did — { built = true, content, editorOnly }, carrying { refused, message } when an operation the build ran was refused, or { built = false, reason, message }.

## globals/layers/active/root {#globals-layers-active-root}

```lua
layers.active:root() -> SceneProxy
```

Return the root SceneProxy — walks up the additive-overlay parent chain to the non-additive root layer.

**Returns** `SceneProxy` — The root layer's proxy.

## globals/layers/active/save {#globals-layers-active-save}

```lua
layers.active:save(opts?) -> string
```

Publish the layer's current state to canonical scene.json — the ONLY path that writes canonical (edit/play cycles never save). Additive overlays cannot be saved.

**Parameters**

- `opts` `table` — { to?

**Returns** `string` — Full VFS path of the canonical scene.json written.

## globals/layers/active/set_visible {#globals-layers-active-set-visible}

```lua
layers.active:set_visible(v)
```

Show or hide this layer's entities.

**Parameters**

- `v` `boolean` — Whether the layer's entities are shown

## globals/layers/active/unload {#globals-layers-active-unload}

```lua
layers.active:unload()
```

Unload this layer: despawn every entity attributed to it and remove its slot from SceneLayers.

## globals/layers/active/writeDirty {#globals-layers-active-writedirty}

```lua
layers.active:writeDirty(opts?) -> string
```

Force-drain every pending edit into the dirty overlay directory (deltas only — changed-entity files + manifest); never touches canonical.

**Parameters**

- `opts` `table` _(optional)_ — Write options

**Returns** `string` — Absolute VFS path of the dirty manifest.

## globals/layers/camera {#globals-layers-camera}

```lua
layers.camera -> any
```

The active root scene's camera handle, the same value `layers.active.camera` answers.

**Returns** `any`

## globals/layers/cost {#globals-layers-cost}

```lua
layers.cost() -> { SceneLayerCost }
```

What each loaded scene's per-frame tick costs, attributed to the layer
that owns it — the `update` / `editorUpdate` its entrypoint declares,
timed where it runs. `totalMs` is a SUM across the window
`layers.observe().window` reports, so divide by `calls` (or read `avgMs`)
for the per-tick figure; a tick that runs every frame makes that the
per-frame figure. Call `layers.resetCostWindow()` first to time a
particular stretch. A layer whose entrypoint declares no tick is absent.

**Returns** `{ SceneLayerCost }` — An array of `SceneLayerCost`.

```lua
layers.resetCostWindow(); task.wait(1); for _, c in layers.cost() do print(c.name, c.avgMs) end
```

## globals/layers/find {#globals-layers-find}

```lua
layers.find(ref: AssetRef<scene> | string) -> any?
```

The loaded layer for a scene, matched on guid — the canonical identity,
since display names can collide and paths drift when assets move. A layer
torn down but not yet pumped out of the engine's loaded list reads as gone.

**Parameters**

- `ref` `AssetRef<scene> | string` — A scene `AssetRef`, or an identity string resolved through `asset.ref`.

**Returns** `any?` — The scene proxy, or nil when that scene has no loaded layer.

```lua
local layer = layers.find("scenes.arena")
```

## globals/layers/fireBeforeLoad {#globals-layers-firebeforeload}

```lua
layers.fireBeforeLoad(proxy: any?) -> nil
```

Announce that a scene layer is about to load: clears any pending
unload for that layer slot, marks the proxy loading, and fans out to every
`layers.onBeforeLoad` subscriber. The scene-load pipeline calls this.

**Parameters**

- `proxy` `any` _(optional)_ — The scene proxy about to load.

**Returns** `nil`

```lua
layers.fireBeforeLoad(sceneProxy)
```

## globals/layers/fireLoad {#globals-layers-fireload}

```lua
layers.fireLoad(proxy: any?) -> nil
```

Announce that a scene layer has loaded, fanning out to every
`layers.onLoad` subscriber. The layer is pinned as the active one for the
duration of the fan-out, so entities a subscriber spawns are attributed to
it rather than landing orphaned. The scene-load pipeline calls this.

**Parameters**

- `proxy` `any` _(optional)_ — The loaded scene proxy.

**Returns** `nil`

```lua
layers.fireLoad(sceneProxy)
```

## globals/layers/fireUnload {#globals-layers-fireunload}

```lua
layers.fireUnload(proxy: any?) -> nil
```

Announce that a scene layer is unloading: fans out to every
`layers.onUnload` subscriber, then drops the layer's cached proxy and
per-layer state so the next load of that scene rebuilds from disk. The
unload path calls this.

**Parameters**

- `proxy` `any` _(optional)_ — The scene proxy being unloaded.

**Returns** `nil`

```lua
layers.fireUnload(sceneProxy)
```

## globals/layers/install {#globals-layers-install}

```lua
layers.install() -> nil
```

Install the `layers` global. `layers.active` is exposed as a property
whose every read resolves the current root scene, so it tracks scene
changes without manual invalidation; other keys resolve against this
module. The prelude calls this once at boot.

**Returns** `nil`

```lua
layers.install()
```

## globals/layers/inventory {#globals-layers-inventory}

```lua
layers.inventory() -> { SceneLayerInventory }
```

What each loaded layer holds: the entities the engine attributes to it,
whether it came up whole, and how many failures it carries. `unattributed`
in `layers.observe().totals` counts what exists in the world that no layer
claims.

**Returns** `{ SceneLayerInventory }` — An array of `SceneLayerInventory`.

```lua
for _, l in layers.inventory() do print(l.name, l.entities, l.ok) end
```

## globals/layers/is_loaded {#globals-layers-is-loaded}

```lua
layers.is_loaded(ref: AssetRef<scene> | string) -> boolean
```

Whether a scene currently has a loaded layer — the boolean form of
`layers.find`. A scene counts as loaded from the frame the engine holds a
layer slot for it — the same slot its entities are attributed to — until
an unload is issued against that slot. So a gate like
`if layers.is_loaded(ref) then layers.unload(ref) end` sees the layer on
the frame its entities exist.

**Parameters**

- `ref` `AssetRef<scene> | string` — A scene `AssetRef`, or an identity string.

**Returns** `boolean` — True when the scene is loaded as a layer.

```lua
if not layers.is_loaded("scenes.hud") then layers.load("scenes.hud", { additive = true }) end
```

## globals/layers/lastLoad {#globals-layers-lastload}

```lua
layers.lastLoad() -> SceneLoadReport?
```

The most recent load's report: what it loaded, what root it replaced
and which overlays went with it, the entity counts on each side, how long
each phase took, and every failure it produced. Nil on an engine that has
loaded nothing — which is how "nothing has loaded" reads differently from
a load that changed nothing.

**Returns** `SceneLoadReport?` — A `SceneLoadReport`, or nil.

```lua
local r = layers.lastLoad(); print(r.name, r.outcome, r.entities.added)
```

## globals/layers/lastUnload {#globals-layers-lastunload}

```lua
layers.lastUnload() -> SceneUnloadReport?
```

The most recent unload's report: the layer it took down under the name
it was loaded with, the overlays it cascaded, and the entities that went
with them. A guid no longer resolves to a name once its layer is gone, so
this is where that name survives.

**Returns** `SceneUnloadReport?` — A `SceneUnloadReport`, or nil.

```lua
local u = layers.lastUnload(); print(u.name, u.entities.removed)
```

## globals/layers/list {#globals-layers-list}

```lua
layers.list() -> { any }
```

Every loaded scene layer as a proxy, root and additive alike, in the
order the engine reports them.

**Returns** `{ any }` — Array of scene proxies — empty before any scene is loaded.

```lua
for _, layer in ipairs(layers.list()) do print(layer.name, layer.additive) end
```

## globals/layers/load {#globals-layers-load}

```lua
layers.load(ref: AssetRef<scene> | string, opts: LoadOpts?) -> any
```

Load a scene into the root non-additive slot ("main") OR as
an additive overlay alongside it. Identity is ref-based: pass an
`AssetRef<scene>` envelope (preferred — caught at the callsite
by the LSP) or an identity string (resolved via `asset.ref` at
entry, hard-error if no stable guid comes back). For non-additive,
idempotency is by guid: re-loading the same scene logs and
returns the existing proxy without tearing anything down.
Different guid → unloads the current root + cascades every
additive overlay it spawned + transitions the multiplayer room +
loads the new scene. Logs every step at info level so a silent
no-op is impossible.

**Parameters**

- `ref` `AssetRef<scene> | string` — `AssetRef<scene>` envelope (preferred) or scene identity string.
- `opts` `LoadOpts` _(optional)_ — Optional load options — additive overlay flag, slot name,
persistence flag, world-origin offset, and whether to rebuild.

**Returns** `any` — SceneProxy for the loaded layer (the cached instance the module also returns from `layers.active` / `layers.find`). Its `lastBuild` field says what the scene's `build.luau` did on this load — whether it ran, and what stood in the way when it did not.

```lua
layers.load(asset.ref("@builtin::scenes.test_arena", "scene"))
layers.load(myAssetRef, { additive = true, name = "hud_overlay" })
```

## globals/layers/loadHistory {#globals-layers-loadhistory}

```lua
layers.loadHistory() -> { SceneLoadReport }
```

Every load report the engine still holds, oldest first. Bounded — old
reports fall off the front, so a long session's memory does not grow with
how many times a scene was swapped.

**Returns** `{ SceneLoadReport }` — An array of `SceneLoadReport`.

```lua
for _, r in layers.loadHistory() do print(r.name, r.durationMs) end
```

## globals/layers/loadInFlight {#globals-layers-loadinflight}

```lua
layers.loadInFlight() -> number
```

Returns the number of scene loads currently in flight (queued
but not yet visible via `onLoad` dispatch). Returns 0 when the
engine is in a stable load state. Used by `engine.mode = ...` to
block flips while a load is mid-air; agents can read this to wait
for a load to finish before driving the next operation.

**Returns** `number`

## globals/layers/localPlayer {#globals-layers-localplayer}

```lua
layers.localPlayer -> any
```

The active root scene's local player handle, the same value `layers.active.players.localPlayer` answers.

**Returns** `any`

## globals/layers/observe {#globals-layers-observe}

```lua
layers.observe() -> SceneObservation
```

What every scene load did, and what each loaded scene costs. One read
covering the last load's report (what it produced, what it replaced, what
it failed to produce and why, and how long each phase took), the load and
unload history, a per-layer inventory of what the engine attributes to
each layer, and the per-frame cost of each layer's entrypoint tick.
Answers in edit mode as well as play.

**Returns** `SceneObservation` — A `SceneObservation`.

```lua
local o = layers.observe(); print(o.lastLoad.outcome, o.lastLoad.durationMs)
for _, c in layers.observe().cost do print(c.name, c.avgMs) end
```

## globals/layers/offBeforeLoad {#globals-layers-offbeforeload}

```lua
layers.offBeforeLoad(h: number) -> boolean
```

Cancel a `layers.onBeforeLoad` subscription.

**Parameters**

- `h` `number` — The handle `layers.onBeforeLoad` returned.

**Returns** `boolean` — True when a subscription was removed.

```lua
layers.offBeforeLoad(h)
```

## globals/layers/offEntityChanged {#globals-layers-offentitychanged}

```lua
layers.offEntityChanged(h: number) -> boolean
```

Remove a subscription made with `layers.onEntityChanged`.

**Parameters**

- `h` `number` — The handle returned by `layers.onEntityChanged`.

**Returns** `boolean` — True when the subscription existed and was removed.

```lua
layers.offEntityChanged(handle)
```

## globals/layers/offLoad {#globals-layers-offload}

```lua
layers.offLoad(h: number) -> boolean
```

Cancel a `layers.onLoad` subscription.

**Parameters**

- `h` `number` — The handle `layers.onLoad` returned.

**Returns** `boolean` — True when a subscription was removed.

```lua
layers.offLoad(h)
```

## globals/layers/offUnload {#globals-layers-offunload}

```lua
layers.offUnload(h: number) -> boolean
```

Cancel a `layers.onUnload` subscription.

**Parameters**

- `h` `number` — The handle `layers.onUnload` returned.

**Returns** `boolean` — True when a subscription was removed.

```lua
layers.offUnload(h)
```

## globals/layers/onBeforeLoad {#globals-layers-onbeforeload}

```lua
layers.onBeforeLoad(cb: (any) -> ()) -> number
```

Run a callback just before a scene layer loads, while the previous
layer's entities are still present.

**Parameters**

- `cb` `(any) -> ()` — Receives the scene proxy about to load.

**Returns** `number` — A handle to pass to `layers.offBeforeLoad`.

```lua
local h = layers.onBeforeLoad(function(scene) print("loading", scene.name) end)
```

## globals/layers/onEntityChanged {#globals-layers-onentitychanged}

```lua
layers.onEntityChanged(cb: (any) -> ()) -> number
```

Subscribe to authored entity changes. The callback runs once per
frame with every entity edited since the previous frame, batched by
layer as `{ { scene = string, entities = { string } } }` — a moved
transform, an edited component field, a spawn, or a despawn (the id
of a despawned entity arrives with `entity.exists` already false).
Any number of subscribers can watch the same edits.

Scope: authored edits in edit mode — what lands in the scene's dirty
overlay. Mutations a component makes from its own `update` are runtime
behavior and do not appear, so a subscriber that rebuilds derived data
cannot re-trigger itself.

**Parameters**

- `cb` `(any) -> ()` — Called with the change batch.

**Returns** `number` — A handle for `layers.offEntityChanged`.

```lua
layers.onEntityChanged(function(batch)
for _, row in ipairs(batch) do
for _, id in ipairs(row.entities) do rebuild(id) end
end
end)
```

## globals/layers/onLoad {#globals-layers-onload}

```lua
layers.onLoad(cb: (any) -> ()) -> number
```

Run a callback once a scene layer has loaded — the point where its
entities exist and player / camera spawners can attach to them.

**Parameters**

- `cb` `(any) -> ()` — Receives the loaded scene proxy.

**Returns** `number` — A handle to pass to `layers.offLoad`.

```lua
local h = layers.onLoad(function(scene) spawnPlayerFor(scene) end)
```

## globals/layers/onUnload {#globals-layers-onunload}

```lua
layers.onUnload(cb: (any) -> ()) -> number
```

Run a callback as a scene layer unloads, while its entities are still
addressable — the place to release anything keyed to them.

**Parameters**

- `cb` `(any) -> ()` — Receives the scene proxy being unloaded.

**Returns** `number` — A handle to pass to `layers.offUnload`.

```lua
local h = layers.onUnload(function(scene) releaseHandlesFor(scene) end)
```

## globals/layers/problems {#globals-layers-problems}

```lua
layers.problems(ref: (AssetRef<scene> | string | any)?) -> { SceneLoadFailure }
```

What a layer failed to produce, and why. Each entry names the phase it
happened in, one reason from the closed set, and the engine's own words —
plus the entity, component or lifecycle hook it is about when it is about
one.

**Parameters**

- `ref` `(AssetRef<scene> | string | any)` _(optional)_ — A scene `AssetRef`, an identity string, or a scene proxy. Omit for
the active root layer.

**Returns** `{ SceneLoadFailure }` — An array of `SceneLoadFailure` — empty for a layer that came up whole.

```lua
for _, f in layers.problems() do print(f.reason, f.entity, f.message) end
```

## globals/layers/rebuildInFlight {#globals-layers-rebuildinflight}

```lua
layers.rebuildInFlight() -> boolean
```

Whether the engine is rebuilding the live scene right now — a scene
load is carrying entities in, or an edit↔play flip's transition is
materialising the layer set. A flip unloads the root layer and loads it
again for the new mode across many frames, and each mode materialises a
different set of entities, so the live entities are a stage of a scene
being built while this reads true. A caller whose answer belongs to the
settled scene — a test taking a root, a validator judging the live tree —
polls it down to false first.

**Returns** `boolean` — true while a load or a mode-flip transition is converging.

```lua
if not layers.rebuildInFlight() then judge(layers.active) end
```

## globals/layers/reload {#globals-layers-reload}

```lua
layers.reload(ref: (AssetRef<scene> | string)?) -> any?
```

Unload and re-load a scene layer in place, so an edited scene asset
takes effect without rebuilding the surrounding layer stack. The scene's
`build.luau` runs against what it resolves right now, so a build script
whose inputs moved — a component that now exists, an asset that now
resolves — produces the scene it describes today.

**Parameters**

- `ref` `(AssetRef<scene> | string)` _(optional)_ — A scene `AssetRef`, or an identity string. Omit to reload the active
root scene.

**Returns** `any?` — What the scene's `build.luau` did — `{ built = true, content, editorOnly }` with the entity counts each half placed, carrying `refused` and a `message` reading them out when an operation the build ran was refused, or `{ built = false, reason, message }` naming what stood in the way. Nil when no layer matched, which is a no-op.

```lua
layers.reload("scenes.arena")
```

## globals/layers/resetCostWindow {#globals-layers-resetcostwindow}

```lua
layers.resetCostWindow() -> nil
```

Open a new cost window, discarding what the previous one measured. Call
this before timing a stretch of frames; the load history is untouched.

**Returns** `nil`

```lua
layers.resetCostWindow()
```

## globals/layers/unload {#globals-layers-unload}

```lua
layers.unload(refOrProxy: (AssetRef<scene> | string | any)?) -> nil
```

Unload a scene layer. Unloading the root cascades through its additive
overlays first, most-recently-loaded first, so none is left as a layer the
engine still lists after its entities are gone; persistent additive layers
survive the cascade. A scene with no loaded layer is a no-op.

**Parameters**

- `refOrProxy` `(AssetRef<scene> | string | any)` _(optional)_ — A scene `AssetRef`, an identity string, or a scene proxy.
Omit to unload the active root scene.

**Returns** `nil`

```lua
layers.unload("scenes.hud")
layers.unload() -- the active root, plus its non-persistent overlays
```

## globals/layers/whyPartial {#globals-layers-whypartial}

```lua
layers.whyPartial(ref: (AssetRef<scene> | string | any)?) -> (string?, string?)
```

Why a layer is not whole. Returns nil when it IS — everything the scene
declared was produced — and otherwise the nearest cause from the closed set
`loaderRaised`, `entrypointCompileFailed`, `entrypointBodyRaised`,
`entrypointRaised`, `buildRaised`, `entityFailed`, `parentMissing`,
`parentRefused`, `parentAbandoned`, `componentUnresolved`,
`componentRefused`, `subscriberRaised`, `updateRaised`. A second return
carries the engine's own words for that cause.

**Parameters**

- `ref` `(AssetRef<scene> | string | any)` _(optional)_ — A scene `AssetRef`, an identity string, or a scene proxy. Omit for
the active root layer.

**Returns** `(string?, string?)` — `(reason, detail)`.

```lua
local why, detail = layers.whyPartial(); if why then print(why, detail) end
```

## modules/layers/README {#modules-layers-readme}

```lua
layers (global)
```

Top-level scene-management namespace + Scene proxy. Owns the public layer-management API surface exposed on `_G.layers`. Pure Luau composition over internal `__layers.*` ECS-glue primitives; the LSP discovers the public shape via this `--!global layers` directive.
Also available as global: layers

## modules/layers/cost {#modules-layers-cost}

```lua
cost(): { SceneLayerCost }
```

What each loaded scene's per-frame tick costs, attributed to the layer
that owns it — the `update` / `editorUpdate` its entrypoint declares,
timed where it runs. `totalMs` is a SUM across the window
`layers.observe().window` reports, so divide by `calls` (or read `avgMs`)
for the per-tick figure; a tick that runs every frame makes that the
per-frame figure. Call `layers.resetCostWindow()` first to time a
particular stretch. A layer whose entrypoint declares no tick is absent.

```lua
layers.resetCostWindow(); task.wait(1); for _, c in layers.cost() do print(c.name, c.avgMs) end
```

## modules/layers/find {#modules-layers-find}

```lua
find(ref: AssetRef<scene> | string): any?
```

The loaded layer for a scene, matched on guid — the canonical identity,
since display names can collide and paths drift when assets move. A layer
torn down but not yet pumped out of the engine's loaded list reads as gone.

**Parameters**

- `ref` `AssetRef<scene> | string` — A scene `AssetRef`, or an identity string resolved through `asset.ref`.

```lua
local layer = layers.find("scenes.arena")
```

## modules/layers/fireBeforeLoad {#modules-layers-firebeforeload}

```lua
fireBeforeLoad(proxy: any): nil
```

Announce that a scene layer is about to load: clears any pending
unload for that layer slot, marks the proxy loading, and fans out to every
`layers.onBeforeLoad` subscriber. The scene-load pipeline calls this.

**Parameters**

- `proxy` `any` _(optional)_ — The scene proxy about to load.

```lua
layers.fireBeforeLoad(sceneProxy)
```

## modules/layers/fireLoad {#modules-layers-fireload}

```lua
fireLoad(proxy: any): nil
```

Announce that a scene layer has loaded, fanning out to every
`layers.onLoad` subscriber. The layer is pinned as the active one for the
duration of the fan-out, so entities a subscriber spawns are attributed to
it rather than landing orphaned. The scene-load pipeline calls this.

**Parameters**

- `proxy` `any` _(optional)_ — The loaded scene proxy.

```lua
layers.fireLoad(sceneProxy)
```

## modules/layers/fireUnload {#modules-layers-fireunload}

```lua
fireUnload(proxy: any): nil
```

Announce that a scene layer is unloading: fans out to every
`layers.onUnload` subscriber, then drops the layer's cached proxy and
per-layer state so the next load of that scene rebuilds from disk. The
unload path calls this.

**Parameters**

- `proxy` `any` _(optional)_ — The scene proxy being unloaded.

```lua
layers.fireUnload(sceneProxy)
```

## modules/layers/install {#modules-layers-install}

```lua
install(): nil
```

Install the `layers` global. `layers.active` is exposed as a property
whose every read resolves the current root scene, so it tracks scene
changes without manual invalidation; other keys resolve against this
module. The prelude calls this once at boot.

```lua
layers.install()
```

## modules/layers/inventory {#modules-layers-inventory}

```lua
inventory(): { SceneLayerInventory }
```

What each loaded layer holds: the entities the engine attributes to it,
whether it came up whole, and how many failures it carries. `unattributed`
in `layers.observe().totals` counts what exists in the world that no layer
claims.

```lua
for _, l in layers.inventory() do print(l.name, l.entities, l.ok) end
```

## modules/layers/is_loaded {#modules-layers-is-loaded}

```lua
is_loaded(ref: AssetRef<scene> | string): boolean
```

Whether a scene currently has a loaded layer — the boolean form of
`layers.find`. A scene counts as loaded from the frame the engine holds a
layer slot for it — the same slot its entities are attributed to — until
an unload is issued against that slot. So a gate like
`if layers.is_loaded(ref) then layers.unload(ref) end` sees the layer on
the frame its entities exist.

**Parameters**

- `ref` `AssetRef<scene> | string` — A scene `AssetRef`, or an identity string.

```lua
if not layers.is_loaded("scenes.hud") then layers.load("scenes.hud", { additive = true }) end
```

## modules/layers/lastLoad {#modules-layers-lastload}

```lua
lastLoad(): SceneLoadReport?
```

The most recent load's report: what it loaded, what root it replaced
and which overlays went with it, the entity counts on each side, how long
each phase took, and every failure it produced. Nil on an engine that has
loaded nothing — which is how "nothing has loaded" reads differently from
a load that changed nothing.

```lua
local r = layers.lastLoad(); print(r.name, r.outcome, r.entities.added)
```

## modules/layers/lastUnload {#modules-layers-lastunload}

```lua
lastUnload(): SceneUnloadReport?
```

The most recent unload's report: the layer it took down under the name
it was loaded with, the overlays it cascaded, and the entities that went
with them. A guid no longer resolves to a name once its layer is gone, so
this is where that name survives.

```lua
local u = layers.lastUnload(); print(u.name, u.entities.removed)
```

## modules/layers/list {#modules-layers-list}

```lua
list(): { any }
```

Every loaded scene layer as a proxy, root and additive alike, in the
order the engine reports them.

```lua
for _, layer in ipairs(layers.list()) do print(layer.name, layer.additive) end
```

## modules/layers/load {#modules-layers-load}

```lua
load(ref: AssetRef<scene> | string, opts: LoadOpts?): any
```

Load a scene into the root non-additive slot ("main") OR as
an additive overlay alongside it. Identity is ref-based: pass an
`AssetRef<scene>` envelope (preferred — caught at the callsite
by the LSP) or an identity string (resolved via `asset.ref` at
entry, hard-error if no stable guid comes back). For non-additive,
idempotency is by guid: re-loading the same scene logs and
returns the existing proxy without tearing anything down.
Different guid → unloads the current root + cascades every
additive overlay it spawned + transitions the multiplayer room +
loads the new scene. Logs every step at info level so a silent
no-op is impossible.

**Parameters**

- `ref` `AssetRef<scene> | string` — `AssetRef<scene>` envelope (preferred) or scene identity string.
- `opts` `LoadOpts?` _(optional)_ — Optional load options — additive overlay flag, slot name,
persistence flag, world-origin offset, and whether to rebuild.

```lua
layers.load(asset.ref("@builtin::scenes.test_arena", "scene"))
layers.load(myAssetRef, { additive = true, name = "hud_overlay" })
```

## modules/layers/loadHistory {#modules-layers-loadhistory}

```lua
loadHistory(): { SceneLoadReport }
```

Every load report the engine still holds, oldest first. Bounded — old
reports fall off the front, so a long session's memory does not grow with
how many times a scene was swapped.

```lua
for _, r in layers.loadHistory() do print(r.name, r.durationMs) end
```

## modules/layers/loadInFlight {#modules-layers-loadinflight}

```lua
loadInFlight(): number
```

Returns the number of scene loads currently in flight (queued
but not yet visible via `onLoad` dispatch). Returns 0 when the
engine is in a stable load state. Used by `engine.mode = ...` to
block flips while a load is mid-air; agents can read this to wait
for a load to finish before driving the next operation.

## modules/layers/observe {#modules-layers-observe}

```lua
observe(): SceneObservation
```

What every scene load did, and what each loaded scene costs. One read
covering the last load's report (what it produced, what it replaced, what
it failed to produce and why, and how long each phase took), the load and
unload history, a per-layer inventory of what the engine attributes to
each layer, and the per-frame cost of each layer's entrypoint tick.
Answers in edit mode as well as play.

```lua
local o = layers.observe(); print(o.lastLoad.outcome, o.lastLoad.durationMs)
for _, c in layers.observe().cost do print(c.name, c.avgMs) end
```

## modules/layers/offBeforeLoad {#modules-layers-offbeforeload}

```lua
offBeforeLoad(h: number): boolean return remove(beforeLoadCbs, h) end
```

Cancel a `layers.onBeforeLoad` subscription.

**Parameters**

- `h` `number` — The handle `layers.onBeforeLoad` returned.

```lua
layers.offBeforeLoad(h)
```

## modules/layers/offEntityChanged {#modules-layers-offentitychanged}

```lua
offEntityChanged(h: number): boolean
```

Remove a subscription made with `layers.onEntityChanged`.

**Parameters**

- `h` `number` — The handle returned by `layers.onEntityChanged`.

```lua
layers.offEntityChanged(handle)
```

## modules/layers/offLoad {#modules-layers-offload}

```lua
offLoad(h: number): boolean return remove(loadCbs, h) end
```

Cancel a `layers.onLoad` subscription.

**Parameters**

- `h` `number` — The handle `layers.onLoad` returned.

```lua
layers.offLoad(h)
```

## modules/layers/offUnload {#modules-layers-offunload}

```lua
offUnload(h: number): boolean return remove(unloadCbs, h) end
```

Cancel a `layers.onUnload` subscription.

**Parameters**

- `h` `number` — The handle `layers.onUnload` returned.

```lua
layers.offUnload(h)
```

## modules/layers/onBeforeLoad {#modules-layers-onbeforeload}

```lua
onBeforeLoad(cb: (any) -> ()): number return push(beforeLoadCbs, cb) end
```

Run a callback just before a scene layer loads, while the previous
layer's entities are still present.

**Parameters**

- `cb` `(any) -> ()` — Receives the scene proxy about to load.

```lua
local h = layers.onBeforeLoad(function(scene) print("loading", scene.name) end)
```

## modules/layers/onEntityChanged {#modules-layers-onentitychanged}

```lua
onEntityChanged(cb: (any) -> ()): number
```

Subscribe to authored entity changes. The callback runs once per
frame with every entity edited since the previous frame, batched by
layer as `{ { scene = string, entities = { string } } }` — a moved
transform, an edited component field, a spawn, or a despawn (the id
of a despawned entity arrives with `entity.exists` already false).
Any number of subscribers can watch the same edits.

Scope: authored edits in edit mode — what lands in the scene's dirty
overlay. Mutations a component makes from its own `update` are runtime
behavior and do not appear, so a subscriber that rebuilds derived data
cannot re-trigger itself.

**Parameters**

- `cb` `(any) -> ()` — Called with the change batch.

```lua
layers.onEntityChanged(function(batch)
for _, row in ipairs(batch) do
for _, id in ipairs(row.entities) do rebuild(id) end
end
end)
```

## modules/layers/onLoad {#modules-layers-onload}

```lua
onLoad(cb: (any) -> ()): number return push(loadCbs, cb) end
```

Run a callback once a scene layer has loaded — the point where its
entities exist and player / camera spawners can attach to them.

**Parameters**

- `cb` `(any) -> ()` — Receives the loaded scene proxy.

```lua
local h = layers.onLoad(function(scene) spawnPlayerFor(scene) end)
```

## modules/layers/onUnload {#modules-layers-onunload}

```lua
onUnload(cb: (any) -> ()): number return push(unloadCbs, cb) end
```

Run a callback as a scene layer unloads, while its entities are still
addressable — the place to release anything keyed to them.

**Parameters**

- `cb` `(any) -> ()` — Receives the scene proxy being unloaded.

```lua
local h = layers.onUnload(function(scene) releaseHandlesFor(scene) end)
```

## modules/layers/problems {#modules-layers-problems}

```lua
problems(ref: (AssetRef<scene> | string | any)?): { SceneLoadFailure }
```

What a layer failed to produce, and why. Each entry names the phase it
happened in, one reason from the closed set, and the engine's own words —
plus the entity, component or lifecycle hook it is about when it is about
one.

**Parameters**

- `ref` `(AssetRef<scene> | string | any)?` _(optional)_ — A scene `AssetRef`, an identity string, or a scene proxy. Omit for
the active root layer.

```lua
for _, f in layers.problems() do print(f.reason, f.entity, f.message) end
```

## modules/layers/rebuildInFlight {#modules-layers-rebuildinflight}

```lua
rebuildInFlight(): boolean
```

Whether the engine is rebuilding the live scene right now — a scene
load is carrying entities in, or an edit↔play flip's transition is
materialising the layer set. A flip unloads the root layer and loads it
again for the new mode across many frames, and each mode materialises a
different set of entities, so the live entities are a stage of a scene
being built while this reads true. A caller whose answer belongs to the
settled scene — a test taking a root, a validator judging the live tree —
polls it down to false first.

```lua
if not layers.rebuildInFlight() then judge(layers.active) end
```

## modules/layers/reload {#modules-layers-reload}

```lua
reload(ref: (AssetRef<scene> | string)?): any?
```

Unload and re-load a scene layer in place, so an edited scene asset
takes effect without rebuilding the surrounding layer stack. The scene's
`build.luau` runs against what it resolves right now, so a build script
whose inputs moved — a component that now exists, an asset that now
resolves — produces the scene it describes today.

**Parameters**

- `ref` `(AssetRef<scene> | string)?` _(optional)_ — A scene `AssetRef`, or an identity string. Omit to reload the active
root scene.

```lua
layers.reload("scenes.arena")
```

## modules/layers/resetCostWindow {#modules-layers-resetcostwindow}

```lua
resetCostWindow(): nil
```

Open a new cost window, discarding what the previous one measured. Call
this before timing a stretch of frames; the load history is untouched.

```lua
layers.resetCostWindow()
```

## modules/layers/unload {#modules-layers-unload}

```lua
unload(refOrProxy: (AssetRef<scene> | string | any)?): nil
```

Unload a scene layer. Unloading the root cascades through its additive
overlays first, most-recently-loaded first, so none is left as a layer the
engine still lists after its entities are gone; persistent additive layers
survive the cascade. A scene with no loaded layer is a no-op.

**Parameters**

- `refOrProxy` `(AssetRef<scene> | string | any)?` _(optional)_ — A scene `AssetRef`, an identity string, or a scene proxy.
Omit to unload the active root scene.

```lua
layers.unload("scenes.hud")
layers.unload() -- the active root, plus its non-persistent overlays
```

## modules/layers/whyPartial {#modules-layers-whypartial}

```lua
whyPartial(ref: (AssetRef<scene> | string | any)?): (string?, string?)
```

Why a layer is not whole. Returns nil when it IS — everything the scene
declared was produced — and otherwise the nearest cause from the closed set
`loaderRaised`, `entrypointCompileFailed`, `entrypointBodyRaised`,
`entrypointRaised`, `buildRaised`, `entityFailed`, `parentMissing`,
`parentRefused`, `parentAbandoned`, `componentUnresolved`,
`componentRefused`, `subscriberRaised`, `updateRaised`. A second return
carries the engine's own words for that cause.

**Parameters**

- `ref` `(AssetRef<scene> | string | any)?` _(optional)_ — A scene `AssetRef`, an identity string, or a scene proxy. Omit for
the active root layer.

```lua
local why, detail = layers.whyPartial(); if why then print(why, detail) end
```

## typed/builtin//modules/api/engine/layers/layers/active {#typed-builtin-modules-api-engine-layers-layers-active}

```lua
layers.active -> any
```

The root scene's proxy, re-resolved on every read.

**Returns** `any`

## typed/builtin//modules/api/engine/layers/layers/camera {#typed-builtin-modules-api-engine-layers-layers-camera}

```lua
layers.camera -> any
```

The active root scene's camera handle, the same value `layers.active.camera` answers.

**Returns** `any`

## typed/builtin//modules/api/engine/layers/layers/localPlayer {#typed-builtin-modules-api-engine-layers-layers-localplayer}

```lua
layers.localPlayer -> any
```

The active root scene's local player handle, the same value `layers.active.players.localPlayer` answers.

**Returns** `any`
