---
title: "modules"
description: "The modules namespace — the engine's Luau API reference for modules."
section: "API Reference"
slug: "api-modules"
canonical: "https://origozero.ai/docs/api-modules"
updated: "2026-09-07T20:15:44.780754690+00:00"
tags: ["api", "reference"]
---

# modules

The `modules` namespace — 2302 functions.

## modules/AgentSkillAssetTypeRef/README {#modules-agentskillassettyperef-readme}

```lua
AgentSkillAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<agentSkill>`. Loaded lazily by `asset_ref.module`.

## modules/AgentSkillAssetTypeRef/getInstructions {#modules-agentskillassettyperef-getinstructions}

```lua
getInstructions(self): string?
```

Read the skill's `instructions.md` body — the prose an agent
receives when it invokes the skill.

**Parameters**

- `self` `any` _(optional)_

```lua
local body = skillRef:getInstructions()
```

## modules/AgentSkillAssetTypeRef/getManifest {#modules-agentskillassettyperef-getmanifest}

```lua
getManifest(self): { [string]: any }
```

Read and parse the skill's `skill.yaml` manifest — its description,
declared dependencies, and subskill ordering.

**Parameters**

- `self` `any` _(optional)_

```lua
local m = skillRef:getManifest()
```

## modules/AgentSkillAssetTypeRef/getReadme {#modules-agentskillassettyperef-getreadme}

```lua
getReadme(self): string?
```

Read the skill's `README.md` body.

**Parameters**

- `self` `any` _(optional)_

```lua
print(skillRef:getReadme())
```

## modules/AgentSkillAssetTypeRef/inspect {#modules-agentskillassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail — the skill's whole structured
surface: `{ description, when, checks, stages, verdicts, instructions,
dependencies, subskills, manifestError }`. `checks` carries each acceptance
criterion as `{ check, observe }` — what must hold, and where it is seen.
`stages` carries the ordered passes as `{ name, detail, checks }`, each
holding the criteria that only mean anything once that pass has run.
`verdicts` carries the outcomes a reader reports as `{ verdict, means }` —
the word, and what reporting it asserts.
`dependencies` carries each declared identity with what it resolved to and
whether it resolves here; a toolbox additionally carries the tools it
holds, a module the exports it carries, and a tool its own signature, all
read live rather than restated.
`subskills` carries each nested skill's `parent/sub` invoke address.
This is the dump `skills.invoke` renders — a skill with no readable
`instructions.md` still describes, reporting the gap rather than erroring.

**Parameters**

- `self` `any` _(optional)_

```lua
local subskills = asset.inspect(skillRef).detail.subskills
```

## modules/AgentSkillAssetTypeRef/onChange {#modules-agentskillassettyperef-onchange}

```lua
onChange(self, change)
```

Lifecycle hook: re-publish this skill when anything inside its folder
is written, so a skill just authored is listed and an edited description
is the one agents see. Reads the manifest and writes nothing back.

**Parameters**

- `self` `any` _(optional)_ — The changed skill's AssetRef.
- `change` `any` _(optional)_ — The write record the dispatcher passes through.

## modules/AgentSkillAssetTypeRef/onRegister {#modules-agentskillassettyperef-onregister}

```lua
onRegister(self)
```

Lifecycle hook: publish this skill to the roster agents read when the
skill first registers. The scope it is listed under is derived from the
asset's own identity.

**Parameters**

- `self` `any` _(optional)_ — The registering skill's AssetRef.

## modules/AnimationAssetTypeBehavior/README {#modules-animationassettypebehavior-readme}

```lua
AnimationAssetTypeBehavior
```

Behaviour for the `animation` asset type — a clip's disk shape. The payload is `data.zanim` (the engine-native binary `AnimAsset`, parallel to `.mesh`'s `data.zmsh`). `onCreate` writes that payload, and — when the clip's source rig guid is supplied — records it as `source_rig.json` (a `.rig` asset reference) so the clip knows the skeleton it was authored on and retargets onto any humanoid. Converters call `asset.create("animation", name, { bytes, rig })` to mint a clip.

## modules/AnimationAssetTypeBehavior/onChange {#modules-animationassettypebehavior-onchange}

```lua
onChange(ref: any, change: { [string]: any })
```

React to a write inside a `.animation/` instance: when the clip's source
rig link (`source_rig.json`) changes, record the rig's humanoid
classification into `.metadata` for search — the clip inherits it from the
rig it targets. Originator-only; `.metadata` syncs as ordinary content.

**Parameters**

- `ref` `any` _(optional)_ — The AssetRef<animation> for the changed clip.
- `change` `{ [string]: any }` — `{ path, asset, type, kind, origin }`.

## modules/AnimationAssetTypeBehavior/reindexSearchMeta {#modules-animationassettypebehavior-reindexsearchmeta}

```lua
reindexSearchMeta(self): ()
```

Re-derive this clip's search `.metadata` (its humanoid classification,
resolved from the source rig). `onChange` calls it when `source_rig.json`
changes; the search-metadata backfill calls it per clip to populate clips
minted before the deriver existed.

**Parameters**

- `self` `any` _(optional)_

```lua
animationRef:reindexSearchMeta()
```

## modules/AssetChangeDispatch/README {#modules-assetchangedispatch-readme}

```lua
require("@builtin/modules/asset_change_dispatch") -- AssetChangeDispatch
```

Routes a VFS source write to the enclosing typed-asset's `onChange(ref, change)` hook. Installs `_G.__zero_dispatch_asset_change`, which the engine calls (via `ffi_callbacks::fire_asset_change_dispatch`) once per source write.

This is the type-level analogue of the component-centric
`onAssetReload(field)` fan-out. Components react to assets they
*reference*; an asset *type* reacts to writes INSIDE its own
instances. When any file under a `<name>.<type>/` folder changes on
the VFS, the engine hands the written path here; this module finds
the enclosing typed-asset folder, loads its
`<type>.assetType/behavior.luau`, and — if that module exports an
`onChange` function — invokes `onChange(ref, change)`.
The engine half is deliberately thin (a generic "this path was
written" signal); all the resolution + behaviour lives here in Luau,
mirroring the `__build_asset_ref_proxy` split.

Usage: local AssetChangeDispatch = require("@builtin/modules/asset_change_dispatch")

## modules/AssetChangeDispatch/dispatch {#modules-assetchangedispatch-dispatch}

```lua
dispatch(path: string, kind: string?, origin: string?)
```

Dispatch the asset-type change hook for a VFS path. Called by the
engine for two orthogonal axes:
- `kind`: a per-file EDIT (`"edited"`, `path` is the written file) vs an
asset COMPLETION (`"seeded"`, `path` is the typed-asset folder, now fully
present from a world seed). The type inspects `kind` to decide whether to
filter by which file changed or act on the whole asset.
- `origin`: `"local"` for a write made on this client, `"remote"` for a
peer-synced write — forwarded so hooks can gate on it (importers run on
the originator only).
Resolves the typed asset, loads its `behavior.luau`, and invokes
`onChange(ref, change)` (`change = { path, asset, type, kind, origin }`).
When the path has no enclosing typed asset, forwards to the loose-file seam
(`dispatch_loose`) so the importer system can claim orphan writes.

**Parameters**

- `path` `string` — The VFS path: the written file (edited) or the asset folder (seeded).
- `kind` `string?` _(optional)_ — "edited" (default) or "seeded".
- `origin` `string?` _(optional)_ — "local" (default) or "remote".

```lua
__zero_dispatch_asset_change("/zero/source/Goblin.dynamicAsset/prompt.json", "edited", "local")
```

## modules/AssetChangeDispatch/dispatchDelete {#modules-assetchangedispatch-dispatchdelete}

```lua
dispatchDelete(path: string)
```

Dispatch the asset-type DELETE hook for a removed typed-asset FOLDER —
the teardown counterpart of `dispatch`. `path` is the folder that was
removed; this resolves its `<name>.<type>` identity, loads the type's
`behavior.luau`, and invokes `onDelete(ref)` if defined (a `.component`
unregisters its type). No-op when the path isn't a registered typed asset
or the type defines no `onDelete`. The engine calls this via
`ffi_callbacks::fire_asset_delete_dispatch` once per typed-asset folder
removal.

**Parameters**

- `path` `string` — The removed asset folder's VFS path.

```lua
__zero_dispatch_asset_delete("/zero/source/Spinner.component")
```

## modules/AssetRef/README {#modules-assetref-readme}

```lua
require("@builtin/modules/asset_ref") -- AssetRef
```

AssetRef proxy builder. Attaches the default method metatable to every `{ __ref, type, name, guid, identity, path }` envelope produced by `asset.resolve` / `asset.ref`, and dispatches type-specific methods from `<typename>.assetType/behavior.luau` so a `.material` ref carries material-only methods (and so on).

The Rust side (`crates/zero_scripting/src/ffi/bindings/asset.rs`)
used to ship a C metatable with a fixed `__index` that knew about
`getSource` / `getBytes` / `getText` / `exists` / `inspect` / `meta`.
That shape couldn't grow without an FFI change, which meant the
per-asset-type behaviour required to make refs *useful* (read a
material's properties, instantiate a bundle, run a tool) had no
hook.
This module owns that responsibility now. It exposes one entry
point — `M.build(envelope)` — that the Rust factory invokes via
the `_G.__build_asset_ref_proxy` global the prelude installs. The
build call attaches a shared metatable whose `__index` first
serves the default method table, then falls through to the type's
own `ref` table (loaded lazily from `@builtin::assetTypes.<type>.behavior`).
The default method surface is fixed and engine-required —
per-type `ref` tables CANNOT shadow `getSource` / `getBytes` /
`getText` / `exists` or the lazy `meta` property, matching the
contract in gh#1889. `inspect` is NOT a fixed default — it falls
through to the type's own `ref.inspect(self)` (returning the
type-specific `detail` for `asset.inspect`'s dispatch), and is nil
when the type defines none.

Usage: local AssetRef = require("@builtin/modules/asset_ref")

## modules/AssetRef/build {#modules-assetref-build}

```lua
build(envelope: any): any
```

Attach the AssetRef method metatable to an envelope table. Invoked
by the Rust factory (`push_asset_ref_handle` →
`_G.__build_asset_ref_proxy`) immediately after the six envelope
fields (`__ref`, `type`, `name`, `guid`, `identity`, `path`) have
been set, so the metatable's `__index` only ever fires for method /
property lookups, never for the literal envelope fields.

**Parameters**

- `envelope` `any` _(optional)_ — The freshly-built envelope table.

```lua
local r = require("modules.asset_ref").build({ type = "material", path = "/zero/source/Gold.material", ... })
```

## modules/AssetRef/canInstantiate {#modules-assetref-caninstantiate}

```lua
canInstantiate(self): boolean
```

Whether this asset can be instantiated into a scene — true iff its
asset type defines an `instantiate` method. Generic capability query
(no type allowlist); consumers gate on it before offering a scene path
(an `Asset.source` field, a viewport drop, a tool argument).

**Parameters**

- `self` `any` _(optional)_

```lua
if asset.resolve("Golem","dynamicAsset"):canInstantiate() then ... end
```

## modules/AssetRef/deps {#modules-assetref-deps}

```lua
deps(self): { deps: { any }, unresolved_deps: { any }, problems: { any } }
```

Return this asset's outbound reference table, aggregated across
every file inside it (for composite asset folders) — same data
`asset.deps(ref)` returns. `deps` holds the references that
resolved (`{ asset_guid, origin, literal, via, line?, checksum?,
... }`), `unresolved_deps` the literals nothing answered
(`{ literal, via, reason, line? }`), and `problems` the findings
attached to the asset. An asset that references nothing returns all
three empty.

**Parameters**

- `self` `any` _(optional)_

## modules/AssetRef/flushPendingPersists {#modules-assetref-flushpendingpersists}

```lua
flushPendingPersists()
```

Write out every asset whose edit-mode persistence is still coalesced,
spending no allowance and waiting on no refill. The runtime-state wipe on a
mode flip calls this first, so a change made in the last window before the
flip reaches the asset instead of being cleared with the overlay it lives
in. Call it before reading an asset's file for a value a runtime write may
have just changed.

```lua
require("modules.asset_ref").flushPendingPersists()
```

## modules/AssetRef/forgetRuntime {#modules-assetref-forgetruntime}

```lua
forgetRuntime(guid: string): boolean
```

Forget everything a type derived from ONE asset's content — the values
it cached in `ref.runtime` off the bytes that asset used to hold. Called
when an asset's content is REPLACED under a guid live consumers already
hold: a type memoizes its parse, its GPU handle, its settings against the
content it read, and each of those describes the previous bytes the moment
the new ones land. Emptying the table in place rather than replacing it is
what makes the clear reach every holder — the runtime table is shared by
every resolver of the guid, and a type may be holding it directly.

**Parameters**

- `guid` `string` — The asset's stable guid.

```lua
require("modules.asset_ref").forgetRuntime(ref.guid)
```

## modules/AssetRef/loadTypeBehavior {#modules-assetref-loadtypebehavior}

```lua
loadTypeBehavior(asset_type: string): ({ [string]: any }?, string?)
```

Load an asset type's `behavior.luau` module table, reporting a
behavior that raised while loading. The first return is the module (nil
when the type ships no `behavior.luau`); the second is set when the type
HAS a `behavior.luau` that raised, and carries the require key plus the
error it raised.
A caller that runs the type's hooks — `asset.create` runs `onCreate` —
reads the second return to tell "this type declares no behavior" from
"this type's behavior is broken", which are opposite situations for the
asset it is about to write.

**Parameters**

- `asset_type` `string` — The type name (e.g. `"dynamicAsset"`, `"material"`).

```lua
local mod, err = require("modules.asset_ref").loadTypeBehavior("dialogue")
```

## modules/AssetRef/loadTypeModule {#modules-assetref-loadtypemodule}

```lua
loadTypeModule(asset_type: string): { [string]: any }?
```

Load the full `behavior.luau` module table for an asset type
(`{ ref?, global?, onChange? }`), or nil when the type ships no
`behavior.luau`. Registry-driven resolution — same path the per-type
`ref` dispatch uses. Exposed so the asset-change dispatcher
(`modules/asset_change_dispatch`) can reach a type's `onChange`
hook without duplicating the resolution logic.

**Parameters**

- `asset_type` `string` — The type name (e.g. `"dynamicAsset"`, `"material"`).

```lua
local m = require("modules.asset_ref").loadTypeModule("dynamicAsset")
```

## modules/AssetRef/persistInEditMode {#modules-assetref-persistineditmode}

```lua
persistInEditMode(self: any)
```

Generic edit-mode persistence hook an assetType calls when a change of
its own is meant to reach the file. In EDIT mode, flush a ref's transient
runtime overlay (`ref.runtime`) to its backing asset file by invoking the
type's own `saveDefinition(self)`, so the change syncs to peers and is
saved. Works for any assetType that defines a `saveDefinition`; whether a
given type's runtime writes route through here is that type's own
contract. The write-through is
rate-limited per asset: an asset carries an allowance of 8 writes that
refills at one per 250ms. Changes made in one frame are coalesced onto a
single re-emit, and a caller that changes a value and moves on has it on
disk a frame or two later. A caller that keeps changing the same asset
runs the allowance down to its refill rate, so over any span the asset
costs at most that allowance plus one write per 250ms, whatever cadence
the changes arrive at.
In PLAY mode this is a deliberate no-op: runtime overlays stay transient
(frame-fast) and are persisted back to the source asset on demand. An
assetType opts in simply by exposing `ref.saveDefinition`; no per-type
branching lives here.

**Parameters**

- `self` `any` _(optional)_ — Any AssetRef.

```lua
require("modules.asset_ref").persistInEditMode(matRef)
```

## modules/AssetRefShapes/README {#modules-assetrefshapes-readme}

```lua
require("@builtin/modules/asset_ref_shapes") -- AssetRefShapes
```

Publishes what every `AssetRef<category>` answers to, so a member read on an asset-typed value is checked against the category's own surface.

An asset category's per-instance surface is authored: a
`<name>.assetType/behavior.luau` declares `M.ref = { ... }`, and each
category declares its own. So the members an `AssetRef<inputMap>`
carries are knowable only to `inputMap` itself — no fixed set of
types covers the ones a world defines, and the checker has no way to
guess them.
This module reads each registered category's `M.ref` table from its
source (never executing it) and renders it as a Luau table type, then
hands the whole set to the engine. From there a `ref:method(...)` on
an asset-typed value resolves against the category's real surface: a
name it does not carry is reported with the list of the ones it does.
The sweep is complete and replaces what was published before, so a
category whose type is removed stops being published. It runs at
world load, and again whenever a `behavior.luau` is written — the
`assetType` type's own `onChange` hook re-publishes, which is what
makes an edited surface take effect without a restart.

Usage: local AssetRefShapes = require("@builtin/modules/asset_ref_shapes")

## modules/AssetRefShapes/ensure {#modules-assetrefshapes-ensure}

```lua
ensure()
```

Publish the surfaces if they are not known to be current, and do
nothing when they are. This is what a checker calls before it reads
them: it makes the published set complete at the moment of use rather
than at some earlier moment that may not have arrived yet.

```lua
AssetRefShapes.ensure()
```

## modules/AssetRefShapes/install {#modules-assetrefshapes-install}

```lua
install()
```

Arm the world-load sweep. Idempotent.

```lua
AssetRefShapes.install()
```

## modules/AssetRefShapes/instanceReturnsOf {#modules-assetrefshapes-instancereturnsof}

```lua
instanceReturnsOf(typeRef: any, out: { { category: string, identity: string, method: string, definition: string, source: string } })
```

The instance-derived returns one category contributes: for each of
its instances, the type each `refShapes` entry states for THAT asset.
A category whose behavior declares no `refShapes` contributes none.

This is how a method whose result is shaped by the asset gets typed at
all. `inputMapRef:activate()` answers one handle per binding the map
declares — a set that is authored, differs per map, and changes when a
control is added — so no fixed signature can state it and only the
type itself can compute it.

Each entry is `function(self) -> (typeExpression, source?)`: the type
that call answers for THIS asset, and the module whose type vocabulary
the expression is written in — the handles an `inputMap:activate()`
answers are `Handle`, a name its own module declares. Omit the source
when the expression names only types visible from anywhere.

**Parameters**

- `typeRef` `any` _(optional)_ — The `AssetRef<assetType>` for the category.
- `out` `{ { category: string, identity: string, method: string, definition: string, source: string } }` — Array the `{ category, identity, method, definition, source }`
records append to.

```lua
AssetRefShapes.instanceReturnsOf(asset.resolve("inputMap", "assetType"), {})
```

## modules/AssetRefShapes/invalidate {#modules-assetrefshapes-invalidate}

```lua
invalidate()
```

Mark the published set stale, so the next `ensure` re-reads every
category. Called when a type definition is written.

```lua
AssetRefShapes.invalidate()
```

## modules/AssetRefShapes/publish {#modules-assetrefshapes-publish}

```lua
publish(): number
```

Sweep every registered asset type and publish its `ref:` surface,
plus every instance-derived return its types compute. Complete each
time: a category the sweep does not reach stops being published, so a
removed type's surface never lingers.

```lua
AssetRefShapes.publish()
```

## modules/AssetRefShapes/published {#modules-assetrefshapes-published}

```lua
published(): { categories: { [string]: string }, returns: { [string]: { [string]: string } } }
```

What the checker currently believes, as
`{ categories = { [category] = definition }, returns = { [identity] =
{ [method] = definition } } }`. Publishes first, so it answers about
the set a check would use rather than a stale one.

This is the answer to "is my type not published, or published and
correct?" — from a call site the two look the same, because both are
simply no diagnostic. Read it when a member access you expected to be
reported was not.

```lua
AssetRefShapes.published().returns["@builtin::inputMaps.default"]
```

## modules/AssetRefShapes/shapeOf {#modules-assetrefshapes-shapeof}

```lua
shapeOf(typeRef: any): string?
```

The Luau table type describing one category's `ref:` surface — the
methods its `behavior.luau` declares, plus everything every `AssetRef`
carries regardless of category. Returns nil when the type ships no
behavior or declares no `M.ref` methods: a category that states nothing
of its own is left opaque rather than described by the common members
alone, so an access on it stays unchecked instead of being judged
against a surface its author never wrote.

**Parameters**

- `typeRef` `any` _(optional)_ — The `AssetRef<assetType>` for the category.

```lua
local t = AssetRefShapes.shapeOf(asset.resolve("inputMap", "assetType"))
```

## modules/AssetTypeAssetTypeRef/README {#modules-assettypeassettyperef-readme}

```lua
AssetTypeAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<assetType>`. Loaded lazily by `asset_ref.module`.

An `AssetRef<assetType>` points at a `<typename>.assetType/`
definition folder. SHARED CODE that a type exposes to every instance
is declared in that type's own `behavior.luau` as a `modules` map of
tracked `require`s, e.g.:
    -- inside `<typename>.assetType/behavior.luau`
    M.modules = { shared = require(".shared") }
and reached from any instance through the pinned instance->type link:
    -- inside any `foo.<thatType>/init.luau`
    local api = asset.containing(__FILE__).modules.shared
Resolution follows the instance's pinned `typeRef` guid (its `.refs`
`via = "asset_type"` dep), so identically-named modules in different
types never collide and an imported instance reaches the exact type
version it was authored against. This is the mechanism that makes a
type fully self-contained: the behaviour every instance relies on
lives in the type, not duplicated as a `require("modules.x")` in
100 instance files. See `modules/asset_ref.module` for the dispatch.

## modules/AssetTypeAssetTypeRef/getReadme {#modules-assettypeassettyperef-getreadme}

```lua
getReadme(self): string?
```

Read the asset type's own `README.md` body (type-level docs —
what THE TYPE is, surfaced by `asset.inspect`).

**Parameters**

- `self` `any` _(optional)_

```lua
print(assetTypeRef:getReadme())
```

## modules/AssetTypeAssetTypeRef/onChange {#modules-assettypeassettyperef-onchange}

```lua
onChange(ref, change)
```

Re-publish every asset category's `ref:` surface after a write
inside a type definition.

**Parameters**

- `ref` `any` _(optional)_ — The `AssetRef<assetType>` for the edited type.
- `change` `any` _(optional)_ — `{ path, asset, type, kind, origin }` for the write.

```lua
-- the engine calls this; a behavior.luau edit is picked up live
```

## modules/AssetTypeAssetTypeRef/onCreate {#modules-assettypeassettyperef-oncreate}

```lua
onCreate(name: string): { [string]: string }
```

Generic-creation hook for `asset.create("assetType", name)`. Scaffolds a
new asset type by cloning this type definition's own `template/` skeleton
with the `[name]` placeholder rewritten to your type's name, so the new
`<name>.assetType/` is ready to edit (`type.yaml`, `behavior.luau`, and its
own `template/` instance body). Pure: returns the substituted file map.

**Parameters**

- `name` `string` — The new type's name. Becomes its `.<name>` instance suffix.

```lua
asset.create("assetType", "Waypoint")
```

## modules/AssetValidator/README {#modules-assetvalidator-readme}

```lua
require("@builtin/systems/worldValidation.package/assetValidator") -- AssetValidator
```

Structure validator for asset folders. Delegates each asset to `asset.validate` — the engine primitive that checks the folder against its type's `type.yaml` (required files, `one_of_group`s, unexpected entries, content constraints), waives the describe-this-asset requirements for private subassets (assets nested inside a non-broadcasting container like a `.bundle`), and runs the type's own semantic `validate` hook — and maps the result into the report's Problem records.

`asset.validate` is the same primitive the `world.push` gate runs,
so a world that validates clean here also passes the structural
half of the publish gate. Each problem is attributed to the asset
path (missing files anchor at the asset root; existing files —
unexpected entries, content violations — anchor at the file).
An asset whose type has no registered `type.yaml` gets a
`schema.unknown_type` warning; an asset the registry cannot
resolve (e.g. written this frame, registration still draining)
gets a `schema.unresolved_asset` warning.

Usage: local AssetValidator = require("@builtin/systems/worldValidation.package/assetValidator")

## modules/AssetValidator/dependencyProblemsFrom {#modules-assetvalidator-dependencyproblemsfrom}

```lua
dependencyProblemsFrom(path: string, deps: any, guidCache: { [string]: boolean })
```

Map an asset's reference table into publish-blocking Problem records.
Split from the lookup so the mapping can be exercised on a reference table
directly. A guid already present in `guidCache` is not looked up again.

**Parameters**

- `path` `string` — Asset path the problems are attributed to.
- `deps` `any` _(optional)_ — Reference table in the shape `asset.deps` returns.
- `guidCache` `{ [string]: boolean }` — Memo of guid → whether the live asset index carries it.

```lua
local problems = AssetValidator.dependencyProblemsFrom(path, asset.deps(path), {})
```

## modules/AssetValidator/validate {#modules-assetvalidator-validate}

```lua
validate(entry, guidCache: { [string]: boolean }?)
```

Validate one asset folder via `asset.validate` and map the
result into Problem records.

**Parameters**

- `entry` `any` _(optional)_ — Asset entry from `vfsScanner` — `{ path, name, type }`.
- `guidCache` `{ [string]: boolean }?` _(optional)_

```lua
local problems = AssetValidator.validate({ path = "/source/Foo.component", name = "Foo.component", type = "component" })
```

## modules/AssetValidator/validateBatch {#modules-assetvalidator-validatebatch}

```lua
validateBatch(assets)
```

Validate a batch of asset entries and flatten the per-asset
problem lists into one array. Convenience wrapper over `M.validate`.

**Parameters**

- `assets` `any` _(optional)_ — Array of asset entries from the scanner.

```lua
local all = AssetValidator.validateBatch(bucket.assets)
```

## modules/AvatarAssetTypeBehavior/README {#modules-avatarassettypebehavior-readme}

```lua
AvatarAssetTypeBehavior
```

Behaviour for the `avatar` asset type — a playable character composed from three INDEPENDENT parts so each swaps on its own axis: - `body` — a `.bundle`: skinned mesh + bone entities (the look). - `controller` — the movement system (default: `CharacterController` + `MovementState` + `Humanoid`, the standard kinematic humanoid mover). - `animation` — the system that animates the body (default: the shared `Locomotion` blend space, which reads the controller's velocity and plays retargeted clips; or `ClipPlayer`; or your own component). Movement and animation are NOT tied together: attaching the controller never pulls in `Locomotion`, and choosing your own `animation` keeps the standard controller — so authoring your own locomotion is a one-field swap. The clip set retargets onto any humanoid rig, so the default locomotion drives any humanoid body with no per-body setup. `:instantiate()` composes the parts; `:setCharacter(root, body)` swaps the body. Point a scene's `PlayerPrototype.body` at a body carrying this avatar to make it the body every connecting player spawns with.

## modules/AvatarAssetTypeBehavior/instantiate {#modules-avatarassettypebehavior-instantiate}

```lua
instantiate(self, target: EntityRef?, opts: any): (EntityRef, { [string]: string })
```

Instantiate this avatar: spawn an avatar root, spawn the `body` bundle
under it, then attach the movement controller and the animation system —
independently. With the defaults the root gets the standard humanoid
controller and the shared Locomotion that drives the body with retargeted
clips. Pass a target entity REF to make that entity the avatar root (the
player-avatar path passes the freshly-spawned avatar entity here).

**Parameters**

- `self` `any` _(optional)_
- `target` `EntityRef?` _(optional)_ — Optional avatar root as an EntityRef. Omit to spawn one.
- `opts` `any` _(optional)_ — Optional `{ position, rotation, scale, name, temporary, idMap,
diff, sourceTag }` — the base placement opts land on the root; `idMap`
pins the composed body root, label, and every body-bundle child to stable
ids across re-instantiations; `diff` replays the user's sparse edits to the
composed body. `sourceTag` marks the call as owned — the `Asset` component
sets it when it drives the composition itself.

```lua
local av = avatarRef:instantiate()
```

## modules/AvatarAssetTypeBehavior/onCreate {#modules-avatarassettypebehavior-oncreate}

```lua
onCreate(name: string, opts: CreateOpts?): { [string]: string }
```

Generic-creation hook for `asset.create("avatar", name, opts)`. Composes
the avatar from a `body` plus an independent movement controller and
animation system, written as `avatar.json`. The `body` is a `.bundle`
(skinned mesh + bones), a plain `.mesh` (a simple visual), or omitted (a
body-less avatar — a controller / first-person camera with no mesh).
Defaults: the standard humanoid controller and, for a humanoid body, the
shared `Locomotion` (clips from the `locomotion` preset, default "synty").
Override `animation` to author your own locomotion without touching movement;
pass `controller = false` for a body the engine doesn't move; pass `clip` for
a single-clip `ClipPlayer`. Humanoid-ness drives the default animation only
and is auto-derived from a rigged body; pass `humanoid` to set it explicitly
(e.g. a body-less first-person avatar that still carries `Humanoid`).

**Parameters**

- `name` `string`
- `opts` `CreateOpts?` _(optional)_

```lua
asset.create("avatar", "my_hero", { body = heroBundle })  -- standard controller + locomotion
asset.create("avatar", "fp_player", { humanoid = true })  -- body-less first-person player
```

## modules/AvatarAssetTypeBehavior/setCharacter {#modules-avatarassettypebehavior-setcharacter}

```lua
setCharacter(self, root: any, body: any): EntityRef
```

Swap the body on a live avatar. Despawns the current body and spawns
`body` (a `.bundle` ref) in its place. The controller + animation systems
live on the avatar root and re-resolve the new body's rig, so the look swaps
while movement and animation are kept. A single-clip `ClipPlayer` rides the
skinned body, so it is re-attached to the new body.

**Parameters**

- `self` `any` _(optional)_
- `root` `any` _(optional)_ — The live avatar root (an EntityRef from `:instantiate()`).
- `body` `any` _(optional)_ — The new body — a `.bundle` ref (guid / identity / AssetRef).

```lua
avatarRef:setCharacter(avatarRoot, asset.resolve("knight", "bundle"))
```

## modules/BlankAppLayout/README {#modules-blankapplayout-readme}

```lua
require("@builtin/_templates.blank_app.blank_app_layout") -- BlankAppLayout
```

Minimum-viable app — one screen built from the raw CSS-parity widget tree. Clone-and-edit starting point; replace `build` with your own tree.

Usage: local BlankAppLayout = require("@builtin/_templates.blank_app.blank_app_layout")

## modules/BundleAssetTypeRef/README {#modules-bundleassettyperef-readme}

```lua
BundleAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<bundle>`. Loaded lazily by `asset_ref.module`.

## modules/BundleAssetTypeRef/getTemplate {#modules-bundleassettyperef-gettemplate}

```lua
getTemplate(self): any
```

Parse the bundle's `entity_template` into a Lua value. The engine
format is a flat array of entity records (`{ name, original_id,
parent_id, components, ... }`), so the result is an array-table; the
return type is `any` because the payload is decoded JSON. Returns nil
when parsing fails or the bundle has no template.
Parsed results are cached per-guid — repeat `:instantiate` on the same
bundle reuses the parsed table instead of re-decoding the JSON. Cleared
when the template is written — by `:setTemplate` or straight to the
bundle's `entity_template` — so authoring-time edits land on the next
instantiate.

**Parameters**

- `self` `any` _(optional)_

```lua
local t = bundleRef:getTemplate()
```

## modules/BundleAssetTypeRef/getTemplateRaw {#modules-bundleassettyperef-gettemplateraw}

```lua
getTemplateRaw(self): string?
```

Read the raw `entity_template` file (JSON) as a string. Use
`:getTemplate()` for a parsed table.

**Parameters**

- `self` `any` _(optional)_

```lua
local raw = bundleRef:getTemplateRaw()
```

## modules/BundleAssetTypeRef/inspectDetail {#modules-bundleassettyperef-inspectdetail}

```lua
inspectDetail(self): any
```

`asset.inspect` type-specific detail: `{ nodeCount,
attachedComponents, rootName }`, parsed from the bundle's own
`entity_template` JSON — never instantiates the hierarchy. A bundle
with no readable template returns an empty detail rather than
erroring.

**Parameters**

- `self` `any` _(optional)_

```lua
local attached = asset.inspect(bundleRef).detail.attachedComponents
```

## modules/BundleAssetTypeRef/instantiate {#modules-bundleassettyperef-instantiate}

```lua
instantiate(self, target: EntityRef?, opts: { [string]: any }?): (EntityRef, { [string]: string })
```

Instantiate this bundle. The DEFAULT — `bundle:instantiate()` with no
target entity — spawns ONE root entity carrying an `Asset` component that
references this bundle: the component spawns the bundle's hierarchy as
TEMPORARY runtime children (never written to the saved scene) and owns
save / reload / diff, so the scene stays clean (one entity per instance,
not the whole exploded permanent tree). This is the one-call path to put a
bundle in the world.

Passing a target `entityId` (instantiate ONTO that entity, which becomes
the bundle root) OR `opts.raw = true` (build a permanent fresh hierarchy)
selects the RAW explode: it spawns every child in the `entity_template`,
remaps cross-entity references, applies any saved sparse `diff`, and writes
the `bundleProvenance` live-link attribute, returning the root entity id
and the `originalId → runtimeId` map. The `Asset` component, Player
avatars, and template tooling use this raw path.

Spawn mode is selected by `opts.deferred`. Default (`deferred = false`)
uses the legacy `batch()` flush — every component is visible on the
SAME tick so spawn-then-query patterns (tests, scene-load critical
path, spawn-then-read flow) keep working. Pass `opts.deferred = true`
for hundreds-to-thousands-of-entities bundles (large levels, density
spawners, gibbed-prop debris bundles): the spawn+component work wraps
in `queue()` and the engine drainer spreads it across multiple frames
at the `QUEUE_DRAIN_BUDGET_PER_FRAME` cap. The root entity id is
minted same-tick either way (entity.spawn always returns immediately),
but in deferred mode children + components arrive in the ECS over the
next few frames — don't read them back synchronously.

**Parameters**

- `self` `any` _(optional)_
- `target` `EntityRef?` _(optional)_ — Optional target entity — an entity REF (proxy) to explode ONTO
(that entity becomes the bundle root; this selects the RAW path). Omit for
the default (fresh root + `Asset` component).
- `opts` `{ [string]: any }?` _(optional)_ — Optional `{ position, rotation, scale, name, temporary, raw,
idMap, diff, sourceTag, deferred }`. The base placement opts land on the
returned root; `raw = true` forces the raw explode into a fresh permanent
hierarchy (no `Asset` component); `idMap` reuses saved child ids (stable
ids across reload); `diff` reapplies sparse child overrides keyed by
template `original_id`; `sourceTag` labels the provenance record (defaults to
`"bundle"`); `deferred=true` switches the spawn pump from same-tick
`batch()` to cross-frame `queue()` — required for thousand-entity bundles
to avoid one huge frame stall; `temporary=true` spawns every child born
temporary (the `Asset` component's re-created scaffolding — kept out of the
saved scene so a reload doesn't respawn them alongside a re-instantiate).
`idMap` / `diff` / `deferred` / `temporary` apply to the raw path only.

```lua
local root = bundleRef:instantiate()                          -- scene-clean instance (Asset component); root is an EntityRef
local root, map = bundleRef:instantiate(entity.spawn("mount"))     -- raw, ONTO an entity ref
local root, map = bundleRef:instantiate(nil, { raw = true })  -- raw permanent fresh hierarchy
```

## modules/BundleAssetTypeRef/listChildren {#modules-bundleassettyperef-listchildren}

```lua
listChildren(self, rootsOnly: boolean?): { string }
```

List the names of every entity captured in THIS bundle instance's
`entity_template`. Pass `rootsOnly = true` to restrict to entities with
no `parent_id`. Best-effort: empty list when the template can't parse.

**Parameters**

- `self` `any` _(optional)_
- `rootsOnly` `boolean?` _(optional)_ — When true, only entities with no `parent_id` are returned.

```lua
for _, name in ipairs(bundleRef:listChildren()) do print(name) end
```

## modules/BundleAssetTypeRef/listContents {#modules-bundleassettyperef-listcontents}

```lua
listContents(self): { { name: string, isDirectory: boolean } }
```

List the entries directly under the bundle root folder (meshes,
textures, materials, sub-bundles) for tooling (inspectors, dependency
graphs).

**Parameters**

- `self` `any` _(optional)_

```lua
for _, e in ipairs(bundleRef:listContents()) do print(e.name) end
```

## modules/BundleAssetTypeRef/meshBindings {#modules-bundleassettyperef-meshbindings}

```lua
meshBindings(self): { any }
```

List each renderable node's mesh→material binding from THIS bundle's
`entity_template` — the static data a spawned `Model` / `SkinnedModel`
resolves — WITHOUT instantiating anything. Answers "which material does
this mesh bind" as a direct read, with no spawn / settle / tree-walk /
despawn cycle. Each entry is `{ node, nodeId, component, mesh, material }`,
where `mesh` and `material` are ref descriptors `{ guid, identity, name,
path }` (nil when the component omits that field). One entry per
renderable component, in template order. Best-effort: empty list when the
template can't parse.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, b in ipairs(bundleRef:meshBindings()) do print(b.node, b.material and b.material.name) end
```

## modules/BundleAssetTypeRef/onChange {#modules-bundleassettyperef-onchange}

```lua
onChange(ref: any, change: { [string]: any })
```

React to a write inside a `.bundle/` instance: an `entity_template`
change means the assembled model changed — regenerate the bundle's
`preview.png`, its persisted visual description (syncs, publishes,
feeds search and browser thumbnails), and record the component set +
humanoid classification into `.metadata` for search facets. Originator-only;
both artifacts sync to peers as ordinary content.

**Parameters**

- `ref` `any` _(optional)_ — The AssetRef<bundle> for the changed container.
- `change` `{ [string]: any }` — `{ path, asset, type, kind, origin }`.

## modules/BundleAssetTypeRef/onCreate {#modules-bundleassettyperef-oncreate}

```lua
onCreate(name: string, opts: CreateOpts?): { [string]: string }
```

Generic-creation hook for `asset.create("bundle", name, opts)`.
With `opts.entity`, composes that LIVE entity's hierarchy into the new
bundle's `entity_template` in the same call — one step, capturing live
component state (serialized component snapshots) + transforms of the root and
every non-temporary descendant. With no opts, the bundle starts from
the template skeleton's `entity_template`.

**Parameters**

- `name` `string`
- `opts` `CreateOpts?` _(optional)_

```lua
asset.create("bundle", "tree_prefab", { entity = rootRef })
```

## modules/BundleAssetTypeRef/preview {#modules-bundleassettyperef-preview}

```lua
preview(self, opts: { [string]: any }?)
```

Render a preview of this bundle — instantiate its entity hierarchy,
auto-frame an offscreen camera over it, render one still, tear down.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ [string]: any }?` _(optional)_ — `{ size? = { width, height }, angle? = { yaw, pitch } }`.

```lua
local p = bundleRef:preview()
```

## modules/BundleAssetTypeRef/reindexSearchMeta {#modules-bundleassettyperef-reindexsearchmeta}

```lua
reindexSearchMeta(self): ()
```

Re-derive this bundle's search `.metadata` (component set + humanoid
classification) from its current `entity_template`, without touching the
preview. `onChange` calls it on every template edit; the search-metadata
backfill calls it per bundle to populate assets minted before the deriver
existed. Reads the template fresh — the parsed cache is only invalidated by
`setTemplate`.

**Parameters**

- `self` `any` _(optional)_

```lua
bundleRef:reindexSearchMeta()
```

## modules/BundleAssetTypeRef/setTemplate {#modules-bundleassettyperef-settemplate}

```lua
setTemplate(self, template: { any }): boolean
```

Overwrite the bundle's `entity_template` with a Lua table,
JSON-encoded. The VFS write triggers the engine's asset hot-reload
pipeline, so every component subscribed to this bundle's guid (via a
declared asset field) reconciles automatically. Returns true on
success.

**Parameters**

- `self` `any` _(optional)_
- `template` `{ any }` — The full entity-template table (array of records) to write.

```lua
bundleRef:setTemplate(bundleRef:getTemplate())
```

## modules/BundleAssetTypeRef/update {#modules-bundleassettyperef-update}

```lua
update(self, entityId: string): boolean
```

Re-compose THIS bundle from `entityId`'s current hierarchy and
write the new template back to the bundle's on-disk path. Walks the
whole hierarchy under `entityId` (recursive), capturing live component
state + transforms of every non-temporary descendant. The VFS write
fires the engine's asset hot-reload pipeline, so every component
subscribed to this bundle's guid reconciles automatically.

**Parameters**

- `self` `any` _(optional)_
- `entityId` `string` — The entity whose live hierarchy is captured into the bundle.

```lua
bundleRef:update(playerId)   -- "save" the live edits back into the bundle
```

## modules/BundleUpdate/README {#modules-bundleupdate-readme}

```lua
require("@builtin/modules/bundle_update") -- BundleUpdate (also available as global 'bundle')
```

Adds `bundle.update` to the existing `bundle` namespace. Pure Luau — thin ergonomic wrapper around `bundle.compose`. The prelude grafts this onto the engine's `bundle` table at boot.

`bundle.update(entityId, bundleRef?)` re-composes the bundle from the
entity's current hierarchy state, writing the new template into the
bundle's existing on-disk path. The reconcile is fully engine-driven:
the VFS write fires the generic asset hot-reload pipeline, which
dispatches `onAssetReload(field)` on every component instance whose
declared asset field references the bundle's guid. Components decide
what reload means for them (Asset.component → despawn + re-instantiate
template; user components → whatever they implement in
`onAssetReload`).
With one arg, the bundle ref is inferred from
`entity(entityId).component.get("Asset").source`. With two args the
explicit ref wins. There is no opt-in subscription surface —
declaring an asset field IS the subscription.

Usage: local BundleUpdate = require("@builtin/modules/bundle_update")
Also available as global: bundle

## modules/BundleUpdate/installInto {#modules-bundleupdate-installinto}

```lua
installInto(bundle: BundleNamespace)
```

Install `update` onto the supplied `bundle`-shaped namespace.
The prelude calls this once at boot with the engine's `bundle`
global; users reach the result as `bundle.update`.

**Parameters**

- `bundle` `BundleNamespace` — The target namespace table. No-op when given a
non-table value.

```lua
require("modules.bundle_update").installInto(bundle)
```

## modules/BundleUpdate/update {#modules-bundleupdate-update}

```lua
update(entityId: string, bundleRef: BundleRef?): any
```

Re-compose a bundle from an entity's current hierarchy and write
it back to the bundle's on-disk path. The VFS write triggers the
engine's generic asset hot-reload pipeline, which fires
`onAssetReload(field)` on every component subscribed to this
bundle's guid via a declared asset field — those components
reconcile per their own policy.

**Parameters**

- `entityId` `string` — The entity whose hierarchy is captured into the bundle.
- `bundleRef` `BundleRef?` _(optional)_ — Optional. When omitted, the ref is inferred from the
entity's `Asset.source` field. When given, the explicit ref wins.

```lua
bundle.update(entityId)                     -- infer from Asset
bundle.update(entityId, { guid = "..." })   -- explicit ref
```

## modules/CanvasAppLayout/README {#modules-canvasapplayout-readme}

```lua
require("@builtin/_templates.canvas_app.canvas_app_layout") -- CanvasAppLayout
```

Node-graph canvas built from the raw CSS-parity widget tree — absolutely positioned node cards over an SVG bezier connector; click a node to select it.

Usage: local CanvasAppLayout = require("@builtin/_templates.canvas_app.canvas_app_layout")

## modules/CombatGlow/README {#modules-combatglow-readme}

```lua
CombatGlow
```

The lit half of the combat effect family: the one additive material all five effects draw with, the four forms it carries, and the instance-data lanes that tell one entity's copy of it apart from another's. An effect leases a card through here and writes its state onto it every frame.

## modules/CombatGlow/along {#modules-combatglow-along}

```lua
along(a: { number }, b: { number }, t: number): { number }
```

A point `t` of the way from `a` to `b`.

**Parameters**

- `a` `{ number }` — `{ x, y, z }`.
- `b` `{ number }` — `{ x, y, z }`.
- `t` `number` — How far along, 0..1.

```lua
local head = CombatGlow.along(from, to, 0.4)
```

## modules/CombatGlow/axis {#modules-combatglow-axis}

```lua
axis(a: { number }, b: { number }): { number }
```

The unit vector running from `a` to `b` — what a rod form is told so it
can leave its two end caps undrawn.

**Parameters**

- `a` `{ number }` — Where the rod starts, `{ x, y, z }`.
- `b` `{ number }` — Where the rod ends, `{ x, y, z }`.

```lua
CombatGlow.write(rod, { axis = CombatGlow.axis(from, to), … })
```

## modules/CombatGlow/ball {#modules-combatglow-ball}

```lua
ball(ctx: any, name: string, position: { number }, diameter: number): any
```

Lease a sphere carrying the family's material — what a bloom is drawn
on. `diameter` is the sphere's world size in metres.

**Parameters**

- `ctx` `any` _(optional)_ — The play context.
- `name` `string` — The entity name the card carries.
- `position` `{ number }` — World position `{ x, y, z }`.
- `diameter` `number` — Sphere diameter in metres.

```lua
local card = CombatGlow.ball(ctx, "muzzle_bloom", pos, 0.7)
```

## modules/CombatGlow/disc {#modules-combatglow-disc}

```lua
disc(ctx: any, name: string, position: { number }, normal: { number },
```

Lease a plane lying across a surface normal — what a ring is drawn on.
`width` is the card's world size in metres, which is twice the ring's
widest radius.

```lua
local card = CombatGlow.disc(ctx, "shock_ring", pos, { 0, 1, 0 }, 12)
```

## modules/CombatGlow/distance {#modules-combatglow-distance}

```lua
distance(a: { number }, b: { number }): number
```

The distance between two world points.

**Parameters**

- `a` `{ number }` — `{ x, y, z }`.
- `b` `{ number }` — `{ x, y, z }`.

```lua
local span = CombatGlow.distance(p.from, p.to)
```

## modules/CombatGlow/lifted {#modules-combatglow-lifted}

```lua
lifted(c: { number }, amount: number): { number }
```

A colour lifted toward white by `amount`, held to 0..1 — the shade a
light or a leading edge carries above the colour the caller asked for.

**Parameters**

- `c` `{ number }` — The colour `{ r, g, b }`.
- `amount` `number` — How far to lift each channel.

```lua
local hot = CombatGlow.lifted(p.color, 0.2)
```

## modules/CombatGlow/rod {#modules-combatglow-rod}

```lua
rod(ctx: any, name: string, from: { number }, to: { number }, width: number): any
```

Lease a rod stretched between two world points — what a streak or a
bolt is drawn on. The rod covers the whole flight path and the shader
lights the part of it the round has reached, so nothing moves per frame.

**Parameters**

- `ctx` `any` _(optional)_ — The play context.
- `name` `string` — The entity name the rod carries.
- `from` `{ number }` — Where the path starts, `{ x, y, z }`.
- `to` `{ number }` — Where the path ends, `{ x, y, z }`.
- `width` `number` — How wide the rod is, in metres.

```lua
local rod = CombatGlow.rod(ctx, "tracer_rod", from, to, 0.06)
```

## modules/CombatGlow/unit {#modules-combatglow-unit}

```lua
unit(v: any, fallback: { number }): { number }
```

A vector as a unit vector, or `fallback` when it has no length. Every
effect in the family takes a direction or a normal from the caller, and a
zero one is a value the caller may write.

**Parameters**

- `v` `any` _(optional)_ — The vector `{ x, y, z }`.
- `fallback` `{ number }` — The unit vector to use when `v` has no length.

```lua
local n = CombatGlow.unit(p.normal, { 0, 1, 0 })
```

## modules/CombatGlow/write {#modules-combatglow-write}

```lua
write(card: any, state: { [string]: any })
```

Write a card's whole state onto its instance-data lanes: which form it
draws, how far through it is, its colour and gain, and the four scalars
that form reads. A card whose entity has not been committed yet is skipped,
and the next frame writes it.

**Parameters**

- `card` `any` _(optional)_ — The geometry instance a lease holds.
- `state` `{ [string]: any }` — `{ form, age, energy, seed, color, gain, a, b, c, d }`.

```lua
CombatGlow.write(card, { form = CombatGlow.BLOOM, age = 0.3, color = c })
```

## modules/CombatGlow/writeTo {#modules-combatglow-writeto}

```lua
writeTo(e: any, state: { [string]: any })
```

Write a frame's state onto an entity that is already in hand — the
spelling a catalogue still uses, where the entity was just spawned and the
proxy is the thing being written.

**Parameters**

- `e` `any` _(optional)_ — The entity proxy.
- `state` `{ [string]: any }` — `{ form, age, energy, seed, color, gain, a, b, c, d }`.

```lua
CombatGlow.writeTo(e, { form = CombatGlow.RING, a = 0.7, b = 0.1 })
```

## modules/ComponentAssetTypeRef/README {#modules-componentassettyperef-readme}

```lua
ComponentAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<component>`. Loaded lazily by `asset_ref.module`.

## modules/ComponentAssetTypeRef/attachTo {#modules-componentassettyperef-attachto}

```lua
attachTo(self, entityId: string, fields: { [string]: any }?): any
```

Attach this component to an entity, equivalent to
`entity(entityId).component.add(compRef.name, fields)`. The
component's type name comes from the ref's `name` (the leaf
folder stem with `.component` stripped) — never guessed.

**Parameters**

- `self` `any` _(optional)_
- `entityId` `string` — Target entity ID.
- `fields` `{ [string]: any }?` _(optional)_ — Optional `public` field overrides.

```lua
compRef:attachTo(playerId, { speed = 5 })
```

## modules/ComponentAssetTypeRef/getAssetFields {#modules-componentassettyperef-getassetfields}

```lua
getAssetFields(self): any
```

The component type's asset-field declarations — a map of field name
to asset category (e.g. `{ material = "material" }`), or nil when the
component declares no `Field.assetRef` fields.

**Parameters**

- `self` `any` _(optional)_

```lua
for field, cat in pairs(compRef:getAssetFields() or {}) do end
```

## modules/ComponentAssetTypeRef/getInfo {#modules-componentassettyperef-getinfo}

```lua
getInfo(self): any
```

Metadata for the component type: `{ name, builtin, executionOrder,
hooks }`, where `hooks` is a `{ <hookName> = true }` map scanned from
the source.

**Parameters**

- `self` `any` _(optional)_

```lua
local info = compRef:getInfo() print(info.executionOrder)
```

## modules/ComponentAssetTypeRef/getInitScript {#modules-componentassettyperef-getinitscript}

```lua
getInitScript(self): string?
```

Read the component's entry script (`init.luau` / `init.lua`)
as raw text.

**Parameters**

- `self` `any` _(optional)_

```lua
local src = compRef:getInitScript()
```

## modules/ComponentAssetTypeRef/getReadme {#modules-componentassettyperef-getreadme}

```lua
getReadme(self): string?
```

Read the component's `README.md` body.

**Parameters**

- `self` `any` _(optional)_

```lua
print(compRef:getReadme())
```

## modules/ComponentAssetTypeRef/getSource {#modules-componentassettyperef-getsource}

```lua
getSource(self): string?
```

The component type's registered source text — the live definition
in the runtime registry. `getInitScript` reads the on-disk entry file;
this reads what the engine actually registered (and resolves builtin
components by identity).

**Parameters**

- `self` `any` _(optional)_

```lua
local src = compRef:getSource()
```

## modules/ComponentAssetTypeRef/inspect {#modules-componentassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail: `{ fields, methods, events,
hooks, assetFields, executionOrder }`, parsed from the component's own
entry script (`getInitScript`) via `luau_introspect`. Cached on the
asset's content checksum, so re-inspecting unchanged source is free.
A component with no readable entry script returns an empty detail
rather than erroring.

**Parameters**

- `self` `any` _(optional)_

```lua
local events = asset.inspect(compRef).detail.events
```

## modules/ComponentAssetTypeRef/isRegistered {#modules-componentassettyperef-isregistered}

```lua
isRegistered(self): boolean
```

Whether the component type is registered with the ECS, so that
`component.add(name)` takes it. The source is stored the moment the
asset is written; the type registers when that registration drains, on
a later frame, and this reads the registration rather than the source.

**Parameters**

- `self` `any` _(optional)_

```lua
Test.waitUntil(function() return compRef:isRegistered() end, 120)
```

## modules/ComponentAssetTypeRef/listInstances {#modules-componentassettyperef-listinstances}

```lua
listInstances(self): { string }
```

List every entity in the live scene that currently has a
component of this type. Useful for inspector tooling.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, id in ipairs(compRef:listInstances()) do print(id) end
```

## modules/ComponentAssetTypeRef/listPublicFields {#modules-componentassettyperef-listpublicfields}

```lua
listPublicFields(self): { string }
```

Best-effort list of the component's `public` field names by
parsing the entry script. Recognises `public.<name> = ...`
assignments at module scope; doesn't expand metatable
declarations. Comments and string literals are not read. Use as a
discovery hint, not a strict schema.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, f in ipairs(compRef:listPublicFields()) do print(f) end
```

## modules/ComponentAssetTypeRef/onChange {#modules-componentassettyperef-onchange}

```lua
onChange(ref, change)
```

Asset-type change callback: (re)register + hot-reload this component
type whenever its `.component` is seeded (a world seed) or its entry script
(`init.luau` / `init.lua`) is edited. This is what registers and live-reloads
USER components — library components register through the VFS write hook
(author-immutable content does not dispatch `onChange`). Mirrors the
`.material` / `.shader` assetTypes owning their own registration. Convergent
+ idempotent: registration never writes back into the asset folder, and the
underlying registry upsert is a no-op when the source is unchanged.

**Parameters**

- `ref` `any` _(optional)_
- `change` `any` _(optional)_

## modules/ComponentAssetTypeRef/onDelete {#modules-componentassettyperef-ondelete}

```lua
onDelete(ref)
```

Asset-type delete callback: unregister this component type when its
`.component` folder is removed. The teardown counterpart of `onChange`'s
registration — the type owns both halves of its runtime lifecycle, the way
the `.material` / `.shader` types do. `__components.unregister` drops the
type from the runtime registry, the FFI type-info / schema mirrors, and the
`/registered/components/` projection; instances already attached to live
entities keep running (their closures are already bound).

**Parameters**

- `ref` `any` _(optional)_

## modules/ComponentAssetTypeRef/onRegister {#modules-componentassettyperef-onregister}

```lua
onRegister(self)
```

Initial-registration callback: register this component's type from its
entry script the moment the instance first registers. Fired by the
world-ready `onRegister` sweep BEFORE the world entrypoint (and its scene
load) runs, so `component.add`-by-name resolves for entities the same
load materialized. Idempotent: the registry upsert is a no-op when the
source is unchanged, and a later `onChange` re-registration converges on
the same definition.

**Parameters**

- `self` `any` _(optional)_

## modules/ComputeShaderAssetTypeRef/README {#modules-computeshaderassettyperef-readme}

```lua
ComputeShaderAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<computeShader>`. Loaded lazily by `asset_ref.module`.

## modules/ComputeShaderAssetTypeRef/buffer {#modules-computeshaderassettyperef-buffer}

```lua
buffer(self, name: string): any?
```

The buffer this shader last made under `name`. Two systems driving one
shader over the same data reach for this rather than each creating their
own; a system that wants its own calls `createBuffer` again.

**Parameters**

- `self` `any` _(optional)_
- `name` `string` — The name the buffer was created under.

```lua
local params = shaderRef:buffer("params") or shaderRef:createBuffer("params", { type = "vec4", len = 3 })
```

## modules/ComputeShaderAssetTypeRef/compile {#modules-computeshaderassettyperef-compile}

```lua
compile(self)
```

Compile this shader now, rather than on its first dispatch. Idempotent.
NORMALLY UNNECESSARY — a dispatch compiles on first use. Reach for this only
to avoid the one-frame first-dispatch warm-up in a latency-critical spot.

**Parameters**

- `self` `any` _(optional)_

```lua
shaderRef:compile()
```

## modules/ComputeShaderAssetTypeRef/compileByName {#modules-computeshaderassettyperef-compilebyname}

```lua
compileByName(ref: string)
```

Compile a compute shader by reference from its `.computeShader` VFS source
— the lazy compile-on-first-use entry. A system that must guarantee the
shader is registered before its first dispatch calls this (via
`compute.compileByName`) to bring it online through the same generic
`compileCompute` path an edit runs. Resolution goes through the universal
asset system — a reference that doesn't resolve is a bad reference in the
content that owns it, not something to special-case here.

**Parameters**

- `ref` `string` — A compute-shader asset reference (identity / guid) resolvable by `asset.resolve`.

```lua
require("modules.asset_ref").loadTypeModule("computeShader").compileByName("@builtin::shaders.compute_double")
```

## modules/ComputeShaderAssetTypeRef/copyBufferToTexture {#modules-computeshaderassettyperef-copybuffertotexture}

```lua
copyBufferToTexture(self, source: any, name: string, width: number, height: number, format: string?): TextureHandle
```

Copy one of this shader's buffers into a cached GPU texture, staying on
the GPU — the path for an image a compute pass produced.

**Parameters**

- `self` `any` _(optional)_
- `source` `any` _(optional)_ — The buffer holding tightly-packed rows in the format's texel layout.
- `name` `string` — Texture name, unique within this shader.
- `width` `number` — Texture width in texels.
- `height` `number` — Texture height in texels.
- `format` `string?` _(optional)_ — Texel format: `"rgba16f"` (default), `"rgba32f"`, `"rgba8"`.

```lua
local tex = shaderRef:copyBufferToTexture(packed, "foam", 256, 256, "rgba16f")
```

## modules/ComputeShaderAssetTypeRef/createBuffer {#modules-computeshaderassettyperef-createbuffer}

```lua
createBuffer(self, name: string, opts: { [string]: any }): any
```

Create a GPU buffer this compute shader owns. It is a substrate buffer —
the same one every other part of the engine deals in — filed under this
shader's guid, `name`, and a serial, so two callers asking this shader for a
`params` each get their own. Pass the handle to any shader's dispatch,
including another shader's, to bind it there. The shader remembers what it
made: `shaderRef:buffer(name)` returns the last buffer created under that
name, which is how two callers share one instead.

**Parameters**

- `self` `any` _(optional)_
- `name` `string` — What this buffer is for, e.g. `"params"` or `"verts"`.
- `opts` `{ [string]: any }` — `{ type, len, usage? }` — `type` is the element (`"f32"`, `"vec3"`,
`"vec4"`, `"quat"`, `"mat4"`), `len` is how many of them, and `usage` adds
what the buffer is used for beyond the storage it always has: `"readback"`
to read it on the CPU, `"vertex"` to draw it as geometry, `"index"` to draw
it as an index run, `"indirect"` for a draw to read its arguments out of.
A buffer can carry several.

There is no integer element: a buffer is a block of 32-bit words, so a
binding the shader declares as `u32` or `atomic<u32>` in `bindings.yaml` is
created as `"f32"` here and written with `buf:writeU32`. The element type
sets the STRIDE; what the words mean is the shader's to say.

```lua
local verts = shaderRef:createBuffer("verts", { type = "vec3", len = 1024, usage = { "readback" } })
verts:write(packed)  -- an array of numbers, or a `buffer` already holding the words
local values = verts:read():result()
local counts = shaderRef:createBuffer("counts", { type = "f32", len = 64 })  -- bindings.yaml: element: u32
counts:writeU32({ 0, 0, 0, 0 })
local geo = shaderRef:createBuffer("geo", { type = "vec3", len = 4096, usage = { "vertex", "readback" } })
local args = shaderRef:createBuffer("args", { type = "f32", len = 5, usage = { "indirect" } })  -- DrawIndexedIndirectArgs
```

## modules/ComputeShaderAssetTypeRef/createSampler {#modules-computeshaderassettyperef-createsampler}

```lua
createSampler(self, name: string, opts: { [string]: any }?): TextureHandle
```

Create a sampler owned by this compute shader, for its texture bindings.

**Parameters**

- `self` `any` _(optional)_
- `name` `string` — Sampler name, unique within this shader.
- `opts` `{ [string]: any }?` _(optional)_ — Sampler options — filtering and addressing.

```lua
local smp = shaderRef:createSampler("linear", { filter = true, clamp = true })
```

## modules/ComputeShaderAssetTypeRef/createStorageTexture2D {#modules-computeshaderassettyperef-createstoragetexture2d}

```lua
createStorageTexture2D(self, name: string, opts: { [string]: any }): TextureHandle
```

Create a write-only 2D storage texture owned by this compute shader —
the target a raymarch or image pass writes.

**Parameters**

- `self` `any` _(optional)_
- `name` `string` — Texture name, unique within this shader.
- `opts` `{ [string]: any }` — `{ width, height, format? }`.

```lua
local out = shaderRef:createStorageTexture2D("out", { width = 1920, height = 1080, format = "rgba16f" })
```

## modules/ComputeShaderAssetTypeRef/createTexture3D {#modules-computeshaderassettyperef-createtexture3d}

```lua
createTexture3D(self, name: string, opts: { [string]: any }): TextureHandle
```

Create a 3D texture owned by this compute shader — a density volume, an
occupancy grid, a signed-distance field. Keyed by the shader's guid plus
`name`, so it cannot collide with another asset's.

**Parameters**

- `self` `any` _(optional)_
- `name` `string` — Texture name, unique within this shader.
- `opts` `{ [string]: any }` — `{ width, height, depth, format?, storage? }`.

```lua
local density = shaderRef:createTexture3D("density", { width = 64, height = 64, depth = 64, format = "r16f", storage = true })
```

## modules/ComputeShaderAssetTypeRef/createTextureHistory {#modules-computeshaderassettyperef-createtexturehistory}

```lua
createTextureHistory(self, name: string, opts: { [string]: any }): TextureHandle
```

Create a temporal history pair owned by this compute shader — the
previous frame's result to read while writing this frame's.

**Parameters**

- `self` `any` _(optional)_
- `name` `string` — History name, unique within this shader.
- `opts` `{ [string]: any }` — `{ width, height, format? }`.

```lua
local history = shaderRef:createTextureHistory("taa", { width = 1920, height = 1080, format = "rgba16f" })
```

## modules/ComputeShaderAssetTypeRef/destroy {#modules-computeshaderassettyperef-destroy}

```lua
destroy(self): boolean
```

Destroy this texture or sampler and free its GPU memory.

**Parameters**

- `self` `any` _(optional)_

## modules/ComputeShaderAssetTypeRef/dispatch {#modules-computeshaderassettyperef-dispatch}

```lua
dispatch(self, opts: { [string]: any }): boolean
```

Dispatch this compute shader with named buffers bound to its declared
storage bindings, in order. Compiles on first use. A zero in any workgroup
dimension is refused and recorded as a dispatch failure, so a count derived
from how much data there is passes through `math.max(1, ...)` first.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ [string]: any }` — `{ buffers, workgroups }` — `buffers` names one compute buffer per
declared storage binding; `workgroups` is `{ x, y, z }`, `{ x }`, or `x`.

```lua
shaderRef:dispatch({ buffers = { "positions" }, workgroups = { 64 } })
```

## modules/ComputeShaderAssetTypeRef/dispatchEx {#modules-computeshaderassettyperef-dispatchex}

```lua
dispatchEx(self, opts: { [string]: any }): boolean
```

Dispatch this compute shader with explicit texture / storage-texture /
sampler resources, one per declared binding in order. A `params:` block's
uniform is engine-owned and takes no entry here. A zero in any workgroup
dimension is refused and recorded as a dispatch failure, so a count derived
from how much data there is passes through `math.max(1, ...)` first.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ [string]: any }` — `{ resources, workgroups }` — each resource is `{ kind, name }`.

```lua
shaderRef:dispatchEx({ resources = { { kind = "storage_2d", name = "target" } }, workgroups = { 8, 8 } })
```

## modules/ComputeShaderAssetTypeRef/dispatchOnVertices {#modules-computeshaderassettyperef-dispatchonvertices}

```lua
dispatchOnVertices(self, opts: { [string]: any }): boolean
```

Dispatch this compute shader with a model's vertex buffer bound at the
first storage binding, and `opts.buffers` filling the rest. Use to mutate
vertex positions directly. A zero in any workgroup dimension is refused and
recorded as a dispatch failure, so a count derived from how many vertices
there are passes through `math.max(1, ...)` first.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ [string]: any }` — `{ model, buffers?, workgroups }` — `model` is the mesh guid whose
vertices the shader writes.

```lua
shaderRef:dispatchOnVertices({ model = meshHandle.guid, workgroups = { 64 } })
```

## modules/ComputeShaderAssetTypeRef/getBindings {#modules-computeshaderassettyperef-getbindings}

```lua
getBindings(self): { [string]: any }
```

List this compute shader's declared bindings + params (parsed from
`bindings.yaml`). Returns `{ bindings = { {name, kind, access?, element?,
format?}, ... }, params = { {name, type, default}, ... } }`. This is the
editor-discovery surface — the SAME parse the compile uses.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, b in ipairs(computeRef:getBindings().bindings) do print(b.name, b.kind) end
```

## modules/ComputeShaderAssetTypeRef/getSource {#modules-computeshaderassettyperef-getsource}

```lua
getSource(self): string?
```

Read the compute WGSL body (`shader.wgsl`) as raw text.

**Parameters**

- `self` `any` _(optional)_

```lua
local src = computeRef:getSource()
```

## modules/ComputeShaderAssetTypeRef/onChange {#modules-computeshaderassettyperef-onchange}

```lua
onChange(ref, change)
```

Asset-type change callback: (re)compile the compute shader whenever its
WGSL body or `bindings.yaml` is written. This is the ONLY thing that compiles
a `.computeShader` — so it fires on the initial create (the template write)
AND on every later edit, with no world reload. Convergent: see
`compileCompute`.

**Parameters**

- `ref` `any` _(optional)_
- `change` `any` _(optional)_

## modules/ComputeShaderAssetTypeRef/read {#modules-computeshaderassettyperef-read}

```lua
read(self): Readback
```

Start a GPU→CPU read-back of this 3D texture's voxels. The read takes
frames to arrive — ask the returned `Readback` whether it is `:ready()`,
then drain it.

**Parameters**

- `self` `any` _(optional)_

```lua
local pending = density:read()
if pending:ready() then local voxels = pending:result() end
```

## modules/ComputeShaderAssetTypeRef/setParam {#modules-computeshaderassettyperef-setparam}

```lua
setParam(self, prop: string, value: number): boolean
```

Set one scalar parameter declared in this shader's `bindings.yaml`
`params:` block. The next dispatch sees the new value; a value set before
the shader's first compile is the value it starts with.

**Parameters**

- `self` `any` _(optional)_
- `prop` `string` — Parameter name as declared in `bindings.yaml`.
- `value` `number` — New scalar value.

```lua
shaderRef:setParam("scale", 4.0)
```

## modules/ComputeShaderAssetTypeRef/setSource {#modules-computeshaderassettyperef-setsource}

```lua
setSource(self, src: string): boolean
```

Overwrite the compute WGSL body on disk. Hot-reload recompiles the shader
on the next frame. Returns true on success.

**Parameters**

- `self` `any` _(optional)_
- `src` `string` — New WGSL source (only `@compute fn main` + helpers).

```lua
computeRef:setSource(myWgsl)
```

## modules/ComputeShaderAssetTypeRef/status {#modules-computeshaderassettyperef-status}

```lua
status(self): { { [string]: any } }
```

What the engine did with this shader's dispatches, one record per
target. A dispatch is recorded into a command encoder frames after the
call that asked for it returned, so this is where its outcome lands:
`ok` is the most recent outcome, `dispatches` counts what reached the
encoder, `failures` how many of those could not be recorded, and
`lastError` says why the last failure failed (kept after a recovery).
`target` is the mesh guid for a `dispatchOnVertices`, empty for a
dispatch that writes only its bound buffers. This answers "is this pass
running?" — an empty result means nothing has dispatched this shader.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, d in ipairs(shaderRef:status()) do print(d.target, d.ok, d.lastError) end
```

## modules/ComputeShaderAssetTypeRef/write {#modules-computeshaderassettyperef-write}

```lua
write(self, data: buffer | string | { number }): boolean
```

Upload voxels into this 3D texture: a `buffer` or a binary string
carrying the texture's byte layout verbatim, or one number per channel in
the texture's format.

**Parameters**

- `self` `any` _(optional)_
- `data` `buffer | string | { number }` — Voxel bytes, or voxel values in texel order.

## modules/ComputeShaderAssetTypeRef/writeFloats {#modules-computeshaderassettyperef-writefloats}

```lua
writeFloats(self, floats: { number }, formatOrOpts: (string | { [string]: any })?): boolean
```

Upload float voxels into this 3D texture, converting to the texture's
format.

**Parameters**

- `self` `any` _(optional)_
- `floats` `{ number }` — Voxel values in texel order.
- `formatOrOpts` `(string | { [string]: any })?` _(optional)_ — Source format name, or an options table.

## modules/ContentVersion/README {#modules-contentversion-readme}

```lua
require("@builtin/modules/content_version") -- ContentVersion
```

Per-path content-version counters — a cheap, synchronous "has this file changed?" token that lets an assetType behavior memoize a parse in its ref's `runtime` and serve repeated reads as a pure table lookup instead of re-reading + re-parsing the file every call.

A source write bumps the written path's counter. A memoized reader keyed
by the value `get(path)` returned when it parsed can then check, on every
later call, whether the counter still matches — an integer compare, no
`vfs.read`, no parse. It rebuilds only when the counter moved.
Two write surfaces feed it, so the token reflects a change no matter where
it came from:
  * `vfs.write` / `vfs.move` / `vfs.remove` bump SYNCHRONOUSLY, in the same
    call — so a script that writes a file and reads it back in the SAME tick
    sees the new content immediately (the asset-change `onChange` dispatch
    fires a frame LATER, too late for a same-tick read).
  * the generic asset-change dispatcher bumps on every source write it
    routes, including peer-synced and engine-originated writes that never
    pass through the Luau `vfs.*` surface — with the engine's normalized
    path, which is the canonical form a reader keys on.
Counters are per PATH (not one global epoch): the per-frame dirty-entity
writer churns scene-dirty paths every frame during play, and a global
epoch would let that churn invalidate every unrelated cache. Per-path
isolation means only a change to THE file a reader depends on rebuilds it.
Per-VM. The map holds one small integer per distinct written source path.

Usage: local ContentVersion = require("@builtin/modules/content_version")

## modules/ContentVersion/bump {#modules-contentversion-bump}

```lua
bump(path: string)
```

Bump `path`'s version counter, invalidating every reader memoized
against its previous value. Called by the `vfs.*` write surface and the
asset-change dispatcher; content code rarely calls it directly.

**Parameters**

- `path` `string` — VFS path whose content changed.

```lua
require("modules.content_version").bump(p)
```

## modules/ContentVersion/get {#modules-contentversion-get}

```lua
get(path: string): number
```

The current version counter for `path` (0 if never written this VM).
A memoized reader stores the value it saw when it parsed, and treats a
later call as a cache hit exactly while `get(path)` still returns it.

**Parameters**

- `path` `string` — Normalized VFS path.

```lua
local v = require("modules.content_version").get(p)
```

## modules/DataAssetTypeRef/README {#modules-dataassettyperef-readme}

```lua
DataAssetTypeRef
```

Per-instance methods on every `AssetRef<data>` — a configured value instance of a dataType contract. Instances carry values only; structure and behavior live on the contract.

## modules/DataAssetTypeRef/contract {#modules-dataassettyperef-contract}

```lua
contract(self)
```

The dataType contract this instance is bound to.

**Parameters**

- `self` `any` _(optional)_

```lua
local weaponType = smg:contract()
```

## modules/DataAssetTypeRef/data {#modules-dataassettyperef-data}

```lua
data(self, wanted: string?)
```

Resolve this instance into a read-only typed value object: this
instance's values.yaml with the contract's schema defaults applied,
ref fields materialized (assetRef -> AssetRef, dataRef -> nested
value object), and the bound contract chain's behavior methods
reachable on it — the bound contract's own methods win over an
ancestor's when both define the same name, and any explicit instance
value wins over both. Errors loudly when the instance violates its
contract, when `wanted` is given and the bound contract's chain
doesn't include it, and when dataRef fields form a circular chain.

**Parameters**

- `self` `any` _(optional)_
- `wanted` `string?` _(optional)_ — Optional contract the caller requires — an assertion, not a
filter: the returned object still carries the FULL bound schema and
method chain.

```lua
local w = smg:data("tdWeapon"); print(w.damage, w:effectiveRating())
```

## modules/DataAssetTypeRef/inspect {#modules-dataassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail: `{ contract, valueKeys }`,
parsed from this instance's own `values.yaml` — the bound contract
identity plus the sorted top-level keys of its `values` map. Never
resolves the contract or materializes ref fields (that's `:data()`).

**Parameters**

- `self` `any` _(optional)_

```lua
local valueKeys = asset.inspect(dataRef).detail.valueKeys
```

## modules/DataAssetTypeRef/onCreate {#modules-dataassettyperef-oncreate}

```lua
onCreate(name: string, opts: { contract: string })
```

Create a data instance bound to a contract. Seeds values.yaml
with the contract's declared defaults so a fresh instance is
immediately valid wherever every required field has a default.

**Parameters**

- `name` `string`
- `opts` `{ contract: string }`

## modules/DataAssetTypeRef/satisfies {#modules-dataassettyperef-satisfies}

```lua
satisfies(self, wanted: string): (boolean, string?)
```

Whether this instance's contract chain includes `wanted` — true
for the bound contract itself and for any contract it extends.

**Parameters**

- `self` `any` _(optional)_
- `wanted` `string` — Contract identity (bare leaf or full identity).

```lua
if smg:satisfies("weapon") then ... end
```

## modules/DataAssetTypeRef/satisfiesDetail {#modules-dataassettyperef-satisfiesdetail}

```lua
satisfiesDetail(self, wanted: string): { ok: boolean, code: string, reason: string? }
```

Chain-membership check that also reports WHY, as a stable code a
caller can branch on without matching reason text.

**Parameters**

- `self` `any` _(optional)_
- `wanted` `string` — Contract identity (bare leaf or full identity).

```lua
local d = smg:satisfiesDetail("weapon")
if not d.ok and d.code ~= "contract-mismatch" then warn(d.reason) end
```

## modules/DataAssetTypeRef/validateInstance {#modules-dataassettyperef-validateinstance}

```lua
validateInstance(self): (boolean, { DS.Violation })
```

Validate this instance's values against its contract's merged
schema (missing required fields, constraint breaches, unknown
fields, ref-field existence + contract compatibility).

**Parameters**

- `self` `any` _(optional)_

```lua
local ok, v = smg:validate()
```

## modules/DataSchema/README {#modules-dataschema-readme}

```lua
DataSchema
```

Pure schema engine for the typed-data system. A contract's `schema.yaml` declares fields + constraints; this module parses the decoded declaration, merges extends chains, applies defaults, and validates value tables. Pure Luau — no FFI, no VFS reads — callers decode the YAML themselves and inject asset/contract resolvers.

## modules/DataSchema/applyDefaults {#modules-dataschema-applydefaults}

```lua
applyDefaults(merged: { [string]: FieldSpec }, values: { [string]: any }): { [string]: any }
```

Produce a NEW value table with every schema default filled in
where `values` has no explicit entry — recursively: struct values
gain their subfield defaults and array elements gain their item
defaults, at every depth. Neither input is mutated.

**Parameters**

- `merged` `{ [string]: FieldSpec }` — Merged field map from `mergeChain`.
- `values` `{ [string]: any }` — The instance's raw value table.

```lua
local filled = DS.applyDefaults(merged, rawValues)
```

## modules/DataSchema/mergeChain {#modules-dataschema-mergechain}

```lua
mergeChain(chain: { Schema? }): ({ [string]: FieldSpec }?, { string })
```

Merge an extends chain of parsed schemas into one field map. The
chain is ordered ROOT PARENT FIRST, derived contract LAST. A child
redeclaring a parent field is a problem — shared shape comes from
the parent, per-child shape from new fields.

**Parameters**

- `chain` `{ Schema? }` — Array of Schema, root parent first. A nil hole (e.g. a
failed `parseSchema` result passed straight in) is a problem entry.

```lua
local merged, problems = DS.mergeChain({ itemSchema, weaponSchema })
```

## modules/DataSchema/parseSchema {#modules-dataschema-parseschema}

```lua
parseSchema(raw: any): (Schema?, { string })
```

Parse a decoded `schema.yaml` table into a Schema. Returns
`(schema, problems)` — schema is nil when any problem was found. `fields`
may be written as a map (name -> spec) or as a sequence of specs each
carrying its own `name:`; both key the resulting fields by name.

**Parameters**

- `raw` `any` _(optional)_ — The decoded document (`{ extends?, fields }`).

```lua
local schema, problems = DS.parseSchema(Yaml.decode(bytes))
```

## modules/DataSchema/validateValues {#modules-dataschema-validatevalues}

```lua
validateValues(
```

Validate a raw value table against a merged field map. Checks
missing required fields (a field with a default is never missing),
per-field constraints, unknown top-level fields, and ref fields via
the injected resolvers.

```lua
local violations = DS.validateValues(merged, rawValues, resolvers)
```

## modules/DataTypeAssetTypeRef/README {#modules-datatypeassettyperef-readme}

```lua
DataTypeAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<dataType>` — the contract surface of the typed-data system: schema (extends chain merged), validation, defaults, chain navigation, instance listing.

## modules/DataTypeAssetTypeRef/chain {#modules-datatypeassettyperef-chain}

```lua
chain(self)
```

The full extends chain as refs, root parent first, this contract last.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, link in ipairs(t:chain()) do print(link.identity) end
```

## modules/DataTypeAssetTypeRef/defaults {#modules-datatypeassettyperef-defaults}

```lua
defaults(self)
```

The default value table the merged schema declares.

**Parameters**

- `self` `any` _(optional)_

```lua
local d = weaponType:defaults()
```

## modules/DataTypeAssetTypeRef/inspect {#modules-datatypeassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail: `{ fields, extends }`, the
contract's OWN declared field schema (not the merged extends chain) —
`fields` is `{ {name, type, required}, ... }` sorted by name, parsed
from this contract's own `schema.yaml`. `extends` is the parent
contract identity, or nil for a root contract.

**Parameters**

- `self` `any` _(optional)_

```lua
local fields = asset.inspect(dataTypeRef).detail.fields
```

## modules/DataTypeAssetTypeRef/instances {#modules-datatypeassettyperef-instances}

```lua
instances(self)
```

Every data instance bound to this contract (or to a contract
that extends it). Scans the whole data-asset registry — a discovery
surface for authoring and tooling, not a per-frame call. A broken
instance (unreadable values.yaml, dangling contract binding) warns
and is skipped, so one bad instance never aborts enumeration of the
rest.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, ref in ipairs(weaponType:instances()) do print(ref.identity) end
```

## modules/DataTypeAssetTypeRef/parent {#modules-datatypeassettyperef-parent}

```lua
parent(self)
```

The parent contract ref (`extends`), or nil for a root contract.

**Parameters**

- `self` `any` _(optional)_

```lua
local base = rangedType:parent()
```

## modules/DataTypeAssetTypeRef/schema {#modules-datatypeassettyperef-schema}

```lua
schema(self)
```

The contract's merged field schema — its own fields plus every
field inherited through the `extends` chain.

**Parameters**

- `self` `any` _(optional)_

```lua
local schema = weaponType:schema()
```

## modules/DataTypeAssetTypeRef/validateValues {#modules-datatypeassettyperef-validatevalues}

```lua
validateValues(self, values: { [string]: any })
```

Validate a value table against this contract's merged schema.

**Parameters**

- `self` `any` _(optional)_
- `values` `{ [string]: any }`

```lua
local ok, v = weaponType:validate({ damage = 12 })
```

## modules/Debris/README {#modules-debris-readme}

```lua
Debris
```

Timed entity despawn — Roblox `Debris:AddItem(instance, lifetime)` analog. Wraps the internal `__debris.*` FFI with a typed Luau surface. Installed as the global `debris` via the prelude.

Collapses the common `task.delay + entity.despawn` pattern into one call.
Use for transient entities — bullet tracers, hit FX, dropped pickups,
tween-completion cleanups, ragdoll cleanup.
Semantics (match Roblox):
  - `debris.add(id, lifetime)` queues a despawn after `lifetime` seconds.
    Default `lifetime` is 10 seconds.
  - Calling `add` twice on the same entity REPLACES the prior deadline.
  - If the entity is despawned through any other path the pending record
    is dropped silently — no error.
  - Pending entries survive `world.save` / `world.load` (saved lifetime
    is seconds-remaining, so timers resume from where they paused).

## modules/Debris/add {#modules-debris-add}

```lua
add(id: any, lifetime: number?): DebrisHandle
```

Schedule the entity for despawn after `lifetime` seconds (default 10). Calling again on the same entity replaces the prior deadline. Negative or zero lifetime despawns immediately. Returns a handle for cancel(), or 0 if the entity id couldn't be resolved.

**Parameters**

- `id` `any` _(optional)_ — Entity id, name, or proxy table.
- `lifetime` `number?` _(optional)_ — Seconds before despawn — defaults to 10 when nil.

```lua
local bullet = entity.spawn("Bullet"); debris.add(bullet.id, 2.0)
local h = debris.add(target.id, 5); debris.cancel(h)
```

## modules/Debris/cancel {#modules-debris-cancel}

```lua
cancel(handleOrId: any): boolean
```

Cancel a pending despawn. Accepts either a handle from `debris.add` or an entity id / proxy. Returns true if a pending record was actually removed.

**Parameters**

- `handleOrId` `any` _(optional)_ — Cancel handle, or entity id / name / proxy.

```lua
debris.cancel(handle); debris.cancel(target.id)
```

## modules/Debris/clear {#modules-debris-clear}

```lua
clear(): boolean
```

Drop every pending entry. Used by the test suite to isolate cases — not part of the user-facing surface.

## modules/Debris/count {#modules-debris-count}

```lua
count(): number
```

Number of currently pending debris entries — handy for diagnostics overlays.

```lua
print(debris.count(), "pending despawns")
```

## modules/Debris/list {#modules-debris-list}

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

Snapshot every pending entry as a flat array of `{id, remainingSecs, handle}` records. Order is not stable — don't rely on it.

```lua
for _, e in debris.list() do print(e.id, e.remainingSecs) end
```

## modules/Debris/pending {#modules-debris-pending}

```lua
pending(id: any): number?
```

Return the number of seconds remaining before the entity is despawned, or nil if it isn't scheduled.

**Parameters**

- `id` `any` _(optional)_ — Entity id, name, or proxy.

```lua
local s = debris.pending(bullet.id); if s then print("dies in", s) end
```

## modules/DockedAppLayout/README {#modules-dockedapplayout-readme}

```lua
require("@builtin/_templates.docked_app.docked_app_layout") -- DockedAppLayout
```

Docked-shell UI template — a top toolbar, a scrolling body, and a bottom status bar built as a raw CSS-parity widget tree. Clone-and-edit starting point for editor-style tool apps.

Usage: local DockedAppLayout = require("@builtin/_templates.docked_app.docked_app_layout")

## modules/DynamicAssetTypeRef/README {#modules-dynamicassettyperef-readme}

```lua
DynamicAssetTypeRef
```

Behaviour for the `dynamicAsset` asset type — a prompt-driven, self-regenerating 3D asset. Reference example for the asset-type `onChange` change-callback. Loaded lazily by `modules/asset_ref`.

## modules/DynamicAssetTypeRef/onChange {#modules-dynamicassettyperef-onchange}

```lua
onChange(ref, change)
```

Regenerate this dynamic asset when its own `prompt.json` is written with
a prompt other than the one already generated. A write anywhere else in the
instance is ignored, and a prompt arriving while a generation is in flight is
held for the poll loop to pick up when that one settles.

**Parameters**

- `ref` `any` _(optional)_ — The changed `.dynamicAsset`'s reference.
- `change` `any` _(optional)_ — The change record the asset dispatcher raised for the write.

## modules/EcsAudioListenerSpec/README {#modules-ecsaudiolistenerspec-readme}

```lua
EcsAudioListenerSpec
```

## modules/EcsAudioSourceSpec/README {#modules-ecsaudiosourcespec-readme}

```lua
EcsAudioSourceSpec
```

## modules/EcsCameraSpec/README {#modules-ecscameraspec-readme}

```lua
EcsCameraSpec
```

## modules/EcsColliderSpec/README {#modules-ecscolliderspec-readme}

```lua
EcsColliderSpec
```

## modules/EcsCollisionGroupsSpec/README {#modules-ecscollisiongroupsspec-readme}

```lua
EcsCollisionGroupsSpec
```

## modules/EcsComponentSpecs/README {#modules-ecscomponentspecs-readme}

```lua
EcsComponentSpecs
```

## modules/EcsHandle/README {#modules-ecshandle-readme}

```lua
EcsHandle
```

## modules/EcsLightSpec/README {#modules-ecslightspec-readme}

```lua
EcsLightSpec
```

## modules/EcsMaterialSpec/README {#modules-ecsmaterialspec-readme}

```lua
EcsMaterialSpec
```

## modules/EcsMeshSpec/README {#modules-ecsmeshspec-readme}

```lua
EcsMeshSpec
```

## modules/EcsMorphWeightsSpec/README {#modules-ecsmorphweightsspec-readme}

```lua
EcsMorphWeightsSpec
```

## modules/EcsPhysicsJointSpec/README {#modules-ecsphysicsjointspec-readme}

```lua
EcsPhysicsJointSpec
```

## modules/EcsPhysicsSpec/README {#modules-ecsphysicsspec-readme}

```lua
EcsPhysicsSpec
```

## modules/EcsPlan/README {#modules-ecsplan-readme}

```lua
EcsPlan
```

## modules/EcsPlayerOwnedSpec/README {#modules-ecsplayerownedspec-readme}

```lua
EcsPlayerOwnedSpec
```

## modules/EcsRetargetProfileSpec/README {#modules-ecsretargetprofilespec-readme}

```lua
EcsRetargetProfileSpec
```

## modules/EcsSkeletonSpec/README {#modules-ecsskeletonspec-readme}

```lua
EcsSkeletonSpec
```

## modules/EcsSkySpec/README {#modules-ecsskyspec-readme}

```lua
EcsSkySpec
```

## modules/EcsTessellationSpec/README {#modules-ecstessellationspec-readme}

```lua
EcsTessellationSpec
```

## modules/EcsTransformConstraintsSpec/README {#modules-ecstransformconstraintsspec-readme}

```lua
EcsTransformConstraintsSpec
```

## modules/EcsTransformSpec/README {#modules-ecstransformspec-readme}

```lua
EcsTransformSpec
```

## modules/EcsVisibilityRangeSpec/README {#modules-ecsvisibilityrangespec-readme}

```lua
EcsVisibilityRangeSpec
```

## modules/EcsWheelColliderSpec/README {#modules-ecswheelcolliderspec-readme}

```lua
EcsWheelColliderSpec
```

## modules/EditorPanelAssetTypeRef/README {#modules-editorpanelassettyperef-readme}

```lua
EditorPanelAssetTypeRef
```

Per-instance methods + the `onRegister` lifecycle hooks for every `AssetRef<editorPanel>`. Loaded lazily by `asset_ref.module`.

## modules/EditorPanelAssetTypeRef/getInitScript {#modules-editorpanelassettyperef-getinitscript}

```lua
getInitScript(self): string?
```

Read the instance's init.luau source as raw text (inspectors).

**Parameters**

- `self` `any` _(optional)_

## modules/EditorPanelAssetTypeRef/loadSpecMethod {#modules-editorpanelassettyperef-loadspecmethod}

```lua
loadSpecMethod(self): any
```

Read this instance's panel spec (the table its init.luau returns).

**Parameters**

- `self` `any` _(optional)_

```lua
local spec = panelRef:loadSpec()
```

## modules/EditorPanelAssetTypeRef/onChange {#modules-editorpanelassettyperef-onchange}

```lua
onChange(self, change)
```

**Parameters**

- `self` `any` _(optional)_
- `change` `any` _(optional)_

## modules/EditorPanelAssetTypeRef/onRegister {#modules-editorpanelassettyperef-onregister}

```lua
onRegister(self)
```

**Parameters**

- `self` `any` _(optional)_

## modules/EffectAssetTypeRef/README {#modules-effectassettyperef-readme}

```lua
EffectAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<effect>`. Loaded lazily by `asset_ref.module` the first time an effect ref is touched in a VM. An effect is a `<name>.effect/` folder holding `effect.yaml` (the family, the declared parameters and the measured cost) and `init.luau` (the definition that builds the effect on screen). `:describe()` reads the declaration, `:play(opts)` runs the definition.

## modules/EffectAssetTypeRef/cost {#modules-effectassettyperef-cost}

```lua
cost(self): { [string]: any }
```

The effect's declared cost — what one unpooled play of it was measured
to draw. `{ gpuMs, vramBytes, measuredOn }`. The asset is the one
machine-readable home of these numbers; a README states them by quoting
this declaration.

**Parameters**

- `self` `any` _(optional)_

```lua
print(fx:cost().gpuMs)
```

## modules/EffectAssetTypeRef/describe {#modules-effectassettyperef-describe}

```lua
describe(self): { [string]: any }
```

Everything the effect declares about itself: its canonical identity, its
family, a one-line summary, the measured cost and the full parameter list.
The single call an author makes before playing an unfamiliar effect.

**Parameters**

- `self` `any` _(optional)_

```lua
local d = fx:describe(); print(d.family, #d.params, d.cost.gpuMs)
```

## modules/EffectAssetTypeRef/getReadme {#modules-effectassettyperef-getreadme}

```lua
getReadme(self): string?
```

Read the effect's `README.md` body.

**Parameters**

- `self` `any` _(optional)_

```lua
print(fx:getReadme())
```

## modules/EffectAssetTypeRef/inspect {#modules-effectassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail: the effect's family, its declared
cost and its parameter names, read from its own `effect.yaml`.

**Parameters**

- `self` `any` _(optional)_

```lua
local detail = asset.inspect(fx).detail
```

## modules/EffectAssetTypeRef/onChange {#modules-effectassettyperef-onchange}

```lua
onChange(ref: any, change: any)
```

Drop the effect declaration cached on this ref after a write inside the
instance, so the next read re-parses `effect.yaml` from the file on disk.

**Parameters**

- `ref` `any` _(optional)_ — The changed `.effect` asset's reference.
- `change` `any` _(optional)_ — The change record the asset dispatcher raised for the write.

## modules/EffectAssetTypeRef/params {#modules-effectassettyperef-params}

```lua
params(self): { { [string]: any } }
```

The effect's declared parameters, in declaration order. Each entry is
`{ name, type, default, min, max, options, desc }` — `min`/`max` are
present only on the numeric ones and `options` only on the enums, where it
is the closed list of names that parameter accepts. This is the list
`:play` validates a caller's overrides against.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, p in ipairs(fx:params()) do print(p.name, p.default) end
```

## modules/EffectAssetTypeRef/play {#modules-effectassettyperef-play}

```lua
play(self, opts: { [string]: any }?): { [string]: any }
```

Play the effect once at a position. This is the unpooled reference path:
it allocates the effect's emitters and entities on the call and releases
them when the effect finishes, and every entity it spawns is temporary, so
nothing it draws enters a saved scene or replicates.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ [string]: any }?` _(optional)_ — `{ position? = { x, y, z }, rotation? = quat, direction? = { x, y, z },
params? = { … }, held? = boolean }`. `params` are overrides on the declaration; anything
omitted takes its declared default. `held` starts the effect stopped at
time zero so the caller drives it with `handle:seek(t)` — what a preview
or a pixel probe needs to read the same frame twice. `effects.play` is the
same call with the pool in front of it, for gameplay code firing the same
effect over and over.

```lua
local h = fx:play { position = { 0, 2, 0 }, params = { scale = 6 } }
```

## modules/EffectAssetTypeRef/preview {#modules-effectassettyperef-preview}

```lua
preview(self, opts: { [string]: any }?): { [string]: any }
```

Render this effect to a still through the shared preview rig — the
image `preview.writePreview` persists as the asset's `preview.png`. The
effect is played on the rig and advanced to the moment its definition
reports as most representative before the frame is taken.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ [string]: any }?` _(optional)_ — `{ size? = { width, height }, angle? = { yaw, pitch } }`.

```lua
local shot = fx:preview({ size = { width = 256, height = 256 } })
```

## modules/EffectAssetTypeRef/resolveParams {#modules-effectassettyperef-resolveparams}

```lua
resolveParams(self, overrides: { [string]: any }?): { [string]: any }
```

Resolve a caller's overrides against the declaration: every declared
parameter gets a value, each one coerced to its declared type and held
inside its documented range. A name the effect does not declare raises,
naming the ones it does — a misspelling that silently did nothing would be
indistinguishable from a parameter that has no effect.

**Parameters**

- `self` `any` _(optional)_
- `overrides` `{ [string]: any }?` _(optional)_ — Table of `{ [paramName] = value }`, or nil for the defaults.

```lua
local p = fx:resolveParams({ scale = 6 })
```

## modules/EffectBackends/README {#modules-effectbackends-readme}

```lua
EffectBackends
```

The five kinds of thing an effect is made of, each behind one contract the runtime leases, re-seats and re-fires. An effect family that needs a new way of drawing registers a backend here rather than widening the runtime: a particle or mesh emitter, a material applied to a mesh the caller already has, generated geometry the effect owns, a decal projector, and a render feature.

## modules/EffectBackends/builtin {#modules-effectbackends-builtin}

```lua
builtin(): { [string]: Backend }
```

The backend kinds this module ships, keyed by name, for the runtime to
register at startup.

```lua
for kind, impl in pairs(EffectBackends.builtin()) do … end
```

## modules/EffectBackends/featureParams {#modules-effectbackends-featureparams}

```lua
featureParams(identity: string): { [string]: any }
```

The parameter table a render feature backend writes for one feature
identity. A render feature reads its own entry each frame to find what the
effect playing through it is asking for; `active` says whether any play
currently holds it.

**Parameters**

- `identity` `string` — The render feature's asset identity.

```lua
local p = require("@builtin::systems.effects.backends").featureParams(IDENTITY)
```

## modules/EffectBackends/setDecalOpacity {#modules-effectbackends-setdecalopacity}

```lua
setDecalOpacity(inst: any, opacity: number)
```

Fade a live decal projector, so a scorch mark or an impact ring dies on
the effect's own clock rather than waiting for a script to fade it by hand.

**Parameters**

- `inst` `any` _(optional)_ — The decal instance a lease holds.
- `opacity` `number` — Master fade, 0..1.

```lua
EffectBackends.setDecalOpacity(lease.instance, 1 - t)
```

## modules/EffectParams/README {#modules-effectparams-readme}

```lua
EffectParams
```

The parameter vocabulary an effect declares in `effect.yaml` and a caller overrides at play time. One declaration of what each type accepts, read by the effect asset's `resolveParams` and by the runtime's `handle:setParam`, so a value means the same thing wherever it is written.

## modules/EffectParams/coerce {#modules-effectparams-coerce}

```lua
coerce(where: string, decl: { [string]: any }, value: any): any
```

Coerce one authored value onto the type its declaration names, and hold
a number inside its documented range. Raises when the value cannot be read
as the declared type, naming what the type takes.

**Parameters**

- `where` `string` — The effect identity the message names.
- `decl` `{ [string]: any }` — The parameter declaration — `{ name, type, min, max }`.
- `value` `any` _(optional)_ — The caller's value.

```lua
local v = EffectParams.coerce(identity, decl, { 0, 3, 0 })
```

## modules/EffectParams/find {#modules-effectparams-find}

```lua
find(declared: { { [string]: any } }, name: string): { [string]: any }?
```

The declaration of one named parameter out of a list, or nil.

**Parameters**

- `declared` `{ { [string]: any } }` — Array of parameter declarations.
- `name` `string` — The parameter name to find.

```lua
local d = EffectParams.find(decls, "scale")
```

## modules/EffectParams/resolve {#modules-effectparams-resolve}

```lua
resolve(where: string, declared: { { [string]: any } },
```

Resolve a caller's overrides against a declaration list: every declared
parameter gets a value, each coerced to its declared type and held inside
its documented range. A name the effect does not declare raises, naming the
ones it does.

```lua
local p = EffectParams.resolve(id, decls, { scale = 6 })
```

## modules/EffectParams/typeNames {#modules-effectparams-typenames}

```lua
typeNames(): { string }
```

The declared type names as an ordered list, for an error that has to
name what is accepted.

```lua
error("takes one of " .. table.concat(EffectParams.typeNames(), ", "))
```

## modules/EffectsRuntime/README {#modules-effectsruntime-readme}

```lua
EffectsRuntime
```

The machinery behind `effects.play` — the backend registry, the pool every play leases its backends from, the frame driver that advances every live play, and the handle a caller stops, retargets and re-tunes. The `effects` global is the documented surface over this; an effect asset's own `:play` is the same call with pooling turned off.

## modules/EffectsRuntime/backendKinds {#modules-effectsruntime-backendkinds}

```lua
backendKinds(): { string }
```

The backend kinds registered right now, in name order.

```lua
print(table.concat(EffectsRuntime.backendKinds(), ", "))
```

## modules/EffectsRuntime/definition {#modules-effectsruntime-definition}

```lua
definition(identity: string): { [string]: any }
```

Load an effect's own definition module — the `init.luau` beside its
`effect.yaml`.

**Parameters**

- `identity` `string` — The effect's canonical identity.

```lua
local def = EffectsRuntime.definition(identity)
```

## modules/EffectsRuntime/drain {#modules-effectsruntime-drain}

```lua
drain(): { [string]: number }
```

Free every backend the pool is holding idle. This is the whole of the
retention policy: the pool keeps what it has leased for as long as the
engine runs, and releases it only here. Nothing a play still holds is
touched — a drain during a live play frees what is idle and leaves the rest
to its own end.

```lua
local r = effects.drain(); print(r.freed, r.kept)
```

## modules/EffectsRuntime/observe {#modules-effectsruntime-observe}

```lua
observe(): { [string]: any }
```

What the effects runtime is holding and driving right now: every live
play with the reason it is silent when it is, plus what the pool has
leased out and what it is keeping idle, in instances and in GPU bytes.

```lua
local o = effects.observe(); print(o.live, o.leased, o.pooled, o.bytes)
```

## modules/EffectsRuntime/play {#modules-effectsruntime-play}

```lua
play(opts: { [string]: any }): { [string]: any }
```

Play an effect. The definition builds itself through a context that
leases its backends from the pool, and the runtime's driver advances it
until it ends — so a caller runs no update loop and a play that finishes
gives back everything it held.

**Parameters**

- `opts` `{ [string]: any }` — `{ identity, path, declared, params, position, direction, target,
held, pooled, definition }`.

```lua
EffectsRuntime.play({ identity = id, definition = def, pooled = true })
```

## modules/EffectsRuntime/registerBackend {#modules-effectsruntime-registerbackend}

```lua
registerBackend(kind: string, impl: Backends.Backend)
```

Register a way of drawing under a kind name. An effect family that
needs one the runtime does not ship registers it here, and every effect
reaches it through `ctx.lease(kind, …)` with no change to the runtime.

**Parameters**

- `kind` `string` — The kind name a spec asks for.
- `impl` `Backends.Backend` — The backend — `key`, `acquire`, `seat`, `start`, `stop`, `quiet`,
`place`, `bytes`, `active`, `silence` and `free`.

```lua
EffectsRuntime.registerBackend("ribbonTrail", myBackend)
```

## modules/EffectsRuntime/resolve {#modules-effectsruntime-resolve}

```lua
resolve(spelling: string): any
```

Find the one effect a spelling names. A canonical identity resolves
directly; a short name resolves when exactly one effect carries it, and
names every candidate when more than one does rather than picking a winner.

**Parameters**

- `spelling` `string` — A canonical identity or a short name.

```lua
local ref = EffectsRuntime.resolve("explosion")
```

## modules/EffectsRuntime/silenceReasons {#modules-effectsruntime-silencereasons}

```lua
silenceReasons(): { { reason: string, means: string } }
```

The closed set of reasons a play can be producing nothing, in the order
a reading resolves them — nearest cause first — each with what it means.
Every reason `observe()` reports is one of these.

```lua
for _, r in ipairs(effects.silenceReasons()) do print(r.reason, r.means) end
```

## modules/Engine/README {#modules-engine-readme}

```lua
require("@builtin/modules/engine") -- Engine (also available as global 'engine')
```

Process-level engine state surface. Read-only boot profile and read-write engine mode. Both exposed as computed properties via metatable __index / __newindex — never call them as methods. Usage: if engine.profile == "editor" then ... end engine.mode = "play" engine.setMode("play", { strict = false }) Implemented as a thin Luau wrapper over internal FFI: engine.profile      →  __engineSettings.get("profile") engine.mode         →  __mode.get() / __mode.set(value) engine.setMode      →  __mode.set(value, strict) engine.paused       →  __pause.get() / __pause.set(value) engine.timeScale    →  __timescale.get() / __timescale.set(value) engine.gameplayReady →  __gameplay.ready() `engine.mode = X` is load-bearing — the setter owns the mode-flip side effects so any path that changes mode behaves identically: edit → play: drain pending edit-mode marks into the dirty overlay (so wld.edit() can reassemble the user's authored state) BEFORE flipping `__mode`. Never writes canonical scene.json. play → edit: flip `__mode` first, then reload the active non-additive layer so the dirty overlay reapplies + play-mode runtime mutations are discarded. Toolbox wrappers (`wld.play()` / `wld.edit()`) are thin pass-throughs — they MUST NOT carry side-effect logic. If a future caller writes `engine.mode = "play"` directly (or via a different toolbox tool), the same side effects fire. Putting drain/reload on the toolbox alone would let a direct assignment leave the scene in a half-applied state. See `man engine` for the full surface and side effects.

Usage: local Engine = require("@builtin/modules/engine")
Also available as global: engine

## modules/Engine/_fireWorldLoaded {#modules-engine-fireworldloaded}

```lua
_fireWorldLoaded()
```

INTERNAL. Mark the world fully loaded and fan out to every
`onWorldLoaded` subscriber. Called by the builtin world-entrypoint
loader once `onWorldLoad` has returned. Idempotent per load — re-fires
on a genuine reload (mirrors a scene's onReady), so the flag is set
true and subscribers run on each call.

## modules/Engine/_resetWorldLoaded {#modules-engine-resetworldloaded}

```lua
_resetWorldLoaded()
```

INTERNAL. Clear the world-loaded latch on unbind/unload so a
subsequent bind re-fires onWorldLoaded for the new world.

## modules/Engine/markScriptingBaseline {#modules-engine-markscriptingbaseline}

```lua
markScriptingBaseline(): number
```

Record the scripting registries — world-event subscriptions, the
four lifecycle-watcher lists, and the require cache — as they stand
right now, and make that the point `engine.resetScriptingState()`
restores to. Replaces any previous mark. Returns the new mark's
generation, counting from 1.
Mark once the engine is serving rather than while it boots: the
registries keep growing as the prelude subscribes, the world
entrypoint runs and the startup scene loads, so a mark taken partway
through sits below the rest of that work and the first reset would
remove it.

```lua
engine.markScriptingBaseline()
world.on("player_join", function() end)
engine.resetScriptingState() -- the subscription above is gone
```

## modules/Engine/offDeviceRebuilt {#modules-engine-offdevicerebuilt}

```lua
offDeviceRebuilt(id: number): boolean
```

Remove an `engine.onDeviceRebuilt` subscriber by its watcher id.
Returns true when a live watcher carried that id, false when it named
none — already removed, or never registered.

**Parameters**

- `id` `number` — Watcher id returned by `engine.onDeviceRebuilt`.

```lua
local id = engine.onDeviceRebuilt(function() end)
engine.offDeviceRebuilt(id)
```

## modules/Engine/offModeChange {#modules-engine-offmodechange}

```lua
offModeChange(id: number): boolean
```

Remove an `engine.onModeChange` subscriber by its watcher id.
Returns true when a live watcher carried that id, false when it
named none — already removed, or never registered.

**Parameters**

- `id` `number` — Watcher id returned by `engine.onModeChange`.

```lua
local id = engine.onModeChange(function() end)
engine.offModeChange(id)
```

## modules/Engine/offPauseChange {#modules-engine-offpausechange}

```lua
offPauseChange(id: number): boolean
```

Remove an `engine.onPauseChange` subscriber by its watcher id.
Returns true when a live watcher carried that id, false when it
named none.

**Parameters**

- `id` `number` — Watcher id returned by `engine.onPauseChange`.

## modules/Engine/offWorldLoaded {#modules-engine-offworldloaded}

```lua
offWorldLoaded(id: number): boolean
```

Remove an `onWorldLoaded` subscriber by its watcher id.

**Parameters**

- `id` `number`

## modules/Engine/offWorldReady {#modules-engine-offworldready}

```lua
offWorldReady(id: number): boolean
```

Remove an `engine.onWorldReady` subscriber by its watcher id.
Returns true when a live watcher carried that id, false when it
named none.

**Parameters**

- `id` `number` — Watcher id returned by `engine.onWorldReady`.

## modules/Engine/offWorldUnloading {#modules-engine-offworldunloading}

```lua
offWorldUnloading(id: number): boolean
```

Remove an `engine.onWorldUnloading` subscriber by its watcher
id. Returns true when a live watcher carried that id, false when it
named none.

**Parameters**

- `id` `number` — Watcher id returned by `engine.onWorldUnloading`.

## modules/Engine/onDeviceRebuilt {#modules-engine-ondevicerebuilt}

```lua
onDeviceRebuilt(callback: (number) -> ()): number
```

Register a callback that fires after the engine has answered a lost
render device by building another one. The callback receives the new
device generation — a number that counts the devices this session has run
on, and moves exactly once per rebuild. Returns a watcher id.

A device is lost when the driver resets, when the GPU is taken away, or
when a browser reclaims a WebGPU context. Everything the engine can
re-derive by itself it does: meshes, materials, shaders, render passes and
the UI are all back on the new device before this fires. What it cannot
re-derive is what YOUR content made and only the GPU held — a texture
uploaded from pixels a script computed, a compute buffer it filled, a
render target it created. Make those again here.

Content that owns no GPU resource of its own needs no subscriber: asset
handles re-materialise on their next use.

**Parameters**

- `callback` `(number) -> ()` — Function invoked as `(generation: number)`.

```lua
engine.onDeviceRebuilt(function(generation)
-- the noise field lived only on the GPU, so it is computed again
regenerateNoiseTexture()
end)
```

## modules/Engine/onModeChange {#modules-engine-onmodechange}

```lua
onModeChange(callback: (string, string) -> ()): number
```

Register a callback that fires synchronously whenever
`engine.mode` changes. Callback receives `(newMode, oldMode)` as
strings. Returns a watcher id for future removal. Consumers
(player_spawner, camera_spawner, editor-UI bootstrap, world
entrypoint top-level `onModeChange`, etc.) all subscribe through
this single API — there is no other fire path. Mode is engine
state, so the watcher hangs off the `engine` module.

**Parameters**

- `callback` `(string, string) -> ()` — Function invoked as `(newMode: string, oldMode: string)`.

```lua
local id = engine.onModeChange(function(new, old)
print("flipped " .. old .. " -> " .. new)
end)
```

## modules/Engine/onPauseChange {#modules-engine-onpausechange}

```lua
onPauseChange(callback: (boolean, boolean) -> ()): number
```

Register a callback that fires synchronously whenever the gameplay
pause flag flips via an explicit `engine.paused` write. Callback
receives `(newPaused, oldPaused)` as booleans. Returns a watcher id.
Pause is independent of `engine.mode`: pausing play mode returns the
editor authoring surface (free camera + EditorOnly entities) over the
frozen play world, and resuming hides it again. Mode-driven pause
resets (the edit=paused / play=running defaults applied on a mode flip)
are delivered through `onModeChange`, not this hook.

**Parameters**

- `callback` `(boolean, boolean) -> ()` — Function invoked as `(newPaused: boolean, oldPaused: boolean)`.

```lua
local id = engine.onPauseChange(function(paused)
print(paused and "frozen" or "running")
end)
```

## modules/Engine/onWorldLoaded {#modules-engine-onworldloaded}

```lua
onWorldLoaded(callback: () -> ()): number
```

Register a callback fired (no args) when the world is fully
LOADED — its `.world_entrypoint.luau` ran AND its `onWorldLoad`
returned (the startup scene loaded, defaults seeded, editor UI
mounted). This is strictly AFTER `onWorldReady` (content synced):
ready = "bytes are in the VFS"; loaded = "the entrypoint has run".
LATCHED — a callback registered after the world is already loaded
fires immediately, so a late consumer never misses it and never has
to poll. Read the same state synchronously via `engine.worldLoaded`.

**Parameters**

- `callback` `() -> ()` — Function invoked with no arguments.

## modules/Engine/onWorldReady {#modules-engine-onworldready}

```lua
onWorldReady(callback: () -> ()): number
```

Register a callback fired (no args) when the bound world's
content has been synced into the VFS and the world is ready to
load. This is the race-free, user-space hook that drives the whole
world-VM lifecycle: the builtin world-entrypoint loader subscribes
to it and, when it fires, `loadstring(vfs.read(...))`s
`/source/.world_entrypoint.luau` and runs its `onWorldLoad` —
exactly the way a scene entrypoint loads. The trusted VM fires this
(via `world.markReady()`) ONLY once the bytes are in the VFS, so a
subscriber never sees a half-synced world. Returns a watcher id.

**Parameters**

- `callback` `() -> ()` — Function invoked with no arguments.

## modules/Engine/onWorldUnloading {#modules-engine-onworldunloading}

```lua
onWorldUnloading(callback: () -> ()): number
```

Symmetric teardown of `engine.onWorldReady`: register a callback
fired (no args) when the bound world is unbinding/swapping out. The
builtin loader runs the world entrypoint's `onWorldUnload` here, so
the world entrypoint has the same load/unload parity a scene
entrypoint has. Returns a watcher id.

**Parameters**

- `callback` `() -> ()` — Function invoked with no arguments.

## modules/Engine/resetScriptingState {#modules-engine-resetscriptingstate}

```lua
resetScriptingState(): { [string]: number }
```

Drop every world-event subscription, lifecycle watcher and
cached module registered since the last
`engine.markScriptingBaseline()`, leaving everything registered
before it in place — including the builtin world-entrypoint loader,
which subscribes at VM boot and so always sits below any mark.
Raises when no mark has been taken. Returns per-registry counts of
what was removed: `worldEvents`, `modeWatchers`,
`worldReadyWatchers`, `worldUnloadingWatchers`, `pauseWatchers`,
`modules`, and `total`.

## modules/Engine/scriptingRegistryCounts {#modules-engine-scriptingregistrycounts}

```lua
scriptingRegistryCounts(): { [string]: number }
```

How many subscriptions each scripting registry holds right now,
plus the size of the require cache and the generation of the mark in
force. Keys: `worldEvents`, `modeWatchers`, `worldReadyWatchers`,
`worldUnloadingWatchers`, `pauseWatchers`, `modules`, and
`baselineGeneration` (nil when no mark has been taken).

## modules/Engine/setMode {#modules-engine-setmode}

```lua
setMode(mode: string, options: { strict: boolean? }?): { mode: string, bypassed: { any } }
```

Change the engine mode with per-call control over the play gate, and
read back what the change went past. `engine.mode = value` is the same
flip with the defaults.

`options.strict = false` lets THIS call enter play while your own content
carries error-severity diagnostics. It settles with the call: the world's
`lsp.strict_mode` is untouched, so no other session and no later session
of the world sees a different gate. The returned `bypassed` array holds
the diagnostics the call went past — each `{ path, line, col, code,
message, severity }` — and the engine log carries the same list. An
error in content another session wrote never gates the flip, so it never
appears here; a push still refuses to publish while any of them stands.

**Parameters**

- `mode` `string` — `"edit"` or `"play"`.
- `options` `{ strict: boolean? }?` _(optional)_ — `{ strict: boolean? }`. `strict = false` waives the play gate
for this call; `true` or omitted honours the world's `lsp.strict_mode`.

```lua
local report = engine.setMode("play", { strict = false })
for _, d in ipairs(report.bypassed) do
print(("entered play past %s:%d — %s"):format(d.path, d.line, d.message))
end
```

## modules/EntityRecords/README {#modules-entityrecords-readme}

```lua
EntityRecords
```

Walks a live entity hierarchy into the flat record array the engine's entity templates use. Shared by `bundle` (its `entity_template`) and by scene builds (their baked output), so both speak one record shape.

## modules/EntityRecords/authoredComponentData {#modules-entityrecords-authoredcomponentdata}

```lua
authoredComponentData(
```

A component instance's snapshot with the fields the instance wrote
about its own runtime removed, leaving what states how it was CONFIGURED.
A capture reads it to build the record, and whoever diffs a live entity
against that record reads it too, so both sides speak the same fields.

```lua
local d = EntityRecords.authoredComponentData(id, ty, nil, snapshot)
```

## modules/EntityRecords/captureRecord {#modules-entityrecords-capturerecord}

```lua
captureRecord(rid: string, parentOriginalId: string?): any
```

Capture ONE entity into a template record. Reads LIVE component public
state (serialized component snapshots), not init data, so the record
matches what is on screen. Each component INSTANCE gets its own entry,
carrying `instance_name` when the instance has one, so a type the entity
carries several of comes back as the same several. The record also
carries the entity's own
`active` flag, every attribute it holds, and its lifecycle mode and
replication scope when either is other than the default. The entity's
runtime id IS its record `original_id`, so cross-entity component
references — which already point at runtime ids — round-trip and get
remapped on the next instantiate. Each component entry names the fields
holding such a reference in `entity_fields`, taken from the component's
declared field kinds, so a rebuild resolves exactly those.

**Parameters**

- `rid` `string` — Runtime entity id to capture.
- `parentOriginalId` `string?` _(optional)_ — Parent's original_id, or nil for a root record.

```lua
local rec = EntityRecords.captureRecord(id, nil)
```

## modules/EntityRecords/componentIsCodeAttached {#modules-entityrecords-componentiscodeattached}

```lua
componentIsCodeAttached(rid: string, componentType: string): boolean
```

Whether another component's lifecycle attached this component instance,
rather than an author putting it there. A composed asset brings its own
machinery with it — a humanoid avatar attaches a character controller to
the body it expands into — and that machinery comes back on its own
wherever the composition does. A record that named it would put a second
one beside the one the expansion just produced, and a rebuild that removed
every component its records leave unnamed would tear the expansion off the
entity it belongs to. Both sides of a rebuild ask this.

Reached through the `_G` singleton the origin module publishes, which is
the same answer the scene serializer takes for the same question; a load
order that has not published it yet reads every component as authored.

**Parameters**

- `rid` `string` — Runtime entity id carrying the instance.
- `componentType` `string` — Component type name as the entity reports it.

```lua
if EntityRecords.componentIsCodeAttached(id, "Humanoid") then continue end
```

## modules/EntityRecords/compose {#modules-entityrecords-compose}

```lua
compose(
```

Build the flat record array by walking `rootId`'s hierarchy. Skips
`temporary` entities and their descendants — scaffolding and editor-only
tooling stay out of a baked result. The explicit root is always captured:
the caller named THAT entity as the thing to serialize, so temporary
pruning applies to descendants.

```lua
local records = EntityRecords.compose(rootId)
```

## modules/EntityRecords/composeMany {#modules-entityrecords-composemany}

```lua
composeMany(
```

Compose several roots into one flat record array. A build captures a
SET of roots (a builder may spawn several unparented entities), not the
single root a bundle composes from. The roots are ordered the same way
siblings are — by `rank`, then name, then id.

```lua
local records = EntityRecords.composeMany({ idA, idB })
```

## modules/ExplosionEffect/README {#modules-explosioneffect-readme}

```lua
ExplosionEffect
```

The definition behind `explosion.effect` — a fireball shell, a rising smoke column, thrown debris and a flash of light, all proportioned off the blast radius the caller asks for.

## modules/FontAssetTypeRef/README {#modules-fontassettyperef-readme}

```lua
FontAssetTypeRef
```

Hooks for `.font` assets. `onCreate` is the type's contribution to the generic `asset.create("font", name, opts)` flow (mirroring `texture.assetType`): it parses the font file ONCE into the baked, vectorized glyph format (`data.zfnt`) — the asset payload. `onRegister` loads that baked format via the engine `font.register(name, zfnt)` primitive — a font is a general CPU resource, so one registration makes `fontFamily = "<name>"` resolve on the egui UI text surface AND on `text.*` 2D/3D rendering, and feeds `font.glyph` / `font.textMesh` for true 3D text.

## modules/FontAssetTypeRef/onCreate {#modules-fontassettyperef-oncreate}

```lua
onCreate(name: string, opts: CreateOpts): { [string]: string }
```

The `.font` type's contribution to `asset.create("font", name, opts)`.
Parses the font file ONCE into the baked vectorized glyph format and stores
it as `data.zfnt`. The original font bytes are embedded inside the baked
payload, so no separate font file is kept. The heavy parse happens here, at
author time — `onRegister` then loads the result cheaply.

**Parameters**

- `name` `string` — The font asset name (also the registered `fontFamily`).
- `opts` `CreateOpts`

```lua
asset.create("font", "Inter", { bytes = fontBytes, ext = "ttf" })
```

## modules/FontAssetTypeRef/onRegister {#modules-fontassettyperef-onregister}

```lua
onRegister(self)
```

Install this `.font` instance into the engine's text systems. Reads the
instance's baked `data.zfnt` and calls `font.register(name, zfnt)`, which
loads the vectorized glyph data into the runtime store (for `font.glyph` /
`font.textMesh`) and feeds the embedded font bytes to the 2D/3D text and
egui UI systems. Falls back to a raw font file for instances authored
before the baked layout (`font.register` reparses, with a slow-path warn).
Fired once per instance by the asset system (live on `asset.create`, and in
the world-load sweep). Guarded so a single bad font never errors the sweep.

**Parameters**

- `self` `any` _(optional)_

## modules/FxFrameProbe/README {#modules-fxframeprobe-readme}

```lua
FxFrameProbe
```

The reader half of the frame probe — the grid `fx_frame_probe.renderFeature` writes each frame, and the measurements taken off it. A suite requires this module and enables the feature; the feature records the target it writes here, so both halves address one target. They are separate assets because `renderer.feature.create` compiles a feature's `init.luau` as its own chunk rather than requiring it, so a feature cannot publish state to a caller through its own module table. What it is for: a returned screenshot is not evidence. A fully transparent emitter reports live particles, reports that it drew, and changes the image hash. A reader needs a magnitude, taken from the frame a viewer actually sees, that a known control is shown to move.

## modules/FxFrameProbe/channelSums {#modules-fxframeprobe-channelsums}

```lua
channelSums(grid: { [string]: any }?): { [string]: number }
```

Sum each colour channel over the grid — how much red, green and blue the
frame carries. What a colour parameter has to move.

**Parameters**

- `grid` `{ [string]: any }?` _(optional)_ — A grid from `read()`.

```lua
local c = probe.channelSums(probe.read())
```

## modules/FxFrameProbe/litRegion {#modules-fxframeprobe-litregion}

```lua
litRegion(grid: { [string]: any }?, baseline: { [string]: any }?, threshold: number): { [string]: number }
```

The size of the lit region: how many tiles rise `threshold` luminance
above `baseline`'s same tile, and the radius of a disc with that area, in
tiles. This is the spatial reading — how WIDE something drew, which no
whole-frame number can answer.

**Parameters**

- `grid` `{ [string]: any }?` _(optional)_ — The grid to measure.
- `baseline` `{ [string]: any }?` _(optional)_ — The grid of the same view with the subject absent.
- `threshold` `number` — How far above the baseline tile a tile must rise to count.

```lua
local r = probe.litRegion(after, before, 6).radius
```

## modules/FxFrameProbe/movedTiles {#modules-fxframeprobe-movedtiles}

```lua
movedTiles(grid: { [string]: any }?, other: { [string]: any }?, threshold: number): number
```

How many tiles differ between two grids by at least `threshold`
luminance, in either direction. Zero says the two readings are the same
picture — which is what a reading that has not caught up with a change yet
also answers, so this is how a caller tells a still frame from one that has
not arrived.

**Parameters**

- `grid` `{ [string]: any }?` _(optional)_ — The grid to measure.
- `other` `{ [string]: any }?` _(optional)_ — The grid to measure it against.
- `threshold` `number` — How far a tile must differ to count.

```lua
if probe.movedTiles(now, before, 4) > 0 then --[[ the change landed ]] end
```

## modules/FxFrameProbe/read {#modules-fxframeprobe-read}

```lua
read(): { [string]: any }?
```

Read the last grid the probe wrote. Returns
`{ width, height, tiles }`, where `tiles[y * width + x + 1]` is that tile's
mean colour as `{ r, g, b }` in 0..255, plus `lum` — the tile's luminance
on the same scale.

```lua
local grid = probe.read(); print(grid.tiles[1].lum)
```

## modules/FxFrameProbe/totalLuminance {#modules-fxframeprobe-totalluminance}

```lua
totalLuminance(grid: { [string]: any }?): number
```

Sum the grid's luminance — the whole frame's brightness as one number.

**Parameters**

- `grid` `{ [string]: any }?` _(optional)_ — A grid from `read()`.

```lua
local before = probe.totalLuminance(probe.read())
```

## modules/FxKindsEffect/README {#modules-fxkindseffect-readme}

```lua
FxKindsEffect
```

The fixture the effects runtime's non-emitter backends are read through. Each parameter stages exactly one backend, and a parameter at zero stages none of it — so one effect covers a play that draws through four kinds and a play that stages nothing at all.

## modules/GI.Scenarios/README {#scenarios-readme}

```lua
require("@builtin/systems/globalIllumination.package/scenarios") -- GI.Scenarios
```

Several baked lighting states per probe volume, blended at runtime.

A volume holds one bake, so a scene lit for noon cannot become a scene lit
for dusk without baking again — which takes far longer than a transition
is allowed to. Capturing each bake under a name and blending the captures
turns that into an interpolation the frame can afford.
Irradiance adds, so blending the spherical-harmonic coefficients is the
same as blending the light that produced them. Each coefficient's fourth
lane is not light, though: it carries the probe's per-axis visibility
reach and the markers the sampler reads. Those describe the geometry the
volume sits in, which every scenario shares, so they are carried from the
heaviest-weighted scenario rather than averaged — the mean of two
distances describes no wall that exists.
Carrying them from the heaviest contributor also makes the ends of a
transition exact: a blend that names one scenario at full weight
reproduces that scenario's field lane for lane.

Usage: local GI.Scenarios = require("@builtin/systems/globalIllumination.package/scenarios")

## modules/GI.Scenarios/blend {#scenarios-blend}

```lua
blend(volumeEntityId: string, weights: { [string]: number }) -> boolean
```

Publish the weighted mix of named scenarios to the renderer.

**Parameters**

- `volumeEntityId` `string`
- `weights` `{ [string]: number }`

**Returns** `boolean`

## modules/GI.Scenarios/capture {#scenarios-capture}

```lua
capture(volumeEntityId: string, name: string) -> number
```

Store the volume's currently published field under a name. Returns how many probes it holds.

**Parameters**

- `volumeEntityId` `string`
- `name` `string`

**Returns** `number`

## modules/GI.Scenarios/clear {#scenarios-clear}

```lua
clear(volumeEntityId: string)
```

**Parameters**

- `volumeEntityId` `string`

## modules/GI.Scenarios/field {#scenarios-field}

```lua
field(volumeEntityId: string, name: string) -> { number }?
```

**Parameters**

- `volumeEntityId` `string`
- `name` `string`

**Returns** `{ number }?`

## modules/GI.Scenarios/forget {#scenarios-forget}

```lua
forget(volumeEntityId: string, name: string)
```

**Parameters**

- `volumeEntityId` `string`
- `name` `string`

## modules/GI.Scenarios/list {#scenarios-list}

```lua
list(volumeEntityId: string) -> { string }
```

**Parameters**

- `volumeEntityId` `string`

**Returns** `{ string }`

## modules/GI.Scenarios/mix {#scenarios-mix}

```lua
mix(fields: { { number } }, weights: { number }) -> { number }
```

Blend baked SH fields by weight. Pure — no volume, no GPU.

**Parameters**

- `fields` `{ { number } }`
- `weights` `{ number }`

**Returns** `{ number }`

## modules/GI.Scenarios/stats {#scenarios-stats}

```lua
stats() -> table
```

**Returns** `table`

## modules/GI.SkyResponse/README {#skyresponse-readme}

```lua
require("@builtin/systems/globalIllumination.package/skyResponse") -- GI.SkyResponse
```

A probe volume's sky term, evaluated at publish time instead of baked in.

A probe bake follows each path until it escapes, and what escapes carries
the sky's colour. Baking that in means the sky is fixed the moment the
bake finishes: a scene cannot dim its sky for dusk, or clear an overcast,
without paying for the bake again.
The sky enters the path integral as `throughput * sky` at the point a ray
escapes, and `throughput` — the product of the albedos the path already
passed through — does not depend on the sky at all. So the baked field
splits exactly into a term that has nothing to do with the sky and a term
that is linear in it, per channel:
    field(sky) = lights + sky * aperture
`lights` is a bake under no sky. `aperture` is what a unit sky adds: how
much of it each probe can see, tinted by whatever the light passed through
on the way, so sky arriving through a red wall stays red.
Both come from real bakes at the same settings, and the bake seeds its
paths from the probe and sample index alone — so the two runs trace the
same paths and the subtraction that isolates the aperture carries no
sampling residual.

Usage: local GI.SkyResponse = require("@builtin/systems/globalIllumination.package/skyResponse")

## modules/GI.SkyResponse/apply {#skyresponse-apply}

```lua
apply(volumeEntityId: string, sky: { number }) -> boolean
```

Publish the volume's field for a sky colour. No bake.

**Parameters**

- `volumeEntityId` `string`
- `sky` `{ number }`

**Returns** `boolean`

## modules/GI.SkyResponse/calibrate {#skyresponse-calibrate}

```lua
calibrate(volumeEntityId: string) -> table
```

Bake the volume twice — once with no sky, once with a unit sky — and keep the two terms the split needs.

**Parameters**

- `volumeEntityId` `string`

**Returns** `table`

## modules/GI.SkyResponse/calibrated {#skyresponse-calibrated}

```lua
calibrated(volumeEntityId: string) -> boolean
```

**Parameters**

- `volumeEntityId` `string`

**Returns** `boolean`

## modules/GI.SkyResponse/clear {#skyresponse-clear}

```lua
clear(volumeEntityId: string)
```

**Parameters**

- `volumeEntityId` `string`

## modules/GI.SkyResponse/combine {#skyresponse-combine}

```lua
combine(lights: { number }, aperture: { number }, sky: { number }) -> { number }
```

The field for a sky colour, from the two calibrated terms. Pure.

**Parameters**

- `lights` `{ number }`
- `aperture` `{ number }`
- `sky` `{ number }`

**Returns** `{ number }`

## modules/GI.SkyResponse/terms {#skyresponse-terms}

```lua
terms(volumeEntityId: string) -> table?
```

**Parameters**

- `volumeEntityId` `string`

**Returns** `table?`

## modules/GaussianSplatAssetTypeBehavior/README {#modules-gaussiansplatassettypebehavior-readme}

```lua
GaussianSplatAssetTypeBehavior
```

Behaviour for the `gaussianSplat` asset type — how a capture becomes something standing in a scene. A cloud draws through a `GaussianSplat` component pointed at the container, so `:instantiate()` — the uniform contract every consumer reaches — spawns exactly that, in the axis convention the container recorded.

## modules/GaussianSplatAssetTypeBehavior/instantiate {#modules-gaussiansplatassettypebehavior-instantiate}

```lua
instantiate(self, target: EntityRef?, opts: { [string]: any }?): (EntityRef, { [string]: string })
```

Instantiate this capture — spawn an entity drawing the cloud, in the
axis convention the container recorded. The same name a `bundle` and an
`avatar` answer to, so an asset goes into a scene the same way whatever
kind it is.

Passing a target `entityRef` spawns the cloud as that entity's CHILD, so
an owner that tears down its children takes the cloud with it. With no
target the cloud is a fresh root.

**Parameters**

- `self` `any` _(optional)_
- `target` `EntityRef?` _(optional)_ — Optional owning `EntityRef` — the cloud spawns as its child.
- `opts` `{ [string]: any }?` _(optional)_ — `{ position?, rotation?, scale?, name?, temporary? }` — the base
placement opts; `temporary` keeps the spawn out of the saved scene.

```lua
local root = asset.resolve("room", "gaussianSplat"):instantiate()
local root = captureRef:instantiate(entity.spawn("mount"))
```

## modules/GuideAssetTypeRef/README {#modules-guideassettyperef-readme}

```lua
GuideAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<guide>`. Loaded lazily by `asset_ref.module`.

## modules/GuideAssetTypeRef/getGuide {#modules-guideassettyperef-getguide}

```lua
getGuide(self): string?
```

Read the guide's `guide.md` body.

**Parameters**

- `self` `any` _(optional)_

```lua
local md = guideRef:getGuide()
```

## modules/GuideAssetTypeRef/getReadme {#modules-guideassettyperef-getreadme}

```lua
getReadme(self): string?
```

Read the guide's `README.md` body.

**Parameters**

- `self` `any` _(optional)_

```lua
print(guideRef:getReadme())
```

## modules/GuideAssetTypeRef/inspect {#modules-guideassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail: `{ headings, wordCount }`,
parsed from this guide's own `guide.md`. A guide with no readable
`guide.md` returns an empty `headings` list and zero `wordCount`
rather than erroring.

**Parameters**

- `self` `any` _(optional)_

```lua
local headings = asset.inspect(guideRef).detail.headings
```

## modules/ImpactEffect/README {#modules-impacteffect-readme}

```lua
ImpactEffect
```

The definition behind `impact.effect` — a flash at the point of impact and a burst thrown back along the surface normal, whose character is the named surface that was hit.

## modules/ImpactEffect/surfaces {#modules-impacteffect-surfaces}

```lua
surfaces(): { string }
```

The names the `surface` parameter accepts, in declaration order — the
same list the parameter's own declaration carries.

```lua
for _, s in ipairs(require(IMPACT).surfaces()) do print(s) end
```

## modules/ImporterAssetTypeRef/README {#modules-importerassettyperef-readme}

```lua
ImporterAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<importer>`. Loaded lazily by `asset_ref.module`.

## modules/ImporterAssetTypeRef/getInitScript {#modules-importerassettyperef-getinitscript}

```lua
getInitScript(self): string?
```

Read the importer's entry script as raw text.

**Parameters**

- `self` `any` _(optional)_

```lua
local src = importerRef:getInitScript()
```

## modules/ImporterAssetTypeRef/getReadme {#modules-importerassettyperef-getreadme}

```lua
getReadme(self): string?
```

Read the importer's README.

**Parameters**

- `self` `any` _(optional)_

```lua
print(importerRef:getReadme())
```

## modules/ImporterAssetTypeRef/run {#modules-importerassettyperef-run}

```lua
run(self, payload: any): any
```

Invoke the importer with a payload (e.g. a path to the file
to import). Loads the importer module on demand and calls its
primary exported function. Raises a Luau error tagged with the
importer's identity on load failure / missing entry.

**Parameters**

- `self` `any` _(optional)_
- `payload` `any` _(optional)_ — Argument forwarded verbatim to the importer entry.

```lua
importerRef:run("/zero/source/foo.glb")
```

## modules/ImporterShared/README {#modules-importershared-readme}

```lua
require("@builtin/@builtin::assetTypes.importer.shared") -- ImporterShared
```

The importer SYSTEM — shared by every `.importer/` instance. Owns dispatch, origin-gating, content-gating, the `asset.containing` bundle skip, re-entrancy, output marking, and bundle relocation. The engine emits one generic "a source path was written" signal per write (`onLooseWrite`); this module decides whether any registered importer should claim it and runs the winner. Individual importers implement ONLY `canImport(path, bytes)` + `import(ctx)` — never trigger logic.

Usage: local ImporterShared = require("@builtin/@builtin::assetTypes.importer.shared")

## modules/ImporterShared/awaitJob {#modules-importershared-awaitjob}

```lua
awaitJob(path: string, timeoutSecs: number?): ImportJob?
```

Wait until the latest job for `path` reaches a terminal state
(imported / failed / unclaimed / skipped — NOT the in-flight "queued" or
"running"), or the timeout elapses. Returns the job (nil when no job exists
for the path at all).

**Parameters**

- `path` `string` — The source VFS path.
- `timeoutSecs` `number?` _(optional)_ — Max seconds to wait (default 30).

## modules/ImporterShared/cancelAllQueued {#modules-importershared-cancelallqueued}

```lua
cancelAllQueued(): number
```

Cancel EVERY queued source that hasn't started importing yet (in-flight
imports are left to finish). Use it to abandon a large accidental drop.

## modules/ImporterShared/cancelQueued {#modules-importershared-cancelqueued}

```lua
cancelQueued(path: string): boolean
```

Cancel a QUEUED source before it runs: drop it from the pump's queue and
settle its job as "cancelled". A source already importing is mid-parse and
can't be unwound cleanly, so only queued items cancel — returns false for a
path that is already running, terminal, or was never queued.

**Parameters**

- `path` `string` — The queued source VFS path.

## modules/ImporterShared/explain {#modules-importershared-explain}

```lua
explain(path: string): { [string]: any }
```

Dry-run the dispatch gates for a path WITHOUT importing: does the file
exist, which importers claim it, and which gate (if any) would stop an
import right now. The answer to "I wrote this file and nothing happened".

**Parameters**

- `path` `string` — The source VFS path.

## modules/ImporterShared/importedAssets {#modules-importershared-importedassets}

```lua
importedAssets(): { { [string]: any } }
```

Every asset in the world carrying import provenance, newest `at` first.
Each row: `{ asset (path), importer (guid), source ({guid,path}), iteration,
at }`. Backed by the asset.list presence filter — one cross-type query.

## modules/ImporterShared/job {#modules-importershared-job}

```lua
job(path: string): ImportJob?
```

The latest import job recorded for an exact source path, or nil when
no dispatch has reached a claimant for it.

**Parameters**

- `path` `string` — The source VFS path.

## modules/ImporterShared/jobs {#modules-importershared-jobs}

```lua
jobs(filter: { state: string?, path: string?, limit: number? }?): { ImportJob }
```

Recent import jobs, newest first. Pass a filter to narrow: `state`
keeps one state, `path` substring-matches the source path, `limit` caps
the count (default 25).

**Parameters**

- `filter` `{ state: string?, path: string?, limit: number? }?` _(optional)_ — Optional `{ state?: string, path?: string, limit?: number }`.

## modules/ImporterShared/listImporters {#modules-importershared-listimporters}

```lua
listImporters(): { { name: string, identity: string } }
```

Every registered importer: `{ name, identity }` per `.importer` asset.

## modules/ImporterShared/onLooseWrite {#modules-importershared-onloosewrite}

```lua
onLooseWrite(path: string, origin: string?)
```

Engine-driven: a source path with no enclosing typed-asset folder
was written. Gate on origin + re-entrancy, then ENQUEUE it on the bounded
import queue (default concurrency 1) — the pump reads the bytes, decides
whether a registered importer claims it, applies the content + containment
gates, and runs the winner, one import at a time.

**Parameters**

- `path` `string` — The written VFS path.
- `origin` `string?` _(optional)_ — "local" for a write made on this client, "remote" for a
peer-synced write. Only "local" writes trigger — peers receive the
originator's derived bundle as ordinary synced content.

## modules/ImporterShared/queue {#modules-importershared-queue}

```lua
queue(): { ImportJob }
```

The live import backlog: queued sources (still waiting behind the
concurrency cap, in FIFO order) followed by the ones importing right now.
The focused "what is the importer doing this instant" view, distinct from
`jobs` (the full recent-dispatch log including terminal states).

## modules/ImporterShared/reimportAsset {#modules-importershared-reimportasset}

```lua
reimportAsset(assetPath: string): string?
```

Reimport a produced asset in place: resolve its source and re-run the
importers on it (the containment gate regenerates the container's derived
assets from the retained source). Returns the produced path, or nil when no
source could be resolved.

**Parameters**

- `assetPath` `string` — The produced asset's path.

## modules/ImporterShared/resolveImportSource {#modules-importershared-resolveimportsource}

```lua
resolveImportSource(assetPath: string): string?
```

Resolve the source file a produced asset was imported from. Prefers the
provenance source guid (survives rename/move), falls back to the recorded
path, then to scanning the container for an importer-claimed file.

**Parameters**

- `assetPath` `string` — The produced asset's path (e.g. a `.bundle`).

## modules/ImporterShared/runImporters {#modules-importershared-runimporters}

```lua
runImporters(path: string, forcedContainer: string?): string?
```

Run the importers on `path` NOW and return the produced asset path
(a `.bundle` / `.texture` / `.audio` / …), or nil if no importer claims it.
The manual, deterministic counterpart to the engine's loose-write dispatch:
forced (no origin, content, or containment gate) and synchronous — it runs
in the calling task and returns only when the import is complete, so a
caller can write a raw source quietly (`vfs.write(path, bytes, { quiet =
true })`) and then import it deterministically instead of racing the
watcher. A source that already lives inside its own output container
re-imports in place, regenerating the container's derived assets from the
retained source.

**Parameters**

- `path` `string` — The raw source VFS path to import.
- `forcedContainer` `string?` _(optional)_ — Optional output container to regenerate in place — used by
`reimportAsset` so a renamed/relocated source still reimports the original
asset instead of minting a differently-named sibling.

## modules/ImporterShared/runTargets {#modules-importershared-runtargets}

```lua
runTargets(target: any, opts: { recursive: boolean?, mode: string? }?): { [string]: any }
```

Import/reimport one target, an array of targets, or a folder. A produced
asset (with provenance) reimports in place; a loose source imports; a folder
is scanned (recursive by default) and its imported assets reimported + loose
sources imported, filtered by `opts.mode` ("all" | "new" | "existing").

**Parameters**

- `target` `any` _(optional)_ — A VFS path string or an array of path strings.
- `opts` `{ recursive: boolean?, mode: string? }?` _(optional)_ — `{ recursive?: boolean (default true), mode?: "all"|"new"|"existing" }`.

## modules/ImporterShared/stats {#modules-importershared-stats}

```lua
stats(): { queued: number, running: number, states: { [string]: number } }
```

Live queue counters: `queued` (sources waiting on the pump — the
authoritative backlog depth), `running` (imports in flight), and `states`
(every recorded job tallied by state). `queued` and `running` are exact;
`states` tallies the job registry, which keeps every in-flight job plus
the most recent settled records.

## modules/InputBindingAssetTypeRef/README {#modules-inputbindingassettyperef-readme}

```lua
InputBindingAssetTypeRef
```

## modules/InputBindingAssetTypeRef/onCreate {#modules-inputbindingassettyperef-oncreate}

```lua
onCreate(name: string, opts: CreateOpts): { [string]: string }
```

Generic-creation hook for `asset.create("inputBinding", name, opts)`.
Writes a record carrying every device class, so a binding is complete
the moment it exists.

**Parameters**

- `name` `string`
- `opts` `CreateOpts`

```lua
asset.create("inputBinding", "boost", { label = "Boost", kind = "button", kbm = '{ B.key("ShiftLeft") }', gamepad = '{ B.padButton("left_shoulder") }', touch = '{ B.touchButton({ zone = "right-lower" }) }' })
```

## modules/InputBindingAssetTypeRef/problemsWith {#modules-inputbindingassettyperef-problemswith}

```lua
problemsWith(record: any, name: string): { string }
```

Check a binding record for the things that make it unusable, and
return the problems rather than raising, so a tool can report every
fault in a map at once instead of stopping at the first.

**Parameters**

- `record` `any` _(optional)_ — The binding record to check.
- `name` `string` — The binding's name, for the messages.

## modules/InputMacroAssetTypeRef/README {#modules-inputmacroassettyperef-readme}

```lua
InputMacroAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<inputMacro>`. Loaded lazily by `asset_ref.module`.

## modules/InputMacroAssetTypeRef/getEvents {#modules-inputmacroassettyperef-getevents}

```lua
getEvents(self): { any }?
```

Parse `events.json` into a Lua table.

**Parameters**

- `self` `any` _(optional)_

```lua
local events = macroRef:getEvents()
```

## modules/InputMacroAssetTypeRef/getEventsRaw {#modules-inputmacroassettyperef-geteventsraw}

```lua
getEventsRaw(self): string?
```

Read the macro's `events.json` body as raw JSON text.

**Parameters**

- `self` `any` _(optional)_

```lua
local raw = macroRef:getEventsRaw()
```

## modules/InputMacroAssetTypeRef/length {#modules-inputmacroassettyperef-length}

```lua
length(self): number
```

Number of recorded events.

**Parameters**

- `self` `any` _(optional)_

```lua
print(macroRef:length())
```

## modules/InputMacroAssetTypeRef/replay {#modules-inputmacroassettyperef-replay}

```lua
replay(self): number
```

Replay the macro by handing its recorded events to the sim
toolbox's `macro` tool, which dispatches each timed input event
through the engine input surface. Returns the number of events
queued for replay.

**Parameters**

- `self` `any` _(optional)_

```lua
local n = macroRef:replay()
```

## modules/InputMapAssetTypeRef/README {#modules-inputmapassettyperef-readme}

```lua
InputMapAssetTypeRef
```

## modules/InputMapAssetTypeRef/activateShape {#modules-inputmapassettyperef-activateshape}

```lua
activateShape(self): (string, string)
```

The type `activate()` answers for one map — a field per control it
declares, each a `Handle`.

**Parameters**

- `self` `any` _(optional)_ — The map.

```lua
local text = M.refShapes.activate(mapRef)
```

## modules/InputMapAssetTypeRef/onChange {#modules-inputmapassettyperef-onchange}

```lua
onChange(self, change)
```

Re-activate this map after a write inside the instance, so an edit
to its bindings takes hold in the running session. Only the map that is
currently active is re-activated; a removal is ignored.

**Parameters**

- `self` `any` _(optional)_ — The changed `.inputMap` asset's reference.
- `change` `any` _(optional)_ — The change record the asset dispatcher raised for the write.

## modules/InputMapAssetTypeRef/onCreate {#modules-inputmapassettyperef-oncreate}

```lua
onCreate(name: string, opts: CreateOpts): { [string]: string }
```

Generic-creation hook for `asset.create("inputMap", name, opts)`.
With `opts.record`, bakes it into both shapes a map is read in — the
"play it, bake it, tweak it" on-ramp `Zin.map.bake` drives.

`init.luau` returns the record's flat `actions` / `axes` tables, which
is what `Zin.map.materialize` reads. Beside it, one
`<name>.inputBinding/` child per entry, which is what a controller
subscribes to through `activate()`. Each child carries all three
device classes, a class the baked map had nothing for written as
`false` with the reason beside it.

A binding that fails to serialize (an unknown kind, or an
`axis`/`vector` composite whose nested arm fails — the whole composite
drops) is dropped from `init.luau` with an
`-- UNSERIALIZED kind: <kind> (<name>)` comment line; a
function-valued axis `gate` / `curve` is dropped with a
`-- <name>.gate omitted` / `-- <name>.curve omitted` comment line.
An entry whose name no asset folder can take, or that lost every
device class, stays in `init.luau` alone and is named in the header
comment as a control the bake could not make.

With no `opts.record`, contributes nothing on top of the type's
`template/` skeleton.

**Parameters**

- `name` `string`
- `opts` `CreateOpts`

```lua
Zin.map.bake("my_scheme")
```

## modules/InspectorAppLayout/README {#modules-inspectorapplayout-readme}

```lua
require("@builtin/_templates.inspector_app.inspector_app_layout") -- InspectorAppLayout
```

Property-inspector shell on the raw widget tree — a section header and labelled field rows (text input, slider, checkbox) whose edits update the displayed state.

Usage: local InspectorAppLayout = require("@builtin/_templates.inspector_app.inspector_app_layout")

## modules/LightmapDataAssetTypeRef/README {#modules-lightmapdataassettyperef-readme}

```lua
LightmapDataAssetTypeRef
```

Per-instance methods on every `AssetRef<lightmapData>` — the baked-lighting container the bake flow writes and component awakes read. Entries are keyed (lightmaps by entity id, probe fields by field id); each entry pairs a manifest record with a raw f32 payload file inside the container.

## modules/LightmapDataAssetTypeRef/beginBatch {#modules-lightmapdataassettyperef-beginbatch}

```lua
beginBatch(self)
```

Hold the manifest open across a run of writes. Each `setLightmap` /
`setProbeField` still writes its payload file as it goes, but the manifest
is read once here and written once by `commitBatch`, instead of being
decoded and re-encoded per entry. A bake storing many entries into one
container is the case this exists for. Re-entrant calls are ignored, and
a batch left open by an error is closed by the next `commitBatch`.

**Parameters**

- `self` `any` _(optional)_

```lua
container:beginBatch()
for _, s in surfaces do container:setLightmap(s.id, s.meta, s.texels) end
container:commitBatch()
```

## modules/LightmapDataAssetTypeRef/clearEntries {#modules-lightmapdataassettyperef-clearentries}

```lua
clearEntries(self)
```

Remove every entry and payload, leaving an empty manifest — the
container-wide teardown `baking.clear` uses for a full-scene clear.

**Parameters**

- `self` `any` _(optional)_

```lua
container:clearEntries()
```

## modules/LightmapDataAssetTypeRef/commitBatch {#modules-lightmapdataassettyperef-commitbatch}

```lua
commitBatch(self)
```

Write the manifest a `beginBatch` has been holding and close the batch.
No-op when no batch is open.

**Parameters**

- `self` `any` _(optional)_

```lua
container:commitBatch()
```

## modules/LightmapDataAssetTypeRef/lightmap {#modules-lightmapdataassettyperef-lightmap}

```lua
lightmap(self, key: string): (LightmapEntry?, { number }?)
```

Read one entity's baked lightmap.

**Parameters**

- `self` `any` _(optional)_
- `key` `string` — The receiver entity id.

```lua
local entry, texels = container:lightmap(entityId)
```

## modules/LightmapDataAssetTypeRef/manifest {#modules-lightmapdataassettyperef-manifest}

```lua
manifest(self)
```

The decoded manifest: `{ version, lightmaps = { [entityId] = entry },
probeFields = { [fieldId] = entry } }`.

**Parameters**

- `self` `any` _(optional)_

```lua
local m = container:manifest()
```

## modules/LightmapDataAssetTypeRef/onCreate {#modules-lightmapdataassettyperef-oncreate}

```lua
onCreate(name: string, opts: { scene: string? }?)
```

Create an empty baked-lighting container. The bake flow
(`baking.all` / `Lightmap.bake` / `VolumeProbe.bake`) fills it.

**Parameters**

- `name` `string`
- `opts` `{ scene: string? }?` _(optional)_

## modules/LightmapDataAssetTypeRef/probeField {#modules-lightmapdataassettyperef-probefield}

```lua
probeField(self, key: string): (ProbeFieldEntry?, { number }?)
```

Read one probe volume's baked field.

**Parameters**

- `self` `any` _(optional)_
- `key` `string` — The volume's stable field id.

```lua
local entry, sh = container:probeField(fieldId)
```

## modules/LightmapDataAssetTypeRef/removeLightmap {#modules-lightmapdataassettyperef-removelightmap}

```lua
removeLightmap(self, key: string)
```

Remove one entity's lightmap entry and its payload file. No-op when
the entry is absent.

**Parameters**

- `self` `any` _(optional)_
- `key` `string` — The receiver entity id.

```lua
container:removeLightmap(entityId)
```

## modules/LightmapDataAssetTypeRef/removeProbeField {#modules-lightmapdataassettyperef-removeprobefield}

```lua
removeProbeField(self, key: string)
```

Remove one probe volume's field entry and its payload file. No-op
when the entry is absent.

**Parameters**

- `self` `any` _(optional)_
- `key` `string` — The volume's stable field id.

```lua
container:removeProbeField(fieldId)
```

## modules/LightmapDataAssetTypeRef/setLightmap {#modules-lightmapdataassettyperef-setlightmap}

```lua
setLightmap(self, key: string, meta: { [string]: any }, texels: { number })
```

Store one entity's baked lightmap: writes the texel payload file
and its manifest entry, replacing any prior entry under the same key.

**Parameters**

- `self` `any` _(optional)_
- `key` `string` — The receiver entity id.
- `meta` `{ [string]: any }` — `{ resolution, intensity }` — the parameters the
runtime needs to rebuild the lightmap and place it in the atlas.
- `texels` `{ number }` — Flat f32 RGBA texel array (resolution² × 4 floats, dilated,
alpha = coverage).

```lua
container:setLightmap(entityId, { resolution = 256, intensity = 1 }, data)
```

## modules/LightmapDataAssetTypeRef/setProbeField {#modules-lightmapdataassettyperef-setprobefield}

```lua
setProbeField(self, key: string, meta: { [string]: any }, sh: { number })
```

Store one probe volume's baked field: writes the SH payload file
and its manifest entry, replacing any prior entry under the same key.

**Parameters**

- `self` `any` _(optional)_
- `key` `string` — The volume's stable field id.
- `meta` `{ [string]: any }` — `{ boundsMin = {x,y,z}, boundsMax = {x,y,z}, res = {x,y,z}, count }`.
- `sh` `{ number }` — Flat f32 SH L2 array — 36 floats per probe, X-fastest.

```lua
container:setProbeField(fieldId, { boundsMin = mn, boundsMax = mx, res = r, count = n }, sh)
```

## modules/MaterialAssetTypeRef/README {#modules-materialassettyperef-readme}

```lua
MaterialAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<material>`. Loaded lazily by `asset_ref.module` via `require("@builtin::assetTypes.material.behavior")` the first time a material ref is touched in a VM.

## modules/MaterialAssetTypeRef/applyToEntity {#modules-materialassettyperef-applytoentity}

```lua
applyToEntity(self, entityId: string): boolean
```

Apply this material to an entity by setting the `material` field on its
Model / SkinnedModel component (where the renderer reads it). A material
only renders where there is a mesh.

**Parameters**

- `self` `any` _(optional)_
- `entityId` `string` — Target entity ID.

```lua
matRef:applyToEntity(playerId)
```

## modules/MaterialAssetTypeRef/getDefinition {#modules-materialassettyperef-getdefinition}

```lua
getDefinition(self): string?
```

Read the on-disk `mat.yaml` body as raw text. Use
`vfs.write(self.path .. "/mat.yaml", ...)` to write the file directly,
`:setProperty` / `:setTexture` followed by `:saveDefinition` to write the
current values into it, or `:setShader` to rewrite it for a new shader.

**Parameters**

- `self` `any` _(optional)_

```lua
local yaml = matRef:getDefinition()
```

## modules/MaterialAssetTypeRef/getShader {#modules-materialassettyperef-getshader}

```lua
getShader(self): string?
```

Read the shader identity currently bound to this material —
parses `mat.yaml` and returns the `shader:` field as a string. The
result is whatever the YAML names (a built-in like `"pbr"`, a
guid, or a full identity like `"@builtin::shaders.pbr"`); pass it
to `asset.resolve(..., "shader")` to get a ref.

**Parameters**

- `self` `any` _(optional)_

```lua
local s = matRef:getShader()
```

## modules/MaterialAssetTypeRef/inspector {#modules-materialassettyperef-inspector}

```lua
inspector(self): { any }
```

The material's editing surface for a host UI: titled sections of field
rows, each carrying its editing kind and the closure that writes the
change back. Kinds come from the SHADER's declared vocabulary (its
`properties.yaml` descriptors), values from the live cache (the shader's
defaults overlaid by this material's overrides). The host renders the rows
in its own field language; this never builds widgets. Writes go through
`setProperty` / `setTexture` / `setShader`, so every edit takes the same
GPU-push + persistence path a scripted write takes.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, section in ipairs(matRef:inspector()) do print(section.title) end
```

## modules/MaterialAssetTypeRef/isRegistered {#modules-materialassettyperef-isregistered}

```lua
isRegistered(self): boolean
```

Whether this material exists as an asset — its `mat.yaml` is present.
Writing the asset is what registers the material, so file presence IS the
registration check.

**Parameters**

- `self` `any` _(optional)_

```lua
if matRef:isRegistered() then ... end
```

## modules/MaterialAssetTypeRef/onChange {#modules-materialassettyperef-onchange}

```lua
onChange(ref, change)
```

Asset-type change callback: (re)register this material into the renderer's
MaterialRegistry whenever its `.material` is seeded (a baked builtin at boot,
or a world seed) or its `mat.yaml` is edited. This is the ONLY thing that
populates the registry for a material — the legacy boot-time library loader
(which registered every material by name) is gone; materials register
through their own assetType exactly as shaders do (`__shader.compile`). Keyed
by identity, guid as alias, so a `MaterialRef.id` (name / identity / guid)
resolves to the right entry. Convergent + idempotent: see `registerToGpu`.

**Parameters**

- `ref` `any` _(optional)_
- `change` `any` _(optional)_

## modules/MaterialAssetTypeRef/onCreate {#modules-materialassettyperef-oncreate}

```lua
onCreate(name: string, opts: CreateOpts): { [string]: string }
```

Generic-creation hook for `asset.create("material", name, opts)`.
Pure: returns the `mat.yaml` content for the caller to persist to the
authored destination; the write registers the material definition
(CPU-side) — GPU resources are built later, only on actual use. Properties
resolve from the shader's `properties.yaml` overlaid by these overrides; no
shader compile happens at create. Flat non-reserved top-level keys on opts
are shader-property overrides (e.g. `base_color = {1,0,0,1}`, `roughness =
0.3`), admitted by the open schema and resolved against the shader's
properties.yaml inside the hook.

**Parameters**

- `name` `string` — Material identity (the instance name).
- `opts` `CreateOpts`

```lua
asset.create("material", "Gold", { shader = "pbr", base_color = {1, 0.84, 0, 1}, metallic = 1, roughness = 0.2 })
asset.create("material", "Glass", { shader = "pbr", base_color = {0.2, 0.9, 0.4, 0.45}, render = { blend = "alphaBlend", depth_write = false } })
```

## modules/MaterialAssetTypeRef/preview {#modules-materialassettyperef-preview}

```lua
preview(self, opts: { [string]: any }?)
```

Render a preview of this material on a unit sphere.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ [string]: any }?` _(optional)_ — `{ size? = { width, height } }`.

```lua
local p = matRef:preview()
```

## modules/MaterialAssetTypeRef/saveDefinition {#modules-materialassettyperef-savedefinition}

```lua
saveDefinition(self): boolean
```

Persist the material's live runtime overrides into its `mat.yaml` (the
lazy/explicit flush). Property/texture sets are frame-fast and transient by
default (they live on the ref's runtime, wiped on mode change); call this to
bake the current values into the asset so they survive a restart. Routes
through the `mat.yaml` write → `RegisterMaterial` path. The changed values
are written where they already stand in the authored file, so its comments,
the order of its keys and blocks, and the spelling of the literals it was
written with all survive the save.

**Parameters**

- `self` `any` _(optional)_

```lua
matRef:saveDefinition()
```

## modules/MaterialAssetTypeRef/setProperties {#modules-materialassettyperef-setproperties}

```lua
setProperties(self, patch: { [string]: any }): number
```

Set many properties at once, resolving each key against the shader's
vocabulary the way `setProperty` does. Entries the material's shader doesn't
expose are skipped (a generic patch table won't error on shader differences).

**Parameters**

- `self` `any` _(optional)_
- `patch` `{ [string]: any }` — Table of `{ [propertyName] = value }` pairs.

```lua
matRef:setProperties({ roughness = 0.2, metallic = 0.9 })
```

## modules/MaterialAssetTypeRef/setShader {#modules-materialassettyperef-setshader}

```lua
setShader(self, shaderRef: any): (boolean, any)
```

Switch this material to a different shader by **rewriting the material
asset itself** (`mat.yaml`), then letting the asset-reload pipeline mark
every instance dirty so the renderer repacks. The full `mat.yaml` is
regenerated for the new shader's property vocabulary: current property
values and texture links are carried across by canonical ROLE (via
`modules.material_remap`), so `MAIN_TEX`→`albedo`→`base_color_texture`
and friends survive the swap to our best ability. Properties the new
shader does not expose are dropped; the `name`, `builtin`, `parent`,
`description`, and `render:` block are preserved verbatim. This modifies
the on-disk asset (or, in play mode, its runtime copy) — not a throwaway
registry entry — so the change persists and propagates to all instances.

**Parameters**

- `self` `any` _(optional)_
- `shaderRef` `any` _(optional)_ — An `AssetRef<shader>` (preferred) or a shader-identity string
(`"pbr"`, `"@builtin::shaders.unlit"`).

```lua
matRef:setShader(asset.resolve("@builtin::shaders.unlit", "shader"))
matRef:setShader("pbr")
```

## modules/MaterialRemap/README {#modules-materialremap-readme}

```lua
MaterialRemap
```

Canonical property/texture-role dictionary for cross-shader value preservation. When a material swaps shaders the new shader exposes a DIFFERENT vocabulary (one shader's `MAIN_TEX` is another's `albedo` is a third's `base_color_texture`). This module maps any known alias onto a canonical role so values carry across the swap "to our best ability".

## modules/MaterialRemap/canonicalizeTextures {#modules-materialremap-canonicalizetextures}

```lua
canonicalizeTextures(
```

Canonicalize texture-slot names so links survive a shader swap. Each
known slot is rewritten to its canonical on-disk slot name; unknown slots
pass through unchanged. (The engine does not yet expose a target shader's
reflected texture-slot list, so canonicalizing to the builtin convention
is the best-effort path — see material_remap module header.)

## modules/MaterialRemap/propertyRole {#modules-materialremap-propertyrole}

```lua
propertyRole(name: string): string?
```

Canonical role for a scalar/color property name, or nil when unknown.

**Parameters**

- `name` `string` — Property name as it appears in a shader / mat.yaml.

```lua
material_remap.propertyRole("MAIN_COLOR") -- "base_color"
```

## modules/MaterialRemap/remapProperties {#modules-materialremap-remapproperties}

```lua
remapProperties(
```

Remap a table of old property values onto a target shader's accepted
property names. Direct name matches win; otherwise the old key's canonical
role is matched against the role of each target name. Values whose role
the target shader does not expose are dropped (best-effort preservation).

## modules/MaterialRemap/roleShapePair {#modules-materialremap-roleshapepair}

```lua
roleShapePair(role: string): ({ colour: string, scalar: string })?
```

The colour+scalar role pair a role belongs to, as `{ colour, scalar }`,
or nil when the role stands alone. Both halves answer with the same pair,
so a caller holding either one can ask which value shape belongs where.

**Parameters**

- `role` `string` — A canonical role from `propertyRole`.

```lua
material_remap.roleShapePair("emissive") -- { colour = "emissive", scalar = "emissive_intensity" }
```

## modules/MaterialRemap/textureRole {#modules-materialremap-texturerole}

```lua
textureRole(slot: string): string?
```

Canonical texture-slot role (and on-disk slot name) for a texture slot
name, or nil when unknown.

**Parameters**

- `slot` `string` — Texture slot name as it appears in a shader / mat.yaml.

```lua
material_remap.textureRole("MAIN_TEX") -- "base_color_texture"
```

## modules/MaterialSchema/README {#modules-materialschema-readme}

```lua
MaterialSchema
```

A shader's declared property vocabulary, and the routing of an authored key onto it. Every path that accepts material properties — the `.material` assetType and `renderer.material.create` — resolves the backing shader's `properties.yaml` through here, so the two agree on which keys are real, which are texture slots, and what to say about a key that is neither.

## modules/MaterialSchema/declaredNames {#modules-materialschema-declarednames}

```lua
declaredNames(schema: Schema): { string }
```

Every name a schema declares, sorted — properties and texture slots.

**Parameters**

- `schema` `Schema` — A `Schema` from `forShader`.

```lua
local names = MaterialSchema.declaredNames(schema)
```

## modules/MaterialSchema/declaredNamesList {#modules-materialschema-declarednameslist}

```lua
declaredNamesList(schema: Schema): string
```

Comma-joined declared names, for the "not declared" diagnostic so the
author sees exactly which keys the shader accepts.

**Parameters**

- `schema` `Schema` — A `Schema` from `forShader`.

```lua
warn("declared: " .. MaterialSchema.declaredNamesList(schema))
```

## modules/MaterialSchema/displacedMessage {#modules-materialschema-displacedmessage}

```lua
displacedMessage(name: string, key: string, declared: string): string
```

The diagnostic for an authored key whose value another spelling of the
same declared property took precedence over.

**Parameters**

- `name` `string` — The material's name or registry key.
- `key` `string` — The authored key whose value did not apply.
- `declared` `string` — The declared property that took its value from another spelling.

```lua
warn(MaterialSchema.displacedMessage(name, "emissive_color", "emissive"))
```

## modules/MaterialSchema/forShader {#modules-materialschema-forshader}

```lua
forShader(shader: string): Schema?
```

The declared vocabulary of the shader backing a material, split into
uniform properties and texture slots. Read from the shader assetType's
`getProperties()` (its `properties.yaml`).

**Parameters**

- `shader` `string` — Shader identity, path, or short name (`"pbr"`).

```lua
local s = MaterialSchema.forShader("pbr")
```

## modules/MaterialSchema/isTextureValue {#modules-materialschema-istexturevalue}

```lua
isTextureValue(value: any): boolean
```

Whether a value is a texture binding rather than a scalar/vector.
A `renderer.texture` handle (`kind == "TextureHandle"`) or any
`AssetRef<texture>` envelope. Scalar/vector values are bare numbers or
numeric arrays, so this never misfires on a colour like `{1, 0, 0, 1}`.

**Parameters**

- `value` `any` _(optional)_ — The authored value.

```lua
MaterialSchema.isTextureValue(tex) -- true
```

## modules/MaterialSchema/roleIndex {#modules-materialschema-roleindex}

```lua
roleIndex(props: { [string]: boolean }): { [string]: string }
```

The role index for a set of declared property names: canonical role ->
the single declared name claiming it. A role two declared names both claim
is left out, so an authored spelling never resolves to an arbitrary one of
them. This is what turns `emissive_color` into the `emissive` a shader
declares, and `ao_strength` into its `occlusion_strength`.

**Parameters**

- `props` `{ [string]: boolean }` — Declared property names, as a `{ [name]: true }` set.

```lua
local byRole = MaterialSchema.roleIndex({ emissive = true })
```

## modules/MaterialSchema/route {#modules-materialschema-route}

```lua
route(schema: Schema, key: string, value: any): (Route, string)
```

Resolve an authored key against a schema: which surface it belongs to
and under what name. Routes by the schema's texture slots and by the
value's own shape (a texture value is a texture binding whatever the key is
called), then by canonical role — so a spelling from another engine's
convention reaches the property this shader declares for that role, under
the name the shader declares it by.

**Parameters**

- `schema` `Schema` — A `Schema` from `forShader`.
- `key` `string` — The authored key.
- `value` `any` _(optional)_ — The authored value.

```lua
local route, name = MaterialSchema.route(schema, "color", {1,0,0,1})
```

## modules/MaterialSchema/routeAll {#modules-materialschema-routeall}

```lua
routeAll(schema: Schema, authored: { [string]: any }): (
```

Route a whole authored property table at once, so two spellings that
resolve to one declared property are settled the same way everywhere.

**Parameters**

- `schema` `Schema` — A `Schema` from `forShader`.
- `authored` `{ [string]: any }` — `{ [key] = value }` as written by the author.

```lua
local props, tex, unknown = MaterialSchema.routeAll(schema, parsed)
```

## modules/MaterialSchema/settle {#modules-materialschema-settle}

```lua
settle(schema: Schema, claimed: { Claim }): (
```

Settle the authored values that resolved onto declared properties, so
every path that accepts material properties answers the same way. One
declared name takes one value — the spelling the shader declares verbatim,
else the first in key order, so the outcome is the authored table's rather
than the order `pairs` walked it in. Two spellings meeting on one half of a
colour+scalar pair the shader declares both halves of are not competing: a
number is the scalar and a vector is the colour, the reading the uniform
buffer already makes of them, so a material naming its glow colour under
one convention and its brightness under another keeps both values.

**Parameters**

- `schema` `Schema` — A `Schema` from `forShader`.
- `claimed` `{ Claim }` — Every `Claim` that routed to a property.

```lua
local props, displaced = MaterialSchema.settle(schema, claims)
```

## modules/MaterialSchema/undeclaredMessage {#modules-materialschema-undeclaredmessage}

```lua
undeclaredMessage(name: string, key: string, shader: string, schema: Schema): string
```

The diagnostic for a key the shader declares under neither surface,
naming the material, the key, the shader, and the accepted vocabulary.
One wording for every path that accepts material properties.

**Parameters**

- `name` `string` — The material's name or registry key.
- `key` `string` — The key that is not declared.
- `shader` `string` — The backing shader's name.
- `schema` `Schema` — A `Schema` from `forShader`.

```lua
warn(MaterialSchema.undeclaredMessage(name, key, shader, schema))
```

## modules/MaterialSchema/valueShape {#modules-materialschema-valueshape}

```lua
valueShape(value: any): "scalar" | "vector" | "either"
```

What shape an authored value has, for the one question a colour+scalar
pair asks of it. A number is the scalar; a numeric array or an `{r, g, b}`
colour is the vector. Anything else answers `"either"` and stays with the
half its key claimed.

**Parameters**

- `value` `any` _(optional)_ — The authored value.

```lua
MaterialSchema.valueShape(5) -- "scalar"
```

## modules/MeshAssetTypeBehavior/README {#modules-meshassettypebehavior-readme}

```lua
MeshAssetTypeBehavior
```

Behaviour for the `mesh` asset type — the disk + CPU side of the disk-asset ↔ GPU-mesh split. `onCreate` writes the engine-native `ZMSH` geometry payload as the container's `data.zmsh` primary; `:load()` decodes it into the CPU store and returns a CPU handle. Both go through the public `renderer.mesh.*` API — this behaviour calls no `__` FFI directly.

## modules/MeshAssetTypeBehavior/getVertices {#modules-meshassettypebehavior-getvertices}

```lua
getVertices(self)
```

Read this mesh's vertices — one entry per vertex,
`{ pos = {x,y,z}, normal = {x,y,z}, uv = {u,v} }`. Requires the CPU copy to be
resident: turn on `keepCpu` (`meshRef:setSettings({ keepCpu = true })`) for an
in-use mesh. Errors loudly — naming the exact reason — rather than silently
loading a transient copy.

**Parameters**

- `self` `any` _(optional)_

```lua
local verts = meshRef:getVertices()
```

## modules/MeshAssetTypeBehavior/handle {#modules-meshassettypebehavior-handle}

```lua
handle(self)
```

Materialize this mesh asset's live GPU resource (Disk→CPU→GPU) and return
its `MeshHandle`. The handle is cached on the interned ref's shared `runtime`
table — its presence IS "loaded to the GPU", so once materialised every later
call (and every consumer of the same asset) gets the SAME handle back
directly → ONE GPU entry, no re-work. (The mode-flip runtime wipe clears the
cache so a mode change re-materialises.) A component that renders a mesh holds
the mesh resource and calls this internally — you rarely call it by hand.

CPU lifecycle: the `keepCpu` setting (`:settings`/`:setSettings`) governs
whether the CPU copy survives the upload. DEFAULT (`keepCpu = false`): the CPU
copy is dropped right after the GPU upload (the GPU handle holds no data → no
double memory). `keepCpu = true` retains the CPU store for geometry reads/edits.

Cluster LOD: the `clusterLod` setting governs whether this materialisation
queues a cluster-LOD bake. DEFAULT (`clusterLod = true`): the bake is queued
and the DAG attaches on the frame it finishes. `clusterLod = false` skips it,
so the mesh carries no hierarchy and costs nothing to virtualize.

**Parameters**

- `self` `any` _(optional)_

```lua
local h = meshRef:handle()
```

## modules/MeshAssetTypeBehavior/instantiate {#modules-meshassettypebehavior-instantiate}

```lua
instantiate(self, target: EntityRef?, opts: { [string]: any }?): (EntityRef, { [string]: string })
```

Instantiate this mesh — the uniform `instantiate(target?, opts?)`
contract every scene-instantiable asset answers to. A mesh becomes an
entity carrying a `Model` that renders it. With `target` the entity
spawns as a child of that owner (so an owning `Asset` component tears it
down with its other children); with no target it is a fresh root. The
base opts — `position`, `rotation`, `scale`, `name`, `temporary` — place
the root.

**Parameters**

- `self` `any` _(optional)_
- `target` `EntityRef?` _(optional)_ — Optional owning entity ref.
- `opts` `{ [string]: any }?` _(optional)_ — `{ position?, rotation?, scale?, name?, temporary? }`.

```lua
meshRef:instantiate(owner)
```

## modules/MeshAssetTypeBehavior/load {#modules-meshassettypebehavior-load}

```lua
load(self)
```

Load this `.mesh` asset's geometry into the guid-keyed CPU store and
return a CPU handle (the Disk→CPU step). The handle carries the guid, vertex
/ index counts, and per-handle geometry ops (`getTriangles` / `getVertices` /
`getBounds` / `encode` / `unload`) that read the Rust-side store — it holds no
geometry itself. Upload to the GPU with `renderer.mesh.create(handle)`; the
DEFAULT is to `handle:unload()` right after. Delegates to
`renderer.mesh.loadCpu` (the sole `__` caller).

**Parameters**

- `self` `any` _(optional)_

```lua
local cpu = meshRef:load(); local gpu = renderer.mesh.create(cpu); cpu:unload()
```

## modules/MeshAssetTypeBehavior/morphTargets {#modules-meshassettypebehavior-morphtargets}

```lua
morphTargets(self): { string }
```

The names of the shapes this mesh blends towards, in the order an
entity's `ecs.MorphWeights` addresses them — weight `i` drives the target
named at `i`. An imported model keeps the names its source file gave its
blend shapes, so a face is driven by the shape it means rather than by the
ordinal that shape imported at. A target the source never named reads as an
empty string, and a mesh with no morph targets returns an empty array.
Requires the mesh to be materialised (`meshRef:handle()`, or anything
rendering it) — it errors loudly naming that, rather than answering as
though the mesh carried no shapes.

**Parameters**

- `self` `any` _(optional)_

```lua
for i, name in meshRef:morphTargets() do print(i, name) end
```

## modules/MeshAssetTypeBehavior/onChange {#modules-meshassettypebehavior-onchange}

```lua
onChange(ref: any, change: { [string]: any })
```

React to a write inside this mesh asset. A write to the stored geometry
re-uploads it into the GPU mesh registered under this asset's guid, so
everything already rendering it draws the new shape. A `.metadata` write
reconciles the second (lightmap) UV set to the `lightmapUvs` setting:
"generate" (re)creates a non-overlapping unwrap into the second UV set,
"none" strips it, "keep" leaves the stored geometry untouched. The re-cook
round-trips the geometry through the codec, so tangents, skinning, and the
skeleton are preserved. In play mode the re-cook returns immediately: a
setting flip never rewrites the persisted geometry while the world is
running (the play-lock); a resident mesh re-materialises on its next fetch.

**Parameters**

- `ref` `any` _(optional)_ — The AssetRef<mesh> for the changed container.
- `change` `{ [string]: any }` — `{ path, asset, kind, origin }` — `path` the written file, `asset`
the container folder, `kind` "edited"/"seeded", `origin` "local"/"remote".

## modules/MeshAssetTypeBehavior/onCreate {#modules-meshassettypebehavior-oncreate}

```lua
onCreate(name: string, opts: CreateOpts): { [string]: string }
```

Generic-creation hook for `asset.create("mesh", name, opts)`. Pure:
returns the content-file map; `asset.create` writes it to the authored
destination, registering the `.mesh` asset under its minted guid. Disk-only —
nothing is uploaded to the GPU here (the GPU mesh is a separate, explicit
`renderer.mesh.create` step keyed by this asset's guid).

`opts` is raw geometry `{ positions, indices, normals?, uvs?, colors? }`
(flat float / u32 arrays, encoded to `data.zmsh` via `renderer.mesh.encode`),
or a pre-encoded `{ bytes }` payload (stored verbatim).

**Parameters**

- `name` `string` — Mesh identity (the instance name).
- `opts` `CreateOpts`

```lua
asset.create("mesh", "tree", { positions = {...}, indices = {...} })
```

## modules/MeshAssetTypeBehavior/preview {#modules-meshassettypebehavior-preview}

```lua
preview(self, opts: { [string]: any }?)
```

Render a preview of this mesh, instantiated and framed. Drives the mesh's
own model-instantiation path in an isolated preview scope.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ [string]: any }?` _(optional)_ — `{ size? = { width, height } }`.

```lua
local p = meshRef:preview()
```

## modules/MeshAssetTypeBehavior/setSettings {#modules-meshassettypebehavior-setsettings}

```lua
setSettings(self, patch: { [string]: any })
```

Write a partial settings patch to this mesh asset's `.metadata`. Pass any
subset of the settings schema; only those keys change, the rest keep their
stored value (`asset.set_field` deep-merges). Unknown keys error loudly.
Settings are serializable and persist across reloads.

**Parameters**

- `self` `any` _(optional)_
- `patch` `{ [string]: any }` — `{ keepCpu: boolean?, lightmapUvs: string?, clusterLod: boolean? }` —
any subset of the settings schema.

```lua
meshRef:setSettings({ keepCpu = true })
```

## modules/MeshAssetTypeBehavior/setVertices {#modules-meshassettypebehavior-setvertices}

```lua
setVertices(self, positions)
```

Replace this mesh's vertex positions IN PLACE — indices, normals/uvs, and
skinning are preserved, the AABB recomputes, and the edit shows on screen (the
GPU re-fetches the changed CPU copy). Requires the CPU copy resident: turn on
`keepCpu` (`meshRef:setSettings({ keepCpu = true })`) for an in-use mesh. Errors
loudly — naming the reason — when the CPU copy isn't resident or the vertex
count doesn't match.

**Parameters**

- `self` `any` _(optional)_
- `positions` `any` _(optional)_ — One position per vertex: an array of `{x,y,z}` (or `[x,y,z]`), or a
flat `{x,y,z, ...}` array. The count must match the mesh's vertex count.

```lua
local v = meshRef:getVertices()
local p = {}; for i, vert in ipairs(v) do p[i] = { vert.pos.x*0.01, vert.pos.y*0.01, vert.pos.z*0.01 } end
meshRef:setVertices(p)   -- scale the mesh to 1/100
```

## modules/MeshAssetTypeBehavior/settings {#modules-meshassettypebehavior-settings}

```lua
settings(self): { [string]: any }
```

Read this mesh asset's settings, with every schema default filled in. The
returned table always carries the full settings schema.

**Parameters**

- `self` `any` _(optional)_

```lua
if meshRef:settings().keepCpu then ... end
```

## modules/ModuleAssetTypeRef/README {#modules-moduleassettyperef-readme}

```lua
ModuleAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<module>`. Loaded lazily by `asset_ref.module`.

## modules/ModuleAssetTypeRef/getExports {#modules-moduleassettyperef-getexports}

```lua
getExports(self): { { name: string, type: string } }?
```

The module's exported names and their value types — requires the
module and reflects over the table it returns. Available for every
module (world-authored or library), since a module is just an asset.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, e in ipairs(modRef:getExports() or {}) do print(e.name, e.type) end
```

## modules/ModuleAssetTypeRef/getInitScript {#modules-moduleassettyperef-getinitscript}

```lua
getInitScript(self): string?
```

Read the module's entry script as raw text.

**Parameters**

- `self` `any` _(optional)_

```lua
local src = modRef:getInitScript()
```

## modules/ModuleAssetTypeRef/getReadme {#modules-moduleassettyperef-getreadme}

```lua
getReadme(self): string?
```

Read the module's README body.

**Parameters**

- `self` `any` _(optional)_

```lua
print(modRef:getReadme())
```

## modules/ModuleAssetTypeRef/inspect {#modules-moduleassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail: `{ exports }`, where `exports`
is parsed from the module's own entry script (`getInitScript`) via
`luau_introspect.moduleExports` — name/kind/signature/desc of every
top-level export, read from the source text rather than a `require()`
reflection. Cached on the asset's content checksum, so re-inspecting
unchanged source is free. A module with no readable entry script
returns an empty `exports` list rather than erroring.

**Parameters**

- `self` `any` _(optional)_

```lua
local exports = asset.inspect(modRef).detail.exports
```

## modules/ModuleAssetTypeRef/loadModule {#modules-moduleassettyperef-loadmodule}

```lua
loadModule(self): any
```

Require the module by its canonical identity — same as
`require(self.identity)`, but pcall-wrapped so a load failure
raises a Luau error tagged with the module identity rather than
propagating the raw error.

**Parameters**

- `self` `any` _(optional)_

```lua
local mod = modRef:loadModule()
```

## modules/ModuleAssetTypeRef/onChange {#modules-moduleassettyperef-onchange}

```lua
onChange(ref, change)
```

Asset-type change callback: hot-reload this module whenever a
`.luau` / `.lua` file inside it is edited (or the module is seeded). This
is what live-reloads USER modules — library modules reload through the VFS
write hook (author-immutable content does not dispatch `onChange`). Mirrors
the `.material` / `.shader` assetTypes owning their own reload. Convergent:
the reload only invalidates the require() cache + fires watchers and never
writes back into the asset folder.

**Parameters**

- `ref` `any` _(optional)_
- `change` `any` _(optional)_

## modules/ModuleAssetTypeRef/onRegister {#modules-moduleassettyperef-onregister}

```lua
onRegister(self)
```

Initial-registration callback: register every `.luau` / `.lua` file this
module owns — its entry AND its plain-file submodules — into the `require()`
layer, so `require("<mod>.<sub>")` resolves the instant it first registers
(fired before the world entrypoint runs). A `.luau` inside a NESTED
typed-asset folder (a nested `.module` / `.component` / …) belongs to that
asset and registers through its own `onRegister`, so it is skipped here.

**Parameters**

- `self` `any` _(optional)_ — The per-instance `AssetRef<module>`.

```lua
-- driven by the assetType lifecycle; not called directly
```

## modules/MuzzleFlashEffect/README {#modules-muzzleflasheffect-readme}

```lua
MuzzleFlashEffect
```

The definition behind `muzzleFlash.effect` — a ragged bloom at the muzzle, a lick of flame down the bore line, a cone of sparks and a flash of light, all proportioned off the flash width the caller asks for.

## modules/PackageAssetTypeRef/README {#modules-packageassettyperef-readme}

```lua
PackageAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<package>`. Loaded lazily by `asset_ref.module`.

## modules/PackageAssetTypeRef/getDefinition {#modules-packageassettyperef-getdefinition}

```lua
getDefinition(self): string?
```

Read the package's `package.yaml` body as raw text.

**Parameters**

- `self` `any` _(optional)_

```lua
local raw = packageRef:getDefinition()
```

## modules/PackageAssetTypeRef/getReadme {#modules-packageassettyperef-getreadme}

```lua
getReadme(self): string?
```

Read the package's README body.

**Parameters**

- `self` `any` _(optional)_

```lua
print(packageRef:getReadme())
```

## modules/PackageAssetTypeRef/inspect {#modules-packageassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail: `{ contents }`, where
`contents` is `{ {name, type}, ... }` sorted by name — the package's
own direct children (components, modules, tools, docs), enumerated via
`vfs.list` against the package's own path. Never reads/executes any
child's content.

**Parameters**

- `self` `any` _(optional)_

```lua
local contents = asset.inspect(packageRef).detail.contents
```

## modules/PackageAssetTypeRef/listContents {#modules-packageassettyperef-listcontents}

```lua
listContents(self): { { name: string, isDirectory: boolean } }
```

List the package's child entries — every VFS entry one level
below the package root. Use this to enumerate components, modules,
tools, etc. shipped by the package.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, e in ipairs(packageRef:listContents()) do print(e.name) end
```

## modules/Particles.Curves/ColorSequence.new {#new}

```lua
ColorSequence.new(a, b?) -> ColorSequence
```

Three shapes: constant `({r,g,b})`, two-point lerp `(startColor, endColor)`, or keypoint table `({ {time=, value={r,g,b,a?}, envelope={r,g,b}?}, ... })`.

**Parameters**

- `a` `any` _(optional)_
- `b` `any` _(optional)_

**Returns** `ColorSequence`

## modules/Particles.Curves/ColorSequence:evaluate {#curves-colorsequence-evaluate}

```lua
ColorSequence:evaluate(t: number) -> (r, g, b, a)
```

Deterministic per-channel sample.

**Parameters**

- `t` `number`

**Returns** `(r, g, b, a)`

## modules/Particles.Curves/ColorSequence:getKeypoints {#curves-colorsequence-getkeypoints}

```lua
ColorSequence:getKeypoints() -> {table}
```

Returns a fresh array of `{ time, value = {r,g,b,a}, envelope = {r,g,b} }`.

**Returns** `{table}`

## modules/Particles.Curves/ColorSequence:pack {#curves-colorsequence-pack}

```lua
ColorSequence:pack(buffer: {number}, offset: number) -> number
```

Pack the color curve into a flat float array; returns the next-write offset.

**Parameters**

- `buffer` `{number}`
- `offset` `number`

**Returns** `number`

## modules/Particles.Curves/ColorSequence:sample {#curves-colorsequence-sample}

```lua
ColorSequence:sample(t: number, rng?: number) -> (r, g, b, a)
```

Sample with per-channel RGB envelope randomness (alpha is deterministic).

**Parameters**

- `t` `number`
- `rng` `number` _(optional)_

**Returns** `(r, g, b, a)`

## modules/Particles.Curves/NumberSequence.new {#new}

```lua
NumberSequence.new(a, b?) -> NumberSequence
```

Three shapes: constant `(value)`, two-point lerp `(start, end)`, or keypoint list `({ {time=, value=, envelope=}, ... })`, whose entries also read positionally as `({ {time, value[, envelope]}, ... })`. A field that is not a number is refused at the call.

**Parameters**

- `a` `any` _(optional)_
- `b` `any` _(optional)_

**Returns** `NumberSequence`

## modules/Particles.Curves/NumberSequence:evaluate {#curves-numbersequence-evaluate}

```lua
NumberSequence:evaluate(t: number) -> number
```

Deterministic interpolation at life-fraction t in [0, 1].

**Parameters**

- `t` `number`

**Returns** `number`

## modules/Particles.Curves/NumberSequence:getKeypoints {#curves-numbersequence-getkeypoints}

```lua
NumberSequence:getKeypoints() -> {table}
```

Returns a fresh array of `{ time, value, envelope }` entries.

**Returns** `{table}`

## modules/Particles.Curves/NumberSequence:pack {#curves-numbersequence-pack}

```lua
NumberSequence:pack(buffer: {number}, offset: number) -> number
```

Pack the curve into a flat float array; returns the next-write offset.

**Parameters**

- `buffer` `{number}`
- `offset` `number`

**Returns** `number`

## modules/Particles.Curves/NumberSequence:sample {#curves-numbersequence-sample}

```lua
NumberSequence:sample(t: number, rng?: number) -> number
```

Envelope-randomized sample; rng (in [0, 1]) seeds the jitter.

**Parameters**

- `t` `number`
- `rng` `number` _(optional)_

**Returns** `number`

## modules/Particles.Curves/README {#curves-readme}

```lua
require("@builtin/systems/particles.package/curves") -- Particles.Curves
```

NumberSequence and ColorSequence — keyframe curves for VFX properties.

Animatable keyframe curves used by the particle system. Modelled on
Roblox's `NumberSequence` / `ColorSequence` so the muscle memory carries
over, with two differences:
  1. Up to 16 keypoints (Roblox caps at 20; we cap a bit lower so the
     GPU pack fits in a fixed-size param block).
  2. ColorSequence supports per-channel `envelope` (RGB) — Roblox does not.
Curves are immutable plain tables with a metatable. Build once, sample many
times. The shader-side pack format is a flat float array — see
`NumberSequence.pack` / `ColorSequence.pack` for the contract.
Usage:
  local size = NumberSequence.new({
      { time = 0.0, value = 0.1 },
      { time = 0.3, value = 1.0, envelope = 0.2 },
      { time = 1.0, value = 0.0 },
  })
  print(size:evaluate(0.5))   -- deterministic interpolation
  print(size:sample(0.5))     -- envelope randomness applied
  local color = ColorSequence.new(
      { 1, 0.8, 0.2 },    -- yellow
      { 1, 0.1, 0.0 }     -- red
  )

Usage: local Particles.Curves = require("@builtin/systems/particles.package/curves")

## modules/Particles.Curves/isColorSequence {#curves-iscolorsequence}

```lua
isColorSequence(x: any) -> boolean
```

True if `x` is a ColorSequence answering the calls one takes. A sequence that crossed a boundary preserving only its fields has its methods put back, so the value a caller tests is one it can go on to sample.

**Parameters**

- `x` `any` _(optional)_

**Returns** `boolean`

## modules/Particles.Curves/isNumberSequence {#curves-isnumbersequence}

```lua
isNumberSequence(x: any) -> boolean
```

True if `x` is a NumberSequence answering the calls one takes. A sequence that crossed a boundary preserving only its fields has its methods put back, so the value a caller tests is one it can go on to sample.

**Parameters**

- `x` `any` _(optional)_

**Returns** `boolean`

## modules/Particles.Curves/new {#curves-new}

```lua
new(a: any, b: any?): any
```

**Parameters**

- `a` `any` _(optional)_
- `b` `any?` _(optional)_

```lua
NumberSequence.new(1.0)
NumberSequence.new(0.0, 1.0)
NumberSequence.new({ {time=0,value=0}, {time=1,value=1,envelope=0.1} })
NumberSequence.new({ {0, 0}, {1, 1, 0.1} })
```

## modules/Particles.Meshes/README {#meshes-readme}

```lua
require("@builtin/systems/particles.package/meshes") -- Particles.Meshes
```

Built-in source-mesh templates for mesh particles.

Source-mesh geometries for the mesh-particle path of the particle system.
Each built-in returns a table with `positions` (flat xyz array),
`normals` (flat xyz array), `uvs` (flat uv array), and `indices` (flat u32
array) — the shape `particles.create` expects under its `mesh` field.
Built-in kinds:
  "cube"        — 24 verts × 36 indices (face-normalled box)
  "octahedron"  — 24 verts × 24 indices (face-normalled octahedron)
  "tetrahedron" — 12 verts × 12 indices (face-normalled tetrahedron)
  "plane"       —  4 verts ×  6 indices (axis-aligned XY quad)
Custom geometry:
  Pass `mesh = { positions = {...}, normals = {...}, uvs = {...},
                indices = {...} }` directly to `particles.create`. The
  module also accepts an asset ref (`assetRef("identity", "mesh")`)
  but resolution happens through the engine's asset system — the
  fast path is built-in kinds.

Usage: local Particles.Meshes = require("@builtin/systems/particles.package/meshes")

## modules/Particles.Meshes/list {#meshes-list}

```lua
list() -> {string}
```

Returns the built-in mesh kind names.

**Returns** `{string}`

## modules/Particles.Meshes/resolve {#meshes-resolve}

```lua
resolve(spec: string | table) -> table
```

Resolve a mesh spec to `{ positions, normals, uvs, indices }`. Spec is one of "cube" | "octahedron" | "tetrahedron" | "plane", or a custom `{ positions, normals, uvs?, indices }` table.

**Parameters**

- `spec` `string | table`

**Returns** `table`

## modules/Particles.Shapes/README {#shapes-readme}

```lua
require("@builtin/systems/particles.package/shapes") -- Particles.Shapes
```

Emission-shape samplers — CPU-side, called at spawn time.

Spawn positions and initial velocity directions for the standard
emission shapes. CPU sampling is fine here because it runs at most
N times per frame where N = emission rate, not N = active particle
count — and the math is trivial.
Shapes (matching Roblox naming):
  point       — emit from origin
  box         — Volume / Surface
  sphere      — Volume / Surface, partial = hemisphere cap
  cylinder    — Volume / Surface, axis = Y
  disc        — Surface (XZ plane), partial = annulus inner radius
  cone        — Surface, partial = half-angle
Styles:
  "volume"    — uniform inside the shape
  "surface"   — uniform on the shape's boundary
inOut (determines initial velocity direction):
  "outward"   — surface-normal outward
  "inward"    — surface-normal inward
  "inandout"  — random sign per particle

Usage: local Particles.Shapes = require("@builtin/systems/particles.package/shapes")

## modules/Particles.Shapes/frame {#shapes-frame}

```lua
frame(ax: number, ay: number, az: number): (number, number, number, number, number, number, number, number, number)
```

Build an orthonormal frame whose middle axis is the given direction.
Shape samplers emit around a local +Y axis; this frame maps those local
samples into world space so emission can be aimed along any vector.
Returns 9 numbers — right, axis, forward — for allocation-free use in
per-particle loops: world = local.x * right + local.y * axis + local.z * forward.
The roll about the axis is unspecified but stable for a given direction.
A zero-length or +Y direction returns the exact identity frame.

**Parameters**

- `ax` `number` — Direction X (any length; normalized internally).
- `ay` `number` — Direction Y.
- `az` `number` — Direction Z.

```lua
local rx, ry, rz, ax2, ay2, az2, fx, fy, fz = Shapes.frame(0, 0, -1)
```

## modules/Particles.Shapes/inOuts {#shapes-inouts}

```lua
inOuts() -> {string}
```

Returns the directions a sample aims in — outward, inward, inandout.

**Returns** `{string}`

## modules/Particles.Shapes/sample {#shapes-sample}

```lua
sample(shape: string, opts: table) -> (px, py, pz, dx, dy, dz)
```

Sample one spawn position + unit direction from the named shape. opts: { size = {x,y,z}, style = "volume"|"surface", inOut = "outward"|"inward"|"inandout", partial = number, spreadAngle = degrees }.

**Parameters**

- `shape` `string`
- `opts` `table`

**Returns** `(px, py, pz, dx, dy, dz)`

## modules/Particles.Shapes/shapes {#shapes-shapes}

```lua
shapes() -> {string}
```

Returns the supported shape names — point, box, sphere, cylinder, disc, cone.

**Returns** `{string}`

## modules/Particles.Shapes/styles {#shapes-styles}

```lua
styles() -> {string}
```

Returns the fill styles a shape is sampled with — volume, surface.

**Returns** `{string}`

## modules/Particles/M.list {#list}

```lua
M.list() -> {ParticleSystem}
```

Every live particle system this VM has created, newest last.

**Returns** `{ParticleSystem}`

## modules/Particles/M.observe {#observe}

```lua
M.observe(system: ParticleSystem?) -> table
```

One emitter's document, or — with no argument — the whole world's: `{ emitters, count, alive, capacity, spawned, silent, bytes, frame }`.

**Parameters**

- `system` `ParticleSystem?` _(optional)_

**Returns** `table`

## modules/Particles/M.silenceReasons {#silencereasons}

```lua
M.silenceReasons() -> table
```

The closed set of reasons an emitter can be producing nothing, in the order they are resolved, each with what it means.

**Returns** `table`

## modules/Particles/M.whySilent {#whysilent}

```lua
M.whySilent(system: ParticleSystem) -> (string?, string?)
```

The reason one emitter is producing nothing and the detail line naming what it is about, or nil when it is producing.

**Parameters**

- `system` `ParticleSystem`

**Returns** `(string?, string?)`

## modules/Particles/ParticleSystem:billboard {#modules-particles-particlesystem-billboard}

```lua
ParticleSystem:billboard(): { [string]: any }
```

The camera frame this emitter's geometry was last built against: which
camera supplied it, the world point it was read at, the right/up pair, and
the direction that pair faces.

A sprite is a flat card placed in the compute pass against ONE camera frame,
so a view looking along `normal` sees it face-on and a view looking across
`normal` sees its edge. A mesh emitter spins each copy about the axis
running from it to `position`. When a frame drawn from somewhere else shows
an emitter that every count reports as producing, this is the reading that
says where its geometry is turned, and `means` names which part of the frame
this emitter's kind builds from.

```lua
local b = sys:billboard(); print(b.source, b.normal[1], b.normal[2], b.normal[3])
```

## modules/Particles/ParticleSystem:clear {#modules-particles-particlesystem-clear}

```lua
ParticleSystem:clear()
```

Kill every live particle by re-zeroing the state buffer.

## modules/Particles/ParticleSystem:destroy {#modules-particles-particlesystem-destroy}

```lua
ParticleSystem:destroy()
```

Release every GPU buffer and the render entity. Idempotent.

## modules/Particles/ParticleSystem:emit {#modules-particles-particlesystem-emit}

```lua
ParticleSystem:emit(count: number)
```

One-shot burst of N particles, independent of `rate` / `enabled`.

**Parameters**

- `count` `number`

## modules/Particles/ParticleSystem:getActiveCount {#modules-particles-particlesystem-getactivecount}

```lua
ParticleSystem:getActiveCount() -> number
```

How many particles are alive right now: the slots whose lifetime has not elapsed under the simulated time this emitter's dispatches have advanced. Falls to 0 when the last particle ages out.

**Returns** `number`

## modules/Particles/ParticleSystem:getCastsShadows {#modules-particles-particlesystem-getcastsshadows}

```lua
ParticleSystem:getCastsShadows(): boolean
```

Whether this emitter's particles block light.

```lua
print(debris:getCastsShadows())
```

## modules/Particles/ParticleSystem:getColliders {#modules-particles-particlesystem-getcolliders}

```lua
ParticleSystem:getColliders(): { any }
```

The colliders currently in force, in the shape `setColliders` takes —
so what comes out of one goes back into the other.

```lua
local n = #sys:getColliders()
```

## modules/Particles/ParticleSystem:getCreator {#modules-particles-particlesystem-getcreator}

```lua
ParticleSystem:getCreator(): { [string]: any }
```

Whose this emitter is. `owner` and `name` are the keys its creator
stated on the spec, and `source` and `line` are the code that made the call,
read off the stack — so an emitter nobody tagged still names the module it
came from. `actor` and `actorName` are the account this engine session runs
under, and `createdAt` is when the emitter was made, which orders two
emitters one creator built across separate loads.

```lua
local who = sys:getCreator(); print(who.owner, who.source, who.line)
```

## modules/Particles/ParticleSystem:getDepthFade {#modules-particles-particlesystem-getdepthfade}

```lua
ParticleSystem:getDepthFade() -> number
```

That distance.

**Returns** `number`

## modules/Particles/ParticleSystem:getGpuBytes {#modules-particles-particlesystem-getgpubytes}

```lua
ParticleSystem:getGpuBytes() -> table
```

Every GPU buffer this emitter holds, by name, plus their `total`.

**Returns** `table`

## modules/Particles/ParticleSystem:getLightEmission {#modules-particles-particlesystem-getlightemission}

```lua
ParticleSystem:getLightEmission() -> number
```

That share.

**Returns** `number`

## modules/Particles/ParticleSystem:getLightInfluence {#modules-particles-particlesystem-getlightinfluence}

```lua
ParticleSystem:getLightInfluence() -> number
```

That share.

**Returns** `number`

## modules/Particles/ParticleSystem:getMaxCount {#modules-particles-particlesystem-getmaxcount}

```lua
ParticleSystem:getMaxCount() -> number
```

Buffer cap.

**Returns** `number`

## modules/Particles/ParticleSystem:getRenderEntity {#modules-particles-particlesystem-getrenderentity}

```lua
ParticleSystem:getRenderEntity() -> string?
```

Entity id of the renderable a sprite emitter spawns at world origin; nil for a mesh emitter, which draws as a GPU population instead.

**Returns** `string?`

## modules/Particles/ParticleSystem:getRenderLayer {#modules-particles-particlesystem-getrenderlayer}

```lua
ParticleSystem:getRenderLayer(): string
```

The render layers this emitter's particles draw on, as the
space-separated name string every render-layer surface speaks.

```lua
print(smoke:getRenderLayer())
```

## modules/Particles/ParticleSystem:getSimulatedTime {#modules-particles-particlesystem-getsimulatedtime}

```lua
ParticleSystem:getSimulatedTime() -> number
```

Seconds of simulation this emitter's dispatches have advanced. Every particle's age is measured against this clock.

**Returns** `number`

## modules/Particles/ParticleSystem:getSpawnedCount {#modules-particles-particlesystem-getspawnedcount}

```lua
ParticleSystem:getSpawnedCount() -> number
```

How many slots the emitter has filled since the last `clear()`, saturating at `maxCount`. The emission schedule's own total, and the span the draw covers.

**Returns** `number`

## modules/Particles/ParticleSystem:isPlaying {#modules-particles-particlesystem-isplaying}

```lua
ParticleSystem:isPlaying() -> boolean
```

True while the timeline emits: enabled, past `delay`, and inside `duration` (or looping / untimed).

**Returns** `boolean`

## modules/Particles/ParticleSystem:isSorted {#modules-particles-particlesystem-issorted}

```lua
ParticleSystem:isSorted() -> boolean
```

Whether this emitter reorders its own particles back to front every frame.

**Returns** `boolean`

## modules/Particles/ParticleSystem:isVisible {#modules-particles-particlesystem-isvisible}

```lua
ParticleSystem:isVisible() -> boolean
```

Whether the emitter's population reaches the frame.

**Returns** `boolean`

## modules/Particles/ParticleSystem:observe {#modules-particles-particlesystem-observe}

```lua
ParticleSystem:observe() -> table
```

Everything the engine holds for this emitter in one document: population, capacity, timeline, GPU bytes, render-side liveness, the GPU's own confirmation of the population, and — when it is producing nothing — the reason from a closed set.

**Returns** `table`

## modules/Particles/ParticleSystem:play {#modules-particles-particlesystem-play}

```lua
ParticleSystem:play(restart?: boolean)
```

Start (or re-arm) the emission timeline: resets the clock to -delay, re-arms scheduled bursts, and enables emission. `restart = true` also clears live particles.

**Parameters**

- `restart` `boolean` _(optional)_

## modules/Particles/ParticleSystem:requestCensus {#modules-particles-particlesystem-requestcensus}

```lua
ParticleSystem:requestCensus()
```

Ask the GPU to count its own live slots on the next dispatch. The answer arrives on a later frame and reads back through `observe().confirmation`.

## modules/Particles/ParticleSystem:setAcceleration {#modules-particles-particlesystem-setacceleration}

```lua
ParticleSystem:setAcceleration(x, y, z: number)
```

Set the constant acceleration vector (combined with gravity + wind).

**Parameters**

- `x` `any` _(optional)_
- `y` `any` _(optional)_
- `z` `number`

## modules/Particles/ParticleSystem:setBlendMode {#modules-particles-particlesystem-setblendmode}

```lua
ParticleSystem:setBlendMode(mode: string)
```

"alpha" (default) or "additive".

**Parameters**

- `mode` `string`

## modules/Particles/ParticleSystem:setBursts {#modules-particles-particlesystem-setbursts}

```lua
ParticleSystem:setBursts(bursts: table)
```

Replace the scheduled-burst list ({ {time, count}, ... }); nil/empty removes the schedule.

**Parameters**

- `bursts` `table`

## modules/Particles/ParticleSystem:setCastsShadows {#modules-particles-particlesystem-setcastsshadows}

```lua
ParticleSystem:setCastsShadows(on: boolean?)
```

State whether this emitter's particles block light. A caster is drawn
into the shadow map as the geometry it is — a sprite emitter's quads as
quads, a mesh emitter's copies as copies — and the surfaces behind it are
shaded in shadow. The declaration reaches both emitter kinds, so it means
the same thing whichever one carries it.

**Parameters**

- `on` `boolean?` _(optional)_ — `true` to block light, `false` to let it through. Omitted, the
emitter goes back to the default, which is letting it through.

```lua
debris:setCastsShadows(true)
```

## modules/Particles/ParticleSystem:setColliders {#modules-particles-particlesystem-setcolliders}

```lua
ParticleSystem:setColliders(colliders: { any }?): number
```

Replace the shapes this emitter's particles collide against. Each entry
is `{ kind = "plane" | "sphere" | "box" | "world", position = {x,y,z}, ... }`
— a plane also takes `normal`, a sphere `radius`, a box `halfExtents`. A
`world` entry is the scene's own geometry, read from the distance field
`sceneProxy` builds: it takes only `radius`, how far from a surface a
particle counts as touching it. At most 8 are carried; the rest are dropped
and reported.

**Parameters**

- `colliders` `{ any }?` _(optional)_ — Array of collider descriptions.

```lua
sys:setColliders({ { kind = "world" } })
```

## modules/Particles/ParticleSystem:setCollision {#modules-particles-particlesystem-setcollision}

```lua
ParticleSystem:setCollision(mode: string?, opts: { [string]: any }?)
```

Choose what a particle does when it meets a collider.

**Parameters**

- `mode` `string?` _(optional)_ — `"off"`, `"bounce"`, `"stop"` or `"kill"`.
- `opts` `{ [string]: any }?` _(optional)_ — Optional `{ restitution, friction }`. `restitution` is how much
normal speed survives a bounce, `friction` how much tangential speed is
lost on contact — both in [0, 1].

```lua
sys:setCollision("bounce", { restitution = 0.5, friction = 0.3 })
```

## modules/Particles/ParticleSystem:setColor {#modules-particles-particlesystem-setcolor}

```lua
ParticleSystem:setColor(value: ColorSequence | {number})
```

Per-particle color curve. A `{number}` array `{r, g, b}` is read as a constant color, and a list of such arrays as a ramp through them.

**Parameters**

- `value` `ColorSequence | {number}`

## modules/Particles/ParticleSystem:setDepthFade {#modules-particles-particlesystem-setdepthfade}

```lua
ParticleSystem:setDepthFade(distance: number)
```

Set the distance, in world units, over which this emitter's particles dissolve into the surface drawn behind them. 0 turns the fade off.

**Parameters**

- `distance` `number`

## modules/Particles/ParticleSystem:setDirection {#modules-particles-particlesystem-setdirection}

```lua
ParticleSystem:setDirection(x, y, z: number)
```

Aim emission: the shape's local +Y axis maps onto this world-space vector (positions and initial velocities both rotate). Pass nil to reset to the native +Y frame.

**Parameters**

- `x` `any` _(optional)_
- `y` `any` _(optional)_
- `z` `number`

## modules/Particles/ParticleSystem:setDrag {#modules-particles-particlesystem-setdrag}

```lua
ParticleSystem:setDrag(d: number)
```

Set the velocity damping factor (per-second exponential decay).

**Parameters**

- `d` `number`

## modules/Particles/ParticleSystem:setEnabled {#modules-particles-particlesystem-setenabled}

```lua
ParticleSystem:setEnabled(b: boolean)
```

Pause / resume continuous emission. Does not kill live particles.

**Parameters**

- `b` `boolean`

## modules/Particles/ParticleSystem:setGravity {#modules-particles-particlesystem-setgravity}

```lua
ParticleSystem:setGravity(x, y, z: number)
```

Set the gravity vector (m/s^2). Default {0, -9.81, 0}.

**Parameters**

- `x` `any` _(optional)_
- `y` `any` _(optional)_
- `z` `number`

## modules/Particles/ParticleSystem:setLifetime {#modules-particles-particlesystem-setlifetime}

```lua
ParticleSystem:setLifetime(min: number, max?: number)
```

Per-particle lifetime range in seconds.

**Parameters**

- `min` `number`
- `max` `number` _(optional)_

## modules/Particles/ParticleSystem:setLightEmission {#modules-particles-particlesystem-setlightemission}

```lua
ParticleSystem:setLightEmission(share: number)
```

How much of itself each particle emits whatever the scene's light is, from 0 to 1. At 1 a particle is self-illuminated.

**Parameters**

- `share` `number`

## modules/Particles/ParticleSystem:setLightInfluence {#modules-particles-particlesystem-setlightinfluence}

```lua
ParticleSystem:setLightInfluence(share: number)
```

How much of the scene's light these particles take, from 0 to 1.

**Parameters**

- `share` `number`

## modules/Particles/ParticleSystem:setMaterial {#modules-particles-particlesystem-setmaterial}

```lua
ParticleSystem:setMaterial(materialName: string)
```

Replace the material applied to the render entity entirely.

**Parameters**

- `materialName` `string`

## modules/Particles/ParticleSystem:setOrientation {#modules-particles-particlesystem-setorientation}

```lua
ParticleSystem:setOrientation(mode: string)
```

"FacingCamera" | "FacingCameraWorldUp" | "VelocityParallel" | "VelocityPerpendicular".

**Parameters**

- `mode` `string`

## modules/Particles/ParticleSystem:setOrigin {#modules-particles-particlesystem-setorigin}

```lua
ParticleSystem:setOrigin(x, y, z: number)
```

Move the emitter to a new world-space origin.

**Parameters**

- `x` `any` _(optional)_
- `y` `any` _(optional)_
- `z` `number`

## modules/Particles/ParticleSystem:setParam {#modules-particles-particlesystem-setparam}

```lua
ParticleSystem:setParam(name: string, value: number)
```

Generic setter — matches PARAM_LAYOUT keys or "user<N>" for the user block.

**Parameters**

- `name` `string`
- `value` `number`

## modules/Particles/ParticleSystem:setRate {#modules-particles-particlesystem-setrate}

```lua
ParticleSystem:setRate(r: number)
```

Set continuous emission rate (particles/sec).

**Parameters**

- `r` `number`

## modules/Particles/ParticleSystem:setRenderLayer {#modules-particles-particlesystem-setrenderlayer}

```lua
ParticleSystem:setRenderLayer(layers: any)
```

Put this emitter's particles on named render layers. A camera or a
capture including the layer draws them and one excluding it does not, so
a reflection probe, a portal camera, a minimap or a clean screenshot can
take the scene with the emitter's effect in it or without. The layers
reach both emitter kinds.

**Parameters**

- `layers` `any` _(optional)_ — A layer name, an array of names, or a space-separated string.
Omitted, the emitter goes back to the `default` layer.

```lua
smoke:setRenderLayer("vfx")
```

## modules/Particles/ParticleSystem:setRotSpeed {#modules-particles-particlesystem-setrotspeed}

```lua
ParticleSystem:setRotSpeed(min: number, max?: number)
```

Per-particle rotation-speed range (degrees/sec).

**Parameters**

- `min` `number`
- `max` `number` _(optional)_

## modules/Particles/ParticleSystem:setRotSpeedCurve {#modules-particles-particlesystem-setrotspeedcurve}

```lua
ParticleSystem:setRotSpeedCurve(value: NumberSequence | number | {start, finish} | {table})
```

Rotation-speed curve — multiplies each particle's own `rotSpeed` across its life. Written the same four ways as the transparency curve.

**Parameters**

- `value` `NumberSequence | number | {start, finish} | {table}`

## modules/Particles/ParticleSystem:setRotation {#modules-particles-particlesystem-setrotation}

```lua
ParticleSystem:setRotation(min: number, max?: number)
```

Per-particle initial rotation range (degrees).

**Parameters**

- `min` `number`
- `max` `number` _(optional)_

## modules/Particles/ParticleSystem:setShape {#modules-particles-particlesystem-setshape}

```lua
ParticleSystem:setShape(opts: table)
```

Replace the emission shape — `{ kind, size, style, inOut, partial, spreadAngle }` (any subset). Existing values are kept for omitted fields.

**Parameters**

- `opts` `table`

## modules/Particles/ParticleSystem:setSize {#modules-particles-particlesystem-setsize}

```lua
ParticleSystem:setSize(value: NumberSequence | number | {min, max} | {table})
```

Size, read the way `create` reads its `size`: a curve — a NumberSequence or the keypoint list `{{time, value, envelope?}, ...}` one is built from — is sampled per particle every frame on the GPU over base 1, and a number or `{min, max}` pair is the base each spawn samples under a constant curve of 1. Either way a particle draws at the size that was written.

**Parameters**

- `value` `NumberSequence | number | {min, max} | {table}`

## modules/Particles/ParticleSystem:setSorted {#modules-particles-particlesystem-setsorted}

```lua
ParticleSystem:setSorted(on: boolean?)
```

State whether this emitter reorders its own particles back to front every frame. `nil` hands the choice back to the blend mode.

**Parameters**

- `on` `boolean?` _(optional)_

## modules/Particles/ParticleSystem:setSpeed {#modules-particles-particlesystem-setspeed}

```lua
ParticleSystem:setSpeed(min: number, max?: number)
```

Per-particle initial-speed range.

**Parameters**

- `min` `number`
- `max` `number` _(optional)_

## modules/Particles/ParticleSystem:setSquash {#modules-particles-particlesystem-setsquash}

```lua
ParticleSystem:setSquash(value: NumberSequence | number | {start, finish} | {table})
```

X-dimension scale curve (>1 stretches, <1 squashes). Written the same four ways as the transparency curve.

**Parameters**

- `value` `NumberSequence | number | {start, finish} | {table}`

## modules/Particles/ParticleSystem:setTexture {#modules-particles-particlesystem-settexture}

```lua
ParticleSystem:setTexture(texture: string)
```

Set the sprite texture (asset id or VFS path).

**Parameters**

- `texture` `string`

## modules/Particles/ParticleSystem:setTransparency {#modules-particles-particlesystem-settransparency}

```lua
ParticleSystem:setTransparency(value: NumberSequence | number | {start, finish} | {table})
```

Transparency curve (0 = opaque, 1 = invisible). A `{start, finish}` pair of numbers is read as a two-stop ramp — a table holding one number as that value across the whole life — and a keypoint list as the curve through its stops.

**Parameters**

- `value` `NumberSequence | number | {start, finish} | {table}`

## modules/Particles/ParticleSystem:setUserParam {#modules-particles-particlesystem-setuserparam}

```lua
ParticleSystem:setUserParam(index: number, value: number)
```

Write one slot (1..32) of the 32-float user param block. Custom WGSL update shaders read these at `params[31 + index]`.

**Parameters**

- `index` `number`
- `value` `number`

## modules/Particles/ParticleSystem:setVisible {#modules-particles-particlesystem-setvisible}

```lua
ParticleSystem:setVisible(on: boolean)
```

Whether the population the emitter holds reaches the frame. Emission is `setEnabled`; the draw is this, and a hidden emitter keeps its particles.

**Parameters**

- `on` `boolean`

## modules/Particles/ParticleSystem:setWind {#modules-particles-particlesystem-setwind}

```lua
ParticleSystem:setWind(x, y, z: number)
```

Set the wind vector (m/s).

**Parameters**

- `x` `any` _(optional)_
- `y` `any` _(optional)_
- `z` `number`

## modules/Particles/ParticleSystem:simulate {#modules-particles-particlesystem-simulate}

```lua
ParticleSystem:simulate(t: number, stepDt?: number)
```

Deterministically advance the system by `t` seconds in fixed steps (default 1/60). Drives the full update — timeline, bursts, compute passes — so a system can be prewarmed or scrubbed to a known state.

**Parameters**

- `t` `number`
- `stepDt` `number` _(optional)_

## modules/Particles/ParticleSystem:stop {#modules-particles-particlesystem-stop}

```lua
ParticleSystem:stop(clearParticles?: boolean)
```

Stop emitting. Live particles finish their lifetime unless `clearParticles = true`.

**Parameters**

- `clearParticles` `boolean` _(optional)_

## modules/Particles/ParticleSystem:update {#modules-particles-particlesystem-update}

```lua
ParticleSystem:update(dt: number)
```

Step the simulation. Drives continuous emission, dispatches the compute update pass, and re-packs per-frame uniforms. Call once per frame.

**Parameters**

- `dt` `number`

## modules/Particles/README {#modules-particles-readme}

```lua
require("@builtin/systems/particles.package/engine") -- Particles
```

Generic GPU-driven particle system — compute-shader simulation, zero-copy rendering.

A generic GPU particle substrate for VFX. Every active particle lives in a
GPU storage buffer; the simulation runs entirely as compute dispatches; the
per-frame vertex output is consumed directly by the renderer via
`renderer.mesh.create` (no readback, no CPU re-upload). Spawning happens
on the CPU (the bookkeeping cost is bounded by emission rate, not particle
count) and writes new particle slots straight into the GPU state buffer.
The module is one-stop: the high-level `ParticleEmitter` component
declared elsewhere in `src/lua/lib/components/` is a thin wrapper around
this API.
Usage:
  local particles = require("@builtin::systems.particles.engine")
  local fire = particles.create({
      maxCount = 2000,
      rate     = 100,                       -- particles/sec
      lifetime = { 0.8, 1.6 },
      speed    = { 2.5, 4.0 },
      shape    = { kind = "cone", size = {1, 1, 1}, partial = 0.3 },
      gravity  = { 0, 1.5, 0 },             -- buoyant
      drag     = 0.6,
      size     = NumberSequence.new({
                     { time = 0,   value = 0.4 },
                     { time = 0.3, value = 1.0, envelope = 0.2 },
                     { time = 1,   value = 0.0 },
                 }),
      color    = ColorSequence.new({ 1, 0.9, 0.3 }, { 0.8, 0.1, 0 }),
      transparency = NumberSequence.new(0, 1),
      texture  = "@builtin::textures.fire_sprite",
      blendMode = "additive",
  })
  -- Each frame:
  fire:setOrigin(torch.position.x, torch.position.y, torch.position.z)
  fire:update(dt)
See `references/luau-cookbook.md#particles` (zero-engine skill) for more
recipes — explosion bursts, magic swirls, custom WGSL update injection.

Usage: local Particles = require("@builtin/systems/particles.package/engine")

## modules/Particles/create {#modules-particles-create}

```lua
create(spec: table) -> ParticleSystem
```

Allocate a new particle system: GPU buffers, registered compute shader, renderer.mesh.create-wrapped renderable. See the `about` block for the full spec field list. Returns a handle whose methods are summarised below.

**Parameters**

- `spec` `table`

**Returns** `ParticleSystem`

## modules/Particles/list {#modules-particles-list}

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

Every particle system this VM has created and not destroyed, in
creation order — or, given a filter, the ones whose creator matches it. An
emitter is something this module made, so the list is answered from its own
registry rather than by walking entities.

Called with nothing it answers with every emitter in the VM, which is what
makes it the way to reach one whose creator has lost its handle, and
`:getCreator()` on an entry says whose that one is. A filter narrows it to
one creator's own, so a module sweeps what it left behind on a previous load
without touching anybody else's.

**Parameters**

- `filter` `any?` _(optional)_ — Optional. A string matches the `owner` key a creator stated; a
table matches every one of `owner`, `name` and `source` that it names.

```lua
for _, sys in ipairs(Particles.list()) do print(sys:getActiveCount()) end
for _, sys in ipairs(Particles.list("starfield")) do sys:destroy() end
```

## modules/Particles/observe {#modules-particles-observe}

```lua
observe(system: any?): { [string]: any }
```

One emitter's reading, or — called with no argument — the whole world's:
every live emitter's document plus the totals they sum to. An engine with
no emitters answers `count = 0` with an empty list, which reads differently
from an engine whose emitters are all silent.

**Parameters**

- `system` `any?` _(optional)_ — Optional ParticleSystem to read; omitted, every live one.

```lua
local world = Particles.observe(); print(world.alive, world.silent)
```

## modules/Particles/silenceReasons {#modules-particles-silencereasons}

```lua
silenceReasons(): { { reason: string, means: string } }
```

The closed set of reasons an emitter can be producing nothing, in the
order a reading resolves them — nearest cause first — each with what it
means. Every `observe().reason` is one of these.

```lua
for _, r in ipairs(Particles.silenceReasons()) do print(r.reason, r.means) end
```

## modules/Particles/whySilent {#modules-particles-whysilent}

```lua
whySilent(system: any): (string?, string?)
```

Why one emitter is producing nothing, from the closed set
`silenceReasons()` enumerates — or nil when it is producing. The second
return is the detail line naming what the reason is about.

**Parameters**

- `system` `any` _(optional)_ — The particle system to ask about.

```lua
local why, detail = Particles.whySilent(fire)
```

## modules/PlasmaBoltEffect/README {#modules-plasmabolteffect-readme}

```lua
PlasmaBoltEffect
```

The definition behind `plasmaBolt.effect` — a round pulsing core crossing a span, a short trail behind it, motes falling off it and a light it carries as it goes.

## modules/PopulationAssetTypeBehavior/README {#modules-populationassettypebehavior-readme}

```lua
PopulationAssetTypeBehavior
```

Behaviour for the `population` asset type — a hardware-instanced population at rest. `onCreate` writes the recipe (`population.json`) plus the instance matrices as bytes (`transforms.bin`); `:draw()` turns that recipe back into live GPU buffers and draw registrations, and `instantiate` puts one entity in the scene that owns them for as long as it lives.

## modules/PopulationAssetTypeBehavior/bounds {#modules-populationassettypebehavior-bounds}

```lua
bounds(self): any
```

The world-space box the drawn instances occupy — each variant's mesh
AABB carried through every one of its matrices. The matrices are
world-space, so this is where the population stands, whatever entity owns
it.

**Parameters**

- `self` `any` _(optional)_

```lua
local box = live:bounds()
```

## modules/PopulationAssetTypeBehavior/count {#modules-populationassettypebehavior-count}

```lua
count(self): number
```

Instances the engine reports drawing across every registration this
holds. Read back from the renderer rather than from the recipe, so a
registration that went away, or that the renderer turned away, counts as
gone.

**Parameters**

- `self` `any` _(optional)_

```lua
print(live:count())
```

## modules/PopulationAssetTypeBehavior/destroy {#modules-populationassettypebehavior-destroy}

```lua
destroy(self)
```

Release every registration and its transform buffer. The draw is
dropped BEFORE its buffer is destroyed: a registration reserves slots
against the buffer it was given, so a buffer that goes away takes its
registration with it. The meshes belong to their `.mesh` assets and stay.
A second call finds an empty list and returns.

**Parameters**

- `self` `any` _(optional)_

```lua
live:destroy()
```

## modules/PopulationAssetTypeBehavior/draw {#modules-populationassettypebehavior-draw}

```lua
draw(self, opts: { [string]: any }?): any
```

Rebuild this population's live draws: allocate a GPU transform buffer
per variant, upload that variant's run of `transforms.bin` into it,
resolve the mesh and material, and register one instanced draw. The
returned value OWNS those resources — hold it and call `:destroy()` to
release them; a registration nobody holds can be neither enumerated nor
dropped afterwards. The matrices are world-space, so the draws stand where
the recipe placed them.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ [string]: any }?` _(optional)_ — `{ castsShadows? = true, renderLayer? }`.

```lua
local live = populationRef:draw(); … ; live:destroy()
```

## modules/PopulationAssetTypeBehavior/drawCalls {#modules-populationassettypebehavior-drawcalls}

```lua
drawCalls(self): number
```

Draw calls this population costs — one per variant the renderer is
drawing, at any instance count. A variant the renderer turned away costs
nothing and is counted nowhere; `:errors()` says why.

**Parameters**

- `self` `any` _(optional)_

```lua
print(live:drawCalls())
```

## modules/PopulationAssetTypeBehavior/errors {#modules-populationassettypebehavior-errors}

```lua
errors(self): { any }
```

Why this population is drawing less than its recipe asks for: one entry
per registration the renderer turned away, carrying the variant it belongs
to, the mesh it names and the renderer's own reason. A population drawing
everything it holds answers with an empty list, so this and `:drawCalls()`
agree with the frame.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, e in ipairs(live:errors()) do warn(e.variant, e.error) end
```

## modules/PopulationAssetTypeBehavior/inspectDetail {#modules-populationassettypebehavior-inspectdetail}

```lua
inspectDetail(self): any
```

`asset.inspect` type-specific detail: `{ total, variantCount,
variants }`, read straight from `population.json` — never allocates a
buffer or registers a draw. A population whose recipe can't be read
returns an empty detail rather than erroring.

**Parameters**

- `self` `any` _(optional)_

```lua
local n = asset.inspect(populationRef).detail.total
```

## modules/PopulationAssetTypeBehavior/instantiate {#modules-populationassettypebehavior-instantiate}

```lua
instantiate(self, target: EntityRef?, opts: { [string]: any }?): (EntityRef, { [string]: string })
```

Instantiate this population — the uniform `instantiate(target?, opts?)`
contract every scene-instantiable asset answers to. A population becomes
ONE entity carrying a `Population` component that references this asset:
the component rebuilds the live draws on awake and releases them on
destroy, so the scene records one entity for a population of any size and
a reload replaces the draws rather than stacking a second set. With
`target` the entity spawns as a child of that owner (so an owning `Asset`
component tears it down with its other children); with no target it is a
fresh root. The base opts — `position`, `rotation`, `scale`, `name`,
`temporary` — place the root.

**Parameters**

- `self` `any` _(optional)_
- `target` `EntityRef?` _(optional)_ — Optional owning entity ref.
- `opts` `{ [string]: any }?` _(optional)_ — `{ position?, rotation?, scale?, name?, temporary? }`.

```lua
populationRef:instantiate(owner)
```

## modules/PopulationAssetTypeBehavior/onCreate {#modules-populationassettypebehavior-oncreate}

```lua
onCreate(name: string, opts: CreateOpts?): { [string]: string }
```

Generic-creation hook for `asset.create("population", name, opts)`.
Pure: returns the content-file map; `asset.create` writes it to the
mode-aware destination. Each variant contributes its mesh + material to
`population.json` and its matrices to `transforms.bin`, in variant order.

**Parameters**

- `name` `string` — Population identity (the instance name).
- `opts` `CreateOpts?` _(optional)_

```lua
asset.create("population", "forest", { variants = { { mesh = meshGuid, material = matGuid, transforms = flat } } })
```

## modules/PopulationAssetTypeBehavior/setRenderLayer {#modules-populationassettypebehavior-setrenderlayer}

```lua
setRenderLayer(self, renderLayer: number)
```

Put every registration this holds on the render layers `renderLayer`
names. Constant time per registration — the transforms are not re-uploaded
and nothing is re-registered — so a population can follow a membership that
moves, and the next frame drawn tests its copies against the new one.

**Parameters**

- `self` `any` _(optional)_
- `renderLayer` `number` — The membership bitmask, the same value `:draw({ renderLayer })`
takes. At least one bit must be set.

```lua
live:setRenderLayer(mask)
```

## modules/PopulationAssetTypeBehavior/settled {#modules-populationassettypebehavior-settled}

```lua
settled(self): boolean
```

Whether the renderer has answered for every registration this holds.
A registration is made a stage before the renderer sees it, so the frame it
is made in is one where nothing yet says whether the copies are drawn;
`:errors()` is complete from the frame this turns true.

**Parameters**

- `self` `any` _(optional)_

```lua
if live:settled() then check(live:errors()) end
```

## modules/PopulationAssetTypeBehavior/spec {#modules-populationassettypebehavior-spec}

```lua
spec(self): any
```

The recipe this population draws from: `{ version, total, variants }`,
where each variant carries `{ mesh, material?, materialKey?, count,
offset }` — the `.mesh` it draws, the material it draws with, how many
instances it holds, and where its matrices start in `transforms.bin`
(counted in instances).

**Parameters**

- `self` `any` _(optional)_

```lua
local total = populationRef:spec().total
```

## modules/PopulationAssetTypeBehavior/transforms {#modules-populationassettypebehavior-transforms}

```lua
transforms(self): string
```

The instance matrices as raw bytes — `total * 64`, little-endian f32,
column-major mat4 per instance, in variant order.

**Parameters**

- `self` `any` _(optional)_

```lua
local blob = populationRef:transforms()
```

## modules/Prelude/README {#modules-prelude-readme}

```lua
require("@builtin/modules/prelude") -- Prelude
```

Auto-require globals available in every script without require(). Injects Entity, Physics, Transform, and Material as global Luau wrappers.

This script runs once after FFI registration. It requires builtin library
modules and exposes them as globals. Users never need to write:
  local Entity = require(".entity_reflect")
Instead they just use `Entity` directly.
Only high-frequency, universally-useful APIs belong here.
Specialized modules (e.g. agent tools, editor UI) still use require().
Convention:
  __name  = raw FFI binding (Rust native call, never used directly by scripts)
  Name    = Luau wrapper (user-facing, auto-injected via this prelude)

Usage: local Prelude = require("@builtin/modules/prelude")

## modules/PresetAssetTypeRef/README {#modules-presetassettyperef-readme}

```lua
PresetAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<preset>`. Loaded lazily by `asset_ref.module`.

## modules/PresetAssetTypeRef/applyTo {#modules-presetassettyperef-applyto}

```lua
applyTo(self, entityId: string, componentType: string, overrides: { [string]: any }?): boolean
```

Apply this preset to a component on an entity. Looks up the
component by `componentType` on `entityId`, then writes each
preset property onto the component's `public` table. Errors
cleanly when the entity has no component of that type. Returns
true on success.

**Parameters**

- `self` `any` _(optional)_
- `entityId` `string` — Target entity ID.
- `componentType` `string` — Component type name (e.g. `"CharacterController"`).
- `overrides` `{ [string]: any }?` _(optional)_ — Optional shallow overrides applied on top of the preset.

```lua
presetRef:applyTo(playerId, "CharacterController")
```

## modules/PresetAssetTypeRef/getDefinition {#modules-presetassettyperef-getdefinition}

```lua
getDefinition(self): string?
```

Read the preset's `preset.yaml` body as raw text.

**Parameters**

- `self` `any` _(optional)_

```lua
local raw = presetRef:getDefinition()
```

## modules/PresetAssetTypeRef/inspect {#modules-presetassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail: `{ componentType, fieldValues
}`, parsed from the preset's own `preset.yaml` — `componentType` is the
`component:` field, `fieldValues` is the decoded `properties` table
(`preset.load` with no overrides). Cached on the asset's content
checksum, so re-inspecting unchanged source is free. A preset with no
readable `preset.yaml` returns an empty detail rather than erroring.

**Parameters**

- `self` `any` _(optional)_

```lua
local fieldValues = asset.inspect(presetRef).detail.fieldValues
```

## modules/PresetAssetTypeRef/load_preset {#modules-presetassettyperef-load-preset}

```lua
load_preset(self, overrides: { [string]: any }?): { [string]: any }?
```

Load the preset's properties as a plain Lua table, optionally
merging caller-supplied overrides on top. Equivalent to
`preset.load(self.identity, overrides)`.

**Parameters**

- `self` `any` _(optional)_
- `overrides` `{ [string]: any }?` _(optional)_ — Optional table merged shallowly over the loaded properties.

```lua
local data = presetRef:load({ speed = 12 })
```

## modules/Preview/README {#modules-preview-readme}

```lua
Preview
```

Compose an asset's own instantiate path into a rendered still preview. Each previewable assetType's `M.ref.preview` calls one of these primitives; they spawn temporary entities, auto-frame an offscreen camera over them, render one frame, read it back as a PNG, and tear down. Scheduled previews drain through one serial work queue whose drainer renders in shared batches — subjects settle together and capture concurrently — so a world-scale backfill completes in seconds per hundred assets while the engine stays responsive.

## modules/Preview/fromEntities {#modules-preview-fromentities}

```lua
fromEntities(makeFn: () -> any, opts: { [string]: any }?): PreviewResult
```

Instantiate entities via `makeFn`, auto-frame an offscreen camera to their
bounds, render one frame, and return the still PNG (base64) + stats. Spawned
entities are marked temporary and despawned after the render. Renders are
serialised on the shared preview rig; renders requested while the preview
queue is draining a batch join its shared pass, so each still shows only
its own subject at single-render wall-clock.

**Parameters**

- `makeFn` `() -> any` — Function returning an entity id/proxy or array of them to preview.
- `opts` `{ [string]: any }?` _(optional)_ — `{ size? = { width, height }, angle? = { yaw, pitch } }`.

```lua
preview.fromEntities(function() local e = entity.spawn("x"); e.component.add("Model", { model = meshRef:handle() }); return e end)
```

## modules/Preview/liveFromEntities {#modules-preview-livefromentities}

```lua
liveFromEntities(makeFn: () -> any, opts: { [string]: any }?): PreviewResult
```

Instantiate entities via `makeFn` and hold them under a live orbiting
camera instead of capturing a still: the returned session's `rtHandle`
names a render target that camera writes EVERY frame (a UI image node
with `src = rtHandle` shows it live), `setOrbit(yaw, pitch, dist?)`
moves the camera around the subject's measured centre, and `dispose()`
despawns the subject, light and camera and destroys the target. The
session holds a key light over the subject the way a still render does.
`fromEntities` routes here when `opts.live` is true, so every type's
`ref:preview({ live = true })` returns one of these with no wiring.

**Parameters**

- `makeFn` `() -> any` — Function returning an entity id/proxy or array of them to preview.
- `opts` `{ [string]: any }?` _(optional)_ — `{ live = true, size? = { width, height }, angle? = { yaw, pitch } }`.

```lua
local p = matRef:preview({ live = true })
```

## modules/Preview/materialOnSphere {#modules-preview-materialonsphere}

```lua
materialOnSphere(matRef: any, opts: { [string]: any }?): PreviewResult
```

Render a material on a unit sphere — the canonical material preview.

**Parameters**

- `matRef` `any` _(optional)_ — An AssetRef<material>, or a material identity/name string.
- `opts` `{ [string]: any }?` _(optional)_ — `{ size? = { width, height }, angle? = { yaw, pitch } }`.

```lua
preview.materialOnSphere(matRef)
```

## modules/Preview/queueStatus {#modules-preview-queuestatus}

```lua
queueStatus(): { [string]: any }
```

Report the preview work queue: how many renders are pending, the
batch currently rendering, session totals, and the most recent failures.

```lua
local s = preview.queueStatus(); print(s.pending, s.active)
```

## modules/Preview/schedulePreview {#modules-preview-schedulepreview}

```lua
schedulePreview(ref: any, opts: { [string]: any }?)
```

Queue a `writePreview` for `ref` on the preview work queue. The
per-type generation hooks (material / texture / bundle `onChange`) call
this on every content write; a burst of writes renders once, after the
content settles, so the render sees the final bytes. Renders drain in
shared batches in schedule order; poll `queueStatus` for progress.

**Parameters**

- `ref` `any` _(optional)_ — The asset's AssetRef.
- `opts` `{ [string]: any }?` _(optional)_ — `{ debounce?: number }` — seconds the entry waits before its
render becomes eligible (default 1; a backfill pass over settled content
passes 0).

```lua
preview.schedulePreview(matRef)
```

## modules/Preview/swatch {#modules-preview-swatch}

```lua
swatch(texRef: any, opts: { [string]: any }?): PreviewResult
```

Render a texture as a flat plane facing the camera — its swatch.

**Parameters**

- `texRef` `any` _(optional)_ — An AssetRef<texture>, or a texture guid/identity string.
- `opts` `{ [string]: any }?` _(optional)_ — `{ size? = { width, height }, angle? = { yaw, pitch } }`.

```lua
preview.swatch(texRef)
```

## modules/Preview/writePreview {#modules-preview-writepreview}

```lua
writePreview(ref: any, opts: { [string]: any }?): (boolean, string?)
```

Render an asset's preview via its type's `ref:preview()` and persist it
as `preview.png` inside the asset folder. The preview is the asset's
visual description — it syncs and publishes like any other file, feeds
image-based search, and gives browsers a thumbnail. Skips scratch content
(`/source/tmp/`). Writes only when the rendered bytes differ from the
existing file, so re-rendering an unchanged asset produces no sync traffic.

**Parameters**

- `ref` `any` _(optional)_ — The asset's AssetRef — its type must expose `preview` (material, texture, bundle).
- `opts` `{ [string]: any }?` _(optional)_ — Forwarded to `ref:preview()`; defaults to a 256×256 render.

```lua
preview.writePreview(matRef)
```

## modules/ProcGraphAssetTypeBehavior/README {#modules-procgraphassettypebehavior-readme}

```lua
ProcGraphAssetTypeBehavior
```

Per-instance methods exposed on every `AssetRef<procGraph>` — a `.procGraph` asset is a serialized procedural graph (`proc.graph.v1`). The methods below let callers use the graph THROUGH its ref (`ref:eval("output:mesh")`, `ref:inputs()`, `ref:asOp()`) instead of round-tripping through the proc module + a path string. `asOp` is also how the op registry resolves a `.procGraph` referenced as a graph node: the type owns "how a graph becomes an op", the evaluator's registry delegates to it. Loaded lazily by `asset_ref.module` via `require("@builtin::systems.procgen.procGraph.behavior")` the first time a procGraph ref is touched in a VM.

## modules/ProcGraphAssetTypeBehavior/asOp {#modules-procgraphassettypebehavior-asop}

```lua
asOp(self): any
```

Wrap this graph as an op def so it can be used as a NODE in another
graph: its params mirror this graph's declared inputs, its outputs mirror
this graph's declared outputs, and its version folds this graph's structure
with every content op it references (so an edit anywhere beneath re-keys the
wrapping node). The op registry resolves a graph node whose op is a `.procGraph`
ref through this method — the type owns the graph-as-op mapping; the
evaluator's `wrapGraphAsOp` is the library that does the heavy folding.

**Parameters**

- `self` `any` _(optional)_

```lua
local opDef = procRef:asOp()
```

## modules/ProcGraphAssetTypeBehavior/compile {#modules-procgraphassettypebehavior-compile}

```lua
compile(self): { [string]: any }
```

Compile this asset's `init.luau` into its `graph.json` — the serialized
form the evaluator loads when another graph composites this one, and the
file whose write makes every live `Generator` bound to this asset re-cook.
This is the SOURCE step, not the evaluation step: it produces the graph, it
does not run it (that is a cook, which the Generator drives).
The type compiles on its own whenever the source is written, so calling this
is only for forcing it — a rebuild after restoring a file, or a script that
wants the node count back.

**Parameters**

- `self` `any` _(optional)_

```lua
local r = procRef:compile()
```

## modules/ProcGraphAssetTypeBehavior/eval {#modules-procgraphassettypebehavior-eval}

```lua
eval(self, target: string, opts: any?): any
```

Evaluate one output of this graph and return the produced value
(Geometry / InstanceSet / Texture / Material / Bundle / …). `target` is an
output name (`"mesh"`), or an explicit `"output:<name>"` / `"node:<id>[:<out>]"`
selector. `opts` forwards to `proc.eval` (`{ inputs = { … }, seed = N }`) so
the graph's exposed inputs can be overridden per call.

**Parameters**

- `self` `any` _(optional)_
- `target` `string` — Output name or selector.
- `opts` `any?` _(optional)_ — Optional `{ inputs, seed, … }` (see `proc.eval`).

```lua
local mesh = procRef:eval("mesh", { inputs = { radius = 3 } })
```

## modules/ProcGraphAssetTypeBehavior/graph {#modules-procgraphassettypebehavior-graph}

```lua
graph(self): any
```

This asset's procedural graph, built from its `init.luau` source. The
source is the graph's definition, so this answers with what the asset
currently describes rather than with whatever was last compiled.

**Parameters**

- `self` `any` _(optional)_

```lua
local g = procRef:graph()
```

## modules/ProcGraphAssetTypeBehavior/inputs {#modules-procgraphassettypebehavior-inputs}

```lua
inputs(self): { [string]: any }
```

The graph's declared inputs — the parameters that drive it, each with its
procgen type and default. This is the vocabulary a Generator exposes as
editable overrides.

**Parameters**

- `self` `any` _(optional)_

```lua
for name, decl in pairs(procRef:inputs()) do print(name, decl.type) end
```

## modules/ProcGraphAssetTypeBehavior/instantiate {#modules-procgraphassettypebehavior-instantiate}

```lua
instantiate(self, target: EntityRef?, opts: { [string]: any }?): (EntityRef, { [string]: string })
```

Put this graph in the scene — the uniform `instantiate(target?, opts?)`
contract every scene-instantiable asset answers to. An entity carrying a
`Generator` bound to this asset: the Generator cooks the graph and keeps
the result as that entity's managed children, re-cooking whenever the
graph or its params change — so the scene holds a live instance of the
description, not a frozen copy of one evaluation. With `target` the
generator spawns as a child of that owner (so an owning `Asset` component
tears it down with its other children); with no target it is a fresh
root. The base opts — `position`, `rotation`, `scale`, `name`,
`temporary` — place the root.

**Parameters**

- `self` `any` _(optional)_
- `target` `EntityRef?` _(optional)_ — Optional owning entity ref.
- `opts` `{ [string]: any }?` _(optional)_ — `{ position?, rotation?, scale?, name?, temporary?, output?,
params?, autoBake? }` — `output` names which declared output to realize,
`params` seeds the graph's exposed inputs.

```lua
local gen = procRef:instantiate()
local gen = procRef:instantiate(nil, { params = { rockCount = 800 } })
```

## modules/ProcGraphAssetTypeBehavior/onChange {#modules-procgraphassettypebehavior-onchange}

```lua
onChange(ref, change)
```

Change callback: recompile whenever the entry source is written. The
`graph.json` this produces lands inside the same folder, which is what a
live `Generator` bound to this asset watches — so editing the source is the
whole update path, with no build step between writing and seeing it.
Writes to any other file in the folder (that `graph.json`, the README, the
sidecars) are not the definition and do not recompile — by the path filter
here, and by the compiled-source guard for a change that names no path.

**Parameters**

- `ref` `any` _(optional)_
- `change` `any` _(optional)_

## modules/ProcGraphAssetTypeBehavior/onRegister {#modules-procgraphassettypebehavior-onregister}

```lua
onRegister(self)
```

Initial-registration callback: compile the graph the moment the instance
registers, so an asset restored without a `graph.json` — or one whose source
changed while the engine was down — has its compiled form before anything
composites or cooks it.

**Parameters**

- `self` `any` _(optional)_

## modules/ProcGraphAssetTypeBehavior/outputs {#modules-procgraphassettypebehavior-outputs}

```lua
outputs(self): { string }
```

The graph's declared output names (sorted). Each is a value the graph
produces and a valid `eval` target.

**Parameters**

- `self` `any` _(optional)_

```lua
local outs = procRef:outputs()
```

## modules/ProcGraphAssetTypeBehavior/promote {#modules-procgraphassettypebehavior-promote}

```lua
promote(self, opts: { [string]: any }?): { [string]: any }
```

Publish this graph as an OPERATION — a `.procNode` whose def is this
graph. A graph referenced as a node is a private subgraph of whatever names
it; an op is part of the vocabulary every graph searches, so `procgen ops`
and `proc.search_ops` find it, and any graph can reach for it by name.
The op's params are this graph's declared inputs and its outputs are this
graph's declared outputs, and the node stays bound to this asset — editing
the graph changes the op, and every graph using it re-cooks.
The `.procNode` is written as source (`init.luau`) like any other, so it is
a node to keep editing: give it its own eval and it becomes an op in its own
right rather than this graph under another name.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ [string]: any }?` _(optional)_ — Optional `{ name, out, description, tags }` — the op's name (default:
this graph's), the `.procNode` folder to write (default: inside this graph,
which is where the op form of it belongs), and the description + tags its
`.metadata` carries (default: this graph's own).

```lua
local node = procRef:promote()
local node = procRef:promote({ name = "StuddedTop", tags = { "mesh", "lego" } })
```

## modules/ProcGraphAssetTypeBehavior/validate {#modules-procgraphassettypebehavior-validate}

```lua
validate(self): { any }
```

Type-check this graph's connections. Returns `proc.validate`'s diagnostic
list (empty when the graph is well-typed) — each entry is
`{ level, code, node, input, expected, actual, suggestions }`.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, d in ipairs(procRef:validate()) do warn(d.code, d.node, d.input) end
```

## modules/ProcNodeAssetTypeBehavior/README {#modules-procnodeassettypebehavior-readme}

```lua
ProcNodeAssetTypeBehavior
```

Registration lifecycle for `.procNode` assets — custom procedural operations authored as content. An instance's `init.luau` returns either a GRAPH (`return proc.define(...)` — the node carrying its own pipeline, the self-contained form) or a def table (op-style `{ inputs, params, outputs, eval }` for a hand-written eval); this behaviour push-registers it into the proc op registry, keyed by the asset's stable GUID. Graphs reference these nodes by a typed GUID ref (never by name), so resolution is push-model with no dynamic name probing.

## modules/ProcNodeAssetTypeBehavior/onChange {#modules-procnodeassettypebehavior-onchange}

```lua
onChange(ref, _change)
```

Change callback: re-register + hot-reload this node whenever its
`.procNode` is seeded or its entry script is edited. The node is
re-registered from its current entry source; the version bump propagates
the edit to every graph that reaches the node.

**Parameters**

- `ref` `any` _(optional)_
- `_change` `any` _(optional)_

## modules/ProcNodeAssetTypeBehavior/onDelete {#modules-procnodeassettypebehavior-ondelete}

```lua
onDelete(ref)
```

Delete callback: unregister this node's op when its `.procNode` folder
is removed. The delete ref carries no guid (the folder is already gone), so
the guid is resolved from the removed folder path via the registry's
path->guid index. A graph referencing it afterward errors loudly at eval —
resolution is push-model, never a silent fallback.

**Parameters**

- `ref` `any` _(optional)_

## modules/ProcNodeAssetTypeBehavior/onRegister {#modules-procnodeassettypebehavior-onregister}

```lua
onRegister(self)
```

Initial-registration callback: register this node's op the moment the
instance first registers, so a graph loaded in the same world-ready sweep
can resolve it. Idempotent with `onChange`.

**Parameters**

- `self` `any` _(optional)_

## modules/ProcPackAssetTypeBehavior/README {#modules-procpackassettypebehavior-readme}

```lua
ProcPackAssetTypeBehavior
```

Registration lifecycle for `.procPack` assets — a FAMILY of procedural operations authored as content. The instance's `init.luau` returns a pack table whose `ops` map op id to def, and this behaviour registers the whole map through `registry.registerPack`, so every op is validated exactly as a builtin is and tagged with the pack it came from. Ops registered this way carry the STABLE STRING IDS the pack names them with, which is what separates a pack from a `.procNode` — a single op keyed by its asset guid.

## modules/ProcPackAssetTypeBehavior/onChange {#modules-procpackassettypebehavior-onchange}

```lua
onChange(ref, _change)
```

Change callback: re-register the family whenever the `.procPack` is
seeded or its entry script is edited. Every op is re-registered from the
current source and the version bump propagates the edit to every graph that
reaches any of them; an op the edit removed is unregistered.

**Parameters**

- `ref` `any` _(optional)_
- `_change` `any` _(optional)_

## modules/ProcPackAssetTypeBehavior/onDelete {#modules-procpackassettypebehavior-ondelete}

```lua
onDelete(ref)
```

Delete callback: unregister every op this pack registered when its
`.procPack` folder is removed. A graph naming one afterwards errors loudly
at eval rather than cooking against a definition that no longer exists.

**Parameters**

- `ref` `any` _(optional)_

## modules/ProcPackAssetTypeBehavior/onRegister {#modules-procpackassettypebehavior-onregister}

```lua
onRegister(self)
```

Initial-registration callback: register this pack's whole family the
moment the instance first registers, so a graph loaded in the same
world-ready sweep can resolve every op in it. Idempotent with `onChange`.

**Parameters**

- `self` `any` _(optional)_

## modules/Queue/README {#modules-queue-readme}

```lua
require("@builtin/modules/queue") -- Queue (also available as global 'queue')
```

Defer FFI mutations across frames — `queue(fn) -> (ok, err, drainPromise)`.

Inside the body, write FFI calls (entity.spawn, component.add, position.set,
etc.) enqueue rather than execute synchronously. The engine's per-frame
drainer applies them in FIFO order with a per-frame budget.
Returns `(true, nil, drainPromise)` on success, `(false, err, nil)` if
the body throws — in which case the partial batch is cleared so it does
not later apply.
`drainPromise` is a promise handle that resolves once every mutation
queued inside `fn` has been applied by the engine drainer.
`await(drainPromise)` blocks the calling coroutine until full drain —
use this to gate post-queue work (scene/layer load fires onLoad after
the drain promise resolves). If nothing was queued (e.g. an empty `fn`),
the promise resolves before `queue()` returns.
Nested queue() is a no-op: the inner call just runs in the already-active
queue scope. The depth counter is re-entrant.
See `docs/plans/2026-05-06-luau-queue-deferred-mutations.md` for the full
design (drain budget, error semantics, future per-key fences for reads).

Usage: local Queue = require("@builtin/modules/queue")
Also available as global: queue

## modules/RenderError/README {#modules-rendererror-readme}

```lua
RenderError
```

Shared "this render is broken" marker. `visibleError(entityId)` swaps an entity to the builtin ERROR text model + error material, so a failed render reads as an unmistakable 3D "ERROR" sign on screen instead of empty pixels — empty silently reads as "fine" and a broken object gets mistaken for working. Every render component (built-in Model / SkinnedModel, or a user-authored one) calls this, so the error model is defined in ONE place: change it here and every render component updates.

## modules/RenderError/visibleError {#modules-rendererror-visibleerror}

```lua
visibleError(entityId: string, reason: string?): boolean
```

Swap `entityId` to the builtin ERROR marker so a broken render is
unmistakable on screen. Un-skins the entity first (a bad skeleton can't
collapse the marker), binds the ERROR mesh + error material via the public
`ecs.*` API, and logs the reason at error level. Returns true if the marker
was applied.

**Parameters**

- `entityId` `string` — The entity whose renderable becomes the ERROR marker.
- `reason` `string?` _(optional)_ — Short human string describing what failed (logged).

```lua
renderError.visibleError(self.entityId, "mesh never became GPU-resident")
```

## modules/RenderFeatureAssetTypeRef/README {#modules-renderfeatureassettyperef-readme}

```lua
RenderFeatureAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<renderFeature>`. Loaded lazily by `asset_ref.module` the first time a renderFeature ref is touched in a VM. A render feature is an `init.luau` exporting `{ setup?(ctx), render(ctx), teardown?(ctx) }`; `:enable()` instantiates it (the engine begins calling its `render(ctx)` hook every frame) and returns a live handle, also visible under `/zero/runtime/renderFeatures/`.

## modules/RenderFeatureShared/README {#modules-renderfeatureshared-readme}

```lua
RenderFeatureShared
```

Shared helpers + the authoring contract for renderFeature modules.

## modules/ReportFormatter/README {#modules-reportformatter-readme}

```lua
require("@builtin/systems/worldValidation.package/reportFormatter") -- ReportFormatter
```

Filtering + formatting helpers for the world validation report. Pure functions: every call returns a new value, never mutates the input report.

Three exports: `filter` (re-filter an existing Report without
re-scanning the VFS), `format` (render to a string in one of
four shapes), and `summary` (one-line health line). All three
are pure — they never mutate the input report.

Usage: local ReportFormatter = require("@builtin/systems/worldValidation.package/reportFormatter")

## modules/ReportFormatter/filter {#modules-reportformatter-filter}

```lua
filter(report, opts)
```

Return a new Report containing only problems that match the
filter options. Counts are recomputed from the filtered set so
the caller can trust `counts` against the visible `problems` list.
Pure — the input report is not mutated.

**Parameters**

- `report` `any` _(optional)_ — Report produced by the main validator.
- `opts` `any` _(optional)_ — Filter options — `{ severity, category, source, code,
path (Lua pattern), includePlaceholders (default true), limit }`.

```lua
local errs = ReportFormatter.filter(r, { severity = "error" })
local libsOnly = ReportFormatter.filter(r, { source = "library:@builtin" })
```

## modules/ReportFormatter/format {#modules-reportformatter-format}

```lua
format(report, format)
```

Render a Report into a string in the chosen format.

**Parameters**

- `report` `any` _(optional)_ — Report produced by the main validator.
- `format` `any` _(optional)_ — One of `"human"` (default), `"markdown"`, `"json"`,
`"summary"`. Unknown values fall back to `"human"`.

```lua
print(ReportFormatter.format(r, "human"))
local md = ReportFormatter.format(r, "markdown")
```

## modules/ReportFormatter/summary {#modules-reportformatter-summary}

```lua
summary(report)
```

Compact one-line health summary string —
`world: NE/NW   libraries: NE/NW   total: OK|FAIL`.

**Parameters**

- `report` `any` _(optional)_ — Report produced by the main validator.

```lua
print(ReportFormatter.summary(r))
```

## modules/ResourceHandle/README {#modules-resourcehandle-readme}

```lua
ResourceHandle
```

Recognises a live GPU resource handle — the `{ kind = "<Category>Handle", category, guid, name }` table `renderer.mesh.create`, `renderer.material.create` and `renderer.texture.create` return. Every boundary that carries a component field value out of the session that produced it consults this to tell a handle from an `AssetRef`.

## modules/ResourceHandle/isLive {#modules-resourcehandle-islive}

```lua
isLive(v: any): boolean
```

Whether a value is a live GPU resource handle.

**Parameters**

- `v` `any` _(optional)_ — Any component field value.

```lua
ResourceHandle.isLive(renderer.mesh.create(geometry)) -- true
```

## modules/ResourceHandle/label {#modules-resourcehandle-label}

```lua
label(v: any): string
```

A short phrase naming a handle, for a message about the value.

**Parameters**

- `v` `any` _(optional)_ — A handle table.

```lua
ResourceHandle.label(meshHandle) -- "mesh handle 'msh_grass_1'"
```

## modules/ResourceHandle/park {#modules-resourcehandle-park}

```lua
park(owner: string, componentType: string, dropped: { [string]: any }?)
```

Hold, for the rest of this session, the live handles one component's
durable record left out — keyed by the entity and component they came
from. Each call replaces what that pair had parked before.

**Parameters**

- `owner` `string` — The entity id the component sits on.
- `componentType` `string` — The component's type name.
- `dropped` `{ [string]: any }?` _(optional)_ — The `{ field = handle }` map left out of the record, or nil when
the component's record carries every field it holds.

```lua
ResourceHandle.park(id, "@builtin::components.Model", { model = mesh })
```

## modules/ResourceHandle/withParked {#modules-resourcehandle-withparked}

```lua
withParked(data: any, owner: string, componentType: string): (any, number)
```

The component field map to apply, with every field this session parked
for `owner`'s `componentType` and the record does not carry put back.

**Parameters**

- `data` `any` _(optional)_ — A component's `{ field = value }` map from a record.
- `owner` `string` — The entity id the component is being applied to.
- `componentType` `string` — The component's type name.

```lua
ResourceHandle.withParked(record.data, id, "@builtin::components.Model")
```

## modules/ResourceHandle/withoutLive {#modules-resourcehandle-withoutlive}

```lua
withoutLive(data: any): (any, { [string]: string }?)
```

The component field map to apply, with any live-handle value left out —
the form a value read from durable content takes in a session other than
the one that minted it. The field falls back to the component's declared
default, and the caller reports what it stood for.

**Parameters**

- `data` `any` _(optional)_ — A component's `{ field = value }` map.

```lua
ResourceHandle.withoutLive(record.data) -- data, nil
```

## modules/RigAssetTypeBehavior/README {#modules-rigassettypebehavior-readme}

```lua
RigAssetTypeBehavior
```

Behaviour for the `rig` asset type — a skeleton's disk shape. The payload is `rig.json` (a readable JSON document: ordered bones with names, parent hierarchy, the node index each maps to, rest local transform, and inverse-bind matrix, plus the retarget `profile` (role -> bone) and the `humanoid` classification). A rig is its own primitive: a skinned mesh references a rig, an animation references its source rig, and retargeting maps one rig onto another. The format is text, not binary, so an agent can open it and fix a mis-derived profile or a bad bone parent with an edit. Importers call `asset.create("rig", name, { json })` to mint a rig.

## modules/RigAssetTypeBehavior/onChange {#modules-rigassettypebehavior-onchange}

```lua
onChange(self, _change)
```

Drop the cached decode when the rig's content changes — a hot-reload
or a re-import — so the next `:doc()` re-parses the new `rig.json`.

**Parameters**

- `self` `any` _(optional)_ — The rig AssetRef that changed.
- `_change` `any` _(optional)_ — What happened to it; the cache is dropped whatever it was.

## modules/RigAssetTypeBehavior/onCreate {#modules-rigassettypebehavior-oncreate}

```lua
onCreate(name: string, opts: CreateOpts): { [string]: string }
```

Generic-creation hook for `asset.create("rig", name, opts)`. Pure:
returns the content-file map; `asset.create` writes it to the authored
destination, registering the `.rig` asset under its minted guid. The JSON
document carries the skeleton, its retarget profile (the role -> bone driver,
present for a humanoid), and its humanoid classification — a non-humanoid rig
(a prop, a plant, a quadruped) simply has no profile in the same document.

**Parameters**

- `name` `string` — Rig identity (the instance name).
- `opts` `CreateOpts`

```lua
asset.create("rig", "PolygonSyntyCharacter", { json = rigJson })
```

## modules/SceneAssetTypeRef/README {#modules-sceneassettyperef-readme}

```lua
SceneAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<scene>`. Loaded lazily by `asset_ref.module`.

## modules/SceneAssetTypeRef/build_scene {#modules-sceneassettyperef-build-scene}

```lua
build_scene(self, opts: { save: boolean?, layer: any?, trigger: string? }?): any
```

Run this scene's `build.luau` against what it resolves right now and
land what it declares in the scene — for the case where something the
builder reads changed and the file did not. Writing `build.luau` already
runs the build, so a call after a write is unnecessary.
`content()` writes the scene's entities and `editorOnly()` writes the ones
that are present while authoring and absent in play; each is reconciled
against the entities the last build placed, so an entity keeps its id
across every rebuild and anything else in the scene is left alone.
Runs in edit mode on a LOADED scene — the entities it lands on are the live
ones. `opts.save = false` leaves the result unsaved; by default the scene is
saved, which is what puts the build in `scene.json`.
A call made while a build for this scene is running returns that build
right away instead of starting a second one — a build the scheduler is
still advancing. One whose task was cancelled, or that stopped for any
other reason without returning, hands the scene back to this call, which
runs the build. A build that a newer write to `build.luau` replaces stops
where it stands and leaves the scene to the rebuild that write asked for.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ save: boolean?, layer: any?, trigger: string? }?` _(optional)_ — Optional `{ save = false }`.

```lua
layers.active.asset:build()
```

## modules/SceneAssetTypeRef/discard_scene {#modules-sceneassettyperef-discard-scene}

```lua
discard_scene(self, opts: any): boolean
```

Discard this scene's UNSAVED (dirty) edits and restore its saved
`scene.json`. When the scene is LOADED, the overlay is deleted and the live
layer is respawned from canonical (with the scene-load gate held so the
respawn is not re-marked dirty); when it is NOT loaded, the on-disk overlay
is simply deleted. Edit-mode overlay only — not the play-mode baseline.

**Parameters**

- `self` `any` _(optional)_
- `opts` `any` _(optional)_ — Optional `{ to = <name|path> }`, or a bare name/path string, to
target a scene other than this asset's own path.

```lua
sceneRef:discard()
```

## modules/SceneAssetTypeRef/getBuildScript {#modules-sceneassettyperef-getbuildscript}

```lua
getBuildScript(self): string?
```

Read the scene's `build.luau` body as raw text.

**Parameters**

- `self` `any` _(optional)_

```lua
local src = sceneRef:getBuildScript()
```

## modules/SceneAssetTypeRef/getEntrypoint {#modules-sceneassettyperef-getentrypoint}

```lua
getEntrypoint(self): string?
```

Read the scene's `entrypoint.luau` body as raw text.

**Parameters**

- `self` `any` _(optional)_

```lua
local code = sceneRef:getEntrypoint()
```

## modules/SceneAssetTypeRef/getSceneJson {#modules-sceneassettyperef-getscenejson}

```lua
getSceneJson(self): { [string]: any }?
```

Parse the scene's `scene.json` into a Lua table.

**Parameters**

- `self` `any` _(optional)_

```lua
local s = sceneRef:getSceneJson()
```

## modules/SceneAssetTypeRef/getSceneJsonRaw {#modules-sceneassettyperef-getscenejsonraw}

```lua
getSceneJsonRaw(self): string?
```

Read the scene's `scene.json` body as raw JSON text.

**Parameters**

- `self` `any` _(optional)_

```lua
local raw = sceneRef:getSceneJsonRaw()
```

## modules/SceneAssetTypeRef/inspect {#modules-sceneassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail: `{ entityCount, entityNames,
player }`, parsed from the scene's own `scene.json` — never executes
`entrypoint.luau`. A scene whose `scene.json` can't be read/parsed
returns an empty detail rather than erroring.

**Parameters**

- `self` `any` _(optional)_

```lua
local entityNames = asset.inspect(sceneRef).detail.entityNames
```

## modules/SceneAssetTypeRef/listEntities {#modules-sceneassettyperef-listentities}

```lua
listEntities(self): { string }
```

List the entity names declared at the top level of the
scene's JSON body. Best-effort; nested children are not
flattened.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, n in ipairs(sceneRef:listEntities()) do print(n) end
```

## modules/SceneAssetTypeRef/load_scene {#modules-sceneassettyperef-load-scene}

```lua
load_scene(self, opts: { [string]: any }?): any
```

Load this scene into the root ("main") slot. Equivalent to
`layers.load(self)` — the AssetRef envelope is passed straight
through, so the loader threads scene identity by guid. Pass
`opts` for additive overlays / persistence / origin offset (same
shape as `layers.load`'s second argument).

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ [string]: any }?` _(optional)_ — Optional load options forwarded to `layers.load`.

```lua
sceneRef:load()
sceneRef:load({ additive = true, name = "hud_overlay" })
```

## modules/SceneAssetTypeRef/onChange {#modules-sceneassettyperef-onchange}

```lua
onChange(ref, change)
```

A write inside a `.scene` folder. A write to `build.luau` re-runs the
build on the loaded scene, which is what makes an edit to the code show up
in the scene without reloading it. The rebuild finishes after the write has
returned, and posts a notice naming the scene and how many entities each
surface placed — the write's own answer is that the file was written. A
write that arrives while a rebuild is running gets a rebuild of its own once
that one finishes, and several such writes get the single run that reads
them all.

**Parameters**

- `ref` `any` _(optional)_ — The scene whose folder was written.
- `change` `any` _(optional)_ — `{ path, asset, type, kind, origin }`.

```lua
__zero_dispatch_asset_change("/zero/source/scenes/main.scene/build.luau")
```

## modules/SceneAssetTypeRef/onCreate {#modules-sceneassettyperef-oncreate}

```lua
onCreate(_name: string): { [string]: string }
```

Generic-creation hook for `asset.create("scene", name)`. A new scene is
the type's template shape verbatim.

**Parameters**

- `_name` `string`

```lua
asset.create("scene", "my_level")
```

## modules/SceneAssetTypeRef/save_scene {#modules-sceneassettyperef-save-scene}

```lua
save_scene(self, opts: any): any
```

Publish this scene's current state to its canonical `scene.json`. When
the scene is LOADED, its live scenegraph is captured into canonical; when
it is NOT loaded, its pending dirty overlay is promoted into canonical.
Either way the durable `scene.json` ends up reflecting the authored state.
`opts.to` (a scene name or path) saves to a different scene ("save as").
`opts.layer` is the layer holding this scene, for a caller that already has
it: a scene is findable through `layers.list` only once its load has
registered it, so a save made DURING that load names its layer itself and
captures the live scenegraph rather than reading it as unloaded.

**Parameters**

- `self` `any` _(optional)_
- `opts` `any` _(optional)_ — Optional `{ to = <name|path>, layer = <SceneProxy> }`, or a bare
name/path string.

```lua
sceneRef:save()
layers.active.asset:save({ to = "level_2" })
```

## modules/SceneAssetTypeRef/validate {#modules-sceneassettyperef-validate}

```lua
validate(self): { { code: string, severity: string, message: string } }
```

Semantic content validation for a scene: the player-setup rule set run
over this scene's scene.json, surfaced through `asset.validate`, plus a
warning when the scene has no explicit sky entity.

**Parameters**

- `self` `any` _(optional)_

## modules/SceneBuild/README {#modules-scenebuild-readme}

```lua
SceneBuild
```

Runs a builder function in an entity capture scope and composes what it created into records, then reconciles records into the scene with ids held stable across rebuilds. Also holds the `build` surface a build script reads, whose `build.asset` authors the assets a build produces and hands back the same one on every run the code has not changed.

## modules/SceneBuild/attribute {#modules-scenebuild-attribute}

```lua
attribute(refusals: { Refusal }): { Refusal }
```

Read a refusal's traceback for the one frame that belongs to the code
being built. A build composed from several contributors reports this so an
author reads which contributor was refused rather than which build ran.

**Parameters**

- `refusals` `{ Refusal }` — The refusal array `entity.capture` hands back.

```lua
local named = SceneBuild.attribute(select(4, entity.capture(fn)))
```

## modules/SceneBuild/buildSurface {#modules-scenebuild-buildsurface}

```lua
buildSurface(folder: string, sourceDigest: string): BuildSurface
```

The `build` surface a build script reads: the operations that belong to
the build itself rather than to the scene it states. `build.asset(kind,
name, produce)` is the asset a build makes — `produce` runs when the build
script changed and its result is authored at `<folder>/<name>.<kind>`,
and every other run hands back that same asset, guid and all, without
running `produce` at all. The returned `AssetRef` is what a component field
names, so the reference survives the save and the reload.

**Parameters**

- `folder` `string` — The build's own folder, which the assets it produces are authored
inside.
- `sourceDigest` `string` — The digest of the build script running now, as `M.digest`
reports it — what decides whether an asset it produced is still the asset
the code states.

```lua
local surface = SceneBuild.buildSurface(dir, SceneBuild.digest(src))
```

## modules/SceneBuild/digest {#modules-scenebuild-digest}

```lua
digest(source: string): string
```

A short, stable digest of a script's source. Two different scripts give
different digests, and the same script gives the same one on every machine
and every run — which is what makes it the answer to "did the code that
produced this change?".

**Parameters**

- `source` `string` — The script body to digest.

```lua
local key = SceneBuild.digest(vfs.read(path))
```

## modules/SceneBuild/drift {#modules-scenebuild-drift}

```lua
drift(owner: string?): { Drift }
```

Where the live scene disagrees with the build that states it. Every
entity a build placed records what that build last said about each of its
properties, so anything an author has changed since reads back differently
— and this is that list: the entity, the property, what the build said, and
what the scene holds now.

These are the values a rebuild KEEPS. A build repeating itself leaves them
alone, and only a build that states something DIFFERENT about that property
takes it back. So this is what to read to know that a scene and its
`build.luau` disagree, and where, before deciding which should win.

Property names are the ones the build records: `n` name, `i` internal,
`p` position, `r` rotation, `s` scale, and `a:<name>` for an attribute.

**Parameters**

- `owner` `string?` _(optional)_ — Optional build name, as `M.ownerOf` reports it, to read just that
build. Omitted, every build-owned entity in the scene is read.

```lua
for _, d in ipairs(SceneBuild.drift()) do print(d.name, d.property) end
```

## modules/SceneBuild/notePreview {#modules-scenebuild-notepreview}

```lua
notePreview(entityId: string, values: { [string]: any }, componentType: string?): nil
```

Record the values an author left on `entityId`, an entity a build owns.
The build states that entity from its own source, so the values hold until
it runs again — and `M.takePreview` is what the next run reads to say which
of them it replaced and with what. Each record REPLACES the one before it:
what it states is everything the entity carries now, so a name dropped
between two records is dropped here too.

**Parameters**

- `entityId` `string` — Runtime entity id of the owned entity.
- `values` `{ [string]: any }` — The values the entity carries now, by name.
- `componentType` `string?` _(optional)_ — The component that states them, so a rebuild knows to state
that type again instead of leaving it to the scene.

```lua
SceneBuild.notePreview(id, { count = 9 }, "SceneModule")
```

## modules/SceneBuild/ownerOf {#modules-scenebuild-ownerof}

```lua
ownerOf(entityId: string): string?
```

The build that placed `entityId`, or nil when no build placed it. A
reconcile writes the name of the build onto every entity it places, as an
attribute the scene records beside the entity's name and transform, so the
answer holds across a reload — and an entity an author spawned carries no
owner at all.

**Parameters**

- `entityId` `string` — Runtime entity id.

```lua
if SceneBuild.ownerOf(id) ~= nil then print("a build states this") end
```

## modules/SceneBuild/previewedComponentType {#modules-scenebuild-previewedcomponenttype}

```lua
previewedComponentType(entityId: string): string?
```

The component type that recorded a preview for `entityId`, or nil when
none is waiting. A component that records one is SAYING that a build states
its fields and that it announces the replacement itself — so a rebuild
states that type again rather than leaving it to the scene, which is what
lets the announcement happen. Every other component is merged.

**Parameters**

- `entityId` `string` — Runtime entity id of the owned entity.

```lua
if SceneBuild.previewedComponentType(id) == "SceneModule" then end
```

## modules/SceneBuild/reconcile {#modules-scenebuild-reconcile}

```lua
reconcile(
```

Apply `records` to the scene under `target`, reusing the entities a
previous reconcile left behind. A record that maps to a live entity
updates THAT entity — same runtime id, so every reference to it survives
the rebuild — and only a record with no live entity spawns one. Entities
the previous build held that this one no longer emits are despawned.
Name, transform, hidden, active, attributes, lifecycle mode, network scope,
whether the entity's live state replicates, and components are all made to
match the record, so a rebuild that drops a component or an attribute drops
it from the scene. Each of them is a diff:
what already matches the record is left exactly as it is, so a rebuild that
changed nothing changes nothing — a running component keeps running and the
scene stays clean. Only entities the build owns are touched: anything else
under `target` is left exactly as it was.
A component field holding an entity reference is resolved as the records
are applied: a reference to an entity of the SAME build points at the
entity this reconcile landed it on, and a reference to any other entity
keeps pointing where it did.
`owner` names the build. Every entity it places carries that name and the
record's identity as attributes of its own, which is what lets a rebuild
find the entities the last one placed without anything being remembered
between them — the pair is in the scene, and a reload brings it back with
the entity. Two builds sharing a target stay out of each other's way by
using different owners.
A record's identity is its place in the hierarchy — the chain of names
from the build root down to it — so dropping, inserting or reordering a
sibling leaves every other entity where it was. Several children of
one parent sharing a name are told apart by their rank among those,
counted in the order the builder created them.

```lua
local ids = SceneBuild.reconcile(records, root, "chairs")
local ids, created = SceneBuild.reconcile(records, layer, "build")
SceneBuild.reconcile(SceneBuild.run(build), layers.active, "build")
```

## modules/SceneBuild/run {#modules-scenebuild-run}

```lua
run(builder: () -> ()): ({ any }, { Refusal })
```

Run `builder` inside an entity capture scope and return the records for
every entity it created. The builder writes ordinary spawn code — real
`entity.spawn`, real `component.add`, real loops — and the entities it
creates are real for the duration of the call. They are composed into
records and then despawned, so `run` leaves the scene untouched and hands
back data. Reconciling that data into a scene is `M.reconcile`.
The builder's entities are despawned even when it raises, so a failed
build never leaks a half-built hierarchy into the scene.
What a component the builder attached created while running its own
lifecycle belongs to that component: the record names the COMPONENT, and
the same lifecycle runs again wherever the record is put back, so the
entities come from there rather than from records of their own. That covers
a nested build — a placement the builder makes runs its own module and owns
what it lands — and every other component that expands into entities.
An operation the scope refused is refused BEFORE it lands, so the records
describe the live world exactly as the builder left it, and a builder that
ran to its end around a refusal somebody caught for it composes what it
did make. Every such refusal comes back as the second return, naming the
contributor it stopped, for the caller to report alongside what it baked.

**Parameters**

- `builder` `() -> ()` — Function taking no arguments; spawns whatever it wants.

```lua
local records, refused = SceneBuild.run(function() entity.spawn("chair") end)
```

## modules/SceneBuild/sourceOf {#modules-scenebuild-sourceof}

```lua
sourceOf(owner: string): string?
```

The file that states the build named `owner` — what the reconcile
running that build passed as `opts.source`. Nil for a build that has not
run in this session and for one that named no source.

**Parameters**

- `owner` `string` — Build name, as `M.ownerOf` reports it.

```lua
local file = SceneBuild.sourceOf(SceneBuild.ownerOf(id))
```

## modules/SceneBuild/takePreview {#modules-scenebuild-takepreview}

```lua
takePreview(entityId: string): { [string]: any }?
```

Take the values `M.notePreview` recorded for `entityId` and clear them.
Each set of values is read once — by whichever run of the build states that
entity next.

**Parameters**

- `entityId` `string` — Runtime entity id of the owned entity.

```lua
local set = SceneBuild.takePreview(id)
```

## modules/SceneModuleAssetTypeRef/README {#modules-scenemoduleassettyperef-readme}

```lua
SceneModuleAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<sceneModule>`. Loaded lazily by `asset_ref.module`.

## modules/SceneModuleAssetTypeRef/build {#modules-scenemoduleassettyperef-build}

```lua
build(self, params: { [string]: any }?): ({ any }, { SceneBuild.Refusal })
```

Run this module's builder with `params` and return the entity records
it built. The builder runs inside the entity capture scope, so it writes
ordinary spawn code and what it created comes back as data — the scene is
untouched by the call. `SceneBuild.reconcile` is what lands the records.

**Parameters**

- `self` `any` _(optional)_
- `params` `{ [string]: any }?` _(optional)_ — Per-placement input overrides, keyed by declared input name. An
input the table omits resolves to its declared default.
A builder that ran to its end around an operation the scope refused — one
it caught itself, or one something between it and the refused call caught —
hands back the records for what it did make, and every such refusal beside
them: the operation was refused before it landed, so the records describe
the scene as the builder left it.

```lua
local records, refused = moduleRef:build({ seed = 3 })
```

## modules/SceneModuleAssetTypeRef/getInitScript {#modules-scenemoduleassettyperef-getinitscript}

```lua
getInitScript(self): string?
```

Read the module's entry script (`init.luau` / `init.lua`) as raw text.

**Parameters**

- `self` `any` _(optional)_

```lua
local src = moduleRef:getInitScript()
```

## modules/SceneModuleAssetTypeRef/inputs {#modules-scenemoduleassettyperef-inputs}

```lua
inputs(self): { InputSpec }
```

The inputs this module declares, sorted by name — each one's name, its
`Field` kind, its declared default, and, for a closed-set input, the
members it accepts. This is what an inspector renders as widgets and what
a caller reads to learn which params a placement can set.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, i in ipairs(moduleRef:inputs()) do print(i.name, i.kind) end
```

## modules/SceneModuleAssetTypeRef/inspectDetail {#modules-scenemoduleassettyperef-inspectdetail}

```lua
inspectDetail(self): any
```

`asset.inspect` type-specific detail: `{ inputs }` — the declared
inputs, as `:inputs()` reports them. A module whose entry script cannot be
loaded reports an empty input list rather than erroring.

**Parameters**

- `self` `any` _(optional)_

```lua
local declared = asset.inspect(moduleRef).detail.inputs
```

## modules/SceneModuleAssetTypeRef/instantiate {#modules-scenemoduleassettyperef-instantiate}

```lua
instantiate(self, target: EntityRef?, opts: { [string]: any }?): (EntityRef, { [string]: string })
```

Instantiate this module — the uniform `instantiate(target?, opts?)`
contract every scene-instantiable asset answers to, and what makes a
sceneModule placeable wherever a scene-instantiable asset is accepted.

With `target` it builds with `opts.params` and reconciles the records
under that entity, owned by that entity: the entities a previous build
placed there name it as their owner and are UPDATED in place, so ids hold
across every rebuild and across a reload.

With no target it places the module the way an author places any asset:
one entity carrying a `SceneModule` component bound to this module. That
component is what runs the build. The base opts — `position`, `rotation`,
`scale`, `name`, `temporary` — place the root either way.

**Parameters**

- `self` `any` _(optional)_
- `target` `EntityRef?` _(optional)_ — Optional owning entity ref.
- `opts` `{ [string]: any }?` _(optional)_ — `{ position?, rotation?, scale?, name?, temporary?, params? }` —
`params` seeds the module's declared inputs.

```lua
moduleRef:instantiate(owner, { params = { seed = 3 } })
```

## modules/SceneModuleInspector/README {#modules-scenemoduleinspector-readme}

```lua
SceneModuleInspector
```

The SceneModule component's custom entity-inspector view — the bound module's DECLARED inputs as editable field rows.

## modules/SceneModuleInspector/buildFieldSpecs {#modules-scenemoduleinspector-buildfieldspecs}

```lua
buildFieldSpecs(declared: { any }, params: { [string]: any }?): { FieldSpec }
```

Build the editable field descriptors for a module's declared inputs:
one spec per input, sorted by name, carrying the input's kind, its current
value (the param override when the placement set one, else the declared
default), and the members a closed-set input accepts. Pure — no UI, no
entity access — so the field mapping is testable headless.

**Parameters**

- `declared` `{ any }` — The module's declared inputs, as `moduleRef:inputs()` reports.
- `params` `{ [string]: any }?` _(optional)_ — The placement's current param-override table (may be nil).

## modules/SceneModuleInspector/sections {#modules-scenemoduleinspector-sections}

```lua
sections(entityId: string, proxy: any): any?
```

The SceneModule's inspector sections: the bound module's identity, the
file that states the placement, one editable row per declared input, and a
Rebuild action. Returns nil when the proxy is unreadable (the inspector
shows the generic fields alone).

**Parameters**

- `entityId` `string` — The owning entity's id.
- `proxy` `any` _(optional)_ — The live SceneModule component proxy.

## modules/SceneModuleInspector/statedIn {#modules-scenemoduleinspector-statedin}

```lua
statedIn(entityId: string): string?
```

The file the build that placed `entityId` is written in, for a
placement a build made. That build states the placement's params every time
it runs, so the rows below read as a preview of what it would state
rather than as the placement's own settings. Nil for a placement an author
made, whose params are the author's.

**Parameters**

- `entityId` `string` — The inspected entity's id.

```lua
local file = SceneModuleInspector.statedIn(id)
```

## modules/ScriptValidator/README {#modules-scriptvalidator-readme}

```lua
require("@builtin/systems/worldValidation.package/scriptValidator") -- ScriptValidator
```

Per-file Luau / Lua script validator. Wraps `lsp.check` to return real parser + type-check diagnostics for a single script, on top of cheap textual sanity checks (read failure, empty file).

Each script gets the full LSP pass — `lsp.check(path, opts)` from
the engine's embedded Luau LSP. Severity, line, column, code, and
message are taken straight from the LSP and re-wrapped in the
validator's `Problem` shape. The LSP diagnostics carry stable
codes (`unknown-global`, `type-error`, `parse-error`, …) — we
forward them verbatim so callers can `severity = "error"` or
`code = "parse-error"` and get exactly the rows they expect.
Two cheap textual checks run BEFORE the LSP is invoked:
  1. `script.read_failed` (error) — `vfs.read` returned nil
     (file deleted between scan and read, or unreadable).
  2. `script.empty` (warning) — zero non-whitespace content.
These don't duplicate anything the LSP produces — the LSP is
skipped when read fails (no source to feed it) and the empty
check is informational about the file rather than the code.

Usage: local ScriptValidator = require("@builtin/systems/worldValidation.package/scriptValidator")

## modules/ScriptValidator/validate {#modules-scriptvalidator-validate}

```lua
validate(script, opts)
```

Validate a single script. Combines two cheap textual checks
(`script.read_failed`, `script.empty`) with the embedded Luau
LSP's full diagnostic pass via `lsp.check(path)`.

**Parameters**

- `script` `any` _(optional)_ — `{ path, name }` script entry from `vfsScanner`.
- `opts` `any` _(optional)_ — Reserved for future use; currently ignored.

```lua
local problems = ScriptValidator.validate({ path = "/source/foo.luau", name = "foo.luau" })
```

## modules/ScriptValidator/validateBatch {#modules-scriptvalidator-validatebatch}

```lua
validateBatch(scripts, opts)
```

Validate a batch of scripts and flatten the per-script
problem lists into one array.

**Parameters**

- `scripts` `any` _(optional)_ — Array of script entries from `vfsScanner`.
- `opts` `any` _(optional)_ — Reserved for future use.

```lua
local all = ScriptValidator.validateBatch(bucket.scripts)
```

## modules/ServiceAssetTypeRef/README {#modules-serviceassettyperef-readme}

```lua
ServiceAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<service>`. Loaded lazily by `asset_ref.module`. These act on the SPECIFIC service the reference points to — `asset.resolve("mesh_gen","service"):invoke{...}` runs THAT service.

## modules/ServiceAssetTypeRef/balance {#modules-serviceassettyperef-balance}

```lua
balance(self): (number?, string?)
```

Read the caller's current credit balance — the balance every service
draws from. Returns (nil, errMsg) when not signed in.

**Parameters**

- `self` `any` _(optional)_

```lua
local credits = serviceRef:balance()
```

## modules/ServiceAssetTypeRef/cost {#modules-serviceassettyperef-cost}

```lua
cost(self, operation: string?): number?
```

The declared credit cost of an operation (the provider's up-front
estimate; the exact charge is returned on each generation). Defaults to the
primary / only operation.

**Parameters**

- `self` `any` _(optional)_
- `operation` `string?` _(optional)_ — Optional operation name.

```lua
local c = serviceRef:cost()
```

## modules/ServiceAssetTypeRef/frameworkInputs {#modules-serviceassettyperef-frameworkinputs}

```lua
frameworkInputs(self, operation: string?): { { [string]: any } }
```

The inputs a call on this service takes on top of what the operation
declares — `operation`, naming which of the service's operations to run,
and `asset_path`, naming where the run writes what it generates. Each row
reads as a declared input does: `{ name, type, required, desc,
framework = true }`.

**Parameters**

- `self` `any` _(optional)_
- `operation` `string?` _(optional)_ — The operation these apply to. Omit for the service's default.

```lua
local extra = serviceRef:frameworkInputs("sfx")
```

## modules/ServiceAssetTypeRef/getDefinition {#modules-serviceassettyperef-getdefinition}

```lua
getDefinition(self): string?
```

Read this service's declaration source (`init.luau`).

**Parameters**

- `self` `any` _(optional)_

```lua
local src = serviceRef:getDefinition()
```

## modules/ServiceAssetTypeRef/getReadme {#modules-serviceassettyperef-getreadme}

```lua
getReadme(self): string?
```

Read this service's `README.md` body.

**Parameters**

- `self` `any` _(optional)_

```lua
print(serviceRef:getReadme())
```

## modules/ServiceAssetTypeRef/info {#modules-serviceassettyperef-info}

```lua
info(self): { [string]: any }
```

A one-line summary of this service: its offering, what it produces, the
operations it offers, and which of them a call runs when it names none.

**Parameters**

- `self` `any` _(optional)_

```lua
local i = serviceRef:info()
```

## modules/ServiceAssetTypeRef/inspect {#modules-serviceassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail: `{ methods, description }`,
where `methods` is this service's declared operations — the top-level
keys of its `operations = { ... }` table, parsed from the declaration's
own source text — and `description` is the declaration's top-level
summary, also parsed from source. A service with no readable
declaration returns an empty `methods` list rather than erroring.

**Parameters**

- `self` `any` _(optional)_

```lua
local methods = asset.inspect(serviceRef).detail.methods
```

## modules/ServiceAssetTypeRef/invoke {#modules-serviceassettyperef-invoke}

```lua
invoke(self, input: { [string]: any }?): { [string]: any }
```

Run a generation for this service. Picks the operation from
`input.operation` (or the service's only / primary operation), runs its
declared pipeline as a background task, and returns immediately with a
generation handle. An input the operation does not declare is refused here,
before anything is charged. Watch the run with the `services` toolbox
`status` tool (or the `watch` tool) until it reads `completed`; that row's
`asset` is the finished, spawnable asset. Consumes credits — check
`:cost()` and `:balance()` first.

**Parameters**

- `self` `any` _(optional)_
- `input` `{ [string]: any }?` _(optional)_ — `{ prompt, ..., operation?, asset_path? }` — the operation's inputs.

```lua
local g = asset.resolve("mesh_gen","service"):invoke({ prompt = "a treasure chest" })
```

## modules/ServiceAssetTypeRef/onCreate {#modules-serviceassettyperef-oncreate}

```lua
onCreate(name: string, opts: { [string]: any }): { [string]: string }
```

Generic-creation hook for `asset.create("service", name, opts)`. Returns
the scaffold content files for a new service declaration.

**Parameters**

- `name` `string` — Service identity (the instance name).
- `opts` `{ [string]: any }`

```lua
asset.create("service", "mesh_gen", { offering = "origozero/mesh_gen" })
```

## modules/ServiceAssetTypeRef/operations {#modules-serviceassettyperef-operations}

```lua
operations(self): { { [string]: any } }
```

List this service's callable operations and their declared inputs,
output, and credit cost — the per-service surface to read before invoking.
`framework` carries the inputs the CALL takes on top of what the operation
declares (`:frameworkInputs()`).

**Parameters**

- `self` `any` _(optional)_

```lua
for _, op in ipairs(serviceRef:operations()) do print(op.name, op.cost) end
```

## modules/ServiceAssetTypeRef/resume {#modules-serviceassettyperef-resume}

```lua
resume(self, record: { [string]: any }): { [string]: any }
```

Pick a recorded run of this service up where an earlier engine left it.
Runs on world load for every run that did not finish; the record names the
operation, the step in flight and the job it submitted, and the run
continues from there without paying for the same work again.

**Parameters**

- `self` `any` _(optional)_
- `record` `{ [string]: any }` — A run record as the framework's `ServiceTask.durable` returns it.

```lua
asset.resolve("mesh_gen","service"):resume(record)
```

## modules/ServiceFramework/README {#modules-serviceframework-readme}

```lua
ServiceFramework
```

The runtime every `.service` instance declares against — reached via `asset.containing(__FILE__).modules.shared`. The TYPE owns all the machinery (metered invoke, the submit→poll→download→write pipeline, the async generation handle, error classification); an instance only declares its surface with `Service.define{...}`. A normal generation service is pure data — no per-instance logic.

## modules/ServiceFramework/balance {#modules-serviceframework-balance}

```lua
balance(_self: any): ({ [string]: any }?, string?)
```

Read what the caller can spend on this service: `spendable` (the number
an operation's `cost` must fit inside), with `pool` (the account balance) and
`agentRemaining` (what is left of the caller's own allocation, when it works
under one) behind it. Returns (nil, errMsg) when not signed in.

**Parameters**

- `_self` `any` _(optional)_

```lua
local credits = asset.resolve("mesh_gen","service"):balance().spendable
```

## modules/ServiceFramework/cost {#modules-serviceframework-cost}

```lua
cost(self: any, operation: string?): number?
```

The declared credit cost of an operation (the provider's estimate). The
exact amount charged is returned on each generation; this is the up-front
figure to budget against. Defaults to the primary/only operation.

**Parameters**

- `self` `any` _(optional)_
- `operation` `string?` _(optional)_ — Optional operation name.

```lua
local c = asset.resolve("mesh_gen","service"):cost()
```

## modules/ServiceFramework/define {#modules-serviceframework-define}

```lua
define(spec: { [string]: any }): any
```

Declare a metered service. An instance's `init.luau` calls this with its
surface — the offering identity and one or more operations — and returns
the result. The TYPE runs the pipeline; the instance writes no machinery.

**Parameters**

- `spec` `{ [string]: any }` — `{ name, description, offering, output?, primary?, retry?, operations }`.
An operation's `result` is either a single file (`bytes` / `url`) or a SET
(`files`), and a set assembles one asset: `files = { { as, url } }` fetches
each map into the asset's own folder (an entry states `bytes` instead of
`url` when a step already bound its content), `pack = { { as, channels = { r, g, b,
a } } }` gathers named maps' channels into one raster where a slot samples
several properties from one image (a channel is a constant 0-255, a file
name for its red, or `"file.g"` for a stated channel), and `bind = { slot =
name }` binds fetched and packed maps to the asset's slots. A map that
reaches no slot is named on the job row and in the log.
`retry` is `{ attempts?, delay? }` — how many times a call refused for a
reason that describes the moment (a rate limit, a busy gateway, a write
conflict) is sent again, and the first wait in seconds between attempts,
which doubles each time. Defaults to 4 attempts starting at 1 second. An
operation may declare its own `retry` to override the service's.

```lua
return Service.define({ offering = "origozero/mesh_gen", operations = { generate = { ... } } })
```

## modules/ServiceFramework/frameworkInputs {#modules-serviceframework-frameworkinputs}

```lua
frameworkInputs(self: any, operation: string?): { { [string]: any } }
```

The inputs a call on this service takes on top of what the operation
declares — `operation`, naming which of the service's operations to run,
and `asset_path`, naming where the run writes what it generates. Each row
is `{ name, type, required, desc, framework = true }`, the same shape a
declared input reads as. `operation` is required of a service that
declares no default; `asset_path` is offered by an operation that writes a
single file, and left out by one that authors a folder of them under a
name of its own. The `operation` row's text names the operation THIS
service runs when a call omits it, or the ones a call chooses between.

**Parameters**

- `self` `any` _(optional)_
- `operation` `string?` _(optional)_ — The operation these apply to. Omit for the service's default.

```lua
local extra = asset.resolve("audio_gen","service"):frameworkInputs("sfx")
```

## modules/ServiceFramework/info {#modules-serviceframework-info}

```lua
info(self: any): { [string]: any }
```

A one-line summary of this service for discovery: its offering, what it
produces, and the operations it offers.

**Parameters**

- `self` `any` _(optional)_

```lua
local i = asset.resolve("mesh_gen","service"):info()
```

## modules/ServiceFramework/invoke {#modules-serviceframework-invoke}

```lua
invoke(self: any, input: { [string]: any }?): { [string]: any }
```

Run a generation for this service. Picks the operation from
`input.operation` (or the service's primary / only operation), checks the
operation's declared cost against the caller's balance/budget up front —
raising with a legible reason if it can't be afforded — then runs the
pipeline as a background task. An input the operation does not declare is
refused here, before anything is charged. Returns immediately with a
generation handle. Watch the task — the `services` toolbox `status` tool
(or the `watch` tool) — until `status == "completed"`, then the finished
asset is that row's `asset`. The engine auto-imports the raw output into
a spawnable asset (a mesh becomes a `.bundle`, an image a `.texture`, a
sound a `.audio`); that imported asset — not the raw file — is what the
completed result points to, ready to spawn. Consumes credits; check
`:cost()` and `:balance()` first.

**Parameters**

- `self` `any` _(optional)_
- `input` `{ [string]: any }?` _(optional)_ — `{ prompt, ..., operation?, asset_path? }` — the operation's inputs.

```lua
local g = asset.resolve("mesh_gen","service"):invoke({ prompt = "a treasure chest" })
```

## modules/ServiceFramework/operations {#modules-serviceframework-operations}

```lua
operations(self: any): { { [string]: any } }
```

List this service's callable operations and their declared inputs,
output, and credit cost — the per-service surface an agent reads before
invoking. `framework` carries the inputs the call takes on top of what the
operation declares (`:frameworkInputs()`).

**Parameters**

- `self` `any` _(optional)_

```lua
for _, op in ipairs(asset.resolve("mesh_gen","service"):operations()) do print(op.name, op.cost) end
```

## modules/ServiceFramework/resume {#modules-serviceframework-resume}

```lua
resume(self: any, record: { [string]: any }): { [string]: any }
```

Pick a run of this service up where an earlier engine left it. The
record names the operation, its inputs, the step in flight, the bindings the
steps before it produced, and the provider or gateway job that step already
submitted; the run continues from there, waiting on that job rather than
paying for the same work again, and lands its asset the way an uninterrupted
run does. Runs on world load for every recorded run that did not finish.

**Parameters**

- `self` `any` _(optional)_
- `record` `{ [string]: any }` — A run record as `ServiceTask.durable` returns it.

```lua
asset.resolve("mesh_gen", "service"):resume(record)
```

## modules/ServiceFramework/resumeAll {#modules-serviceframework-resumeall}

```lua
resumeAll(): number
```

Pick up every recorded run that did not finish: the ones an earlier
engine submitted and did not live to collect. Runs when the world has
loaded. A run's service is waited for rather than assumed present, because
a service can be authored in the world and register a moment after the
library's own; each run resumes on its own task, so one that has to wait
holds up none of the others.

```lua
require("@builtin::assetTypes.service.shared").resumeAll()
```

## modules/ServiceRunAssetTypeRef/README {#modules-servicerunassettyperef-readme}

```lua
ServiceRunAssetTypeRef
```

Per-instance methods on every `AssetRef<serviceRun>` — one generation's durable record: what it was asked to make, the gateway job doing the work, and the state that job reached.

## modules/ServiceRunAssetTypeRef/finished {#modules-servicerunassettyperef-finished}

```lua
finished(self): boolean
```

Whether this run reached a terminal state. A run that is neither
completed nor failed was still working when it was last heard from.

**Parameters**

- `self` `any` _(optional)_

```lua
if not run:finished() then print("still out there") end
```

## modules/ServiceRunAssetTypeRef/jobId {#modules-servicerunassettyperef-jobid}

```lua
jobId(self): string?
```

The gateway job this run's work is running under. The job outlives the
engine that submitted it, so this is what reaches an already-paid result
when the run did not finish here.

**Parameters**

- `self` `any` _(optional)_

```lua
local id = asset.resolve("gen_4f2a_0", "serviceRun"):jobId()
```

## modules/ServiceRunAssetTypeRef/record {#modules-servicerunassettyperef-record}

```lua
record(self): { [string]: any }
```

This run's record: `{ id, service, operation, prompt, jobId, status,
progress, assetPath, error }`.

**Parameters**

- `self` `any` _(optional)_

```lua
local rec = asset.resolve("gen_4f2a_0", "serviceRun"):record()
```

## modules/ShaderAssetTypeRef/README {#modules-shaderassettyperef-readme}

```lua
ShaderAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<shader>`. Loaded lazily by `asset_ref.module`.

## modules/ShaderAssetTypeRef/compileByName {#modules-shaderassettyperef-compilebyname}

```lua
compileByName(ref: string)
```

Compile a shader by reference from its `.shader` VFS source — the lazy
compile-on-first-use entry. A material that references an as-yet-uncompiled
shader makes the renderer record the want; the engine calls this (via
`__zero_request_shader_compile`) to bring the shader online through the same
generic compile path an edit runs. Resolution goes through the
universal asset system — a reference that doesn't resolve is a bad reference
in the content that owns it, not something to special-case here.

**Parameters**

- `ref` `string` — A shader asset reference (identity / guid) resolvable by `asset.resolve`.

```lua
require("modules.asset_ref").loadTypeModule("shader").compileByName("@builtin::shaders.pbr")
```

## modules/ShaderAssetTypeRef/compileStatus {#modules-shaderassettyperef-compilestatus}

```lua
compileStatus(self): { status: string, error: string?, key: string? }
```

This shader's latest compile outcome — WITHOUT reading the engine log.
Returns `{ status, error?, key? }` where `status` is `"compiled"`
(registered clean under every key), `"failed"` (with `error` = the real
compiler message), or `"pending"` (not compiled yet / unknown). A shader
registers under each of its keys — identity AND guid — and a material may
look it up by either, so this checks them all and reports the WORST one
(`key` names it): a registration that landed under the identity but not
the guid reads as `"pending"` instead of hiding behind the healthy key.
Compilation is async — a write queues it — so a `"pending"` right after
editing means check again next frame. This is the authoritative "did my
shader compile?" signal: a write succeeding and `getProperties` returning
a schema do NOT mean the WGSL compiled.

**Parameters**

- `self` `any` _(optional)_

```lua
local s = shaderRef:compileStatus(); if s.status == "failed" then print(s.error) end
```

## modules/ShaderAssetTypeRef/compiledWgsl {#modules-shaderassettyperef-compiledwgsl}

```lua
compiledWgsl(self): string?
```

The WGSL the shader compiler received for this shader, exactly as it
received it. What `getWgsl` returns is the body as written; this is what
that body became — the generated group(1) material interface above it, the
domain's framework and entry points around it, every `#include` expanded
and every `#ifdef` resolved. A compile error's line numbers, and the handle
index naga prints where it has no name, are positions in THIS text, so a
`compileStatus()` of `"failed"` is read against it. It answers for a failed
compile as well as a clean one, and needs no material, entity or draw.

**Parameters**

- `self` `any` _(optional)_

```lua
local s = shaderRef:compileStatus()
if s.status == "failed" then print(s.error, shaderRef:compiledWgsl()) end
```

## modules/ShaderAssetTypeRef/getGlsl {#modules-shaderassettyperef-getglsl}

```lua
getGlsl(self): string?
```

Read the GLSL body, when present. Returns nil for WGSL-only
shaders.

**Parameters**

- `self` `any` _(optional)_

```lua
local glsl = shaderRef:getGlsl()
```

## modules/ShaderAssetTypeRef/getProperties {#modules-shaderassettyperef-getproperties}

```lua
getProperties(self): { { [string]: any } }
```

List this shader's declared material properties (parsed from
`properties.yaml`). Each entry is `{ name, type, default, min?, max? }`.
This is the editor-discovery surface — the SAME parse the compile uses.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, p in ipairs(shaderRef:getProperties()) do print(p.name, p.type) end
```

## modules/ShaderAssetTypeRef/getSourceCode {#modules-shaderassettyperef-getsourcecode}

```lua
getSourceCode(self): string?
```

Read the primary shader body (`shader.wgsl`) as raw text.

**Parameters**

- `self` `any` _(optional)_

```lua
local src = shaderRef:getSourceCode()
```

## modules/ShaderAssetTypeRef/getWgsl {#modules-shaderassettyperef-getwgsl}

```lua
getWgsl(self): string?
```

Read the WGSL body directly, ignoring the GLSL fallback. Use
when you need to detect "is this shader WGSL-native?" vs the
generic `getSourceCode` lookup that auto-falls-back.

**Parameters**

- `self` `any` _(optional)_

```lua
local wgsl = shaderRef:getWgsl()
```

## modules/ShaderAssetTypeRef/listBindings {#modules-shaderassettyperef-listbindings}

```lua
listBindings(self): { string }
```

List which top-level uniform / storage-buffer block names
appear in the shader source — best-effort regex parse. Useful to
cross-check against `material:getPropertyNames()` when debugging a
"property doesn't exist" gap. Not a full WGSL parser; complex
shaders with macros may report incomplete results.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, name in ipairs(shaderRef:listBindings()) do print(name) end
```

## modules/ShaderAssetTypeRef/listMaterialsUsing {#modules-shaderassettyperef-listmaterialsusing}

```lua
listMaterialsUsing(self): { string }
```

List the material identities currently bound to this shader,
by scanning the registered material catalogue. O(n) over the
material list; cache the result if you call it on a hot path.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, m in ipairs(shaderRef:listMaterialsUsing()) do print(m) end
```

## modules/ShaderAssetTypeRef/onChange {#modules-shaderassettyperef-onchange}

```lua
onChange(ref, change)
```

Asset-type change callback: (re)compile the shader whenever its WGSL body
or `properties.yaml` is written, and bring materials already bound to it onto
the declared property list when that list changed shape. This is the ONLY
thing that compiles a `.shader` — the implicit "WGSL written → recompile" path
is gone — so it fires on the initial create (the template write) AND on every
later edit, with no world reload. Convergent: see `compileShader`.

**Parameters**

- `ref` `any` _(optional)_
- `change` `any` _(optional)_

## modules/ShaderAssetTypeRef/schemaParseCount {#modules-shaderassettyperef-schemaparsecount}

```lua
schemaParseCount(): number
```

How many times a shader's `properties.yaml` has been parsed in this
session, across every shader and every surface that reads one — the
editor-discovery method, the compile, the alias registration and the alias
lookup. A read whose bytes match the parse already held answers from it and
leaves this unchanged, so the count rises once per distinct revision of a
file rather than once per read.

```lua
local m = require("modules.asset_ref").loadTypeModule("shader"); local before = m.schemaParseCount(); ref:getProperties(); print(m.schemaParseCount() - before)
```

## modules/ShaderAssetTypeRef/setWgsl {#modules-shaderassettyperef-setwgsl}

```lua
setWgsl(self, source: string): boolean
```

Overwrite the WGSL body on disk. Hot-reload picks the new
body up on the next frame so any material using this shader
recompiles. Returns true on success.

**Parameters**

- `self` `any` _(optional)_
- `source` `string` — New WGSL source.

```lua
shaderRef:setWgsl(myWgsl)
```

## modules/ShaderAssetTypeRef/shadingModel {#modules-shaderassettyperef-shadingmodel}

```lua
shadingModel(self): string
```

Which shading model this shader's body uses, and with it what the
engine can take the shader apart into.

`"engine-lit"` — the body exposes `fn surface(...) -> PbrSurface`. It hands
the engine a surface (albedo, roughness, metallic, emissive, normal,
occlusion) and the engine lights it, so the capture tool's PBR debug passes
read real material channels.

`"self-shading"` — the body exposes `fn fragment(...) -> vec4<f32>` and
returns the finished pixel. There is no separate albedo to read, so those
same passes render what the body returns.

`"unknown"` — no readable body, or one that exposes neither entry point.

The test is the literal one the compiler applies to the same source, so
this reports the model the shader was actually built as.

**Parameters**

- `self` `any` _(optional)_

```lua
if shaderRef:shadingModel() == "self-shading" then print("albedo pass shows final colour") end
```

## modules/ShaderModuleAssetTypeRef/README {#modules-shadermoduleassettyperef-readme}

```lua
ShaderModuleAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<shaderModule>`. Loaded lazily by `asset_ref.module`.

## modules/ShaderModuleAssetTypeRef/getSource {#modules-shadermoduleassettyperef-getsource}

```lua
getSource(self): string?
```

Read this module's WGSL (`module.wgsl`) as raw text.

**Parameters**

- `self` `any` _(optional)_

```lua
local src = moduleRef:getSource()
```

## modules/ShaderModuleAssetTypeRef/onRegister {#modules-shadermoduleassettyperef-onregister}

```lua
onRegister(self)
```

Initial-registration callback: file this module's WGSL under every name
it answers to the moment the instance first registers, so a shader that
`#include`s it resolves on its first compile rather than only after the
module has been written once this session. Idempotent — the guard below
skips a re-register of identical source.

**Parameters**

- `self` `any` _(optional)_

## modules/ShaderModuleAssetTypeRef/register {#modules-shadermoduleassettyperef-register}

```lua
register(self): string?
```

Read this module's WGSL through the VFS and file what it holds now under
every name it answers to, so a shader compiled next expands this text.
Files unconditionally: the registry answers whether the text moved, and
keeps the catalog generation still when the same bytes arrive again.

**Parameters**

- `self` `any` _(optional)_

```lua
local wgsl = moduleRef:register()
```

## modules/ShaderModuleAssetTypeRef/setSource {#modules-shadermoduleassettyperef-setsource}

```lua
setSource(self, src: string): boolean
```

Overwrite this module's WGSL. Every shader that includes it recompiles
on the next frame.

**Parameters**

- `self` `any` _(optional)_
- `src` `string` — New WGSL source.

```lua
moduleRef:setSource(myWgsl)
```

## modules/ShockwaveRingEffect/README {#modules-shockwaveringeffect-readme}

```lua
ShockwaveRingEffect
```

The definition behind `shockwaveRing.effect` — an annulus expanding across a surface from a point, thinning and fading as it runs out to the radius it was given.

## modules/SoundClipAssetTypeRef/README {#modules-soundclipassettyperef-readme}

```lua
SoundClipAssetTypeRef
```

Hooks for `.soundClip` assets. `onCreate` is the type's contribution to the generic `asset.create("soundClip", name, opts)` flow (mirroring `texture.assetType`). `onChange` keeps a managed container's `data.zaud` encoded payload in sync when its `source.<ext>` or `.metadata` settings are edited — the asset type reacting to writes inside its own instances (the type-level analogue of a component's `onAssetReload`). This hook owns every re-encode after the container exists.

## modules/SoundClipAssetTypeRef/loopSeam {#modules-soundclipassettyperef-loopseam}

```lua
loopSeam(self): (any?, string?)
```

Measure what this clip's samples do where a whole-clip loop wraps — the
reading that says whether the clip can be looped without a click. The
wrap's own step is reported against the step the signal ordinarily makes
between neighbouring samples, so the figure is in the units the signal
moves in and a quiet ambience reads the same way as a loud drone. A clip
whose partials wrap reads near 1; one carrying a strike at its head and
silence at its tail reads in the tens, and `seamless` is `ratio <=
threshold`. Taken on the decoded payload, so it answers for what the codec
left behind — including for a clip that arrived already encoded.

**Parameters**

- `self` `any` _(optional)_

```lua
local seam = clipRef:loopSeam(); if not seam.seamless then print(seam.ratio) end
```

## modules/SoundClipAssetTypeRef/onChange {#modules-soundclipassettyperef-onchange}

```lua
onChange(ref: any, change: { [string]: any })
```

React to a write inside a `.soundClip/` instance, keeping the encoded
`data.zaud` payload in sync. Editing `source.<ext>` re-encodes from the new
audio. Editing the `.metadata` `settings` block re-encodes from the
container's source: the managed `source.<ext>`, or — for a PCM-baked
container — the decoded `data.zaud` itself. `data.zaud` / `README.md`
writes are ignored. The dispatcher's same-asset guard suppresses the
re-dispatch of our own synchronous `data.zaud` write, so no loop forms.

**Parameters**

- `ref` `any` _(optional)_ — The AssetRef<soundClip> for the changed container.
- `change` `{ [string]: any }` — `{ path, asset, type, kind, origin }` — `path` is the written
file, `asset` the container folder, `kind` "edited"/"seeded", `origin`
"local"/"remote".

## modules/SoundClipAssetTypeRef/onCreate {#modules-soundclipassettyperef-oncreate}

```lua
onCreate(name: string, opts: CreateOpts): { [string]: string }
```

Generic-creation hook for `asset.create("soundClip", name, opts)`. Pure:
returns the content-file map; the caller (`asset.create`) writes it to the
authored destination (`/source/<name>.soundClip/`) and that write registers
the soundClip asset.

Two input shapes, mirroring how clips originate:
* PCM — `{ pcm, sampleRate, channels }`: generated / decoded interleaved
f32 samples, in any container `audio.encodePcm` reads — a `buffer`, a
binary string of little-endian f32, or a flat number array (no source
file). Encoded to the canonical `data.zaud` payload
(the engine's ZAUD format) via `audio.encodePcm`. `data.zaud` is the
primary the runtime decodes — so a generated clip becomes a persistent,
reload-stable asset addressed by guid.
* ENCODED AUDIO — `{ bytes, ext }`: OGG / MP3 / WAV / FLAC source bytes,
kept verbatim as `source.<ext>`, with `data.zaud` encoded from them
against the instance's settings.

**Parameters**

- `name` `string` — SoundClip identity (the instance name).
- `opts` `CreateOpts`

```lua
asset.create("soundClip", "beep", { pcm = buffer.create(960 * 4), sampleRate = 48000, channels = 1 })
asset.create("soundClip", "music", { bytes = oggBytes, ext = "ogg" })
```

## modules/SoundClipAssetTypeRef/pcm {#modules-soundclipassettyperef-pcm}

```lua
pcm(self): (string?, number?, number?)
```

Decode this soundClip asset's `data.zaud` payload into its samples, the
rate they play at, and the number of channels they interleave.

**Parameters**

- `self` `any` _(optional)_

```lua
local pcm, sr, ch = clipRef:pcm()
```

## modules/SoundClipAssetTypeRef/setSettings {#modules-soundclipassettyperef-setsettings}

```lua
setSettings(self, patch: { [string]: any })
```

Write a partial settings patch to this soundClip asset's `.metadata`.
Pass any subset of the settings schema; only those keys change, the rest
keep their stored value (`asset.set_field` deep-merges). Unknown keys error
loudly. Writing `.metadata` re-runs the type's `onChange`, which re-encodes
`data.zaud` against the new settings — so changing `bitrateKbps` recompresses
the clip.

**Parameters**

- `self` `any` _(optional)_
- `patch` `{ [string]: any }` — `{ codec: string?, bitrateKbps: number?, vbr: boolean?, sampleRate: number?, forceMono: boolean?, loadType: string?, loopStart: number?, loopEnd: number? }`

```lua
clipRef:setSettings({ bitrateKbps = 64, forceMono = true })
```

## modules/SoundClipAssetTypeRef/settings {#modules-soundclipassettyperef-settings}

```lua
settings(self): { [string]: any }
```

Read this soundClip asset's settings, with every schema default filled
in. The returned table always carries the full settings schema. The
settings say how the clip is encoded and where its loop points sit; what
its samples do where a whole-clip loop wraps is `clipRef:loopSeam()`.

**Parameters**

- `self` `any` _(optional)_

```lua
if clipRef:settings().forceMono then ... end
```

## modules/StyleAssetTypeRef/README {#modules-styleassettyperef-readme}

```lua
StyleAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<style>`. Loaded lazily by `asset_ref.module`.

## modules/StyleAssetTypeRef/getInitScript {#modules-styleassettyperef-getinitscript}

```lua
getInitScript(self): string?
```

Read the style's entry script as raw text.

**Parameters**

- `self` `any` _(optional)_

```lua
local src = styleRef:getInitScript()
```

## modules/StyleAssetTypeRef/getReadme {#modules-styleassettyperef-getreadme}

```lua
getReadme(self): string?
```

Read the style's README.

**Parameters**

- `self` `any` _(optional)_

```lua
print(styleRef:getReadme())
```

## modules/StyleAssetTypeRef/inspect {#modules-styleassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail: `{ tokenCategories }`, the
top-level keys of the style's own `M.tokens = { ... }` table literal,
parsed from the entry script's source text via
`luau_introspect.tableLiteralKeys` — never `require`s the style.
Cached on the asset's content checksum, so re-inspecting unchanged
source is free. A style with no readable entry script returns an
empty detail rather than erroring.

**Parameters**

- `self` `any` _(optional)_

```lua
local tokenCategories = asset.inspect(styleRef).detail.tokenCategories
```

## modules/StyleAssetTypeRef/loadTheme {#modules-styleassettyperef-loadtheme}

```lua
loadTheme(self): any
```

Load the style module and return its exported theme table.
Raises a Luau error tagged with the style identity if the require
fails.

**Parameters**

- `self` `any` _(optional)_

```lua
local theme = styleRef:loadTheme()
```

## modules/TestSuiteAssetTypeRef/README {#modules-testsuiteassettyperef-readme}

```lua
TestSuiteAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<testSuite>`. Loaded lazily by `asset_ref.module`. These methods act on the SPECIFIC asset instance the reference points to — `asset.resolve(id, "testSuite"):run()` runs only THAT suite. Running every suite is the `tests` toolbox's job (it iterates `asset.list("testSuite")` and calls `:run()` on each); it is deliberately not offered here.

## modules/TestSuiteAssetTypeRef/getReadme {#modules-testsuiteassettyperef-getreadme}

```lua
getReadme(self): string?
```

Read this suite's `README.md` body.

**Parameters**

- `self` `any` _(optional)_

```lua
print(suiteRef:getReadme())
```

## modules/TestSuiteAssetTypeRef/inspect {#modules-testsuiteassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail: `{ testCount, testNames }`,
parsed from `Test.it("<name>", ...)` calls in this suite's own
`init.luau` text. A string scan, not a suite run — inspecting a suite
never registers or executes its tests. A suite with no readable
`init.luau` returns an empty `testNames` list rather than erroring.

**Parameters**

- `self` `any` _(optional)_

```lua
local testNames = asset.inspect(suiteRef).detail.testNames
```

## modules/TestSuiteAssetTypeRef/run {#modules-testsuiteassettyperef-run}

```lua
run(self, opts: { quiet: boolean? }?): any
```

Run THIS test suite (only this one) and return its results. Refuses in
play mode — tests are an edit-mode / authoring concern, not gameplay. The
run is cooperative (the framework yields a frame between tests) so it never
blocks the engine or trips the execute watchdog.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ quiet: boolean? }?` _(optional)_ — Optional `{ quiet }`.

```lua
local r = asset.resolve("vfs", "testSuite"):run()
```

## modules/TestSuiteAssetTypeRef/tests {#modules-testsuiteassettyperef-tests}

```lua
tests(self): { { name: string, skip: boolean } }
```

List the tests this suite declares (loads THIS asset's `init.luau` to
read its registered `Test.it` / `Test.skip` names; does not run them).

**Parameters**

- `self` `any` _(optional)_

```lua
for _, t in ipairs(suiteRef:tests()) do print(t.name) end
```

## modules/TextureAssetTypeRef/README {#modules-textureassettyperef-readme}

```lua
TextureAssetTypeRef
```

Hooks for `.texture` assets. `onCreate` is the type's contribution to the generic `asset.create("texture", name, opts)` flow (mirroring `material.assetType`). `onChange` keeps a MANAGED container's `data.ztex` encoded payload in sync when its `source.<ext>` or `.metadata` settings are edited — the asset type reacting to writes inside its own instances (the type-level analogue of a component's `onAssetReload`). The loose-image → container PROMOTE step is the separate `texture.importer` (loose-write seam); this hook owns every re-encode AFTER the container exists.

## modules/TextureAssetTypeRef/handle {#modules-textureassettyperef-handle}

```lua
handle(self)
```

Put this texture asset on the GPU under its own guid and return its
`TextureHandle` at once. The asset's bytes are decoded off the frame and
the texture lands on the device when the decode finishes, a frame or more
later: a material naming the guid draws the shader's default for that
slot until then and rebinds when it arrives, and
`renderer.texture.isResident(guid)` reports the arrival. The handle is
cached on the interned ref's shared `runtime` table for as long as
something holds the one it handed out, so every consumer and material slot
naming the asset over that time gets the SAME handle back → ONE GPU entry.
Once the last of them lets go, the next call asks for the asset again and
is answered with a handle on the texture the device already holds under
that guid — which is also what a mode flip's runtime wipe leads to. The
material binds this handle's guid; it never creates the GPU texture itself.

CPU lifecycle: governed by the asset's SERIALIZABLE `keepCpu` setting in its
`.metadata` `settings` block (`asset.set_field(ref, "settings", { keepCpu =
true })`). By DEFAULT (unset) the decoded pixels are dropped right after
the GPU upload (the GPU handle holds no data → no double-memory cost);
with `keepCpu = true` the CPU store keeps them for later pixel reads /
edits.

**Parameters**

- `self` `any` _(optional)_

```lua
local h = texRef:handle() -- bind h.guid on a material; it draws once resident
```

## modules/TextureAssetTypeRef/load {#modules-textureassettyperef-load}

```lua
load(self)
```

Load this `.texture` asset's pixels into the guid-keyed CPU store and
return a CPU handle for per-pixel access (no GPU readback). The handle holds
no pixels — only the guid, dims, texel format, and the read/write/encode/
unload ops. The pixels stay at the precision they were authored with:
`handle.format` is `"rgba8"`, `"rgba16"` or `"rgba32f"`, and `:readPixel`
reports channels in that format's own units. Upload to the GPU with
`renderer.texture.create(handle)`; the DEFAULT is to `handle:unload()`
after. The handle's `:encode()` re-encodes the (possibly edited) pixels
into a fresh ZTEX blob for `asset.create("texture", …)`, at the same
format.

**Parameters**

- `self` `any` _(optional)_

```lua
local cpu = texRef:load(); local r,g,b,a = cpu:readPixel(3, 4); cpu:unload()
```

## modules/TextureAssetTypeRef/onChange {#modules-textureassettyperef-onchange}

```lua
onChange(ref: any, change: { [string]: any })
```

React to a write inside a `.texture/` instance, keeping the encoded
`data.ztex` payload in sync. Editing `source.<ext>` re-encodes from the
new image. Editing the `.metadata` `settings` block re-encodes from the
container's source: the managed `source.<ext>`, a plain container's
image primary, or — for a raw-pixel container — the decoded `data.ztex`
itself. Every pixel change also regenerates the container's
`preview.png`. `README.md` writes are ignored. The dispatcher's
same-asset guard suppresses the re-dispatch of our own synchronous
`data.ztex` write, so no loop forms.

**Parameters**

- `ref` `any` _(optional)_ — The AssetRef<texture> for the changed container.
- `change` `{ [string]: any }` — `{ path, asset, type, kind, origin }` — `path` is the written
file, `asset` the container folder, `kind` "edited"/"seeded", `origin`
"local"/"remote".

## modules/TextureAssetTypeRef/onCreate {#modules-textureassettyperef-oncreate}

```lua
onCreate(name: string, opts: CreateOpts): { [string]: string }
```

Generic-creation hook for `asset.create("texture", name, opts)`. Pure:
returns the content-file map; the caller (`asset.create`) writes it to the
authored destination (`/source/<name>.texture/`) and that write registers
the texture asset. Disk-only — nothing is uploaded to the GPU here.

Two input shapes, mirroring how textures originate:
* RAW PIXELS — `{ rgba, width, height, format? }`: a generated / decoded
pixel buffer (no source image). Encoded to the canonical `data.ztex`
payload (the engine's `ZTEX` format; `zero_texture::blob`) via
`__texture.encode`. `data.ztex` is the primary the renderer
uploads — so a generated texture becomes a persistent, reload-stable
asset addressed by guid, never an ephemeral GPU handle. `format` picks
the on-disk precision: 8 bits per channel by default, or `"rgba16"` /
`"rgba32f"` for a data raster (height / displacement field, baked
lightmap, imported elevation) whose values 8 bits would quantize.
* ENCODED IMAGE — `{ bytes, ext }`: PNG / JPEG / WebP / … source bytes,
stored verbatim as the `<name>.<ext>` primary (the renderer image-decodes
on upload; the same shape `asset.create` produced before).

**Parameters**

- `name` `string` — Texture identity (the instance name).
- `opts` `CreateOpts`

```lua
asset.create("texture", "skyGradient", { rgba = pixels, width = 256, height = 256 })
asset.create("texture", "terrain_height", { rgba = heights, width = 512, height = 512, format = "rgba16" })
asset.create("texture", "brick_albedo", { rgba = pixels, width = 256, height = 256, format = "bc7_srgb" })
asset.create("texture", "bricks", { bytes = imageBytes, ext = "jpg" })
```

## modules/TextureAssetTypeRef/preview {#modules-textureassettyperef-preview}

```lua
preview(self, opts: { [string]: any }?)
```

Render a preview of this texture as a flat swatch.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ [string]: any }?` _(optional)_ — `{ size? = { width, height } }`.

```lua
local p = texRef:preview()
```

## modules/TextureAssetTypeRef/setSettings {#modules-textureassettyperef-setsettings}

```lua
setSettings(self, patch: { [string]: any })
```

Write a partial settings patch to this texture asset's `.metadata`. Pass
any subset of the settings schema; only those keys change, the rest keep
their stored value (`asset.set_field` deep-merges). Unknown keys error
loudly. Writing `.metadata` re-runs the type's `onChange`, which re-encodes
`data.ztex` against the new settings — so changing `filter` recompiles the
texture and the renderer rebinds it with the new sampler.

**Parameters**

- `self` `any` _(optional)_
- `patch` `{ [string]: any }` — `{ format: string?, generateMipmaps: boolean?, maxDimension: number?, filter: string?, keepCpu: boolean? }`

```lua
texRef:setSettings({ filter = "nearest" })
```

## modules/TextureAssetTypeRef/settings {#modules-textureassettyperef-settings}

```lua
settings(self): { [string]: any }
```

Read this texture asset's settings, with every schema default filled in.
The returned table always carries the full settings schema.

**Parameters**

- `self` `any` _(optional)_

```lua
if texRef:settings().filter == "nearest" then ... end
```

## modules/TextureRef/README {#modules-textureref-readme}

```lua
TextureRef
```

The GPU key a material's texture slot binds by, resolved from whatever form the author wrote it in. Every path that accepts a texture reference — the `.material` assetType, `renderer.material.create`, `renderer.material.setTexture` — resolves through here, so the same string binds the same texture wherever it is written.

## modules/TextureRef/isProcedural {#modules-textureref-isprocedural}

```lua
isProcedural(ref: string): boolean
```

Whether a reference is one the GPU texture cache resolves on its own
(`color:` / `default:` / `runtime:`), so it must be passed through untouched
rather than looked up as an asset.

**Parameters**

- `ref` `string` — The reference string.

```lua
TextureRef.isProcedural("color:1,0,0,1") -- true
```

## modules/TextureRef/resolve {#modules-textureref-resolve}

```lua
resolve(ref: any, altIdentity: string?): (string, string)
```

Resolve a texture reference to the resident GPU key the renderer binds a
slot by, materialising the texture on the way. Accepts a guid, an asset
identity, a bare name, a `.texture` path, or the image path a texture was
imported from. `color:` / `default:` / `runtime:` forms and live GPU handles
(a video frame, a render target) pass through untouched.

**Parameters**

- `ref` `any` _(optional)_ — The authored reference.
- `altIdentity` `string?` _(optional)_ — Optional second candidate, tried when `ref` resolves to
nothing — a slot's stable identity, so a binding whose guid was orphaned by
a delete + recreate still finds the texture the author named.

```lua
TextureRef.resolve("wall.texture") -- "9f2c…", "asset"
```

## modules/TextureRef/unresolvedMessage {#modules-textureref-unresolvedmessage}

```lua
unresolvedMessage(ref: string, what: string): string
```

The message describing a reference that names no texture. Bound anyway,
the slot renders the shader's declared fallback, so the caller says this
rather than letting the material render as though nothing was asked for.

**Parameters**

- `ref` `string` — The unresolved reference.
- `what` `string` — The call being made, for the message's subject.

```lua
TextureRef.unresolvedMessage("sky.jpg", "renderer.material.setTexture")
```

## modules/ToolAssetTypeRef/README {#modules-toolassettyperef-readme}

```lua
ToolAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<tool>`. Loaded lazily by `asset_ref.module`.

## modules/ToolAssetTypeRef/getDefinition {#modules-toolassettyperef-getdefinition}

```lua
getDefinition(self): string?
```

Read the tool's definition — its `init.luau` source, which carries
the typed signature and the `--!desc`/`--!arg`/`--!return`/`--!example`
docstring that together form the tool's schema.

**Parameters**

- `self` `any` _(optional)_

```lua
local raw = toolRef:getDefinition()
```

## modules/ToolAssetTypeRef/getInitScript {#modules-toolassettyperef-getinitscript}

```lua
getInitScript(self): string?
```

Read the tool's entry script as raw text.

**Parameters**

- `self` `any` _(optional)_

```lua
local src = toolRef:getInitScript()
```

## modules/ToolAssetTypeRef/getReadme {#modules-toolassettyperef-getreadme}

```lua
getReadme(self): string?
```

Read the tool's README body.

**Parameters**

- `self` `any` _(optional)_

```lua
print(toolRef:getReadme())
```

## modules/ToolAssetTypeRef/inspect {#modules-toolassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail: `{ desc, args, returns,
examples, signature }`, parsed from the tool's own entry script
(`getInitScript`) via `luau_introspect.docstrings` — the same
`--!desc`/`--!arg`/`--!return`/`--!example` docstring that documents the
tool's schema. Cached on the asset's content checksum, so re-inspecting
unchanged source is free. A tool with no readable entry script returns
an empty detail rather than erroring.

**Parameters**

- `self` `any` _(optional)_

```lua
local args = asset.inspect(toolRef).detail.args
```

## modules/ToolAssetTypeRef/run {#modules-toolassettyperef-run}

```lua
run(self, args: any): any
```

Invoke the tool's entry script. Requires the tool's identity
and calls the first function it exports — the canonical
`function M.<name>(args)` shape every tool ships. `args` is
forwarded verbatim. Raises a Luau error (tagged with the tool's
identity) on load or invocation failure rather than returning a
swallowed nil — failing loudly matches the rest of the engine's
tool dispatch surface.

**Parameters**

- `self` `any` _(optional)_
- `args` `any` _(optional)_ — Optional table of arguments to pass to the tool's entry.

```lua
toolRef:run({ subject = "world" })
```

## modules/ToolAssetTypeRef/wrap {#modules-toolassettyperef-wrap}

```lua
wrap(fn: (...any) -> ...any, regionName: string): (...any) -> ...any
```

Standardize a single tool function into a ZmToolResult-returning call.
THIS is where the tool-result contract lives — the engine's tool-bind
paths (boot + runtime) apply `wrap` to every tool function so the result
type is a system guarantee, never the individual tool's choice. The tool
body returns its raw value, returns the Lua failure convention
`(nil, reason)`, or raises with `error(msg)`; `wrap` produces the
canonical envelope `{ ok, value | error, durationMs, tool }` from all
three — a `(nil, reason)` return becomes `{ ok = false, error = reason }`
instead of silently dropping the reason and reporting a bare success
with no value. Timing is measured with the engine profiler: a region
named for the tool is opened when the call is invoked and closed when it
returns, so each invocation is both timed (region elapsed ->
`durationMs`) and visible as a profiler region. Each envelope is also
reported into the running task's tool-result buffer, which execute()
auto-surfaces as the response's `toolResults`.

A tool that states MORE than one value on success — a path AND what that
path holds — keeps them: the envelope carries the first as `value`, and
every value past it follows the envelope out, so `local a, b, c =
tools.use(...)` reads the tool the way the tool's own signature declares
it. Keeping only the first turns every such declaration into a promise
nobody can read.

**Parameters**

- `fn` `(...any) -> ...any`
- `regionName` `string`

**Returns** `...any`

## modules/ToolAssetTypeRef/wrapToolbox {#modules-toolassettyperef-wraptoolbox}

```lua
wrapToolbox(box: { [string]: any }, namespace: string): { [string]: any }
```

Wrap every function on a toolbox table so each tool call returns a
ZmToolResult (see `wrap`). Non-function fields pass through untouched.

**Parameters**

- `box` `{ [string]: any }`
- `namespace` `string`

## modules/ToolboxAssetTypeRef/README {#modules-toolboxassettyperef-readme}

```lua
ToolboxAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<toolbox>`. Loaded lazily by `asset_ref.module`.

## modules/ToolboxAssetTypeRef/getReadme {#modules-toolboxassettyperef-getreadme}

```lua
getReadme(self): string?
```

Read the toolbox's `README.md` body.

**Parameters**

- `self` `any` _(optional)_

```lua
print(toolboxRef:getReadme())
```

## modules/ToolboxAssetTypeRef/hasShared {#modules-toolboxassettyperef-hasshared}

```lua
hasShared(self): boolean
```

Check whether the toolbox ships a `shared.module/`.

**Parameters**

- `self` `any` _(optional)_

```lua
if toolboxRef:hasShared() then ... end
```

## modules/ToolboxAssetTypeRef/inspect {#modules-toolboxassettyperef-inspect}

```lua
inspect(self): any
```

`asset.inspect` type-specific detail: `{ tools }`, where `tools` is
`{ name, desc }` for every `*.tool/` child the toolbox owns, walked
directly from the toolbox's own folder — `desc` is the child tool's
own `--!desc` docstring line, read from its entry script without
requiring the tool module. A toolbox with no readable folder returns
an empty `tools` list rather than erroring.

**Parameters**

- `self` `any` _(optional)_

```lua
local boxTools = asset.inspect(toolboxRef).detail.tools
```

## modules/ToolboxAssetTypeRef/listTools {#modules-toolboxassettyperef-listtools}

```lua
listTools(self): { any }
```

List the tool refs the toolbox carries. Walks the toolbox
folder, finds every `*.tool/` child, and resolves each to an
`AssetRef<tool>`.

**Parameters**

- `self` `any` _(optional)_

```lua
for _, t in ipairs(toolboxRef:listTools()) do print(t.identity) end
```

## modules/TracerEffect/README {#modules-tracereffect-readme}

```lua
TracerEffect
```

The definition behind `tracer.effect` — a hot head running a span at a muzzle velocity, with a tail drawn out behind it.

## modules/Trails/README {#modules-trails-readme}

```lua
require("@builtin/systems/trails.package/trails") -- Trails
```

Continuous ribbon geometry that follows a moving point.

A trail is a strip of quads threaded along the positions something
occupied over the last few seconds. Each recorded point contributes two
vertices, offset either side of the direction of travel, and consecutive
points are joined into a continuous surface — so a spark, a wingtip
vapour trail or a sword arc is one mesh rather than a queue of sprites
that betrays its spacing when the subject moves fast.
Width, colour and opacity run from the head (the newest point) to the tail
(the oldest), indexed by each point's age rather than its position in the
list, so the fade reads the same whether the subject is crawling or
sprinting.
`ribbon` is pure: the same points, camera and settings produce the same
arrays, so a trail's geometry can be checked without a scene.

Usage: local Trails = require("@builtin/systems/trails.package/trails")

## modules/Trails/expire {#modules-trails-expire}

```lua
expire(path: table, now: number) -> number
```

Drop points older than `lifetime`. Returns how many went.

**Parameters**

- `path` `table`
- `now` `number`

**Returns** `number`

## modules/Trails/newPath {#modules-trails-newpath}

```lua
newPath(opts: table?) -> table
```

A fresh path. `lifetime` seconds a point survives, `minDistance` metres before a new one is recorded, `maxPoints` the ring's bound.

**Parameters**

- `opts` `table?` _(optional)_

**Returns** `table`

## modules/Trails/pathOf {#modules-trails-pathof}

```lua
pathOf(id: string) -> table?
```

**Parameters**

- `id` `string`

**Returns** `table?`

## modules/Trails/push {#modules-trails-push}

```lua
push(path: table, x: number, y: number, z: number, now: number) -> boolean
```

Record the head position when it has travelled `minDistance` from the last point. Returns whether a point was recorded.

**Parameters**

- `path` `table`
- `x` `number`
- `y` `number`
- `z` `number`
- `now` `number`

**Returns** `boolean`

## modules/Trails/register {#modules-trails-register}

```lua
register(id: string, path: table)
```

**Parameters**

- `id` `string`
- `path` `table`

## modules/Trails/ribbon {#modules-trails-ribbon}

```lua
ribbon(path: table, opts: table) -> table?
```

Build the ribbon over a path's points — flat `positions` / `normals` / `uvs` / `colors` / `indices`, the shape `renderer.mesh.create` takes. `nil` under two points, which is no surface.

**Parameters**

- `path` `table`
- `opts` `table`

**Returns** `table?`

## modules/Trails/stats {#modules-trails-stats}

```lua
stats() -> table
```

**Returns** `table`

## modules/Trails/unregister {#modules-trails-unregister}

```lua
unregister(id: string)
```

**Parameters**

- `id` `string`

## modules/Transform/README {#modules-transform-readme}

```lua
Transform (global)
```

Math helpers for positions, rotations, and directions on transforms. Exposed as the global `Transform` table; entity-aware helpers accept an id string or an entity proxy.
Also available as global: Transform

## modules/Transform/direction {#modules-transform-direction}

```lua
direction(fromX: number, fromY: number, fromZ: number, toX: number, toY: number, toZ: number): (number, number, number)
```

Normalized direction vector from point A to point B. Returns
zeros when the two points coincide (within ~0.001 units).

**Parameters**

- `fromX` `number` — From x.
- `fromY` `number` — From y.
- `fromZ` `number` — From z.
- `toX` `number` — To x.
- `toY` `number` — To y.
- `toZ` `number` — To z.

```lua
local dx, dy, dz = Transform.direction(0, 0, 0, 1, 0, 0)
```

## modules/Transform/directionBetween {#modules-transform-directionbetween}

```lua
directionBetween(entityA: string | EntityRef, entityB: string | EntityRef): (number, number, number)
```

Normalized world-space direction from one entity to another, read
from their world positions. Returns zeros if either entity can't be
resolved.

**Parameters**

- `entityA` `string | EntityRef` — Source entity (id string or proxy).
- `entityB` `string | EntityRef` — Target entity (id string or proxy).

```lua
local dx, dy, dz = Transform.directionBetween("cam", "target")
```

## modules/Transform/distance {#modules-transform-distance}

```lua
distance(x1: number, y1: number, z1: number, x2: number, y2: number, z2: number): number
```

Euclidean distance between two world-space positions.

**Parameters**

- `x1` `number` — First point x.
- `y1` `number` — First point y.
- `z1` `number` — First point z.
- `x2` `number` — Second point x.
- `y2` `number` — Second point y.
- `z2` `number` — Second point z.

```lua
local d = Transform.distance(0, 0, 0, 1, 1, 1)
```

## modules/Transform/distanceBetween {#modules-transform-distancebetween}

```lua
distanceBetween(entityA: string | EntityRef, entityB: string | EntityRef): number?
```

Distance between two entities in world space. Each entity's world
position is what is measured, so a parent's offset counts toward the
distance the way the scene shows it.

**Parameters**

- `entityA` `string | EntityRef` — First entity (id string or proxy).
- `entityB` `string | EntityRef` — Second entity (id string or proxy).

```lua
local d = Transform.distanceBetween("cam", "box")
```

## modules/Transform/euler {#modules-transform-euler}

```lua
euler(qx: number, qy: number, qz: number, qw: number): (number, number, number)
```

Convert quaternion to euler angles (yaw, pitch, roll) in radians.

**Parameters**

- `qx` `number` — Quaternion x.
- `qy` `number` — Quaternion y.
- `qz` `number` — Quaternion z.
- `qw` `number` — Quaternion w.

```lua
local yaw, pitch, roll = Transform.euler(0, 0, 0, 1)
```

## modules/Transform/eulerToQuat {#modules-transform-eulertoquat}

```lua
eulerToQuat(yaw: number, pitch: number?, roll: number?): (number, number, number, number)
```

Identity-aware overload of euler-to-quaternion. Uses the negative-yaw
convention shared with `quatFromYaw`, `quatFromYawPitch`, `lookAtQuat`, and
`T.euler` extraction — so `T.euler(T.eulerToQuat(y, p, r))` returns
`(y, p, r)`. Order is yaw (Y) then pitch (X) then roll (Z).

**Parameters**

- `yaw` `number` — Y-axis rotation in radians.
- `pitch` `number?` _(optional)_ — X-axis rotation in radians. Defaults to 0.
- `roll` `number?` _(optional)_ — Z-axis rotation in radians. Defaults to 0.

```lua
local qx, qy, qz, qw = Transform.eulerToQuat(math.pi / 2)
```

## modules/Transform/lerp {#modules-transform-lerp}

```lua
lerp(ax: number, ay: number, az: number, bx: number, by: number, bz: number, t: number): (number, number, number)
```

Linearly interpolate between two positions.

**Parameters**

- `ax` `number` — Start x.
- `ay` `number` — Start y.
- `az` `number` — Start z.
- `bx` `number` — End x.
- `by` `number` — End y.
- `bz` `number` — End z.
- `t` `number` — Interpolation factor `[0, 1]`.

```lua
local x, y, z = Transform.lerp(0, 0, 0, 1, 1, 1, 0.5)
```

## modules/Transform/lerp1 {#modules-transform-lerp1}

```lua
lerp1(a: number, b: number, t: number): number
```

Linearly interpolate two scalars.

**Parameters**

- `a` `number` — Start value.
- `b` `number` — End value.
- `t` `number` — Interpolation factor `[0, 1]`.

```lua
local v = Transform.lerp1(0, 10, 0.5)
```

## modules/Transform/lerpAngle {#modules-transform-lerpangle}

```lua
lerpAngle(a: number, b: number, t: number): number
```

Lerp between two angles via the shortest arc; returns a value in `[-pi, pi]`.

**Parameters**

- `a` `number` — Start angle in radians.
- `b` `number` — End angle in radians.
- `t` `number` — Interpolation factor `[0, 1]`.

```lua
local a = Transform.lerpAngle(0, math.pi, 0.5)
```

## modules/Transform/localToWorld {#modules-transform-localtoworld}

```lua
localToWorld(px: number, py: number, pz: number, pqx: number, pqy: number, pqz: number, pqw: number, lx: number, ly: number, lz: number): (number, number, number)
```

Transform a local-space position into world space using a parent pose.

**Parameters**

- `px` `number` — Parent position x.
- `py` `number` — Parent position y.
- `pz` `number` — Parent position z.
- `pqx` `number` — Parent rotation x.
- `pqy` `number` — Parent rotation y.
- `pqz` `number` — Parent rotation z.
- `pqw` `number` — Parent rotation w.
- `lx` `number` — Local x.
- `ly` `number` — Local y.
- `lz` `number` — Local z.

```lua
local wx, wy, wz = Transform.localToWorld(px, py, pz, pqx, pqy, pqz, pqw, lx, ly, lz)
```

## modules/Transform/lookAt {#modules-transform-lookat}

```lua
lookAt(entityOrId: string | EntityRef, txOrTarget: any, ty: any?, tz: number?, up: any?): (boolean, string?)
```

Make an entity face a world position. The target slot accepts three
explicit coordinates, one point as `{ x, y, z }` / `{ x =, y =, z = }` / a
vector, or an entity — an id string, an entity NAME, or a proxy — whose
WORLD position is resolved. A table carrying an entity id reads as that
entity; any other table reads as the point it spells. The subject slot
takes the three entity spellings.
Everything here is world space: the subject and the target are
read as `entity(id).position` and the aim is written as
`entity(id).rotation`, so a parent under either one moves the entity and
the aim still lands on the point named.
Returns whether the rotation was written, so a caller that named an entity
the scene does not carry learns the aim did not happen instead of reading
a stale orientation back as the answer.

**Parameters**

- `entityOrId` `string | EntityRef` — Entity id, name, or proxy for the entity to rotate.
- `txOrTarget` `any` _(optional)_ — A number (world x), a point table, or an entity id / name /
proxy whose world position is resolved as the look-at target.
- `ty` `any?` _(optional)_ — World y of the target. Omitted when `txOrTarget` is a point or an entity.
- `tz` `number?` _(optional)_ — World z of the target. Omitted when `txOrTarget` is a point or an entity.
- `up` `any?` _(optional)_ — Optional world up hint deciding the roll — `{ x, y, z }`,
`{ x =, y =, z = }` or a vector. World +Y when omitted. It never bends the
aim; it only says which way is up around it. When the target slot is an
entity or a point this is the third argument, and when it is coordinates
the fifth.

```lua
Transform.lookAt("cam", 0, 1, 0)
Transform.lookAt("cam", "box")  -- resolve target entity position
Transform.lookAt(cam, box)      -- entity proxies for both
Transform.lookAt("cam", { 0, 1, 0 })         -- one point table
Transform.lookAt("cam", "box", { 0, 0, 1 })  -- rolled to a +Z up
```

## modules/Transform/lookAtQuat {#modules-transform-lookatquat}

```lua
lookAtQuat(fx: number, fy: number, fz: number, tx: number, ty: number, tz: number): (number?, number?, number?, number?)
```

Compute quaternion to look from origin position toward a target.
Returns four components `(qx, qy, qz, qw)`, or `nil` when the from
and to points are too close to derive a meaningful direction.

**Parameters**

- `fx` `number` — Origin x.
- `fy` `number` — Origin y.
- `fz` `number` — Origin z.
- `tx` `number` — Target x.
- `ty` `number` — Target y.
- `tz` `number` — Target z.

```lua
local qx, qy, qz, qw = Transform.lookAtQuat(0, 0, 0, 1, 0, 1)
```

## modules/Transform/lookRotation {#modules-transform-lookrotation}

```lua
lookRotation(fx: number, fy: number, fz: number, tx: number, ty: number, tz: number, ux: number?, uy: number?, uz: number?): (number?, number?, number?, number?)
```

The rotation that aims an entity standing at one world point at another,
with a world up hint deciding the roll. Where `lookAtQuat` derives the aim
from yaw and pitch alone — clamping the pitch just short of vertical, so a
point directly overhead comes back a twentieth of a degree off — this builds
all three axes, so the aim lands on the point at any elevation and straight
up and straight down are ordinary cases.
The aimed axis is the entity's local -Z, the same forward `quatFromBasis`,
`Transform.lookAt` and `entity(id):lookAt` state and the direction
`entity(id).transform.forward` reads back.
The up hint is a world direction the entity's own +Y is turned toward as
far as the aim allows; it never bends the forward axis. A hint parallel to
the aim leaves the roll undetermined, and a hint of no length names no
direction — both fall back to a stable roll rather than a NaN.

**Parameters**

- `fx` `number` — Eye x — where the entity stands.
- `fy` `number` — Eye y.
- `fz` `number` — Eye z.
- `tx` `number` — Target x — the world point it faces.
- `ty` `number` — Target y.
- `tz` `number` — Target z.
- `ux` `number?` _(optional)_ — Up hint x. World +Y when the hint is omitted.
- `uy` `number?` _(optional)_ — Up hint y.
- `uz` `number?` _(optional)_ — Up hint z.

```lua
local qx, qy, qz, qw = Transform.lookRotation(0, 2, 10, 0, 1, 0)
entity("cam").rotation = { Transform.lookRotation(0, 2, 10, 0, 1, 0) }
-- a dutch tilt: the same aim, rolled by leaning the up hint
local q = { Transform.lookRotation(0, 2, 10, 0, 1, 0, 0.2, 1, 0) }
```

## modules/Transform/normalizeAngle {#modules-transform-normalizeangle}

```lua
normalizeAngle(a: number): number
```

Normalize an angle into `[-pi, pi]`.

**Parameters**

- `a` `number` — The angle in radians.

```lua
local a = Transform.normalizeAngle(3 * math.pi)
```

## modules/Transform/orbit {#modules-transform-orbit}

```lua
orbit(centerX: number, centerY: number, centerZ: number, radius: number, height: number, angle: number): (number, number, number, number, number, number, number)
```

Position + rotation for orbiting around a center point. Returns
the world position followed by the orientation that faces the center.

**Parameters**

- `centerX` `number` — Center x.
- `centerY` `number` — Center y.
- `centerZ` `number` — Center z.
- `radius` `number` — Horizontal distance from the center.
- `height` `number` — Vertical offset from `centerY`.
- `angle` `number` — Orbital angle in radians.

```lua
local x, y, z, qx, qy, qz, qw = Transform.orbit(0, 1, 0, 5, 2, t)
```

## modules/Transform/quatFromAxisAngle {#modules-transform-quatfromaxisangle}

```lua
quatFromAxisAngle(ax: number, ay: number, az: number, angle: number): (number, number, number, number)
```

Create quaternion from axis and angle (radians). Returns the
identity quaternion when the axis is degenerate (length < 0.001).

**Parameters**

- `ax` `number` — Axis x.
- `ay` `number` — Axis y.
- `az` `number` — Axis z.
- `angle` `number` — Rotation angle in radians.

```lua
local qx, qy, qz, qw = Transform.quatFromAxisAngle(0, 1, 0, math.pi)
```

## modules/Transform/quatFromBasis {#modules-transform-quatfrombasis}

```lua
quatFromBasis(rx: number, ry: number, rz: number, ux: number, uy: number, uz: number, fx: number, fy: number, fz: number): (number, number, number, number)
```

Build the rotation whose right, up and forward ARE the given axes. Where
`lookAtQuat` derives a rotation from a direction alone — yaw and pitch, with
pitch clamped just short of straight up or down and no say in the roll — this
states all three axes, so a view straight down has a defined image-up instead
of whatever the yaw implied. The axes are expected orthonormal and are used as
given: `right` and `up` are the entity's local +X and +Y, `forward` its local
-Z (the direction it faces).

**Parameters**

- `rx` `number` — Right axis x.
- `ry` `number` — Right axis y.
- `rz` `number` — Right axis z.
- `ux` `number` — Up axis x.
- `uy` `number` — Up axis y.
- `uz` `number` — Up axis z.
- `fx` `number` — Forward axis x.
- `fy` `number` — Forward axis y.
- `fz` `number` — Forward axis z.

```lua
local qx, qy, qz, qw = Transform.quatFromBasis(1,0,0, 0,1,0, 0,0,-1) -- identity
-- looking straight down with the subject's front toward the top of frame
local qx, qy, qz, qw = Transform.quatFromBasis(1,0,0, 0,0,-1, 0,-1,0)
```

## modules/Transform/quatFromYaw {#modules-transform-quatfromyaw}

```lua
quatFromYaw(yaw: number): (number, number, number, number)
```

Create quaternion from yaw (Y-axis rotation) in radians. Uses the
negative-yaw convention shared with `quatFromYawPitch`, `lookAtQuat`,
and `T.euler` extraction — so `T.euler(T.quatFromYaw(y))` round-trips
to `y`.

**Parameters**

- `yaw` `number` — Rotation in radians around the Y axis.

```lua
local qx, qy, qz, qw = Transform.quatFromYaw(math.pi / 2)
```

## modules/Transform/quatFromYawPitch {#modules-transform-quatfromyawpitch}

```lua
quatFromYawPitch(yaw: number, pitch: number): (number, number, number, number)
```

Create quaternion from yaw and pitch in radians.

**Parameters**

- `yaw` `number` — Y-axis rotation in radians.
- `pitch` `number` — X-axis rotation in radians.

```lua
local qx, qy, qz, qw = Transform.quatFromYawPitch(0, math.pi / 4)
```

## modules/Transform/quatIdentity {#modules-transform-quatidentity}

```lua
quatIdentity(): (number, number, number, number)
```

Identity quaternion (`0, 0, 0, 1`).

```lua
local qx, qy, qz, qw = Transform.quatIdentity()
```

## modules/Transform/quatInverse {#modules-transform-quatinverse}

```lua
quatInverse(qx: number, qy: number, qz: number, qw: number): (number, number, number, number)
```

Quaternion inverse. Equal to the conjugate for unit quaternions.

**Parameters**

- `qx` `number` — Quaternion x.
- `qy` `number` — Quaternion y.
- `qz` `number` — Quaternion z.
- `qw` `number` — Quaternion w.

```lua
local ix, iy, iz, iw = Transform.quatInverse(qx, qy, qz, qw)
```

## modules/Transform/quatMul {#modules-transform-quatmul}

```lua
quatMul(ax: number, ay: number, az: number, aw: number, bx: number, by: number, bz: number, bw: number): (number, number, number, number)
```

Quaternion multiplication: returns `qa * qb` (composition: rotate
by `qb` then `qa`).

**Parameters**

- `ax` `number` — Left quat x.
- `ay` `number` — Left quat y.
- `az` `number` — Left quat z.
- `aw` `number` — Left quat w.
- `bx` `number` — Right quat x.
- `by` `number` — Right quat y.
- `bz` `number` — Right quat z.
- `bw` `number` — Right quat w.

```lua
local qx, qy, qz, qw = Transform.quatMul(ax, ay, az, aw, bx, by, bz, bw)
```

## modules/Transform/quatRotateVec {#modules-transform-quatrotatevec}

```lua
quatRotateVec(qx: number, qy: number, qz: number, qw: number, vx: number, vy: number, vz: number): (number, number, number)
```

Rotate a 3-vector by a quaternion.

**Parameters**

- `qx` `number` — Quaternion x.
- `qy` `number` — Quaternion y.
- `qz` `number` — Quaternion z.
- `qw` `number` — Quaternion w.
- `vx` `number` — Vector x.
- `vy` `number` — Vector y.
- `vz` `number` — Vector z.

```lua
local rx, ry, rz = Transform.quatRotateVec(qx, qy, qz, qw, 1, 0, 0)
```

## modules/Transform/quatToEuler {#modules-transform-quattoeuler}

```lua
quatToEuler(qx: number, qy: number, qz: number, qw: number): (number, number, number)
```

Convert quaternion to `(yaw, pitch, roll)`. Alias of `euler` with
the explicit name so callers don't have to remember the order.

**Parameters**

- `qx` `number` — Quaternion x.
- `qy` `number` — Quaternion y.
- `qz` `number` — Quaternion z.
- `qw` `number` — Quaternion w.

```lua
local yaw, pitch, roll = Transform.quatToEuler(qx, qy, qz, qw)
```

## modules/Transform/readVec3 {#modules-transform-readvec3}

```lua
readVec3(value: Vec3Input, label: string?): { number }
```

Normalize a vector a caller wrote to a plain `{ x, y, z }` array.
Accepts a positional array `{1, 2, 3}`, a keyed table
`{x =, y =, z =}`, or a live vec handle. Missing components read as 0.
Raises when the value is not a vector; `label` names the caller in
that error.

**Parameters**

- `value` `Vec3Input` — The vector to normalize.
- `label` `string?` _(optional)_ — Name reported in the error when the value is not a vector. Defaults to "Transform".

```lua
local v = Transform.readVec3({ x = 1, y = 2, z = 3 })
```

## modules/Transform/slerp {#modules-transform-slerp}

```lua
slerp(ax: number, ay: number, az: number, aw: number, bx: number, by: number, bz: number, bw: number, t: number): (number, number, number, number)
```

Spherical linear interpolation between two quaternions. Picks
the shortest path (flips sign if dot < 0). Falls back to
lerp+normalize when the two quats are very close (avoids
div-by-zero on near-parallel inputs).

**Parameters**

- `ax` `number` — Start quaternion x.
- `ay` `number` — Start quaternion y.
- `az` `number` — Start quaternion z.
- `aw` `number` — Start quaternion w.
- `bx` `number` — End quaternion x.
- `by` `number` — End quaternion y.
- `bz` `number` — End quaternion z.
- `bw` `number` — End quaternion w.
- `t` `number` — Interpolation factor `[0, 1]`.

```lua
local qx, qy, qz, qw = Transform.slerp(0, 0, 0, 1, 1, 0, 0, 0, 0.5)
```

## modules/Transform/snapVec3 {#modules-transform-snapvec3}

```lua
snapVec3(v: { number }, step: number | Vec3Input): { number }
```

Quantize each component of a vector to the nearest multiple of
`step` — a number for uniform steps, or a vector for per-axis steps.
A step of 0 on an axis leaves that axis at its exact value.

**Parameters**

- `v` `{ number }` — The vector to quantize, as `{ x, y, z }`.
- `step` `number | Vec3Input` — Uniform step size, or a per-axis vector of step sizes.

```lua
local v = Transform.snapVec3({ 1.4, 2.6, -0.4 }, 1)
```

## modules/Transform/toQuaternion {#modules-transform-toquaternion}

```lua
toQuaternion(rotation: any, label: string?): { number }
```

Normalize a rotation a caller wrote to a `{ qx, qy, qz, qw }`
quaternion. Accepts a quaternion (`{x,y,z,w}` or `{x=,y=,z=,w=}`) or
euler DEGREES (`{pitch,yaw,roll}` or `{pitch=,yaw=,roll=}`), so one
call site takes whichever form the caller finds natural. This is the
reading every rotation-taking surface in the engine shares, so a
quaternion and euler degrees mean the same thing at all of them.
Raises when the value matches no form; `label` names the caller in that
error, and a value that is one of the shapes a quaternion helper returns
is named as such along with the packing it goes in as.

**Parameters**

- `rotation` `any` _(optional)_ — The rotation to normalize, in any form of the `RotationInput` union.
- `label` `string?` _(optional)_ — Name reported in the error when the value is not a rotation. Defaults to "Transform".

```lua
local q = Transform.toQuaternion({ pitch = 0, yaw = 90, roll = 0 })
```

## modules/Transform/tryQuaternion {#modules-transform-tryquaternion}

```lua
tryQuaternion(rotation: any, label: string?): ({ number }?, string?)
```

Read a rotation a caller wrote WITHOUT raising: returns the
canonical `{ qx, qy, qz, qw }`, or nil and the message describing what
arrived. The forms are the `RotationInput` union — a quaternion
(`{x,y,z,w}` or `{x=,y=,z=,w=}`) or euler DEGREES (`{pitch,yaw,roll}` or
`{pitch=,yaw=,roll=}`). Takes any value because reporting on a value that
is none of those forms is the whole job; a setter built on this raises the
returned message itself, so the error points at the line that wrote the
value rather than at the reading.

**Parameters**

- `rotation` `any` _(optional)_ — The value to read as a rotation.
- `label` `string?` _(optional)_ — Name reported in the message. Defaults to "Transform".

```lua
local q, why = Transform.tryQuaternion(value, "myTool")
```

## modules/Transform/vec.add {#add}

```lua
vec.add(ax: number, ay: number, az: number, bx: number, by: number, bz: number): (number, number, number)
```

Component-wise vec3 addition.

**Parameters**

- `ax` `number` — First vector x.
- `ay` `number` — First vector y.
- `az` `number` — First vector z.
- `bx` `number` — Second vector x.
- `by` `number` — Second vector y.
- `bz` `number` — Second vector z.

```lua
local x, y, z = Transform.vec.add(1, 2, 3, 4, 5, 6)
```

## modules/Transform/vec.cross {#cross}

```lua
vec.cross(ax: number, ay: number, az: number, bx: number, by: number, bz: number): (number, number, number)
```

Cross product `a x b`.

**Parameters**

- `ax` `number` — First vector x.
- `ay` `number` — First vector y.
- `az` `number` — First vector z.
- `bx` `number` — Second vector x.
- `by` `number` — Second vector y.
- `bz` `number` — Second vector z.

```lua
local cx, cy, cz = Transform.vec.cross(1, 0, 0, 0, 1, 0)
```

## modules/Transform/vec.dot {#dot}

```lua
vec.dot(ax: number, ay: number, az: number, bx: number, by: number, bz: number): number
```

Dot product of two vec3s.

**Parameters**

- `ax` `number` — First vector x.
- `ay` `number` — First vector y.
- `az` `number` — First vector z.
- `bx` `number` — Second vector x.
- `by` `number` — Second vector y.
- `bz` `number` — Second vector z.

```lua
local d = Transform.vec.dot(1, 0, 0, 0, 1, 0)
```

## modules/Transform/vec.length {#length}

```lua
vec.length(x: number, y: number, z: number): number
```

Euclidean length of a vec3.

**Parameters**

- `x` `number` — Vector x.
- `y` `number` — Vector y.
- `z` `number` — Vector z.

```lua
local len = Transform.vec.length(1, 2, 3)
```

## modules/Transform/vec.normalize {#normalize}

```lua
vec.normalize(x: number, y: number, z: number): (number, number, number)
```

Normalize a vec3. Returns zeros when the input is degenerate
(length < 1e-8).

**Parameters**

- `x` `number` — Vector x.
- `y` `number` — Vector y.
- `z` `number` — Vector z.

```lua
local nx, ny, nz = Transform.vec.normalize(0, 5, 0)
```

## modules/Transform/vec.scale {#scale}

```lua
vec.scale(x: number, y: number, z: number, s: number): (number, number, number)
```

Component-wise scalar multiplication of a vec3.

**Parameters**

- `x` `number` — Vector x.
- `y` `number` — Vector y.
- `z` `number` — Vector z.
- `s` `number` — Scalar factor.

```lua
local x, y, z = Transform.vec.scale(1, 2, 3, 2)
```

## modules/Transform/vec.sub {#sub}

```lua
vec.sub(ax: number, ay: number, az: number, bx: number, by: number, bz: number): (number, number, number)
```

Component-wise vec3 subtraction (`a - b`).

**Parameters**

- `ax` `number` — First vector x.
- `ay` `number` — First vector y.
- `az` `number` — First vector z.
- `bx` `number` — Second vector x.
- `by` `number` — Second vector y.
- `bz` `number` — Second vector z.

```lua
local x, y, z = Transform.vec.sub(4, 5, 6, 1, 2, 3)
```

## modules/Transform/worldToLocal {#modules-transform-worldtolocal}

```lua
worldToLocal(px: number, py: number, pz: number, pqx: number, pqy: number, pqz: number, pqw: number, wx: number, wy: number, wz: number): (number, number, number)
```

Transform a world-space position into a parent's local space.

**Parameters**

- `px` `number` — Parent position x.
- `py` `number` — Parent position y.
- `pz` `number` — Parent position z.
- `pqx` `number` — Parent rotation x.
- `pqy` `number` — Parent rotation y.
- `pqz` `number` — Parent rotation z.
- `pqw` `number` — Parent rotation w.
- `wx` `number` — World x.
- `wy` `number` — World y.
- `wz` `number` — World z.

```lua
local lx, ly, lz = Transform.worldToLocal(px, py, pz, pqx, pqy, pqz, pqw, wx, wy, wz)
```

## modules/UiMotionCapture/README {#modules-uimotioncapture-readme}

```lua
UiMotionCapture
```

Publishes the UI-animation capture views — the UI analogues of the `motion_vectors` pass. `capture pass=ui_motion` shows WHERE the UI is animating (change-magnitude heatmap); `capture pass=ui_motion_flow` shows WHICH WAY it is moving (directional optical flow). Each view's drawing feature is created on demand the first time it is captured, so a session that never selects one pays nothing.

## modules/UiMotionCapture/register {#modules-uimotioncapture-register}

```lua
register()
```

Register the `ui_motion` (change magnitude) and `ui_motion_flow`
(directional flow) capture views. Idempotent — safe to call at boot and
again later; re-registering keeps each view's channel.

```lua
require("modules.ui_motion_capture").register()
```

## modules/Validator/README {#modules-validator-readme}

```lua
require("@builtin/systems/worldValidation.package/validator") -- Validator
```

Orchestrator for the world validator. Composes vfsScanner + scriptValidator + assetValidator + reportFormatter into one call that produces a Report with world and library buckets cleanly separated.

The validator does ONE pass over the VFS to discover every
script and asset, then dispatches each entry to the appropriate
per-type validator (scripts → scriptValidator → lsp.check; asset
folders → assetValidator → asset.validate). It does not spawn
entities or allocate GPU resources. Repeated calls are
independent — there is no shared mutable state across runs.
The four helper modules (vfsScanner, scriptValidator,
assetValidator, reportFormatter) sit alongside this module at
the package root and are pulled in via the `~.X` package-relative
form so the whole package is position-independent — moving it to
any identity continues to resolve correctly without code edits.

Usage: local Validator = require("@builtin/systems/worldValidation.package/validator")

## modules/Validator/check {#modules-validator-check}

```lua
check(opts)
```

Validate authored content. By DEFAULT scopes to YOUR world —
everything under `/source/` EXCEPT `/source/libs/` — because imported
libraries and engine builtins are not yours to validate (and scanning
the whole builtin tree is slow and noisy). Pass `opts.scope` to widen:
`"libraries"` for every imported library, `"library:<name>"` for one,
`"all"` for world + libraries together. The `cargo check` equivalent
for a Zero world.

**Parameters**

- `opts` `any` _(optional)_ — Optional table — `scope?: "world"|"libraries"|"library:<name>"|"all"`
(default `"world"`) plus filter fields forwarded to the formatter:
`{ severity, category, code, source, path, includePlaceholders, limit }`.

```lua
local r = WorldValidation.check()                         -- your world only
local r = WorldValidation.check({ severity = "error" })   -- your world, errors only
local r = WorldValidation.check({ scope = "all" })        -- world + imported libraries
```

## modules/Validator/filter {#modules-validator-filter}

```lua
filter(report, opts)
```

Re-filter an existing Report without re-scanning the VFS.
Forwards to `reportFormatter.filter`; the resulting Report's
`counts` are recomputed from the visible problems.

**Parameters**

- `report` `any` _(optional)_ — Report produced by any of the validate* functions.
- `opts` `any` _(optional)_ — FilterOpts — `{ severity, category, code, source, path, includePlaceholders, limit }`.

```lua
local errs = WorldValidation.filter(report, { severity = "error" })
```

## modules/Validator/format {#modules-validator-format}

```lua
format(report, format)
```

Render a Report into a string. `format` selects the renderer.

**Parameters**

- `report` `any` _(optional)_ — Report produced by any of the validate* functions.
- `format` `any` _(optional)_ — `"human"` (default) / `"markdown"` / `"json"` / `"summary"`.

```lua
print(WorldValidation.format(report, "human"))
local md = WorldValidation.format(report, "markdown")
```

## modules/Validator/placeholders {#modules-validator-placeholders}

```lua
placeholders()
```

Enumerate the registered placeholder checks. Each placeholder
is a check the validator runs today but with a stub implementation
— listing them tells callers which validations still need real
primitives wired up.

```lua
for _, ph in ipairs(WorldValidation.placeholders()) do print(ph.code) end
```

## modules/Validator/saveReport {#modules-validator-savereport}

```lua
saveReport(report, path, opts)
```

Render a Report and write it to `path`. Format is taken from
`opts.format` if present, otherwise inferred from the destination
extension (`.md` → markdown, `.json` → json, anything else → human).
Returns `(ok, message?)`.

**Parameters**

- `report` `any` _(optional)_ — Report produced by any of the validate* functions.
- `path` `any` _(optional)_ — Destination VFS path (e.g. `/source/.validation/run.md`).
- `opts` `any` _(optional)_ — Optional `{ format }` override.

```lua
WorldValidation.saveReport(report, "/source/.validation/run.md")
WorldValidation.saveReport(report, "/source/audit.json", { format = "json" })
```

## modules/Validator/summary {#modules-validator-summary}

```lua
summary(report)
```

Compact one-line health summary —
`world: NE/NW   libraries: NE/NW   total: OK|FAIL`.

**Parameters**

- `report` `any` _(optional)_ — Report produced by any of the validate* functions.

```lua
print(WorldValidation.summary(WorldValidation.check()))
```

## modules/Validator/validateLibraries {#modules-validator-validatelibraries}

```lua
validateLibraries(opts)
```

Validate every imported library under `/source/libs/`. The
returned Report has `world = nil` and `libraries` populated for
every library that exists on disk.

**Parameters**

- `opts` `any` _(optional)_ — Optional filter table — same shape as `M.check`.

```lua
local r = WorldValidation.validateLibraries()
local r = WorldValidation.validateLibraries({ source = "library:@builtin" })
```

## modules/Validator/validateLibrary {#modules-validator-validatelibrary}

```lua
validateLibrary(name, opts)
```

Validate ONE named library under `/source/libs/<name>/`. When
the library does not exist, the Report carries a single
`library.missing` error against that name so callers can tell a
clean run from a missing-dependency run.

**Parameters**

- `name` `any` _(optional)_ — Library directory name (e.g. `"@builtin"`, `"@mylib"`).
- `opts` `any` _(optional)_ — Optional filter table — same shape as `M.check`.

```lua
local r = WorldValidation.validateLibrary("@builtin")
local r = WorldValidation.validateLibrary("@mylib", { severity = "error" })
```

## modules/Validator/validateWorld {#modules-validator-validateworld}

```lua
validateWorld(opts)
```

Validate ONLY the world's authored content (`/source/`
excluding `/source/libs/`). The returned Report has `world`
populated and `libraries = {}`.

**Parameters**

- `opts` `any` _(optional)_ — Optional filter table — same shape as `M.check`.

```lua
local r = WorldValidation.validateWorld()
local r = WorldValidation.validateWorld({ severity = "error" })
```

## modules/ValueType/README {#modules-valuetype-readme}

```lua
ValueType
```

Converts a handle-backed value type — `ColorSequence`, `NumberSequence` — between the live object a session holds and the durable payload its `serialize()` produces. Every boundary that writes a component field to a record, or applies a record back onto a component, converts here.

## modules/ValueType/bind {#modules-valuetype-bind}

```lua
bind(v: any, kind: string): any
```

Put a value type's methods back on a value read out of a component
field. `Field.table` keeps the table it is handed without its metatable and
gives that stored table back on every read, so binding once makes the field
answer `:evaluate` / `:keypoints` for the rest of the session.

**Parameters**

- `v` `any` _(optional)_ — A live value carrying a handle.
- `kind` `string` — The kind to bind as when `v` names none itself.

```lua
ValueType.bind(component.color, "ColorSequence"):evaluate(0)
```

## modules/ValueType/isLive {#modules-valuetype-islive}

```lua
isLive(v: any): boolean
```

Whether a value is a live handle-backed value type — the form that
holds a session-local curve handle.

**Parameters**

- `v` `any` _(optional)_ — Any component field value.

```lua
ValueType.isLive(NumberSequence.new(0, 1)) -- true
```

## modules/ValueType/isPayload {#modules-valuetype-ispayload}

```lua
isPayload(v: any): boolean
```

Whether a value is the durable payload of a handle-backed value type —
the form a record carries.

**Parameters**

- `v` `any` _(optional)_ — Any component field value.

```lua
ValueType.isPayload(NumberSequence.new(0, 1):serialize()) -- true
```

## modules/ValueType/keypoints {#modules-valuetype-keypoints}

```lua
keypoints(v: any, kind: string): { any }?
```

The keypoint list a value holds, whichever of the two forms it is in.
A caller that knows the field's type passes it as `kind` so a bare
`{ __h = n }` — a handle written by a session that named no kind — is still
read as that type.

**Parameters**

- `v` `any` _(optional)_ — A live value, a durable payload, or a bare handle table.
- `kind` `string` — The kind to read `v` as when `v` names none itself.

```lua
ValueType.keypoints(field, "ColorSequence")
```

## modules/ValueType/kindOf {#modules-valuetype-kindof}

```lua
kindOf(v: any): string?
```

The kind name a value declares, when it is one this module converts.

**Parameters**

- `v` `any` _(optional)_ — Any component field value.

```lua
ValueType.kindOf(ColorSequence.new({1, 0, 0})) -- "ColorSequence"
```

## modules/ValueType/revive {#modules-valuetype-revive}

```lua
revive(v: any): any?
```

The live value a durable payload names, rebuilt in this session.

**Parameters**

- `v` `any` _(optional)_ — Any component field value.

```lua
ValueType.revive(record.color)
```

## modules/ValueType/serialize {#modules-valuetype-serialize}

```lua
serialize(v: any): any?
```

The durable payload for a live value — what a record stores in place of
the session-local handle.

**Parameters**

- `v` `any` _(optional)_ — Any component field value.

```lua
ValueType.serialize(field) -- { kind = "ColorSequence", keypoints = {...} }
```

## modules/ValueType/withRevived {#modules-valuetype-withrevived}

```lua
withRevived(data: any): (any, number)
```

The component field map to apply, with every durable payload rebuilt as
the live value it names — the counterpart of the saver writing payloads in
place of handles.

**Parameters**

- `data` `any` _(optional)_ — A component's `{ field = value }` map from a record.

```lua
ValueType.withRevived(record.data)
```

## modules/VfsScanner/README {#modules-vfsscanner-readme}

```lua
require("@builtin/systems/worldValidation.package/vfsScanner") -- VfsScanner
```

Recursive `/source/` walker for the world validator. Separates world content from imported libraries so downstream validators can attribute every problem to the right bucket.

An asset root is any folder whose name has a registered asset
type suffix (`Foo.component`, `bar.module`, `Baz.toolbox`, …).
When the scanner crosses one it records the root and does NOT
recurse into it as raw files — the asset validator handles the
interior. Scripts (`.luau`, `.lua`) discovered outside any asset
root are also recorded (e.g. `_shared.luau` siblings inside a
toolbox, or stray top-level scripts).

Usage: local VfsScanner = require("@builtin/systems/worldValidation.package/vfsScanner")

## modules/VfsScanner/assetSuffixes {#modules-vfsscanner-assetsuffixes}

```lua
assetSuffixes(): { string }
```

Expose the registered asset-suffix list (read-only). External
callers that want to recognise asset folders the same way the
scanner does can iterate this list.

```lua
for _, s in ipairs(VfsScanner.assetSuffixes()) do print(s) end
```

## modules/VfsScanner/listLibraryNames {#modules-vfsscanner-listlibrarynames}

```lua
listLibraryNames(): { string }
```

Enumerate the immediate children of `/source/libs/`. Each
child is a library identity (e.g. `@builtin`, `@mylib`). Returns
an empty array if `/source/libs/` does not exist.

```lua
for _, name in ipairs(VfsScanner.listLibraryNames()) do print(name) end
```

## modules/VfsScanner/scanAll {#modules-vfsscanner-scanall}

```lua
scanAll()
```

Convenience: scan world + every imported library in one call.

```lua
local scan = VfsScanner.scanAll(); print(#scan.world.assets)
```

## modules/VfsScanner/scanLibraries {#modules-vfsscanner-scanlibraries}

```lua
scanLibraries(): { [string]: any }
```

Walk every imported library and return a map keyed by name.

```lua
local libs = VfsScanner.scanLibraries(); for n, b in pairs(libs) do print(n, #b.assets) end
```

## modules/VfsScanner/scanLibrary {#modules-vfsscanner-scanlibrary}

```lua
scanLibrary(name: string)
```

Walk one named library under `/source/libs/<name>/`. The
returned Bucket's `rootPath` is the library root so callers can
derive relative paths cheaply.

**Parameters**

- `name` `string` — Library directory name (e.g. `"@builtin"`).

```lua
local bucket = VfsScanner.scanLibrary("@builtin")
```

## modules/VfsScanner/scanWorld {#modules-vfsscanner-scanworld}

```lua
scanWorld()
```

Walk only the world bucket — everything under `/source/`
except `/source/libs/`. The scanner stops recursing whenever it
reaches an asset-suffixed folder; asset interiors are handled by
the assetValidator.

```lua
local bucket = VfsScanner.scanWorld()
```

## modules/WorkflowAssetTypeRef/README {#modules-workflowassettyperef-readme}

```lua
WorkflowAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<workflow>`. Loaded lazily by `asset_ref.module`.

## modules/WorkflowAssetTypeRef/getManifest {#modules-workflowassettyperef-getmanifest}

```lua
getManifest(self): { [string]: any }
```

Read and parse `workflow.yaml`: what this workflow is, when it is
reached for, and the phases it moves through.

**Parameters**

- `self` `any` _(optional)_

```lua
local m = wf:getManifest()
```

## modules/WorkflowAssetTypeRef/getSource {#modules-workflowassettyperef-getsource}

```lua
getSource(self): string?
```

Read the program itself — the JavaScript body that runs when the
workflow is started.

**Parameters**

- `self` `any` _(optional)_

```lua
local src = wf:getSource()
```

## modules/WorkflowAssetTypeRef/inspect {#modules-workflowassettyperef-inspect}

```lua
inspect(self): { [string]: any }
```

What this workflow is, without running it: its description, when to
reach for it, the phases it moves through, and what it expects in `args`.

**Parameters**

- `self` `any` _(optional)_

```lua
local info = wf:inspect()
```

## modules/WorkflowAssetTypeRef/start {#modules-workflowassettyperef-start}

```lua
start(self, args: { [string]: any }?): { [string]: any }
```

Start a run of this workflow. Returns immediately: the run is already
executing, and it parks the moment it asks its first question. Answer what
it asks through the `workflow` toolbox — the run decides what comes next.

**Parameters**

- `self` `any` _(optional)_
- `args` `{ [string]: any }?` _(optional)_ — Optional table handed to the program as its `args`.

```lua
local run = wf:start({ concept = "outrun a tornado" })
```

## modules/World/README {#modules-world-readme}

```lua
require("@builtin/modules/world") -- World (also available as global 'world')
```

Public Luau API for the bound world. Composes internal `__world` FFI primitives with per-mode slot defaults (world_defaults), source-control toolbox (world_vcs), and the connected-users registry (connected_users) into a single namespace. Usage: world.guid()                       -- current world GUID, nil if none world.swap(guid)                   -- bind to another world (promise) world.avatar_default_edit = ref    -- per-mode avatar default world.on("player_join", cb)        -- world-level event hooks Implemented as a thin Luau wrapper. The `world` global is a plain table whose `__index` metatable falls through to the internal `__world` namespace for unknown reads. Other library modules (`world_defaults`, `world_vcs`, `connected_users`) attach their surfaces via `installInto(world)` from `prelude.luau`; their metatable wrappers chain through this base layer correctly.

Usage: local World = require("@builtin/modules/world")
Also available as global: world

## modules/Yaml/README {#modules-yaml-readme}

```lua
Yaml
```

YAML decode + encode for authored engine content. Supports the YAML subset engine configs use: block mappings + sequences, flow collections, typed plain scalars, quoted strings, comments, literal and folded block scalars, an optional leading `---`. Unsupported constructs (anchors, aliases, tags, directives, multi-document streams, tab indentation) raise with the offending line number.

## modules/Yaml/decode {#modules-yaml-decode}

```lua
decode(text: string): any
```

Decode a YAML document into a Luau value. Raises (with the line
number) on malformed input or constructs outside the supported
subset — never misparses silently.

**Parameters**

- `text` `string` — The YAML document text.

```lua
local doc = Yaml.decode(vfs.read(path))
```

## modules/Yaml/encode {#modules-yaml-encode}

```lua
encode(value: { [any]: any }): string
```

Encode a Luau table as a YAML document (block style, two-space
indent, sorted keys). Raises on values YAML can't represent
(functions, userdata, non-string mapping keys).

**Parameters**

- `value` `{ [any]: any }` — The table to encode.

```lua
vfs.write(path, Yaml.encode({ contract = "weapon", values = v }))
```

## modules/ZJsAssetTypeRef/README {#modules-zjsassettyperef-readme}

```lua
ZJsAssetTypeRef
```

Per-instance methods exposed on every `AssetRef<zJs>`. Loaded lazily by `asset_ref.module` the first time a zJs ref is touched in a VM. A zJs asset is a `<name>.zJs/` folder whose `main.js` holds a JavaScript ES module. The methods here surface the static write-time diagnostics the type computes for that module and execute it: `run` / `runAsync` for a script or module, and `exports` to read a module's export namespace as a Luau table.

## modules/ZJsAssetTypeRef/check {#modules-zjsassettyperef-check}

```lua
check(self): { ok: boolean, diagnostics: { Diagnostic } }
```

Static diagnostics for THIS module's `main.js`: parse errors plus imports
that do not resolve to a zJs module. Reads the cache `onChange` maintains,
running the parse+resolve pipeline once on a cold reference.

**Parameters**

- `self` `any` _(optional)_

```lua
local r = asset.resolve("greeter", "zJs"):check(); if not r.ok then ... end
```

## modules/ZJsAssetTypeRef/exports {#modules-zjsassettyperef-exports}

```lua
exports(self, opts: { env: { [string]: any }? }?): any
```

Evaluate THIS module as an ES module on a fresh VM and return its export
namespace marshaled to a Luau table: each named export plus `default`.
Cross-asset imports resolve through the live asset index, so a JS library
built from several `.zJs` assets is consumed as one table. Refuses when the
module carries diagnostics, naming the first; a cycle, an unresolved import,
or a thrown module body surfaces as a Luau error.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ env: { [string]: any }? }?` _(optional)_

```lua
local lib = asset.resolve("mathlib", "zJs"):exports(); print(lib.add(1, 2))
```

## modules/ZJsAssetTypeRef/onChange {#modules-zjsassettyperef-onchange}

```lua
onChange(ref, change)
```

Asset-type change callback: recompute this module's static diagnostics
whenever its `main.js` is edited or the whole instance is seeded. Convergent:
it reads the source and asset index and replaces the ref's cached pipeline
result; it never writes to the VFS. Edits to sidecars (`README.md`,
`.metadata`) leave the cache untouched.

**Parameters**

- `ref` `any` _(optional)_
- `change` `any` _(optional)_

## modules/ZJsAssetTypeRef/onCreate {#modules-zjsassettyperef-oncreate}

```lua
onCreate(name: string, opts: CreateOpts): { [string]: string }
```

Generic-creation hook for `asset.create("zJs", name, opts)`. Pure: returns
the instance's content file map for the caller to persist. `opts.source`, when
given, becomes `main.js` verbatim; otherwise a hello-world module naming the
instance is scaffolded from the template.

**Parameters**

- `name` `string` — zJs module identity (the instance name).
- `opts` `CreateOpts`

```lua
asset.create("zJs", "greeter", { source = "export const x = 1" })
```

## modules/ZJsAssetTypeRef/run {#modules-zjsassettyperef-run}

```lua
run(self, opts: { env: { [string]: any }? }?): any
```

Execute THIS module on a fresh JavaScript VM and marshal the result to
Luau. A plain script (no imports or exports) runs as a script and returns
its completion value; a module evaluates through the module graph and returns
nil, since module evaluation has no completion value. `opts.env` seeds host
values as JavaScript globals. Refuses when the module carries diagnostics,
naming the first, and directs a script that leaves asynchronous work pending
to `runAsync`.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ env: { [string]: any }? }?` _(optional)_

```lua
local sum = asset.resolve("calc", "zJs"):run({ env = { base = 10 } })
```

## modules/ZJsAssetTypeRef/runAsync {#modules-zjsassettyperef-runasync}

```lua
runAsync(self, opts: { env: { [string]: any }?, timeoutMs: number? }?): any
```

Execute THIS module's program on a fresh VM under the asynchronous runner,
driving armed timers and pending promises to completion. Returns the engine
run handle: poll `handle.done`, then read `handle.ok` / `handle.value` /
`handle.error`, or call `handle:await()` from a yieldable context.
`opts.timeoutMs` bounds a never-settling run. Refuses when the module carries
diagnostics, naming the first.

**Parameters**

- `self` `any` _(optional)_
- `opts` `{ env: { [string]: any }?, timeoutMs: number? }?` _(optional)_

```lua
local h = asset.resolve("job", "zJs"):runAsync({ timeoutMs = 1000 }); h:await()
```

## modules/ZinputActions/README {#modules-zinputactions-readme}

```lua
ZinputActions
```

DEPRECATED: A control asset carries what an action carried, plus the gamepad and touch an action never had. Author an `.inputMap` with `.inputBinding` children, activate it, and subscribe: `local map = self.inputMap:activate()` then `map.jump:onPressed(fn)`. See `man topics/input`.

## modules/ZinputActions/_clearHandlers {#modules-zinputactions-clearhandlers}

```lua
_clearHandlers()
```

Test-only: clear every handler (does NOT touch action
definitions).

```lua
Zin.actions._clearHandlers()
```

## modules/ZinputActions/_dispatchHandlers {#modules-zinputactions-dispatchhandlers}

```lua
_dispatchHandlers(firstTickThisFrame: boolean?)
```

Internal: dispatch action handlers. Called by `Zin.tick` after
axes/chords advance. Fires `Begin`/`End`/`Change`/`Held` handlers
based on each action's polling state this tick.
`firstTickThisFrame` is `false` on a same-engine-frame re-tick (e.g.
the autoTick worker and an explicit `Zin.tick` both land in one
frame): edge fires (`Begin`/`End`/`Change`) are per-frame events and
must not fire twice, so they are gated to the first tick of the
frame. `Held` is a per-tick redeliver and still fires every call.
A `nil` argument is treated as the first tick (edges fire).

**Parameters**

- `firstTickThisFrame` `boolean?` _(optional)_ — Whether this is the frame's first dispatch pass.

```lua
Zin.actions._dispatchHandlers()
```

## modules/ZinputActions/_owns {#modules-zinputactions-owns}

```lua
_owns(handle: number): boolean
```

Internal: cross-API ownership probe. Used by `Zin.disconnect` to
route handles to the right `disconnect` implementation, since
`Zin.input.on*` and `Zin.actions.bind` share a handle namespace.

**Parameters**

- `handle` `number` — The numeric handle to probe.

```lua
if Zin.actions._owns(h) then Zin.actions.disconnect(h) end
```

## modules/ZinputActions/_resetUnknownWarnings {#modules-zinputactions-resetunknownwarnings}

```lua
_resetUnknownWarnings()
```

Test-only: forget which names have already been reported as
unregistered, so a fresh suite sees the warning again.

```lua
Zin.actions._resetUnknownWarnings()
```

## modules/ZinputActions/_setAllocator {#modules-zinputactions-setallocator}

```lua
_setAllocator(fn: () -> number)
```

Internal: wire a shared id allocator, so handles from this module
and from `Zin.input.on*` never collide. Called once at module-load
time from `zinput/init.luau`.

**Parameters**

- `fn` `() -> number` — The allocator function that returns the next handle id.

```lua
M._setAllocator(allocateZinHandle)
```

## modules/ZinputActions/_setEnsureBindingsFn {#modules-zinputactions-setensurebindingsfn}

```lua
_setEnsureBindingsFn(fn: () -> ())
```

Internal: wire the lazy-default-map hook. Called once at module-
load time from `zinput/init.luau`.

**Parameters**

- `fn` `() -> ()` — The hook invoked on a cold read (name not in the registry).

```lua
M._setEnsureBindingsFn(ensureDefaultBindings)
```

## modules/ZinputActions/_setEnsureLiveFn {#modules-zinputactions-setensurelivefn}

```lua
_setEnsureLiveFn(fn: () -> ())
```

Internal: wire the liveness hook. Called once at module-load
time from `zinput/init.luau`.

**Parameters**

- `fn` `() -> ()` — The hook invoked on every cold-checked read below.

```lua
M._setEnsureLiveFn(ensureInputLive)
```

## modules/ZinputActions/_settled {#modules-zinputactions-settled}

```lua
_settled(): boolean
```

Internal: whether the most recent dispatch pass delivered
nothing and saw nothing held. The tick's quiescence gate reads it.

```lua
if Zin.actions._settled() then ... end
```

## modules/ZinputActions/active {#modules-zinputactions-active}

```lua
active(name: string): boolean
```

True if an action is currently active in the input context
stack. An action is "active" iff its declared context matches the
top of the context stack (so `push("ui")` suppresses every
non-"ui" action).

**Parameters**

- `name` `string` — The action name.

```lua
if Zin.actions.active("jump") then ... end
```

## modules/ZinputActions/bind {#modules-zinputactions-bind}

```lua
bind(name: string, fn, opts: BindOpts?): ActionHandle?
```

Register a handler. Returns a numeric handle (also accepted by
`Zin.input.disconnect`). Returns `nil` if `name` is not a defined
action.

**Parameters**

- `name` `string` — The action name.
- `fn` `any` _(optional)_ — Handler `fn(name, state, io, gpe) -> "sink" | any`.
- `opts` `BindOpts?` _(optional)_ — Optional `{ priority, fire, once }`.

```lua
local h = Zin.actions.bind("jump", function() jump() end)
```

## modules/ZinputActions/clear {#modules-zinputactions-clear}

```lua
clear()
```

Wipe every defined action. Primarily for tests.

```lua
Zin.actions.clear()
```

## modules/ZinputActions/define {#modules-zinputactions-define}

```lua
define(spec: ActionSpec)
```

Define one or more actions. Each entry replaces any existing
action under the same name; other actions are preserved.

**Parameters**

- `spec` `ActionSpec` — Map of `name -> binding | { binding... } | { context, binding(s) }`.

```lua
Zin.actions.define({ jump = Zin.bindings.key("Space") })
```

## modules/ZinputActions/disconnect {#modules-zinputactions-disconnect}

```lua
disconnect(handle: ActionHandle): boolean
```

Tear down a handler returned by `bind`. Idempotent.

**Parameters**

- `handle` `ActionHandle` — The handle from `bind` (or `onPressed`/`onReleased`/etc).

```lua
Zin.actions.disconnect(h)
```

## modules/ZinputActions/get {#modules-zinputactions-get}

```lua
get(name: string): ActionEntry?
```

Internal: the registry record behind a name, for profile capture
and conflict indexing. Returns nil if the action is not defined.

**Parameters**

- `name` `string` — The action name.

```lua
local entry = Zin.actions.get("jump")
```

## modules/ZinputActions/handlerCount {#modules-zinputactions-handlercount}

```lua
handlerCount(name: string): number
```

Number of registered handlers for an action (0 if none /
unknown).

**Parameters**

- `name` `string` — The action name.

```lua
assert(Zin.actions.handlerCount("jump") == 1)
```

## modules/ZinputActions/has {#modules-zinputactions-has}

```lua
has(name: string): boolean
```

True if an action with this name is defined.

**Parameters**

- `name` `string` — The action name to test.

```lua
if Zin.actions.has("jump") then ... end
```

## modules/ZinputActions/held {#modules-zinputactions-held}

```lua
held(name: string): boolean
```

True if any binding on the action is currently delivering
input. For boolean bindings: any held. For axis/vector bindings:
non-zero magnitude. Suppressed by context gating.

**Parameters**

- `name` `string` — The action name.

```lua
if Zin.actions.held("attack") then swing() end
```

## modules/ZinputActions/heldTime {#modules-zinputactions-heldtime}

```lua
heldTime(name: string): number?
```

Seconds the action has been held, taken as the MAX held-time
across the action's boolean bindings. Returns `nil` if no binding
is held or if the action is gated off by the current input
context. Vector / axis bindings are skipped — use a held-time
threshold against `Zin.axes.value` for held-direction analogs.

**Parameters**

- `name` `string` — The action name.

```lua
local t = Zin.actions.heldTime("interact")
```

## modules/ZinputActions/names {#modules-zinputactions-names}

```lua
names(): { string }
```

All defined action names, in arbitrary order.

```lua
for _, n in ipairs(Zin.actions.names()) do print(n) end
```

## modules/ZinputActions/onChanged {#modules-zinputactions-onchanged}

```lua
onChanged(name: string, fn, opts: BindOpts?): ActionHandle?
```

Fire on axis/vector value delta (state = "Change"). For boolean
actions Change fires on every press AND release transition — use
`onPressed` / `onReleased` instead if you only want edges.

**Parameters**

- `name` `string` — The action name.
- `fn` `any` _(optional)_ — Handler `fn(name, state, io, gpe)`.
- `opts` `BindOpts?` _(optional)_ — Optional `{ priority, once }`.

```lua
Zin.actions.onChanged("move", function(_, _, io) print(io.value) end)
```

## modules/ZinputActions/onHeld {#modules-zinputactions-onheld}

```lua
onHeld(name: string, fn, opts: BindOpts?): ActionHandle?
```

Fire every tick while held (state = "Held"). Fires whenever
`held()` is true at dispatch time, regardless of value change.
Inherits the action's context constraint (no per-handler context
filter).

**Parameters**

- `name` `string` — The action name.
- `fn` `any` _(optional)_ — Handler `fn(name, state, io, gpe)`.
- `opts` `BindOpts?` _(optional)_ — Optional `{ priority, once }`.

```lua
Zin.actions.onHeld("interact", function(_, _, io) charge(io.value) end)
```

## modules/ZinputActions/onPressed {#modules-zinputactions-onpressed}

```lua
onPressed(name: string, fn, opts: BindOpts?): ActionHandle?
```

Fire on rising edge (state = "Begin"). Sugar for `bind` with
`fire = {"Begin"}`.

**Parameters**

- `name` `string` — The action name.
- `fn` `any` _(optional)_ — Handler `fn(name, state, io, gpe)`.
- `opts` `BindOpts?` _(optional)_ — Optional `{ priority, once }`.

```lua
Zin.actions.onPressed("jump", function() ... end)
```

## modules/ZinputActions/onReleased {#modules-zinputactions-onreleased}

```lua
onReleased(name: string, fn, opts: BindOpts?): ActionHandle?
```

Fire on falling edge (state = "End"). Sugar for `bind` with
`fire = {"End"}`.

**Parameters**

- `name` `string` — The action name.
- `fn` `any` _(optional)_ — Handler `fn(name, state, io, gpe)`.
- `opts` `BindOpts?` _(optional)_ — Optional `{ priority, once }`.

```lua
Zin.actions.onReleased("attack", function() ... end)
```

## modules/ZinputActions/pressed {#modules-zinputactions-pressed}

```lua
pressed(name: string): boolean
```

True if any boolean binding on the action was just pressed
this frame — the press EDGE, so it fires once per press no matter
how long the input is held. Use it for one-shot input: fire, jump,
pause, undo. For continuous input that should repeat every frame
the input is down, read the level instead with
`Zin.state.keyDown(key)`. Axis/vector bindings do not contribute to
press edges. Suppressed by context gating.

**Parameters**

- `name` `string` — The action name.

```lua
if Zin.actions.pressed("jump") then ... end
```

## modules/ZinputActions/reason {#modules-zinputactions-reason}

```lua
reason(name: string): string
```

Why a named action is not delivering, from the closed set this
registry can distinguish: `unknownControl` (no action is registered
under the name — the value readers answer their neutral value, which is
not a reading), `contextInactive` (registered, but its context is not
on top of the stack), `atRest` (live, and the devices it binds are not
being driven), or `delivering`.

**Parameters**

- `name` `string` — The action name.

```lua
if Zin.actions.reason("jump") == "unknownControl" then ... end
```

## modules/ZinputActions/released {#modules-zinputactions-released}

```lua
released(name: string): boolean
```

True if any boolean binding on the action was just released
this frame. Suppressed by context gating.

**Parameters**

- `name` `string` — The action name.

```lua
if Zin.actions.released("attack") then ... end
```

## modules/ZinputActions/remove {#modules-zinputactions-remove}

```lua
remove(name: string)
```

Remove an action by name. No-op if not defined.

**Parameters**

- `name` `string` — The action name to remove.

```lua
Zin.actions.remove("jump")
```

## modules/ZinputActions/repeated {#modules-zinputactions-repeated}

```lua
repeated(name: string, opts: { delay: number?, period: number? }?): boolean
```

Should a synthetic repeat fire this frame for the action?
Returns true if any of the action's boolean key bindings reports
`State.keyRepeatFired`. Mouse bindings are skipped (use a hold-
time threshold for press-and-hold UX). Suppressed by context
gating.

**Parameters**

- `name` `string` — The action name.
- `opts` `{ delay: number?, period: number? }?` _(optional)_ — Optional `{ delay, period }` override of the global repeat defaults.

```lua
if Zin.actions.repeated("scrollLeft") then ... end
```

## modules/ZinputActions/value {#modules-zinputactions-value}

```lua
value(name: string): any
```

Read the action's current value.
- Axis binding → number in [-1, 1]
- Vector binding → `{ x, y }` numbers in [-1, 1]
- Boolean binding → 1 when held, 0 when not (consumers usually use
`held()` instead; this exists so a single API works for any kind)
When multiple bindings exist, the first one whose kind matches the
caller's expectation wins (axis > vector > boolean in declaration
order). When suppressed by context, returns the identity value for
the first binding's kind: 0 for axis/boolean, `{ x = 0, y = 0 }`
for vector.

**Parameters**

- `name` `string` — The action name.

```lua
local mv = Zin.actions.value("move")  -- { x, y }
```

## modules/ZinputAxes/README {#modules-zinputaxes-readme}

```lua
ZinputAxes
```

DEPRECATED: An `axis1` / `axis2` control carries the same deadzone, smoothing, curve and invert, and reads a stick and a dragging thumb as well as a key. Author an `.inputMap` with `.inputBinding` children, activate it, and subscribe: `local map = self.inputMap:activate()` then `map.move:onInput(fn)`. See `man topics/input`.

## modules/ZinputAxes/_resetGateWarnings {#modules-zinputaxes-resetgatewarnings}

```lua
_resetGateWarnings()
```

Test-only: reset the once-per-axis gate-error warning state so
a fresh suite can verify warning behavior again.

```lua
Zin.axes._resetGateWarnings()
```

## modules/ZinputAxes/_resetUnknownWarnings {#modules-zinputaxes-resetunknownwarnings}

```lua
_resetUnknownWarnings()
```

Test-only: forget which names have already been reported as
unregistered, so a fresh suite sees the warning again.

```lua
Zin.axes._resetUnknownWarnings()
```

## modules/ZinputAxes/_setEnsureBindingsFn {#modules-zinputaxes-setensurebindingsfn}

```lua
_setEnsureBindingsFn(fn: () -> ())
```

Internal: wire the lazy-default-map hook. Called once at module-
load time from `zinput/init.luau`.

**Parameters**

- `fn` `() -> ()` — The hook invoked on a cold read (name not in the registry).

```lua
M._setEnsureBindingsFn(ensureDefaultBindings)
```

## modules/ZinputAxes/_setEnsureLiveFn {#modules-zinputaxes-setensurelivefn}

```lua
_setEnsureLiveFn(fn: () -> ())
```

Internal: wire the liveness hook. Called once at module-load
time from `zinput/init.luau`.

**Parameters**

- `fn` `() -> ()` — The hook invoked on every cold-checked read below.

```lua
M._setEnsureLiveFn(ensureInputLive)
```

## modules/ZinputAxes/_settled {#modules-zinputaxes-settled}

```lua
_settled(): boolean
```

Internal: whether every axis sits at zero, current and target
alike. The tick's quiescence gate reads it.

```lua
if Zin.axes._settled() then ... end
```

## modules/ZinputAxes/advance {#modules-zinputaxes-advance}

```lua
advance(dt: number)
```

**Parameters**

- `dt` `number`

## modules/ZinputAxes/clear {#modules-zinputaxes-clear}

```lua
clear()
```

Wipe every axis and its state. Primarily for tests.

```lua
Zin.axes.clear()
```

## modules/ZinputAxes/define {#modules-zinputaxes-define}

```lua
define(spec: AxisSpec)
```

Define one or more axes. Each entry replaces any existing axis
of the same name; other axes are preserved.

**Parameters**

- `spec` `AxisSpec` — Map of `name -> { binding, deadzone?, smoothing?, curve?, invert?, context?, gate? }`.

```lua
Zin.axes.define({ aim_x = { binding = ..., deadzone = 0.05 } })
```

## modules/ZinputAxes/get {#modules-zinputaxes-get}

```lua
get(name: string): AxisDef?
```

Internal introspection: definition record (or nil).

**Parameters**

- `name` `string` — The axis name.

```lua
local def = Zin.axes.get("aim_x")
```

## modules/ZinputAxes/has {#modules-zinputaxes-has}

```lua
has(name: string): boolean
```

True if an axis with this name is defined.

**Parameters**

- `name` `string` — The axis name.

```lua
if Zin.axes.has("aim_x") then ... end
```

## modules/ZinputAxes/names {#modules-zinputaxes-names}

```lua
names(): { string }
```

All defined axis names, in arbitrary order.

```lua
for _, n in ipairs(Zin.axes.names()) do print(n) end
```

## modules/ZinputAxes/raw {#modules-zinputaxes-raw}

```lua
raw(name: string): any
```

Read the raw, unsmoothed, unshaped value of the underlying
binding. For vector bindings returns `{x,y}`; for everything else
returns a number in `[-1, 1]`. Useful for debugging or comparing
pre/post processing.

**Parameters**

- `name` `string` — The axis name.

```lua
print(Zin.axes.raw("aim_x"))
```

## modules/ZinputAxes/reason {#modules-zinputaxes-reason}

```lua
reason(name: string): string
```

Why a named axis is not delivering, from the closed set this
registry can distinguish: `unknownControl` (no axis is registered under
the name — the value readers answer zero, which is not a reading),
`contextInactive` (registered, but its context is not on top of the
stack), `gateRefused` (its own gate answered no), `atRest` (live, and
the binding it reads is not being driven), or `delivering`.

**Parameters**

- `name` `string` — The axis name.

```lua
if Zin.axes.reason("look") == "gateRefused" then ... end
```

## modules/ZinputAxes/remove {#modules-zinputaxes-remove}

```lua
remove(name: string)
```

Remove an axis. No-op if not defined.

**Parameters**

- `name` `string` — The axis name.

```lua
Zin.axes.remove("aim_x")
```

## modules/ZinputAxes/value {#modules-zinputaxes-value}

```lua
value(name: string): any
```

Read the smoothed, shaped, context-gated value.
Scalar axes return a number in `[-1, 1]`.
Vector axes return `{x, y}` numbers in `[-1, 1]`.
Returns 0 / `{x=0,y=0}` if the axis isn't defined.

**Parameters**

- `name` `string` — The axis name.

```lua
local mv = Zin.axes.value("move")  -- { x, y }
```

## modules/ZinputMap/README {#modules-zinputmap-readme}

```lua
ZinputMap
```

DEPRECATED: An `.inputMap` asset with `.inputBinding` children is the map, and `Zin.scheme` is the live set: several can be live at once, each declaring the groups it suppresses. `Zin.map.bake(name)` writes the active map out as one, which is the migration. See `man topics/input`.

## modules/ZinputMap/_reactivate {#modules-zinputmap-reactivate}

```lua
_reactivate(record: any): any
```

Re-apply the active map from a changed record — the edit-in-place
path an `.inputMap` asset takes when its source is written while it is
live. Who asked for the map is carried across: a write to its source
is the same map with new bindings, not a caller taking it up.

**Parameters**

- `record` `any` _(optional)_ — The map record, freshly read from its source.

```lua
Zin.map._reactivate(loadRecord(self))
```

## modules/ZinputMap/_reset {#modules-zinputmap-reset}

```lua
_reset()
```

Test-only: clear active-map state (the profile registry keeps
whatever was applied).

```lua
Zin.map._reset()
```

## modules/ZinputMap/activate {#modules-zinputmap-activate}

```lua
activate(record: any): any
```

Activate a map record: materialize it and apply the flattened
result as the live binding set (through the profile registry, so
persistence and conflict surfaces keep working). Per-class axis
bindings beyond the primary register as `<axis>@<class>` sibling
axes; consumers that combine device values read both (e.g.
`look` + `look@touch`).

**Parameters**

- `record` `any` _(optional)_ — The map (or profile) record, or an inputMap asset ref.

```lua
Zin.map.activate(require("@builtin::inputMaps.default"))
```

## modules/ZinputMap/activeName {#modules-zinputmap-activename}

```lua
activeName(): string?
```

The active map's name, or nil.

```lua
if Zin.map.activeName() == "default" then ... end
```

## modules/ZinputMap/addTouchButton {#modules-zinputmap-addtouchbutton}

```lua
addTouchButton(actionName: string, buttonOpts: { zone: string?, label: string?, icon: string? }, emitKey: string?): any
```

Add a touchButton binding to an action's touch class on the
active effective map, then re-flatten and re-activate so it takes
effect immediately. Creates the action entry if `actionName`
doesn't exist yet (the overlay's synthetic `emit:<code>` buttons).

**Parameters**

- `actionName` `string` — The action to attach the button to.
- `buttonOpts` `{ zone: string?, label: string?, icon: string? }` — `{ zone: string?, label: string?, icon: string? }` —
the touchButton binding's presentation (see
`Zin.bindings.touchButton`).
- `emitKey` `string?` _(optional)_ — Optional key code — when set and the action has no kbm
class yet, seeds it with `B.key(emitKey)` so a synthetic action is
self-contained from the moment it's created.

```lua
Zin.map.addTouchButton("emit:KeyF", { label = "Cast" }, "KeyF")
```

## modules/ZinputMap/bake {#modules-zinputmap-bake}

```lua
bake(name: string): any
```

Write the active effective map as a new inputMap asset —
synthesis made explicit and editable. The snapshot includes every
live entry, overlay-registered `emit:<code>` actions included.
Returns the created ref.

**Parameters**

- `name` `string` — The new asset's name.

```lua
Zin.map.bake("my_scheme")
```

## modules/ZinputMap/bindingsFor {#modules-zinputmap-bindingsfor}

```lua
bindingsFor(eff: any, name: string, class: string): any
```

The effective bindings for one action or axis and device class.

**Parameters**

- `eff` `any` _(optional)_ — An effective map (from materialize/effective).
- `name` `string` — The action or axis name.
- `class` `string` — "kbm" | "gamepad" | "touch".

```lua
local touch = Zin.map.bindingsFor(eff, "jump", "touch")
```

## modules/ZinputMap/effective {#modules-zinputmap-effective}

```lua
effective(): any
```

The active map's effective form, or nil before any activation.

```lua
local eff = Zin.map.effective()
```

## modules/ZinputMap/ensureActive {#modules-zinputmap-ensureactive}

```lua
ensureActive(): any
```

Ensure a map is active: keeps the current one, else activates
the builtin default map. The bootstrap the on-screen controls and
controllers call.

```lua
Zin.map.ensureActive()
```

## modules/ZinputMap/isFallback {#modules-zinputmap-isfallback}

```lua
isFallback(): boolean
```

Whether the active map is the fallback `ensureActive` armed on
its own, rather than one a caller activated. A reader that presents
the map to a player — the on-screen controls — asks this to tell a
scheme a world offered from the keyboard floor under a name that was
read.

```lua
if not Zin.map.isFallback() then draw(Zin.map.effective()) end
```

## modules/ZinputMap/materialize {#modules-zinputmap-materialize}

```lua
materialize(record: any): any
```

Materialize a map record into its effective form: extends chain
resolved (child wins per action/axis/class), then the touch class
synthesized from the kbm shape wherever absent. Returns
{ name, description, actions = { [name] = { context, classes,
synthesized = { touch = true? } } }, axes = { ... } }.

**Parameters**

- `record` `any` _(optional)_ — The map (or profile) record.

```lua
local eff = Zin.map.materialize(require("@builtin::inputMaps.default"))
```

## modules/ZinputMap/removeTouchButton {#modules-zinputmap-removetouchbutton}

```lua
removeTouchButton(actionName: string, binding: any): boolean
```

Remove a touchButton binding previously added via
`addTouchButton`, then re-flatten and re-activate. Drops the
action entry entirely once every class is empty — cleanup for
synthetic `emit:<code>` actions the overlay created.

**Parameters**

- `actionName` `string` — The action the binding was added to.
- `binding` `any` _(optional)_ — The binding table returned by `addTouchButton`.

```lua
Zin.map.removeTouchButton("emit:KeyF", binding)
```

## modules/ZinputObserve/README {#modules-zinputobserve-readme}

```lua
ZinputObserve
```

## modules/ZinputObserve/_publish {#modules-zinputobserve-publish}

```lua
_publish()
```

Internal: publish this layer's half of the engine's input
observation for the current frame. Called once per frame from
`Zin.tick` while `Zin.observe.wanted()` holds.

```lua
Zin.observe._publish()
```

## modules/ZinputObserve/arm {#modules-zinputobserve-arm}

```lua
arm(on: boolean?)
```

Hold the engine's input observation open, so `/runtime/input` and
`input.observe()` carry this layer's half of the document every frame.
A read of either arms it for a window of frames on its own; this is for
a test or a tool that wants it building continuously.

**Parameters**

- `on` `boolean?` _(optional)_ — Arm (the default) or disarm.

```lua
Zin.observe.arm(true)
```

## modules/ZinputObserve/armedFrames {#modules-zinputobserve-armedframes}

```lua
armedFrames(): number
```

How many more frames the arming window has left. A read of
`Zin.observe.frame()`, `input.observe()` or `/runtime/input` sets it
back to the full window; every frame that passes takes one off it, and
`0` means nothing is observing.

```lua
print(Zin.observe.armedFrames())
```

## modules/ZinputObserve/control {#modules-zinputobserve-control}

```lua
control(name: string): any
```

Everything known about one named control in a single call: which
maps contribute it, its bindings per device class, its subscriber
count, the value it reported on the most recent tick, whether that
reached a subscriber, and — when it is live and silent — why.

**Parameters**

- `name` `string` — The control name.

```lua
local c = Zin.observe.control("move")
```

## modules/ZinputObserve/frame {#modules-zinputobserve-frame}

```lua
frame(): any
```

The mapping layer's account of the most recent tick: every live map,
every live control with what it did and why, and what the tick cost.

The window is ONE tick — the most recent one. Reading consumes nothing,
so any number of observers in the same frame all get the same answers.

```lua
local f = Zin.observe.frame()
```

## modules/ZinputObserve/means {#modules-zinputobserve-means}

```lua
means(reason: string): string?
```

What one reason name means, or `nil` for a name outside the set.

**Parameters**

- `reason` `string` — The reason name.

```lua
print(Zin.observe.means("gateRefused"))
```

## modules/ZinputObserve/reasons {#modules-zinputobserve-reasons}

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

The closed set of reasons a control resolves to, each with what it
means and what to do about it. The resolver answers with exactly one of
these names.

```lua
for _, r in ipairs(Zin.observe.reasons()) do print(r.name, r.means) end
```

## modules/ZinputObserve/wanted {#modules-zinputobserve-wanted}

```lua
wanted(): boolean
```

Whether the engine wants this layer's half of the input observation
built this frame — true while something has read `input.observe()` or
`/runtime/input` recently enough.

```lua
if Zin.observe.wanted() then ... end
```

## modules/ZinputObserve/whySilent {#modules-zinputobserve-whysilent}

```lua
whySilent(name: string): any
```

Why a named control is not reaching the game right now, as one
reason from the closed set `Zin.observe.reasons()` lists, with the
particulars behind it.

Resolves against the devices as they are at the moment of the call, so
it answers for a control the tick has never reached and for one that
does not exist. The `layer` field says which of the three naming layers
answered — the live maps' controls, the action registry, or the axis
registry — since a name can be live in one and unknown in the others.

**Parameters**

- `name` `string` — The control name.

```lua
local why = Zin.observe.whySilent("look")
```

## modules/animGraph/README {#modules-animgraph-readme}

```lua
require("@builtin/modules/api/engine/animGraph") -- animGraph (also available as global 'animGraph')
```

Per-entity engine animation graph over the `__animGraph` FFI: clips, mixers, 2D blend spaces, crossfade, weights, and graph state. Each call routes onto the entity's `AnimGraphComponent` (auto-resolved from script context or passed explicitly).

Usage: local animGraph = require("@builtin/modules/api/engine/animGraph")
Also available as global: animGraph

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

```lua
require("@builtin/modules/api/engine/animation") -- animation (also available as global 'animation')
```

Observe what the engine is animating: every body it is posing, the clips driving each one and where their playheads are, how many of a body's bones a clip's retarget reached, and — for a body that is not moving — the one reason why, from a closed set.

Usage: local animation = require("@builtin/modules/api/engine/animation")
Also available as global: animation

## modules/animation/animating {#modules-animation-animating}

```lua
animating(): { AnimationBody }
```

The bodies the engine measured a changing pose on — what is animating
right now.

```lua
for _, b in animation.animating() do print(b.entity, b.clips[1] and b.clips[1].name) end
```

## modules/animation/bodies {#modules-animation-bodies}

```lua
bodies(): { AnimationBody }
```

Every body the engine holds animation state for.

```lua
for _, b in animation.bodies() do print(b.entity, b.matched .. "/" .. b.total) end
```

## modules/animation/body {#modules-animation-body}

```lua
body(entityId: string | EntityRef): AnimationBody?
```

The report for one body, or nil when the engine holds no animation
state for it. Accepts the body itself or any ancestor of it, so a character
root answers for the skinned body underneath it.

**Parameters**

- `entityId` `string | EntityRef` — The entity's stable id, or an EntityRef.

```lua
local b = animation.body(hero.id); print(b and b.reason)
```

## modules/animation/clips {#modules-animation-clips}

```lua
clips(entityId: string | EntityRef): { AnimationClip }
```

The clips contributing to a body's pose right now, with their playheads
and their retarget coverage.

**Parameters**

- `entityId` `string | EntityRef` — The entity's stable id, or an EntityRef.

```lua
for _, c in animation.clips(hero.id) do print(c.name, c.time, c.matched) end
```

## modules/animation/coverage {#modules-animation-coverage}

```lua
coverage(entityId: string | EntityRef): (number, number)
```

How many of a body's bones the clips driving it actually reach.
Returns `(matched, total)`. A clip that retargets onto nothing reads
`(0, 50)` while its playhead advances; a partial retarget reads its own
count, so 3 of 50 is as visible as none.

**Parameters**

- `entityId` `string | EntityRef` — The entity's stable id, or an EntityRef.

```lua
local m, t = animation.coverage(hero.id); print(m .. "/" .. t)
```

## modules/animation/declare {#modules-animation-declare}

```lua
declare(entityId: string, facts: { [string]: any })
```

Publish what an animator is running on a body, so the observation names
its clips, playheads and retarget coverage beside the pose the engine
measures. The shipped animators declare through `AnimGraph:publish`; a
custom animator calls this itself, once per frame it runs.

**Parameters**

- `entityId` `string` — The body the animator drives.
- `facts` `{ [string]: any }` — `{ driver, bound, playing, outputKind, failure, clips }`, where
each clip is `{ name, nodeKind, time, duration, playing, finished, looping,
weight, matched, total, unmatched }`.

```lua
animation.declare(body.id, { driver = "MyAnimator", playing = true, clips = {} })
```

## modules/animation/forget {#modules-animation-forget}

```lua
forget(entityId: string)
```

Drop the declaration and the pose evidence the engine holds for one
body. An animator calls this when it releases a body, so the observation
reports the body as undriven from the next frame.

**Parameters**

- `entityId` `string` — The body to drop.

```lua
animation.forget(body.id)
```

## modules/animation/observe {#modules-animation-observe}

```lua
observe(): AnimationObservation
```

Report what the engine is posing right now and why a body is not
moving. One read covering every body the engine holds animation state for,
each with the pose evidence the engine measured on its armature beside the
clips the animator driving it declared. Answers in edit mode as well as
play mode.

```lua
local a = animation.observe(); print(a.animatingCount, a.riggedBodyCount)
for _, b in animation.observe().bodies do print(b.entity, b.animating, b.reason) end
```

## modules/animation/whyStill {#modules-animation-whystill}

```lua
whyStill(entityId: string | EntityRef): (string?, string?)
```

Why the body on an entity is not animating. Returns nil when it IS
animating, and otherwise one of `deactivated`, `noRiggedSkeleton`,
`noGraph`, `clipUnreadable`, `noOutputNode`, `retargetMatchedNoRoles`,
`stopped`, `finished`, `paused`, `poseNotApplied`, `poseUnchanged` — the
nearest cause, so the answer names the thing to change. A second return
carries the animator's own words when it could not build a graph.

An entity the engine holds no animation state for is answered from the
entity itself, in the same order the engine resolves a body it does hold:
one carrying no rigged `Skeleton` is `noRiggedSkeleton`, and a rigged one
nothing drives is `noGraph`. An id no entity carries is neither — the
reason is nil and the detail says so.

**Parameters**

- `entityId` `string | EntityRef` — The entity's stable id, or an EntityRef.

```lua
local why, detail = animation.whyStill(hero.id); if why then print(why, detail) end
```

## modules/antiAliasing/README {#modules-antialiasing-readme}

```lua
require("@builtin/systems/antiAliasing/antiAliasing") -- antiAliasing
```

Edge antialiasing from the finished frame — the stair-stepping along a high-contrast silhouette is replaced by a gradient, without softening the regions on either side of it.

Usage: local antiAliasing = require("@builtin/systems/antiAliasing/antiAliasing")

## modules/antiAliasing/active {#modules-antialiasing-active}

```lua
active(): boolean
```

Whether the antialiasing pass is running this frame.

```lua
if antiAliasing.active() then ... end
```

## modules/antiAliasing/disable {#modules-antialiasing-disable}

```lua
disable()
```

Turn edge antialiasing off and release the pass. The settings are kept,
so a later `enable()` brings back the same tuning.

```lua
antiAliasing.disable()
```

## modules/antiAliasing/enable {#modules-antialiasing-enable}

```lua
enable(opts: AntiAliasingOpts?): AntiAliasingState
```

Turn edge antialiasing on and set it. Any omitted field keeps its
current value.

**Parameters**

- `opts` `AntiAliasingOpts?` _(optional)_ — Antialiasing settings — see `AntiAliasingOpts`.

```lua
antiAliasing.enable({ edgeThreshold = 0.125 })
```

## modules/antiAliasing/get {#modules-antialiasing-get}

```lua
get(): AntiAliasingState
```

The antialiasing settings currently in force.

```lua
local t = antiAliasing.get().edgeThreshold
```

## modules/antiAliasing/paramsBuffer {#modules-antialiasing-paramsbuffer}

```lua
paramsBuffer(): any?
```

The buffer this system's passes read. The render feature binds what
this hands it, so the pass has the values this module packed.

```lua
local p = antiAliasing.paramsBuffer()
```

## modules/ao.shared/README {#shared-readme}

```lua
require("@builtin/systems/ambientOcclusion/aoShared") -- ao.shared
```

The parts every ambient-occlusion technique has in common: the WGSL prelude its kernel is written against, and the render targets, filter and passes that turn a per-pixel visibility term into shading.

A technique differs from its siblings in one thing only: how it estimates,
for one pixel, what fraction of the hemisphere above the surface is
visible. Everything either side of that estimate — reconstructing the
surface from depth and normal, sizing the screen-space reach of a
world-space radius, filtering the result across the noise the estimate
carries, and multiplying it into the frame — is the same work whichever
estimate produced it.
So it lives here once. A technique file is its kernel and nothing else,
which is what makes the three readable against each other.

Usage: local ao.shared = require("@builtin/systems/ambientOcclusion/aoShared")

## modules/ao.shared/feature {#shared-feature}

```lua
feature(name: string, kernel: AssetRef<computeShader>) -> table
```

Build the render feature for one technique from its kernel shader.

**Parameters**

- `name` `string`
- `kernel` `AssetRef<computeShader>`

**Returns** `table`

## modules/ao.shared/scale {#shared-scale}

```lua
scale() -> number
```

The fraction of the frame's resolution the occlusion is computed at.

**Returns** `number`

## modules/ao.shared/setScale {#shared-setscale}

```lua
setScale(scale: number)
```

**Parameters**

- `scale` `number`

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

```lua
require("@builtin/systems/ambientOcclusion/ao") -- ao
```

Screen-space ambient occlusion — the contact darkening in corners, creases and where objects meet. Without it every concave region is lit exactly like a flat one.

Usage: local ao = require("@builtin/systems/ambientOcclusion/ao")

## modules/ao/active {#modules-ao-active}

```lua
active(): boolean
```

Whether the occlusion pass is running this frame.

```lua
if ao.active() then ... end
```

## modules/ao/clear {#modules-ao-clear}

```lua
clear()
```

Turn occlusion off and release the pass. The other settings are kept,
so a later `set({ intensity = ... })` brings back the same look.

```lua
ao.clear()
```

## modules/ao/get {#modules-ao-get}

```lua
get(): AoState
```

The occlusion settings currently in force.

```lua
local r = ao.get().radius
```

## modules/ao/paramsBuffer {#modules-ao-paramsbuffer}

```lua
paramsBuffer(): any?
```

The buffer the AO kernel reads. It belongs to whichever technique is
running, and is remade when the technique swaps, so the pass binds what this
hands it rather than looking it up.

```lua
local p = ao.paramsBuffer()
```

## modules/ao/qualityLevels {#modules-ao-qualitylevels}

```lua
qualityLevels(): { [string]: { slices: number, steps: number, scale: number } }
```

What each quality level costs: `slices` × `steps` taps per pixel (total
`slices * steps * 2`, the same for every technique), computed on a grid
`scale` of the frame's resolution.

```lua
local cost = ao.qualityLevels().ultra
```

## modules/ao/set {#modules-ao-set}

```lua
set(opts: AoOpts?): AoState
```

Set the scene's ambient occlusion. Any omitted field keeps its current
value, so a call can adjust one knob without restating the rest. An
`intensity` of 0 turns occlusion off and releases the pass.

**Parameters**

- `opts` `AoOpts?` _(optional)_ — Occlusion settings — see `AoOpts`.

```lua
ao.set({ technique = "hbao", intensity = 0.9, radius = 1.5 })
```

## modules/ao/techniques {#modules-ao-techniques}

```lua
techniques(): { [string]: string }
```

The techniques that can be selected, each with what it does.

```lua
for name in pairs(ao.techniques()) do print(name) end
```

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

```lua
require("@builtin/modules/api/engine/asset") -- asset (also available as global 'asset')
```

Asset resolver, ref envelope builder, sidecar metadata. Public Luau surface over the `__asset` Internal FFI namespace.

Usage: local asset = require("@builtin/modules/api/engine/asset")
Also available as global: asset

## modules/asset/add_tag {#modules-asset-add-tag}

```lua
add_tag(ref: RefArg, tag: string)
```

Add a tag to the asset's `.metadata.tags`. Idempotent.
Creates the sidecar and the tags array if missing.

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `tag` `string` — Tag to add.

```lua
asset.add_tag("brick", "wip")
```

## modules/asset/alias {#modules-asset-alias}

```lua
alias(ref: RefArg, alias: string): boolean
```

Add a name the asset answers to. `asset.resolve`, leaf
shorthand, and the typed-argument coercion that content refs
travel through all reach the asset by the alias from here on,
exactly as they do by its identity — so a material naming a
shader by its alias resolves, and content written against an
older name keeps working after a rename. The name survives
writes to the asset's own files.
Raises when the name already resolves to a DIFFERENT asset — an
alias extends the identity namespace and never takes a name out
of another asset's hands — and when it is shaped like a guid or
a VFS path, forms that resolve before identity lookup, so an
alias in that shape could never answer.

**Parameters**

- `ref` `RefArg` — The asset gaining the name.
- `alias` `string` — The additional name. Any identity form: a bare leaf
(`standard`) or a scope-qualified path (`@builtin::shaders.legacy`).

```lua
asset.alias("@builtin::shaders.pbr", "standard")
```

## modules/asset/aliases {#modules-asset-aliases}

```lua
aliases(ref: RefArg): { string }
```

The additional names this asset answers to, beyond its own
identity — what `asset.alias` registered, plus the
package-relative `~pkg.tail` form when the asset lives inside a
package.

**Parameters**

- `ref` `RefArg` — Any name the asset has.

```lua
for _, n in asset.aliases("pbr") do print(n) end
```

## modules/asset/canCreate {#modules-asset-cancreate}

```lua
canCreate(typeName: string): boolean
```

Whether `asset.create` can instance `typeName`: the type declares
creation logic (a `behavior.luau` `onCreate` hook) or ships a
`template/` skeleton the hookless fallback clones. A type with neither
— one whose instances only arrive by import — answers false. The query
a creation UI derives its offering from, so what it offers is what
`asset.create` accepts.

**Parameters**

- `typeName` `string` — Registered asset type (e.g. "material", "scene").

```lua
if asset.canCreate(kind) then asset.create(kind, name) end
```

## modules/asset/categories {#modules-asset-categories}

```lua
categories(): { string }
```

List every asset category the engine currently recognises.
Use to discover valid `type` argument values for the rest of
`asset.*`.

```lua
for _, c in asset.categories() do print(c) end
```

## modules/asset/containing {#modules-asset-containing}

```lua
containing(path: string): AssetRef?
```

Walk `path`'s ancestors and return an `AssetRef` handle for
the OUTERMOST category-folder containing it (e.g. `main.scene`
for `"/source/scenes/main.scene/scene.json"`). Returns nil for
paths outside any registered asset type.

**Parameters**

- `path` `string` — VFS path to inspect.

```lua
local a = asset.containing("/source/scenes/main.scene/scene.json")
```

## modules/asset/cpuResident {#modules-asset-cpuresident}

```lua
cpuResident(ref: RefArg, typeName: string?): boolean
```

True when the asset is CPU-resident — a live script-component context
holds it (a component's assetRef field, or an imperative
`asset.resolve`/`ref` made while a component is the caller), which is what
warms its bytes into memory. The CPU pool is a different pool from the
device's: `asset.observe().cpu` lists it, `asset.observe().textures` /
`.meshes` list what the device holds, and an asset can be in one and not
the other.

**Parameters**

- `ref` `RefArg` — Any name the asset has — handle, identity, guid, name or path.
- `typeName` `string?` _(optional)_ — Category to restrict the match to. Omit to search every category.

```lua
if asset.cpuResident(ref) then print("bytes are warm") end
```

## modules/asset/create {#modules-asset-create}

```lua
create(typeName: string, name: string, opts: { [string]: any }?): (AssetRef, { durable: boolean, warning: string?, playShadow: string?, shadowed: { string }? })
```

Instance a new asset of an existing type. Runs the type's
`behavior.luau` `onCreate(name, opts)` hook to produce the asset's
files, then writes them under `/source/<name>.<type>/`. This is the
single generic asset-creation API. Refuses to clobber an existing
edit-mode asset unless `opts.overwrite = true`, which re-authors it in
place and keeps the existing guid (only the checksum changes). Pairs with
`asset.exists` for content generators that re-run over the same names.

A create made from a script component's callback or a scene entrypoint is
output the world reproduces on every load, so it is filed in the ephemeral
`/runtime/assets/` store instead, where the saved manifest never carries a
second copy of it. `name` and `folder` spell the same IDENTITY in either
store, so a reference written against that identity resolves the asset
wherever the call filed it, and one generator run from an `execute` and
from a component names one asset.

**Parameters**

- `typeName` `string` — The asset category to instance — one of `asset.categories()`.
- `name` `string` — The new asset's name.
- `opts` `{ [string]: any }?` _(optional)_ — Optional table forwarded to the type's `onCreate` hook, minus four
framework keys consumed here and never seen by the hook:
`folder` (a relative subfolder under `/source` to author the asset in, so
generated content groups instead of accumulating at the source root, and
the asset's identity carries that folder as its dotted prefix),
`into` (author INSIDE a resolved container ref), `dest` (an absolute
destination path), and `overwrite` (re-author in place, keeping the guid).

```lua
local m = asset.create("material", "brick", { shader = "pbr" })
local mesh = asset.create("mesh", "tree", { positions = {...}, indices = {...} })
local mesh = asset.create("mesh", "rock", { positions = {...}, indices = {...}, folder = "terrain/props" })
local mesh = asset.create("mesh", name, { positions = p, indices = i, overwrite = true }) -- idempotent rebuild
local clip, d = asset.create("soundClip", "hit", { pcm = buf, sampleRate = 48000, channels = 1 })
if not d.durable then log.warn(d.warning .. " " .. d.playShadow) end
```

## modules/asset/declareReferenceArg {#modules-asset-declarereferencearg}

```lua
declareReferenceArg(call: string, position: number, assetType: string)
```

Declare that `call`'s argument at 1-based `position` names an
asset of `type`, so a string literal written there is recorded as a
reference. The positional counterpart of
`asset.declareReferenceField`, for a call that takes its asset as a
plain argument — including a world's own spawn helper, which is
where a name most often stops being visible to the reference graph.
A lookup whose asset is its FIRST argument (`asset.resolve` and its
siblings) is already read and needs no declaration. Only a literal —
or a name the file holds in a top-level string constant — is
recorded; anything computed is reported as a dynamic resolve.

**Parameters**

- `call` `string` — The callee as it is written at a call site.
- `position` `number` — Which argument holds the name, counting from 1.
- `assetType` `string`

```lua
asset.declareReferenceArg("spawnModel", 3, "mesh")
```

## modules/asset/declareReferenceField {#modules-asset-declarereferencefield}

```lua
declareReferenceField(call: string, field: string, assetType: string)
```

Declare that `call`'s options table names an asset of `type` in
its `field`, so a string literal written there is recorded as a
reference by whatever writes the file. This is what puts an API
that takes an asset BY NAME into the reference graph: the named
asset becomes a dependency, travels with the content that names it
into a pack or a pull, and a name nothing answers to becomes an
unresolved dependency `worldValidation` reports and the push gate
refuses. A field holding a TABLE of names — a material's `textures`
— records every name in it. Declare once, beside the API; a call
taking its asset as the FIRST positional argument is already read
and needs no declaration. Only a literal is recorded; a computed
name resolves at runtime and is reported as a dynamic resolve.

**Parameters**

- `call` `string` — The callee as it is written at a call site.
- `field` `string` — The options-table field holding the name, read at the
table's own level.
- `assetType` `string`

```lua
asset.declareReferenceField("fx.beam", "material", "material")
```

## modules/asset/declareReferenceKey {#modules-asset-declarereferencekey}

```lua
declareReferenceKey(assetType: string, key: string, refType: string)
```

Declare that, in a data file belonging to an `assetType` asset,
the top-level `key` names an asset of `type` — a `.material`'s
`mat.yaml` naming the shader it draws with and the textures it
binds. The names a format holds are references as surely as ones
written in code: recording them carries a material's shader along
with the material into a pack or a pull, and turns a name nothing
answers to into an unresolved dependency instead of a surface that
renders as the magenta error material. A key holding a table of
names records one per entry.

**Parameters**

- `assetType` `string` — The category owning the file, e.g. "material".
- `key` `string` — The top-level key holding the name(s).
- `refType` `string`

```lua
asset.declareReferenceKey("material", "shader", "shader")
```

## modules/asset/deps {#modules-asset-deps}

```lua
deps(ref: RefArg, type: string?): DepsResult
```

Return the asset's outbound dependency graph — every other
asset recorded as a content dependency of it.

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `type` `string?` _(optional)_ — Category hint (optional).

```lua
for _, d in asset.deps("main.scene").deps do print(d.asset_guid) end
```

## modules/asset/describe {#modules-asset-describe}

```lua
describe(typeName: string): DescribeResult
```

The creation contract for an asset type: the parameters its
`onCreate(name, opts)` hook accepts, as data. `kind` is "schema"
(typed contract), "legacy" (untyped opts — anything passes), "none"
(template scaffold — takes no opts), or "error" (the type's schema
failed to parse; `error` says why). `contract` is the human-readable
rendering validation errors print.

**Parameters**

- `typeName` `string` — Registered asset type to describe (e.g. "texture").

```lua
local contract = asset.describe("texture").contract
```

## modules/asset/diagnose {#modules-asset-diagnose}

```lua
diagnose(ref: RefArg): any
```

Why one asset can or cannot be used, read from the engine rather than
from what the caller asked for. Always carries `usable`; when false,
`reason` is one of `asset.unusableReasons()` and `detail` is the engine's
own message. `primary` names the file the type's declared `primary` list
resolved to, so an asset that loaded a preview image instead of its
payload shows the wrong filename rather than a successful load. The
payload's bytes are read by the engine's own decoder wherever it has one
for that container, so `usable` is the verdict a load would reach and the
call costs that decode.

**Parameters**

- `ref` `RefArg` — Any name the asset has — handle, identity, guid, name or path.

```lua
local d = asset.diagnose("myTex") if not d.usable then print(d.reason, d.detail) end
```

## modules/asset/exists {#modules-asset-exists}

```lua
exists(name: string, typeName: string): boolean
```

**Parameters**

- `name` `string`
- `typeName` `string`

## modules/asset/get_field {#modules-asset-get-field}

```lua
get_field(ref: RefArg, key: string): any
```

Read one top-level field from the asset's `.metadata`.

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `key` `string` — Field name.

```lua
local author = asset.get_field("brick", "author")
local settings = asset.get_field("tree", "settings") -- → a Luau table
```

## modules/asset/gpuResident {#modules-asset-gpuresident}

```lua
gpuResident(ref: RefArg): boolean
```

True when the device holds a texture or mesh under this asset's guid,
read off the inventory the renderer publishes.

**Parameters**

- `ref` `RefArg` — Any name the asset has — handle, identity, guid, name or path.

```lua
print(asset.gpuResident("@builtin::models.Sample.DamagedHelmet"))
```

## modules/asset/guid {#modules-asset-guid}

```lua
guid(ref: RefArg, type: string?): string
```

Return the guid for an asset.

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `type` `string?` _(optional)_ — Category hint (optional).

```lua
local g = asset.guid("@builtin::components.Camera")
```

## modules/asset/has_field {#modules-asset-has-field}

```lua
has_field(ref: RefArg, key: string): boolean
```

True when the asset's `.metadata` carries the named field.

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `key` `string` — Field name.

```lua
if asset.has_field("brick", "author") then end
```

## modules/asset/has_tag {#modules-asset-has-tag}

```lua
has_tag(ref: RefArg, tag: string): boolean
```

True when the asset's `.metadata.tags` contains `tag`.

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `tag` `string` — Tag to check for.

```lua
if asset.has_tag("brick", "wip") then end
```

## modules/asset/identity {#modules-asset-identity}

```lua
identity(ref: RefArg, type: string?): string
```

Return the canonical identity for an asset.

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `type` `string?` _(optional)_ — Category hint (optional).

```lua
local id = asset.identity("brick")
```

## modules/asset/import {#modules-asset-import}

```lua
import(path: string): string?
```

Import a raw source file NOW and return the produced asset path
(a `.bundle` for a model, `.texture` for an image, `.audio` for a
sound, …), or nil if no importer claims it. This is the deterministic,
on-demand counterpart to the engine's automatic import-on-write: it runs
in the calling task and returns only when the import is complete. Pair it
with a quiet write — `vfs.write(path, bytes, { quiet = true })` lands the
raw bytes without firing the automatic importer, then `asset.import(path)`
imports them under your control, so you can act on the result instead of
polling for the import to appear.

**Parameters**

- `path` `string` — The raw source VFS path to import (e.g. a just-written `.glb`).

```lua
local bundle = asset.import("/zero/source/generated/chest.glb")
```

## modules/asset/inspect {#modules-asset-inspect}

```lua
inspect(ref: RefArg, type: string?): InspectRecord
```

Everything known about one asset in a single record: identity, guid,
source, type, scope and origin, its description and tags, the ref methods
its type exposes, and the type's own `inspect` detail when it declares one.
The read-everything counterpart to `asset.resolve`, which hands back a ref.

**Parameters**

- `ref` `RefArg` — An `AssetRef`, an identity string, or a path.
- `type` `string?` _(optional)_ — Narrow the resolve to one asset type when assets of several
categories answer to the same bare name.

```lua
local rec = asset.inspect("@builtin::materials.default")
local rec = asset.inspect(name, "mesh"); print(rec.guid, #rec.tags)
```

## modules/asset/list {#modules-asset-list}

```lua
list(type_or_opts: (AssetCategory | ListOpts)?, scope: string?, opts: ListOpts?): ListResult
```

Query registered assets, returning each match as a resolved
`AssetRef` handle. Every filter narrows the same enumeration and
they compose: `path` selects a VFS subtree (the folder and
everything under it), `type` keeps only those asset types within
it, `scope` keeps only that scope, and `fields` keeps only assets
whose `.metadata` matches. `type` and `path` each take one value or
a list matching any of its entries, and `all` / `any` / `none`
group whole filters — `none` excludes what it matches. `order`,
`limit`, and `offset` shape the result: matches come back ordered
by identity unless `order` names another field
(`name` / `path` / `type` / `guid`).
Each entry is the same envelope `asset.resolve` returns (`__ref` /
`type` / `name` / `guid` / `identity` / `path`), so it can be passed
anywhere an AssetRef is accepted, and the result carries
`:first()` / `:random()` / `:filter()` / `:sort()` and friends.
`type` takes the same values `asset.categories()` lists. The first
positional argument is a path when it is absolute, a type
otherwise. An unknown key raises, as does a table setting both
`type` and its older spelling `category`.
A static (literal) type or path makes the enumeration part of the
calling file's content dependencies when it is saved — the set
travels with published content, so consumers get at-least the
authoring world's assets.

**Parameters**

- `type_or_opts` `(AssetCategory | ListOpts)?` _(optional)_ — Type or VFS path filter (a static literal so the
enumeration can be captured for publish), or the full query table.
- `scope` `string?` _(optional)_ — Scope filter (when first arg is a type).
- `opts` `ListOpts?` _(optional)_ — The query table — see `ListOpts`.

```lua
local hero = asset.list({ path = "/zero/source/props", type = "mesh", fields = { tags = "hero" } }):first()
```

## modules/asset/list_field_values {#modules-asset-list-field-values}

```lua
list_field_values(key: string): { any }
```

Distinct values seen for the named field across every
asset's `.metadata`.

**Parameters**

- `key` `string` — Field name.

```lua
local authors = asset.list_field_values("author")
```

## modules/asset/list_fields {#modules-asset-list-fields}

```lua
list_fields(): { string }
```

Distinct top-level field keys observed across every asset's
`.metadata`. Useful for tooling discovering custom keys in use.

```lua
for _, k in asset.list_fields() do print(k) end
```

## modules/asset/meta {#modules-asset-meta}

```lua
meta(ref: RefArg, type: string?): AssetMeta
```

Read the asset's engine-owned identity record (guid /
checksum). Distinct from `.metadata` (agent-editable);
for that use `asset.metadata`.

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `type` `string?` _(optional)_ — Category hint (optional).

```lua
local m = asset.meta("brick") -- { guid = ..., checksum = ... }
```

## modules/asset/metadata {#modules-asset-metadata}

```lua
metadata(ref: RefArg, type: string?): AssetMeta
```

Read the asset's agent-editable `.metadata` sidecar as a
Lua table. Missing sidecar returns `{}`. Distinct from
`asset.meta` (engine-owned).

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `type` `string?` _(optional)_ — Category hint (optional).

```lua
local md = asset.metadata("brick")
```

## modules/asset/observe {#modules-asset-observe}

```lua
observe(): any
```

What the engine is holding for content right now, in one reading:
`textures` and `meshes` (one row per resource the device holds, each with
the bytes it costs, its dimensions or buffer split, and where it came
from), `cpu` (one row per asset a live script-component context holds),
and `totals` — the aggregates those rows sum to, so the listing reconciles
against `renderer.textureMemory()` and `renderer.gpuMemory()`.

Each pool is named because they are different pools: an asset can be on
the device and not CPU-resident, or the reverse. `devicePublished` is
false when no renderer has published an inventory and `cpuPublished` when
the scripting VM has not published its pool — an engine that cannot answer
reads differently from one answering with nothing resident.

```lua
local r = asset.observe() print(#r.textures, r.totals.textureBytes)
```

## modules/asset/preview {#modules-asset-preview}

```lua
preview(ref: RefArg, opts: { [string]: any }?, type: string?): { [string]: any }
```

Render a preview of an asset. Resolves the ref and dispatches to its
type's `preview` ref-method when present; otherwise returns the
`{ available = false }` sentinel ("no preview available for this type").

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `opts` `{ [string]: any }?` _(optional)_ — Optional `{ size = { width, height }, angle = { yaw, pitch } }`.
- `type` `string?` _(optional)_ — Category hint (optional).

```lua
local p = asset.preview("@builtin::materials.gold", { size = { width = 512, height = 512 } })
```

## modules/asset/primaryFile {#modules-asset-primaryfile}

```lua
primaryFile(ref: RefArg): any
```

The file the asset type's declared `primary` list resolves to inside
this asset, as the loader itself resolves it. `resolved` is false when no
declaration matched and `path` is then absent; `declared` is the type's
own primary list in match order.

**Parameters**

- `ref` `RefArg` — Any name the asset has — handle, identity, guid, name or path.

```lua
print(asset.primaryFile("myTex").path)
```

## modules/asset/ref {#modules-asset-ref}

```lua
ref(ref: RefArg, type: string?): AssetRef
```

Build a reference handle for an asset — the canonical ref
envelope constructor. Identical shape to `asset.resolve`;
preferred name for the author-side use case (embedding refs in
YAML / JSON / Luau output).

Naming the asset here reads exactly as naming it in `asset.resolve`,
down to raising on a miss: a literal is recorded as this source's
dependency, a computed name is a dynamic resolve — free in a tool,
refused on the gameplay path. `asset.exists(name, type)` is the probe a
computed name can ask.

**Parameters**

- `ref` `RefArg` — The asset to reference — an identity, a guid, a VFS path, or a handle.
- `type` `string?` _(optional)_ — Category hint (optional).

```lua
local r = asset.ref("animations.idle", "animation")
```

## modules/asset/reloadPending {#modules-asset-reloadpending}

```lua
reloadPending(ref: RefArg, typeName: string?): boolean
```

True while a write to this asset still owes it a reload — the write is
inside the settle window that collects one authoring step's writes, or its
reload is queued and the engine has not run it yet. False means every
content change written so far has reached its subscribers, so a consumer
bound to the asset now cannot be interrupted by a reload the earlier
writes already earned. The recording is synchronous with the write, so a
call made right after one already reads true.

**Parameters**

- `ref` `RefArg` — Any name the asset has — handle, identity, guid, name or path.
- `typeName` `string?` _(optional)_ — Category to restrict the match to. Omit to search every category.

```lua
repeat task.wait() until not asset.reloadPending(ref)
```

## modules/asset/reloadSeq {#modules-asset-reloadseq}

```lua
reloadSeq(ref: RefArg, typeName: string?): number
```

How many content-change reloads this asset has been through — the
count of `onAssetReload` dispatches the engine has RUN for it. A write to
a file inside an asset does not reload it on the spot: the writes of one
authoring step are collected for a settle window and the reload runs on a
later frame. Read this, write, then poll for a larger number to learn the
write's reload has actually reached subscribers. Monotonic per asset and
session-scoped; 0 for an asset whose content has not changed since boot.

**Parameters**

- `ref` `RefArg` — Any name the asset has — handle, identity, guid, name or path.
- `typeName` `string?` _(optional)_ — Category to restrict the match to. Omit to search every category.

```lua
local at = asset.reloadSeq(ref)
vfs.write(asset.source(ref) .. "/graph.json", encoded)
repeat task.wait() until asset.reloadSeq(ref) > at
```

## modules/asset/remove_field {#modules-asset-remove-field}

```lua
remove_field(ref: RefArg, key: string)
```

Remove one top-level field from the asset's `.metadata`.
No-op when the field isn't present.

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `key` `string` — Field name.

```lua
asset.remove_field("brick", "author")
```

## modules/asset/remove_tag {#modules-asset-remove-tag}

```lua
remove_tag(ref: RefArg, tag: string)
```

Remove a tag from the asset's `.metadata.tags`. No-op when
the tag isn't present.

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `tag` `string` — Tag to remove.

```lua
asset.remove_tag("brick", "wip")
```

## modules/asset/resolve<C> {#modules-asset-resolve-c}

```lua
resolve<C>(ref: RefArg, type: (C & string)?): AssetRef<C>
```

Find an asset. The returned handle carries every name form
the asset has (`guid`, `identity`, `path`, `type`) so
downstream code can read any one of them without calling
`resolve` again. Raises when `ref` resolves to no asset — or, with a
`type`, to no asset of that type — and when `ref` reaches more than one
asset, where it names the candidates for you to pick from instead of
picking one of them. A `<scope>::`-qualified identity reaches exactly one:
`@root::name` for the asset this world holds at its source root, the
library identity (`@builtin::…`) for a library's. For the same lookup
answering a miss with nil, use `asset.tryResolve(ref, type)`.

A name written as a string LITERAL is recorded as this source's
dependency on that asset, so the asset travels with the content and
still resolves once someone installs it in another world. A COMPUTED
name cannot be written down, so nothing pins what it reaches: that is a
dynamic resolve — free in a tool, refused on the gameplay path (a
component or scene entrypoint). `asset.tryResolve`, `asset.ref` and
`asset.source` read the name they are given exactly this way too, so
which of the four you reach for changes neither answer. To ask whether a
computed name has files without reaching a handle, use
`asset.exists(name, type)`.

**Parameters**

- `ref` `RefArg` — The asset to find — an identity, a guid, a VFS path, or a handle.
- `type` `(C & string)?` _(optional)_ — Category to restrict the match to (optional). Separates a bare
name that assets of different categories share (`asset.resolve("cube",
"mesh")`); where several assets of the SAME category answer to it, the
scope-qualified identity is what separates them.
A reference naming a file an importer has since promoted (`wall.png`
after the texture importer turned it into `wall.texture`) resolves to the
promoted asset, and says so in the log once per reference.

```lua
local a = asset.resolve("@builtin::components.Camera")
```

## modules/asset/set_field {#modules-asset-set-field}

```lua
set_field(ref: RefArg, key: string, value: any)
```

Set one field in the asset's `.metadata`, creating the sidecar if missing.
Sibling fields are preserved. When the new value AND the existing value are
both maps (objects), the new value DEEP-MERGES into the existing one, so
writing one sub-key never drops the others — `set_field(ref, "settings",
{ keepCpu = true })` keeps every other setting. Arrays and scalars replace.
Clear a whole field with `asset.remove_field`; replace the entire sidecar with
`asset.set_metadata`.

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `key` `string` — Field name.
- `value` `any` _(optional)_ — Field value (any JSON-serialisable Lua value).

```lua
asset.set_field("brick", "author", "me")
asset.set_field("tree", "settings", { keepCpu = true }) -- merges; sibling settings kept
```

## modules/asset/set_metadata {#modules-asset-set-metadata}

```lua
set_metadata(ref: RefArg, data: AssetMeta)
```

Replace the asset's `.metadata` sidecar with the given
table. Pass an empty table to clear all fields.

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `data` `AssetMeta` — Full JSON-shaped contents for the sidecar.

```lua
asset.set_metadata("brick", { author = "me", tags = { "wip" } })
```

## modules/asset/source {#modules-asset-source}

```lua
source(ref: RefArg, type: string?): string
```

Return the VFS source path for an asset.

It reaches the asset, so the name carries the same reference contract
`asset.resolve`'s does: a literal is recorded as this source's
dependency, a computed name is a dynamic resolve — free in a tool,
refused on the gameplay path. `asset.exists(name, type)` is the probe a
computed name can ask.

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `type` `string?` _(optional)_ — Category hint (optional).

```lua
local p = asset.source("brick") -- "/source/brick.material"
```

## modules/asset/storeHoldsIdentity {#modules-asset-storeholdsidentity}

```lua
storeHoldsIdentity(identity: string, typeName: string, reproduced: boolean): boolean
```

Whether an asset of type `typeName` that `name` reaches has files in
the store `asset.create` writes from this context — the authored `/source`
tree, plus the ephemeral `/runtime/assets/` store when the caller is a
script component or a scene entrypoint, which is where a create there
files it. `name` is any name the registry answers to for that asset: its
canonical identity (`"a.b.thing"`), a registered alias, or the bare leaf
(`"thing"`) — the spelling `asset.list` publishes as an entry's `name` and
the spelling `asset.create` was given alongside `opts.folder`. So the
`if not asset.exists(n, t) then asset.create(t, n, opts) end` pairing is
satisfied by its own create, spelled the way the create was, in either
store and at any folder depth. A plain existence probe — it does NOT
resolve a handle or pin a content dependency, so it is safe to call with a
COMPUTED name (unlike `asset.resolve`, whose handle would become a
static-pinned dependency).

The name is read the way `asset.resolve` reads one; the ANSWER comes from
the store, so a registered asset whose files live outside the store this
context writes — every `@builtin::` asset among them — is `false`.
`asset.tryResolve(name, typeName)` asks the registry the wider question
and hands back the handle — and because it reaches the asset, the name it
is given follows the reference rule every lookup follows: a literal is
pinned, a computed one is a dynamic resolve. So a name this source
computed is what `asset.exists` is for.
This call names the asset FIRST and its category second, as every
`asset.*` call taking both does except `asset.create(category, name,
opts)`. A call carrying a category where the asset goes and a non-category
where the category goes is refused, naming which way round the call reads,
rather than reporting the asset absent.

**Parameters**

- `identity` `string`
- `typeName` `string` — The asset type (e.g. "mesh", "texture", "material") — one of
`asset.categories()`.
- `reproduced` `boolean`

```lua
if not asset.exists(meshName, "mesh") then asset.create("mesh", meshName, geo) end
if not asset.exists(n, "mesh") then asset.create("mesh", n, { folder = "props", positions = p, indices = i }) end
```

## modules/asset/tags {#modules-asset-tags}

```lua
tags(ref: RefArg): { string }
```

Convenience read of the `.metadata.tags` array.

**Parameters**

- `ref` `RefArg` — Any name the asset has.

```lua
for _, t in asset.tags("brick") do print(t) end
```

## modules/asset/tryResolve {#modules-asset-tryresolve}

```lua
tryResolve(ref: RefArg, type: string?, base: string?): AssetRef?
```

The same lookup `asset.resolve` performs, answering a miss with nil
instead of raising. Every name form, the same `type` narrowing, and the
same handle on success — so "use it if it is there" needs no `pcall`
around a call whose failure would otherwise be indistinguishable from a
real error.

This consults the asset REGISTRY, so it sees registered assets wherever
their files live, `@builtin::` ones included. `asset.exists(name, type)`
answers the narrower question of whether an asset's files are present in
the current mode's store.

A name that reaches more than one asset still raises — that is a question
about the reference, not about presence, and a nil there would report
absence for content that is present twice.

It reaches the asset, so the name carries the same reference contract
`asset.resolve`'s does: a literal is recorded as this source's
dependency, a computed name is a dynamic resolve — free in a tool,
refused on the gameplay path. `asset.exists(name, type)` is the probe a
computed name can ask.

**Parameters**

- `ref` `RefArg` — The asset to look up — an identity, a guid, a VFS path, or a handle.
- `type` `string?` _(optional)_ — Category to restrict the match to (optional).
A reference naming a file an importer has since promoted resolves to the
promoted asset, the same as `asset.resolve`.
- `base` `string?` _(optional)_ — Referring VFS path a `~` / `~.tail` ref expands against, the same
as `asset.resolve`'s — so the two answer the same question and differ only
in what a miss is.

```lua
local mat = asset.tryResolve(name, "material")
```

## modules/asset/typeRef {#modules-asset-typeref}

```lua
typeRef(target: RefArg): string?
```

Return the pinned asset_type reference (the type's guid)
that the asset is an instance of. Resolve the full type with
`asset.resolve(asset.typeRef(target))`. Returns nil for loose
files / assets with no pinned type.

**Parameters**

- `target` `RefArg` — Asset handle / identity / guid / VFS path.

```lua
local t = asset.resolve(asset.typeRef("brick"))
```

## modules/asset/unusableReasons {#modules-asset-unusablereasons}

```lua
unusableReasons(): { string }
```

Every reason `asset.diagnose` can report an asset unusable for, sorted.

```lua
for _, r in ipairs(asset.unusableReasons()) do print(r) end
```

## modules/asset/validate {#modules-asset-validate}

```lua
validate(ref: RefArg, type: string?): ValidateResult
```

Validate an asset folder against its type's `type.yaml`, plus
the type's own semantic validation. Structural problems come from
`type.yaml` — missing required files, unsatisfied `one_of_group`
alternatives, and (when `allow_unlisted: false`) unexpected
children. `validated = false` when no `type.yaml` is registered
— nothing structural to check. On top of that, when the asset's
type ships a `behavior.luau` exporting a top-level
`validate(assetRef) -> { { code, message, severity? } }`, its
reported problems (severity defaults to `"error"`) are appended to
`problems`; error-severity problems flip `ok` to false, warnings
leave it untouched. A hook that raises or returns a non-table is
itself reported as a `validate.hook_failed` error problem — a
broken hook blocks. A type with no `validate` export behaves
exactly as the structural check alone.
`world.push` calls this per user asset, so a type's semantic
validation is enforced at publish time with no further wiring.

**Parameters**

- `ref` `RefArg` — Any name the asset has.
- `type` `string?` _(optional)_ — Category hint (optional).

```lua
local v = asset.validate("@builtin::components.Camera")
```

## modules/asset/warmup {#modules-asset-warmup}

```lua
warmup(ref: RefArg, opts: WarmupOpts?): WarmupResult
```

Warm an asset's bytes into CPU memory and follow its declared
content dependencies to each referenced asset, deduped by
guid. Type-agnostic (reads the generic ref graph) and CPU-only —
never touches the GPU. Side-effect-free name resolution (uses
`asset.guid`/`asset.deps`, not `asset.resolve`).

**Parameters**

- `ref` `RefArg` — Any name the root asset has — handle, identity, guid, or path.
- `opts` `WarmupOpts?` _(optional)_ — Optional `{ vias, max }` — restrict ref-edge kinds / cap closure size.

```lua
local w = asset.warmup("@builtin::scenes.test_arena")
```

## modules/asset_tag/README {#modules-asset-tag-readme}

```lua
asset_tag
```

The `assetTag` field-constraint validator: a constrained value must be an asset carrying `constraint.tag` in its `.metadata.tags`. This is what lets a slot declare the KIND of asset it takes — a camera behavior, a player visual — without naming the assets themselves, so a new asset becomes assignable the moment it is tagged. Registers itself with the generic field_constraints registry on load. `nil` (no asset) passes — the field is optional.

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

```lua
require("@builtin/systems/atmosphere/atmosphere") -- atmosphere
```

Physically-based atmospheric scattering — aerial perspective on distant geometry, and a sky whose colour follows from the sun's elevation rather than from an authored gradient.

Usage: local atmosphere = require("@builtin/systems/atmosphere/atmosphere")

## modules/atmosphere/active {#modules-atmosphere-active}

```lua
active(): boolean
```

Whether the atmosphere passes are currently running.

```lua
if atmosphere.active() then print("scattering") end
```

## modules/atmosphere/clear {#modules-atmosphere-clear}

```lua
clear()
```

Turn the atmosphere off and release its passes. The other settings are
kept, so a later `set({ aerial = ... })` brings back the same look.

```lua
atmosphere.clear()
```

## modules/atmosphere/get {#modules-atmosphere-get}

```lua
get(): AtmosphereState
```

The atmosphere settings currently in force.

```lua
local km = atmosphere.get().worldUnitsPerKm
```

## modules/atmosphere/paramsBuffer {#modules-atmosphere-paramsbuffer}

```lua
paramsBuffer(): any?
```

The buffer this system's passes read. The render feature binds what
this hands it, so the pass has the values this module packed.

```lua
local p = atmosphere.paramsBuffer()
```

## modules/atmosphere/set {#modules-atmosphere-set}

```lua
set(opts: AtmosphereOpts?): AtmosphereState
```

Set the scene's atmosphere. Any omitted field keeps its current value,
so a call can adjust one knob without restating the rest. With `aerial` at
0 and `sky` off nothing is wanted and the passes are released.

**Parameters**

- `opts` `AtmosphereOpts?` _(optional)_ — Atmosphere settings — see `AtmosphereOpts`.

```lua
atmosphere.set({ aerial = 1, sky = true, worldUnitsPerKm = 1000 })
```

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

```lua
require("@builtin/modules/api/engine/audio") -- audio (also available as global 'audio')
```

Engine-native audio: encode audio (or raw PCM) into the ZAUD compressed payload, decode/inspect it, set what the mix is heard at — a level per named channel, a master level and a mute — and observe what the mixer is making audible right now: live voices, why a source is silent, master levels, mixer voice accounting, listener state and subsystem cost.

Usage: local audio = require("@builtin/modules/api/engine/audio")
Also available as global: audio

## modules/audio/decode {#modules-audio-decode}

```lua
decode(zaud: buffer | string): (string?, number?, number?)
```

Decode a ZAUD payload into interleaved f32 PCM. A PCM payload comes
back as the frames its header accounts for, held to the whole frames the
bytes behind it fill, so the sample count is always a whole number of
`channels` and a consumer walking it `channels` at a time ends on a frame.

**Parameters**

- `zaud` `buffer | string` — A ZAUD payload — a buffer or a binary string.

## modules/audio/device {#modules-audio-device}

```lua
device(): AudioDeviceStatus
```

What the engine's audio output is doing: `state` is `"open"` while a
stream is running on an output device and `"silent"` while none is, and
`device` names the device an open stream runs on. The counters record
what the engine has been through keeping one open — `faults` a live
stream reported, `changes` of the host's default output, `reopens` the
engine made, `failedOpens` the platform refused, and the `glitches` a
listener heard as dropouts, with `lastError` carrying what the platform
said. A device that goes away leaves the mixer running and the engine
opening a stream again as soon as one is there.

```lua
local d = audio.device(); print(d.state, d.device, d.reopens)
```

## modules/audio/encode {#modules-audio-encode}

```lua
encode(sourceBytes: buffer | string, opts: { [string]: any }?): (string?, string?)
```

Encode container audio bytes (ogg / mp3 / wav / flac) into a ZAUD
payload. Every decoded sample must be finite; a source whose samples carry
a NaN or an infinity comes back as `(nil, err)` naming how many fail and
where the first one sits.

**Parameters**

- `sourceBytes` `buffer | string` — Encoded source audio bytes — a buffer or a binary string.
- `opts` `{ [string]: any }?` _(optional)_ — `{ codec: "opus"|"pcm"?, bitrateKbps: number?, vbr: boolean?, sampleRate: number?, forceMono: boolean?, loopStart: number?, loopEnd: number? }`

```lua
local zaud = audio.encode(oggBytes, { bitrateKbps = 96 })
```

## modules/audio/encodePcm {#modules-audio-encodepcm}

```lua
encodePcm(pcm: any, sampleRate: number, channels: number, opts: { [string]: any }?): (string?, string?)
```

Encode raw interleaved f32 PCM into a ZAUD payload. Every sample must
be finite; a buffer carrying a NaN or an infinity comes back as
`(nil, err)` naming how many fail and where the first one sits, so a
filter that diverged over part of a bake is caught before it is written.
The sample count is a whole number of `channels`: a buffer with a tail
over comes back as `(nil, err)` naming the whole frames it holds and the
samples past them.

**Parameters**

- `pcm` `any` _(optional)_ — Interleaved f32 samples — a buffer or a binary string of
little-endian f32, the shape `microphone.samples` and `audio.decode` hand
back, or a flat number array. A byte payload's samples are its 4-byte
lanes, and a length that stops partway through one comes back as
`(nil, err)` naming the whole samples it holds and the bytes past them.
- `sampleRate` `number` — Source sample rate in Hz.
- `channels` `number` — 1 or 2, and a divisor of the sample count.
- `opts` `{ [string]: any }?` _(optional)_ — Same shape as `audio.encode`.

```lua
local s = microphone.status(); local zaud = audio.encodePcm(microphone.samples(), s.sampleRate, 1)
```

## modules/audio/info {#modules-audio-info}

```lua
info(zaud: buffer | string): (AudioInfo?, string?)
```

Read a ZAUD payload's header. A PCM payload's samples are its bytes, and
the header is read against them: a sample count differing from
`frames * channels` comes back as `(nil, err)` naming both counts, and a
sample carrying a NaN or an infinity comes back as `(nil, err)` naming how
many fail and where the first one sits, so the header handed back describes
a clip that is as long as it says and can sound. The header describes the
clip's shape — rate, channels, frames, duration, codec, loop points. What
the samples do where a whole-clip loop wraps is a reading of its own,
`audio.loopSeam`, which is the call that answers whether a bed cycles
without a click.

**Parameters**

- `zaud` `buffer | string` — A ZAUD payload — a buffer or a binary string.

```lua
local info = audio.info(zaud); print(info.durationMs)
```

## modules/audio/levels {#modules-audio-levels}

```lua
levels(): AudioLevels
```

The master mix's peak and RMS over the meter's most recent closed
window, measured without recording anything.

```lua
local l = audio.levels(); print(l.peak, l.rms, l.windowMs)
```

## modules/audio/listener {#modules-audio-listener}

```lua
listener(): AudioListenerState
```

Where the scene is heard from, how many active listeners exist, and
which entity's listener drives the ears.

```lua
local l = audio.listener(); print(l.present, l.count, l.entity)
```

## modules/audio/loopSeam {#modules-audio-loopseam}

```lua
loopSeam(zaud: buffer | string): (AudioLoopSeam?, string?)
```

Measure what a clip's samples do where a whole-clip loop wraps, so a bed
can be judged before anyone hears it tick. The wrap's own step
(`|x[1] - x[frames]|`) is reported against the step the signal ordinarily
makes between neighbouring samples, as `ratio = step / meanStep` — a figure
in the units the signal itself moves in, so a quiet ambience and a loud
drone are read the same way. A bed whose partials wrap reads near 1; one
carrying a strike at its head and silence at its tail reads in the tens.
`ratio` and the `step` / `meanStep` / `maxStep` beside it belong to the
worst channel, `channel` names it, and `channels` carries every channel's
own reading. `seamless` is `ratio <= threshold`, the same threshold
`asset.create("soundClip", ...)` warns past. The reading is taken on the
DECODED samples, so it answers for what the codec left behind and for a
clip that arrived already encoded and whose source buffer nobody holds.
Costs a decode of the whole payload; `audio.info` reads a header without
one.

**Parameters**

- `zaud` `buffer | string` — A ZAUD payload — a buffer or a binary string.

```lua
local seam = audio.loopSeam(clipRef:getBytes()); print(seam.ratio, seam.seamless)
```

## modules/audio/mixer {#modules-audio-mixer}

```lua
mixer(): AudioMixerLevels
```

The levels the mixer is applying to the mix right now: the master
level, whether the mix is muted, and the level of every channel one has
been set on. A channel absent from `channels` plays at unity, so a
source naming it is heard at the volume it asks for.

```lua
local m = audio.mixer(); print(m.master, m.muted, m.channels.music)
```

## modules/audio/observe {#modules-audio-observe}

```lua
observe(): AudioObservation
```

Report what the mixer is making audible right now, and why a source
is not. One read covering every live voice with the mixer's own playback
state and effective gain, the master mix's level, the mixer's voice
accounting, the listener, the output device the mix is reaching, and what
the subsystem costs. Answers in edit mode as well as play mode.

```lua
local a = audio.observe(); print(a.audibleCount, a.levels.rms)
for _, v in audio.observe().voices do print(v.entity, v.mixerState, v.silence) end
```

## modules/audio/peakSince {#modules-audio-peaksince}

```lua
peakSince(window: number): number?
```

The loudest peak the master mix reached across the meter's windows
that closed after its `windows` count stood at `window`. `audio.levels()`
carries the window that closed last, so a reader sees the windows its own
frames happen to land on; this spans all of them, which is what measuring
a sound shorter than the gap between two reads takes. Take the mark from
`audio.levels().windows` before the sound starts, wait until `windows` has
advanced past the sound's length, then read the span.

**Parameters**

- `window` `number` — A `windows` count taken from `audio.levels()` earlier.

```lua
local mark = audio.levels().windows
local peak = audio.peakSince(mark)
```

## modules/audio/profile {#modules-audio-profile}

```lua
profile(): AudioProfile
```

What the audio subsystem has cost since the profiling window opened —
the streaming pump, clip decode, clip encode, voice starts, and building
the observation itself. Every total is a SUM across that window rather
than a per-frame figure, and the window runs from the last
`audio.resetProfile()` or from engine start. For what a frame costs now,
reset, let frames pass, then divide by the `frames` the window reports.

```lua
audio.resetProfile(); task.wait(1); local p = audio.profile()
print("per frame:", (p.pump.totalMs + p.observe.totalMs) / p.frames)
```

## modules/audio/resetProfile {#modules-audio-resetprofile}

```lua
resetProfile()
```

Open a new audio profiling window, discarding what the previous one
measured. Call this before timing a stretch of frames: without it
`audio.profile()` reports totals reaching back to engine start.

```lua
audio.resetProfile()
```

## modules/audio/setChannelVolume {#modules-audio-setchannelvolume}

```lua
setChannelVolume(channel: string, volume: number)
```

Set the level of one mixer channel — the `channel` an `Audio`
component names, such as "sfx", "music" or "ambient", or any name the
scene invents. It scales every voice on that channel and nothing else,
reaches voices that are already playing, and comes back per voice as
`gain.channel`. A channel no level has been set on plays at unity.

**Parameters**

- `channel` `string` — The channel name, matching `Audio.channel`.
- `volume` `number` — Channel level, 0..1.

```lua
audio.setChannelVolume("music", 0.3)
for _, v in audio.voices() do print(v.channel, v.gain.channel) end
```

## modules/audio/setMasterVolume {#modules-audio-setmastervolume}

```lua
setMasterVolume(volume: number)
```

Set the master level of the mix, on the engine's 0..1 amplitude
scale. It scales every voice whatever channel it plays on, reaches
voices that are already playing, and comes back per voice as
`gain.master`.

**Parameters**

- `volume` `number` — Master level, 0..1.

```lua
audio.setMasterVolume(0.5)
```

## modules/audio/setMuted {#modules-audio-setmuted}

```lua
setMuted(muted: boolean)
```

Silence or unsilence the whole mix. A muted mix sounds nothing
whatever its master and channel levels read, every voice reports
`masterSilent`, and unmuting hands the levels back untouched.

**Parameters**

- `muted` `boolean` — Whether the mix is silenced.

```lua
audio.setMuted(true)
```

## modules/audio/voice {#modules-audio-voice}

```lua
voice(entityId: string): AudioVoice?
```

The voice on one entity, or nil when that entity carries no audio
source.

**Parameters**

- `entityId` `string` — The entity's stable id.

```lua
local v = audio.voice(e.id); print(v and v.mixerState)
```

## modules/audio/voiceAccounting {#modules-audio-voiceaccounting}

```lua
voiceAccounting(): AudioVoiceAccounting
```

How many voices the mixer can hold, how many are in use, how many
are free — read off the mixer's own tracks, so the free count is the one
a play call is granted or refused against. The two pools are reported
apart: `capacity` / `inUse` / `free` are the main track, which carries
the NON-spatial voices, while a spatial voice plays through its own
sub-track and is counted by `spatialInUse` instead. `sourcesHolding`
counts both pools from the sources that own them, so it equals
`inUse + spatialInUse` while every voice answers to a source.

```lua
local v = audio.voiceAccounting(); print(v.inUse .. "/" .. v.capacity)
local v = audio.voiceAccounting(); print(v.sourcesHolding - (v.inUse + v.spatialInUse))
```

## modules/audio/voices {#modules-audio-voices}

```lua
voices(): { AudioVoice }
```

Every live audio source with the mixer's opinion of it.

```lua
for _, v in audio.voices() do print(v.clip, v.gain.effective) end
```

## modules/audio/whySilent {#modules-audio-whysilent}

```lua
whySilent(entityId: string): (string?, string?)
```

Why the source on an entity is making no sound. Returns nil when it
IS sounding, and one of `noBackend`, `noDevice`, `notResident`, `neverStarted`,
`refused`, `paused`, `ended`, `gainZero`, `channelSilent`,
`masterSilent`, `outOfRange` when it is not — the nearest cause, so the
answer names the thing to change. A second
return carries the mixer's own words when it refused the source, and
`"no audio source on this entity"` when nothing there plays at all.

**Parameters**

- `entityId` `string` — The entity's stable id.

```lua
local why = audio.whySilent(e.id); if why then print(why) end
```

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

```lua
require("@builtin/modules/api/engine/av") -- av (also available as global 'av')
```

Audio/video encode + mux control — live streaming, recording, encoder/muxer primitives. Public Luau surface over the `__av` Internal FFI namespace.

Usage: local av = require("@builtin/modules/api/engine/av")
Also available as global: av

## modules/av/is_live {#modules-av-is-live}

```lua
is_live(): boolean
```

True if a live-stream session is currently active.

```lua
if av.is_live() then av.stop_live() end
```

## modules/av/is_recording {#modules-av-is-recording}

```lua
is_recording(): boolean
```

True if a recording session is currently active.

```lua
print("recording:", av.is_recording())
```

## modules/av/live {#modules-av-live}

```lua
live(opts: LiveOpts?): string?
```

Start the live-stream encoder. The stream is served at
`/engine/live.stream` and reverse-proxied at
`/stream/<instance>/live.stream` as a binary length-prefixed
protocol consumed by the multiviewer UI's WebCodecs decoder.
When `texture_handle` is set, the encoder reads from that GPU
texture's guid (a Camera pointed at it via `setTargetTexture`)
instead of the scene's viewport — that's how spectator cameras
work. Returns a stream URL, or nil when unsupported or a
session is already active.

**Parameters**

- `opts` `LiveOpts?` _(optional)_ — Encoder options.

```lua
local url = av.live({ width = 1280, height = 720, fps = 60 })
```

## modules/av/record {#modules-av-record}

```lua
record(path: string, opts: RecordOpts?): (string?, string?)
```

Start recording the engine output to a VFS path. Default dir
is `/zero/runtime/recordings/` when `path` is not absolute. The
take runs until `av.stop_recording()` unless `opts` bounds it
with `max_duration_sec` (seconds of the take's own clock) or
`frames` (captured frames); `max_duration_sec` wins when both are
given, and the bound in force reads back as
`av.status().recordingBound`. With
no `chroma`/`range` opts the format defaults to full-range 4:4:4
HEVC where the GPU supports it, else 4:2:0. On the `"software"`
backend the take is H.264 encoded on the CPU, which costs the run
it records: read `av.status().recordingAchievedFps` against
`recordingRequestedFps` to see the rate it reached. What the take
did with the master mix reads back as
`av.status().recordingAudio`. `cadence` picks the clock the take
stamps its frames from. `"realtime"` (the default) stamps each
frame with the wall-clock slot it was captured in, so a recorded
session is watched back at the speed it happened and an engine
ticking under `fps` leaves slots empty. `"frame"` stamps every
rendered frame one fixed slot after the last, so a timeline whose
own clock advances a step per rendered frame — a cutscene, a
scripted demo, anything on a fixed timestep — is delivered at the
length that timeline runs to, however slowly the engine drew it: a
take of `frames = n` at `fps` is `n / fps` seconds of film, and a
`max_duration_sec` bound counts that film's seconds. A `"frame"`
take records silent, because the master mix plays in wall-clock
seconds and cannot share a file with a fixed-step picture;
`recordingAudio` says so, and an explicit `audio = true` beside it
is refused. Record the sound as a second `"realtime"` take.
`camera` names the camera the take draws its film from — an entity
proxy, an entity id, or an entity name. That camera holds the viewport
for as long as the take runs, above the priority contest and above
`camera.setEditorOverride`, so the film is its view and the frames
carry everything the presented frame carries. Only frames that camera
drew go into the film, and a camera that never draws the viewport ends
the take with the reason on `av.status().recordingError` — so a take is
the view it named or it is no take. The camera belongs to the take:
nothing is written to it, and the viewport is back under its own
contest the moment the take ends. It reads back as
`av.status().recordingCamera` while the take runs. Omitted, the take
records whichever camera holds the viewport, which in an engine on the
editor profile is the editor's own fly camera rather than the scene's.
`renderLayers` is the render-layer include spec the viewport is
drawn under for as long as the take runs — the same token string a
capture takes: `all` seeds every layer, `name` adds one and `!name`
drops one, so `"all !EditorUI !debug"` films the scene without the
editor's chrome or the authoring overlays (gizmos, light and probe
icons, frustums, collider wireframes) over it, and
`"all !ui !EditorUI !debug"` drops the authored HUD as well. The
viewport admits geometry and screens by that one spec, so it states
the whole picture. It belongs to the take: nothing is written to the
camera it is stated against, and the moment the take ends — its
bound reached, stopped, or refused — the viewport is back under the
camera's own spec. While a take states layers, the window shows what
the film holds, and `av.status().recordingLayers` reads the spec
back. Omitted, the take records the engine output as presented.
Returns the destination path of a session that is open and
recording, or nil
and the reason it is not — an adapter that cannot encode, a take
already running, an option the encoder rejects, a resolution the
device refuses. The engine opens the session, so the call waits
for it: run it where it can yield, wrapping it in `task.spawn`
from a callback that cannot. How a take finished reads back as
`av.status().recordingEnd`; a refused request puts its reason
there and on `recordingError` and leaves no take report behind,
while a request refused because a take is already running leaves
that take's report as it is.

**Parameters**

- `path` `string` — VFS destination path.
- `opts` `RecordOpts?` _(optional)_ — Encoder options (optional).

```lua
local clip = av.record("intro.mp4", { fps = 60 })
local film = av.record("cut.mp4", { fps = 24, frames = 24 * 181, cadence = "frame" })
local clean = av.record("take.mp4", { fps = 24, renderLayers = "all !EditorUI !debug" })
local shot = av.record("film.mp4", { fps = 24, frames = 240, camera = "FilmCamera" })
```

## modules/av/status {#modules-av-status}

```lua
status(): AvStatus
```

Report the encoder subsystem's state. Always available
regardless of GPU support. `backend` is the encode backend in use
— `"vulkan"` or `"vaapi"` on an adapter with a media engine,
`"software"` where encode runs on the CPU — and `hardware` is true
for the first two, so a caller that pays for the take in engine
time knows which it is getting. `codecs` lists what the backend
encodes with the recording default first. `live` is true while the
`av.live` stream is running. A take of its own reads back on the
recording fields: `recording` is the destination of the take in
flight, `recordingBound` what will end it, `recordingEnd` how the
most recent one ended, and `recordingError` why one produced no
file. `recordingAudio` is the codec the take is writing the master
mix with (`"opus"`), or the reason the file carries no audio track
— read it to tell a film with a soundtrack from a silent one.
`recordingLayers` is the render-layer include spec the armed take is
drawing the viewport under, in the words its caller wrote, and nil for
a take that stated none — the reading that answers what is in the
picture rather than how much of it there is. `recordingCamera` is the
entity id of the camera the take's most recent captured frame was drawn
from, and stands as the source of the most recent take once that take
has ended — it is read off the frame the engine drew, so it answers
which view a film holds whether or not the take named a camera.
`recordingCadence` is the clock the take stamps its frames from,
`"realtime"` or `"frame"`, and so what the tally below is a reading
against. What the take produced reads off `recordingFrames`,
`recordingBytes` (every byte the take has produced so far, climbing
while it runs and ending equal to the size of the file),
`recordingSeconds` (the timeline those frames cover),
`recordingAchievedFps` (the rate they arrived at) and
`recordingRequestedFps` (the rate asked for) — live while a take
runs, and its final tally once it ends. On `"realtime"` the
requested rate is a ceiling and an engine ticking under it reaches
less; on `"frame"` every rendered frame is a slot of the recorded
timeline, so `recordingSeconds` is that timeline's length and
`recordingAchievedFps` is the rate it plays back at.

```lua
local s = av.status(); print(s.backend, s.hardware, s.recordingAudio)
```

## modules/av/stop_live {#modules-av-stop-live}

```lua
stop_live(): boolean
```

Stop any active live-stream session.

```lua
av.stop_live()
```

## modules/av/stop_recording {#modules-av-stop-recording}

```lua
stop_recording(handle: string?): (boolean, string?)
```

Stop the active recording (or the one for the given promise
handle). Returns true when a recording was armed at call time. A
false return carries a second value naming how the most recent
recording already ended — the bound it reached, or the failure
that cut it short — and nil when no recording has run at all. The
engine finalizes the take on its next tick: wait for
`av.is_recording()` to go false, then read what it produced off
`av.status()`.

**Parameters**

- `handle` `string?` _(optional)_ — Promise handle of a specific recording (optional).

```lua
local stopped, ended = av.stop_recording()
```

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

```lua
require("@builtin/modules/api/engine/base64") -- base64 (also available as global 'base64')
```

Base64 encode / decode between binary and text Luau strings (standard RFC 4648 alphabet, padded). Public Luau surface over the `__base64` Internal FFI namespace.

Usage: local base64 = require("@builtin/modules/api/engine/base64")
Also available as global: base64

## modules/base64/decode {#modules-base64-decode}

```lua
decode(text: string): (string?, string?)
```

Decode standard-alphabet base64 text back to the original binary string.

**Parameters**

- `text` `string` — Base64 text to decode.

```lua
local bytes = base64.decode(text)
```

## modules/base64/encode {#modules-base64-encode}

```lua
encode(bytes: buffer | string): string
```

Encode a binary string to standard-alphabet (padded) base64 text.

**Parameters**

- `bytes` `buffer | string` — Binary bytes to encode.

```lua
local text = base64.encode(jpegBytes)
```

## modules/bitmask_bits/README {#modules-bitmask-bits-readme}

```lua
bitmask_bits
```

The `bitmask` field-constraint validator: a constrained value must be a whole number that fits the declared width, so what the field reads back is a mask the system consuming it can actually address. A rejection names the width and why the value is not a mask of it. Registers itself with the generic field_constraints registry on load. `nil` passes, so a mask field may be left unset.

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

```lua
require("@builtin/modules/api/engine/blend") -- blend (also available as global 'blend')
```

Record-stride blend primitives over Buffer slices — layout registry + weighted/lerp combiners. Public Luau surface over the `__blend` Internal FFI namespace.

Usage: local blend = require("@builtin/modules/api/engine/blend")
Also available as global: blend

## modules/blend/destroyLayout {#modules-blend-destroylayout}

```lua
destroyLayout(handle: number): boolean
```

Drop the layout from the registry.

**Parameters**

- `handle` `number` — Layout handle.

## modules/blend/layout {#modules-blend-layout}

```lua
layout(slots: { BlendSlot }, totalStride: number?): number?
```

Register a record-stride layout. Each slot is
`{ offset, stride, op }` where `op` is `"lerp"` / `"slerp"` /
`"sum"` / `"step"`. Slerp slots must have stride 4.
`totalStride` defaults to `max(offset + stride)` across slots;
pass an explicit value when records contain padding past the
last slot.

**Parameters**

- `slots` `{ BlendSlot }` — Array of slot tables.
- `totalStride` `number?` _(optional)_ — Optional explicit record stride.

```lua
local l = blend.layout({ { offset = 0, stride = 3, op = "lerp" } })
```

## modules/blend/lerpInto {#modules-blend-lerpinto}

```lua
lerpInto(outBuffer: Substrate.TypedBuffer, layout: number, aBuffer: Substrate.TypedBuffer, bBuffer: Substrate.TypedBuffer, t: number): boolean
```

Two-input crossfade shortcut. Equivalent to
`blend.weightedInto(out, layout, { {a, 1-t}, {b, t} })`.
Faster for the common A/B fade case because it skips the
inputs-table walk.

**Parameters**

- `outBuffer` `Substrate.TypedBuffer` — The buffer written into.
- `layout` `number` — Layout handle.
- `aBuffer` `Substrate.TypedBuffer` — The A side of the fade.
- `bBuffer` `Substrate.TypedBuffer` — The B side of the fade.
- `t` `number` — Crossfade weight on B (0..1).

## modules/blend/weightedInto {#modules-blend-weightedinto}

```lua
weightedInto(outBuffer: Substrate.TypedBuffer, layout: number, inputs: { BlendInput }): boolean
```

Combine N weighted input buffers into the output buffer
using the layout's slot ops. The output buffer's length must
be a whole multiple of `layout.totalStride`; every input
buffer must be at least as long as the output. Returns false
on any handle / size mismatch.

**Parameters**

- `outBuffer` `Substrate.TypedBuffer` — The buffer written into.
- `layout` `number` — Layout handle.
- `inputs` `{ BlendInput }` — Array of `{ buffer, weight }`.

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

```lua
require("@builtin/systems/oceans/modules/buoyancy") -- buoyancy
```

Floats a rigid body on the sea the simulation is already drawing — displacement, damping and the righting moment that keeps a hull upright.

Usage: local buoyancy = require("@builtin/systems/oceans/modules/buoyancy")

## modules/buoyancy/apply {#modules-buoyancy-apply}

```lua
apply(self, dt: number): boolean
```

Step the body once. The `Buoyancy` component calls this every frame;
call it yourself only when driving a body without that component.

**Parameters**

- `self` `any` _(optional)_
- `dt` `number` — Seconds since the last step.

```lua
float:apply(1 / 60)
```

## modules/buoyancy/attach {#modules-buoyancy-attach}

```lua
attach(target: any, options: any?): (any?, string?)
```

Float a rigid body on the sea. The entity needs a dynamic `Physics`
body; the hull is measured from what it draws unless `sizeX/Y/Z` say
otherwise.

**Parameters**

- `target` `any` _(optional)_ — The entity id or proxy to float.
- `options` `any?` _(optional)_ — `{ density, damping, angularDamping, columns, sizeX, sizeY, sizeZ,
mass, gravityScale, ocean }`. `density` is relative to water, and the lower
it is the higher the hull rides.

```lua
local float = buoyancy.attach(barrel, { density = 0.4 })
```

## modules/buoyancy/clear {#modules-buoyancy-clear}

```lua
clear()
```

Stop floating every body. Each one is released, so a body driven by a
`Buoyancy` component stops being pushed as well.

```lua
buoyancy.clear()
```

## modules/buoyancy/columns {#modules-buoyancy-columns}

```lua
columns(size: any, columns: number): { { x: number, z: number } }
```

The local-space footprint of a hull's columns: an evenly spaced grid
over its X/Z extent, each column standing for an equal share of the hull.

**Parameters**

- `size` `any` _(optional)_ — `{ x, y, z }` full extents of the hull in its own space.
- `columns` `number` — Grid resolution per horizontal axis. 1 gives a single central
column, which floats but cannot right itself; 2 is the smallest grid that
produces a righting moment.

```lua
local cols = buoyancy.columns({ x = 4, y = 1, z = 2 }, 2)
```

## modules/buoyancy/configure {#modules-buoyancy-configure}

```lua
configure(self, options: any)
```

Reconfigure a floating body. Any field may be passed; anything omitted
is left as it was.

**Parameters**

- `self` `any` _(optional)_
- `options` `any` _(optional)_ — `{ density, damping, angularDamping, columns, sizeX, sizeY,
sizeZ, mass, gravityScale, ocean }`. `mass` and `gravityScale` stand in for
the rigid body's own, which is what they are read from otherwise.

```lua
float:configure({ density = 0.8 })
```

## modules/buoyancy/destroy {#modules-buoyancy-destroy}

```lua
destroy(self)
```

Stop floating this body. The rigid body keeps everything else about it.

**Parameters**

- `self` `any` _(optional)_

```lua
float:destroy()
```

## modules/buoyancy/forEntity {#modules-buoyancy-forentity}

```lua
forEntity(entityId: string): any
```

The floating body on an entity, if it has one.

**Parameters**

- `entityId` `string` — The entity's id.

```lua
local float = buoyancy.forEntity(barrelId)
```

## modules/buoyancy/list {#modules-buoyancy-list}

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

Every body currently floating.

```lua
print(#buoyancy.list())
```

## modules/buoyancy/restingY {#modules-buoyancy-restingy}

```lua
restingY(waterY: number, height: number, density: number): number
```

The height a hull of this density displaces its own weight at on flat
water — the waterline its lift balances at, with no wave motion in it.

**Parameters**

- `waterY` `number` — World Y of the undisturbed surface.
- `height` `number` — The hull's full height.
- `density` `number` — The hull's density relative to water.

```lua
local y = buoyancy.restingY(0, 1, 0.45)
```

## modules/buoyancy/submergedFraction {#modules-buoyancy-submergedfraction}

```lua
submergedFraction(centreY: number, waterY: number, height: number): number
```

How much of a column stands under water: 0 clear of it, 1 fully under.

**Parameters**

- `centreY` `number` — World Y of the column's mid-height.
- `waterY` `number` — World Y of the surface above it.
- `height` `number` — The column's full height.

```lua
local f = buoyancy.submergedFraction(0.2, 0.0, 1.0)
```

## modules/buoyancy/submersion {#modules-buoyancy-submersion}

```lua
submersion(self): number
```

The share of the hull that was under water on the last step, averaged
over its columns. 0 is clear of the sea, 1 is fully submerged.

**Parameters**

- `self` `any` _(optional)_

```lua
print(float:submersion())
```

## modules/buoyancy/waterline {#modules-buoyancy-waterline}

```lua
waterline(self): number?
```

The world Y of the water surface under the hull's centre on the last
step — where the waterline stood, wave motion included.

**Parameters**

- `self` `any` _(optional)_

```lua
print(float:waterline())
```

## modules/cachedIndirect/README {#modules-cachedindirect-readme}

```lua
require("@builtin/systems/radianceCache/cachedIndirect") -- cachedIndirect
```

Indirect diffuse light that is gathered once per patch of world and reused, rather than re-gathered for every pixel of every frame. It is the scene-wide user of `@builtin::systems.radianceCache.radianceCache` and the worked example of what a cache buys a lighting technique: the same bounce, converged over frames instead of within one, at a fraction of the gathering per frame.

Usage: local cachedIndirect = require("@builtin/systems/radianceCache/cachedIndirect")

## modules/cachedIndirect/active {#modules-cachedindirect-active}

```lua
active(): boolean
```

Whether the cached-indirect passes are running this frame.

```lua
if cachedIndirect.active() then ... end
```

## modules/cachedIndirect/cache {#modules-cachedindirect-cache}

```lua
cache(): any
```

The cache this effect drives. The render feature takes its passes from
here, and a script can read its counters or invalidate it through the same
handle.

```lua
cachedIndirect.cache():stats()
```

## modules/cachedIndirect/clear {#modules-cachedindirect-clear}

```lua
clear()
```

Turn the cached bounce off and release the passes, the cache table and
the resolve target. The other settings are kept, so a later
`set({ intensity = ... })` brings the effect back at the same settings and
refills the table over `history * stride` frames.

```lua
cachedIndirect.clear()
```

## modules/cachedIndirect/get {#modules-cachedindirect-get}

```lua
get(): { [string]: number }
```

The cached-indirect settings currently in force.

```lua
local s = cachedIndirect.get().stride
```

## modules/cachedIndirect/invalidate {#modules-cachedindirect-invalidate}

```lua
invalidate()
```

Declare that the lighting changed, so every patch takes its next gather
whole instead of averaging it into light that is gone. The cache is rebuilt
within `stride` frames.

```lua
cachedIndirect.invalidate()
```

## modules/cachedIndirect/set {#modules-cachedindirect-set}

```lua
set(opts: CachedIndirectOpts?): { [string]: number }
```

Set the scene's cached indirect light. Any omitted field keeps its
current value. An `intensity` of 0 turns it off and releases the passes.

**Parameters**

- `opts` `CachedIndirectOpts?` _(optional)_ — Cached-indirect settings — see `CachedIndirectOpts`.

```lua
cachedIndirect.set({ intensity = 1.0, stride = 8 })
```

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

```lua
require("@builtin/modules/api/engine/camera") -- camera (also available as global 'camera')
```

Script-facing camera queries: the main scene camera, the on-screen render camera, the editor fly-camera, per-frame view data, and the camera observation — which cameras drew this frame, with what projection, into what, and at what cost. Public Luau surface over the `__camera` Internal FFI namespace.

Usage: local camera = require("@builtin/modules/api/engine/camera")
Also available as global: camera

## modules/camera/active {#modules-camera-active}

```lua
active(): string?
```

Entity id of the on-screen render camera this frame — whichever camera
wins the viewport by priority (the editor fly-camera in edit mode, the
gameplay camera in play). Render features, billboards, and input bases that
must follow the human's on-screen view read this.

```lua
local camId = camera.active()
```

## modules/camera/cut {#modules-camera-cut}

```lua
cut()
```

Declare that the camera on screen cuts: the next frame it draws stands
somewhere it did not travel to. Motion vectors are the difference between
where a surface projects now and where it projected on the camera's
previous frame, and everything temporal reads that difference — the shutter
reconstructs the frame by walking it, a temporal resolve reprojects its
history along it. Across a cut that difference describes a displacement no
surface made, so the frame is reconstructed from taps a whole screen away
and belongs to neither shot. A declared cut leaves the camera with no
previous frame for exactly one frame, which is the state its very first
frame is already in, so every consumer reads zero motion across the cut.
Declare it in the same step that places the camera at the new station;
declaring it again before that frame draws still costs the one frame.
Handing the viewport from one camera to another is already a cut without
being declared one: the incoming camera stands where it always stood, and
the engine performs the handover, so it is what states it.

```lua
camera.cut(); entity(camId).position = { 40, 6, -12 }
```

## modules/camera/editor {#modules-camera-editor}

```lua
editor(): string?
```

Entity id of the editor fly-camera (the EditorOnly authoring camera), or
nil if the scene has none. This is the camera the editor viewport renders
through, so it is the one a `capture` of the screen sees. Its pose is its
entity transform: assign `entity(id).position` to move it and aim it with
the camera toolbox's `lookAt`, which makes a screen capture repeatable
instead of whatever pose the instance booted with.

```lua
local camId = camera.editor()
local id = camera.editor(); entity(id).position = { 12, 8, 12 }; tools.use("camera", "lookAt", id, { 0, 0, 0 })
```

## modules/camera/editorOverride {#modules-camera-editoroverride}

```lua
editorOverride(): string?
```

Entity id currently overriding viewport selection, or nil when the
viewport is decided by highest-priority-wins.

```lua
local owner = camera.editorOverride()
```

## modules/camera/get {#modules-camera-get}

```lua
get(target: (string | EntityRef)): CameraReport?
```

One camera's report from the observation — the same record
`camera.list` yields, for the camera the caller names. Takes an entity id,
an entity name, or an entity proxy, the same way the camera tools do.

**Parameters**

- `target` `(string | EntityRef)` — Entity id, entity name, or entity proxy of the camera to report on.

```lua
local c = camera.get(camera.active()); print(c.frame.far, c.authored.far)
local c = camera.get("minimapCam"); print(c.rendering, c.reason)
```

## modules/camera/list {#modules-camera-list}

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

Every camera in the world as a compact row each, ordered the way the
renderer resolves the on-screen camera: highest priority first. Reads the
same observation `camera.observe` does, so a row can never disagree with
the full report about whether a camera is `enabled` or which one drew.

```lua
for _, c in ipairs(camera.list()) do print(c.name, c.enabled, c.rendering) end
```

## modules/camera/main {#modules-camera-main}

```lua
main(): string?
```

Entity id of the main scene camera — the scene camera the viewport is
drawn from, and while the editor fly-camera holds the screen, the scene
camera that would take it. The gameplay/PlayerPrototype camera, an
agent-placed scene camera, or a cutscene camera. Never the editor camera;
nil if the scene has only the editor camera. It comes off the same
selection the frame does, so writing a pose to it moves what is drawn
whenever a scene camera is on screen. The scene camera with the highest
authored `priority` takes it; cameras tied on priority settle on the order
the frame visits them, so a scene that needs a specific camera — a
prototype and the clone play makes of it both stand at 0 — states a
distinct priority rather than resting on that order. For the camera drawn
on screen whichever partition owns it, use `camera.active()`.

```lua
local camId = camera.main(); local cam = camId and entity(camId)
```

## modules/camera/motionTally {#modules-camera-motiontally}

```lua
motionTally(): { frames: number, withoutHistory: number }
```

Frames the camera on screen has drawn, and how many of them had no
previous frame to difference their motion vectors against — its first
frame, every declared cut, and every frame the viewport changes hands on.
Both counts are monotonic across the session, so two readings either side
of a run say what happened in between.

```lua
local before = camera.motionTally().withoutHistory
```

## modules/camera/observe {#modules-camera-observe}

```lua
observe(): CameraObservation?
```

Every camera in the world, for the frame that has just been drawn.
Answers "why is this camera not showing what I expect" in one call:
`rendering` says whether each camera drew and `reason` names the single
cause when it did not — `"disabled"`, `"entityInactive"`, `"targetMissing"`,
`"noLayers"`, `"outranked"`, `"notDrawn"`. Each camera carries both
projections: `authored` is what the Camera component holds and `frame` is
what the renderer actually built, with `mismatch` naming every field the
two disagree on — so a clip range or a lens the frame did not use is one
field read. `frame`, `viewProj`, `frustum` and the `cost` numbers describe
a camera that drew; every cost is for that one frame.
One snapshot is published per drawn frame, from after the frame is drawn,
so a read describes the last frame rather than the world at the instant of
the call — a write and a read in one script step return the frame that ran
before the write. Put a `task.wait()` between them to compare a camera
either side of a change; `frame` counts the frames observed, so a poll can
wait for it to advance.

```lua
local obs = camera.observe(); for _, c in ipairs(obs.cameras) do print(c.name, c.rendering, c.reason) end
local dark = {}; for _, c in ipairs(camera.observe().cameras) do if not c.rendering then table.insert(dark, c.name .. ": " .. tostring(c.reason)) end end
```

## modules/camera/setEditorOverride {#modules-camera-seteditoroverride}

```lua
setEditorOverride(entityId: string?)
```

Give one camera the viewport outright, or pass nil to clear it. While
set, that camera IS the on-screen camera and priority is never consulted,
so no authored priority can take the viewport from it — which is what makes
an authoring camera safe to fly over a scene holding a camera at any
priority. An override naming a camera that is despawned or disabled falls
back to highest-priority-wins rather than blanking the screen.

**Parameters**

- `entityId` `string?` _(optional)_ — Entity id of the camera to route the viewport to, or nil to clear.

```lua
camera.setEditorOverride(camera.editor())
camera.setEditorOverride(nil)
```

## modules/camera/viewData {#modules-camera-viewdata}

```lua
viewData(target: ((string | EntityRef)?)): CameraView?
```

Camera render data. Called with no argument it is the active viewport
camera's data for this frame: world position, which projection it drew and
the field describing that frame, viewport pixel size, the 6 world-space
frustum planes (the same inward-pointing, normalized planes the renderer
culls with), and the view-projection matrix. The camera state a render
feature needs for camera-relative work — LOD selection, frustum culling,
billboards. Render features also get it as `ctx.camera`.
Called with an entity id it is that camera's data, read from the frame's
camera observation, and carries the identity the bare form has no room for:
which camera it describes, which frame it was built for, what it rendered
into, and the render layers it resolved to.

**Parameters**

- `target` `((string | EntityRef)?)` _(optional)_ — Entity id, name, or proxy of the camera to read, or nil for the
viewport camera.

```lua
local c = camera.viewData(); if c then print(c.position.x, c.fovY) end
local minimap = camera.viewData("minimapCam"); print(minimap.output.target, minimap.viewport.w)
```

## modules/camera_spawner/README {#modules-camera-spawner-readme}

```lua
camera_spawner
```

DEPRECATED: v7 scenes author their own Camera entity. This procedural primary-camera spawner serves legacy v6 scenes only; M.ensure stands down (returns early) for any scene carrying a string `playerIntent`.

Spawns the scene's primary Camera entity on non-additive `layers.onLoad`, for legacy v6 scenes. The per-mode world default (`world.camera_default_<mode>`) is the fallback; scene-level overrides via `sceneProxy.settings.camera` win when present. Missing refs → log.error + skip (no hardcoded fallback).

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

```lua
require("@builtin/modules/api/engine/channel") -- channel (also available as global 'channel')
```

Keyframe-channel sampling primitives — registry + sampleInto variants. Public Luau surface over the `__channel` Internal FFI namespace.

Usage: local channel = require("@builtin/modules/api/engine/channel")
Also available as global: channel

## modules/channel/create {#modules-channel-create}

```lua
create(opts: ChannelOpts): number?
```

Register a keyframe channel. `times` is the sorted keyframe
time array; `values` is the packed value array (layout depends
on `interp`); `stride` is the floats-per-sample width; `interp`
is `"step"` | `"linear"` | `"slerp"` | `"cubicHermite"`. Returns
the channel handle, or nil on malformed input.

**Parameters**

- `opts` `ChannelOpts` — `{ times, values, stride, interp }`.

```lua
local h = channel.create({ times = ts, values = vs, stride = 3, interp = "linear" })
```

## modules/channel/destroy {#modules-channel-destroy}

```lua
destroy(handle: number): boolean
```

Drop the channel from the registry.

**Parameters**

- `handle` `number` — Channel handle.

## modules/channel/sampleInto {#modules-channel-sampleinto}

```lua
sampleInto(ch: number, time: number, buf: Substrate.TypedBuffer, offset: number): boolean
```

Sample the channel at `time` and write `stride` floats into
the buffer starting at f32 index `offset`. Returns false
on unknown handle, layout mismatch, or out-of-bounds; the
buffer is unchanged on failure.

**Parameters**

- `ch` `number` — Channel handle.
- `time` `number` — Sample time in seconds.
- `buf` `Substrate.TypedBuffer` — The buffer written into.
- `offset` `number` — Starting f32 index in the buffer.

## modules/channel/sampleManyInto {#modules-channel-samplemanyinto}

```lua
sampleManyInto(ch: number, time: number, buf: Substrate.TypedBuffer, offsets: { number }): boolean
```

Sample once, blit the result into every position in
`offsets`. Saves the per-offset binary search when one channel
feeds many bones / particles / parameters.

**Parameters**

- `ch` `number` — Channel handle.
- `time` `number` — Sample time in seconds.
- `buf` `Substrate.TypedBuffer` — The buffer written into.
- `offsets` `{ number }` — Array of f32 indices.

## modules/channel/sampleQuat {#modules-channel-samplequat}

```lua
sampleQuat(ch: number, time: number): (number?, number?, number?, number?)
```

Convenience accessor for stride-4 quaternion channels.

**Parameters**

- `ch` `number` — Channel handle.
- `time` `number` — Sample time.

## modules/channel/sampleVec3 {#modules-channel-samplevec3}

```lua
sampleVec3(ch: number, time: number): (number?, number?, number?)
```

Convenience accessor for stride-3 channels. Returns the
three components as multiret, or nil if the channel is
unknown / has a different stride.

**Parameters**

- `ch` `number` — Channel handle.
- `time` `number` — Sample time.

```lua
local x, y, z = channel.sampleVec3(h, t)
```

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

```lua
require("@builtin/modules/api/engine/color") -- color (also available as global 'color')
```

Color construction, conversion, and perceptual ops (RGB / HSL / HSV / Oklch / hex). Public Luau surface over the `__color` Internal FFI namespace.

Usage: local color = require("@builtin/modules/api/engine/color")
Also available as global: color

## modules/color/coerce {#modules-color-coerce}

```lua
coerce(value: any): Color?
```

Read a value written in any of the shapes a colour is authored
in — a hex string, an `{r=,g=,b=,a=}` map, or an `{r,g,b,a}` array
— as an sRGB color table. Returns `nil` when the value does not
describe a colour, so a caller can name the value it was handed
instead of substituting one. Channels absent from a map or array
read as 0; alpha absent reads as 1.

**Parameters**

- `value` `any` _(optional)_ — Value to read as a colour.

```lua
local c = color.coerce("#5a5a62") or color.coerce({ 0.2, 0.7, 0.2 })
```

## modules/color/complementary {#modules-color-complementary}

```lua
complementary(c: Color): Color
```

Complementary color — rotate hue 180° in Oklch space.

**Parameters**

- `c` `Color` — Input color.

```lua
local accent = color.complementary(primary)
```

## modules/color/darken {#modules-color-darken}

```lua
darken(c: Color, amount: number): Color
```

Decrease the lightness of a color in Oklch perceptual space.

**Parameters**

- `c` `Color` — Input color.
- `amount` `number` — Lightness decrease 0-1.

```lua
local pressed = color.darken(base, 0.1)
```

## modules/color/desaturate {#modules-color-desaturate}

```lua
desaturate(c: Color, amount: number): Color
```

Decrease the chroma (saturation) of a color in Oklch space.

**Parameters**

- `c` `Color` — Input color.
- `amount` `number` — Chroma decrease (typically 0-0.2).

```lua
local muted = color.desaturate(base, 0.05)
```

## modules/color/hex {#modules-color-hex}

```lua
hex(hexString: string): Color?
```

Parse a hex color string into an sRGB color table. Accepts 3,
4, 6, or 8 hex digits with or without a leading `#` (e.g. "#f00",
"f00f", "#ff0000", "ff000080"). Returns `nil` on parse failure.

**Parameters**

- `hexString` `string` — Hex color string.

```lua
local fromCss = color.hex("#ff8800")
```

## modules/color/hsl {#modules-color-hsl}

```lua
hsl(h: number, s: number, l: number): Color
```

Build a color from HSL (`h: 0-360`, `s: 0-1`, `l: 0-1`).
Returned as sRGB.

**Parameters**

- `h` `number` — Hue (degrees, 0-360).
- `s` `number` — Saturation (0-1).
- `l` `number` — Lightness (0-1).

```lua
local teal = color.hsl(180, 0.5, 0.5)
```

## modules/color/hsla {#modules-color-hsla}

```lua
hsla(h: number, s: number, l: number, a: number): Color
```

Build a color from HSLA, returned as sRGB.

**Parameters**

- `h` `number` — Hue (0-360).
- `s` `number` — Saturation (0-1).
- `l` `number` — Lightness (0-1).
- `a` `number` — Alpha (0-1).

```lua
local fadedTeal = color.hsla(180, 0.5, 0.5, 0.3)
```

## modules/color/hsv {#modules-color-hsv}

```lua
hsv(h: number, s: number, v: number): Color
```

Build a color from HSV (`h: 0-360`, `s: 0-1`, `v: 0-1`).

**Parameters**

- `h` `number` — Hue (0-360).
- `s` `number` — Saturation (0-1).
- `v` `number` — Value / brightness (0-1).

```lua
local primary = color.hsv(220, 0.7, 0.9)
```

## modules/color/lighten {#modules-color-lighten}

```lua
lighten(c: Color, amount: number): Color
```

Increase the lightness of a color in Oklch perceptual space.

**Parameters**

- `c` `Color` — Input color.
- `amount` `number` — Lightness increase 0-1.

```lua
local hover = color.lighten(base, 0.1)
```

## modules/color/linear {#modules-color-linear}

```lua
linear(r: number, g: number, b: number, a: number?): Color
```

Build a color from linear RGB values (not gamma-corrected),
output converted to sRGB. Useful for GPU-correct blending. Alpha
defaults to 1.

**Parameters**

- `r` `number` — Linear red (0-1).
- `g` `number` — Linear green (0-1).
- `b` `number` — Linear blue (0-1).
- `a` `number?` _(optional)_ — Alpha (0-1, default 1).

```lua
local gpuBlue = color.linear(0.0, 0.0, 1.0)
```

## modules/color/mix {#modules-color-mix}

```lua
mix(c1: Color, c2: Color, t: number): Color
```

Perceptually blend two colors in Oklch space — better than RGB
mixing for gradients.

**Parameters**

- `c1` `Color` — First color.
- `c2` `Color` — Second color.
- `t` `number` — Blend factor 0-1 (0 = c1, 1 = c2).

```lua
local mid = color.mix(color.rgb(255, 0, 0), color.rgb(0, 0, 255), 0.5)
```

## modules/color/mixRgb {#modules-color-mixrgb}

```lua
mixRgb(c1: Color, c2: Color, t: number): Color
```

Linearly blend two colors in sRGB space — simple, but not
perceptually uniform. Prefer `color.mix` for natural gradients.

**Parameters**

- `c1` `Color` — First color.
- `c2` `Color` — Second color.
- `t` `number` — Blend factor 0-1.

```lua
local plain = color.mixRgb(a, b, 0.5)
```

## modules/color/oklch {#modules-color-oklch}

```lua
oklch(l: number, c: number, h: number): Color
```

Build a color from Oklch perceptual color space (`l: 0-1`,
`c: 0-0.4`, `h: 0-360`). Ideal for perceptually uniform gradients
and color manipulation.

**Parameters**

- `l` `number` — Lightness (0-1).
- `c` `number` — Chroma / saturation (0-0.4).
- `h` `number` — Hue (0-360).

```lua
local accent = color.oklch(0.7, 0.15, 30)
```

## modules/color/rgb {#modules-color-rgb}

```lua
rgb(r: number, g: number, b: number): Color
```

Build an sRGB color from CSS-style 0-255 RGB channels. Alpha
defaults to 1. Channels are normalised to 0-1 on the way out so
the result composes with every other color helper.

**Parameters**

- `r` `number` — Red channel (0-255).
- `g` `number` — Green channel (0-255).
- `b` `number` — Blue channel (0-255).

```lua
local red = color.rgb(255, 0, 0)
```

## modules/color/rgba {#modules-color-rgba}

```lua
rgba(r: number, g: number, b: number, a: number): Color
```

Build an sRGB color from CSS-style 0-255 RGB channels with
explicit alpha. RGB are normalised to 0-1; alpha is taken as-is
in the 0-1 range.

**Parameters**

- `r` `number` — Red channel (0-255).
- `g` `number` — Green channel (0-255).
- `b` `number` — Blue channel (0-255).
- `a` `number` — Alpha (0-1).

```lua
local halfRed = color.rgba(255, 0, 0, 0.5)
```

## modules/color/rotateHue {#modules-color-rotatehue}

```lua
rotateHue(c: Color, degrees: number): Color
```

Rotate the hue of a color by a given number of degrees in
Oklch space.

**Parameters**

- `c` `Color` — Input color.
- `degrees` `number` — Hue rotation (positive or negative).

```lua
local triadic = color.rotateHue(base, 120)
```

## modules/color/saturate {#modules-color-saturate}

```lua
saturate(c: Color, amount: number): Color
```

Increase the chroma (saturation) of a color in Oklch space.

**Parameters**

- `c` `Color` — Input color.
- `amount` `number` — Chroma increase (typically 0-0.2).

```lua
local pop = color.saturate(base, 0.05)
```

## modules/color/toHex {#modules-color-tohex}

```lua
toHex(c: Color): string
```

Convert a color to a hex string. Returns `"#rrggbb"` or
`"#rrggbbaa"` if alpha is not 1.

**Parameters**

- `c` `Color` — Input color.

```lua
print(color.toHex(color.rgb(255, 136, 0))) -- "#ff8800"
```

## modules/color/toHsl {#modules-color-tohsl}

```lua
toHsl(c: Color): HslColor
```

Convert a color to HSL.

**Parameters**

- `c` `Color` — Input color.

```lua
local hsl = color.toHsl(base)
```

## modules/color/toLinear {#modules-color-tolinear}

```lua
toLinear(c: Color): Color
```

Convert a color from sRGB to linear RGB space — useful for GPU
calculations that need linear-space values.

**Parameters**

- `c` `Color` — Input sRGB color.

```lua
local gpu = color.toLinear(base)
```

## modules/color/toOklch {#modules-color-tooklch}

```lua
toOklch(c: Color): OklchColor
```

Convert a color to Oklch perceptual color space.

**Parameters**

- `c` `Color` — Input color.

```lua
local okl = color.toOklch(base)
```

## modules/color/withAlpha {#modules-color-withalpha}

```lua
withAlpha(c: Color, a: number): Color
```

Return a copy of a color with a different alpha value.

**Parameters**

- `c` `Color` — Input color.
- `a` `number` — New alpha (0-1).

```lua
local ghost = color.withAlpha(base, 0.3)
```

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

```lua
require("@builtin/modules/api/engine/compute") -- compute (also available as global 'compute')
```

GPU compute pipelines — compile shaders, dispatch workgroups, read back results. Public Luau surface over the `__compute` Internal FFI namespace. A buffer belongs to the shader that owns it (`shaderRef:createBuffer`) or to the substrate (`substrate.createBuffer`), and reaches a dispatch as a handle.

Usage: local compute = require("@builtin/modules/api/engine/compute")
Also available as global: compute

## modules/compute/absentReasons {#modules-compute-absentreasons}

```lua
absentReasons(): { string }
```

Every reason `compute.diagnose` reports, sorted. `resident` is the one
that means the resource is there.

```lua
for _, r in ipairs(compute.absentReasons()) do print(r) end
```

## modules/compute/beginBvh {#modules-compute-beginbvh}

```lua
beginBvh(instances: { any }, opts: { [string]: any }?): (number?, string?)
```

Start the build `compute.buildBvh` runs, without running any of it.
Takes the same instances and options and reports the same non-resident
guids, and returns an id `compute.stepBvh` advances a bounded slice at a
time and `compute.finishBvh` collects. Each mesh the instances name is
copied as this is called — once per guid however many instances share it
— so the CPU mesh may be unloaded on the next line and the build still
finishes on the copy it holds. `compute.buildBvhSliced` is the whole loop
as one call.

**Parameters**

- `instances` `{ any }` — Array of `{ guid, transform, attributes? }` mesh instances.
- `opts` `{ [string]: any }?` _(optional)_ — Optional `{ maxLeaf? }` — max triangles per leaf.

```lua
local id = compute.beginBvh(gather.instances)
```

## modules/compute/buildBvh {#modules-compute-buildbvh}

```lua
buildBvh(instances: { any }, opts: { [string]: any }?): (any, string?)
```

Build a bounding-volume hierarchy over the world-space triangles of a
set of mesh instances and upload it as two named compute buffers —
geometry never passes through the scripting heap. Each instance is
`{ guid, transform, attributes? }`: `guid` names a mesh resident in the
meshcpu store (materialise with `ref:load()` / `meshcpu.load`),
`transform` is 16 numbers, row-major, translation in slots 4/8/12, and
`attributes` is up to 40 floats stamped onto every triangle of that
instance (surface colors, material ids, physics tags — whatever the
consuming shader wants per-surface). Triangles pack 18 vec4 each
(v0/v1/v2, n0/n1/n2, uvs, then 10 attribute vec4s — float slots 32..
carry the instance attributes, zero when absent) in BVH leaf order;
nodes 2 vec4 each (min + first-or-left, max + leaf-tagged
count-or-right). Consumers: GI baking, ray-traced passes, GPU picking,
navmesh and SDF generation.

**Parameters**

- `instances` `{ any }` — Array of `{ guid, transform, attributes? }` mesh instances.
- `opts` `{ [string]: any }?` _(optional)_ — Optional `{ maxLeaf? }` — max triangles per leaf.

```lua
local bvh = compute.buildBvh(instances)
shader:dispatch({ buffers = { bvh.nodes, bvh.tris }, workgroups = { 64, 1, 1 } })
```

## modules/compute/buildBvhSliced {#modules-compute-buildbvhsliced}

```lua
buildBvhSliced(instances: { any }, opts: { [string]: any }?): (any, string?)
```

The hierarchy `compute.buildBvh` builds, spread over as many frames as
it takes: a slice of the build per frame, so a scene's triangle count
costs the frame loop `budgetMs` at a time instead of the whole build at
once. Yields, so it is called from a task. The result is the same pair of
buffers and the same counts `compute.buildBvh` returns.

**Parameters**

- `instances` `{ any }` — Array of `{ guid, transform, attributes? }` mesh instances.
- `opts` `{ [string]: any }?` _(optional)_ — Optional `{ maxLeaf?, budgetMs? }` — max triangles per leaf, and
the wall time one frame may spend on the build (default 4 ms).

```lua
local built, err = compute.buildBvhSliced(gather.instances, { budgetMs = 4 })
```

## modules/compute/bvhBuilds {#modules-compute-bvhbuilds}

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

What the builds started by `compute.beginBvh` and not yet finished are
costing, oldest id first. Each row is `{ id, phase, triangles, units,
slices, cpuMs, uploadedBytes }`: `phase` is `"gather"`, `"build"`,
`"serialize"`, `"upload"` or `"ready"`, `triangles` how many have been
gathered, `units` the work units run, `slices` the `compute.stepBvh`
calls they ran in, `cpuMs` the wall time spent inside those calls, and
`uploadedBytes` how much of the hierarchy has reached the GPU.

```lua
print(#compute.bvhBuilds(), "hierarchies in flight")
```

## modules/compute/cancelBvh {#modules-compute-cancelbvh}

```lua
cancelBvh(id: number): boolean
```

Drop a build along with the triangles it has gathered.

**Parameters**

- `id` `number` — Build id from `compute.beginBvh`.

```lua
compute.cancelBvh(id)
```

## modules/compute/compile {#modules-compute-compile}

```lua
compile(nameOrHandle: string | { [string]: any } | AssetRef, opts: { [string]: any }?): boolean
```

Compile a compute shader from inline WGSL + a declarative binding
schema — the same codegen a `.computeShader` asset uses. The engine
generates the `@group/@binding` declarations from `bindings`/`params`,
so the source writes only `@compute fn main`. Symmetric with
`registerShader`, but with zero-scaffolding bindings (incl. textures,
samplers, storage textures and a params uniform). For asset-backed
shaders prefer authoring a `.computeShader` (compiled automatically);
use this for dynamic/generated compute shaders.

**Parameters**

- `nameOrHandle` `string | { [string]: any } | AssetRef` — Shader identity to register under (string or asset handle).
- `opts` `{ [string]: any }?` _(optional)_ — `{ source, entryPoint?, bindings, params? }` — `bindings` is an
ordered list of `{ name, kind, access?, element?, format?, array? }`.

```lua
compute.compile("my_sim", { source = WGSL, bindings = { { name = "data", kind = "buffer", access = "read_write", element = "f32" } } })
```

## modules/compute/compileByName {#modules-compute-compilebyname}

```lua
compileByName(ref: string | { [string]: any } | AssetRef)
```

Optional explicit pre-warm for a `.computeShader` asset (idempotent —
fingerprint-guarded). NORMALLY UNNECESSARY: `compute.dispatch` / `dispatchEx`
auto-compile a `.computeShader` on first use. Reach for this only to avoid
the one-frame first-dispatch warm-up in a latency-critical spot. Accepts an
identity/guid string or a resolved asset handle (its `.identity` is used).

**Parameters**

- `ref` `string | { [string]: any } | AssetRef` — A `.computeShader` identity/guid string, or a resolved asset handle.

```lua
compute.compileByName("@builtin::shaders.compute_double")
```

## modules/compute/copyBufferToTexture {#modules-compute-copybuffertotexture}

```lua
copyBufferToTexture(bufferName: string, textureKey: string, width: number, height: number, format: string?): boolean
```

Copy a compute buffer into a cached GPU texture under
`textureKey`, staying on the GPU. The path for an image a compute
pass produced: the buffer holds tightly-packed rows in the format's
texel layout, and the result is an ordinary cached texture — sample
it from a material, or pack it into the shared feature-texture array.
Rows must be a multiple of 256 bytes (at `rgba16f`, any width from 32
up in powers of two).

**Parameters**

- `bufferName` `string` — Source compute buffer.
- `textureKey` `string` — Cache key to register the texture under.
- `width` `number` — Texture width in texels.
- `height` `number` — Texture height in texels.
- `format` `string?` _(optional)_ — Texel format: `"rgba16f"` (default), `"rgba32f"`, `"rgba8"`.

```lua
compute.copyBufferToTexture("gi_resolved", "lm_wall", 128, 128)
```

## modules/compute/createBuffer {#modules-compute-createbuffer}

```lua
createBuffer(name: string, opts: { [string]: any }): boolean
```

Allocate a buffer under `name`, sized in bytes.

**Parameters**

- `name` `string` — The name a dispatch binds it by.
- `opts` `{ [string]: any }` — `{ size, readback? }` — `size` in bytes.

## modules/compute/createSampler {#modules-compute-createsampler}

```lua
createSampler(name: string, opts: { [string]: any }?): boolean
```

Create a named GPU sampler. opts: filter/wrap settings.

**Parameters**

- `name` `string`
- `opts` `{ [string]: any }?` _(optional)_

## modules/compute/createStorageTexture2D {#modules-compute-createstoragetexture2d}

```lua
createStorageTexture2D(name: string, opts: { [string]: any }): boolean
```

Create a 2D storage texture (compute-writable render target). opts: `{ width, height, format? }`.

**Parameters**

- `name` `string`
- `opts` `{ [string]: any }`

## modules/compute/createTexture3D {#modules-compute-createtexture3d}

```lua
createTexture3D(name: string, opts: { [string]: any }): boolean
```

Create a 3D texture volume. opts: `{ width, height, depth, format?, storage? }`.

**Parameters**

- `name` `string` — Unique volume name.
- `opts` `{ [string]: any }` — Dimensions + format (`r8`/`r16f`/`r32f`/`rgba8`/`rgba16f`/`rgba32f`).

## modules/compute/createTextureHistory {#modules-compute-createtexturehistory}

```lua
createTextureHistory(name: string, opts: { [string]: any }): boolean
```

Create a temporal history buffer (ping-pong textures) for a target. opts: `{ width, height, format? }`.

**Parameters**

- `name` `string`
- `opts` `{ [string]: any }`

## modules/compute/destroyBuffer {#modules-compute-destroybuffer}

```lua
destroyBuffer(name: string): boolean
```

Release the buffer allocated under `name`.

**Parameters**

- `name` `string` — The name it was created under.

## modules/compute/destroySampler {#modules-compute-destroysampler}

```lua
destroySampler(name: string): boolean
```

Release a named sampler created by `compute.createSampler` and free
it. The counterpart to that call, alongside `destroyBuffer`,
`destroyTexture`, `destroyTexture3D`, `destroyStorageTexture2D` and
`destroyTextureHistory`. The manager's own defaults (`linear_clamp`,
`linear_repeat`, `nearest_clamp`) are kept for the session, since a
compute pass binds them by name.

**Parameters**

- `name` `string` — Sampler name.

```lua
compute.createSampler("soft", { filter = true }); compute.destroySampler("soft")
```

## modules/compute/destroyShader {#modules-compute-destroyshader}

```lua
destroyShader(name: string): boolean
```

Destroy a named compute shader pipeline.

**Parameters**

- `name` `string` — Shader name.

## modules/compute/destroyShaderEx {#modules-compute-destroyshaderex}

```lua
destroyShaderEx(name: string): boolean
```

Destroy a shader registered via `registerShaderEx`.

**Parameters**

- `name` `string`

## modules/compute/destroyStorageTexture2D {#modules-compute-destroystoragetexture2d}

```lua
destroyStorageTexture2D(name: string): boolean
```

Destroy a named 2D storage texture.

**Parameters**

- `name` `string`

## modules/compute/destroyTexture {#modules-compute-destroytexture}

```lua
destroyTexture(textureKey: string): boolean
```

Release the cached GPU texture `copyBufferToTexture` registered
under `textureKey`, freeing its memory. Call it once the image is no
longer sampled. Writing the same key again replaces the texture, so a
key you keep re-using holds one allocation.

**Parameters**

- `textureKey` `string` — Cache key the texture was registered under.

```lua
compute.destroyTexture("lm_wall")
```

## modules/compute/destroyTexture3D {#modules-compute-destroytexture3d}

```lua
destroyTexture3D(name: string): boolean
```

Destroy a named 3D volume and free its GPU memory.

**Parameters**

- `name` `string`

## modules/compute/destroyTextureHistory {#modules-compute-destroytexturehistory}

```lua
destroyTextureHistory(name: string): boolean
```

Destroy a named texture-history buffer.

**Parameters**

- `name` `string`

## modules/compute/diagnose {#modules-compute-diagnose}

```lua
diagnose(key: string): { [string]: any }
```

Whether a resource is filed under `key` right now, and when none is,
which state the inventory says the key is in. A key out of a dispatch
failure resolves here; a mistyped one reports why it does not.

**Parameters**

- `key` `string` — The resource key, verbatim.

```lua
local d = compute.diagnose(key)
if not d.exists then print(d.reason, d.current) end
```

## modules/compute/dispatch {#modules-compute-dispatch}

```lua
dispatch(shaderNameOrHandle: string | { [string]: any } | AssetRef, opts: DispatchOpts): boolean
```

Dispatch a compute shader with bound buffers. Accepts a
shader name string or an asset handle from `asset.load()`.

**Parameters**

- `shaderNameOrHandle` `string | { [string]: any } | AssetRef` — Shader name or asset handle.
- `opts` `DispatchOpts` — `{ buffers, workgroups }`.
A zero in any workgroup dimension is refused and recorded as a dispatch
failure — clamp a computed count with `math.max(1, math.ceil(n / 64))`.

```lua
compute.dispatch("blur", { buffers = { "src", "dst" }, workgroups = { 8, 8 } })
```

## modules/compute/dispatchEx {#modules-compute-dispatchex}

```lua
dispatchEx(shaderNameOrHandle: string | { [string]: any } | AssetRef, opts: { [string]: any }): boolean
```

Dispatch a compute shader with extended texture/storage/sampler bindings.
Asset-backed `.computeShader`s resolve to their stable guid (collision-safe,
lazily compiled on first dispatch); raw `registerShaderEx` names pass through.
`resources` covers the bindings the shader DECLARES. A `params:` block's
uniform is engine-owned — the compile creates and packs it, `setParam`
writes it, and the dispatch binds it — so it takes no entry here.

**Parameters**

- `shaderNameOrHandle` `string | { [string]: any } | AssetRef` — Shader name or asset handle.
- `opts` `{ [string]: any }` — `{ resources, workgroups }` — each resource is `{ kind, name }`.
A zero in any workgroup dimension is refused and recorded as a dispatch
failure — clamp a computed count with `math.max(1, math.ceil(n / 64))`.

## modules/compute/dispatchOnVertices {#modules-compute-dispatchonvertices}

```lua
dispatchOnVertices(shaderNameOrHandle: string | { [string]: any } | AssetRef, opts: DispatchOnVerticesOpts): boolean
```

Dispatch a compute shader with a model's vertex buffer bound
at binding 0 (read_write). Use to mutate vertex positions
directly. Asset-backed `.computeShader`s resolve to their stable guid
(collision-safe, lazily compiled on first dispatch); raw
`registerShader` names pass through.

**Parameters**

- `shaderNameOrHandle` `string | { [string]: any } | AssetRef` — Shader name or asset handle.
- `opts` `DispatchOnVerticesOpts` — `{ model, buffers?, workgroups }`.
A zero in any workgroup dimension is refused and recorded as a dispatch
failure — clamp a computed count with `math.max(1, math.ceil(n / 64))`.

```lua
compute.dispatchOnVertices("flatten", { model = "@user/mesh", workgroups = { 64 } })
```

## modules/compute/failing {#modules-compute-failing}

```lua
failing(): { { [string]: any } }
```

Every compute dispatch whose most recent run FAILED, one record per
`(shader, target)` pair. A dispatch is recorded into a command encoder
frames after the call that asked for it returned, so a pass that stops
running reports here rather than through that call's return value: each
record carries the shader key, the target it writes (a mesh guid for a
dispatch over vertices, the buffers it bound for one that writes only
those), how
many dispatches and failures it has had, and `lastError`. An empty result
means every dispatch the engine has been given is running.

```lua
for _, d in ipairs(compute.failing()) do print(d.shader, d.lastError) end
```

## modules/compute/finishBvh {#modules-compute-finishbvh}

```lua
finishBvh(id: number): (any, string?)
```

Hand over a finished build's hierarchy as the same two buffers
`compute.buildBvh` returns, and release the build. The slices put every
byte of it on the GPU as they ran, so this costs the frame it is called
in the handover and nothing of the scene.

**Parameters**

- `id` `number` — Build id from `compute.beginBvh`, stepped until `"ready"`.

```lua
local built = compute.finishBvh(id)
```

## modules/compute/getReadbackResult {#modules-compute-getreadbackresult}

```lua
getReadbackResult(resultKey: string): { number }?
```

Poll for a completed read-back and return its bytes as a
1-indexed array of f32 values, nil if pending. The f32
reinterpretation applies to whatever the buffer holds: bytes
written as u32 `1, 2, 3, 4` read back here as `1.4e-45, 2.8e-45,
4.2e-45, 5.6e-45` — use `getReadbackResultU32()` for those, or
`getReadbackResultBytes()` for a `buffer` the rest of the buffer
surface accepts. Result is consumed on retrieval, and polling a key
that was never issued raises rather than reading as forever-pending.

**Parameters**

- `resultKey` `string` — Key returned by `readBuffer()`.

```lua
local floats = compute.getReadbackResult(key)
```

## modules/compute/getReadbackResultBytes {#modules-compute-getreadbackresultbytes}

```lua
getReadbackResultBytes(resultKey: string): buffer?
```

Poll for a completed read-back and get its raw bytes as a
`buffer`, copied once. The read counterpart of `writeBufferBytes`:
read values out with `buffer.readf32` / `buffer.readu32`, or hand the
buffer straight to `writeBuffer` — a payload that stays packed never
becomes a table. Result is consumed on retrieval.

**Parameters**

- `resultKey` `string` — Key returned by `readBuffer()`.

```lua
local bytes = compute.getReadbackResultBytes(key)
local firstTexel = buffer.readf32(bytes, 0)
```

## modules/compute/getReadbackResultU32 {#modules-compute-getreadbackresultu32}

```lua
getReadbackResultU32(resultKey: string): { number }?
```

Poll for a completed read-back interpreting bytes as u32.
Returns array of integer values if ready, nil if pending.

**Parameters**

- `resultKey` `string` — Key returned by `readBuffer()`.

## modules/compute/isReadbackReady {#modules-compute-isreadbackready}

```lua
isReadbackReady(resultKey: string): boolean
```

Check if a readback result is available without consuming it.
Raises for a key this engine never issued, or whose result was already
drained — `nil`/`false` already means "still in flight", so a mistyped
key reports itself instead of polling forever. Use `readbackState()`
to test that case without raising.

**Parameters**

- `resultKey` `string` — Key returned by `readBuffer()`.

## modules/compute/observe {#modules-compute-observe}

```lua
observe(): { [string]: any }
```

Every GPU resource the compute subsystem is holding right now — its
storage and uniform buffers, its 3D textures, its 2D storage targets, its
history pairs and its samplers — with what each one costs and which shader
asked for it. This is the call to reach for when compute is holding memory
and you do not know what, or when a key out of a dispatch failure needs
matching against what exists.

```lua
local r = compute.observe()
print(r.totals.count, r.totals.bytes)
for _, res in ipairs(r.resources) do print(res.key, res.kind, res.bytes) end
```

## modules/compute/program.compile {#compile}

```lua
program.compile(key: string, spec: { [string]: any }): boolean
```

Register a compiled program under `key` from WGSL plus a declared
binding schema. The engine generates the `@group`/`@binding` declarations
from the schema, expands `#include`s, naga-validates, and registers the
result.

**Parameters**

- `key` `string` — The key to register under.
- `spec` `{ [string]: any }` — `{ source, entryPoint?, bindings, params }` — the parsed schema.

## modules/compute/program.destroy {#destroy}

```lua
program.destroy(key: string): boolean
```

Release the program registered under `key`.

**Parameters**

- `key` `string` — The program's key.

## modules/compute/program.dispatch {#dispatch}

```lua
program.dispatch(key: string, opts: { [string]: any }): boolean
```

Dispatch the program under `key` with one buffer per declared storage
binding, in declaration order.

**Parameters**

- `key` `string` — The program's key.
- `opts` `{ [string]: any }` — `{ buffers, workgroups }`.
A zero in any workgroup dimension is refused and recorded as a dispatch
failure — clamp a computed count with `math.max(1, math.ceil(n / 64))`.

## modules/compute/program.dispatchEx {#dispatchex}

```lua
program.dispatchEx(key: string, opts: { [string]: any }): boolean
```

Dispatch the program under `key` with explicit resources — one
`{ kind, name }` per declared binding, in declaration order.

**Parameters**

- `key` `string` — The program's key.
- `opts` `{ [string]: any }` — `{ resources, workgroups }`.
A zero in any workgroup dimension is refused and recorded as a dispatch
failure — clamp a computed count with `math.max(1, math.ceil(n / 64))`.

## modules/compute/program.dispatchOnVertices {#dispatchonvertices}

```lua
program.dispatchOnVertices(key: string, opts: { [string]: any }): boolean
```

Dispatch the program under `key` over a mesh's vertices. The mesh
`opts.model` names fills the shader's `vertices` binding, and `opts.buffers`
fills the remaining storage bindings.

**Parameters**

- `key` `string` — The program's key.
- `opts` `{ [string]: any }` — `{ model, buffers?, workgroups }`.
A zero in any workgroup dimension is refused and recorded as a dispatch
failure — clamp a computed count with `math.max(1, math.ceil(n / 64))`.

## modules/compute/program.setParam {#setparam}

```lua
program.setParam(key: string, prop: string, value: number): boolean
```

Write one scalar of the program's `params:` uniform. A value set before
the program's first compile is the value it starts with.

**Parameters**

- `key` `string` — The program's key.
- `prop` `string` — Parameter name as declared.
- `value` `number` — New scalar value.

## modules/compute/program.status {#status}

```lua
program.status(key: string): { { [string]: any } }
```

What the engine did with the dispatches of the program under `key`,
one record per target.

**Parameters**

- `key` `string` — The program's key.

## modules/compute/programState {#modules-compute-programstate}

```lua
programState(ref: string | { [string]: any } | AssetRef): (string, string?)
```

Where a shader's compiled program stands. A registration is queued
from script and the pipeline is built on the render side frames later,
so the call that asked for the compile cannot say whether it produced a
program: `"absent"` (the engine holds nothing under this key and nothing
is in flight — never asked for, or released), `"pending"` (asked for, not
on the device yet — a recompile of a resident program reads pending too,
because what it produces is a different program from the one bound now),
`"ready"` (compiled and resident, so a dispatch binds it), or `"failed"`
(the most recent registration produced no program), returned with the
reason as a second value. Wait for `"ready"` before a dispatch whose
result is read back, rather than for a count of frames.

**Parameters**

- `ref` `string | { [string]: any } | AssetRef` — A `.computeShader` identity/guid string, a resolved asset handle,
or the name a raw registration chose.

```lua
if compute.programState(carve) == "ready" then carve:dispatch(opts) end
```

## modules/compute/readBuffer {#modules-compute-readbuffer}

```lua
readBuffer(name: string): string
```

Start a GPU→CPU read of the buffer under `name`.

**Parameters**

- `name` `string` — The name it was created under.

## modules/compute/readTexture3D {#modules-compute-readtexture3d}

```lua
readTexture3D(name: string): string
```

Start a GPU→CPU readback of a named 3D volume. Returns a result key to poll.

**Parameters**

- `name` `string`

## modules/compute/readbackState {#modules-compute-readbackstate}

```lua
readbackState(resultKey: string): string
```

Where a readback key stands, without consuming it and without
raising: `"pending"` (issued, GPU has not delivered), `"ready"`
(delivered, waiting to be drained), or `"unknown"` (never issued by
`readBuffer()`, or already drained — a result is delivered once).

**Parameters**

- `resultKey` `string` — Key returned by `readBuffer()`.

```lua
if compute.readbackState(key) == "ready" then ... end
```

## modules/compute/registerShader {#modules-compute-registershader}

```lua
registerShader(nameOrHandle: string | { [string]: any } | AssetRef, opts: ShaderOpts?): boolean
```

Register a compute shader. Accepts an asset handle from
`asset.load()`, or `(name, opts)` with inline WGSL source.

**Parameters**

- `nameOrHandle` `string | { [string]: any } | AssetRef` — Shader name or asset handle.
- `opts` `ShaderOpts?` _(optional)_ — Shader options. `bindings` comes from the source's own
`@group(0) @binding(n)` declarations when omitted; supplying a count that
disagrees with them raises. Every `readOnlyBindings` entry names one of
those declared bindings, as a whole number from 0 to `bindings - 1`; an
entry outside that run raises.

```lua
compute.registerShader("blur", { source = WGSL, entryPoint = "main" })
```

## modules/compute/registerShaderEx {#modules-compute-registershaderex}

```lua
registerShaderEx(nameOrHandle: string | { [string]: any } | AssetRef, opts: { [string]: any }?): boolean
```

Register a compute shader with extended texture/sampler bindings. Accepts a name + opts or an asset handle.

**Parameters**

- `nameOrHandle` `string | { [string]: any } | AssetRef`
- `opts` `{ [string]: any }?` _(optional)_

## modules/compute/resources {#modules-compute-resources}

```lua
resources(owner: any?): { any }
```

The resource rows on their own, optionally narrowed to what one shader
owns.

**Parameters**

- `owner` `any?` _(optional)_ — A `.computeShader` ref, its guid, or its asset identity. Omit for
every resource compute holds. A value carrying no shader raises, so a
narrowing that cannot be done reads as an error rather than as the whole
inventory. A guid stands for itself, so resources outlive the asset that
made them and stay reachable by their owner.

```lua
for _, r in ipairs(compute.resources(shaderRef)) do print(r.key, r.bytes) end
```

## modules/compute/setParam {#modules-compute-setparam}

```lua
setParam(nameOrHandle: string | { [string]: any } | AssetRef, prop: string, value: number): boolean
```

Set a named scalar parameter on a `.computeShader` (a `params:`
entry in its `bindings.yaml`). Updates the shader's params uniform
in place; the next dispatch sees the new value. No effect on raw
`registerShader` shaders, which have no params block.

**Parameters**

- `nameOrHandle` `string | { [string]: any } | AssetRef` — Shader identity (the `.computeShader` asset name), or the
handle `asset.load` / `asset.resolve` returns — the same forms `dispatch`
takes.
- `prop` `string` — Parameter name as declared in `bindings.yaml`.
- `value` `number` — New scalar value (numbers only).

```lua
compute.setParam("my_sim", "scale", 4.0)
```

## modules/compute/stepBvh {#modules-compute-stepbvh}

```lua
stepBvh(id: number, budgetMs: number?): (string?, string?)
```

Advance a build by as many work units as `budgetMs` buys, and report
whether it has finished: `"pending"` means there is work left,
`"ready"` means `compute.finishBvh` will hand over the buffers. The
slices carry the hierarchy onto the GPU as well as building it, so a
build that reads `"ready"` has already uploaded every byte of itself. A
slice always runs at least one unit, so a budget of 0 advances the build
by exactly one and the largest single unit sets the floor under a slice.

**Parameters**

- `id` `number` — Build id from `compute.beginBvh`.
- `budgetMs` `number?` _(optional)_ — Wall time this slice may spend, in milliseconds (default 4).

```lua
while compute.stepBvh(id, 4) == "pending" do task.wait() end
```

## modules/compute/textureFormatBytes {#modules-compute-textureformatbytes}

```lua
textureFormatBytes(format: string): number
```

Bytes-per-voxel for a texture format string (`rgba16f`, `r8`, ...).

**Parameters**

- `format` `string`

## modules/compute/writeBuffer {#modules-compute-writebuffer}

```lua
writeBuffer(name: string, values: { number } | buffer | string, offset: number?): boolean
```

Write words into the buffer under `name`.

**Parameters**

- `name` `string` — The name it was created under.
- `values` `{ number } | buffer | string` — The floats to write, or a `buffer` / binary string already holding them.
- `offset` `number?` _(optional)_ — 32-bit word offset to write at.

## modules/compute/writeBufferBytes {#modules-compute-writebufferbytes}

```lua
writeBufferBytes(name: string, bytes: buffer | string, offsetBytes: number?): boolean
```

Write packed bytes into the buffer under `name`.

**Parameters**

- `name` `string` — The name it was created under.
- `bytes` `buffer | string` — The payload.
- `offsetBytes` `number?` _(optional)_ — Byte offset to write at.

## modules/compute/writeBufferU32 {#modules-compute-writebufferu32}

```lua
writeBufferU32(name: string, values: { number } | buffer | string, offsetBytes: number?): boolean
```

Write 32-bit words into the buffer under `name`.

**Parameters**

- `name` `string` — The name it was created under.
- `values` `{ number } | buffer | string` — The words to write.
- `offsetBytes` `number?` _(optional)_ — Byte offset to write at.

## modules/compute/writeFloatsTexture3D {#modules-compute-writefloatstexture3d}

```lua
writeFloatsTexture3D(name: string, floats: { number }, formatOrOpts: (string | { [string]: any })?): boolean
```

Upload float values into a named 3D volume, packed via the given format (default rgba16f).

**Parameters**

- `name` `string`
- `floats` `{ number }`
- `formatOrOpts` `(string | { [string]: any })?` _(optional)_

## modules/compute/writeTexture3D {#modules-compute-writetexture3d}

```lua
writeTexture3D(name: string, data: buffer | string | { number }): boolean
```

Upload raw bytes (u8) into a named 3D volume. A `buffer` or a binary
string holds the volume's byte layout verbatim and crosses in one copy —
the shape a file's voxel payload arrives in; an array carries one byte
value (0..255) per entry.

**Parameters**

- `name` `string` — Volume name.
- `data` `buffer | string | { number }` — Voxel bytes as a `buffer`, a binary string, or an array of bytes.

## modules/connected_users/README {#modules-connected-users-readme}

```lua
connected_users
```

`world.connectedUsers.*` — server-replicated user registry. This module is **user-scope and user-editable**. The file you're reading is `/zero/source/libs/@builtin/modules/connected_users.module/init.luau` — anyone (any script, any agent, any user with VFS write) can rewrite it; hot-reload picks the change up and the engine uses the new version. There is no security boundary here. The read-only metatable below catches accidental writes loudly (API hygiene); it doesn't enforce anything. Trust boundaries that DO exist: - The Rust FFI (`__connected_users.local_identity()`) is registered into the VM state by the engine at boot and cannot be replaced from Luau. When it's called, it returns the real JWT `sub`. - The trusted VM (`src/lua/trusted/**`) is a separate Luau state, not on the user-writable VFS root, holds the `auth.*` namespace. User-scope Luau cannot reach it. - The server verifies the JWT on every RPC. Anything the server gates on flows through that check, not through whatever this module reports. What IS load-bearing: - `__connected_users.local_identity()` (Rust FFI) cannot be replaced. It always returns the real JWT `sub` of the engine's `UserCredential`, or nil for anonymous sessions. - The JWT bytes and session token NEVER cross any FFI exposed here; only the extracted identity string does. A malicious user-scope script can lie about identity but cannot exfiltrate the bearer token. - Authority on the server is established by the JWT the SDK presents on every request, not by anything this module reports. Multi-user replication (other connected users' records) plugs in on top of the same `User` metatable shape; today the registry contains only `localUser` because the boot path is the only populated source. The list/get/exists/count surface is shaped so it stays correct once server replication populates the remaining records.

## modules/contactShadows/README {#modules-contactshadows-readme}

```lua
require("@builtin/systems/contactShadows/contactShadows") -- contactShadows
```

Short screen-space shadow traces that supply the small-scale contact a shadow map cannot resolve — the grounding under a chair leg, a prop on a table, anything whose contact is finer than one shadow texel.

Usage: local contactShadows = require("@builtin/systems/contactShadows/contactShadows")

## modules/contactShadows/active {#modules-contactshadows-active}

```lua
active(): boolean
```

Whether the contact-shadow pass is running this frame.

```lua
if contactShadows.active() then ... end
```

## modules/contactShadows/clear {#modules-contactshadows-clear}

```lua
clear()
```

Turn contact shadows off and release the pass. The other settings are
kept, so a later `set({ strength = ... })` brings back the same look.

```lua
contactShadows.clear()
```

## modules/contactShadows/get {#modules-contactshadows-get}

```lua
get(): ContactState
```

The contact-shadow settings currently in force.

```lua
local l = contactShadows.get().length
```

## modules/contactShadows/lights {#modules-contactshadows-lights}

```lua
lights(): { ContactLight }
```

The point, spot and distant lights the last refresh packed for the trace
pass, ranked by what each is worth at the main camera.

```lua
local n = #contactShadows.lights()
```

## modules/contactShadows/lightsBuffer {#modules-contactshadows-lightsbuffer}

```lua
lightsBuffer(): any?
```

The light buffer the trace pass reads — one row per light the scene's
contact traces reach toward, packed by the last refresh.

```lua
local l = contactShadows.lightsBuffer()
```

## modules/contactShadows/paramsBuffer {#modules-contactshadows-paramsbuffer}

```lua
paramsBuffer(): any?
```

The buffer this system's passes read. The render feature binds what
this hands it, so the pass has the values this module packed.

```lua
local p = contactShadows.paramsBuffer()
```

## modules/contactShadows/refresh {#modules-contactshadows-refresh}

```lua
refresh()
```

Re-read the scene's lights and re-push what the trace pass reads: the
sun's direction and weight, and the lights supplying contact of their own.
The render feature calls this every frame, so the traces follow lights that
move, brighten or are spawned while the scene runs.

```lua
contactShadows.refresh()
```

## modules/contactShadows/set {#modules-contactshadows-set}

```lua
set(opts: ContactOpts?): ContactState
```

Set the scene's contact shadows. Any omitted field keeps its current
value. A `strength` of 0 turns them off and releases the pass.

**Parameters**

- `opts` `ContactOpts?` _(optional)_ — Contact-shadow settings — see `ContactOpts`.

```lua
contactShadows.set({ strength = 0.9, length = 0.35, steps = 16 })
```

## modules/data_contract/README {#modules-data-contract-readme}

```lua
data_contract
```

The `dataContract` field-constraint validator: a constrained value must be a `.data` instance whose dataType contract chain includes `constraint.contract`. Registers itself with the generic field_constraints registry on load.

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

```lua
require("@builtin/systems/debanding/debanding") -- debanding
```

Gradient debanding. Rebuilds a shallow ramp that eight-bit storage flattened into shelves, so a sky or a light falloff reads as continuous instead of as a stack of contour lines.

Usage: local debanding = require("@builtin/systems/debanding/debanding")

## modules/debanding/active {#modules-debanding-active}

```lua
active(): boolean
```

Whether the debanding pass is running this frame.

```lua
if debanding.active() then ... end
```

## modules/debanding/disable {#modules-debanding-disable}

```lua
disable()
```

Turn debanding off and release the pass.

```lua
debanding.disable()
```

## modules/debanding/enable {#modules-debanding-enable}

```lua
enable(strength: number?): State
```

Turn debanding on at a given strength.

**Parameters**

- `strength` `number?` _(optional)_ — Strength in [0, 1]. Omit to keep the current value.

```lua
debanding.enable()
```

## modules/debanding/get {#modules-debanding-get}

```lua
get(): State
```

The debanding settings currently in force.

```lua
local s = debanding.get().threshold
```

## modules/debanding/paramsBuffer {#modules-debanding-paramsbuffer}

```lua
paramsBuffer(): any?
```

The buffer this system's passes read. The render feature binds what
this hands it, so the pass has the values this module packed.

```lua
local p = debanding.paramsBuffer()
```

## modules/debanding/set {#modules-debanding-set}

```lua
set(opts: DebandOpts?): State
```

Set the debanding settings. Any omitted field keeps its current value.

**Parameters**

- `opts` `DebandOpts?` _(optional)_ — Debanding settings — see `DebandOpts`.

```lua
debanding.set({ threshold = 3, radius = 16 })
```

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

```lua
require("@builtin/modules/api/engine/debugger") -- debugger (also available as global 'debugger')
```

Luau debugger — breakpoints, stepping, stack inspection, watches. Public Luau surface over the `__debugger` Internal FFI namespace.

Usage: local debugger = require("@builtin/modules/api/engine/debugger")
Also available as global: debugger

## modules/debugger/__diagnostics {#modules-debugger-diagnostics}

```lua
__diagnostics(): DebuggerDiagnostics
```

Internal diagnostic counters for debugging the debugger
itself: `{ installs, debugbreakHits }`.

## modules/debugger/addWatch {#modules-debugger-addwatch}

```lua
addWatch(expr: string): number
```

Register an expression to re-evaluate on every pause.

**Parameters**

- `expr` `string` — Luau expression.

## modules/debugger/continue_ {#modules-debugger-continue}

```lua
continue_(): boolean
```

Resume the paused thread.

## modules/debugger/disableAll {#modules-debugger-disableall}

```lua
disableAll()
```

Disable every registered breakpoint. Records persist;
bytecode BREAK ops are cleared.

## modules/debugger/disconnect {#modules-debugger-disconnect}

```lua
disconnect(handle: number): boolean
```

Disconnect an onBreak or onResume callback.

**Parameters**

- `handle` `number` — Handle returned by onBreak/onResume.

## modules/debugger/enableAll {#modules-debugger-enableall}

```lua
enableAll()
```

Enable every registered breakpoint and re-install them in
the VM bytecode.

## modules/debugger/evaluate {#modules-debugger-evaluate}

```lua
evaluate(expr: string, frame: number?): (string?, string?)
```

Evaluate an expression against the paused frame's
environment. Returns `(value, error)`.

**Parameters**

- `expr` `string` — Luau expression.
- `frame` `number?` _(optional)_ — 1-based frame index (default 1).

## modules/debugger/getLocals {#modules-debugger-getlocals}

```lua
getLocals(frame: number?): { [string]: string }
```

Locals captured at the active pause for the given frame
index (1 = top). Values are stringified for safe display.

**Parameters**

- `frame` `number?` _(optional)_ — 1-based frame index (default 1).

## modules/debugger/getPauseInfo {#modules-debugger-getpauseinfo}

```lua
getPauseInfo(): PauseInfo?
```

Info about the active pause, or nil if nothing is paused.

## modules/debugger/getStack {#modules-debugger-getstack}

```lua
getStack(): { Frame }
```

Captured stack from the active pause, top frame first.
Empty when nothing is paused.

## modules/debugger/getUpvalues {#modules-debugger-getupvalues}

```lua
getUpvalues(frame: number?): { [string]: string }
```

Upvalues captured at the active pause for the given frame.

**Parameters**

- `frame` `number?` _(optional)_ — 1-based frame index.

## modules/debugger/getWatchValue {#modules-debugger-getwatchvalue}

```lua
getWatchValue(id: number): (string?, string?)
```

Re-evaluate the watch expression against the paused frame's
environment and return `(value, error)`.

**Parameters**

- `id` `number` — Watch id.

## modules/debugger/getWatches {#modules-debugger-getwatches}

```lua
getWatches(): { Watch }
```

Snapshot of all watches with their last evaluated value and
error, sorted by id.

## modules/debugger/isPauseOnError {#modules-debugger-ispauseonerror}

```lua
isPauseOnError(): boolean
```

Current pause-on-error toggle state for this VM.

## modules/debugger/isPaused {#modules-debugger-ispaused}

```lua
isPaused(): boolean
```

Whether the debugger currently has a paused thread.

## modules/debugger/listBreakpoints {#modules-debugger-listbreakpoints}

```lua
listBreakpoints(): { Breakpoint }
```

Snapshot of every registered breakpoint, sorted by id
ascending. Each entry reports whether it is installed:
`chunkNames` lists the loaded chunks carrying it, and
`pendingReason` says why an empty list is empty.

## modules/debugger/onBreak {#modules-debugger-onbreak}

```lua
onBreak(fn: (PauseInfo) -> ()): number
```

Register a callback invoked on every pause with
`{ path, line, reason }`. Returns a handle usable with
`debugger.disconnect`.

**Parameters**

- `fn` `(PauseInfo) -> ()` — Callback.

## modules/debugger/onResume {#modules-debugger-onresume}

```lua
onResume(fn: () -> ()): number
```

Register a callback invoked when the paused thread is
resumed.

**Parameters**

- `fn` `() -> ()` — Callback.

## modules/debugger/removeBreakpoint {#modules-debugger-removebreakpoint}

```lua
removeBreakpoint(id: number): boolean
```

Remove the breakpoint with the given id.

**Parameters**

- `id` `number` — Breakpoint id returned by setBreakpoint.

## modules/debugger/removeWatch {#modules-debugger-removewatch}

```lua
removeWatch(id: number): boolean
```

Remove the watch with the given id.

**Parameters**

- `id` `number` — Watch id.

## modules/debugger/setBreakpoint {#modules-debugger-setbreakpoint}

```lua
setBreakpoint(path: string, line: number, opts: BreakpointOpts?): Breakpoint
```

Set a breakpoint at `line` in the script `path` names — its
VFS path, its require identity, or the chunk name it loaded
under. An installed breakpoint carries `resolvedLine` and lists
the loaded chunks holding it in `chunkNames`; one whose script is
not loaded carries `pendingReason`, an empty `chunkNames`, and
installs itself when that script loads.

**Parameters**

- `path` `string` — VFS path, require identity, or chunk name.
- `line` `number` — 1-based source line.
- `opts` `BreakpointOpts?` _(optional)_ — `{ condition?, logMessage?, hitCount?, enabled? }`.

```lua
local bp = debugger.setBreakpoint("/zero/source/main.luau", 42)
print(bp.pendingReason or ("installed in " .. bp.chunkNames[1]))
```

## modules/debugger/setPauseOnError {#modules-debugger-setpauseonerror}

```lua
setPauseOnError(enabled: boolean)
```

When true, uncaught Luau errors fire the onBreak callback
(observation only — the error still propagates).

**Parameters**

- `enabled` `boolean` — Toggle state.

## modules/debugger/stepInto {#modules-debugger-stepinto}

```lua
stepInto(): boolean
```

Run until the next line, descending into any function call.

## modules/debugger/stepOut {#modules-debugger-stepout}

```lua
stepOut(): boolean
```

Run until the current frame returns; pauses in the caller.

## modules/debugger/stepOver {#modules-debugger-stepover}

```lua
stepOver(): boolean
```

Run until the next line in the current frame. Calls inside
the current line are skipped.

## modules/debugger/toggleBreakpoint {#modules-debugger-togglebreakpoint}

```lua
toggleBreakpoint(path: string, line: number): Breakpoint?
```

Toggle a breakpoint at the given line: removes if present,
adds otherwise.

**Parameters**

- `path` `string` — VFS path, require identity, or chunk name.
- `line` `number` — 1-based line.

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

```lua
denoiser
```

Edge-aware denoising a render feature routes a noisy signal through. A feature that shades from a few stochastic samples per pixel writes a result carrying that sampling noise, and the only way to quieten it in the feature itself is to cast more rays. Filtering the result instead buys the same quality far more cheaply, and the filter is the same one for every such feature, so it lives here rather than being rewritten per effect. A filter smooths in two directions. Across the frame it is an à-trous wavelet: successive passes with a doubling tap stride, so a handful of 5x5 passes reach the radius a single wide blur would need hundreds of taps for. Each tap is weighted by how much the surface under it resembles the surface under the centre pixel — its world position from `@scene.depth` and its normal from `@scene.normal` — so the smoothing follows geometry and stops at depth and normal discontinuities instead of bleeding an object's occlusion onto the wall behind it. Across time — with `temporal` set — it first carries the previous frame's estimate forward through `@scene.motion`, so the standing average holds far more samples than any one frame casts and the feature feeding it can trace fewer rays for the same quietness. A reprojected estimate is admitted only where the surface it was written on is the surface being shaded now, and never for longer than `historyFrames`. Each filter owns its targets and its compiled passes, keyed by the name it was created with, so two features denoising in the same frame do not interfere.

## modules/denoiser/create {#modules-denoiser-create}

```lua
create(name: string, opts: DenoiseOpts?): Filter
```

Create a filter that owns its own targets and passes. `name` keys those
resources, so two features denoising in the same frame each pass their own
name and never share state.

**Parameters**

- `name` `string` — Identifies this filter's resources. Unique per feature.
- `opts` `DenoiseOpts?` _(optional)_ — Filtering settings — see `DenoiseOpts`.

```lua
local d = denoiser.create("rt_ao", { iterations = 4, worldSigma = 0.5, temporal = true })
```

## modules/denoiser/destroy {#modules-denoiser-destroy}

```lua
destroy(self: Filter)
```

Release the filter's targets. The filter rebuilds on its next `run`.

**Parameters**

- `self` `Filter`

```lua
filter:destroy()
```

## modules/denoiser/passes {#modules-denoiser-passes}

```lua
passes(self: Filter): number
```

Consecutive order slots `run` occupies, counted from the order it is
given, so a caller knows where its own next pass can sit.

**Parameters**

- `self` `Filter`

```lua
local apply = 51 + filter:passes()
```

## modules/denoiser/reset {#modules-denoiser-reset}

```lua
reset(self: Filter)
```

Drop what the accumulation holds, so the next frame starts from its own
samples. Call it at a camera cut, where nothing on screen was on the last
frame and no reprojection could find it.

**Parameters**

- `self` `Filter`

```lua
filter:reset()
```

## modules/denoiser/run {#modules-denoiser-run}

```lua
run(self: Filter, ctx: any, source: string, opts: { phase: string?, order: number? }?): string
```

Enqueue this filter's passes over `source`, and answer the guid holding
the filtered result. Call it from a render feature's `render`, passing the
same `ctx`; the result is ready for the phase and order given.

**Parameters**

- `self` `Filter`
- `ctx` `any` _(optional)_ — The render context the calling feature received.
- `source` `string` — Guid of the texture holding the noisy signal.
- `opts` `{ phase: string?, order: number? }?` _(optional)_ — `{ phase, order }` — where the filter's passes run. `order` is the
first of `passes()` consecutive slots.

```lua
local clean = filter:run(ctx, noisy.guid, { phase = "afterLighting", order = 55 })
```

## modules/denoiser/stats {#modules-denoiser-stats}

```lua
stats(self: Filter): DenoiseStats
```

What the filter is doing right now — whether it accumulates, whether it
holds an accumulation, how many times that has been dropped, and the size
its targets are built for.

**Parameters**

- `self` `Filter`

```lua
if not filter:stats().warmed then print("first frame of the accumulation") end
```

## modules/depthOfField/README {#modules-depthoffield-readme}

```lua
require("@builtin/systems/depthOfField/depthOfField") -- depthOfField
```

Depth of field from a lens — focus distance, focal length and aperture, so the falloff behaves the way a camera's does.

Usage: local depthOfField = require("@builtin/systems/depthOfField/depthOfField")

## modules/depthOfField/active {#modules-depthoffield-active}

```lua
active(): boolean
```

Whether the defocus passes are currently running.

```lua
if depthOfField.active() then print("shallow") end
```

## modules/depthOfField/clear {#modules-depthoffield-clear}

```lua
clear()
```

Turn defocus off and release the passes. The lens is kept, so a later
`set({ fStop = ... })` brings back the same look.

```lua
depthOfField.clear()
```

## modules/depthOfField/get {#modules-depthoffield-get}

```lua
get(): DepthOfFieldState
```

The lens currently in force.

```lua
local f = depthOfField.get().focusDistance
```

## modules/depthOfField/paramsBuffer {#modules-depthoffield-paramsbuffer}

```lua
paramsBuffer(): any?
```

The buffer this system's passes read. The render feature binds what
this hands it, so the pass has the values this module packed.

```lua
local p = depthOfField.paramsBuffer()
```

## modules/depthOfField/set {#modules-depthoffield-set}

```lua
set(opts: DepthOfFieldOpts?): DepthOfFieldState
```

Set the lens. Any omitted field keeps its current value, so a call can
rack focus without restating the rest. An `fStop` of 0 turns defocus off
and releases the passes.

**Parameters**

- `opts` `DepthOfFieldOpts?` _(optional)_ — Lens settings — see `DepthOfFieldOpts`.

```lua
depthOfField.set({ focusDistance = 8, fStop = 1.8, focalLength = 85 })
```

## modules/edui.app/README {#app-readme}

```lua
edui.app
```

The edui reactive core: an `App` owns one `ui.*` screen, maps author closures to `ui.*` string callback ids, dispatches the broadcast that `ui.registerCallbackEnv` delivers, and rebuilds the widget tree on state change. This is the layer that lets editor chrome be written with closures (`onClick = function() ... end`) instead of hand-managed string ids — the footgun the deprecated `zui` grew three shapes for.

## modules/edui.app/adoptHandlers {#app-adopthandlers}

```lua
adoptHandlers(self: any, bucket: { [string]: (any) -> () })
```

Re-register a bucket of handlers collected by `collectHandlers` into
the current build, keeping a cached subtree's callbacks live.

**Parameters**

- `self` `any` _(optional)_
- `bucket` `{ [string]: (any) -> () }` — The handler bucket to adopt.

```lua
app:adoptHandlers(cached.bucket)
```

## modules/edui.app/cb {#app-cb}

```lua
cb(self: any, closure: (any) -> (), key: (string | number)?): string
```

Allocate (or reuse) a callback id bound to `closure` for this build.
Pass a stable `key` so the id is identical across rebuilds — required for
anything the renderer tracks by id (focus, drag, `ui.widgetState`).
Without a key the id is a per-build sequence number (fine for a
fire-and-forget button).

**Parameters**

- `self` `any` _(optional)_
- `closure` `(any) -> ()` — The handler `(data) -> ()` the id dispatches to.
- `key` `(string | number)?` _(optional)_ — Optional stable key (unique within this screen).

```lua
props = { onClick = app:cb(function() doThing() end, "save") }
```

## modules/edui.app/cbRaw {#app-cbraw}

```lua
cbRaw(self: any, id: string, closure: (any) -> ()): string
```

Register `closure` under the EXACT id `id`, without the screen-name
prefix `cb` adds. For wiring engine-emitted interaction ids that a widget
publishes itself (e.g. a dockArea's `<panelId>-close`), which arrive
unprefixed. Re-issue it each build, like `cb`.

**Parameters**

- `self` `any` _(optional)_
- `id` `string` — The exact callback id the engine will deliver.
- `closure` `(any) -> ()` — The handler `(data) -> ()`.

```lua
app:cbRaw(panelId .. "-close", function() closePanel(panelId) end)
```

## modules/edui.app/collectHandlers {#app-collecthandlers}

```lua
collectHandlers(self: any, fn: () -> any): (any, { [string]: (any) -> () })
```

Collect every callback registered while `fn` runs into a named bucket,
returned alongside `fn`'s result. A host that CACHES the subtree `fn`
built re-adopts the bucket on later builds (`adoptHandlers`), so the
cached tree's callback ids stay live across rebuilds that skipped it.

**Parameters**

- `self` `any` _(optional)_
- `fn` `() -> any` — The builder to run.

**Returns** `() })` — `fn`'s result, and the bucket of handlers it registered.

```lua
local tree, bucket = app:collectHandlers(function() return panel.build() end)
```

## modules/edui.app/current {#app-current}

```lua
current(): any
```

The app whose builder is currently running, or nil outside a build.
The `edui.*` primitive builders read this to register their closures, so
authors don't thread the app through every call.

```lua
local app = edui.app.current()
```

## modules/edui.app/dispatch {#app-dispatch}

```lua
dispatch(self: any, id: string, data: any): boolean
```

Route a callback id to its closure and schedule a rebuild. This is
what the screen's `onCallback` broadcast calls. Returns true when the id
was handled by this app (an id from another surface returns false so a
host can keep routing).

**Parameters**

- `self` `any` _(optional)_
- `id` `string` — The callback id the broadcast delivered.
- `data` `any` _(optional)_ — The engine event envelope `{ value, eventType, widgetId, button,
mouseX, mouseY }`. The handler receives its `value`: a scalar for
`onChange` (checkbox bool, input string, select value), a
`{ dx, dy, shift, ctrl, alt }` table for a canvas `onDrag`/`onScroll`,
`nil` for a bare `onClick`.

```lua
function onCallback(id, data) app:dispatch(id, data) end
```

## modules/edui.app/markDirty {#app-markdirty}

```lua
markDirty(self: any)
```

Mark the app dirty and rebuild its tree. Coalesces a rebuild
requested WHILE a build is running into a single follow-up build (so a
handler that mutates state and a builder that reads it never recurse),
and one requested WHILE a dispatch's handler runs into the single
rebuild that dispatch performs after the handler returns.

**Parameters**

- `self` `any` _(optional)_

## modules/edui.app/mount {#app-mount}

```lua
mount(self: any, builderFn: (any) -> any): any
```

Mount the app: register the broadcast callback env and do the first
build. `builderFn(app) -> widgetTree` is called now and on every rebuild;
inside it, `app:cb(...)` (or the `edui.*` primitives) wire closures.

**Parameters**

- `self` `any` _(optional)_
- `builderFn` `(any) -> any` — `(app) -> widgetTree`.

```lua
app:mount(function(a) return { type = "vertical", children = { ... } } end)
```

## modules/edui.app/new {#app-new}

```lua
new(screenName: string, opts: { [string]: any }?): any
```

Create an editor app that owns the `ui.*` screen `screenName`.

**Parameters**

- `screenName` `string` — Unique screen id (also the callback-id namespace prefix).
- `opts` `{ [string]: any }?` _(optional)_ — `{ layer? = <renderLayerMask>, order? = <number>, callbackKey? = <string> }`.
`layer` is a render-layer membership mask (e.g. the EditorUI bit) applied
via `ui.setScreenRenderLayer` on first register; omit for the default.
`order` is the screen's Z-ORDER — higher paints on top; a floating
surface (the command palette) states one to stand over the dock.

```lua
local app = edui.app.new("myPanel", { layer = editorMask })
```

## modules/edui.app/rebuild {#app-rebuild}

```lua
rebuild(self: any)
```

Run the builder and push the resulting tree to the screen. First call
registers the screen (+ render layer); later calls update it. Builder
errors are logged, never thrown, so one bad build never wedges the editor.

**Parameters**

- `self` `any` _(optional)_

## modules/edui.app/unmount {#app-unmount}

```lua
unmount(self: any)
```

Tear the app down: release the callback env and unregister the screen.

**Parameters**

- `self` `any` _(optional)_

## modules/edui.argForm/README {#argform-readme}

```lua
require("@builtin/~edui.argForm") -- edui.argForm
```

The typed argument form — a declared argument list becomes a form of REAL controls, and the filled form becomes the typed values a call takes. A person never types a Luau literal: strings get a text field, numbers a numeric field, booleans a checkbox, string-literal unions a chip row, colours a colour swatch, Vec3 three axis fields, and an options table expands one level into typed rows of its own. Only a type outside the model falls back to the literal field. The command palette renders every tool through this; the Inspector renders an asset type's operations through the same form, so any surface that knows a signature can offer it.

Usage: local edui.argForm = require("@builtin/~edui.argForm")

## modules/edui.argForm/fieldRows {#argform-fieldrows}

```lua
fieldRows(self: any, path: string, t: string, optional: boolean,
```

The label + control rows for one argument (or one expanded table
field). `depth` indents expanded option fields under their parent.

## modules/edui.argForm/make {#argform-make}

```lua
make(W: any): any
```

Bind the form builder to the widgets barrel `W`. The barrel calls this
once; consumers reach the result as `edui.argForm`.

**Parameters**

- `W` `any` _(optional)_

## modules/edui.argForm/new {#argform-new}

```lua
new(o: { [string]: any }): any
```

A new form instance. `o.ns` (REQUIRED — the id namespace every
control keys under), `o.typeDefs` (the schema's named definitions,
`{ { name, definition } }`), `o.onSubmit` (fired when Enter lands in
a text field — the run affordance), `o.onChanged` (fired after any
control writes a value, for hosts that gate rebuilds on an epoch).

**Parameters**

- `o` `{ [string]: any }`

## modules/edui.argForm/parseSignature {#argform-parsesignature}

```lua
parseSignature(sig: string): { any }
```

Parse a method signature string — `"(self, name: string, opts: T?)"` —
into the argument list a form renders: `{ { name, type, optional } }`.
A leading `self` is the receiver, not an argument, and is dropped. The
arguments are the balanced parenthesised run at the head of the text, so a
signature that goes on to declare what the call hands back —
`"(self, name: string): boolean"` — renders the same form as one that
stops at the arguments.

**Parameters**

- `sig` `string` — The signature text.

## modules/edui.argForm/rows {#argform-rows}

```lua
rows(self: any, args: { any }): { any }
```

The rows for a whole argument list (each `{ name, type, optional,
description? }`), in order.

**Parameters**

- `self` `any` _(optional)_
- `args` `{ any }`

## modules/edui.argForm/values {#argform-values}

```lua
values(self: any, args: { any }): (boolean, any, number?)
```

Assemble the positional values for `args` from the filled form.
Returns `(true, values, n)` — `n` the last non-nil position for
`table.unpack(values, 1, n)` — or `(false, message)`.

**Parameters**

- `self` `any` _(optional)_
- `args` `{ any }`

## modules/edui.cmdPalette/README {#cmdpalette-readme}

```lua
require("@builtin/~edui.cmdPalette") -- edui.cmdPalette
```

The command palette — search everything under one keystroke. Ctrl+K (or the topbar's Tools button) opens a floating surface whose one query reaches the scene's entities (select + frame), the registered assets (select — the Inspector shows it), the editor's panels (focus), and the whole tool registry (pick one and its typed argument schema becomes a form, Run executing it in place). A `t:` / `e:` / `a:` / `p:` prefix narrows to one domain. Every domain reads its live registry, so what exists is findable with no UI work per addition.

Usage: local edui.cmdPalette = require("@builtin/~edui.cmdPalette")

## modules/edui.cmdPalette/isOpen {#cmdpalette-isopen}

```lua
isOpen(): boolean
```

Whether the palette is up. The screen's live visibility is the one
answer every scope shares — the menu bar, the entrypoint, and a panel
each hold their own copy of this module, and a module-local flag left
them disagreeing about whether the palette was open, so a Close click
handled by one copy re-showed what another copy had shown.

## modules/edui.cmdPalette/mount {#cmdpalette-mount}

```lua
mount(layerMask: number?)
```

Mount the palette (idempotent): its own screen, hidden until toggled.

**Parameters**

- `layerMask` `number?` _(optional)_ — Optional EditorUI render-layer mask (the menu bar passes its own).

## modules/edui.cmdPalette/openTool {#cmdpalette-opentool}

```lua
openTool(name: string)
```

Open the palette directly at a tool's form — the deep link another
surface uses to hand a person a ready-to-fill tool ("run this operation"
from an inspector, a docs page, an agent suggestion). Opens the palette
if it is closed, then loads `name`'s schema as the form.

**Parameters**

- `name` `string` — The tool's full name, `toolbox.tool`.

## modules/edui.cmdPalette/screenName {#cmdpalette-screenname}

```lua
screenName(): string
```

The palette's screen name (capture / element addressing).

## modules/edui.cmdPalette/toggle {#cmdpalette-toggle}

```lua
toggle()
```

Open / close the palette. Opening starts fresh at the search and
puts the caret in it. The decision reads the screen's live visibility,
never a module-local flag.

## modules/edui.cmdPalette/unmount {#cmdpalette-unmount}

```lua
unmount()
```

Tear the palette down.

## modules/edui.framework/README {#framework-readme}

```lua
require("@builtin/~edui.framework") -- edui.framework
```

Editor UI framework on the CSS-parity `ui.*` surface. A small, editor-ONLY toolkit: a reactive app that maps author closures to `ui.*` callback ids, a dock shell over `ui.*` native docking, and editor-chrome primitives (panels, trees, toolbars, inspector rows, context menus, drag-and-drop). Gameplay / normal UI authors raw `ui.*` trees and needs none of this — `edui` earns its keep only for the editor.

Usage: local edui.framework = require("@builtin/~edui.framework")

## modules/edui.framework/createApp {#framework-createapp}

```lua
createApp(name: string, opts: { [string]: any }?): any
```

Create + return an editor app that owns the `ui.*` screen `name`.
Shorthand for `edui.app.new`. Call `app:mount(builderFn)` to bring it up.

**Parameters**

- `name` `string` — Unique screen id (also the callback-id namespace).
- `opts` `{ [string]: any }?` _(optional)_ — `{ layer? = <renderLayerMask> }`.

```lua
local a = edui.createApp("myPanel"); a:mount(function(app) return tree end)
```

## modules/edui.framework/current {#framework-current}

```lua
current(): any
```

The app whose builder is currently running (nil outside a build). The
`edui.*` primitives read this to register their closures.

## modules/edui.query/README {#query-readme}

```lua
require("@builtin/~edui.query") -- edui.query
```

Resolves the engine-provided query globals edui panels read — `queryEntitiesTable`, `queryLogsTable`, `getProfilingDataTable`, and the like. The engine installs these on `_G` at boot (before the global table is sealed read-only), so panels read them through this one indirection rather than each touching `_G` directly. `override`/`restore` swap a source for a stub or a mock feed without writing the sealed `_G`.

Usage: local edui.query = require("@builtin/~edui.query")

## modules/edui.query/override {#query-override}

```lua
override(name: string, fn: any)
```

Shadow an engine query global with a function until restored.

**Parameters**

- `name` `string` — The global name.
- `fn` `any` _(optional)_ — The function to resolve in its place.

## modules/edui.query/resolve {#query-resolve}

```lua
resolve(name: string): any
```

Resolve a named engine query global, honouring any active override.

**Parameters**

- `name` `string` — The global name (e.g. "queryEntitiesTable").

## modules/edui.query/restore {#query-restore}

```lua
restore(name: string)
```

Clear an override so `resolve` falls back to the engine global again.

**Parameters**

- `name` `string` — The global name.

## modules/edui.shell/README {#shell-readme}

```lua
require("@builtin/~edui.shell") -- edui.shell
```

The editor dock shell on the CSS-parity `ui.*` surface. One edui app owns a `ui.*` native `dockArea` whose children are a `dockPanel` per registered edui panel — real egui_dock tabs, splits and drag. The shell keeps its OWN panel registry (separate from the deprecated zui editor registry) so the zui editor stays untouched while panels migrate one at a time; the two registries fold into one at cutover.

Usage: local edui.shell = require("@builtin/~edui.shell")

## modules/edui.shell/addPanel {#shell-addpanel}

```lua
addPanel(spec: any): boolean
```

Register (or replace) an edui dock panel. A duplicate id replaces the
prior registration; the live shell rebuilds so the change shows at once.

**Parameters**

- `spec` `any` _(optional)_ — `{ id (REQUIRED), build (REQUIRED, () -> widget), title?, order?,
dock?, badge?, badgeColor?, startClosed? }`. `build` is an edui builder:
it may call the `edui.*` primitives, whose closures register on the shell
app automatically. `startClosed = true` registers into the Window-menu
catalog without opening a tab; the panel opens when someone opens it.

```lua
edui.shell.addPanel{ id = "entities", title = "Entities", build = fn }
```

## modules/edui.shell/app {#shell-app}

```lua
app(): any
```

The mounted shell App, or nil when the shell is not up.

## modules/edui.shell/catalog {#shell-catalog}

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

Every catalogued panel (open or closed), sorted by (order, id), each
`{ id, title, order, dock, open }` — the Window menu's source.

## modules/edui.shell/exportLayout {#shell-exportlayout}

```lua
exportLayout(): string?
```

The live dock arrangement, serialized — what saveLayout writes and
loadLayout applies. Nil before the dock's first render.

## modules/edui.shell/focusPanel {#shell-focuspanel}

```lua
focusPanel(id: string): boolean
```

Bring a panel's tab to the front of its dock leaf, opening it from
the catalog first if its tab is closed — what a menu entry naming a
panel does. Unlike `openPanel`, this acts visibly when the tab is
already open behind another.

**Parameters**

- `id` `string` — The panel id.

## modules/edui.shell/layoutMode {#shell-layoutmode}

```lua
layoutMode(): string
```

The current editor layout mode: "full" (every panel + toolstrip) or
"simple" (viewport-first — for sessions driven mainly through agents).

## modules/edui.shell/listLayouts {#shell-listlayouts}

```lua
listLayouts(): { string }
```

The saved layout names, sorted — the files under the layout folder.

## modules/edui.shell/loadLayout {#shell-loadlayout}

```lua
loadLayout(name: string): (boolean, string?)
```

Apply the saved layout `name` to the live dock. Opens every catalogued
panel first so each tab the arrangement references exists, then restores
the arrangement one-shot — a drag afterwards owns it, exactly as after a
reset.

**Parameters**

- `name` `string` — A name `listLayouts` reports.

```lua
edui.shell.loadLayout("modeling")
```

## modules/edui.shell/mount {#shell-mount}

```lua
mount(opts: any?): any
```

Mount the shell (idempotent — returns the existing app if already up).
Registers the `ui.*` screen on the EditorUI layer and does the first build.

**Parameters**

- `opts` `any?` _(optional)_ — `{ refresh? = <seconds between liveness rebuilds, default 0.5> }`.

```lua
edui.shell.mount()
```

## modules/edui.shell/openPanel {#shell-openpanel}

```lua
openPanel(id: string): boolean
```

Re-open a catalogued panel by id — restores its tab in its preferred
dock region. A no-op (returns false) if the id was never registered or is
already open.

**Parameters**

- `id` `string` — The panel id.

## modules/edui.shell/panel {#shell-panel}

```lua
panel(id: string): any?
```

The catalogued panel record for `id` — the spec table its
registration passed to addPanel, extra keys included. This is how one
panel reaches another's exported surface: the Files panel opens a file
in the Code panel through the `openFile` its record carries.

**Parameters**

- `id` `string` — The panel id passed to addPanel.

```lua
local rec = edui.shell.panel("code"); if rec then rec.openFile(path) end
```

## modules/edui.shell/panelsSorted {#shell-panelssorted}

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

The registered panels sorted by (order, id) — the dock/tab order.

## modules/edui.shell/refresh {#shell-refresh}

```lua
refresh()
```

Rebuild every active panel now — each re-queries live data. Call after
a change the shell can't observe (a scene edit made outside its own
handlers). For a change that concerns ONE panel, `refreshPanel` rebuilds
just that panel.

## modules/edui.shell/refreshPanel {#shell-refreshpanel}

```lua
refreshPanel(id: string)
```

Rebuild one panel — its own screen republishes; every other panel and
the dock itself are untouched. The scoped path for a data event with a
known audience (a selection change concerns the entity tree and the
inspector, not the console).

**Parameters**

- `id` `string` — The panel id to rebuild.

```lua
edui.shell.refreshPanel("inspector")
```

## modules/edui.shell/removePanel {#shell-removepanel}

```lua
removePanel(id: string): boolean
```

Remove a registered panel by id — closes its tab. The panel stays in
the catalog, so the Window menu can re-open it later. A spec that
declares `close` is told: the hook runs as the tab goes, so a panel
holding live resources (a render session, a watcher) releases them.

**Parameters**

- `id` `string` — The panel id passed to addPanel.

## modules/edui.shell/resetLayout {#shell-resetlayout}

```lua
resetLayout()
```

Restore the seeded default dock arrangement — the escape hatch for a
layout dragged into an unusable state. Reopens the mode's panel set (every
catalogued panel in full mode, the viewport alone in simple) and rebuilds
the dock from each panel's `dock` region hint.

```lua
edui.shell.resetLayout()
```

## modules/edui.shell/saveLayout {#shell-savelayout}

```lua
saveLayout(name: string): (boolean, string?)
```

Save the live dock arrangement under `name` — one file at
`/zero/source/editor/layout/saved/<name>.json`, renameable and removable
through the Files panel like any other file.

**Parameters**

- `name` `string` — The layout's name; non-identifier characters fold to `_`.

```lua
edui.shell.saveLayout("modeling")
```

## modules/edui.shell/screenName {#shell-screenname}

```lua
screenName(): string
```

The shell's screen name (for `ui.showScreen` / capture `screen`).

## modules/edui.shell/setLayoutMode {#shell-setlayoutmode}

```lua
setLayoutMode(mode: string, opts: any?): boolean
```

Switch the editor between the full authoring layout and the simple,
viewport-first one. "simple" closes every panel but the Scene viewport and
hides the toolstrip; "full" restores the panels that were open when simple
was entered (or every catalogued panel on a fresh boot into simple). The
choice persists across sessions alongside the saved dock arrangement.

**Parameters**

- `mode` `string` — "full" | "simple".
- `opts` `any?` _(optional)_ — `{ persist? = false }` skips the write (the boot restore path).

```lua
edui.shell.setLayoutMode("simple")
```

## modules/edui.shell/togglePanel {#shell-togglepanel}

```lua
togglePanel(id: string): boolean
```

Toggle a catalogued panel open/closed — the Window-menu action.

**Parameters**

- `id` `string` — The panel id.

## modules/edui.shell/unmount {#shell-unmount}

```lua
unmount()
```

Tear the shell down (unregisters the screen + callback env). Panel
registrations are kept, so a later `mount` brings the same set back up.

## modules/edui.shell/update {#shell-update}

```lua
update(dt: number)
```

Drive the shell's liveness refresh. Call each frame from the editor
update loop; every ACTIVE panel rebuilds every `refresh` seconds so it
reflects live scene state without arming its own timer. A tab switch is
also caught here: the newly shown panel refreshes on the tick after the
switch.

**Parameters**

- `dt` `number` — Seconds since the last call.

## modules/edui.topbar/README {#topbar-readme}

```lua
require("@builtin/~edui.topbar") -- edui.topbar
```

The editor menu bar on edui — a `ui.*` ctx-level `topPanel` above the dock: domain dropdown menus on the left (Scene / Content / Debug), the Window menu that opens/closes edui panels, and the play/pause transport on the right. Every menu entry names a panel this editor ships and focuses it. It owns one edui app on its own screen, so it composes above the shell's dock and toolstrip.

Usage: local edui.topbar = require("@builtin/~edui.topbar")

## modules/edui.topbar/mount {#topbar-mount}

```lua
mount(layerMask: number?): any
```

Mount the menu bar (idempotent). Registers its `ui.*` screen on the
EditorUI layer and does the first build.

**Parameters**

- `layerMask` `number?` _(optional)_ — Optional EditorUI render-layer mask; computed when omitted.

```lua
edui.topbar.mount()
```

## modules/edui.topbar/screenName {#topbar-screenname}

```lua
screenName(): string
```

The bar's screen name (for `ui.showScreen` / capture `screen`).

## modules/edui.topbar/unmount {#topbar-unmount}

```lua
unmount()
```

Tear the menu bar down.

## modules/edui.widgets.assetBrowser/README {#assetbrowser-readme}

```lua
require("@builtin/~edui.widgets.assetBrowser") -- edui.widgets.assetBrowser
```

The generic asset browser — one surface for browsing and for picking. Search (name and type), a scope filter (project / builtin), a type filter built from the live registry, list and grid presentation with adjustable tile size and image previews where the asset is one, over the world's asset registry. Browse mode is the Assets panel's body; picker mode is what a REF field or an Add Component flow opens, filtered to the kinds the target accepts, firing `onPick` with the chosen record.

Usage: local edui.widgets.assetBrowser = require("@builtin/~edui.widgets.assetBrowser")

## modules/edui.widgets.assetBrowser/data {#assetbrowser-data}

```lua
data(): { rows: { AssetRecord }, kinds: { { id: string, count: number } } }
```

The shared registry reading — `{ rows, kinds }`, fetched on first
use and held until `invalidate`. The capability queries above resolve
their per-kind probes against it.

## modules/edui.widgets.assetBrowser/epoch {#assetbrowser-epoch}

```lua
epoch(): number
```

The browser's view epoch — fold into the host panel's build signature.

## modules/edui.widgets.assetBrowser/instantiableKinds {#assetbrowser-instantiablekinds}

```lua
instantiableKinds(): { string }
```

The placeable kind ids in the live registry, sorted — each answered
by its type's `canInstantiate` capability. For an accepts list or a
label.

## modules/edui.widgets.assetBrowser/invalidate {#assetbrowser-invalidate}

```lua
invalidate()
```

Drop the shared registry cache; the next build re-reads the registry.
Call after authoring/installing content so every open browser sees it.

## modules/edui.widgets.assetBrowser/isInstantiable {#assetbrowser-isinstantiable}

```lua
isInstantiable(kind: any): boolean
```

Whether assets of `kind` can be placed into a scene — the asset
type's `canInstantiate` capability, answered once per kind. Drop
targets and filters that accept "a placeable asset" resolve the
question here, so every surface answers it the same way.

**Parameters**

- `kind` `any` _(optional)_

## modules/edui.widgets.assetBrowser/make {#assetbrowser-make}

```lua
make(W: any): (any) -> any
```

Bind the browser builder to the widgets barrel `W`. The barrel calls
this once and exposes the result as `edui.assetBrowser`.

**Parameters**

- `W` `any` _(optional)_ — The `edui.widgets` table.

**Returns** `any` — `assetBrowser(o) -> widget`.

## modules/edui.widgets.assetBrowser/previewSrc {#assetbrowser-previewsrc}

```lua
previewSrc(path: any): string?
```

The image source that pictures an asset — its own file when the path
is an image, else the preview/source file inside its folder. Nil when
nothing drawable is found. Cached per path; `M.invalidate()` clears it.

**Parameters**

- `path` `any` _(optional)_

## modules/edui.widgets.controls/README {#controls-readme}

```lua
edui.widgets.controls
```

edui's OWN interactive controls, drawn on the `ui.*` canvas substrate (paint commands + pointer/key/scroll events) rather than the generic `ui.*` widgets — so an editor control looks and behaves like an editor control, independent of general UI, and enforces its type. A number is a drag-scrub field that only ever holds a number (drag to scrub, scroll to nudge, double-click to type digits — letters can't enter); a bool is a toggle switch. `Controls.make(W)` binds them to the widgets barrel.

## modules/edui.widgets.controls/make {#controls-make}

```lua
make(W: any): any
```

Bind the canvas controls to the widgets barrel `W`. Returns
`{ numberField, boolToggle }`.

**Parameters**

- `W` `any` _(optional)_

## modules/edui.widgets.entityPicker/README {#entitypicker-readme}

```lua
require("@builtin/~edui.widgets.entityPicker") -- edui.widgets.entityPicker
```

The entity picker — the Hierarchy's tree shape wherever an entity is chosen. A search field over a windowed, expandable entity tree (collapsed by default, so skeleton bones and other deep noise stay behind their roots until unfolded or matched), firing `onPick` with the chosen entity's id. What a REF field opens instead of a flat dump of every entity in the world.

Usage: local edui.widgets.entityPicker = require("@builtin/~edui.widgets.entityPicker")

## modules/edui.widgets.entityPicker/epoch {#entitypicker-epoch}

```lua
epoch(): number
```

The picker's view epoch — fold into the host panel's build signature.

## modules/edui.widgets.entityPicker/make {#entitypicker-make}

```lua
make(W: any): (any) -> any
```

Bind the picker builder to the widgets barrel `W`. The barrel calls
this once and exposes the result as `edui.entityPicker`.

**Parameters**

- `W` `any` _(optional)_ — The `edui.widgets` table.

**Returns** `any` — `entityPicker(o) -> widget`.

## modules/edui.widgets.fields/README {#fields-readme}

```lua
edui.widgets.fields
```

Inspector field rows for edui — a two-column (label + control) row whose control is chosen by the field's declared TYPE (from the component's backing schema), falling back to the value's shape when no type is given. The registry maps: number → numeric field, bool → checkbox, string → text field, enum → a dropdown of its members, color → a colour picker, `{x,y,z}` → a vec3 triple, a quaternion → an editable euler (X/Y/Z degrees), an asset slot → a live-asset chip, a nested table → a recursing disclosure. Each control wraps the matching `ui.*` widget and carries the author's `onChange` closure, so a field writes straight back to the live component. `Fields.make(W)` binds these to the widgets barrel; the barrel exposes `edui.field` / `edui.section`.

## modules/edui.widgets.fields/epoch {#fields-epoch}

```lua
epoch(): number
```

The field layer's interaction epoch — moves on every dropdown /
nested-table / picker open or close, and on every view mutation inside
an open asset or entity picker. Fold it into a panel's build signature
so those interactions repaint through a no-change gate.

## modules/edui.widgets.fields/field {#fields-field}

```lua
field(o: any): any
```

An inspector field row. `o = { label, value, kind?, options?, accepts?,
onChange?, readOnly?, key }`. `kind` (from the component schema) selects
the control; without it the control is inferred from the value's shape.
An editable leaf fires `onChange(newValue)` (vec3/quat fire the full new
table).

**Parameters**

- `o` `any` _(optional)_

```lua
edui.field{ label = "kind", value = c.kind, kind = "enum", options = {"a","b"}, onChange = set, key = "k" }
```

## modules/edui.widgets.fields/make {#fields-make}

```lua
make(W: any): any
```

Bind the field builders to the widgets barrel `W`. Returns
`{ field, section }`.

**Parameters**

- `W` `any` _(optional)_ — The edui widgets barrel.

## modules/edui.widgets.fields/section {#fields-section}

```lua
section(o: any): any
```

A collapsible inspector section, drawn as a CARD — a bordered, rounded
container whose clickable header (chevron + optional icon + uppercase
title, with an optional trailing widget) sits over a body shown while
open. `o = { title, open, onToggle, children, key, headerRight?, icon?,
muted? }`. `headerRight` is a SIBLING of the clickable header region, so
its click isn't swallowed by the header toggle.

**Parameters**

- `o` `any` _(optional)_

```lua
edui.section{ title = "Transform", icon = tfIcon, open = st, onToggle = t, children = rows }
```

## modules/edui.widgets.livePreview/README {#livepreview-readme}

```lua
edui.widgets.livePreview
```

The ONE live preview session, following the asset selection. Every surface that shows the selected asset live — the Preview panel, the Inspector's Preview section — reads this module instead of holding its own rig, so one camera and one subject serve them all. The session starts when the asset selection lands, swaps with it, and tears down when it clears. `subscribe` tells a consumer the session's state moved (started, came live, failed) so it can rebuild; `epoch` folds that state into a build signature.

## modules/edui.widgets.livePreview/assetId {#livepreview-assetid}

```lua
assetId(): string? return sessionFor end
```

The guid the session (or attempt) is for, or nil.

## modules/edui.widgets.livePreview/dragOrbit {#livepreview-dragorbit}

```lua
dragOrbit(d: any)
```

Apply a pointer-drag delta as an orbit — the shared handler every
live-preview surface hands its `onDrag`.

**Parameters**

- `d` `any` _(optional)_

## modules/edui.widgets.livePreview/ensure {#livepreview-ensure}

```lua
ensure()
```

Bring the session in line with the asset selection: a new primary
disposes the old rig and assembles one for it, a cleared selection
tears down. Idempotent — consumers call it from their builds; the
selection subscription below calls it on every change.

## modules/edui.widgets.livePreview/epoch {#livepreview-epoch}

```lua
epoch(): number return epoch end
```

The monotonic state counter — fold into a build signature so the
session coming live is a change the panel's no-change gate can see.

## modules/edui.widgets.livePreview/isStarting {#livepreview-isstarting}

```lua
isStarting(): boolean return starting end
```

True while a session is assembling.

## modules/edui.widgets.livePreview/name {#livepreview-name}

```lua
name(): string return sessionName end
```

The selected asset's display name once known, else "".

## modules/edui.widgets.livePreview/reason {#livepreview-reason}

```lua
reason(): string? return failReason end
```

Why the last attempt produced no live session, or nil.

## modules/edui.widgets.livePreview/resetView {#livepreview-resetview}

```lua
resetView()
```

Back to the framed opening view.

## modules/edui.widgets.livePreview/scrollZoom {#livepreview-scrollzoom}

```lua
scrollZoom(d: any)
```

Apply a wheel delta as a zoom — the shared handler every
live-preview surface hands its `onScroll`. Wheel-up moves in.

**Parameters**

- `d` `any` _(optional)_

## modules/edui.widgets.livePreview/session {#livepreview-session}

```lua
session(): any return session end
```

The live session for the selected asset, or nil while there is none
(nothing selected, still starting, or the type has no live path).

## modules/edui.widgets.livePreview/subscribe {#livepreview-subscribe}

```lua
subscribe(fn: () -> ())
```

Register a consumer's rebuild closure, called whenever the session's
state moves. Registration is for the VM lifetime.

**Parameters**

- `fn` `() -> ()`

```lua
livePreview.subscribe(function() edui.shell.refreshPanel("preview") end)
```

## modules/edui.widgets.livePreview/zoomBy {#livepreview-zoomby}

```lua
zoomBy(factor: number)
```

Zoom by a plain factor (toolbar buttons).

**Parameters**

- `factor` `number`

## modules/edui.widgets.tree/README {#tree-readme}

```lua
edui.widgets.tree
```

The editor hierarchy tree primitive — flattens a nested node graph into the rows that are actually visible under the current expand state, and renders them as indented, selectable `ui.*` rows inside a virtualized scroll area. The flatten pass is pure and separately exported, so row order is testable without a rendered frame.

## modules/edui.widgets.tree/flatten {#tree-flatten}

```lua
flatten(o: { [string]: any }): { Row }
```

Flatten `o.roots` into the ordered list of rows visible under the
current expand state — a node's children are included only while that node
is expanded. Pure: no `ui.*` calls, no app required.

**Parameters**

- `o` `{ [string]: any }` — `{ roots, childrenOf?, idOf?, expanded?, isExpanded? }`. `expanded` is
an `{ [id] = true }` set; `isExpanded(node, id) -> boolean` overrides it.

```lua
local rows = edui.widgets.flattenTree{ roots = roots, expanded = { root = true } }
```

## modules/edui.widgets.tree/make {#tree-make}

```lua
make(W: any): (any) -> any
```

Bind the tree builder to a widgets barrel `W`. The barrel calls this
once and exposes the result as `edui.tree`.

**Parameters**

- `W` `any` _(optional)_ — The `edui.widgets` table (supplies palette/text/svgIcon/cbId/merge).

**Returns** `any` — `tree(o) -> widget`.

## modules/edui.widgets/README {#widgets-readme}

```lua
edui.widgets
```

Editor-chrome primitives for edui — styled `ui.*` subtree builders (box/text/icon/iconButton/button/toolbar/panel/divider/spacer). Each reads the active theme's editor tokens so chrome looks like the editor by default, and interactive builders register their closures with the currently-building `edui` app (`edui.current()`), so an author passes a closure, not a callback id.

## modules/edui.widgets/button {#widgets-button}

```lua
button(o: { [string]: any }): any
```

A text button. `o.text`, `o.onClick`, `o.key`, `o.primary`, `o.icon`
(SVG path), `o.tooltip`.

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.button{ text = "Add", primary = true, onClick = onAdd, key = "add" }
```

## modules/edui.widgets/divider {#widgets-divider}

```lua
divider(o: { [string]: any }?): any
```

A 1px divider line (horizontal by default).

**Parameters**

- `o` `{ [string]: any }?` _(optional)_

## modules/edui.widgets/group {#widgets-group}

```lua
group(o: { [string]: any }): any
```

A FLAT collapsible group (chevron + uppercase title + optional count),
with none of the section card's border/shadow — for grouping a list inside
a panel. `o.title`, `o.count?`, `o.open`, `o.onToggle`, `o.children`, `o.key`.

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.group{ title = "@builtin", count = 12, open = o, onToggle = t, children = rows }
```

## modules/edui.widgets/hbox {#widgets-hbox}

```lua
hbox(o: { [string]: any }): any
```

A horizontal flex container. Forwards `onClick`, `onDoubleClick`,
`onDrag`, `dragPayload`, `onDrop` and `tooltip`.

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.hbox{ gap = 6, align = "center", children = { ... } }
```

## modules/edui.widgets/iconButton {#widgets-iconbutton}

```lua
iconButton(o: { [string]: any }): any
```

A compact icon button — a hoverable, optionally-active square holding
an SVG icon. `o.d` (icon path), `o.tooltip`, `o.active`, `o.onClick`,
`o.key`, `o.size`, `o.color`, `o.id` (widget id, e.g. a popup anchor).

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.iconButton{ d = eyeIcon, tooltip = "Visible", active = vis, onClick = toggle, key = "vis:"..id }
```

## modules/edui.widgets/input {#widgets-input}

```lua
input(o: { [string]: any }): any
```

A flat text-entry field — a styled container holding an optional leading
icon and a borderless input, so it reads as one clean field instead of the
raw widget's heavy frame. `o.text`, `o.placeholder`, `o.onChange` (live
per-keystroke), `o.onSubmit` (command-line mode: the full line on Enter,
buffer cleared, caret kept), `o.key`, `o.icon` (SVG path), `o.style`,
`o.bare` (no container frame at all — the input alone, for a surface like
a terminal prompt that draws its own ground).

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.input{ placeholder = "Search…", icon = searchPath, onChange = fn, key = "search" }
```

## modules/edui.widgets/menu {#widgets-menu}

```lua
menu(o: { [string]: any }): any?
```

A context/action menu — a `ui.*` popup pinned below an anchor widget,
holding clickable action items. `o.anchorTo` (widget id of the anchor, which
must render before this in tree order), `o.open` (bool), `o.items` (list of
`{ label, icon?, onClick, danger?, disabled?, hint?, separator?, key? }` —
a disabled item dims and takes no click; `hint` renders right-aligned dim
text, where a shortcut goes), `o.onDismiss` (closure, fired on
click-outside / Escape, and after an item's `onClick` runs — a menu closes
once it has acted), `o.key` (id namespace), `o.pivot`. Returns nil when
closed.

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.menu{ anchorTo = "rowmenu:"..id, open = open, items = {...}, onDismiss = close }
```

## modules/edui.widgets/notice {#widgets-notice}

```lua
notice(o: { [string]: any }): any
```

An inline status banner. `o.text`, `o.tone` ("info" | "ok" | "error").
edui has no timer, so a transient toast is the caller gating this on/off;
this draws the styled line.

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.notice{ text = "Saved", tone = "ok" }
```

## modules/edui.widgets/panel {#widgets-panel}

```lua
panel(o: { [string]: any }): any
```

A panel frame — an optional title/toolbar header over a body that
fills the remaining height. This is the standard dockable-panel shell.
`o.title` (string) OR `o.toolbar` (a prebuilt toolbar widget); `o.body`
(widget); `o.style`.

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.panel{ title = "Entities", body = tree }
```

## modules/edui.widgets/scroll {#widgets-scroll}

```lua
scroll(o: { [string]: any }): any
```

A first-class vertical scroll container filling its parent. `o.children`,
`o.height?`, `o.maxHeight?`, `o.style?`.

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.scroll{ children = rows }
```

## modules/edui.widgets/spacer {#widgets-spacer}

```lua
spacer(): any
```

A flexible spacer that eats remaining space in a flex row/column.

## modules/edui.widgets/stat {#widgets-stat}

```lua
stat(o: { [string]: any }): any
```

A dense read-only telemetry row: `label` on the left, `value` on the
right (mono by default). `good`/`warn` numeric thresholds tint the value
(higher = worse: ≥warn is danger, ≥good is warn-hue, else ok); an explicit
`color` overrides. For readouts too light to warrant an editable `field`.

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.stat{ label = "RSS", value = "412 MB", good = 400, warn = 800, mono = true }
```

## modules/edui.widgets/svgIcon {#widgets-svgicon}

```lua
svgIcon(o: { [string]: any }): any
```

An inline SVG icon. `o.d` is an SVG path (or full `<svg>`); `o.size`,
`o.color`.

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.svgIcon{ d = "<path d='M6 9l6 6 6-6'/>", size = 14 }
```

## modules/edui.widgets/switch {#widgets-switch}

```lua
switch(o: { [string]: any }): any
```

A bare toggle switch (pill track + sliding knob) — the switch control on
its own, distinct from a checkbox or a power button. `o.value` (bool),
`o.onChange`, `o.key`, `o.readOnly`.

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.switch{ value = enabled, onChange = function(v) ... end, key = "comp:en" }
```

## modules/edui.widgets/table {#widgets-table}

```lua
table(o: { [string]: any }): any
```

A multi-column table with a header row, on the real CSS grid. `o.columns`
is `{ { key, label?, width?, align?, mono? } }` (width defaults to `1fr`);
`o.rows` is `{ [colKey] = value }` records. `o.key` (widget id).

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.table{ columns = {{key="name",label="Script"},{key="ms",label="ms",align="right",mono=true}}, rows = rows, key = "vm" }
```

## modules/edui.widgets/text {#widgets-text}

```lua
text(o: { [string]: any } | string): any
```

A text label. `o.text`, `o.color`, `o.dim` (muted), `o.weight`,
`o.size`, `o.style`.

**Parameters**

- `o` `{ [string]: any } | string`

```lua
edui.text{ text = "Entities", weight = "600" }
```

## modules/edui.widgets/toolbar {#widgets-toolbar}

```lua
toolbar(o: { [string]: any }): any
```

A header row — items laid out horizontally with comfortable padding
and a hairline rule beneath, on the panel's own surface (no competing
fill). `o.items` (widget list), `o.style`.

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.toolbar{ items = { edui.text{text="Entities"}, edui.spacer(), addBtn } }
```

## modules/edui.widgets/typeBadge {#widgets-typebadge}

```lua
typeBadge(kind: string?): any?
```

A tiny type badge — a mono uppercase pill that names a field's kind in
its own hue (num/str/bool/enum/rgb/vec3/rot/ref/obj), so a row's type reads
at a glance. `kind` is a field kind (`number`/`string`/`enum`/…).

**Parameters**

- `kind` `string?` _(optional)_

```lua
edui.typeBadge("enum")
```

## modules/edui.widgets/vbox {#widgets-vbox}

```lua
vbox(o: { [string]: any }): any
```

A vertical flex container. `o.style` overrides; `o.children` (or the
positional 1st arg) are the children. Forwards `onClick`, `onDoubleClick`,
`onDrag`, `dragPayload`, `onDrop` and `tooltip`.

**Parameters**

- `o` `{ [string]: any }`

```lua
edui.vbox{ gap = 4, children = { ... } }
```

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

```lua
require("@builtin/modules/api/engine/effects") -- effects (also available as global 'effects')
```

Fire a finished visual effect from gameplay code in one line. `play` puts an effect at a position and `playOn` sticks it to an entity; both return a handle that stops it early, moves it, or re-tunes a parameter while it runs. The effect owns its own lifetime — nothing here needs the caller to tick it — and repeated firing re-uses what the last one left rather than allocating again.

Usage: local effects = require("@builtin/modules/api/engine/effects")
Also available as global: effects

## modules/effects/backends {#modules-effects-backends}

```lua
backends(): { string }
```

The backend kinds an effect can be built out of, in name order. The
runtime ships `emitter`, `geometry`, `material`, `decal` and `feature`.

```lua
print(table.concat(effects.backends(), ", "))
```

## modules/effects/describe {#modules-effects-describe}

```lua
describe(identity: string): { [string]: any }
```

What an effect declares about itself: its family, a one-line summary,
every parameter with its type, default and documented range, and the cost
one unpooled play of it was measured to draw. The one call to make against
an unfamiliar effect before playing it.

**Parameters**

- `identity` `string` — The effect's canonical identity, or a short name.

```lua
local d = effects.describe("explosion"); print(d.family, d.cost.gpuMs)
```

## modules/effects/drain {#modules-effects-drain}

```lua
drain(): { [string]: number }
```

Free every backend the pool is holding idle. The pool keeps what it has
leased for as long as the engine runs — that is what makes repeated firing
cost nothing after the first — and this is the one call that gives it back.
A backend a live play still holds is left to that play's own end.

```lua
print(effects.drain().freed)
```

## modules/effects/families {#modules-effects-families}

```lua
families(): { string }
```

Every family the effects in this world declare, sorted — the values
`list { family = … }` filters on. An effect declaring no family is not one
of them.

```lua
for _, f in ipairs(effects.families()) do print(f, #effects.list({ family = f })) end
```

## modules/effects/list {#modules-effects-list}

```lua
list(opts: table?): { string }
```

The canonical identity of every effect this world can play, sorted.
These are the exact strings `play` takes. Pass `{ family = "combat" }` to
get only the effects of one family — the catalogue filtered the way an
effect declares itself.

**Parameters**

- `opts` `table?` _(optional)_ — `{ family? = string }`. A family is matched without regard to case.

```lua
for _, id in ipairs(effects.list()) do print(id) end
for _, id in ipairs(effects.list({ family = "combat" })) do print(id) end
```

## modules/effects/observe {#modules-effects-observe}

```lua
observe(): { [string]: any }
```

What the runtime is holding and driving right now — every live play with
the reason it is silent when it is, plus what the pool has leased out and
what it is keeping idle, in instances and in GPU bytes. This is how a caller
and a test tell a working effect from a silent one, and how they tell a pool
warming to a wider burst from something leaking: the pool is sized by the
most effects it has had to cover at once, which `peakLive` and `peakLeased`
report beside the current totals.

```lua
local o = effects.observe(); print(o.live, o.leased, o.pooled, o.bytes)
print(o.peakLive, o.peakLeased)   -- the widest burst the pool covers
```

## modules/effects/play {#modules-effects-play}

```lua
play(identity: string, opts: table?): any
```

Play an effect once at a world position. The effect allocates what it
needs from the shared pool, draws itself, and gives everything back when it
ends — with no update loop on the caller's side.

**Parameters**

- `identity` `string` — The effect's canonical identity, or a short name that reaches
exactly one effect.
- `opts` `table?` _(optional)_ — `{ position? = { x, y, z }, rotation? = quat, direction? = { x, y, z },
params? = { … }, duration? = number, held? = boolean }`. Anything `params`
omits takes the effect's declared default, and an effect that declares a
`duration` parameter reads its length from there rather than from `duration`
here.

```lua
local h = effects.play("@builtin::systems.effects.combat.explosion", {
position = { 0, 2, 0 }, params = { scale = 4, coreColor = { 1, 0.4, 0.1 } },
})
```

## modules/effects/playOn {#modules-effects-playon}

```lua
playOn(identity: string, target: any, opts: table?): any
```

Play an effect on an entity: it starts where the entity stands and ends
if the entity leaves the world. Move it with the entity by calling
`handle:retarget(theEntity)` as it goes.

**Parameters**

- `identity` `string` — The effect's canonical identity, or a short name.
- `target` `any` _(optional)_ — An entity proxy or entity id.
- `opts` `table?` _(optional)_ — The same options `play` takes; `position` is read from the entity.

```lua
local h = effects.playOn("explosion", drum, { params = { scale = 3 } })
```

## modules/effects/registerBackend {#modules-effects-registerbackend}

```lua
registerBackend(kind: string, backend: table)
```

Register a new way of drawing under a kind name, so an effect family
that needs one the runtime does not ship adds it rather than widening the
runtime. Every effect reaches it through `ctx.lease(kind, spec)`.

**Parameters**

- `kind` `string` — The kind name a spec asks for.
- `backend` `table` — The backend — `key`, `acquire`, `seat`, `start`, `stop`, `quiet`,
`place`, `bytes`, `active`, `silence` and `free`.

```lua
effects.registerBackend("ribbonTrail", myBackend)
```

## modules/effects/silenceReasons {#modules-effects-silencereasons}

```lua
silenceReasons(): { { reason: string, means: string } }
```

The closed set of reasons a play can be producing nothing, in the order
a reading resolves them — nearest cause first — each with what it means.
Every `reason` an observation reports is one of these.

```lua
for _, r in ipairs(effects.silenceReasons()) do print(r.reason, r.means) end
```

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

```lua
require("@builtin/modules/api/engine/egress") -- egress (also available as global 'egress')
```

Credential-injecting HTTP for BYO-key world egress (Mechanism B). Public Luau surface over the `__egress` Internal FFI namespace.

Usage: local egress = require("@builtin/modules/api/engine/egress")
Also available as global: egress

## modules/egress/clearCredential {#modules-egress-clearcredential}

```lua
clearCredential(name: string): boolean
```

TRUSTED ONLY. Remove a named credential.

**Parameters**

- `name` `string` — Credential name.

```lua
egress.clearCredential("meshy")
```

## modules/egress/credentialNames {#modules-egress-credentialnames}

```lua
credentialNames(): { string }
```

List the names of configured credentials. Names only — secret
values are never exposed to Luau.

```lua
for _, n in ipairs(egress.credentialNames()) do print(n) end
```

## modules/egress/fetch {#modules-egress-fetch}

```lua
fetch(name: string, method: string, url: string,
```

Perform an HTTP request with a named credential injected
server-side (in Rust). Returns a promise handle for
`task.await()`, or nil when the credential is unknown or `url`
is outside the credential's allowed `base_url`. The secret is
never exposed to Luau. This is the seam that production points
at the ZeroMind egress endpoint.

```lua
local h = egress.fetch("meshy", "POST", url, nil, { prompt = p })
```

## modules/egress/hasCredential {#modules-egress-hascredential}

```lua
hasCredential(name: string): boolean
```

Whether a named credential is configured. Returns only a
boolean — never the value. Service handlers use this to fail
with a clear "not configured" message.

**Parameters**

- `name` `string` — Credential name.

```lua
if not egress.hasCredential("meshy") then error("set MESHY_API_KEY") end
```

## modules/egress/setCredential {#modules-egress-setcredential}

```lua
setCredential(name: string, base_url: string,
```

TRUSTED ONLY. Register a named credential whose header is
injected into matching `egress.fetch` calls. The value is held
in Rust and never returned to Luau.

```lua
egress.setCredential("meshy", "https://api.meshy.ai/", "Authorization", "Bearer " .. key)
```

## modules/engine.dirty_hot_reload/README {#dirty-hot-reload-readme}

```lua
require("@builtin/modules/engine/dirty_hot_reload") -- engine.dirty_hot_reload
```

Per-entity hot reload on `<scene>.dirty/entities/`. Subscribes to the layer's dirty entities directory via the generic `vfs.watch(folder, callback)` primitive and reapplies changed bodies to live entities — the consumer side of the collaborative-via-VFS-sync edit model. Local edits write a dirty file; VFS sync replicates the bytes to every peer's local VFS; the subscription fires for both Local and Remote writes; the callback reads the replicated file and applies it to the peer's live entity. No polling. Local writes fire watchers synchronously inside the FFI call. Peer-driven writes are queued in `zero_vfs::write_events` and drained by the engine schedule's `apply_vfs_mutations` system, which fires watchers within the same frame the bytes land. Cost is O(0) when nothing changes. Mark-suppression contract: Body application happens inside `__scene_load.begin()` / `__scene_load.finish()` so the Rust mark sites (`mark_entity_dirty`, `mark_manifest_dirty`) early-return — without the gate, applying a peer's edit would re-mark the entity dirty locally, the saver would re-write the same body to disk, VFS sync would re-broadcast back, and the feedback loop would saturate the relay. The same gate the scene loader uses on full-scene loads. Echo-loop suppression: Local writes round-trip through the watcher too (lua_vfs_write fires synchronously). The `known` per-eid content cache short- circuits re-apply when the file content matches the last-seen string — we just wrote it, no need to re-apply our own write. Lifecycle: `layers.M.fireLoad(proxy)` calls `M.install(proxy)` for every scene (additive or not) that just loaded — the install seeds `known` from current dir contents and registers one `vfs.watch` on `<entitiesDir>` (folder subscription). `M.fireUnload(proxy)` calls `M.uninstall(proxy)` which calls `vfs.unwatch(id)` and drops the per-layer state. Authored content lives in additive overlays too (editor side-panels, side games, custom HUD overlays) — they get the same hot-reload treatment. Scenes that genuinely don't resolve to a dirty subtree (e.g. an engine-internal scaffolding overlay) early-return inside `entitiesDirFor`.

Usage: local engine.dirty_hot_reload = require("@builtin/modules/engine/dirty_hot_reload")

## modules/engine.dirty_hot_reload/canonicalChanged {#dirty-hot-reload-canonicalchanged}

```lua
canonicalChanged(sceneGuid: string): number
```

Take the layer to what its canonical `scene.json` now says, and report
what that reached. The entry point for a write this module's own
subscription does not see: `vfs.watch` fires for a write made inside
the vm and for one replicated from a peer, and NOT for one made through the
host (`write_file` / `edit_file`), which is the route an author reaches for
first. The scene assetType's `onChange` sees that one and calls this.

Guarded by the same content cache the subscription uses, so whichever of
the two arrives first applies the write and the other reads an echo. A
record whose entity already matches costs nothing either way.

**Parameters**

- `sceneGuid` `string` — The layer's guid.

```lua
DirtyHotReload.canonicalChanged(layers.active.guid)
```

## modules/engine.dirty_hot_reload/debugFire {#dirty-hot-reload-debugfire}

```lua
debugFire(guid, path, kind)
```

Diagnostic: synchronously dispatch a synthetic write event for the
given guid + path. Used by tests / debugging — production reads come
from `vfs.watch` callbacks.

**Parameters**

- `guid` `any` _(optional)_
- `path` `any` _(optional)_
- `kind` `any` _(optional)_

## modules/engine.dirty_hot_reload/debugState {#dirty-hot-reload-debugstate}

```lua
debugState(guid)
```

Diagnostic: return a shallow copy of the per-layer state for inspection.
Returns `{ entitiesDir, knownKeys, active, watcherId, eventCount }`.

**Parameters**

- `guid` `any` _(optional)_

## modules/engine.dirty_hot_reload/install {#dirty-hot-reload-install}

```lua
install(sceneProxy)
```

Subscribe to the layer's dirty/entities/ directory via
`vfs.watch` (folder subscription — fires for any descendant
write/remove, both Local and Remote origins). Called automatically
from `layers.M.fireLoad`
for EVERY loaded scene (additive or root) — scenes don't need to
install it manually. Scenes that don't resolve to a dirty subtree
(engine-internal scaffolding overlays, persistent UI layers with
no on-disk authoring path) early-return inside `entitiesDirFor`.

**Parameters**

- `sceneProxy` `any` _(optional)_ — SceneProxy for the just-loaded layer.

## modules/engine.dirty_hot_reload/installed {#dirty-hot-reload-installed}

```lua
installed()
```

Return the set of currently-installed layer guids. Observability
hook for tests / debugging.

## modules/engine.dirty_hot_reload/uninstall {#dirty-hot-reload-uninstall}

```lua
uninstall(sceneProxy)
```

Stop the watcher for the given layer. Called from `layers.M.fireUnload`.
Idempotent — safe to call when no install ran or after a prior uninstall.

**Parameters**

- `sceneProxy` `any` _(optional)_ — SceneProxy for the layer being unloaded.

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

```lua
require("@builtin/modules/api/engine/entity") -- entity (also available as global 'entity')
```

Entity spawn / despawn / query / hierarchy surface. Calling the table itself — `entity(idOrProxy)` — resolves an id or proxy to its live entityRef proxy. Public Luau surface over the `__entity` Internal FFI namespace, composed with the entityRef proxy metatable, the hierarchy swap helper, id/proxy coercion, and the polymorphic batch read/write dispatch.

Usage: local entity = require("@builtin/modules/api/engine/entity")
Also available as global: entity

## modules/entity/batchAddComponent {#modules-entity-batchaddcomponent}

```lua
batchAddComponent(targets: { string | entityRef }, type_name: string, data: table?): number
```

Add the same component type to many entities in one call. Returns the
count of entities the component was added to — an entity already
carrying an unnamed instance of the same type is skipped rather than
double-added.

**Parameters**

- `targets` `{ string | entityRef }` — Array of entity ids or entity proxies (e.g. the return of
`entity.batchSpawn` or `entity.findAll`).
- `type_name` `string` — Component type to add to every entity.
- `data` `table?` _(optional)_ — Init data table, applied identically to every entity — the same
shape the second arg to `entity(id).component.add(type, data)` takes.

```lua
local n = entity.batchAddComponent(ids, "Debris", { lifetime = 5 })
```

## modules/entity/batchDespawn {#modules-entity-batchdespawn}

```lua
batchDespawn(targets: { string | entityRef }): number
```

Despawn many entities in one call. Locked or unresolvable entities
are skipped. Returns the count queued for despawn.

**Parameters**

- `targets` `{ string | entityRef }` — Array of entity ids, entity proxies, or display names (e.g.
the return of `entity.batchSpawn` / `entity.findAll`).

```lua
local n = entity.batchDespawn(ids)
```

## modules/entity/batchProxy {#modules-entity-batchproxy}

```lua
batchProxy(targets: { string | entityRef }): { entityRef? }
```

Resolve an array of entity ids to proxies in one call. Each output
slot is the standard `entity(id)` proxy; ids missing from the frame
cache surface as nil at that index. Use when iterating over a snapshot
of entities so per-id lookups don't dominate the hot path.

**Parameters**

- `targets` `{ string | entityRef }` — Array of entity ids or entity proxies.

```lua
local proxies = entity.batchProxy(ids)
```

## modules/entity/batchRead {#modules-entity-batchread}

```lua
batchRead(target: { string | entityRef } | binding, component: string?, field: string?, sink: buffer?): { any? } | number
```

Read a component-field across many entities in one call.
Polymorphic on the shape of `target` and `sink`:
- `entity.batchRead(ids)` / `(ids, comp)` / `(ids, comp, field)` —
returns one value per entity (a whole snapshot, one component table,
or one field value). Missing entities/components/fields surface as
nil at that slot.
- `entity.batchRead(binding, comp, field, buffer)` — reads each
entity's field directly into a typed CPU substrate buffer
(`substrate.createBuffer({type="vec3"})`, etc.) with no per-entity
Lua table allocation. Returns the count of successful reads.
`target` accepts an entity-id array or a `ecs.bindEntities(ids)`
handle. Buffer sinks require a binding — the typed kernel is
binding-only.

**Parameters**

- `target` `{ string | entityRef } | binding` — Array of entity ids or entity proxies, or a binding handle
from `ecs.bindEntities(ids)`.
- `component` `string?` _(optional)_ — Component type name (e.g. "Transform").
- `field` `string?` _(optional)_ — Field name (e.g. "position").
- `sink` `buffer?` _(optional)_ — Typed CPU buffer from `substrate.createBuffer({...})` to memcpy
field values into. Required when `target` is a binding.

```lua
local snapshot = entity.batchRead(ids)
local positions = entity.batchRead(ids, "Transform", "position")
```

## modules/entity/batchReadToBuffer {#modules-entity-batchreadtobuffer}

```lua
batchReadToBuffer(binding: number, component: string, field: string, buffer: number): number
```

FFI primitive backing `entity.batchRead(binding, ..., buffer)`.
Prefer the unified `entity.batchRead`, which auto-dispatches by
argument shape. Reads each entity's component field directly into a
typed CPU substrate buffer, with no per-entity Lua table allocation.
After the call, read the buffer via `buf:read(0, count*stride)`.

**Parameters**

- `binding` `number` — Binding id from `ecs.bindEntities(ids).id`.
- `component` `string` — Component type name.
- `field` `string` — Field name to read.
- `buffer` `number` — Destination buffer id (must be the matching type).

```lua
entity.batchReadToBuffer(binding.id, "Transform", "position", buf.id)
```

## modules/entity/batchSpawn {#modules-entity-batchspawn}

```lua
batchSpawn(count: number, name_prefix: string?): { string }
```

Spawn `count` entities in one call. Returns an array of the new
entity ids in spawn order. Each entity is given a display name of
`<name_prefix><i>` (or `entity<i>` if the prefix is omitted). Prefer this
over looping `entity.spawn` when creating large entity counts.

**Parameters**

- `count` `number` — How many entities to spawn (capped at 1,000,000).
- `name_prefix` `string?` _(optional)_ — Display-name prefix appended with the 1-based index.
Defaults to "entity".

```lua
local ids = entity.batchSpawn(100, "grass_")
```

## modules/entity/batchWrite {#modules-entity-batchwrite}

```lua
batchWrite(target: { string | entityRef } | binding, component: string, field: string, source: { any? } | buffer): number
```

Write a single component-field across many entities in one call.
Polymorphic on the shape of `target` and `source`:
- `entity.batchWrite(ids, comp, field, values)` — per-call entity-id
resolution; `values` is an array the same length as `ids` (nil slots
are skipped). Use for one-shot writes.
- `entity.batchWrite(binding, comp, field, values)` — binding handle
from `ecs.bindEntities(ids)`; skips per-call id resolution. Use for
per-frame writes against a stable entity set.
- `entity.batchWrite(binding, comp, field, buffer)` — typed CPU buffer
source (`substrate.createBuffer({type="vec3"})`, etc.), with no
per-entity table allocation.
Returns the count of successful writes. Buffer sources require a
binding — the typed kernel is binding-only.

**Parameters**

- `target` `{ string | entityRef } | binding` — Array of entity ids or entity proxies, or a binding handle
from `ecs.bindEntities(ids)`.
- `component` `string` — Component type name.
- `field` `string` — Field name to write.
- `source` `{ any? } | buffer` — Per-entity values array (nil entries are skipped), or a typed
CPU buffer from `substrate.createBuffer({...})`. A buffer source
requires a binding `target`.

```lua
entity.batchWrite(ids, "Transform", "position", positions)
```

## modules/entity/batchWriteBound {#modules-entity-batchwritebound}

```lua
batchWriteBound(binding: number, component: string, field: string, values: { any? }): number
```

FFI primitive backing `entity.batchWrite(binding, ...)` with a
per-entity values table. Prefer the unified `entity.batchWrite`, which
auto-dispatches by argument shape; this entry stays for power users /
debug code that wants to skip dispatch overhead.

**Parameters**

- `binding` `number` — Binding id from `ecs.bindEntities(ids).id`.
- `component` `string` — Component type name.
- `field` `string` — Field name to write.
- `values` `{ any? }` — Per-entity source values (nil = skip). Length must match the
binding's entity count.

```lua
entity.batchWriteBound(binding.id, "Transform", "position", values)
```

## modules/entity/batchWriteFromBuffer {#modules-entity-batchwritefrombuffer}

```lua
batchWriteFromBuffer(binding: number, component: string, field: string, buffer: number): number
```

FFI primitive backing `entity.batchWrite(binding, ..., buffer)`.
Prefer the unified `entity.batchWrite`, which auto-dispatches by
argument shape. Caller fills a typed substrate buffer
(`substrate.createBuffer({type="vec3"})`) once via `buf:write(...)`,
then this memcpys 12 (vec3) or 16 (quat) bytes per entity into the
component field. Buffer count and binding count should match — a
mismatch processes the smaller of the two.

**Parameters**

- `binding` `number` — Binding id from `ecs.bindEntities(ids).id`.
- `component` `string` — Component type name.
- `field` `string` — Field name to write.
- `buffer` `number` — Buffer id from `substrate.createBuffer({type="vec3", len=N}).id`.

```lua
entity.batchWriteFromBuffer(binding.id, "Transform", "position", buf.id)
```

## modules/entity/capture {#modules-entity-capture}

```lua
capture(builder: () -> ()): ({ string }, any?, { string })
```

Run `builder` inside an entity capture scope and return the entity ids
it minted, in creation order, the error it raised (if any), and the ids
among them that a component the builder attached minted in its own
lifecycle. Every id minted while the builder runs is recorded — through
`entity.spawn`, `entity.spawnSynced`, `entity.batchSpawn`, and
`entity.instantiate` alike. Scopes nest: an id minted inside an inner
capture is recorded by that capture AND every enclosing one — the
innermost capture answers, so a nested build shapes its own entities,
not the ones around it. A builder that raises still returns its ids, so
the caller can despawn what a failed build left behind; the scope closes
either way and never outlives this call. While the builder runs, an
operation whose result cannot be composed into a record is refused
rather than applied, and so is any operation aimed at an entity the
builder did not mint — a builder that returned while something it did
was refused comes back with an error naming every refusal.

**Parameters**

- `builder` `() -> ()` — Function run inside the scope; the entities it creates are
what comes back.

```lua
local ids, err, reproduced = entity.capture(function() entity.spawn("chair") end)
```

## modules/entity/despawn {#modules-entity-despawn}

```lua
despawn(target: string | entityRef)
```

Despawn an entity and all its components. Pass an id string or an
entity proxy to despawn that ONE entity. Pass a name to despawn EVERY
entity with that name — names are not unique, so a name argument
despawns all matches, not one arbitrary match. A despawned id becomes
invalid after this call. Raises if no entity matches; for a bulk name
despawn, locked entities are skipped with a logged summary and only
raise if every match is locked.

**Parameters**

- `target` `string | entityRef` — Entity id, name, or entity proxy. A name despawns all entities
sharing that name.

```lua
entity.despawn(id)
entity.despawn("Enemy") -- despawns every entity named "Enemy"
```

## modules/entity/duplicate {#modules-entity-duplicate}

```lua
duplicate(sourceId: string | entityRef, name: string?, opts: table?): string?
```

Duplicate an entity with all its components (transform, script
components, attributes, visuals, material) and its descendants. Returns
the new entity's id, or nil when `sourceId` names no live entity.
Descendants marked temporary are left out of the copy: they are
scaffolding whatever spawned them re-creates, so a component that
regenerates its own children rebuilds them on the copy rather than the
copy carrying a second set. `includeTemporary` copies them too, for the
hierarchy that IS the temporary thing.

**Parameters**

- `sourceId` `string | entityRef` — Entity id or entity proxy of the source entity to clone.
- `name` `string?` _(optional)_ — Display name for the copy (defaults to source name + " (copy)").
- `opts` `table?` _(optional)_ — `{ includeTemporary?: boolean, name?: string }` — `name` is the
same field the `name` argument sets, and wins when both are given.

```lua
local copyId = entity.duplicate(id); if copyId then entity(copyId).position = { 1, 0, 0 } end
local copyId = entity.duplicate(id, "Turret", { includeTemporary = true })
```

## modules/entity/exists {#modules-entity-exists}

```lua
exists(idOrProxy: string | entityRef): boolean
```

Check whether an entity currently exists in the scene. Accepts an
entity-id string or an entity proxy, matched by entity id — so it agrees
exactly with `entity(id)`. A name is a different kind of identifier: a
string that misses as an id but names a live entity raises rather than
answering false, since false there is indistinguishable from absence.
Check by name with `entity.find(name) ~= nil`.

**Parameters**

- `idOrProxy` `string | entityRef` — Entity id or an entity proxy.

```lua
if entity.exists(id) then ... end
```

## modules/entity/find {#modules-entity-find}

```lua
find(nameOrGlob: string): entityRef?
```

Find the first entity matching `nameOrGlob`. A plain string matches
an exact id or Name component; a string containing `*` (any run of
characters) or `?` (any single character) matches Names as a glob, so
`entity.find("enemy_*")` is the first entity whose name starts with
`enemy_`. A glob addresses Names only, never ids. Same-frame pending
spawns are searched too, and anything queued for despawn in the same
frame is skipped. Names are NOT unique — use `entity.findAll` when every
match matters.

**Parameters**

- `nameOrGlob` `string` — Exact entity Name or id, or a `*` / `?` glob over Names.

```lua
local e = entity.find("enemy_*")
```

## modules/entity/findAll {#modules-entity-findall}

```lua
findAll(nameOrGlob: string?): { entityRef }
```

Enumerate entity proxies. With a `nameOrGlob` argument, returns every
entity whose Name component or id matches (names are not unique): a
plain string matches exactly, while a `*` / `?` glob matches Names. With
no argument, returns every entity in the current snapshot —
`findAll("")` is the exact-match filter for the empty name, which
normally matches nothing. Same-frame pending spawns are included and
same-frame despawns filtered out. Elements are entity proxies, not id
strings — for ids, wrap the result: `entity.ids(entity.findAll(...))`.

**Parameters**

- `nameOrGlob` `string?` _(optional)_ — Exact entity Name or id to filter by, or a `*` / `?` glob
over Names. Omit to enumerate every entity.

```lua
for _, e in entity.findAll("enemy_*") do e:despawn() end
```

## modules/entity/getChildren {#modules-entity-getchildren}

```lua
getChildren(id: string | entityRef): { entityRef }
```

Get an array of the direct children as entity proxies. Each element
carries `.name`, `.id`, `.position`, `.component`, and the rest of the
per-entity surface — the same shape `entity.findAll` returns.

**Parameters**

- `id` `string | entityRef` — Entity id or entity proxy.

```lua
for _, c in entity.getChildren(id) do c.internal = true end
```

## modules/entity/getDescendants {#modules-entity-getdescendants}

```lua
getDescendants(id: string | entityRef): { entityRef }
```

Get every descendant (children, grandchildren, and deeper) of the
given entity as entity proxies in breadth-first order, excluding the
entity itself. Resolves the whole subtree in one linear pass over the
entity set, so a large subtree costs proportionally to the entity count
rather than to the subtree size times the entity count.

**Parameters**

- `id` `string | entityRef` — Entity id or entity proxy.

```lua
local all = entity.getDescendants(id)
```

## modules/entity/getParent {#modules-entity-getparent}

```lua
getParent(id: string | entityRef): entityRef?
```

Get the parent entity proxy, or nil if the entity is a root entity.
The returned proxy carries `.name`, `.id`, `.position`, `.component`,
and the rest of the per-entity surface — the same shape `entity.find`
returns.

**Parameters**

- `id` `string | entityRef` — Entity id or entity proxy.

```lua
local p = entity.getParent(id)
```

## modules/entity/instantiate {#modules-entity-instantiate}

```lua
instantiate(handle: number, count: number, fn: ((number) -> EntityInstantiateOverrides?)?): { string }
```

Spawn `count` instances of a template registered with
`entity.template`. Each instance gets a fresh entity id; the optional
`fn(i)` callback runs per instance (`i` in 1..=count) and may return an
overrides table. Override keys: `name`, `position`, `rotation`, `scale`,
`parent`, `temporary` / `active` / `internal`, `attributes`, `components`
(script components, merged over the template body's data for that type
— a type the template lacks is added fresh), and `ecs` (native
components, merged the same way). Each override supersedes the
template's shared config for that instance. The whole batch crosses in
one call and lands as a single deferred mutation the engine expands
into bulk work — per-instance cost drops from a full round trip to one
callback plus one mutation. Inside `queue()` the batch is deferred onto
the cross-frame ring; outside, it lands in the next frame's drain.
Returns the array of newly-minted entity ids in spawn order.

**Parameters**

- `handle` `number` — Template handle from `entity.template`.
- `count` `number` — Number of instances to spawn (capped at 1,000,000).
- `fn` `((number) -> EntityInstantiateOverrides?)?` _(optional)_ — Per-instance override callback `(i) -> table?`.

```lua
local ids = entity.instantiate(h, 50, function(i) return { position = { i, 0, 0 } } end)
```

## modules/entity/spawn {#modules-entity-spawn}

```lua
spawn(nameOrOpts: (string | SpawnOpts)?, opts: SpawnOpts?): entityRef
```

Spawn a new entity and return its PROXY (the same value entity(id)
yields) — act on it immediately (`entity.spawn(name).component.add(...)`,
`.localPosition = ...`) with no second `entity(id)` round trip. The proxy
still exposes `.id` for the rare site that needs the raw string. An
entity with no components carries only a Transform and is invisible;
pass `components` to give it the components that make it visible in the
same call — `entity.spawn { name = "crate", components = { Model = {
model = "cube" } } }` — or add them afterwards through the returned
proxy. Mirrors `entity.find` / `entity.findAll`, which also return
proxies. The options table can be passed on its own with the name inside
it — `entity.spawn { name = "turret", position = { 1, 2, 3 } }` is the
same call as `entity.spawn("turret", { position = { 1, 2, 3 } })`.

**Parameters**

- `nameOrOpts` `(string | SpawnOpts)?` _(optional)_ — Display name for the entity, or the options table itself.
- `opts` `SpawnOpts?` _(optional)_ — Options: `components` = component types to attach to the new
entity, keyed by type name with each value the component's init table
(attached in sorted type order; a failing add raises), `internal` = take
the entity out of the default entity listings (it still renders —
`entity(id):hide()` stops the draw), `parent` = parent entity id or
proxy, `temporary` = skip this entity (and descendants) from
scene/world saves, `position` / `rotation` / `scale` = place the
entity's Transform at spawn, `id` = restore a previously-assigned entity
id (scene_loader use; leave unset for a normal spawn). An unrecognised
key is rejected loudly.

```lua
local e = entity.spawn("crate", { components = { Model = { model = "cube" } } })
local e = entity.spawn { name = "turret", position = { 1, 2, 3 } }
```

## modules/entity/spawnSynced {#modules-entity-spawnsynced}

```lua
spawnSynced(nameOrOpts: (string | SpawnOpts)?, opts: SpawnOpts?): entityRef
```

Spawn an entity already flagged multiplayer-synced at the root — the
explicit form of `entity.spawn` for SHARED, host-authoritative content.
The entity's existence broadcasts to every peer; joiners receive it from
the relay snapshot instead of spawning their own copy. Use this (NOT
`entity.spawn`) for anything that must be the SAME object on all
clients: enemies, pickups, projectiles, dynamic world props. Call it
ONLY where exactly one client runs the code — a scene's `onHostLoad`
(host-only) phase, or behind `multiplayer.isHost()`. Calling it in
all-client code makes every client spawn+sync its own copy — the
double-spawn "explosion". Equivalent to
`entity.spawn(name, { synced = true })`; identical in every other
respect.

**Parameters**

- `nameOrOpts` `(string | SpawnOpts)?` _(optional)_ — Display name for the entity, or the options table itself.
- `opts` `SpawnOpts?` _(optional)_ — Same options as `entity.spawn` (`synced` is already implied).

```lua
if multiplayer.isHost() then entity.spawnSynced("Goblin") end
```

## modules/entity/template {#modules-entity-template}

```lua
template(def: EntityTemplateDef): number
```

Construct a reusable spawn template. Captures a shared entity config
ONCE and returns a stable handle for `entity.instantiate(handle, count,
fn?)` — one call per batch instead of one per entity. `def` keys:
`components` (script components, `{ [type] = init-data }`), `ecs`
(array of native `ecs.X{...}` components), `temporary` (instances skip
scene/world saves), `active` (spawn state), `internal` (instances are
taken out of the default entity listings; they still render),
`attributes` (`{ key = value }` applied to every instance). Every value
is a shared default; a per-instance `entity.instantiate` override
supersedes it. The template body is captured by value — later edits to
the source table do not affect templates already created.

**Parameters**

- `def` `EntityTemplateDef` — Template definition: `components` / `ecs` / `temporary` /
`active` / `internal` / `attributes`. Per-instance `name` / `position` /
`rotation` / `scale` / `parent` and any override go through the
`instantiate` callback.

```lua
local h = entity.template({ components = { Model = { model = "cube" } } })
```

## modules/entity/tree {#modules-entity-tree}

```lua
tree(opts: { [string]: any }?): { [string]: any }
```

A windowed, lean view over the scene's entity tree, in one crossing.
Rows carry id, name, parentId, depth, childCount, active, sceneLayer and
componentNames — names only, never component values — so the call costs
the rows it answers with rather than the size of the scene. Entities group
under scene layers, per-layer roots and children name-sorted; internal
entities and their subtrees stay out. `expanded` names the ids whose
children unfold, and a collapsed node still reports its `childCount`;
`filter` keeps the rows whose name or id contains the needle plus every
ancestor on a path to one, auto-unfolded, with the actual matches flagged
`matched`. `offset` / `limit` window the flattened rows, `layer` scopes the
window and its `total` to one layer while `layers` still reports every
layer's row count, and `revision` echoes
`getEntitiesRevision("structure")`, which moves only on structural change.

**Parameters**

- `opts` `{ [string]: any }?` _(optional)_ — `{ layer?, expanded?, filter?, offset?, limit? }`.

```lua
local view = entity.tree({ filter = "crate", limit = 50 })
```

## modules/entityMembers/README {#modules-entitymembers-readme}

```lua
entityMembers
```

The declarative description of every entityRef member. The runtime dispatch, the accepted-member set, the miss diagnostics and the LSP tree all derive from this table, so they cannot disagree.

## modules/enum_values/README {#modules-enum-values-readme}

```lua
enum_values
```

The `enum` field-constraint validator: a constrained value must be one of the strings the field declared. A rejection names every member, so the error carries the whole set the caller may choose from. Registers itself with the generic field_constraints registry on load. `nil` passes, so an enum field may be left unset.

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

```lua
require("@builtin/modules/api/engine/environment") -- environment (also available as global 'environment')
```

Environment / reflection capture — bake the scene into reflection-probe cube slots from world positions, persist them as `faces6` `.texture` assets, and set per-probe blend data so surfaces reflect the nearest probe(s). Public Luau surface over the `__environment` Internal FFI namespace. The generic "render the scene into a cubemap from a point" capability the reflection probe system is built on.

Usage: local environment = require("@builtin/modules/api/engine/environment")
Also available as global: environment

## modules/environment/capture {#modules-environment-capture}

```lua
capture(x: number, y: number, z: number): boolean
```

Bake the scene into the environment from `(x, y, z)` as the single global
reflection (slot 0 + one full-coverage probe). Every PBR surface reflects it.
Queued — takes effect on the next frame. For multiple proximity-blended
probes use the reflectionProbe system instead.

**Parameters**

- `x` `number` — World X of the capture position.
- `y` `number` — World Y of the capture position.
- `z` `number` — World Z of the capture position.

```lua
environment.capture(0, 2, 0)
```

## modules/environment/captureSky {#modules-environment-capturesky}

```lua
captureSky(x: number?, y: number?, z: number?): boolean
```

Render the SKY alone into the environment's sky slot from `(x, y, z)` and
arm the sky fallback. A reflective surface no probe covers then reflects the
sky rather than black, and a partially covered one blends the shortfall
against it. The capture holds whatever the scene's sky draws — a gradient, a
physical atmosphere, a skybox material — with no geometry in it, so it stays
correct wherever the camera goes. Once captured, the slot follows the sky
the scene draws: a sky that changes is recaptured from the same position.
Queued — takes effect on the next frame.

**Parameters**

- `x` `number?` _(optional)_ — World X of the capture position. Defaults to 0.
- `y` `number?` _(optional)_ — World Y of the capture position — the altitude a height-dependent
atmosphere is sampled at. Defaults to 0.
- `z` `number?` _(optional)_ — World Z of the capture position. Defaults to 0.

```lua
environment.captureSky()
```

## modules/environment/captureSlot {#modules-environment-captureslot}

```lua
captureSlot(slot: number, x: number, y: number, z: number): boolean
```

Bake the scene into reflection-probe `slot` from `(x, y, z)`.
Renders the FULL scene (geometry + sky) six times from that
point into that slot. Register the probe's position+radius via `setProbes`
so surfaces blend it by proximity. Queued — takes effect next frame.

**Parameters**

- `slot` `number` — Reflection-probe slot (0-based).
- `x` `number` — World X of the capture position.
- `y` `number` — World Y of the capture position.
- `z` `number` — World Z of the capture position.

```lua
environment.captureSlot(0, 0, 2, 0)
```

## modules/environment/captureSlotToAsset {#modules-environment-captureslottoasset}

```lua
captureSlotToAsset(name: string, slot: number, x: number, y: number, z: number, timeoutFrames: number?): (string?, string?)
```

Bake the scene into reflection-probe `slot` from `(x, y, z)` AND persist
the 6 rendered faces into a `faces6` `.texture` cubemap asset at
`/source/<name>.texture/` (px/nx/py/ny/pz/nz PNGs + a `cube.yaml` sidecar).
Survives an engine restart and syncs like any other texture. Yields a few
frames while the bake + GPU readback complete; must be called from a
task/coroutine context (component hook, `task.spawn`, or `execute`). NATIVE
only — the wasm async-readback path is a tracked follow-up.

**Parameters**

- `name` `string` — Destination asset identity (writes `/source/<name>.texture/`).
- `slot` `number` — Reflection-probe slot (0-based).
- `x` `number` — World X of the capture position.
- `y` `number` — World Y of the capture position.
- `z` `number` — World Z of the capture position.
- `timeoutFrames` `number?` _(optional)_ — Optional max frames to wait for the readback (default 180).

```lua
environment.captureSlotToAsset("probe_lobby", 0, 0, 2, 0)
```

## modules/environment/captureToAsset {#modules-environment-capturetoasset}

```lua
captureToAsset(name: string, x: number, y: number, z: number): (string?, string?)
```

Bake the single global reflection AND persist it to a `faces6` `.texture`
asset (slot 0). Yields a few frames; call from a task/coroutine context.

**Parameters**

- `name` `string` — Destination asset identity (writes `/source/<name>.texture/`).
- `x` `number` — World X of the capture position.
- `y` `number` — World Y of the capture position.
- `z` `number` — World Z of the capture position.

```lua
environment.captureToAsset("env_main", 0, 2, 0)
```

## modules/environment/ensureSkyFallback {#modules-environment-ensureskyfallback}

```lua
ensureSkyFallback(): boolean
```

Ensure the scene's sky is in the environment's sky slot: a reflective
surface no probe covers then reflects the sky rather than black, and a
partially covered one blends the shortfall against it. Queues a capture
when the sky slot holds none, and re-arms the fallback when a capture is
there but switched off. The engine's own state answers both questions, so
everything that stands a sky up can call this and one capture is shared
between them. Once captured, the slot follows the sky the scene draws on
its own.

```lua
environment.ensureSkyFallback()
```

## modules/environment/loadFromAsset {#modules-environment-loadfromasset}

```lua
loadFromAsset(name: string): (boolean, string?)
```

Load a persisted global reflection asset into slot 0 and make it the
active single reflection (one full-coverage probe).

**Parameters**

- `name` `string` — Source asset identity (reads `/source/<name>.texture/`).

```lua
environment.loadFromAsset("env_main")
```

## modules/environment/loadSlotFromAsset {#modules-environment-loadslotfromasset}

```lua
loadSlotFromAsset(name: string, slot: number): (boolean, string?)
```

Load a persisted `faces6` `.texture` cubemap (written by
`captureSlotToAsset`) into reflection-probe `slot` WITHOUT re-rendering the
scene. Reads the 6 face PNGs from `/source/<name>.texture/` and uploads them
into the slot's cube layers. How a persisted probe restores its baked
environment on reload.

**Parameters**

- `name` `string` — Source asset identity (reads `/source/<name>.texture/`).
- `slot` `number` — Reflection-probe slot (0-based).

```lua
environment.loadSlotFromAsset("probe_lobby", 0)
```

## modules/environment/setProbes {#modules-environment-setprobes}

```lua
setProbes(probes: { any }): boolean
```

Set the active reflection probes' blend data. `probes` is an array of
`{ x, y, z, radius }` (or `{ position = {x,y,z}, radius = r }`); index i is
probe slot i. Surfaces blend the probe slots by proximity to these
positions, gathering the highest `priority` first — each rank takes the
coverage the ranks above it left, so a small interior probe ranked above a
large exterior one wins outright wherever it reaches full weight. Coverage
left over reflects the sky once `captureSky` has run. Queued for next frame.

**Parameters**

- `probes` `{ any }` — Array of `{ x, y, z, radius, priority? }`, one per active probe
slot. `priority` defaults to 0.

```lua
environment.setProbes({ { x = 0, y = 2, z = 0, radius = 12 } })
```

## modules/environment/setSkyFallback {#modules-environment-setskyfallback}

```lua
setSkyFallback(active: boolean): boolean
```

Arm or disarm the sky fallback against the sky already captured, with no
recapture. Disarmed, reflections come from the probes alone. Arming is
refused while the sky slot holds no capture (`captureSky` fills it), since
an uncaptured slot reflects black; `renderer.reflectionEnvironment()`
reports whether the fallback ended up armed.

**Parameters**

- `active` `boolean` — Whether reflections fall back to the captured sky.

```lua
environment.setSkyFallback(false)
```

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

```lua
require("@builtin/systems/exposure/exposure") -- exposure
```

Exposure in stops, and eye adaptation — the image settles when the scene gets brighter or darker instead of clipping or going black.

Usage: local exposure = require("@builtin/systems/exposure/exposure")

## modules/exposure/active {#modules-exposure-active}

```lua
active(): boolean
```

Whether the exposure passes are currently running.

```lua
if exposure.active() then print("metering") end
```

## modules/exposure/buffers {#modules-exposure-buffers}

```lua
buffers(): { [string]: any }?
```

The buffers the exposure passes read: `params` carries the settings this
module packs, `state` is the adaptation value the GPU owns between frames.
The render feature binds what this hands it.

```lua
local b = exposure.buffers()
```

## modules/exposure/clear {#modules-exposure-clear}

```lua
clear()
```

Turn exposure off and release the passes. The other settings are kept,
so a later `set` brings back the same behaviour.

```lua
exposure.clear()
```

## modules/exposure/get {#modules-exposure-get}

```lua
get(): ExposureState
```

The exposure settings currently in force.

```lua
local ev = exposure.get().compensation
```

## modules/exposure/set {#modules-exposure-set}

```lua
set(opts: ExposureOpts?): ExposureState
```

Set the scene's exposure. Any omitted field keeps its current value, so
a call can adjust one knob without restating the rest. With `auto` off and
`compensation` at 0 nothing is being asked for and the passes are released.
Each setting names the interval it means something in, and a value outside
that interval is refused naming the field, the value and the interval —
the whole call, so the scene stays on the exposure it already had. The
settings this returns are therefore the settings the frame is rendered
with.

**Parameters**

- `opts` `ExposureOpts?` _(optional)_ — Exposure settings — see `ExposureOpts`.

```lua
exposure.set({ auto = true, targetGrey = 0.18, meter = "centre" })
```

## modules/exposure/tick {#modules-exposure-tick}

```lua
tick(dt: number)
```

Advance adaptation by `dt` seconds. Adaptation is a rate, so the passes
need the frame's own delta to move at the same speed whatever the frame
rate. The `AutoExposure` component calls this; code driving the module
directly calls it once a frame.

**Parameters**

- `dt` `number` — Seconds since the last frame.

```lua
exposure.tick(dt)
```

## modules/field_constraints/README {#modules-field-constraints-readme}

```lua
field_constraints
```

Generic field-constraint dispatch. A Field descriptor may carry an opaque `constraint` table with a `kind`; the engine calls `_G.__zero_check_field_constraint(value, constraint)` on every write to (and default of) a constrained field. This module owns that hook and the validator registry — the engine core carries the constraint verbatim and never interprets it.

## modules/field_constraints/register {#modules-field-constraints-register}

```lua
register(kind: string, fn: (value: any, constraint: any) -> (boolean, string?))
```

Register the validator for a constraint kind. One validator per
kind; re-registering a kind is an error (one path).

**Parameters**

- `kind` `string` — The constraint kind string (matches `constraint.kind`).
- `fn` `(value: any, constraint: any) -> (boolean, string?)` — `(value, constraint) -> ok, reason?`.

```lua
FieldConstraints.register("dataContract", checkDataContract)
```

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

```lua
require("@builtin/systems/fluidSim/fluid") -- fluid
```

Grid-based GPU fluid simulation — smoke, fire and gas that curls, rolls and is deflected by forces, rather than translating rigidly the way billboard particles do.

Usage: local fluid = require("@builtin/systems/fluidSim/fluid")

## modules/fluid/addForce {#modules-fluid-addforce}

```lua
addForce(self: any, opts: ForceOpts)
```

Place a directional force. Same one-step lifetime as a source, so a
sustained wind is re-applied each frame.

**Parameters**

- `self` `any` _(optional)_
- `opts` `ForceOpts` — Force placement and direction — see `ForceOpts`.

```lua
sim:addForce({ position = { 2, 1, 0 }, direction = { -1, 0, 0 }, strength = 5 })
```

## modules/fluid/addSource {#modules-fluid-addsource}

```lua
addSource(self: any, opts: SourceOpts)
```

Place a density/heat source. It emits for one step, so a continuous
plume calls this each frame — which is also what lets emission follow a
moving object without any separate binding.

**Parameters**

- `self` `any` _(optional)_
- `opts` `SourceOpts` — Source placement and emission — see `SourceOpts`.

```lua
sim:addSource({ position = { 0, 1, 0 }, density = 1.0, temperature = 400 })
```

## modules/fluid/create {#modules-fluid-create}

```lua
create(opts: FluidOpts?): any
```

Create a fluid simulation over a world-space box.

**Parameters**

- `opts` `FluidOpts?` _(optional)_ — Grid and solver settings — see `FluidOpts`.

```lua
local sim = fluid.create({ resolution = { 64, 64, 64 } })
```

## modules/fluid/destroy {#modules-fluid-destroy}

```lua
destroy(self: any)
```

Release every GPU resource the simulation owns. The handle is unusable
afterwards.

**Parameters**

- `self` `any` _(optional)_

```lua
sim:destroy()
```

## modules/fluid/step {#modules-fluid-step}

```lua
step(self: any, dt: number)
```

Advance the simulation one step. Emitters added since the last step are
consumed here, so they act exactly once.

**Parameters**

- `self` `any` _(optional)_
- `dt` `number` — Step length in seconds.

```lua
sim:step(1 / 60)
```

## modules/fluid/velocityTexture {#modules-fluid-velocitytexture}

```lua
velocityTexture(self: any): string
```

The 3D texture currently holding the velocity field. Velocity changes
texture each step, so read this when you need it rather than caching it.

**Parameters**

- `self` `any` _(optional)_

```lua
local vel = sim:velocityTexture()
```

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

```lua
require("@builtin/systems/atmosphere/fog") -- fog
```

Scene-wide exponential height fog with directional in-scattering. Density falls off with altitude, so valleys pool fog while hilltops clear, and the medium brightens toward the sun so looking into it is not the same as looking away from it.

Usage: local fog = require("@builtin/systems/atmosphere/fog")

## modules/fog/active {#modules-fog-active}

```lua
active(): boolean
```

Whether the fog pass is running this frame.

```lua
if fog.active() then ... end
```

## modules/fog/clear {#modules-fog-clear}

```lua
clear()
```

Turn fog off and release the pass. The other settings are kept, so a
later `set({ density = ... })` brings back the same look.

```lua
fog.clear()
```

## modules/fog/get {#modules-fog-get}

```lua
get(): FogState
```

The fog settings currently in force.

```lua
local d = fog.get().density
```

## modules/fog/paramsBuffer {#modules-fog-paramsbuffer}

```lua
paramsBuffer(): any?
```

The buffer this system's passes read. The render feature binds what
this hands it, so the pass has the values this module packed.

```lua
local p = fog.paramsBuffer()
```

## modules/fog/set {#modules-fog-set}

```lua
set(opts: FogOpts?): FogState
```

Set the scene's fog. Any omitted field keeps its current value, so a
call can adjust one knob without restating the rest. A `density` of 0
turns fog off and releases the pass.

**Parameters**

- `opts` `FogOpts?` _(optional)_ — Fog settings — see `FogOpts`.

```lua
fog.set({ density = 0.03, heightFalloff = 0.12, heightRef = 0, inscatter = 0.85 })
```

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

```lua
require("@builtin/modules/api/engine/font") -- font (also available as global 'font')
```

Font primitive — parse a font file ONCE into a baked, vectorized glyph format (`ZFNT`), then drive every text surface from it. A font is a general CPU resource addressed by name (the CPU counterpart of a renderer GPU resource), so a single registration is usable from UI text, 2D text, and true 3D glyph geometry. Public Luau surface over the `__font` Internal FFI namespace. Authored fonts are `.font` assets whose `onRegister` hook calls `font.register`.

Usage: local font = require("@builtin/modules/api/engine/font")
Also available as global: font

## modules/font/glyph {#modules-font-glyph}

```lua
glyph(name: string, codepoint: number): any
```

Read one glyph's vectorized outline from a registered font, in font
units (resolution-independent — scale by `fontSize / unitsPerEm`).

**Parameters**

- `name` `string` — Registered family name.
- `codepoint` `number` — Unicode codepoint (e.g. `string.byte("A")`).

```lua
local g = font.glyph("Inter", string.byte("A"))
```

## modules/font/list {#modules-font-list}

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

List every registered font family name.

```lua
for _, fam in font.list() do print(fam) end
```

## modules/font/observe {#modules-font-observe}

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

What the text system is holding for fonts: one row per family the
shaper can resolve, with its face count, the numeric weights those faces
carry, whether any of them is slanted, and whether the family arrived
through a registration rather than from the platform. `weights` is what a
style's `weight` can name for that family. The same rows are `fonts` in
`text.observe()`.

```lua
for _, f in ipairs(font.observe()) do print(f.family, #f.weights) end
```

## modules/font/parse {#modules-font-parse}

```lua
parse(bytes: buffer | string): string?
```

Parse a font file (TTF / OTF raw bytes) ONCE into the baked, vectorized
glyph format (`ZFNT`): per-glyph vector outlines + metrics + character map,
plus the original bytes. Heavy — run at import time (the `.font` assetType's
onCreate / the font importer), then store the result as the asset payload.
`font.register` loads it cheaply.

**Parameters**

- `bytes` `buffer | string` — Raw font-file bytes (binary-safe) — TTF / OTF.

```lua
local zfnt = font.parse(vfs.read("/zero/source/Inter.ttf"))
```

## modules/font/reconcile {#modules-font-reconcile}

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

Every family the text shaper can resolve, held against what the shaper
does with it. `family` is the name, `faces` how many faces of it the font
database holds, `weights` the numeric weights those faces carry, `loaded`
whether it arrived through a registration rather than from the platform,
`registered` whether content registered the name, `selectable` whether some
style naming the family reaches it, `matched` whether `fontFamily = family`
on its own reaches it — the family name at the default weight over Latin
text — `weight` the weight it needs when the default is not it, `shapedWith`
the face that answered, and `reason` why when it is not the one asked for. A
family is probed at its own weights and over content from several scripts,
so a family reachable only at one weight or covering only one script is
reported selectable, with `matched` false and `weight` naming what the style
must carry. Every probe object is destroyed again, so the live text-object
count is where it was.

```lua
for _, f in ipairs(font.reconcile()) do if f.selectable and not f.matched then print(f.family, f.weight) end end
```

## modules/font/register {#modules-font-register}

```lua
register(name: string, zfnt: string, opts: table?): any
```

Register a baked font (`ZFNT` from `font.parse`) under `name`, making it
usable on every text surface via `fontFamily = "<name>"`. Loads the
vectorized glyph data into the runtime store (for `font.glyph` /
`font.textMesh`) and feeds the embedded face to the 2D text and egui UI
systems. Passing raw font bytes still works but logs a slow-path warning —
bake with `font.parse` at import. Re-registering the same name replaces it.
`opts` groups several weight/style faces under one CSS family and maps
web-font names onto it: `opts.family` is the shared group key, `opts.role`
is `"regular" | "bold" | "italic" | "bolditalic"`, and `opts.aliases` is a
list of extra selectable names (web fonts + CSS generics like `"Arial"`,
`"sans-serif"`) that resolve to this group, matched case-insensitively.
With a group set, `font-weight` / `font-style` on a `font-family` pick the
real metric-compatible face instead of a synthesized one.

**Parameters**

- `name` `string` — Family name to register under.
- `zfnt` `string` — Baked `ZFNT` payload from `font.parse` (binary-safe string).
- `opts` `table?` _(optional)_ — `{ family: string?, role: string?, aliases: {string}? }` — group key,
weight/style role, and case-insensitive selectable aliases.

```lua
local info = font.register("Inter", font.parse(vfs.read("/zero/source/Inter.ttf")))
```

## modules/font/textMesh {#modules-font-textmesh}

```lua
textMesh(name: string, text: string, opts: table?): any
```

Tessellate a string into renderable mesh geometry from a registered
font's glyph outlines — true 3D text, laid out left-to-right by advance
(newlines drop a line). Hand the result to `renderer.mesh.create()` (GPU)
or `asset.create("mesh")` (persistable).

**Parameters**

- `name` `string` — Registered family name.
- `text` `string` — String to lay out.
- `opts` `table?` _(optional)_ — `{ size?=1, depth?=0 (extrude, EM units), tolerance?=0.0015, letterSpacing?=0, lineHeight?=0 }`.

```lua
local geom = font.textMesh("Inter", "Hello", { size = 1, depth = 0.1 })
```

## modules/frameStream/README {#modules-framestream-readme}

```lua
require("@builtin/modules/api/engine/frameStream") -- frameStream (also available as global 'frameStream')
```

Carries an image the GPU drew out to another program — the view a camera renders, read back off its render target and written into a byte stream frame after frame, so pixels that sit in GPU memory reach a process outside the engine while the world runs. Public Luau surface over the `__framestream` Internal FFI namespace.

Usage: local frameStream = require("@builtin/modules/api/engine/frameStream")
Also available as global: frameStream

## modules/frameStream/attach {#modules-framestream-attach}

```lua
attach(texture: string, stream: string, opts: AttachOpts?): (string?, string?)
```

Carry an image the GPU drew out to an open byte stream, frame
after frame. `texture` is the guid of the render target it was
drawn into — `renderer.texture.create({ width = W, height = H })`
makes one, and a Camera component draws into it as its
`textureHandle`; the session reads that target back when a frame
comes due, so what the camera drew last reaches the far end.
`stream` is a handle from `stream.open`. What reaches the stream
is one frame's pixels then the next frame's, with nothing between
them: a frame is `width * height * bytesPerPixel` bytes of tight
rows, written in a single call so a consumer reads a whole frame
or none of it. Each frame is read back off the render thread, so
the stream never holds the renderer up. `fps` caps how often a
frame is taken and defaults to one per rendered frame; `format`
accepts `"rgb24"` (3 bytes per pixel, the default) or `"rgba8"`
(4) — a call with a format outside those two raises, naming both;
`flipY` writes the last texture row first. Returns the session
handle, or nil and the reason an empty texture, a handle naming no
open stream, a stream another session already carries, or a
non-positive fps was refused with.

**Parameters**

- `texture` `string` — Guid of the render target the image was drawn into (a Camera's textureHandle).
- `stream` `string` — Stream handle from stream.open.
- `opts` `AttachOpts?` _(optional)_ — Rate, pixel layout and row order (optional).

```lua
local session = frameStream.attach(rt.guid, handle, { fps = 30 })
```

## modules/frameStream/detach {#modules-framestream-detach}

```lua
detach(handle: string): boolean
```

End the session and free the staging buffers it read frames
back through. The stream stays open — whoever opened it closes it.

**Parameters**

- `handle` `string` — Session handle from frameStream.attach.

```lua
frameStream.detach(session)
```

## modules/frameStream/list {#modules-framestream-list}

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

Every live session handle, in a stable order.

```lua
for _, h in frameStream.list() do frameStream.detach(h) end
```

## modules/frameStream/status {#modules-framestream-status}

```lua
status(handle: string): FrameStreamStatus?
```

Report what the session has carried and lost. `frames` counts
the frames the stream accepted and `bytes` the bytes they
carried. `dropped` counts the frames it refused, of which
`droppedBackpressure` is the part refused because the consumer was
behind; `stalledReadbacks` counts the frames that came due while
every staging buffer still held a copy on its way from the GPU.
`achievedFps` is the rate the accepted frames arrived at, across
the span from the first to the most recent, and reads 0 until two
have been accepted — compare it against `requestedFps` to see a
display running slower than it was asked to. `lastOutcome` names
what became of the most recent frame offered. nil when handle
names no live session.

**Parameters**

- `handle` `string` — Session handle from frameStream.attach.

```lua
local s = frameStream.status(session); print(s.frames, s.dropped, s.achievedFps)
```

## modules/gaussianSplats/README {#modules-gaussiansplats-readme}

```lua
require("@builtin/systems/gaussianSplats") -- gaussianSplats
```

Registry of live Gaussian splat clouds — the entity-id-keyed table the `gaussianSplats` render feature reads each frame. `GaussianSplat.component` writes the declaration into it; the feature owns every GPU buffer and reports back one thing, its verdict on whether it could build the cloud.

Usage: local gaussianSplats = require("@builtin/systems/gaussianSplats")

## modules/gaussianSplats/clear {#modules-gaussiansplats-clear}

```lua
clear(id: string)
```

Drop an entity's cloud, along with the placement recorded for it. The
render feature frees its GPU buffers on the next frame that finds the entry
gone.

**Parameters**

- `id` `string` — Entity id.

```lua
gaussianSplats.clear(id)
```

## modules/gaussianSplats/clearFailure {#modules-gaussiansplats-clearfailure}

```lua
clearFailure(id: string)
```

Drop the failure standing against an entity's cloud. The feature calls
this on the frame it builds the cloud.

**Parameters**

- `id` `string` — Entity id.

```lua
gaussianSplats.clearFailure(id)
```

## modules/gaussianSplats/entries {#modules-gaussiansplats-entries}

```lua
entries(): { [string]: SplatEntry }
```

The live registry, keyed by entity id. Read-only for callers other than
`GaussianSplat.component`.

```lua
for id, entry in pairs(gaussianSplats.entries()) do ... end
```

## modules/gaussianSplats/failure {#modules-gaussiansplats-failure}

```lua
failure(id: string): string?
```

Why the feature could not build an entity's cloud, or nil while it has
nothing against it.

**Parameters**

- `id` `string` — Entity id.

```lua
local why = gaussianSplats.failure(id)
```

## modules/gaussianSplats/get {#modules-gaussiansplats-get}

```lua
get(id: string): SplatEntry?
```

The entry registered for one entity, or nil.

**Parameters**

- `id` `string` — Entity id.

```lua
local e = gaussianSplats.get(id)
```

## modules/gaussianSplats/placement {#modules-gaussiansplats-placement}

```lua
placement(id: string): { number }?
```

The placement an entity's cloud was last culled and drawn at — 16
column-major numbers, translation in elements 13, 14, 15. The cull
transforms every splat position by this matrix and the draw conjugates each
covariance by its upper-left 3x3, so it is where the cloud was cut as well
as where it was drawn. A fresh table each call, so writing to it leaves the
record alone. Nil before the feature has drawn the cloud, on any frame it
does not draw it, and once the cloud has left the registry.

**Parameters**

- `id` `string` — Entity id.

```lua
local m = gaussianSplats.placement(id)
```

## modules/gaussianSplats/recordPlacement {#modules-gaussiansplats-recordplacement}

```lua
recordPlacement(id: string, matrix: { number }?)
```

Record the placement an entity's splats were culled and drawn at, as 16
column-major numbers. The render feature calls this each frame it draws the
cloud, with the matrix it hands the cull pass; nil drops the record. The
numbers are copied in, so the caller keeps its own matrix to itself.

**Parameters**

- `id` `string` — Entity id.
- `matrix` `{ number }?` _(optional)_ — The 16 column-major numbers the cloud was placed by.

```lua
gaussianSplats.recordPlacement(id, entity(id).worldMatrix())
```

## modules/gaussianSplats/reportFailure {#modules-gaussiansplats-reportfailure}

```lua
reportFailure(id: string, message: string)
```

Report that the feature could not build an entity's cloud. The message
reaches the entry's status listener, which is how it lands on the
component's error surface.

**Parameters**

- `id` `string` — Entity id.
- `message` `string` — What the feature refused the cloud for.

```lua
gaussianSplats.reportFailure(id, "no capture at 'captures/room.gaussianSplat'")
```

## modules/gaussianSplats/set {#modules-gaussiansplats-set}

```lua
set(id: string, entry: SplatEntry, onStatus: StatusListener?)
```

Register or update the cloud an entity renders. Changing `source` or
`convention` bumps the entry's generation, which makes the render feature
re-decode and re-upload on its next frame, and drops any verdict the
feature reached about the capture asked for before.

**Parameters**

- `id` `string` — Entity id.
- `entry` `SplatEntry` — The cloud's declaration.
- `onStatus` `StatusListener?` _(optional)_ — Called with the feature's message when it cannot build the
cloud, and with nil once it can. `GaussianSplat.component` passes the call
that puts the message on its own error surface.

```lua
gaussianSplats.set(id, { source = "captures/ceramic.spz", opacity = 1 })
```

## modules/gaussianSplats/setVelocity {#modules-gaussiansplats-setvelocity}

```lua
setVelocity(enabled: boolean): boolean
```

Whether a moving cloud writes its screen-space displacement into the
frame's velocity buffer, which is what makes motion blur, temporal
antialiasing, temporal upsampling and a denoiser's history term treat it as
moving. On costs two screen-sized targets and two full-screen passes while
any cloud is on screen. On by default.

**Parameters**

- `enabled` `boolean` — Whether the clouds report their motion.

```lua
gaussianSplats.setVelocity(false)
```

## modules/gaussianSplats/velocity {#modules-gaussiansplats-velocity}

```lua
velocity(): boolean
```

Whether the clouds report their motion into the frame's velocity buffer.

```lua
if gaussianSplats.velocity() then ... end
```

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

```lua
require("@builtin/modules/api/engine/http") -- http (also available as global 'http')
```

Async HTTP — GET/POST returning JSON or raw bytes. Public Luau surface over the `__http` Internal FFI namespace.

Usage: local http = require("@builtin/modules/api/engine/http")
Also available as global: http

## modules/http/get_bytes {#modules-http-get-bytes}

```lua
get_bytes(url: string, headers: Headers?): PromiseId
```

Async HTTP GET returning raw bytes (binary-safe string).
Suitable for piping into `vfs.write` to download a file.

**Parameters**

- `url` `string` — Request URL.
- `headers` `Headers?` _(optional)_ — Header key-value pairs (optional).

```lua
local bytes = task.await(http.get_bytes("https://example.com/sound.ogg"))
```

## modules/http/get_json {#modules-http-get-json}

```lua
get_json(url: string, headers: Headers?): PromiseId
```

Async HTTP GET returning JSON. Returns a promise handle — wrap
with `task.await()` to block until the response arrives.

**Parameters**

- `url` `string` — Request URL.
- `headers` `Headers?` _(optional)_ — Header key-value pairs (optional).

```lua
local data = task.await(http.get_json("https://api.example.com/info"))
```

## modules/http/post_bytes {#modules-http-post-bytes}

```lua
post_bytes(url: string, headers: Headers?, body: JsonBody?): PromiseId
```

Async HTTP POST returning raw bytes — use for APIs that accept
JSON input but return binary output (audio, images).

**Parameters**

- `url` `string` — Request URL.
- `headers` `Headers?` _(optional)_ — Header key-value pairs (optional).
- `body` `JsonBody?` _(optional)_ — JSON body (optional).

```lua
local audio = task.await(http.post_bytes(ttsUrl, nil, { text = "hello" }))
```

## modules/http/post_json {#modules-http-post-json}

```lua
post_json(url: string, headers: Headers?, body: JsonBody?): PromiseId
```

Async HTTP POST returning JSON. Body is a Luau table; the FFI
layer JSON-encodes it before the request goes out.

**Parameters**

- `url` `string` — Request URL.
- `headers` `Headers?` _(optional)_ — Header key-value pairs (optional).
- `body` `JsonBody?` _(optional)_ — JSON body (optional).

```lua
local r = task.await(http.post_json(url, nil, { name = "Alice" }))
```

## modules/http/request {#modules-http-request}

```lua
request(method: string, url: string, headers: Headers?, body: JsonBody?): PromiseId
```

Async HTTP request with an arbitrary verb (GET/POST/PUT/PATCH/
DELETE/…) returning JSON. Body is a Luau table; an empty 2xx
response resolves to an empty table.

**Parameters**

- `method` `string` — HTTP verb (case-insensitive).
- `url` `string` — Request URL.
- `headers` `Headers?` _(optional)_ — Header key-value pairs (optional).
- `body` `JsonBody?` _(optional)_ — JSON body (optional).

```lua
local w = task.await(http.request("PATCH", url, hdrs, { description = "hi" }))
```

## modules/http/request_raw {#modules-http-request-raw}

```lua
request_raw(method: string, url: string, headers: Headers?, body: buffer | string | nil): PromiseId
```

Async HTTP request with an arbitrary verb and a RAW binary
request body (a binary-safe string), for content-addressed blob
uploads. The resolved value is the response body text.

**Parameters**

- `method` `string` — HTTP verb (case-insensitive).
- `url` `string` — Request URL.
- `headers` `Headers?` _(optional)_ — Header key-value pairs (optional).
- `body` `buffer | string | nil` _(optional)_ — Raw binary request body (optional).

```lua
local r = task.await(http.request_raw("POST", blobsUrl, hdrs, pngBytes))
```

## modules/httpServer/README {#modules-httpserver-readme}

```lua
require("@builtin/modules/api/engine/httpServer") -- httpServer (also available as global 'httpServer')
```

Serve HTTP from this engine. A world registers a handler for a method and a path, and the engine's own HTTP server routes matching requests to it — so a browser tab, a curl call or another process on this machine reaches the running world over plain HTTP, with the world deciding what every address answers. The engine's own HTTP server listens on the loopback interface, so a world that asks for nothing is reachable from this machine, and through a forward another program opens to it (`adb forward`, an SSH tunnel, a reverse proxy). `httpServer.listen(target)` holds a second address of this world's own choosing: the host in the target is the interface bound and the whole of what decides who can reach it, so `"0.0.0.0:8080"` answers a phone on the same wifi and `"127.0.0.1:8080"` answers this machine. `httpServer.address(path)` is the URL to call, and `httpServer.status()` reports the host, the port and the `reach` those routes answer under. Content routes are served under the `/app` mount: `httpServer.route("GET", "/status", h)` answers `http://<host>:<port>/app/status`. The engine's own `/engine/*` routes are matched first, and every registration lands under `/app`, so the two trees stay disjoint. A route belongs to the chunk that registered it, and so does an address that chunk opened. When that chunk runs again — a module hot-reload, a cleared require cache — both are released and the new run makes its own, so an edited handler is the one that answers. `httpServer.routes()` names the owner of every address. A handler runs on the script thread, inside the frame, like any other world code — it may read and write the world, and it holds the tick for as long as it runs. The request waits at most `timeoutMs` (5 s by default) for its answer; past that the caller is told 504 and the connection closes, while the handler itself carries on to completion.

Usage: local httpServer = require("@builtin/modules/api/engine/httpServer")
Also available as global: httpServer

## modules/httpServer/address {#modules-httpserver-address}

```lua
address(path: string): (string?, string?)
```

The URL a path answers on — scheme, host, port and the `/app` mount,
ready to be fetched or printed for someone to open. Takes the same path
spelling `route` does, and reads the interface and port from the socket
routes answer on: the address `listen` opened while one is open, and the
engine's own server otherwise.

**Parameters**

- `path` `string` — Path under the `/app` mount, e.g. "/status".

```lua
print(httpServer.address("/status")) --> http://127.0.0.1:7607/app/status
```

## modules/httpServer/listen {#modules-httpserver-listen}

```lua
listen(target: string): (HttpListener?, string?)
```

Hold an interface and port of this world's own, and answer content
routes on it.

The host in `target` is the interface bound, and the whole of what decides
who can reach those routes: `"127.0.0.1:8080"` answers programs on this
machine, `"0.0.0.0:8080"` answers any host that routes to this machine on
that port — a phone on the same wifi, and whatever else the network lets
through. Bind loopback unless you want that. A port of `0` asks the
operating system for a free one, which the returned record reports, and
`http://` may be spelled out in front.

This address serves the routes registered under the `/app` mount. The
engine's own `/engine/*` tree answers on the loopback server it booted
with, whose interface stays what the boot bound.

The address belongs to the chunk that opened it and is released when that
chunk runs again, so an edited module holds the address its current source
names. Asking for the address already held is the same address back.

**Parameters**

- `target` `string` — Interface and port to hold, e.g. "0.0.0.0:8080".

```lua
local l = assert(httpServer.listen("0.0.0.0:8080"))
```

## modules/httpServer/route {#modules-httpserver-route}

```lua
route(
```

Serve one method and path from this engine, answering each matching
request with `handler`.

The path is relative to the `/app` mount, and a trailing `/*` segment
matches the rest of the path — `"/files/*"` answers `/app/files/a/b`, with
`"a/b"` in `request.wildcard`. An exact path answers ahead of a wildcard,
and among wildcards the longest one wins.

One method and path is served by one handler. Registering an address
another chunk serves returns nil and a reason naming the handle and the
chunk holding it; `httpServer.routes()` finds that handle and
`httpServer.unroute` frees the address. Registering an address this same
chunk already serves takes it back and releases the handler it replaces,
so a chunk that runs twice serves the handler it just built.

The handler runs on the script thread. Raising inside it answers 500 and
writes the error to the engine log; returning something that is not a
response table or a string answers 500 saying what arrived.

```lua
local h = httpServer.route("GET", "/status", function(req)
```

## modules/httpServer/routes {#modules-httpserver-routes}

```lua
routes(): { HttpRoute }
```

Every route this engine currently serves, in registration order —
handle, method, registered path, the address it answers on, its full URL,
the chunk that registered it, and how long a request for it waits.

```lua
for _, r in ipairs(httpServer.routes()) do print(r.method, r.url, r.owner) end
```

## modules/httpServer/status {#modules-httpserver-status}

```lua
status(): HttpServerStatus
```

Whether this engine serves content routes, on which interface, port
and mount, who can reach them, and how many routes and waiting requests it
holds. `host`, `port`, `url` and `reach` are read from the socket routes
answer on — the one `listen` opened while one is open, and the engine's
own server otherwise — and `listeners` carries every address, each with
its own reach. When `supported` is false, `reason` says why: a browser tab
answers HTTP requests and holds no address of its own.

```lua
local s = httpServer.status(); print(s.url, s.reach)
```

## modules/httpServer/unlisten {#modules-httpserver-unlisten}

```lua
unlisten(): boolean
```

Release the address `listen` opened. Returns once the socket is free,
so the same port binds again straight after.

```lua
httpServer.unlisten()
```

## modules/httpServer/unroute {#modules-httpserver-unroute}

```lua
unroute(handle: number): boolean
```

Stop serving a route and release its handler. The address is free for
another registration once this returns true.

**Parameters**

- `handle` `number` — The handle `httpServer.route` returned.

```lua
httpServer.unroute(h)
```

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

```lua
require("@builtin/systems/imageBasedLighting/ibl") -- ibl
```

Image-based lighting from the scene's own sky — metal reflects what is actually above it, and matte surfaces pick up the sky's colour.

Usage: local ibl = require("@builtin/systems/imageBasedLighting/ibl")

## modules/ibl/active {#modules-ibl-active}

```lua
active(): boolean
```

Whether the environment-lighting passes are currently running.

```lua
if ibl.active() then print("lit by the sky") end
```

## modules/ibl/clear {#modules-ibl-clear}

```lua
clear()
```

Turn environment lighting off and release the passes. The other settings
are kept, so a later `set` brings back the same look.

```lua
ibl.clear()
```

## modules/ibl/follow {#modules-ibl-follow}

```lua
follow()
```

Go back to reading the sky and sun from the scene, after a call pinned
them.

```lua
ibl.follow()
```

## modules/ibl/get {#modules-ibl-get}

```lua
get(): IblState
```

The environment-lighting settings currently in force.

```lua
local s = ibl.get().specular
```

## modules/ibl/paramsBuffer {#modules-ibl-paramsbuffer}

```lua
paramsBuffer(): any?
```

The buffer this system's passes read. The render feature binds what
this hands it, so the pass has the values this module packed.

```lua
local p = ibl.paramsBuffer()
```

## modules/ibl/refresh {#modules-ibl-refresh}

```lua
refresh()
```

Carry the scene's current sky and sun into the running passes. The
scales — `diffuse`, `specular`, `skyIntensity`, `horizonSharpness` and
`sunSize` — stay as they stand, so a caller ticking this every frame keeps
a day/night cycle reaching the reflections without restating them. It
reads while the passes are running and the scene is on automatic tracking;
a colour or direction pinned through `set` holds it off until `follow`.

```lua
ibl.refresh()
```

## modules/ibl/set {#modules-ibl-set}

```lua
set(opts: IblOpts?): IblState
```

Set the scene's environment lighting. Any omitted field keeps its
current value. With both `diffuse` and `specular` at 0 nothing is being
asked for and the passes are released.

**Parameters**

- `opts` `IblOpts?` _(optional)_ — Settings — see `IblOpts`.

```lua
ibl.set({ diffuse = 1, specular = 1 })
```

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

```lua
require("@builtin/systems/photometrics.package/ies") -- ies
```

Photometric light distributions in the IESNA LM-63 format, turned into a texture a spot light projects through its cone.

Usage: local ies = require("@builtin/systems/photometrics.package/ies")

## modules/ies/parse {#modules-ies-parse}

```lua
parse(src: string): (Profile?, string?)
```

Read an IESNA LM-63 photometric file.

**Parameters**

- `src` `string` — The file's text.

```lua
local p = ies.parse(vfs.read("/source/lights/downlight.ies"))
```

## modules/ies/toLayer {#modules-ies-tolayer}

```lua
toLayer(profile: Profile, layer: number, coneHalfAngleDeg: number, resolution: number?): (number?, string?)
```

Rasterize a profile into one layer of the shared feature-texture array,
ready for a spot light's `cookieLayer` to project it.

**Parameters**

- `profile` `Profile` — A profile from `ies.parse`.
- `layer` `number` — Which feature-texture layer to fill.
- `coneHalfAngleDeg` `number` — The spot's outer half-angle, so the profile's angles land
where the cone actually reaches.
- `resolution` `number?` _(optional)_ — Layer size in pixels, a multiple of 32. Defaults to 256.

```lua
ies.toLayer(profile, 0, spot.angle)
```

## modules/layeredMaterial/README {#modules-layeredmaterial-readme}

```lua
require("@builtin/systems/layeredMaterial/layeredMaterial") -- layeredMaterial
```

A surface written as a stack of materials that already exist, compiled to one WGSL surface shader. Rust over painted metal, snow over rock, mud over a vehicle, lacquer over paint: each is one material laid over another. The two materials are already authored; what is missing is a way to say "this one, over that one, where the mask says". Written by hand, that means a new `fn surface()` for every pair, and the pair is what the shader is about — neither half is reusable. A stack names the materials instead, and `material()` compiles it, writes the shader out as an ordinary `.shader` asset and hands back a material wearing it. Each layer is read off the material it names — its shading values and the textures it binds — and the emitted shader carries every layer's inputs under its own name, blends them by coverage, and shades **once**. Shading each layer and adding the results would put more energy back out than arrived; interpolating the inputs and shading the result cannot, which is what keeps a half-covered surface from reading brighter than either layer alone. A layer past the first is revealed by the product of three terms, each of which can be left neutral: a mask texture read through one channel and a contrast, a per-material amount, and one lane of the entity's own shader data. All three are ordinary material properties, so the blend is drivable at runtime, and the instance term is what lets two entities wearing one material carry different amounts of wear in the same frame. `property(i, name)` spells the naming convention out for a caller driving them, `inputs()` lists what a layer carries, and `limits()` reports the bounds a stack is compiled against.

Usage: local layeredMaterial = require("@builtin/systems/layeredMaterial/layeredMaterial")

## modules/layeredMaterial/check {#modules-layeredmaterial-check}

```lua
check(stack: Stack): (boolean, any)
```

Compile a stack without raising. The same work `compile` does, with the
error handed back rather than thrown — what an editor wants while the author
is still choosing materials.

**Parameters**

- `stack` `Stack` — The stack to check.

```lua
local ok, result = layeredMaterial.check(stack)
```

## modules/layeredMaterial/compile {#modules-layeredmaterial-compile}

```lua
compile(stack: Stack, name: string?): Compiled
```

Compile a stack of materials into the two files a `.shader` asset holds.
The layers are read off the materials they name, so this reaches the asset
graph; it touches no renderer and no GPU, and a layer written as plain
`values` and `textures` instead of a `material` reference needs no asset at
all.

**Parameters**

- `stack` `Stack` — `{ name, layers = { { material, blend, mask, ... }, ... } }`, the
bottom layer first.
- `name` `string?` _(optional)_ — Overrides `stack.name` for the shader this compiles to.

```lua
local out = layeredMaterial.compile({ name = "worn", layers = { { material = "@builtin::materials.default" }, { material = "@builtin::materials.gold", blend = 0.5 } } })
print(out.wgsl)
```

## modules/layeredMaterial/inputs {#modules-layeredmaterial-inputs}

```lua
inputs(): {
```

What a layer carries: the shading inputs the stack blends, the texture
slots a layer may bind, the coverage controls a layer past the first
declares, and the properties that belong to the whole surface.

```lua
for _, decl in ipairs(layeredMaterial.inputs().values) do print(decl.name) end
```

## modules/layeredMaterial/install {#modules-layeredmaterial-install}

```lua
install(stack: Stack, opts: { name: string?, into: any? }?): Installed
```

Compile a stack and write it out as a real `.shader` asset. The result is
an ordinary shader asset — it can be read, hand-edited and shipped like any
other. Installing the same stack again rewrites the same asset. The shader
is compiled at the next frame boundary, the way any shader edit is;
`asset.ref(name, "shader"):compileStatus()` is what reports the outcome.

**Parameters**

- `stack` `Stack` — The stack to install.
- `opts` `{ name: string?, into: any? }?` _(optional)_ — `{ name = <shader name>, into = { path = <folder> } }`. `into` places
the asset as it is created; installing again writes wherever it already is.

```lua
local shader = layeredMaterial.install(stack, { name = "worn_barrel" })
local status = asset.ref(shader.name, "shader"):compileStatus()
```

## modules/layeredMaterial/limits {#modules-layeredmaterial-limits}

```lua
limits(): { maxLayers: number, textureSlots: number }
```

The bounds a stack is compiled against: how many layers one holds, and
how many texture slots the layers may spend between them.

```lua
print(layeredMaterial.limits().textureSlots)
```

## modules/layeredMaterial/material {#modules-layeredmaterial-material}

```lua
material(
```

Install a stack and make a material wearing the shader it compiled to,
carrying every layer's values and every texture the layers bind. The result
is an ordinary material asset: hand it to a Model's `material` field, or
drive its properties afterwards like any other. Calling it again with the
same material name is how a stack is iterated on — the shader is rewritten,
the material is brought onto it, and the layers are applied over it, so what
the call says is what the material holds when it returns.

```lua
local mat = layeredMaterial.material(stack, { name = "worn_barrel" })
entity.spawn("barrel").component.add("Model", { model = "cube", material = mat })
```

## modules/layeredMaterial/property {#modules-layeredmaterial-property}

```lua
property(index: number, input: string): string
```

The name the generated shader declares one of a layer's inputs under.
The convention is `l<index>_<input>`, and this is what says so — a caller
driving a blend at runtime asks for the name rather than spelling it.

**Parameters**

- `index` `number` — Which layer, counting the bottom one as 1.
- `input` `string` — The input's name — one of `inputs()`, or a coverage control. The
coverage controls belong to a layer laid over another, so asking for one on
the bottom layer raises rather than naming a property no stack declares.

```lua
matRef:setProperty(layeredMaterial.property(2, "coverage"), 0.7)
```

## modules/layeredMaterial/read {#modules-layeredmaterial-read}

```lua
read(materialRef: any): {
```

Read a layer's inputs off a material that already exists — the values it
carries for everything a stack blends, and the textures it binds for them.
This is what `compile` does with a layer written as `{ material = ... }`,
exposed on its own so a caller can see what a material would contribute
before stacking it. A slot the material leaves on a built-in fallback
(`default:white`, `default:normal`) is read as bound to nothing, since that
fallback is what a slot left undeclared samples anyway.

**Parameters**

- `materialRef` `any` _(optional)_ — The material — a name, an identity, or an `AssetRef<material>`.

```lua
local layer = layeredMaterial.read("@builtin::materials.gold")
print(layer.values.metallic, layer.textures.base_color_texture)
```

## 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
```

## modules/lensFx/README {#modules-lensfx-readme}

```lua
require("@builtin/systems/lensFx/lensFx") -- lensFx
```

The lens and the film — flare thrown by bright sources, dirt on the front element, and grain that is redrawn every frame rather than a fixed screen pattern.

Usage: local lensFx = require("@builtin/systems/lensFx/lensFx")

## modules/lensFx/active {#modules-lensfx-active}

```lua
active(): boolean
```

Whether the lens passes are running this frame.

```lua
if lensFx.active() then ... end
```

## modules/lensFx/clear {#modules-lensfx-clear}

```lua
clear()
```

Turn the flare and grain off and release the passes. The other settings
are kept, so a later `set` brings back the same look.

```lua
lensFx.clear()
```

## modules/lensFx/get {#modules-lensfx-get}

```lua
get(): LensFxState
```

The lens settings currently in force.

```lua
local g = lensFx.get().grainIntensity
```

## modules/lensFx/paramsBuffer {#modules-lensfx-paramsbuffer}

```lua
paramsBuffer(): any?
```

The buffer this system's passes read. The render feature binds what
this hands it, so the pass has the values this module packed.

```lua
local p = lensFx.paramsBuffer()
```

## modules/lensFx/set {#modules-lensfx-set}

```lua
set(opts: LensFxOpts?): LensFxState
```

Set the lens and film. Any omitted field keeps its current value. With
both `flareIntensity` and `grainIntensity` at 0 the passes are released.

**Parameters**

- `opts` `LensFxOpts?` _(optional)_ — Lens settings — see `LensFxOpts`.

```lua
lensFx.set({ flareIntensity = 1.0, grainIntensity = 0.04 })
```

## modules/lensFx/sync {#modules-lensfx-sync}

```lua
sync()
```

Bring the buffer's grain clock to the instant this frame draws at. The
render feature calls it once a frame, so the field follows a
`renderer.temporal.hold` the moment one is taken or released, whatever is
driving the scene's own clock.

```lua
lensFx.sync()
```

## modules/lensFx/tick {#modules-lensfx-tick}

```lua
tick(dt: number)
```

Advance the clock the grain is drawn against. Grain is a fresh field
every frame rather than a fixed screen pattern, so it needs the frame's
own time — which cannot arrive through `set`, since a value that has not
changed is not re-pushed.

**Parameters**

- `dt` `number` — Seconds since the previous frame.

```lua
function update(dt) lensFx.tick(dt) end
```

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

```lua
require("@builtin/modules/api/engine/library") -- library (also available as global 'library')
```

Discover, check, and import library assets — the `@builtin/*` tree the engine ships and the `@namespace/*` trees imported from other worlds.

Usage: local library = require("@builtin/modules/api/engine/library")
Also available as global: library

## modules/library/has {#modules-library-has}

```lua
has(path: string): boolean
```

Check if a library asset exists at the given path.

**Parameters**

- `path` `string` — Library asset path (e.g. "@builtin/models/Sample/DamagedHelmet").

```lua
assert(library.has("@builtin/models/Cube"))
```

## modules/library/import {#modules-library-import}

```lua
import(namespace: string, worldRef: string): LibraryImport
```

Import another world as a library under the given namespace.
Resolves the world, pins its current commit, and writes the
library marker at `/source/libs/@<namespace>`. Once the engine has
fetched the pinned commit, the imported tree answers to
`require("@<namespace>::path")`, is listed by `library.list()`, and
is readable under `/zero/source/libs/@<namespace>/`.

**Parameters**

- `namespace` `string` — Library namespace, with or without the leading `@`
(e.g. `"@mylib"` or `"mylib"`).
- `worldRef` `string` — The upstream world's guid, or its name as it appears
in `world.list()`.

```lua
library.import("@mylib", "my-shared-world")
```

## modules/library/list {#modules-library-list}

```lua
list(assetType: string?): { LibraryAsset }
```

List all available library assets. Optionally filter by asset
type — call `asset.categories()` for the live set.

**Parameters**

- `assetType` `string?` _(optional)_ — Asset type filter (optional).

```lua
for _, a in ipairs(library.list("model")) do print(a.path) end
```

## modules/lightCookies/README {#modules-lightcookies-readme}

```lua
require("@builtin/systems/lightCookies.package/lightCookies") -- lightCookies
```

Project an authored image through a spot light's cone — a gobo, a window pattern, a headlight cutoff.

Usage: local lightCookies = require("@builtin/systems/lightCookies.package/lightCookies")

## modules/lightCookies/clear {#modules-lightcookies-clear}

```lua
clear(light: any): boolean
```

Stop projecting a cookie through a light's cone. The layer keeps its
contents; the light stops reading it.

**Parameters**

- `light` `any` _(optional)_ — The spot light's entity id or entity proxy.

```lua
lightCookies.clear(lampId)
```

## modules/lightCookies/configure {#modules-lightcookies-configure}

```lua
configure(opts: { resolution: number, layers: number }): (number?, string?)
```

Size the shared feature-texture array for cookies. Call once, before
setting any cookie, with a layer count covering every layer the scene
uses — resizing the array zeroes every layer in it, including layers other
features own. `renderer.featureTexture.state()` reports the extent the array
carries and the layers holding content, so a cookie that has left `filled`
is one to set again.

**Parameters**

- `opts` `{ resolution: number, layers: number }` — `{ resolution, layers }` — `resolution` is the square extent of each
layer in pixels, a multiple of 32; `layers` is how many the array holds.

```lua
lightCookies.configure({ resolution = 256, layers = 4 })
```

## modules/lightCookies/fill {#modules-lightcookies-fill}

```lua
fill(image: any, opts: Options): (number?, string?)
```

Fill one layer of the shared array with an authored image, ready for a
spot light's `cookieLayer` to project it.

**Parameters**

- `image` `any` _(optional)_ — A texture `AssetRef`, a `TextureHandle`, or any string `asset.ref`
resolves to one — a guid, an identity, a name or a source path.
- `opts` `Options` — `{ layer, gain?, tint? }`.

```lua
lightCookies.fill("/textures/cookies/window_blinds.png", { layer = 0 })
```

## modules/lightCookies/layerOf {#modules-lightcookies-layerof}

```lua
layerOf(light: any): number?
```

The layer a light is currently projecting, or nil when it has no cookie.

**Parameters**

- `light` `any` _(optional)_ — The spot light's entity id or entity proxy.

```lua
print(lightCookies.layerOf(lampId))
```

## modules/lightCookies/project {#modules-lightcookies-project}

```lua
project(light: any, image: any, opts: Options): (number?, string?)
```

Project an image through a spot light's cone: fill a layer with it and
point the light at that layer.

**Parameters**

- `light` `any` _(optional)_ — The spot light's entity id or entity proxy.
- `image` `any` _(optional)_ — A texture asset, in any form `lightCookies.fill` accepts.
- `opts` `Options` — `{ layer, gain?, tint? }`.

```lua
lightCookies.project(lampId, "/textures/cookies/blinds.png", { layer = 0 })
```

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

```lua
require("@builtin/modules/api/engine/logs") -- logs (also available as global 'logs')
```

Read-only query surface over the engine's in-memory log ring buffer. Public Luau surface over the `__logs` Internal FFI namespace.

Usage: local logs = require("@builtin/modules/api/engine/logs")
Also available as global: logs

## modules/logs/clear {#modules-logs-clear}

```lua
clear(): boolean
```

Drop all buffered log entries. Lifetime per-level counts
(`logs.count`) are preserved.

```lua
logs.clear()
```

## modules/logs/count {#modules-logs-count}

```lua
count(opts: LogQueryOpts?): LogCounts
```

Aggregate counters for the log ring. Lifetime counts survive
eviction, so `errors` reflects the total seen even if the lines
have scrolled out of the buffer. `opts` takes the same filter table
as `logs.query`, and `matched` is how many held entries it selects,
counted without materialising them — `limit` and `newest_first` bound
and order what a query RETURNS, so they leave `matched` alone. `mcp`
is how many held entries record your own tool traffic; a query leaves
those out, so with no `opts`, `matched` + `mcp` is everything held.
`last_seq` is the cursor for
incremental polling: read it before an action, then pass it as
`logs.query({ since = <that> })` afterwards to see only what the
action logged.

**Parameters**

- `opts` `LogQueryOpts?` _(optional)_ — Filter options, as `logs.query` takes.

```lua
print("errors:", logs.count().errors)
local before = logs.count().last_seq
```

## modules/logs/errors {#modules-logs-errors}

```lua
errors(limit: number?): { LogEntry }
```

Most-recent ERROR-level entries (newest first). `limit`
defaults to 100.

**Parameters**

- `limit` `number?` _(optional)_ — Maximum entries to return.

```lua
for _, e in ipairs(logs.errors(20)) do print(e.message) end
```

## modules/logs/find {#modules-logs-find}

```lua
find(text: string, limit: number?): { LogEntry }
```

Case-insensitive substring search over log messages. `limit`
defaults to 200 (keeps the most recent matches). Searches what the
engine logged, so looking for a marker cannot return the call that
looked for it; `logs.query({ contains = ..., include_mcp = true })`
searches your own tool traffic too.

**Parameters**

- `text` `string` — Substring to search for.
- `limit` `number?` _(optional)_ — Maximum entries to return.

```lua
local hits = logs.find("MY_MARKER")
```

## modules/logs/query {#modules-logs-query}

```lua
query(opts: LogQueryOpts?): { LogEntry }
```

Query the engine's in-memory log ring — the filtered view of what
also reads as plain text at `/zero/runtime/logs/engine`. Answers about what the
engine logged: the MCP record of your own tool traffic is left out,
because the call carrying the query is one of those records and an
unqualified search would match itself. `type = "MCP"` selects them;
`include_mcp = true` mixes them in with everything else. On a world
several sessions share, `origin = "local"` narrows the answer to the
lines this session's own authoring caused.

**Parameters**

- `opts` `LogQueryOpts?` _(optional)_ — Filter options.

```lua
logs.query({ entity = "guard-1", limit = 20 })
logs.query({ level = "error", context = 3 })
for _, e in ipairs(logs.query({ level = "warn", limit = 50 })) do print(e.message) end
```

## modules/logs/tail {#modules-logs-tail}

```lua
tail(limit: number?): { LogEntry }
```

Most-recent entries of any level in chronological order.
`limit` defaults to 100.

**Parameters**

- `limit` `number?` _(optional)_ — Maximum entries to return.

```lua
for _, e in ipairs(logs.tail(20)) do print(e.level, e.message) end
```

## modules/logs/template {#modules-logs-template}

```lua
template(message: string): string
```

Normalize a message to its template — the same line with the parts
that vary between occurrences (numbers, hashes, entity ids) masked out.
Two messages that differ only in those parts share a template, which is
what turns "this error repeated 400 times" into one row instead of 400.
The engine keys its own error retention by the same normalization, so
grouping built on this agrees with what survives ring eviction.

**Parameters**

- `message` `string` — Log message to normalize.

```lua
local key = logs.template(entry.message)
```

## modules/logs/warnings {#modules-logs-warnings}

```lua
warnings(limit: number?): { LogEntry }
```

Most-recent WARN+ entries (newest first). `limit` defaults
to 100.

**Parameters**

- `limit` `number?` _(optional)_ — Maximum entries to return.

```lua
print(#logs.warnings(), "warnings")
```

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

```lua
require("@builtin/modules/api/engine/lsp") -- lsp (also available as global 'lsp')
```

Embedded Luau language server — check / search / inspect Public Luau surface over the `__lsp` Internal FFI namespace.

Usage: local lsp = require("@builtin/modules/api/engine/lsp")
Also available as global: lsp

## modules/lsp/check {#modules-lsp-check}

```lua
check(path: string, opts: CheckOpts?): DiagnosticsResult
```

Validate a single `.luau` file in the VFS and return its
diagnostics. A path the check could not read comes back as one
`lsp-check-*` error naming the path and the reason, so `errors == 0`
means a code body was read and is clean.

**Parameters**

- `path` `string` — VFS path.
- `opts` `CheckOpts?` _(optional)_ — `{ severity?, limit?, context? }`.

```lua
local diags = lsp.check("/zero/source/main.luau")
```

## modules/lsp/checkAll {#modules-lsp-checkall}

```lua
checkAll(opts: CheckAllOpts?): CheckAllResult
```

Validate the user's Luau scripts and return an aggregate
summary plus diagnostic list. `opts.scope = "user"` (default)
skips library mounts; `"all"` includes them. The sweep is
time-budgeted (ZERO_EXECUTE_INLINE_BUDGET_MS, ~20s by default): if
the budget elapses it returns the partial result gathered so far
with `budgetExceeded = true` rather than blocking the engine.

**Parameters**

- `opts` `CheckAllOpts?` _(optional)_ — `{ scope?, severity?, limit? }`.

## modules/lsp/checkCode {#modules-lsp-checkcode}

```lua
checkCode(source: string, opts: CheckOpts?): DiagnosticsResult
```

Validate inline Luau source without a backing file. Useful
for checking code before writing it to disk.

**Parameters**

- `source` `string` — Luau source.
- `opts` `CheckOpts?` _(optional)_ — `{ severity?, limit?, context? }`.

## modules/lsp/checkDirty {#modules-lsp-checkdirty}

```lua
checkDirty(): DiagnosticsResult
```

Drain the dirty-file set populated by the hot-reload hook,
validate each, and return the combined diagnostic list.

## modules/lsp/describe {#modules-lsp-describe}

```lua
describe(path: string, opts: DescribeOpts?): DocEntry?
```

Inspect a single documented entry. Returns the full doc
table (signature, args, returns, examples, level), or nil.
The path is resolved independently of which root the doc is
registered under and of separator style, so the spelling that reads
off the API surface (`renderer.texture.create`) finds the entry
registered as `globals/renderer/texture/create`. A path naming a
binding the engine registered internally answers with the entry a Luau
module publishes over it where there is one, so the signature is the
call content makes; `opts.includeInternal` answers with the internally
registered entry itself. When a path does not resolve,
`lsp.describePaths` says what the registry holds near it.

**Parameters**

- `path` `string` — Doc path (e.g. `"asset/resolve"`, `"renderer.texture.create"`).
- `opts` `DescribeOpts?` _(optional)_ — Optional `{ includeInternal? }` — default prefers the published entry.

```lua
local doc = lsp.describe("renderer.texture.create")
```

## modules/lsp/describePaths {#modules-lsp-describepaths}

```lua
describePaths(path: string): { string }
```

List the registered doc paths related to `path`. A path that names
an entry returns every root it is registered under (the first is what
`lsp.describe` resolves to); a path that names a namespace returns the
entries registered under it. Empty when the registry holds nothing
near the path — so a lookup that returns nil can always be turned into
the list of what does exist.

**Parameters**

- `path` `string` — Doc path in any spelling (`"renderer.texture"`, `"ecs/query"`).

```lua
for _, p in ipairs(lsp.describePaths("renderer.texture")) do print(p) end
```

## modules/lsp/describeTool {#modules-lsp-describetool}

```lua
describeTool(path: string): string?
```

Return the full documentation text for a code-mode tool.

**Parameters**

- `path` `string` — Tool path (e.g. `"scene/spawnLight"`).

## modules/lsp/docsByKind {#modules-lsp-docsbykind}

```lua
docsByKind(kind: string): { MethodSummary }
```

List every doc whose registration kind matches `kind`.
Valid: `"binding"`, `"runtime_tool"`, `"module"`, `"component"`,
`"library"`, `"lua_export"`.

**Parameters**

- `kind` `string` — Registration kind.

## modules/lsp/getStrictMode {#modules-lsp-getstrictmode}

```lua
getStrictMode(): StrictMode
```

Return the current strict mode.

## modules/lsp/isStrict {#modules-lsp-isstrict}

```lua
isStrict(): boolean
```

Is the pre-execute LSP gate fully strict? False when off or
in soft mode.

## modules/lsp/lastCheckGen {#modules-lsp-lastcheckgen}

```lua
lastCheckGen(): number
```

Generation counter — bumped each time the cache is rebuilt.
UI polls this to know when to redraw.

## modules/lsp/methods {#modules-lsp-methods}

```lua
methods(namespace: string, opts: MethodsOpts?): { MethodSummary } | { string }
```

List every documented method / entry under a namespace. A broad
namespace (`ui`, `renderer`) returns a large dump by default, so two
options narrow it: `opts.filter` keeps only methods whose name (or
doc path) contains the substring, case-insensitively; `opts.namesOnly`
returns a plain list of method-name strings instead of the full
per-method summary tables — much smaller, and nothing to unwrap. The
listing answers with the surface content calls: an entry registered
internally is left out where its signature spells the `__` binding or a
Luau module publishes the same member, and `opts.includeInternal` lists
every registered entry instead.

**Parameters**

- `namespace` `string` — Namespace name (e.g. `"entity"`, `"modules/Transform"`).
- `opts` `MethodsOpts?` _(optional)_ — Optional `{ filter?, namesOnly?, includeInternal? }`.

```lua
for _, name in ipairs(lsp.methods("ui", { namesOnly = true })) do print(name) end
lsp.methods("renderer", { filter = "shadow" })
```

## modules/lsp/modules {#modules-lsp-modules}

```lua
modules(): { ModuleEntry }
```

List every Luau library module the engine currently knows
about — discovered via `--!module` headers, library scans, and
manually-recorded docs.

## modules/lsp/namespaces {#modules-lsp-namespaces}

```lua
namespaces(opts: NamespacesOpts?): { NamespaceEntry }
```

List the documentation namespaces reachable from Luau. By
default only namespaces exposing at least one PUBLIC method are
returned, so the list matches what you can actually call — internal
FFI plumbing (e.g. `pause`, `native_entity`), whose public surface
lives elsewhere (`engine.paused`, the `entity` proxy, …), is left
out. Pass `{ includeInternal = true }` to list every namespace,
internal ones included.

**Parameters**

- `opts` `NamespacesOpts?` _(optional)_ — Optional `{ includeInternal? }` — default lists public only.

```lua
for _, ns in ipairs(lsp.namespaces()) do print(ns.name) end
```

## modules/lsp/readDirectives {#modules-lsp-readdirectives}

```lua
readDirectives(source: string): DirectiveBlock
```

Parse the leading `--!` directive block of a Luau source
string. Used by UIs that audit which files have skip directives
and what they suppress.

**Parameters**

- `source` `string` — Luau source text.

## modules/lsp/search {#modules-lsp-search}

```lua
search(query: string, opts: SearchOpts?): { MethodSummary }
```

Case-insensitive substring search across every registered
doc's path, signature, and description. Hits answer with the surface
content calls: an entry registered internally is left out where its
signature spells the `__` binding or a Luau module publishes the same
member, and `opts.includeInternal` searches every registered entry.

**Parameters**

- `query` `string` — Substring to search for.
- `opts` `SearchOpts?` _(optional)_ — `{ limit? = 50, includeInternal? }`.

## modules/lsp/setStrict {#modules-lsp-setstrict}

```lua
setStrict(enabled: boolean): boolean
```

Toggle the pre-execute LSP gate. Returns true when the change
was persisted to `.world_settings`, false when the play-mode write
lock blocked the write.

**Parameters**

- `enabled` `boolean` — True = strict, false = off.

## modules/lsp/setStrictMode {#modules-lsp-setstrictmode}

```lua
setStrictMode(mode: StrictMode): boolean
```

Set the pre-execute strict gate's mode. Returns true when the
change was persisted to `.world_settings`, false when the
play-mode write lock blocked the write.

**Parameters**

- `mode` `StrictMode` — `"off"` | `"soft"` | `"strict"`.

## modules/lsp/summary {#modules-lsp-summary}

```lua
summary(): Summary
```

Counts only — does not re-run validation.

## modules/lsp/tools {#modules-lsp-tools}

```lua
tools(): { ToolEntry }
```

List every code-mode tool registered in the VFS under
`/zero/docs/tools/<category>/<tool>`.

## modules/lsp/typeOf {#modules-lsp-typeof}

```lua
typeOf(expr_source: string, context_path: string?): TypeDescriptor
```

Infer the static type of a Luau expression. When
`context_path` is given, the file is loaded and walked so the
inference env contains every local + alias in scope at its end.

**Parameters**

- `expr_source` `string` — Luau expression source (no surrounding chunk).
- `context_path` `string?` _(optional)_ — VFS path whose scope should be visible.

```lua
local td = lsp.typeOf("Transform.lookAt", "/zero/source/main.luau")
```

## modules/luau_coverage/README {#modules-luau-coverage-readme}

```lua
require("@builtin/modules/api/engine/luau_coverage") -- luau_coverage (also available as global 'luau_coverage')
```

Luau source-based coverage dump (LCOV + sources manifest). Public Luau surface over the `__luau_coverage` Internal FFI namespace.

Usage: local luau_coverage = require("@builtin/modules/api/engine/luau_coverage")
Also available as global: luau_coverage

## modules/luau_coverage/dump_lcov {#modules-luau-coverage-dump-lcov}

```lua
dump_lcov(path: string): DumpResult
```

Walk every Luau chunk loaded since the VM started (or since
the last `reset`), collect per-line hit counts via Luau's
built-in coverage API, render the aggregate as LCOV, and write
it to `path`. Also writes a sibling `luau_sources/` directory
next to the LCOV file containing one source file per tracked
chunk plus a `manifest.json` mapping chunk names to filenames
— used by the proxy `/ui/coverage` page for per-file source
drill-down. Raises a Luau error on failure.

**Parameters**

- `path` `string` — Absolute filesystem path to write the LCOV tracefile to.

```lua
local r = luau_coverage.dump_lcov("/tmp/luau.lcov")
```

## modules/luau_coverage/level {#modules-luau-coverage-level}

```lua
level(): number
```

The `coverageLevel` the Luau compiler was configured with
(1 = statement coverage, 2 = statement + expression). Returns 0
when coverage is off.

```lua
if luau_coverage.level() > 0 then ... end
```

## modules/luau_coverage/reset {#modules-luau-coverage-reset}

```lua
reset(): boolean
```

Drop every tracked chunk ref and clear the coverage
accumulator. The VM stops reporting hits for previously loaded
scripts — use before exercising a specific scenario to isolate
its coverage.

```lua
luau_coverage.reset()
```

## modules/luau_profile/README {#modules-luau-profile-readme}

```lua
require("@builtin/modules/api/engine/luau_profile") -- luau_profile (also available as global 'luau_profile')
```

Sampling profiler + manual regions for Luau scripts. Public Luau surface over the `__luau_profile` Internal FFI namespace.

Usage: local luau_profile = require("@builtin/modules/api/engine/luau_profile")
Also available as global: luau_profile

## modules/luau_profile/begin {#modules-luau-profile-begin}

```lua
begin(name: string): number
```

Open a named manual region. Returns an opaque integer id;
pass it back to `end_region(id)` to close and record elapsed
wall-clock under `name`.

**Parameters**

- `name` `string` — Region name; aggregated across opens.

```lua
local id = luau_profile.begin("walk"); ...; luau_profile.end_region(id)
```

## modules/luau_profile/dump {#modules-luau-profile-dump}

```lua
dump(path: string): DumpResult
```

Write the folded-stack dump to `path` on the HOST filesystem,
one line per stack as `<ticks> <stack_csv>` — the format
upstream Luau emits and `tools/perfgraph.py` consumes
unchanged. A path naming the engine filesystem (`/zero/...`, or
a bare root such as `/source/...`) is refused, and says so:
`luau_profile.folded()` with `vfs.write` puts the dump there.

**Parameters**

- `path` `string` — Absolute host filesystem path to write.

```lua
local r = luau_profile.dump("/tmp/profile.folded")
```

## modules/luau_profile/dump_regions {#modules-luau-profile-dump-regions}

```lua
dump_regions(path: string): DumpRegionsResult
```

Write per-region stats to `path` as JSON, on the HOST
filesystem. A path naming the engine filesystem is refused, the
same way `dump` refuses one.

**Parameters**

- `path` `string` — Absolute host filesystem path to write.

```lua
luau_profile.dump_regions("/tmp/regions.json")
```

## modules/luau_profile/end_region {#modules-luau-profile-end-region}

```lua
end_region(id: number)
```

Close a region previously opened by `begin(name)`. Records
elapsed wall-clock under the region's name. Silently no-ops on
unknown id (typically a double-close or swapped-out VM).

**Parameters**

- `id` `number` — Region id returned by `begin()`.

```lua
luau_profile.end_region(id)
```

## modules/luau_profile/folded {#modules-luau-profile-folded}

```lua
folded(): string
```

The folded-stack dump as a string, one line per stack as
`<ticks> <stack_csv>` — the format upstream Luau emits and
`tools/perfgraph.py` consumes unchanged. The same bytes `dump`
writes, handed back instead of written, so the profile can go
wherever the caller keeps it: `vfs.write` puts it in the engine
filesystem, where `bash` and `vfs.read` reach it.

```lua
vfs.write("/source/tmp/sample.folded", luau_profile.folded())
```

## modules/luau_profile/is_running {#modules-luau-profile-is-running}

```lua
is_running(): boolean
```

True iff the background sampler is currently running.

```lua
if luau_profile.is_running() then luau_profile.stop() end
```

## modules/luau_profile/reset {#modules-luau-profile-reset}

```lua
reset()
```

Clear every accumulated sample and region stat. The sampler
keeps running if it was already on; only the data is wiped.

```lua
luau_profile.reset()
```

## modules/luau_profile/sampling_available {#modules-luau-profile-sampling-available}

```lua
sampling_available(): boolean
```

True on platforms where the background sampler can run
(native targets), false on WASM. Manual regions work
everywhere — only the sampler is platform-gated.

```lua
if luau_profile.sampling_available() then luau_profile.start() end
```

## modules/luau_profile/snapshot {#modules-luau-profile-snapshot}

```lua
snapshot(top_n: number?): Snapshot
```

Snapshot the current accumulator without touching the
filesystem — cheap enough for per-frame UI polling. `top_n`
truncates `stacks` to the N hottest entries; omitting it
returns all stacks sorted descending by `self_us`. `regions`
is always returned in full (sorted by `total_us`).

**Parameters**

- `top_n` `number?` _(optional)_ — Truncate stacks to this many entries; omit for all.

```lua
local snap = luau_profile.snapshot(10)
```

## modules/luau_profile/span<T...> {#}

```lua
span<T...>(name: string, fn: () -> T..., ...): T...
```

Call `fn(...)` inside a manual region named `name`. The
region is closed even if `fn` raises (the call goes through
pcall internally). Returns whatever `fn` returned.

**Parameters**

- `name` `string` — Region name.
- `fn` `() -> T...` — Function to invoke with the trailing varargs.

```lua
local r = luau_profile.span("walk", function() return walk() end)
```

## modules/luau_profile/start {#modules-luau-profile-start}

```lua
start(hz: number?): StartResult
```

Start the background Luau sampling profiler at `hz` samples
per second (default 1000, clamped to `[1, 100000]`). Idempotent
— calling while already running is a no-op. Returns
`{ available, hz }` — `available = false` on WASM (no
std::thread). Manual regions work regardless.

**Parameters**

- `hz` `number?` _(optional)_ — Sampling rate in Hz.

```lua
luau_profile.start(500)
```

## modules/luau_profile/stop {#modules-luau-profile-stop}

```lua
stop()
```

Stop the background sampler. Blocks until the sampler thread
joins (typically <1ms). Safe when not running. Does not clear
the accumulator — call `reset()` to drop samples.

```lua
luau_profile.stop()
```

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

```lua
require("@builtin/modules/lut") -- lut
```

Colour lookup tables — the table a `lut` post-process effect reads. Builds one from a grading description, imports one a colourist exported as a `.cube` file or a strip image, samples it the way the shader does, and installs it as a `.texture` asset the effect can bind.

A LUT is an N-entry colour cube: the answer to "what does this colour
become" stored for N^3 input colours, with everything in between read by
trilinear interpolation. A grade of any complexity therefore costs the
same eight texel reads, which is why colourists deliver a look as a table
rather than as a chain of operations.
The engine stores a cube as a STRIP: N square tiles in one row, so the
image measures `N*N` wide by `N` tall. Tile `b` holds the plane of
constant blue index, red runs across a tile and green runs down it. The
`lut` post shader reads N from the image's own height, so one shader
serves a 16-, 32- or 64-entry cube with nothing to configure.
Apply one through the post chain:
  local lut = require("@builtin::modules.lut")
  local ref = lut.install("warm_evening", lut.fromGrade({
      exposure = 0.3, temperature = 0.25, saturation = 1.1,
  }))
  tools.use("pp", "add", "lut", { texture = ref.guid, amount = 1.0 })
A `lut` effect with no table bound passes the frame through untouched, so
adding the effect before its table exists changes nothing.

Usage: local lut = require("@builtin/modules/lut")

## modules/lut/build {#modules-lut-build}

```lua
build(size: number, fn: (number, number, number) -> (number, number, number)): Lut
```

Build a table by asking `fn` what each of its N^3 lattice colours
becomes. The input is the lattice colour in 0..1, and so is the answer,
which is clamped to that range and stored as it stands.

**Parameters**

- `size` `number` — Cube edge — how many entries each axis holds. 2..90.
- `fn` `(number, number, number) -> (number, number, number)` — `(r, g, b) -> r, g, b`, called once per lattice entry.

```lua
local invert = lut.build(16, function(r, g, b) return 1 - r, 1 - g, 1 - b end)
```

## modules/lut/fromCube {#modules-lut-fromcube}

```lua
fromCube(text: string): Lut
```

Read a table out of `.cube` text — the interchange format DaVinci
Resolve, Photoshop and every other grading tool writes. `LUT_3D_SIZE`
gives the cube edge and the rows that follow are its entries with red
varying fastest, which is the order this reader expects. The table is
addressed over 0..1, so a file declaring any other `DOMAIN_MIN` /
`DOMAIN_MAX` is refused by name rather than read as if it were.

**Parameters**

- `text` `string` — The file's contents.

```lua
local look = lut.fromCube(vfs.read("/source/looks/kodak2383.cube"))
```

## modules/lut/fromGrade {#modules-lut-fromgrade}

```lua
fromGrade(spec: GradeSpec?, size: number?): Lut
```

Bake a grade into a table. The same look as calling `lut.grade`'s
function per pixel, at the cost of eight texel reads however involved the
grade is.

**Parameters**

- `spec` `GradeSpec?` _(optional)_ — What the grade does — see `GradeSpec`.
- `size` `number?` _(optional)_ — Cube edge. Defaults to 16.

```lua
local look = lut.fromGrade({ contrast = 1.2, saturation = 0.85, lift = { 0.02, 0.02, 0.05 } })
```

## modules/lut/fromImage {#modules-lut-fromimage}

```lua
fromImage(bytes: buffer | string): Lut
```

Read a table out of a strip image laid out as `N*N` by `N` — what a
grading tool exports as a "2D LUT". Takes either source image bytes (PNG,
JPEG, WebP) or the `.texture` blob `lut.install` wrote, so a table can be
read back out of the asset it was installed as.

**Parameters**

- `bytes` `buffer | string` — The encoded image, or a `.texture` blob.

```lua
local look = lut.fromImage(vfs.readBytes("/source/looks/teal_orange.png"))
```

## modules/lut/grade {#modules-lut-grade}

```lua
grade(spec: GradeSpec?): (number, number, number) -> (number, number, number)
```

The colour transform a `GradeSpec` describes, as a plain function.
Useful on its own — to grade a single colour, to compose two looks, or to
hand to `lut.build` — and it is what `lut.fromGrade` bakes.

**Parameters**

- `spec` `GradeSpec?` _(optional)_ — What the grade does. Every field is optional.

**Returns** `(number, number, number)` — `(r, g, b) -> r, g, b` over 0..1.

```lua
local warm = lut.grade({ temperature = 0.3 }); local r, g, b = warm(0.5, 0.5, 0.5)
```

## modules/lut/identity {#modules-lut-identity}

```lua
identity(size: number?): Lut
```

The table that changes nothing — every entry answers with the colour
that indexed it. The starting point for a hand-authored look, and the
control an A/B measures against.

**Parameters**

- `size` `number?` _(optional)_ — Cube edge. Defaults to 16.

```lua
local base = lut.identity(32)
```

## modules/lut/install {#modules-lut-install}

```lua
install(name: string, table_: Lut, opts: { [string]: any }?): any
```

Write the table as a `.texture` asset the `lut` post effect can bind,
and upload it to the GPU under that asset's own guid. Stored as a float
raster, unfiltered and with no mip chain: a table's entries are addresses,
so they reach the shader as they were written, with no transfer function
between and no mip average to land on a colour the table holds nowhere.
The upload is what makes the returned guid bindable from the next frame,
and what puts a re-baked look in front of the camera under the name it
already had.

**Parameters**

- `name` `string` — The asset's name.
- `table_` `Lut` — The `Lut` to write.
- `opts` `{ [string]: any }?` _(optional)_ — `{ dest = "<vfs path>", folder = "<vfs folder>", overwrite = true }`
— placement, forwarded to `asset.create`. `overwrite` defaults to true, so
installing under a name that exists rewrites that asset and keeps its guid.

```lua
local ref = lut.install("dusk", lut.fromGrade({ temperature = -0.2 }))
```

## modules/lut/sample {#modules-lut-sample}

```lua
sample(table_: Lut, r: number, g: number, b: number): (number, number, number)
```

What the table answers for a colour — the same trilinear read the
shader performs, so a table can be checked without rendering a frame.

**Parameters**

- `table_` `Lut` — The `Lut` to read.
- `r` `number` — Red, 0..1. Values outside are clamped, as they are on the GPU.
- `g` `number` — Green, 0..1.
- `b` `number` — Blue, 0..1.

```lua
local r, g, b = lut.sample(look, 0.5, 0.5, 0.5)
```

## modules/lut/strip {#modules-lut-strip}

```lua
strip(table_: Lut): ({ number }, number, number)
```

The table's strip raster — the channel values, its width and its
height. What `renderer.texture.encode` and `asset.create("texture", ...)`
take at `rgba32f`.

**Parameters**

- `table_` `Lut` — The `Lut` to read.

```lua
local px, w, h = lut.strip(look); print(w, h)
```

## modules/lut/toCube {#modules-lut-tocube}

```lua
toCube(table_: Lut, title: string?): string
```

Write a table out as `.cube` text, so a look built here can be opened
in a grading tool or handed to another pipeline.

**Parameters**

- `table_` `Lut` — The `Lut` to write.
- `title` `string?` _(optional)_ — What the file calls itself. Defaults to "zero".

```lua
vfs.write("/source/looks/mine.cube", lut.toCube(look, "mine"))
```

## modules/materialGraph/README {#modules-materialgraph-readme}

```lua
materialGraph
```

## modules/materialGraph/check {#modules-materialgraph-check}

```lua
check(graph: Graph): (boolean, any)
```

Compile a graph without raising. The same work `compile` does, with the
error handed back rather than thrown — what an editor wants while the
author is still typing.

**Parameters**

- `graph` `Graph` — The graph to check.

```lua
local ok, result = materialGraph.check(graph)
```

## modules/materialGraph/compile {#modules-materialgraph-compile}

```lua
compile(graph: Graph, name: string?): Compiled
```

Compile a graph into the two files a `.shader` asset holds. Pure text
generation: it touches no asset, no renderer and no GPU, so a graph can be
checked, compared and tested with nothing installed.

**Parameters**

- `graph` `Graph` — The graph — `nodes`, `surface`, and optionally `name` + `properties`.
- `name` `string?` _(optional)_ — Overrides `graph.name` for the shader this compiles to.

```lua
local out = materialGraph.compile(graph)
print(out.wgsl)
```

## modules/materialGraph/install {#modules-materialgraph-install}

```lua
install(graph: Graph, opts: { name: string?, into: any? }?): Installed
```

Compile a graph and write it out as a real `.shader` asset. The result
is an ordinary shader asset — nothing keeps a link back to the graph, so it
can be read, hand-edited and shipped like any other. Installing the same
graph again rewrites the same asset. The shader itself is compiled at the
next frame boundary, the way any shader edit is;
`asset.ref(name, "shader"):compileStatus()` is what reports the outcome.

**Parameters**

- `graph` `Graph` — The graph to install.
- `opts` `{ name: string?, into: any? }?` _(optional)_ — `{ name = <shader name>, into = { path = <folder> } }`. `into` places
the asset as it is created; installing again writes wherever it already is,
and an `into` naming somewhere else is refused rather than ignored.

```lua
local shader = materialGraph.install(graph, { name = "rusty_metal" })
local status = asset.ref(shader.name, "shader"):compileStatus()
```

## modules/materialGraph/material {#modules-materialgraph-material}

```lua
material(graph: Graph, opts: { name: string?, shader: string?, into: any?, values: any? }?): string
```

Install a graph and make a material wearing the shader it compiled to.
The material is an ordinary material asset: hand it to a Model's `material`
field, or edit its values afterwards like any other. Calling it again with
the same material name is how an author iterates: the shader is rewritten
from the graph, the material is brought onto that shader's property list,
and `values` is applied over it — so what the call says is what the
material holds when it returns.

**Parameters**

- `graph` `Graph` — The graph to install.
- `opts` `{ name: string?, shader: string?, into: any?, values: any? }?` _(optional)_ — `{ name = <material name>, shader = <shader name>, into = ..., values = { <property> = <value> } }`.

```lua
local mat = materialGraph.material(graph, { name = "rusty", values = { wear = 0.8 } })
```

## modules/materialGraph/nodeTypes {#modules-materialgraph-nodetypes}

```lua
nodeTypes(): { [string]: { ports: { string }, required: { string }, result: string, doc: string } }
```

Every node operation this compiler knows: the inputs a node of that op
is written with, which of them it cannot be written without, the type it
produces and a line on what it does. A graph written from this listing
compiles.

```lua
for op, info in pairs(materialGraph.nodeTypes()) do print(op, info.doc) end
print(table.concat(materialGraph.nodeTypes().sampleTexture.required, ", "))
```

## modules/materialGraph/surfaceChannels {#modules-materialgraph-surfacechannels}

```lua
surfaceChannels(): { [string]: { field: string, ty: string } }
```

The channels the `surface` terminal accepts, and the shading-model field
each one drives.

```lua
print(materialGraph.surfaceChannels().roughness.field)
```

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

```lua
require("@builtin/modules/api/engine/mathx") -- mathx (also available as global 'mathx')
```

Batch math kernels over buffer slices (damp, lerp/slerp, transform). Public Luau surface over the `__mathx` Internal FFI namespace.

Usage: local mathx = require("@builtin/modules/api/engine/mathx")
Also available as global: mathx

## modules/mathx/addScaledVec3 {#modules-mathx-addscaledvec3}

```lua
addScaledVec3(dstBuffer: Substrate.TypedBuffer, srcBuffer: Substrate.TypedBuffer,
```

`dst[i] += src[i] * scale` for `count` vec3 elements. Both
buffers must hold at least `count * 3` floats. Useful for
particle integration (position += velocity * dt) and accumulator
passes.

```lua
mathx.addScaledVec3(positions, velocities, n, dt)
```

## modules/mathx/dampScalar {#modules-mathx-dampscalar}

```lua
dampScalar(buffer: Substrate.TypedBuffer, offset: number, count: number,
```

Critically-damped exponential approach toward `target` for
`count` scalars at `buffer[offset .. offset+count]`. `smoothTime`
is the time constant (~ 0.16 ⇒ ~63% per frame at 60 Hz). Pass
`smoothTime <= 0` to snap to the target.

```lua
mathx.dampScalar(buf, 0, 16, 0.0, 0.16, dt)
```

## modules/mathx/lerpVec3 {#modules-mathx-lerpvec3}

```lua
lerpVec3(buffer: Substrate.TypedBuffer, offset: number, count: number,
```

Element-wise linear blend of `count` vec3s in
`buffer[offset .. offset+count*3]` toward `(tx, ty, tz)` by `t`.

```lua
mathx.lerpVec3(buf, 0, n, 0, 1, 0, 0.5)
```

## modules/mathx/normalizeQuat {#modules-mathx-normalizequat}

```lua
normalizeQuat(buffer: Substrate.TypedBuffer, offset: number, count: number): boolean
```

Re-normalise `count` quaternions in place. Zero-length quats
become identity (0, 0, 0, 1) so downstream code never sees NaN.

**Parameters**

- `buffer` `Substrate.TypedBuffer` — The buffer to operate on.
- `offset` `number` — Starting f32 index.
- `count` `number` — Number of quaternions.

```lua
mathx.normalizeQuat(buf, 0, n)
```

## modules/mathx/slerpQuat {#modules-mathx-slerpquat}

```lua
slerpQuat(buffer: Substrate.TypedBuffer, offset: number, count: number,
```

Slerp `count` quaternions (xyzw) at `buffer[offset..]` toward
`(tx, ty, tz, tw)` by `t`. Falls back to nlerp+normalize for
very-close quats. Always picks the shortest-arc path.

```lua
mathx.slerpQuat(buf, 0, n, 0, 0, 0, 1, 0.25)
```

## modules/mathx/transformVec3 {#modules-mathx-transformvec3}

```lua
transformVec3(buffer: Substrate.TypedBuffer, offset: number,
```

Treat each vec3 in `buffer[offset..]` as a position (w = 1),
multiply by the 4x4 column-major matrix `mat16` (16-element
array), write `.xyz` of the result back. Layout matches glam,
wgpu, and GLSL conventions.

```lua
mathx.transformVec3(positions, 0, n, worldMatrix)
```

## modules/mcpLog/README {#modules-mcplog-readme}

```lua
require("@builtin/modules/api/engine/mcpLog") -- mcpLog (also available as global 'mcpLog')
```

Read-only MCP tool-call log ring buffer. Public Luau surface over the `__mcpLog` Internal FFI namespace.

Usage: local mcpLog = require("@builtin/modules/api/engine/mcpLog")
Also available as global: mcpLog

## modules/mcpLog/clear {#modules-mcplog-clear}

```lua
clear(): boolean
```

Clear all entries from the engine's MCP log ring buffer.

```lua
mcpLog.clear()
```

## modules/mcpLog/query {#modules-mcplog-query}

```lua
query(limit: number?): { McpLogEntry }
```

Return the most-recent MCP tool-call entries from the engine's
MCP log ring buffer (newest last). Pass `limit` to cap how many
entries are returned — omit for the full ring (up to 500 entries).

**Parameters**

- `limit` `number?` _(optional)_ — Maximum number of entries to return.

```lua
for _, e in ipairs(mcpLog.query(50)) do print(e.tool_name, e.status) end
```

## modules/mediaTransmittance/README {#modules-mediatransmittance-readme}

```lua
require("@builtin/systems/volumetrics/mediaTransmittance") -- mediaTransmittance
```

Light attenuation through participating media, in a form both media and surfaces can sample. A fog bank dims what is behind it, and overlapping volumes stack.

Usage: local mediaTransmittance = require("@builtin/systems/volumetrics/mediaTransmittance")

## modules/mediaTransmittance/active {#modules-mediatransmittance-active}

```lua
active(): boolean
```

Whether the transmittance passes are running this frame.

```lua
if mediaTransmittance.active() then ... end
```

## modules/mediaTransmittance/buffers {#modules-mediatransmittance-buffers}

```lua
buffers(): { [string]: any }?
```

The buffer(s) this system's passes read. A pass binds what this hands
it, so it has the values this module packed.

```lua
local b = <module>.buffers()
```

## modules/mediaTransmittance/clear {#modules-mediatransmittance-clear}

```lua
clear()
```

Remove every medium and release the passes. The settings are kept.

```lua
mediaTransmittance.clear()
```

## modules/mediaTransmittance/get {#modules-mediatransmittance-get}

```lua
get(): State
```

The transmittance settings currently in force.

```lua
local s = mediaTransmittance.get().strength
```

## modules/mediaTransmittance/removeMedium {#modules-mediatransmittance-removemedium}

```lua
removeMedium(key: string): number
```

Remove a registered medium.

**Parameters**

- `key` `string` — The id it was registered under.

```lua
mediaTransmittance.removeMedium("bank")
```

## modules/mediaTransmittance/set {#modules-mediatransmittance-set}

```lua
set(opts: TransmittanceOpts?): State
```

Set the scene-wide transmittance settings. Any omitted field keeps its
current value.

**Parameters**

- `opts` `TransmittanceOpts?` _(optional)_ — Settings — see `TransmittanceOpts`.

```lua
mediaTransmittance.set({ sunDirection = { 0.4, 0.8, 0.2 }, steps = 32 })
```

## modules/mediaTransmittance/setMedium {#modules-mediatransmittance-setmedium}

```lua
setMedium(key: string, opts: MediumOpts): number
```

Register (or move) a medium. Pushing the same key again replaces it.

**Parameters**

- `key` `string` — A stable id for this medium.
- `opts` `MediumOpts` — Placement and density — see `MediumOpts`.

```lua
mediaTransmittance.setMedium("bank", { position = { 0, 8, 0 }, size = { 20, 6, 20 }, density = 0.12 })
```

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

```lua
require("@builtin/modules/api/engine/microphone") -- microphone (also available as global 'microphone')
```

Capture from an input device and read what is arriving: a loudness, a magnitude spectrum, and the raw PCM. Public Luau surface over the `__microphone` Internal FFI namespace.

Usage: local microphone = require("@builtin/modules/api/engine/microphone")
Also available as global: microphone

## modules/microphone/awaitRunning {#modules-microphone-awaitrunning}

```lua
awaitRunning(timeout: number?): (MicState, string?)
```

Wait until the capture settles out of `starting` and
`permissionPending`, and report where it landed. Returns as soon as the
state settles, or when `timeout` seconds have passed, whichever comes
first — a browser permission prompt nobody answers never settles, so
the wait is always bounded.

**Parameters**

- `timeout` `number?` _(optional)_ — Seconds to wait at most. Defaults to 10.

```lua
microphone.start(); local state, why = microphone.awaitRunning()
```

## modules/microphone/devices {#modules-microphone-devices}

```lua
devices(): { MicDevice }
```

Every input device the platform offers. `id` is what
`microphone.start` takes to select one and is stable across reboots
where the platform provides a stable identifier; `name` is the label a
person recognises.

An empty list is a legitimate answer, not a failure: a machine with no
input hardware offers none, and a browser names none until microphone
access has been granted at least once — the labels are part of what the
permission protects.

```lua
for _, d in ipairs(microphone.devices()) do print(d.name, d.default) end
```

## modules/microphone/frequencies {#modules-microphone-frequencies}

```lua
frequencies(): { number }
```

The frequency each spectrum bin is centred on, in Hz, as an array
parallel to `microphone.spectrum()`. Derived from the capture's rate and
transform size, so it changes only when a capture is started with
different ones. Empty while no capture is running.

```lua
local hz = microphone.frequencies(); print(hz[#hz]) -- the Nyquist frequency
```

## modules/microphone/level {#modules-microphone-level}

```lua
level(): number
```

Loudness of the most recent analysis window, as an RMS amplitude in
0..1. A full-scale sine reads about 0.707 and silence reads 0.

Measured over only the samples that have arrived, so a capture that has
just started reports the loudness of what it holds rather than a level
diluted by a window it has not filled yet. 0 while no capture is
running.

```lua
if microphone.level() > 0.05 then print("someone is talking") end
```

## modules/microphone/peak {#modules-microphone-peak}

```lua
peak(): { [string]: number }?
```

The bin carrying the most energy and what it says: the frequency it
is centred on, its amplitude, and the loudness of the whole window.
A capture reading silence answers with amplitude 0 at bin 1.

```lua
local p = microphone.peak(); if p and p.amplitude > 0.05 then print(p.hz) end
```

## modules/microphone/samples {#modules-microphone-samples}

```lua
samples(max: number?): buffer?
```

Captured mono PCM no caller has taken yet, oldest sample first, as a
buffer of little-endian f32 read with `buffer.readf32`. The samples are
removed, so successive calls walk forward through the capture and a
caller doing its own analysis sees every frame once.

nil while no capture is running, and a zero-length buffer when the
capture is running and nothing new has arrived. Samples nobody takes
are discarded once the queue fills, and `status().overruns` counts
every one.

**Parameters**

- `max` `number?` _(optional)_ — How many samples to take at most. Omitted, everything held comes back.

```lua
local pcm = microphone.samples(); if pcm then print(buffer.len(pcm) // 4) end
```

## modules/microphone/spectrum {#modules-microphone-spectrum}

```lua
spectrum(): { number }
```

Amplitude per frequency bin over the most recent analysis window:
`fftSize / 2 + 1` numbers, DC at index 1 through the Nyquist frequency
at the last. Bin `i` covers `(i - 1) * status().binHz` Hz.

Each value is an amplitude estimate rather than a raw transform
magnitude, so a full-scale tone sitting on a bin centre reads about 1.0
and the numbers stay comparable across transform sizes.

The window is multiplied by a **Hann** taper before the transform. An
untapered window ends abruptly at both edges and the transform reads
that as energy spread across every bin, smearing one tone into a skirt
that buries quieter tones beside it. Hann trades a slightly wider main
lobe — a tone occupies about three bins rather than one — for sidelobes
that fall away steeply, which is what lets neighbouring tones be told
apart. Read a peak as "a tone near here", not "a tone exactly here".

Reading this takes no samples away from `microphone.samples()`. Empty
while no capture is running.

```lua
local bins = microphone.spectrum(); print(#bins, bins[1])
```

## modules/microphone/start {#modules-microphone-start}

```lua
start(opts: MicOpts?): (MicState?, string?)
```

Open an input device and begin capturing. Returns the state the
capture reached — `"running"` once a device is delivering, or
`"permissionPending"` where the platform must ask for access first,
which is the browser's normal path. Poll `microphone.status()` from
there, or use `microphone.awaitRunning()`.

A request that cannot be made at all returns nil and the reason: an
`fftSize` that is not a whole power of two between 64 and 16384, a
device no machine here offers, a rate the device does not capture at,
or a capture that is already running.

Omitting `device` opens the platform default. Omitting `sampleRate`
takes the device's own rate, which is what avoids a resample.
`fftSize` is how many samples one analysis window covers and defaults
to 1024 — at 48 kHz that spans ~21 ms and resolves ~47 Hz per bin.

**Parameters**

- `opts` `MicOpts?` _(optional)_ — `{ device, sampleRate, fftSize }`.

```lua
local state, why = microphone.start({ fftSize = 2048 })
```

## modules/microphone/status {#modules-microphone-status}

```lua
status(): MicStatus
```

Where the capture stands.

`reason` carries the platform's own message: the refusal for `denied`,
the device's message for `failed`, what is being waited on for
`permissionPending`. `binHz` is the width of one spectrum bin and
`bins` how many `microphone.spectrum()` returns.

`framesCaptured` counts every mono frame the device delivered whether
or not anything drained it, so a silent room reads differently from a
stalled device. `overruns` counts samples discarded because a consumer
did not keep up — it standing still is what says the readings are
continuous, and it climbing is why a caller sees gaps.

```lua
local s = microphone.status(); print(s.state, s.framesCaptured, s.overruns)
```

## modules/microphone/stop {#modules-microphone-stop}

```lua
stop(): boolean
```

Stop the capture and release the device. True when a capture was
open or being opened at call time. The device is let go before this
returns, so a stop followed by a start opens it again rather than
finding it held.

```lua
microphone.stop()
```

## modules/modelImport/README {#modules-modelimport-readme}

```lua
require("@builtin/modules/api/engine/modelImport") -- modelImport (also available as global 'modelImport')
```

The model-import pipeline: decompose any assimp-supported 3D model (fbx, obj, dae, gltf, glb, stl, ply, 3ds, …) into meshes, materials, textures, animation clips and a node graph; extract a single clip to its `.zanim` payload; and derive a `.rig` from a skinned mesh or from an animation-only file's driven skeleton. Public Luau surface over the `__model` and `__rig` Internal FFI namespaces.

Usage: local modelImport = require("@builtin/modules/api/engine/modelImport")
Also available as global: modelImport

## modules/modelImport/decompose {#modules-modelimport-decompose}

```lua
decompose(bytes: buffer | string, format: string): string
```

Parse raw model bytes on a background thread. `format` is the real source
extension (`"fbx"`, `"obj"`, `"dae"`, `"gltf"`, `"glb"`, `"stl"`, `"ply"`,
`"3ds"`, …), forwarded to assimp as the format hint. Returns a promise
handle: `task.await` it, then read the data with `result(handle)`.

**Parameters**

- `bytes` `buffer | string` — Raw model file bytes (from `vfs.readAsync`).
- `format` `string` — The source file extension (lowercase, no dot).

```lua
local h = modelImport.decompose(bytes, "obj"); task.await(h)
```

## modules/modelImport/decomposeFiles {#modules-modelimport-decomposefiles}

```lua
decomposeFiles(files: { ModelFile }, mainName: string): string
```

Parse a model plus its companion files on a background thread, so assimp
resolves the model's external references (a `.gltf`'s external `.bin` and
image files, an `.obj`'s `.mtl` colors/textures, MD5's `.md5anim`, …).
`files` is an array of `{ name = basename, bytes = <bytes> }` that MUST
include the model file itself; `mainName` is that file's basename. Returns a
promise handle: `task.await` it, then read the data with `result(handle)` —
the same shape `decompose` produces.

**Parameters**

- `files` `{ ModelFile }` — Array of `{ name, bytes }`: the model file plus its companions.
- `mainName` `string` — Basename of the model file to import (one of `files`' names).

```lua
local h = modelImport.decomposeFiles(files, "CesiumMilkTruck.gltf"); task.await(h)
```

## modules/modelImport/extractAnimation {#modules-modelimport-extractanimation}

```lua
extractAnimation(sourcePath: string, clipName: string): string
```

Read a model source file and extract one animation clip to its `.zanim`
payload, stashed for retrieval. The source extension decides the parser, so
this is format-agnostic. Returns a promise handle: `task.await` it, then
`extractAnimationResult(handle)` returns the bytes.

**Parameters**

- `sourcePath` `string` — VFS path to the source model file.
- `clipName` `string` — Clip name as returned by `result(handle).animations[i].name`.

## modules/modelImport/extractAnimationResult {#modules-modelimport-extractanimationresult}

```lua
extractAnimationResult(handle: string): string?
```

After awaiting an `extractAnimation` handle, return the extracted
`.zanim` bytes (binary-safe), consuming them. The bytes to hand to
`asset.create("animation", name, { bytes })`. Returns nil on failure or if
already taken.

**Parameters**

- `handle` `string` — Promise handle from `extractAnimation`.

## modules/modelImport/result {#modules-modelimport-result}

```lua
result(handle: string): any?
```

Read the decomposed model after `decompose`'s handle has been awaited.
Every format decomposes into the same shape, so this is format-agnostic.
Runs on the main thread; consumes the stored result.

**Parameters**

- `handle` `string` — Promise handle from `decompose`.

## modules/modelImport/retryHandle {#modules-modelimport-retryhandle}

```lua
retryHandle(makeHandle: () -> any, retries: number?, yield: (() -> ())?): string?
```

Call `makeHandle` — which returns a promise-handle string, or a falsy
value on a transient failure (e.g. a source read that raced a pending
write during a parallel import) — up to `retries + 1` times, yielding via
`yield` between attempts so a pending write can land before the next try.
Returns the handle string once one is produced, or nil when every attempt
failed. Callers `task.await` the result only when it is non-nil, so a
transient miss never reaches `task.await` as a non-string.

**Parameters**

- `makeHandle` `() -> any` — Returns a promise-handle string, or a falsy value on failure.
- `retries` `number?` _(optional)_ — Extra attempts after the first (default 3).
- `yield` `(() -> ())?` _(optional)_ — Called between attempts (default `task.wait`).

## modules/modelImport/rigFromMeshSkin {#modules-modelimport-rigfrommeshskin}

```lua
rigFromMeshSkin(meshBytes: buffer | string): string?
```

Lift the skeleton out of a skinned `.mesh` (ZMSH) payload and return it
as a `.rig` JSON document: bones (hierarchy, rest pose, inverse-bind), the
auto-derived humanoid profile, and the humanoid classification. The source
rig a skinned mesh's clips retarget through. Returns nil when the bytes are
not a mesh or carry no skin.

**Parameters**

- `meshBytes` `buffer | string` — Raw ZMSH mesh bytes carrying a skin.

## modules/modelImport/rigFromSkeleton {#modules-modelimport-rigfromskeleton}

```lua
rigFromSkeleton(skeleton: AnimationSkeleton): string?
```

Build a `.rig` JSON document from the skeleton an animation-only file was
authored on — `result(handle).skeleton`, the bones its clips drive with
their local rest transforms. Forward kinematics over the locals resolves
globals + inverse-bind; the humanoid profile + classification are derived as
for `rigFromMeshSkin`. The source rig a standalone clip retargets through.
Returns nil on malformed input.

**Parameters**

- `skeleton` `AnimationSkeleton` — `{ names, parents, locals }` (a `decompose` result's `skeleton`).

```lua
local rigJson = modelImport.rigFromSkeleton(data.skeleton)
```

## modules/motionBlur/README {#modules-motionblur-readme}

```lua
require("@builtin/systems/motionBlur/motionBlur") -- motionBlur
```

Camera-shutter motion blur. Blur length comes from a shutter angle, and the reconstruction lets a moving object smear past its own silhouette instead of stopping dead at its edge.

Usage: local motionBlur = require("@builtin/systems/motionBlur/motionBlur")

## modules/motionBlur/active {#modules-motionblur-active}

```lua
active(): boolean
```

Whether the motion-blur passes are running this frame.

```lua
if motionBlur.active() then ... end
```

## modules/motionBlur/buffers {#modules-motionblur-buffers}

```lua
buffers(): { [string]: any }?
```

The parameter buffer the motion-blur passes read, carrying the settings
this module packs. The render feature binds what this hands it.

```lua
local b = motionBlur.buffers()
```

## modules/motionBlur/clear {#modules-motionblur-clear}

```lua
clear()
```

Close the shutter and release the passes. The other settings are kept,
so a later `set({ shutterAngle = ... })` brings back the same look.

```lua
motionBlur.clear()
```

## modules/motionBlur/get {#modules-motionblur-get}

```lua
get(): MotionBlurState
```

The shutter settings currently in force.

```lua
local a = motionBlur.get().shutterAngle
```

## modules/motionBlur/set {#modules-motionblur-set}

```lua
set(opts: MotionBlurOpts?): MotionBlurState
```

Set the camera's shutter. Any omitted field keeps its current value. A
`shutterAngle` of 0 closes the shutter and releases the passes.

**Parameters**

- `opts` `MotionBlurOpts?` _(optional)_ — Shutter settings — see `MotionBlurOpts`.

```lua
motionBlur.set({ shutterAngle = 180, samples = 16 })
```

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

```lua
require("@builtin/modules/api/engine/multiplayer") -- multiplayer (also available as global 'multiplayer')
```

Multiplayer sync state and operations — connection, peers, ownership, rooms, undo/redo. Public Luau surface over the `__multiplayer` Internal FFI namespace.

Usage: local multiplayer = require("@builtin/modules/api/engine/multiplayer")
Also available as global: multiplayer

## modules/multiplayer/beginOperation {#modules-multiplayer-beginoperation}

```lua
beginOperation(description: string)
```

Begin recording an undoable operation. All mutations until
`commitOperation()` are grouped into one undo entry.

**Parameters**

- `description` `string` — Human-readable label.

```lua
multiplayer.beginOperation("move cube")
```

## modules/multiplayer/canRedo {#modules-multiplayer-canredo}

```lua
canRedo(): boolean
```

Check if this client has any redoable operations.

## modules/multiplayer/canUndo {#modules-multiplayer-canundo}

```lua
canUndo(): boolean
```

Check if this client has any undoable operations.

## modules/multiplayer/cancelOperation {#modules-multiplayer-canceloperation}

```lua
cancelOperation()
```

Cancel the current operation and restore all properties to
their values at begin time.

```lua
multiplayer.cancelOperation()
```

## modules/multiplayer/claimOwnership {#modules-multiplayer-claimownership}

```lua
claimOwnership(entityId: (string | entityRef)?): boolean
```

Request ownership of an entity. Returns true if the claim
was tentatively granted (relay confirmation pending).

**Parameters**

- `entityId` `(string | entityRef)?` _(optional)_ — Entity id or proxy to claim.

## modules/multiplayer/clearHistory {#modules-multiplayer-clearhistory}

```lua
clearHistory()
```

Drop this client's whole undo/redo history — for boundaries where
old edits stop being meaningful (a scene load, a test rig reset).

```lua
multiplayer.clearHistory()
```

## modules/multiplayer/commitOperation {#modules-multiplayer-commitoperation}

```lua
commitOperation()
```

Finalize the current operation and push it onto the undo
stack. Only changes that actually differ from the start state
are recorded.

```lua
multiplayer.commitOperation()
```

## modules/multiplayer/connect {#modules-multiplayer-connect}

```lua
connect(relayUrl: string)
```

Connect to a multiplayer relay server for the current world.
Uses the loaded world's `world_id` as the room prefix for scene
isolation. A world must be loaded before connecting.

**Parameters**

- `relayUrl` `string` — Relay server URL.

```lua
multiplayer.connect("https://relay.example.com")
```

## modules/multiplayer/disconnect {#modules-multiplayer-disconnect}

```lua
disconnect()
```

Disconnect from the multiplayer relay server.

```lua
multiplayer.disconnect()
```

## modules/multiplayer/explain {#modules-multiplayer-explain}

```lua
explain(
```

Why a synced property is not reaching the peers this client shares
its entity's room with. Answers from the engine's own registry, so a
name the component never registered is reported as such instead of
inferred from a second client's silence.

```lua
local v = multiplayer.explain(player, "Health", "hp")
if not v.arriving then print(v.reason) end
```

## modules/multiplayer/getDiagnostics {#modules-multiplayer-getdiagnostics}

```lua
getDiagnostics(): SyncDiagnostics
```

Get sync diagnostics — traffic counts, bandwidth, link quality,
peer count. The counts — `bytesSent/Received`,
`datagramsSent/Received`, `rpcsSent/Received`, `ownershipChanges` —
are running totals for the session, so a sparse event stays readable
long after it happened; subtract two samples for the rate over the
interval between them. `bytesSentPerSec` / `bytesReceivedPerSec` are
averages over the last completed ~1 second window.
`rttMs` is the smoothed round-trip time to the relay and
`packetLoss` the fraction (0..1) of packets lost over the last 5
seconds; both read 0 until the transport has sampled a live
connection. `messagesAwaitingEntity` counts the sync messages this
peer is holding for an entity it has not received yet — each waits
for the spawn that names it, applies the moment it arrives, and is
released once its wait runs out.

```lua
local d = multiplayer.getDiagnostics()
if d.packetLoss > 0.05 then warnThePlayer(d.rttMs) end
print(d.messagesAwaitingEntity .. " message(s) waiting for their entity")
```

## modules/multiplayer/getPeerId {#modules-multiplayer-getpeerid}

```lua
getPeerId(): number?
```

Get this client's peer ID in the current session.

## modules/multiplayer/getPeers {#modules-multiplayer-getpeers}

```lua
getPeers(): { PeerInfo }
```

Get a list of all connected peers in the current session.

```lua
for _, p in ipairs(multiplayer.getPeers()) do print(p.name) end
```

## modules/multiplayer/getRoomPeers {#modules-multiplayer-getroompeers}

```lua
getRoomPeers(roomKey: string): { PeerInfo }
```

Get the peers this client shares the given room with, ordered by
peer id. `getPeers` answers for the whole session — the union of every
room this client is in — while this answers for one room, so a peer
that leaves this room while staying in another disappears from here
and remains in `getPeers`.

**Parameters**

- `roomKey` `string` — Fully-qualified room key
(`{worldGuid}/{profile}/{mode}/{sceneGuid}`).

```lua
for _, p in ipairs(multiplayer.getRoomPeers(key)) do print(p.id) end
```

## modules/multiplayer/getRooms {#modules-multiplayer-getrooms}

```lua
getRooms(): { string }
```

The relay rooms this client has joined, sorted. A broadcast reaches
only the peers that share one of these.

```lua
for _, key in ipairs(multiplayer.getRooms()) do print(key) end
```

## modules/multiplayer/getTickRate {#modules-multiplayer-gettickrate}

```lua
getTickRate(): number
```

Get the current sync tick rate (network updates per second).

## modules/multiplayer/heldMessages {#modules-multiplayer-heldmessages}

```lua
heldMessages(): { HeldMessage }
```

The sync messages this peer is holding for entities it has not
received — what `getDiagnostics().messagesAwaitingEntity` counts, one
entry each, with the entity sync id it names, its age and the grace it
is held against.

```lua
for _, m in ipairs(multiplayer.heldMessages()) do print(m.kind, m.ageMs) end
```

## modules/multiplayer/isConnected {#modules-multiplayer-isconnected}

```lua
isConnected(): boolean
```

Check if a multiplayer session is active and connected to a
relay.

## modules/multiplayer/isHost {#modules-multiplayer-ishost}

```lua
isHost(): boolean
```

Whether THIS client is the host (authoritative owner) of the
current scene's play room — the relay room CREATOR, or offline /
single-player. Host code spawns the shared synced world (via
`entity.spawnSynced` or a scene's `onHostLoad`) and runs authoritative
simulation; a non-host (JOINER) receives that content from the relay
snapshot and must NOT re-create it. Gate ANY code that spawns synced
entities or owns shared state with this so it runs on exactly one
client — running it on every peer is the double-spawn 'explosion'.

```lua
if multiplayer.isHost() then enemy = entity.spawnSynced("enemy") end
```

## modules/multiplayer/isOwner {#modules-multiplayer-isowner}

```lua
isOwner(entityId: (string | entityRef)?): boolean
```

Check if the local client owns the given entity (or the
current entity if called from a component). Only the owner can
modify synced properties directly.

**Parameters**

- `entityId` `(string | entityRef)?` _(optional)_ — Entity id or proxy to check (defaults to `self.entityId`
in component context).

## modules/multiplayer/isRoomCreator {#modules-multiplayer-isroomcreator}

```lua
isRoomCreator(roomKey: string): boolean?
```

Whether this client created the given room — it was the FIRST peer
to join it (race-free; the relay assigns it on join). In play mode the
creator instantiates the scene's entities (synced) and every other
joiner receives them from the relay snapshot, so the scene is never
double-instantiated.

**Parameters**

- `roomKey` `string` — Fully-qualified room key
(`{worldGuid}/{profile}/{mode}/{sceneGuid}`).

```lua
if multiplayer.isRoomCreator(key) ~= false then layers.load(scene) end
```

## modules/multiplayer/joinRoom {#modules-multiplayer-joinroom}

```lua
joinRoom(roomKey: string)
```

Join a relay room. Room keys are built as
`{worldGuid}/{profile}/{mode}/{sceneGuid}` — four segments, the
`{profile}` one keeping a runtime peer (published content) and an
editor peer (live content) in separate rooms even when both are in
play mode. Rooms partition the relay's fan-out: only peers in the
same room receive each other's broadcasts. `getRooms()` reports the
keys this client is already in and `roomFor(entity)` the one an
entity broadcasts into, so a key can be read rather than rebuilt.
No-op when not connected or already joined.

**Parameters**

- `roomKey` `string` — Fully-qualified room key.

```lua
multiplayer.joinRoom(worldGuid .. "/" .. engine.profile .. "/play/" .. sceneGuid)
```

## modules/multiplayer/leaveRoom {#modules-multiplayer-leaveroom}

```lua
leaveRoom(roomKey: string)
```

Leave a relay room. The key is reported under
`observe().withdrawnRooms` until `joinRoom` names it again. No-op
when not connected or not joined.

**Parameters**

- `roomKey` `string` — Fully-qualified room key.

## modules/multiplayer/loopback {#modules-multiplayer-loopback}

```lua
loopback(): { [string]: any }
```

Loopback testing harness. Returns a table with `enable()`,
`disable()`, `flush()`, `receive()` methods for testing sync
without a relay server.

## modules/multiplayer/observe {#modules-multiplayer-observe}

```lua
observe(): ReplicationObservation
```

Report what this peer is replicating and why a property is not
arriving. Carries the rooms this client joined, one record per entity
with a sync id — its owner, the room it broadcasts into, how many
other peers share that room, and every REGISTERED synced component
with its declared property names, wire indices, public/private table
and dirty bits — the messages held for entities that have not arrived,
and the registry's totals. Every property carries `notArriving`: one
name from `reasons`, or nil when it is on its way. Answers in edit
mode as well as play mode, for what the relay carries in each: in
edit mode scene content is left out of the sync-id pass, so its
changes travel to the other clients with the source they are
written into and it reads `entityNotSynced` here.

```lua
local o = multiplayer.observe()
print(#o.entities .. " entities, " .. o.totals.properties .. " synced properties")
```

## modules/multiplayer/observeComponent {#modules-multiplayer-observecomponent}

```lua
observeComponent(
```

The registered synced component of the named type on an entity's
record. Matches a fully-qualified type (`@builtin::components.Model`)
and the leaf name it ends in (`Model`) alike.

```lua
local c = multiplayer.observeComponent(player, "Health")
print(#c.properties .. " declared properties")
```

## modules/multiplayer/observeEntity {#modules-multiplayer-observeentity}

```lua
observeEntity(entityId: (string | entityRef)): EntityReplication?
```

The replication record for one entity — its sync id, owner, room,
and the synced components registered on it.

**Parameters**

- `entityId` `(string | entityRef)` — Entity id or proxy.

```lua
local r = multiplayer.observeEntity(e)
for _, c in ipairs(r.components) do print(c.componentType) end
```

## modules/multiplayer/on {#modules-multiplayer-on}

```lua
on(channel: string, callback: (number, ...any) -> ())
```

Subscribe to a custom message channel. The callback runs as
`callback(fromPeerId, ...args)` whenever another peer calls
`multiplayer.send(channel, ...)`. Multiple callbacks per channel fire
in registration order.

**Parameters**

- `channel` `string` — Channel name to listen on.
- `callback` `(number, ...any) -> ()` — `function(fromPeerId: number, ...)` — the sender's peer id then the sent args.

## modules/multiplayer/recordSpawn {#modules-multiplayer-recordspawn}

```lua
recordSpawn(entityId: string)
```

Adopt an existing entity into the open operation as its spawn —
for flows that create an entity before the operation opens (a drag
preview adopted on drop). Undoing the operation despawns it.

**Parameters**

- `entityId` `string` — Entity id to record as spawned by this operation.

```lua
multiplayer.recordSpawn(id)
```

## modules/multiplayer/redo {#modules-multiplayer-redo}

```lua
redo(): boolean
```

Redo this client's last undone operation.

## modules/multiplayer/releaseOwnership {#modules-multiplayer-releaseownership}

```lua
releaseOwnership(entityId: (string | entityRef)?): boolean
```

Release ownership of an entity.

**Parameters**

- `entityId` `(string | entityRef)?` _(optional)_ — Entity id or proxy to release.

## modules/multiplayer/roomFor {#modules-multiplayer-roomfor}

```lua
roomFor(entityId: (string | entityRef)): string?
```

The room key an entity's spawns and property deltas broadcast into.

**Parameters**

- `entityId` `(string | entityRef)` — Entity id or proxy.

```lua
local key = multiplayer.roomFor(player)
if key then multiplayer.joinRoom(key) end
```

## modules/multiplayer/send {#modules-multiplayer-send}

```lua
send(channel: string, ...: any)
```

Broadcast a message on a named channel to every OTHER peer in the
room. The relay forwards it transparently; peers receive it via
`multiplayer.on`. Arguments may be any synced value (nil, boolean,
number, string, Vec3, entity/component proxy, or table) and are
delivered to listeners in order. No-op when not connected.

**Parameters**

- `channel` `string` — Channel name listeners subscribe to via `multiplayer.on`.
- `args` `any` _(optional)_

## modules/multiplayer/syncTotals {#modules-multiplayer-synctotals}

```lua
syncTotals(): SyncTotals
```

What the sync registry holds across every entity: entities with a
registered synced component, component instances, declared properties,
declared functions, and the component instances holding a dirty
property this tick.

```lua
print(multiplayer.syncTotals().properties .. " synced properties registered")
```

## modules/multiplayer/undo {#modules-multiplayer-undo}

```lua
undo(): boolean
```

Undo this client's last edit-mode operation.

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

```lua
require("@builtin/modules/api/engine/notices") -- notices (also available as global 'notices')
```

Post an event record that surfaces to the operating agent on its next tool call. Public Luau surface over the `__notices_post` Internal FFI global.

Usage: local notices = require("@builtin/modules/api/engine/notices")
Also available as global: notices

## modules/notices/post {#modules-notices-post}

```lua
post(template: string, params: { [string]: any }?, opts: NoticeOpts?)
```

Post a notice. `template` is a fixed sentence used to collapse
repeats; put varying values in `params`. `opts.severity` defaults to
"info"; `opts.includeLocation` attaches the emitting call site.

**Parameters**

- `template` `string` — Fixed sentence identifying the notice.
- `params` `{ [string]: any }?` _(optional)_ — Optional table of named values rendered alongside the template.
- `opts` `NoticeOpts?` _(optional)_ — Optional table: severity ("info" | "warn" | "error"), includeLocation (boolean).

```lua
notices.post("wave complete", { wave = 3 })
notices.post("save slot corrupted, using defaults", { slot = id }, { severity = "warn" })
```

## modules/onUnload {#modules-onunload}

```lua
modules.onUnload(callback) -> ()
```

Register a teardown for the calling module's current run. It runs once, at the moment this run ends — immediately before the next run of that chunk replaces it, and when the module leaves the require cache — while this run's module-level locals are still in scope, so the run that spawned the entities, created the particle systems or subscribed to the event bus is the run that releases them. Each run registers its own, and the registration goes with the run that made it.

**Parameters**

- `callback` `function` — Called with no arguments just before this run of the module is replaced

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

```lua
require("@builtin/modules/api/engine/packages") -- packages (also available as global 'packages')
```

Discover and inspect registered packages (folders marked with `package.yaml`). Public Luau surface over the `__packages` Internal FFI namespace.

Usage: local packages = require("@builtin/modules/api/engine/packages")
Also available as global: packages

## modules/packages/list {#modules-packages-list}

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

List every registered package across scopes.

```lua
for _, p in ipairs(packages.list()) do print(p.name, p.scope) end
```

## modules/packages/lookup {#modules-packages-lookup}

```lua
lookup(name_or_scope: string, name: string?): PackageEntry?
```

Look up a single package by name (any scope) or by exact
`(scope, name)`.

**Parameters**

- `name_or_scope` `string` — Package name, or scope if a second arg is given.
- `name` `string?` _(optional)_ — Package name when the first arg is a scope.

```lua
local p = packages.lookup("@builtin", "audio")
```

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

```lua
require("@builtin/modules/api/engine/particles") -- particles (also available as global 'particles')
```

Particle emitters: create one, list the ones that are live — every emitter, or one creator's own — and read what each is simulating and drawing right now: whose it is, how many particles are alive, what it costs on the GPU, and when it is producing nothing, which reason explains it.

Usage: local particles = require("@builtin/modules/api/engine/particles")
Also available as global: particles

## modules/particles/create {#modules-particles-create}

```lua
create(spec: table?): any
```

Create a GPU particle system from a spec, allocating its buffers and
registering it with the auto-update driver. The handle it returns carries
`:emit`, `:update`, the setters, `:observe`, and `:getCreator`.

**Parameters**

- `spec` `table?` _(optional)_ — `{ maxCount, rate, lifetime, speed, shape, ... }` — every field
optional, each falling back to the emitter's default. `owner` and `name`
say whose the emitter is: `owner` is the key `list(owner)` matches, so a
creator reaches exactly its own emitters after it has lost their handles,
and `name` says which of them this one is. An emitter that states neither
is still attributed to the module and line it was created from.
optional, each falling back to the emitter's default. A field that names
one of a closed set takes a name from it and raises with the whole set
otherwise; a key the spec does not define is reported on its own, naming
the key that writes what it was written for. `man particles.create` lists
every key the spec defines.

```lua
local fire = particles.create({ maxCount = 2000, rate = 100 })
local star = particles.create({ owner = "starfield", name = "shell" })
```

## modules/particles/list {#modules-particles-list}

```lua
list(filter: (string | ParticleCreatorFilter)?): { any }
```

Every particle system this VM has created and not destroyed, in
creation order — or, given a filter, the ones whose creator matches it.
Answered from the emitter registry, so finding an emitter costs nothing per
entity in the scene.

Called with nothing it answers with every emitter in the VM, which is what
makes it the way to reach one whose creator has lost its handle, and
`:getCreator()` on an entry says whose that one is. A filter narrows it to
one creator's own, so a module clears what a previous load of it left
behind and leaves every other emitter in the world standing.

**Parameters**

- `filter` `(string | ParticleCreatorFilter)?` _(optional)_ — Optional. A string matches the `owner` key a creator stated; a
table matches every one of `owner`, `name` and `source` that it names.

```lua
for _, sys in ipairs(particles.list()) do print(sys:getActiveCount()) end
for _, sys in ipairs(particles.list("starfield")) do sys:destroy() end
local mine = particles.list({ source = debug.info(1, "s") })
```

## modules/particles/observe {#modules-particles-observe}

```lua
observe(system: any?): { [string]: any }
```

What the engine is simulating and drawing for particles right now.
With no argument, every live emitter plus the totals they sum to; with an
emitter, that one's reading. An engine holding no emitters answers
`count = 0` with an empty list, which reads differently from an engine
whose emitters are all silent (`count > 0`, `silent = count`).

**Parameters**

- `system` `any?` _(optional)_ — Optional particle system handle to read on its own.

```lua
local o = particles.observe(); print(o.count, o.alive, o.silent)
local r = particles.observe(fire); print(r.alive, r.bytes.total)
```

## modules/particles/silenceReasons {#modules-particles-silencereasons}

```lua
silenceReasons(): { { reason: string, means: string } }
```

The closed set of reasons an emitter can be producing nothing, in the
order a reading resolves them — nearest cause first — each with what it
means. Every `observe().reason` is one of these.

```lua
for _, r in ipairs(particles.silenceReasons()) do print(r.reason, r.means) end
```

## modules/particles/whySilent {#modules-particles-whysilent}

```lua
whySilent(system: any): (string?, string?)
```

Why one emitter is producing nothing, from the closed set
`silenceReasons()` enumerates — or nil when it is producing. The second
return is the detail line naming what the reason is about.

**Parameters**

- `system` `any` _(optional)_ — The particle system handle to ask about.

```lua
local why, detail = particles.whySilent(fire)
```

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

```lua
persist
```

## modules/persist_origin/README {#modules-persist-origin-readme}

```lua
persist_origin
```

Provenance / origin-context layer for the persist (create-flow) system. origin kinds: "execute"   — an agent call (the engine's authoring window is open) "scene"     — scene loader / entrypoint onLoad (`__scene_load.inProgress()`) "component" — a script-component lifecycle callback (awake/update/...) "engine"    — engine-driven code that is none of the above (an assetType behavior composing an avatar, a bundle exploding its hierarchy). The DEFAULT: a surface is authored only while the authoring window is open, so a surface added later classifies as code without being enumerated anywhere.

## modules/persist_player_camera/README {#modules-persist-player-camera-readme}

```lua
persist_player_camera
```

Freeze the LIVE player + camera into a scene's player/camera config. The persist north star is "what you see is what you get": the freeze PRESERVES the exact live state, it never synthesizes. PLAYER. The live player body is `layers.active.players.localPlayer.avatar` — whatever entity is in that slot right now, however it was built (procedurally spawned, instantiated, hand-assembled). The scene CONFIG (`player.avatar_<mode>`) is a BUNDLE ref the spawner instantiates on the next load. So the freeze CONVERTS the live avatar entity-tree into a bundle and points the config at it: * If the live avatar is an UNMODIFIED instance of an existing bundle (its `bundleProvenance` carries exactly one source bundle with no added components/entities), reference THAT bundle — don't duplicate. * Otherwise compose the live tree into a bundle (new on first freeze, re-composed in place on re-freeze) and reference it. The entity-tree -> bundle work goes through the bundle assetType's own composeTemplate path: first freeze = one-step `asset.create("bundle", name, { entity = ref })` (onCreate composes the live tree), re-freeze = `bundleRef:update(entityId)` in place. Both capture LIVE component state via serialized component snapshots — exactly what's on screen. CAMERA. The live primary camera's behavior is a COMPONENT (the agent authors one to drive the camera); the freeze references it as `camera.behavior_<mode>`. Camera parameters (fov/near/far/follow) are baked into the live Camera component and preserved with it. No synthesis. Bundle CREATION is side-effecting, so it runs from `confirm()`, never `plan()` (a cancelled plan must leave no orphan bundle in /source).

## modules/persist_serializer/README {#modules-persist-serializer-readme}

```lua
persist_serializer
```

Live-state serializer driver for persist. The missing half of the scene-save story: scene_saver.serializeEntity already turns a LIVE entity into the v6 per-entity body, but it is only ever fed ids from the EDIT-mode dirty-mark queue (empty in play). This driver supplies the play-mode side — it ENUMERATES the active layer's live entities, filters them by PROVENANCE (execute-origin only, via persist.origin) + authored-ness (scene_saver's spawner-managed / temporary filter), and assembles a loadable v6 scene body. Lighting stays ENTITY-PRIMARY: lighting comes from Light components on entities, which serialize as normal entities — so we deliberately do NOT emit scene_saver's global `lighting` manifest block (it would compete with / override the entity lights). Only the player + camera config blocks are carried over.

## modules/playerSetupValidation/README {#modules-playersetupvalidation-readme}

```lua
require("@builtin/modules/api/engine/playerSetupValidation") -- playerSetupValidation
```

Agent-facing validation for authored player setups. A player-spawn scene is built from PlayerSpawn entities (each naming a PlayerPrototype subtree to instantiate on join) and PlayerPrototype roots (marked PrototypeOnly, with a `body` and a `camera` field each naming a DESCENDANT of the prototype — the entity adopted as the avatar and the entity carrying the player's Camera). The prototype is cloned as a self-contained subtree, so both refs must resolve inside it and it may hold no camera other than the one `camera` names. checkEntity inspects one such entity and returns human-readable messages that name what is wrong and what to do about it; checkScene validates the scene's player intent against its PlayerSpawn / Camera counts. checkActiveScene runs the full rule set across the live active-layer scene, resolving each spawn's prototype wherever the materialisation holds it — the live entity in edit, the captured authored template in play; checkSceneJson runs it statically over a scene.json document — the path the scene assetType's `validate` hook uses so `asset.validate`, `worldValidation`, and the `world.push` gate all catch a broken player setup at authoring time.

Usage: local playerSetupValidation = require("@builtin/modules/api/engine/playerSetupValidation")

## modules/playerSetupValidation/checkActiveScene {#modules-playersetupvalidation-checkactivescene}

```lua
checkActiveScene(): { { entity: string, message: string } }
```

Gather every player-setup validation message for the live active-layer
scene: the per-entity rules across all PlayerSpawn / PlayerPrototype entities,
the competing-camera rule, and the scene-intent rule. Returns a flat list an
agent can read to see what to fix. The verdict belongs to the settled scene,
so the call holds while a scene load or a mode-flip transition is rebuilding
the live tree, and judges what the rebuild lands on.

## modules/playerSetupValidation/checkEntity {#modules-playersetupvalidation-checkentity}

```lua
checkEntity(entityId: string): { string }
```

Validate a single PlayerSpawn or PlayerPrototype entity, returning
agent-facing messages naming what is wrong and what to do. An entity carrying
neither component (or one that does not exist) yields no messages.

**Parameters**

- `entityId` `string` — The entity to inspect.

## modules/playerSetupValidation/checkScene {#modules-playersetupvalidation-checkscene}

```lua
checkScene(opts: { playerIntent: string, spawnCount: number, cameraCount: number }): { string }
```

Validate a scene's player intent against its PlayerSpawn / Camera counts,
returning agent-facing messages. A "spawns" scene with no PlayerSpawn, or a
"none" scene with no Camera, yields a message; every other combination is
clean.

**Parameters**

- `opts` `{ playerIntent: string, spawnCount: number, cameraCount: number }` — `{ playerIntent: string, spawnCount: number, cameraCount: number }`.

## modules/playerSetupValidation/checkSceneJson {#modules-playersetupvalidation-checkscenejson}

```lua
checkSceneJson(sceneJson: { [string]: any }): { { code: string, severity: string, message: string } }
```

Validate a decoded scene.json document statically: the full player-setup
rule set (per-entity, competing-camera, scene-intent) run over the scene's
authored entity tree without loading it. This is what the scene assetType's
`validate` hook calls, so `asset.validate` / `worldValidation` / the
`world.push` gate all report a broken player setup at authoring time.

**Parameters**

- `sceneJson` `{ [string]: any }` — The decoded scene.json table (`{ player, version, entities }`).

## modules/playerSetupValidation/playReadinessProblems {#modules-playersetupvalidation-playreadinessproblems}

```lua
playReadinessProblems(): { { entity: string, message: string } }
```

The player-setup problems that must block a flip into play: the per-entity
spawn/prototype rules (body + camera refs set, resolving to descendants, a
single referenced camera) and the scene-intent rule, over the LIVE active
scene. A "spawns" scene with none of these problems is ready to play. The
competing-camera rule is deliberately excluded — the editor's own free-fly
camera is a live viewport camera outside every prototype, so running it here
would false-positive on every edit session; that rule stays a static /
publish-time concern. Empty for a non-"spawns" scene (no player requirement),
and empty while the active scene is still being materialised — the verdict
belongs to the settled scene, so it waits for the layer to finish loading
and for any mode-flip transition to converge.

## modules/player_lifecycle/README {#modules-player-lifecycle-readme}

```lua
player_lifecycle
```

Bridges the UserIdentity component's `awake / onDestroy` into the per-scene players registry. Installed by the prelude. The UserIdentity component requires this module and calls `playerJoined(eid)` in awake, `playerLeft(eid)` in onDestroy, and `localAvatarBound(eid, av)` when the local avatar slot fills. Each routes into `layers.active.players._addPlayer / _removePlayer / _onLocalAvatarBound`, which update the per-scene set AND fire `onPlayerJoined / onPlayerLeft` in one atomic step. onLocalReady is fired separately when the joining entity matches `world.connectedUsers.localUser.entity`. `install()` also registers `__layers_*` dispatch channels the player_spawner uses.

## modules/player_prototype_spawn/README {#modules-player-prototype-spawn-readme}

```lua
require("@builtin/modules/api/engine/player_prototype_spawn") -- player_prototype_spawn
```

The deterministic spawn core for authored player prototypes. A PlayerSpawn entity names a PlayerPrototype subtree to instantiate; spawnFor clones that subtree, activates and reveals the clone, prunes clone-subtree nodes whose networkScope excludes the caller's owner/authority role, marks the clone RuntimeOnly, and turns the clone ROOT into the joining user's internal identity: it removes the PlayerPrototype / PlayerSpawn markers from the root and adds the UserIdentity component, so the root plugs into the existing players registry / join-leave / ownership / sync as a first-class local player. The clone root's authored children are detached to standalone world entities — nothing is parented to the identity. The joining user's avatar is the body named by the root's `PlayerPrototype.body` ref; it is positioned at the PlayerSpawn's world transform (placement `at_spawn_transform`) and bound by assigning the identity's `avatar`, which links it back through `PlayerAvatar.owner`. The clone's Camera node follows the bound body. Runtime provenance attributes (source prototype, owner user, owner player) are stamped on the root and read back with runtimeSpawnedInfo. The attributes are runtime-only: they live on the live entity and are not serialized into the world. installJoinHook wires spawnFor to a scene's user-join event so a joining user is placed from a PlayerSpawn automatically.

Usage: local player_prototype_spawn = require("@builtin/modules/api/engine/player_prototype_spawn")

## modules/player_prototype_spawn/applyNetworkScope {#modules-player-prototype-spawn-applynetworkscope}

```lua
applyNetworkScope(cloneRootId: string, isOwner: boolean, isAuthority: boolean)
```

Prune a clone subtree by each node's networkScope against the caller's
role. Walks the subtree from `cloneRootId`; a node scoped OwnerOnly is
despawned when the caller is not the owner, AuthorityOnly when the caller is
not the authority, and Replicated (or any other value) is kept.

**Parameters**

- `cloneRootId` `string` — The clone's root entity id.
- `isOwner` `boolean` — Whether the caller owns this clone.
- `isAuthority` `boolean` — Whether the caller is the simulation authority for this clone.

## modules/player_prototype_spawn/authorDefault {#modules-player-prototype-spawn-authordefault}

```lua
authorDefault(): { [string]: string }
```

Author the canonical default player setup into the active scene — the
same shape the default world and the static_player canonical scene ship: a
PrototypeOnly prototype whose body adopts the humanoid avatar and whose
OwnerOnly camera rig runs the orbital follow behavior, plus a spawn at the
origin. Returns the authored entity ids. This is the single builder
scene.player("spawns") and the "player" scene template both resolve to, so
a joining user's avatar always replaces the same authored body.

## modules/player_prototype_spawn/captureTemplatesFromEntities {#modules-player-prototype-spawn-capturetemplatesfromentities}

```lua
captureTemplatesFromEntities(entities: { any })
```

Build the prototype-template registry from a scene's authored entity
records (the parsed scene data, not live entities). This is the primary
capture path: it is independent of scene-load order and runtime
composition, so it captures the clean authored subtree (no composed avatar)
and works in the runtime profile, which boots straight to play. Called by
the scene loader for v7 scenes.

**Parameters**

- `entities` `{ any }` — The scene's authored entity records (each `{ id, name, parent,
networkScope, renderLayer, transform, components }`).

## modules/player_prototype_spawn/capturedTemplate {#modules-player-prototype-spawn-capturedtemplate}

```lua
capturedTemplate(prototypeId: string): any
```

The captured authored subtree for a PlayerPrototype — the clone source
`spawnFor` instantiates for each joining player, keyed by the prototype's
authored entity id (the id a PlayerSpawn's `prototype` field carries). Each
node is `{ id, name, participation, networkScope, renderLayer, position,
rotation, scale, components = { [type] = data }, children }`. Where the
materialisation keeps authored prototype subtrees out of the live scene —
play — this template is the authored prototype, and it is the subtree
`spawnFor` clones for each joining player.

**Parameters**

- `prototypeId` `string` — The PlayerPrototype root's authored entity id.

```lua
local proto = player_prototype_spawn.capturedTemplate(spawn.prototype.id)
```

## modules/player_prototype_spawn/chooseSpawn {#modules-player-prototype-spawn-choosespawn}

```lua
chooseSpawn(ctx): (string?, { [string]: any }?, string?)
```

Pick the PlayerSpawn-carrying entity to spawn from. Enumerates entities
carrying the PlayerSpawn component in the joining user's ROOT scene, skipping
any that live in an additive overlay layer (editor UI, HUD scenes). When the
root scene resolves (`ctx.rootSceneGuid`, else `layers.active.guid`), only
spawns in that scene's layer are considered; otherwise every non-overlay
spawn is eligible. Spawns with no layer attribution yet belong to the world
root and stay eligible either way. Honors an optional `ctx.spawnId`
override (used for
deterministic selection), otherwise returns the first matching spawn.

**Parameters**

- `ctx` `any` _(optional)_ — A table; `ctx.spawnId` optionally names the spawn entity to select,
`ctx.rootSceneGuid` optionally names the scene layer to scope the search to.

## modules/player_prototype_spawn/clearJoinHook {#modules-player-prototype-spawn-clearjoinhook}

```lua
clearJoinHook(guid: string)
```

Clear a scene's join-hook flag. Called when a "spawns" scene unloads so
the once-registered connect / play-entry handlers stand down (they no-op
while no wired scene remains). Idempotent for an unknown guid.

**Parameters**

- `guid` `string` — The scene guid passed to installJoinHook.

## modules/player_prototype_spawn/installJoinHook {#modules-player-prototype-spawn-installjoinhook}

```lua
installJoinHook(sceneProxy): boolean
```

Wire spawnFor to the world's connected-user join event. When a user
connects, the hook picks a PlayerSpawn and instantiates that user's prototype
instance (internal identity + avatar + camera-follow) via spawnFor. The
trigger is `world.connectedUsers.onConnect` — the WORLD-level "a user joined
the session" event — not the room players registry, so the internal identity the
clone becomes (which folds into that registry) does not re-trigger a spawn.
Entering play spawns every already-connected user (their onConnect fired in
edit, ignored then). A scene wired while ALREADY in play — the runtime
profile boots straight into play, or a scene swapped in mid-play — gets that
same sweep immediately, since no play flip follows to trigger it. Every spawn
path is per-user idempotent: a user who already owns a live clone is skipped,
so overlapping paths and re-flips never produce a second player. Idempotent
per scene proxy: a second call for the same scene installs nothing further.

**Parameters**

- `sceneProxy` `any` _(optional)_ — A non-additive Scene proxy.

## modules/player_prototype_spawn/runtimeSpawnedInfo {#modules-player-prototype-spawn-runtimespawnedinfo}

```lua
runtimeSpawnedInfo(id: string): { [string]: any }?
```

Read back the runtime provenance stamped on a clone root by spawnFor.

**Parameters**

- `id` `string` — The clone root entity id.

## modules/player_prototype_spawn/spawnFor {#modules-player-prototype-spawn-spawnfor}

```lua
spawnFor(ctx): string?
```

Spawn a player instance for a joining user from the chosen PlayerSpawn's
prototype. Chooses a spawn (honoring `ctx.spawnId`), resolves and validates
its prototype, clones the prototype subtree, activates and reveals the clone,
prunes it by networkScope against the caller's owner/authority role (both
default true), marks the clone RuntimeOnly, stamps provenance attributes,
places the clone at the spawn's world transform, and registers it with the
prototype lifecycle so it is despawned on the return to edit.

**Parameters**

- `ctx` `any` _(optional)_ — `{ userId, playerEntityId?, spawnId?, isOwner?, isAuthority? }`.

## modules/player_prototype_spawn/storePrototypeTemplate {#modules-player-prototype-spawn-storeprototypetemplate}

```lua
storePrototypeTemplate(prototypeId: string)
```

Capture a PlayerPrototype's authored subtree into the template registry.
Called by PlayerPrototype.awake (before its Asset composes and before it
deactivates) so spawnFor can instantiate the authored structure per player.

**Parameters**

- `prototypeId` `string` — The PlayerPrototype root entity id.

## modules/player_prototype_spawn/userHasSpawnedPlayer {#modules-player-prototype-spawn-userhasspawnedplayer}

```lua
userHasSpawnedPlayer(userId: string?): boolean
```

Whether a live clone spawned by spawnFor already carries this user's owner
provenance. Scans the live entities for a root whose `ownerUserId` attribute
matches. The idempotency guard the auto-spawn paths use so a user who already
has a spawned player never gets a second one.

**Parameters**

- `userId` `string?` _(optional)_ — The joining user's account id.

## modules/player_spawner/README {#modules-player-spawner-readme}

```lua
player_spawner
```

DEPRECATED: v7 scenes place players through the PlayerSpawn / PlayerPrototype flow. This engine-default-Player avatar path serves legacy v6 scenes only; M.ensure stands down (returns early) for any scene carrying a string `playerIntent`.

Binds the per-mode avatar bundle to the engine-default identity entity on non-additive `layers.onLoad`, for legacy v6 scenes. The avatar ref resolves as: per-scene `settings.player.avatar_<mode>` when set, else the world default `world.avatar_default_<mode>`. Missing-but-required is `log.error` + skip — no hardcoded fallback bundle. A single `avatar` slot combines visual + controller in one bundle. It spawns a fresh body entity from that bundle, then binds it by assigning the identity's `avatar` field, which marks the body synced + PlayerOwned and attaches its `PlayerAvatar` link. Scene-level `avatar_<mode> = ""` is the explicit opt-out — the scene builds its own body in `entrypoint.luau::onLocalReady`.

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

```lua
players
```

Per-scene players registry. Tied to a non-additive Scene proxy. Reached as `layers.active.players` or `layers.find(name).players`. Returns curated player handles — never entity or component proxies — so the caller reads/writes player data (`.userId`, `.displayName`) and reaches the body via `player.avatar` (an entity ref) uniformly across all consumers. Both colon (`p:onJoin(cb)`) and dot (`p.onJoin(cb)`) call styles are supported on every method; the registry is a namespace surface, not an object, so neither style is canonical. Additive layers do NOT carry a players surface today (multiplayer support for players living inside additive overlays is a follow-up — see the layers.module additive-scene comment). `layers.find(<additive>).players` returns nil; this module is only instantiated on the root scene proxy.

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

```lua
require("@builtin/modules/api/engine/postprocess") -- postprocess (also available as global 'postprocess')
```

Fullscreen post-process effects — register / remove / toggle / named-property updates / list the chain / read one effect's declared property schema and the value each property holds. Public Luau surface over the `__postprocess` Internal FFI namespace.

Usage: local postprocess = require("@builtin/modules/api/engine/postprocess")
Also available as global: postprocess

## modules/postprocess/add {#modules-postprocess-add}

```lua
add(name: string, shader: string | AssetRef, opts: PostprocessOpts?): boolean
```

Register a fullscreen post-process effect. This call is what
puts a pass into the frame — a `post-process` `.shader` asset defines an
effect, and renders only once registered here. The chain applies the
registration on the caller's own stack and the returned boolean is its
answer, so a `setProperty` or `setTexture` naming the effect in the same
call finds it. `shader` is a `.shader` asset reference whose `shader.wgsl`
provides `fn fragment(in: PostInput) -> vec4<f32>` and whose
`properties.yaml` declares the effect's properties; the engine generates the
group(0) framework + schema-driven group(1) from that schema. Editing that
shader afterwards recompiles this effect in place, keeping its enabled
state, priority, layer and tuned property values. WGSL text is also
accepted, and then `opts.properties` is the whole schema. Effects run in
priority order (lower first, default 100).
A registered effect runs over the live viewport's frame AND over every
offscreen one — a capture from a world-space station, one orbiting an
entity, one of a named camera, a render-to-texture camera. In each of those
the effect's `engine.view_proj` / `engine.prev_view_proj` /
`engine.inv_view_proj` are the camera THAT render was drawn from and
`engine.resolution` is that target's own size, so a pass reconstructing
world space from `zero_scene_depth(uv)` reconstructs against the station
and lens the capture asked for. An offscreen capture is therefore an oracle
for an authored grade: it photographs a chosen station without taking the
on-screen camera from whoever else is driving the scene, and a capture's
`postProcessing = false` is the one control that takes the chain off the
frame it returns. An offscreen render keeps no view history of its own, so
`engine.prev_view_proj` there holds that same matrix rather than the frame
before it, and a pass taking camera motion from the two reads none.

**Parameters**

- `name` `string` — Unique effect name.
- `shader` `string | AssetRef` — A resolved `shader` asset reference, or author WGSL
(`fn fragment(in: PostInput)` only).
- `opts` `PostprocessOpts?` _(optional)_ — `{ priority = 100, enabled = true, layer = "all"|"scene", properties = {{name, type, default?, min?, max?, textureDefault?}} }`
— with a shader asset, `properties` layers over the asset's own schema.
`layer` picks which composited image the effect grades: `"scene"` runs it
before the UI is drawn, so it grades the rendered picture and leaves every
widget on screen as authored, and `"all"` (the default) runs it after the UI
has landed, so the interface is graded along with the picture — an effect
that belongs to the world's look wants `"scene"`, since a screen another
author drew is otherwise graded by it too.
`textureDefault` is what a `type = "texture"` property samples while
nothing is bound to it: `"white"` (1,1,1,1 — the default), `"black"`
(0,0,0,1), `"normal"` (0.5,0.5,1,1) or `"transparent"` (0,0,0,0). An
effect that lays its texture over the scene wants `"transparent"`, so the
frame is untouched until `setTexture` binds a texture that exists.

```lua
postprocess.add("vignette", asset.resolve("@builtin::shaders.post.vignette", "shader"))
postprocess.add("vignette", VIGNETTE_WGSL, { properties = {{ name = "intensity", type = "float", default = 0.5 }} })
```

## modules/postprocess/describe {#modules-postprocess-describe}

```lua
describe(name: string): PostprocessDescription?
```

One effect by name, read in full: the chain state
`postprocess.status()` lists for it, and on top of that `properties` — the
schema the effect declared, each entry `{ name, type, default?, min?, max?,
textureDefault? }` in the shape `add` takes — and `values`, what each of
those properties currently holds. A property's value is the one the last
`setProperty` wrote, or the schema's own default where nothing has written
one, and it comes back as a number for a scalar and as the array for a
wider value, which is what `setProperty` takes, so a property read here is
written straight back.

This is the read-back for a property write. `setProperty` answers whether
the uniform took the value; this answers what the effect holds now, which
is the reading a pass that writes its properties every frame needs and the
one that tells a mistyped property name from an effect that is not
grading. The schema and the values are the engine's own record of the
effect — the schema it was registered with and every write the chain
accepted into its uniform, the same record `/runtime/fx/<name>/meta.json`
is serialized from. A write the chain refused is not in it, and neither is
one made against a property the schema does not declare.

Before an effect is registered its schema lives on the `.shader` asset it
will render: `asset.resolve("@builtin::shaders.post.bloom",
"shader"):getProperties()` names what that shader declares.

**Parameters**

- `name` `string` — Effect name.

```lua
local e = postprocess.describe("vignette")
print(if e then e.values.intensity else "not registered")
for _, p in ipairs(postprocess.describe("bloom").properties) do
print(p.name, p.type, p.min, p.max)
end
```

## modules/postprocess/list {#modules-postprocess-list}

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

List all registered post-process effect names in renderer
priority order (lower priority runs first).

```lua
for _, n in ipairs(postprocess.list()) do print(n) end
```

## modules/postprocess/remove {#modules-postprocess-remove}

```lua
remove(name: string): boolean
```

Queue removal of a post-process effect. Takes effect on the
next frame. Removing a name that isn't registered is a silent
no-op.

**Parameters**

- `name` `string` — Effect name to remove.

```lua
postprocess.remove("vignette")
```

## modules/postprocess/setEnabled {#modules-postprocess-setenabled}

```lua
setEnabled(name: string, enabled: boolean): boolean
```

Queue an enable/disable toggle on a registered post-process
effect. Targeting an unknown name is a silent no-op.

**Parameters**

- `name` `string` — Effect name.
- `enabled` `boolean` — True to enable, false to disable.

```lua
postprocess.setEnabled("bloom", false)
```

## modules/postprocess/setProperty {#modules-postprocess-setproperty}

```lua
setProperty(name: string, prop: string, value: (number | { number })): boolean
```

Set a named material property on a registered post-process
effect. The property must be declared in the effect's `properties`
schema; read in WGSL as `material.<prop>`. `value` is a number or a
number array (vec/color).

**Parameters**

- `name` `string` — Effect name.
- `prop` `string` — Declared property name.
- `value` `(number | { number })` — Number or array of numbers.

```lua
postprocess.setProperty("vignette", "intensity", 0.6)
```

## modules/postprocess/setSampler {#modules-postprocess-setsampler}

```lua
setSampler(name: string, opts: { [string]: any }): boolean
```

Configure the per-effect user sampler shared by the effect's
declared texture properties. opts.filter = "linear" (default) or
"nearest". opts.wrap (alias .address) = "clamp" (default), "repeat",
or "mirror" — applied to all axes.

**Parameters**

- `name` `string` — Effect name.
- `opts` `{ [string]: any }` — `{ filter = "linear"|"nearest", wrap = "clamp"|"repeat"|"mirror" }`.

```lua
postprocess.setSampler("blur", { filter = "linear", wrap = "clamp" })
```

## modules/postprocess/setTexture {#modules-postprocess-settexture}

```lua
setTexture(name: string, prop: string, path: string): boolean
```

Bind a texture to one of an effect's declared `texture` properties.
Declare it in `properties` (`{ name = "noise", type = "texture" }`) and
sample in WGSL as `textureSample(noise, noise_sampler, in.uv)`. `path`
is any TextureCache-resolvable spec (`@builtin::textures.foo`,
`color:1,0,0`, `default:white`, a render-target name, ...). A path whose
texture has not reached the GPU yet — one this same script created — is
held and bound as soon as it does; `postprocess.status()` reports it under
`pendingTextures` until then.

**Parameters**

- `name` `string` — Effect name.
- `prop` `string` — Declared texture-property name.
- `path` `string` — Texture path / spec.

```lua
postprocess.setTexture("__vsky_composite", "cloud", "cloud_target")
```

## modules/postprocess/status {#modules-postprocess-status}

```lua
status(): { PostprocessStatus }
```

Every registered effect in chain order with the state that decides
whether it reaches the frame — enabled flag, priority, layer, the
shader's compile error when it has one, the `.shader` asset it renders
when it was registered from one, the texture each declared slot is bound
to (`textures`) and the bindings still waiting for their texture
(`pendingTextures`). This is what the renderer draws with, so a survey of
the chain answers "is this one affecting the picture right now?" without
capturing a frame and reading pixels.

An effect this script has just registered is listed with `pending =
true` until the renderer publishes it, since a registration is queued
for the next frame.

```lua
for _, e in ipairs(postprocess.status()) do
print(e.name, e.enabled, e.layer, e.error)
end
```

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

```lua
require("@builtin/modules/api/engine/profiler") -- profiler (also available as global 'profiler')
```

Frame-level profiler capture, EMA stats, and named profiling blocks. Public Luau surface over the `__profiler` Internal FFI namespace.

Usage: local profiler = require("@builtin/modules/api/engine/profiler")
Also available as global: profiler

## modules/profiler/begin {#modules-profiler-begin}

```lua
begin(name: string)
```

Start a named profiling block. Call `profiler.finish(name)` to
record the duration. Blocks appear in `profiler.stats()` under
`"script.<name>"` and inside captures.

**Parameters**

- `name` `string` — Block name (e.g. "MyComponent.update").

```lua
profiler.begin("MyComponent.update"); ...; profiler.finish()
```

## modules/profiler/disableRing {#modules-profiler-disablering}

```lua
disableRing()
```

Disable the ring buffer and clear its history.

```lua
profiler.disableRing()
```

## modules/profiler/enableRing {#modules-profiler-enablering}

```lua
enableRing(seconds: number?): boolean
```

Enable the always-recording ring buffer, retaining the last
`seconds` of per-frame data (default 20). Query it AFTER the fact
with `profiler.retro()` — latency-immune, since the data is
historical. Editor profile only: returns false in the runtime
profile. The enable is the gate; the ring costs nothing until on.

**Parameters**

- `seconds` `number?` _(optional)_ — Seconds of history to retain (default 20).

```lua
if profiler.enableRing(30) then ... end
```

## modules/profiler/finish {#modules-profiler-finish}

```lua
finish(name: string?): number?
```

Finish a profiling block and record the elapsed duration as
`"script.<name>"`. Without an argument, closes the most-recently-
begun block (LIFO stack). With a name, closes the most recent
block whose name matches — useful when blocks of different names
are nested.

**Parameters**

- `name` `string?` _(optional)_ — Block name to finish. Omit to pop the top of the stack.

```lua
local ms = profiler.finish("MyComponent.update")
```

## modules/profiler/gpuFrame {#modules-profiler-gpuframe}

```lua
gpuFrame(): GpuFrameReport
```

Label-aggregated GPU pass timings over the last `window_frames`
resolved frames, measured with GPU timestamp queries. `supported`
is false when the device lacks timestamp queries — `spans` stays
empty. Each span covers every render/compute pass recorded under
one label — `compute.<shader>` per compute dispatch, `scene.*` for
the scene passes, `post.<effect>` per post-process effect,
`feature.*` for render-feature passes: `ms` is the median of its
per-frame totals, `min_ms`/`max_ms` the range that median sits in,
`count` the passes per frame and `frames` how much of the window
carried it. `at_floor` marks a label whose every sample landed
within a few ticks of the device's timestamp counter (`tick_ms`) —
those passes ran and the device resolved no duration for them,
which is not the same as a measured zero. `ran` is whether the
label recorded a measured pass in the newest resolved frame, and
`last_frame` the newest frame that did. The window outlives the
work it describes, so a pass that stops being recorded leaves a row
standing for up to `window_frames` frames carrying the median of
the frames it did run in: read `ran` to answer whether a pass is
running, `frame - last_frame` for how many resolved frames ago it
last did, and `ms` as the cost of the frames it ran in.
`frame_span_ms` (first pass begin to last pass end) and
`total_ms` are medians too, so
rows do not sum to `total_ms`, and the GPU may overlap passes so
`total_ms` can exceed `frame_span_ms`. The readback is
asynchronous: the window lags the live frame by a few frames.

```lua
local g = profiler.gpuFrame(); print(g.frame_span_ms, g.spans[1] and g.spans[1].label)
```

## modules/profiler/hits {#modules-profiler-hits}

```lua
hits(label: string?): string?
```

Drain the watchdog's recorded hit frames into a capture stored
under `label` (default `"watch_hits"`) and clear the buffer.
Returns the capture JSON (same shape as `stopCapture`), or nil if
there were no hits.

**Parameters**

- `label` `string?` _(optional)_ — Capture label to store under (default "watch_hits").

```lua
local json = profiler.hits()
```

## modules/profiler/isCapturing {#modules-profiler-iscapturing}

```lua
isCapturing(): boolean
```

Check if a profiler capture is currently active.

```lua
if profiler.isCapturing() then ... end
```

## modules/profiler/lastCapture {#modules-profiler-lastcapture}

```lua
lastCapture(): string?
```

Get the most recent completed capture result as a JSON string.
Same shape as `profiler.stopCapture()`. Returns nil if no capture
has been completed yet.

```lua
local last = profiler.lastCapture()
```

## modules/profiler/measure<T...> {#}

```lua
measure<T...>(name: string, fn: () -> T...): T...
```

Run a function inside a profiling block. Equivalent to a
begin/finish pair but handles errors correctly. Returns the
function's return values.

**Parameters**

- `name` `string` — Block name.
- `fn` `() -> T...` — Function to profile.

```lua
local count = profiler.measure("walk", function() return walk() end)
```

## modules/profiler/retro {#modules-profiler-retro}

```lua
retro(seconds: number?, label: string?): { [string]: any }?
```

Retroactively aggregate the last `seconds` of the ring (default:
the whole ring). The full per-frame capture is retained under `label`
(default `"retro"`) for in-engine drill-down (the `frame` / `hotspots`
tools);
this RETURNS a compact structured aggregate table (frame-time distribution
+ per-system summary), never the raw per-frame array — bounded, so it is
safe over the ZeroMind bridge. Code-facing primitive; the `retro` tool
renders the agent-facing report. Latency-immune: the data is historical.

**Parameters**

- `seconds` `number?` _(optional)_ — How many seconds back to include (default: whole ring).
- `label` `string?` _(optional)_ — Capture label to store under (default "retro").

```lua
local agg = profiler.retro(8, "collapse")
```

## modules/profiler/ringStatus {#modules-profiler-ringstatus}

```lua
ringStatus(): string
```

Ring buffer status as a JSON string:
`{ enabled, frames, capacity, span_seconds }`.

```lua
local s = profiler.ringStatus()
```

## modules/profiler/startCapture {#modules-profiler-startcapture}

```lua
startCapture(label: string?): boolean
```

Start recording per-frame profiler data. Each frame's system
timings are captured until `stopCapture()` is called. Results are
accessible via `profiler.lastCapture()` and VFS at
`/zero/runtime/profiler/<label>.json`.

**Parameters**

- `label` `string?` _(optional)_ — Capture label (default `"capture"`).

```lua
if profiler.startCapture("frame-spike") then ... end
```

## modules/profiler/stats {#modules-profiler-stats}

```lua
stats(pattern: string?): { ProfilerStat }
```

Get current EMA profiling statistics from the SystemProfiler.
Optional glob pattern filters by metric name (supports `*` and `?`
wildcards). Each entry carries two averages: `avg_ms` averages one
RUN of the block and is folded when the block runs, so a block that
has stopped running keeps the last value it saw; `avg_frame_ms`
averages one FRAME and is folded every frame, including the frames
the block did not run in, so it is the block's share of the current
frame and falls back to zero once the block stops running.

**Parameters**

- `pattern` `string?` _(optional)_ — Filter pattern (e.g. "schedule.*", "system.schedule.render.*").

```lua
for _, s in ipairs(profiler.stats("schedule.*")) do print(s.name, s.avg_frame_ms) end
```

## modules/profiler/stopCapture {#modules-profiler-stopcapture}

```lua
stopCapture(): string?
```

Stop the active profiler capture and return its result as a
JSON string. The capture is also saved to VFS at
`/zero/runtime/profiler/<label>.json`. Top-level fields: `label`,
`frame_count`, `started_at`, `ended_at`, `frames`, `summary`.
Compute duration as `ended_at - started_at`.

```lua
local json = profiler.stopCapture()
```

## modules/profiler/unwatch {#modules-profiler-unwatch}

```lua
unwatch()
```

Disarm the watchdog. Recorded hits are kept for a final
`profiler.hits()`.

```lua
profiler.unwatch()
```

## modules/profiler/watch {#modules-profiler-watch}

```lua
watch(ceilingMs: number, mode: string?, excludeAgent: boolean?, maxHits: number?): boolean
```

Arm the frame-time watchdog. When a frame's EFFECTIVE time
(total minus agent-injected `execute` cost) crosses `ceilingMs`,
mode `"record"` logs every offending frame (read with
`profiler.hits()`), and mode `"pause"` pauses gameplay ONCE to
freeze the bad state, then disarms. Editor profile only: returns
false in the runtime profile. `excludeAgent` (default true) keeps
the agent's own calls from tripping it.

**Parameters**

- `ceilingMs` `number` — Effective frame-time ceiling in ms.
- `mode` `string?` _(optional)_ — "record" (default) or "pause".
- `excludeAgent` `boolean?` _(optional)_ — Subtract agent cost before comparing (default true).
- `maxHits` `number?` _(optional)_ — Max frames retained in record mode (default 240).

```lua
if profiler.watch(50, "pause") then ... end
```

## modules/profiler/watchStatus {#modules-profiler-watchstatus}

```lua
watchStatus(): string
```

Watchdog status as a JSON string: `{ armed, ceiling_ms, mode,
exclude_agent, hits, dropped_hits, tripped }`.

```lua
local s = profiler.watchStatus()
```

## modules/prototype_lifecycle/README {#modules-prototype-lifecycle-readme}

```lua
require("@builtin/modules/api/engine/prototype_lifecycle") -- prototype_lifecycle
```

The play-mode invariant for authored player prototypes and EditorOnly entities. In play a PlayerPrototype subtree is the clone source, not a live scene entity: the scene loader spawns it only in edit and the spawn-on-join flow instantiates a clone per joining user in play. This module deactivates and hides any prototype still live when play begins (the fallback when the loader spawned one) and every EditorOnly entity, so neither is simulated nor rendered in play. In edit both are fully live. Runtime clones are tracked here and despawned on the return to edit. Deactivating and hiding a root cascades to its subtree through the hierarchy, so operating on the root covers its children.

Usage: local prototype_lifecycle = require("@builtin/modules/api/engine/prototype_lifecycle")

## modules/prototype_lifecycle/activatePrototypes {#modules-prototype-lifecycle-activateprototypes}

```lua
activatePrototypes()
```

Reactivate and unhide every prototype root and EditorOnly entity.

## modules/prototype_lifecycle/deactivatePrototypes {#modules-prototype-lifecycle-deactivateprototypes}

```lua
deactivatePrototypes()
```

Deactivate and hide every prototype root and EditorOnly entity so play
mode neither simulates nor renders them.

## modules/prototype_lifecycle/despawnClones {#modules-prototype-lifecycle-despawnclones}

```lua
despawnClones()
```

Despawn every still-existing tracked clone and clear the tracking list.

## modules/prototype_lifecycle/enterEdit {#modules-prototype-lifecycle-enteredit}

```lua
enterEdit()
```

Enter edit mode: despawn runtime clones, then reactivate prototypes and
EditorOnly entities.

## modules/prototype_lifecycle/enterPlay {#modules-prototype-lifecycle-enterplay}

```lua
enterPlay()
```

Enter play mode: deactivate and hide prototypes and EditorOnly entities.

## modules/prototype_lifecycle/hideEditorSurface {#modules-prototype-lifecycle-hideeditorsurface}

```lua
hideEditorSurface()
```

Deactivate and hide the EditorOnly authoring surface without touching
player-prototype roots. Used when play mode resumes so the surface
disappears and gameplay cameras take the viewport back.

## modules/prototype_lifecycle/install {#modules-prototype-lifecycle-install}

```lua
install()
```

Keep the play-mode invariant applied for every flip, in every world.
`enterPlay` / `enterEdit` are what make `PrototypeOnly` and `EditorOnly`
mean something at runtime, and until something calls them on the flip a
template stays live: its camera competes for the viewport with the camera
of the player cloned from it, carries no follow target, and holds the shot
at the spawn point; its body answers the same input as a second character.

Registered from the prelude beside the other engine installs rather than
from a scene-load path — a load that does not run leaves the invariant
unapplied with nothing reporting it, and a flip that reloads no scene
never reaches a loader hook at all. Idempotent: a second call registers
nothing, and the current mode is applied once on install so a world opened
straight into play does not start with its templates live.

```lua
PrototypeLifecycle.install()
```

## modules/prototype_lifecycle/prototypeRoots {#modules-prototype-lifecycle-prototyperoots}

```lua
prototypeRoots(): { string }
```

Ids of every active-layer entity carrying the PlayerPrototype component.

## modules/prototype_lifecycle/registerClone {#modules-prototype-lifecycle-registerclone}

```lua
registerClone(id: string)
```

Track a runtime clone root so it can be despawned on the return to edit.

**Parameters**

- `id` `string` — The clone's root entity id.

## modules/prototype_lifecycle/showEditorSurface {#modules-prototype-lifecycle-showeditorsurface}

```lua
showEditorSurface()
```

Reactivate and unhide the EditorOnly authoring surface (free camera +
editor-only visualizers) without touching player-prototype roots. Used
when play mode is paused so the editor camera returns over the frozen
world.

## modules/proxyOcclusion/README {#modules-proxyocclusion-readme}

```lua
require("@builtin/systems/proxyOcclusion/proxyOcclusion") -- proxyOcclusion
```

Analytic occlusion from coarse proxy shapes — grounding shadow for subjects a shadow map does not reach, at a cost that scales with the number of proxies rather than with scene geometry.

Usage: local proxyOcclusion = require("@builtin/systems/proxyOcclusion/proxyOcclusion")

## modules/proxyOcclusion/active {#modules-proxyocclusion-active}

```lua
active(): boolean
```

Whether the occlusion pass is currently running.

```lua
if proxyOcclusion.active() then print("occluding") end
```

## modules/proxyOcclusion/buffers {#modules-proxyocclusion-buffers}

```lua
buffers(): { [string]: any }?
```

The buffer(s) this system's passes read. A pass binds what this hands
it, so it has the values this module packed.

```lua
local b = <module>.buffers()
```

## modules/proxyOcclusion/clear {#modules-proxyocclusion-clear}

```lua
clear()
```

Drop every proxy and release the pass. The settings are kept.

```lua
proxyOcclusion.clear()
```

## modules/proxyOcclusion/configure {#modules-proxyocclusion-configure}

```lua
configure(opts: ProxyOcclusionOpts?): ProxyOcclusionState
```

Adjust how the occlusion is applied. Any omitted field keeps its current
value. An `intensity` of 0 releases the pass.

**Parameters**

- `opts` `ProxyOcclusionOpts?` _(optional)_ — Settings — see `ProxyOcclusionOpts`.

```lua
proxyOcclusion.configure({ intensity = 0.8, minDistance = 40 })
```

## modules/proxyOcclusion/count {#modules-proxyocclusion-count}

```lua
count(): number
```

How many proxies are registered.

```lua
print(proxyOcclusion.count())
```

## modules/proxyOcclusion/remove {#modules-proxyocclusion-remove}

```lua
remove(key: string): boolean
```

Remove the proxy registered under `key`.

**Parameters**

- `key` `string` — The identifier the proxy was registered with.

```lua
proxyOcclusion.remove("boulder")
```

## modules/proxyOcclusion/set {#modules-proxyocclusion-set}

```lua
set(key: string, shape: ProxyShape): number
```

Add or replace a proxy under `key`. Re-submitting the same key moves
that proxy rather than adding another, which is what lets a component push
its shape every frame as its entity moves.

**Parameters**

- `key` `string` — Stable identifier for this proxy — an entity id works well.
- `shape` `ProxyShape` — The capsule — see `ProxyShape`.

```lua
proxyOcclusion.set("boulder", { a = { 0, 1, 0 }, radius = 2 })
```

## modules/proxyOcclusion/settings {#modules-proxyocclusion-settings}

```lua
settings(): ProxyOcclusionState
```

The settings currently in force.

```lua
local i = proxyOcclusion.settings().intensity
```

## modules/radianceCache/README {#modules-radiancecache-readme}

```lua
require("@builtin/systems/radianceCache/radianceCache") -- radianceCache
```

A world-space store of lighting results that survives the frame that produced it. A lighting technique that gathers per pixel throws its answer away when the frame ends and pays for it again the next one; a technique that writes into a cache pays once per patch of world and reuses the answer for every later frame and every pixel standing on that patch. The cache is a fixed table of slots addressed by hashing a world-space cell, so it covers an unbounded world in bounded memory: `capacity` slots at 68 bytes each, and nothing about the size of the scene changes that. Cells coarsen with distance from the camera, and a slot no pixel has asked for in `maxAge` frames is reclaimed, so what the table holds tracks the view rather than accumulating everything ever seen. Each cache is created by name and owns its own table, so two techniques caching in the same frame do not share slots. Either drive the built-in screen-space producer with `run`, or enqueue your own producing pass over `bindings()` and let this own the table, the addressing and the eviction.

Usage: local radianceCache = require("@builtin/systems/radianceCache/radianceCache")

## modules/radianceCache/allocate {#modules-radiancecache-allocate}

```lua
allocate(self: Cache, ctx: any, opts: { phase: string?, order: number? }?)
```

Claim a slot for every patch of world the frame is looking at, and keep
the ones already held alive. Every technique using the cache runs this
first: it is what decides what the table holds, and a producing pass can
only fill patches this has stamped.

**Parameters**

- `self` `Cache`
- `ctx` `any` _(optional)_ — The render context the calling feature received.
- `opts` `{ phase: string?, order: number? }?` _(optional)_ — `{ phase, order }` — where the pass runs.

```lua
cache:allocate(ctx, { phase = "afterLighting", order = 40 })
```

## modules/radianceCache/bindings {#modules-radiancecache-bindings}

```lua
bindings(self: Cache): { [string]: any }
```

The buffers a pass binds to reach this cache. Hand them to
`ctx.enqueue`'s `buffers` and `#include
"@builtin::systems.radianceCache.radiance_cache"` in the shader — that is
the whole contract for a technique that wants to produce into this cache
or read out of it with its own pass.

**Parameters**

- `self` `Cache`

```lua
ctx.enqueue { kind = "compute", program = mine, buffers = cache:bindings(), ... }
```

## modules/radianceCache/create {#modules-radiancecache-create}

```lua
create(name: string, opts: CacheOpts?): Cache
```

Create a cache that owns its own table. `name` keys its buffers and its
resolve target, so two techniques caching in the same frame each pass their
own name and never share slots.

**Parameters**

- `name` `string` — Identifies this cache's resources. Unique per technique.
- `opts` `CacheOpts?` _(optional)_ — How the cache is sized and how it fills — see `CacheOpts`.

```lua
local c = radianceCache.create("indirect", { capacity = 65536, stride = 8 })
```

## modules/radianceCache/destroy {#modules-radiancecache-destroy}

```lua
destroy(self: Cache)
```

Release the table, the read-back and the resolve target. The cache
rebuilds — empty — on its next use.

**Parameters**

- `self` `Cache`

```lua
cache:destroy()
```

## modules/radianceCache/gather {#modules-radiancecache-gather}

```lua
gather(self: Cache, ctx: any, opts: { phase: string?, order: number? }?)
```

Gather light into the slots this frame is scheduled to visit, from the
scene that was just drawn. The built-in producer: it needs no acceleration
structure and no bake, so it runs wherever the deferred path does. A
technique with its own way of computing radiance enqueues that instead and
skips this.

**Parameters**

- `self` `Cache`
- `ctx` `any` _(optional)_ — The render context the calling feature received.
- `opts` `{ phase: string?, order: number? }?` _(optional)_ — `{ phase, order }` — where the pass runs.

```lua
cache:gather(ctx, { phase = "afterLighting", order = 41 })
```

## modules/radianceCache/get {#modules-radiancecache-get}

```lua
get(self: Cache): CacheState
```

This cache's settings.

**Parameters**

- `self` `Cache`

```lua
local n = cache:get().capacity
```

## modules/radianceCache/invalidate {#modules-radiancecache-invalidate}

```lua
invalidate(self: Cache)
```

Declare that the lighting which produced what is in the cache is gone.
Every slot takes its next gather whole instead of averaging it into light
that no longer exists, so the cache is rebuilt within `stride` frames
rather than over `history * stride`. Call it after moving, recolouring or
switching off a light.

**Parameters**

- `self` `Cache`

```lua
lighting.setSunIntensity(0); cache:invalidate()
```

## modules/radianceCache/memoryBytes {#modules-radiancecache-memorybytes}

```lua
memoryBytes(self: Cache): number
```

What this cache's TABLE costs, in bytes: `capacity` slots of payload
plus one key word each. Fixed at creation and independent of the scene —
the resolve target the cache also owns is screen-sized and scales with the
viewport instead.

**Parameters**

- `self` `Cache`

```lua
print(cache:memoryBytes() // 1024, "KiB")
```

## modules/radianceCache/resolve {#modules-radiancecache-resolve}

```lua
resolve(self: Cache, ctx: any, opts: { phase: string?, order: number? }?): string
```

Read the cache back out per pixel and answer the guid of the texture
holding it. The light in it arrived over however many frames have visited
the patches on screen, so a pixel drawn for the first time still gets the
converged answer.

**Parameters**

- `self` `Cache`
- `ctx` `any` _(optional)_ — The render context the calling feature received.
- `opts` `{ phase: string?, order: number? }?` _(optional)_ — `{ phase, order }` — where the pass runs.

```lua
local gi = cache:resolve(ctx, { phase = "afterLighting", order = 42 })
```

## modules/radianceCache/run {#modules-radiancecache-run}

```lua
run(self: Cache, ctx: any, opts: { phase: string?, order: number? }?): string
```

Allocate, gather and resolve in three consecutive slots — the whole
cache for a technique that wants the built-in screen-space producer.

**Parameters**

- `self` `Cache`
- `ctx` `any` _(optional)_ — The render context the calling feature received.
- `opts` `{ phase: string?, order: number? }?` _(optional)_ — `{ phase, order }` — `order` is the first of three consecutive slots.

```lua
local gi = cache:run(ctx, { phase = "afterLighting", order = 40 })
```

## modules/radianceCache/set {#modules-radiancecache-set}

```lua
set(self: Cache, opts: CacheOpts?): CacheState
```

Change this cache's settings. Any omitted field keeps its current value.
`capacity` is fixed at creation — a table cannot be resized under the
patches already in it — so changing it is refused rather than silently
ignored.

**Parameters**

- `self` `Cache`
- `opts` `CacheOpts?` _(optional)_ — The settings to change — see `CacheOpts`.

```lua
cache:set({ stride = 4, samples = 16 })
```

## modules/radianceCache/stats {#modules-radiancecache-stats}

```lua
stats(self: Cache): CacheStats?
```

What the cache did on the most recent frame a read-back has landed for,
or nil before the first one arrives. Counted on the GPU by the passes.

**Parameters**

- `self` `Cache`

```lua
local s = cache:stats(); print(s.live, s.dropped)
```

## modules/range_bounds/README {#modules-range-bounds-readme}

```lua
range_bounds
```

The `range` field-constraint validator: a constrained value must be a finite number inside the interval the field declared. A rejection names the interval, so the error carries the range the caller may write in. Registers itself with the generic field_constraints registry on load. `nil` passes, so a ranged field may be left unset.

## modules/referenceView/README {#modules-referenceview-readme}

```lua
require("@builtin/systems/pathTracing/referenceView") -- referenceView
```

A progressive path-traced view of the scene through the active camera, accumulating samples while the view holds still, so the real-time image has a converged reference to be judged against.

Usage: local referenceView = require("@builtin/systems/pathTracing/referenceView")

## modules/referenceView/__frame {#modules-referenceview-frame}

```lua
__frame(): { [string]: any }?
```

Advance one frame of accumulation: read the camera, restart if it has
moved, and write the parameter block the trace pass reads. Called by the
`pathTrace` render feature once per frame.

## modules/referenceView/active {#modules-referenceview-active}

```lua
active(): boolean
```

Whether the reference view is tracing.

```lua
if referenceView.active() then ... end
```

## modules/referenceView/disable {#modules-referenceview-disable}

```lua
disable()
```

Stop tracing and release the accumulation buffer and scene snapshot.
The render feature's own targets are released with it.

```lua
referenceView.disable()
```

## modules/referenceView/enable {#modules-referenceview-enable}

```lua
enable(opts: ViewOpts?): ({ [string]: any }?, string?)
```

Start path tracing the active camera. Allocates the accumulation buffer
and snapshots the scene's geometry and lights; the image begins converging
on the next frame the camera holds still for.

**Parameters**

- `opts` `ViewOpts?` _(optional)_ — Trace settings — see the fields below. All are optional.

```lua
referenceView.enable({ samplesPerFrame = 4, bounces = 5 })
```

## modules/referenceView/refresh {#modules-referenceview-refresh}

```lua
refresh(): (boolean, string?)
```

Retake the scene snapshot — geometry and lights as they now stand — and
begin converging again. What to call after moving, adding or removing
anything the tracer must see.

```lua
referenceView.refresh()
```

## modules/referenceView/reset {#modules-referenceview-reset}

```lua
reset()
```

Throw away every sample gathered so far and begin converging again from
the current camera. The camera is watched automatically — this is for a
change the view cannot see, such as a light being retuned.

```lua
referenceView.reset()
```

## modules/referenceView/settings {#modules-referenceview-settings}

```lua
settings(): { [string]: any }?
```

The settings in force, the size of the scene snapshot, and how far the
image has converged — `samples` is the count folded into the displayed
image, and `converged` is true once it has reached `maxSamples`.

```lua
local s = referenceView.settings(); print(s.samples, s.converged)
```

## modules/reflectionProbe/README {#modules-reflectionprobe-readme}

```lua
require("@builtin/modules/api/engine/reflectionProbe") -- reflectionProbe (also available as global 'reflectionProbe')
```

Reflection-probe system — multiple proximity-blended reflection probes in a scene. Each probe bakes the scene into its own cube slot from its position; surfaces reflect the probes covering them, gathered highest `priority` first and blended by proximity within a rank (the renderer's per-fragment probe blend), with the scene's sky under whatever coverage the probes leave. One-liner authoring (`reflectionProbe.add`) and a one-call bake-everything (`reflectionProbe.bakeAll`).

Usage: local reflectionProbe = require("@builtin/modules/api/engine/reflectionProbe")
Also available as global: reflectionProbe

## modules/reflectionProbe/add {#modules-reflectionprobe-add}

```lua
add(x: number, y: number, z: number, opts: { [string]: any }?): string
```

Add a reflection probe at `(x, y, z)` in one call: spawns a probe entity
carrying a ReflectionProbe component (which registers it and, unless
`opts.bake == false`, bakes it). The probe is an editor gizmo — invisible in
play mode. Returns the probe entity id.

**Parameters**

- `x` `number` — World X.
- `y` `number` — World Y.
- `z` `number` — World Z.
- `opts` `{ [string]: any }?` _(optional)_ — Optional `{ radius = 12, probeId = "...", name = "..." }`. `probeId`
is the STABLE asset identity (so a re-created probe reloads the same baked
cube); defaults to the entity id. The probe does NOT bake on add — call
`bakeAll()` once the scene is built (baking is an authoring step).

```lua
reflectionProbe.add(0, 3, 0, { radius = 15, probeId = "lobby" })
```

## modules/reflectionProbe/apply {#modules-reflectionprobe-apply}

```lua
apply(): number
```

Push the current active-probe blend data (live positions + radii) to the
renderer. Builds a dense slot array so each probe's data lands at its cube
slot; freed/missing slots become inert placeholders. Called automatically by
add / bake / remove; call it directly after moving a probe entity.

## modules/reflectionProbe/bake {#modules-reflectionprobe-bake}

```lua
bake(id: string): (string?, string?)
```

Bake the scene into probe `id`'s cube slot from its current position AND
persist it to a `faces6` `.texture` asset (so it survives reload + syncs),
then re-apply the probe set. Yields a few frames; call from a task/coroutine
context (component hook via task.spawn, `bakeAll`, or `execute`).

**Parameters**

- `id` `string` — Probe entity id.

## modules/reflectionProbe/bakeAll {#modules-reflectionprobe-bakeall}

```lua
bakeAll(): { baked: number, failed: number, errors: { string } }
```

Bake EVERY registered probe in the active layers, in one call. Captures
the sky into the fallback slot, then each probe's scene from its position
into its slot, persists it, and applies the full probe set. The agent/editor
one-liner. Yields; call from a task/coroutine context (`execute`, a tool, or
`task.spawn`).

```lua
reflectionProbe.bakeAll()
```

## modules/reflectionProbe/count {#modules-reflectionprobe-count}

```lua
count(): number
```

Number of registered probes.

## modules/reflectionProbe/ensureSkyFallback {#modules-reflectionprobe-ensureskyfallback}

```lua
ensureSkyFallback(): boolean
```

Ensure the scene's sky is in the environment's sky fallback: a reflective
surface no probe covers then reflects the sky rather than black, and a
partially covered one blends the shortfall against it. Queues a capture
when the sky slot holds none, and re-arms the fallback when a capture is
there but switched off. The engine's own state answers both questions, so
calling this on every probe that comes up costs one capture between them,
and a scene that lost its fallback gets it back. Once captured, the
fallback follows the sky the scene draws on its own.

```lua
reflectionProbe.ensureSkyFallback()
```

## modules/reflectionProbe/list {#modules-reflectionprobe-list}

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

List every registered probe: `{ { id, slot, radius, priority, asset, position }, ... }`.

## modules/reflectionProbe/loadBaked {#modules-reflectionprobe-loadbaked}

```lua
loadBaked(id: string): boolean
```

Load probe `id`'s PERSISTED baked cube (`probe_<key>.texture`) into its
slot WITHOUT re-rendering the scene — the runtime path. A probe bakes once at
authoring time and loads the asset on every subsequent scene load. Returns
false (not an error) when no baked asset exists yet.

**Parameters**

- `id` `string` — Probe entity id.

## modules/reflectionProbe/register {#modules-reflectionprobe-register}

```lua
register(id: string, radius: number, key: string?): number?
```

Register a reflection probe for entity `id` with influence `radius`.
Assigns a free cube slot and applies the updated probe set. Idempotent — a
re-register keeps the same slot and just updates the radius. Called by the
ReflectionProbe component's awake; rarely called directly.

**Parameters**

- `id` `string` — Probe entity id.
- `radius` `number` — Influence radius (world units) — surfaces within blend it.
- `key` `string?` _(optional)_ — Optional STABLE asset identity (the probe's probeId). Defaults to `id`.
The baked cube persists at `probe_<key>.texture` so an authored probe keeps
the same asset across reloads even though its runtime entity id changes.

## modules/reflectionProbe/setPriority {#modules-reflectionprobe-setpriority}

```lua
setPriority(id: string, priority: number)
```

Set a probe's blend rank against the probes it overlaps, and re-apply.
Probes are gathered highest rank first and each rank takes the coverage the
ranks above it left, so a small interior probe ranked above the large
exterior one it sits inside wins outright wherever it reaches full weight,
while probes of equal rank crossfade by proximity as before.

**Parameters**

- `id` `string` — Probe entity id.
- `priority` `number` — Blend rank. Defaults to 0 on every probe.

```lua
reflectionProbe.setPriority(interiorId, 1)
```

## modules/reflectionProbe/setProxy {#modules-reflectionprobe-setproxy}

```lua
setProxy(id: string, kind: string, x: number, y: number, z: number)
```

Anchor a probe's reflections to a proxy volume and re-apply. A cube
records the environment from one point, so sampling it along the raw
reflection vector puts everything it recorded at infinity and the
reflection slides across a surface as the camera moves. Sizing a proxy to
the geometry the probe recorded — a room's walls, say — keeps the
reflection anchored to what it depicts.

**Parameters**

- `id` `string` — Probe entity id.
- `kind` `string` — "box" (sized by all three half-extents), "sphere" (sized by `x`),
or "none" to sample along the raw reflection vector.
- `x` `number` — Half-extent along X, in world units — the sphere radius for "sphere".
- `y` `number` — Half-extent along Y.
- `z` `number` — Half-extent along Z.

```lua
reflectionProbe.setProxy(id, "box", 5, 3, 4)  -- a 10x6x8 room
```

## modules/reflectionProbe/setRadius {#modules-reflectionprobe-setradius}

```lua
setRadius(id: string, radius: number)
```

Update a probe's influence radius and re-apply.

**Parameters**

- `id` `string` — Probe entity id.
- `radius` `number` — New influence radius.

## modules/reflectionProbe/unregister {#modules-reflectionprobe-unregister}

```lua
unregister(id: string)
```

Unregister entity `id`'s probe, freeing its cube slot, and re-apply.

**Parameters**

- `id` `string` — Probe entity id.

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

```lua
require("@builtin/modules/api/engine/renderer") -- renderer (also available as global 'renderer')
```

GPU-resource factory + CPU codec/store wrappers — the GPU/CPU half of the asset↔resource split. This module (under `modules/api/`) is the SOLE caller of the internal `__mesh` / `__meshcpu` / `__meshgpu` / `__splat` / `__texture` / `__texturecpu` / `__texturegpu` / `__instancedata` FFI; assetType behaviours, components, and every other module call `renderer.*`, never the `__` internals.

Usage: local renderer = require("@builtin/modules/api/engine/renderer")
Also available as global: renderer

## modules/renderer/anisotropy {#modules-renderer-anisotropy}

```lua
anisotropy(): number
```

The maximum anisotropy material textures are sampled with right now —
the requested level clamped to what this device honours.

```lua
if renderer.anisotropy() < 4 then ... end
```

## modules/renderer/atmospherics.held {#held}

```lua
atmospherics.held(): boolean
```

Whether a hold is standing on the air right now.

```lua
if renderer.atmospherics.held() then print("clear air") end
```

## modules/renderer/atmospherics.hold {#hold}

```lua
atmospherics.hold(share: number?): () -> ()
```

Hold the air between the camera and every surface at a stated share of
what the scene authored, and return the release. At the default 0 the
media contribute nothing and a surface renders in its own colour, which is
what lets a reader judge an albedo, a tint or a material while another
slice of a shared world drives the weather. The share reaches aerial
perspective, height fog and volumetric light scattering; the sky, the sun
and the light they put on a surface are untouched, because those are what
the surface's colour is made of. Holds nest: the innermost names the
share, and the authored air is back once the last release is called. Each
release ends its own hold whatever order the releases come in, so two
callers holding at once each end their own.

**Parameters**

- `share` `number?` _(optional)_ — How much of the authored air reaches the image, in [0, 1].
Defaults to 0 — no air at all.

**Returns** `()` — A function that releases this hold. Calling it twice releases once.

```lua
local release = renderer.atmospherics.hold() ; local png = tools.use("capture", "fromPosition", { position = { 0, 2, 8 } }) ; release()
```

## modules/renderer/atmospherics.onChange {#onchange}

```lua
atmospherics.onChange(listener: (number) -> ()): () -> ()
```

Register a listener called with the share now in force whenever it
changes — a hold taken, a hold released — and return the unsubscribe. A
system that packs a medium into a GPU buffer registers here and re-packs
what it has already pushed, so the buffer carries the share before the
frame the hold was taken on is drawn rather than a frame later.

**Parameters**

- `listener` `(number) -> ()` — Called with the share now in force, in [0, 1].

**Returns** `()` — A function that removes this listener.

```lua
local stop = renderer.atmospherics.onChange(function(share) pushParams() end)
```

## modules/renderer/atmospherics.share {#share}

```lua
atmospherics.share(): number
```

The share of the authored air that reaches the image: the innermost
hold's share while one stands, and 1 otherwise. A system that packs a
medium multiplies its extinction — `aerial`, a fog `density` — by this,
and a hold then reaches that medium however it is being driven.

```lua
local density = state.density * renderer.atmospherics.share()
```

## modules/renderer/blendedBatching {#modules-renderer-blendedbatching}

```lua
blendedBatching(): boolean
```

Whether blended neighbours sharing a draw key draw together.

## modules/renderer/bounds.clear {#clear}

```lua
bounds.clear(id: string): boolean
```

Withdraw the box an entity published, so it stops contributing to the
entity's reported extent.

**Parameters**

- `id` `string` — Entity id.

```lua
renderer.bounds.clear(id)
```

## modules/renderer/bounds.set {#set}

```lua
bounds.set(id: string, min: any, max: any): boolean
```

Publish the local-space box an entity's content-drawn geometry occupies.
`entity:bounds()` and `entity:hierarchyBounds()` union it with whatever
mesh geometry the entity has, each carried out of its own local space, so
framing a camera on the entity frames what a feature actually draws.

## modules/renderer/captureView.channelId {#channelid}

```lua
captureView.channelId(name: string): number?
```

The debug channel a registered view draws on — what a feature passes as
its pass `debugChannel`. Nil when no view is registered under `name`.

**Parameters**

- `name` `string` — The view name.

```lua
ctx.enqueue { ..., debugChannel = renderer.captureView.channelId("lightmap") }
```

## modules/renderer/captureView.list {#list}

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

Every registered capture view as `{ name, channel, description }` records
— what backs the discoverability of `capture pass=<name>` and the
unknown-view error's suggestion list.

```lua
for _, v in ipairs(renderer.captureView.list()) do ... end
```

## modules/renderer/captureView.ready {#ready}

```lua
captureView.ready(name: string): boolean
```

Whether a registered view can draw yet. A view's passes are enqueued
from the moment its render feature first runs, but they are skipped while
the materials they name have no pipeline — their shader is still compiling —
so for the first frames of a session a camera bound to the view renders the
ORDINARY view into its target, and the image gives no sign of it. This
reports the difference, and reports it before any camera is on the view, so
it is answerable for the first camera bound to one. False for an
unregistered name.

**Parameters**

- `name` `string` — The view name.

```lua
repeat task.wait() until renderer.captureView.ready("zfighting")
```

## modules/renderer/captureView.register {#register}

```lua
captureView.register(name: string, config: any): number
```

Register (or update) a content capture view under `name` and return the
debug CHANNEL number assigned to it. A render feature gates its pass to this
channel (`debugChannel = channel`) so the pass draws only when a capture
selects the view. Idempotent: re-registering the same name keeps its channel.

**Parameters**

- `name` `string` — The view name, selected via `capture pass=<name>`.
- `config` `any` _(optional)_ — `{ description?, ensure?, warmup?, renderLayers? }`. `ensure` is
called before a capture of this view so the feature that draws it is live
(e.g. create it on demand). `warmup` is how many present frames a capture
lets the view accumulate before it reads — set it when the feature retains
prior-frame state (a temporal diff) so the first capture reads a warm
result. `renderLayers` is the layer spec a capture of this view uses when
the caller named none — a view that draws its own geometry and wants the
scene's kept out of the frame (and out of the depth buffer it tests
against) names only its own layer.

```lua
local ch = renderer.captureView.register("lightmap", { description = "...", ensure = fn })
```

## modules/renderer/captureView.resolve {#resolve}

```lua
captureView.resolve(name: string): any
```

Resolve a capture view by name to its `{ channel, ensure, description,
warmup }` record, or nil when no view is registered under `name`.

**Parameters**

- `name` `string` — The view name.

```lua
local v = renderer.captureView.resolve("lightmap")
```

## modules/renderer/captureView.unregister {#unregister}

```lua
captureView.unregister(name: string): boolean
```

Withdraw a capture view. A subsequent `capture pass=<name>` no longer
resolves to it (falls through to the unknown-view error).

**Parameters**

- `name` `string` — The view name.

```lua
renderer.captureView.unregister("lightmap")
```

## modules/renderer/clearShadowHero {#modules-renderer-clearshadowhero}

```lua
clearShadowHero(): boolean
```

Release the hero caster, so the directional shadow is the cascades'
alone again and the layer the hero view rendered into is given back.

```lua
renderer.clearShadowHero()
```

## modules/renderer/clearShadowProxy {#modules-renderer-clearshadowproxy}

```lua
clearShadowProxy(mesh: string?): number
```

Stop proxying `mesh`, so it rasterizes its own geometry into shadow
views again. Called with no argument, drops every registration.

**Parameters**

- `mesh` `string?` _(optional)_ — The mesh to stop proxying. Omit to clear all of them.

```lua
renderer.clearShadowProxy(statueMesh)
print(renderer.clearShadowProxy(), "proxies dropped")
```

## modules/renderer/collect {#modules-renderer-collect}

```lua
collect(): RuntimeCollection
```

Release every runtime texture, material, mesh and render feature nothing
holds: no handle a script still reaches, no live owner, no reference from
live engine state, no asset backing it, no hold. A root scene load runs this
once the new scene stands, so what the previous scene's content created and
nothing still wears goes with that scene; calling it directly collects at
any other moment. A session material's handle counts as reached while the
entity it was keyed for stands, and stops counting once that entity is
gone.
It reaches the GPU textures the device holds beside the registry's own: a
texture the cache loaded for an asset goes once nothing live names it and
is read back from that asset the next time something asks for it, while one
no asset answers for stays, there being nothing to read it back from — a
render pass's own target, a colour swatch, an atlas the engine built. A
texture the ASSET path uploaded and whose asset has since been removed has
nothing to come back from either, and the collection decides about it from
its holders the way it does about every other resource: a handle a script
still reaches, a live owner, a reference from live engine state, a hold.
Features go first, then materials, then meshes, then textures, so a texture
only a released material named goes with the material. Runs a full garbage
collection first, so a handle nothing reaches counts as let go, and yields
for the frame the census runs on. A handle the calling function still has
in a variable — or in a temporary it has not overwritten — is one a script
reaches, so a resource created in the function that collects is let go by
the next collection rather than this one.

```lua
local c = renderer.collect() print(c.released.texture, c.kept)
```

## modules/renderer/compiledShaders {#modules-renderer-compiledshaders}

```lua
compiledShaders(): { string }
```

Every name `renderer.compiledSource` answers for — one per name a
shader compile has run under this session, whether it succeeded or failed.
What makes the composed-source surface enumerable rather than something to
guess a key for.

```lua
for _, name in renderer.compiledShaders() do print(name) end
```

## modules/renderer/compiledSource {#modules-renderer-compiledsource}

```lua
compiledSource(shader: string): string?
```

The WGSL the shader compiler received under one name, exactly as it
received it — the composed module, which is what a compile error's line
numbers and handle indices are positions in. Answers under any name a
compile ran under (identity, guid, alias, or a `program` from
`renderer.shaderVariants()`), for a shader that declares no features, and
for a shader whose compile FAILED, which is the case it exists for: a
message about a function body carries a position and nothing else, and the
text that position is in is this. The failed text stands for as long as
`shaderRef:compileStatus()` reports that failure under the same name.

**Parameters**

- `shader` `string` — Any name a shader compiled under — identity, guid, alias, or a
`shaderVariants()` program name.

```lua
local status = asset.resolve("myShader", "shader"):compileStatus()
if status.status == "failed" then
print(status.error)
print(renderer.compiledSource("myShader"))
end
```

## modules/renderer/compositeSize {#modules-renderer-compositesize}

```lua
compositeSize(): { width: number, height: number }
```

The size of the image the post-scene phases worked on in the last
presented frame — the target the UI composites onto, which every pass
after the scene reads as `@scene.color` and writes into, and which a
`screenSpace = "composite"` render target follows. While the renderer
presents the viewport itself that is the display's own size, whatever
fraction of it the scene rasterized at; while a UI viewport panel owns
the presentation it is the size the scene rasterized at, since the panel
draws the scene target at its own rect and nothing upscales before the
composite. Both read `0` before a frame has drawn.

```lua
local c = renderer.compositeSize()
```

## modules/renderer/cullStats {#modules-renderer-cullstats}

```lua
cullStats(): {
```

What the last completed frame decided to draw. `total` renderables went
into the frustum test, `culled` fell outside it and `visible` survived. Of
those, occlusion culling measured `occlusionTested` against the depth
pyramid and proved `occlusionCulled` were entirely behind other geometry —
both 0 while `renderer.occlusionCulling()` is false. A renderable the
pyramid has no say over — one that laid no depth in the pre-pass, one whose
bounds were never recorded, one straddling the near plane — is measured
against nothing and counted in neither, so the gap between `visible` and
`occlusionTested` reads how much of the frame the test could speak for.

This answers for the main camera. What a shadow view's own volume did with
the frame's casters is on that view's row in `renderer.shadowViews()`.

```lua
local s = renderer.cullStats(); print(s.visible - s.occlusionCulled, "drawn")
```

## modules/renderer/debugPass.builtins {#builtins}

```lua
debugPass.builtins(): { string }
```

The built-in debug-pass names, one per channel in channel order — the
engine's built-in pass vocabulary (final, albedo, normal, depth, …).

```lua
for _, n in ipairs(renderer.debugPass.builtins()) do ... end
```

## modules/renderer/debugPass.channel {#channel}

```lua
debugPass.channel(name: string): number?
```

The channel a debug-pass NAME renders on: a built-in pass, else a content
capture view registered via `renderer.captureView`. Nil when the name is
neither — the signal a selector uses to reject an unknown pass.

**Parameters**

- `name` `string` — A debug-pass name (e.g. "normal", "depth", "lightmap").

```lua
local ch = renderer.debugPass.channel("normal")   -- 7
```

## modules/renderer/debugPass.list {#list}

```lua
debugPass.list(): { string }
```

Every selectable debug-pass name: the built-in passes plus every
registered content capture view. What a debug-pass selector offers.

```lua
local passes = renderer.debugPass.list()
```

## modules/renderer/debugPass.name {#name}

```lua
debugPass.name(channel: number): string?
```

The canonical NAME for a debug channel: a built-in pass name for a
built-in channel, else a registered capture view's name. Channel 0 is
"final" (the lit image). Nil when no pass owns the channel.

**Parameters**

- `channel` `number` — The channel number.

```lua
local name = renderer.debugPass.name(7)   -- "normal"
```

## modules/renderer/depthPrepass {#modules-renderer-depthprepass}

```lua
depthPrepass(): boolean
```

Whether the opaque depth pre-pass is currently enabled.

## modules/renderer/depthPrepassOrder {#modules-renderer-depthprepassorder}

```lua
depthPrepassOrder(): { runs: number, reordered: number }
```

What the last frame's depth pre-passes planned, and how far their
sequences were from near-to-far before they ordered. `runs` counts the
instanced draws planned; `reordered` counts the adjacent pairs the sort
moved past each other, taken before it ran. Both are summed over every
pre-pass the frame ran — the window plus each render-target camera, each
ordering against its own camera. Both read `0` while the pre-pass or the
ordering is off, and `reordered` reads `0` for a frame that already stood
in order. The ordering leaves no other trace — the draws, the depth and the
image are the same either way.

```lua
local o = renderer.depthPrepassOrder()  -- o.reordered > 0 → it sorted
```

## modules/renderer/depthPrepassOrdering {#modules-renderer-depthprepassordering}

```lua
depthPrepassOrdering(): boolean
```

Whether the depth pre-pass is submitted nearest-first.

## modules/renderer/destroy {#modules-renderer-destroy}

```lua
destroy(handleOrKind: any, id: string?): boolean
```

Free the GPU resource a renderer resource holds (the GPU-destroy verb).
Takes any of the forms that name it: the handle a create returned, routed
by its `category` so one call releases a mixed set of handles; the id a
listing hands out, whose kind is read back off what the renderer holds
under it — the runtime registry, the material definitions, the live
features, and the device itself for an asset's own texture or mesh; or the
kind with the id beside it, the shape `renderer.hold` and
`renderer.references` take, which is what names the kind for an id two of
them answer to. An id nothing holds anything under releases nothing and
answers false. The on-disk asset, if any, is untouched. A CPU handle's
`:unload()` frees the CPU copy separately.

**Parameters**

- `handleOrKind` `any` _(optional)_ — A `MeshHandle`, `TextureHandle`, `MaterialHandle` or feature
handle; the id itself; or the kind (`"texture"`, `"material"`, `"mesh"`,
`"feature"`) with the id as the second argument.
- `id` `string?` _(optional)_ — The guid or registry key, when the first argument is a kind.

```lua
renderer.destroy(meshHandle); renderer.destroy(materialHandle)
renderer.destroy(renderer.texture.list()[1].guid)
renderer.destroy("mesh", guid)
```

## modules/renderer/deviceGeneration {#modules-renderer-devicegeneration}

```lua
deviceGeneration(): number
```

Which render device this process is on, counted from the first.

A render device is lost when a driver resets, when the GPU is taken away,
or when a browser reclaims a WebGPU context. The engine answers by building
another device and re-deriving this session's resources onto it, and this
number moves by one each time it does. Anything held across frames that was
built from a GPU resource records this beside it and remakes it when the two
differ; `engine.onDeviceRebuilt` is the hook that fires when it moves.

```lua
local generation = renderer.deviceGeneration()
engine.onDeviceRebuilt(function(g) print("device " .. g) end)
```

## modules/renderer/deviceState {#modules-renderer-devicestate}

```lua
deviceState(): string
```

Whether the render device this process draws through is the one it is
using, one it is replacing, or one it has stopped trying to replace.

`"ready"` is a live device. `"rebuilding"` is the window between a device
reporting itself lost and another being in place: every GPU resource built
from the old one is invalid, the frames in that window draw nothing, and
anything reaching the GPU refuses. `"abandoned"` is after the engine gave
up — the adapter refused every attempt, so this session draws no more
frames.

Work that spans the device — build a render target, draw into it, read it
back — reads this to tell an operation that failed because the device went
out from under it, which is worth doing again once
`renderer.deviceGeneration()` moves, from one that failed on its own terms.
The loss is reported before the next device exists, so the two readings
answer different halves: this one says a replacement is coming, the
generation says it arrived.

```lua
if renderer.deviceState() == "rebuilding" then return end
```

## modules/renderer/drawDiagnostics {#modules-renderer-drawdiagnostics}

```lua
drawDiagnostics(): { DrawDiagnostic }
```

Every renderable that is NOT drawing what its material says — the one
call for "why does this surface look wrong". Three states land here: a
surface rendering as the magenta placeholder (`substituted`), one the
renderer could bind nothing for at all (`outcome = "skipped"`), and one
drawing a program whose most recent compile FAILED (`stale`), which is what
a shader edited into brokenness looks like — the pipeline its last good
compile built keeps drawing, so the picture is intact and answers to none of
the edits since. Each row names the entity, the program asked for, the
program bound, `programStatus` — the compile gate's word about the program
the material NAMED — and the one cause
from `shaderCompileFailed` / `shaderNotRegistered` / `shaderNotCompiledYet`
/ `noGbufferEntry` / `renderStateKeyNotBuilt` / `noPipelineForTarget` /
`unshaded`, with the compiler's own message in `detail` or `programError`.
Covers every renderable the renderer holds, whether or not a camera reached
it: a row with `observed = false` and `outcome = "notDrawn"` carries the
renderer's own resolution for one this frame drew nowhere, so a broken
surface off-screen is reported the same as one in frame. An empty result
means every renderable the renderer holds is drawing the program its
material named and that program compiles. Answers on the deferred path as
well as forward, and in edit mode as well as play.

```lua
for _, d in renderer.drawDiagnostics() do print(d.entity, d.reason, d.detail) end
if #renderer.drawDiagnostics() == 0 then print("every surface is drawing what it says") end
```

## modules/renderer/drawStats {#modules-renderer-drawstats}

```lua
drawStats(): {
```

What the last completed frame actually submitted. `draws` counts every
geometry draw call the frame issued — the camera's passes, each shadow
view a shadow-casting light adds, and whatever a render feature draws —
and `instances` counts the instances those draws covered. The pair is what
separates one draw carrying five hundred instances from five hundred draws
carrying one each, so it reads how well the scene batches rather than how
many objects are in it.

`compacted` is how many of those instances the frame planned through draws
whose instance count the GPU decides: the culler's own per-object answers
packed into a dense run, so an object it rejects is absent from the draw
instead of collapsing to nothing in the vertex stage. `compactedDrawn` is
how many of them survived, counted on the GPU as it packed them — a pass
that then skips a whole draw over its own layer or visibility answer
leaves that draw's instances in both numbers.

The plan is made over the populations the frame draws, and the tests
answer which of their instances the packing keeps. That packing runs
before any pass has resolved the depth occlusion culling is tested
against, so on its own it reads the frustum and screen-size answers
alone. With `setOcclusionCulling` armed the frame packs the same plan a
second time once the test has answered, and `compactedDrawn` then counts
what came through occlusion as well.

`compactedDrawn` comes back from the buffer the GPU wrote, so it describes
a frame that has finished while `compacted` describes the most recent
plan, and it holds the last count the GPU wrote until another arrives — a
frame that compacts nothing reads `compacted` 0 beside the count from the
last frame that did. In a scene standing still the gap between the two is
the front-end work culling removed.

`materialBinds` is how many times the frame's geometry passes set a
material's parameter group, and `materialBindsElided` how many times a
pass reached that decision and found the group already bound. Their sum
is how many times the decision was reached — once per unit of geometry
submitted, which sits at or below `draws`, since a mesh of several
primitives draws once per primitive under one set of binds. The ratio
inside the pair is what material binding costs the frame: the batched
opaque geometry is gathered into runs sharing a material, so a frame of
many such draws over few materials binds about once per material rather
than once per unit. `materialExtraBinds` and `materialExtraBindsElided`
are the same pair for the second group, the storage bindings a shader
declares for itself, which only the shaders that have them ever bind.

`pipelineBinds` and `pipelineBindsElided` are the same pair for the
pipeline itself: how many times the frame's geometry passes set one, and
how many times a pass reached that decision and found the pipeline it
wanted already bound. Which pipeline a unit needs follows its shader, its
material's render state and its mesh's vertex layout together, so a scene
whose units share all three costs one set for the run of them, while units
differing in any one of the three each pay their own. Their sum is how
many units reached the pipeline decision, which sits at or above what the
material pair reports: a unit the pass settles a pipeline for and then
abandons — one whose material group resolved to nothing — counts here and
never reaches the material decision.

Every figure here is the whole frame's, the main camera's draws and every
shadow view's summed together. `renderer.shadowViews()` splits `compacted`
and `compactedDrawn` across the views that made them, and carries the
camera's own share beside them.

```lua
local d = renderer.drawStats(); print(d.instances / math.max(d.draws, 1), "instances per draw")
print(renderer.drawStats().compactedDrawn, "of", renderer.drawStats().compacted, "survived the cull")
local d = renderer.drawStats(); print(d.materialBinds, "material binds over", d.materialBinds + d.materialBindsElided, "units")
local d = renderer.drawStats(); print(d.pipelineBinds, "pipeline sets over", d.pipelineBinds + d.pipelineBindsElided, "units")
```

## modules/renderer/feature.create {#create}

```lua
feature.create(ref: any, guid: string?): any
```

Instantiate a render feature so the engine calls its `render(ctx)` hook
every frame. `ref` is an `AssetRef<renderFeature>` whose `init.luau` returns
`{ setup?, render, teardown? }`. Returns a live `RenderFeatureHandle` (its
`guid` is the stable id, same as mesh/texture handles); tear it down with
`renderer:destroy(handle)`. Pass `guid` to assign a specific id.

**Parameters**

- `ref` `any` _(optional)_ — An `AssetRef<renderFeature>`, or a string identity/guid resolved via
`asset.resolve(ref, "renderFeature")`.
- `guid` `string?` _(optional)_ — Optional explicit handle guid (minted when omitted).

```lua
local h = renderer.feature.create(asset.resolve("acrylic", "renderFeature"))
local h = renderer.feature.create("acrylic")
```

## modules/renderer/feature.destroy {#destroy}

```lua
feature.destroy(handleOrGuid: any): boolean
```

Tear down a live render feature by its `RenderFeatureHandle` OR its guid
string — the by-id path for when the handle was lost (e.g. across `execute`
calls). Same effect as `renderer.destroy(handle)`. Returns true if a feature
was live under that id.

**Parameters**

- `handleOrGuid` `any` _(optional)_ — A `RenderFeatureHandle` or its `guid` string.

```lua
renderer.feature.destroy("eb623975-d8bd-47a1-a0a4-5c0e56238e2f")
```

## modules/renderer/feature.list {#list}

```lua
feature.list(): { { guid: string, identity: string } }
```

List every render feature currently live (running its `render(ctx)` each
frame). Each entry is `{ guid, identity }` — the `guid` is the same id a
`RenderFeatureHandle` carries, so you can tear a feature down by guid even
after losing its handle (e.g. across separate `execute` calls).

```lua
for _, f in renderer.feature.list() do print(f.identity, f.guid) end
```

## modules/renderer/feature.shaded {#shaded}

```lua
feature.shaded(): { [string]: number }
```

How many pixels each fragment pass a render feature enqueued shaded on
the last drawn frame, keyed by the pass's shader/effect name. A fragment
pass draws one triangle over its target, so it shades the whole screen
whatever its effect actually reaches — unless it declares `bounds` on the
pass spec, the world-space box its effect stays inside, in which case it
shades the rectangle that box projects into for the camera drawing it and
is skipped for a camera that cannot see the box at all. This is the reading
that says which of the two a pass is: it moves when the effect moves, and a
pass absent from it shaded nothing. Summed over every camera the frame drew.

```lua
local px = renderer.feature.shaded(); for name, n in pairs(px) do print(name, n) end
```

## modules/renderer/featureTexture.configure {#configure}

```lua
featureTexture.configure(width: number, height: number, layers: number)
```

Size the shared feature-texture array — the layers a surface shader reads
through `zero_feature_texture(uv, layer)`, and the layers a `SpotLight`
projects through its cone via `cookieLayer`. Layers are `rgba16f`.
A call for the size the array already has is left alone. One that changes
the size reallocates, and the replacement is zeroed — so it empties every
layer in the array, including the layers other features and other cookies
own. `renderer.featureTexture.state()` reports the extent and the layers
holding content, which is how a feature re-fills the layer a resize took
from it.

**Parameters**

- `width` `number` — Layer width in pixels.
- `height` `number` — Layer height in pixels.
- `layers` `number` — How many layers the array holds.

```lua
renderer.featureTexture.configure(512, 512, 4)
```

## modules/renderer/featureTexture.setLayer {#setlayer}

```lua
featureTexture.setLayer(layer: number, textureKey: string, x: number, y: number)
```

Copy a texture already on the GPU into one layer of the shared array,
its top-left corner at `(x, y)` — GPU to GPU, with no readback. Several
small images pack into one layer by calling this once per image at
different offsets. The source must be `rgba16f` and fit at that offset.

**Parameters**

- `layer` `number` — Which layer of the array to write into.
- `textureKey` `string` — The source texture's name — the one it was created under.
A `compute.createStorageTexture2D` target, a `compute.createTextureHistory`
pair (its current side), and a texture a `compute.copyBufferToTexture`
wrote all answer to the name they were given.
- `x` `number` — Left edge of the destination rectangle, in pixels.
- `y` `number` — Top edge of the destination rectangle, in pixels.

```lua
compute.createStorageTexture2D("gobo", { width = 256, height = 256, format = "rgba16f" })
renderer.featureTexture.setLayer(0, "gobo", 0, 0)
```

## modules/renderer/featureTexture.state {#state}

```lua
featureTexture.state(): {
```

What the shared feature-texture array is right now: the extent every
layer carries, and `filled`, the ascending 0-based indices of the layers a
`setLayer` has landed in since the array was last sized. One array is
shared by every feature and every light cookie in the scene, and it has no
allocator, so this is the call that tells a feature whether the array it
sized and filled is still the array it is writing into — a `configure` that
changed the size reallocates and zeroes every layer, and the layer it
emptied leaves `filled` without it. Measured off the renderer at the end of
the last rendered frame, so a `configure` or `setLayer` issued this frame
reads back on a later one.

What this describes is the array a shader samples. The source texture a
`setLayer` copied FROM is a GPU resource of its own and keeps the bytes it
was written with for as long as it lives, so `filled` is the reading that
answers whether the layer behind a `cookieLayer` is live right now.

```lua
local ft = renderer.featureTexture.state()
print(("feature textures: %dx%d over %d layers"):format(ft.width, ft.height, ft.layers))
-- Re-fill the cookie layer this module owns if anything emptied it.
if ft.width ~= myWidth or table.find(ft.filled, myLayer) == nil then
refillMyCookie()
end
```

## modules/renderer/framePacing {#modules-renderer-framepacing}

```lua
framePacing(): FramePacing?
```

How far the CPU is allowed to run ahead of the GPU, and what holding it
there cost the frame just finished. Submitting work to the GPU returns
before the GPU has done it, and everything that submission holds — its
staging allocations, its bind groups, its command buffer — stays alive
until it completes. A frame that asks for more work than the GPU finishes
in a frame's time therefore leaves that behind it, and unbounded that is
memory growth rather than a lower frame rate.

`framesInFlight` is how many submitted frames have not reported done
through the queue's completion signal, held under `maxFramesInFlight`: a
device that keeps up reads under the bound, one that is behind reads at it.
It counts submissions, which is its own quantity — how many presented
images the swapchain permits in flight is a separate setting.
`mechanism` names how that bound is enforced
here: `submission-wait` waits for the frame that many frames back and
reports the wait in `waitMs`, so a paced frame costs latency and still
draws; `submitted-work-done` counts outstanding frames off the queue's
completion signal and declines to start a frame while the bound is met,
counting those in `pacedFrames` and leaving the last presented image up.
`submittedFrames` counts the frames that were admitted and submitted, so it
rises for as long as the renderer is producing frames — which is what tells
a renderer running slowly under a tight bound from one that has stopped.
`stalled` reads true while that completion signal has stopped arriving and
the pacer stood down rather than hold the image indefinitely; it clears on
the first frame that finds the count back under the bound.

`producing` is whether the renderer is drawing frames at all. A headless
renderer draws into an offscreen framebuffer that nothing presents, so its
image reaches a reader only through something that copies it out: it draws
while a consumer is asking — an MCP call in flight, a queued texture
readback, a recording, a frame-egress session — and declines the frames
between two asks, counting them in `idleSkippedFrames`. Every other
renderer stat answers with the last frame that drew, so `producing` is what
separates a live reading from a frozen one. A windowed renderer presents
every frame it draws and reads `producing = true` throughout.

`presentMode` is what the surface presents with and `presentModes` what it
offers; both are empty of meaning on a headless renderer, which never
presents.

```lua
local p = renderer.framePacing()
print(("%d of %d frames in flight, paced by %s"):format(p.framesInFlight, p.maxFramesInFlight, p.mechanism))
```

## modules/renderer/getRaytrace {#modules-renderer-getraytrace}

```lua
getRaytrace(): boolean
```

Whether ray tracing is currently enabled.

## modules/renderer/gpuMemory {#modules-renderer-gpumemory}

```lua
gpuMemory(): GpuMemory
```

Where the renderer's GPU memory went at the last completed frame — the
call to reach for when something is holding memory and you do not know
what.

Three figures answer three different questions, and they are meant to be
read against each other:

* The categories — `shadow`, `textures`, `meshes`, `instances`, `compute`,
summing to `categorised` — are the renderer's own accounting of what it
asked for on purpose. Always present, on every backend.
* `allocator` is the device allocator's ledger, with a row per creation
label largest first, which is what names an allocation no category
claims. It exceeds `categorised` by the per-frame render targets and the
scratch nothing categorises. The allocator hands memory out from blocks
it reserves whole from the device and returns a block only once nothing
is left in it, so `reservedBytes` runs above `allocatedBytes` by what
those blocks hold unused; `blocks` lists them emptiest first with the
labels that keep each one alive, and `emptyBytes` plus `slackBytes` is
that distance exactly — the pool held in empty blocks, and the room
pinned inside blocks something still sits in.
* `driver.deviceLocalBytes` is what the graphics driver charges this
process, out of the kernel's own accounting. It is the biggest of the
three and the one that fills a card, because it also holds the
swapchain, the images the driver keeps on the renderer's behalf, and the
rounding to whole pages and heap blocks that neither figure above sees.
Read it when the question is how much of the machine's GPU this engine
is using; read the two above when the question is what the engine spent
it on. A platform with no per-process accounting reports
`available = false` and the reason.
* `driver.outsideAllocatorBytes` is that charge less everything the
allocator reserved — what the driver holds on its own account, and the
one figure here nothing releases: a dropped pipeline, another scene and
`renderer.collect()` all leave it where it is, and it falls when the
device is destroyed. Read it when a session's device memory has grown
and no ledger row accounts for the growth.

`compute` is what the compute subsystem holds; `compute.observe()` names
each of those resources and what it costs. `renderTargets` counts the
offscreen render targets the renderer holds at that frame, which is what
says a `renderer.destroy` has been applied rather than queued.

```lua
local m = renderer.gpuMemory()
print(("shadows %.1f MiB"):format(m.shadow.total / 1024 / 1024))
-- how much of the card this engine is holding:
if m.driver.available then
print(("driver %.1f MiB"):format(m.driver.deviceLocalBytes / 1024 / 1024))
else
print("no driver figure: " .. m.driver.reason)
end
-- the biggest allocation in the engine:
local top = m.allocator and m.allocator.byLabel[1]
print(top and top.label, top and top.bytes)
-- the block held for the least, and what pins it:
local block = m.allocator and m.allocator.blocks[1]
if block and block.allocationCount > 0 then
print(block.size, block.allocatedBytes, block.byLabel[1].label)
end
```

## modules/renderer/hold {#modules-renderer-hold}

```lua
hold(handleOrKind: any, id: string?): boolean
```

Pin a runtime resource for the session. A held texture, material, mesh
or render feature survives every collection — the one a root scene load
runs and a direct `renderer.collect()` alike — until `renderer.release`
lets it go or its destroy frees it. It is the way to keep an ad-hoc
resource across the scenes that come and go under it. A hold keeps the
resource in the registry; a mesh's GPU buffers are governed by what draws
it, parked as a CPU definition when the last instance naming it goes and
brought back when one names it again, so `renderer.mesh.isResident(guid)`
is the separate question about the buffers.

**Parameters**

- `handleOrKind` `any` _(optional)_ — The resource's handle, or its kind (`"texture"`, `"material"`,
`"mesh"`, `"feature"`) with the guid or key as the second argument.
- `id` `string?` _(optional)_ — The guid or key, when the first argument is a kind.

```lua
renderer.hold(tex)
renderer.hold("material", "swatch")
```

## modules/renderer/instanceData.clear {#clear}

```lua
instanceData.clear(target: string | entityRef)
```

Drop every lane of an entity's per-instance shader data, so its draws
read zero again — how a feature releases a subject it is still holding.
Despawning an entity releases its block too, so this is for a subject that
stays. It takes an entity that has already gone, which is when a feature
releasing its subjects often runs, and does nothing for an entity holding
no block.

**Parameters**

- `target` `string | entityRef` — The entity — a proxy from `entity(...)` / `entity.spawn(...)`, or
an entity-id string.

```lua
renderer.instanceData.clear(subject)
```

## modules/renderer/instanceData.laneCount {#lanecount}

```lua
instanceData.laneCount(): number
```

How many `vec4` lanes each entity's per-instance block holds, so a lane
index runs `0 .. laneCount() - 1`. The same count a surface shader indexes
`input.shader_data` against.

```lua
for lane = 0, renderer.instanceData.laneCount() - 1 do
renderer.instanceData.set(subject, lane, 0)
end
```

## modules/renderer/instanceData.set {#set}

```lua
instanceData.set(
```

Write one `vec4` lane of an entity's per-instance shader data — the
channel that lets ONE material serve many entities that differ in a value.
A surface shader reads the lane back as `input.shader_data[lane]`, so a
dissolve at its own progress per subject, an effect at its own age per
firing, or a per-entity mask costs one material rather than one material
per entity.

The engine attaches no meaning to a lane: a feature picks the lane indices
it owns and packs whatever its shader agrees they carry. Name those indices
in the module that writes them, so the writer and the shader read the block
the same way.

The write reaches the block where it is called, so the entity it names is
the one holding that id at that point in the tick, and the value is on the
draw from the next frame. It is held until the lane is written again, the
entity's block is cleared, or the entity is despawned — a despawned entity
releases its whole block. A lane an entity was never given reads zero.

## modules/renderer/loseDevice {#modules-renderer-losedevice}

```lua
loseDevice()
```

Destroy the render device on the next frame, so the engine meets a real
device loss.

This is the one loss that can be caused on purpose, and it travels the same
path a driver reset does: frames draw nothing until the rebuild lands,
`GET /engine/status` reports the renderer as `recovering` while it does,
`engine.onDeviceRebuilt` fires afterwards, and `renderer.deviceGeneration()`
moves. Use it to prove that a world's content survives a device loss —
anything it holds only on the GPU has to be remade from the rebuild hook, and
this is how you find out whether it is.

```lua
renderer.loseDevice()
-- some frames later:
print(renderer.deviceGeneration()) -- one higher than before
```

## modules/renderer/mainCameraView {#modules-renderer-maincameraview}

```lua
mainCameraView(): { number }?
```

The main camera's inverse view-projection (column-major, 16 numbers)
followed by its world position (3 numbers) — `{m0..m15, px,py,pz}` — for
reconstructing world positions from the depth buffer in a ray-tracing pass.
Nil before the first render.

## modules/renderer/material.animatedTexture {#animatedtexture}

```lua
material.animatedTexture(
```

Build a material that PLAYS a layered texture: its layers bound as the
frames, its timing bound beside them, and the engine's `animatedTexture`
shader turning the clock into the layer showing now. One call from an
imported animated image to a material an entity can wear.

The layer showing is resolved per pixel against the texture's own schedule,
so frames of unequal length are shown for the lengths they were authored
with, and the sequence loops. `speed` scales the clock (2 plays twice as
fast, 0 holds the frame `startTime` lands in) and `startTime` offsets into
the sequence, so two surfaces sharing one texture can run out of phase.

The clock is the engine's, and it runs in edit mode as much as in play and
through a pause, so two screenshots of one surface taken moments apart are
two different frames of it. `speed = 0` holds one frame for as long as it
is set, which is the state to compare two screenshots in.

The returned handle is what a surface wears — `Model:applySessionMaterial`
takes it, and so does a Model's `material` field. The handle's `guid` is
this material's REGISTRY KEY, the currency of `setProperty`, `describe` and
`destroy`; a component field resolves an asset, so a bare key in one leaves
the component waiting for an asset to register under that name.

The builtin `plane` mesh emits `uv = (u, v)` with `v` along its own +Z, so
a quad pitched +90° about X (`Transform.eulerToQuat(0, math.pi / 2)`) shows
the image upright to a camera on +Z, and -90° shows it first-row-last.

A texture whose layers carry no timing is rejected — there is nothing to
play. `renderer.texture.info(bytes).animated` is the test.

```lua
local mat = renderer.material.animatedTexture("banner.texture")
local id = entity.spawn("billboard", { rotation = { Transform.eulerToQuat(0, math.pi / 2) } })
entity(id).component.add("Model", { model = "plane" })
entity(id).component.get("Model"):applySessionMaterial(mat)
renderer.material.setProperty(mat.guid, "speed", 2)
```

## modules/renderer/material.create {#create}

```lua
material.create(content: MaterialContent, key: string): MaterialHandle
```

**Parameters**

- `content` `MaterialContent`
- `key` `string`

## modules/renderer/material.describe {#describe}

```lua
material.describe(key: string | { [string]: any } | AssetRef): any
```

The recoverable definition (`{ shader, properties, textures, name }`)
this module registered under `key` via `renderer.material.create`, or nil
for keys registered elsewhere (e.g. material assets resolved by the
assetType). `properties` and `textures` carry the material's current values:
each `setProperty` / `setTexture` write lands on this record, a texture slot
under the GPU key the slot binds by — these are the WRITES, held here
whether or not the renderer took them up. `renderer` beside them is what the
renderer holds for the same key: the program its prepared bind group was
built against, the render state its draws are looked up under, whether a
pipeline exists for that key, and how many draws the observed frame gave
it. `renderer` is nil when the renderer holds no material under this key at
all, and `resident` states the same fact as a boolean. Writes reach the
screen through both halves: `resident = false` says the renderer holds
nothing to put them in, and `renderer.draws = 0` on a resident material
says it holds them and no renderable is drawing with it. For a material
that is resident AND drawn and still looks wrong,
`renderer.drawDiagnostics()` names the renderable and the cause.

**Parameters**

- `key` `string | { [string]: any } | AssetRef` — The material's registry key, the `MaterialHandle` from
`renderer.material.create`, or an `AssetRef` from `asset.resolve`.

## modules/renderer/material.destroy {#destroy}

```lua
material.destroy(key: string | { [string]: any } | AssetRef): boolean
```

Drop a runtime material registered via `renderer.material.create`: clears
its recoverable definition, unregisters its runtime-resource stamp so it is no
longer swept into the material freeze/save flow, and frees the GPU record. Use
for transient materials (e.g. a preview swatch) that must not outlive their use.
The on-disk asset, if any, is untouched.

The reach is the registry: after this, `describe` and `list` stop answering
for the key. A surface already wearing the handle goes on drawing what it
was given — `Model:restoreSessionMaterial` is what puts a Model back on its
authored material.

**Parameters**

- `key` `string | { [string]: any } | AssetRef` — The material's registry key (the one passed to `create`), the
`MaterialHandle` `create` returned, or an `AssetRef` from `asset.resolve`.

```lua
renderer.material.destroy("__preview_swatch_" .. texGuid)
```

## modules/renderer/material.list {#list}

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

Every runtime material currently registered, ordered by registry key.
Each entry carries the key, where it came from, and the shader it binds.
`renderer.references("material", key)` says what is still holding a row,
and `renderer.collect()` releases the rows nothing holds.

```lua
for _, m in ipairs(renderer.material.list()) do print(m.guid, m.shader) end
```

## modules/renderer/material.renderState {#renderstate}

```lua
material.renderState(key: string | { [string]: any } | AssetRef): MaterialObservation?
```

What the renderer holds for a material, which is a different document
from the values written to it. `shader` is the program its prepared bind
group was built against, `renderState` the blend / cull / topology / queue /
depth key its draws are looked up under, `keyBuilt` whether a pipeline
exists for that key, and `draws` / `instances` / `placeholderDraws` /
`binds` / `bindsElided` what it cost in the frame the renderer last
observed — those five read 0 until something arms per-draw recording, which
`renderer.materialCost()` and
`renderer.drawDiagnostics()` do. `nil` means the renderer holds no material
under this key at all — the writes landed on a record nothing is drawing
with.

**Parameters**

- `key` `string | { [string]: any } | AssetRef` — The material's registry key, the `MaterialHandle` from
`renderer.material.create`, or an `AssetRef` from `asset.resolve`.

```lua
local r = renderer.material.renderState("water"); print(r.renderState.blend, r.keyBuilt)
```

## modules/renderer/material.sessionKeyFor {#sessionkeyfor}

```lua
material.sessionKeyFor(entityId: string): string
```

The canonical registry key for an entity's SESSION material — the
runtime material a system (e.g. GI baking) shows on an entity in place
of its authored material for the lifetime of the engine session. One
session material per entity: create it under this key, hand the handle
to `Model:applySessionMaterial`, and the component re-adopts it across
VM reloads by probing this key with `describe`. The key names the entity
for as long as the entity stands: once it is gone the session store lets
the handle go, and a collection releases the material and whatever its
bindings were the last to hold.

**Parameters**

- `entityId` `string` — The entity carrying the material.

```lua
local key = renderer.material.sessionKeyFor(entityId)
```

## modules/renderer/material.setProperty {#setproperty}

```lua
material.setProperty(key: string | { [string]: any } | AssetRef, name: string, value: any): ()
```

Push one changed uniform property to a registered material's GPU record
(frame-fast incremental update; no re-register). Keyed by the material's
registry key. The value written becomes the material's current one: it is
what `describe` reports, and — for a property the material's shader
declares, which is what the uniform buffer is packed by — what a material
`AssetRef` reads back through `getProperty` / `getProperties` and what the
surface is drawn with. A write under any other name reaches the record
`describe` reports, which is where it reads back.

**Parameters**

- `key` `string | { [string]: any } | AssetRef` — The material's registry key, the `MaterialHandle` from
`renderer.material.create`, or an `AssetRef` from `asset.resolve`.
- `name` `string` — Property name.
- `value` `any` _(optional)_ — New value.

```lua
renderer.material.setProperty(asset.resolve("wall", "material"), "roughness", 0.2)
```

## modules/renderer/material.setTexture {#settexture}

```lua
material.setTexture(key: string | { [string]: any } | AssetRef, slot: string, ref: string | { [string]: any } | AssetRef): ()
```

Push one changed texture slot to a registered material's GPU record.
Keyed by the material's registry key.

**Parameters**

- `key` `string | { [string]: any } | AssetRef` — The material's registry key, the `MaterialHandle` from
`renderer.material.create`, or an `AssetRef` from `asset.resolve`.
- `slot` `string` — Texture slot name (`"base_color_texture"`, …).
- `ref` `string | { [string]: any } | AssetRef` — Texture reference — a `.texture` guid / identity / name / path, the
image path it was imported from, a `color:` / `default:` form, a live GPU
handle, or a texture `AssetRef` carrying one. An asset reference is
materialised (Disk→CPU→GPU) and bound by the key the upload lands under.

```lua
renderer.material.setTexture("sky", "sky_texture", "panorama.texture")
```

## modules/renderer/materialCost {#modules-renderer-materialcost}

```lua
materialCost(): { MaterialObservation }
```

What each material cost the frame the renderer last drew, and the state
it holds each one under. One row per material the renderer holds a prepared
bind group for — a material an author wrote and the renderer never prepared
is absent, which is itself the answer to "why is nothing I set reaching the
screen". `draws` and `instances` cover that one frame; `placeholderDraws`
is how many of those draws bound the magenta placeholder instead of this
material's own program; `binds` is how many material-owned bind groups the
frame's passes SET for it and `bindsElided` how many of its draws wanted a
group the pass already held, which is what draw-key sorting buys; a draw
that fell back to the placeholder bound the placeholder's group, so it
counts in `placeholderDraws` and in neither bind count. `uniformBytes` is
the GPU uniform buffer's own size,
which is the reflected property block raised to the 16-byte floor and
rounded up to the copy alignment. `renderer.drawDiagnostics()` names WHICH
renderable is not drawing what its material says, and why.

```lua
for _, m in renderer.materialCost() do print(m.material, m.draws, m.binds, m.bindsElided) end
```

## modules/renderer/materialIdentity {#modules-renderer-materialidentity}

```lua
materialIdentity(): MaterialIdentity
```

Which material each renderable draws with, as a number a shader can
carry. A material is authored and bound by name, and no shader can read a
string — so every renderable's per-instance record holds a material index
instead. `slots` is the name → index table those indices are drawn from: an
index is assigned the first time the renderer draws with that material and
does not move afterwards, so two renderables that differ only in material
read different indices, and one renderable reads the same index frame after
frame. It follows that the table keeps a row for every material name drawn
this session, whether or not anything still draws with it. `renderables` is
a row per renderable that owns a GPU slot — the entity it belongs to, that
slot, and the index the record at it carries; `populations` is the same for
an instanced draw, whose whole reserved run of slots carries the one
material its registration named. That index is what a shader reads as
`instance_data[slot].material_index`, and the row a ray hit resolves
through `zeroMaterial()`. A renderable draws with the material its entity
references, so one whose entity names none carries index 0.

```lua
local id = renderer.materialIdentity()
for _, r in id.renderables do print(r.entity, r.slot, r.index, r.material) end
```

## modules/renderer/materialIndex {#modules-renderer-materialindex}

```lua
materialIndex(name: string): number?
```

The index standing for a material, or `nil` for one the renderer has not
drawn with yet. Pass it to a shader (or compare it against what a shader
read out of `instance_data[slot].material_index`) to tell which material a
drawing instance carries.

**Parameters**

- `name` `string` — `string` Material name, as `renderer.material.create` filed it.

```lua
local red = renderer.materialIndex("brick_red")
```

## modules/renderer/maxAnisotropy {#modules-renderer-maxanisotropy}

```lua
maxAnisotropy(): number
```

The highest anisotropy this device honours: 16 on hardware that filters
anisotropically, 1 on hardware that does not, where a higher request would
be downgraded to trilinear regardless. Read it to report quality honestly —
`renderer.setAnisotropy` clamps for you, so a request never needs guarding.

```lua
local best = renderer.maxAnisotropy()
```

## modules/renderer/maxViewportExtent {#modules-renderer-maxviewportextent}

```lua
maxViewportExtent(): number
```

The largest number of pixels this device draws a surface at, per axis
— the bound `renderer.setViewportSize` refuses past. `0` before the first
frame has drawn.

```lua
local bound = renderer.maxViewportExtent()
```

## modules/renderer/mesh.boundsSource {#boundssource}

```lua
mesh.boundsSource(mesh: string | { [string]: any } | AssetRef): string
```

Where this mesh's culling bounds come from. `"compute"` once a compute
pass has written its vertices: the engine reduces those vertices to an AABB
every frame, so the mesh is culled against the geometry the pass produced
wherever it puts it. `"geometry"` otherwise: the AABB of the geometry the
mesh was created with.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh — a `MeshHandle`, a `MeshCpuHandle`, a guid, or a mesh `AssetRef`.

```lua
print(renderer.mesh.boundsSource(mesh))
```

## modules/renderer/mesh.buildClusters {#buildclusters}

```lua
mesh.buildClusters(mesh: string | { [string]: any } | AssetRef): string?
```

Build a cluster-LOD DAG (Nanite-style virtualized geometry) for the
static CPU mesh held under `guid` and return its serialized `data.clusters`
bytes. Returns nil when the mesh is degenerate, and on an engine whose
`renderer.mesh.canBuildClusters` reports false. Pair with
`renderer.mesh.uploadClusters`.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — A mesh loaded into the CPU store (`renderer.mesh.loadCpu`) — the
`MeshCpuHandle`, a `MeshHandle`, a guid, or a mesh `AssetRef`.

```lua
local cb = renderer.mesh.buildClusters(cpu)
```

## modules/renderer/mesh.canBuildClusters {#canbuildclusters}

```lua
mesh.canBuildClusters(): boolean
```

Whether this engine bakes cluster-LOD hierarchies. It reads the binding
the running engine registered: every target the engine ships on carries the
builder, so a mesh loaded in a browser bakes its own clusters the same way
one loaded natively does, and an engine built without it reports false and
answers nil from `renderer.mesh.buildClusters`.

```lua
if renderer.mesh.canBuildClusters() then ... end
```

## modules/renderer/mesh.clusterBakeBudget {#clusterbakebudget}

```lua
mesh.clusterBakeBudget(ms: number?): number
```

The wall time one frame may spend advancing scheduled cluster bakes, in
milliseconds — set first when `ms` is given. A slice always runs at least
one unit of the build, so the budget bounds what a frame spends by choice
and the largest single unit a mesh imposes sets the floor under it.

**Parameters**

- `ms` `number?` _(optional)_ — New per-frame budget in milliseconds, capped at 1000. A value that is
not a positive, finite number raises.

```lua
renderer.mesh.clusterBakeBudget(2)
```

## modules/renderer/mesh.clusterBakes {#clusterbakes}

```lua
mesh.clusterBakes(): { [string]: any }
```

What the scheduled cluster bakes are costing. `budgetMs` is the slice a
frame may spend, `pending` how many bakes are queued, `completed` how many
have finished since the engine started, `dropped` how many left the queue
because the geometry they were scheduled over stopped being readable, and
`heldBytes` the source geometry the queue is holding across all of them —
the vertex pool and index run the bake at the head is reading, plus a copy
for each queued mesh the engine holds no definition for.
`inFlight` is one row per queued bake —
`{ guid, cpuMs, frames, slices, bytes, state }`: the wall time spent
advancing it, the frames it has been queued for, the slices it has been
advanced by, the geometry it is holding, and `"baking"` for the one being
advanced against `"queued"` for the ones waiting their turn.

```lua
print(renderer.mesh.clusterBakes().heldBytes)
```

## modules/renderer/mesh.clusterComponents {#clustercomponents}

```lua
mesh.clusterComponents(clusterBytes: buffer | string): (ClusterComponents?, string?)
```

Split a cluster blob (from `renderer.mesh.buildClusters`) into its
GPU-ready component byte pools — the cluster vertex pool, the
geometry-addressing pool (every cluster's local→global vertex map, then
every cluster's triangle bytes), and the per-cluster record array — plus
their counts. A cluster's triangles address positions inside its own vertex
map one byte at a time, and a record's `vertexOffset` indexes the geometry
pool in `u32` elements while its `indexOffset` indexes it in bytes, so ONE
binding resolves a corner. A pure decode (no GPU work): upload the pools
into buffers a compute shader owns (`shaderRef:createBuffer` +
`buf:writeBytes`) to drive a cluster draw from Luau.

**Parameters**

- `clusterBytes` `buffer | string` — Serialized cluster bytes (binary-safe).

```lua
local c = renderer.mesh.clusterComponents(cb)
```

## modules/renderer/mesh.clusters {#clusters}

```lua
mesh.clusters(mesh: string | { [string]: any } | AssetRef): { [string]: any }?
```

The shape of the cluster-LOD hierarchy the renderer holds for a mesh:
`clusterCount` across every level, `levelCount` with the finest counted as
one, and `triangleCount` across every cluster. The renderer keys one entry
per mesh that carries a hierarchy, so this answers whether the mesh has
clusters as well as what they are — nil for a mesh that carries none.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh to read — a `MeshHandle`, a `MeshCpuHandle`, a guid, or a mesh `AssetRef`.

```lua
local c = renderer.mesh.clusters(gpu) ; if c then print(c.levelCount) end
```

## modules/renderer/mesh.create {#create}

```lua
mesh.create(src: any, guid: string?): MeshHandle
```

Create (or fetch) a GPU mesh resource and return its `MeshHandle`. `src`:
a `MeshCpuHandle` from `meshRef:load()` (CPU→GPU upload under the asset's
guid, idempotent — returns the resident handle if already uploaded); raw
geometry `{positions, indices, normals?, uvs?, colors?, uvs1?, unwrapUvs?,
tangents?, skinning?, skins?}` (a new runtime mesh — `uvs1` is the lightmap
UV set, `unwrapUvs` generates one, `skinning`/`skins` bind a skeleton); GPU
compute buffers `{vertexBuffer, indexBuffer, vertexCount, indexCount,
aabbMin?, aabbMax?, prevVertexBuffer?}` (size the vertex buffer at
`vertexCount * engine.vertexStride` bytes, the engine's standard Vertex
layout); or a `MeshHandle` (returned as-is). NEVER takes an AssetRef —
load the CPU first.

`prevVertexBuffer` is a second buffer of the same size and layout holding
those vertices as they stood on the previous frame. Naming it is what makes
geometry a compute pass moves report a motion vector: the surface
differences the two streams, so every consumer of screen-space velocity —
motion blur, temporal reprojection — sees the movement. The engine fills it
from the current vertices once per frame, ahead of that frame's compute
dispatches, so a frame in which the pass does not run leaves the two
streams equal and the geometry reports standing still.

`morphTargets` are the shapes the mesh can blend towards: a list of
`{ name?, positions, normals? }` records, each holding one offset per vertex
from the base geometry, in the mesh's own vertex order. An entity blends
them with `ecs.MorphWeights`, weight `i` scaling target `i`. A `name` makes
the shape addressable as itself — `renderer.mesh.morphTargets` reads the
names back and `renderer.mesh.morphWeights` drives them by name.

Raw geometry is read against the mesh type's conventions: `indices` count
vertices from 0, and a triangle's FRONT face is the one whose vertices turn
counter-clockwise as the viewer sees them — `cross(v1 - v0, v2 - v0)` points
out of it. A material culls its back faces by default, so a triangle wound
the other way draws nothing where it stands; reverse the index triple, or
give the material `render = { cull = "none" }`, to draw that side. `normals`
give the surface its outward direction and shade the face; the side that
draws comes from the index order alone. `uvs` sample `(0,0)` at the image's
top-left. Model space carries the world's basis: +X right, +Y up, -Z the
direction `transform.forward` points. `guides { path = "types/mesh" }` has
the whole table.
A geometry src carrying `keepCpu = true` also keeps its geometry in the
guid-keyed CPU store, so `renderer.mesh.getVertices` reads it and
`renderer.mesh.setVertices` rewrites its positions in place — the per-frame
deformation path, which sends positions alone where `renderer.mesh.update`
re-sends the whole geometry. `renderer.mesh.unloadCpu(mesh)` releases that
copy. Without it the geometry lives on the GPU alone and
`renderer.mesh.readback(mesh)` is what brings it back.

**Parameters**

- `src` `any` _(optional)_ — A MeshCpuHandle, geometry, compute buffers, or a MeshHandle.
- `guid` `string?` _(optional)_ — Optional v4 guid for a NEW runtime mesh (minted Luau-side when
absent). Ignored for the CPU-handle path (the asset's guid is used).

```lua
local gpu = renderer.mesh.create(meshRef:load())
local gpu = renderer.mesh.create({ positions = {...}, indices = {...} })
-- a runtime mesh whose positions are rewritten in place each frame
local m = renderer.mesh.create({ positions = P, indices = I, keepCpu = true })
renderer.mesh.setVertices(m, P)
-- a runtime mesh carrying a lightmap UV set (unwrapped at creation)
local gpu = renderer.mesh.create({ positions = {...}, indices = {...}, unwrapUvs = true })
-- a mesh with one shape to blend towards, driven by ecs.MorphWeights
local gpu = renderer.mesh.create({ positions = P, indices = I, morphTargets = { { positions = D } } })
```

## modules/renderer/mesh.decode {#decode}

```lua
mesh.decode(zmsh: buffer | string): (MeshGeometry?, string?)
```

Decode engine-native `ZMSH` bytes back into a `MeshGeometry`. Inverse of
`renderer.mesh.encode`; each optional stream is present only when the blob
carries it. Takes the bytes themselves — the geometry of a mesh the engine
is holding comes from `renderer.mesh.geometry(mesh)`.

**Parameters**

- `zmsh` `buffer | string` — Engine-native ZMSH bytes (binary-safe).

```lua
local geom = renderer.mesh.decode(meshRef:getBytes())
```

## modules/renderer/mesh.destroy {#destroy}

```lua
mesh.destroy(mesh: string | { [string]: any } | AssetRef): boolean
```

Release the GPU mesh `mesh` names, the release that pairs with
`renderer.mesh.create`. Takes every form that names a mesh — the
`MeshHandle` `create` returned, the guid `renderer.mesh.list` hands out, a
`MeshCpuHandle` or a mesh `AssetRef` — and routes through
`renderer.destroy`, the verb that releases any renderer resource by its
kind. The CPU copy, if one was loaded, is freed separately by the CPU
handle's `:unload()`.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh to release — a `MeshHandle`, a guid, a `MeshCpuHandle` or a
mesh `AssetRef`.

```lua
local m = renderer.mesh.create(cpu); renderer.mesh.destroy(m)
renderer.mesh.destroy(renderer.mesh.list()[1].guid)
```

## modules/renderer/mesh.drawInstanced {#drawinstanced}

```lua
mesh.drawInstanced(mesh: string | { [string]: any } | AssetRef, opts: any): InstancedDraw
```

Draw one mesh `instanceCount` times in a single call, each copy placed by
a world matrix read from a GPU buffer. The population is a renderable in its
own right — it goes through the mesh's ordinary pipeline and the material's
ordinary bind groups, so it appears in the deferred pass, the forward passes
and the shadow maps exactly as an entity-backed draw of that mesh does.

The buffer holds `instanceCount` **column-major** 4x4 matrices, 64 bytes
each, tightly packed — the layout a vertex shader reads as
`array<mat4x4<f32>>`, which puts each matrix's translation in its LAST four
floats (Lua indices 13/14/15 for x/y/z). Packing row-major transposes every
instance.

The matrices are COPIED into the engine's transform slots once per frame,
which is what buys that full-pass parity. Rewrite the buffer between frames
and the instances move — no re-registration, no re-upload.

`material` is what the population draws with, and it is required: a
`MaterialHandle` (`matRef:handle()`), an `AssetRef`, or a registry key.

`instanceDataBuffer` names a second buffer, holding 64 bytes per instance —
four `vec4` lanes, tightly packed, in instance order. Those lanes arrive in
the fragment stage as `zero_object_data(in.instance_id, lane)`, the same
read a per-entity `__instancedata` block answers, so the members of one
population can differ in whatever their material's shader agrees the lanes
carry. Copied every frame like the transforms, from a buffer a compute pass
writes: the values never touch the CPU. Omit it and the lanes read zero.

`reserveCount` sizes the reservation above `instanceCount` so
`renderer.mesh.setInstanceCount` can raise the drawn count later without
re-registering; both buffers must back the reservation, not just the count.

`mobility` states whether the copies stand still — `"static"`, or
`"movable"` when it is left out. It is what a scene gather collecting
geometry for precomputed lighting admits a population on, the same
declaration `Model.mobility` makes for an entity: the transforms live in a
buffer anything may rewrite between frames, so a population that says
nothing is taken as one that moves.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh the population draws — a `MeshHandle`, the guid
`renderer.mesh.list` hands out, a `MeshCpuHandle` or a mesh `AssetRef`. A
registration holds the mesh on the device for as long as it lives, and takes
a mesh that is currently held off the device — one nothing displays — back
onto it.
- `opts` `any` _(optional)_ — `{ transformBuffer, instanceCount, material, instanceDataBuffer?, reserveCount?, renderLayer?, castsShadows?, mobility? }`.

```lua
local m = renderer.mesh.create({ positions = ..., indices = ... })
local buf = substrate.createBuffer({
name = "crowd.xf", type = "mat4", len = 64, kind = "gpu",
})
-- Column-major: translation lives at indices 13/14/15.
local xf = {}
for i = 0, 63 do
local m4 = { 1,0,0,0, 0,1,0,0, 0,0,1,0, i * 2, 0, 0, 1 }
for _, v in ipairs(m4) do xf[#xf + 1] = v end
end
buf:write(xf)
local rock = asset.resolve("rock", "material"):handle()
local draw = renderer.mesh.drawInstanced(m, { transformBuffer = "crowd.xf", instanceCount = 64, material = rock })
```

## modules/renderer/mesh.dropClusters {#dropclusters}

```lua
mesh.dropClusters(mesh: string | { [string]: any } | AssetRef): boolean
```

Detach a mesh's cluster-LOD hierarchy and cancel a bake still in flight
for it, so the renderer holds none for it. The inverse of
`renderer.mesh.uploadClusters`.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh to detach — a `MeshHandle`, a `MeshCpuHandle`, a guid, or a mesh `AssetRef`.

```lua
renderer.mesh.dropClusters(gpu)
```

## modules/renderer/mesh.dropInstanced {#dropinstanced}

```lua
mesh.dropInstanced(draw: InstancedDraw): boolean
```

Release an instanced-draw registration and the transform slots it
reserved. The mesh and the transform buffer outlive it — destroy those
through `renderer.destroy` and the buffer handle's `:destroy()`.

**Parameters**

- `draw` `InstancedDraw` — The `InstancedDraw` to release.

```lua
renderer.mesh.dropInstanced(draw)
```

## modules/renderer/mesh.encode {#encode}

```lua
mesh.encode(geom: MeshGeometry): (string?, string?)
```

Encode raw geometry into engine-native `ZMSH` bytes (the on-disk mesh
payload). The CPU codec behind the mesh assetType's `onCreate`. Every stream
the format carries — including tangents, per-vertex skinning, and the
skeleton — round-trips back through `renderer.mesh.decode`. This pair moves
DATA the caller is holding; the geometry of a mesh the ENGINE is holding
comes from `renderer.mesh.geometry(mesh)`.

**Parameters**

- `geom` `MeshGeometry` — `MeshGeometry` — flat per-vertex float / u32 arrays plus optional `skinning` and `skins`.

```lua
local bytes = renderer.mesh.encode({ positions = {...}, indices = {...} })
local bytes = renderer.mesh.encode(renderer.mesh.geometry(meshHandle))
```

## modules/renderer/mesh.encodeCpu {#encodecpu}

```lua
mesh.encodeCpu(mesh: string | { [string]: any } | AssetRef): string
```

Encode a mesh's resident CPU copy into `ZMSH` bytes. Reads the ONE
guid-keyed CPU store — `meshRef:load()` populates it for assets, and
`renderer.mesh.readback(mesh)` populates it for a runtime mesh. Errors
loudly when the mesh has no resident CPU copy.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh — a `MeshHandle`, a `MeshCpuHandle`, a guid, or a mesh `AssetRef`.

```lua
local bytes = renderer.mesh.encodeCpu(handle)
```

## modules/renderer/mesh.geometry {#geometry}

```lua
mesh.geometry(mesh: string | { [string]: any } | AssetRef): MeshGeometry
```

The complete geometry of a mesh the engine is holding, as a
`MeshGeometry` — the same shape `renderer.mesh.create` and
`renderer.mesh.encode` take, carrying every stream the mesh has
(`positions`, `indices`, and whichever of `normals`, `uvs`, `colors`,
`uvs1`, `tangents`, `skinning`, `skins` it was built with). The read that
pairs with `create`: hand it the `MeshHandle` `create` returned and get the
vertex data back. Reads the resident CPU copy when there is one; for a
runtime mesh that lives only on the GPU it reads the geometry back off the
GPU first (yielding a frame or two) and leaves CPU residency as it found it.
An optional stream is present only when the mesh carries one, so `uvs1 ==
nil` is the answer to whether it has a second UV set. The drawable mesh
the renderer holds carries the tangent basis its positions, uvs and normals
determine — supplied by the caller, or derived at the ingest that made it
drawable — and that is what the GPU read gives back. The CPU store answers
with the streams the bytes it decoded hold, so a `.mesh` written without a
tangent stream reads back `tangents == nil` for as long as a CPU copy of it
is resident.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh — a `MeshHandle`, a `MeshCpuHandle`, a guid, or a mesh `AssetRef`.

```lua
local geom = renderer.mesh.geometry(renderer.mesh.create({ positions = P, indices = I }))
local tangents = renderer.mesh.geometry(handle).tangents
```

## modules/renderer/mesh.getVertices {#getvertices}

```lua
mesh.getVertices(mesh: string | { [string]: any } | AssetRef): { any }
```

Read the vertices of a mesh's resident CPU copy — one entry per vertex,
`{ pos = {x,y,z}, normal = {x,y,z}, uv = {u,v} }`. Reads the resident CPU
store directly (no re-decode). Errors when the mesh has no resident CPU copy
— `renderer.mesh.geometry(mesh)` is the read that works wherever the mesh
lives, and returns the tangent, colour and skinning streams too.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh — a `MeshHandle`, a `MeshCpuHandle`, a guid, or a mesh `AssetRef`.

## modules/renderer/mesh.instanceInfo {#instanceinfo}

```lua
mesh.instanceInfo(draw: InstancedDraw): InstancedDrawInfo?
```

What a live instanced-draw registration is drawing: which mesh, which
transform buffer, which per-instance data buffer if it named one, how many
instances, and how many slots it reserved. Returns nil once the
registration has been dropped.

`status` is what the renderer did with it. The fields above it are the
request, made a stage before the renderer sees it; `status` is the answer:
`"drawing"` for a registration the renderer is drawing, `"refused"` for one
it turned away — `error` carries its reason — and `"pending"` for the frame
between the call and the renderer answering. So a registration whose copies
are not being drawn says so here.

**Parameters**

- `draw` `InstancedDraw` — The `InstancedDraw` to report on.

```lua
print(renderer.mesh.instanceInfo(draw).instanceCount)
local info = renderer.mesh.instanceInfo(draw)
if info.status == "refused" then error(info.error) end
```

## modules/renderer/mesh.instanceTransforms {#instancetransforms}

```lua
mesh.instanceTransforms(draw: InstancedDraw): any
```

Read back the world matrices a registration's drawn copies are placed
by: `instanceCount` matrices of 16 floats, column-major and tightly
packed, in the layout the transform buffer holds them. The read is of the
buffer as it stands when it runs, so a population a compute pass rewrites
every frame answers with the placement of the frame the read lands in.

**Parameters**

- `draw` `InstancedDraw` — The `InstancedDraw` whose copies to locate.

```lua
local pending = renderer.mesh.instanceTransforms(draw)
while not pending:ready() do task.wait() end
local floats = pending:result()
```

## modules/renderer/mesh.isCpuResident {#iscpuresident}

```lua
mesh.isCpuResident(mesh: string | { [string]: any } | AssetRef): boolean
```

True if this mesh has a resident CPU copy in the guid-keyed CPU store.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh — a `MeshHandle`, a `MeshCpuHandle`, a guid, or a mesh `AssetRef`.

```lua
if renderer.mesh.isCpuResident(handle) then ... end
```

## modules/renderer/mesh.isResident {#isresident}

```lua
mesh.isResident(mesh: string | { [string]: any } | AssetRef): boolean
```

True if a GPU mesh is resident under this mesh's guid — the device
holds its buffers, or the upload pass is still going to hand them over.
This is the store the draw paths are gated on, so a mesh this reports
resident is one `renderer.mesh.drawInstanced` and a `Model` can draw.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh — a `MeshHandle`, a `MeshCpuHandle`, a guid, or a mesh `AssetRef`.

```lua
print(renderer.mesh.isResident(handle))
```

## modules/renderer/mesh.list {#list}

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

Every mesh currently registered, ordered by guid — the ones a script
created and the ones that reached the device through an asset alike.
Answers "which mesh is this?" when all that is known is a size: each entry
carries the guid, the vertex/index counts it was created with, where it came
from (`origin` is `"asset"` for a mesh the asset path uploaded), whether the
GPU still holds it, and where its culling bounds come from (`boundsFrom` is
`"compute"` for a mesh a compute pass writes). A resident entry also carries
the bytes its buffers cost. `bytes` is the mesh's whole VRAM footprint and
is the sum of the THREE buffer columns beside it — `vertexBytes +
vertexStorageBytes + indexBytes`, where the storage column is the same
vertices bound as a storage buffer for the passes that read them that way.
Summing only the vertex and index columns understates a mesh by its vertex
size. The `bytes` column is what sums to the `meshes` category of
`renderer.gpuMemory()`.
`renderer.references("mesh", guid)` says what is still holding a row, and
`renderer.collect()` releases the rows nothing holds.

```lua
for _, m in ipairs(renderer.mesh.list()) do print(m.guid, m.bytes) end
```

## modules/renderer/mesh.listInstanced {#listinstanced}

```lua
mesh.listInstanced(): { InstancedDrawInfo }
```

Every instanced-draw registration this engine is drawing, in
registration order. Each record is what `instanceInfo` answers with, and
carries a `draw` handle of its own — so a population whose handle its
caller no longer holds is reached here and released, resized or read like
any other.

```lua
for _, pop in ipairs(renderer.mesh.listInstanced()) do
renderer.mesh.dropInstanced(pop.draw)
end
```

## modules/renderer/mesh.loadCpu {#loadcpu}

```lua
mesh.loadCpu(ref: string | AssetRef): MeshCpuHandle
```

Load a `.mesh` asset's geometry into the ONE guid-keyed CPU store (the
Disk→CPU step) and return a CPU handle. The handle holds NO geometry — only
the guid plus counts and the per-handle read/encode/unload ops (which read
the Rust-side store). Called by `meshRef:load()`. DEFAULT lifecycle: upload
to the GPU then `handle:unload()`; the store is populated only by this call.

**Parameters**

- `ref` `string | AssetRef` — A mesh `AssetRef` (carries `.guid` and reads its primary via getBytes),
or any string `asset.ref` resolves to one — the guid `encodeCpu` takes, an
identity, a name or a source path.

```lua
local cpu = meshRef:load(); local gpu = renderer.mesh.create(cpu); cpu:unload()
local cpu = renderer.mesh.loadCpu(gpuMesh.guid)
```

## modules/renderer/mesh.morphTargets {#morphtargets}

```lua
mesh.morphTargets(mesh: string | { [string]: any } | AssetRef): { string }
```

The names of the shapes this mesh blends towards, in the order an
entity's `ecs.MorphWeights` addresses them — weight `i` drives the target
named at `i`. An imported model carries the names its source file gave its
blend shapes, so content drives a face by the shape it means rather than by
the ordinal that shape happened to import at (which moves when the model is
re-exported). A target the source never named reads as an empty string.

Empty for a mesh with no morph targets. Errors when the mesh is neither
GPU- nor CPU-resident — materialise it first (`meshRef:handle()`).

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh — a `MeshHandle`, a `MeshCpuHandle`, a guid, or a mesh `AssetRef`.

```lua
for i, name in renderer.mesh.morphTargets(meshRef) do print(i, name) end
```

## modules/renderer/mesh.morphWeights {#morphweights}

```lua
mesh.morphWeights(
```

Turn weights named by shape into the ordered weight array
`ecs.MorphWeights` takes — the drive-a-face-by-name call. Every target the
mesh carries gets a slot; the ones `weights` names take their value and the
rest are 0, so the returned array always describes the whole mesh and a
shape left out is a shape at rest.

A name the mesh does not carry is an error listing the names it does: a
mistyped viseme that silently moved nothing would be indistinguishable from
a rig that never had it.

```lua
local w = renderer.mesh.morphWeights(meshRef, { Eyes_Blink = 1, Mouth_Smile = 0.4 })
ecs.set(face, ecs.MorphWeights { weights = w })
```

## modules/renderer/mesh.readback {#readback}

```lua
mesh.readback(mesh: string | { [string]: any } | AssetRef): MeshCpuHandle
```

Read a runtime GPU mesh's geometry back to CPU and return a
`MeshCpuHandle` for it — the GPU→CPU half of the runtime-mesh freeze path. A
mesh made with `renderer.mesh.create` keeps no CPU copy, so persisting it
(`:encode()` → `asset.create("mesh", …)`) reads it back here first. Yields
until the readback completes (a frame or two). After it returns the geometry
is resident in the guid-keyed CPU store: `:getTriangles`, `:getVertices`,
`:getBounds`, `:geometry`, `:encode`, `:unload` all work. Errors if the mesh
never becomes resident in the vertex pool.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh — the `MeshHandle` `renderer.mesh.create` returned, a guid, or a mesh `AssetRef`.

```lua
local cpu = renderer.mesh.readback(handle); local zmsh = cpu:encode(); cpu:unload()
```

## modules/renderer/mesh.readbackPosed {#readbackposed}

```lua
mesh.readbackPosed(requests: { { entity: string, mesh: any } }): { [string]: MeshCpuHandle }
```

Read the POSED geometry of skinned entities back to CPU: for each
request, the vertices the skinning pass wrote for that entity this frame,
joined by the indices of the mesh it is posed from. A skinned surface's
world-space triangles are produced on the GPU from the entity's joint
matrices, so the mesh asset holds the bind pose and only this reads where
the surface actually is. The posed vertices are in model space, so the
entity's own world transform still places them — the same transform the
raster draw uses.

Takes a LIST and answers a map, because the readbacks are queued together
and polled together: a scene's worth of characters costs the frames of one
readback rather than one entity's after another. Each posed mesh lands in
the CPU store under a guid of its own, derived from the entity, so
`compute.buildBvh`, `meshcpu.*` and every other guid-keyed reader takes it
like any other mesh. Call `handle:unload()` when done with it.

An entity the map omits holds no live pose — nothing skinned it this frame,
which is also what makes its draws read the source mesh, so its bind-pose
geometry is what stands for it.

**Parameters**

- `requests` `{ { entity: string, mesh: any } }` — `{ { entity = <id>, mesh = <mesh> } }` — the entity to read, and the mesh it is posed from (a guid, `MeshHandle` or mesh `AssetRef`).

```lua
local posed = renderer.mesh.readbackPosed({ { entity = id, mesh = ecs.get(id, ecs.Mesh).mesh } })
local tris = posed[id]:getTriangles()
```

## modules/renderer/mesh.scheduleClusters {#scheduleclusters}

```lua
mesh.scheduleClusters(mesh: string | { [string]: any } | AssetRef): boolean
```

Queue a cluster-LOD bake for the static CPU mesh held under `guid`, and
attach the DAG to the GPU mesh of that same guid on the frame it finishes.
The CPU mesh may be unloaded on the very next line; the DAG is then built
one bounded slice per frame, so a dense mesh virtualizes without the frame
loop stopping for the whole bake.

One bake is advanced per frame — the one at the head of the queue — and the
geometry is read on the frame a bake gets there, from the definition the
engine holds for the mesh. A queue of meshes the engine holds definitions
for therefore holds one mesh's geometry rather than one per mesh, whatever
its depth. A mesh the engine holds no definition for is copied into the
queue as it is scheduled, since the CPU store is then the only thing
holding it. `renderer.mesh.clusterBakes().heldBytes` reports what the queue
is holding, and its `inFlight` rows report which bakes it is holding for.
This is what the `.mesh` assetType materialisation path uses; reach for
`renderer.mesh.buildClusters` when you want the bytes in hand instead.
Scheduling the same mesh again replaces the bake already in flight for it.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — A mesh loaded into the CPU store (`renderer.mesh.loadCpu`) — the
`MeshCpuHandle`, a `MeshHandle`, a guid, or a mesh `AssetRef`.

```lua
renderer.mesh.scheduleClusters(cpu) ; cpu:unload()
```

## modules/renderer/mesh.setInstanceCount {#setinstancecount}

```lua
mesh.setInstanceCount(draw: InstancedDraw, count: number): InstancedDraw
```

Change how many of a registration's instances draw. Constant time — the
reservation, the transform buffer and the pipeline all stay put, so this is
the verb for a population whose size changes per frame. The new count must
fit the reservation `drawInstanced` was given.

**Parameters**

- `draw` `InstancedDraw` — The `InstancedDraw` to reconfigure.
- `count` `number` — Instances to draw, at least 1 and within the reservation.

```lua
renderer.mesh.setInstanceCount(draw, visibleCount)
```

## modules/renderer/mesh.setInstanceRenderLayer {#setinstancerenderlayer}

```lua
mesh.setInstanceRenderLayer(draw: InstancedDraw, renderLayer: number): InstancedDraw
```

Change which render layers a registration's copies belong to. Constant
time — the reservation, the transform buffer and the pipeline all stay put,
and the next frame drawn tests the copies against the new membership. It is
the verb for a population that follows something whose membership moves: a
camera or a capture including the layer draws the copies, one excluding it
does not.

**Parameters**

- `draw` `InstancedDraw` — The `InstancedDraw` to reconfigure.
- `renderLayer` `number` — The membership bitmask, the same value `drawInstanced` takes
as `renderLayer`. At least one bit must be set.

```lua
renderer.mesh.setInstanceRenderLayer(draw, mask)
```

## modules/renderer/mesh.setVertices {#setvertices}

```lua
mesh.setVertices(mesh: string | { [string]: any } | AssetRef, positions: { number })
```

Replace a mesh's resident CPU vertex positions (flat `{ x,y,z, ... }`)
IN PLACE — indices, normals/uvs, and skinning are preserved, the AABB
recomputes, and the GPU re-fetches the new geometry so it shows on screen.
The positions alone travel, so this is the per-frame deformation path where
`renderer.mesh.update` re-sends the whole geometry. The mesh must be
CPU-resident: `renderer.mesh.create({ ..., keepCpu = true })` keeps a copy
from the start, `renderer.mesh.readback(mesh)` recovers one from the GPU,
and `meshRef:load()` loads one for a `.mesh` asset. Errors with the reason
otherwise, or when the vertex count doesn't match.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh — a `MeshHandle`, a `MeshCpuHandle`, a guid, or a mesh `AssetRef`.
- `positions` `{ number }` — Flat `{ x,y,z, ... }` — one xyz per vertex; count must match the mesh.

```lua
local m = renderer.mesh.create({ positions = P, indices = I, keepCpu = true })
renderer.mesh.setVertices(m, P) -- P mutated in place each frame
```

## modules/renderer/mesh.unloadCpu {#unloadcpu}

```lua
mesh.unloadCpu(mesh: string | { [string]: any } | AssetRef)
```

Drop a mesh's resident CPU copy from the guid-keyed CPU store.
The explicit release for a runtime geometry mesh's recoverable definition.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh — a `MeshHandle`, a `MeshCpuHandle`, a guid, or a mesh `AssetRef`.

## modules/renderer/mesh.update {#update}

```lua
mesh.update(mesh: string | { [string]: any } | AssetRef, src: any): MeshHandle
```

Overwrite the GPU resource `mesh` names IN PLACE, under the same guid,
from new geometry or compute buffers. Never writes a `.mesh` file — the
play-mode mutate path. A Model bound to the guid reflects the change with no
re-bind. Takes every form that names a mesh — the `MeshHandle` `create`
returned, the guid `renderer.mesh.list` hands out, a `MeshCpuHandle` or a
mesh `AssetRef`. Returns a handle carrying the bounds the new geometry has:
the handle it was given, refreshed, and a handle over the guid otherwise.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh to update — a `MeshHandle`, a guid, a `MeshCpuHandle` or a
mesh `AssetRef`.
- `src` `any` _(optional)_ — New geometry `{positions, indices, ...}` or compute buffers
`{vertexBuffer, indexBuffer, vertexCount, indexCount, prevVertexBuffer?}`.

## modules/renderer/mesh.uploadClusters {#uploadclusters}

```lua
mesh.uploadClusters(mesh: string | { [string]: any } | AssetRef, clusters: string): boolean
```

Attach a cluster-LOD DAG (bytes from `renderer.mesh.buildClusters`) to
the GPU mesh keyed by `guid`, enabling the continuous-cut cluster draw path
for that mesh.

**Parameters**

- `mesh` `string | { [string]: any } | AssetRef` — The mesh the clusters belong to — a `MeshHandle`, a `MeshCpuHandle`, a guid, or a mesh `AssetRef`.
- `clusters` `string` — Serialized cluster bytes (binary-safe).

```lua
renderer.mesh.uploadClusters(gpu, cb)
```

## modules/renderer/minScreenSize {#modules-renderer-minscreensize}

```lua
minScreenSize(): number
```

The on-screen radius, in pixels, an object must reach to be drawn. `0`
while the cutoff is off.

```lua
local px = renderer.minScreenSize()
```

## modules/renderer/morphStats {#modules-renderer-morphstats}

```lua
morphStats(): {
```

The morph state the last frame drew with. A mesh carries the shapes it
can blend towards and an entity carries how strongly each is blended
(`ecs.MorphWeights`); where both are present, the vertex stage adds the
weighted deltas to the base geometry.

`instances` is how many render slots that happened at, and `blends` how
many single-target blends those slots carry between them: a slot
contributes one per target its weights move, or that they moved the frame
before, so the number of targets a mesh can be given is bounded by the
buffer the blends live in. `meshes` is how
many meshes hold a delta block and `targets` how many targets those blocks
cover between them; `deltaBytes` is what the shared buffer they are
appended into holds. A morph-target mesh whose weights are all zero reads a
`meshes` above zero beside an `instances` and `blends` of zero.

```lua
local m = renderer.morphStats()
print(("%d instances carrying %d blends over %d meshes"):format(m.instances, m.blends, m.meshes))
```

## modules/renderer/observe {#modules-renderer-observe}

```lua
observe(): RenderObservation
```

Everything the renderer knows about the frame it last drew: what
program it bound for each renderable, the render state it holds each
material under, and what each program has cost in pipeline builds.
`renderables` is one row per renderable in the renderer's draw list,
carrying the program its material named (`requestedProgram`) beside the one
that was bound (`boundProgram`) — `__error__` wherever the lookup missed
and the draw went ahead on the magenta placeholder — plus `substituted`,
the `outcome` (`drew` / `drewPlaceholder` / `skipped` / `notDrawn`), the
`reason` that forced it and the compiler's own `detail` for a failed
compile. `observed` says which of two answers a row is: `true` for a
resolution a geometry pass took as it drew, `false` for the renderer's own
resolution of a renderable this frame drew nowhere, which is what a
renderable outside every camera's frustum or layer mask reports.
`materials` is one row per
material the renderer holds a prepared bind group for; `shaders` is one row
per program pipelines have been built for. `frame` names the frame every
per-frame count covers; `retainedFrames` how many frames a resolution a
pass took is kept for after the last frame that drew it; `window` and
`costWindow` state both in the document itself. Recording is armed by the
first read, so this waits for the frame that first records rather than
answering empty.

```lua
local o = renderer.observe(); print(o.placeholderDraws, "renderables drew the placeholder in frame", o.frame)
```

## modules/renderer/occlusionCulling {#modules-renderer-occlusionculling}

```lua
occlusionCulling(): boolean
```

Whether occlusion culling is currently enabled.

## modules/renderer/passSchedule {#modules-renderer-passschedule}

```lua
passSchedule(): {
```

The schedule check over this frame's enqueued render passes. Passes
declare what they read (`inputs`) and what they write (`output` /
`outputs` / `storage`), and the frame runs them in phase order and, inside
a phase, in `order` order. `violations` holds every input bound to a
resource the frame produces LATER: that read samples the resource as it
stands ahead of that pass, which is the previous frame's contents for a
render target that persists, an empty target for one just created, and the
scene draw's own output for a `@scene.*` buffer — and the pass renders
either way. The frame's own buffers are checked on the same terms as a
render target: bind `@scene.motion` at a phase ahead of the pass that
writes it and the read is reported, naming the buffer and its writer.
A pass reading a resource ahead of that write on purpose declares that slot
in its enqueue's `readsPrevious` and drops out of the list;
`unboundPrevious` holds declared slots the pass binds no such resource to,
which cover nothing.
A resource no queued pass writes is not reported — a camera rendering to
texture and `compute.dispatch` both fill targets outside the pass queue,
and the scene draw fills the `@scene.*` buffers every frame.
A read the frame has only one order for is not reported either: where the
writing pass consumes something the reading pass produces, the reader runs
first or the writer has nothing to write, which is what a pass reading a
buffer into a target of its own and a second pass copying that target back
over the buffer forms.
`unreachable` holds passes at a phase that does not run their kind: every
phase drains its fragment and compute passes, while `afterLighting` is the
one that draws geometry, draw and splat passes, so one of those enqueued
elsewhere sits in the queue and never runs.
Each finding is also stated in the engine log the first time it appears.

```lua
local s = renderer.passSchedule()
for _, v in s.violations do print(v.message) end
```

## modules/renderer/pipelineCache {#modules-renderer-pipelinecache}

```lua
pipelineCache(): PipelineCache?
```

What the driver's compiled-pipeline store held, built, and wrote back.
A pipeline is machine code the GPU driver compiles from the shader bound
into it, and that compile is what a launch pays before the first frame
drawing with each pipeline can appear. The store keeps that compiled code
across runs, so a launch whose shaders have not changed reads back what the
previous one compiled.

`restoredBytes` is what a previous run left for this GPU and this launch
read; `pipelinesBuilt` counts the pipelines built since startup and
`buildMs` is what they cost together, which is the number the store lowers.
`saves` and `savedBytes` describe writing it back — deferred until a burst
of builds settles, so one launch is one write — and `dirty` is true while
pipelines have been built that the file does not hold, including after a
write that failed, which `lastError` then names. `path` is the file, named
after the GPU it belongs to.

`supported` is false where the platform holds no store a program can carry:
a browser keeps its own and hands none out, and an adapter can lack the
capability. `reason` says which, and the build count and timing still read
true there. `lastError` names a read or write failure; a failed store costs
the saved compile and never the frame, since every pipeline is built from
its source either way.
`pipelinesBuilt` and `buildMs` are engine-wide totals; `renderer.shaderCost()`
is the same cost broken down per program, with each one's permutation count.

```lua
local c = renderer.pipelineCache()
print(("%d pipelines in %.1f ms, %d bytes restored"):format(c.pipelinesBuilt, c.buildMs, c.restoredBytes))
```

## modules/renderer/pointShadowBudget {#modules-renderer-pointshadowbudget}

```lua
pointShadowBudget(): PointShadowBudget
```

The point-light shadow pool now in force. A point light with
`castsShadows` renders an omnidirectional cube map, six faces of depth,
and `slots` is how many of them fit — a further caster is lit but throws
no shadow, and the engine log names how many were turned away. The slot
count is bought rather than authored: `megabytes` of VRAM at `resolution`
texels per face is what decides it.

```lua
local p = renderer.pointShadowBudget()
print(("%d shadowed point lights, %.1f MiB"):format(p.slots, p.bytes / 1024 / 1024))
```

## modules/renderer/projectionOffset {#modules-renderer-projectionoffset}

```lua
projectionOffset(): (number, number)
```

The sub-pixel projection offset in force for the main camera, in NDC.

```lua
local ox, oy = renderer.projectionOffset()
```

## modules/renderer/raycast {#modules-renderer-raycast}

```lua
raycast(
```

Cast a ray against the geometry the renderer DRAWS and return the
nearest surface it meets. Every visible mesh answers, whether or not
anything gave it a rigid body — so a terrain, a procedurally generated
mesh, or any plain `Model` reports the surface at a point, which is what a
camera station, a prop, a sound source or a scatter standing on the ground
needs to know. The answer is the nearest triangle of the mesh, so a sloped
or terraced surface reports its height where it was asked rather than the
extent of its bounding box.

`distance` is measured from `origin` along the direction given, so it is a
world-space distance whenever that direction is a unit vector, and it is
directly comparable to a `physics.raycast` distance along the same ray.
`normal` is a unit vector turned to face back along the ray. `exact` is
true when the answer is a triangle and false when it is the object's
bounding box, which is what a mesh whose vertices live only in GPU buffers
answers with. The triangles are the mesh's own, placed by the entity's
transform and by the mesh's bind pose, so a surface a skinning or morph
pass deforms on the GPU answers as the geometry the mesh holds.

EVERYTHING drawn is in scope — the ground you meant, and equally a
character standing on it, a prop, a placeholder floor. The hit names its
entity in `entityId`, `exclude` steps over the ones you do not want, and
`renderer.raycastAll` hands back the whole column so you can pick the
surface yourself. A height you did not expect is usually a nearer surface
you did not mean to ask about, so read `entityId` before trusting a number.

```lua
local hit = renderer.raycast({ x, 100, z }, { 0, -1, 0 }, 200)
if hit then camera.position = { x, hit.point.y + 1.7, z } end
```

## modules/renderer/raycastAll {#modules-renderer-raycastall}

```lua
raycastAll(
```

Cast a ray against the geometry the renderer draws and return every
surface along it, nearest first. One entry per renderable the ray crosses —
the nearest intersection with each — so a stack of surfaces reads as the
order they stand in, and a caller after one particular surface finds it by
`entityId` rather than hoping it is the nearest. Each entry carries the
fields `renderer.raycast` returns.

```lua
for _, hit in renderer.raycastAll(eye, look, 500) do print(hit.entityId, hit.distance) end
```

## modules/renderer/raytraceCapability {#modules-renderer-raytracecapability}

```lua
raytraceCapability(): string
```

The active ray-tracing backend: `"hardware"` (GPU ray query) or
`"compute"` (software traversal — the path on devices without hardware ray
query, e.g. the web). The same ray-tracing features work on both.

```lua
if renderer.raytraceCapability() == "hardware" then ... end
```

## modules/renderer/raytraceStats {#modules-renderer-raytracestats}

```lua
raytraceStats(): { [string]: any }
```

What the ray-tracing acceleration structure holds, and what this
session's frames have spent building it. A ray walks a structure built over
the scene's geometry, and keeping it current is work a frame pays before it
traces anything. On the `"compute"` backend geometry that has stood still
long enough is filed under a static partition the frames after it leave
alone: `staticTriangles` + `dynamicTriangles` = `triangles`, `nodes` is the
hierarchy over them, `fullRebuilds` / `partialRebuilds` / `reusedFrames`
count what the session's frames did, and `trianglesRebuilt` is what those
rebuilds re-emitted, summed. On the `"hardware"` backend `blas` is the
bottom-level structures cached, `blasBuilt` how many the last frame built,
and `tlasInstances` what the top-level structure names. The counters are
cumulative — sample, run the scene, sample again.

```lua
local before = renderer.raytraceStats().trianglesRebuilt
```

## modules/renderer/references {#modules-renderer-references}

```lua
references(handleOrKind: any, id: string?): RuntimeResourceStatus?
```

What holds a runtime resource right now — the answer a root scene load
reads before releasing it. `references` names each live consumer the engine
found: `{ by = "entity", id }` for an entity wearing the material or mesh,
`"material"` for a material whose slot names the texture, `"instancedDraw"`,
`"camera"`, `"sky"`, `"lightmap"`, `"ui"` (a screen drawing it) and
`"postProcess"` (an effect sampling it). `handleHeld` says whether a script
still reaches a handle to it, `assetBacked` whether an asset stands behind
it, `ownerLive` whether the component instance, scene load or feature that
created it still stands, and `held` whether a hold pins it. `origin` reads
`"device"` for a GPU texture the device holds that no script created — the
one the cache loaded for an asset, the atlas the engine built — whose
holders are the references, a handle and the asset. Runs a full garbage
collection first, the same one `renderer.collect` runs, so a handle nothing
reaches counts as let go and the row says what the next collection does
with the resource. Yields for the frame the census runs on.

**Parameters**

- `handleOrKind` `any` _(optional)_ — The resource's handle, or its kind with the id second.
- `id` `string?` _(optional)_ — The guid or key, when the first argument is a kind.

```lua
local s = renderer.references(mat) for _, r in s.references do print(r.by, r.id) end
```

## modules/renderer/reflectionEnvironment {#modules-renderer-reflectionenvironment}

```lua
reflectionEnvironment(): {
```

What a reflective surface is reflecting. `probes` is how many reflection
probes the shading blends; they are gathered highest `priority` first, each
rank taking the coverage the ranks above it left, so a small interior probe
ranked above the large exterior one it sits inside wins outright wherever it
reaches full weight. `ranks` is the priority each of those probe slots was
published with, in slot order. `sky` is whether the sky fallback is armed:
with it, coverage no probe claims reflects the captured sky, and without it
a surface outside every probe's radius falls back to the nearest probe
alone. `skyCaptured` is whether the sky slot holds a capture — arming is
refused until it does, since an uncaptured slot reflects black.
`slots` is how many cube slots the environment array holds right now: the
sky's alone, at index `skySlot`, until a probe is captured into it, then
that one plus one per probe. `maxProbes` is how many of them probes may
take, and `resident` whether the array has grown past the sky's single
slot. Capture the sky with `environment.captureSky()`.

```lua
local env = renderer.reflectionEnvironment()
print(("%d probes, sky fallback %s"):format(env.probes, tostring(env.sky)))
```

## modules/renderer/release {#modules-renderer-release}

```lua
release(handleOrKind: any, id: string?): boolean
```

Let go of the hold `renderer.hold` placed. The resource stays until
nothing else holds it and a collection releases it — the one a root scene
load runs, or a direct `renderer.collect()`.

**Parameters**

- `handleOrKind` `any` _(optional)_ — The resource's handle, or its kind with the id second.
- `id` `string?` _(optional)_ — The guid or key, when the first argument is a kind.

```lua
renderer.release(tex)
```

## modules/renderer/renderTargetLimits {#modules-renderer-rendertargetlimits}

```lua
renderTargetLimits(): {
```

The size a render target may be on this device. `maxDimension` is the
device's own maximum 2D texture dimension — the largest either side of a
render target may take. `maxPixels` is how many pixels one render target
may hold, so the RGBA8 image it reads back as fits in a single buffer on
every platform the engine runs on, and `maxSquare` is the largest square
that budget buys. A capture, a `renderer.texture.create({ width, height })`
or a render-to-texture camera past either bound is refused at the call with
the reason, so ask here for the size to request.

```lua
local lim = renderer.renderTargetLimits()
local w = math.min(want, lim.maxSquare)
```

## modules/renderer/renderTargets {#modules-renderer-rendertargets}

```lua
renderTargets(): {
```

Every render target the renderer owns and what each one costs, measured
from the texture that is allocated. One row per target, each carrying its
`name`, whether it is `resident`, the `bytes` it holds while it is, its
`width`/`height`/`layers`/`mipLevels`, and `onDemand`.
An `onDemand` target exists only while something needs it: a target nothing
writes into reads `resident = false` and `bytes = 0` and appears again the
frame something writes it, and one sized by content — the reflection-probe
cube array — holds the slots content asked for. The scratch the draws into
a render target have needed is reported as `camera[<handle>].*` rows:
depth and motion vectors under any rasterized pass, and the occlusion
channel and G-buffer over them under a camera's scene render. A draw builds
what it needs, and the set goes once no live camera names the target and
sixty frames have passed without a draw, so a target nothing draws into
carries no such row; the colour image drawn into belongs to the texture
cache and outlives every one of those releases.
`totalBytes` is what the resident targets hold together. Measured at the
end of the last rendered frame.

```lua
local rt = renderer.renderTargets()
print(("render targets: %.1f MiB over %d resident"):format(rt.totalBytes / 1048576, rt.residentCount))
for _, t in rt.targets do
if t.onDemand then print(t.name, t.resident, t.bytes) end
end
```

## modules/renderer/resolutionScale {#modules-renderer-resolutionscale}

```lua
resolutionScale(): number
```

The fraction of the display resolution the scene is currently rendered
at. `1` until something sets it.

```lua
local s = renderer.resolutionScale()
```

## modules/renderer/setAnisotropy {#modules-renderer-setanisotropy}

```lua
setAnisotropy(level: number): number
```

Set the maximum anisotropy material textures are sampled with. Takes
effect on the next frame for content already on screen — no reload, no
texture re-upload. 1 is plain trilinear.

**Parameters**

- `level` `number` — One of 1, 2, 4, 8, 16. Any other value is an error.

```lua
renderer.setAnisotropy(16)
```

## modules/renderer/setBlendedBatching {#modules-renderer-setblendedbatching}

```lua
setBlendedBatching(enabled: boolean): ()
```

Whether neighbours in a view's back-to-front blended order draw
together. On by default: alpha-blended geometry is submitted farthest-first,
and a stretch of neighbours in that order sharing a mesh, a material, a
shader and a pose is submitted as one instanced draw over those neighbours,
which puts the same members on screen in the same order out of a single
submission. A run stops wherever a differently-drawn renderable sorts
between two of its members, and a mesh of several primitives keeps a draw
per renderable — both would otherwise move fragments through each other.
Off, every blended renderable draws on its own at its own slot, so a
transparent crowd costs a draw per member. The image is the same either way,
which is what makes this the comparison a frame suspected of being formed by
the batching is made against; `renderer.drawStats().draws` counts the
difference.

**Parameters**

- `enabled` `boolean` — `boolean`

```lua
renderer.setBlendedBatching(false)  -- a draw per blended renderable
```

## modules/renderer/setDepthPrepass {#modules-renderer-setdepthprepass}

```lua
setDepthPrepass(enabled: boolean): ()
```

Enable or disable the opaque depth pre-pass. While enabled the renderer
resolves opaque depth in its own pass before shading, so each shaded pixel
runs its material once instead of once per surface stacked behind it, and
the resolved depth is what occlusion culling reads. Enabled by default.

**Parameters**

- `enabled` `boolean` — `boolean`

```lua
renderer.setDepthPrepass(false) -- shade every layer, for comparison
```

## modules/renderer/setDepthPrepassOrdering {#modules-renderer-setdepthprepassordering}

```lua
setDepthPrepassOrdering(enabled: boolean): ()
```

Submit the depth pre-pass nearest-first. Renderables reach the pre-pass
in the order they were registered, which stands in no relation to where the
camera is: a scene built back-to-front makes every layer write depth and be
overwritten by the layer in front of it. Ordered, the nearest surface
writes first and the surfaces behind it are rejected by the depth test
before they write. The same draws go out either way and the depth that
comes out is the same, so `scene.depth_prepass` in `profiler.gpuFrame()` is
what moves. Enabled by default.

**Parameters**

- `enabled` `boolean` — `boolean`

```lua
renderer.setDepthPrepassOrdering(false) -- submit in registration order
```

## modules/renderer/setGpuMemoryTracking {#modules-renderer-setgpumemorytracking}

```lua
setGpuMemoryTracking(frames: number?): number
```

Set how often the GPU allocator sampler reads — one reading every
`frames` frames — or turn it off with 0. It starts at 60, a reading a
second at 60 Hz, so `renderer.gpuMemory().allocator` answers without
anything arming it. Building the ledger walks every live allocation, which
is why it is sampled rather than read every frame; the category figures
cost nothing either way, and a reader between samples sees the most recent
ledger, so a slow interval still answers.

Called with no argument it reports the interval in force and changes
nothing, which is how something that retimes the sampler puts it back
afterwards instead of restoring a number it assumed was the default.

**Parameters**

- `frames` `number?` _(optional)_ — `number?` Frames between readings; 0 turns the sampler off. Omit
to read the interval without changing it.

```lua
renderer.setGpuMemoryTracking(60)
local was = renderer.setGpuMemoryTracking()
renderer.setGpuMemoryTracking(1)
-- ... take a tight reading ...
renderer.setGpuMemoryTracking(was)
```

## modules/renderer/setMaxFramesInFlight {#modules-renderer-setmaxframesinflight}

```lua
setMaxFramesInFlight(frames: number): number
```

Set how many frames of GPU work may be outstanding before the renderer
stops running ahead. One is the least overlap this can express — a frame's
work is waited for as soon as the next frame has been submitted — which is
the lowest latency and the lowest throughput; higher values let a slow
frame build a longer backlog, and that backlog is memory. Takes effect on
the next frame.

Answers the bound after clamping to [1, 8], so asking for more than the
renderer honours reports what you actually got.

**Parameters**

- `frames` `number` — number Frames of GPU work that may be outstanding, 1 through 8.

```lua
renderer.setMaxFramesInFlight(1) -- lowest latency
print(renderer.setMaxFramesInFlight(99), "was clamped")
```

## modules/renderer/setMinScreenSize {#modules-renderer-setminscreensize}

```lua
setMinScreenSize(pixels: number): ()
```

Stop drawing an object once its on-screen radius falls below this many
pixels. A few pixels across, an object carries no detail a viewer can
resolve while still costing a full vertex and submission pass, and the
cutoff drops it from the camera's draws entirely — `0`, the default,
keeps every object however small it lands. Measured from the object's own
bounds against the camera's projection, so the same threshold means the
same apparent size at any distance or field of view. Shadow casters have
their own threshold in `renderer.setShadowCasterCutoff`.

**Parameters**

- `pixels` `number` — `number` — smallest on-screen radius still drawn; 0 disables.

```lua
renderer.setMinScreenSize(4) -- drop anything under 4 px of radius
print(renderer.drawStats().compactedDrawn, "instances survived it")
```

## modules/renderer/setOcclusionCulling {#modules-renderer-setocclusionculling}

```lua
setOcclusionCulling(enabled: boolean): ()
```

Enable or disable occlusion culling. While enabled the renderer reduces
the pre-pass depth into a pyramid each frame and tests every renderable
that cleared the frustum against it, dropping the ones another surface
entirely covers before their geometry is submitted. The pyramid describes
the frame being drawn, so an object that becomes visible this frame is
never held back a frame. Requires the depth pre-pass.

**Parameters**

- `enabled` `boolean` — `boolean`

```lua
renderer.setOcclusionCulling(true); print(renderer.cullStats().occlusionCulled)
```

## modules/renderer/setPointShadowBudget {#modules-renderer-setpointshadowbudget}

```lua
setPointShadowBudget(cfg: {
```

Set how much VRAM the point-light shadow atlas may hold, and at what
per-face resolution. An omitted field keeps its current value. The atlas
is reallocated on the next frame, so `renderer.pointShadowBudget().slots`
reports the new pool one frame later; the returned number is what this
budget buys. Raising `resolution` sharpens every point shadow and spends
the same memory on fewer of them — doubling it quarters the slot count.
Values are clamped: megabytes [1, 1024], resolution [64, 4096], and the
pool never exceeds `renderer.pointShadowBudget().maxSlots`. One slot is
always granted, so a budget too small for a single cube shadows one light
and the pool costs what that slot costs rather than what was asked for —
`{ megabytes = 1, resolution = 4096 }` buys 384 MiB of ceiling. Read
`pointShadowBudget().bytes` back to see what a budget actually bought, and
`renderer.shadowMemory().point` to see what the scene has made resident.

```lua
renderer.setPointShadowBudget({ megabytes = 96 })
renderer.setPointShadowBudget({ resolution = 1024, megabytes = 96 })
```

## modules/renderer/setPresentMode {#modules-renderer-setpresentmode}

```lua
setPresentMode(mode: string): string
```

Set how a presented frame reaches the display. `fifo` queues every frame
and shows it on a vertical blank, which never tears and never drops one;
`mailbox` replaces the queued frame with the newest, which does not tear
and does not hold the renderer to the refresh rate; `immediate` presents as
soon as a frame is ready and can tear; `fifo_relaxed` is `fifo` that tears
rather than stall when a frame misses its blank; `auto_vsync` and
`auto_no_vsync` leave the choice to the backend.

A surface that does not offer the mode presents `fifo` instead, so read
`renderer.framePacing().presentMode` for what took effect and
`.presentModes` for what this surface offers. Takes effect on the next
frame.

**Parameters**

- `mode` `string` — string One of "fifo", "fifo_relaxed", "mailbox", "immediate", "auto_vsync", "auto_no_vsync".

```lua
renderer.setPresentMode("mailbox")
print(renderer.framePacing().presentMode, "is what the surface took")
```

## modules/renderer/setProjectionOffset {#modules-renderer-setprojectionoffset}

```lua
setProjectionOffset(x: number, y: number)
```

Offset the main camera's projection by a sub-pixel amount, in NDC, for
the frames until it is set again. The offset is in NDC because that is the
space it is constant in: one pixel is `2.0 / width` across, so half a pixel
is `1.0 / width`. Velocity (`@scene.motion`) is measured against the
offset-free projection, so a still scene reports no motion however the
samples are placed — and picking resolves a click to the same ray either
way. `(0, 0)` samples pixel centres.

**Parameters**

- `x` `number` — Horizontal offset in NDC. One pixel is `2.0 / width`.
- `y` `number` — Vertical offset in NDC. One pixel is `2.0 / height`.

```lua
renderer.setProjectionOffset(0.5 * 2 / w, -0.25 * 2 / h)
```

## modules/renderer/setRaytrace {#modules-renderer-setraytrace}

```lua
setRaytrace(enabled: boolean): ()
```

Enable or disable GPU ray tracing. While enabled the engine builds the
scene acceleration structure each frame so ray-tracing render features can
trace against it; disabling stops the build (so it costs nothing until a
ray-traced effect is active). Required before any ray-traced shadows / AO /
reflections render.

**Parameters**

- `enabled` `boolean` — `boolean`

```lua
renderer.setRaytrace(true); renderer.feature.create("rt_shadows")
```

## modules/renderer/setResolutionScale {#modules-renderer-setresolutionscale}

```lua
setResolutionScale(scale: number): number
```

Render the scene at a fraction of the display's resolution and present
it at the display's own size. Shading cost scales with pixel count and with
nothing else, so this trades sharpness for frame time without taking
anything out of the scene: at `0.5` the scene rasterizes a quarter of the
pixels. UI and text are unaffected — they are drawn after the scene is
brought back up to size. The scene rows in `profiler.gpuFrame()` are what
move.

**Parameters**

- `scale` `number` — `number` — fraction of the display resolution, clamped to [0.25, 1].

```lua
renderer.setResolutionScale(0.7)
```

## modules/renderer/setShadowCaching {#modules-renderer-setshadowcaching}

```lua
setShadowCaching(enabled: boolean): ()
```

Whether a shadow map that nothing changed is kept rather than drawn
again. On by default: a shadow view — one directional cascade, one atlas
layer of spot tiles, one face of a point light's cube — is rasterized on
the frames its own inputs change and holds the depth it drew on the ones
they do not.
Off, every view is drawn on every pass, which is what a shadow suspected of
holding a stale image is compared against.

**Parameters**

- `enabled` `boolean` — `boolean`

```lua
renderer.setShadowCaching(false)  -- draw every shadow view, every frame
```

## modules/renderer/setShadowCasterBatching {#modules-renderer-setshadowcasterbatching}

```lua
setShadowCasterBatching(enabled: boolean): ()
```

Whether a shadow view draws every caster of one mesh together. On by
default: a view — one directional cascade, one atlas layer of spot tiles,
one face of a point light's cube — submits one draw per geometry over every
caster of it the view admits, wherever those casters sit in render order
and whatever transform slots they hold. Off, a view draws the runs of render-order
neighbours that share a mesh AND hold consecutive slots, so a scene that has
spawned and despawned anything fragments into many more draws. The image is
the same either way, which is what makes this the comparison a shadow
suspected of being placed by the batching is made against.

**Parameters**

- `enabled` `boolean` — `boolean`

```lua
renderer.setShadowCasterBatching(false)  -- draw the runs the scene presents
```

## modules/renderer/setShadowCasterCutoff {#modules-renderer-setshadowcastercutoff}

```lua
setShadowCasterCutoff(cfg: {
```

Set the shadow-caster cutoff. An omitted field keeps its current value,
so a call can adjust one threshold without restating the other. Both are
measured against the camera the frame draws from rather than against each
light, so one setting covers every cascade, spot and cube face, and a
caster that stops casting is one whose shadow the viewer could not have
resolved. `maxDistance` is measured to the near side of the caster's
bounding sphere, so a large object keeps casting while any part of it is in
range. 0 releases a threshold; releasing both draws the casters the frame
drew before either was set.

```lua
renderer.setShadowCasterCutoff({ minRadiusPx = 2 })
renderer.setShadowCasterCutoff({ minRadiusPx = 1.5, maxDistance = 120 })
```

## modules/renderer/setShadowConfig {#modules-renderer-setshadowconfig}

```lua
setShadowConfig(cfg: {
```

Set the directional shadow quality. Any omitted field keeps its current
value, so a call can adjust one knob without restating the rest. Values are
clamped: resolution [64, 8192], cascades [1, 4], distance >= 0, splitLambda
[0, 1], fadeFraction [0, 1], softness [0, 1]. Changing `resolution` or
`cascades` reallocates the depth array; the rest are per-frame values. A
`distance` of 0 hands the range to the frame — the splits are cut over the
depth its own shadow-taking renderables reach — and a positive one caps it,
which is what a scene bounding its shadow cost states.

```lua
renderer.setShadowConfig({ softness = 0.65, fadeFraction = 0.28 })
renderer.setShadowConfig({ cascades = 4, resolution = 2048, distance = 240 })
```

## modules/renderer/setShadowHero {#modules-renderer-setshadowhero}

```lua
setShadowHero(entity: string, padding: number?): ()
```

Give one caster a directional shadow view of its own, fit to its world
bounds.

A cascade covers the slab of world the camera sees, so its texels are spread
over tens of metres and one character standing in the middle of it is
resolved by a handful of them. The hero view is the same light and the same
depth range zoomed onto that entity's bounds, so the whole map goes into the
shadow it and the ground under it carry — `renderer.shadowHero().zoom` is
the factor its texel density gains.

It renders beside the cascades, into a layer of the same texture allocated
while a hero is registered, and every surface inside it reads it in place of
the cascade, crossing back at its edge. Nothing else about the shadow
changes: the same casters reach it, at the same depth range, through the
same filter.

**Parameters**

- `entity` `string` — The entity whose renderables the view is fit around.
- `padding` `number?` _(optional)_ — How much room the fit leaves around those bounds — for a pose that
leaves the bind-pose box and for the filter that samples outside a
silhouette. 1.0 fits them exactly.

```lua
renderer.setShadowHero(player.id)
print(("hero shadow: %.1f texels/unit vs %.1f"):format(
renderer.shadowHero().texelsPerUnit, renderer.shadowHero().cascadeTexelsPerUnit))
```

## modules/renderer/setShadowProxy {#modules-renderer-setshadowproxy}

```lua
setShadowProxy(mesh: string, proxy: string): ()
```

Rasterize `proxy` in place of `mesh` in every shadow view. A shadow is a
silhouette resolved at the resolution of a shadow map, so the triangles that
carry a mesh's close-up detail write depth no reader can resolve — a
decimated version of the shape, a level of its own LOD chain, or a
hand-built hull casts the same shadow for a fraction of the geometry.

The registration is keyed by MESH, so one call covers every instance of it —
entities and GPU-driven populations alike — and a crowd sharing that mesh
stays one draw. The proxy is placed by whatever places the caster, its
instance's own transforms, so it stands where the caster stands, at the
caster's scale.

An entity caster keeps its own geometry where a stand-in could not be placed
or deformed correctly: it is skinned (it rasterizes the post-skinned
vertices written for its own mesh), it blends morph targets (whose deltas
describe its own mesh and are read by vertex id), or its proxy would be
placed by a different node of its model than the source mesh is. Either
caster keeps it where the renderer holds no geometry under the proxy's
guid. Each of those is counted in `renderer.shadowProxies()`.

Nothing else in the scene draws a proxy, so this call is what brings it onto
the GPU, and it raises where it cannot. A proxy already resident there is
registered as it stands.

**Parameters**

- `mesh` `string` — The mesh a caster draws, as a guid or any mesh reference.
- `proxy` `string` — The mesh it rasterizes into shadow views instead.

```lua
renderer.setShadowProxy(statueMesh, statueHullMesh)
print(renderer.shadowProxies().triangles, "vs", renderer.shadowProxies().sourceTriangles)
```

## modules/renderer/setSkinnedBatching {#modules-renderer-setskinnedbatching}

```lua
setSkinnedBatching(enabled: boolean): ()
```

Whether skinned instances holding one pose draw together. On by default:
instances of one mesh wearing one material and posed alike read the same
post-skinned vertices, so the camera's colour passes submit them as a single
instanced draw, and so does each shadow view and the velocity pass while
`renderer.shadowCasterBatching()` is on — that switch is what makes a depth
view form its draws by geometry at all. The camera depth pre-pass submits
its casters nearest-first, which is a run per span of neighbours rather than
a draw per geometry, so a crowd costs a draw per member there. Off, each
skinned instance draws on its own at its own slot in every pass that
rasterizes it. The image is the same either way, which is what makes this
the comparison a frame suspected of being formed by the batching is made
against — `renderer.drawStats().draws` counts the difference and
`renderer.skinningStats().poses` says how many distinct poses it holds.

**Parameters**

- `enabled` `boolean` — `boolean`

```lua
renderer.setSkinnedBatching(false)  -- a draw per skinned instance
```

## modules/renderer/setSkinningPoseHold {#modules-renderer-setskinningposehold}

```lua
setSkinningPoseHold(enabled: boolean): ()
```

Whether a pose the skinning pass already wrote is read as it stands. On
by default: the pass produces an instance's vertices from its joint
matrices, its node transforms, its blend weight and its blend model, so the
slice holding a pose already holds what running the pass over those same
inputs would write. A frame binding a pose whose slice still holds it reads
the slice and dispatches nothing, and skinning costs what the frame's poses
CHANGED — a paused clip, a skeleton nothing drives, a cast standing in one
pose, each cost compute the frame the pose arrived and nothing after it.
Off, every pose a frame binds is dispatched again, which is the comparison a
frame suspected of reading a slice that no longer holds its pose is made
against; the image is the same either way and
`renderer.skinningStats()` counts the difference as `dispatches` against
`held`. A mesh whose vertices a compute pass writes is dispatched every
frame however this stands.

**Parameters**

- `enabled` `boolean` — `boolean`

```lua
renderer.setSkinningPoseHold(false)  -- dispatch every pose, every frame
```

## modules/renderer/setSpotShadowBudget {#modules-renderer-setspotshadowbudget}

```lua
setSpotShadowBudget(cfg: {
```

Set how much VRAM the spot/area shadow atlas may hold, and the per-side
resolution of one layer. An omitted field keeps its current value. The
atlas is reallocated on the next frame, so `renderer.spotShadowBudget()`
reports it one frame later; the returned number is what this budget buys.
Raising `resolution` sharpens the lights that cover the most screen and
spends the same memory on fewer layers — doubling it quarters the layer
count. Raising `megabytes` buys layers, which is what lets several lights
hold a large tile at once. Values are clamped: megabytes [1, 1024],
resolution [64, 4096], and the atlas never exceeds
`spotShadowBudget().maxLayers`. One layer is always granted, so a budget
too small for one still shadows lights and the atlas costs what that layer
costs rather than what was asked for.

```lua
renderer.setSpotShadowBudget({ megabytes = 64 })
renderer.setSpotShadowBudget({ resolution = 2048, megabytes = 64 })
```

## modules/renderer/setTextureBudget {#modules-renderer-settexturebudget}

```lua
setTextureBudget(opts: TextureBudgetOpts): TextureBudget
```

Bound the VRAM a world's textures occupy, by keeping only the mip levels
the frame is actually sampling. Pass `{ megabytes = 256 }`; `0` — the
default — leaves texture residency alone and every texture stays fully
resident the way it uploaded.

With a budget armed, each frame measures how many screen pixels ONE
traversal of a texture's coordinate range covers on the surface that spans
it widest, and asks for the mip level that serves that span one texel per
pixel — the level the GPU picks from the fragment's own derivatives. A
material with `uvScale = 8` lays eight copies of its texture across a
surface, so each copy spans an eighth of the surface and asks for three
levels coarser than the surface's own size would. A shader that declares
`// @uv_space: world` advances its coordinate over world units rather than
over the mesh's UVs, so how many copies a surface carries follows how large
that surface is. The textures whose surfaces cover the fewest pixels give
up levels until the set fits. Detail climbs one level per frame, from the
image already on screen, so a surface the camera approaches sharpens rather
than popping, and no texture is taken below the level whose longest side is
64 texels.

`bias` shifts every measurement by whole mip levels either way — negative
for finer than the sampling implies, positive for coarser — over a world
whose look wants a different trade than one texel per pixel.

The plan moves a texture whose demand the frame can measure: one at least
256 texels on its narrowest side, worn by a surface an entity draws. A
texture a UI image, a post-process property or a render feature holds a
view of stays whole, because nothing measures how much of the screen those
cover.

Which textures the budget governs follows the surfaces the frame draws. A
texture whose asset still holds its bytes is enrolled the frame a measured
surface wears it — whenever it loaded, and whenever the budget was armed —
because a level change reads the levels it needs back from the asset; when
the last such surface goes it leaves the set whole, at the level it
uploaded at, and a surface reaching it again takes it back up. A texture a
script uploaded has its pixels nowhere else, so one enrolled while it is
resident holds them in system memory
(`renderer.textureMemory().streamSourceBytes`) from the upload until a
surface has worn it and gone, and releases them then, which is what keeps
it out for the rest of the session; one whose pixels were already released
when the budget was armed is out from the start.
`renderer.textureMemory().pinnedTextures` counts those, together with the
textures whose asset could not be read back and the ones a UI image, a
post-process property or a render feature holds a view of. Disarming
returns every texture to the level it uploaded at, and arming again governs
the textures the frame's surfaces are wearing then.

**Parameters**

- `opts` `TextureBudgetOpts` — `{ megabytes: number?, bias: number? }`

```lua
renderer.setTextureBudget({ megabytes = 128 })
renderer.setTextureBudget({ megabytes = 128, bias = -1 })  -- one level finer everywhere
renderer.setTextureBudget({ megabytes = 0 })               -- leave residency alone
```

## modules/renderer/setTransmissionShadows {#modules-renderer-settransmissionshadows}

```lua
setTransmissionShadows(enabled: boolean): ()
```

Let translucent casters tint the sunlight they block instead of blocking
it outright. A shadow map holds one depth per texel and is compared as a
yes-or-no test, so stained glass, water and thin fabric all project the same
black silhouette a wall does. With this on, a caster whose material declares
opacity (`base_color` alpha under a transparent blend) or `transmission`
also draws into a light-space transmittance map, and the colour it lets
through multiplies into the directional light reaching whatever stands
behind it. Stacked casters compose. Opaque casters are unaffected, and a
scene with no translucent caster allocates nothing and records no pass.

**Parameters**

- `enabled` `boolean` — `boolean`

```lua
renderer.setTransmissionShadows(true)  -- stained glass tints the floor
```

## modules/renderer/setViewportSize {#modules-renderer-setviewportsize}

```lua
setViewportSize(width: number, height: number): { width: number, height: number }
```

Draw at this many pixels. The engine's drawing surface is resized to
it, and everything measured against that surface follows within a frame:
`getViewportSize()`, `ui.screenSize()`, the layout every UI screen
rebuilds from it, each camera's aspect, and what `capture` encodes. This
is how one session checks a responsive layout at a second shape — a HUD
written against `ui.screenSize()` is re-laid-out at the new size, so an
anchored element is drawn where that shape puts it rather than scaled
from where the boot size put it.

Who honours the size depends on who owns the surface. A headless engine
and a browser canvas own theirs and are resized exactly. Where an OS
window owns it, the window manager is asked and has the last word — a
tiled or maximized window keeps the size it has. Read
`renderer.surfaceSize()` on a later frame for what was realized.

The new size is in force from the NEXT frame, so read it back on a later
call — `renderer.surfaceSize()` read in the same call still reports the
size that call started at.

The logical UI space is normalised to about 1280 points wide, so a resize
to a size of the same aspect moves `ui.pixelRatio()` and leaves
`ui.screenSize()` where it was, while a resize that changes the aspect
changes that shape too. Both resize the surface.

A size larger than the device draws is refused naming the bound, which
`renderer.maxViewportExtent()` reports.

**Parameters**

- `width` `number` — `number` — width in pixels, at least 1.
- `height` `number` — `number` — height in pixels, at least 1.

```lua
renderer.setViewportSize(1920, 1080)
task.waitFrames(1); print(renderer.surfaceSize()) -- what was realized
```

## modules/renderer/shaderCache {#modules-renderer-shadercache}

```lua
shaderCache(): ShaderCache?
```

What the shader compile gate's store of baked WGSL held, answered and
wrote back. Compiling a `.shader` wraps the author's body in its framework,
expands every `#include`, and hands the result to naga to parse and
validate — work that is a pure function of the text going in, and that a
launch would otherwise repeat for every shader it draws with. The store
keeps that baked text across launches.

`restoredEntries` and `restoredBytes` are what a previous launch left that
this one read back. `hits` counts the compiles answered out of the store
and `misses` those that ran in full; `savedMs` sums what each hit's own
recorded compile had cost, against `compileMs`, what the misses spent.
`stale` counts the misses whose key was held but whose `#include`d modules
had changed underneath — an entry records every module its expansion
consumed, so editing a module invalidates exactly the shaders that included
it and leaves the rest.

`entries` and `bytes` are what the store now holds, `evictions` how many a
write dropped to stay inside its bounds, and `saves` / `savedBytes` /
`dirty` describe writing it back, deferred until a burst of compiles
settles. `persistent` is false where a launch has nowhere to keep
artifacts and `reason` says why; `location` is the file, or the browser
store, they are kept in. `restoreState` is how the read of what a previous
launch left has gone — `pending` while it is still out (a browser answers
through a promise, so a launch reaches its first frames before it lands),
`restored` once entries came back, `empty` when there were none to come
back, `failed` when what was there could not be read, and `none` where a
launch keeps nothing. A cold, missing or corrupt store leaves every
shader compiling from source with identical output, and `lastError` then
names what went wrong.

```lua
local c = renderer.shaderCache()
print(("%d hits, %d misses, %.1f ms saved"):format(c.hits, c.misses, c.savedMs))
```

## modules/renderer/shaderCost {#modules-renderer-shadercost}

```lua
shaderCost(): { ShaderCost }
```

What each program has cost in pipeline builds, beside the compile
gate's most recent word about it. `variants` is how many pipelines this
engine has built for it — one per (target format, vertex layout,
render-state key) permutation reached — and `buildMs` what those builds
cost, both summed since engine start. A pipeline the driver's own store
restored is not built and so is not counted, so a second launch on the same
adapter reports less than the first. `status` is `compiled`, `failed` or
`pending`, and `error` carries the compiler's message for a failure.
Ordered by cost, most expensive first.

```lua
local top = renderer.shaderCost()[1]; print(top.shader, top.variants, top.buildMs)
```

## modules/renderer/shaderVariants {#modules-renderer-shadervariants}

```lua
shaderVariants(): { ShaderVariants }
```

Every shader that declares optional features, and the programs its
materials have made it compile. Each row carries the features the shader
declares, the base program it ships as, and one entry per variant with the
features that variant holds — so the permutation count a scene's materials
are spending is a number to read rather than something to infer from
compile time. A shader whose variants reach `budget` compiles no more; the
materials asking for further feature sets draw with the base program.

```lua
for _, s in renderer.shaderVariants() do print(s.shader, #s.variants, s.budget) end
```

## modules/renderer/shadingOf {#modules-renderer-shadingof}

```lua
shadingOf(subject: string | { [string]: any }): ShadingReading
```

What the renderer is shading ONE subject with, taken from the document
the renderer publishes — the call a system holding a handle makes to find
out whether what reaches the screen is its own material or the magenta
placeholder standing in for it, without reading the engine log. `subject` is
an entity that draws or the registry key of a material. `state` reads
`itsMaterial` where the renderer bound the program the material names,
`errorMaterial` where it bound the placeholder instead, `stalePipeline`
where the pipeline drawing it was built before that program's most recent
compile, `nothingBound` where the renderer resolved no pipeline for it,
`pending` where this call is the one that armed per-draw recording and the
frame after it publishes, and `unknown` where the renderer holds a
resolution under no such subject. A fault state carries the renderer's own
`reason` from the closed set `renderer.drawDiagnostics()` names — plus
`materialNotPrepared`, which a material subject reads where the renderer
prepared nothing under that key — the compiler's `detail`, the `program`
the material asked for and the `bound` one; `means` states the reading in a
sentence. A material subject answers from the renderables drawing with it,
and from the renderer's record for the material itself where a draw
registered against the material carries no row of its own; a subject that
several renderables draw answers with a refused one wherever there is one.
The reading follows the renderer, so a program that compiles on a later
edit puts the subject back on `itsMaterial` from the frame the renderer
draws it with again.

**Parameters**

- `subject` `string | { [string]: any }` — The entity — a proxy from `entity(...)` or an entity-id string —
or the material, as its registry key or the `MaterialHandle`
`renderer.material.create` returned.

```lua
local s = renderer.shadingOf(emitter); if s.state ~= "itsMaterial" then print(s.means) end
```

## modules/renderer/shadowCacheStats {#modules-renderer-shadowcachestats}

```lua
shadowCacheStats(): {
```

What the last frame did with the shadow maps it already had. A shadow
view — one directional cascade, one atlas layer of spot tiles, one face of
a point light's cube — is drawn again only when something it draws from
changed:
its light moved, a caster it can see moved or appeared or vanished, a
caster's geometry or material changed, a caster changed pose or moved the
nodes its parts are placed by, or the map it writes into was reallocated.
Anything else keeps the depth already in the texture, so a scene that stops
moving reads `rendered` 0 while `cached` keeps climbing. A mesh whose
vertices a compute pass writes — a population, or a mesh built from a
compute buffer — re-renders the views it stands in every frame. A shadowed
point light contributes six views, one per cube face, so a caster moving on
one side of it re-renders the face that can see it and leaves the other
five holding what they have. Counted per light kind, plus the totals across
all three.

These are totals over every view of a kind. `renderer.shadowViews()` is the
same frame one view at a time, each row naming the light that owns it and
what it drew.

```lua
local s = renderer.shadowCacheStats()
print(("shadow views: %d drawn, %d cached"):format(s.rendered, s.cached))
```

## modules/renderer/shadowCaching {#modules-renderer-shadowcaching}

```lua
shadowCaching(): boolean
```

Whether a shadow view may keep the depth it already holds.

## modules/renderer/shadowCasterBatching {#modules-renderer-shadowcasterbatching}

```lua
shadowCasterBatching(): boolean
```

Whether a shadow view draws every caster of one mesh together.

## modules/renderer/shadowCasterCutoff {#modules-renderer-shadowcastercutoff}

```lua
shadowCasterCutoff(): ShadowCasterCutoff
```

How small, and how far away, a caster may get before it stops writing
depth into any shadow view. A shadow view rasterizes a caster's whole
triangle count whatever the shadow it produces ends up covering, so an
object the viewer resolves a fraction of a pixel of, and one past the range
the scene cares about, each cost a full depth pass per shadowed light for
detail nothing reads. Both thresholds are 0 — released — until something
sets them.

```lua
local c = renderer.shadowCasterCutoff(); print(c.minRadiusPx, c.maxDistance)
```

## modules/renderer/shadowConfig {#modules-renderer-shadowconfig}

```lua
shadowConfig(): ShadowConfig
```

The directional shadow quality now in force. `resolution` and `cascades`
size the cascade depth array; `distance` and `splitLambda` place the splits
along the view; `fadeFraction` and `softness` shape how the result is
sampled.

```lua
print(renderer.shadowConfig().cascades)
```

## modules/renderer/shadowHero {#modules-renderer-shadowhero}

```lua
shadowHero(): ShadowHeroReport
```

The registered hero caster and what the last frame's fit produced. A
frame that fit nothing says why in `decline`.

```lua
local h = renderer.shadowHero()
print(h.active, h.zoom, h.decline)
```

## modules/renderer/shadowMemory {#modules-renderer-shadowmemory}

```lua
shadowMemory(): {
```

How much GPU memory the shadow maps hold right now, in bytes, by the
light kind that owns them. The spot atlas and the point pool are sized to
the casters in the scene rather than to the budget, so `spot` and `point`
move as lights that cast shadows appear and leave, and a scene with one
shadowed light holds far less than one that fills every slot. A budget is
the ceiling they grow within — `renderer.spotShadowBudget().layers` and
`renderer.pointShadowBudget().slots` report that ceiling, unmoved by how
many casters exist. Raising shadow resolution costs the square of the
change across every cascade.

```lua
local m = renderer.shadowMemory()
print(("shadows: %.1f MiB"):format(m.total / 1024 / 1024))
```

## modules/renderer/shadowProxies {#modules-renderer-shadowproxies}

```lua
shadowProxies(): ShadowProxyReport
```

The shadow proxies in force and what the last frame's shadow passes did
with them. `triangles` and `sourceTriangles` are what those passes
submitted and what they would have submitted from the source meshes — the
before/after of every registration, equal while nothing is proxied.

```lua
local p = renderer.shadowProxies()
print(("shadow triangles: %d of %d"):format(p.triangles, p.sourceTriangles))
```

## modules/renderer/shadowViews {#modules-renderer-shadowviews}

```lua
shadowViews(): ShadowViewReport?
```

Every shadow view the last rendered frame considered, and what each one
cost.

A frame rasterizes a depth view per directional cascade, one for the hero
caster, one per shadow-casting spot and six per shadow-casting point.
`renderer.shadowCacheStats()` counts those views by light kind,
`renderer.drawStats()` sums their draws with the camera's, and
`profiler.gpuFrame()` carries one `scene.shadow` span across all of them.
This is the same frame read one view at a time.

Each row names the view and the light that owns it, says whether it drew or
kept the depth it already held, and carries the draws, the instances and the
casters that went into it. `span` is the label the view's pass is timed
under, so its GPU time is a lookup in `profiler.gpuFrame()`; every one of
those labels is a variant of `scene.shadow`, which still carries their
total. `camera` carries the same instance counters for the main camera, so
the camera's share of a frame-wide total is a read rather than a measurement
taken by turning every light's shadow off.

A cascade's `near` and `far` are where the split scheme cut its slice, not
the world it covers: the fit takes the bounding sphere of that slice and
rasterizes the ortho box around it, and both reach past `far`. What the
cascade covers is `center` and `radius`, with `viewProj` the exact test;
`coversNear` and `coversFar` read that volume back along one ray, the
camera's view axis. `directional` states the axis reading for the set —
how far it reaches (`coversFar`), the range the splits were run over
(`distance`), how far the camera draws (`cameraFar`), and the
depth past the reach the camera still draws (`uncovered`). A receiver
further along the axis than `coversFar` has no directional depth map over
it and is shaded as if the sun reached it, so `uncovered` is the room a
missing shadow has and a surface standing in that room is what makes one;
`@builtin::systems.proxyOcclusion` occludes past the cascades. The box is
bounded in every direction, so a receiver standing wide of the axis leaves
it at its own distance even where `uncovered` is 0 — `viewProj` is what
answers for that receiver.

The list is rebuilt every frame: a view whose light stopped casting is
absent from the next report rather than standing at the numbers it last had,
and a frame that drew no shadow view answers a report whose `views` is
empty. `views` grouped the way the shadow cache decides — a row per cascade,
per spot atlas layer, per point cube — counts what
`renderer.shadowCacheStats()` reports as `rendered + cached`.

The frame names its views only while something is reading them, so this
call asks the frames after it to name theirs and waits out the first one.
Nil on an engine that renders no frame at all.

```lua
local report = renderer.shadowViews()
print(("camera submitted %d of %d instances"):format(
report.camera.submittedInstances, renderer.drawStats().compactedDrawn))
for _, view in report.views do
print(("%s %d (%s): %d draws, %d instances, %s"):format(
view.role, view.index, view.light, view.draws, view.instances,
view.rendered and "drew" or "cached"))
end
local d = report.directional
if d ~= nil and d.uncovered > 0 then
print(("sun shadows stop at %.0f; the camera draws to %.0f"):format(
d.coversFar, d.cameraFar))
end
```

## modules/renderer/skinnedBatching {#modules-renderer-skinnedbatching}

```lua
skinnedBatching(): boolean
```

Whether skinned instances holding one pose draw together.

## modules/renderer/skinningPoseHold {#modules-renderer-skinningposehold}

```lua
skinningPoseHold(): boolean
```

Whether a pose already written into its slice skips its dispatch.

## modules/renderer/skinningStats {#modules-renderer-skinningstats}

```lua
skinningStats(): {
```

What the last frame's skinned instances cost. A skinned instance is
posed by a compute pass that writes its vertices into a shared pool, and
instances holding the same pose read one slice of that pool and the single
dispatch that fills it. `instances` is how many were posed, `poses` how
many distinct poses they held, and `dispatches` how many dispatches those
poses cost this frame — so a crowd whose members move together costs what
its poses cost rather than what its head count does, while members at
different animation times each hold their own pose and pay for it.

`held` is how many of the frame's poses cost no dispatch at all. The pass
produces a slice from what the pose is made of, so a slice an earlier frame
filled already holds what running it again would write, and a pose still
wearing that slice is read as it stands. Skinning is paid for by the poses
that CHANGED: a cast standing still reads `dispatches` 0 beside a `held`
equal to its `poses`, and the two add up to `poses` in any frame.

`reusedSlices` is how many of the frame's poses took a slice the pool
already held — one a retired pose gave back, or one a pose nothing has
asked for this frame was holding — rather than one cut from pool the
engine had never used. A scene whose poses keep changing reads a non-zero
count beside a `poolBytes` that stays where it was.

`liveBytes` is what the slices holding this frame's poses occupy, against
`unsharedBytes` — what the same instances would occupy with a slice each.
`poolBytes` is what the pool holds; a previous-position buffer of the same
size rides alongside it so skinned deformation reaches motion vectors.

```lua
local s = renderer.skinningStats()
print(("%d instances over %d poses"):format(s.instances, s.poses))
print(("%d poses dispatched, %d read as they stood"):format(s.dispatches, s.held))
print(("skinned vertex storage: %d B of an unshared %d B"):format(s.liveBytes, s.unsharedBytes))
```

## modules/renderer/splat.components {#components}

```lua
splat.components(bytes: any, convention: string?): (SplatComponents?, string?)
```

Decode a Gaussian splat capture — a Niantic `.spz` (gzipped or raw) or a
3DGS `.ply` — into the GPU-ready byte pools a render feature uploads.
`records` is the packed splat array at `recordBytes` per splat (position,
log scale, quaternion, DC colour + opacity); `sh` is the quantized
higher-order spherical-harmonics pool at `shStrideWords` u32 words per
splat, empty at degree 0. A pure decode (no GPU work): upload the pools with
`shaderRef:createBuffer` + `buf:writeBytes` and draw them with a
`kind = "splat"`, `channel = "gaussian"` pass.

**Parameters**

- `bytes` `any` _(optional)_ — Capture bytes — `.spz` or `.ply`, as a `buffer` or a binary string.
- `convention` `string?` _(optional)_ — Source axis convention: `"rightDownFront"` (the default, what
COLMAP-trained captures use) or `"engineNative"` for a capture already in
engine space.

```lua
local c = renderer.splat.components(vfs.readBytes("captures/ceramic.spz"))
```

## modules/renderer/spotShadowBudget {#modules-renderer-spotshadowbudget}

```lua
spotShadowBudget(): SpotShadowBudget
```

The spot and area-light shadow atlas now in force. Each shadow-casting
spot is given a tile of it every frame, sized to what the camera can
resolve: a light filling the view gets a whole layer at `resolution`, one
far away gets a `minResolution` tile, and the atlas holds `tiles` of the
smallest kind. That is what lets one budget serve a close hero light and a
street of distant ones without either the memory or the sharpness being set
for the worst case.

```lua
local s = renderer.spotShadowBudget()
print(("%d layers of %d, %.1f MiB"):format(s.layers, s.resolution, s.bytes / 1024 / 1024))
```

## modules/renderer/surfaceSize {#modules-renderer-surfacesize}

```lua
surfaceSize(): { width: number, height: number }
```

The whole drawing surface in pixels — the window, the browser canvas
or the headless framebuffer. This is the size `renderer.setViewportSize`
sets and the size every UI screen is laid out over, so it is what says
whether a resize was realized, on every layout including an editor one
whose viewport panel holds a smaller rect than the window.
`{ width = 0, height = 0 }` before the first frame has drawn.

```lua
local s = renderer.surfaceSize()
```

## modules/renderer/temporal.held {#held}

```lua
temporal.held(): boolean
```

Whether a hold is pinning the per-frame clock right now.

```lua
if renderer.temporal.held() then print("frame is pinned") end
```

## modules/renderer/temporal.hold {#hold}

```lua
temporal.hold(at: number?, options: TemporalHoldOptions?): () -> ()
```

Pin the clock every per-frame effect draws itself against, and return
the release. While the hold stands, `renderer.temporal.now` answers `at`
instead of the running clock, so film grain and every other field redrawn
each frame is redrawn as the same field. Two renders taken under holds at
the same instant therefore agree pixel for pixel wherever the scene itself
has not moved, which is what makes one frame comparable with another.
Holds nest: the innermost names the instant, and the clock runs again once
the last release is called. Each release takes its own hold off the stack
whatever order the releases come in, so two callers holding at once — two
captures in flight together — each end their own hold and the clock runs
again when both have.
`exclusive` takes the clock for the `owner` key the call states: while
that hold stands, a hold is admitted only when it states the same key, and
every other one is refused with an error naming the key and the instant
holding it. That is what lets one caller wind the clock to the second it
means to photograph and keep it there while another agent drives the same
engine. The key is what an owner presents to take a nested hold of its
own, and what `renderer.temporal.release` hands the clock back by. A
capture taken while the hold stands renders at the held instant; a
`deterministic` capture takes a hold of its own that states no key, so it
runs once the clock is handed back.

**Parameters**

- `at` `number?` _(optional)_ — The instant to pin the clock at, in seconds. Two holds that state the
same instant produce the same field; the default 0 is that shared instant.
- `options` `TemporalHoldOptions?` _(optional)_ — `owner` is the key this hold is taken under, and an exclusive
hold states one. A hold that states no key is labelled with the agent the
call is attributed to, which is the account the caller presented a token
for and is shared by every session driving this engine under it.
`exclusive` takes the clock for the stated key until the hold is released.

**Returns** `()` — A function that releases this hold. Calling it twice releases once.

```lua
local release = renderer.temporal.hold() ; local png = tools.use("capture", "fromPosition", { position = { 0, 2, 8 } }) ; release()
local release = renderer.temporal.hold(46.0, { exclusive = true, owner = "stage-air" })
```

## modules/renderer/temporal.now {#now}

```lua
temporal.now(): number
```

The instant a per-frame effect should draw itself at: the innermost
hold's instant while one stands, and seconds since boot otherwise. A
system that redraws a field every frame reads this rather than the running
clock, and a capture asking for a repeatable frame then gets one.

```lua
local params = { grainTime = renderer.temporal.now() }
```

## modules/renderer/temporal.onChange {#onchange}

```lua
temporal.onChange(listener: (number) -> ()): () -> ()
```

Register a listener called with the pinned instant whenever it changes
— a hold taken, a hold released — and return the unsubscribe. A system
whose shader reads the clock out of a GPU buffer registers here, so the
buffer carries the pinned instant before the frame that hold was taken on
is drawn rather than a frame later.

**Parameters**

- `listener` `(number) -> ()` — Called with the instant now in force, in seconds.

**Returns** `()` — A function that removes this listener.

```lua
local stop = renderer.temporal.onChange(function(t) pushClock(t) end)
```

## modules/renderer/temporal.owner {#owner}

```lua
temporal.owner(): { id: string?, name: string?, at: number, exclusive: boolean }?
```

The hold naming the instant the clock answers right now: who took it,
what instant it pinned, and whether it took the clock exclusively. Several
agents drive one engine at once and a hold any of them takes moves the
clock every registered field is redrawn against, so this is how a caller
sees that another agent holds it before its own instant is quietly
replaced — and, when `exclusive` is true, `id` is the key a hold of its
own states to be admitted, and the key `renderer.temporal.release` hands
the clock back by. `id` and `name` are nil for a hold that stated no key
and that the engine attributes to no agent.

```lua
local who = renderer.temporal.owner()
if who ~= nil and who.exclusive then print(who.name, "holds the clock at", who.at) end
```

## modules/renderer/temporal.release {#release}

```lua
temporal.release(owner: string): number
```

Hand the clock back by the key its holds were taken under, and report
how many came off. A hold stands until its release is called, and the
release is a closure the call that took the hold holds: a caller that
takes a hold in one call and comes back in another, and a task that ends
between the two, both leave the clock pinned with nobody holding a release
for it. Naming the key is how the clock runs again, and how a caller
refused by an exclusive hold takes one over.

**Parameters**

- `owner` `string` — The key the holds to release were taken under — what `owner`
stated when they were taken, which `renderer.temporal.owner` reports.

```lua
renderer.temporal.release("stage-air")
```

## modules/renderer/texture.capture {#capture}

```lua
texture.capture(texture: string | { [string]: any } | AssetRef): string
```

Request a CPU readback of the GPU texture `texture` names (e.g. a
camera's rendered output). Returns a result key to pass to a
TextureCpuHandle's `:encode()` once the readback completes. Takes every form
that names a texture — the `TextureHandle` `create` returned, the guid
`renderer.texture.list` hands out, a `TextureCpuHandle` or a texture
`AssetRef`.

**Parameters**

- `texture` `string | { [string]: any } | AssetRef` — The texture to read back — a `TextureHandle`, a guid, a
`TextureCpuHandle` or a texture `AssetRef`.

```lua
local key = renderer.texture.capture(cameraTarget)
```

## modules/renderer/texture.cpuCreate {#cpucreate}

```lua
texture.cpuCreate(width: number, height: number, fill: any?): TextureCpuHandle
```

Allocate a blank CPU image (RGBA8) filled with a solid colour and return a
`TextureCpuHandle`. Compose into it with `canvas:blit(src, x, y, w, h)`, then
`canvas:encodeJpeg()` / `:encodePng()` for the bytes; `:unload()` drops it.

**Parameters**

- `width` `number` — number Canvas width in pixels.
- `height` `number` — number Canvas height in pixels.
- `fill` `any?` _(optional)_ — Optional `{ r, g, b, a }` (0-255) solid fill; defaults to opaque white.

```lua
local c = renderer.texture.cpuCreate(1024, 576, { 255, 255, 255, 255 })
```

## modules/renderer/texture.cpuFromBytes {#cpufrombytes}

```lua
texture.cpuFromBytes(bytes: buffer | string, encodeOpts: any?): TextureCpuHandle
```

Load engine-native ZTEX bytes — or an encoded image (png / jpg / webp)
— into the CPU store under a fresh guid and answer the CPU handle, for
pixels that come from somewhere other than a texture asset: a `data.ztex`
read as a file, a payload held in memory. The pixels stay at the format
they were encoded in. DEFAULT: `handle:unload()` once done with them.

**Parameters**

- `bytes` `buffer | string` — The ZTEX or image bytes.
- `encodeOpts` `any?` _(optional)_ — `{ format?, srgb?, generateMipmaps?, maxDimension? }` applied
when the bytes are an encoded image and need the engine-native encode.

```lua
local cpu = renderer.texture.cpuFromBytes(vfs.read(path)); local png = cpu:encodePng(); cpu:unload()
```

## modules/renderer/texture.create {#create}

```lua
texture.create(src: any, guid: string?): TextureHandle
```

Create (or fetch) a GPU texture resource and return its `TextureHandle`.
`src`: a `TextureCpuHandle` from `texRef:load()` (CPU→GPU under the asset's
guid, idempotent); raw pixels `{rgba, width, height, srgb?, format?}` (a
flat width*height*4 byte payload, 0-255, row-major, top-to-bottom, RGBA —
a `buffer`, a binary string, or a number array; `format = "rgba16f"`
uploads an HDR texture instead, where `rgba` carries float channel
values); a `TextureHandle` (returned as-is);
or render-target dimensions `{width, height, name?, format?}` with no pixel
source — an empty GPU texture a render pass writes into (camera output,
UI surface) and that samples like any other texture. `format` names the
colour format the target is allocated in, and the passes drawing into it
are built for that format: `"rgba8unorm"` / `"bgra8unorm"` (the two
eight-bit channel orders, either of which a surface may carry),
`"rgba16f"` / `"rgba32f"`, `"rg16f"` / `"rg32f"`, `"r16f"` / `"r32f"`.
Each also answers to its spelled-out width (`"rgba16float"`, `"r32float"`,
and so on), in any case. Omit it to take the surface's own. A float format
carries what eight bits quantize — positions, velocities, HDR. Any other
`format` raises an error naming every name that works, so a target is
allocated in the format it was asked for or not at all. A render target
takes `filter` the way raw pixels do: `"nearest"` keeps its own pixels square
wherever something draws it larger than it is — a viewport widget, a
magnified capture — which is what an image whose pixels ARE the subject
needs, since a 64x32 panel holds no detail between its pixels to
interpolate; `"linear"` (the default) smooths between them. It also
takes `screen` (the engine keeps it the size of the image being drawn),
`screenScale` (the fraction of that size it takes) and `screenSpace`
(`"scene"`, the default, or `"composite"` — the image the post-scene
phases draw into, which is the display's own resolution while the renderer
presents the viewport itself and the scene's size while a UI viewport panel
owns the presentation). A scene-space target is resized for every render
target drawn and cleared before an offscreen one; a composite-space target
follows the presented frame alone, which is what lets a pass keep an
accumulation in it. One scene-space `screen` target is therefore one
resource every render target draws through in turn, so its guid holds the
last one's image at the last one's size, and a value read back from it
belongs to whichever render target was drawn last. A reading that has to
be the viewport's own comes from `screenSpace = "composite"`, or from a
target created without `screen`. NEVER takes an AssetRef — load the CPU
first.

**Parameters**

- `src` `any` _(optional)_ — A TextureCpuHandle, raw pixels, a TextureHandle, or render-target dimensions.
- `guid` `string?` _(optional)_ — Optional v4 guid for a NEW runtime texture — the asset identity the
texture is filed under, which a material's texture slot resolves through.
Minted when absent. Ignored for the CPU-handle and render-target paths.

```lua
local gpu = renderer.texture.create(texRef:load())
local gpu = renderer.texture.create({ rgba = pixels, width = 16, height = 16 })
local px = buffer.create(16 * 16 * 4); local gpu = renderer.texture.create({ rgba = px, width = 16, height = 16 })
local rt = renderer.texture.create({ width = 512, height = 256, name = "panel_rt" })
local hdr = renderer.texture.create({ width = 512, height = 256, name = "cam_rt", format = "rgba16f" })
local led = renderer.texture.create({ width = 64, height = 32, name = "panel", filter = "nearest" })
```

## modules/renderer/texture.createFromAsset {#createfromasset}

```lua
texture.createFromAsset(
```

Put a `.texture` asset on the GPU under its own guid and answer its
handle at once. The asset's bytes are decoded off the frame and the
texture lands on the device when the decode finishes, a frame or more
later: a material naming the guid draws the shader's default for that
slot until then and rebinds when it arrives, and
`renderer.texture.isResident` reports the arrival. The decoded pixels are
dropped once uploaded unless `keepCpu` holds them in the CPU store for
`textureRef:load()`-style reads. An asset the device already holds is
answered from the shape the device reports, without reading the asset's
bytes and without a second decode.

```lua
local h = renderer.texture.createFromAsset(texRef) -- bind h.guid on a material; it draws once resident
```

## modules/renderer/texture.decode {#decode}

```lua
texture.decode(bytes: buffer | string): (any, any, any, any)
```

Decode a texture payload to its pixel buffer. Takes the two shapes the
renderer's own texture loader takes, told apart by their leading bytes:

* an engine-native `ZTEX` payload — handed back at the texel format the
payload was written in, so a height field read back here keeps every bit
it was authored with. A `ZTEX` holding block-compressed or verbatim
source-image levels decodes to `"rgba8"`.
* source image bytes — png, jpeg, gif or webp, straight off disk or out of
a `capture` — decoded to `"rgba8"` at whatever colour type, bit depth or
interlacing the file was written with. This is the call that reads the
pixels of a screenshot.

The fourth return names the format the buffer came back in: `"rgba8"` (4
bytes/texel, channels 0-255), `"rgba16"` (8 bytes/texel, 16-bit unsigned
normalized channels 0-65535) or `"rgba32f"` (16 bytes/texel, float
channels).

**Parameters**

- `bytes` `buffer | string` — A `ZTEX` payload or source image bytes.

```lua
local pixels, w, h = renderer.texture.decode(vfs.read("/source/tmp/shot.png"))
```

## modules/renderer/texture.destroy {#destroy}

```lua
texture.destroy(texture: string | { [string]: any } | AssetRef): boolean
```

Release the GPU texture `texture` names. For an empty render-into texture
(camera output, UI surface) this also frees its render scratch; for an
uploaded runtime texture it drops the GPU resource (and any CPU shadow).
After this, `renderer.texture.list` stops answering for the guid. Takes
every form that names a texture — the `TextureHandle` `create` returned, the
guid the listing hands out, a `TextureCpuHandle` or a texture `AssetRef`.

**Parameters**

- `texture` `string | { [string]: any } | AssetRef` — The texture to release — a `TextureHandle`, a guid, a
`TextureCpuHandle` or a texture `AssetRef`.

```lua
renderer.texture.destroy(rt)
renderer.texture.destroy(renderer.texture.list()[1].guid)
```

## modules/renderer/texture.encode {#encode}

```lua
texture.encode(rgba: any, width: number, height: number, opts: any): (string?, string?)
```

Encode raw pixels into an engine-native `ZTEX` payload (the on-disk
texture content). The CPU codec behind the texture assetType's `onCreate`.
`opts.format` selects the on-disk precision: `"rgba8"` / `"srgb"` (default,
8 bits/channel, `rgba` is width*height*4 bytes) or the high-precision data
formats `"rgba16"` (16-bit unsigned normalized, width*height*8 bytes) /
`"rgba32f"` (32-bit float, width*height*16 bytes) — for height/displacement
fields, baked lightmaps, and other data rasters an 8-bit format quantizes
visibly. The two high-precision formats store `rgba` verbatim and reject
`opts.generateMipmaps` / `opts.maxDimension`.

**Parameters**

- `rgba` `any` _(optional)_ — Pixel payload at `opts.format`'s native byte width — a `buffer`, a binary string, or a number array.
- `width` `number` — number
- `height` `number` — number
- `opts` `any` _(optional)_ — `{ format?, srgb?, generateMipmaps?, maxDimension? }`

## modules/renderer/texture.encodeFromImage {#encodefromimage}

```lua
texture.encodeFromImage(bytes: buffer | string, opts: any): (string?, string?)
```

Encode source image bytes (png/jpg/webp/…) into an engine-native `ZTEX`
payload. Used by the texture importer / assetType `onChange`.

**Parameters**

- `bytes` `buffer | string` — source image bytes.
- `opts` `any` _(optional)_ — `{ format?, srgb?, generateMipmaps?, maxDimension? }`

## modules/renderer/texture.frameSchedule {#frameschedule}

```lua
texture.frameSchedule(texture: string | AssetRef): { number }?
```

The times at which each layer of a timed texture stops being shown,
in seconds from the start of the sequence — the running total of the layer
display times, so the last entry is the length of one pass.

This is the form a sampler reads a sequence through: a time is turned into
a layer by finding the first entry it has not passed, whatever the
individual layer times are. It is what the `schedule` slot of the builtin
`animatedTexture` shader holds, one entry per layer.

A texture whose layers carry no timing — a still image, a sprite sheet, a
LUT stack — has no schedule and answers nil.

**Parameters**

- `texture` `string | AssetRef` — The texture — a guid, an identity, a name, a path, or a texture `AssetRef`.

```lua
local ends = renderer.texture.frameSchedule(texRef) -- {0.1, 0.15, 0.35}
```

## modules/renderer/texture.info {#info}

```lua
texture.info(ztex: buffer | string): (any, any)
```

Read the header of an engine-native `ZTEX` payload without copying the
pixels. Returns its format, dimensions, mip count, `filter` ("nearest"
or "linear" — the sampler baked into the blob from the asset's
`settings.filter`), and the payload's layer shape.

`layers` counts the array layers the payload carries and `isArray` is true
past one — the answer to "am I about to sample a `texture_2d_array`?",
available before anything samples it. `animated` is true when those layers
are a sequence in time; then `frameDelaysMs` lists each layer's display
time in milliseconds in display order, and `durationMs` totals one pass.
An animated image imports as one layer per frame, so `layers` is its frame
count. A still texture reports `layers = 1`, `isArray = false`.

**Parameters**

- `ztex` `buffer | string` — ZTEX bytes.

```lua
local i = renderer.texture.info(bytes); if i.animated then print(i.layers, "frames", i.durationMs, "ms") end
```

## modules/renderer/texture.isResident {#isresident}

```lua
texture.isResident(texture: string | { [string]: any } | AssetRef): boolean
```

True if a GPU texture is resident under this texture's guid.

**Parameters**

- `texture` `string | { [string]: any } | AssetRef` — The texture — a `TextureHandle`, a `TextureCpuHandle`, a guid, or a texture `AssetRef`.

```lua
print(renderer.texture.isResident(handle))
```

## modules/renderer/texture.list {#list}

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

Every texture currently registered, ordered by guid — the ones a script
created and the ones that reached the device through an asset alike. Each
entry carries the guid, where it came from (`origin` is `"asset"` for a
texture the asset path uploaded), and whether the GPU still holds it. A
resident entry also carries the bytes it costs, its dimensions and its
texel format, so the listing sums to `renderer.textureMemory()`. A
streamable one carries `streamOrigin` — `"asset"` when a level change reads
the levels it needs back from the asset, `"retained"` when the cache holds
the pixels for it.
A script-created entry also carries `held` — whether `renderer.hold` pins
it for the session — and `scene`, the load that created it.
`renderer.references("texture", guid)` says what is still holding a row,
and `renderer.collect()` releases the rows nothing holds.

```lua
for _, t in ipairs(renderer.texture.list()) do print(t.guid, t.bytes) end
```

## modules/renderer/texture.loadCpu {#loadcpu}

```lua
texture.loadCpu(
```

Load a `.texture` asset's pixels into the ONE guid-keyed CPU store (the
Disk→CPU step) and return a CPU handle for per-pixel access (no GPU
readback). The handle holds NO pixels — only the guid, dims and texel
format plus the read/write/encode/unload ops (which read the Rust store).
The pixels stay at the format they were authored in: `handle.format` is
`"rgba8"`, `"rgba16"` or `"rgba32f"`, and `:readPixel` reports channels in
that format's own units. Called by `texRef:load()`. DEFAULT: upload to the
GPU then `handle:unload()`.

```lua
local cpu = texRef:load(); local r,g,b,a = cpu:readPixel(3, 4); cpu:unload()
```

## modules/renderer/texture.readback {#readback}

```lua
texture.readback(texture: string | { [string]: any } | AssetRef): TextureCpuHandle
```

Read a runtime GPU texture's pixels back to CPU and return a
`TextureCpuHandle` for them — the GPU→CPU half of the runtime-texture freeze
path. A texture made with `renderer.texture.create` keeps no CPU copy, so
persisting it (`:encode()` → `asset.create("texture", …)`) reads it back
here first. Yields until the readback completes (a frame or two). After it
returns the pixels are resident in the guid-keyed CPU store: `:readPixel`,
`:writePixel`, `:getInfo`, `:encode`, `:unload` all work. Errors if the
texture never becomes GPU-resident.

A SCENE-space `screen`-sized render target is one resource shared by every
render target drawn — the viewport, an offscreen capture, a camera
rendering into a texture — resized and re-derived for each of them in
turn. The copy is taken ahead of all of them for the frame, so what a
readback of its guid answers is the content of the last frame the renderer
drew: the presented view's own image at the presented resolution, since
the presented view is the sink that draws last. A request made while the
renderer is holding frames back is carried to the next frame it draws
rather than being answered from a target another sink left standing, so a
readback can wait a frame longer than the copy itself takes.

**Parameters**

- `texture` `string | { [string]: any } | AssetRef` — The texture — the `TextureHandle` `renderer.texture.create` returned, a guid, or a texture `AssetRef`.

```lua
local cpu = renderer.texture.readback(handle); local ztex = cpu:encode(); cpu:unload()
```

## modules/renderer/texture.tone {#tone}

```lua
texture.tone(histogram: any): TextureTone
```

Reduce a histogram to what the picture's tone IS: where its darkest and
brightest pixels sit, where the body of it sits, and how much of it is
standing on the floor or the ceiling — all in code values on the 0-255
scale the pixels were delivered at.

`span` (`max - min`) is the whole range including a single stray pixel;
`spread` (`p95 - p5`) is the range the body of the picture occupies, which
is the reading that says whether a shot is legible. A frame whose subject is
modelled and shaded but delivered inside a few code values reads a large
`mean` and a tiny `spread`, and no mean alone can tell that apart from a
frame with a subject in it.

`crushed` and `clipped` are the shares of the picture at code 0 and at code
255, each 0..1 — what a shot loses to the floor and to the ceiling.

**Parameters**

- `histogram` `any` _(optional)_ — A histogram from `cpu:histogram()`.

```lua
local t = cpu:tone(); if t.spread < 24 then error("the shot is flat") end
```

## modules/renderer/texture.update {#update}

```lua
texture.update(texture: string | { [string]: any } | AssetRef, src: any): TextureHandle
```

Overwrite the GPU texture `texture` names IN PLACE, under the same guid,
from new raw pixels. Never writes a `.texture` file — the play-mode mutate
path. Takes every form that names a texture — the `TextureHandle` `create`
returned, the guid `renderer.texture.list` hands out, a `TextureCpuHandle`
or a texture `AssetRef`. Returns a handle carrying the new dimensions: the
handle it was given, refreshed, and a handle over the guid otherwise.

**Parameters**

- `texture` `string | { [string]: any } | AssetRef` — The texture to update — a `TextureHandle`, a guid, a
`TextureCpuHandle` or a texture `AssetRef`.
- `src` `any` _(optional)_ — New raw pixels `{rgba, width, height, srgb?, format?}` — `rgba` as a
`buffer`, a binary string, or a number array.

## modules/renderer/textureMemory {#modules-renderer-texturememory}

```lua
textureMemory(): {
```

What the GPU texture cache holds, split by whether the texture is
block-compressed. `compressedBytes` and `uncompressedBytes` are what those
textures cost in VRAM, measured from each texture's own format and mip
chain — so a `.texture` whose settings name `format = "bc7"` appears in the
compressed columns at a quarter of what the same image costs as RGBA8.
`blockCompressionSupported` is whether this adapter can hold
block-compressed textures at all; where it is false a BC7 payload is
uploaded decoded and lands in the uncompressed columns instead, so the
texture is present everywhere and compressed where the hardware allows it.
Measured at the end of the last rendered frame.
`streamableTextures` is how many of them a texture budget can move the
base mip level of, split by where a level change reads the levels it needs
from: `assetStreamedTextures` are read back from the asset they came from
and hold nothing in system memory, `retainedTextures` hold the payload
because a script uploaded their pixels and the GPU copy is the only other
one there is. `streamSourceBytes` is what those held payloads occupy in
system memory — bytes that are not VRAM — so it is a reading on the
retained half alone. `pinnedTextures` counts the textures big enough to
stream that stand at a level nothing can move: their pixels were released
and no asset holds them, the asset behind them could not be read back, or a
UI image, a post-process property or a render feature holds a view of them.
A texture out of the streamable set only because no measured surface wears
it stands in neither count: a surface reaching it takes it back up, so its
level moves again as soon as there is a footprint to move it by. It reads 0
while no budget is armed.

```lua
local tm = renderer.textureMemory()
print(("%d compressed textures hold %.1f MiB"):format(tm.compressedTextures, tm.compressedBytes / 1048576))
print(("%d textures stream from their asset, %d hold %.1f MiB of pixels"):format(
tm.assetStreamedTextures, tm.retainedTextures, tm.streamSourceBytes / 1048576))
```

## modules/renderer/textureStreaming {#modules-renderer-texturestreaming}

```lua
textureStreaming(): TextureStreaming
```

What the last frame's texture-residency plan decided. `budgetBytes` is
the armed budget, and `0` means residency is left alone. `streamable` is
how many textures the plan can move. `residentBytes` is what those textures
occupy now, measured from the textures that are allocated; `demandedBytes`
is what the frame's demand alone would have cost, so the two part exactly
where the budget is doing something. `starved` counts the textures left
coarser than the frame asked for, `promoted` the ones that climbed a level
this frame, and `changed` the ones whose GPU texture was replaced. A camera
approaching a surface reads `promoted` above zero for a few frames and then
zero once it settles.

`textures` is one row per streamable texture, ordered by key, carrying the
level each one was asked for and the measurement that asked. Two byte
totals can agree while a single texture sits several levels off what its
surface samples, so read the row when the question is which level a texture
holds and why.

With `budgetBytes` at 0 nothing holds a level back, so `residentBytes`,
`plannedBytes` and `demandedBytes` all read the whole chain of every
texture still enrolled and `textures` is empty — which is how a session
that armed a budget and dropped it reads back that the levels came home.

```lua
local ts = renderer.textureStreaming()
print(("textures: %.1f MiB resident of %.1f MiB demanded, %d starved"):format(
ts.residentBytes / 1048576, ts.demandedBytes / 1048576, ts.starved))
```

## modules/renderer/transmissionShadows {#modules-renderer-transmissionshadows}

```lua
transmissionShadows(): boolean
```

Whether translucent casters tint the directional light they block.

## modules/renderer/uploadStats {#modules-renderer-uploadstats}

```lua
uploadStats(): {
```

What the last completed frame spent re-describing its renderables to the
GPU. Every renderable owns a slot in the per-instance data a draw reads —
its world matrix, the bounds the culler tests it by, and the flags that
decide which passes and which culling stages see it — and a frame uploads
only the slots whose contents changed. `bytes` is what those uploads
carried, `fullBytes` what re-sending every slot would have cost, and
`writes` how many buffer writes carried it. The three numbers cover that
per-renderable data alone, so a scene standing still reads `bytes = 0`
against a `fullBytes` that grows with the scene, and the ratio says how much
of it the scene's own churn — rather than its size — is paying for.

```lua
local u = renderer.uploadStats()
print(("instance upload: %d B of %d B in %d writes"):format(u.bytes, u.fullBytes, u.writes))
```

## modules/renderer/variantSource {#modules-renderer-variantsource}

```lua
variantSource(program: string): string?
```

The WGSL one of the programs `renderer.shaderVariants()` lists holds,
exactly as the shader compiler received it. `program` is the `program`
field of a row's `base` or of one of its `variants`. Reading a base
alongside a variant shows what a feature set selected: each program's text
holds the code its own features guard. The variant-report spelling of
`renderer.compiledSource`, which answers the same for every other shader.

**Parameters**

- `program` `string` — A `program` name from `renderer.shaderVariants()`.

```lua
local row = renderer.shaderVariants()[1]
local base = renderer.variantSource(row.base.program)
```

## modules/renderer/viewportSize {#modules-renderer-viewportsize}

```lua
viewportSize(): { width: number, height: number }
```

The rect the scene was drawn into in the frame just drawn, in pixels.
That is the whole drawing surface in a runtime window, a browser canvas
and a headless engine, and the editor's viewport panel — smaller than the
surface — in an editor layout. Follows a `renderer.setViewportSize`, a
window drag and a browser page resize alike, so it reports what is
realized rather than what was asked for.

```lua
local v = renderer.viewportSize()
```

## modules/restirLighting/README {#modules-restirlighting-readme}

```lua
require("@builtin/systems/restirLighting/restirLighting") -- restirLighting
```

Direct light from many small sources at a cost that does not grow with how many there are. A shading pass that loops every light pays for every light at every pixel, which is why the count has to be capped; resampled importance sampling instead draws a few candidates per pixel, keeps one in proportion to what it would contribute, and carries a weight that makes the survivor stand for the whole set. What a pixel keeps is reused — by its neighbours this frame and by itself on the next one — so the number of candidates each pixel has to draw stays small while the set it effectively samples keeps growing. A cave of glowing crystals or a street of practicals costs what a handful of lights costs. Sources registered here are additional to the lights the engine holds rows for: this lights what it is given, on top of the scene as it was drawn. Register a source with `set`, drop it with `remove`, and the pass starts and stops with the registry.

Usage: local restirLighting = require("@builtin/systems/restirLighting/restirLighting")

## modules/restirLighting/active {#modules-restirlighting-active}

```lua
active(): boolean
```

Whether the resampling pass is currently running.

```lua
if restirLighting.active() then print("resampling") end
```

## modules/restirLighting/beginFrame {#modules-restirlighting-beginframe}

```lua
beginFrame(width: number, height: number): { [string]: any }?
```

Size the buffers to the frame, advance the frame counter and push the
settings. The render feature calls this once per frame before it enqueues
the passes; it is what gives the temporal reuse a frame to count and the
grid a size.

**Parameters**

- `width` `number` — Viewport width in pixels.
- `height` `number` — Viewport height in pixels.

```lua
local f = restirLighting.beginFrame(ctx.viewport.w, ctx.viewport.h)
```

## modules/restirLighting/capacity {#modules-restirlighting-capacity}

```lua
capacity(): number
```

The most sources the registry holds.

```lua
print(restirLighting.capacity())
```

## modules/restirLighting/clear {#modules-restirlighting-clear}

```lua
clear()
```

Drop every source and release the pass. The settings are kept.

```lua
restirLighting.clear()
```

## modules/restirLighting/configure {#modules-restirlighting-configure}

```lua
configure(opts: Settings?): State
```

Change how the resampling is run. Any omitted field keeps its current
value.

**Parameters**

- `opts` `Settings?` _(optional)_ — The settings to change — see `Settings`.

```lua
restirLighting.configure({ candidates = 16, mode = "reference" })
```

## modules/restirLighting/count {#modules-restirlighting-count}

```lua
count(): number
```

How many sources are registered.

```lua
print(restirLighting.count())
```

## modules/restirLighting/defaults {#modules-restirlighting-defaults}

```lua
defaults(): State
```

The settings a registry runs under until something changes them. Pass
this to `configure` to put every one of them back.

```lua
restirLighting.configure(restirLighting.defaults())
```

## modules/restirLighting/memoryBytes {#modules-restirlighting-memorybytes}

```lua
memoryBytes(): number
```

What the reservoir grid costs, in bytes: two vec4 per cell, twice over
because reuse reads one grid and writes the other.

```lua
print(restirLighting.memoryBytes() // 1024, "KiB")
```

## modules/restirLighting/perPixelCost {#modules-restirlighting-perpixelcost}

```lua
perPixelCost(): number
```

How many candidate evaluations a pixel pays for, per frame. It is the
answer the whole technique exists to give: fresh candidates plus borrowed
neighbours plus the one history, and no term in it is the source count.

```lua
print(restirLighting.perPixelCost(), "evaluations regardless of light count")
```

## modules/restirLighting/remove {#modules-restirlighting-remove}

```lua
remove(key: string): boolean
```

Remove the source registered under `key`.

**Parameters**

- `key` `string` — The identifier the source was registered with.

```lua
restirLighting.remove("crystal")
```

## modules/restirLighting/set {#modules-restirlighting-set}

```lua
set(key: string, source: Source): number
```

Add or replace the source registered under `key`. Re-submitting the same
key moves that source rather than adding another, which is what lets a
component push its position every frame as its entity moves.

**Parameters**

- `key` `string` — Stable identifier — an entity id works well.
- `source` `Source` — Where it is and what it emits — see `Source`.

```lua
restirLighting.set("crystal", { position = { 2, 1, 0 }, color = { 0.4, 0.8, 1 }, intensity = 6 })
```

## modules/restirLighting/settings {#modules-restirlighting-settings}

```lua
settings(): State
```

The settings currently in force.

```lua
local c = restirLighting.settings().candidates
```

## modules/restirLighting/stats {#modules-restirlighting-stats}

```lua
stats(): Stats?
```

What the resampling did on the most recent frame a read-back has landed
for, or nil before the first one arrives.

```lua
local s = restirLighting.stats(); print(s.lit, "of", s.cells, "cells lit")
```

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

```lua
require("@builtin/modules/retarget") -- retarget
```

Skeletal animation retargeting — map a clip authored on one rig onto another humanoid rig, preserving the target's shape. Pure, readable Luau: the behavior an agent follows and tweaks. `bake` is the cold, cached transform (clip + source rig + target rig -> a clip in the target's bone space); the hot path just samples the baked clip. `plan` reports which canonical roles map across the two rigs and which don't.

Usage: local retarget = require("@builtin/modules/retarget")

## modules/retarget/animation {#modules-retarget-animation}

```lua
animation(clipRef: any, targetMeshRef: any, sourceMeshRef: any?): (boolean, string)
```

Retarget an animation clip onto a target rig, returning the VFS path of a
new `.anim` whose channels name the target skeleton's bones with bind-pose
corrected rotations. The source rig is the clip's embedded `rig.zmsh` (else
`sourceMeshRef`'s skin, else the skinned mesh beside the clip in its bundle);
the target rig is `targetMeshRef`'s skin. Play the result with
`animGraph.addClip(entity, path)`. Pure asset transform — no entity/ECS state.

**Parameters**

- `clipRef` `any` _(optional)_ — Animation asset to retarget.
- `targetMeshRef` `any` _(optional)_ — Target rig mesh whose skin defines the destination skeleton.
- `sourceMeshRef` `any?` _(optional)_ — Source rig mesh the clip was authored for; omit to use the clip's embedded rig.

```lua
local ok, path = retarget.animation(clipRef, targetMeshRef)
```

## modules/retarget/aux {#modules-retarget-aux}

```lua
aux(bakeKey: string)
```

Read what was cached beside the bake at `bakeKey`.

**Parameters**

- `bakeKey` `string` — A key from `bakeKey()`.

## modules/retarget/bake {#modules-retarget-bake}

```lua
bake(clip, srcRig, tgtRig, opts)
```

Retarget a decoded clip from its source rig onto a target rig, producing
a clip in the TARGET's bone space (channels named for target bones). Per
frame it forward-kinematics the source pose on the rig AS AUTHORED (the bind
the clip's channel rotations are local to), measures each mapped role's world
rotation as a deviation from the source's CANONICAL bind, re-applies that
deviation to the target's CANONICAL bind, and converts back to a target-local
rotation through the target's ANIMATED parent. The target chain is rebuilt
top-down, so error never accumulates down a limb. Both rigs are re-posed to
the geometry-derived canonical T-pose (`normalizeToTPose`) for that deviation,
so the result depends only on the T-pose the two rigs share — never on
whatever arbitrary pose either was authored in (an A-pose source idle lands
the target's arms down, not splayed out at the A-pose offset). The apply path
seeds that same canonical rest. Translation routes through the role and is
size-scaled by the hip-height ratio; the apply path makes it relative to the
target's bind. This is the cold step — bake once per (clip, target rig) and
cache (see `bakeBytes`).

**Parameters**

- `clip` `any` _(optional)_ — A decoded clip table `{ name, duration, channels, bone_names }`
(e.g. `json.decode(skeleton.clipDecode(bytes))`).
- `srcRig` `any` _(optional)_ — Source rig the clip was authored on (parsed rig / table / JSON).
- `tgtRig` `any` _(optional)_ — Target rig to retarget onto (parsed rig / table / JSON).
- `opts` `any` _(optional)_ — Optional `{ symmetrize: boolean }` forwarded to `normalizeToTPose`.

## modules/retarget/bakeBytes {#modules-retarget-bakebytes}

```lua
bakeBytes(clipBytes, srcRig, tgtRig, cacheKey, opts)
```

Bake from clip BYTES to retargeted clip BYTES — `clipDecode` -> `bake`
-> `clipEncode` — with an in-memory cache. Retarget is cold: pass a stable
`cacheKey` (e.g. clip identity + target rig identity) and the second call
for the same pair returns the cached bytes. The hot path then just samples
the result like any native clip.

**Parameters**

- `clipBytes` `any` _(optional)_ — The source clip's `zanim` payload bytes.
- `srcRig` `any` _(optional)_ — Source rig (parsed rig / table / JSON).
- `tgtRig` `any` _(optional)_ — Target rig (parsed rig / table / JSON).
- `cacheKey` `any` _(optional)_ — Optional stable key; when given, the result is cached and reused.
- `opts` `any` _(optional)_ — Optional `{ symmetrize: boolean }` forwarded to `normalizeToTPose`
(absolute vs relative bind correction). Each mode caches separately.

## modules/retarget/bakeKey {#modules-retarget-bakekey}

```lua
bakeKey(cacheKey: string, opts): string
```

The key a bake is stored under, so a caller that derives something FROM
a bake can hold it under the same key and have it dropped at the same time.
Each correction mode bakes separately, which is what the suffix carries.

**Parameters**

- `cacheKey` `string` — The stable key passed to `bakeBytes`.
- `opts` `any` _(optional)_ — The same `{ symmetrize }` passed to `bakeBytes`.

## modules/retarget/clearCache {#modules-retarget-clearcache}

```lua
clearCache(cacheKey: string?)
```

Drop every cached bake and everything derived from it (or just
`cacheKey` when given). Call after editing a rig's profile so clips re-bake
against the corrected mapping.

**Parameters**

- `cacheKey` `string?` _(optional)_ — Optional single key to evict; omit to clear all. Accepts either
the key passed to `bakeBytes` or an already-composed `bakeKey()`.

## modules/retarget/extractRig {#modules-retarget-extractrig}

```lua
extractRig(meshBytes: buffer | string): string?
```

Strip a `.mesh` (ZMSH) payload to a lean skin-only rig: the skeleton with
geometry removed, re-encoded as a ZMSH whose only content is the skin. Returns
the rig bytes, or nil when the mesh carries no skin. A `.animation` composite
embeds this as `rig.zmsh` so a clip travels with its own source rig.

**Parameters**

- `meshBytes` `buffer | string` — Raw ZMSH mesh bytes carrying a skin.

```lua
local rig = retarget.extractRig(meshBytes)
```

## modules/retarget/humanoidProfile {#modules-retarget-humanoidprofile}

```lua
humanoidProfile(meshBytes: buffer | string): HumanoidHolder?
```

Derive the humanoid retarget holder for a rig from a `.mesh` (ZMSH)
payload, when that skeleton has the essential humanoid structure (a hips root,
a head or neck, at least one full arm chain and one full leg chain). Returns
nil for a rig that is not a humanoid — a prop, a plant whose leaves animate, a
quadruped — so a clip from it stays a plain clip rather than joining the shared
humanoid-animation pool. A rig whose bone hierarchy loops answers nil and a
message naming the bone edge that closes the loop, so a caller reading the
second return value can tell malformed input from a plain non-humanoid.

**Parameters**

- `meshBytes` `buffer | string` — Raw ZMSH mesh bytes carrying a skin.

```lua
local holder = retarget.humanoidProfile(meshBytes)
```

## modules/retarget/isHumanoid {#modules-retarget-ishumanoid}

```lua
isHumanoid(meshBytes: buffer | string): boolean
```

Whether a rig is a humanoid avatar — true when `humanoidProfile` resolves a
holder for it. Use this to tell a humanoid character apart from a generic
animated mesh (a prop, a plant, a quadruped) before treating its clips as
shareable humanoid animations.

**Parameters**

- `meshBytes` `buffer | string` — Raw ZMSH mesh bytes carrying a skin.

```lua
if retarget.isHumanoid(meshBytes) then ... end
```

## modules/retarget/loadRig {#modules-retarget-loadrig}

```lua
loadRig(ref)
```

Resolve a `.rig` asset and return its parsed, FK-enriched rig (ready for
`plan` / `bake`). The rig payload is the asset's `rig.json`.

**Parameters**

- `ref` `any` _(optional)_ — A `.rig` asset ref (identity / guid / path / handle).

## modules/retarget/normalizeToTPose {#modules-retarget-normalizetotpose}

```lua
normalizeToTPose(rig, opts)
```

Re-pose a rig's bind to the EXACT canonical T-pose, so a clip's source
rig and the avatar it drives share one reference pose. Retarget transfers
RELATIVE motion, so any residual bind mismatch (hands rolled the wrong way,
feet pointing askew, an A-pose vs a T-pose) shows up as broken hands/feet in
the result. Each bone is posed to a canonical world frame for its role —
direction AND roll: arms horizontal palms-down, legs straight down, spine up.
Only the limb bones whose bind direction differs between an A-pose and a
T-pose are aimed; limb ENDPOINTS (hands, feet, toes) and bones with no role
keep their authored orientation relative to the re-posed parent (their pose is
mesh-defined, so aiming them twists the hand / tips the foot). The whole body
is also rigidly de-rotated into an upright, forward-facing frame (handling a
baked root rotation) and centered on its sagittal plane.
Bind correction is RELATIVE by default — bone offsets/lengths/inverse-bind are
untouched, so the rig keeps its own proportions and any authored left/right
asymmetry. Pass `opts.symmetrize = true` for ABSOLUTE correction: left/right
bones are mirrored across the sagittal plane for a perfectly symmetric bind,
overriding the rig's authored asymmetry/proportions.

**Parameters**

- `rig` `any` _(optional)_ — The rig to normalize (parsed rig / table / JSON).
- `opts` `any` _(optional)_ — Optional `{ symmetrize: boolean }`. `symmetrize=true` = absolute
correction (force symmetry); default/false = relative (preserve proportions).

## modules/retarget/plan {#modules-retarget-plan}

```lua
plan(srcRig, tgtRig)
```

Report how a source rig's clips map onto a target rig: which canonical
roles both rigs fill (`mapped`), which the source has but the target lacks
(`unmappedSource` — those channels are dropped), and which the target has
spare (`unmappedTarget`). Use it to see why a retarget is partial and which
bone to hand-map in a rig's profile.

**Parameters**

- `srcRig` `any` _(optional)_ — Source rig — a parsed rig, a `.rig` table, or its JSON string.
- `tgtRig` `any` _(optional)_ — Target rig — same forms.

## modules/retarget/serializeProfile {#modules-retarget-serializeprofile}

```lua
serializeProfile(holder: HumanoidHolder): string
```

Serialize a humanoid holder to the `humanoid.profile` file body: an
editable YAML role -> bone-name map. Roles list hips-first head-to-toe through
the limbs, then any extras name-sorted, so the file reads top-down and diffs
stably. Edit a value to correct an auto-derived mapping.

**Parameters**

- `holder` `HumanoidHolder` — A holder from `humanoidProfile`.

```lua
files["humanoid.profile"] = retarget.serializeProfile(holder)
```

## modules/retarget/setAux {#modules-retarget-setaux}

```lua
setAux(bakeKey: string, value)
```

Cache a value beside the bake at `bakeKey`. It is dropped whenever that
bake is, so it cannot outlive the bytes it was derived from.

**Parameters**

- `bakeKey` `string` — A key from `bakeKey()`.
- `value` `any` _(optional)_ — The value to hold.

## modules/rt_ao/README {#modules-rt-ao-readme}

```lua
require("@builtin/modules/rt_ao") -- rt_ao
```

Ray-traced ambient occlusion — the settings the `rt_ao` render feature runs on, and the lifetime of the pass that draws it. A hemisphere of short rays per pixel is traced against the scene acceleration structure, and the fraction that hits nearby geometry darkens the frame.

Usage: local rt_ao = require("@builtin/modules/rt_ao")

## modules/rt_ao/active {#modules-rt-ao-active}

```lua
active(): boolean
```

Whether the occlusion pass is running. Read from the live feature
registry, so a feature created directly through `renderer.feature.create`
counts the same as one this module started.

```lua
if rt_ao.active() then print(rt_ao.stats().raysPerFrame) end
```

## modules/rt_ao/clear {#modules-rt-ao-clear}

```lua
clear()
```

Turn occlusion off and release the pass. The other settings are kept, so
a later `set({ strength = ... })` brings back the same look.

```lua
rt_ao.clear()
```

## modules/rt_ao/get {#modules-rt-ao-get}

```lua
get(): RtAoState
```

The occlusion settings currently in force.

```lua
local rays = rt_ao.get().rays
```

## modules/rt_ao/publish {#modules-rt-ao-publish}

```lua
publish(built: { traceWidth: number, traceHeight: number, dispatches: number, traceTarget: string? })
```

Record the grid the feature allocated and the dispatches it enqueues.
The feature calls this as it builds, which is what gives `stats` the shape
of the chain that is running.

**Parameters**

- `built` `{ traceWidth: number, traceHeight: number, dispatches: number, traceTarget: string? }` — The grid and dispatch count the feature just created.

```lua
rt_ao.publish({ traceWidth = 960, traceHeight = 540, dispatches = 9, traceTarget = rt.guid })
```

## modules/rt_ao/qualityLevels {#modules-rt-ao-qualitylevels}

```lua
qualityLevels(): { [string]: { rays: number, resolution: number } }
```

What each quality level costs: `rays` hemisphere rays per pixel, cast
from a grid `resolution` of the frame's own. The rays a frame traces is
those two multiplied by the frame's pixels, and the trace pass's cost is
linear in it.

```lua
local shape = rt_ao.qualityLevels().ultra
```

## modules/rt_ao/set {#modules-rt-ao-set}

```lua
set(opts: RtAoOpts?): RtAoState
```

Set how the occlusion is traced. Any omitted field keeps its current
value, so a call can move one knob without restating the rest. A `strength`
of 0 turns occlusion off and releases the pass.

**Parameters**

- `opts` `RtAoOpts?` _(optional)_ — Occlusion settings — see `RtAoOpts`.

```lua
rt_ao.set({ quality = "low", radius = 1.5 })
```

## modules/rt_ao/stats {#modules-rt-ao-stats}

```lua
stats(): RtAoStats
```

What the running feature built — the grid it traces from, the rays that
grid costs each frame, and the dispatches it enqueues. The feature writes
these as it allocates its targets, so they describe the pass that exists
this frame; `traceTarget` is that grid as a resource, for a reader that
wants to measure it.

```lua
local s = rt_ao.stats(); print(s.traceWidth, s.traceHeight, s.raysPerFrame)
```

## modules/runtime_participation/README {#modules-runtime-participation-readme}

```lua
require("@builtin/modules/api/engine/runtime_participation") -- runtime_participation
```

Reads and writes the RuntimeParticipation lifecycle axis for an entity, and answers the save / edit-liveness / play-liveness questions that follow from a mode. One source of truth for the four modes (WorldEntity, PrototypeOnly, EditorOnly, RuntimeOnly) so save and play-mode code agree on what each mode means.

Usage: local runtime_participation = require("@builtin/modules/api/engine/runtime_participation")

## modules/runtime_participation/isSaved {#modules-runtime-participation-issaved}

```lua
isSaved(mode: string): boolean
```

Whether an entity with this mode is written to the persisted world.
True for WorldEntity, PrototypeOnly, and EditorOnly; false for RuntimeOnly.

**Parameters**

- `mode` `string` — A RuntimeParticipation mode string.

## modules/runtime_participation/liveInEdit {#modules-runtime-participation-liveinedit}

```lua
liveInEdit(mode: string): boolean
```

Whether an entity with this mode is live while authoring in edit mode.
True for WorldEntity, PrototypeOnly, and EditorOnly; false for RuntimeOnly.

**Parameters**

- `mode` `string` — A RuntimeParticipation mode string.

## modules/runtime_participation/liveInPlay {#modules-runtime-participation-liveinplay}

```lua
liveInPlay(mode: string): boolean
```

Whether an entity with this mode is live during play.
True for WorldEntity and RuntimeOnly; false for PrototypeOnly and EditorOnly.

**Parameters**

- `mode` `string` — A RuntimeParticipation mode string.

## modules/runtime_participation/modeOf {#modules-runtime-participation-modeof}

```lua
modeOf(entityId: string): string
```

The entity's RuntimeParticipation mode. Defaults to "WorldEntity".

**Parameters**

- `entityId` `string` — Entity id to read.

## modules/runtime_participation/set {#modules-runtime-participation-set}

```lua
set(entityId: string, mode: string)
```

Sets the RuntimeParticipation mode on an entity. A mode that is not
saved marks the entity temporary so the scene-save exclusion drops it.

**Parameters**

- `entityId` `string` — Entity id to write.
- `mode` `string` — The mode to store.

## modules/runtime_participation/standsDown {#modules-runtime-participation-standsdown}

```lua
standsDown(mode: string, engineMode: string): boolean
```

Whether an entity with this mode stands down — stops rendering and
ticking — when an EDITOR session is in `engineMode`. This is the question a
mode flip actually asks, and it is not `liveInPlay`: that answers which
entities a SHIPPED RUNTIME contains, where there is no authoring surface at
all. A session able to flip modes is an editor session by construction (the
runtime profile forbids mode swaps), so the editor's own cameras, panels and
gizmos are present in both of its modes and stand down in neither. What
stands down in play is a template, whose clones are what runs; what stands
down in edit is a runtime entity.

**Parameters**

- `mode` `string` — A RuntimeParticipation mode string.
- `engineMode` `string` — The engine mode the session is in, "play" or "edit".

```lua
if rp.standsDown(entity(id).participation, tostring(engine.mode)) then ... end
```

## modules/sceneProxy/README {#modules-sceneproxy-readme}

```lua
require("@builtin/systems/sceneProxy/sceneProxy") -- sceneProxy
```

A coarse volumetric stand-in for the scene's geometry: a grid that answers how far the nearest surface is from any point, cheaply enough to ask along a whole ray.

Usage: local sceneProxy = require("@builtin/systems/sceneProxy/sceneProxy")

## modules/sceneProxy/build {#modules-sceneproxy-build}

```lua
build(opts: ProxyOpts?): ({ [string]: any }?, string?)
```

Build the proxy over the scene as it currently stands. Allocates the
grid, scatters the scene's triangles into it, and floods the result into a
distance field.

**Parameters**

- `opts` `ProxyOpts?` _(optional)_ — Grid settings — see the fields below. All are optional.

```lua
sceneProxy.build({ resolution = 64 })
```

## modules/sceneProxy/building {#modules-sceneproxy-building}

```lua
building(): boolean
```

Whether a build or refresh is running right now. Both yield while the
GPU answers, so this is what a caller checks before starting one of its
own over the same scene.

```lua
if not sceneProxy.building() then sceneProxy.build() end
```

## modules/sceneProxy/built {#modules-sceneproxy-built}

```lua
built(): boolean
```

Whether a field is built.

```lua
if sceneProxy.built() then ... end
```

## modules/sceneProxy/claim {#modules-sceneproxy-claim}

```lua
claim(key: string, opts: TrackOpts?): boolean
```

Ask for the field to be kept current, on behalf of something that will
say when it no longer wants it. Tracking follows the claims that stand: it
is on while there is at least one, and the settings in force are those of
the claim made most recently. Two scene objects each wanting a proxy
therefore share one grid, and neither turns the other's off.

**Parameters**

- `key` `string` — What is asking — anything that names the claimant, an entity id for a
component.
- `opts` `TrackOpts?` _(optional)_ — What to follow and how closely, as `track` takes them.

```lua
sceneProxy.claim(entityId, { resolution = 64 })
```

## modules/sceneProxy/claimed {#modules-sceneproxy-claimed}

```lua
claimed(key: string): boolean
```

Whether a claim made under this key still stands. A release from
elsewhere — `destroy` drops every claim there is — is what this answers
false after, so something whose presence IS the request for a proxy can
make it again.

**Parameters**

- `key` `string` — The key the claim was made under.

```lua
if not sceneProxy.claimed(id) then sceneProxy.claim(id, opts) end
```

## modules/sceneProxy/destroy {#modules-sceneproxy-destroy}

```lua
destroy()
```

Release the proxy's grid and its working volumes, and with them every
claim on it and any build or refresh still in flight — what that work was
making is a grid nothing asked for any more.

```lua
sceneProxy.destroy()
```

## modules/sceneProxy/distanceAt {#modules-sceneproxy-distanceat}

```lua
distanceAt(point: { [string]: number }): number?
```

The world-space distance from `point` to the nearest surface. Reads the
field the way a shader does — interpolated between voxel centres, and `far`
outside the extent the grid covers. Yields while the GPU answers, so call
it from a task or `execute`; a shader samples the field directly instead.

**Parameters**

- `point` `{ [string]: number }` — `{ x, y, z }` world position.

```lua
local d = sceneProxy.distanceAt({ x = 0, y = 2, z = 0 })
```

## modules/sceneProxy/gridParams {#modules-sceneproxy-gridparams}

```lua
gridParams(): { number }?
```

The grid a shader needs to read the field: the two vec4 that
`scene_proxy.shaderModule`'s `spGridFrom` unpacks, as eight floats ready to
write into a consuming pass's own parameter buffer.

```lua
local p = sceneProxy.gridParams(); myParams:write(p)
```

## modules/sceneProxy/maintain {#modules-sceneproxy-maintain}

```lua
maintain(): boolean
```

One maintenance tick: build the field when tracking is armed and nothing
is built yet, otherwise walk a slice of the scene and start a refresh once a
whole walk has found that the geometry the proxy covers moved. Cheap on a
scene standing still, bounded on a big one, and never yields — the work it
starts runs as its own task, which is what lets a component `update` drive
it.

```lua
function update() sceneProxy.maintain() end
```

## modules/sceneProxy/refresh {#modules-sceneproxy-refresh}

```lua
refresh(): (boolean, string?)
```

Rebuild the field from the scene's current geometry, over the grid the
proxy already has. What to call after something moves.

```lua
sceneProxy.refresh()
```

## modules/sceneProxy/release {#modules-sceneproxy-release}

```lua
release(key: string): boolean
```

Drop a claim. The grid is released when it was the last one standing;
otherwise the claim made most recently before it takes the settings back.

**Parameters**

- `key` `string` — The key the claim was made under.

```lua
sceneProxy.release(entityId)
```

## modules/sceneProxy/sampleAt {#modules-sceneproxy-sampleat}

```lua
sampleAt(points: { any }): ({ { distance: number, normal: { number } } }?, string?)
```

Ask the field about a batch of world points in one dispatch. Yields
while the GPU answers, so call it from a task or `execute`.

**Parameters**

- `points` `{ any }` — A list of world positions, each `{ x, y, z }` or `{ X, Y, Z }`.

```lua
local s = sceneProxy.sampleAt({ { x = 0, y = 2, z = 0 } })
```

## modules/sceneProxy/settings {#modules-sceneproxy-settings}

```lua
settings(): { [string]: any }?
```

The grid in force, the world extent it covers, and what it cost.
`boundsMin` and `boundsMax` are the corners of the box the grid spans —
`resolution` voxels along each axis from `boundsMin`, and what a point has
to fall inside to have an answer. The geometry the grid was fitted to sits
one voxel inside them at each end. `gridParams()` is what a consuming
shader wants — the same numbers in the layout `spGridFrom` reads.

```lua
local s = sceneProxy.settings(); print(s.voxelSize, s.memoryBytes)
```

## modules/sceneProxy/track {#modules-sceneproxy-track}

```lua
track(opts: TrackOpts?): boolean
```

Keep the field current by itself: from here on the proxy watches the
geometry it covers and refreshes when that geometry moved. Returns at once
— it records what to follow and leaves the work to `maintain`, which
something has to drive each frame; `SceneProxy.component` is that driver for
an authored scene. A proxy that is not built yet is built by the first tick,
at `resolution`.

**Parameters**

- `opts` `TrackOpts?` _(optional)_ — What to follow and how closely — see the fields below. All are
optional.

```lua
sceneProxy.track({ resolution = 64, interval = 0.2 })
```

## modules/sceneProxy/tracking {#modules-sceneproxy-tracking}

```lua
tracking(): boolean
```

Whether the proxy is following the scene.

```lua
if not sceneProxy.tracking() then sceneProxy.track() end
```

## modules/sceneProxy/trackingStats {#modules-sceneproxy-trackingstats}

```lua
trackingStats(): { [string]: any }
```

What tracking is set to follow, what it has done, and what it costs: the
settings in force, how many claims stand, how many entities the last
completed walk over the scene looked at and how long the last slice of one
took, how many GPU-driven populations the field standing in the grid
covers, how many builds, refreshes and refitting rebuilds it has started,
how many ticks it stood aside for work already running, and the last error
a walk or a refresh reported.

```lua
print(sceneProxy.trackingStats().refreshes)
```

## modules/sceneProxy/untrack {#modules-sceneproxy-untrack}

```lua
untrack()
```

Stop keeping the field current. The grid stays built and readable; it
simply stops following the scene.

```lua
sceneProxy.untrack()
```

## modules/scene_instantiable/README {#modules-scene-instantiable-readme}

```lua
scene_instantiable
```

The instantiation contract's shared half. An asset type opts into scene instantiation by defining `instantiate(self, target?, opts?)` on its behaviour `ref` table. Both halves of that call are shared, so a caller writes the same code against every type. IN — the base opts `position`, `rotation`, `scale`, `name`, `temporary` mean the same thing for every type, so their implementation lives here. `rotation` takes three numbers as pitch/yaw/roll in DEGREES, or four as a quaternion. `root` stands the root entity (parented, born temporary, named, placed) and `place` applies the placement opts to a root the type adopted (a bundle exploding onto its target). OUT — every type returns `(root, idMap)` through `result`: the composed root as a LIVE `EntityRef`, and the `originalId -> runtimeId` map naming what the composition spawned (`{}` for a type with no addressable children). Composition is synchronous — the root is usable the moment the call returns. `AssetRef.instantiate` is dispatched through this same check whether or not the type called it, so the two values a caller gets back never depend on which asset it held. Also registers the `sceneInstantiable` field-constraint validator: a constrained value must be an asset whose type defines `instantiate` (`ref:canInstantiate()`), which is what makes `Field.instantiableRef` accept by CAPABILITY instead of a hardcoded type list. `nil` (no asset) passes — the field is optional.

## modules/scene_instantiable/isOwned {#modules-scene-instantiable-isowned}

```lua
isOwned(opts: { [string]: any }?): boolean
```

Whether this `instantiate` call already has an owner. The `Asset` /
`SceneModule` components drive `instantiate` themselves and tag the call
with `sourceTag`; they hold the asset reference, persist the composition's
`idMap`, and re-run the composition on every load. A call with no tag came
straight from `ref:instantiate(...)` and has no such owner, so a type whose
composition must survive a reload composes, then hands the result one.

**Parameters**

- `opts` `{ [string]: any }?` _(optional)_ — The `instantiate` opts table (nil-safe).

```lua
if not Instantiable.isOwned(opts) then ... end
```

## modules/scene_instantiable/own {#modules-scene-instantiable-own}

```lua
own(root: any, self: any, idMap: { [string]: string }?): any
```

Hand an ALREADY-COMPOSED root to an `Asset` component pointing at
`self`. The type composes first and calls this last: the component adopts
the composition standing on `root` rather than building a second one, and
from then on owns the reference — it keeps `idMap` in a persisted field
and re-composes with those same ids on the next load, so cross-entity
references into the composition (`SkinnedModel.skeletonRoot`) stay valid.
Composed children never reach `scene.json`; the scene stores the reference
and re-composes from it.

**Parameters**

- `root` `any` _(optional)_ — The root entity, as an `EntityRef` proxy, with the composition live.
- `self` `any` _(optional)_ — The asset ref being instantiated.
- `idMap` `{ [string]: string }?` _(optional)_ — The `original_id -> runtime id` map naming that composition.

```lua
if not Instantiable.isOwned(opts) then Instantiable.own(root, self, freshMap) end
```

## modules/scene_instantiable/place {#modules-scene-instantiable-place}

```lua
place(root: any, opts: { [string]: any }?): any
```

Apply the base placement opts to a root the type already has — the
adopt path (a bundle exploding onto its target, a sceneModule
reconciling under one). `position` / `rotation` / `scale` land on the
root's local transform; `name` renames it. `rotation` takes three numbers
as pitch/yaw/roll in DEGREES, or four as a quaternion.

**Parameters**

- `root` `any` _(optional)_ — The root entity, as an `EntityRef` proxy.
- `opts` `{ [string]: any }?` _(optional)_ — The `instantiate` opts table (nil-safe).

```lua
return Instantiable.place(target, opts), idMap
Instantiable.place(root, { rotation = { 0, 90, 0 } })  -- yaw 90°
```

## modules/scene_instantiable/result {#modules-scene-instantiable-result}

```lua
result(self: any, root: any, idMap: { [string]: string }?): (any, { [string]: string })
```

Return an `instantiate` through the contract — the OUT half, the
counterpart of `root` / `place`. Checks that `root` is a live entity ref
and normalises a missing map to `{}`, so every type hands its caller the
same two values: the composed root, live on return, and the
`originalId -> runtimeId` map naming what it spawned. `AssetRef` runs
every `instantiate` through this on the way out, so a type that returns
something else fails at its own call rather than handing a caller a nil
root or a map that is sometimes absent.

**Parameters**

- `self` `any` _(optional)_ — The asset ref being instantiated — named in the error.
- `root` `any` _(optional)_ — The composed root, as an `EntityRef` proxy.
- `idMap` `{ [string]: string }?` _(optional)_ — The `original_id -> runtime id` map, or nil for a type that
spawns no addressable children.

```lua
return Instantiable.result(self, root, freshMap)
return Instantiable.result(self, Instantiable.root(self, target, opts))
```

## modules/scene_instantiable/root {#modules-scene-instantiable-root}

```lua
root(self: any, target: any?, opts: { [string]: any }?): any
```

Stand the root entity for an asset type's `instantiate` — the whole
base contract in one call. Validates `target` (an owning entity ref, or
nil), spawns the root as its child (born temporary when `opts.temporary`,
named `opts.name` else the asset's own name), and applies the placement
opts. The type adds its components to the returned root; what it returns
from `instantiate` is `(thisRoot, idMap)`.

**Parameters**

- `self` `any` _(optional)_ — The asset ref being instantiated.
- `target` `any?` _(optional)_ — Optional owning entity ref — the root spawns as its child.
- `opts` `{ [string]: any }?` _(optional)_ — The `instantiate` opts table (nil-safe). `rotation` takes three
numbers as pitch/yaw/roll in DEGREES, or four as a quaternion.

```lua
local root = Instantiable.root(self, target, opts)
```

## modules/scene_loader/README {#modules-scene-loader-readme}

```lua
scene_loader
```

Luau-side scene loader. Reads scene.json v6 and v7, refuses versions outside that range with a typed error, dispatches to entity.spawn / component.add / lights.setup, auto-discovers the sibling entrypoint.luau via vfs.exists. v6 attaches the declarative player + camera blocks to the Scene proxy for procedural resolution; v7 stashes the string player intent and does no procedural player/camera spawn. Replaces the legacy Rust __layers.load FFI path; the Rust FFI remains for one release as a safety net but is no longer invoked by any in-tree caller. Delta-overlay aware: when a `scene_dirty/` directory exists next to canonical scene.json, the loader hands the merge off to `scene_saver.composeMerged` — canonical scene.json + dirty manifest overrides + per-entity overlay files = the assembled body. Single merge point so the load + promote paths can never disagree. See § 10 of the player-camera-unification integration design for the architecture rationale (pure Luau, performance budget ~5 ms per 1k-entity scene, ECS FFI is sufficient without new primitives).

## modules/scene_saver/README {#modules-scene-saver-readme}

```lua
scene_saver
```

Luau-side scene saver. Persists scene state via a delta-overlay model: Canonical (committed work) <scene folder>/scene.json Dirty (work-in-progress, deltas only) <scene folder>/scene_dirty/manifest.json     scene-level config overrides (lighting, player, camera, format, version) <scene folder>/scene_dirty/entities/<id>.json one file per CHANGED entity: * full body  — modified or newly spawned * tombstone  — { tombstone = true } for despawn The dirty directory carries ONLY the deltas. Entities unchanged since the last canonical save have NO entry under entities/. Editing one cube in a 100k-entity scene writes exactly one ~1KB file per drain; the manifest is touched only when scene-level config changes. The entity-id list is NOT carried in the manifest — it's derived at load / promote time from `canonical.entities[]` plus a filesystem listing of `entities/`. Concurrent writes to per-entity files therefore never produce manifest-conflict orphans (the conflict surface is one entity at a time, not the whole-scene index). Tombstones survive in dirty until the next save (when `clearDirty` wipes the directory). An orphan tombstone — one targeting an entity that wasn't in canonical either (i.e. the entity was spawned and deleted inside the same edit session before save) — is a no-op at compose time, so the file shape is robust regardless of operation order. The composer (`composeMerged`) is the canonical merge point used by both this saver's promote/save paths AND `scene_loader.M.load`, so there's exactly one place that knows how to combine canonical with the overlay. Captures authored intent only: no spawner-managed entities (player identities, primary camera), no temporary entities, no runtime player position. FFI shapes (discovered at runtime — differ from plan): - entity.findAll() → array of {id: string, name: string} tables. - localPosition / localScale expose number components .x/.y/.z. - localRotation exposes quaternion components .x/.y/.z/.w. - entity(id).getParent() → parent entity proxy or nil; its `.id` is the id string. - entity(id).name → string name (direct field, no function call). - lighting snapshot is read directly from settings.lighting.

## modules/scene_saver/componentShortName {#modules-scene-saver-componentshortname}

```lua
componentShortName(t: string): string
```

The component type name without its library prefix, so a saved record
(`Model`) and a live one (`@builtin::components.Model`) name the same type.

**Parameters**

- `t` `string` — A component type name in either form.

```lua
require("@builtin::modules.api.engine.scene_saver").componentShortName("@builtin::components.Model")
```

## modules/scene_saver/discardSceneEdits {#modules-scene-saver-discardsceneedits}

```lua
discardSceneEdits(name: string, select: (string | { string })?): SceneEditDiscard
```

Take a scene's unbaked overlay edits back out, leaving the canonical
file as what the scene carries. This is the second verdict on the edits
`pendingSceneEdits` reports and a publication call refuses over: staging
bakes them into the scene, this drops them. Each edit's overlay record is
deleted and its entity withdrawn so no writer re-states it, whichever
session wrote the record and however long it has stood.

**Parameters**

- `name` `string` — The scene — a `.scene` folder path, a `scene.json` path, or a bare
scene name.
- `select` `(string | { string })?` _(optional)_ — Which edits to drop: an entity id or entity name, or a list of
them. Omitted, every edit the scene has pending.

```lua
require("@builtin::modules.api.engine.scene_saver").discardSceneEdits(layers.active.name)
require("@builtin::modules.api.engine.scene_saver").discardSceneEdits("/zero/source/scenes/main.scene", "look")
```

## modules/scene_saver/hasPendingSceneEdits {#modules-scene-saver-haspendingsceneedits}

```lua
hasPendingSceneEdits(name: string): boolean
```

Whether baking the scene's dirty overlay into its canonical file would
change the scene. False when the overlay is absent, and false when it
holds only records the canonical file already states.

**Parameters**

- `name` `string` — The scene — a `.scene` folder path, a `scene.json` path, or a bare
scene name.

```lua
require("@builtin::modules.api.engine.scene_saver").hasPendingSceneEdits(layers.active.name)
```

## modules/scene_saver/pendingSceneEdits {#modules-scene-saver-pendingsceneedits}

```lua
pendingSceneEdits(name: string): ({ PendingSceneEdit }, string?)
```

Every edit a scene's dirty overlay holds that baking it would write
into the canonical scene file: an added entity, an updated one, a removed
one, or a change to the scene's own lighting / player / camera config. An
EMPTY result is the verdict that the canonical scene already says what the
overlay says, whatever rows the overlay carries. Each entry names the
entity and describes the difference.

**Parameters**

- `name` `string` — The scene — a `.scene` folder path, a `scene.json` path, or a bare
scene name.

```lua
require("@builtin::modules.api.engine.scene_saver").pendingSceneEdits("/zero/source/scenes/main.scene")
```

## modules/scene_saver/recordDiffLines {#modules-scene-saver-recorddifflines}

```lua
recordDiffLines(oldRec: any, newRec: any, maxLines: number?): { string }
```

Human lines describing how a live entity record differs from the record
the scene carries: transform channels, component fields, component
additions and removals, and attribute additions, changes and removals.
Compares authored intent — a component field participates where the
scene's record declares it, numbers compare within a float-noise epsilon,
and asset references compare by the asset they name rather than by the
shape they are written in. An EMPTY result is the "unchanged" verdict.

**Parameters**

- `oldRec` `any` _(optional)_ — The scene's entity record.
- `newRec` `any` _(optional)_ — The live entity record.
- `maxLines` `number?` _(optional)_ — How many lines to report before summarizing the rest as "…".

```lua
local ss = require("@builtin::modules.api.engine.scene_saver"); ss.recordDiffLines(saved, ss.serializeEntity(id))
```

## modules/scene_saver/recordFieldValue {#modules-scene-saver-recordfieldvalue}

```lua
recordFieldValue(v: any): (any, string?)
```

The durable form of one component field value — what a record states
for it. An asset reference keeps the identity a later session re-resolves
it from; a live GPU resource handle names a slot in this session's GPU
registry, so it is left out and named in the second return instead.
Reading a live field through this is what lets a consumer of a record
compare what it holds against what the record says in one form.

**Parameters**

- `v` `any` _(optional)_ — A field value read off a live component.

```lua
require("@builtin::modules.api.engine.scene_saver").recordFieldValue(model.material) -- { __ref = "..." }, nil
```

## modules/scene_saver/trackingReason {#modules-scene-saver-trackingreason}

```lua
trackingReason(): string?
```

Why an authored scene edit made from THIS call's own context would not
be recorded right now, or nil while it would be. A scene records its edits
in edit mode, outside a scene load, outside the world entrypoint's respawn
pass, and outside a component or entrypoint callback tick; inside any of
those a spawn or a change reaches the live session and no file. This is the
question an empty `pendingSceneEdits` list cannot answer on its own — the
same list stands for "the scene is saved" and for "nothing is watching it".

```lua
require("@builtin::modules.api.engine.scene_saver").trackingReason()
```

## modules/scene_saver/transformDiffLines {#modules-scene-saver-transformdifflines}

```lua
transformDiffLines(oldRec: any, newRec: any): { string }
```

Diff lines for an entity's transform channels (position / rotation /
scale), comparing the live record against the record the scene carries. A
channel the saved record OMITTED defaults to the identity transform, so a
move away from origin registers even for an entity saved at identity (which
carries no transform block) — while an unmoved entity whose live record
materializes the identity transform produces no line.

**Parameters**

- `oldRec` `any` _(optional)_ — The scene's entity record (may omit `transform` or channels).
- `newRec` `any` _(optional)_ — The live entity record.

```lua
require("@builtin::modules.api.engine.scene_saver").transformDiffLines({}, { transform = { position = { 0, 1, 0 } } })
```

## modules/scene_swap_orchestrator/README {#modules-scene-swap-orchestrator-readme}

```lua
scene_swap_orchestrator
```

Drives multiplayer room transitions + the scene-swap gate around scene load/unload events. Subscribes to layers.onUnload + layers.onBeforeLoad and translates them into a leaveRoom -> gate.begin -> teardown -> gate.finish -> joinRoom sequence. Room key is `{worldGuid}/{profile}/{mode}/{sceneGuid}` — never name-based; world and scene segments are always GUIDs (stable across renames and collaborators), and `{profile}` (runtime/editor) keeps published and live peers apart. Without this orchestrator, scene swaps world would broadcast EntityDespawn to peers still subscribed to the old room, and transient teardown state would land in the dirty file.

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

```lua
require("@builtin/modules/scopes") -- scopes (also available as global 'scopes')
```

The owning contexts live resources are registered under — what each context holds right now, and how to end everything one holds. -- What is live, and what will never be reached by a seam? for _, r in scopes.list() do if not r.endsAtASeam then print(r.kind, r.handle, r.scope, r.detail) end end -- End everything an earlier execute chunk left behind. scopes.release("exec:__exec_12")

A resource reached through a handle — a substrate job, and every other
handle-based resource as it adopts this — outlives the call that made it.
Each one records the context it was registered from, and the engine ends
what a context left behind once that context's run is over.
Three contexts own resources, and they differ in what ends them:
  * `chunk:<identity>` — a module. Ends when the module runs again (a VFS
    write to its source) or is dropped from the require cache
    (`vfs.reload`). The next run registers its own.
  * `component:<instanceId>` — one component instance. Ends when that
    instance is destroyed: its entity despawned, its scene cleared, the
    component removed.
  * `exec:<chunk>` — a chunk submitted for a single run, such as an
    `execute` call. It is never re-entered, so nothing ends it on its own.
That last one is what this module is for. A chunk that registered a
resource and lost the handle — it raised before storing it, or simply
finished — left something live that no variable names. `list()` finds it
by the context that registered it, and `release(scope)` ends it.
Explicit release is unchanged: `destroy` / `cancel` / `close` end a
resource the moment content calls them. This is what happens to the ones
nobody ended.

Usage: local scopes = require("@builtin/modules/scopes")
Also available as global: scopes

## modules/scopes/current {#modules-scopes-current}

```lua
current(): string?
```

The scope the calling code registers a resource under right now — the
module whose body is running, the component instance whose lifecycle hook
is on the stack, or the chunk of this call. Nil when the caller registers
under no context.

```lua
print("resources I register follow", scopes.current())
```

## modules/scopes/list {#modules-scopes-list}

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

Every live resource that follows an owning context, across every
subsystem holding them. A resource registered with no context above it —
the engine's own — is not listed, because no scope reaches it.

```lua
for _, r in scopes.list() do print(r.scope, r.kind, r.detail) end
```

## modules/scopes/release {#modules-scopes-release}

```lua
release(scope: string): { Released }
```

End every resource registered under `scope`, across every subsystem.
Reaches contexts no seam does — the chunk of an `execute` call that
registered something and ended without releasing it.

**Parameters**

- `scope` `string` — A scope tag, as the `scope` field of a `list()` row carries it.

```lua
local ended = scopes.release("exec:__exec_12")
```

## modules/screenSpaceGI/README {#modules-screenspacegi-readme}

```lua
require("@builtin/systems/screenSpaceGI/screenSpaceGI") -- screenSpaceGI
```

Indirect diffuse light gathered from the scene that was just drawn, so anything on screen bounces light onto its neighbours — including geometry that moved this frame, which a baked lightmap cannot follow.

Usage: local screenSpaceGI = require("@builtin/systems/screenSpaceGI/screenSpaceGI")

## modules/screenSpaceGI/active {#modules-screenspacegi-active}

```lua
active(): boolean
```

Whether the screen-space GI pass is running this frame.

```lua
if screenSpaceGI.active() then ... end
```

## modules/screenSpaceGI/clear {#modules-screenspacegi-clear}

```lua
clear()
```

Turn screen-space GI off and release the pass. The other settings are
kept, so a later `set({ intensity = ... })` brings back the same look.

```lua
screenSpaceGI.clear()
```

## modules/screenSpaceGI/get {#modules-screenspacegi-get}

```lua
get(): SSGIState
```

The screen-space GI settings currently in force.

```lua
local r = screenSpaceGI.get().radius
```

## modules/screenSpaceGI/paramsBuffer {#modules-screenspacegi-paramsbuffer}

```lua
paramsBuffer(): any?
```

The buffer this system's passes read. The render feature binds what
this hands it, so the pass has the values this module packed.

```lua
local p = screenSpaceGI.paramsBuffer()
```

## modules/screenSpaceGI/set {#modules-screenspacegi-set}

```lua
set(opts: SSGIOpts?): SSGIState
```

Set the scene's screen-space GI. Any omitted field keeps its current
value. An `intensity` of 0 turns it off and releases the pass.

**Parameters**

- `opts` `SSGIOpts?` _(optional)_ — Screen-space GI settings — see `SSGIOpts`.

```lua
screenSpaceGI.set({ intensity = 1.0, radius = 2.0 })
```

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

```lua
require("@builtin/modules/api/engine/service") -- service (also available as global 'service')
```

Credit-metered service invoke. Public Luau surface over the `__service` Internal FFI namespace.

Usage: local service = require("@builtin/modules/api/engine/service")
Also available as global: service

## modules/service/authenticated {#modules-service-authenticated}

```lua
authenticated(): boolean
```

Whether a platform identity (JWT) is available to attach to
service calls. Returns only a boolean — never the token.

```lua
if not service.authenticated() then error("link ZeroMind") end
```

## modules/service/balance {#modules-service-balance}

```lua
balance(): string?
```

Read the caller's credit balance from ZeroMind. Returns a
promise handle for `task.await()` resolving the balance JSON, or nil
when the gateway is unconfigured or no caller identity is available.

```lua
local h = service.balance(); local raw = h and task.await(h)
```

## modules/service/configureGateway {#modules-service-configuregateway}

```lua
configureGateway(baseUrl: string): boolean
```

TRUSTED ONLY. Set the ZeroMind base URL that `service.invoke`
and `service.balance` target. The trusted-VM auth bootstrap calls
this with the resolved issuer.

**Parameters**

- `baseUrl` `string` — ZeroMind base URL (e.g. "https://origozero.ai").

```lua
service.configureGateway("https://origozero.ai")
```

## modules/service/configureWorld {#modules-service-configureworld}

```lua
configureWorld(guid: string): boolean
```

TRUSTED ONLY. Set the bound world guid attached to metered
service invocations, so the credit ledger attributes each charge to
the world it happened in. The trusted-VM world-load hook calls this
on every bind so a runtime world switch re-points attribution.

**Parameters**

- `guid` `string` — The bound world's guid.

```lua
service.configureWorld(world.guid())
```

## modules/service/gatewayConfigured {#modules-service-gatewayconfigured}

```lua
gatewayConfigured(): boolean
```

Whether the ZeroMind service gateway has been configured.
Service handlers use this to distinguish "gateway not configured"
from "not signed in" when `invoke` returns nil.

```lua
if not service.gatewayConfigured() then error("no gateway") end
```

## modules/service/invoke {#modules-service-invoke}

```lua
invoke(offering: string, endpoint: string, opts: InvokeOpts?): string?
```

Invoke a provider offering's logical endpoint through ZeroMind.
Returns a promise handle for `task.await()` resolving the
InvokeResponse JSON, or nil when the gateway is unconfigured or no
caller identity is available. The JWT and real upstream URL are
never exposed to Luau.

**Parameters**

- `offering` `string` — Fully-qualified offering identity `provider/name` (e.g. "origozero/mesh_gen").
- `endpoint` `string` — Logical endpoint name (e.g. "create_preview").
- `opts` `InvokeOpts?` _(optional)_ — `{ params?, headers?, body?, idempotency_key? }`.

```lua
local h = service.invoke("origozero/mesh_gen", "create_preview", { body = { prompt = p } })
```

## modules/service/jobStatus {#modules-service-jobstatus}

```lua
jobStatus(jobId: string): string?
```

Poll a submitted service job. Returns a promise handle for
`task.await()` resolving the JobStatusResponse JSON `{ job_id, status,
result?, error? }`: `status` walks `pending`/`running` -> `succeeded`
(with `result`, the same InvokeResponse `invoke` returns) or `failed`
(with `error`). nil when the gateway is unconfigured or no caller
identity is available.

**Parameters**

- `jobId` `string` — Job id returned by `submitJob`.

```lua
local h = service.jobStatus(jobId); local raw = h and task.await(h)
```

## modules/service/submitJob {#modules-service-submitjob}

```lua
submitJob(offering: string, endpoint: string, opts: InvokeOpts?): string?
```

Submit a durable async invocation of an offering endpoint. Same
arguments as `invoke`, but the provider round-trip runs server-side
(off this connection), so a slow synchronous provider or a dropped
link no longer loses the result. Returns a promise handle for
`task.await()` resolving `{ job_id, status }`; poll it with
`jobStatus`. nil when the gateway is unconfigured or no caller
identity is available.

**Parameters**

- `offering` `string` — Fully-qualified offering identity `provider/name` (e.g. "origozero/mesh_gen").
- `endpoint` `string` — Logical endpoint name (e.g. "create_preview").
- `opts` `InvokeOpts?` _(optional)_ — `{ params?, headers?, body?, idempotency_key? }`.

```lua
local h = service.submitJob("origozero/mesh_gen", "create_preview", { body = { prompt = p } })
```

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

```lua
require("@builtin/modules/api/engine/shader") -- shader (also available as global 'shader')
```

Shader compilation — turning authored WGSL into registered GPU programs, and the reusable modules those programs include. Public Luau surface over the `__shader` Internal FFI namespace.

Usage: local shader = require("@builtin/modules/api/engine/shader")
Also available as global: shader

## modules/shader/compile {#modules-shader-compile}

```lua
compile(keys: string | { string }, opts: { [string]: any }): boolean
```

Compile a zero-scaffolding SURFACE shader: the author wrote only
`vertex()` / `fragment()` and declared its material properties, and the
engine generates the group(1) material interface plus every render-mode
entry point. Compiles once and registers the result under every key.

**Parameters**

- `keys` `string | { string }` — One registration key, or the array of keys (guid, identity,
aliases) the one compiled program answers to.
- `opts` `{ [string]: any }` — `{ source, domain?, properties? }` — the author's WGSL, its
`@domain`, and the declared property schema.

```lua
shader.compile({ ref.guid, ref.identity }, { source = wgsl, properties = props })
```

## modules/shader/registerModule {#modules-shader-registermodule}

```lua
registerModule(keys: string | { string }, source: string): boolean
```

Register a block of WGSL other shaders include. Every key names the same
source, so a shader includes it by whichever name it holds — its guid, its
identity, or an alias. Registering again replaces it, and the shaders that
include it recompile.

**Parameters**

- `keys` `string | { string }` — One key, or the array of keys this module answers to.
- `source` `string` — The module's WGSL.

```lua
shader.registerModule({ ref.guid, ref.identity }, wgsl)
```

## modules/shader/status {#modules-shader-status}

```lua
status(name: string): (string, string?)
```

A shader's latest compile outcome, without reading the engine log:
`"compiled"`, `"failed"` (with the compiler error second), or `"pending"`.
Compilation is async, so a `"pending"` straight after a write means ask
again next frame.

**Parameters**

- `name` `string` — Shader identity or guid — the key it compiled under.

```lua
local status, err = shader.status(ref.guid)
```

## modules/shader_includes/README {#modules-shader-includes-readme}

```lua
require("@builtin/modules/shader_includes") -- shader_includes
```

Resolves the `#include` lines of a WGSL source against the asset system, so a shader includes a `.shaderModule` by every name form `require` and `asset.resolve` accept.

Usage: local shader_includes = require("@builtin/modules/shader_includes")

## modules/shader_includes/canonicalize {#modules-shader-includes-canonicalize}

```lua
canonicalize(source: string, base: string): string
```

Rewrite every `#include` in `source` whose literal names a
`.shaderModule` to that module's guid, resolved against `base`, and bring
every module the source reaches up to date with what the VFS serves. A
literal that resolves to no asset is left as it was written, so a framework
name reaches the expander unchanged.

**Parameters**

- `source` `string` — The WGSL as authored.
- `base` `string` — VFS path of the asset the source belongs to — what a `~` / `~.tail`
/ `.relative.tail` literal expands against.

```lua
local wgsl = ShaderIncludes.canonicalize(vfs.read(path .. "/shader.wgsl"), path)
```

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

```lua
require("@builtin/systems/sharpening/sharpening") -- sharpening
```

Contrast-adaptive sharpening. Restores local acuity to the finished frame, backing off wherever the neighbourhood has no headroom left, which is what keeps a bright fringe from forming along high-contrast edges.

Usage: local sharpening = require("@builtin/systems/sharpening/sharpening")

## modules/sharpening/active {#modules-sharpening-active}

```lua
active(): boolean
```

Whether the sharpening pass is running this frame.

```lua
if sharpening.active() then ... end
```

## modules/sharpening/disable {#modules-sharpening-disable}

```lua
disable()
```

Turn sharpening off and release the pass.

```lua
sharpening.disable()
```

## modules/sharpening/enable {#modules-sharpening-enable}

```lua
enable(sharpness: number?): State
```

Turn sharpening on at a given strength.

**Parameters**

- `sharpness` `number?` _(optional)_ — Strength in [0, 1]. Omit to keep the current value.

```lua
sharpening.enable(0.5)
```

## modules/sharpening/get {#modules-sharpening-get}

```lua
get(): State
```

The sharpening settings currently in force.

```lua
local s = sharpening.get().sharpness
```

## modules/sharpening/paramsBuffer {#modules-sharpening-paramsbuffer}

```lua
paramsBuffer(): any?
```

The buffer this system's passes read. The render feature binds what
this hands it, so the pass has the values this module packed.

```lua
local p = sharpening.paramsBuffer()
```

## modules/sharpening/set {#modules-sharpening-set}

```lua
set(opts: SharpenOpts?): State
```

Set the sharpening strength. Any omitted field keeps its current value.

**Parameters**

- `opts` `SharpenOpts?` _(optional)_ — Sharpening settings — see `SharpenOpts`.

```lua
sharpening.set({ sharpness = 0.6 })
```

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

```lua
require("@builtin/modules/api/engine/shell") -- shell (also available as global 'shell')
```

Engine emulated Unix shell — same shell that powers the MCP `bash` tool. Public Luau surface over the `__shell` Internal FFI namespace.

Usage: local shell = require("@builtin/modules/api/engine/shell")
Also available as global: shell

## modules/shell/run {#modules-shell-run}

```lua
run(command: string): ShellResult
```

Execute a command in the engine's emulated Unix shell and
return once it has completed. This is the same shell as the MCP
`bash` tool — 60+ builtins (ls, cat, grep, find, echo, ...)
operating on the virtual scene filesystem. A command that runs
Luau (`run`, `luau`, `zm`, `zero`) needs the engine's frame loop,
so from a coroutine it is queued to run off the frame loop and
this yields until it finishes; everything else runs inline. That
queueing runs the whole line, so a line that also ran a command
of its own comes back with the explanation in `stderr` and
`shell.runAsync` as the way to run it whole.

**Parameters**

- `command` `string` — Shell command to execute.

```lua
local r = shell.run("ls /zero/source")
```

## modules/shell/runAsync {#modules-shell-runasync}

```lua
runAsync(command: string): string
```

Asynchronous version of `shell.run`. Returns a promise ID that
resolves to a JSON-encoded result string. Use with
`task.await()`.

**Parameters**

- `command` `string` — Shell command to execute.

```lua
local json = task.await(shell.runAsync("find /zero -name '*.luau'"))
```

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

```lua
require("@builtin/modules/api/engine/skeleton") -- skeleton (also available as global 'skeleton')
```

The skeleton pose-data pipeline: sample a clip into a pose buffer, and bind/apply a pose buffer onto a Skeleton + Model entity. Public Luau surface over the `__skeleton` and `__clip` Internal FFI namespaces.

Usage: local skeleton = require("@builtin/modules/api/engine/skeleton")
Also available as global: skeleton

## modules/skeleton/applyPose {#modules-skeleton-applypose}

```lua
applyPose(sinkHandle: number, poseBuffer: Substrate.TypedBuffer): boolean
```

Snapshot the buffer's first `layout.total_floats` values and
queue a pending apply for the next ECS drain. Returns false on
unknown sink/buffer or buffer too small for the layout. The
Buffer is unchanged.

**Parameters**

- `sinkHandle` `number` — Sink handle from `bindPose`.
- `poseBuffer` `Substrate.TypedBuffer` — The pose buffer to apply.

## modules/skeleton/bindClip {#modules-skeleton-bindclip}

```lua
bindClip(zanimBytes: buffer | string, boneOrder: { string }): ClipBindInfo?
```

Decode a `zanim` payload and bind it to `boneOrder`,
precomputing which of the clip's channels feed each bone so
per-frame `sampleClip` is allocation-free. Returns
`{ handle, matched, total, duration }`, or nil on a malformed
payload / empty bone order. Check `matched`: 0 means the clip
drives none of these bones.

**Parameters**

- `zanimBytes` `buffer | string` — The clip's `data.zanim` payload bytes (binary-safe).
- `boneOrder` `{ string }` — Output bone names — one stride-10 record per bone.

## modules/skeleton/bindPose {#modules-skeleton-bindpose}

```lua
bindPose(entityId: (string | entityRef)?, opts: SkeletonLayout): number?
```

Register a pose sink targeting `entityId`. The opts table
carries the layout: `boneOrder` is the bone-name array
(`{"hip", "spine", ...}`), `stride` defaults to 10
(translation.xyz + rotation.xyzw + scale.xyz). Pass `entityId`
as nil to use the current component's owning entity.

**Parameters**

- `entityId` `(string | entityRef)?` _(optional)_ — Engine entity id or proxy, or nil for the current entity.
- `opts` `SkeletonLayout` — `{ boneOrder, stride }`.

```lua
local h = skeleton.bindPose(nil, { boneOrder = bones, stride = 10 })
```

## modules/skeleton/clipBones {#modules-skeleton-clipbones}

```lua
clipBones(zanimBytes: buffer | string): { string }?
```

Decode a `zanim` payload and return its bone-name array. Pure:
build a bind order or a retarget map from a clip without binding a
sampler. Returns nil on bytes that aren't a valid zanim payload.

**Parameters**

- `zanimBytes` `buffer | string` — The clip's `data.zanim` payload bytes (binary-safe).

```lua
local names = skeleton.clipBones(vfs.read(path .. "/data.zanim"))
```

## modules/skeleton/clipDecode {#modules-skeleton-clipdecode}

```lua
clipDecode(zanimBytes: buffer | string): string?
```

Decode a `zanim` payload to its readable JSON form
(`{ name, duration, channels, bone_names }`). The binary parse is
the engine's; `json.decode` the result to inspect or transform a
clip's channels (e.g. the retarget bake) in Luau. Returns nil on
bytes that aren't a valid zanim payload. Inverse of `clipEncode`.

**Parameters**

- `zanimBytes` `buffer | string` — The clip's `data.zanim` payload bytes (binary-safe).

```lua
local clip = json.decode(skeleton.clipDecode(bytes))
```

## modules/skeleton/clipEncode {#modules-skeleton-clipencode}

```lua
clipEncode(jsonString: string): string?
```

Encode a clip's JSON form (the shape `clipDecode` returns) back
to a `zanim` payload — the bytes a `.animation` stores and
`bindClip`/`sampleClip` consume. Inverse of `clipDecode`. Returns
nil on invalid JSON.

**Parameters**

- `jsonString` `string` — A clip JSON document.

```lua
local bytes = skeleton.clipEncode(json.encode(clip))
```

## modules/skeleton/jointTransforms {#modules-skeleton-jointtransforms}

```lua
jointTransforms(entityId: string | entityRef): table
```

Read a skinned entity's per-joint world transforms for the
current animated pose.

**Parameters**

- `entityId` `string | entityRef` — Engine entity id or proxy of a skinned entity.

```lua
local joints = skeleton.jointTransforms(meshId)
```

## modules/skeleton/sampleClip {#modules-skeleton-sampleclip}

```lua
sampleClip(handle: number, time: number, poseBuffer: Substrate.TypedBuffer): boolean
```

Sample the bound clip at `time` (clamped to `[0, duration]`)
and write one stride-10 pose record per bound bone into the
Buffer, starting at index 0. Bones the clip does not drive are
written as identity. Returns false on unknown handle/buffer or a
buffer too small for the bone count.

**Parameters**

- `handle` `number` — Sampler handle from `bindClip`.
- `time` `number` — Sample time in seconds.
- `poseBuffer` `Substrate.TypedBuffer` — The stride-10 pose buffer written into.

## modules/skeleton/unbindClip {#modules-skeleton-unbindclip}

```lua
unbindClip(handle: number): boolean
```

Drop the bound clip sampler from the registry.

**Parameters**

- `handle` `number` — Sampler handle to remove.

## modules/skeleton/unbindPose {#modules-skeleton-unbindpose}

```lua
unbindPose(sinkHandle: number): boolean
```

Remove the sink from the registry.

**Parameters**

- `sinkHandle` `number` — Sink handle to remove.

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

```lua
require("@builtin/modules/api/engine/sky") -- sky (also available as global 'sky')
```

Sky configuration — type, time of day, day/night cycle, procedural parameters, presets, explicit sun direction. Public Luau surface over the `__sky` Internal FFI namespace.

Usage: local sky = require("@builtin/modules/api/engine/sky")
Also available as global: sky

## modules/sky/get {#modules-sky-get}

```lua
get(): { [string]: any }
```

Get all current sky configuration as a table. Returns the
same fields as `sky.set` accepts, plus read-only fields like
`material_name` and `type`. Color values are returned as
positional arrays `[r, g, b]`.

```lua
local cfg = sky.get(); print(cfg.time_of_day)
```

## modules/sky/getTimeOfDay {#modules-sky-gettimeofday}

```lua
getTimeOfDay(): number
```

Get the current time of day in hours (0-24).

```lua
local t = sky.getTimeOfDay()
```

## modules/sky/installFallback {#modules-sky-installfallback}

```lua
installFallback()
```

Register the engine fallback sky material and install it as the
engine-level fallback (rendered when a scene has no sky entity).
Idempotent; requires a live renderer — the scene loader calls it.

```lua
sky.installFallback()
```

## modules/sky/preset {#modules-sky-preset}

```lua
preset(name: string)
```

Apply a named sky preset. Available: `clear_day`, `sunset`,
`sunrise`, `overcast`, `night`, `studio`, `none`. Raises a Luau
error for unrecognized names — wrap in `pcall` if uncertain.

**Parameters**

- `name` `string` — Preset name (case-sensitive).

```lua
sky.preset("sunset")
```

## modules/sky/set {#modules-sky-set}

```lua
set(opts: SkyOpts)
```

Configure the sky system. All fields are optional — only
provided fields are updated. Color fields accept both named
`{x=r, y=g, z=b}` and positional `{r, g, b}` forms. `color` is
an alias for `solid_color`.

**Parameters**

- `opts` `SkyOpts` — Sky configuration properties.

```lua
sky.set({ type = "procedural", time_of_day = 14, sync_sun_to_light = true })
```

## modules/sky/setSunDirection {#modules-sky-setsundirection}

```lua
setSunDirection(dir: SkyColor)
```

Set an explicit sun direction and disable time-based sun
positioning. The directional light is updated to match.

**Parameters**

- `dir` `SkyColor` — Normalized sun direction vector.

```lua
sky.setSunDirection({ 0.5, -1, 0.3 })
```

## modules/sky/setTimeOfDay {#modules-sky-settimeofday}

```lua
setTimeOfDay(time: number)
```

Set the time of day (0-24 hours). 0 = midnight, 6 = sunrise,
12 = noon, 18 = sunset.

**Parameters**

- `time` `number` — Time of day in hours.

```lua
sky.setTimeOfDay(18.5)
```

## modules/spatialStreaming/README {#modules-spatialstreaming-readme}

```lua
spatialStreaming
```

## modules/spatialStreaming/add {#modules-spatialstreaming-add}

```lua
add(records: { Record }, opts: { [string]: any }?): string
```

Register a group of records for content that is not spawned. This is
the path that lets a world hold more than it can spawn at once: with
`store = "vfs"` the records are written to a file under the configured
directory and only the cell's manifest stays in memory until a source
arrives.

**Parameters**

- `records` `{ Record }` — Array of records, root first. A record's `parent` indexes another
record of the same array.
- `opts` `{ [string]: any }?` _(optional)_ — `{ layer = "default", store = "memory" | "vfs" }`.

```lua
spatialStreaming.add({ { name = "rock", position = { x = 300, y = 0, z = 0 }, components = { Model = { model = "@builtin::meshes.cube" } } } }, { store = "vfs" })
```

## modules/spatialStreaming/addSource {#modules-spatialstreaming-addsource}

```lua
addSource(target: any, opts: { [string]: any }?): number
```

Add a streaming source. A cell is resident while ANY source wants it
resident and released only once every source wants it released, so several
sources — a player and a spectator camera, two split-screen players — each
keep the region they stand near.

A source carries its own radii, which is what lets a distant spectator
stream a thin shell while the player streams a deep one. Radii left out
follow the layer's, and the layer's follow the configuration.

**Parameters**

- `target` `any` _(optional)_ — An entity id, an entity proxy, an entity name, or a fixed world
position `{ x, y, z }`.
- `opts` `{ [string]: any }?` _(optional)_ — `{ loadRadius, unloadRadius, proxyRadius, proxyUnloadRadius }` —
this source's own radii, for the content and for the far field it sees
proxies in. A source that names an unload radius of its own sees a far
field measured from it unless it names that too.

```lua
spatialStreaming.addSource(entity.find("Player"), { loadRadius = 90, unloadRadius = 140 })
```

## modules/spatialStreaming/capture {#modules-spatialstreaming-capture}

```lua
capture(targets: any, opts: { [string]: any }?): { [string]: any }
```

Hand live entities to the streaming store. Each target is the ROOT of a
group: it and its descendants are serialized together and placed in the
cell the root stands in. The entities are left standing — residency passes
to the streaming rule, which releases them on the first tick that puts them
past the unload radius.

A target that is replicated to other peers is refused: residency is a local
decision, and despawning a replicated entity on one client would reach the
others. A target that already has a parent is refused too — its root is the
group, and capturing a branch of one would leave the rest behind.
A target the store already holds is refused as well, and counted: a second
group over the same live entities would despawn them on the first release
and leave the second group naming content that is gone.

**Parameters**

- `targets` `any` _(optional)_ — Array of entity ids, proxies, or names, or a single name glob.
- `opts` `{ [string]: any }?` _(optional)_ — `{ layer = "default", store = "memory" | "vfs" }`.

```lua
spatialStreaming.capture(entity.findAll("rock_*"), { layer = "props" })
```

## modules/spatialStreaming/cellBounds {#modules-spatialstreaming-cellbounds}

```lua
cellBounds(key: string, cellSize: number): { minX: number, minZ: number, maxX: number, maxZ: number }
```

Ground footprint of a cell.

**Parameters**

- `key` `string` — Cell key.
- `cellSize` `number` — Edge length of a cell in world units.

```lua
local b = spatialStreaming.cellBounds("2:-1", 64)
```

## modules/spatialStreaming/cellCoords {#modules-spatialstreaming-cellcoords}

```lua
cellCoords(key: string): (number, number)
```

Grid coordinates a cell key names.

**Parameters**

- `key` `string` — Cell key from `cellKeyAt`.

```lua
local cx, cz = spatialStreaming.cellCoords("2:-1")
```

## modules/spatialStreaming/cellDistance {#modules-spatialstreaming-celldistance}

```lua
cellDistance(key: string, cellSize: number, x: number, z: number): number
```

Distance from a point to the nearest edge of a cell's footprint, zero
when the point stands inside it. Measuring to the centre instead would put
a cell's near corner inside the load radius while the cell itself reads as
far, so a source walking along a boundary would see the ground it is on
released.

**Parameters**

- `key` `string` — Cell key.
- `cellSize` `number` — Edge length of a cell in world units.
- `x` `number` — World-space X of the point.
- `z` `number` — World-space Z of the point.

```lua
local d = spatialStreaming.cellDistance("2:-1", 64, 10, 10)
```

## modules/spatialStreaming/cellKeyAt {#modules-spatialstreaming-cellkeyat}

```lua
cellKeyAt(x: number, z: number, cellSize: number): string
```

Key of the cell a world-space point stands in. Cells are square columns
on the ground plane: height never enters, because a world's content is
spread over its ground rather than through its air, and a column keeps a
tower and its foundation in one cell.

**Parameters**

- `x` `number` — World-space X.
- `z` `number` — World-space Z.
- `cellSize` `number` — Edge length of a cell in world units.

```lua
local key = spatialStreaming.cellKeyAt(130, -40, 64)
```

## modules/spatialStreaming/cells {#modules-spatialstreaming-cells}

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

Per-cell view of the store, for inspection and for tests.

```lua
local c = spatialStreaming.cells()
```

## modules/spatialStreaming/clearProxy {#modules-spatialstreaming-clearproxy}

```lua
clearProxy(target: any, opts: { [string]: any }?): boolean
```

Take a cell's proxy away, despawning it if it is standing.

**Parameters**

- `target` `any` _(optional)_ — A cell key or a `{ x, y, z }` world position.
- `opts` `{ [string]: any }?` _(optional)_ — `{ layer = "default" }`.

```lua
spatialStreaming.clearProxy("4:0")
```

## modules/spatialStreaming/clearSources {#modules-spatialstreaming-clearsources}

```lua
clearSources()
```

Drop every streaming source. Cells hold whatever residency they have —
nothing loads or releases while no source stands anywhere.

```lua
spatialStreaming.clearSources()
```

## modules/spatialStreaming/config {#modules-spatialstreaming-config}

```lua
config(): { [string]: any }
```

The configuration now in force. The far field is reported as the
distances it is measured at, whether they were given or follow the content
radii.

```lua
local c = spatialStreaming.config()
```

## modules/spatialStreaming/configure {#modules-spatialstreaming-configure}

```lua
configure(opts: { [string]: any }?): { [string]: any }
```

Set the grid and the radii every layer inherits. Keys left out keep
their current value.

A new `cellSize` re-buckets everything the store already holds, by each
group's own root position. A cell key means nothing without the size it was
measured with, so content filed under the old grid would otherwise be
measured against footprints it never stood in.

**Parameters**

- `opts` `{ [string]: any }?` _(optional)_ — `{ cellSize, loadRadius, unloadRadius, proxyRadius,
proxyUnloadRadius, budget, dir }`. `budget` is how many entity records one
tick may spend on loading and releasing; the proxy pair is the far field a
released cell's stand-in covers, and follows `unloadRadius` unless it is
given — passing 0 for either hands it back to that; `dir` is the VFS
directory a file-backed cell writes under.

```lua
spatialStreaming.configure({ cellSize = 50, loadRadius = 100, unloadRadius = 160 })
```

## modules/spatialStreaming/decide {#modules-spatialstreaming-decide}

```lua
decide(distance: number, loadRadius: number, unloadRadius: number): string
```

Residency a cell whose nearest edge is `distance` from the closest
source should be in. Inside `loadRadius` it is wanted resident, past
`unloadRadius` it is wanted released, and between the two it keeps whatever
it already is — the band is what stops a source resting on a boundary from
loading and releasing the same cell every frame.

**Parameters**

- `distance` `number` — Distance from the nearest source to the cell's nearest edge.
- `loadRadius` `number` — Distance within which a cell is wanted resident.
- `unloadRadius` `number` — Distance past which a cell is wanted released.

```lua
local want = spatialStreaming.decide(140, 128, 192)
```

## modules/spatialStreaming/deriveProxies {#modules-spatialstreaming-deriveproxies}

```lua
deriveProxies(opts: { [string]: any }?): { [string]: any }
```

Build bounding-silhouette proxies from the content the store already
holds — one box over a whole cell, or one over each group in it. This is
the automatic path; `setProxy` is the one that takes an authored mesh or
impostor.

Each record is measured as a box of its own `scale`, placed through the
whole of its parent's transform, so a group standing rotated and scaled is
enclosed where it actually stands. A record whose mesh is larger than one
unit at scale 1 is measured as the unit box it is scaled from — `padding`
is what covers the difference, and `setProxy` is what takes an authored
silhouette instead.

A file-backed cell's records are read to measure them and dropped again, so
deriving over a world that is held in files costs one read per cell and
leaves the store as it found it.

**Parameters**

- `opts` `{ [string]: any }?` _(optional)_ — `{ layer, mesh = "@builtin::meshes.cube", material, granularity =
"cell" | "group", padding = 0, replace = false }`. `layer` limits the walk
to one layer; `replace` overwrites a proxy a cell already has.

```lua
spatialStreaming.deriveProxies({ granularity = "group", material = "@builtin::materials.default" })
```

## modules/spatialStreaming/flush {#modules-spatialstreaming-flush}

```lua
flush(): number
```

Write every file-backed cell that has no group standing out to its file
and drop its records. A cell already written is left alone. This is what
bounds memory while a world's content is being registered; `tick` calls it
each step, so a world that streams needs it only to measure the store
between an `add` batch and the first step.

```lua
spatialStreaming.flush()
```

## modules/spatialStreaming/layers {#modules-spatialstreaming-layers}

```lua
layers(): { [string]: any }
```

Settings of every configured layer, keyed by name.

```lua
local l = spatialStreaming.layers()
```

## modules/spatialStreaming/proxies {#modules-spatialstreaming-proxies}

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

Per-cell view of the proxies the store holds. `records` is what the
stand-in is made of; `entities` is how much of it is standing right now,
which is zero while the cell's content covers it.

```lua
local p = spatialStreaming.proxies()
```

## modules/spatialStreaming/proxyDecide {#modules-spatialstreaming-proxydecide}

```lua
proxyDecide(distance: number, proxyRadius: number, proxyUnloadRadius: number): string
```

Residency a cell's PROXY should be in, for a cell whose content is not
standing. Same shape as `decide` and for the same reason: the band between
the two radii is what keeps a source resting at the far edge from spawning
and despawning the same stand-in every frame.

The rule reads a distance and the far-field radii alone. Whether the cell's
own content is standing is the tick's question, and the tick lets the
content's answer win: a proxy stands where the content does not.

**Parameters**

- `distance` `number` — Distance from the nearest source to the cell's nearest edge.
- `proxyRadius` `number` — Distance within which a released cell's proxy stands.
- `proxyUnloadRadius` `number` — Distance past which the proxy is dropped too.

```lua
local want = spatialStreaming.proxyDecide(560, 512, 640)
```

## modules/spatialStreaming/proxyIds {#modules-spatialstreaming-proxyids}

```lua
proxyIds(): { string }
```

Entity ids the proxies currently have standing, across every cell.

```lua
local ids = spatialStreaming.proxyIds()
```

## modules/spatialStreaming/removeSource {#modules-spatialstreaming-removesource}

```lua
removeSource(target: any): boolean
```

Remove a streaming source by the entity it follows.

**Parameters**

- `target` `any` _(optional)_ — Entity id, proxy, or name the source was added with.

```lua
spatialStreaming.removeSource(entity.find("Player"))
```

## modules/spatialStreaming/reset {#modules-spatialstreaming-reset}

```lua
reset()
```

Release every resident group, forget the store, and drop every source.
Live entities the store owns are despawned; nothing else in the scene is
touched.

```lua
spatialStreaming.reset()
```

## modules/spatialStreaming/residentIds {#modules-spatialstreaming-residentids}

```lua
residentIds(): { string }
```

Entity ids the store currently has standing, across every cell.

```lua
local ids = spatialStreaming.residentIds()
```

## modules/spatialStreaming/setLayer {#modules-spatialstreaming-setlayer}

```lua
setLayer(name: string, opts: { [string]: any }?): { [string]: any }
```

Configure a content layer. A layer streams on its own radii and can be
switched off entirely, so decorative content can be released long before
the content a player interacts with. Each layer keeps its own grid, so two
layers standing in the same square still stream apart.

**Parameters**

- `name` `string` — Layer name. Content lands in "default" unless `capture` / `add` say
otherwise.
- `opts` `{ [string]: any }?` _(optional)_ — `{ enabled, loadRadius, unloadRadius, proxyRadius,
proxyUnloadRadius }`. A nil radius follows the global configuration, and a
layer that names an unload radius of its own gets a far field measured from
it. A disabled layer holds nothing standing — neither its content nor its
proxies.

```lua
spatialStreaming.setLayer("props", { loadRadius = 60, unloadRadius = 90 })
```

## modules/spatialStreaming/setProxy {#modules-spatialstreaming-setproxy}

```lua
setProxy(target: any, records: { Record }, opts: { [string]: any }?): string
```

Give a cell the stand-in it is drawn as while its content is released.
The proxy is a group of records like any other, so what it represents is
the caller's: a merged low-detail mesh, a billboard impostor, a bounding
silhouette. It stands whenever the cell's content does not and the cell is
inside the proxy radius, and it is exchanged for the content in an order
that leaves no frame with neither standing.

A cell that has no content yet takes a proxy too, which is what lets a
skyline be registered before — or instead of — the content it stands for.

**Parameters**

- `target` `any` _(optional)_ — A cell key from `cellKeyAt` / `cells()`, or a `{ x, y, z }` world
position the cell is looked up from.
- `records` `{ Record }` — Array of records, the same shape `add` takes. Positions are
world-space for a record with no parent.
- `opts` `{ [string]: any }?` _(optional)_ — `{ layer = "default" }`.

```lua
spatialStreaming.setProxy("4:0", { { name = "skyline", position = { x = 288, y = 8, z = 32 }, scale = { x = 64, y = 16, z = 64 }, components = { Model = { model = "@builtin::meshes.cube" } } } })
```

## modules/spatialStreaming/sourcePositions {#modules-spatialstreaming-sourcepositions}

```lua
sourcePositions(): { Vec3 }
```

World positions of the live sources. An entity source that has been
despawned is dropped here rather than reporting a stale position.

```lua
local p = spatialStreaming.sourcePositions()
```

## modules/spatialStreaming/stats {#modules-spatialstreaming-stats}

```lua
stats(): { [string]: any }
```

What the store holds and how much of it is standing. `bytesResident` is
the encoded size of the groups that are live; `bytesStored` is the encoded
size of everything the store knows about, resident or not. The gap between
the two is what streaming bought.

The proxy figures stand apart from the content's: `entitiesProxy` and
`bytesProxy` are what the far field costs right now, against the
`entitiesTotal` / `bytesStored` it stands in for.

```lua
local s = spatialStreaming.stats()
```

## modules/spatialStreaming/tick {#modules-spatialstreaming-tick}

```lua
tick(_dt: number?): { [string]: any }
```

Advance streaming by one step. Loads and releases at most `budget`
entity records, so crossing a cell boundary spreads its cost over frames
instead of spending it all in one. A group is atomic: a group larger than
the whole budget still moves in one piece, so the budget is the floor a
step stops at rather than a ceiling it never passes.

Releases are spent before loads, which keeps the peak residency at what the
radius bought rather than at the sum of the cells on both sides of a
boundary.

A cell that has a proxy raises it before the first of its groups is
released and drops it once the cell's own content has landed, so the
exchange between the two representations leaves neither a gap nor a
silhouette standing over the content it covered for.

One step belongs to the frame, not to the caller: a second call inside the
same engine frame reports `stepped = false` and changes nothing, so a world
carrying several `StreamingSource` components spends one budget rather than
one per source. Waiting a frame is what advances it again.

**Parameters**

- `_dt` `number?` _(optional)_ — Frame delta, accepted so a component can pass its own and ignored —
the step is driven by distance, not by time.

```lua
spatialStreaming.tick(dt)
```

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

```lua
require("@builtin/systems/reflections/ssr") -- ssr
```

Screen-space reflections — polished floors reflect what is standing on them, and wet ground reflects what is above it, from the frame the engine has already drawn.

Usage: local ssr = require("@builtin/systems/reflections/ssr")

## modules/ssr/active {#modules-ssr-active}

```lua
active(): boolean
```

Whether the reflection passes are currently running.

```lua
if ssr.active() then print("reflecting") end
```

## modules/ssr/clear {#modules-ssr-clear}

```lua
clear()
```

Turn reflections off and release the passes. The other settings are
kept, so a later `set({ intensity = ... })` brings back the same look.

```lua
ssr.clear()
```

## modules/ssr/get {#modules-ssr-get}

```lua
get(): SsrState
```

The reflection settings currently in force.

```lua
local d = ssr.get().maxDistance
```

## modules/ssr/paramsBuffer {#modules-ssr-paramsbuffer}

```lua
paramsBuffer(): any?
```

The buffer this system's passes read. The render feature binds what
this hands it, so the pass has the values this module packed.

```lua
local p = ssr.paramsBuffer()
```

## modules/ssr/set {#modules-ssr-set}

```lua
set(opts: SsrOpts?): SsrState
```

Set the scene's screen-space reflections. Any omitted field keeps its
current value, so a call can adjust one knob without restating the rest.
An `intensity` of 0 turns reflections off and releases the passes.

**Parameters**

- `opts` `SsrOpts?` _(optional)_ — Reflection settings — see `SsrOpts`.

```lua
ssr.set({ intensity = 1, maxDistance = 40, quality = "high" })
```

## modules/state {#modules-state}

```lua
modules.state(path?) -> table
```

The calling module's durable state table — the same table on every call for the life of the VM, kept across an in-place hot reload of that module and across the re-run a reloaded dependency triggers in it. A module-level `local` is an upvalue of the chunk that declared it, so it starts again from its initial value each time that chunk runs; a field on this table is held by the engine and does not. Put here what a reload has to survive: a built flag, the entities and particle systems a build owns, an unsubscribe list, a generation counter. Pass a module require path to read another module's table.

**Parameters**

- `path` `string` _(optional)_ — Module require path. Omit inside a module to get that module's own table.

**Returns** `table` — The module's durable state table

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

```lua
require("@builtin/modules/api/engine/stream") -- stream (also available as global 'stream')
```

Named byte streams by URL scheme — TCP, tty, Bluetooth Low Energy and loopback transports, dialled out or listened for, with a common read/write/status/close surface over every one of them. Public Luau surface over the `__stream` Internal FFI namespace.

Usage: local stream = require("@builtin/modules/api/engine/stream")
Also available as global: stream

## modules/stream/accept {#modules-stream-accept}

```lua
accept(listener: string): string?
```

Take the connection that has waited longest on the listener, as a
stream handle that reads, writes, and closes exactly like one
`stream.open` returned. Returns nil when nothing is waiting, so call
it in a loop each tick to take every peer that arrived.
`stream.listenerStatus(listener).pending` is how many are still
waiting.

**Parameters**

- `listener` `string` — Listener handle from stream.listen.

```lua
while true do local h = stream.accept(listener); if not h then break end; table.insert(peers, h) end
```

## modules/stream/close {#modules-stream-close}

```lua
close(handle: string): boolean
```

Finish whatever `handle` names — a stream or a listener — and
drop it from the registry.

Closing a stream refuses every later write and carries the bytes
already queued to the peer before the connection ends, so a write and
a close in the same tick deliver — the shape a request answered with
one response has. A peer that has stopped reading altogether holds
that finish for thirty seconds; past that the connection ends and
what is still queued ends with it, so a caller that must know its
bytes went out watches `stream.status(handle).pending` reach zero
before it closes.

Closing a listener stops it answering new peers and closes the
connections nobody took; the connections `stream.accept` already
handed over keep running until they are closed themselves.

**Parameters**

- `handle` `string` — Stream handle from stream.open or stream.accept, or listener handle from stream.listen.

```lua
stream.write(peer, response); stream.close(peer)
```

## modules/stream/listen {#modules-stream-listen}

```lua
listen(url: string, opts: StreamListenOpts?): string
```

Hold the address `url` names and answer the peers that dial it —
the other direction from `stream.open`, for when the thing you are
talking to starts the conversation and restarts on its own schedule.
Returns a promise handle: `task.await()` it to get the listener
handle once the address is held, or it raises the reason a malformed
url, a scheme that cannot listen, or a failed bind was refused with.
Take the connections with `stream.accept`.

**The host in the url is the interface bound, and the whole of what
decides who can reach it.** `tcp://127.0.0.1:9000` answers only
programs on this same machine. `tcp://0.0.0.0:9000` answers any host
that can route to this machine on that port — every device on the
wifi, and anything beyond it the network lets through. Write the one
you mean; there is no default, and `stream.listenerStatus` reports
which of the two you got. A port of `0` asks the operating system to
choose one, which that same status then reports.

`opts.inboundCapacity` and `opts.outboundCapacity` bound each
answered connection (65536 bytes each by default);
`opts.backlog` bounds the connections held for `stream.accept`
before the listener stops taking them from the operating system,
which leaves the rest queued in the kernel rather than answered and
forgotten (16 by default, and at least 1).

The listener belongs to the chunk that opened it — the chunk whose
own code called `stream.listen`, which is the module holding that
line even when something else called into it. When that chunk runs
again — a module hot-reload, a cleared require cache — the listener
and the connections it answered are closed, and the new run binds the
address for itself. Peers see the connection close and dial again.
`stream.listeners()` names that chunk as each entry's `owner`.

**Parameters**

- `url` `string` — Listen URL — scheme://host:port.
- `opts` `StreamListenOpts?` _(optional)_ — Per-connection capacities and the accept backlog (optional).

```lua
local pending = stream.listen("tcp://127.0.0.1:9000"); local listener = task.await(pending)
```

## modules/stream/listenerStatus {#modules-stream-listenerstatus}

```lua
listenerStatus(listener: string): ListenerStatus?
```

Report what the listener holds and has handed over. `address` is
the address the operating system resolved the bind to, port
included — the one to hand a peer. `reach` says who can connect to
it: `"thisMachine"` when it is a loopback address and only programs
on this machine can, `"network"` when any host that can route here
can. `accepted` counts the connections `stream.accept` handed over,
`pending` the ones still waiting, and `capacity` the value `pending`
may reach before the listener stops taking connections from the
operating system. nil when handle names no open listener.

**Parameters**

- `listener` `string` — Listener handle from stream.listen.

```lua
local s = stream.listenerStatus(listener); print(s.address, s.reach, s.pending)
```

## modules/stream/listeners {#modules-stream-listeners}

```lua
listeners(): { OpenListener }
```

Every listener this engine currently holds an address for, in the
order they were opened. Each entry is what `stream.listenerStatus`
reports about it, plus the `handle` it is addressed by and the `owner`
chunk its life follows.

This is how an address is reached again once nothing holds its handle:
filter on `address` for the port you want and close the entry by its
`handle`, rather than guessing at handles.

```lua
for _, l in stream.listeners() do if l.address == want then stream.close(l.handle) end end
```

## modules/stream/open {#modules-stream-open}

```lua
open(url: string, opts: StreamOpenOpts?): string
```

Open a byte stream at url (`scheme://target[?k=v]`). `loopback`
carries written bytes back out of the same stream and works on
every platform; `tcp` dials `host:port`; `tty` opens a serial
device node — `/dev/ttyACM0` or `/dev/ttyUSB0` for a USB CDC board
such as an ESP32, `/dev/rfcomm0` for a Bluetooth controller paired
over classic SPP (both present as a tty on Linux, so one transport
serves either peer), `COM5` on Windows. `tty` query parameters:
`baud` (default 115200), `dataBits` (5-8, default 8), `parity`
(`none` | `odd` | `even`, default `none`), `stopBits` (1 or 2,
default 1).

`ble` connects to a Bluetooth Low Energy device over GATT, on a
desktop engine and in a browser alike — the wireless transport a
web world reaches a device through:
`ble://<device>?service=<uuid>&write=<uuid>&notify=<uuid>`. The
device is the name it advertises, `*` any device offering the
service, a trailing `*` a name prefix (`Paw*`). `write` is the
characteristic this engine writes to and `notify` the one it
subscribes to, which on a Nordic UART peripheral are that
peripheral's RX and TX; a module with one bidirectional
characteristic names it for both. UUIDs may be 16-bit (`ffe0`),
32-bit, or full. Optional: `chunk` (bytes per packet, 1-512 —
otherwise what the connection carries), `writeMode`
(`withResponse` | `withoutResponse`, default `withResponse`),
`timeout` (seconds to find and connect to the device, default
15).

`opts` bounds the stream's undrained inbound buffer
and in-flight outbound bytes (default 65536 each). Returns a
promise handle: `task.await()` it
to get the stream handle once the transport is open, or it raises
the reason a malformed url, an unknown or unsupported scheme, or a
failed connect was refused with. A `ble` stream resolves as soon as
it exists and reports the rest as state — watch
`stream.status(handle).state` go `opening`, `permissionPending`
while the browser asks the person at the machine to pick a device,
then `open`; writes made meanwhile are queued and go out when it
connects. Check `stream.transports()` first
to tell a mistyped scheme from one this build does not carry.

**Parameters**

- `url` `string` — Stream URL — scheme://target[?k=v&k=v].
- `opts` `StreamOpenOpts?` _(optional)_ — Buffer capacities (optional).

```lua
local pending = stream.open("loopback://echo"); local handle = task.await(pending)
local paw = task.await(stream.open("ble://Paw*?service=ffe0&write=ffe1&notify=ffe1"))
```

## modules/stream/read {#modules-stream-read}

```lua
read(handle: string, max: number?): string
```

Drain up to max buffered inbound bytes from the stream.

**Parameters**

- `handle` `string` — Stream handle from stream.open.
- `max` `number?` _(optional)_ — Maximum bytes to drain (optional). Omit to drain everything buffered.

```lua
local chunk = stream.read(handle)
```

## modules/stream/serialPorts {#modules-stream-serialports}

```lua
serialPorts(): SerialPorts
```

Every serial device this machine has, for picking the one to open.
`ports` is an array ordered by path. Each entry carries the `path` the
device is at (`/dev/ttyACM0` on Linux, `COM3` on Windows), the `url`
that opens it, the `kind` of bus it attaches by, and — for a USB
device — the `vendorId`, `productId`, `serialNumber`, `manufacturer`
and `product` it advertises.

A device's path moves with enumeration order: a board that came up at
`/dev/ttyACM0` is at `/dev/ttyACM1` once something else is plugged in
first, and moves across `COM3`-`COM5` on Windows. What the device
advertises holds still across those moves, so match on
`vendorId`/`productId` — or on `serialNumber` to tell two of the same
board apart — and open the `url` that entry carries, appending the
port settings `stream.open` documents.

Three answers are distinct. `supported` false with a `reason` means
this platform has no serial bus to enumerate at all. `error` set means
it has one and the operating system refused this enumeration, so a
later call may answer. An empty `ports` with neither means the machine
has no serial device attached, which is an ordinary result.

```lua
for _, p in stream.serialPorts().ports do if p.vendorId == 0x303A then print(p.url, p.product) end end
```

## modules/stream/status {#modules-stream-status}

```lua
status(handle: string): StreamStatus?
```

Report what the stream has carried and lost. `state` is where
the stream is in its life: `opening`, `permissionPending` while the
platform asks the person at the machine to allow the connection,
`open`, `denied` when that permission was refused, and `closed`
when it is finished. `pending` is bytes
accepted and not yet handed to the peer; `capacity` is the value
`pending` may reach before a write is refused. `error` holds the
most recent transport failure and the refusal a `denied` stream
carries, retained for the life of the
stream. nil when handle names no open stream.

**Parameters**

- `handle` `string`

```lua
local s = stream.status(handle); print(s.pending, s.capacity)
```

## modules/stream/streams {#modules-stream-streams}

```lua
streams(): { OpenStream }
```

Every open stream, dialled or answered, in the order they were
opened. Each entry is what `stream.status` reports about it, plus the
`handle` it is addressed by and the `owner` chunk its life follows —
a connection `stream.accept` handed over carries the owner of the
listener that answered it.

```lua
for _, s in stream.streams() do print(s.handle, s.transport, s.pending, s.owner) end
```

## modules/stream/transports {#modules-stream-transports}

```lua
transports(): { [string]: TransportSupport }
```

Every stream scheme this build knows about — a capability
probe, in both directions. `supported` answers `stream.open` and
`listen` answers `stream.listen`, since a scheme can carry one and
not the other. Each reason is nil when its direction works,
otherwise it names why not: an unbuilt transport names its own
absence, a transport this platform lacks (`tcp` and `tty` on wasm;
`ble` in a browser without Web Bluetooth or with the radio off,
which the page itself answers) names that, and a loopback stream,
whose peer is itself, names that nothing dials it. A typo'd scheme
is absent from this table entirely, which is what tells it apart
from a real transport this build lacks.

```lua
local t = stream.transports(); if not t.tcp.listen then warn(t.tcp.listenReason) end
```

## modules/stream/write {#modules-stream-write}

```lua
write(handle: string, bytes: string): WriteOutcome
```

Queue bytes for the stream's peer. Never blocks. `"accepted"`
means the bytes were queued. `"full"` means the outbound queue has
no room right now — backpressure, not failure: the peer is alive
and draining slower than this call is producing, so a retry after
it catches up can succeed. Compare `pending` against `capacity` on
`stream.status()` to see it coming before a write is refused.
`"closed"` means the stream is finished, or handle names no open
stream — reopen to continue, retrying never succeeds. `"tooLarge"`
means bytes is bigger than the stream's whole outbound capacity, so
it can never fit at any queue depth — retrying the same write
returns this again.

**Parameters**

- `handle` `string` — Stream handle from stream.open.
- `bytes` `string` — Bytes to queue, byte-safe.

```lua
local outcome = stream.write(handle, data)
```

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

```lua
require("@builtin/modules/api/engine/streaming") -- streaming (also available as global 'streaming')
```

What the engine has resident of a world's detail right now, and why a piece of it is not on screen. Covers the four systems that decide how much of a world stands at any moment: terrain's LOD cut, a voxel world's chunk meshes, spatial streaming's cell store, and mesh LOD's level selection. Reading a `Terrain`, `VoxelWorld`, `StreamingSource` or `MeshLod` component's fields back tells you what was asked for. `streaming.observe()` answers the other question: what is standing, what it costs, and for a chunk that is not drawn, which of a closed set of reasons it is not drawn for. The same reading is served at `/zero/runtime/observations/streaming`. It is built by the call and published as its last act, so both transports carry the document one pass produced.

Usage: local streaming = require("@builtin/modules/api/engine/streaming")
Also available as global: streaming

## modules/streaming/cells {#modules-streaming-cells}

```lua
cells(): { [string]: any }
```

What the spatial-streaming store has resident: the configured radii and
budget, the counters the store keeps, and one row per cell with how many of
its groups are standing, what it costs, and whether a release wrote it to a
file it now reads back from.

```lua
local s = streaming.cells()
```

## modules/streaming/levels {#modules-streaming-levels}

```lua
levels(scene: any?): { [string]: any }
```

Which level every mesh-LOD receiver is drawing at, and the screen
fraction that selection was measured from.
A receiver whose entity the scene no longer holds is reported as
`standing = false`: the chain is registered and there is nothing left for
it to draw.

**Parameters**

- `scene` `any?` _(optional)_ — The scene walk to read against. Omitted, the call takes its own.

```lua
local l = streaming.levels()
```

## modules/streaming/observe {#modules-streaming-observe}

```lua
observe(): { [string]: any }
```

The whole reading in one document: terrain, voxel, streaming cells and
mesh LOD, plus the totals those rows sum to.

Built by this call and published as its last act, so
`/zero/runtime/observations/streaming` serves the same document rather
than a second derivation of it.

```lua
local r = streaming.observe()
```

## modules/streaming/reasons {#modules-streaming-reasons}

```lua
reasons(): { string }
```

Every reason `whyNotDrawn` can answer with, so a caller can enumerate
the set rather than meeting it one failure at a time.

```lua
local r = streaming.reasons()
```

## modules/streaming/terrain {#modules-streaming-terrain}

```lua
terrain(scene: any?): { [string]: any }
```

What each terrain entity is drawing: whether a heightfield is bound to
it, the LOD cut it settled on, what that cut costs in indices and in the
vertex pool, and the eye the cut was refined under.

**Parameters**

- `scene` `any?` _(optional)_ — The scene walk to read against. Omitted, the call takes its own,
which is what makes a whole reading one walk rather than four.

```lua
local t = streaming.terrain()
```

## modules/streaming/voxel {#modules-streaming-voxel}

```lua
voxel(scene: any?): { [string]: any }
```

What became of every chunk of every voxel world: how many are meshed,
queued, failed or empty, and one row per chunk carrying the state, the
engine's reason when a build failed, and what the build reserved on the
device.

**Parameters**

- `scene` `any?` _(optional)_ — The scene walk to read against. Omitted, the call takes its own.

```lua
local v = streaming.voxel()
```

## modules/streaming/whyNotDrawn {#modules-streaming-whynotdrawn}

```lua
whyNotDrawn(subject: any): { [string]: any }
```

Why a piece of a world's detail is not on screen, as one reason from
the closed set `streaming.reasons()` enumerates, with a detail line naming
what that reason is about.

The subject picks which system answers:
* an entity ref, id or name — whichever of the four systems holds it
* `{ entity = ..., chunk = "cx_cy_cz" }` — one chunk of a voxel world
* `{ entity = ..., level = n }` — one level of a mesh-LOD chain
* `{ cell = "x_z" }` — one cell of the spatial-streaming store

**Parameters**

- `subject` `any` _(optional)_ — The entity, chunk, level or cell to answer about.

```lua
local w = streaming.whyNotDrawn({ entity = "Vox", chunk = "0_0_0" })
```

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

```lua
require("@builtin/modules/api/engine/stringx") -- stringx (also available as global 'stringx')
```

Batch text-scanning kernels — read a whole run of numbers out of a string in one call. Public Luau surface over the `__stringx` Internal FFI namespace.

Usage: local stringx = require("@builtin/modules/api/engine/stringx")
Also available as global: stringx

## modules/stringx/scanNumbers {#modules-stringx-scannumbers}

```lua
scanNumbers(s: string, pos: number?): ({ number }, number)
```

Read the run of numbers starting at `pos` — separated by commas and/or
whitespace — and report where the run ended.

The run stops at the first character that neither continues a number nor
separates two of them (`]`, `}`, a quote, a letter), and `nextPos` is that
character's index, so the caller's own parser resumes exactly there. A
token that is not a valid number also ends the run, with `nextPos` left ON
it rather than past it, so nothing is skipped without the caller seeing it.

**Parameters**

- `s` `string` — The text to read.
- `pos` `number?` _(optional)_ — 1-based index to start at. Defaults to 1.

```lua
-- A JSON array of numbers, in one crossing instead of one per token.
local values, nextPos = stringx.scanNumbers(payload, afterBracket)
-- A whitespace-separated block (OBJ, PLY, a matrix dump).
local m = stringx.scanNumbers("1 0 0 0  0 1 0 0", 1)
```

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

```lua
require("@builtin/modules/api/engine/subscriptions") -- subscriptions (also available as global 'subscriptions')
```

Runtime inspection and cancellation of component-event subscriptions. Public Luau surface over the `__event_inspect_*` / `__event_track_*` Internal FFI globals; the same data is browsable at `/zero/runtime/events/`.

Usage: local subscriptions = require("@builtin/modules/api/engine/subscriptions")
Also available as global: subscriptions

## modules/subscriptions/cancel {#modules-subscriptions-cancel}

```lua
cancel(id: string): boolean
```

Cancel a subscription by id: disconnects the live connection
immediately and marks the row cancelled. Returns true when a live
subscription was cancelled, false for an unknown or
already-disconnected id.

**Parameters**

- `id` `string` — Subscription id to cancel.

```lua
subscriptions.cancel(conn.id)
```

## modules/subscriptions/get {#modules-subscriptions-get}

```lua
get(id: string): SubscriptionRow?
```

One subscription row by id, or nil when the id is unknown (never
tracked, or evicted after its publisher was destroyed).

**Parameters**

- `id` `string` — Subscription id (`conn.id`, or a `/zero/runtime/events/subscriptions/` entry).

```lua
local row = subscriptions.get(conn.id); print(row and row.deliveries)
```

## modules/subscriptions/list {#modules-subscriptions-list}

```lua
list(filter: SubscriptionFilter?): { SubscriptionRow }
```

Every tracked subscription row, optionally filtered by publisher
instance id, publisher entity id, event name, and/or connected state.

**Parameters**

- `filter` `SubscriptionFilter?` _(optional)_ — Optional filter table.

```lua
for _, s in ipairs(subscriptions.list({ connected = true })) do print(s.id, s.event, s.deliveries) end
```

## modules/subscriptions/publishers {#modules-subscriptions-publishers}

```lua
publishers(): { PublisherRow }
```

Every live event publisher: component instance, entity, and
per-event fire stats (fires happen whether or not anyone subscribes)
plus current subscriber ids.

```lua
for _, p in ipairs(subscriptions.publishers()) do print(p.component, p.entityName) end
```

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

```lua
require("@builtin/modules/api/engine/substrate") -- substrate (also available as global 'substrate')
```

Typed data buffers, on the CPU or the GPU — the engine's one buffer primitive. Public Luau surface over the `__substrate` Internal FFI namespace.

Usage: local substrate = require("@builtin/modules/api/engine/substrate")
Also available as global: substrate

## modules/substrate/createBuffer {#modules-substrate-createbuffer}

```lua
createBuffer(opts: BufferOpts): TypedBuffer?
```

Allocate a typed buffer and return its handle.

A `"gpu"` buffer is storage a compute shader binds; `usage` adds
`"vertex"`, `"index"`, `"indirect"` or `"readback"` on top of the storage
it always has. A `"cpu"` buffer lives in the scripting heap and reads back
as a flat array of floats.

The handle's `write` answers whether the words landed: a payload whose end
falls past the end of the buffer is refused whole on both kinds, so the
buffer keeps what it held and the call answers false. `writeU32` and
`writeBytes` answer the same way, against the same extent.

**Parameters**

- `opts` `BufferOpts` — `{ type, len, kind?, usage?, name? }` — `type` is `"f32"`, `"vec3"`,
`"vec4"`, `"quat"` or `"mat4"`; `kind` is `"cpu"` (the default) or `"gpu"`.
`name` is the name a dispatch binds a `"gpu"` buffer by, and the name
`substrate.getBuffer` and `substrate.destroyBuffer` reach it under.

```lua
local pose = substrate.createBuffer({ type = "mat4", len = boneCount })
local field = substrate.createBuffer({ type = "vec3", len = 4096, kind = "gpu" })
local values = pose:read(0, 16):result()
```

## modules/substrate/destroyBuffer {#modules-substrate-destroybuffer}

```lua
destroyBuffer(name: string): boolean
```

Free the GPU buffer `name` denotes, whatever else still holds a handle
to it.

The allocation goes and the name is free to be created again at any type
and length; every handle that pointed at it answers `:alive()` false. This
is what releases a name whose creating handle is gone, so a build that
re-runs at a different size gets its name back.

**Parameters**

- `name` `string` — The name the buffer was created under.

```lua
substrate.destroyBuffer("env.town.xf")
```

## modules/substrate/getBuffer {#modules-substrate-getbuffer}

```lua
getBuffer(name: string): TypedBuffer?
```

The GPU buffer `name` denotes, as a handle you now hold.

A name is how a dispatch binds a buffer, so the name is what an owner asks
by once the handle it created with has gone out of scope — a `.module`
that hot-reloaded, a build that ran in an earlier `execute`. The handle
carries everything `createBuffer`'s does and releases its reference with
`:destroy()`.

**Parameters**

- `name` `string` — The name the buffer was created under.

```lua
local xf = substrate.getBuffer("env.town.xf")
local shape = xf and { xf:type(), xf:length() }
```

## modules/substrate/gpuReadback {#modules-substrate-gpureadback}

```lua
gpuReadback(key: string?): Readback?
```

Wrap the key an FFI read handed back as the `Readback` that polls it.
Every GPU→CPU read reaches the caller through this, so a texture's read
and a buffer's read answer with the same thing.

**Parameters**

- `key` `string?` _(optional)_ — The key the read returned.

```lua
local pending = substrate.gpuReadback(compute.readTexture3D(handle))
```

## modules/substrate/listBuffers {#modules-substrate-listbuffers}

```lua
listBuffers(): { NamedBuffer }
```

Every named GPU buffer the engine holds, in name order.

Each record states `id`, `name`, `type` (`"F32"`, `"Vec3"`, `"Vec4"`,
`"Quat"`, `"Mat4"`), `len` in records, and `refs` — how many holders it
has. This is what states which names are taken and at what shape.

```lua
for _, b in ipairs(substrate.listBuffers()) do print(b.name, b.type, b.len) end
```

## modules/substrate/ready {#modules-substrate-ready}

```lua
ready(self): boolean
```

Whether this read has arrived.

**Parameters**

- `self` `any` _(optional)_

## modules/substrate/result {#modules-substrate-result}

```lua
result(self): { number }?
```

Drain this read as f32 values, nil while it is still on its way.

**Parameters**

- `self` `any` _(optional)_

## modules/substrate/resultBytes {#modules-substrate-resultbytes}

```lua
resultBytes(self): buffer?
```

Drain this read as a Luau `buffer`, nil while it is still on its way.

**Parameters**

- `self` `any` _(optional)_

## modules/substrate/resultU32 {#modules-substrate-resultu32}

```lua
resultU32(self): { number }?
```

Drain this read as u32 values, nil while it is still on its way.

**Parameters**

- `self` `any` _(optional)_

## modules/substrate/state {#modules-substrate-state}

```lua
state(self): string
```

Where this read stands, without draining it and without raising:
`"pending"`, `"ready"`, or `"unknown"` (already drained).

**Parameters**

- `self` `any` _(optional)_

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

```lua
require("@builtin/systems/subsurfaceScattering/subsurface") -- subsurface
```

Light that enters a surface at one point and leaves at another — the transport that softens and reddens the terminator on skin, and that a per-pixel shading model cannot produce.

A surface shaded per-pixel answers only for the light that arrived at that
pixel. Skin does not work that way: light entering the lit side keeps
travelling beneath the surface and emerges past where a cosine has already
reached zero, and it emerges red, because red travels furthest through
flesh. That is what makes the terminator on a face soft and warm instead of
a hard line, and it is why a face with no scattering reads as plastic.
The transport is a spread of exitant light across the surface, so it is
computed on the drawn frame: marked meshes write their scattering into a
mask, and the lit colour is spread along that mask. This module owns which
entities are marked and what they scatter, and ties the pass's lifetime to
whether anything is marked at all.

Usage: local subsurface = require("@builtin/systems/subsurfaceScattering/subsurface")

## modules/subsurface/active {#modules-subsurface-active}

```lua
active() -> boolean
```

**Returns** `boolean`

## modules/subsurface/clear {#modules-subsurface-clear}

```lua
clear()
```

## modules/subsurface/groups {#modules-subsurface-groups}

```lua
groups() -> table
```

**Returns** `table`

## modules/subsurface/list {#modules-subsurface-list}

```lua
list() -> { string }
```

**Returns** `{ string }`

## modules/subsurface/mark {#modules-subsurface-mark}

```lua
mark(entityRef: string, opts: MarkOpts?) -> table
```

Give an entity's meshes a scattering tint and radius.

**Parameters**

- `entityRef` `string`
- `opts` `MarkOpts?` _(optional)_

**Returns** `table`

## modules/subsurface/marked {#modules-subsurface-marked}

```lua
marked(entityRef: string) -> table?
```

**Parameters**

- `entityRef` `string`

**Returns** `table?`

## modules/subsurface/paramsBuffer {#modules-subsurface-paramsbuffer}

```lua
paramsBuffer(): any?
```

The buffer this system's passes read. The render feature binds what
this hands it, so the pass has the values this module packed.

```lua
local p = subsurface.paramsBuffer()
```

## modules/subsurface/setStrength {#modules-subsurface-setstrength}

```lua
setStrength(strength: number) -> number
```

**Parameters**

- `strength` `number`

**Returns** `number`

## modules/subsurface/strength {#modules-subsurface-strength}

```lua
strength() -> number
```

**Returns** `number`

## modules/subsurface/unmark {#modules-subsurface-unmark}

```lua
unmark(entityRef: string) -> boolean
```

**Parameters**

- `entityRef` `string`

**Returns** `boolean`

## modules/surfaceLight/README {#modules-surfacelight-readme}

```lua
require("@builtin/systems/areaLights/surfaceLight") -- surfaceLight
```

Rectangular area lights — a screen, a window or a strip that emits from its whole surface, so its highlight is a shape rather than a dot.

Usage: local surfaceLight = require("@builtin/systems/areaLights/surfaceLight")

## modules/surfaceLight/active {#modules-surfacelight-active}

```lua
active(): boolean
```

Whether the area-lighting pass is currently running.

```lua
if surfaceLight.active() then print("emitting") end
```

## modules/surfaceLight/buffers {#modules-surfacelight-buffers}

```lua
buffers(): { [string]: any }?
```

The buffers the area-lighting pass reads: the settings and the packed
light records. The render feature binds what this hands it.

```lua
local b = surfaceLight.buffers()
```

## modules/surfaceLight/clear {#modules-surfacelight-clear}

```lua
clear()
```

Drop every area light and release the pass. The scales are kept.

```lua
surfaceLight.clear()
```

## modules/surfaceLight/configure {#modules-surfacelight-configure}

```lua
configure(opts: SurfaceLightOpts?): SurfaceLightState
```

Adjust how the two terms are weighted. Any omitted field keeps its
current value.

**Parameters**

- `opts` `SurfaceLightOpts?` _(optional)_ — Settings — see `SurfaceLightOpts`.

```lua
surfaceLight.configure({ specular = 0.5 })
```

## modules/surfaceLight/count {#modules-surfacelight-count}

```lua
count(): number
```

How many area lights are registered.

```lua
print(surfaceLight.count())
```

## modules/surfaceLight/remove {#modules-surfacelight-remove}

```lua
remove(key: string): boolean
```

Remove the area light registered under `key`.

**Parameters**

- `key` `string` — The identifier the light was registered with.

```lua
surfaceLight.remove("tv")
```

## modules/surfaceLight/set {#modules-surfacelight-set}

```lua
set(key: string, shape: SurfaceLightShape): number
```

Add or replace the area light registered under `key`. Re-submitting the
same key moves that light rather than adding another, which is what lets a
component push its rectangle every frame as its entity moves.

**Parameters**

- `key` `string` — Stable identifier — an entity id works well.
- `shape` `SurfaceLightShape` — The emitting rectangle — see `SurfaceLightShape`.

```lua
surfaceLight.set("tv", { position = { 0, 2, 0 }, right = { 1, 0, 0 }, up = { 0, 1, 0 }, width = 2, height = 1.2 })
```

## modules/surfaceLight/settings {#modules-surfacelight-settings}

```lua
settings(): SurfaceLightState
```

The settings currently in force.

```lua
local d = surfaceLight.settings().diffuse
```

## modules/temporalAntiAliasing/README {#modules-temporalantialiasing-readme}

```lua
require("@builtin/systems/antiAliasing/temporalAntiAliasing") -- temporalAntiAliasing
```

Antialiasing that accumulates one sample per pixel per frame. The projection samples a different point inside each pixel every frame, and the frames are carried forward through the scene's own motion, so edges, highlights and fine texture settle instead of crawling.

Usage: local temporalAntiAliasing = require("@builtin/systems/antiAliasing/temporalAntiAliasing")

## modules/temporalAntiAliasing/active {#modules-temporalantialiasing-active}

```lua
active(): boolean
```

Whether the temporal pass is running this frame.

```lua
if temporalAntiAliasing.active() then ... end
```

## modules/temporalAntiAliasing/buffers {#modules-temporalantialiasing-buffers}

```lua
buffers(): { [string]: any }?
```

The parameter buffer the accumulation reads, carrying the settings this
module packs. The render feature binds what this hands it.

```lua
local b = temporalAntiAliasing.buffers()
```

## modules/temporalAntiAliasing/disable {#modules-temporalantialiasing-disable}

```lua
disable()
```

Turn temporal antialiasing off and release the pass. The projection goes
back to sampling pixel centres. The settings are kept, so a later `enable()`
brings back the same tuning.

```lua
temporalAntiAliasing.disable()
```

## modules/temporalAntiAliasing/enable {#modules-temporalantialiasing-enable}

```lua
enable(opts: TemporalAntiAliasingOpts?): TemporalAntiAliasingState
```

Turn temporal antialiasing on and set it. Any omitted field keeps its
current value.

**Parameters**

- `opts` `TemporalAntiAliasingOpts?` _(optional)_ — Temporal antialiasing settings — see `TemporalAntiAliasingOpts`.

```lua
temporalAntiAliasing.enable({ historyWeight = 0.9 })
```

## modules/temporalAntiAliasing/get {#modules-temporalantialiasing-get}

```lua
get(): TemporalAntiAliasingState
```

The temporal antialiasing settings currently in force.

```lua
local w = temporalAntiAliasing.get().historyWeight
```

## modules/temporalUpscale/README {#modules-temporalupscale-readme}

```lua
require("@builtin/systems/temporalUpscale/temporalUpscale") -- temporalUpscale
```

Reconstruction of a display-resolution image from a lower-resolution render. The projection samples a different point inside each pixel every frame and the frames are carried forward through the scene's own motion, so a scene rasterized at a fraction of the display's pixels resolves detail no single one of those frames holds.

Usage: local temporalUpscale = require("@builtin/systems/temporalUpscale/temporalUpscale")

## modules/temporalUpscale/active {#modules-temporalupscale-active}

```lua
active(): boolean
```

Whether the reconstruction is running this frame.

```lua
if temporalUpscale.active() then ... end
```

## modules/temporalUpscale/buffers {#modules-temporalupscale-buffers}

```lua
buffers(): { [string]: any }?
```

The parameter buffer the reconstruction reads, carrying the settings
this module packs. The render feature binds what this hands it.

```lua
local b = temporalUpscale.buffers()
```

## modules/temporalUpscale/disable {#modules-temporalupscale-disable}

```lua
disable()
```

Turn temporal upsampling off and release the pass. The projection goes
back to sampling pixel centres, and the render scale returns to what it was
before this module first moved it — unless something else has steered it
since, which keeps that number. The settings are kept, so a later
`enable()` brings back the same tuning.

```lua
temporalUpscale.disable()
```

## modules/temporalUpscale/enable {#modules-temporalupscale-enable}

```lua
enable(opts: TemporalUpscaleOpts?): TemporalUpscaleState
```

Turn temporal upsampling on and set it. Any omitted field keeps its
current value. Passing `renderScale` also moves the resolution the scene
rasterizes at, and `disable` puts back the scale that was in force before
the first such move.

**Parameters**

- `opts` `TemporalUpscaleOpts?` _(optional)_ — Temporal upsampling settings — see `TemporalUpscaleOpts`.

```lua
temporalUpscale.enable({ renderScale = 0.5 })
```

## modules/temporalUpscale/get {#modules-temporalupscale-get}

```lua
get(): TemporalUpscaleState
```

The temporal upsampling settings currently in force.

```lua
local s = temporalUpscale.get().renderScale
```

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

```lua
require("@builtin/modules/api/engine/text") -- text (also available as global 'text')
```

Text rasterisation resource — create a text handle, set its content and style, then rasterise it to a texture for display, and observe what the text system is holding. Public Luau surface over the `__text` and `__textObserve` Internal FFI namespaces.

Usage: local text = require("@builtin/modules/api/engine/text")
Also available as global: text

## modules/text/alive {#modules-text-alive}

```lua
alive(handle: any): boolean
```

Whether the text system still holds this handle — true between
`text.create` and the `text.destroy` that released it.

**Parameters**

- `handle` `any` _(optional)_ — Text handle from `text.create`.

```lua
if not text.alive(h) then h = text.create({ content = "again" }) end
```

## modules/text/count {#modules-text-count}

```lua
count(): number
```

How many text objects the text system is holding — the number that
moves when `text.create` and `text.destroy` are called.

```lua
local before = text.count()
```

## modules/text/create {#modules-text-create}

```lua
create(options: table): any
```

Create a text handle from an initial content + style table. The handle
owns a runtime GPU texture (see `text.textureGuid`); pass it to every other
call.

**Parameters**

- `options` `table` — Table of `content` plus style fields (fontSize, color,
alignment, richText, maxWidth, ...).

```lua
local h = text.create({ content = "Hello", fontSize = 48 })
```

## modules/text/destroy {#modules-text-destroy}

```lua
destroy(handle: any): boolean
```

Destroy a text handle and release its raster + glyph layout.

**Parameters**

- `handle` `any` _(optional)_ — Text handle from `text.create`.

```lua
text.destroy(h)
```

## modules/text/face {#modules-text-face}

```lua
face(handle: any): any
```

Which font face one handle actually shaped with, and whether that is
the family its style asked for. `requested` is what was asked, `resolved`
is the face that answered, `matched` says whether they agree and `reason`
says why when they do not — one of `text.faceReasons()`. A style that named
no family reports `noFamilyRequested`: it got the default because it asked
for nothing, so `reason` rather than `matched` is what an alert switches
on. `faces` lists
every face the shaper used, most glyphs first, so a fallback that covered
part of the string is visible alongside the face that covered the rest.

**Parameters**

- `handle` `any` _(optional)_ — Text handle from `text.create`.

```lua
local r = text.face(h).reason; if r == "familyUnknown" or r == "familyNotSelectable" then print(r) end
```

## modules/text/faceReasons {#modules-text-facereasons}

```lua
faceReasons(): { string }
```

Every reason the face readings give for a label or a family not being
in the family a style named, nearest cause first. `text.face` gives them
for one label; `font.reconcile()` also gives `familyCoveredNoGlyph`, which
it can only reach by laying the family out under its own weights and over
several scripts.

```lua
for _, r in ipairs(text.faceReasons()) do print(r) end
```

## modules/text/listFonts {#modules-text-listfonts}

```lua
listFonts(): { string }
```

List the font families currently available to the text system.

```lua
local fonts = text.listFonts()
```

## modules/text/loadFont {#modules-text-loadfont}

```lua
loadFont(ref: any): any
```

Load a font from an asset reference so it becomes available to
`setStyle`'s `fontFamily`.

**Parameters**

- `ref` `any` _(optional)_ — Font asset reference or path.

```lua
text.loadFont(asset.ref("fonts.inter", "font"))
```

## modules/text/measure {#modules-text-measure}

```lua
measure(handle: any): any
```

Measure the rasterised text in pixels without producing a texture.

**Parameters**

- `handle` `any` _(optional)_ — Text handle from `text.create`.

```lua
local size = text.measure(h)
```

## modules/text/observe {#modules-text-observe}

```lua
observe(): any
```

Everything the text system is holding right now. `count` is the live
text objects; `objects` is one row each, carrying its content, the style
it was laid out with, its measured extent, whether it is dirty, the `face`
the shaper actually used, the `owner` entity whose component created it
with whether that entity is still there, and the `raster` texture its last
rasterisation landed in with the bytes it costs. `orphans` is the subset
whose owning entity is gone, `fonts` the families the shaper can resolve,
and `raster` the glyph-raster bytes with the pool they belong to named.
Built when you ask, so it costs nothing per frame and reads the same in
edit mode as in play.

```lua
local live = text.observe().count
```

## modules/text/orphans {#modules-text-orphans}

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

The text objects whose owning entity no longer exists — a quad the
engine is still holding for something that has been despawned. Each row is
the same shape `text.observe().objects` carries.

```lua
print(#text.orphans() .. " labels outlived their entity")
```

## modules/text/rasterMemory {#modules-text-rastermemory}

```lua
rasterMemory(): any
```

The glyph-raster bytes, broken out of the runtime GPU texture pool.
`bytes` is summed off the same map `renderer.gpuMemory().textures` is
totalled from, so `shareOfPool` is a share of that number rather than a
second count of the same memory.

```lua
local r = text.rasterMemory(); print(r.bytes .. " of " .. r.poolBytes)
```

## modules/text/rasterize {#modules-text-rasterize}

```lua
rasterize(handle: any, texture: any, scale: number?): any
```

Rasterise the handle's current text + style into the given runtime GPU
texture. Bind that texture's guid as a material's `base_color_texture` to
display the text; re-rasterising the same texture overwrites it in place.

**Parameters**

- `handle` `any` _(optional)_ — Text handle from `text.create`.
- `texture` `any` _(optional)_ — Destination GPU texture handle (`renderer.texture.create`) or its
guid string — WHERE the raster lands.
- `scale` `number?` _(optional)_ — World/pixel scale factor for the raster (default 1.0).

```lua
local tex = renderer.texture.create({ width = 256, height = 64 })
local r = text.rasterize(h, tex, 1.0)
```

## modules/text/setStyle {#modules-text-setstyle}

```lua
setStyle(handle: any, style: table): boolean
```

Replace the handle's style. Fields not present keep their current
value.

**Parameters**

- `handle` `any` _(optional)_ — Text handle from `text.create`.
- `style` `table` — Style table (fontSize, color, alignment, outline, ...).

```lua
text.setStyle(h, { fontSize = 64, color = "yellow" })
```

## modules/text/setText {#modules-text-settext}

```lua
setText(handle: any, content: string): boolean
```

Replace the handle's text content.

**Parameters**

- `handle` `any` _(optional)_ — Text handle from `text.create`.
- `content` `string` — New text string.

```lua
if not text.setText(h, "HP: 100") then h = text.create({ content = "HP: 100" }) end
```

## modules/text/textureGuid {#modules-text-textureguid}

```lua
textureGuid(handle: any): string?
```

The runtime GPU texture guid this handle rasterises into — bind it as a
material texture (`base_color_texture`) to display the text.

**Parameters**

- `handle` `any` _(optional)_ — Text handle from `text.create`.

```lua
entity(id).component.get("Material"):setTexture("base_color_texture", text.textureGuid(h))
```

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

```lua
require("@builtin/modules/trusted_client") -- trusted
```

User-space client for the trusted -> user call bridge (`trusted.call`).

Lets user-space scripts TRIGGER orchestration that lives in the engine's
trusted VM (auth / connection / service flows we author in trusted Luau)
WITHOUT exposing the trusted source or the privileged primitives those
flows use. Backed by the single `__trustedBridge.invoke` Rust transport:
the named call is marshalled into the trusted VM, run against its
__TRUSTED_EXPORTS registry, and the result marshalled back as plain data.
Trusted methods are registered on the other side by the trusted module
`/zero/trusted/exports` (its `expose(name, handler)`). This module is
auto-injected as the global `trusted` by the prelude.

Usage: local trusted = require("@builtin/modules/trusted_client")

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

```lua
require("@builtin/modules/api/engine/ui") -- ui (also available as global 'ui')
```

UI system — screens, styles, themes, widget responses, focus, custom-widget builders, per-widget state. Public Luau surface over the `__ui` Internal FFI namespace.

Usage: local ui = require("@builtin/modules/api/engine/ui")
Also available as global: ui

## modules/ui/blur {#modules-ui-blur}

```lua
blur()
```

Surrender keyboard focus from whichever widget currently
holds it.

## modules/ui/bringAreaToFront {#modules-ui-bringareatofront}

```lua
bringAreaToFront(id: string)
```

Raise a movable `area` to the top of the window stacking order —
the programmatic equivalent of clicking it. Areas sharing a stacking
band order by interaction, so this is the call that brings one forward
from code: use it when a taskbar button, focus change, or app launch
should raise a window. Moving a screen to a higher `layer` band raises
it over the bands below.

**Parameters**

- `id` `string` — Area widget id.

## modules/ui/captureWindow {#modules-ui-capturewindow}

```lua
captureWindow(screen: string, window: string, opts: CaptureOpts?): CaptureResult?
```

Render a single Window widget to its own offscreen texture
and write the result as PNG at
`/runtime/render_surfaces/<rtHandle>.png`. The screen does NOT
need to be visible. Returns `{ rtHandle, texturePath }` or nil
on invalid inputs (width/height clamped to `[1, 8192]`,
defaults 600x400).

**Parameters**

- `screen` `string` — Screen id containing the target Window.
- `window` `string` — Widget id of the Window.
- `opts` `CaptureOpts?` _(optional)_ — `{ width, height }` (optional).

## modules/ui/click {#modules-ui-click}

```lua
click(callbackId: string, value: any?)
```

Simulate a widget click / interaction by its callback id. The call
carries no screen, so an id that names widgets on several screens reaches
every component that declared it, once each.

**Parameters**

- `callbackId` `string` — Callback id assigned to the widget.
- `value` `any?` _(optional)_ — Optional value to pass with the callback.

## modules/ui/defineStyle {#modules-ui-definestyle}

```lua
defineStyle(name: string, style: StyleProps)
```

Define a named style. Style keys follow
`<widgetType>.<className>` (e.g. `"label.h1"`, `"button.primary"`)
or bare `<className>` to apply across widget types. Widgets
reference styles via the `classes` (or `class`) prop.

**Parameters**

- `name` `string` — Style name.
- `style` `StyleProps` — Style properties table.

## modules/ui/defineStyles {#modules-ui-definestyles}

```lua
defineStyles(styles: { [string]: StyleProps })
```

Define multiple named styles at once.

**Parameters**

- `styles` `{ [string]: StyleProps }` — Map of style name to style properties.

## modules/ui/defineWidget {#modules-ui-definewidget}

```lua
defineWidget(name: string, builderFn: (WidgetTree, { WidgetTree }) -> WidgetTree)
```

Register a custom widget kind. When a tree contains
`{ type = name, props = ..., children = ... }`, the decoder
calls `builderFn(props, children)` at register / update time and
substitutes the returned widget table in place. Errors surface
through `ui.lastValidation()` with codes `widget-builder-error`
/ `widget-builder-bad-return` / `decode-recursion-depth-exceeded`.

**Parameters**

- `name` `string` — Custom widget kind name.
- `builderFn` `(WidgetTree, { WidgetTree }) -> WidgetTree` — Builder closure `(props, children) -> widgetTable`.

## modules/ui/diagnose {#modules-ui-diagnose}

```lua
diagnose(widgetId: string): WidgetPaint?
```

Why one widget did or did not reach the last frame. Returns that
widget's row from `ui.observe()` — the same fields, resolved against the
same reading. An id no registered screen carries reads `noSuchWidget`,
which is how a misspelling separates from a widget whose screen is
hidden and from one the frame laid out no box for.

**Parameters**

- `widgetId` `string` — The id the widget records layout under.

```lua
"hud-healthbar"
```

## modules/ui/dragState {#modules-ui-dragstate}

```lua
dragState(): { payload: string, x: number, y: number }?
```

The in-flight drag-and-drop payload while a `dragPayload` widget is
being dragged, else nil. `x`/`y` are the pointer's position in the
logical space `ui.getLayoutInfo` rects live in, so the reading resolves
directly against widget rects. Poll during a drag to drive live
feedback (a placement ghost following the cursor); the drop itself
still lands through the target's `onDrop`. Snapshotted each frame.

## modules/ui/elementTree {#modules-ui-elementtree}

```lua
elementTree(screenName: string): ElementNode?
```

Introspect a screen's rendered widget hierarchy with each
element's layout rect. Every node the renderer draws appears, nested
exactly as the widgets nest, under the id it records layout against:
the `id` set on the node when the author gave it one, otherwise
`<screen>/<type>@<path>`. `bounds` is that element's rect — the same
table `ui.getLayoutInfo(id)` returns — and appears once the element has
been measured. Kinds registered through `ui.defineWidget` appear
expanded into the primitives they build. Feeds the `gui.captureElement`
tool: list the tree, pick the ids to frame, capture their region.

**Parameters**

- `screenName` `string` — Screen id passed to `ui.registerScreen`.

## modules/ui/focus {#modules-ui-focus}

```lua
focus(widgetId: string)
```

Programmatically request keyboard focus on a widget. Queued
as a one-shot; the next render of the matching widget calls
`response.request_focus()`.

**Parameters**

- `widgetId` `string` — Widget id to focus.

## modules/ui/focusedWidget {#modules-ui-focusedwidget}

```lua
focusedWidget(): string?
```

Return the widget id of whichever widget currently holds
keyboard focus, or nil. Snapshotted post-render each frame.

## modules/ui/getAreaPos {#modules-ui-getareapos}

```lua
getAreaPos(id: string): AreaPos?
```

Read the current pivot position of an `area` widget,
including any user drag deltas. Returns `{ x, y }` or nil if
the area didn't render this frame.

**Parameters**

- `id` `string` — Area widget id.

## modules/ui/getAreaSize {#modules-ui-getareasize}

```lua
getAreaSize(id: string): AreaSize?
```

Read the measured size of an `area` widget, including any user
resize-grip drags if the area is `resizable`. Returns `{ w, h }`
or nil if the area didn't render this frame.

**Parameters**

- `id` `string` — Area widget id.

## modules/ui/getDockLayout {#modules-ui-getdocklayout}

```lua
getDockLayout(id: string): string?
```

Read the current serialized layout (split/tab arrangement) of
a `dockArea` widget as a JSON string. Returns nil if the dockArea
didn't render this frame. Persist the string and pass it back via
the dockArea's `layout` prop to restore the arrangement.

**Parameters**

- `id` `string` — DockArea widget id.

## modules/ui/getLayoutInfo {#modules-ui-getlayoutinfo}

```lua
getLayoutInfo(widgetId: string?): LayoutInfo?
```

Get layout info (position, size, content bounds) for UI
containers. If `widgetId` is given, returns info for that
widget only; otherwise returns all.

**Parameters**

- `widgetId` `string?` _(optional)_ — Optional widget id to query.

## modules/ui/getScreenTree {#modules-ui-getscreentree}

```lua
getScreenTree(screenName: string): WidgetTree?
```

Return the last widget tree table passed to
`registerScreen` / `updateScreen` for `screenName`.

**Parameters**

- `screenName` `string` — Screen name to query.

## modules/ui/getTheme {#modules-ui-gettheme}

```lua
getTheme(): string
```

Get the name of the currently active theme.

## modules/ui/getToken {#modules-ui-gettoken}

```lua
getToken(name: string): string?
```

Look up a single design token value from the active theme.

**Parameters**

- `name` `string` — Token name (without `$` prefix).

## modules/ui/getTokens {#modules-ui-gettokens}

```lua
getTokens(): { [string]: string }
```

Get all design tokens from the active theme as a key-value
map.

## modules/ui/getWidgetProps {#modules-ui-getwidgetprops}

```lua
getWidgetProps(typeName: string): { WidgetPropDescriptor }?
```

Get the property definitions for a widget type.

**Parameters**

- `typeName` `string` — Widget type name.

## modules/ui/getWidgetTypes {#modules-ui-getwidgettypes}

```lua
getWidgetTypes(): { string }
```

Get all available widget type names that can be used in
widget trees.

## modules/ui/hideScreen {#modules-ui-hidescreen}

```lua
hideScreen(name: string): boolean
```

Hide a registered screen, and report whether a screen by that name
is registered. The engine applies the hide later in the frame;
`listScreens` reflects it from the next call onwards.

**Parameters**

- `name` `string` — Screen identifier to hide.

## modules/ui/hitTest {#modules-ui-hittest}

```lua
hitTest(x: number, y: number): PaintHitTest?
```

Which widget a pointer at `(x, y)` reaches, and the stack beneath it.
Coordinates are in the space `ui.screenSize()` reports — the same space
`getLayoutInfo` rects and `gui.clickAt` use.

**Parameters**

- `x` `number` — Logical X.
- `y` `number` — Logical Y.

```lua
640, 360
```

## modules/ui/invisibilityReasons {#modules-ui-invisibilityreasons}

```lua
invisibilityReasons(): { string }
```

Every verdict `ui.diagnose` can report, as a closed list.

## modules/ui/lastRegistration {#modules-ui-lastregistration}

```lua
lastRegistration(): { name: string, layer: number? }?
```

The name and layer passed to the most recent `ui.registerScreen`
call, recorded synchronously at call time. A host that mounts a nested
app reads this immediately after the mount to learn which screen the
nested code registered, without intercepting the `ui` table.

## modules/ui/lastValidation {#modules-ui-lastvalidation}

```lua
lastValidation(screenName: string?): any
```

Validation diagnostics produced at the most recent
`registerScreen` / `updateScreen`, plus what the render stage
found while painting — `unknown-font-family` reports a
`style.fontFamily` that named no registered font family, once
per family per screen, and `wrap-label-no-width` reports a
label with `props.wrap` whose box came out narrower than its
own longest word, once per label per screen. With no args
returns a
`{ [screen] = entry }` map; with a name returns that screen's
entry or nil. Validation gated by world setting
`ui.validation` = `"off" | "warn" | "strict"` (default `"warn"`).

**Parameters**

- `screenName` `string?` _(optional)_ — Optional screen name.

## modules/ui/listFonts {#modules-ui-listfonts}

```lua
listFonts(): { FontFamilyInfo }
```

Every font family a `style.fontFamily` can select. Read from
the registry the UI text renderer resolves a family token
through, so a family this returns is one a label renders in.
`family` and every name in `aliases` are accepted as a
`fontFamily`, case-insensitively; `aliases` carries the
web-font names, CSS generic families and face names that
select the same group. `faces` names the concrete face in each
weight/style slot, so a `fontWeight = 700` against a family
with no `bold` face gets a synthesised heavy. `system = true`
marks a family taken from the host OS — present on this
machine, absent on one without it, and absent on WASM — so a
UI that must look the same everywhere picks a family with
`system = false`. A `fontFamily` naming nothing in this list
is reported as an `unknown-font-family` warning through
`ui.lastValidation(screen)` once the screen paints, and the
text renders in the default proportional face.

```lua
for _, f in ui.listFonts() do print(f.family) end
```

## modules/ui/listScreens {#modules-ui-listscreens}

```lua
listScreens(): { ScreenSummary }
```

List every registered screen with its current visibility,
layer, and whether the screen has a populated root widget tree,
including the register / show / hide / unregister calls the running
script has already made. Sorted by layer ascending, then name.

## modules/ui/listThemes {#modules-ui-listthemes}

```lua
listThemes(): { string }
```

List all registered theme names.

## modules/ui/observe {#modules-ui-observe}

```lua
observe(screenName: string?): PaintObservation?
```

What the last UI frame painted. Returns
`{ generation, viewport, pointer, pointerOverUi, pointerWidget, widgets }`
with one `widgets` row per widget any registered screen holds — its
layout box, the clip chain it painted under, the part of that box which
reached the frame (`visible`), the order it painted in (`paintIndex`),
and its `reason` from the closed set `ui.invisibilityReasons()` lists.
`generation` advances once per re-rendered frame, so two calls reporting
the same number describe the same frame.

**Parameters**

- `screenName` `string?` _(optional)_ — Narrow the rows to one screen. Omit for every screen.

```lua
"hud"
```

## modules/ui/paintOrder {#modules-ui-paintorder}

```lua
paintOrder(a: string, b: string): number?
```

Which of two widgets paints later: `-1` when `a` paints before `b`,
`1` when after, `0` when level. This is what separates two widgets whose
rects are identical.

**Parameters**

- `a` `string` — First widget id.
- `b` `string` — Second widget id.

```lua
"panel-a", "panel-b"
```

## modules/ui/pixelRatio {#modules-ui-pixelratio}

```lua
pixelRatio(): number
```

Physical pixels per logical point — the factor between the logical
space `ui.screenSize()` / `getLayoutInfo` rects live in and the physical
space `input.mousePosition`, the camera viewport rect and
`input.simulateMouse*` coordinates live in. Multiply a layout coordinate
by this to aim a simulated pointer at a widget.

## modules/ui/pointerWidget {#modules-ui-pointerwidget}

```lua
pointerWidget(): PointerRead?
```

Whether the UI is consuming the pointer, and which widget holds it —
the pointer counterpart of `ui.focusedWidget()`.

## modules/ui/registerBackgroundShader {#modules-ui-registerbackgroundshader}

```lua
registerBackgroundShader(shaderHandle: any, width: number?, height: number?)
```

Register a screen-domain `.shader` as a UI background, drawn
via the `backgroundShader` style. Takes the shader's asset handle
from `asset.resolve`.

**Parameters**

- `shaderHandle` `any` _(optional)_ — The screen `.shader`'s asset handle, from `asset.resolve`.
- `width` `number?` _(optional)_ — Render target width (default 1280).
- `height` `number?` _(optional)_ — Render target height (default 720).

## modules/ui/registerCallbackEnv {#modules-ui-registercallbackenv}

```lua
registerCallbackEnv(key: string, env: { [string]: any })
```

Register an environment table to receive widget-callback
broadcasts: its global `onCallback(id, value)` fires for any widget
callback not owned by a specific component instance — the same
broadcast a component's `onCallback` receives. Keyed by `key`;
re-registering the same key replaces the previous env. A component
instance is folded into the callback dispatch automatically, so reach
for this from a non-component context that hosts a UI surface (a scene
entrypoint registering its own screen). Pair with
`ui.unregisterCallbackEnv(key)` so the ref is released.

**Parameters**

- `key` `string` — Stable identifier for this registration (re-register replaces).
- `env` `{ [string]: any }` — Environment table whose `onCallback` receives the broadcasts.

## modules/ui/registerScreen {#modules-ui-registerscreen}

```lua
registerScreen(name: string, widgetTree: WidgetTree, layer: number?)
```

Register a named UI screen with a widget tree. Optional
`layer` controls z-ordering (higher = on top), in bands: below 0
behind everything, 0-99 ordinary app depth, 100-999 always-on-top
chrome, 1000+ menu and popup depth. A screen in a higher band
covers one in a lower band whatever their roots are; inside a band
a floating `area` or `window` root sits over ordinary content, and
a `modal` root sits over the whole stack. Tag-based
grouping lives in `Z.tags` (`Z.tags.set(name, { "editor" })`
after register).

**Parameters**

- `name` `string` — Unique screen identifier.
- `widgetTree` `WidgetTree` — Root widget table.
- `layer` `number?` _(optional)_ — Z-order layer (optional).

```lua
ui.registerScreen("hud", tree)
```

## modules/ui/registerTheme {#modules-ui-registertheme}

```lua
registerTheme(name: string, theme: ThemeDefinition)
```

Register a theme from a flat Luau table. Most callers
should use `Z.theme.register(name, table)` which runs the
cascade for them.

**Parameters**

- `name` `string` — Theme name to register.
- `theme` `ThemeDefinition` — Flat-resolved theme table.

## modules/ui/removeScreen {#modules-ui-removescreen}

```lua
removeScreen(name: string): boolean
```

Alias for `ui.unregisterScreen`.

**Parameters**

- `name` `string` — Screen identifier to remove.

## modules/ui/resetAreaSize {#modules-ui-resetareasize}

```lua
resetAreaSize(id: string)
```

Clear a `resizable` `area`'s remembered size (from a grip drag or
`ui.setAreaSize`) so its declared — or content — size takes over again.

**Parameters**

- `id` `string` — Area widget id.

## modules/ui/response {#modules-ui-response}

```lua
response(widgetId: string): WidgetResponse?
```

Per-widget interaction snapshot for the most recent frame.
Returns `{ clicked, hovered, focused, changed, value }` where
`clicked` / `changed` mark transitions and `hovered` / `focused`
mark current state.

**Parameters**

- `widgetId` `string` — The widget id (NOT the onClick / onChange callback id).

## modules/ui/screen {#modules-ui-screen}

```lua
screen(name: string): { [string]: any }?
```

Get a screen proxy with methods like `setResolution` and
`rasterize`.

**Parameters**

- `name` `string` — Screen name.

## modules/ui/screenSize {#modules-ui-screensize}

```lua
screenSize(): { width: number, height: number }
```

The UI coordinate space as `{ width, height }` (logical points). This is
the space `area` `pos`, anchors, and `getLayoutInfo` rects use — and it is
NOT the pixel size of a `capture` screenshot, which may be downscaled. Use
this for absolute `area` positioning (e.g. pinning a menu above a bottom
taskbar) instead of guessing the size from a capture image.

It follows the size the engine draws at, and `renderer.setViewportSize`
changes that size at runtime — which is how a layout written against this
is checked at a second shape without rebooting the engine. The pixel size
behind these points is `renderer.surfaceSize()` — the whole drawing
surface a screen is laid out over, which an editor layout makes larger
than the rect `renderer.viewportSize()` draws the scene into — and
`ui.pixelRatio()` is the factor between the two spaces.

## modules/ui/scroll {#modules-ui-scroll}

```lua
scroll(deltaX: number, deltaY: number)
```

Simulate a mouse-wheel scroll event on the UI.

**Parameters**

- `deltaX` `number` — Horizontal scroll delta.
- `deltaY` `number` — Vertical scroll delta.

## modules/ui/setAreaPos {#modules-ui-setareapos}

```lua
setAreaPos(id: string, x: number, y: number)
```

Programmatically move a movable `area` widget to `(x, y)`.
Applied for one frame; subsequent frames let drag tracking
take over.

**Parameters**

- `id` `string` — Area widget id.
- `x` `number` — Target pivot x (screen coords).
- `y` `number` — Target pivot y (screen coords).

## modules/ui/setAreaSize {#modules-ui-setareasize}

```lua
setAreaSize(id: string, w: number, h: number)
```

Programmatically set a `resizable` `area`'s size (the user-size
override) — for maximize / restore / tile. Persists until the area's
declared width/height changes or `ui.resetAreaSize(id)` clears it.

**Parameters**

- `id` `string` — Area widget id.
- `w` `number` — Target width (screen coords).
- `h` `number` — Target height (screen coords).

## modules/ui/setDockWindowRect {#modules-ui-setdockwindowrect}

```lua
setDockWindowRect(
```

Place the floating window of a `dockArea` panel at `(x, y)` with
size `(width, height)`. Applies once the panel occupies a window —
a request made before then waits for it.

## modules/ui/setScreenRenderLayer {#modules-ui-setscreenrenderlayer}

```lua
setScreenRenderLayer(name: string, mask: number)
```

Set a screen's render-layer membership bitmask. A screen draws into a
camera or capture only when this mask intersects the camera's include
mask — the same rule geometry follows. Content UI defaults to the `ui`
bit; the editor places its chrome on `EditorUI` so agent captures can
drop it. Masks come from `__renderLayers.bit(name)`.

**Parameters**

- `name` `string` — Screen identifier.
- `mask` `number` — Render-layer membership bitmask.

## modules/ui/setScrollPosition {#modules-ui-setscrollposition}

```lua
setScrollPosition(widgetId: string, offsetY: number)
```

Set the scroll offset of a scrollArea widget.

**Parameters**

- `widgetId` `string` — Scroll area widget id.
- `offsetY` `number` — Vertical scroll offset in pixels.

## modules/ui/setShaderUniforms {#modules-ui-setshaderuniforms}

```lua
setShaderUniforms(name: string, uniforms: { [string]: number })
```

Set uniform values on a registered background shader.

**Parameters**

- `name` `string` — Shader name identifier.
- `uniforms` `{ [string]: number }` — Map of uniform name to number value.

## modules/ui/setTheme {#modules-ui-settheme}

```lua
setTheme(name: string)
```

Switch the active global theme by name.

**Parameters**

- `name` `string` — Theme name to activate.

## modules/ui/showScreen {#modules-ui-showscreen}

```lua
showScreen(name: string): boolean
```

Make a registered screen visible, and report whether a screen by
that name is registered. The engine applies the show later in the
frame; `listScreens` reflects it from the next call onwards.

**Parameters**

- `name` `string` — Screen identifier to show.

## modules/ui/unregisterCallbackEnv {#modules-ui-unregistercallbackenv}

```lua
unregisterCallbackEnv(key: string)
```

Remove an environment registered with `ui.registerCallbackEnv`. Its
`onCallback` stops receiving broadcasts. No-op if `key` isn't registered.

**Parameters**

- `key` `string` — The key passed to `ui.registerCallbackEnv`.

## modules/ui/unregisterScreen {#modules-ui-unregisterscreen}

```lua
unregisterScreen(name: string): boolean
```

Remove a screen from the registry entirely. Unlike
`hideScreen`, this deletes the entry so it no longer appears in
`listScreens` or render iteration.

**Parameters**

- `name` `string` — Screen identifier to unregister.

## modules/ui/unregisterWidget {#modules-ui-unregisterwidget}

```lua
unregisterWidget(name: string)
```

Drop a registered custom widget kind. Subsequent references
produce an `unknown-widget-type` diagnostic.

**Parameters**

- `name` `string` — Custom widget kind name.

## modules/ui/updateScreen {#modules-ui-updatescreen}

```lua
updateScreen(name: string, widgetTree: WidgetTree)
```

Replace the widget tree of an already-registered screen.

**Parameters**

- `name` `string` — Screen identifier to update.
- `widgetTree` `WidgetTree` — New root widget table.

## modules/ui/useStyles {#modules-ui-usestyles}

```lua
useStyles(themeName: string)
```

Apply a registered style file's classes additively without
changing the active theme.

**Parameters**

- `themeName` `string` — Name of the registered style / theme asset.

## modules/ui/widgetState {#modules-ui-widgetstate}

```lua
widgetState(widgetId: string, key: string, default: any?): any
```

Read per-widget cross-frame state. Returns the value
previously written via `widgetStateSet`, or `default` (or nil).
State is keyed by widget id and persists across re-renders
within a screen's lifetime; cleared automatically when the
owning screen is unregistered.

**Parameters**

- `widgetId` `string` — Widget id whose state to read.
- `key` `string` — State key.
- `default` `any?` _(optional)_ — Value to return when nothing has been written.

## modules/ui/widgetStateClear {#modules-ui-widgetstateclear}

```lua
widgetStateClear(widgetId: string, key: string)
```

Remove a per-widget state entry.

**Parameters**

- `widgetId` `string` — Widget id whose state to clear.
- `key` `string` — State key.

## modules/ui/widgetStateSet {#modules-ui-widgetstateset}

```lua
widgetStateSet(widgetId: string, key: string, value: any)
```

Write per-widget cross-frame state. Replaces any existing
value under `(widgetId, key)`. Tables are stored by reference.

**Parameters**

- `widgetId` `string` — Widget id to scope the state under.
- `key` `string` — State key.
- `value` `any` _(optional)_ — Value to store (must be non-nil).

## modules/unwatch {#modules-unwatch}

```lua
modules.unwatch(watcherId) -> boolean
```

Remove a previously registered module source watcher by its ID.

**Parameters**

- `watcherId` `number` — Watcher ID returned by modules.watch()

**Returns** `boolean` — true if watcher was found and removed

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

```lua
require("@builtin/modules/api/engine/userfile") -- userfile (also available as global 'userfile')
```

User-system → engine file upload. Opens the user's own file picker (native OS dialog / Android / web browser) and brings the chosen file(s) into the engine. Public Luau surface over the `__userfile` Internal FFI namespace.

Usage: local userfile = require("@builtin/modules/api/engine/userfile")
Also available as global: userfile

## modules/userfile/pick {#modules-userfile-pick}

```lua
pick(opts: PickOpts?): PickResult
```

Open the user's system file picker and bring the chosen file(s)
into the engine. Yields until the user finishes (call from a coroutine /
task, like any `task.await`) and returns
`{ cancelled, files = {{ name, mime, size, bytes?, vfsPath? }} }`.
Without `writeTo` each file carries `bytes` (a binary-safe string);
with `writeTo` each carries `vfsPath` (read it with `vfs.read`).
Cancelling returns `{ cancelled = true, files = {} }`; a genuine failure
(e.g. a lost browser user-activation gesture) raises an error.

**Parameters**

- `opts` `PickOpts?` _(optional)_ — Picker options (optional): multiple, folder, title, filters, writeTo.

```lua
local r = userfile.pick({ filters = {{ name = "Images", extensions = {"png","jpg"} }} })
if not r.cancelled then vfs.write("/source/textures/wall.png", r.files[1].bytes) end
```

## modules/userfile/pickFolder {#modules-userfile-pickfolder}

```lua
pickFolder(opts: PickOpts?): PickResult
```

Convenience for `userfile.pick({ folder = true })` — pick a whole
directory tree. Yields until the user finishes and returns the same
result table as `pick`. On the web this degrades to a multi-file selection.

**Parameters**

- `opts` `PickOpts?` _(optional)_ — Picker options (optional); `folder` is forced true.

```lua
local r = userfile.pickFolder({ writeTo = "/source/imported/" })
```

## modules/velocityDilation/README {#modules-velocitydilation-readme}

```lua
require("@builtin/systems/velocityDilation/velocityDilation") -- velocityDilation
```

How far a moving surface's velocity reaches past its own silhouette in the frame's velocity buffer. Every temporal technique reads that buffer one texel per pixel, so widening it is what lets a reprojection and a blur follow a moving object over the pixels it is about to cover.

Usage: local velocityDilation = require("@builtin/systems/velocityDilation/velocityDilation")

## modules/velocityDilation/active {#modules-velocitydilation-active}

```lua
active(): boolean
```

Whether the dilation passes are running this frame.

```lua
if velocityDilation.active() then ... end
```

## modules/velocityDilation/clear {#modules-velocitydilation-clear}

```lua
clear()
```

Set the radius to 0 and release the passes, leaving the velocity buffer
as the geometry passes wrote it.

```lua
velocityDilation.clear()
```

## modules/velocityDilation/get {#modules-velocitydilation-get}

```lua
get(): VelocityDilationState
```

The dilation settings currently in force.

```lua
local r = velocityDilation.get().radius
```

## modules/velocityDilation/maxRadius {#modules-velocitydilation-maxradius}

```lua
maxRadius(): number
```

The widest neighbourhood `set` accepts, in pixels.

```lua
local ceiling = velocityDilation.maxRadius()
```

## modules/velocityDilation/paramsBuffer {#modules-velocitydilation-paramsbuffer}

```lua
paramsBuffer(): any
```

The parameter buffer the dilation pass reads, carrying the radius this
module packs. The render feature binds what this hands it.

```lua
local b = velocityDilation.paramsBuffer()
```

## modules/velocityDilation/set {#modules-velocitydilation-set}

```lua
set(opts: VelocityDilationOpts?): VelocityDilationState
```

Set how far velocity reaches past a silhouette. Any omitted field keeps
its current value. A `radius` of 0 releases the passes and leaves the
velocity buffer as the geometry passes wrote it.

**Parameters**

- `opts` `VelocityDilationOpts?` _(optional)_ — Dilation settings — see `VelocityDilationOpts`.

```lua
velocityDilation.set({ radius = 2 })
```

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

```lua
require("@builtin/modules/api/engine/vfs") -- vfs (also available as global 'vfs')
```

Virtual filesystem — read, write, list, watch. Public Luau surface over the `__vfs` Internal FFI namespace.

A write to authored `/source` WHILE PLAY IS RUNNING lands on the play
shadow: the bytes are live in the session immediately, disk source is
untouched, and a guarded play-exit discards them unless they were kept.
This is why a session's work can read back correctly and still stage
nothing — `zm add` and a commit look at disk, and the shadow is not on it.
`vfs.durability(path)` answers where any write's bytes went: `durable`,
the state in `warning`, the routes out in `playShadow`, and which of the
paths you asked about the shadow holds in `shadowed`.
`vfs.playShadowPaths()` lists everything the session is holding, and
`vfs.playShadowAuthors()` says whose each one is.
Three routes keep a write, differing in what they cost the session:
  vfs.promotePlayShadow(path)            -- or a list of paths: THOSE
                                         -- paths onto canonical source,
                                         -- play keeps running, the rest
                                         -- of the set untouched
  vfs.write(path, bytes, { durable = true })  -- the write skips the
                                         -- shadow, nothing to promote
  tools.use("sceneAuthoring", "changes") -- then acceptChanges: reaches
                                         -- ENTITY changes too, session
                                         -- paused until the verdict
`vfs.revertPlayShadow` takes the same path or list and does the opposite.
Promote the whole SET the asset landed, not the path you passed: a path
carrying an asset-type suffix names the asset, so one `.component` write
shadows its entry file, its README and its metadata together, and a
play-exit refuses over whichever of them are left behind. Read that set
out of `vfs.playShadowPaths()`, filtered to the paths under the asset.
The `core/vfs` guide has the model and what each route costs.

Usage: local vfs = require("@builtin/modules/api/engine/vfs")
Also available as global: vfs

## modules/vfs/clearPlayShadow {#modules-vfs-clearplayshadow}

```lua
clearPlayShadow(): boolean
```

Forget the entire play-shadow set after a bulk promote or discard.
Tracking only — never touches the bytes.

```lua
vfs.clearPlayShadow()
```

## modules/vfs/copy {#modules-vfs-copy}

```lua
copy(src: string, dst: string): (boolean, string?)
```

Copy a file OR directory from `src` to `dst`, `cp -r` style. A
directory recurses — every descendant is replicated at the same
relative path under `dst`, `.refs` sidecars included. `.meta`
sidecars are minted fresh, so a copy is a distinct asset with its
own identity. Both paths are absolute. The source may live in any
layer (writable, library mount, builtin, runtime-generated); the
destination must be a writable route.

**Parameters**

- `src` `string` — Source absolute VFS path (file or directory).
- `dst` `string` — Destination absolute VFS path.

```lua
vfs.copy("/zero/runtime/recordings/take1.mp4", "/zero/source/clips/take1.mp4")
```

## modules/vfs/currentAuthor {#modules-vfs-currentauthor}

```lua
currentAuthor(): { id: string, name: string? }?
```

The agent this call is attributed to — the author a `/source` write
made right now would be recorded under in the play shadow. Nil when the
call carries no actor identity, which is the case for engine-authored
work and for a caller that presented no token. Compare its `id` against
`vfs.playShadowAuthors()` to separate your own pending edits from a
co-author's.

```lua
local me = vfs.currentAuthor()
print(if me ~= nil then me.id else "unattributed")
```

## modules/vfs/durability {#modules-vfs-durability}

```lua
durability(paths: string | { string }): { durable: boolean, warning: string?, playShadow: string?, shadowed: { string }? }
```

Did that write save to disk, and if not how is it kept? What became of
the bytes just written at `paths` — one path, or an array of them
answered as ONE write. `durable` is true when they are where
the call filed them, and false when the play shadow took any of them: live
in this session, disk source untouched, discarded on a guarded play-exit
unless kept. `durable` is present whatever the answer is, so its absence is
never a reading. A non-durable answer carries `warning` (the state, for a
reader scanning values rather than checking a field), `playShadow` (the
routes to disk and what each costs a session other people are running in)
and `shadowed` (which of the given paths the shadow holds).

This is the answer, off the same shadow set and in the same words, that the
`write_file` / `edit_file` / `capture` tools attach to their own results and
that `asset.create` reports as its second return value. Ask it here at any
other site that lands files, so every write surface states where the bytes
went in one set of terms.

**Parameters**

- `paths` `string | { string }` — One VFS path, or an array of paths answered together as one
write. A path resolves the way `vfs.write` resolves its own — absolute or
`@`-rooted as it stands, a bare one under `/source/` — so the answer is
about the file that write landed. A value that is not a path — an
AssetRef, a record, a number, a string with nothing in it — raises rather
than being answered off the empty set it reads as; a list with no entries
names nothing and answers durable.

```lua
local ok = vfs.write(path, body)
local d = vfs.durability(path)
if not d.durable then log.warn(d.warning .. " " .. d.playShadow) end
```

## modules/vfs/evict {#modules-vfs-evict}

```lua
evict(path: string, opts: VfsOpts?): boolean
```

Drop the in-memory bytes for `path` from the writable
MemFs layer without removing the asset. Use after processing
large binaries to reclaim RAM.

**Parameters**

- `path` `string` — VFS path whose bytes should be evicted.
- `opts` `VfsOpts?` _(optional)_ — `{ root = "/source/" }`.

```lua
vfs.evict("/zero/source/textures/imported_big.png")
```

## modules/vfs/exists {#modules-vfs-exists}

```lua
exists(path: string, opts: VfsOpts?): boolean
```

Is the path known to the VFS? Checks the Stage-1 metadata
(`.meta` sidecar / ManifestView) — NOT "are the bytes locally
cached?". Use `vfs.read(path) ~= nil` to confirm bytes are
reachable.

**Parameters**

- `path` `string` — VFS path to check.
- `opts` `VfsOpts?` _(optional)_ — `{ root = "/source/" }`.

```lua
assert(vfs.exists("@builtin/models/Cube"))
```

## modules/vfs/isDirectory {#modules-vfs-isdirectory}

```lua
isDirectory(path: string, opts: VfsOpts?): boolean
```

Is ONE path a directory? Answers from reality — the writable
layer's children, a resolver-served folder listing, an explicit
empty-directory marker — so a loose file whose extension collides
with an assetType name (`notes.json`) reads as the file it is while
a real `<name>.<type>/` folder reads as a folder. Costs the same
whatever the containing folder holds; use `vfs.list` when you want
every entry's kind, this when you hold one path.

**Parameters**

- `path` `string` — VFS path to classify.
- `opts` `VfsOpts?` _(optional)_ — `{ root = "/source/" }`.

```lua
if vfs.isDirectory("/zero/source/Goblin.dynamicAsset") then print("folder asset") end
```

## modules/vfs/isSaveExcluded {#modules-vfs-issaveexcluded}

```lua
isSaveExcluded(path: string, opts: VfsOpts?): boolean
```

Does this path hold content the machine keeps to itself?
`/source/tmp/` is session scratch and `/source/local/` is this
machine's own durable content — each directory itself included,
and everything under it. Both are writable, hot-reloadable and
enumerable like the rest of `/source/`; what separates them is
where they stop. The engine filters them out of every world save
and every peer broadcast, so they reach no world, carry no
manifest row there, and a staging verb handed one refuses it by
name. The match reads a whole path segment, so
`/source/tmpfoo/` is ordinary content. Ask here whenever your
code has to agree with what a world can hold.

**Parameters**

- `path` `string` — VFS path to classify.
- `opts` `VfsOpts?` _(optional)_ — `{ root = "/source/" }`.

```lua
if not vfs.isSaveExcluded(p) then table.insert(publishable, p) end
```

## modules/vfs/list {#modules-vfs-list}

```lua
list(path: string?): { VfsListEntry }
```

List entries in a VFS directory.

**Parameters**

- `path` `string?` _(optional)_ — Directory path (defaults to `/zero`).

```lua
for _, e in ipairs(vfs.list("/zero/source")) do print(e.name) end
```

## modules/vfs/memResident {#modules-vfs-memresident}

```lua
memResident(): { { path: string, bytes: number, kind: string } }
```

List the MemFs entries that are NOT resident-by-default — the writable
in-memory layer's binary blobs and its large text files (text at or above
the inline-text size threshold). These are the bytes `vfs.evict` can
reclaim: the ones kept in RAM rather than left to fall through to the
on-disk BlobStore cache. Small text (resident by default) is omitted. The
audit counterpart to `vfs.evict` and to reading with `{ keep = true }` —
use it to see what encoded bytes are held in RAM, and why.

```lua
for _, e in ipairs(vfs.memResident()) do print(e.path, e.bytes, e.kind) end
```

## modules/vfs/mkdir {#modules-vfs-mkdir}

```lua
mkdir(path: string, opts: VfsOpts?): boolean
```

Create a directory. `mkdir -p` semantics — idempotent.
Errors if a file already exists at the same path. While play is
running an authored `/source` directory waits for the lock to
lift and the refusal RAISES with the reason; writing a file under
the path creates it as part of that write, and scratch under
`/source/tmp/` creates as in edit mode.

**Parameters**

- `path` `string` — Directory path.
- `opts` `VfsOpts?` _(optional)_ — `{ root = "/source/" }`.

```lua
vfs.mkdir("/zero/source/scenes/")
```

## modules/vfs/move {#modules-vfs-move}

```lua
move(src: string, dst: string, opts: { quiet: boolean? }?): (boolean, string?)
```

Move a file from `src` to `dst`. By default fires the destination's
write side effects; pass `opts.quiet = true` to suppress them.
While play is running a move takes the source away, so authored
`/source` content that predates play is refused and the refusal
RAISES with the reason; content this play session created moves and
stays tracked on the play shadow.

**Parameters**

- `src` `string` — Source absolute VFS path.
- `dst` `string` — Destination absolute VFS path.
- `opts` `{ quiet: boolean? }?` _(optional)_ — Optional `{ quiet: boolean? }`.

```lua
vfs.move("/zero/source/a.luau", "/zero/source/b.luau")
```

## modules/vfs/mutationSeq {#modules-vfs-mutationseq}

```lua
mutationSeq(): number
```

Lifetime count of VFS mutations the engine has APPLIED — the drain's
clock. A write queues its side effects (an asset's content reload, the
assetType's `onChange`, a component or scene registration) and a later
frame runs them; this number advances as each one completes. Read it,
write, then poll for a larger value to learn the queue has moved past the
point you wrote at — instead of waiting a guessed number of frames. It
counts every mutation kind, so it answers about the pipeline rather than
about one file; `asset.reloadSeq(ref)` is the per-asset reading.

```lua
local at = vfs.mutationSeq()
vfs.write("/zero/source/tmp/note.txt", "hi")
repeat task.wait() until vfs.mutationSeq() > at
```

## modules/vfs/pendingWrites {#modules-vfs-pendingwrites}

```lua
pendingWrites(): { string }
```

List the `/source` paths with an in-flight local write the synced
manifest has not reflected yet — the read-your-writes frontier. A
just-written file appears here until its upload round-trips and the
synced dirty state catches up; `world.vcsStatus` unions these so a
fresh edit reads back as dirty immediately. Empty when fully synced.

```lua
for _, p in ipairs(vfs.pendingWrites()) do print(p) end
```

## modules/vfs/playShadowAuthors {#modules-vfs-playshadowauthors}

```lua
playShadowAuthors(): { [string]: { id: string, name: string? } }
```

The agent behind each currently-shadowed `/source` path: the ZeroMind
user id the write was attributed to, and the username to show for it.
Several agents drive one engine at once and every one of their in-play
source edits sits in the same shadow set, so this is how a review, a
refusal or a verdict tells one agent's pending work from another's. A
path written with no actor identity carries no entry — it belongs to no
agent in particular, and stays settleable by any of them.

```lua
local mine = vfs.currentAuthor()
for path, who in pairs(vfs.playShadowAuthors()) do
if mine == nil or who.id ~= mine.id then print(path, "belongs to", who.name) end
end
```

## modules/vfs/playShadowPaths {#modules-vfs-playshadowpaths}

```lua
playShadowPaths(): { string }
```

Every source write made during play that is not durable yet — the set
to keep or discard before leaving play. Lists the `/source` paths edited
during running play that are currently held as copy-on-write SHADOWS
(MemFs-only, on-disk original untouched) — the universal play
shadow-copy set. These are the in-play edits persist
promotes over the originals on confirm, or drops on a guarded discard.
Empty outside play or when nothing was edited.

```lua
for _, p in ipairs(vfs.playShadowPaths()) do print(p) end
```

## modules/vfs/promotePlayShadow {#modules-vfs-promoteplayshadow}

```lua
promotePlayShadow(path: string | { string }): string | { string }
```

KEEP a source write made while play was running — the call that saves
a play-mode edit onto disk and makes it durable. Promotes play-shadow
edits into canonical writes: re-asserts the live overlay bytes through
the full write pipeline, then unmarks each path.
The bytes stay in the engine end to end, so binary content promotes
exactly. It answers while play is RUNNING and leaves the mode, the
clock and every shadow entry it did not name exactly where they stood.
Takes ONE path, or an ARRAY of them — a single folder-asset write
shadows the entry file, the README and the metadata together, so a
slice is tens of paths, and naming them keeps the call to the caller's
own work on an engine other sessions are running in. Every named path
is attempted; one that refuses does not stop the ones after it. A
promotion that cannot happen raises with the reason: the path is not
shadowed, the path is a folder covering shadowed edits, the workspace
is read-only, or the write-through failed. A shadow entry whose bytes
are gone is dropped as promoted, so the path comes back with nothing
written for it.

**Parameters**

- `path` `string | { string }` — A shadowed VFS path to promote, or an array of them (from
vfs.playShadowPaths()).

```lua
local promoted = vfs.promotePlayShadow("/zero/source/cover.jpg")
local mine = {}
for _, p in ipairs(vfs.playShadowPaths()) do
if string.find(p, "/zero/source/mine/", 1, true) == 1 then table.insert(mine, p) end
end
local settled = vfs.promotePlayShadow(mine)
```

## modules/vfs/read {#modules-vfs-read}

```lua
read(path: string, opts: VfsOpts?): string?
```

Read a file from the virtual filesystem. Binary-safe.
Returns file contents as a string, or nil if the file is not
known. Relative paths resolve under `opts.root` (default
`/source/`). When called from a coroutine and the bytes
aren't locally cached, transparently yields the coroutine
while the lazy fetch runs.

**Parameters**

- `path` `string` — VFS path.
- `opts` `VfsOpts?` _(optional)_ — `{ root = "/source/" }`.

```lua
local src = vfs.read("@builtin/components/Camera.luau")
```

## modules/vfs/readAsync {#modules-vfs-readasync}

```lua
readAsync(path: string, opts: VfsOpts?): string
```

Asynchronous binary-safe read. Returns a promise ID that
resolves to the file contents. Useful for reading render
textures from the main thread without blocking.

**Parameters**

- `path` `string` — VFS path.
- `opts` `VfsOpts?` _(optional)_ — `{ root = "/source/" }`.

```lua
local data = task.await(vfs.readAsync("/zero/runtime/screenshots/last.png"))
```

## modules/vfs/reload {#modules-vfs-reload}

```lua
reload(modulePath: string?): boolean
```

Clear entries from the `require()` cache so the next
`require(name)` re-runs the module's source. Pass a single
module identity to drop only that entry; call with no
arguments to drop every cached module.

**Parameters**

- `modulePath` `string?` _(optional)_ — Module identity to reload (omit to reload all).

```lua
vfs.reload("@mylib/utils.helpers")
```

## modules/vfs/remove {#modules-vfs-remove}

```lua
remove(path: string, opts: VfsOpts?): (boolean, string?)
```

Remove a file. Refuses to remove directories unless
`opts.recursive = true`. Refuses protected system roots. While
play is running, authored `/source` content that predates play is
refused and the refusal RAISES with the reason; content this play
session created is removable, a folder included.

**Parameters**

- `path` `string` — VFS path to remove.
- `opts` `VfsOpts?` _(optional)_ — `{ root = "/source/", recursive = false }`.

```lua
vfs.remove("/zero/source/scratch.luau")
```

## modules/vfs/revertPlayShadow {#modules-vfs-revertplayshadow}

```lua
revertPlayShadow(path: string | { string }): string | { string }
```

DISCARD a source write made while play was running, keeping nothing —
the opposite of promoting it. Reverts play-shadow edits: restores the
pre-play copy captured at the
first play-mode write (the last edit-mode state, unstaged edits
included) into the live slot — or remove the file when it did not exist
at that moment — then unmark the path. Hot-reload picks the original
back up, so the running session actually reverts. It answers while play
is RUNNING and takes ONE path or an ARRAY of them, on the same terms as
vfs.promotePlayShadow. A revert that cannot happen raises with the
reason.

**Parameters**

- `path` `string | { string }` — A shadowed VFS path to revert, or an array of them (from
vfs.playShadowPaths()).

```lua
local reverted = vfs.revertPlayShadow("/zero/source/Foo.component/init.luau")
local dropped = vfs.revertPlayShadow({ "/zero/source/a.md", "/zero/source/b.md" })
```

## modules/vfs/unmarkPlayShadow {#modules-vfs-unmarkplayshadow}

```lua
unmarkPlayShadow(path: string): boolean
```

Forget a single play-shadow path after it has been promoted (saved
over source) or discarded. Tracking only — never touches the bytes.

**Parameters**

- `path` `string` — VFS path to unmark.

```lua
vfs.unmarkPlayShadow("/zero/source/Foo.component/init.luau")
```

## modules/vfs/unwatch {#modules-vfs-unwatch}

```lua
unwatch(watcherId: number): boolean
```

Remove a previously registered VFS watcher.

**Parameters**

- `watcherId` `number` — Watcher id returned by `vfs.watch`.

```lua
vfs.unwatch(id)
```

## modules/vfs/watch {#modules-vfs-watch}

```lua
watch(path: string, callback: (string, string) -> ()): number
```

Register a callback that fires when a VFS path is written or
removed. Two match modes: exact, or folder/prefix (key ends with
`/`, and fires for any descendant). The callback runs in the VM
that registered it. Returns a watcher id for `vfs.unwatch`.

**Parameters**

- `path` `string` — Exact path, or folder path ending in `/`.
- `callback` `(string, string) -> ()` — `(mutated_path, kind) -> ()`, kind `"write"` or `"remove"`.

```lua
local id = vfs.watch("/zero/source/", function(path, kind) print(kind, path) end)
```

## modules/vfs/write {#modules-vfs-write}

```lua
write(path: string, content: string, opts: VfsOpts?): (boolean, string?)
```

Write content to a file. Binary-safe. Overwrites existing
files by default — pass `opts.overwrite = false` to refuse to
clobber. While play is running a `/source` write lands on the play
shadow: it succeeds and reads back, live in the session with disk
source untouched, and is discarded on a guarded play-exit unless
accepted. Scratch under `/source/tmp/` writes through untouched.
Pass `opts.durable = true` to say these bytes ARE the source: the
write reaches canonical `/source` with play still running and the
session still in play, hot-reloading the modules and components that
read it, so the edit is observed running in the same play session
with nothing left to promote. A durable write RAISES with the reason
when the bytes cannot become canonical source.

**Parameters**

- `path` `string` — VFS path to write to.
- `content` `string` — File content (binary-safe).
- `opts` `VfsOpts?` _(optional)_ — `{ root = "/source/", overwrite = true, quiet = false, durable = false }`.

```lua
vfs.write("/zero/source/notes.md", body)
vfs.write("/zero/source/game/Vent.component/init.luau", src, { durable = true })
```

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

```lua
require("@builtin/modules/api/engine/video") -- video (also available as global 'video')
```

Video playback — create / play / pause / seek / setRate / setLoop / destroy on render-target-backed video players. Public Luau surface over the `__video` Internal FFI namespace.

Usage: local video = require("@builtin/modules/api/engine/video")
Also available as global: video

## modules/video/create {#modules-video-create}

```lua
create(url: string, options: VideoOptions?): string
```

Create a video player. Returns a texture handle (e.g.
`"video_0"`) usable directly in `material.setTexture()` — its
frames sample like any other texture.

**Parameters**

- `url` `string` — URL or asset path to an MP4 video file.
- `options` `VideoOptions?` _(optional)_ — Playback options: `loop` (default false), `autoplay`
(default false), `rate` (default 1.0).

```lua
local tex = video.create("http://example.com/clip.mp4", { autoplay = true })
```

## modules/video/destroy {#modules-video-destroy}

```lua
destroy(handle: string): boolean
```

Destroy a video player and free the render target and all
resources.

**Parameters**

- `handle` `string` — Video handle from `video.create`.

```lua
video.destroy(rt)
```

## modules/video/getInfo {#modules-video-getinfo}

```lua
getInfo(handle: string): VideoInfo?
```

Get video information and current playback state.

**Parameters**

- `handle` `string` — Video handle.

```lua
local i = video.getInfo(rt); print(i.currentTime, "/", i.duration)
```

## modules/video/pause {#modules-video-pause}

```lua
pause(handle: string): boolean
```

Pause video playback. Can be resumed with `video.play`.

**Parameters**

- `handle` `string` — Video handle.

```lua
video.pause(rt)
```

## modules/video/play {#modules-video-play}

```lua
play(handle: string): boolean
```

Start or resume video playback.

**Parameters**

- `handle` `string` — Video handle from `video.create`.

```lua
video.play(rt)
```

## modules/video/seek {#modules-video-seek}

```lua
seek(handle: string, time: number): boolean
```

Seek to a specific time (seconds) in the video.

**Parameters**

- `handle` `string` — Video handle.
- `time` `number` — Target time in seconds.

```lua
video.seek(rt, 30.5)
```

## modules/video/setLoop {#modules-video-setloop}

```lua
setLoop(handle: string, loop: boolean): boolean
```

Enable or disable looping.

**Parameters**

- `handle` `string` — Video handle.
- `loop` `boolean` — Whether to loop playback.

```lua
video.setLoop(rt, true)
```

## modules/video/setRate {#modules-video-setrate}

```lua
setRate(handle: string, rate: number): boolean
```

Set the playback speed multiplier. 1.0 = normal, 2.0 = double
speed, 0.5 = half speed.

**Parameters**

- `handle` `string` — Video handle.
- `rate` `number` — Playback rate.

```lua
video.setRate(rt, 2.0)
```

## modules/video/stop {#modules-video-stop}

```lua
stop(handle: string): boolean
```

Stop video playback and reset to the beginning.

**Parameters**

- `handle` `string` — Video handle.

```lua
video.stop(rt)
```

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

```lua
require("@builtin/systems/volumetrics/volume") -- volume
```

3D textures as volumes: build one procedurally or from imported voxels, page it into bricks so it costs what it holds, and raymarch it through an entity's transform.

Usage: local volume = require("@builtin/systems/volumetrics/volume")

## modules/volume/Volume:buildSparse {#modules-volume-volume-buildsparse}

```lua
Volume:buildSparse(opts: SparseOpts?)
```

Store this volume as bricks, keeping only the ones holding anything
over `threshold`. What the volume costs on the GPU becomes what it
contains rather than the size of its bounding box, and the page table
built along the way is the grid the raymarcher skips empty space with.
Counting the bricks reads the allocation counter back from the GPU, so
this yields — twice unless `capacity` says how many slots to take;
`refreshSparse` re-pages without waiting on either.

**Parameters**

- `opts` `SparseOpts?` _(optional)_ — See `SparseOpts` — brick size, density threshold, which channel
carries density, and how much slot headroom to leave for a volume that
will grow.

```lua
local stats = v:buildSparse({ brickSize = 8, threshold = 0.01 })
print(stats.residentBytes, stats.denseBytes)
```

## modules/volume/Volume:destroy {#modules-volume-volume-destroy}

```lua
Volume:destroy()
```

Free the GPU resources backing this Volume — the named 3D
texture, any companion occupancy R8 texture, and the brick pool and
page table if the volume is paged. Subsequent operations on the
wrapper return false silently.

```lua
v:destroy()
```

## modules/volume/Volume:readSparseCounts {#modules-volume-volume-readsparsecounts}

```lua
Volume:readSparseCounts(): { [string]: number }
```

Read how many bricks the last paging pass stored and how many found
the pool full. Yields until the counter arrives.

```lua
local counts = v:readSparseCounts()
```

## modules/volume/Volume:refreshSparse {#modules-volume-volume-refreshsparse}

```lua
Volume:refreshSparse(): boolean
```

Re-page this volume from its current contents. Two dispatches and no
wait, so a volume a compute shader rewrites every frame keeps a page
table that matches what it now holds. The brick counts the pass produces
are collected on a later call rather than waited on, so a volume that
grows past its pool reports the overflow — and warns — a frame or two
after the refresh that caused it.

```lua
v:fillCompute(myShader); v:refreshSparse()
```

## modules/volume/Volume:releaseDense {#modules-volume-volume-releasedense}

```lua
Volume:releaseDense(): boolean
```

Free the dense volume, leaving the brick pool as the only copy. The
volume goes on rendering from the pool; re-paging it needs the dense
copy, so this is for a volume that is finished changing.

```lua
v:buildSparse(); v:releaseDense()
```

## modules/volume/Volume:releaseSparse {#modules-volume-volume-releasesparse}

```lua
Volume:releaseSparse(): boolean
```

Free the brick pool and page table, returning the volume to rendering
from its dense texture. The dense copy has to still be there, so a volume
that released it stays paged.

```lua
v:buildSparse(); v:releaseSparse()
```

## modules/volume/Volume:render {#modules-volume-volume-render}

```lua
Volume:render(opts: RenderOpts): string
```

Dispatch the shared compute raymarcher to render this Volume
through the entity's transform AABB. Output goes to a 2D storage
texture (auto-created) — composite from there via a post-process
effect, a material sampler, or another GPU copy.

**Parameters**

- `opts` `RenderOpts` — See `RenderOpts` above.

```lua
v:render({ entity = entity(id), targetWidth = 1280, targetHeight = 720, density = 8.0 })
```

## modules/volume/Volume:sparseStats {#modules-volume-volume-sparsestats}

```lua
Volume:sparseStats(): { [string]: any }
```

What this volume costs on the GPU, and what it would cost dense.

```lua
local s = v:sparseStats(); print(s.residentBytes / s.denseBytes)
```

## modules/volume/box {#modules-volume-box}

```lua
box(opts: { [string]: any })
```

Build a 3D volume filled with a solid-box SDF.

**Parameters**

- `opts` `{ [string]: any }` — `{name, size, color={1,1,1}, format="rgba16f"}`.

```lua
local v = M.box({ name = "cube_volume", size = 64 })
```

## modules/volume/compositeShaderSource {#modules-volume-compositeshadersource}

```lua
compositeShaderSource(): (string, string)
```

WGSL source for the post-process composite that blends the volume
render target over the scene with premultiplied-alpha. Zero-scaffolding:
author only `fragment()`; `vol_rt` is a declared `texture` property. Register
with `postprocess.add(name, src, { properties = {{ name="vol_rt",
type="texture", textureDefault="transparent" }} })` and bind the target via
`postprocess.setTexture(name, "vol_rt", <render-target>)`.

```lua
local src, name = M.compositeShaderSource()
```

## modules/volume/create {#modules-volume-create}

```lua
create(opts: CreateOpts)
```

Allocate a fresh, zero-filled 3D texture and return a Volume
wrapper bound to its name. The volume answers to that name in `M.get`
from here on; building over a name a live volume already holds releases
that volume first, so one volume owns the name and its brick pool.

**Parameters**

- `opts` `CreateOpts` — Creation options; see `CreateOpts`.

```lua
local v = M.create({ name = "cloud", width = 64, height = 64, depth = 64, storage = true })
```

## modules/volume/get {#modules-volume-get}

```lua
get(name: string): any
```

The live volume built under `name`, with everything it knows about
itself: its voxel dimensions, its channel count, its occupancy grid, and
the brick pool it is paged into. Every volume this module builds answers
to its texture name here, so a script or a component that has only the
name renders the volume as it stands — including a paged one, whose
voxels live in the pool rather than under that name.

**Parameters**

- `name` `string` — The texture name the volume was built under.

```lua
local v = M.get("cloud")
if v then v:render({ entity = e }) end
```

## modules/volume/names {#modules-volume-names}

```lua
names(): { string }
```

The names every live volume is registered under, sorted.

```lua
for _, name in ipairs(M.names()) do print(name, M.get(name):sparseStats().residentBytes) end
```

## modules/volume/noise {#modules-volume-noise}

```lua
noise(opts: { [string]: any })
```

Build a 3D volume filled with FBM value-noise. Good base for
procedural clouds, smoke, nebulae.

**Parameters**

- `opts` `{ [string]: any }` — `{name, size=64, scale=4, octaves=4, threshold=0.5, seed=42,
color={1,1,1}, format="rgba16f"}`.

```lua
local cloud = M.noise({ name = "cloud", size = 64, scale = 4, threshold = 0.55 })
```

## modules/volume/raymarchShaderIdentity {#modules-volume-raymarchshaderidentity}

```lua
raymarchShaderIdentity(): string
```

Return the built-in raymarch shader's asset identity. Callers
that want to diff or override the default raymarcher pull source
via `asset.inspect(Volume.raymarchShaderIdentity())` and register
their variant under a different name.

```lua
local src = vfs.read(asset.inspect(M.raymarchShaderIdentity()).source .. "/shader.wgsl")
```

## modules/volume/register {#modules-volume-register}

```lua
register(volume: any): any
```

Publish a wrapped volume under its own texture name, so holders of
the name reach this object rather than building a wrapper of their own.
Volumes this module builds are published as they are created; a wrapper
over a texture another system owns is published by this call.

**Parameters**

- `volume` `any` _(optional)_ — A Volume — the value `M.wrap` or a builder returned.

```lua
M.register(M.wrap({ name = "imported", width = 64, height = 64, depth = 64 }))
```

## modules/volume/releaseTarget {#modules-volume-releasetarget}

```lua
releaseTarget(name: string): boolean
```

Destroy the 2D storage texture a render names as its `target` and
forget the size this module built it at, so the next render builds it
again. A target is created on the first render that names it and shared
by every volume marching into it.

**Parameters**

- `name` `string` — The render-target name, as passed to `Volume:render`.

```lua
M.releaseTarget("scene_volume_rt")
```

## modules/volume/sphere {#modules-volume-sphere}

```lua
sphere(opts: { [string]: any })
```

Build a 3D volume filled with a soft sphere SDF (centred at the
volume's middle).

**Parameters**

- `opts` `{ [string]: any }` — `{name, size, falloffStart=0.3, falloffEnd=0.5, color={1,1,1}, format="rgba16f"}`.

```lua
local v = M.sphere({ name = "blob", size = 64, falloffStart = 0.3 })
```

## modules/volume/unregister {#modules-volume-unregister}

```lua
unregister(name: string): any
```

Drop the registration under `name` and hand back the volume that held
it, leaving its GPU resources alone. The returned volume is the way back
to the data — `destroy` it to free the texture and any brick pool.

**Parameters**

- `name` `string` — The texture name to stop answering for.

```lua
local v = M.unregister("imported")
if v then v:destroy() end
```

## modules/volume/wrap {#modules-volume-wrap}

```lua
wrap(opts: { [string]: any })
```

Wrap an existing named 3D texture as a Volume without creating
a new one. Use when a producer outside this module owns the
texture lifetime (e.g. the `.zvol` viewer uploads voxels through
`compute.writeFloatsTexture3D` and then wraps the result for
rendering).

**Parameters**

- `opts` `{ [string]: any }` — `{name, width?, height?, depth?, format?, occupancyName?, occupancyBrick?}`.

```lua
local v = M.wrap({ name = "imported", format = "rgba16f", occupancyName = "imported_occ", occupancyBrick = 8 })
```

## modules/volume/zvolHeader {#modules-volume-zvolheader}

```lua
zvolHeader(bytes: string): (ZvolHeader?, string?)
```

Read a `.zvol` file's header. The payload it describes uploads
verbatim — `payloadOffset` and `payloadBytes` cut the voxel bytes out of
the same string, and `writeBytes` takes them as they are.

**Parameters**

- `bytes` `string` — The file's contents.

```lua
local h = M.zvolHeader(vfs.read(path))
v:writeBytes(string.sub(bytes, h.payloadOffset, h.payloadOffset + h.payloadBytes - 1))
```

## modules/volumeSequence/README {#modules-volumesequence-readme}

```lua
require("@builtin/systems/volumetrics/volumeSequence") -- volumeSequence
```

An ordered run of `.zvol` frames played back through a fixed ring of resident volumes: frames are read from the VFS a little ahead of the playhead and uploaded into whichever ring slot is furthest from it, so what the sequence costs on the GPU is the ring, whatever the run's length.

Usage: local volumeSequence = require("@builtin/systems/volumetrics/volumeSequence")

## modules/volumeSequence/Sequence:bounds {#modules-volumesequence-sequence-bounds}

```lua
Sequence:bounds(): ({ number }, { number })
```

The world-space bounds frame 1's header declared, as the importer wrote
them.

```lua
local mn, mx = seq:bounds()
```

## modules/volumeSequence/Sequence:close {#modules-volumesequence-sequence-close}

```lua
Sequence:close(): boolean
```

Cancel any read still in flight, free the ring and drop the sequence
from the registry.

```lua
seq:close()
```

## modules/volumeSequence/Sequence:current {#modules-volumesequence-sequence-current}

```lua
Sequence:current()
```

The volume holding the frame currently on screen. Render it the way any
other volume renders — the wrapper it answers with is one of the ring's
slots, so the same handle comes back for as long as that frame is shown.

```lua
local v = seq:current(); if v then v:render({ entity = e, density = 6 }) end
```

## modules/volumeSequence/Sequence:pause {#modules-volumesequence-sequence-pause}

```lua
Sequence:pause(): boolean
```

Hold the playhead where it is. Reads already in flight still land.

```lua
seq:pause()
```

## modules/volumeSequence/Sequence:play {#modules-volumesequence-sequence-play}

```lua
Sequence:play(): boolean
```

Resume advancing the playhead.

```lua
seq:play()
```

## modules/volumeSequence/Sequence:residency {#modules-volumesequence-sequence-residency}

```lua
Sequence:residency(): { { frame: number?, loading: boolean } }
```

What each ring slot holds, in slot order — one entry per slot, whether
or not it has ever been filled. A closed sequence holds no slots and
answers with an empty array.

```lua
for i, slot in ipairs(seq:residency()) do print(i, slot.frame, slot.loading) end
```

## modules/volumeSequence/Sequence:seek {#modules-volumesequence-sequence-seek}

```lua
Sequence:seek(frame: number): number
```

Put the playhead on a frame. The clock moves with it, so playback
resumes from there rather than jumping back.

**Parameters**

- `frame` `number` — 1-based frame index; wrapped for a looping sequence, clamped
otherwise.

```lua
seq:seek(12)
```

## modules/volumeSequence/Sequence:setFps {#modules-volumesequence-sequence-setfps}

```lua
Sequence:setFps(fps: number): number
```

Set the playback rate. The playhead keeps the frame it stands on and
the fraction of the way through it, so playback carries on from there at
the new rate. Zero holds the playhead while leaving `playing` alone.

**Parameters**

- `fps` `number` — Frames per second.

```lua
seq:setFps(12)
```

## modules/volumeSequence/Sequence:stats {#modules-volumesequence-sequence-stats}

```lua
Sequence:stats(): { [string]: any }
```

What the sequence costs and how playback is keeping up. `residentBytes`
counts the ring, `allBytes` counts what holding every frame at once would
cost, `stalls` counts the frames playback reached before their read did,
and `errors` counts the frames of the run that could not be read — each
one counted and logged once, and stepped over from then on.

```lua
local s = seq:stats(); print(s.residentBytes, s.allBytes)
```

## modules/volumeSequence/Sequence:tick {#modules-volumesequence-sequence-tick}

```lua
Sequence:tick(dt: number): number?
```

Advance the playhead by `dt` seconds, start the reads the new position
calls for, and promote the newest frame whose slot has filled. The
playhead moves once per engine frame however many callers tick the
sequence, so two entities can play one run without it running double
speed; every call promotes and reads ahead.

**Parameters**

- `dt` `number` — Seconds since the last call.

```lua
seq:tick(dt)
```

## modules/volumeSequence/all {#modules-volumesequence-all}

```lua
all(): { [string]: any }
```

Every sequence currently open, by name.

```lua
for name, seq in pairs(M.all()) do print(name, seq:stats().residentBytes) end
```

## modules/volumeSequence/close {#modules-volumesequence-close}

```lua
close(name: string): boolean
```

Close the sequence open under this name.

**Parameters**

- `name` `string` — Name passed to `open`.

```lua
M.close("plume")
```

## modules/volumeSequence/get {#modules-volumesequence-get}

```lua
get(name: string)
```

The sequence open under this name.

**Parameters**

- `name` `string` — Name passed to `open`.

```lua
local seq = M.get("plume")
```

## modules/volumeSequence/open {#modules-volumesequence-open}

```lua
open(opts: OpenOpts)
```

Open a run of `.zvol` frames for playback. Frame 1's header sizes the
ring, so every frame of the run has to carry the same dimensions; the ring
itself is `resident` volumes and is the whole GPU cost of the sequence.
Reading frame 1 yields.

**Parameters**

- `opts` `OpenOpts` — See `OpenOpts` — the frame paths, the ring size, and the playback
rate.

```lua
local seq = M.open({ name = "plume", frames = paths, resident = 3, fps = 24 })
seq:tick(dt); local v = seq:current(); if v then v:render({ entity = e }) end
```

## modules/volumetricLighting/README {#modules-volumetriclighting-readme}

```lua
require("@builtin/systems/volumetrics/volumetricLighting") -- volumetricLighting
```

Light scattered by the air between the camera and the scene — a spotlight cone visible in fog, a shaft where the sun cuts past an occluder, haze that brightens toward a source.

Usage: local volumetricLighting = require("@builtin/systems/volumetrics/volumetricLighting")

## modules/volumetricLighting/active {#modules-volumetriclighting-active}

```lua
active(): boolean
```

Whether the volumetric passes are running this frame.

```lua
if volumetricLighting.active() then ... end
```

## modules/volumetricLighting/clear {#modules-volumetriclighting-clear}

```lua
clear()
```

Empty the air and release the passes. The other settings are kept, so a
later `set({ density = ... })` brings back the same medium.

```lua
volumetricLighting.clear()
```

## modules/volumetricLighting/get {#modules-volumetriclighting-get}

```lua
get(): VolumetricState
```

The medium settings currently in force.

```lua
local d = volumetricLighting.get().density
```

## modules/volumetricLighting/paramsBuffer {#modules-volumetriclighting-paramsbuffer}

```lua
paramsBuffer(): any?
```

The buffer the marching passes read. `lightScattering.renderFeature`
binds what this hands it, so both passes carry the values this module
packed.

```lua
local p = volumetricLighting.paramsBuffer()
```

## modules/volumetricLighting/set {#modules-volumetriclighting-set}

```lua
set(opts: VolumetricOpts?): VolumetricState
```

Set the scene's participating medium. Any omitted field keeps its
current value. A `density` of 0 empties the air and releases the passes.

**Parameters**

- `opts` `VolumetricOpts?` _(optional)_ — Medium settings — see `VolumetricOpts`.

```lua
volumetricLighting.set({ density = 0.06, anisotropy = 0.7 })
```

## modules/watch {#modules-watch}

```lua
modules.watch(path, callback) -> number
```

Register a callback that fires when a module's source code changes via VFS write. Use for live-reload: re-require the module inside the callback. Returns a watcher ID.

**Parameters**

- `path` `string` — Module require path to watch (e.g. '@builtin/modules/terminal')
- `callback` `function` — Called with (path) when the module source changes

**Returns** `number` — Watcher ID (pass to modules.unwatch to remove)

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

```lua
require("@builtin/systems/weather/weather") -- weather
```

How surfaces respond to weather — wetness darkens and sharpens, snow settles on what faces up, and anything under cover stays clear.

Usage: local weather = require("@builtin/systems/weather/weather")

## modules/weather/active {#modules-weather-active}

```lua
active(): boolean
```

Whether the weather pass is currently running.

```lua
if weather.active() then print("wet") end
```

## modules/weather/bakeShelter {#modules-weather-bakeshelter}

```lua
bakeShelter(): ShelterField
```

Re-derive the cover field the shelter test reads from the geometry the
renderer currently draws. The field is baked when weather starts and
re-derived when the count of renderables moves; call this after moving or
reshaping cover that left that count where it was.

```lua
weather.bakeShelter()
```

## modules/weather/clear {#modules-weather-clear}

```lua
clear()
```

Clear the weather and release the pass. The other settings are kept, so
a later `set` brings back the same look.

```lua
weather.clear()
```

## modules/weather/coverBuffer {#modules-weather-coverbuffer}

```lua
coverBuffer(): any?
```

The cover field the shelter test reads, as a buffer a pass binds.

```lua
local b = <module>.coverBuffer()
```

## modules/weather/get {#modules-weather-get}

```lua
get(): WeatherState
```

The weather currently in force.

```lua
local w = weather.get().wetness
```

## modules/weather/paramsBuffer {#modules-weather-paramsbuffer}

```lua
paramsBuffer(): any?
```

The parameter buffer this system's passes read. A pass binds what this
hands it, so it has the values this module packed.

```lua
local b = <module>.paramsBuffer()
```

## modules/weather/refresh {#modules-weather-refresh}

```lua
refresh()
```

Re-pack the buffer against the light the scene is standing in now —
its ambient and its sun — and bring the cover field along with the scene.
The pass runs every frame and the scene's lighting moves between frames, so
the sheen follows the light rather than the value it had when the weather
was last set. Writes only when something in the buffer has moved.

```lua
weather.refresh()
```

## modules/weather/set {#modules-weather-set}

```lua
set(opts: WeatherOpts?): WeatherState
```

Set the scene's weather. Any omitted field keeps its current value, so a
call can move one knob without restating the rest. With both `wetness` and
`snow` at 0 nothing is falling and the pass is released.

**Parameters**

- `opts` `WeatherOpts?` _(optional)_ — Weather settings — see `WeatherOpts`.

```lua
weather.set({ wetness = 0.8, snow = 0 })
```

## modules/weather/shelterField {#modules-weather-shelterfield}

```lua
shelterField(): ShelterField
```

Where the cover field the shelter test reads currently stands. A
`resolution` of 0 means no field is baked, and every surface is then open
to the sky.

```lua
print(weather.shelterField().filled, "columns hold a surface")
```

## modules/world_defaults/README {#modules-world-defaults-readme}

```lua
world (global)
```

Grafts the per-world defaults + args + lifecycle-callback registry onto the `world` global. Companion to `world_vcs.module`. Backed by `.world_settings` for the persisted fields; callbacks live in in-process registries. Slot fields exposed on `world.*` (4 per-mode + 1 mode-agnostic): - `avatar_default_edit`  AssetRef<bundle> (tag: playerAvatar) - `avatar_default_play`  AssetRef<bundle> (tag: playerAvatar) - `camera_default_edit`  AssetRef<component> (tag: cameraBehavior) - `camera_default_play`  AssetRef<component> (tag: cameraBehavior) - `startup_scene`        AssetRef<scene> — engine auto-loads this scene at boot when set Per-mode slots are selected by `wld.mode()` at spawner-resolution time (player_spawner / camera_spawner). Worlds that don't care about the split set both halves to the same value. All setters are play-mode-gated: writes target `.world_settings` (a source-VFS file) which is locked in play mode. The gate raises a typed error at the API boundary instead of letting the call hit a downstream "VFS write refused" error. Set `engine.mode = "edit"` first. All bundle-typed setters enforce the slot's required tag (§ 7 of the player-camera-unification plan). Writing a wrongly-tagged ref is refused with a clear message naming the missing tag.
Also available as global: world

## modules/world_defaults/offLoaded {#modules-world-defaults-offloaded}

```lua
offLoaded(handle: number): boolean
```

Stop a callback registered with `world.onLoaded` from running.

**Parameters**

- `handle` `number` — The handle `world.onLoaded` returned.

```lua
world.offLoaded(h)
```

## modules/world_defaults/offSaved {#modules-world-defaults-offsaved}

```lua
offSaved(handle: number): boolean
```

Stop a callback registered with `world.onSaved` from running.

**Parameters**

- `handle` `number` — The handle `world.onSaved` returned.

```lua
world.offSaved(h)
```

## modules/world_defaults/offUnloaded {#modules-world-defaults-offunloaded}

```lua
offUnloaded(handle: number): boolean
```

Stop a callback registered with `world.onUnloaded` from running.

**Parameters**

- `handle` `number` — The handle `world.onUnloaded` returned.

```lua
world.offUnloaded(h)
```

## modules/world_defaults/onLoaded {#modules-world-defaults-onloaded}

```lua
onLoaded(cb: (...any) -> ()): number
```

Register a callback to run after a world finishes loading.

**Parameters**

- `cb` `(...any) -> ()` — Called when the event fires, with whatever the event supplies.

```lua
local h = world.onLoaded(function() log.info("loaded") end)
```

## modules/world_defaults/onSaved {#modules-world-defaults-onsaved}

```lua
onSaved(cb: (...any) -> ()): number
```

Register a callback to run after a world is saved.

**Parameters**

- `cb` `(...any) -> ()` — Called when the event fires, with whatever the event supplies.

```lua
local h = world.onSaved(function() log.info("saved") end)
```

## modules/world_defaults/onUnloaded {#modules-world-defaults-onunloaded}

```lua
onUnloaded(cb: (...any) -> ()): number
```

Register a callback to run after a world is unloaded.

**Parameters**

- `cb` `(...any) -> ()` — Called when the event fires, with whatever the event supplies.

```lua
local h = world.onUnloaded(function() log.info("unloaded") end)
```

## modules/world_status/README {#modules-world-status-readme}

```lua
world_status
```

Composes `world.status()` + `world.status_text()` — a snapshot of world identity, mode, running flag, primary scene, all loaded scenes, and players across all scenes. Pure-Luau (no Rust); uses existing globals: world.guid / world.branch / world.title, engine.mode, layers.active, layers.list, scene proxy's players / camera registries, world.connectedUsers.localUser. Installed onto the `world` global by `world_defaults.module/init.luau` via the world-namespace metatable machinery (see § 4b of the player-camera-unification integration design).

## modules/zerojs.compiler/README {#compiler-readme}

```lua
zerojs.compiler
```

Compiles a JavaScript AST (zerojs.parser) to Luau source that executes against the SAME realm value model as the interpreter (zerojs.runtime). Objects, prototypes, the stdlib, typed arrays and the bridge are shared, so compiled code interoperates with interpreted code and host marshaling with no second value model. Speed comes from eliminating per-node dispatch and environment lookups, plus integer-indexed array fast paths (rt.iget/iset). `compile` returns Luau source; `load` returns a chunk taking the runtime companion `rtc` (built by `makeRtc` from a realm + its global object). A construct outside the covered subset raises "compile bail: <node>" so the caller can fall back to the interpreter for that program.

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

```lua
zui
```

DEPRECATED: Author screens as raw widget trees ({ type, style, props, children }) styled with the engine's CSS-parity `ui.*` surface; read @builtin::examples.ui.* for complete worked screens. This convenience layer predates CSS parity and writes unlike CSS.

## modules/zui/defineWidget {#modules-zui-definewidget}

```lua
defineWidget(name: string, builderFn: (any, any) -> any)
```

Register a custom widget kind. `builderFn(props, children)` is
called at registerScreen / updateScreen time and its return value
is decoded in place — the renderer never sees the custom name.
Validates args locally so misuse fails immediately rather than
silently. Requires the engine `ui` global; off-host execution
raises a clear error.

**Parameters**

- `name` `string` — Non-empty widget name (the value of `{ type = name, ... }`).
- `builderFn` `(any, any) -> any` — `(props, children) -> widget` builder.

```lua
Z.defineWidget("myCard", function(props, children) return ... end)
```

## modules/zui/set {#modules-zui-set}

```lua
set(widgetId: string, key: string, value: any)
```

Per-widget state write. Persists `value` against
`(widgetId, key)` so a Luau-defined widget can own state across
frames without threading it through the app's reactive store.
No-op when the engine `ui.widgetStateSet` global is missing.

**Parameters**

- `widgetId` `string` — The widget instance id.
- `key` `string` — State key within the widget.
- `value` `any` _(optional)_ — New value.

```lua
Z.widgetState.set("toggle:1", "on", true)
```

## modules/zui/unregisterWidget {#modules-zui-unregisterwidget}

```lua
unregisterWidget(name: string)
```

Unregister a previously-defined custom widget. No-op when the
engine `ui` global is absent.

**Parameters**

- `name` `string` — Non-empty widget name.

```lua
Z.unregisterWidget("myCard")
```
