Log inGet started

typed

The typed namespace — the engine's Luau API reference for typed.

The typed namespace — 1371 functions.

typed/builtin//assetTypes/testSuite/shared/Test/afterEach

Test.afterEach(fn: () -> ())

Register an after-each hook on the current suite. Runs after every test body in the suite. Hook errors print a warning rather than aborting Test.run.

typed/builtin//assetTypes/testSuite/shared/Test/beforeEach

Test.beforeEach(fn: () -> ())

Register a before-each hook on the current suite. Runs before every test body in the suite. Hook errors mark the test failed rather than aborting Test.run.

typed/builtin//assetTypes/testSuite/shared/Test/beginWorldBaseline

Test.beginWorldBaseline() -> WorldBaseline

Capture a clean-slate world baseline: snapshot every non-persistent layer (by guid + additive flag) then unload them, so suites can't depend on whatever scene the engine booted with. Persistent layers (e.g. the editor overlay) are left untouched. Yields one frame so the unload cascade drains before the caller starts running tests. Pair with Test.restoreWorldBaseline to put the captured layers back afterwards.

typed/builtin//assetTypes/testSuite/shared/Test/cleanupTmp

Test.cleanupTmp()

Remove the sandbox tmp root and everything in it. Logs a warning if the remove fails but doesn't error.

typed/builtin//assetTypes/testSuite/shared/Test/clear

Test.clear()

Clear all suites and reset stats / leaked-id tracking. Use this to re-run the suite from a clean state (in particular: re-runs in the same execute() batch).

typed/builtin//assetTypes/testSuite/shared/Test/describe

Test.describe(name: string, fn: () -> ()) -> Suite

Define a test suite. Collects tests via Test.it / Test.skip calls inside the supplied function and registers them under name. Per-suite and per-test documentation (overall description + per-test pass condition) is authored as --!desc / --!pass doc-comments above the Test.describe / Test.it calls and extracted statically by the engine's doc parser (zero_scripting::module_docs); it is not passed at runtime.

typed/builtin//assetTypes/testSuite/shared/Test/detectSourcePollution

Test.detectSourcePollution(pre: { [string]: boolean }) -> { string }

Compare the current top-level /zero/source entries against a pre-suite snapshot and return every NEW entry that isn't engine- or runner-managed. A non-empty result means the suite left content at the world root — pollution it must instead sandbox under Test.TMP_ROOT or remove via Test.registerCleanup.

typed/builtin//assetTypes/testSuite/shared/Test/expect

Test.expect(value: any) -> any

Create an expectation builder over a value. Returns a chainable table with matchers like toBe, toBeTruthy, toContain, toMatch, toHaveLength, toBeCloseTo, and a never flip.

typed/builtin//assetTypes/testSuite/shared/Test/generateJsonReport

Test.generateJsonReport(stats: Stats, results: { Result }) -> string

Render the engine test results as a machine-readable JSON document. This is the format the tests toolbox saves for diffing runs (tests.compare). Consumers should index results by (suite, test).

typed/builtin//assetTypes/testSuite/shared/Test/generateMarkdownReport

Test.generateMarkdownReport(stats: Stats, results: { Result }) -> string

Render the engine test results as a Markdown report (the format written to /source/tmp/test_results.md).

typed/builtin//assetTypes/testSuite/shared/Test/getResults

Test.getResults() -> { Result }

Get the detailed result records from the last Test.run.

typed/builtin//assetTypes/testSuite/shared/Test/getStats

Test.getStats() -> Stats

Get the aggregate stats from the last Test.run.

typed/builtin//assetTypes/testSuite/shared/Test/it

Test.it(name: string, fn: (TestContext) -> ()) -> any?

Define a single test within the enclosing describe. The test body receives an optional context t exposing waitFrames, expect, fail, and identifying metadata.

typed/builtin//assetTypes/testSuite/shared/Test/prepareTmp

Test.prepareTmp()

Recreate the sandbox tmp root. Removes any leftover files and creates a fresh empty directory at Test.TMP_ROOT. Safe to call from Test.beforeEach.

typed/builtin//assetTypes/testSuite/shared/Test/registerCleanup

Test.registerCleanup(fn: () -> ()) -> nil

Push a cleanup function onto the current test's auto-teardown list. Drained LIFO after Test.afterEach, on both success and failure paths, so the cleanup fires even when the test body errors out. Use this when a test allocates additional resources (extra layers.load after the initial useScene, temp VFS paths outside the sandbox, registered MCP tools, …) that the standard useScene auto-teardown doesn't cover.

typed/builtin//assetTypes/testSuite/shared/Test/restoreWorldBaseline

Test.restoreWorldBaseline(baseline: WorldBaseline?)

Restore the layers captured by Test.beginWorldBaseline, leaving the engine in the shape it was found. Each layer is reloaded by guid via asset.resolve; the additive flag decides root vs overlay. Per-layer pcall'd so one failed restore doesn't block the rest.

typed/builtin//assetTypes/testSuite/shared/Test/run

Test.run() -> boolean

Run every registered suite. Resets stats, executes each test body inside a pcall so a runtime error marks the test failed rather than aborting the run, snapshots/cleans up leaked entities between tests, and defensively returns the scene to edit mode if a test leaks play mode. On the way out — pass, fail, OR an uncaught framework error — it always tears down the entire sandbox tmp root, so no test artifacts ever outlive the run.

typed/builtin//assetTypes/testSuite/shared/Test/sandbox

Test.sandbox(tag: string?) -> string

Create a fresh, empty sandbox container folder under the current test's tmp dir and return its absolute path. Pass it as an into container path to asset.create / Material.Create (into = { path = Test.sandbox("mats") }) so the new asset is authored under the sync-excluded /source/tmp/tests/... sandbox instead of the world root. The runner sweeps the folder at end-of-test, and the egress filter keeps everything under it out of the bound world's content store — so even hundreds of fixtures never pollute the user's /source tree or block play / push.

typed/builtin//assetTypes/testSuite/shared/Test/skip

Test.skip(name: string, fn: (TestContext) -> ()) -> any?

Define a skipped test. Same shape as Test.it but marked skip = true so the runner counts it under skipped and does not execute the body.

typed/builtin//assetTypes/testSuite/shared/Test/snapshotEntities

Test.snapshotEntities() -> { [any]: boolean }

Snapshot the set of entity ids currently alive. Pair with Test.sweepLeakedEntities to despawn everything spawned after the snapshot — the safety net for entities leaked outside a test body (suite-registration side effects, crashed tests) that the per-test cleanup can't see.

typed/builtin//assetTypes/testSuite/shared/Test/snapshotScreens

Test.snapshotScreens() -> { [string]: boolean }

Snapshot the UI screens currently registered, mapping each name to its current visibility. Pair with Test.sweepLeakedScreens, which unregisters every screen registered after the snapshot AND restores the visibility of the snapshotted screens — the safety net for UI screens a suite mounts and never tears down (which pile up as ghost screens) and for a suite that toggles a pre-existing screen's visibility (e.g. Z.screens.hideAll) and leaves the user's own UI hidden after the run.

typed/builtin//assetTypes/testSuite/shared/Test/snapshotSourceContent

Test.snapshotSourceContent() -> { [string]: boolean }

Snapshot the set of top-level /zero/source entry names that exist before a suite runs. Paired with Test.detectSourcePollution to flag content a suite leaks OUTSIDE its sandbox — world state that would bleed into later suites (and the publish gate). The world-content analogue of Test.snapshotEntities.

typed/builtin//assetTypes/testSuite/shared/Test/sweepLeakedEntities

Test.sweepLeakedEntities(preSnapshot: { [any]: boolean }) -> number

Despawn every entity not present in preSnapshot (from Test.snapshotEntities). Unlocks destroy-locked entities first so even PlayerOwned leaks can be cleaned. Yields one frame so the deferred despawns drain before the next suite snapshots its own baseline.

typed/builtin//assetTypes/testSuite/shared/Test/sweepLeakedScreens

Test.sweepLeakedScreens(preSnapshot: { [string]: boolean }) -> number

Restore the screen set captured by Test.snapshotScreens: unregister every screen registered after the snapshot, and put each snapshotted screen's visibility back to how the run found it. Screens reloaded with a world layer come back in the restore pass, so only screens a suite mounted outside a layer get swept; a suite that hid a pre-existing screen (e.g. via Z.screens.hideAll) gets that screen re-shown so the user's UI doesn't stay blank after a test run. Yields one frame so the changes drain before the caller reads the screen set again.

typed/builtin//assetTypes/testSuite/shared/Test/tmpPath

Test.tmpPath(relativePath: string?) -> string

Build a sandboxed path for a test fixture under the CURRENT test's own folder (TMP_ROOT/<suite>/<test>/...). Every write a test makes should go through this so it lands inside the per-test sandbox the runner cleans up automatically — never at a hand-rolled /source/... path that survives the run and syncs to spacetime. Empty / non-string relativePath returns the test's folder itself. Called outside a running test it falls back to the suite folder, then to TMP_ROOT (see currentTestDir).

typed/builtin//assetTypes/testSuite/shared/Test/useScene

Test.useScene(opts: { fixture: string?, additive: boolean? }?) -> any

typed/builtin//assetTypes/testSuite/shared/Test/useSceneEach

Test.useSceneEach(opts: { fixture: string?, additive: boolean? }?) -> nil

Suite-level sugar for "mint a fresh scene before every test in this suite". Equivalent to writing Test.beforeEach(function() Test.useScene(opts) end) but composable — preserves any beforeEach the suite already registered and adds the useScene call after it.

typed/builtin//assetTypes/testSuite/shared/Test/waitFrames

Test.waitFrames(n: number?)

Wait at least n engine frames before continuing. Yields the running coroutine and returns control after at least n frame boundaries have elapsed. When invoked through a non-yieldable C-call chain the underlying task.wait raises; the runner catches that sentinel and treats the test as SKIPPED for that invocation. Run suites via the tests toolbox (tests.run) — or call Test.run from a yieldable context — to actually exercise the wait paths.

typed/builtin//assetTypes/testSuite/shared/Test/waitUntil

Test.waitUntil(predicate: () -> any, maxFrames: number?) -> boolean

typed/builtin//components/Asset/public/bakeIntoScene

public.bakeIntoScene()

Promote the bundle's spawned children from temporary to permanent scene state and remove the Asset component, "baking" the bundle's contents directly into the owning scene. Subsequent saves persist the baked entities verbatim and stop replaying the bundle template.

typed/builtin//components/Camera/public/capture

public.capture()

Capture a frame from this camera to its current render target. Alias of render() — kept so the verb matches the agent-facing capture toolbox.

typed/builtin//components/Camera/public/lookAt

public.lookAt(target: string | table)

Aim this camera at a world position or another entity.

typed/builtin//components/Camera/public/render

public.render(rtGuid: string?)

Schedule a single-frame render for this camera. Works whether the component is enabled or disabled. Uses the camera's current transform, fov, near/far, and render layers. Pass a render-target guid to render this frame into THAT texture instead of the camera's configured output — the one-shot-target form the capture path uses to read a camera's exact view back without disturbing where it normally renders.

typed/builtin//components/Camera/public/setTargetTexture

public.setTargetTexture(tex: renderer.TextureHandle?)

Point the camera at a GPU texture to render into, or back to the main viewport. Create the texture first with renderer.texture.create({ width, height }) (it owns its own size); the camera only references it — free it with renderer.destroy(handle) when done.

typed/builtin//components/Collider/public/setRadius

public.setRadius(r: number)

Set the radius for sphere or capsule colliders.

typed/builtin//components/Collider/public/setShape

public.setShape(shape: string)

Change the collider's shape. Triggers a full rebuild of the native collider with the new geometry.

typed/builtin//components/Collider/public/setSize

public.setSize(size: table)

Set the box collider's half-extents. Accepts a vector-shaped table — array form ({x, y, z}) or map form ({x =, y =, z =}). When only one axis is provided in array form, the other axes copy that value.

typed/builtin//components/Collider/public/setTrigger

public.setTrigger(trigger: boolean)

Toggle trigger mode. Triggers detect overlaps but do not physically block other bodies.

typed/builtin//components/Humanoid/public/attach

public.attach(point: string, childId: string)

typed/builtin//components/Humanoid/public/bone

public.bone(name: string)

typed/builtin//components/Humanoid/public/socket

public.socket(point: string)

typed/builtin//components/Light/public/setCastsShadows

public.setCastsShadows(b: boolean)

Enable or disable shadow casting. Point lights cast omnidirectional (cube) shadows; spot lights cast a single projected shadow. Capacity is capped per kind — past the cap the light stays lit but unshadowed.

typed/builtin//components/Light/public/setColor

public.setColor(color: table)

Set the light color. Values >1 are auto-scaled from 0..255.

typed/builtin//components/Light/public/setDirection

public.setDirection(dir: table)

Set the direction vector (directional lights only).

typed/builtin//components/Light/public/setIntensity

public.setIntensity(i: number)

Set the light intensity (0..N).

typed/builtin//components/Light/public/setKind

public.setKind(lightKind: string)

Switch the light kind ("point" / "directional" / "ambient").

typed/builtin//components/Light/public/setRadius

public.setRadius(r: number)

Set the radius (point lights only).

typed/builtin//components/Model/public/clearOutline

public.clearOutline()

Remove the outline from this mesh.

typed/builtin//components/Model/public/clearTint

public.clearTint()

Reset the tint so the mesh renders with its original material colour.

typed/builtin//components/Model/public/getMaterialProperty

public.getMaterialProperty(property: string)

Read a property from this Model's material.

typed/builtin//components/Model/public/getMaterialPropertyNames

public.getMaterialPropertyNames()

List all property names available on this Model's material.

typed/builtin//components/Model/public/setMaterialProperty

public.setMaterialProperty(property: string, value: any)

Set a property on this Model's material. Affects every entity sharing the material since material properties are registry-wide.

typed/builtin//components/Model/public/setOutline

public.setOutline(color: table, intensity: number?)

Set the outline colour and intensity for this mesh.

typed/builtin//components/Model/public/setTint

public.setTint(color: table, blend: number?)

Set the mesh tint colour and blend amount.

typed/builtin//components/PlayerNameLabel/public/refresh

public.refresh()

Re-read the owner and rasterise the label. Called by PlayerAvatar when the owning identity or its display name changes.

typed/builtin//components/ProceduralSky/public/applyPreset

public.applyPreset(preset: string)

Apply a named look (clear_day, sunset, sunrise, overcast, night).

typed/builtin//components/ProceduralSky/public/setGroundColor

public.setGroundColor(color: { [any]: number })

Set the ground (below-horizon) colour. Values >1 auto-scale from 0..255.

typed/builtin//components/ProceduralSky/public/setHorizonColor

public.setHorizonColor(color: { [any]: number })

Set the horizon sky colour. Values >1 auto-scale from 0..255.

typed/builtin//components/ProceduralSky/public/setTimeOfDay

public.setTimeOfDay(hours: number)

Set the time of day in hours (0..24). Orients the sun and the day/night gradient.

typed/builtin//components/ProceduralSky/public/setZenithColor

public.setZenithColor(color: { [any]: number })

Set the zenith (straight-up) sky colour. Values >1 auto-scale from 0..255.

typed/builtin//components/SkinnedModel/public/clearOutline

public.clearOutline()

Remove the outline from this mesh.

typed/builtin//components/SkinnedModel/public/clearTint

public.clearTint()

Reset the tint so the mesh renders with its original material colour.

typed/builtin//components/SkinnedModel/public/getMaterialProperty

public.getMaterialProperty(property: string)

Read a property from this model's material.

typed/builtin//components/SkinnedModel/public/getMaterialPropertyNames

public.getMaterialPropertyNames()

List all property names available on this model's material.

typed/builtin//components/SkinnedModel/public/setMaterialProperty

public.setMaterialProperty(property: string, value: any)

Set a property on this model's material. Affects every entity sharing the material since material properties are registry-wide.

typed/builtin//components/SkinnedModel/public/setOutline

public.setOutline(color: table, intensity: number?)

Set the outline colour and intensity for this mesh.

typed/builtin//components/SkinnedModel/public/setTint

public.setTint(color: table, blend: number?)

Set the mesh tint colour and blend amount.

typed/builtin//components/Text3D/public/getSize

public.getSize()

Measure the rasterised text in pixels.

typed/builtin//components/Text3D/public/getText

public.getText()

Read the current text content.

typed/builtin//components/Text3D/public/getWorldSize

public.getWorldSize()

Read the world-space size of the text quad after rasterisation.

typed/builtin//components/Text3D/public/refresh

public.refresh()

Force the text to re-rasterise now.

typed/builtin//components/Text3D/public/setStyle

public.setStyle(options: table)

Update one or more style fields in a single call. Unknown keys are ignored. Each changed field fires the reactive rebuild (position-only for offset/pivot keys, a re-rasterise for styling keys).

typed/builtin//components/Text3D/public/setText

public.setText(content: string)

Replace the displayed text content.

typed/builtin//modules/api/engine/asset/asset/add_tag

asset.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.

typed/builtin//modules/api/engine/asset/asset/categories

asset.categories() -> { string }

List every asset category the engine currently recognises. Use to discover valid type argument values for the rest of asset.*.

typed/builtin//modules/api/engine/asset/asset/containerize

asset.containerize(ref: RefArg, outputName: string) -> string

Copy an asset and every dependency it transitively references into /source/<outputName>.bundle/ with fresh guids. Returns a promise — await(...) it before treating the bundle as ready.

typed/builtin//modules/api/engine/asset/asset/containing

asset.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.

typed/builtin//modules/api/engine/asset/asset/create

asset.create(typeName: string, name: string, opts: { [string]: any }?) -> AssetRef

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.

typed/builtin//modules/api/engine/asset/asset/deps

asset.deps(ref: RefArg, type: string?) -> DepsResult

Return the asset's outbound dependency graph — every other asset recorded as a content dependency of it.

typed/builtin//modules/api/engine/asset/asset/describe

asset.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.

typed/builtin//modules/api/engine/asset/asset/exists

asset.exists(name: string, typeName: string) -> boolean

Whether an asset named name of type typeName exists in the current mode's store (/source in edit, the runtime fork in play). 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).

typed/builtin//modules/api/engine/asset/asset/get_field

asset.get_field(ref: RefArg, key: string) -> any

Read one top-level field from the asset's .metadata.

typed/builtin//modules/api/engine/asset/asset/guid

asset.guid(ref: RefArg, type: string?) -> string

Return the guid for an asset.

typed/builtin//modules/api/engine/asset/asset/has_field

asset.has_field(ref: RefArg, key: string) -> boolean

True when the asset's .metadata carries the named field.

typed/builtin//modules/api/engine/asset/asset/has_tag

asset.has_tag(ref: RefArg, tag: string) -> boolean

True when the asset's .metadata.tags contains tag.

typed/builtin//modules/api/engine/asset/asset/identity

asset.identity(ref: RefArg, type: string?) -> string

Return the canonical identity for an asset.

typed/builtin//modules/api/engine/asset/asset/import

asset.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.

typed/builtin//modules/api/engine/asset/asset/inspect

asset.inspect(ref: RefArg, type: string?) -> InspectRecord

Inspect an asset. Resolves ref, builds the common envelope every asset shares (identity, name, guid, source, typeName, typeDefinitionPath, scope, origin, description, tags), then dispatches to the resolved type's ref.inspect(self) (declared on its behavior.luau) for the type-specific detail. A type with no inspect hook leaves detail nil — the envelope alone. A hook that raises leaves detail nil and sets warning with the error text; asset.inspect itself never raises for a resolved ref.

typed/builtin//modules/api/engine/asset/asset/list

asset.list(type_or_opts: (AssetCategory | ListOpts)?, scope: string?, opts: ListOpts?) -> { AssetRef }

List registered assets as resolved AssetRef handles, optionally filtered by type, VFS path, scope, and .metadata fields. 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. Accepts the table-only call form asset.list({ type = ..., path = ..., scope = ..., fields = ... }); type takes the same values asset.categories() lists, and path narrows to one VFS subtree (the folder and everything under it). The first positional argument is a path when it starts with /, a type otherwise. A key outside type / path / scope / fields raises. category is the older spelling of type; a table setting both raises. 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.

typed/builtin//modules/api/engine/asset/asset/list_field_values

asset.list_field_values(key: string) -> { any }

Distinct values seen for the named field across every asset's .metadata.

typed/builtin//modules/api/engine/asset/asset/list_fields

asset.list_fields() -> { string }

Distinct top-level field keys observed across every asset's .metadata. Useful for tooling discovering custom keys in use.

typed/builtin//modules/api/engine/asset/asset/meta

asset.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.

typed/builtin//modules/api/engine/asset/asset/metadata

asset.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).

typed/builtin//modules/api/engine/asset/asset/preview

asset.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").

typed/builtin//modules/api/engine/asset/asset/ref

asset.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).

typed/builtin//modules/api/engine/asset/asset/remove_field

asset.remove_field(ref: RefArg, key: string)

Remove one top-level field from the asset's .metadata. No-op when the field isn't present.

typed/builtin//modules/api/engine/asset/asset/remove_tag

asset.remove_tag(ref: RefArg, tag: string)

Remove a tag from the asset's .metadata.tags. No-op when the tag isn't present.

typed/builtin//modules/api/engine/asset/asset/resolve

asset.resolve(ref: RefArg, type: string?) -> AssetRef?

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 a bare no-type name is ambiguous across categories (it never silently prefers one category). For a presence check that never raises, use asset.exists(name, type); to handle a possible miss inline, wrap the call in pcall.

typed/builtin//modules/api/engine/asset/asset/set_field

asset.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.

typed/builtin//modules/api/engine/asset/asset/set_metadata

asset.set_metadata(ref: RefArg, data: AssetMeta)

Replace the asset's .metadata sidecar with the given table. Pass an empty table to clear all fields.

typed/builtin//modules/api/engine/asset/asset/source

asset.source(ref: RefArg, type: string?) -> string

Return the VFS source path for an asset.

typed/builtin//modules/api/engine/asset/asset/tags

asset.tags(ref: RefArg) -> { string }

Convenience read of the .metadata.tags array.

typed/builtin//modules/api/engine/asset/asset/typeRef

asset.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.

typed/builtin//modules/api/engine/asset/asset/validate

asset.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.

typed/builtin//modules/api/engine/asset/asset/warmup

asset.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).

typed/builtin//modules/api/engine/audio/audio/decode

audio.decode(zaud: string) -> (string?, number?, number?)

Decode a ZAUD payload into interleaved f32 PCM.

typed/builtin//modules/api/engine/audio/audio/encode

audio.encode(sourceBytes: string, opts: { [string]: any }?) -> (string?, string?)

Encode container audio bytes (ogg / mp3 / wav / flac) into a ZAUD payload.

typed/builtin//modules/api/engine/audio/audio/encodePcm

audio.encodePcm(pcm: any, sampleRate: number, channels: number, opts: { [string]: any }?) -> (string?, string?)

Encode raw interleaved f32 PCM into a ZAUD payload.

typed/builtin//modules/api/engine/audio/audio/info

audio.info(zaud: string) -> (AudioInfo?, string?)

Read a ZAUD payload's header without decoding the audio.

typed/builtin//modules/api/engine/av/av/is_live

av.is_live() -> boolean

True if a live-stream session is currently active.

typed/builtin//modules/api/engine/av/av/is_recording

av.is_recording() -> boolean

True if a recording session is currently active.

typed/builtin//modules/api/engine/av/av/live

av.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.

typed/builtin//modules/api/engine/av/av/record

av.record(path: string, opts: RecordOpts?) -> string

Start recording the engine output to a VFS path. Default dir is /zero/runtime/recordings/ when path is not absolute. With no chroma/range opts the format defaults to full-range 4:4:4 HEVC where the GPU supports it, else 4:2:0 limited. Returns a promise handle — use task.await() for the final result.

typed/builtin//modules/api/engine/av/av/status

av.status() -> AvStatus

Report the encoder subsystem's state. Always available regardless of GPU support. Returns { supported, reason, backend, live, recording }backend is the hardware encode backend in use ("vulkan" or "vaapi") when supported.

typed/builtin//modules/api/engine/av/av/stop_live

av.stop_live() -> boolean

Stop any active live-stream session.

typed/builtin//modules/api/engine/av/av/stop_recording

av.stop_recording(handle: string?) -> boolean

Stop the active recording (or the one for the given promise handle). The promise resolves with the final result once stop completes.

typed/builtin//modules/api/engine/base64/base64/decode

base64.decode(text: string) -> (string?, string?)

Decode standard-alphabet base64 text back to the original binary string.

typed/builtin//modules/api/engine/base64/base64/encode

base64.encode(bytes: string) -> string

Encode a binary string to standard-alphabet (padded) base64 text.

typed/builtin//modules/api/engine/blend/blend/destroyLayout

blend.destroyLayout(handle: number) -> boolean

Drop the layout from the registry.

typed/builtin//modules/api/engine/blend/blend/layout

blend.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.

typed/builtin//modules/api/engine/blend/blend/lerpInto

blend.lerpInto(outBuffer: number, layout: number, aBuffer: number, bBuffer: number, 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.

typed/builtin//modules/api/engine/blend/blend/weightedInto

blend.weightedInto(outBuffer: number, 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.

typed/builtin//modules/api/engine/camera/camera/active

camera.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.

typed/builtin//modules/api/engine/camera/camera/editor

camera.editor() -> string?

Entity id of the editor fly-camera (the EditorOnly authoring camera), or nil if the scene has none.

typed/builtin//modules/api/engine/camera/camera/main

camera.main() -> string?

Entity id of the main scene camera — the highest-priority active camera that is NOT the editor fly-camera. 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. For the camera currently drawn on screen, use camera.active().

typed/builtin//modules/api/engine/camera/camera/viewData

camera.viewData() -> CameraView?

The active viewport camera's render data this frame: world position, vertical FOV, 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.

typed/builtin//modules/api/engine/channel/channel/create

channel.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.

typed/builtin//modules/api/engine/channel/channel/destroy

channel.destroy(handle: number) -> boolean

Drop the channel from the registry.

typed/builtin//modules/api/engine/channel/channel/sampleInto

channel.sampleInto(ch: number, time: number, buf: number, offset: number) -> boolean

Sample the channel at time and write stride floats into the Buffer's data starting at f32 index offset. Returns false on unknown handle, layout mismatch, or out-of-bounds; the buffer is unchanged on failure.

typed/builtin//modules/api/engine/channel/channel/sampleManyInto

channel.sampleManyInto(ch: number, time: number, buf: number, 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.

typed/builtin//modules/api/engine/channel/channel/sampleQuat

channel.sampleQuat(ch: number, time: number) -> (number?, number?, number?, number?)

Convenience accessor for stride-4 quaternion channels.

typed/builtin//modules/api/engine/channel/channel/sampleVec3

channel.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.

typed/builtin//modules/api/engine/color/color/complementary

color.complementary(c: Color) -> Color

Complementary color — rotate hue 180° in Oklch space.

typed/builtin//modules/api/engine/color/color/darken

color.darken(c: Color, amount: number) -> Color

Decrease the lightness of a color in Oklch perceptual space.

typed/builtin//modules/api/engine/color/color/desaturate

color.desaturate(c: Color, amount: number) -> Color

Decrease the chroma (saturation) of a color in Oklch space.

typed/builtin//modules/api/engine/color/color/hex

color.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.

typed/builtin//modules/api/engine/color/color/hsl

color.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.

typed/builtin//modules/api/engine/color/color/hsla

color.hsla(h: number, s: number, l: number, a: number) -> Color

Build a color from HSLA, returned as sRGB.

typed/builtin//modules/api/engine/color/color/hsv

color.hsv(h: number, s: number, v: number) -> Color

Build a color from HSV (h: 0-360, s: 0-1, v: 0-1).

typed/builtin//modules/api/engine/color/color/lighten

color.lighten(c: Color, amount: number) -> Color

Increase the lightness of a color in Oklch perceptual space.

typed/builtin//modules/api/engine/color/color/linear

color.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.

typed/builtin//modules/api/engine/color/color/mix

color.mix(c1: Color, c2: Color, t: number) -> Color

Perceptually blend two colors in Oklch space — better than RGB mixing for gradients.

typed/builtin//modules/api/engine/color/color/mixRgb

color.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.

typed/builtin//modules/api/engine/color/color/oklch

color.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.

typed/builtin//modules/api/engine/color/color/rgb

color.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.

typed/builtin//modules/api/engine/color/color/rgba

color.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.

typed/builtin//modules/api/engine/color/color/rotateHue

color.rotateHue(c: Color, degrees: number) -> Color

Rotate the hue of a color by a given number of degrees in Oklch space.

typed/builtin//modules/api/engine/color/color/saturate

color.saturate(c: Color, amount: number) -> Color

Increase the chroma (saturation) of a color in Oklch space.

typed/builtin//modules/api/engine/color/color/toHex

color.toHex(c: Color) -> string

Convert a color to a hex string. Returns "#rrggbb" or "#rrggbbaa" if alpha is not 1.

typed/builtin//modules/api/engine/color/color/toHsl

color.toHsl(c: Color) -> HslColor

Convert a color to HSL.

typed/builtin//modules/api/engine/color/color/toLinear

color.toLinear(c: Color) -> Color

Convert a color from sRGB to linear RGB space — useful for GPU calculations that need linear-space values.

typed/builtin//modules/api/engine/color/color/toOklch

color.toOklch(c: Color) -> OklchColor

Convert a color to Oklch perceptual color space.

typed/builtin//modules/api/engine/color/color/withAlpha

color.withAlpha(c: Color, a: number) -> Color

Return a copy of a color with a different alpha value.

typed/builtin//modules/api/engine/compute/compute/compile

compute.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.

typed/builtin//modules/api/engine/compute/compute/compileByName

compute.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).

typed/builtin//modules/api/engine/compute/compute/createBuffer

compute.createBuffer(name: string, opts: BufferOpts) -> boolean

Create a named GPU storage buffer.

typed/builtin//modules/api/engine/compute/compute/createSampler

compute.createSampler(name: string, opts: { [string]: any }?) -> boolean

Create a named GPU sampler. opts: filter/wrap settings.

typed/builtin//modules/api/engine/compute/compute/createStorageTexture2D

compute.createStorageTexture2D(name: string, opts: { [string]: any }) -> boolean

Create a 2D storage texture (compute-writable render target). opts: { width, height, format? }.

typed/builtin//modules/api/engine/compute/compute/createTexture3D

compute.createTexture3D(name: string, opts: { [string]: any }) -> boolean

Create a 3D texture volume. opts: { width, height, depth, format?, storage? }.

typed/builtin//modules/api/engine/compute/compute/createTextureHistory

compute.createTextureHistory(name: string, opts: { [string]: any }) -> boolean

Create a temporal history buffer (ping-pong textures) for a target. opts: { width, height, format? }.

typed/builtin//modules/api/engine/compute/compute/destroyBuffer

compute.destroyBuffer(name: string) -> boolean

Destroy a named GPU compute buffer and free its memory.

typed/builtin//modules/api/engine/compute/compute/destroyShader

compute.destroyShader(name: string) -> boolean

Destroy a named compute shader pipeline.

typed/builtin//modules/api/engine/compute/compute/destroyShaderEx

compute.destroyShaderEx(name: string) -> boolean

Destroy a shader registered via registerShaderEx.

typed/builtin//modules/api/engine/compute/compute/destroyStorageTexture2D

compute.destroyStorageTexture2D(name: string) -> boolean

Destroy a named 2D storage texture.

typed/builtin//modules/api/engine/compute/compute/destroyTexture3D

compute.destroyTexture3D(name: string) -> boolean

Destroy a named 3D volume and free its GPU memory.

typed/builtin//modules/api/engine/compute/compute/destroyTextureHistory

compute.destroyTextureHistory(name: string) -> boolean

Destroy a named texture-history buffer.

typed/builtin//modules/api/engine/compute/compute/dispatch

compute.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().

typed/builtin//modules/api/engine/compute/compute/dispatchEx

compute.dispatchEx(shaderNameOrHandle: string | { [string]: any } | AssetRef, opts: { [string]: any }) -> boolean

Dispatch a compute shader with extended texture/storage/sampler bindings. Asset-backed .computeShaders resolve to their stable guid (collision-safe, lazily compiled on first dispatch); raw registerShaderEx names pass through.

typed/builtin//modules/api/engine/compute/compute/dispatchOnVertices

compute.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.

typed/builtin//modules/api/engine/compute/compute/getReadbackResult

compute.getReadbackResult(resultKey: string) -> { number }?

Poll for a completed read-back. Returns array of f32 values if ready, nil if pending. Result is consumed on retrieval.

typed/builtin//modules/api/engine/compute/compute/getReadbackResultU32

compute.getReadbackResultU32(resultKey: string) -> { number }?

Poll for a completed read-back interpreting bytes as u32. Returns array of integer values if ready, nil if pending.

typed/builtin//modules/api/engine/compute/compute/isReadbackReady

compute.isReadbackReady(resultKey: string) -> boolean

Check if a readback result is available without consuming it.

typed/builtin//modules/api/engine/compute/compute/readBuffer

compute.readBuffer(bufferName: string) -> string

Start an async GPU→CPU read-back of a named buffer. The buffer must have been created with readback = true. Returns a result key to poll with getReadbackResult().

typed/builtin//modules/api/engine/compute/compute/readTexture3D

compute.readTexture3D(name: string) -> string

Start a GPU→CPU readback of a named 3D volume. Returns a result key to poll.

typed/builtin//modules/api/engine/compute/compute/registerShader

compute.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.

typed/builtin//modules/api/engine/compute/compute/registerShaderEx

compute.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.

typed/builtin//modules/api/engine/compute/compute/setParam

compute.setParam(name: string, 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.

typed/builtin//modules/api/engine/compute/compute/textureFormatBytes

compute.textureFormatBytes(format: string) -> number

Bytes-per-voxel for a texture format string (rgba16f, r8, ...).

typed/builtin//modules/api/engine/compute/compute/writeBuffer

compute.writeBuffer(name: string, data: { number }, offset: number?) -> boolean

Write an array of floats to a named GPU buffer (little- endian f32 bytes).

typed/builtin//modules/api/engine/compute/compute/writeBufferBytes

compute.writeBufferBytes(name: string, bytes: string, offset: number?) -> boolean

Write the raw bytes of a binary string to a named GPU buffer, verbatim. For packed binary that already matches a GPU layout (decoded vertex / index / record pools, file bytes, a network message) — no number-array round trip, unlike writeBuffer / writeBufferU32 which reinterpret each element as one f32 / u32.

typed/builtin//modules/api/engine/compute/compute/writeBufferU32

compute.writeBufferU32(name: string, data: { number }, offset: number?) -> boolean

Write an array of unsigned integers to a named GPU buffer (little-endian u32 bytes).

typed/builtin//modules/api/engine/compute/compute/writeFloatsTexture3D

compute.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).

typed/builtin//modules/api/engine/compute/compute/writeTexture3D

compute.writeTexture3D(name: string, data: { number }) -> boolean

Upload raw bytes (u8) into a named 3D volume.

typed/builtin//modules/api/engine/debugger/debugger/__diagnostics

debugger.__diagnostics() -> DebuggerDiagnostics

Internal diagnostic counters for debugging the debugger itself: { installs, debugbreakHits }.

typed/builtin//modules/api/engine/debugger/debugger/addWatch

debugger.addWatch(expr: string) -> number

Register an expression to re-evaluate on every pause.

typed/builtin//modules/api/engine/debugger/debugger/continue_

debugger.continue_() -> boolean

Resume the paused thread.

typed/builtin//modules/api/engine/debugger/debugger/disableAll

debugger.disableAll()

Disable every registered breakpoint. Records persist; bytecode BREAK ops are cleared.

typed/builtin//modules/api/engine/debugger/debugger/disconnect

debugger.disconnect(handle: number) -> boolean

Disconnect an onBreak or onResume callback.

typed/builtin//modules/api/engine/debugger/debugger/enableAll

debugger.enableAll()

Enable every registered breakpoint and re-install them in the VM bytecode.

typed/builtin//modules/api/engine/debugger/debugger/evaluate

debugger.evaluate(expr: string, frame: number?) -> (string?, string?)

Evaluate an expression against the paused frame's environment. Returns (value, error).

typed/builtin//modules/api/engine/debugger/debugger/getLocals

debugger.getLocals(frame: number?) -> { [string]: string }

Locals captured at the active pause for the given frame index (1 = top). Values are stringified for safe display.

typed/builtin//modules/api/engine/debugger/debugger/getPauseInfo

debugger.getPauseInfo() -> PauseInfo?

Info about the active pause, or nil if nothing is paused.

typed/builtin//modules/api/engine/debugger/debugger/getStack

debugger.getStack() -> { Frame }

Captured stack from the active pause, top frame first. Empty when nothing is paused.

typed/builtin//modules/api/engine/debugger/debugger/getUpvalues

debugger.getUpvalues(frame: number?) -> { [string]: string }

Upvalues captured at the active pause for the given frame.

typed/builtin//modules/api/engine/debugger/debugger/getWatchValue

debugger.getWatchValue(id: number) -> (string?, string?)

Re-evaluate the watch expression against the paused frame's environment and return (value, error).

typed/builtin//modules/api/engine/debugger/debugger/getWatches

debugger.getWatches() -> { Watch }

Snapshot of all watches with their last evaluated value and error, sorted by id.

typed/builtin//modules/api/engine/debugger/debugger/isPauseOnError

debugger.isPauseOnError() -> boolean

Current pause-on-error toggle state for this VM.

typed/builtin//modules/api/engine/debugger/debugger/isPaused

debugger.isPaused() -> boolean

Whether the debugger currently has a paused thread.

typed/builtin//modules/api/engine/debugger/debugger/listBreakpoints

debugger.listBreakpoints() -> { Breakpoint }

Snapshot of every registered breakpoint, sorted by id ascending.

typed/builtin//modules/api/engine/debugger/debugger/onBreak

debugger.onBreak(fn: (PauseInfo) -> ()) -> number

Register a callback invoked on every pause with { path, line, reason }. Returns a handle usable with debugger.disconnect.

typed/builtin//modules/api/engine/debugger/debugger/onResume

debugger.onResume(fn: () -> ()) -> number

Register a callback invoked when the paused thread is resumed.

typed/builtin//modules/api/engine/debugger/debugger/removeBreakpoint

debugger.removeBreakpoint(id: number) -> boolean

Remove the breakpoint with the given id.

typed/builtin//modules/api/engine/debugger/debugger/removeWatch

debugger.removeWatch(id: number) -> boolean

Remove the watch with the given id.

typed/builtin//modules/api/engine/debugger/debugger/setBreakpoint

debugger.setBreakpoint(path: string, line: number, opts: BreakpointOpts?) -> Breakpoint

Set a breakpoint at line in the script at VFS path.

typed/builtin//modules/api/engine/debugger/debugger/setPauseOnError

debugger.setPauseOnError(enabled: boolean)

When true, uncaught Luau errors fire the onBreak callback (observation only — the error still propagates).

typed/builtin//modules/api/engine/debugger/debugger/stepInto

debugger.stepInto() -> boolean

Run until the next line, descending into any function call.

typed/builtin//modules/api/engine/debugger/debugger/stepOut

debugger.stepOut() -> boolean

Run until the current frame returns; pauses in the caller.

typed/builtin//modules/api/engine/debugger/debugger/stepOver

debugger.stepOver() -> boolean

Run until the next line in the current frame. Calls inside the current line are skipped.

typed/builtin//modules/api/engine/debugger/debugger/toggleBreakpoint

debugger.toggleBreakpoint(path: string, line: number) -> Breakpoint?

Toggle a breakpoint at the given line: removes if present, adds otherwise.

typed/builtin//modules/api/engine/ecs/blobs/blobs/clear

blobs.clear(handle: string)

Drop a staged payload that will not be consumed, freeing its memory.

typed/builtin//modules/api/engine/ecs/blobs/blobs/get

blobs.get(handle: string) -> string?

Read back a copy of the bytes staged under handle without removing them. Returns nil for an unknown or already-cleared handle.

typed/builtin//modules/api/engine/ecs/blobs/blobs/set

blobs.set(bytes: string) -> string

Stage binary bytes and return a handle to pass through a component field; a native consumer reads the bytes back by that handle.

typed/builtin//modules/api/engine/egress/egress/clearCredential

egress.clearCredential(name: string) -> boolean

TRUSTED ONLY. Remove a named credential.

typed/builtin//modules/api/engine/egress/egress/credentialNames

egress.credentialNames() -> { string }

List the names of configured credentials. Names only — secret values are never exposed to Luau.

typed/builtin//modules/api/engine/egress/egress/fetch

egress.fetch(name: string, method: string, url: string, headers: Headers?, body: JsonBody?, response: EgressResponseType?) -> 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.

typed/builtin//modules/api/engine/egress/egress/hasCredential

egress.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.

typed/builtin//modules/api/engine/egress/egress/setCredential

egress.setCredential(name: string, base_url: string, header_name: string, header_value: string) -> boolean

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.

typed/builtin//modules/api/engine/engine/M/offWorldLoaded

M.offWorldLoaded(id: number) -> boolean

Remove an onWorldLoaded subscriber by its watcher id.

typed/builtin//modules/api/engine/engine/M/onModeChange

M.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.

typed/builtin//modules/api/engine/engine/M/onPauseChange

M.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.

typed/builtin//modules/api/engine/engine/M/onWorldLoaded

M.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.

typed/builtin//modules/api/engine/engine/M/onWorldReady

M.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.

typed/builtin//modules/api/engine/engine/M/onWorldUnloading

M.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.

typed/builtin//modules/api/engine/environment/environment/capture

environment.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.

typed/builtin//modules/api/engine/environment/environment/captureSlot

environment.captureSlot(slot: number, x: number, y: number, z: number) -> boolean

Bake the scene into reflection-probe slot (cube-array index) 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.

typed/builtin//modules/api/engine/environment/environment/captureSlotToAsset

environment.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.

typed/builtin//modules/api/engine/environment/environment/captureToAsset

environment.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.

typed/builtin//modules/api/engine/environment/environment/loadFromAsset

environment.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).

typed/builtin//modules/api/engine/environment/environment/loadSlotFromAsset

environment.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.

typed/builtin//modules/api/engine/environment/environment/setProbes

environment.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 maps to cube slot i. Surfaces blend the probe slots by proximity to these positions, so objects reflect the nearest probe(s). Queued for next frame.

typed/builtin//modules/api/engine/font/font/glyph

font.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).

typed/builtin//modules/api/engine/font/font/list

font.list() -> { string }

List every registered font family name.

typed/builtin//modules/api/engine/font/font/parse

font.parse(bytes: 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.

typed/builtin//modules/api/engine/font/font/register

font.register(name: string, zfnt: string) -> 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.

typed/builtin//modules/api/engine/font/font/textMesh

font.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).

typed/builtin//modules/api/engine/http/http/get_bytes

http.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.

typed/builtin//modules/api/engine/http/http/get_json

http.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.

typed/builtin//modules/api/engine/http/http/post_bytes

http.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).

typed/builtin//modules/api/engine/http/http/post_json

http.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.

typed/builtin//modules/api/engine/http/http/request

http.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.

typed/builtin//modules/api/engine/http/http/request_raw

http.request_raw(method: string, url: string, headers: Headers?, body: string?) -> 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.

typed/builtin//modules/api/engine/layers/M/find

M.find(ref: AssetRef<scene> | string) -> any?

typed/builtin//modules/api/engine/layers/M/fireBeforeLoad

M.fireBeforeLoad(proxy: any) -> nil

typed/builtin//modules/api/engine/layers/M/fireLoad

M.fireLoad(proxy: any) -> nil

typed/builtin//modules/api/engine/layers/M/fireUnload

M.fireUnload(proxy: any) -> nil

typed/builtin//modules/api/engine/layers/M/install

M.install() -> nil

typed/builtin//modules/api/engine/layers/M/is_loaded

M.is_loaded(ref: AssetRef<scene> | string) -> boolean

typed/builtin//modules/api/engine/layers/M/list

M.list() -> { any }

typed/builtin//modules/api/engine/layers/M/load

M.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.

typed/builtin//modules/api/engine/layers/M/loadInFlight

M.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.

typed/builtin//modules/api/engine/layers/M/offBeforeLoad

M.offBeforeLoad(h: number) -> boolean

typed/builtin//modules/api/engine/layers/M/offLoad

M.offLoad(h: number) -> boolean

typed/builtin//modules/api/engine/layers/M/offUnload

M.offUnload(h: number) -> boolean

typed/builtin//modules/api/engine/layers/M/onBeforeLoad

M.onBeforeLoad(cb: (any) -> ()) -> number

typed/builtin//modules/api/engine/layers/M/onLoad

M.onLoad(cb: (any) -> ()) -> number

typed/builtin//modules/api/engine/layers/M/onUnload

M.onUnload(cb: (any) -> ()) -> number

typed/builtin//modules/api/engine/layers/M/reload

M.reload(ref: (AssetRef<scene> | string)?) -> any?

typed/builtin//modules/api/engine/layers/M/unload

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

typed/builtin//modules/api/engine/library/library/has

library.has(path: string) -> boolean

Check if a library asset exists at the given path.

typed/builtin//modules/api/engine/library/library/import

library.import(namespace: string, worldName: string)

Import a saved world as a library. The world directory at data/worlds/<worldName>/ is loaded and registered under the given namespace. After import, all files in the world are accessible via require('@namespace/path') and visible at /zero/source/libs/@namespace/.

typed/builtin//modules/api/engine/library/library/list

library.list(assetType: string?) -> { LibraryAsset }

List all available library assets. Optionally filter by asset type — call asset.categories() for the live set.

typed/builtin//modules/api/engine/logs/logs/clear

logs.clear() -> boolean

Drop all buffered log entries. Lifetime per-level counts (logs.count) are preserved.

typed/builtin//modules/api/engine/logs/logs/count

logs.count() -> 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.

typed/builtin//modules/api/engine/logs/logs/errors

logs.errors(limit: number?) -> { LogEntry }

Most-recent ERROR-level entries (newest first). limit defaults to 100.

typed/builtin//modules/api/engine/logs/logs/find

logs.find(text: string, limit: number?) -> { LogEntry }

Case-insensitive substring search over log messages. limit defaults to 200 (keeps the most recent matches).

typed/builtin//modules/api/engine/logs/logs/query

logs.query(opts: LogQueryOpts?) -> { LogEntry }

Query the engine's in-memory log ring. The live alternative to grepping data/logs/engine-<port>.log.

typed/builtin//modules/api/engine/logs/logs/tail

logs.tail(limit: number?) -> { LogEntry }

Most-recent entries of any level in chronological order. limit defaults to 100.

typed/builtin//modules/api/engine/logs/logs/warnings

logs.warnings(limit: number?) -> { LogEntry }

Most-recent WARN+ entries (newest first). limit defaults to 100.

typed/builtin//modules/api/engine/lsp/lsp/check

lsp.check(path: string, opts: CheckOpts?) -> { Diagnostic }

Validate a single .luau file in the VFS and return its diagnostics.

typed/builtin//modules/api/engine/lsp/lsp/checkAll

lsp.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.

typed/builtin//modules/api/engine/lsp/lsp/checkCode

lsp.checkCode(source: string, opts: CheckOpts?) -> { Diagnostic }

Validate inline Luau source without a backing file. Useful for checking code before writing it to disk.

typed/builtin//modules/api/engine/lsp/lsp/checkDirty

lsp.checkDirty() -> { Diagnostic }

Drain the dirty-file set populated by the hot-reload hook, validate each, and return the combined diagnostic list.

typed/builtin//modules/api/engine/lsp/lsp/describe

lsp.describe(path: string) -> DocEntry?

Inspect a single documented entry. Returns the full doc table (signature, args, returns, examples, level), or nil.

typed/builtin//modules/api/engine/lsp/lsp/describeTool

lsp.describeTool(path: string) -> string?

Return the full documentation text for a code-mode tool.

typed/builtin//modules/api/engine/lsp/lsp/docsByKind

lsp.docsByKind(kind: string) -> { MethodSummary }

List every doc whose registration kind matches kind. Valid: "binding", "runtime_tool", "module", "component", "library", "lua_export".

typed/builtin//modules/api/engine/lsp/lsp/getStrictMode

lsp.getStrictMode() -> StrictMode

Return the current strict mode.

typed/builtin//modules/api/engine/lsp/lsp/isStrict

lsp.isStrict() -> boolean

Is the pre-execute LSP gate fully strict? False when off or in soft mode.

typed/builtin//modules/api/engine/lsp/lsp/lastCheckGen

lsp.lastCheckGen() -> number

Generation counter — bumped each time the cache is rebuilt. UI polls this to know when to redraw.

typed/builtin//modules/api/engine/lsp/lsp/methods

lsp.methods(namespace: string) -> { MethodSummary }

List every documented method / entry under a namespace.

typed/builtin//modules/api/engine/lsp/lsp/modules

lsp.modules() -> { ModuleEntry }

List every Luau library module the engine currently knows about — discovered via --!module headers, library scans, and manually-recorded docs.

typed/builtin//modules/api/engine/lsp/lsp/namespaces

lsp.namespaces() -> { NamespaceEntry }

List every top-level documentation namespace the engine knows about — FFI bindings, library / prelude modules, component contexts, Luau builtins, globals.

typed/builtin//modules/api/engine/lsp/lsp/readDirectives

lsp.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.

lsp.search(query: string, opts: SearchOpts?) -> { MethodSummary }

Case-insensitive substring search across every registered doc's path, signature, and description.

typed/builtin//modules/api/engine/lsp/lsp/setStrict

lsp.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.

typed/builtin//modules/api/engine/lsp/lsp/setStrictMode

lsp.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.

typed/builtin//modules/api/engine/lsp/lsp/summary

lsp.summary() -> Summary

Counts only — does not re-run validation.

typed/builtin//modules/api/engine/lsp/lsp/tools

lsp.tools() -> { ToolEntry }

List every code-mode tool registered in the VFS under /zero/docs/tools/<category>/<tool>.

typed/builtin//modules/api/engine/lsp/lsp/typeOf

lsp.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.

typed/builtin//modules/api/engine/luau_profile/luau_profile/begin

luau_profile.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.

typed/builtin//modules/api/engine/luau_profile/luau_profile/dump

luau_profile.dump(path: string) -> DumpResult

Write the folded-stack dump to path, one line per stack as <ticks> <stack_csv> — the format upstream Luau emits and tools/perfgraph.py consumes unchanged.

typed/builtin//modules/api/engine/luau_profile/luau_profile/dump_regions

luau_profile.dump_regions(path: string) -> DumpRegionsResult

Write per-region stats to path as JSON.

typed/builtin//modules/api/engine/luau_profile/luau_profile/end_region

luau_profile.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).

typed/builtin//modules/api/engine/luau_profile/luau_profile/is_running

luau_profile.is_running() -> boolean

True iff the background sampler is currently running.

typed/builtin//modules/api/engine/luau_profile/luau_profile/reset

luau_profile.reset()

Clear every accumulated sample and region stat. The sampler keeps running if it was already on; only the data is wiped.

typed/builtin//modules/api/engine/luau_profile/luau_profile/sampling_available

luau_profile.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.

typed/builtin//modules/api/engine/luau_profile/luau_profile/snapshot

luau_profile.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).

typed/builtin//modules/api/engine/luau_profile/luau_profile/start

luau_profile.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.

typed/builtin//modules/api/engine/luau_profile/luau_profile/stop

luau_profile.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.

typed/builtin//modules/api/engine/mathx/mathx/addScaledVec3

mathx.addScaledVec3(dstBuffer: number, srcBuffer: number, count: number, scale: number) -> boolean

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.

typed/builtin//modules/api/engine/mathx/mathx/dampScalar

mathx.dampScalar(buffer: number, offset: number, count: number, target: number, smoothTime: number, dt: number) -> boolean

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.

typed/builtin//modules/api/engine/mathx/mathx/lerpVec3

mathx.lerpVec3(buffer: number, offset: number, count: number, tx: number, ty: number, tz: number, t: number) -> boolean

Element-wise linear blend of count vec3s in buffer[offset .. offset+count*3] toward (tx, ty, tz) by t.

typed/builtin//modules/api/engine/mathx/mathx/normalizeQuat

mathx.normalizeQuat(buffer: number, 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.

typed/builtin//modules/api/engine/mathx/mathx/slerpQuat

mathx.slerpQuat(buffer: number, offset: number, count: number, tx: number, ty: number, tz: number, tw: number, t: number) -> boolean

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.

typed/builtin//modules/api/engine/mathx/mathx/transformVec3

mathx.transformVec3(buffer: number, offset: number, count: number, mat16: { number }) -> boolean

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.

typed/builtin//modules/api/engine/mcpLog/mcpLog/clear

mcpLog.clear() -> boolean

Clear all entries from the engine's MCP log ring buffer.

typed/builtin//modules/api/engine/mcpLog/mcpLog/query

mcpLog.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).

typed/builtin//modules/api/engine/mode_flip_guard/M/isOwned

M.isOwned() -> boolean

Whether the layers module currently owns the mode-flip reset.

typed/builtin//modules/api/engine/mode_flip_guard/M/setOwned

M.setOwned(v: boolean) -> nil

Set whether the layers module owns the current mode-flip reset.

typed/builtin//modules/api/engine/modelImport/modelImport/decompose

modelImport.decompose(bytes: 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).

typed/builtin//modules/api/engine/modelImport/modelImport/decomposeFiles

modelImport.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.

typed/builtin//modules/api/engine/modelImport/modelImport/extractAnimation

modelImport.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.

typed/builtin//modules/api/engine/modelImport/modelImport/extractAnimationResult

modelImport.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.

typed/builtin//modules/api/engine/modelImport/modelImport/result

modelImport.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.

typed/builtin//modules/api/engine/modelImport/modelImport/retryHandle

modelImport.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.

typed/builtin//modules/api/engine/modelImport/modelImport/rigFromMeshSkin

modelImport.rigFromMeshSkin(meshBytes: 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.

typed/builtin//modules/api/engine/modelImport/modelImport/rigFromSkeleton

modelImport.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.

typed/builtin//modules/api/engine/multiplayer/multiplayer/beginOperation

multiplayer.beginOperation(description: string)

Begin recording an undoable operation. All mutations until commitOperation() are grouped into one undo entry.

typed/builtin//modules/api/engine/multiplayer/multiplayer/canRedo

multiplayer.canRedo() -> boolean

Check if this client has any redoable operations.

typed/builtin//modules/api/engine/multiplayer/multiplayer/canUndo

multiplayer.canUndo() -> boolean

Check if this client has any undoable operations.

typed/builtin//modules/api/engine/multiplayer/multiplayer/cancelOperation

multiplayer.cancelOperation()

Cancel the current operation and restore all properties to their values at begin time.

typed/builtin//modules/api/engine/multiplayer/multiplayer/claimOwnership

multiplayer.claimOwnership(entityId: string?) -> boolean

Request ownership of an entity. Returns true if the claim was tentatively granted (relay confirmation pending).

typed/builtin//modules/api/engine/multiplayer/multiplayer/commitOperation

multiplayer.commitOperation()

Finalize the current operation and push it onto the undo stack. Only changes that actually differ from the start state are recorded.

typed/builtin//modules/api/engine/multiplayer/multiplayer/connect

multiplayer.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.

typed/builtin//modules/api/engine/multiplayer/multiplayer/disconnect

multiplayer.disconnect()

Disconnect from the multiplayer relay server.

typed/builtin//modules/api/engine/multiplayer/multiplayer/getDiagnostics

multiplayer.getDiagnostics() -> SyncDiagnostics

Get sync diagnostics — bandwidth, latency, peer count, top consumers.

typed/builtin//modules/api/engine/multiplayer/multiplayer/getPeerId

multiplayer.getPeerId() -> number?

Get this client's peer ID in the current session.

typed/builtin//modules/api/engine/multiplayer/multiplayer/getPeers

multiplayer.getPeers() -> { PeerInfo }

Get a list of all connected peers in the current session.

typed/builtin//modules/api/engine/multiplayer/multiplayer/getTickRate

multiplayer.getTickRate() -> number

Get the current sync tick rate (network updates per second).

typed/builtin//modules/api/engine/multiplayer/multiplayer/isConnected

multiplayer.isConnected() -> boolean

Check if a multiplayer session is active and connected to a relay.

typed/builtin//modules/api/engine/multiplayer/multiplayer/isHost

multiplayer.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'.

typed/builtin//modules/api/engine/multiplayer/multiplayer/isOwner

multiplayer.isOwner(entityId: string?) -> 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.

typed/builtin//modules/api/engine/multiplayer/multiplayer/isRoomCreator

multiplayer.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.

typed/builtin//modules/api/engine/multiplayer/multiplayer/joinRoom

multiplayer.joinRoom(roomKey: string)

Join a relay room. Room keys are built as {worldGuid}/{mode}/{sceneGuid} and partition the relay's fan-out — only peers in the same room receive each other's broadcasts. No-op when not connected or already joined.

typed/builtin//modules/api/engine/multiplayer/multiplayer/leaveRoom

multiplayer.leaveRoom(roomKey: string)

Leave a relay room. No-op when not connected or not joined.

typed/builtin//modules/api/engine/multiplayer/multiplayer/loopback

multiplayer.loopback() -> { [string]: any }

Loopback testing harness. Returns a table with enable(), disable(), flush(), receive() methods for testing sync without a relay server.

typed/builtin//modules/api/engine/multiplayer/multiplayer/on

multiplayer.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.

typed/builtin//modules/api/engine/multiplayer/multiplayer/redo

multiplayer.redo() -> boolean

Redo this client's last undone operation.

typed/builtin//modules/api/engine/multiplayer/multiplayer/releaseOwnership

multiplayer.releaseOwnership(entityId: string?) -> boolean

Release ownership of an entity.

typed/builtin//modules/api/engine/multiplayer/multiplayer/send

multiplayer.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.

typed/builtin//modules/api/engine/multiplayer/multiplayer/undo

multiplayer.undo() -> boolean

Undo this client's last edit-mode operation.

typed/builtin//modules/api/engine/notices/notices/post

notices.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.

typed/builtin//modules/api/engine/packages/packages/list

packages.list() -> { PackageEntry }

List every registered package across scopes.

typed/builtin//modules/api/engine/packages/packages/lookup

packages.lookup(name_or_scope: string, name: string?) -> PackageEntry?

Look up a single package by name (any scope) or by exact (scope, name).

typed/builtin//modules/api/engine/playerSetupValidation/M/checkActiveScene

M.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.

typed/builtin//modules/api/engine/playerSetupValidation/M/checkEntity

M.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.

typed/builtin//modules/api/engine/playerSetupValidation/M/checkScene

M.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.

typed/builtin//modules/api/engine/playerSetupValidation/M/checkSceneJson

M.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.

typed/builtin//modules/api/engine/playerSetupValidation/M/playReadinessProblems

M.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).

typed/builtin//modules/api/engine/player_prototype_spawn/M/applyNetworkScope

M.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.

typed/builtin//modules/api/engine/player_prototype_spawn/M/captureTemplatesFromEntities

M.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.

typed/builtin//modules/api/engine/player_prototype_spawn/M/chooseSpawn

M.chooseSpawn(ctx: any) -> (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.

typed/builtin//modules/api/engine/player_prototype_spawn/M/clearJoinHook

M.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.

typed/builtin//modules/api/engine/player_prototype_spawn/M/installJoinHook

M.installJoinHook(sceneProxy: any) -> 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 (hidden 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 hidden 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.

typed/builtin//modules/api/engine/player_prototype_spawn/M/runtimeSpawnedInfo

M.runtimeSpawnedInfo(id: string) -> { [string]: any }?

Read back the runtime provenance stamped on a clone root by spawnFor.

typed/builtin//modules/api/engine/player_prototype_spawn/M/spawnFor

M.spawnFor(ctx: any) -> 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.

typed/builtin//modules/api/engine/player_prototype_spawn/M/storePrototypeTemplate

M.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.

typed/builtin//modules/api/engine/player_prototype_spawn/M/userHasSpawnedPlayer

M.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.

typed/builtin//modules/api/engine/postprocess/postprocess/add

postprocess.add(name: string, source: string, opts: PostprocessOpts?) -> boolean

Queue registration of a fullscreen post-process effect. The effect is applied on the next frame. source is WGSL providing ONLY fn fragment(in: PostInput) -> vec4<f32>; the engine generates the group(0) framework + schema-driven group(1) from opts.properties. Effects run in priority order (lower first, default 100).

typed/builtin//modules/api/engine/postprocess/postprocess/list

postprocess.list() -> { string }

List all registered post-process effect names in renderer priority order (lower priority runs first).

typed/builtin//modules/api/engine/postprocess/postprocess/remove

postprocess.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.

typed/builtin//modules/api/engine/postprocess/postprocess/setEnabled

postprocess.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.

typed/builtin//modules/api/engine/postprocess/postprocess/setProperty

postprocess.setProperty(name: string, prop: string, value: (number | { number })) -> boolean

Queue a named material-property update 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). Targeting an unknown effect or an undeclared property is a silent no-op.

typed/builtin//modules/api/engine/postprocess/postprocess/setSampler

postprocess.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.

typed/builtin//modules/api/engine/postprocess/postprocess/setTexture

postprocess.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, ...). Targeting an unknown effect / property or unresolvable path silently no-ops.

typed/builtin//modules/api/engine/profiler/profiler/begin

profiler.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.

typed/builtin//modules/api/engine/profiler/profiler/disableRing

profiler.disableRing()

Disable the ring buffer and clear its history.

typed/builtin//modules/api/engine/profiler/profiler/enableRing

profiler.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.

typed/builtin//modules/api/engine/profiler/profiler/finish

profiler.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.

typed/builtin//modules/api/engine/profiler/profiler/gpuFrame

profiler.gpuFrame() -> GpuFrameReport

Label-aggregated GPU pass timings of the most recent resolved frame, measured with GPU timestamp queries. supported is false when the device lacks timestamp queries — spans stays empty. Each span sums every render/compute pass recorded under one label that frame (count passes): compute.<shader> per compute dispatch, scene.* for the scene passes, post.<effect> per post-process effect, feature.* for render-feature passes. The GPU may overlap passes, so total_ms can exceed frame_span_ms (first pass begin to last pass end). The readback is asynchronous: the report lags the live frame by a few frames. Steady per-frame workloads read reliably; a lone one-shot dispatch submitted in isolation can under-report on some drivers.

typed/builtin//modules/api/engine/profiler/profiler/hits

profiler.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.

typed/builtin//modules/api/engine/profiler/profiler/isCapturing

profiler.isCapturing() -> boolean

Check if a profiler capture is currently active.

typed/builtin//modules/api/engine/profiler/profiler/lastCapture

profiler.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.

typed/builtin//modules/api/engine/profiler/profiler/retro

profiler.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 (profiler.frame/hotspots); 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.

typed/builtin//modules/api/engine/profiler/profiler/ringStatus

profiler.ringStatus() -> string

Ring buffer status as a JSON string: { enabled, frames, capacity, span_seconds }.

typed/builtin//modules/api/engine/profiler/profiler/startCapture

profiler.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.

typed/builtin//modules/api/engine/profiler/profiler/stats

profiler.stats(pattern: string?) -> { ProfilerStat }

Get current EMA profiling statistics from the SystemProfiler. Optional glob pattern filters by metric name (supports * and ? wildcards).

typed/builtin//modules/api/engine/profiler/profiler/stopCapture

profiler.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.

typed/builtin//modules/api/engine/profiler/profiler/unwatch

profiler.unwatch()

Disarm the watchdog. Recorded hits are kept for a final profiler.hits().

typed/builtin//modules/api/engine/profiler/profiler/watch

profiler.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.

typed/builtin//modules/api/engine/profiler/profiler/watchStatus

profiler.watchStatus() -> string

Watchdog status as a JSON string: { armed, ceiling_ms, mode, exclude_agent, hits, dropped_hits, tripped }.

typed/builtin//modules/api/engine/prototype_lifecycle/M/activatePrototypes

M.activatePrototypes()

Reactivate and unhide every prototype root and EditorOnly entity.

typed/builtin//modules/api/engine/prototype_lifecycle/M/deactivatePrototypes

M.deactivatePrototypes()

Deactivate and hide every prototype root and EditorOnly entity so play mode neither simulates nor renders them.

typed/builtin//modules/api/engine/prototype_lifecycle/M/despawnClones

M.despawnClones()

Despawn every still-existing tracked clone and clear the tracking list.

typed/builtin//modules/api/engine/prototype_lifecycle/M/enterEdit

M.enterEdit()

Enter edit mode: despawn runtime clones, then reactivate prototypes and EditorOnly entities.

typed/builtin//modules/api/engine/prototype_lifecycle/M/enterPlay

M.enterPlay()

Enter play mode: deactivate and hide prototypes and EditorOnly entities.

typed/builtin//modules/api/engine/prototype_lifecycle/M/hideEditorSurface

M.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.

typed/builtin//modules/api/engine/prototype_lifecycle/M/prototypeRoots

M.prototypeRoots() -> { string }

Ids of every active-layer entity carrying the PlayerPrototype component.

typed/builtin//modules/api/engine/prototype_lifecycle/M/registerClone

M.registerClone(id: string)

Track a runtime clone root so it can be despawned on the return to edit.

typed/builtin//modules/api/engine/prototype_lifecycle/M/showEditorSurface

M.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.

typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/add

reflectionProbe.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.

typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/apply

reflectionProbe.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.

typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/bake

reflectionProbe.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).

typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/bakeAll

reflectionProbe.bakeAll() -> { baked: number, failed: number, errors: { string } }

Bake EVERY registered probe in the active layers, in one call. Captures 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).

typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/count

reflectionProbe.count() -> number

Number of registered probes.

typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/list

reflectionProbe.list() -> { any }

List every registered probe: { { id, slot, radius, asset, position }, ... }.

typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/loadBaked

reflectionProbe.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.

typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/register

reflectionProbe.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.

typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/setRadius

reflectionProbe.setRadius(id: string, radius: number)

Update a probe's influence radius and re-apply.

typed/builtin//modules/api/engine/reflectionProbe/reflectionProbe/unregister

reflectionProbe.unregister(id: string)

Unregister entity id's probe, freeing its cube slot, and re-apply.

typed/builtin//modules/api/engine/renderer/renderer/destroy

renderer.destroy(handle: any) -> boolean

Free the GPU resource behind a MeshHandle / TextureHandle (the GPU-destroy verb). Routes by the handle's category. The on-disk asset, if any, is untouched. A CPU handle's :unload() frees the CPU copy separately.

typed/builtin//modules/api/engine/renderer/renderer/feature/create

renderer.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.

typed/builtin//modules/api/engine/renderer/renderer/feature/destroy

renderer.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.

typed/builtin//modules/api/engine/renderer/renderer/feature/list

renderer.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).

typed/builtin//modules/api/engine/renderer/renderer/getRaytrace

renderer.getRaytrace() -> boolean

Whether ray tracing is currently enabled.

typed/builtin//modules/api/engine/renderer/renderer/mainCameraView

renderer.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.

typed/builtin//modules/api/engine/renderer/renderer/material/create

renderer.material.create(content: MaterialContent, key: string) -> MaterialHandle

Register (or update) a material's GPU resource under key and return its MaterialHandle. content = { shader, properties, textures, aliases?, render? }. The referenced textures must already be GPU-resident (the material assetType materialises each slot via texRef:handle() before calling this) — this only files the shader+property+texture-slot record the renderer binds. Mirrors renderer.mesh.create / renderer.texture.create; idempotent upsert by key. render sets pipeline render-state (cull / depthWrite / blend) — e.g. { cull = "front", depthWrite = false } for an inverted-hull outline program.

typed/builtin//modules/api/engine/renderer/renderer/material/describe

renderer.material.describe(key: string) -> 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).

typed/builtin//modules/api/engine/renderer/renderer/material/destroy

renderer.material.destroy(key: string) -> 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.

typed/builtin//modules/api/engine/renderer/renderer/material/setProperty

renderer.material.setProperty(key: string, 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.

typed/builtin//modules/api/engine/renderer/renderer/material/setTexture

renderer.material.setTexture(key: string, slot: string, ref: string) -> ()

Push one changed texture slot to a registered material's GPU record. The texture must already be GPU-resident (materialise it with texRef:handle() first). Keyed by the material's registry key.

typed/builtin//modules/api/engine/renderer/renderer/mesh/buildClusters

renderer.mesh.buildClusters(guid: string) -> 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. The native offline bake; returns nil when the mesh is degenerate or the platform has no builder (the cross-platform runtime consumes pre-baked clusters). Pair with renderer.mesh.uploadClusters.

typed/builtin//modules/api/engine/renderer/renderer/mesh/clusterComponents

renderer.mesh.clusterComponents(clusterBytes: string) -> (ClusterComponents?, string?)

Split a cluster blob (from renderer.mesh.buildClusters) into its GPU-ready component byte pools — the cluster vertex pool, the u32 index pool, and the per-cluster record array — plus their counts. A pure decode (no GPU work): upload the pools to compute buffers (compute.createBuffer + compute.writeBufferBytes) to drive a cluster draw from Luau.

typed/builtin//modules/api/engine/renderer/renderer/mesh/create

renderer.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?} (a new runtime mesh); GPU compute buffers {vertexBuffer, indexBuffer, vertexCount, indexCount, aabbMin?, aabbMax?}; or a MeshHandle (returned as-is). NEVER takes an AssetRef — load the CPU first.

typed/builtin//modules/api/engine/renderer/renderer/mesh/decode

renderer.mesh.decode(zmsh: string) -> (MeshGeometry?, string?)

Decode engine-native ZMSH bytes back into geometry { positions, indices, normals?, uvs?, colors? }. Inverse of renderer.mesh.encode.

typed/builtin//modules/api/engine/renderer/renderer/mesh/encode

renderer.mesh.encode(geom: MeshGeometry) -> string?

Encode raw geometry into engine-native ZMSH bytes (the on-disk mesh payload). The CPU codec behind the mesh assetType's onCreate.

typed/builtin//modules/api/engine/renderer/renderer/mesh/encodeCpu

renderer.mesh.encodeCpu(guid: string) -> string

Encode the CPU mesh resident under guid into ZMSH bytes. Reads the ONE guid-keyed CPU store — meshRef:load() populates it for assets, and renderer.mesh.readback(guid) populates it for a runtime mesh. Errors loudly when no CPU mesh is resident under the guid.

typed/builtin//modules/api/engine/renderer/renderer/mesh/getVertices

renderer.mesh.getVertices(guid: string) -> { any }

Read the vertices of the CPU mesh resident under guid — 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 no CPU mesh is resident under the guid — load it (meshRef:load()) or retain it (keepCpu) first.

typed/builtin//modules/api/engine/renderer/renderer/mesh/isCpuResident

renderer.mesh.isCpuResident(guid: string) -> boolean

True if a CPU mesh is resident under guid in the guid-keyed CPU store.

typed/builtin//modules/api/engine/renderer/renderer/mesh/isResident

renderer.mesh.isResident(guid: string) -> boolean

True if a GPU mesh is resident under guid.

typed/builtin//modules/api/engine/renderer/renderer/mesh/loadCpu

renderer.mesh.loadCpu(ref: any) -> 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.

typed/builtin//modules/api/engine/renderer/renderer/mesh/readback

renderer.mesh.readback(guid: string) -> 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, :encode, :unload all work. Errors if no GPU mesh is resident in the vertex pool under guid.

typed/builtin//modules/api/engine/renderer/renderer/mesh/setVertices

renderer.mesh.setVertices(guid: string, positions: { number })

Replace the resident CPU mesh's vertex positions (flat { x,y,z, ... }) under guid, 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 mesh must be CPU-resident (load it, or retain it with keepCpu). Errors with the reason otherwise, or when the vertex count doesn't match.

typed/builtin//modules/api/engine/renderer/renderer/mesh/unloadCpu

renderer.mesh.unloadCpu(guid: string)

Drop the CPU mesh resident under guid from the guid-keyed CPU store. The explicit release for a runtime geometry mesh's recoverable definition.

typed/builtin//modules/api/engine/renderer/renderer/mesh/update

renderer.mesh.update(handle: MeshHandle, src: any) -> MeshHandle

Overwrite the GPU resource behind handle 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 handle.guid reflects the change with no re-bind. Returns the same handle with refreshed bounds.

typed/builtin//modules/api/engine/renderer/renderer/mesh/uploadClusters

renderer.mesh.uploadClusters(guid: string, 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.

typed/builtin//modules/api/engine/renderer/renderer/raytraceCapability

renderer.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.

typed/builtin//modules/api/engine/renderer/renderer/setRaytrace

renderer.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.

typed/builtin//modules/api/engine/renderer/renderer/texture/capture

renderer.texture.capture(handle: TextureHandle) -> string

Request a CPU readback of the GPU texture behind handle (e.g. a camera's rendered output). Returns a result key to pass to a TextureCpuHandle's :encode() once the readback completes.

typed/builtin//modules/api/engine/renderer/renderer/texture/cpuCreate

renderer.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.

typed/builtin//modules/api/engine/renderer/renderer/texture/create

renderer.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?} (a flat widthheight4 byte buffer, 0-255, row-major, top-to-bottom, RGBA); a TextureHandle (returned as-is); or render-target dimensions {width, height, name?} with no pixel source — an empty GPU texture a render pass writes into (camera output, UI surface) and that samples like any other texture. NEVER takes an AssetRef — load the CPU first.

typed/builtin//modules/api/engine/renderer/renderer/texture/decode

renderer.texture.decode(ztex: string) -> (any, any, any)

Decode an engine-native ZTEX payload to RGBA8 pixels.

typed/builtin//modules/api/engine/renderer/renderer/texture/destroy

renderer.texture.destroy(handle: TextureHandle)

Release the GPU texture behind handle. 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).

typed/builtin//modules/api/engine/renderer/renderer/texture/encode

renderer.texture.encode(rgba: any, width: number, height: number, opts: any) -> (string?, string?)

Encode raw RGBA8 pixels into an engine-native ZTEX payload (the on-disk texture content). The CPU codec behind the texture assetType's onCreate.

typed/builtin//modules/api/engine/renderer/renderer/texture/encodeFromImage

renderer.texture.encodeFromImage(bytes: 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.

typed/builtin//modules/api/engine/renderer/renderer/texture/info

renderer.texture.info(ztex: string) -> (any, any)

Read the header of an engine-native ZTEX payload without copying the pixels. Returns its format, dimensions, mip count, and filter ("nearest" or "linear" — the sampler baked into the blob from the asset's settings.filter).

typed/builtin//modules/api/engine/renderer/renderer/texture/isResident

renderer.texture.isResident(guid: string) -> boolean

True if a GPU texture is resident under guid.

typed/builtin//modules/api/engine/renderer/renderer/texture/loadCpu

renderer.texture.loadCpu(ref: any, encodeOpts: any?) -> TextureCpuHandle

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 plus dims and the read/write/encode/unload ops (which read the Rust store). Called by texRef:load(). DEFAULT: upload to the GPU then handle:unload().

typed/builtin//modules/api/engine/renderer/renderer/texture/readback

renderer.texture.readback(guid: string) -> 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 no GPU texture is resident under guid.

typed/builtin//modules/api/engine/renderer/renderer/texture/update

renderer.texture.update(handle: TextureHandle, src: any) -> TextureHandle

Overwrite the GPU texture behind handle IN PLACE, under the same guid, from new raw pixels. Never writes a .texture file — the play-mode mutate path. Returns the same handle (refreshed dims).

typed/builtin//modules/api/engine/retarget/retarget/animation

retarget.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.

typed/builtin//modules/api/engine/retarget/retarget/extractRig

retarget.extractRig(meshBytes: 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.

typed/builtin//modules/api/engine/retarget/retarget/humanoidProfile

retarget.humanoidProfile(meshBytes: 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.

typed/builtin//modules/api/engine/retarget/retarget/isHumanoid

retarget.isHumanoid(meshBytes: 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.

typed/builtin//modules/api/engine/retarget/retarget/serializeProfile

retarget.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.

typed/builtin//modules/api/engine/service/service/authenticated

service.authenticated() -> boolean

Whether a platform identity (JWT) is available to attach to service calls. Returns only a boolean — never the token.

typed/builtin//modules/api/engine/service/service/balance

service.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.

typed/builtin//modules/api/engine/service/service/configureGateway

service.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.

typed/builtin//modules/api/engine/service/service/gatewayConfigured

service.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.

typed/builtin//modules/api/engine/service/service/invoke

service.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.

typed/builtin//modules/api/engine/shell/shell/run

shell.run(command: string) -> ShellResult

Execute a command in the engine's emulated Unix shell. Blocks until the command completes. This is the same shell as the MCP bash tool — 60+ builtins (ls, cat, grep, find, echo, ...) operating on the virtual scene filesystem.

typed/builtin//modules/api/engine/shell/shell/runAsync

shell.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().

typed/builtin//modules/api/engine/skeleton/skeleton/applyPose

skeleton.applyPose(sinkHandle: number, bufferHandle: number) -> 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.

typed/builtin//modules/api/engine/skeleton/skeleton/bindClip

skeleton.bindClip(zanimBytes: 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.

typed/builtin//modules/api/engine/skeleton/skeleton/bindPose

skeleton.bindPose(entityId: string?, 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.

typed/builtin//modules/api/engine/skeleton/skeleton/clipBones

skeleton.clipBones(zanimBytes: 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.

typed/builtin//modules/api/engine/skeleton/skeleton/clipDecode

skeleton.clipDecode(zanimBytes: 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.

typed/builtin//modules/api/engine/skeleton/skeleton/clipEncode

skeleton.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.

typed/builtin//modules/api/engine/skeleton/skeleton/jointTransforms

skeleton.jointTransforms(entityId: string) -> table

Read a skinned entity's per-joint world transforms for the current animated pose.

typed/builtin//modules/api/engine/skeleton/skeleton/sampleClip

skeleton.sampleClip(handle: number, time: number, buffer: number) -> 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.

typed/builtin//modules/api/engine/skeleton/skeleton/unbindClip

skeleton.unbindClip(handle: number) -> boolean

Drop the bound clip sampler from the registry.

typed/builtin//modules/api/engine/skeleton/skeleton/unbindPose

skeleton.unbindPose(sinkHandle: number) -> boolean

Remove the sink from the registry.

typed/builtin//modules/api/engine/sky/sky/get

sky.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].

typed/builtin//modules/api/engine/sky/sky/getTimeOfDay

sky.getTimeOfDay() -> number

Get the current time of day in hours (0-24).

typed/builtin//modules/api/engine/sky/sky/preset

sky.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.

typed/builtin//modules/api/engine/sky/sky/set

sky.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.

typed/builtin//modules/api/engine/sky/sky/setSunDirection

sky.setSunDirection(dir: SkyColor)

Set an explicit sun direction and disable time-based sun positioning. The directional light is updated to match.

typed/builtin//modules/api/engine/sky/sky/setTimeOfDay

sky.setTimeOfDay(time: number)

Set the time of day (0-24 hours). 0 = midnight, 6 = sunrise, 12 = noon, 18 = sunset.

typed/builtin//modules/api/engine/subscriptions/subscriptions/cancel

subscriptions.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.

typed/builtin//modules/api/engine/subscriptions/subscriptions/get

subscriptions.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).

typed/builtin//modules/api/engine/subscriptions/subscriptions/list

subscriptions.list(filter: SubscriptionFilter?) -> { SubscriptionRow }

Every tracked subscription row, optionally filtered by publisher instance id, publisher entity id, event name, and/or connected state.

typed/builtin//modules/api/engine/subscriptions/subscriptions/publishers

subscriptions.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.

typed/builtin//modules/api/engine/text/text/create

text.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.

typed/builtin//modules/api/engine/text/text/destroy

text.destroy(handle: any)

Destroy a text handle and release its raster + glyph layout.

typed/builtin//modules/api/engine/text/text/listFonts

text.listFonts() -> { string }

List the font families currently available to the text system.

typed/builtin//modules/api/engine/text/text/loadFont

text.loadFont(ref: any) -> any

Load a font from an asset reference so it becomes available to setStyle's fontFamily.

typed/builtin//modules/api/engine/text/text/measure

text.measure(handle: any) -> any

Measure the rasterised text in pixels without producing a texture.

typed/builtin//modules/api/engine/text/text/rasterize

text.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.

typed/builtin//modules/api/engine/text/text/setStyle

text.setStyle(handle: any, style: table)

Replace the handle's style. Fields not present keep their current value.

typed/builtin//modules/api/engine/text/text/setText

text.setText(handle: any, content: string)

Replace the handle's text content.

typed/builtin//modules/api/engine/text/text/textureGuid

text.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.

typed/builtin//modules/api/engine/ui/ui/blur

ui.blur()

Surrender keyboard focus from whichever widget currently holds it.

typed/builtin//modules/api/engine/ui/ui/bringAreaToFront

ui.bringAreaToFront(id: string)

Raise a movable area to the top of the window stacking order — the programmatic equivalent of clicking it. egui orders overlapping areas by interaction, so bumping a screen layer alone will NOT bring an unclicked window forward; call this when a taskbar button, focus change, or app launch should bring its window to the front.

typed/builtin//modules/api/engine/ui/ui/captureWindow

ui.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).

typed/builtin//modules/api/engine/ui/ui/click

ui.click(callbackId: string, value: any?)

Simulate a widget click / interaction by its callback id.

typed/builtin//modules/api/engine/ui/ui/defineStyle

ui.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.

typed/builtin//modules/api/engine/ui/ui/defineStyles

ui.defineStyles(styles: { [string]: StyleProps })

Define multiple named styles at once.

typed/builtin//modules/api/engine/ui/ui/defineWidget

ui.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.

typed/builtin//modules/api/engine/ui/ui/focus

ui.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().

typed/builtin//modules/api/engine/ui/ui/focusedWidget

ui.focusedWidget() -> string?

Return the widget id of whichever widget currently holds keyboard focus, or nil. Snapshotted post-render each frame.

typed/builtin//modules/api/engine/ui/ui/getAreaPos

ui.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.

typed/builtin//modules/api/engine/ui/ui/getAreaSize

ui.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.

typed/builtin//modules/api/engine/ui/ui/getDockLayout

ui.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.

typed/builtin//modules/api/engine/ui/ui/getLayoutInfo

ui.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.

typed/builtin//modules/api/engine/ui/ui/getScreenTree

ui.getScreenTree(screenName: string) -> WidgetTree?

Return the last widget tree table passed to registerScreen / updateScreen for screenName.

typed/builtin//modules/api/engine/ui/ui/getTheme

ui.getTheme() -> string

Get the name of the currently active theme.

typed/builtin//modules/api/engine/ui/ui/getToken

ui.getToken(name: string) -> string?

Look up a single design token value from the active theme.

typed/builtin//modules/api/engine/ui/ui/getTokens

ui.getTokens() -> { [string]: string }

Get all design tokens from the active theme as a key-value map.

typed/builtin//modules/api/engine/ui/ui/getWidgetProps

ui.getWidgetProps(typeName: string) -> { WidgetPropDescriptor }?

Get the property definitions for a widget type.

typed/builtin//modules/api/engine/ui/ui/getWidgetTypes

ui.getWidgetTypes() -> { string }

Get all available widget type names that can be used in widget trees.

typed/builtin//modules/api/engine/ui/ui/hideScreen

ui.hideScreen(name: string)

Hide a registered screen.

typed/builtin//modules/api/engine/ui/ui/lastRegistration

ui.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.

typed/builtin//modules/api/engine/ui/ui/lastValidation

ui.lastValidation(screenName: string?) -> any

Validation diagnostics produced at the most recent registerScreen / updateScreen. 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").

typed/builtin//modules/api/engine/ui/ui/listScreens

ui.listScreens() -> { ScreenSummary }

List every registered screen with its current visibility, layer, and whether the screen has a populated root widget tree. Sorted by layer ascending, then name.

typed/builtin//modules/api/engine/ui/ui/listThemes

ui.listThemes() -> { string }

List all registered theme names.

typed/builtin//modules/api/engine/ui/ui/registerBackgroundShader

ui.registerBackgroundShader(shaderHandle: any, width: number?, height: number?)

Register a shader for UI backgrounds. Accepts an asset handle from asset.load(), or legacy (name, wgslSource, width?, height?) for inline source.

typed/builtin//modules/api/engine/ui/ui/registerScreen

ui.registerScreen(name: string, widgetTree: WidgetTree, layer: number?)

Register a named UI screen with a widget tree. Optional layer controls z-ordering (higher = on top). Tag-based grouping lives in Z.tags (Z.tags.set(name, { "editor" }) after register).

typed/builtin//modules/api/engine/ui/ui/registerTheme

ui.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.

typed/builtin//modules/api/engine/ui/ui/removeScreen

ui.removeScreen(name: string)

Alias for ui.unregisterScreen.

typed/builtin//modules/api/engine/ui/ui/resetAreaSize

ui.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.

typed/builtin//modules/api/engine/ui/ui/response

ui.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.

typed/builtin//modules/api/engine/ui/ui/screen

ui.screen(name: string) -> { [string]: any }?

Get a screen proxy with methods like setResolution and rasterize.

typed/builtin//modules/api/engine/ui/ui/screenSize

ui.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.

typed/builtin//modules/api/engine/ui/ui/scroll

ui.scroll(deltaX: number, deltaY: number)

Simulate a mouse-wheel scroll event on the UI.

typed/builtin//modules/api/engine/ui/ui/setAreaPos

ui.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.

typed/builtin//modules/api/engine/ui/ui/setAreaSize

ui.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.

typed/builtin//modules/api/engine/ui/ui/setScreenRenderLayer

ui.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).

typed/builtin//modules/api/engine/ui/ui/setScrollPosition

ui.setScrollPosition(widgetId: string, offsetY: number)

Set the scroll offset of a scrollArea widget.

typed/builtin//modules/api/engine/ui/ui/setShaderUniforms

ui.setShaderUniforms(name: string, uniforms: { [string]: number })

Set uniform values on a registered background shader.

typed/builtin//modules/api/engine/ui/ui/setTheme

ui.setTheme(name: string)

Switch the active global theme by name.

typed/builtin//modules/api/engine/ui/ui/showScreen

ui.showScreen(name: string)

Make a registered screen visible.

typed/builtin//modules/api/engine/ui/ui/unregisterScreen

ui.unregisterScreen(name: string)

Remove a screen from the registry entirely. Unlike hideScreen, this deletes the entry so it no longer appears in listScreens or render iteration.

typed/builtin//modules/api/engine/ui/ui/unregisterWidget

ui.unregisterWidget(name: string)

Drop a registered custom widget kind. Subsequent references produce an unknown-widget-type diagnostic.

typed/builtin//modules/api/engine/ui/ui/updateScreen

ui.updateScreen(name: string, widgetTree: WidgetTree)

Replace the widget tree of an already-registered screen.

typed/builtin//modules/api/engine/ui/ui/useStyles

ui.useStyles(themeName: string)

Apply a registered style file's classes additively without changing the active theme.

typed/builtin//modules/api/engine/ui/ui/widgetState

ui.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.

typed/builtin//modules/api/engine/ui/ui/widgetStateClear

ui.widgetStateClear(widgetId: string, key: string)

Remove a per-widget state entry.

typed/builtin//modules/api/engine/ui/ui/widgetStateSet

ui.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.

typed/builtin//modules/api/engine/userfile/userfile/pick

userfile.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.

typed/builtin//modules/api/engine/userfile/userfile/pickFolder

userfile.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.

typed/builtin//modules/api/engine/vfs/vfs/clearPlayShadow

vfs.clearPlayShadow() -> boolean

Forget the entire play-shadow set after a bulk promote or discard. Tracking only — never touches the bytes.

typed/builtin//modules/api/engine/vfs/vfs/evict

vfs.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.

typed/builtin//modules/api/engine/vfs/vfs/exists

vfs.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.

typed/builtin//modules/api/engine/vfs/vfs/list

vfs.list(path: string?) -> { VfsListEntry }

List entries in a VFS directory.

typed/builtin//modules/api/engine/vfs/vfs/mkdir

vfs.mkdir(path: string, opts: VfsOpts?) -> boolean

Create a directory. mkdir -p semantics — idempotent. Errors if a file already exists at the same path.

typed/builtin//modules/api/engine/vfs/vfs/move

vfs.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.

typed/builtin//modules/api/engine/vfs/vfs/pendingWrites

vfs.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.

typed/builtin//modules/api/engine/vfs/vfs/playShadowPaths

vfs.playShadowPaths() -> { string }

List 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.

typed/builtin//modules/api/engine/vfs/vfs/promotePlayShadow

vfs.promotePlayShadow(path: string) -> (boolean, string?)

Promote a single play-shadow edit into a canonical write. Re-asserts the live overlay bytes through the full write pipeline with the play write lock released, then unmarks the path. The bytes stay in the engine end to end, so binary content promotes exactly. Requires play to be paused.

typed/builtin//modules/api/engine/vfs/vfs/read

vfs.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.

typed/builtin//modules/api/engine/vfs/vfs/readAsync

vfs.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.

typed/builtin//modules/api/engine/vfs/vfs/reload

vfs.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.

typed/builtin//modules/api/engine/vfs/vfs/remove

vfs.remove(path: string, opts: VfsOpts?) -> (boolean, string?)

Remove a file. Refuses to remove directories unless opts.recursive = true. Refuses protected system roots.

typed/builtin//modules/api/engine/vfs/vfs/revertPlayShadow

vfs.revertPlayShadow(path: string) -> (boolean, string?)

Revert a single play-shadow edit: restore 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. Requires play to be paused.

typed/builtin//modules/api/engine/vfs/vfs/unmarkPlayShadow

vfs.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.

typed/builtin//modules/api/engine/vfs/vfs/unwatch

vfs.unwatch(watcherId: number) -> boolean

TRUSTED ONLY. Remove a previously registered VFS watcher.

typed/builtin//modules/api/engine/vfs/vfs/watch

vfs.watch(path: string, callback: (string, string) -> ()) -> number

TRUSTED ONLY. Register a callback that fires when a VFS path is written or removed. Two match modes: exact, or folder/prefix (key ends with /). Callback signature: function(path: string, kind: "write" | "remove"). Returns a watcher id for vfs.unwatch.

typed/builtin//modules/api/engine/vfs/vfs/write

vfs.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. Locked in play mode (returns (false, errmsg)).

typed/builtin//modules/api/engine/video/video/create

video.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.

typed/builtin//modules/api/engine/video/video/destroy

video.destroy(handle: string) -> boolean

Destroy a video player and free the render target and all resources.

typed/builtin//modules/api/engine/video/video/getInfo

video.getInfo(handle: string) -> VideoInfo?

Get video information and current playback state.

typed/builtin//modules/api/engine/video/video/pause

video.pause(handle: string) -> boolean

Pause video playback. Can be resumed with video.play.

typed/builtin//modules/api/engine/video/video/play

video.play(handle: string) -> boolean

Start or resume video playback.

typed/builtin//modules/api/engine/video/video/seek

video.seek(handle: string, time: number) -> boolean

Seek to a specific time (seconds) in the video.

typed/builtin//modules/api/engine/video/video/setLoop

video.setLoop(handle: string, loop: boolean) -> boolean

Enable or disable looping.

typed/builtin//modules/api/engine/video/video/setRate

video.setRate(handle: string, rate: number) -> boolean

Set the playback speed multiplier. 1.0 = normal, 2.0 = double speed, 0.5 = half speed.

typed/builtin//modules/api/engine/video/video/stop

video.stop(handle: string) -> boolean

Stop video playback and reset to the beginning.

typed/builtin//modules/asset_ref/M/build

M.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.

typed/builtin//modules/asset_ref/M/loadTypeModule

M.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.

typed/builtin//modules/asset_ref/M/persistInEditMode

M.persistInEditMode(self: any)

Generic edit-mode persistence hook. 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). This enforces the edit-mode contract uniformly across EVERY assetType that defines a saveDefinition: in edit mode a runtime modification is written through to the asset immediately, so it syncs to peers and is saved (edit mode is not "playing" — there is no per-frame mutation and no perf concern). 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.

typed/builtin//modules/bundle_update/M/installInto

M.installInto(bundleNamespace: BundleNamespace)

Install update onto the supplied bundle-shaped namespace. The prelude calls this once at boot with the engine's bundle global; users shouldn't call it directly.

typed/builtin//modules/bundle_update/M/update

M.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.

typed/builtin//modules/colorSequence/M/deserialize

M.deserialize(data: any) -> ColorSequenceObj

Rebuild a ColorSequence from a {kind = "ColorSequence", keypoints = {...}} payload produced by :serialize(). Used by scene save/load.

typed/builtin//modules/colorSequence/M/new

M.new(...: any) -> ColorSequenceObj

Construct a ColorSequence from one of three signatures: a constant color (3-array {r,g,b} or {r=,g=,b=} record), a two-point lerp from c0 to c1, or a keypoints array. envelope is optional and may be a single number (broadcast across channels) or a 3-array. Up to 64 keypoints; the first must anchor at time = 0, the last at time = 1. NaN / Inf rejected.

typed/builtin//modules/component_proxy/M/computed

M.computed(fn: (any) -> any) -> string

Mark a function as a computed property. The function takes self (the proxy) and returns the computed value. Returns a string sentinel that the Rust-side public_index dispatches through the registry on every read.

typed/builtin//modules/component_proxy/M/installGlobal

M.installGlobal()

Install computed as a global so component modules can write public.X = computed(fn) without an explicit require. Called by the prelude.

typed/builtin//modules/component_proxy/M/isComputedSentinel

M.isComputedSentinel(v: any) -> boolean

True iff v is a computed-property sentinel — the string a computed(fn) declaration stores in a proxy's public table. Reads of the property resolve the sentinel to the getter's value, but a raw pairs() over the backing table yields the sentinel itself. Serializers call this to skip computed (derived) fields, which are re-derived on load.

typed/builtin//modules/content_version/M/bump

M.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.

typed/builtin//modules/content_version/M/get

M.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.

typed/builtin//modules/data_schema/M/applyDefaults

M.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.

typed/builtin//modules/data_schema/M/mergeChain

M.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.

typed/builtin//modules/data_schema/M/parseSchema

M.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.

typed/builtin//modules/data_schema/M/validateValues

M.validateValues(merged: { [string]: FieldSpec }, values: { [string]: any }, resolvers: Resolvers) -> { Violation }

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.

typed/builtin//modules/debris/M/add

M.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.

typed/builtin//modules/debris/M/cancel

M.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.

typed/builtin//modules/debris/M/clear

M.clear() -> boolean

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

typed/builtin//modules/debris/M/count

M.count() -> number

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

typed/builtin//modules/debris/M/list

M.list() -> { DebrisEntry }

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

typed/builtin//modules/debris/M/pending

M.pending(id: any) -> number?

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

typed/builtin//modules/entity_hierarchy/M/swap

M.swap(entityId: string, assetPath: string, opts: SwapOpts?) -> (string?, string?)

Replace a blockout entity with a generated/imported asset, fitting the asset to the source's bounds and inheriting the source's world rotation. The new entity is reparented to the source's parent, optionally inherits the source name, and the original is despawned.

typed/builtin//modules/entity_proxy/M/build

M.build(id: string) -> EntityRef

Factory that backs entity(id). Returns a cached proxy when one already exists for id; otherwise allocates and caches a fresh one. The cache is weak-valued so unreferenced proxies are GC'd.

typed/builtin//modules/entity_reflect/E/allTypes

E.allTypes() -> { string }

List all registered reflectable component types in this engine instance.

typed/builtin//modules/entity_reflect/E/distance

E.distance(entityIdA: string, entityIdB: string) -> number?

Compute the straight-line distance between two entities' Transform.position fields.

typed/builtin//modules/entity_reflect/E/getComponents

E.getComponents(entityId: string) -> { string }?

List all reflected component types on an entity.

typed/builtin//modules/entity_reflect/E/getField

E.getField(entityId: string, component: string, field: string) -> any

Get a specific component field value via the __reflect FFI.

typed/builtin//modules/entity_reflect/E/getName

E.getName(entityId: string) -> string?

Get the name of an entity from its Name component.

typed/builtin//modules/entity_reflect/E/getPosition

E.getPosition(entityId: string) -> Vec3?

Get the position of an entity — shortcut for getField(id, "Transform", "position").

typed/builtin//modules/entity_reflect/E/getRotation

E.getRotation(entityId: string) -> Quat?

Get the rotation of an entity — shortcut for getField(id, "Transform", "rotation").

typed/builtin//modules/entity_reflect/E/getScale

E.getScale(entityId: string) -> Vec3?

Get the scale of an entity — shortcut for getField(id, "Transform", "scale").

typed/builtin//modules/entity_reflect/E/getSchema

E.getSchema(componentName: string) -> { ComponentFieldSchema }?

Get the full schema of a component type — field names + types.

typed/builtin//modules/entity_reflect/E/isVisible

E.isVisible(entityId: string) -> boolean

Check if an entity is visible — reads the Visible component. Missing component is treated as visible.

typed/builtin//modules/entity_reflect/E/patch

E.patch(entityId: string, component: string, fields: { [string]: any }) -> boolean

Patch multiple fields on a single component at once.

typed/builtin//modules/entity_reflect/E/setField

E.setField(entityId: string, component: string, field: string, value: any) -> boolean

Set a specific component field value via the __reflect FFI.

typed/builtin//modules/entity_reflect/E/setPosition

E.setPosition(entityId: string, pos: Vec3)

Set the position of an entity — shortcut for setField(id, "Transform", "position", pos).

typed/builtin//modules/entity_reflect/E/setScale

E.setScale(entityId: string, scale: Vec3)

Set the scale of an entity — shortcut for setField(id, "Transform", "scale", scale).

typed/builtin//modules/entity_reflect/E/snapshot

E.snapshot(entityId: string) -> any

Snapshot all reflected components on an entity into a { ComponentName = { field = value, ... }, ... } map.

typed/builtin//modules/entity_signals/M/get

M.get(entityId: string, phase: string) -> any

Return the onDestroying/onDestroyed signal for an entity, creating it on first access. phase is "destroying" or "destroyed".

typed/builtin//modules/field/Field/alias

Field.alias(target: string | { string }) -> FieldDesc<any>

typed/builtin//modules/field/Field/assetRef

Field.assetRef(category: C & string, default: AssetRef<C> | string | nil, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<AssetRef<C>>

typed/builtin//modules/field/Field/bool

Field.bool(default: boolean, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<boolean>

Boolean field. Default must be a boolean.

typed/builtin//modules/field/Field/color

Field.color(default: color, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<color>

Color field. Default is a color — either {r = .., g = .., b = .., a = ..?} or {r, g, b, a?}.

typed/builtin//modules/field/Field/componentRef

Field.componentRef(componentType: T & string, default: ComponentRef<T> | nil, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<ComponentRef<T>>

Typed component reference field. T is the component-type name — a singleton string type inferred from the componentType argument ("Camera", "Transform", "@user/Inventory"). The engine validates the referent exists and is of the declared type at every write.

typed/builtin//modules/field/Field/dataRef

Field.dataRef(contract: C & string, default: AssetRef<"data"> | string | nil, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<AssetRef<"data">>

Contract-constrained typed-data reference field. Accepts only .data assets whose dataType contract chain includes contract. Rides the assetRef machinery (category "data") — dependency graph, sync, and rehydration behave exactly like Field.assetRef — with the contract gate enforced through the generic field-constraint hook on every write and on the registration-time default.

typed/builtin//modules/field/Field/entityRef

Field.entityRef(default: EntityRef | string | nil, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<EntityRef>

Entity reference field. Accepts a live entity proxy (EntityRef), a raw entity-id string, or nil (no target). Writes are normalised to the plain id string for storage/replication; reads return a live EntityRef proxy (or nil), so public.<field>:method() and public.<field>.id work directly without re-resolving.

typed/builtin//modules/field/Field/list

Field.list(element: FieldDesc<any>, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<ListValue>

List field — an array of one repeated element type. The element is the Field constructor descriptor every item conforms to, often a Field.struct for a list of records. The list value is an array of the element's value type. Like Field.struct, the engine descends the element schema to resolve nested asset refs into envelopes, so a stack of structs each holding an asset ref has every ref appear in the asset dependency graph, validates each item, and the LSP type-checks the array. The default value is an empty list. The element declares its own Sync or NoSync for typing; the list's own mode governs replication of the whole array as a unit.

typed/builtin//modules/field/Field/number

Field.number(default: number, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<number>

Number field. Default must be a number.

typed/builtin//modules/field/Field/quat

Field.quat(default: quat, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<quat>

Quaternion field. Default is a quat — either {x = .., y = .., z = .., w = ..} or {x, y, z, w}.

typed/builtin//modules/field/Field/resource

Field.resource(category: C & string, default: AssetRef<C> | Handle<C> | string | nil, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<AssetRef<C> | Handle<C>>

Category-gated RESOURCE field — accepts EITHER a persistent AssetRef<C> OR a live GPU Handle<C>, gated by category. This is the renderer-facing field type (e.g. Model.model, Model.material, material texture slots): content can author a persistent asset OR pass a runtime handle (renderer.<resource>.create(...)); the component bridges either to the GPU resource. The category gate still holds — an AssetRef<audio> or a wrong-category handle (a TextureHandle on a "mesh" slot) is a type error AND a runtime rejection. Use Field.assetRef instead when the field MUST be a persistent asset (handles rejected). With Sync, persistent-asset values replicate to peers; a live GPU handle value is local by construction and stays local — peers keep the last replicated asset value.

typed/builtin//modules/field/Field/string

Field.string(default: string, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<string>

String field. Default must be a string.

typed/builtin//modules/field/Field/struct

Field.struct(schema: FieldSchema, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<StructValue>

Struct field — a table whose keys are themselves typed fields. The schema maps each subfield name to its Field constructor descriptor; the struct value is a table holding one value per subfield. Use this instead of Field.table when the table carries asset references or other typed data: the engine descends the schema to resolve nested asset refs into envelopes at registration and at write time, so they appear in the asset dependency graph, validates writes per subfield, and the LSP type-checks the shape. Each subfield declares its own Sync or NoSync for typing; the struct's own mode governs replication of the whole value as a unit.

typed/builtin//modules/field/Field/table

Field.table(default: T, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<T>

Generic table field. T is the table's shape — usually inferred from the default value, or supplied explicitly via an explicit ascription Field.table({} :: MyShape, mode) when the default doesn't cover every key the runtime will write. The engine accepts any Luau table as a value at write time; per-shape enforcement is opt-in static typing only.

typed/builtin//modules/field/Field/vec2

Field.vec2(default: vec2, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<vec2>

Vec2 field. Default is a vec2 — either {x = .., y = ..} or the 2-element array form {x, y}.

typed/builtin//modules/field/Field/vec3

Field.vec3(default: vec3, mode: SyncMode, marker: SerializedMode?) -> FieldDesc<vec3>

Vec3 field. Default is a vec3 — either {x = .., y = .., z = ..} or the 3-element array form {x, y, z}.

typed/builtin//modules/icons/Icon/styled

Icon.styled(extra: LabelOpts?) -> LabelOpts

Build an opts table for UI.label with the phosphor font family applied. Existing keys on extra merge through; extra.style.fontFamily is forced to "phosphor".

typed/builtin//modules/jobs/M/find

M.find(name: string) -> JobHandle?

Look up a registered job by name. Returns a JobHandle or nil for anonymous / unknown names. Single FFI crossing — returns the id directly, no registry snapshot.

typed/builtin//modules/jobs/M/inspect

M.inspect(target: JobHandle | string) -> JobInfo?

Return a snapshot row by job handle or by name without retrieving a full handle. Single FFI crossing — pulls only the matching row.

typed/builtin//modules/jobs/M/list

M.list(phase: string?) -> { JobInfo }

List registered job summaries. Pass a phase name to filter to a single phase. Single FFI crossing — only the requested rows cross the bridge.

typed/builtin//modules/jobs/M/register

M.register(descriptor: table) -> JobHandle?

Register a substrate job. Returns a JobHandle on success, nil on validation failure. Dispatches by executor.kind:\n - "kernel" / "stub" → standard __jobs.register (JSON-only descriptor).\n - "luau"__jobs.register_luau(descriptor, executor.run) so the Luau function survives the JSON crossing as a stable registry ref. The dispatcher invokes the run closure once per frame; the closure captures any bindings/buffers it needs.\n\norigin is auto-filled with the VFS path of the calling script unless the descriptor already supplies one — surfaced under /zero/runtime/jobs/<phase>/<key>/origin.txt for agent traceability. Single FFI crossing — auto-origin runs Rust-side via lua_getinfo, no separate stack-inspection trip.

typed/builtin//modules/jobs/jobhandle_cancel

jobhandle_cancel(self: JobHandle) -> boolean

Cancel the job — drops one refcount, last drop unregisters and the dispatcher stops invoking it. Symmetric with vfs.remove("/runtime/jobs/<phase>/<id>").

typed/builtin//modules/jobs/jobhandle_info

jobhandle_info(self: JobHandle) -> JobInfo?

Latest snapshot row for this job (id, name, phase, status, origin, metadata, reads, writes…). Single FFI crossing — pulls only this job's row, not the full registry.

typed/builtin//modules/jobs/jobhandle_pause

jobhandle_pause(self: JobHandle) -> boolean

Pause the job — skipped on subsequent ticks but stays registered.

typed/builtin//modules/jobs/jobhandle_resume

jobhandle_resume(self: JobHandle) -> boolean

Resume a paused or errored job (clears ErroredPending).

typed/builtin//modules/jobs/jobhandle_status

jobhandle_status(self: JobHandle) -> JobStatus?

Read the job's current scheduler status.

typed/builtin//modules/jobs/jobhandle_valid

jobhandle_valid(self: JobHandle) -> boolean

Whether the substrate still tracks this job (false after :cancel/:destroy).

typed/builtin//modules/json/Json/decode

Json.decode(str: string) -> any

Decode a JSON string to a Lua value. Returns the decoded value, or nil + error message on failure.

typed/builtin//modules/json/Json/encode

Json.encode(value: any, indent: string?, currentIndent: string?) -> string

Encode a Lua value to a compact JSON string. Functions and unknown types serialise to null; NaN/Inf serialise to null (JSON has no representation for them).

typed/builtin//modules/json/Json/encodeArgs

Json.encodeArgs(...: any) -> string

Encode a list of arguments as a JSON array string. Useful when forwarding varargs to a JSON-based bridge.

typed/builtin//modules/json/Json/encodePretty

Json.encodePretty(value: any, indentStr: string?) -> string

Encode a Lua value to a pretty-printed JSON string. Indents nested values and sorts object keys for diff-friendly output.

typed/builtin//modules/luau_introspect/M/docstrings

M.docstrings(src: string) -> DocMap

Scans src for --!desc / --!arg / --!return / --!example doc-comment runs and binds each run to the name of the declaration on the next code line (the identifier after function, public:, local function, M., public.<name>, or a <name> = Field.<...> / <name> = Event(...) field/event declaration). A continuation line ("--! " with no tag word) extends whichever field the run's last tag opened. Blank and plain -- comment lines between the run and the declaration are skipped without terminating the run.

typed/builtin//modules/luau_introspect/M/events

M.events(src: string) -> { EventEntry }

Parses events = { name = Event(payloadSchema?, syncMode?), ... } table-literal entries. The payload schema — a { k = Field.<kind>(...) } table — is parsed like publicFields and reduced to {name, type} pairs; a payloadless Event() yields an empty payload. sync is true only when the SECOND positional Event argument is the literal identifier Sync. Comments and string literals never register. Folds in desc from docstrings(src).

typed/builtin//modules/luau_introspect/M/forSource

M.forSource(src: string, computeFn: (string) -> any) -> any

Memoises computeFn(src) keyed on src itself in a bounded module-local table. The same source text returns the cached result without re-invoking computeFn; different source text recomputes. The cache is capped (oldest key evicted first), so an evicted key recomputes on its next request.

typed/builtin//modules/luau_introspect/M/lifecycleHooks

M.lifecycleHooks(src: string, catalog: { string }) -> { string }

Finds top-level function <name>( declarations whose name is in the caller-supplied catalog. Excludes local function, public: methods, and M. exports — only a bare top-level function NAME( declaration matches. Never hardcodes the lifecycle-callback catalog; the caller passes the list of names to match against. Commented-out declarations never match.

typed/builtin//modules/luau_introspect/M/maskNonCode

M.maskNonCode(src: string) -> string

A same-length copy of src where comment bodies and string-literal contents are replaced by spaces (delimiters and newlines preserved), so structural pattern matching over the result never registers a comment or string body. Index-aligned with src — a match position in the mask is the same position in src.

typed/builtin//modules/luau_introspect/M/methods

M.methods(src: string) -> { MethodEntry }

Parses function public:<name>(<params>) and typed function public:<name>(<params>) declarations — with an optional : <ret> return-type annotation immediately after the closing paren — into {name, params, returns}. Each param is split on top-level commas into {name, type?}; a ... variadic is captured with name = "...". Folds in desc from docstrings(src).

typed/builtin//modules/luau_introspect/M/moduleExports

M.moduleExports(src: string) -> { ExportEntry }

Parses M.<name> = function(...) assignments, function M.<name>(...) declarations, and a trailing return { foo = foo, ... } export table into {name, kind, signature?, desc?}. kind is "function" for a function assignment/declaration, "value" for any other M.<name> = <expr> assignment (a == comparison is not an assignment). A name that appears only in the return { ... } table infers its kind from whether a same-named function <name>( / local function <name>( declaration exists. Folds in desc from docstrings(src).

typed/builtin//modules/luau_introspect/M/publicFields

M.publicFields(src: string) -> { FieldEntry }

Parses public = { name = Field.<kind>(...), ... } table-literal entries and module-scope public.<name> = Field.<kind>(...) assignments. For a ref constructor (assetRef / dataRef / resource / componentRef) the first positional argument is captured as category and the second as default; for every other kind the first argument is the default. Both are raw trimmed source-text slices, comments stripped. A trailing Sync/NoSync identifier becomes sync. Entries whose key is a computed/indirect expression ([expr] = Field...) are omitted. Comments and string literals never register as entries. Folds in desc from docstrings(src).

typed/builtin//modules/luau_introspect/M/refMethods

M.refMethods(src: string) -> { MethodEntry }

Parses the methods a behavior.luau-style module exposes on a M.ref = { name = fn, ... } table — the assetType's per-asset behavior surface (ref:method(...)). Each entry's key maps to its backing local function <fn>(self, <params>): <ret> (or function <fn>(...)) declaration: the leading self parameter is dropped (it is the ref the method is called on), the remaining params + return annotation + the declaration's --!desc are captured. A key whose value is a table literal or an expression other than a bare function name is skipped. Runs over the comment/string-aware mask, so a commented M.ref never registers.

typed/builtin//modules/luau_introspect/M/tableLiteral

M.tableLiteral(src: string, assignmentName: string) -> TableNode?

Parses a named table literal assignmentName = { ... } into a nested TableNode — each top-level key = value becomes an entry whose value is either a scalar (the trimmed source text of a non-table value, quotes included) or a nested table (TableNode) when the value is itself a { ... }. Runs over the comment/string-aware mask, so a key, {, or } inside a comment or string never registers. Computed ([expr] =) and positional entries are skipped. Returns nil when the assignment is absent.

typed/builtin//modules/luau_introspect/M/tableLiteralKeys

M.tableLiteralKeys(src: string, assignmentName: string) -> { string }

Finds <assignmentName> = { ... } in src and returns the top-level literal-identifier keys of that table (e.g. tableLiteralKeys(src, "operations") on operations = { generate = {...}, from_image = {...} } returns {"generate","from_image"}). Runs over the comment/string-aware mask, so a -- comment or string literal mentioning the assignment name never registers. Comment/string/nesting inside a value never breaks the scan (balanced brace matching, same as publicFields/events). A computed ["key"] entry is omitted — only bare identifier keys are recognised. Returns {} when the assignment is absent.

typed/builtin//modules/material_utils/M/Apply

M.Apply(entityId: string, materialRef: MaterialRefOrName) -> boolean

PascalCase back-compat alias for apply.

typed/builtin//modules/material_utils/M/Create

M.Create(name: string, opts_or_shader: MaterialOpts | string | nil, props: MaterialOpts?) -> MaterialRef?

PascalCase back-compat alias for create. Accepts the legacy 3-arg form (name, shader_string, opts_table) by folding shader into opts, and the canonical 2-arg form (name, opts).

typed/builtin//modules/material_utils/M/Exists

M.Exists(name: MaterialRefOrName) -> boolean

PascalCase back-compat alias for exists.

typed/builtin//modules/material_utils/M/GetProperty

M.GetProperty(materialName: MaterialRefOrName, propertyName: string) -> any

PascalCase back-compat alias for getProperty.

typed/builtin//modules/material_utils/M/GetPropertyNames

M.GetPropertyNames(materialName: MaterialRefOrName) -> { string }?

PascalCase back-compat alias for getPropertyNames.

typed/builtin//modules/material_utils/M/SetProperty

M.SetProperty(materialName: MaterialRefOrName, property: string, value: any) -> any

PascalCase alias. Writes the property on the material ASSET by name/ref (persists into its mat.yaml, affecting every entity using it) — distinct from M.setProperty, which targets the material on one entity's model.

typed/builtin//modules/material_utils/M/SetTexture

M.SetTexture(materialName: MaterialRefOrName, slot: string, textureRef: string) -> boolean

PascalCase back-compat alias for setTexture.

typed/builtin//modules/material_utils/M/apply

M.apply(entity: any, materialRef: MaterialRefOrName) -> boolean

Apply a material to an entity's Model / SkinnedModel component by setting its material field. Accepts either an AssetRef envelope (from Material.create) or a bare material-name string. Errors when the entity has no Model or SkinnedModel — a material only renders where there is a mesh.

typed/builtin//modules/material_utils/M/create

M.create(name: string, opts: MaterialOpts?) -> MaterialRef?

Create a named material in the MaterialRegistry. Returns the canonical AssetRef envelope ({ __ref, type="material", name, guid }) — pass directly to Material.apply, the Model / SkinnedModel material field, or any AssetRef<material> consumer.

typed/builtin//modules/material_utils/M/exists

M.exists(name: MaterialRefOrName) -> boolean

Check whether a material exists in the registry. Accepts an AssetRef envelope or a bare material name.

typed/builtin//modules/material_utils/M/getProperty

M.getProperty(materialName: MaterialRefOrName, propertyName: string) -> any

Read the current value of a material property.

typed/builtin//modules/material_utils/M/getPropertyNames

M.getPropertyNames(materialName: MaterialRefOrName) -> { string }?

List the property names exposed by a registered material.

typed/builtin//modules/material_utils/M/setProperty

M.setProperty(target: any, property: string, value: any)

Set a material property. Addresses the target the same way getProperty does: pass a material name / AssetRef to write the material ASSET (affecting every entity using it), or an entity proxy / id to write the material bound to that entity's Model / SkinnedModel. Errors when an entity target has no Model or SkinnedModel.

typed/builtin//modules/material_utils/M/setTexture

M.setTexture(materialName: MaterialRefOrName, slot: string, textureRef: any) -> boolean

Set a texture slot on a named material.

typed/builtin//modules/numberSequence/M/deserialize

M.deserialize(data: any) -> NumberSequenceObj

Rebuild a NumberSequence from a {kind = "NumberSequence", keypoints = {...}} payload produced by :serialize(). Used by scene save/load.

typed/builtin//modules/numberSequence/M/new

M.new(...: any) -> NumberSequenceObj

Construct a NumberSequence from one of three signatures: a constant value, a two-point lerp from v0 to v1, or a keypoints array of { time, value, envelope? } records. Envelope defaults to 0 when omitted. Up to 64 keypoints; the first must anchor at time = 0, the last at time = 1. NaN / Inf in time / value / envelope is rejected.

typed/builtin//modules/number_range/M/new

M.new(min: number, max: number?) -> any

Construct a NumberRange. Pass one number for a constant range (min == max); pass two for a uniform random range. Reversed arguments are normalized to ascending order.

typed/builtin//modules/nx/gpu/M/fft1d

M.fft1d(opts: Fft1dOpts) -> boolean

1D complex FFT over a power-of-two-sized interleaved complex compute buffer. size is the number of complex samples (must be a power of two ≥ 2). Pass the same input / output name for in-place.

typed/builtin//modules/nx/gpu/M/fft2d

M.fft2d(opts: Fft2dOpts) -> boolean

2D complex FFT over a power-of-two-sized row-major interleaved complex compute buffer. Width and height must both be powers of two ≥ 2.

typed/builtin//modules/nx/gpu/M/ifft1d

M.ifft1d(opts: Fft1dOpts) -> boolean

Convenience: forward 1D FFT with inverse=true — equivalent to M.fft1d(opts) after stamping opts.inverse = true.

typed/builtin//modules/nx/gpu/M/ifft2d

M.ifft2d(opts: Fft2dOpts) -> boolean

Convenience: forward 2D FFT with inverse=true — equivalent to M.fft2d(opts) after stamping opts.inverse = true.

typed/builtin//modules/nx/nx/add

nx.add(dst: NxBuffer, x: NxScalarOrBuffer) -> boolean

b[i] += x (x scalar) or b[i] += x[i] (x buffer). Dispatches on type(x). For interleaved-stride writes use nx.addStrided.

typed/builtin//modules/nx/nx/addStrided

nx.addStrided(b: NxBuffer, scalar: number, stride: number, offset: number?) -> boolean

Strided add: buf[k * stride + offset] += scalar for every valid k.

typed/builtin//modules/nx/nx/addStridedFrom

nx.addStridedFrom(dst: NxBuffer, src: NxBuffer, scale: number?, dst_stride: number, dst_off: number?, src_stride: number, src_off: number?) -> boolean

Strided BLAS-axpy from src into dst: dst[k * dst_stride + dst_off] += scale * src[k * src_stride + src_off].

typed/builtin//modules/nx/nx/applyAbs

nx.applyAbs(b: NxBuffer) -> boolean

In-place b[i] = abs(b[i]).

typed/builtin//modules/nx/nx/applyCeil

nx.applyCeil(b: NxBuffer) -> boolean

In-place b[i] = ceil(b[i]).

typed/builtin//modules/nx/nx/applyCos

nx.applyCos(b: NxBuffer) -> boolean

In-place b[i] = cos(b[i]).

typed/builtin//modules/nx/nx/applyExp

nx.applyExp(b: NxBuffer) -> boolean

In-place b[i] = exp(b[i]).

typed/builtin//modules/nx/nx/applyFloor

nx.applyFloor(b: NxBuffer) -> boolean

In-place b[i] = floor(b[i]).

typed/builtin//modules/nx/nx/applyFract

nx.applyFract(b: NxBuffer) -> boolean

In-place b[i] = fract(b[i]) (fractional part).

typed/builtin//modules/nx/nx/applyLog

nx.applyLog(b: NxBuffer) -> boolean

In-place b[i] = ln(b[i]).

typed/builtin//modules/nx/nx/applyLog2

nx.applyLog2(b: NxBuffer) -> boolean

In-place b[i] = log2(b[i]).

typed/builtin//modules/nx/nx/applyNeg

nx.applyNeg(b: NxBuffer) -> boolean

In-place b[i] = -b[i].

typed/builtin//modules/nx/nx/applyRecip

nx.applyRecip(b: NxBuffer) -> boolean

In-place b[i] = 1 / b[i].

typed/builtin//modules/nx/nx/applyRecipSqrt

nx.applyRecipSqrt(b: NxBuffer) -> boolean

In-place b[i] = 1 / sqrt(b[i]).

typed/builtin//modules/nx/nx/applyRound

nx.applyRound(b: NxBuffer) -> boolean

In-place b[i] = round(b[i]).

typed/builtin//modules/nx/nx/applySign

nx.applySign(b: NxBuffer) -> boolean

In-place b[i] = sign(b[i]) (returns -1, 0, or +1).

typed/builtin//modules/nx/nx/applySin

nx.applySin(b: NxBuffer) -> boolean

In-place b[i] = sin(b[i]).

typed/builtin//modules/nx/nx/applySqrt

nx.applySqrt(b: NxBuffer) -> boolean

In-place b[i] = sqrt(b[i]).

typed/builtin//modules/nx/nx/applySquare

nx.applySquare(b: NxBuffer) -> boolean

In-place b[i] = b[i] * b[i].

typed/builtin//modules/nx/nx/applyTan

nx.applyTan(b: NxBuffer) -> boolean

In-place b[i] = tan(b[i]).

typed/builtin//modules/nx/nx/applyTrunc

nx.applyTrunc(b: NxBuffer) -> boolean

In-place b[i] = trunc(b[i]).

typed/builtin//modules/nx/nx/applyWindow

nx.applyWindow(signal: NxBuffer, window: NxBuffer) -> boolean

Element-wise signal[i] *= window[i] in place. Operates over the shorter of the two — passing a longer window to window a shorter clip is intentional, not an error.

typed/builtin//modules/nx/nx/axpby

nx.axpby(dst: NxBuffer, a: number, src: NxBuffer, b: number) -> boolean

BLAS axpby: dst[i] = a*dst[i] + b*src[i].

typed/builtin//modules/nx/nx/clamp

nx.clamp(b: NxBuffer, min_v: number, max_v: number) -> boolean

In-place clamp: b[i] = clamp(b[i], min_v, max_v).

typed/builtin//modules/nx/nx/copy

nx.copy(dst: NxBuffer, src: NxBuffer) -> boolean

Copy every record from src into dst (memcpy fast path).

typed/builtin//modules/nx/nx/copyStridedFrom

nx.copyStridedFrom(dst: NxBuffer, src: NxBuffer, scale: number?, dst_stride: number, dst_off: number?, src_stride: number, src_off: number?) -> boolean

Strided copy from src into dst with optional scaling: dst[k * dst_stride + dst_off] = scale * src[k * src_stride + src_off].

typed/builtin//modules/nx/nx/create

nx.create(type_: NxType, n: number) -> NxBuffer?

Allocate a CPU buffer of type × len records. Thin alias for substrate.createBuffer({type=type_, len=n, kind="cpu"}) — kept here so the public nx library is the canonical entry point and users never need to import buffer separately.

typed/builtin//modules/nx/nx/div

nx.div(dst: NxBuffer, x: NxScalarOrBuffer) -> boolean

b[i] /= x (x scalar) or b[i] /= x[i] (x buffer).

typed/builtin//modules/nx/nx/dot

nx.dot(a: NxBuffer, b: NxBuffer) -> number?

Reduction: dot product of two same-shaped buffers.

typed/builtin//modules/nx/nx/fft1d

nx.fft1d(re: NxBuffer, im: NxBuffer, inverse: boolean?) -> boolean

In-place 1D FFT over parallel re / im CPU buffers. inverse=true runs the inverse transform scaled by 1/N (so ifft(fft(x)) ≈ x).

typed/builtin//modules/nx/nx/fft2d

nx.fft2d(re: NxBuffer, im: NxBuffer, width: number, height: number, inverse: boolean?) -> boolean

In-place 2D FFT over row-major parallel re / im buffers of length width*height. inverse=true is scaled by 1 / (width * height).

typed/builtin//modules/nx/nx/fill

nx.fill(b: NxBuffer, value: number?) -> boolean

Fill the buffer with value (default 0.0). Equivalent to the scalar form of nx.add against a zeroed buffer, but skips the type-dispatch.

typed/builtin//modules/nx/nx/fillRandomNormal

nx.fillRandomNormal(b: NxBuffer, mean: number?, stddev: number?, seed: NxSeed) -> boolean

Fill the buffer with Gaussian samples (Box-Muller), with the given mean and standard deviation, using a splitmix-keyed PRNG.

typed/builtin//modules/nx/nx/fillRandomUniform

nx.fillRandomUniform(b: NxBuffer, min_v: number?, max_v: number?, seed: NxSeed) -> boolean

Fill the buffer with uniform-random samples in [min, max), using a splitmix-keyed deterministic PRNG.

typed/builtin//modules/nx/nx/fillStrided

nx.fillStrided(b: NxBuffer, value: number, stride: number, offset: number?) -> boolean

Strided fill: buf[k * stride + offset] = value for every valid k.

typed/builtin//modules/nx/nx/fromTable

nx.fromTable(arr: { number }, type_: NxType?) -> NxBuffer?

Build a CPU buffer from a Lua table of numbers. The table is written through buf:write in a single FFI crossing — no per-element Lua loop. For large arrays, prefer one of the nx.* constructors + a kernel pass over building a Lua array first.

typed/builtin//modules/nx/nx/full

nx.full(n: number, type_: NxType?, value: number?) -> NxBuffer?

Allocate a buffer of type × len records and fill with value.

typed/builtin//modules/nx/nx/ifft1d

nx.ifft1d(re: NxBuffer, im: NxBuffer) -> boolean

Convenience: nx.fft1d(re, im, true).

typed/builtin//modules/nx/nx/ifft2d

nx.ifft2d(re: NxBuffer, im: NxBuffer, width: number, height: number) -> boolean

Convenience: nx.fft2d(re, im, w, h, true).

typed/builtin//modules/nx/nx/integratePosition

nx.integratePosition(pos: NxBuffer, vel: NxBuffer, dt: number) -> boolean

Per-vec3: pos[i] += vel[i] * dt — semi-implicit Euler position integration. Both buffers must be vec3 (stride 3).

typed/builtin//modules/nx/nx/irfft1d

nx.irfft1d(re: NxBuffer, im: NxBuffer) -> NxBuffer?

Real-output inverse 1D FFT. Input re / im are length N/2 + 1. Returns a fresh CPU f32 buffer of length 2 * (N/2 + 1 - 1) = N real samples.

typed/builtin//modules/nx/nx/irfft2d

nx.irfft2d(re: NxBuffer, im: NxBuffer, width: number, height: number) -> NxBuffer?

Real-output inverse 2D FFT. Input re / im are (width/2 + 1) * height row-major. Returns a fresh f32 buffer of length width * height.

typed/builtin//modules/nx/nx/lerpTo

nx.lerpTo(dst: NxBuffer, src: NxBuffer, t: number) -> boolean

dst[i] += t * (src[i] - dst[i]) — element-wise lerp toward src by t.

typed/builtin//modules/nx/nx/max

nx.max(b: NxBuffer) -> number?

Reduction: maximum of all elements.

typed/builtin//modules/nx/nx/maxOp

nx.maxOp(dst: NxBuffer, x: NxScalarOrBuffer) -> boolean

Element-wise b[i] = max(b[i], x) (scalar) or b[i] = max(b[i], x[i]) (buffer).

typed/builtin//modules/nx/nx/mean

nx.mean(b: NxBuffer) -> number?

Reduction: arithmetic mean of all elements.

typed/builtin//modules/nx/nx/min

nx.min(b: NxBuffer) -> number?

Reduction: minimum of all elements.

typed/builtin//modules/nx/nx/minOp

nx.minOp(dst: NxBuffer, x: NxScalarOrBuffer) -> boolean

Element-wise b[i] = min(b[i], x) (scalar) or b[i] = min(b[i], x[i]) (buffer).

typed/builtin//modules/nx/nx/mul

nx.mul(dst: NxBuffer, x: NxScalarOrBuffer) -> boolean

b[i] *= x (x scalar) or b[i] *= x[i] (x buffer).

typed/builtin//modules/nx/nx/mulStrided

nx.mulStrided(b: NxBuffer, scalar: number, stride: number, offset: number?) -> boolean

Strided multiply: buf[k * stride + offset] *= scalar for every valid k.

typed/builtin//modules/nx/nx/normL1

nx.normL1(b: NxBuffer) -> number?

Reduction: L1 norm — sum(|b[i]|).

typed/builtin//modules/nx/nx/normL2

nx.normL2(b: NxBuffer) -> number?

Reduction: L2 norm — sqrt(sum(b[i]^2)).

typed/builtin//modules/nx/nx/normalizeVec3

nx.normalizeVec3(b: NxBuffer) -> boolean

Normalise each vec3 in-place. Vectors below 1e-8 are left untouched.

typed/builtin//modules/nx/nx/ones

nx.ones(n: number, type_: NxType?) -> NxBuffer?

Allocate a buffer of type × len records and fill with 1.0.

typed/builtin//modules/nx/nx/pow

nx.pow(b: NxBuffer, p: number) -> boolean

In-place b[i] = b[i] ^ p (scalar exponent).

typed/builtin//modules/nx/nx/quatFromYaw

nx.quatFromYaw(dst: NxBuffer, yaw: NxBuffer) -> boolean

Per-quat: dst[i] = (0, sin(yaw[i]/2), 0, cos(yaw[i]/2)) — the pure-Y axis-angle quaternion for each yaw value. dst must be stride-4 (quat); yaw must be stride-1 (f32).

typed/builtin//modules/nx/nx/rfft1d

nx.rfft1d(signal: NxBuffer?) -> (NxBuffer?, NxBuffer?)

Real-input forward 1D FFT. Allocates two new CPU f32 buffers of length N/2 + 1 holding the (re, im) parts of the Hermitian-symmetric spectrum (same convention as NumPy np.fft.rfft).

typed/builtin//modules/nx/nx/rfft2d

nx.rfft2d(signal: NxBuffer, width: number, height: number) -> (NxBuffer?, NxBuffer?)

Real-input forward 2D FFT. Input signal is row-major width*height. Returns (re_buf, im_buf) of length (width/2 + 1) * height each (matches np.fft.rfft2 layout).

typed/builtin//modules/nx/nx/scale

nx.scale(b: NxBuffer, s: number) -> boolean

In-place b[i] *= s.

typed/builtin//modules/nx/nx/sinCosTo

nx.sinCosTo(src: NxBuffer, sin_dst: NxBuffer, cos_dst: NxBuffer) -> boolean

Compute sin_dst[i] = sin(src[i]) and cos_dst[i] = cos(src[i]) in one pass using cheaper paired-trig argument reduction.

typed/builtin//modules/nx/nx/sub

nx.sub(dst: NxBuffer, x: NxScalarOrBuffer) -> boolean

b[i] -= x (x scalar) or b[i] -= x[i] (x buffer).

typed/builtin//modules/nx/nx/sum

nx.sum(b: NxBuffer) -> number?

Reduction: sum of all elements.

typed/builtin//modules/nx/nx/wanderYaw

nx.wanderYaw(args: NxWanderArgs) -> boolean

Fused per-entity wander step. Each entity's yaw[i] walks by a uniform random delta in [-yawDelta, +yawDelta], then pos[i] advances forward in the (sin yaw, cos yaw) direction by step. Optional rot quat output writes a pure-Y axis-angle rotation. Replaces the per-entity Luau loop pattern (~12 ms / 5000 in interpreter) with a single Rust pass (~0.2 ms / 5000). Buffer requirements: pos vec3 (stride 3), yaw f32 (stride 1), rot optional quat (stride 4). All counts should match (kernel walks min(count_i)).

typed/builtin//modules/nx/nx/window/blackman

nx.window.blackman(n: number) -> NxBuffer?

Allocate a fresh CPU f32 buffer of length n filled with a symmetric Blackman window (NumPy np.blackman convention).

typed/builtin//modules/nx/nx/window/hamming

nx.window.hamming(n: number) -> NxBuffer?

Allocate a fresh CPU f32 buffer of length n filled with a symmetric Hamming window (NumPy np.hamming convention).

typed/builtin//modules/nx/nx/window/hann

nx.window.hann(n: number) -> NxBuffer?

Allocate a fresh CPU f32 buffer of length n filled with a symmetric Hann window (NumPy np.hanning convention).

typed/builtin//modules/nx/nx/zeros

nx.zeros(n: number, type_: NxType?) -> NxBuffer?

Allocate a buffer of type × len records and fill with 0.0.

typed/builtin//modules/physics_utils/P/addCollider

P.addCollider(entityId: string, config: table)

Add a Collider component to an entity.

typed/builtin//modules/physics_utils/P/addConstraint

P.addConstraint(entityId: string, opts: table?)

Add a transform constraint to an entity.

typed/builtin//modules/physics_utils/P/addJoint

P.addJoint(entityIdA: string, entityIdB: string, opts: table?)

Add a Joint component connecting two entities. Accepts either vec3-style anchor inputs (localAnchor = {x,y,z}) or pre-split scalar keys (localAnchorX/Y/Z).

typed/builtin//modules/physics_utils/P/addVelocity

P.addVelocity(a: string | number | vec3, b: (number | vec3)?, c: number?, d: number?)

Add to the linear velocity of an entity. Same call shapes as setVelocity.

typed/builtin//modules/physics_utils/P/addWheelCollider

P.addWheelCollider(entityId: string, config: table?)

Add a WheelCollider to an entity. The entity must be a child (or descendant) of a rigid body — the system walks up the hierarchy to find the Physics component.

typed/builtin//modules/physics_utils/P/applyForce

P.applyForce(entityIdOrForce: string | vec3, force: vec3?)

Apply a force to an entity's rigid body for the next physics step — call every frame for continuous thrust. With one argument the script-context entity is targeted; with two args the explicit entity id wins.

typed/builtin//modules/physics_utils/P/applyForceAtPoint

P.applyForceAtPoint(entityId: string, force: vec3, point: vec3)

Apply a force at a specific world-space point — generates the matching torque from the lever arm.

typed/builtin//modules/physics_utils/P/applyImpulse

P.applyImpulse(entityIdOrImpulse: string | vec3, impulse: vec3?)

Apply an instantaneous impulse (one-shot velocity change). With one argument the script-context entity is targeted; with two args the explicit entity id wins.

typed/builtin//modules/physics_utils/P/applyTorque

P.applyTorque(entityIdOrTorque: string | vec3, torque: vec3?)

Apply a torque to an entity's rigid body for the next physics step — call every frame for continuous spin-up. With one argument the script-context entity is targeted; with two args the explicit entity id wins.

typed/builtin//modules/physics_utils/P/boxCast

P.boxCast(origin: vec3, halfExtents: vec3, direction: vec3, maxDistance: number?) -> table?

Cast a box along a direction and return the first hit.

typed/builtin//modules/physics_utils/P/colliderShapes

P.colliderShapes(entityId: string) -> table

Read an entity's resolved physics collider shape(s) — box half-extents, sphere/capsule radius, or convex line points — as the physics engine sees them, including auto-sized colliders.

typed/builtin//modules/physics_utils/P/getAngularVelocity

P.getAngularVelocity(entityId: string?) -> vec3?

Read the angular velocity of an entity's rigid body.

typed/builtin//modules/physics_utils/P/getGravity

P.getGravity() -> vec3

Read the current world gravity vector.

typed/builtin//modules/physics_utils/P/getVelocity

P.getVelocity(entityId: string?) -> vec3?

Read the linear velocity of an entity's rigid body.

typed/builtin//modules/physics_utils/P/getWheelState

P.getWheelState(entityId: string) -> table?

Read a wheel collider's runtime state. Reads the native component the wheel system writes after each physics step.

typed/builtin//modules/physics_utils/P/hasLineOfSight

P.hasLineOfSight(fromId: string, toId: string) -> boolean

Check whether two entities have line-of-sight between their origins.

typed/builtin//modules/physics_utils/P/ignoreCollision

P.ignoreCollision(entityIdA: string, entityIdB: string, ignore: boolean?)

Toggle ignored-collision state between two specific entities.

typed/builtin//modules/physics_utils/P/isSleeping

P.isSleeping(entityId: string?) -> boolean?

Whether an entity's rigid body is currently asleep (at rest and not simulating). A body sleeps once it stops moving, to save simulation cost.

typed/builtin//modules/physics_utils/P/overlapSphere

P.overlapSphere(center: vec3, radius: number) -> table

Find every entity id whose colliders overlap a sphere.

typed/builtin//modules/physics_utils/P/raycast

P.raycast(origin: vec3, direction: vec3, maxDistance: number?, exclude: (string | {string})?) -> table?

Cast a ray and return the first hit.

typed/builtin//modules/physics_utils/P/raycastAll

P.raycastAll(origin: vec3, direction: vec3, maxDistance: number?, maxHits: number?, exclude: (string | {string})?) -> table

Cast a ray and return every hit up to maxHits.

typed/builtin//modules/physics_utils/P/raycastBetween

P.raycastBetween(fromId: string, toId: string, maxDistance: number?) -> table?

Cast a ray from one entity toward another and return the first hit.

typed/builtin//modules/physics_utils/P/raycastScreen

P.raycastScreen(sx: number, sy: number, maxDistance: number?, exclude: (string | {string})?) -> table?

Cast a ray from a screen pixel into the scene and return the first hit. Unprojects the pixel with screenToRay, then casts with raycast.

typed/builtin//modules/physics_utils/P/removeCollider

P.removeCollider(entityId: string)

Remove the Collider component from an entity (if present).

typed/builtin//modules/physics_utils/P/removeConstraint

P.removeConstraint(entityId: string, index: number?)

Remove transform constraints from an entity (if any are present).

typed/builtin//modules/physics_utils/P/removeJoint

P.removeJoint(entityId: string)

Remove the Joint component from an entity (if present).

typed/builtin//modules/physics_utils/P/removeWheelCollider

P.removeWheelCollider(entityId: string)

Remove the WheelCollider component from an entity (if present).

typed/builtin//modules/physics_utils/P/setAngularDamping

P.setAngularDamping(entityIdOrDamping: string | number, damping: number?)

Set angular damping on an entity's rigid body. One-arg form targets the script-context entity.

typed/builtin//modules/physics_utils/P/setAngularVelocity

P.setAngularVelocity(a: string | number | vec3, b: (number | vec3)?, c: number?, d: number?)

Set the angular velocity of an entity (radians/sec). Same call shapes as setVelocity.

typed/builtin//modules/physics_utils/P/setBodyType

P.setBodyType(entityId: string, bodyType: string)

Change a rigid body's type at runtime. Mass, colliders, and joints are preserved — only the body's response to forces and position writes changes.

typed/builtin//modules/physics_utils/P/setCcdEnabled

P.setCcdEnabled(entityIdOrEnabled: string | boolean, enabled: boolean?)

Enable or disable continuous collision detection on an entity's rigid body. One-arg form targets the script-context entity.

typed/builtin//modules/physics_utils/P/setCollisionGroups

P.setCollisionGroups(entityId: string, membership: number, filter: number)

Set the collision-group membership and filter bitmasks on an entity's colliders. Adds a CollisionGroup component if missing.

typed/builtin//modules/physics_utils/P/setGravity

P.setGravity(gravity: vec3)

Replace the world gravity vector.

typed/builtin//modules/physics_utils/P/setGravityScale

P.setGravityScale(entityIdOrScale: string | number, scale: number?)

Set the per-entity gravity scale (1.0 = normal, 0.0 = no gravity). One-arg form targets the script-context entity.

typed/builtin//modules/physics_utils/P/setJointMotor

P.setJointMotor(entityId: string, targetVelocity: number, maxForce: number)

Set a motor on an entity's joint.

typed/builtin//modules/physics_utils/P/setLinearDamping

P.setLinearDamping(entityIdOrDamping: string | number, damping: number?)

Set linear damping on an entity's rigid body (0 = no damping). One-arg form targets the script-context entity.

typed/builtin//modules/physics_utils/P/setMass

P.setMass(entityIdOrMass: string | number, mass: number?)

Set the mass of an entity's rigid body (kg). One-arg form targets the script-context entity.

typed/builtin//modules/physics_utils/P/setRotationLocks

P.setRotationLocks(entityId: string, x: boolean, y: boolean, z: boolean)

Lock or unlock rotation on specific axes.

typed/builtin//modules/physics_utils/P/setTranslationLocks

P.setTranslationLocks(entityId: string, x: boolean, y: boolean, z: boolean)

Lock or unlock translation on specific axes.

typed/builtin//modules/physics_utils/P/setVelocity

P.setVelocity(a: string | number | vec3, b: (number | vec3)?, c: number?, d: number?)

Set the linear velocity of an entity. Accepts (x, y, z) or a {x, y, z} vector for the script-context entity, or the same prefixed with an explicit entityId.

typed/builtin//modules/physics_utils/P/sphereCast

P.sphereCast(origin: vec3, radius: number, direction: vec3, maxDistance: number?) -> table?

Cast a sphere along a direction and return the first hit.

typed/builtin//modules/physics_utils/P/wakeUp

P.wakeUp(entityId: string?)

Wake an entity's sleeping rigid body so it resumes simulating. The motion setters (applyImpulse, setVelocity, setAngularVelocity) wake the body for you; call this to wake one explicitly.

typed/builtin//modules/preset/M/create

M.create(name: string, entityId: string, componentType: string, opts: PresetCreateOpts?) -> PresetCreateResult

Snapshot an existing component's public property table into a preset asset on disk. Bare names land under /source/presets/<name>.preset/preset.yaml; absolute paths must point to a .preset directory or its inner preset.yaml.

typed/builtin//modules/preset/M/load

M.load(source: AssetRef<preset>, overrides: table?) -> { [string]: any }

Load a preset asset and return the plain component property table.

typed/builtin//modules/settings/settings/all

settings.all() -> { [string]: any }

Snapshot of the entire settings document (parsed). Modifying the returned table does NOT propagate — call set or setMany to persist. Useful for editors/inspectors that render every section.

typed/builtin//modules/settings/settings/get

settings.get(key: string) -> any

Look up a value by dotted key. Returns whatever the file holds at that path — string / number / boolean / array / table — or nil if missing.

typed/builtin//modules/settings/settings/getBool

settings.getBool(key: string, default: boolean?) -> boolean

Boolean-typed accessor. Returns the value when present and boolean-typed; falls back to default (or false) on missing key or type mismatch.

typed/builtin//modules/settings/settings/getNumber

settings.getNumber(key: string, default: number?) -> number

Number-typed accessor. Returns the value when present and number-typed; falls back to default (or 0) on missing key or type mismatch.

typed/builtin//modules/settings/settings/getString

settings.getString(key: string, default: string?) -> string

String-typed accessor. Returns the value when present and string-typed; falls back to default (or "" if omitted) on missing key or type mismatch.

typed/builtin//modules/settings/settings/set

settings.set(key: string, value: any)

Set a value by dotted key, then serialize and write the file. In play mode the write fails like any other source-file write — call wld.edit() first to unlock.

typed/builtin//modules/settings/settings/setMany

settings.setMany(updates: { [string]: any })

Apply many key/value updates in one batched write — fewer serialize+write round-trips than calling set per-key. Same lock semantics as set.

typed/builtin//modules/signal/M/disconnectAllFromEntity

M.disconnectAllFromEntity(entityId: string) -> number

Disconnect every connection that was sourced from entityId (connections made while that entity's script was on the call stack). Returns the number disconnected. Called by the entity-destroy dispatch so a destroyed entity's connections never leak.

typed/builtin//modules/signal/M/disconnectAllFromInstance

M.disconnectAllFromInstance(instanceId: string) -> number

Disconnect every connection sourced from a specific component instance (connections made while that instance's script was on the call stack). Returns the number disconnected. Called by the component hot-reload / teardown path so a reloaded instance's stale connections don't accumulate.

typed/builtin//modules/signal/M/new

M.new() -> any

Construct a new Signal.

typed/builtin//modules/substrate_batch/M/installInto

M.installInto(entity: EntityNamespace)

Install the polymorphic batchWrite / batchRead wrappers onto an entity-shaped namespace. The prelude calls this once at boot with the engine's entity global; users shouldn't call it directly. Errors if the namespace is missing any of the five required FFI primitives.

typed/builtin//modules/text_diff/M/added

M.added(newText: string?, opts: DiffOpts?) -> FileDiff

Pure-add convenience: build a diff representing the full content of newText as added. Equivalent to M.diff("", newText, opts).

typed/builtin//modules/text_diff/M/diff

M.diff(oldText: string?, newText: string?, opts: DiffOpts?) -> FileDiff

Diff two strings and return the structured per-file shape. LCS-based; produces op-tagged hunks rather than unified-diff text so consumers can pattern-match on op instead of parsing prefixes. Files larger than M.SIZE_CAP_BYTES return a size-only summary with is_text=false.

typed/builtin//modules/text_diff/M/removed

M.removed(oldText: string?, opts: DiffOpts?) -> FileDiff

Pure-remove convenience: full removal of oldText. Equivalent to M.diff(oldText, "", opts).

typed/builtin//modules/text_diff/M/toStatLine

M.toStatLine(fileDiff: FileDiff) -> string

Compact --stat-style summary line for a single file. Mirrors git diff --stat's per-file row.

typed/builtin//modules/text_diff/M/toUnifiedText

M.toUnifiedText(fileDiff: FileDiff) -> string

Render a single file's structured diff back into unified-diff text. Used by zm diff / zm show shell commands when the user wants the conventional +/-/ text output instead of structured hunks. Pure derivation from the structured shape — no second LCS pass.

typed/builtin//modules/toml/toml/encode

toml.encode(root: { [string]: any }) -> string

Encode a Luau table as canonical TOML bytes. Top-level string-keyed sub-tables become section headers ([name]); deeper string-keyed tables become dotted sections ([a.b]). Sequence tables are emitted as inline arrays, and string-keyed tables in value position (e.g. array elements) as inline tables ({ k = v }). Section + key order is alphabetical so the same input always produces the same bytes.

typed/builtin//modules/toml/toml/parse

toml.parse(src: string) -> { [string]: any }

Parse a TOML document into a nested Luau table. Sections ([a.b]) become nested tables; key/value pairs become entries on the current section (or root if before any section header). Throws with the line number on syntax errors.

typed/builtin//modules/tools/M/create

M.create(args: { [string]: any }) -> { ok: boolean, path: string?, identity: string?, signature: string?, error: string? }

Create a new tool on disk inside an EXISTING toolbox. Scaffolds the .tool/ folder via asset.create("tool", …), then writes the supplied code wrapped in a documented typed function into init.luau (the --!desc/--!arg/--!return/ --!example doc block + signature built from the structured metadata), the tags into .metadata, and a brief README.md — so the authored tool is indistinguishable from a builtin. Errors cleanly if the parent toolbox doesn't exist — call tools.createToolbox first so the toolbox starts out with a real description instead of the placeholder template body. The engine's normal hot-reload pipeline picks up the new files and binds the tool's global on the next pass. Every toolbox created via tools.createToolbox ships a shared.module/ (the template default has ok/fail result-envelope constructors; users can extend or replace it via sharedCode at create time or by editing the module later). The generated init.luau automatically declares local shared = require(".shared") before your function body, so the code you pass can reference shared.ok(...) / shared.fail(...) (or whatever the toolbox's custom helpers expose) directly. If a toolbox doesn't have a shared.module/ for some reason, the require is skipped so there's no dangling import to fail.

typed/builtin//modules/tools/M/createToolbox

M.createToolbox(args: { [string]: any }) -> { ok: boolean, path: string?, identity: string?, error: string? }

Create a new toolbox folder. A toolbox is the namespace container for tools — .toolbox/ on disk; once tools are authored inside it they are invoked as tools.use("<name>", "<toolName>", …). This call scaffolds the .toolbox/ folder via asset.create("toolbox", …) and overwrites the placeholder README.md with a real description so the toolbox doesn't ship the template stub. Optionally seeds shared.module/ if the caller supplies cross-tool helper code. Authoring a tool inside this toolbox is the separate tools.create call.

typed/builtin//modules/tools/M/delete

M.delete(identity: string) -> { ok: boolean, path: string?, error: string? }

Remove a previously-authored tool by identity. Deletes the .tool/ folder and its contents from the VFS via vfs.remove(..., { recursive = true }). The engine drops the tool's global on the next hot-reload pass. Refuses to operate on a path that doesn't exist (returns { ok = false } with an explanatory error).

typed/builtin//modules/tools/M/get

M.get(identity: string) -> ToolMeta?

Read back a tool's assembled metadata — description, typed signature, per-argument docs, return, examples, and tags — gathered from the four canonical sources in its .tool/ folder. Individual tools aren't entries in the asset index (only their parent toolboxes are), so this resolves the toolbox via asset.resolve(toolbox, "toolbox") and reads the tool relative to it. Returns nil when the toolbox or tool is missing.

typed/builtin//modules/tools/M/list

M.list(tier: (number | string)?, toolbox: string?) -> { stdout: string, value: any }

Discover registered code-mode tools, grouped by toolbox. Default tier returns just { <toolbox> = { name, name, … } } plus a formatted stdout listing every toolbox on one line with its tools — compact enough that listing the whole catalogue doesn't flood agent context. Higher tiers enrich each entry with its one-line description (tier 2) or its full assembled metadata — signature, args, returns, examples (tier 3). Pass a toolbox name to restrict the output to one toolbox.

M.search(query: string?, opts: { toolbox: string?, limit: number? }?) -> { stdout: string, value: any }

Search registered code-mode tools by relevance, the canonical in-engine tool-discovery entry point — callable from execute Luau so an agent can find the tool it needs without leaving the engine. Enumerates every tool across every toolbox (reusing the same filesystem discovery tools.list uses), then scores each against the query: a token hit in the tool NAME weighs most, then its DESCRIPTION, then its TAGS. Tools scoring above zero are returned best-first. With an empty/omitted query and no toolbox filter, returns the whole catalogue (name + signature

  • toolbox) so the agent can browse. Each returned name is the tool's <toolbox>.<tool> identity; invoke it with the use_tool MCP tool (toolbox + tool + positional args), the form each entry's examples are rendered in.

typed/builtin//modules/tools/M/toolboxes

M.toolboxes() -> { stdout: string, value: { { toolbox: string, purpose: string, toolCount: number } } }

Discover the registered toolboxes as a grouped overview — one row per toolbox with its one-line purpose and tool count. The toolbox-first entry point to tool discovery: an agent navigates by DOMAIN (which toolbox), then drills into a toolbox's tools with tools.search("", { toolbox = "<name>" }). purpose is sourced from the toolbox's README.md (its first descriptive line), falling back to the .metadata description.

typed/builtin//modules/tools/M/use

M.use(toolbox: string, tool: string, ...: any) -> any

Invoke one code-mode tool by naming its toolbox and tool explicitly — the Luau-code counterpart to the use_tool MCP tool. The normal path is the use_tool MCP tool; this is the escape hatch for editor panels and shipped modules that script a tool from engine Luau. Resolves the toolbox from the runtime store (builtin, library, and user-authored runtime toolboxes all work), calls the named tool with the remaining args, and returns the tool's value directly — unwrapping the ZmToolResult envelope and RAISING a Luau error when the tool fails. Because every call names both toolbox and tool, it can never read as a tools.<box> namespace.

typed/builtin//modules/transform/T/direction

T.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).

typed/builtin//modules/transform/T/directionBetween

T.directionBetween(entityA: EntityRef, entityB: EntityRef) -> (number, number, number)

Normalized direction from one entity to another. Returns zeros if either entity can't be resolved.

typed/builtin//modules/transform/T/distance

T.distance(x1: number, y1: number, z1: number, x2: number, y2: number, z2: number) -> number

Euclidean distance between two world-space positions.

typed/builtin//modules/transform/T/distanceBetween

T.distanceBetween(entityA: EntityRef, entityB: EntityRef) -> number?

Distance between two entities in world space.

typed/builtin//modules/transform/T/euler

T.euler(qx: number, qy: number, qz: number, qw: number) -> (number, number, number)

Convert quaternion to euler angles (yaw, pitch, roll) in radians.

typed/builtin//modules/transform/T/eulerToQuat

T.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).

typed/builtin//modules/transform/T/lerp

T.lerp(ax: number, ay: number, az: number, bx: number, by: number, bz: number, t: number) -> (number, number, number)

Linearly interpolate between two positions.

typed/builtin//modules/transform/T/lerp1

T.lerp1(a: number, b: number, t: number) -> number

Linearly interpolate two scalars.

typed/builtin//modules/transform/T/lerpAngle

T.lerpAngle(a: number, b: number, t: number) -> number

Lerp between two angles via the shortest arc; returns a value in [-pi, pi].

typed/builtin//modules/transform/T/localToWorld

T.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.

typed/builtin//modules/transform/T/lookAt

T.lookAt(entityOrId: EntityRef, txOrTarget: number | string, ty: number?, tz: number?)

Make an entity face a world position. The target slot accepts either three explicit coordinates or an entity id whose position is resolved.

typed/builtin//modules/transform/T/lookAtQuat

T.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.

typed/builtin//modules/transform/T/normalizeAngle

T.normalizeAngle(a: number) -> number

Normalize an angle into [-pi, pi].

typed/builtin//modules/transform/T/orbit

T.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.

typed/builtin//modules/transform/T/quatFromAxisAngle

T.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).

typed/builtin//modules/transform/T/quatFromYaw

T.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.

typed/builtin//modules/transform/T/quatFromYawPitch

T.quatFromYawPitch(yaw: number, pitch: number) -> (number, number, number, number)

Create quaternion from yaw and pitch in radians.

typed/builtin//modules/transform/T/quatIdentity

T.quatIdentity() -> (number, number, number, number)

Identity quaternion (0, 0, 0, 1).

typed/builtin//modules/transform/T/quatInverse

T.quatInverse(qx: number, qy: number, qz: number, qw: number) -> (number, number, number, number)

Quaternion inverse. Equal to the conjugate for unit quaternions.

typed/builtin//modules/transform/T/quatMul

T.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).

typed/builtin//modules/transform/T/quatRotateVec

T.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.

typed/builtin//modules/transform/T/quatToEuler

T.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.

typed/builtin//modules/transform/T/slerp

T.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).

typed/builtin//modules/transform/T/vec/add

T.vec.add(ax: number, ay: number, az: number, bx: number, by: number, bz: number) -> (number, number, number)

Component-wise vec3 addition.

typed/builtin//modules/transform/T/vec/cross

T.vec.cross(ax: number, ay: number, az: number, bx: number, by: number, bz: number) -> (number, number, number)

Cross product a x b.

typed/builtin//modules/transform/T/vec/dot

T.vec.dot(ax: number, ay: number, az: number, bx: number, by: number, bz: number) -> number

Dot product of two vec3s.

typed/builtin//modules/transform/T/vec/length

T.vec.length(x: number, y: number, z: number) -> number

Euclidean length of a vec3.

typed/builtin//modules/transform/T/vec/normalize

T.vec.normalize(x: number, y: number, z: number) -> (number, number, number)

Normalize a vec3. Returns zeros when the input is degenerate (length < 1e-8).

typed/builtin//modules/transform/T/vec/scale

T.vec.scale(x: number, y: number, z: number, s: number) -> (number, number, number)

Component-wise scalar multiplication of a vec3.

typed/builtin//modules/transform/T/vec/sub

T.vec.sub(ax: number, ay: number, az: number, bx: number, by: number, bz: number) -> (number, number, number)

Component-wise vec3 subtraction (a - b).

typed/builtin//modules/transform/T/worldToLocal

T.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.

typed/builtin//modules/vfs_async_read/M/installInto

M.installInto(vfs: VfsNamespace)

Install the yielding read wrapper onto the supplied vfs-shaped namespace. The prelude calls this once at boot with the engine's vfs global; users shouldn't call it directly. No-op if the target doesn't expose both read and readAsync as functions.

typed/builtin//modules/viz/viz/clear

viz.clear(vizId: string, channel: string?)

Clear a specific visualization by ID (and optional channel).

typed/builtin//modules/viz/viz/clearAll

viz.clearAll()

Clear every active visualization.

typed/builtin//modules/viz/viz/create

viz.create(name: string, duration: number, updateSource: string?) -> VizContext

Create a managed visualization context. Returns a context table with :spawn(name), :track(id), and :done(). Entities created via :spawn() are placed in the __viz scene layer and auto-despawned when the viz expires; existing entities can be marked for auto-despawn via :track.

typed/builtin//modules/viz/viz/flashOutline

viz.flashOutline(entityId: string, duration: number?, color: Color3?)

Flash an outline on an entity (no scale change). Good for modification feedback.

typed/builtin//modules/viz/viz/flashTint

viz.flashTint(entityId: string, duration: number?, color: Color3?)

Brief colour tint that fades. Good for property-change feedback.

typed/builtin//modules/viz/viz/label

viz.label(entityId: string, text: string, duration: number?)

Spawn a 3D text label above an entity that fades after duration. Currently a no-op pending the Luau WASM -fwasm-exceptions rebuild (see #1230) — viz.label is purely cosmetic and was breaking the WASM logic tick when its spawn-chain ran before vtables were published. Keeps the surface stable so tool scripts can still call it; behaviour returns when the engine binding is unblocked.

typed/builtin//modules/viz/viz/lightRadius

viz.lightRadius(entityId: string, radius: number, duration: number?, color: Color3?)

Light radius indicator — brief sphere outline showing a light's range. Flashes the light entity itself.

typed/builtin//modules/viz/viz/popIn

viz.popIn(entityId: string, duration: number?, color: Color3?)

Pop-in animation: entity scales from 0 to 1 with a coloured outline pulse. Call this right after spawning an entity to give it a smooth entrance. Uses VizTransform overlay — never touches the entity's real Transform.

typed/builtin//modules/viz/viz/shrinkOut

viz.shrinkOut(entityId: string, duration: number?)

Shrink-out animation: entity scales from 1 to 0 with a red tint. Uses VizTransform overlay — never touches the entity's real Transform. Call this BEFORE despawning to give a smooth exit; the actual entity.despawn should be issued by the caller after this duration.

typed/builtin//modules/viz/viz/smooth

viz.smooth(entityId: string, duration: number?)

Smooth visual transition for any transform change (position, rotation, scale). Pure visual — never touches the entity's real Transform. Call this after making any transform change; it automatically reads PreviousTransform (auto-maintained by the engine) to compute the delta and animate the visual offset back to identity.

typed/builtin//modules/viz/viz/spin

viz.spin(entityId: string, opts: SpinOpts?)

Spin animation: entity rotates around an axis over duration then stops. Uses VizTransform overlay — never touches the entity's real Transform.

typed/builtin//modules/viz/viz/trigger

viz.trigger(nameOrOpts: string | TriggerOpts, source: string?, duration: number?, updateSource: string?)

Trigger a raw visualization. Accepts either a name + positional args, or an opts table.

typed/builtin//modules/world_sync/M/installInto

M.installInto(world: WorldNamespace)

Graft syncStatus / resolveConflict onto the supplied world namespace. The prelude calls this once at boot.

typed/builtin//modules/world_sync/world/resolveConflict

world.resolveConflict(path: string, mode: string, content: string?) -> ResolveResult

Resolve one conflicted /source record, one path at a time. mode is merge | apply | take-local | take-backend | discard. merge returns { merged, clean } and mutates nothing — a clean merge can be finalized with apply, and a conflicted one carries <<<<<<< / ======= / >>>>>>> markers to edit first. apply writes the finalized content to /source; take-local writes the retained local bytes; take-backend / discard keep the backend head. Errors when the record is absent, a merge has no common ancestor or hits binary content, or a write fails.

typed/builtin//modules/world_sync/world/syncStatus

world.syncStatus() -> SyncStatus

Read the durable-sync status: { subscribed, content_synced, progress, pending_writes, conflicts }. conflicts maps each conflicted /source path to { base_sha, local_sha, backend_sha, isBinary }. Synchronous.

typed/builtin//modules/world_vcs/M/__hasConflictMarkers

M.__hasConflictMarkers(text: string) -> boolean

True if text contains a git-style conflict-marker line (<<<<<<<, =======, or >>>>>>>) anchored at the start of a line. The gate's resolution validator: a conflicted row can only clear once its file has no marker lines left. Anchoring at line start (not a bare substring search) avoids false-flagging prose that merely mentions the marker text mid-line.

typed/builtin//modules/world_vcs/M/__reconcileDecision

M.__reconcileDecision(base: string, ours: string, theirs: string) -> string

Decide the three-way reconcile action for one pulled-asset row from its three content checksums (base = last-known origin checksum, ours = current local checksum, theirs = latest upstream checksum). Pure — no I/O, no VCS calls. world.pullAsset drives its reconcile loop off this decision per row.

typed/builtin//modules/world_vcs/M/installInto

M.installInto(world: WorldNamespace)

Graft the VCS public API (add, add_all, unstage, discard, discardFile, commit, push, head, vcsStatus, log, show, diff, affirm, trash, restore, stash, stashes, stashPop, stashDrop, reset, list, installLibrary, uninstallLibrary, installAsset) onto the supplied world namespace. The prelude calls this once at boot.

typed/builtin//modules/world_vcs/world/add

world.add(path: string, opts: AddOpts?)

Stage one path's manifest row, expanding to the full asset family if the path lives inside a composite asset. Idempotent at (stage, manifest_row). Pass { force = true } to bypass the .zmignore / .gitignore gate — same intent as git add -f. Without force, attempts to stage an ignored path (or a path whose .refs points at an ignored dep) error.

typed/builtin//modules/world_vcs/world/add_all

world.add_all() -> { string }

Stage every dirty manifest row, skipping any path that matches .zmignore / .gitignore. Paths that match an ignore pattern are silently skipped — world.add(path, { force = true }) is the explicit way to override the gate for an individual path. Rows still flagged conflicted by world.pullAsset are held back too — resolve them (edit + world.add(path), or world.resolvePullConflict) and re-run.

typed/builtin//modules/world_vcs/world/affirm

world.affirm(token: string)

Consume an XXX-XXX-XXX-style affirmation token returned by a destructive op surface (e.g. vfs.remove). The destruction commits atomically with the pending-row delete; the token is one-shot. Errors verbatim on expiry / wrong-user.

typed/builtin//modules/world_vcs/world/checkUpdates

world.checkUpdates() -> { UpdateReport }

Discover upstream changes for every asset this world has pulled. Read-only — makes no local mutation and no VCS write. Each locally-pulled row identifies its own origin asset via origin_asset_guid (recorded as that entry's own asset guid at pull time — see world.installAsset). For every distinct origin asset among the pulled rows, this re-resolves that asset's latest transitive closure and compares each returned entry's checksum against the matching local row's recorded origin_checksum.

typed/builtin//modules/world_vcs/world/commit

world.commit(message: string) -> string

typed/builtin//modules/world_vcs/world/conflicts

world.conflicts() -> { ConflictEntry }

List every locally-pulled row currently flagged conflicted — the findable surface world.pullAsset leaves behind on an unresolved merge. Read-only.

typed/builtin//modules/world_vcs/world/contentRequirements

world.contentRequirements(scope: { string }?) -> { { asset: string, typeName: string, detail: string } }

List the world's unmet content requirements: user-authored assets whose type-declared content constraints are not yet satisfied (an empty README, a .metadata with no description or tags — the empty-skeleton state a fresh create emits for the author to fill). The same walk world.push gates on: push refuses while this list is non-empty, and zm status surfaces it as "requires content before publish". Empty list = every checked asset meets its type's contract.

typed/builtin//modules/world_vcs/world/contribute

world.contribute(opts: ContributeOpts?) -> { ContributeOutcome }

Send improvements to installed content back upstream — git subtree push ending in a pull request. For each targeted origin world: the diverging subtree is remapped to the origin's canonical paths, three-way merged against the origin's CURRENT content (regions the origin also changed become local conflicts to resolve first), pushed as a contrib/<id> branch in the origin world, and opened as a pull request there. With merge (the default) the pull request is merged immediately when authorized — a refusal leaves it open and reported, never a failure. After a merge, the local fork re-pulls so its origin pins advance and the asset no longer reads as ahead.

typed/builtin//modules/world_vcs/world/createBranch

world.createBranch(name: string, fromCommit: string?)

Create a branch — git branch <name> [<start>]. The branch starts at fromCommit (defaults to the session branch's HEAD) and gets its own working tree, materialized from that commit. The session stays on its current branch; move with world.swap(world.guid(), "", "", "<branch>") (git checkout).

typed/builtin//modules/world_vcs/world/diff

world.diff(...: string) -> any

Mirror git diff's CLI arg shape. Returns per-file diffs by default; pass --stat for summary stats, --name-only for just paths. Positional commit ids drive the two sources; --staged pivots to staged-vs-HEAD. ---separated args scope the diff to specific paths.

typed/builtin//modules/world_vcs/world/discard

world.discard()

Drop the implicit stage without committing. Live manifest dirty flags are preserved so the user can re-stage later. No-op if the stage doesn't exist.

typed/builtin//modules/world_vcs/world/discardFile

world.discardFile(path: string)

Discard one file's unstaged working edits, reverting its content to the last commit — the git restore <path> shape. One shot: the discarded bytes are snapshotted to trash first, so the discard is recoverable via world.restore(<handle>). Errors when the path is not dirty (nothing to discard) or was never committed (nothing to revert to — remove it instead).

typed/builtin//modules/world_vcs/world/fetch

world.fetch(branch: string?) -> FetchResult

Update the origin/<branch> remote-tracking ref — git fetch. Mirrors the world's ZeroMind branch head into the local commit history (no working-tree change) and reports how the session branch relates to it: behind origin commits to pull, ahead local commits to push, diverged when both. A stale installed pin or out-of-band ZeroMind change shows up here as behind — reconcile with world.pull().

typed/builtin//modules/world_vcs/world/forkLive

world.forkLive(opts: { source: string, sourceBranch: string?, maxBatches: number? }) -> number

Seed THIS (empty) world's live content from another world by copying its whole manifest as clean Pulled rows — the in-engine half of "fork a world". Provenance is preserved: each row points at the content's ORIGINAL owner (a fork of a fork-of-A still points at A), so the fork never claims to have authored what it pulled. The copy runs server-side in bounded batches (idempotent + resumable), looping until the source is fully mirrored. Pair with world.add_all() + world.commit() + world.push() to publish the fork.

typed/builtin//modules/world_vcs/world/forkStatus

world.forkStatus() -> { ForkStatus }

Per-asset "ahead of origin" report — the fork analogue of git status against an upstream. Every installed (pulled) row whose content diverges from its pinned origin is listed, partitioned by the TRUE origin world it was pulled from (nested dependencies carry the world that authored them, not the intermediary they arrived through). This is information for judgment: decide whether a change belongs upstream, then world.contribute.

typed/builtin//modules/world_vcs/world/head

world.head() -> string?

Return the current branch HEAD commit id, or nil if the branch has no commits yet.

typed/builtin//modules/world_vcs/world/installAsset

world.installAsset(opts: InstallAssetOpts) -> InstallAssetResult

typed/builtin//modules/world_vcs/world/installLibrary

world.installLibrary(opts: InstallLibraryOpts) -> InstallLibraryResult

Declarative cross-world dependency. Writes a single marker file at /source/libs/@<name> whose body is the zero/world-import/v1 JSON. The next commit ships it as one regular manifest entry; ZM's import-derivation pass at finalize-time decodes the marker and stamps the new commit's imports[]. Unmodified library content never ships in the importing world's tree — it's fetched from the source world on demand by the engine's library resolver.

typed/builtin//modules/world_vcs/world/list

world.list() -> { WorldEntry }

List every world the authenticated user has access to. Calls the spacetime list_my_worlds procedure which wraps ZeroMind's GET /v1/me/worlds. Flattens each entry to one record per world with the role promoted to a top-level field.

typed/builtin//modules/world_vcs/world/log

world.log(opts: LogOpts?) -> { CommitRow }

Return the commit log for the current branch, newest first. Pass opts.path to get the per-path history (git log -- <path>): only the commits that touched that file, newest-first.

typed/builtin//modules/world_vcs/world/merge

world.merge(sourceBranch: string) -> MergeResult

Merge another branch into the session branch — git merge <source>. The merge runs locally in the world's SpacetimeDB clone and is abortable with world.mergeAbort; nothing reaches ZeroMind until the result is pushed. Requires a clean working tree (commit or stash first — that is also what makes abort exact). Clean → a two-parent merge commit lands on the session branch and the merged content appears in the working tree. Conflicts → git-style markers are projected into each conflicting text file, the cleanly-merged remainder is applied as working-tree changes, and world.vcsStatus().unmerged lists what needs attention: resolve each path (edit out the markers / rewrite / remove the file), then world.add + world.commit — that commit records the merge (second parent = the source head) and clears the unmerged set.

typed/builtin//modules/world_vcs/world/mergeAbort

world.mergeAbort()

Abort the in-progress merge — git merge --abort. Clears the unmerged set and restores the working tree to the pre-merge state (the target head's committed content; the branch head never moved during a conflicted merge). Errors when no merge is in progress.

typed/builtin//modules/world_vcs/world/prList

world.prList(worldGuid: string?, number: number?) -> any

List a world's pull requests, or fetch one.

typed/builtin//modules/world_vcs/world/prMerge

world.prMerge(worldGuid: string, number: number, strategy: string?) -> any

Merge a pull request — the agent-side merge button.

typed/builtin//modules/world_vcs/world/previewInstall

world.previewInstall(opts: InstallAssetOpts) -> PreviewResult

Preview what installing an asset WOULD write, without writing anything. Fetches + decodes the closure and plans placement (the same helpers world.installAsset uses), returning a flat node list plus rollup totals. A truncated closure is reported (not raised) so a caller can surface it and block import.

typed/builtin//modules/world_vcs/world/pull

world.pull(branch: string?) -> PullResult

Fetch and reconcile with origin — git pull. Strictly behind → fast-forward (the branch head moves to the origin mirror, no merge commit). Diverged → three-way merge of the origin mirror, with the same conflict/marker/resolve flow as world.merge (resolve the unmerged paths, then world.add + world.commit; abortable with world.mergeAbort). Requires a clean working tree.

typed/builtin//modules/world_vcs/world/pullAsset

world.pullAsset(opts: PullAssetOpts?) -> PullAssetResult

typed/builtin//modules/world_vcs/world/push

world.push(commitId: string?) -> string?

Publish the current branch to ZeroMind. The no-argument form is a git merge --squash push: EVERY unpushed commit on the branch collapses into a SINGLE ZeroMind commit (latest content per path, parented on the branch's current remote HEAD). Because only the merged final state's bytes are uploaded, a superseded or lost intermediate-commit blob can never break the push — this is what makes a churn-heavy world publishable. The local commit history is preserved as the editing journal; on success every squashed commit shares the one remote commit id. The explicit commitId form still pushes that single commit verbatim via publish_commit (advanced / chain-replay use; its parent must already be on the remote).

typed/builtin//modules/world_vcs/world/reset

world.reset(targetCommitId: string) -> string?

Rewind HEAD to targetCommitId in one shot. Non-destructive — orphaned commits stay in storage and each becomes a trash entry the user can world.restore (in chain order) to re-attach the branch. Errors when targetCommitId is not an ancestor of HEAD. Returns a summary of what was rewound.

typed/builtin//modules/world_vcs/world/resolvePullConflict

world.resolvePullConflict(path: string, choice: string)

typed/builtin//modules/world_vcs/world/restore

world.restore(handle: any)

Restore one trash entry by row_id. Errors verbatim on handler-not-yet-implemented / world-mismatch.

typed/builtin//modules/world_vcs/world/show

world.show(...: string) -> any

Mirror git show's CLI arg shape. Default returns commit metadata + full diff vs parent. world.show("commit:/path") returns just the bytes. Flags: --stat, --name-only.

typed/builtin//modules/world_vcs/world/stash

world.stash(label: string?)

Save the caller's current pending dirty + staged state on the active (world, branch) into a stash row. label is optional free-form text. Non-destructive — dirty + staged state is preserved on disk.

typed/builtin//modules/world_vcs/world/stashDrop

world.stashDrop(handle: any)

Request an affirmation token to drop a stash. Always errors — successful mint surfaces the token as affirmation required: zm affirm <token>. The agent runs zm affirm <token> to actually drop; restoration via world.restore() reappears the stash under a new row_id.

typed/builtin//modules/world_vcs/world/stashPop

world.stashPop(handle: any) -> StashSnapshot

Author-only. Pop the stash row (deletes it server-side) and return the decoded snapshot. The caller is responsible for re-applying the snapshot to disk via the normal write paths (so ACL gates fire on every restored path).

typed/builtin//modules/world_vcs/world/stashes

world.stashes() -> { StashRow }

List every stash row in the world. Anyone with read access sees every stash; the per-row author_hex makes it clear which entries the caller can pop / drop themselves.

typed/builtin//modules/world_vcs/world/trash

world.trash() -> { TrashRow }

List trash entries for the world. Anyone with read access to the world can list trash — recovery is a shared safety net, not a privacy boundary. The handle (row_id) feeds back into world.restore.

typed/builtin//modules/world_vcs/world/uninstallLibrary

world.uninstallLibrary(name: string) -> string

Delete the library marker file. name accepts "@combat" or "combat" (the leading @ is the convention carried by the on-disk path).

typed/builtin//modules/world_vcs/world/unstage

world.unstage(path: string)

Remove a path from the staging area. Live manifest dirty state is untouched.

typed/builtin//modules/world_vcs/world/vcsStatus

world.vcsStatus() -> StatusResult

Return the working-tree VCS status: dirty paths, staged entries, and (always empty in the spacetime model) untracked. Named vcsStatus (not status) because world.status() is the runtime-snapshot accessor owned by world_status.module; the source-control surface keeps its own VCS-specific name so the two never shadow each other. Each dirty[i].dirtied_by is the SpacetimeDB Identity hex of the most recent writer; dirty_since_micros is the microsecond timestamp of the first write of the current dirty run.

typed/builtin//modules/yaml/M/decode

M.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.

typed/builtin//modules/yaml/M/encode

M.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).

typed/builtin//modules/zinput/M/_resetLiveArmed

M._resetLiveArmed()

Test-only: reset the liveness auto-arm guard so a suite can exercise the arming decision from a cold state.

typed/builtin//modules/zinput/M/_resetTickGuard

M._resetTickGuard()

Test-only: reset the idempotency guard so the next tick() call runs unconditionally. Suite isolation; not part of the public contract for production code.

typed/builtin//modules/zinput/M/disconnect

M.disconnect(handle: number) -> boolean

Disconnect any Zin handle (from Zin.input.on* or Zin.actions.bind). Returns true if a handler/subscription was removed; false on miss.

typed/builtin//modules/zinput/M/lastTickAt

M.lastTickAt() -> number

Test/debug: timestamp of the most recent tick (os.clock()), or -1 if Zin.tick has never been called.

typed/builtin//modules/zinput/M/lastTickFrameId

M.lastTickFrameId() -> number

Test/debug: engine frame id of the most recent tick, or -1 if Zin.tick has never been called (or __zero_input.frameId() is unavailable). Used by Zin.autoTick's worker loop to dedup against explicit ticks (Phase 8 / #2566).

typed/builtin//modules/zinput/M/tick

M.tick(dt: number?)

Advance every stateful zinput subsystem by dt seconds. dt is the frame delta. Pass the value your host already computes for animation. If omitted, computed from os.clock() since the last tick() call (first call defaults to 1/60). Order each tick:

  1. clear chord per-tick fire flags, Gestures per-tick deltas, Surface per-frame device-class flags, Virtual button edges + drag deltas
  2. route this tick's raw touches into Zin.virtual (Zin.touchControls._advance() — auto-mounts, writes stick/button/drag), then run the key-emulation floor over that fresh state (Zin.emulation._advance()). Both PRODUCE the Zin.virtual state the binding/axis/action evaluators below consume THIS tick, so they run before any of them.
  3. advance Axes smoothing, Chords window aging, Rebind timeouts, Gestures time-based recognition (long-press) + pinch/pan deltas
  4. drain __zero_input.events() once (first tick of the frame only)
  5. feed each event into State (held-time), Chords (state machines), Input (lastInputType tracking — Phase 9), Gestures (contact tracks + discrete recognition), Surface (device-class flags)
  6. resolve Surface's device class for this frame, then dispatch event subscribers (Zin.events.on / Zin.input.on* callbacks — Phase 9 priority + sink/pass + gpe)
  7. dispatch action handlers (Zin.actions.bind / onPressed / onReleased / onChanged / onHeld — Phase 9)
  8. dispatch chord onFire callbacks and Gestures discrete-gesture callbacks for anything that fired this tick

typed/builtin//modules/zinput/actions/M/_clearHandlers

M._clearHandlers()

Test-only: clear every handler (does NOT touch action definitions).

typed/builtin//modules/zinput/actions/M/_dispatchHandlers

M._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).

typed/builtin//modules/zinput/actions/M/_owns

M._owns(handle: number) -> boolean

Internal: cross-API ownership probe. Used by Zin.disconnect (Phase 9.A.2) to route handles to the right disconnect implementation when Zin.input.on* and Zin.actions.bind share a handle namespace.

typed/builtin//modules/zinput/actions/M/_setAllocator

M._setAllocator(fn: () -> number)

Internal: wire a shared id allocator. Called once at module- load time from zinput/init.luau (Phase 9.A.2).

typed/builtin//modules/zinput/actions/M/_setEnsureBindingsFn

M._setEnsureBindingsFn(fn: () -> ())

Internal: wire the lazy-default-map hook. Called once at module- load time from zinput/init.luau.

typed/builtin//modules/zinput/actions/M/_setEnsureLiveFn

M._setEnsureLiveFn(fn: () -> ())

Internal: wire the liveness hook. Called once at module-load time from zinput/init.luau.

typed/builtin//modules/zinput/actions/M/active

M.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).

typed/builtin//modules/zinput/actions/M/bind

M.bind(name: string, fn: any, opts: BindOpts?) -> ActionHandle?

Register a handler. Returns a numeric handle (also accepted by Zin.input.disconnect, Phase 9.A.2). Returns nil if name is not a defined action.

typed/builtin//modules/zinput/actions/M/clear

M.clear()

Wipe every defined action AND every registered handler. Primarily for tests.

typed/builtin//modules/zinput/actions/M/define

M.define(spec: ActionSpec)

Define one or more actions. Each entry replaces any existing action under the same name; other actions are preserved.

typed/builtin//modules/zinput/actions/M/disconnect

M.disconnect(handle: ActionHandle) -> boolean

Tear down a handler returned by bind. Idempotent.

typed/builtin//modules/zinput/actions/M/get

M.get(name: string) -> ActionEntry?

Internal: introspection for tests / Phase 3 profile work. Returns nil if action is not defined.

typed/builtin//modules/zinput/actions/M/handlerCount

M.handlerCount(name: string) -> number

Number of registered handlers for an action (0 if none / unknown).

typed/builtin//modules/zinput/actions/M/has

M.has(name: string) -> boolean

True if an action with this name is defined.

typed/builtin//modules/zinput/actions/M/held

M.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.

typed/builtin//modules/zinput/actions/M/heldTime

M.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.

typed/builtin//modules/zinput/actions/M/names

M.names() -> { string }

All defined action names, in arbitrary order.

typed/builtin//modules/zinput/actions/M/onChanged

M.onChanged(name: string, fn: any, 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.

typed/builtin//modules/zinput/actions/M/onHeld

M.onHeld(name: string, fn: any, 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).

typed/builtin//modules/zinput/actions/M/onPressed

M.onPressed(name: string, fn: any, opts: BindOpts?) -> ActionHandle?

Fire on rising edge (state = "Begin"). Sugar for bind with fire = {"Begin"}.

typed/builtin//modules/zinput/actions/M/onReleased

M.onReleased(name: string, fn: any, opts: BindOpts?) -> ActionHandle?

Fire on falling edge (state = "End"). Sugar for bind with fire = {"End"}.

typed/builtin//modules/zinput/actions/M/pressed

M.pressed(name: string) -> boolean

True if any boolean binding on the action was just pressed this frame. Axis/vector bindings do not contribute to press edges. Suppressed by context gating.

typed/builtin//modules/zinput/actions/M/released

M.released(name: string) -> boolean

True if any boolean binding on the action was just released this frame. Suppressed by context gating.

typed/builtin//modules/zinput/actions/M/remove

M.remove(name: string)

Remove an action by name. Also tears down every handler that was bound to it. No-op when the action isn't defined.

typed/builtin//modules/zinput/actions/M/repeated

M.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.

typed/builtin//modules/zinput/actions/M/value

M.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.

typed/builtin//modules/zinput/autoTick/M/_setLastTickFrameIdFn

M._setLastTickFrameIdFn(fn: () -> number)

Internal: register the accessor that returns the engine frame id of the most recent M.tick. Wired by init.luau so the worker can dedup itself against explicit ticks within the same engine frame (Phase 8 / #2566). Optional — when nil, the worker ticks unconditionally.

typed/builtin//modules/zinput/autoTick/M/_setTickFn

M._setTickFn(fn: (number?) -> ())

Internal: register the function that the auto-tick loop should call each frame. Wired by init.luau at module load.

typed/builtin//modules/zinput/autoTick/M/isRunning

M.isRunning() -> boolean

True if the auto-tick loop is currently running.

typed/builtin//modules/zinput/autoTick/M/start

M.start() -> boolean

Start the auto-tick loop. No-op if already running.

typed/builtin//modules/zinput/autoTick/M/stop

M.stop()

Stop the auto-tick loop on its next yield. No-op if not running.

typed/builtin//modules/zinput/axes/M/_resetGateWarnings

M._resetGateWarnings()

Test-only: reset the once-per-axis gate-error warning state so a fresh suite can verify warning behavior again.

typed/builtin//modules/zinput/axes/M/_setEnsureBindingsFn

M._setEnsureBindingsFn(fn: () -> ())

Internal: wire the lazy-default-map hook. Called once at module- load time from zinput/init.luau.

typed/builtin//modules/zinput/axes/M/_setEnsureLiveFn

M._setEnsureLiveFn(fn: () -> ())

Internal: wire the liveness hook. Called once at module-load time from zinput/init.luau.

typed/builtin//modules/zinput/axes/M/advance

M.advance(dt: number)

Internal: advance every defined axis by dt seconds. Called by Zin.tick(dt) once per frame. Recomputes targets from the underlying bindings, applies shaping, then exponentially smooths current toward target using smoothing as the time constant. Context mismatch or a false gate snaps target to 0.

typed/builtin//modules/zinput/axes/M/clear

M.clear()

Wipe every axis and its state. Primarily for tests.

typed/builtin//modules/zinput/axes/M/define

M.define(spec: AxisSpec)

Define one or more axes. Each entry replaces any existing axis of the same name; other axes are preserved.

typed/builtin//modules/zinput/axes/M/get

M.get(name: string) -> AxisDef?

Internal introspection: definition record (or nil).

typed/builtin//modules/zinput/axes/M/has

M.has(name: string) -> boolean

True if an axis with this name is defined.

typed/builtin//modules/zinput/axes/M/names

M.names() -> { string }

All defined axis names, in arbitrary order.

typed/builtin//modules/zinput/axes/M/raw

M.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.

typed/builtin//modules/zinput/axes/M/remove

M.remove(name: string)

Remove an axis. No-op if not defined.

typed/builtin//modules/zinput/axes/M/value

M.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.

typed/builtin//modules/zinput/bindings/M/arrowKeys

M.arrowKeys() -> Binding

Convenience: arrow keys as a vector binding. Identical to vector(key("ArrowRight"), key("ArrowLeft"), key("ArrowUp"), key("ArrowDown")).

typed/builtin//modules/zinput/bindings/M/axis

M.axis(plus: Binding, minus: Binding) -> Binding

Bind to a 1-D axis composed of two opposing button bindings. Value = (plus held ? 1 : 0) - (minus held ? 1 : 0).

typed/builtin//modules/zinput/bindings/M/evalAxis

M.evalAxis(b: any) -> number

Resolve a 1-D axis binding to a scalar. For axis bindings the result is in [-1, 1]. For mouseDelta / scroll bindings the result is a raw physical delta (pixels, wheel clicks) and may exceed that range — shape it with Zin.axes.

typed/builtin//modules/zinput/bindings/M/evalHeld

M.evalHeld(b: any) -> boolean

Is this binding currently delivering a held signal? key/mouse/modKey/pointerLocked → boolean held. axis/vector/mouseDelta/scroll → magnitude non-zero.

typed/builtin//modules/zinput/bindings/M/evalPressed

M.evalPressed(b: any) -> boolean

Did this binding's press edge fire this frame? Boolean bindings only. Axis/vector return false (use evalAxis/evalVector with a held-time threshold for edge tracking — Phase 3+).

typed/builtin//modules/zinput/bindings/M/evalReleased

M.evalReleased(b: any) -> boolean

Did this binding's release edge fire this frame?

typed/builtin//modules/zinput/bindings/M/evalVector

M.evalVector(b: any) -> Vec2

Resolve a 2-D vector binding to { x, y }. For vector bindings the result is in [-1, 1]. For mouseDelta / scroll bindings (with no axis set) the result is the raw frame delta — mouseDelta = { x = dx, y = dy }, scroll = { x = 0, y = wheel_delta } (x reserved for future h-scroll).

typed/builtin//modules/zinput/bindings/M/format

M.format(b: any) -> string

Render a single binding descriptor as a user-readable string. Stable output across runs — the rebinding UI uses this verbatim. Returns "<invalid>" for malformed input (does not throw).

typed/builtin//modules/zinput/bindings/M/formatAll

M.formatAll(bindings: any?, sep: string?) -> string

Render an array of bindings joined by sep (default ", "). Returns "<no bindings>" if the argument isn't a table, "<empty>" for an empty array. Used by the Input tab's action / axis row summaries.

typed/builtin//modules/zinput/bindings/M/isAxis

M.isAxis(binding: any) -> boolean

True for binding descriptors that resolve to a scalar (axis, a mouseDelta / scroll with a non-nil axis field, or touchPinch).

typed/builtin//modules/zinput/bindings/M/isBoolean

M.isBoolean(binding: any) -> boolean

True for binding descriptors that resolve to a boolean (key, mouse, modKey, pointerLocked, touchButton).

typed/builtin//modules/zinput/bindings/M/isVector

M.isVector(binding: any) -> boolean

True for binding descriptors that resolve to a 2-D vector (vector, a mouseDelta / scroll with a nil axis field, touchStick, or touchDrag).

typed/builtin//modules/zinput/bindings/M/key

M.key(code: string) -> Binding

Bind to a single key. Code is a web-style identifier (e.g. "KeyW", "Space", "ShiftLeft", "ArrowUp") — same vocabulary as Zin.state.keyDown(code).

typed/builtin//modules/zinput/bindings/M/modKey

M.modKey(spec: string) -> Binding

Parse a modifier-decorated key spec like "Ctrl+S", "Shift+Alt+P", or just "Escape". Recognized modifier tokens (case-insensitive): "Ctrl", "Control", "Shift", "Alt". Anything else is treated as the base key code. The last segment is the base key.

typed/builtin//modules/zinput/bindings/M/mouse

M.mouse(button: string) -> Binding

Bind to a single mouse button by name ("left", "right", or "middle").

typed/builtin//modules/zinput/bindings/M/mouseDelta

M.mouseDelta(axis: string?) -> Binding

Bind to the mouse delta this frame.

  • axis = nil → vector binding returning { x = dx, y = dy }
  • axis = "x" → scalar binding returning dx
  • axis = "y" → scalar binding returning dy Values are not normalised to [-1, 1] — mouse delta is a physical pixel count. Use Zin.axes.define with smoothing / deadzone to shape the signal before consumption.

typed/builtin//modules/zinput/bindings/M/pointerLocked

M.pointerLocked() -> Binding

Bind to pointer-lock state. evalHeld is true while the pointer is locked. evalPressed / evalReleased always return false (use Zin.events.on for edge events).

typed/builtin//modules/zinput/bindings/M/scroll

M.scroll(axis: string?) -> Binding

Bind to the scrollwheel delta this frame.

  • axis = nil → vector binding returning { x = 0, y = scroll_delta }
  • axis = "y" → scalar binding returning the wheel delta
  • axis = "x" → scalar binding returning 0 (no horizontal-scroll surface today; reserved for future hardware support)

typed/builtin//modules/zinput/bindings/M/touchButton

M.touchButton(opts: { zone: string?, label: string?, icon: string?, priority: number?, size: string?, group: string? }) -> Binding

Virtual-button binding: a boolean fed by the on-screen button identified by opts.label (else opts.zone). label and icon also carry the control's presentation. priority (lower renders first/more prominent on the touch overlay; defaults to 50 when omitted), size ("small"|"medium"|"large", defaults to "medium"), and group (buttons sharing a group render adjacently) shape the overlay's layout — see Zin.touchControls.

typed/builtin//modules/zinput/bindings/M/touchDrag

M.touchDrag(opts: { zone: string }) -> Binding

Touch-drag binding: a per-frame delta vector fed by drags in opts.zone (mouseDelta semantics — px this frame).

typed/builtin//modules/zinput/bindings/M/touchPinch

M.touchPinch() -> Binding

Pinch binding: a scalar axis fed by the two-finger pinch delta (px this tick; positive = spreading).

typed/builtin//modules/zinput/bindings/M/touchStick

M.touchStick(opts: { zone: string }) -> Binding

Virtual-stick binding: a vector fed by the on-screen stick in opts.zone (components -1..1). Evaluates {x=0,y=0} while no control writes the zone.

typed/builtin//modules/zinput/bindings/M/vector

M.vector(right: Binding, left: Binding, up: Binding, down: Binding) -> Binding

Bind to a 2-D vector. Each arm is a binding that contributes to one axis when held. The returned vector is { x = right - left, y = up - down }.

typed/builtin//modules/zinput/bindings/M/wasd

M.wasd() -> Binding

Convenience: WASD as a vector binding. Identical to vector(key("KeyD"), key("KeyA"), key("KeyW"), key("KeyS")).

typed/builtin//modules/zinput/chords/M/_advanceTime

M._advanceTime(_dt: number)

Internal: age out stale recognizers. Called once per tick.

typed/builtin//modules/zinput/chords/M/_beginTick

M._beginTick()

Internal: clear per-frame firedThisTick flags. Called at the start of each Zin.tick.

typed/builtin//modules/zinput/chords/M/_dispatchFires

M._dispatchFires()

Internal: dispatch onFire callbacks for chords that fired this tick. Called at the end of Zin.tick.

typed/builtin//modules/zinput/chords/M/_observeEvent

M._observeEvent(ev: any)

Internal: feed one event into each defined chord's state machine. Called by Zin.tick for every event in this frame's __zero_input.events().

typed/builtin//modules/zinput/chords/M/cancel

M.cancel(name: string)

Manually reset the chord's progress (e.g. on context switch).

typed/builtin//modules/zinput/chords/M/clear

M.clear()

Wipe every chord, state, and subscriber. Primarily for tests.

typed/builtin//modules/zinput/chords/M/define

M.define(spec: ChordSpec)

Define one or more chords. Each entry replaces any existing chord under the same name; other chords are preserved.

typed/builtin//modules/zinput/chords/M/fired

M.fired(name: string) -> boolean

True on exactly one frame: the frame the chord completed its pattern.

typed/builtin//modules/zinput/chords/M/get

M.get(name: string) -> ChordDef?

Internal introspection: definition record (or nil).

typed/builtin//modules/zinput/chords/M/has

M.has(name: string) -> boolean

True if a chord with this name is defined.

typed/builtin//modules/zinput/chords/M/names

M.names() -> { string }

All defined chord names, in arbitrary order.

typed/builtin//modules/zinput/chords/M/off

M.off(handle: OnFireHandle)

Cancel an onFire subscription.

typed/builtin//modules/zinput/chords/M/onFire

M.onFire(name: string, callback: () -> (), opts: OnFireOpts?) -> OnFireHandle

Register a callback fired when the named chord completes. Returns a handle for off(). Multiple callbacks per chord dispatch in insertion order.

typed/builtin//modules/zinput/chords/M/progress

M.progress(name: string) -> number

Progress through the chord, 0..1. For sequences: matched- steps / total. For simultaneous: matched / total. Always 0 when not in flight.

typed/builtin//modules/zinput/chords/M/remove

M.remove(name: string)

Remove a chord. No-op if not defined. Subscribers on the same name are dropped along with it.

typed/builtin//modules/zinput/conflicts/M/_loadIntentionalPairs

M._loadIntentionalPairs(pairs_: any)

Internal: seed the working set from a saved profile's intentional_pairs field. Called on Zin.profile.activate. The input shape is { ["a"] = "b", ... } or { {a, b}, ... } — the JSON encoder lays it out as the array shape, but a hand- edited profile may use either. Silently ignores malformed entries.

typed/builtin//modules/zinput/conflicts/M/_resetIntentional

M._resetIntentional()

Test-only: wipe the working set. Suite isolation; not part of the public contract.

typed/builtin//modules/zinput/conflicts/M/_serializeIntentional

M._serializeIntentional() -> { { string } }

Serialize the working set for Zin.profile.save / export. Output is an array of { "a", "b" } pairs in canonical order — matches the shape _loadIntentionalPairs consumes on activate, so the round-trip is lossless.

typed/builtin//modules/zinput/conflicts/M/_setPersistFn

M._setPersistFn(fn: () -> ())

Internal: register the closure that writes the current intentional-pair list back to the active profile. Wired by zinput.init so the profile module doesn't have to depend on conflicts (one-way edge).

typed/builtin//modules/zinput/conflicts/M/bindingKey

M.bindingKey(b: any) -> string?

Canonical leaf key for a single discrete binding, or nil if the binding has no single discrete identity (axis, vector, mouseDelta, scroll, pointerLocked). Outputs: key:Space{ kind = "key", code = "Space" } modKey:Ctrl+Shift+KeyS{ kind = "modKey", code = "KeyS", mods = { ctrl, shift } } mouse:left{ kind = "mouse", button = "left" }

typed/builtin//modules/zinput/conflicts/M/find

M.find(binding: any) -> { Owner }

Find every action/axis whose binding shares a leaf key with the probe. Returns an array of { target, name, slot? } owners. Empty on no conflict. Decomposes axis/vector bindings on both sides — a probe key:Space matches an axis whose plus = Space.

typed/builtin//modules/zinput/conflicts/M/forActiveProfile

M.forActiveProfile() -> { ConflictRow }

Enumerate every leaf key shared by two or more owners across the active action + axis registries. Returns an array sorted by key for deterministic UI rendering; empty when there are no conflicts. Each row carries a kind = "real" | "intentional" field — see module about-block for the classification rule.

typed/builtin//modules/zinput/conflicts/M/isIntentional

M.isIntentional(actionA: string, actionB: string) -> boolean

True when (actionA, actionB) is currently marked intentional. Symmetric: (a, b) and (b, a) produce the same answer.

typed/builtin//modules/zinput/conflicts/M/listIntentional

M.listIntentional() -> { { string } }

All currently-marked pairs, sorted lexicographically for deterministic UI rendering. Each pair is returned in canonical order (lexicographic ascending).

typed/builtin//modules/zinput/conflicts/M/markIntentional

M.markIntentional(actionA: string, actionB: string) -> (boolean, string?)

Mark a pair of actions as intentionally sharing a binding. The pair is suppressed from realOnly() until unmarkIntentional reverses it. Stored in the active user profile's JSON so the mark survives restart. Built-in profiles (Luau modules) hold marks in memory only for the session — the natural flow is "mark → save as user profile" if you want them to persist.

typed/builtin//modules/zinput/conflicts/M/realOnly

M.realOnly() -> { ConflictRow }

Subset of forActiveProfile() filtered to kind == "real" rows only — the noise-filtered view the Input tab uses by default.

typed/builtin//modules/zinput/conflicts/M/unmarkIntentional

M.unmarkIntentional(actionA: string, actionB: string) -> boolean

Remove a previously-marked intentional pair. Idempotent: unmarking an absent pair is a no-op success.

typed/builtin//modules/zinput/context/M/contains

M.contains(name: string) -> boolean

True if name is anywhere in the active stack (not just the top). Useful for "is UI open?" checks regardless of further pushes.

typed/builtin//modules/zinput/context/M/current

M.current() -> string

Current (top-of-stack) context name. Always at least default.

typed/builtin//modules/zinput/context/M/default

M.default() -> string

The always-on context name. Actions defined without an explicit context belong here. The bottom of the stack is permanently this value; pop cannot remove it.

typed/builtin//modules/zinput/context/M/pop

M.pop() -> string?

Pop the top context. No-op when only default remains (so unbalanced pop is safe and never leaves the stack empty).

typed/builtin//modules/zinput/context/M/push

M.push(name: any)

Push a context onto the stack. Becomes the new "current" context. Pushing the same context twice requires two pops to fully remove (matches typical UI nesting).

typed/builtin//modules/zinput/context/M/reset

M.reset()

Pop everything except default. Useful for "exit all menus" flows and for test setup/teardown.

typed/builtin//modules/zinput/context/M/stack

M.stack() -> { string }

Snapshot of the full stack, bottom→top. Returned table is a copy; mutating it does not affect the live stack.

typed/builtin//modules/zinput/context/M/with

M.with(name: string, fn: () -> T...) -> T...

Run fn with name pushed onto the stack; pop guaranteed on return or error. Returns whatever fn returns.

typed/builtin//modules/zinput/controllers/M/fps

M.fps(opts: FpsOpts) -> FpsController

Construct a first-person walker controller.

typed/builtin//modules/zinput/controllers/M/free

M.free(opts: FreeOpts) -> FreeController

Construct a free-fly designer/debug camera controller. WASD plane motion + Q/E vertical + ShiftLeft sprint multiplier + raw mouse-look (always reads the per-frame mouse delta — gating is via Zin.context, not via pointer-lock). Mandatory: opts.entity (entity ID string from entity.spawn(...).id). All other fields default; pass actionPrefix to namespace if two free controllers must coexist.

typed/builtin//modules/zinput/controllers/M/orbit

M.orbit(opts: OrbitOpts) -> OrbitController

Construct an orbit camera controller around opts.target. target is either an entity ID string (the orbit center tracks that entity each frame) or a fixed { x, y, z } table.

typed/builtin//modules/zinput/emulation/M/_advance

M._advance()

Internal: advance the emulation floor one tick. Releases every emitted key when the active map or the input context changed since the previous tick, then re-derives button / stick / drag emulation from the current effective map's touch/kbm binding pairs — active- context entries only. No-op when no map is active. Wired into Zin.tick.

typed/builtin//modules/zinput/emulation/M/_reset

M._reset()

Test-only: release everything emitted and clear tracked state.

typed/builtin//modules/zinput/emulation/M/getSensitivity

M.getSensitivity() -> number

The current touchDrag -> emulated mouse-delta multiplier.

typed/builtin//modules/zinput/emulation/M/setSensitivity

M.setSensitivity(n: number)

Set the touchDrag -> emulated mouse-delta multiplier (default 1.0).

typed/builtin//modules/zinput/events/M/_dispatch

M._dispatch(events: any)

Internal: dispatch a batch of events to every registered subscriber. Called once per Zin.tick from the events stage of the tick pipeline.

typed/builtin//modules/zinput/events/M/clearSubscribers

M.clearSubscribers()

Cancel every subscription. Primarily for test isolation.

typed/builtin//modules/zinput/events/M/frame

M.frame() -> { InputEvent }

Get this frame's events as an array of records, in dispatch order. Returns an empty table if __zero_input.events is missing or returns a non-table value.

typed/builtin//modules/zinput/events/M/iter

M.iter()

Iterate this frame's events. Identical to ipairs(Zin.events.frame()) but the explicit name reads better at call sites.

typed/builtin//modules/zinput/events/M/keysDown

M.keysDown() -> { InputEvent }

All key.down events this frame.

typed/builtin//modules/zinput/events/M/keysUp

M.keysUp() -> { InputEvent }

All key.up events this frame.

typed/builtin//modules/zinput/events/M/mouseDowns

M.mouseDowns() -> { InputEvent }

All mouse.down events this frame.

typed/builtin//modules/zinput/events/M/mouseMoves

M.mouseMoves() -> { InputEvent }

All mouse.move events this frame.

typed/builtin//modules/zinput/events/M/mouseUps

M.mouseUps() -> { InputEvent }

All mouse.up events this frame.

typed/builtin//modules/zinput/events/M/mouseWheels

M.mouseWheels() -> { InputEvent }

All mouse.wheel events this frame.

typed/builtin//modules/zinput/events/M/off

M.off(handle: SubHandle | number)

Cancel a subscription. Accepts a Handle returned from on or a numeric id.

typed/builtin//modules/zinput/events/M/on

M.on(filter: EventFilter, callback: (any) -> (), opts: SubOpts?) -> SubHandle

Register a callback fired when matching events arrive on Zin.tick. Returns a handle for off().

typed/builtin//modules/zinput/events/M/subscriberCount

M.subscriberCount() -> number

Test/introspection: number of active subscribers.

typed/builtin//modules/zinput/events/M/texts

M.texts() -> { InputEvent }

All text events this frame (composed text commits).

typed/builtin//modules/zinput/gestures/M/_advanceTime

M._advanceTime(_dt: number)

Internal: time-based recognition (long-press) + continuous two-finger deltas (pinch, pan). Runs every tick.

typed/builtin//modules/zinput/gestures/M/_beginTick

M._beginTick()

Internal: clear per-tick continuous deltas. First tick of each engine frame.

typed/builtin//modules/zinput/gestures/M/_dispatchFires

M._dispatchFires()

Internal: deliver this tick's discrete gesture fires. Handler errors are caught and logged.

typed/builtin//modules/zinput/gestures/M/_observeEvent

M._observeEvent(ev: any)

Internal: per-event observer — builds contact tracks and classifies discrete gestures on release.

typed/builtin//modules/zinput/gestures/M/_reset

M._reset()

Test-only: clear all tracks, fires, deltas, and subscriptions.

typed/builtin//modules/zinput/gestures/M/configure

M.configure(opts: { [string]: number })

Override recognition thresholds. Unspecified fields keep their current values.

typed/builtin//modules/zinput/gestures/M/getConfig

M.getConfig() -> GestureConfig

Current recognition thresholds (a copy).

typed/builtin//modules/zinput/gestures/M/off

M.off(handle: number) -> boolean

Unsubscribe a handle returned by any Zin.gestures.on* function.

typed/builtin//modules/zinput/gestures/M/onDoubleTap

M.onDoubleTap(fn: (any) -> ()) -> number

Subscribe to double-taps. fn(ev) with ev = { x, y, id }. The release that completes a double-tap also emits a tap on the same tick (each qualifying release taps; the second one additionally double-taps).

typed/builtin//modules/zinput/gestures/M/onLongPress

M.onLongPress(fn: (any) -> ()) -> number

Subscribe to long-presses (fires once per contact, while the finger is still down). fn(ev) with ev = { x, y, id }.

typed/builtin//modules/zinput/gestures/M/onSwipe

M.onSwipe(fn: (any) -> ()) -> number

Subscribe to swipes (fires on release). fn(ev) with ev = { direction = "left"|"right"|"up"|"down", dx, dy, velocity, id }.

typed/builtin//modules/zinput/gestures/M/onTap

M.onTap(fn: (any) -> ()) -> number

Subscribe to taps. fn(ev) with ev = { x, y, id, duration }.

typed/builtin//modules/zinput/gestures/M/panDelta

M.panDelta() -> (number, number)

This tick's two-finger pan delta: movement of the contacts' centroid, in px. Zeros unless exactly two contacts are down.

typed/builtin//modules/zinput/gestures/M/pinchDelta

M.pinchDelta() -> number

This tick's two-finger pinch delta: change in the distance between the two contacts, in px (positive = spreading). 0 unless exactly two contacts are down.

typed/builtin//modules/zinput/input/M/_disconnectAll

M._disconnectAll()

Test-only: tear down every Zin.input subscription installed this session.

typed/builtin//modules/zinput/input/M/_observeEvent

M._observeEvent(ev: any)

Internal observer driven by Zin.tick. Receives every event in the same drain loop as State / Chords and updates _lastInputType.

typed/builtin//modules/zinput/input/M/_owns

M._owns(handle: number) -> boolean

Internal: reports whether handle was issued by this module. Used by the unified Zin.disconnect to route ownership.

typed/builtin//modules/zinput/input/M/_reset

M._reset()

Test-only: clear lastInputType. Public so test suites can isolate cases.

typed/builtin//modules/zinput/input/M/_setAllocator

M._setAllocator(fn: () -> number)

Internal: wire a shared id allocator. Called once at module-load time from zinput/init.luau.

typed/builtin//modules/zinput/input/M/disconnect

M.disconnect(handle: Handle) -> boolean

Tear down a subscription returned by Zin.input.on*. Idempotent.

typed/builtin//modules/zinput/input/M/lastInputType

M.lastInputType() -> string?

Returns the userInputType of the most recent input event this session. "Keyboard" | "Mouse" | "Touch" | nil.

typed/builtin//modules/zinput/input/M/onBegan

M.onBegan(fn: (any, boolean) -> any, opts: SubOpts?) -> Handle

Fires on press / mouse-button-down. Handler: fn(io, gpe) -> "sink"?.

typed/builtin//modules/zinput/input/M/onChanged

M.onChanged(fn: (any, boolean) -> any, opts: SubOpts?) -> Handle

Fires on mouse motion / scroll. Handler: fn(io, gpe) -> "sink"?.

typed/builtin//modules/zinput/input/M/onEnded

M.onEnded(fn: (any, boolean) -> any, opts: SubOpts?) -> Handle

Fires on release / mouse-button-up. Handler: fn(io, gpe) -> "sink"?.

typed/builtin//modules/zinput/input/M/onTextInput

M.onTextInput(fn: (string, boolean) -> any, opts: SubOpts?) -> Handle

Fires on committed text input. Handler: fn(text, gpe) -> "sink"?.

typed/builtin//modules/zinput/input/M/subscriberCount

M.subscriberCount() -> number

Test/introspection: number of active Zin.input.* subscriptions (composite handles, not the underlying per-kind Events subscribers).

typed/builtin//modules/zinput/map/M/_reset

M._reset()

Test-only: clear active-map state (the profile registry keeps whatever was applied).

typed/builtin//modules/zinput/map/M/activate

M.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).

typed/builtin//modules/zinput/map/M/activeName

M.activeName() -> string?

The active map's name, or nil.

typed/builtin//modules/zinput/map/M/addTouchButton

M.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).

typed/builtin//modules/zinput/map/M/bake

M.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.

typed/builtin//modules/zinput/map/M/bindingsFor

M.bindingsFor(eff: any, name: string, class: string) -> any

The effective bindings for one action or axis and device class.

typed/builtin//modules/zinput/map/M/effective

M.effective() -> any

The active map's effective form, or nil before any activation.

typed/builtin//modules/zinput/map/M/ensureActive

M.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.

typed/builtin//modules/zinput/map/M/materialize

M.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 = { ... } }.

typed/builtin//modules/zinput/map/M/removeTouchButton

M.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.

typed/builtin//modules/zinput/pointer/M/lock

M.lock()

Request pointer lock (cursor grab + hide). Records intent; the cursor is captured once the surface is active — native: window focused + clicked; WASM: on the next user gesture (browser policy).

typed/builtin//modules/zinput/pointer/M/locked

M.locked() -> boolean

Convenience: query the current pointer-lock state. Identical to Zin.state.pointerLocked().

typed/builtin//modules/zinput/pointer/M/unlock

M.unlock()

Release pointer lock (cursor ungrab + show).

typed/builtin//modules/zinput/profile/M/_reset

M._reset()

Test-only: clear all in-memory state. Suite isolation; not part of the public contract.

typed/builtin//modules/zinput/profile/M/_resetApplied

M._resetApplied()

Test-only: clear the applied/active markers so suites can simulate a cold session without touching the registered profiles. Not part of the public contract.

typed/builtin//modules/zinput/profile/M/_setMapEnsureFn

M._setMapEnsureFn(fn: (string) -> boolean)

Internal: wire the map-delegation hook. Called once at module- load time from zinput/init.luau.

typed/builtin//modules/zinput/profile/M/activate

M.activate(name: string, opts: ActivateOpts?) -> (boolean, string?)

Activate a registered profile: clear current actions/axes/chords, then apply the profile's definitions. Sets the active name and notifies subscribers. Activating the already-active profile is a no-op unless opts.reactivate = true.

typed/builtin//modules/zinput/profile/M/appliedName

M.appliedName() -> string?

The name of the profile whose sections are currently applied to the actions/axes/chords registries, or nil when nothing has been applied this session.

typed/builtin//modules/zinput/profile/M/current

M.current() -> string?

Active profile name for this session, or nil if none has been activated yet.

typed/builtin//modules/zinput/profile/M/delete

M.delete(name: string) -> (boolean, string?)

Remove a user profile's JSON file. Refuses to delete built-ins. The in-memory registry entry is also dropped. If the deleted profile was active, current() keeps the name until a different profile is activated — but the registry no longer has the descriptor.

typed/builtin//modules/zinput/profile/M/ensureActive

M.ensureActive(fallback: string?) -> (boolean, string?)

Bootstrap helper for controllers. If no profile is active, activates the session-active profile or fallback if there is none. Idempotent — if a profile is already active this is a no-op. Each migrated camera/locomotion controller calls this on awake() so a scene with no explicit Zin.profile.activate still has working bindings. When the resolved scheme is the builtin "default", activation routes through Zin.map so every device class (kbm, gamepad, touch) comes along, not just kbm.

typed/builtin//modules/zinput/profile/M/export

M.export(name: string, vfsPath: string) -> (boolean, string?)

Write a named profile's serializable JSON to an arbitrary VFS path. Same shape as save() — round-trips through import() losslessly. Built-in profiles can be exported; their function fields (gate, curve closure form) are stripped from the exported JSON.

typed/builtin//modules/zinput/profile/M/get

M.get(name: string?) -> any?

Active profile descriptor (no arg) or the named profile (with arg). Returns nil if missing.

typed/builtin//modules/zinput/profile/M/import

M.import(vfsPath: string, opts: ImportOpts?) -> (boolean, string)

Read a profile JSON from a VFS path and register() it. Does NOT activate it — pass opts.activate = true (or call activate(name) separately) to make it current.

typed/builtin//modules/zinput/profile/M/list

M.list() -> { string }

Built-in and user profile names, sorted and deduplicated.

typed/builtin//modules/zinput/profile/M/load

M.load(name: string) -> (boolean, any?)

Load and register a profile. Tries @builtin::profiles.<name> first (Luau module), then falls back to /zero/profiles/<name>.json.

typed/builtin//modules/zinput/profile/M/off

M.off(handle: number)

Drop a subscription registered via onChange. No-op if the handle is unknown.

typed/builtin//modules/zinput/profile/M/onChange

M.onChange(cb: ChangeCallback) -> number

Subscribe to active-profile changes. Callback fires with (profileName, profileDescriptor) on activate and on register of the currently active profile.

typed/builtin//modules/zinput/profile/M/register

M.register(name: string, profile: any) -> (boolean, string?)

Register a profile table. Validates the shape; replaces any prior registration under the same name. If the registered name is currently active, subscribers are notified (so editor UIs refresh).

typed/builtin//modules/zinput/profile/M/save

M.save(name: string, opts: SaveOpts?) -> (boolean, string?)

Capture the current Zin.actions / Zin.axes / Zin.chords state to a JSON file under /zero/profiles/<name>.json. Refuses to overwrite a built-in profile name or an existing user profile (unless opts.overwrite = true). Functions (axis gate, function-valued curve) are dropped — only data-typed fields persist.

typed/builtin//modules/zinput/rebind/M/_advanceTime

M._advanceTime(dt: number)

Internal: per-frame timeout sweep. Called by Zin.tick after the event pump so timed-out sessions retire on the same frame their budget runs out, before the next observed event.

typed/builtin//modules/zinput/rebind/M/begin

M.begin(opts: BeginOpts?) -> Session

Start a new capture session. Returns the session table. The session auto-subscribes to Zin.events.on so once Zin.tick runs the first matching event commits the capture without the caller having to pump consume manually.

typed/builtin//modules/zinput/rebind/M/cancelAll

M.cancelAll()

Cancel every live session. Test-only / shutdown.

typed/builtin//modules/zinput/rebind/M/liveCount

M.liveCount() -> number

Live sessions count; primarily for test introspection.

typed/builtin//modules/zinput/state/M/_observeEvent

M._observeEvent(ev: any)

Internal: per-event observer called by the Zin.tick coordinator. Updates held-time state for keys and mouse buttons. Not part of the public contract — exposed on M so the tick coordinator can wire it.

typed/builtin//modules/zinput/state/M/_reset

M._reset()

Test-only: clear all held-time / repeat state. Public so test suites can isolate cases.

typed/builtin//modules/zinput/state/M/_setEnsureLiveFn

M._setEnsureLiveFn(fn: () -> ())

Internal: wire the liveness hook. Called once at module-load time from zinput/init.luau.

typed/builtin//modules/zinput/state/M/get

M.get() -> Snapshot

Get the full snapshot table for this frame. Empty table if __zero_input.snapshot is missing or returns non-table.

typed/builtin//modules/zinput/state/M/getRepeatDefaults

M.getRepeatDefaults() -> RepeatDefaults

Read the current synthetic-repeat defaults. Returned table is a copy.

typed/builtin//modules/zinput/state/M/keyDown

M.keyDown(key: string) -> boolean

Is key currently held?

typed/builtin//modules/zinput/state/M/keyDownReal

M.keyDownReal(key: string) -> boolean

Is key held by a real press — held, and NOT (also) held by the input-emulation floor? The floor merges emulated holds into keys so keyDown can't tell them apart; this checks keys minus keys_emulated.

typed/builtin//modules/zinput/state/M/keyHeldTime

M.keyHeldTime(code: string) -> number?

Seconds the given key has been held since its most recent press, or nil if the key isn't currently held. Wall-clock based (os.clock()), updated as events arrive via the tick.

typed/builtin//modules/zinput/state/M/keyPressed

M.keyPressed(key: string) -> boolean

Was key just pressed this frame?

typed/builtin//modules/zinput/state/M/keyReleased

M.keyReleased(key: string) -> boolean

Was key just released this frame?

typed/builtin//modules/zinput/state/M/keyRepeatFired

M.keyRepeatFired(code: string, opts: RepeatOpts?) -> boolean

Should a synthetic key-repeat fire this frame for code? Returns true once per period, beginning delay seconds after the initial press. Distinct from the repeat field on OS-level key.down events (which surfaces hardware autorepeat — see Zin.events.on). Each call advances per-key state, so call once per frame per logical consumer to avoid "consuming" the repeat early.

typed/builtin//modules/zinput/state/M/mouseButtonDown

M.mouseButtonDown(button: (number | string)?) -> boolean

Is mouse button held? Accepts the 0-based index or a name — 0/"left", 1/"right", 2/"middle".

typed/builtin//modules/zinput/state/M/mouseButtonHeldTime

M.mouseButtonHeldTime(button: (number | string)?) -> number?

Seconds the given mouse button has been held, or nil. Accepts the 0-based index or a name — 0/"left", 1/"right", 2/"middle".

typed/builtin//modules/zinput/state/M/mouseButtonPressed

M.mouseButtonPressed(button: (number | string)?) -> boolean

Was mouse button just pressed this frame? Accepts the 0-based index or a name — 0/"left", 1/"right", 2/"middle".

typed/builtin//modules/zinput/state/M/mouseButtonReleased

M.mouseButtonReleased(button: (number | string)?) -> boolean

Was mouse button just released this frame? Accepts the 0-based index or a name — 0/"left", 1/"right", 2/"middle".

typed/builtin//modules/zinput/state/M/mouseDelta

M.mouseDelta() -> (number, number)

Mouse delta since last frame. Returns (dx, dy) as two numbers.

typed/builtin//modules/zinput/state/M/mousePosition

M.mousePosition() -> (number, number)

Current mouse position. Returns (x, y) as two numbers.

typed/builtin//modules/zinput/state/M/pointerLocked

M.pointerLocked() -> boolean

Is the pointer currently locked?

typed/builtin//modules/zinput/state/M/scrollDelta

M.scrollDelta() -> number

Mouse wheel delta this frame.

typed/builtin//modules/zinput/state/M/setRepeatDefaults

M.setRepeatDefaults(opts: RepeatOpts?)

Set the global default delay / period for synthetic key repeat. Either field is optional; omitted fields keep their current value. Default: delay = 0.4 s, period = 0.1 s.

typed/builtin//modules/zinput/state/M/uiWantsPointer

M.uiWantsPointer() -> boolean

True when egui (or the UI layer) wants pointer input. Useful for gating game-side input when a UI is hovered.

typed/builtin//modules/zinput/surface/M/_beginFrame

M._beginFrame()

Internal: clear this frame's per-class flags. On the first tick of the session, also captures the capability default as the reported class the change signal compares against. Called by the Zin.tick coordinator on the first tick of each engine frame.

typed/builtin//modules/zinput/surface/M/_observeEvent

M._observeEvent(ev: any)

Internal: per-event observer called by the Zin.tick coordinator. Collects which device classes produced events this frame.

typed/builtin//modules/zinput/surface/M/_reset

M._reset()

Test-only: clear resolution state and subscriptions. Suite isolation; not part of the public contract.

typed/builtin//modules/zinput/surface/M/_resolveFrame

M._resolveFrame()

Internal: resolve this frame's class and fire onChange on a flip. Touch wins a frame containing any touch event (the primary contact's projected mouse events never mask their own touch).

typed/builtin//modules/zinput/surface/M/current

M.current() -> string

The active input-surface class: "touch" or "kbm". Event history wins; before any input it defaults by capability (touch sessions start as "touch").

typed/builtin//modules/zinput/surface/M/off

M.off(handle: number) -> boolean

Unsubscribe an onChange handle. Returns true when removed.

typed/builtin//modules/zinput/surface/M/onChange

M.onChange(fn: (string, string?) -> ()) -> number

Subscribe to surface-class changes. fn(now, prev) fires from the tick pipeline on the frame the class flips; prev is the previously reported class (the first-tick capability default when no event had resolved yet).

typed/builtin//modules/zinput/test/M/clickMouse

M.clickMouse(opts: ClickOpts?)

Press + release a mouse button. opts.button (default 0); opts.x / opts.y optionally move the cursor before pressing; opts.duration holds the button for that many seconds before releasing. Does NOT tick — call Zin.tick(dt) between clickMouse and your assertion if you need binding-action handlers to fire.

typed/builtin//modules/zinput/test/M/engage

M.engage()

Explicit opt-out for suites/harnesses that own their own tick cadence but haven't injected synthetic input yet — call before the first Zin.state / Zin.actions / Zin.axes read so the liveness auto-arm doesn't start Zin.autoTick underneath the harness.

typed/builtin//modules/zinput/test/M/engaged

M.engaged() -> boolean

True once any synthetic test-input helper (pressKey, touchStart, etc.) or engage() has run this VM. Read by the liveness auto-arm so a test/harness VM keeps explicit control of Zin.tick cadence instead of the first real input read starting Zin.autoTick.

typed/builtin//modules/zinput/test/M/moveMouse

M.moveMouse(x: number, y: number)

Move the cursor to a screen position. Sets the absolute position; the engine computes mouse_delta as new - old, so successive calls produce meaningful deltas for orbit / look bindings.

typed/builtin//modules/zinput/test/M/pressKey

M.pressKey(code: string)

Hold a key DOWN and leave it held until releaseKey. Returns inside the frame where keys_pressed contains code, so Zin.actions.pressed polls and onPressed handlers both fire as the call returns. A second pressKey on a key that is still held produces no new press edge — release first, or use tapKey for a full press+release.

typed/builtin//modules/zinput/test/M/pressMouse

M.pressMouse(button: number?)

Simulate a mouse button press. Default: 0 (left).

typed/builtin//modules/zinput/test/M/releaseKey

M.releaseKey(code: string)

Simulate a key release. Returns inside the frame where keys_released contains code.

typed/builtin//modules/zinput/test/M/releaseMouse

M.releaseMouse(button: number?)

Simulate a mouse button release. Default: 0 (left).

typed/builtin//modules/zinput/test/M/runFrame

M.runFrame()

Advance one engine frame: yield so simulated events drain and the next snapshot is published. Use between manual __zero_input.simulate* calls when you need to checkpoint state without queueing a new event. Does NOT call Zin.tick() — run it yourself if you want action / event handlers to dispatch.

typed/builtin//modules/zinput/test/M/scroll

M.scroll(dy: number)

Simulate a mouse wheel scroll. Positive dy = up.

typed/builtin//modules/zinput/test/M/tapKey

M.tapKey(code: string, duration: number?)

Press + release in one call. If duration is set, waits that many seconds (held over multiple frames) between press and release. Does NOT tick — call Zin.tick(dt) between tapKey and your assertion if you need binding-action handlers to fire.

typed/builtin//modules/zinput/test/M/touchCancel

M.touchCancel(id: number)

Simulate the platform cancelling a touch contact.

typed/builtin//modules/zinput/test/M/touchEnd

M.touchEnd(id: number)

Simulate a touch contact lifting.

typed/builtin//modules/zinput/test/M/touchMove

M.touchMove(id: number, x: number, y: number, pressure: number?)

Simulate a touch contact moving.

typed/builtin//modules/zinput/test/M/touchStart

M.touchStart(id: number, x: number, y: number, pressure: number?)

Simulate a touch contact beginning. id is any stable number identifying the finger until its matching touchEnd/touchCancel. The primary contact (slot 0) also drives the mouse path.

typed/builtin//modules/zinput/touch/M/byId

M.byId(id: number) -> TouchPoint?

Look up an active contact by its finger id.

typed/builtin//modules/zinput/touch/M/capable

M.capable() -> boolean

Whether the session has (or has declared) a touch input source. Latched by the first contact, or set at boot by platforms that know up front.

typed/builtin//modules/zinput/touch/M/count

M.count() -> number

Number of active touch contacts this frame.

typed/builtin//modules/zinput/touch/M/off

M.off(handle: any)

Unsubscribe a handle returned by any Zin.touch.on* function.

typed/builtin//modules/zinput/touch/M/onBegan

M.onBegan(fn: (any, boolean) -> any, opts: any?)

Subscribe to touch-contact-begin events. fn(ev, gpe) where ev = { kind = "touch.down", id, x, y, pressure } and gpe is the UI-focus flag at fire time. Return "sink" to consume. Returns an Zin.events handle for off.

typed/builtin//modules/zinput/touch/M/onCancelled

M.onCancelled(fn: (any, boolean) -> any, opts: any?)

Subscribe to platform touch-cancel events ({ kind = "touch.cancel", id }).

typed/builtin//modules/zinput/touch/M/onEnded

M.onEnded(fn: (any, boolean) -> any, opts: any?)

Subscribe to touch-lift events ({ kind = "touch.up", id, x, y }).

typed/builtin//modules/zinput/touch/M/onMoved

M.onMoved(fn: (any, boolean) -> any, opts: any?)

Subscribe to touch-move events ({ kind = "touch.move", id, x, y, dx, dy, pressure }).

typed/builtin//modules/zinput/touch/M/primary

M.primary() -> TouchPoint?

The primary contact (slot 0), if a finger is down.

typed/builtin//modules/zinput/touch/M/slots

M.slots() -> { TouchPoint }

All active touch contacts this frame, in begin order.

typed/builtin//modules/zinput/touchControls/M/_advance

M._advance()

Internal: advance the touch-controls overlay one tick — route this tick's raw touches into Zin.virtual and recompute layout first, then auto-mount by Zin.surface.current() and repaint the overlay if its draw state changed. Wired into Zin.tick, before Zin.emulation._advance() (the floor consumes the Zin.virtual state this routing produces).

typed/builtin//modules/zinput/touchControls/M/_forceMount

M._forceMount(on: boolean)

Test-only: force the overlay to mount regardless of Zin.surface.current() — for headless tests that want to exercise rendering without a real touch surface. Touch routing itself is always active regardless of this flag.

typed/builtin//modules/zinput/touchControls/M/_reset

M._reset()

Test-only: unmount, clear all routing/layout state, drop bespoke buttons, close the fan, clear the viewport override, and reset the force-mount flag. Registration (ui.registerScreen) itself is not undone.

typed/builtin//modules/zinput/touchControls/M/_setViewportOverride

M._setViewportOverride(w: number?, h: number?)

Test-only: override the logical screen size (ui.screenSize() space) the layout budget/fan math uses, without resizing the real window — for headless tests that need to prove budget math at a phone-sized viewport. Pass nil for both to clear the override and fall back to the real ui.screenSize().

typed/builtin//modules/zinput/touchControls/M/button

M.button(opts: ButtonOpts) -> number

Add an overlay button. Two flavors:

  • { action = "jump" } attaches an extra touchButton binding to an existing action on the active map — a second on-screen instance of a control the map already defines.
  • { emit = "KeyF", label = "Cast" } registers an overlay-only button: a synthetic emit:KeyF action carrying both the kbm key binding and the touchButton, so the emulation floor drives KeyF straight from this button through the same binding/emulation path every other control uses. label/zone/icon set the button's presentation (see Zin.bindings.touchButton); when neither is given the button falls back to the action name (or the emit key).

typed/builtin//modules/zinput/touchControls/M/claimed

M.claimed() -> { number }

The contact ids currently claimed by the stick, a button, or the drag zone.

typed/builtin//modules/zinput/touchControls/M/layout

M.layout() -> any

The overlay's current control layout — a copy, safe to hold and mutate. buttons is the budgeted, VISIBLE stack in draw order (each entry { id, label, actionName, priority, size, group, cx, cy, radius } in ui.screenSize() space); fan is nil unless the button set exceeded the two-column budget, in which case it's { open, cx, cy, radius, buttons }open is whether the overflow sheet is currently expanded, buttons the overflowed entries at their sheet positions (tappable only while open). stick / drag name the axis + virtual zone each region feeds, or nil when the active map defines none in the current context. Empty until the first _advance() resolves a screen size. Backs custom control-placement UI and headless tests that need a button's (or the fan's) center to aim a simulated touch at.

typed/builtin//modules/zinput/touchControls/M/removeButton

M.removeButton(handle: number) -> boolean

Remove a button previously added via M.button.

typed/builtin//modules/zinput/utils/M/buttonIndex

M.buttonIndex(name: string) -> number?

Convert a mouse button name to its 0-based index.

typed/builtin//modules/zinput/utils/M/buttonName

M.buttonName(idx: number) -> string?

Convert a 0-based mouse button index to its name.

typed/builtin//modules/zinput/utils/M/matchModifiers

M.matchModifiers(snapshot: any, mods: Modifiers) -> boolean

Check whether the current frame's snapshot has the given modifiers held. Pass any subset of { ctrl, shift, alt }; unspecified keys are not checked. Returns false if snapshot is not a table — callers can forward Zin.state.get() directly without nil-checking first.

typed/builtin//modules/zinput/utils/M/normalizeKey

M.normalizeKey(code: string) -> string

Normalize a key code. Phase 1: identity (the codes coming out of Zin.state.get().keys are already in the documented web-style form — "KeyW", "Space", "ArrowUp", "ShiftLeft", …). Reserved as a future hook for layout-independent keys (e.g. Phase 3+ rebinding).

typed/builtin//modules/zinput/virtual/M/_beginFrame

M._beginFrame()

Internal: frame boundary — shift button edges, clear drag deltas. Called by the Zin.tick coordinator on the first tick of each engine frame.

typed/builtin//modules/zinput/virtual/M/_reset

M._reset()

Test-only: clear all virtual state.

typed/builtin//modules/zinput/virtual/M/addDrag

M.addDrag(zone: string, dx: number, dy: number)

Accumulate a drag delta for a zone this tick (cleared at the next frame boundary, like the mouse delta).

typed/builtin//modules/zinput/virtual/M/button

M.button(id: string) -> boolean

A virtual button's held state.

typed/builtin//modules/zinput/virtual/M/buttonPressed

M.buttonPressed(id: string) -> boolean

Whether a virtual button was pressed this frame (held now, not held at the previous frame boundary).

typed/builtin//modules/zinput/virtual/M/buttonReleased

M.buttonReleased(id: string) -> boolean

Whether a virtual button was released this frame.

typed/builtin//modules/zinput/virtual/M/drag

M.drag(zone: string) -> (number, number)

A zone's accumulated drag delta this frame.

typed/builtin//modules/zinput/virtual/M/setButton

M.setButton(id: string, held: boolean)

Set a virtual button's held state. Edges (pressed/released) are derived at the frame boundary.

typed/builtin//modules/zinput/virtual/M/setStick

M.setStick(zone: string, x: number, y: number)

Set a virtual stick's normalized vector (each component -1..1; values are clamped). Persists until set again or reset.

typed/builtin//modules/zinput/virtual/M/stick

M.stick(zone: string) -> (number, number)

A virtual stick's current vector ({x=0,y=0} when unset).

typed/builtin//modules/zui/M/defineWidget

M.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.

typed/builtin//modules/zui/M/unregisterWidget

M.unregisterWidget(name: string)

Unregister a previously-defined custom widget. No-op when the engine ui global is absent.

typed/builtin//modules/zui/app/App/_forgetScreen

App._forgetScreen(screenName: string)

Internal: drop a screen from every bookkeeping table after unregistering it.

typed/builtin//modules/zui/app/App/_isFirstRegister

App._isFirstRegister(screenName: string) -> boolean

Internal: true only on the FIRST register call for this screen — distinguishes register-vs-update for dynamic items that appear mid-life.

typed/builtin//modules/zui/app/App/_isRegistered

App._isRegistered(screenName: string) -> boolean

Internal: is screenName already in the registered list?

typed/builtin//modules/zui/app/App/_nextAnonId

App._nextAnonId(prefix: string?) -> string

Internal: allocate a stable per-tick anonymous id for closure-as-callback widgets. The id folds in the current screen name so same-text buttons in different screens don't collide.

typed/builtin//modules/zui/app/App/_register

App._register(firstMount: boolean)

Internal: walk the builder return table and (re)register every screen, diffing dynamic-list buckets against the previous tick.

typed/builtin//modules/zui/app/App/_renderOne

App._renderOne(screenName: string, buildFn: () -> any, firstMount: boolean, opts: RenderOpts?)

Internal: register-or-update a single screen, guarded by the per-screen token. opts carries tags (forwarded to Z.tags.set) and layer (passed to ui.registerScreen).

typed/builtin//modules/zui/app/App/_routerForTest

App._routerForTest() -> any

Test introspection: the embedded router instance.

typed/builtin//modules/zui/app/App/_runBuilder

App._runBuilder()

Internal: invoke the builder and cache its returned screen table.

typed/builtin//modules/zui/app/App/_screensForTest

App._screensForTest() -> { string }

Test introspection: copy of the registered screen list.

typed/builtin//modules/zui/app/App/_showAll

App._showAll()

Internal: call ui.showScreen for every currently-registered screen.

typed/builtin//modules/zui/app/App/cb

App.cb(id: string, handler: any) -> any

Register a callback id with the router and return the id (for passing as a widget prop). Equivalent to app._router:cb(id, handler).

typed/builtin//modules/zui/app/App/create

App.create(name: string, builderFn: BuilderFn) -> AppInstance

Construct an App instance. The builder is called immediately with (state, ctx). ctx is whatever the caller passed into :mount — typically self for a component or the UiPanel ctx. The builder MUST return a table of { [screenName] = buildFn | dynamic } describing every screen the app owns. The builder's return table is captured here at construction time; subsequent :ticks call each buildFn fresh to produce the live widget tree. Z.dynamic(...) values are recognised and exploded per-item by :tick.

typed/builtin//modules/zui/app/App/current

App.current() -> any

Returns the App instance whose buildFn is currently executing, or nil when called outside of Z.app(...). Used by widget builders (Z.collapsible, future controlled wrappers) to register handlers and mark dirty without an explicit app arg.

typed/builtin//modules/zui/app/App/dispatch

App.dispatch(callbackId: string, data: any?) -> any

Dispatch a callback id through the router. Used by raw event handlers that receive a (callbackId, data) pair.

typed/builtin//modules/zui/app/App/isDirty

App.isDirty() -> boolean

Has any reactive state changed since the last :tick?

typed/builtin//modules/zui/app/App/markDirty

App.markDirty()

Mark this App's screens as dirty so the next :tick re-renders.

typed/builtin//modules/zui/app/App/mount

App.mount(ctx: any) -> any

Mount the app. Calls the builder once to produce the initial set of screens; registers each via ui.registerScreen. Re-mount is safe (idempotent): the per-screen token claim makes any older App instance of the same screen name skip its :tick so we don't compete over ui.updateScreen.

typed/builtin//modules/zui/app/App/on

App.on(idOrPattern: string, handler: any) -> any

Register a router handler. Equivalent to app._router:on(idOrPattern, handler).

typed/builtin//modules/zui/app/App/set

App.set(key: string, value: any) -> any

Convenience: set a single reactive state key. Equivalent to app.state:set(key, value).

typed/builtin//modules/zui/app/App/tick

App.tick(_dt: number?)

Tick from the host's update(dt). Re-renders dirty screens.

typed/builtin//modules/zui/app/App/unmount

App.unmount()

Unmount: unregister every owned screen (static + dynamic) and drop the token claims.

typed/builtin//modules/zui/app/App/update

App.update(updates: { [string]: any }) -> any

Convenience: bulk-update state. Equivalent to app.state:update(updates).

typed/builtin//modules/zui/dataSource/DataSource/invalidate

DataSource.invalidate()

Clear the cached value and timestamp so the next :read() will re-fetch — even when the gate is currently closed. Invalidate is the documented "force a refresh" entry point; the gate's job is to optimize steady-state cost, not to veto explicit invalidations, so this sets a one-shot _forceFetch flag that the next read clears.

typed/builtin//modules/zui/dataSource/M/_peekForTest

M._peekForTest(key: string) -> Source?

Test hook: peek at a registered source by key. Returns nil when the key is unknown.

typed/builtin//modules/zui/dataSource/M/_seedForTest

M._seedForTest(key: string, value: any) -> Source?

Test hook: seed a value WITHOUT invoking the fetcher.

typed/builtin//modules/zui/dataSource/M/create

M.create(fetchFn: () -> any, opts: Opts?) -> Source

Create a data source instance wrapping a fetch function with TTL

  • optional gate. Auto-allocates a key when opts.key is omitted.

typed/builtin//modules/zui/dataSource/M/invalidate

M.invalidate(key: string)

Force a re-fetch on the next read for a registered key. No-op when the key is unknown.

typed/builtin//modules/zui/dataSource/M/reset

M.reset()

Wipe the registry. Used by destroy() paths to release retained values.

typed/builtin//modules/zui/dynamic/Dynamic/create

Dynamic.create(list: { any }, fn: (any, number) -> any) -> Wrapper

Construct a dynamic-list bucket. list is the live array of items the App reads each tick; fn(item, index) returns the widget tree for one item. Each item must carry a stable id field — the App uses it to compute the per-item screen name <base>-<item.id> and to diff against the previous tick's set.

typed/builtin//modules/zui/dynamic/Dynamic/is

Dynamic.is(value: any) -> boolean

True if value is a Z.dynamic(...) wrapper. The App calls this when walking the builder's return table to decide between register single screen vs register one screen per list item.

typed/builtin//modules/zui/dynamic/Dynamic/itemId

Dynamic.itemId(item: any, index: number) -> string

Stable per-item id. Falls back to the array index when the item doesn't carry one — keeps the API forgiving for prototypes that add .id later.

typed/builtin//modules/zui/highlight/M/dispatch

M.dispatch(language: string, text: string) -> { Segment }

Dispatch a highlighter by language name, with yml and md aliases matching the engine's pre-Phase-3 parse_editor_language. Unknown languages return a single default-colored segment so callers can pass arbitrary user input without crashing.

typed/builtin//modules/zui/highlight/json/highlightJson

highlightJson(text: string) -> { Segment }

Tokenize a JSON string into colored text segments for the zui code renderer. Distinguishes object keys (via lookahead for :) from string values, colors numbers (including scientific notation), bool/null literals, and structural punctuation.

typed/builtin//modules/zui/highlight/lua/highlightLua

highlightLua(text: string) -> { Segment }

Tokenize a Luau source string into colored text segments for the zui code renderer. Walks lines, dispatching the pre-comment portion through the code tokenizer (string/number/keyword/identifier) and the ---introduced comment tail through the comment color.

typed/builtin//modules/zui/highlight/markdown/highlightMarkdown

highlightMarkdown(text: string) -> { Segment }

Tokenize a Markdown source string into colored text segments for the zui code renderer. Block-level pass recognises fenced code (```), headings (#), blockquotes (>), bullet and ordered lists; inline pass within each non-block line recognises inline code, bold, and links.

typed/builtin//modules/zui/highlight/wgsl/highlightWgsl

highlightWgsl(text: string) -> { Segment }

Tokenize a WGSL source string into colored text segments for the zui code renderer. Handles // and /* */ comments, "..." strings with backslash escapes, @attribute tokens, numeric literals with suffixes (1u, 0xFF, 1.0_f32), and identifiers dispatched against the WGSL keyword and built-in type tables.

typed/builtin//modules/zui/highlight/yaml/highlightYaml

highlightYaml(text: string) -> { Segment }

Tokenize a YAML source string into colored text segments for the zui code renderer. Splits each line on a # comment first, then on the first : to extract a key from its value; the value is then classified as quoted string / bool / null / numeric / plain.

typed/builtin//modules/zui/router/Router/_resetWarnings

Router._resetWarnings()

Test-only helper: clear the unhandled-id warning gate so a test can assert the warn-once behaviour by running dispatch, then resetting, then running again. Production code never calls this.

typed/builtin//modules/zui/router/Router/_wasWarned

Router._wasWarned(id: string) -> boolean

Test-only helper: returns true if id has triggered an unhandled warning. Used by the test suite to assert the one-shot gate.

typed/builtin//modules/zui/router/Router/cb

Router.cb(id: string, handler: Handler) -> string

Inline-register shorthand. Used as Z.btn("Save", app:cb("save:click", fn)) — registers the handler AND returns the id so the widget binds to it in one expression. Always treats the input as a literal id (the inline shorthand is for naming a specific widget; pattern matching is reserved for :on).

typed/builtin//modules/zui/router/Router/create

Router.create() -> RouterInstance

Create a new empty router instance. The returned object owns its handler map, pattern list, and unhandled-warning gate; nothing is shared between routers.

typed/builtin//modules/zui/router/Router/dispatch

Router.dispatch(callbackId: string, data: any?) -> boolean

Dispatch a callback. Tries the exact-match map first, then patterns in registration order. The handler is called with (value, callbackId, ...captures):

  • value: extracted via Utils.eventValue(data) so handlers see the scalar (slider position, last-clicked hotbar slot, text- input contents, dndList from,to payload, ...) without unwrapping data manually.
  • callbackId: the original id, useful for shared handlers.
  • captures: the pattern's string.match captures, expanded positionally so app:on("cell:%d+:%d+", function(_, id, row, col) ...) reads naturally. Logs a one-shot Warn on the first miss for an id so authors find typos without spam.

typed/builtin//modules/zui/router/Router/on

Router.on(idOrPattern: string, handler: Handler) -> RouterInstance

Register a handler. Detects pattern strings automatically; literal ids land in the fast-path map, patterns land in the ordered list. Last-write-wins for both — registering the same id twice replaces the previous handler.

typed/builtin//modules/zui/screens/M/byName

M.byName() -> { [string]: ScreenEntry }

Same data as list() but { [name] = entry } shape for O(1) lookup.

typed/builtin//modules/zui/screens/M/exists

M.exists(name: string) -> boolean

Does a screen with this name exist in ui.listScreens()? Returns false for screens registered this frame (the snapshot is one frame behind on register/update commands).

typed/builtin//modules/zui/screens/M/hideAll

M.hideAll()

Hide every currently-visible screen. No-op when nothing is visible or the ui global has no hideScreen.

typed/builtin//modules/zui/screens/M/list

M.list() -> { ScreenEntry }

Pass-through to ui.listScreens() — array of { name, visible, layer, hasRoot } entries sorted by layer ascending then name. Provided for parity with the rest of Z.screens.

typed/builtin//modules/zui/screens/M/toggle

M.toggle(name: string)

Toggle a screen: visible → hidden via ui.hideScreen, hidden → visible via ui.showScreen. Unknown screens are silent no-ops.

typed/builtin//modules/zui/screens/M/visible

M.visible(name: string) -> boolean

Is the named screen currently visible? Returns false when the screen doesn't exist OR exists but is hidden.

typed/builtin//modules/zui/shell/canvas/canvasShell

canvasShell(opts: CanvasOpts?)

Render a node-graph canvas widget from a node/connection state. Background rect + bezier connections + per-node rounded rects with labels, with optional pointer-event wiring to caller-supplied callback ids for select/move.

typed/builtin//modules/zui/shell/dockApp/M/create

M.create(opts: DockAppOpts) -> DockAppHandle

Create a visibility-driven docked-app handle. Wraps Z.app with a per-panel refresh scheduler over the same tab contract as Z.shell.tabApp, but renders open panels as Z.dockPanels inside a single Z.dockArea (real egui_dock tabs / splits / drag). The app costs zero engine work when hidden; each open panel polls on its own refresh interval.

typed/builtin//modules/zui/shell/docked/dockedShell

dockedShell(opts: DockedOpts?)

Render a docked-panel layout from top/left/center/right/bottom slots. Outer vbox with gap=0, theme bg; the center slot is flex-grown horizontally; missing slots are omitted cleanly.

typed/builtin//modules/zui/shell/inspector/inspectorShell

inspectorShell(opts: InspectorOpts?)

Render an inspector pane with a title, fields (or collapsible sections), and action buttons. Field editors are auto-selected from the value type, with field.kind overriding (e.g. for color swatches or free-form int/float inputs).

typed/builtin//modules/zui/shell/tabApp/M/create

M.create(opts: TabAppOpts) -> TabAppHandle

Create a visibility-driven tabbed-app handle. Wraps Z.app with a per-tab refresh scheduler — the panel costs zero engine work when hidden, closed, or minimized; only the active tab's build() is invoked when open.

typed/builtin//modules/zui/state/State/create

State.create(initial: { [string]: any }?, app: App?) -> StateInstance

Construct a new State instance.

typed/builtin//modules/zui/tags/M/add

M.add(name: string, tag: string)

Add a single tag to name. Creates the registry entry if absent. No-op when name or tag is empty / not a string.

typed/builtin//modules/zui/tags/M/clear

M.clear(name: string)

Drop every tag for name. Idempotent — safe to call when no entry exists.

typed/builtin//modules/zui/tags/M/findByTag

M.findByTag(tag: string) -> { string }

Return { "screenName", ... } of every registered screen carrying tag. Sorted. Entries whose screen isn't currently in ui.listScreens() are filtered out (but kept in the registry).

typed/builtin//modules/zui/tags/M/get

M.get(name: string) -> { string }

Return name's tags as a sorted { string } array (deterministic order for tests and debug output). Returns an empty array when there is no registry entry.

typed/builtin//modules/zui/tags/M/hideByTag

M.hideByTag(tag: string)

Hide every currently-visible screen tagged with tag. Calls ui.hideScreen once per match. No-op if no match.

typed/builtin//modules/zui/tags/M/remove

M.remove(name: string, tag: string)

Remove a single tag from name. If the resulting set is empty, the registry entry is dropped so the screen no longer counts as tagged at all. No-op when there is no entry for name.

typed/builtin//modules/zui/tags/M/set

M.set(name: string, tags: { any }?)

Replace name's tag set with the array tags. Passing nil or an empty list clears the entry. Non-string / empty tags are filtered out; if the resulting set is empty the entry is dropped entirely.

typed/builtin//modules/zui/tags/M/showByTag

M.showByTag(tag: string)

Show every currently-hidden screen tagged with tag. Calls ui.showScreen once per match. No-op if no match.

typed/builtin//modules/zui/theme/M/activate

M.activate(name: string) -> boolean

Activate a registered theme. Thin wrapper over ui.setTheme(name) for symmetry with register / load.

typed/builtin//modules/zui/theme/M/defaults

M.defaults() -> TokenMap

Return the raw fallback token map shipped with this module. Used by tests / introspection; not part of the cascade.

typed/builtin//modules/zui/theme/M/load

M.load(name: string) -> (boolean, string?)

Convenience: require("@builtin::themes." .. name) then register. Built-in themes (dark, light, debug) live at src/lua/lib/themes/<name>.module/init.luau.

typed/builtin//modules/zui/theme/M/register

M.register(name: string, theme: any) -> (boolean, string?)

Register a theme with the engine under name. Walks the theme's tokens + styles, resolves every $variable reference (with cycle detection), and pushes flat values to the active ThemeRegistry.

typed/builtin//modules/zui/theme/M/resolve

M.resolve(theme: any) -> (ResolvedTheme?, string?)

Resolve $variable references in a theme table and return the flat { name, tokens, styles } shape the engine consumes. Pure function — used by register and exposed for tests.

typed/builtin//modules/zui/theme/M/tokenNames

M.tokenNames() -> { string }

Return the sorted list of token names shipped with this module. Useful for theme editors / token pickers.

typed/builtin//modules/zui/theme/M/with

M.with(overrides: TokenMap?) -> ThemeView

Build a read-only theme view that overlays the given overrides on top of the engine-or-defaults token map. Module functions are exposed alongside tokens so the view doubles as the namespace.

typed/builtin//modules/zui/theme/cascade/M/resolveStyles

M.resolveStyles(theme: any, resolvedTokens: any) -> (StyleMap?, string?)

Walk theme.styles and resolve every $reference inside style values against resolvedTokens. Returns a { [selector]: { [prop]: value } } map with no remaining $variable strings. Selector and property keys pass through unchanged (cascade ordering is the caller's concern).

typed/builtin//modules/zui/theme/cascade/M/resolveTokens

M.resolveTokens(theme: any) -> (TokenMap?, string?)

Walk theme.tokens and resolve every $reference to a literal. Tokens that reference other tokens are flattened — after this pass, every value is a literal string / number / etc.

typed/builtin//modules/zui/utils/M/compact

M.compact(widgets: { any }?) -> { any }

Drop nil entries from a widget list. Pairs with Utils.when so conditional widgets can be nil and removed in a single pass.

typed/builtin//modules/zui/utils/M/eventValue

M.eventValue(data: EventEnvelope?) -> any

Extract data.value from v2 event objects (fallback to raw data for older senders). Used by every demo's onCallback handler today. Strings flow through unchanged. Structured payloads (canvas onDrag / onDoubleClick — {x, y, dx, dy, shift, ctrl, alt, ...}) come through as a Luau table on data.value; this helper returns the table verbatim so handlers can local d = Utils.eventValue(data); print(d.dx) without manual unwrapping.

typed/builtin//modules/zui/utils/M/fmt

M.fmt(v: number?, decimals: number?) -> string

Format v as a string with decimals places (default 2). Thin wrapper over roundtostring.

typed/builtin//modules/zui/utils/M/fmtVec3

M.fmtVec3(vec: Vec3Array?, decimals: number?) -> string

Format a { x, y, z } array as "(x, y, z)" with each component rounded to decimals places (default 2). Missing components default to 0.

typed/builtin//modules/zui/utils/M/id

M.id(parent: any, child: any) -> string

Stable hierarchical widget id construction. egui's per-id state persistence (scroll offsets, expanded sections, etc.) needs stable ids across rebuilds — Z.id("toolbar", "save")"toolbar/save".

typed/builtin//modules/zui/utils/M/map

M.map(items: { any }?, fn: (any, number) -> any?) -> { any }

Map fn(item, i) over items, dropping any nil results. Useful for building child widget arrays from data — Utils.map(rows, function(r) return Z.lbl(r.name) end).

typed/builtin//modules/zui/utils/M/round

M.round(v: number?, decimals: number?) -> number

Round v to decimals places (default 2). Pure arithmetic — no string.format dependency so it's WASM-safe.

typed/builtin//modules/zui/utils/M/when

M.when(cond: any, widget: any) -> any

Return widget when cond is truthy, else nil. Useful for conditional widgets inside Z.vbox{...} arrays — Z.when(showFoo, Z.lbl("foo")) slots cleanly between other children and is dropped by Utils.compact.

typed/builtin//modules/zui/widget/_axes/M/axisCommands

M.axisCommands(viewport: Viewport, bounds: Bounds, opts: AxesOpts?) -> { CanvasCommand }

Build canvas commands for X + Y axes — axis lines, tick marks, and tick labels. X axis at the bottom of viewport, Y axis at the left. Tick positions come from computeTicks and are clipped to the viewport's pixel bounds.

typed/builtin//modules/zui/widget/_axes/M/computeTicks

M.computeTicks(minV: number, maxV: number, nTicks: number?, customFormat: TickFormatter?) -> TickResult

D3-style nice ticks: snaps the step to {1, 2, 5} × 10^n so the tick values are human-readable. Returns parallel arrays of numeric tick values and their formatted label strings. nTicks is a target count (default 5); the algorithm returns a count close to but not exactly nTicks. Label formatting uses an integer format when the step is >= 1 and a %.Nf format with appropriate digit count for fractional steps. Pass customFormat to override the default formatter (e.g. currency or time-series).

typed/builtin//modules/zui/widget/_axes/M/gridCommands

M.gridCommands(viewport: Viewport, bounds: Bounds, opts: AxesOpts?) -> { CanvasCommand }

Build canvas line commands for vertical and horizontal gridlines — one per major tick. Visibility is per-axis via opts.gridX / opts.gridY (default both true). Gridlines are clipped to the viewport's pixel bounds.

typed/builtin//modules/zui/widget/_markers/M/commands

M.commands(shape: MarkerShape, cx: number, cy: number, radius: number, opts: MarkerOpts?) -> { CanvasCommand }

Returns the canvas commands for marker shape centered at (cx, cy) with size radius. Unknown shapes warn and fall back to circle (parity with the deleted Rust path).

typed/builtin//modules/zui/widget/_rowCanvas/rowCanvas

rowCanvas(opts: RowOpts?) -> Node

Build a selectable-row canvas widget — background + optional radio glyph + label rendered as a single focusable canvas. Click emits <groupId>:select:<index> via onClick; arrow keys reach the parent via onKey = <groupId>:nav. Used by Z.radioGroup and Z.selectableList.

typed/builtin//modules/zui/widget/_viewport/Viewport/bounds

Viewport.bounds(self: ViewportInstance) -> Bounds

Snapshot the current bounds as a Bounds table. Called as a free function (Viewport.bounds(vp)), not via colon syntax.

typed/builtin//modules/zui/widget/_viewport/Viewport/dataToScreen

Viewport.dataToScreen(x: number, y: number) -> (number, number)

Map (x, y) in data space to canvas-local pixels. yMax maps to the top of the viewport (rect.y) so the cursor sits above the data point. Honors invertX / invertY for flipped axes.

typed/builtin//modules/zui/widget/_viewport/Viewport/make

Viewport.make(plotId: string?, rect: Rect?, defaultBounds: Bounds?) -> ViewportInstance

Constructs a viewport for plotId over the given canvas-local rect (the rectangle reserved for the plot body, excluding axes / labels). defaultBounds seeds widgetState on first call; subsequent calls re-hydrate the cached bounds.

typed/builtin//modules/zui/widget/_viewport/Viewport/pan

Viewport.pan(dxScreen: number, dyScreen: number, axisAllow: AxisFilter?)

Pan by a screen-space delta. Positive dxScreen shifts the view rightward (bounds shift left so the same data point stays under the cursor). Pass axisAllow = { x, y } to filter per axis. Writes the new bounds back to widgetState.

typed/builtin//modules/zui/widget/_viewport/Viewport/screenToData

Viewport.screenToData(sx: number, sy: number) -> (number, number)

Inverse of dataToScreen — map (sx, sy) in canvas-local pixels to data space. Honors invertX / invertY.

typed/builtin//modules/zui/widget/_viewport/Viewport/setBounds

Viewport.setBounds(bounds: Bounds)

Reset to a given bounds table. Useful for "fit data" / double-click. Writes the new bounds back to widgetState.

typed/builtin//modules/zui/widget/_viewport/Viewport/zoom

Viewport.zoom(factor: number, anchorScreen: ScreenPoint?, axisAllow: AxisFilter?)

Zoom by factor (> 1 zoom in, < 1 zoom out) around an anchor in screen space. axisAllow = { x, y } filters per axis. Writes the new bounds back to widgetState.

typed/builtin//modules/zui/widget/anchor/anchorWidget

anchorWidget(anchor: AnchorPos, margin: Margin, children: { Node }?, opts: AnchorOpts?) -> Node

Corner a child to a screen edge. Root-only — must be the top-level widget of its registered screen. Emits anchor and margin at the widget root (not inside props) so the validator doesn't flag prop-shape-misplaced.

typed/builtin//modules/zui/widget/area/areaWidget

areaWidget(children: { Node }?, opts: AreaOpts?) -> Node

Free-positioned area widget. Root-only — must be the top-level node of its registered screen. The pos field sits at the widget root level (not inside props) because that's what the engine's area decoder expects.

typed/builtin//modules/zui/widget/args/resolve

resolve(builderName: string, a: any, b: any) -> ({ any }, { [string]: any })

Resolve a container builder's flexible (children, opts) arguments into a definite (children, opts) pair, accepting the single options-table form and erroring loudly on ambiguous input rather than silently dropping children.

typed/builtin//modules/zui/widget/bottomPanel/bottomPanelWidget

bottomPanelWidget(children: { Node }?, opts: PanelOpts?) -> Node

Bottom-docked panel. Root-only — must be the top-level widget of its registered screen.

typed/builtin//modules/zui/widget/button/button

button(text: string?, callbackId: any?, opts: ButtonOpts?) -> any

Build a clickable button widget node. The 2nd arg accepts a string callback id, a closure (auto-wired via the surrounding Z.app), or an options table (JS-style call shape: Z.btn(text, opts)).

typed/builtin//modules/zui/widget/canvas/canvas

canvas(id: string?, opts: CanvasOpts?) -> any

Build a 2D-paint canvas widget. The widget body is a list of paint commands (line, bezier, polyline, rect, circle, text) drawn in widget-local coords. Pointer/keyboard/scroll handlers are wired through as engine props.

typed/builtin//modules/zui/widget/card/card

card(opts: CardOpts?) -> any

Build a card composite — title + description + optional image placeholder + arbitrary children inside a styled panel.

typed/builtin//modules/zui/widget/centralPanel/centralPanel

centralPanel(children: { any }?, opts: { [string]: any }?) -> any

Build a centralPanel widget — fills the area not consumed by the docked edge panels. Root-only; intended as the body of a docked-shell layout.

typed/builtin//modules/zui/widget/checkbox/checkbox

checkbox(label: string?, id: string?, checked: any?, opts: CheckboxOpts?) -> any

Build a checkbox widget node — a boolean input with a trailing label.

typed/builtin//modules/zui/widget/chip/chip

chip(text: string?, opts: ChipOpts?) -> any

Build a compact tag/badge chip. Variant selects a foreground/ background colour pair from the active theme; bg and color override per-call.

typed/builtin//modules/zui/widget/codeEditor/codeEditor

codeEditor(id: string?, value: any?, opts: CodeEditorOpts?) -> any

Build a code-editor widget — input configured for code editing with syntax highlighting via the Luau zui.highlight.* dispatcher. Defaults multiline, codeEditor, lineNumbers true and language = "lua".

typed/builtin//modules/zui/widget/collapsible/collapsible

collapsible(header: any?, children: { any }?, opts: CollapsibleOpts?) -> any

Build a collapsible section — a header bar that toggles expansion of the children block. Auto-wires open/closed state through ui.widgetState and the surrounding Z.app router.

typed/builtin//modules/zui/widget/colorSwatch/colorSwatch

colorSwatch(color: any?, callbackId: any?, opts: ColorSwatchOpts?) -> any

Build a click-only coloured swatch — a small coloured rect that routes clicks to the given callback. Useful as palette swatches, material chips, or any colour-as-click-target indicator.

typed/builtin//modules/zui/widget/contextMenu/contextMenu

contextMenu(anchorId: string?, items: { any }?, opts: ContextMenuOpts?) -> any

Build a context-menu popup pinned to an anchor widget. Thin convenience wrapper over Z.popup with menu-friendly defaults.

typed/builtin//modules/zui/widget/datePicker/datePicker

datePicker(id: string?, value: any?, opts: DatePickerOpts?) -> any

Build a calendar-popup date-picker widget. Value flows as an ISO-style date string; format defaults to "%Y-%m-%d" and can be overridden via opts.format (jiff strftime spec).

typed/builtin//modules/zui/widget/dialogueBox/dialogueBox

dialogueBox(opts: DialogueBoxOpts?) -> any

Build a narrative dialogue panel — speaker name + dialogue text + per-option response buttons inside a styled panel. Each option emits a click event to <id>-<index> for pattern-handler routing.

typed/builtin//modules/zui/widget/dndList/dndList

dndList(id: string?, children: { any }?, opts: DndListOpts?) -> any

Build a drag-and-drop reorderable list — per-row canvases plus a transparent overlay for drag detection and the insertion indicator. Dispatches onReorder with { from, to, value } when a drag commits.

typed/builtin//modules/zui/widget/dockArea/dockArea

dockArea(opts: Opts?) -> any

Build a docking container of dockPanel children. Root-only: it must be the screen tree root. Layout persists across frames and round-trips via ui.getDockLayout(id) + the layout prop.

typed/builtin//modules/zui/widget/dockPanel/dockPanel

dockPanel(opts: Opts?) -> any

Build a single dockable panel for a dockArea. The panel id is the stable tab id; its children are the tab content subtree.

typed/builtin//modules/zui/widget/dragValue/build

build(id: string, value: number?, lo: number?, hi: number?, opts: DragValueOpts?) -> WidgetNode

Build a drag-to-change numeric scrubber on a canvas — drag accumulates a delta scaled by opts.speed; Shift halves the per-pixel step.

typed/builtin//modules/zui/widget/dropdown/build

build(id: string, options: { string }?, selected: number?, opts: DropdownOpts?) -> WidgetNode

Build a combobox-style dropdown — trigger button + popup with a SelectableList inside. Full keyboard nav (ArrowUp/Down/Home/End/Enter/Esc).

typed/builtin//modules/zui/widget/fader/build

build(id: string, value: number?, lo: number?, hi: number?, opts: FaderOpts?) -> WidgetNode

Build a DAW-style vertical fader on a canvas — drag (or click) the cap to set a value in [lo, hi]; double-click restores defaultValue when set.

typed/builtin//modules/zui/widget/filterRow/build

build(opts: FilterRowOpts?) -> WidgetNode

Build a composite filter row — optional search input + toggle checkboxes + sort dropdown + counter + action buttons inside a single hbox.

typed/builtin//modules/zui/widget/flex/build

build() -> Spacer

Build a flex-grow spacer widget node that pushes siblings apart inside an hbox/vbox.

typed/builtin//modules/zui/widget/fs/breadcrumb/build

build(path: string, opts: BreadcrumbOpts?) -> WidgetNode

Build a breadcrumb path widget — renders an absolute path as a row of clickable segments.

typed/builtin//modules/zui/widget/fs/detailsList/build

build(entries: { DetailsEntry }?, opts: DetailsListOpts?) -> WidgetNode

Build the Explorer's right pane — a scrollable details list of a directory's entries (icon · name · kind), folders first, selected row highlighted.

typed/builtin//modules/zui/widget/fs/dialog/build

build(model: any, opts: DialogOpts?) -> WidgetNode

Build a modal save / load file dialog around the two-pane Explorer.

typed/builtin//modules/zui/widget/fs/explorer/build

build(model: any, opts: ExplorerOpts?) -> WidgetNode

Build the two-pane Explorer (breadcrumb + up/refresh, folder tree left, details list right) from a controller model.

typed/builtin//modules/zui/widget/fs/fileList/build

build(entries: { FileEntry }?, opts: FileListOpts?) -> WidgetNode

Build a scrollable flat row list of files in a directory — folders first, selected file highlighted.

typed/builtin//modules/zui/widget/fs/preview/build

build(data: PreviewData?, opts: PreviewOpts?) -> WidgetNode

Build a file preview pane — header, optional note line, separator, and body.

typed/builtin//modules/zui/widget/fs/tree/build

build(roots: { FsNode }?, opts: FsTreeOpts?) -> WidgetNode

Build a folder-tree composite over Z.tree with folder/file icons and absolute-path callback ids.

typed/builtin//modules/zui/widget/graph/build

build(data: { number }?, opts: GraphOpts?) -> WidgetNode

Build a sparkline-class chart over a canvas — bar or line mode, auto-ranged Y axis, optional gridlines / axes / tooltip.

typed/builtin//modules/zui/widget/grid/build

build(children: ({ WidgetNode } | GridOpts)?, columns: (number | GridOpts)?, opts: GridOpts?) -> WidgetNode

Build a fixed-column grid container — children flow left-to-right then wrap.

typed/builtin//modules/zui/widget/hbox/build

build(children: ({ WidgetNode } | HboxOpts)?, opts: HboxOpts?) -> WidgetNode

Build a horizontal layout container that lays children out left-to-right.

typed/builtin//modules/zui/widget/lsp/diagnosticsList/diagnosticsList

diagnosticsList(diags: { Diagnostic }?, onSelect: string?, opts: Opts?) -> any

Render a scrollable list of LSP diagnostics. Each row shows severity, location, code chip, and message. Clicking a row emits the callback id <onSelect>-<idx> (1-based).

typed/builtin//modules/zui/widget/lsp/directiveBadge/directiveBadge

directiveBadge(skipMode: SkipMode?, opts: Opts?) -> any?

Render a colored chip for a file's LSP skip directive. Returns nil for mode == "none" so callers can drop the result into a layout without conditionals. Pass opts.showNone = true to render a neutral "no directive" chip in that case instead.

typed/builtin//modules/zui/widget/lsp/docBrowser/docBrowser

docBrowser(state: State?, opts: Opts?) -> any

Render the three-pane API doc browser. Driven by the caller-owned state table; the widget never calls lsp.* itself. Emits callback ids prefixed by opts.onSelect (default "lsp-docs") for namespace / method / search / kind changes.

typed/builtin//modules/zui/widget/lsp/severitySummary/severitySummary

severitySummary(counts: Counts?, opts: Opts?) -> any

Render a horizontal row of colored severity-count chips matching the shape returned by lsp.summary() / lsp.checkAll(). Zero-count severities are hidden unless opts.showZero is set; when all counts are zero, a neutral "0 diagnostics" chip is rendered so the layout doesn't collapse.

typed/builtin//modules/zui/widget/lsp/strictModeToggle/strictModeToggle

strictModeToggle(currentMode: string?, onChange: string?, opts: Opts?) -> any

Render the LSP strict-gate three-button radio. Presentational only — emits callback ids of the form <onChange>-<mode> so the owning app can call lsp.setStrictMode() and mirror the change into its state.

typed/builtin//modules/zui/widget/meter/meter

meter(value: number?, opts: Opts?) -> any

Render a peak-style level meter on canvas. Either continuous fill (default) or LED-style segmented (set opts.segments). Tracks peak hold + decay through ui.widgetState when opts.id is set; without an id the peak indicator is skipped.

typed/builtin//modules/zui/widget/minimap/minimap

minimap(opts: Opts?) -> any

Render a square minimap canvas with an optional set of normalized markers. With no opts.markers, falls back to the legacy single light-green centre dot.

typed/builtin//modules/zui/widget/modal/modal

modal(opts: Opts?) -> any

Render a top-layer modal dialog with backdrop dim, click-outside

  • Escape dismissal. Root-only — the render arm dispatches at the screen-root path, just like Window. Pass dismissible = false to force an explicit-button answer (no backdrop / Escape close).

typed/builtin//modules/zui/widget/node/node

node(widgetType: string, opts: Opts?, children: any?) -> any

Build a generic widget table with optional id, classes, props, style, and children. The constructor every zui widget composes on. Accepts either a single child or an array of children — single children get wrapped automatically, matching the scroll.module precedent.

typed/builtin//modules/zui/widget/panel/panel

panel(children: ({ any } | Opts)?, opts: Opts?) -> any

Build a bordered grouping surface. Top-level shortcut keys (bg, border, borderWidth, padding, gap, minWidth/ minHeight / maxWidth / maxHeight) merge into opts.style so the common case doesn't require nesting under style = { ... }. Pass scroll = true to wrap children in a scrollArea; pair with maxHeight (or scrollMaxHeight to bound only the scroll region) so content taller than the panel scrolls in place rather than overflowing past the viewport (closes #3270).

typed/builtin//modules/zui/widget/plot/Plot/bezierLine

Plot.bezierLine(p0: Point, p1: Point, p2: Point, p3: Point, samples: number?, opts: any?) -> LineSpec

Sample a cubic Bezier defined by four control points and return it as a Line-typed element ready to drop into a PlotSpec's elements array.

typed/builtin//modules/zui/widget/plot/Plot/boxPlot

Plot.boxPlot(spec: BoxPlotSpec) -> BoxPlotSpec spec.type = "boxPlot";

Tag an element spec with type = "boxPlot" for use inside a PlotSpec's elements array.

typed/builtin//modules/zui/widget/plot/Plot/heatmap

Plot.heatmap(spec: HeatmapSpec) -> HeatmapSpec spec.type = "heatmap";

Tag an element spec with type = "heatmap" for use inside a PlotSpec's elements array.

typed/builtin//modules/zui/widget/plot/Plot/line

Plot.line(spec: LineSpec) -> LineSpec spec.type = "line";

Tag an element spec with type = "line" for use inside a PlotSpec's elements array.

typed/builtin//modules/zui/widget/plot/Plot/points

Plot.points(spec: PointsSpec) -> PointsSpec spec.type = "points";

Tag an element spec with type = "points" for use inside a PlotSpec's elements array.

typed/builtin//modules/zui/widget/popup/popup

popup(opts: Opts?) -> any

Render an anchored floating popup pinned to another widget's rect. The anchor MUST render before the popup in the tree — earlier-than-anchor popups silently fail with a WARN log.

typed/builtin//modules/zui/widget/progressBar/progressBar

progressBar(value: number?, opts: Opts?) -> any

Render a horizontal progress bar canvas. value is clamped to [0, 1] and rendered as a percent-width fill rect over a full-width track. Declares role = "progressbar" + ARIA value attrs for assistive tech.

typed/builtin//modules/zui/widget/radioGroup/radioGroup

radioGroup(id: string, options: { any }?, selected: number?, opts: RadioGroupOpts?) -> any

Build a single-select radio-group widget composed of focusable per-row canvases inside a panel.

typed/builtin//modules/zui/widget/richText/richText

richText(segments: { RichTextSegment }?, opts: RichTextOpts?) -> any

Build a read-only multi-colored text widget from a flat list of { text, color, italic?, monospace? } segments.

typed/builtin//modules/zui/widget/rightPanel/rightPanel

rightPanel(children: { any }?, opts: RightPanelOpts?) -> any

Build a right-docked panel widget. Must be a screen's top-level (root) widget.

typed/builtin//modules/zui/widget/scene/scene

scene(opts: SceneOpts?) -> any

Build a pan/zoom 2D viewport widget. Children render inside a transformed coordinate space — mouse-wheel zooms, primary-drag pans.

typed/builtin//modules/zui/widget/scroll/scroll

scroll(children: any?, opts: ScrollOpts?) -> any

Build a scrollable container widget. Top-level shortcuts maxHeight / maxWidth / minHeight / minWidth merge into opts.style, and stickToBottom merges into opts.props, so the common case doesn't require nesting under style = { ... } (closes #3270 discoverability).

typed/builtin//modules/zui/widget/section/section

section(title: any, children: { any }?, opts: SectionOpts?) -> any

Build a panel widget prefixed with a bold header label.

typed/builtin//modules/zui/widget/selectableList/selectableList

selectableList(id: string, options: { any }?, selected: number?, opts: SelectableListOpts?) -> any

Build a single-select listbox widget composed of focusable per-row canvases inside a panel. Same handler shape as Z.radioGroup; rows are highlight-only with no glyph.

typed/builtin//modules/zui/widget/sep/sep

sep(opts: SepOpts?) -> any

Build a horizontal-line separator widget.

typed/builtin//modules/zui/widget/sides/sides

sides(opts: SidesOpts?) -> any

Build a two-slot horizontal row anchoring the first child left and the second child right, with a flex-grow spacer between.

typed/builtin//modules/zui/widget/slider/slider

slider(id: string, value: number?, lo: number?, hi: number?, opts: SliderOpts?) -> any

Build a horizontal slider widget for a numeric value in [min, max].

typed/builtin//modules/zui/widget/spacer/spacer

spacer(n: number?) -> any

Build a fixed-size spacer widget.

typed/builtin//modules/zui/widget/split/split

split(children: { any }?, opts: SplitOpts?) -> any

Build a two-pane resizable split widget.

typed/builtin//modules/zui/widget/statRow/statRow

statRow(labelText: any, value: any, opts: StatRowOpts?) -> any

Build a label-value row — [label] [value] — with consistent label width and theme-aware defaults.

typed/builtin//modules/zui/widget/statusLabel/build

build(value: any, thresholds: StatusThresholds?, opts: StatusLabelOpts?) -> any

Build a status-coloured numeric label whose class is picked from threshold ranges.

typed/builtin//modules/zui/widget/tabs/build

build(items: { TabItem }?, activeKey: string?, onChange: string?, opts: TabsOpts?) -> any

Build a horizontal tab strip widget node. Each tab dispatches <onChange>-<key> on click and (under Z.app) arrow-key navigation cycles tabs in-place.

typed/builtin//modules/zui/widget/terminal/build

build(terminalId: number, opts: TerminalOpts?) -> any

Build a terminal widget node that renders a registry terminal's live grid inside the UI tree.

typed/builtin//modules/zui/widget/toggle/build

build(label: string?, id: string?, checked: boolean?, opts: ToggleOpts?) -> any

Build an iOS-style on/off switch as a canvas-based widget node.

typed/builtin//modules/zui/widget/topPanel/build

build(children: { any }?, opts: TopPanelOpts?) -> any

Build a top-docked panel widget node containing the given children. Must be the root widget of its registered screen.

typed/builtin//modules/zui/widget/tree/fromFlat/build

build(items: { any }?, opts: FromFlatOpts?) -> ({ TreeNode }, { [string]: TreeNode })

Convert a flat array of parent-pointer records into the recursive { key, label, children, ... } node table that Z.tree consumes.

typed/builtin//modules/zui/widget/vbox/build

build(children: ({ any } | VboxOpts)?, opts: VboxOpts?) -> any

Build a vertical layout container that stacks children top-to-bottom.

typed/builtin//modules/zui/widget/viewport/build

build(target: any?, opts: ViewportOpts?) -> any

Build a viewport widget node that embeds a render target inside the UI tree.

typed/builtin//modules/zui/widget/window/build

build(title: any, children: { any }?, opts: WindowOpts?) -> Node

Build a floating window widget node. Must be the root widget of its registered screen. Emits pos and movable at the widget root (not inside props) so the validator doesn't flag prop-shape-misplaced. Warns loudly when title is not a string so the older window(children, opts) calling shape is caught at the call site instead of producing a silent default header.

typed/builtin//modules/zui/widgetState/set

widgetState.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.

typed/builtin//systems/anim/AnimGraph/AnimGraph/bindSink

AnimGraph.bindSink(body: EntityRef)

Bind a pose sink targeting body's armature, stored on the graph so :tick(dt) applies the evaluated pose to it. The bone order is the graph's layout. Re-binding replaces any prior sink. Raises when the sink cannot be bound (the body has no Skeleton + Model when the sink is created).

typed/builtin//systems/anim/AnimGraph/AnimGraph/crossfadeTo

AnimGraph.crossfadeTo(toNode: any, duration: number, removeFromOnDone: boolean?)

Crossfade from the current output to toNode over duration seconds. Inserts a 2-input Mixer over the previous output and the new node and ramps weights from (1, 0) to (0, 1); on completion the output collapses to toNode. Falls back to an instant swap when there is no active output or duration <= 0 (the old output is freed unless removeFromOnDone is false).

typed/builtin//systems/anim/AnimGraph/AnimGraph/destroy

AnimGraph.destroy()

Free the whole graph: cascade-destroy() the output subtree, unbind the pose sink, and clear any active crossfade.

typed/builtin//systems/anim/AnimGraph/AnimGraph/evaluate

AnimGraph.evaluate() -> any?

Evaluate the output subtree and return its pose buffer. Returns nil when there is no output.

typed/builtin//systems/anim/AnimGraph/AnimGraph/layoutForEntity

AnimGraph.layoutForEntity(body: EntityRef, opts: { symmetrize: boolean? }?) -> Layout

Build the layout for a graph that drives a skinned body. Resolves the body's rig from its ecs.Skeleton and packs everything Clip nodes need to retarget clips onto it and apply poses relative to its canonical bind: boneOrder, the parsed targetRig, its stride-10 canonical restPose, and the bake-cache key. Raises when body has no rigged Skeleton — call it on a body you intend to animate, after its skeleton is hydrated.

typed/builtin//systems/anim/AnimGraph/AnimGraph/new

AnimGraph.new(layout: Layout) -> AnimGraph

Construct an empty AnimGraph with no output. :setOutput names the root node the graph drives; :bindSink binds the body the pose is applied to.

typed/builtin//systems/anim/AnimGraph/AnimGraph/play

AnimGraph.play()

Start the graph's per-frame update loop. Equivalent to :setPlaying(true).

typed/builtin//systems/anim/AnimGraph/AnimGraph/setOutput

AnimGraph.setOutput(node: any)

Name the node the graph drives. The node and the subtree it owns become the graph's output; :update / :evaluate / :destroy cascade from here. Replacing the output does NOT free the old one — detach or destroy it first if it is no longer used.

typed/builtin//systems/anim/AnimGraph/AnimGraph/setPlaying

AnimGraph.setPlaying(p: boolean)

Set the playing flag explicitly. true resumes per-frame updates; false freezes them.

typed/builtin//systems/anim/AnimGraph/AnimGraph/state

AnimGraph.state() -> { [string]: any }

Snapshot of graph state — handy for tools and debugging. Walks the output subtree; no internal references are leaked.

typed/builtin//systems/anim/AnimGraph/AnimGraph/stop

AnimGraph.stop()

Stop the graph's per-frame update loop. Equivalent to :setPlaying(false).

typed/builtin//systems/anim/AnimGraph/AnimGraph/tick

AnimGraph.tick(dt: number, sink: any?) -> any?

One-call per-frame driver. Advances the graph + crossfade by dt, evaluates the output, and (when a sink is bound or passed) hands the pose buffer to skeleton.applyPose. Returns the pose buffer so callers can read it directly (e.g. screenshot tests).

typed/builtin//systems/anim/AnimGraph/AnimGraph/update

AnimGraph.update(dt: number)

Advance the output subtree and the active crossfade by dt. No-op when the graph is not playing. When a crossfade reaches the end the output collapses to the target node and the crossfade mixer (plus, by default, the faded-out source) is freed.

typed/builtin//systems/anim/AnimGraph/Node/BlendSpace2D/BlendSpace2D/destroy

BlendSpace2D.destroy()

Destroy the internal Mixer — which cascade-destroy()s the sample sources it holds — then clear sample/triangle state. Destroying a BlendSpace2D frees the subtree below it, same as any composite node.

typed/builtin//systems/anim/AnimGraph/Node/BlendSpace2D/BlendSpace2D/evaluate

BlendSpace2D.evaluate() -> any

Find the triangle containing the current parameter, compute barycentric weights, push them into the internal Mixer, evaluate. Falls back to the nearest sample (weight 1) when the parameter lies outside the triangulated hull.

typed/builtin//systems/anim/AnimGraph/Node/BlendSpace2D/BlendSpace2D/new

BlendSpace2D.new(layout: Layout, samples: { Sample }) -> any

Construct a BlendSpace2D Node. Triangulates the sample anchors once at construction time and reuses an internal Mixer to do the per-frame barycentric weighted blend.

typed/builtin//systems/anim/AnimGraph/Node/BlendSpace2D/BlendSpace2D/setParams

BlendSpace2D.setParams(x: number, y: number)

Set the (x, y) parameter that drives the blend.

typed/builtin//systems/anim/AnimGraph/Node/BlendSpace2D/BlendSpace2D/update

BlendSpace2D.update(dt: number)

Cascade update(dt) to every sample source that defines it.

typed/builtin//systems/anim/AnimGraph/Node/Clip/Clip/destroy

Clip.destroy()

Free the bound clip sampler and the owned pose buffer.

typed/builtin//systems/anim/AnimGraph/Node/Clip/Clip/evaluate

Clip.evaluate() -> any

Sample the clip at the current playhead. With a body layout, returns a COMPLETE local pose: the body's bind, with every driven bone's rotation and translation overlaid — translation applied relative to the bind (rest plus the clip's displacement from its own start). Without a body layout, returns the raw sample.

typed/builtin//systems/anim/AnimGraph/Node/Clip/Clip/new

Clip.new(clipRef: any, layout: Layout, looping: boolean, speed: number?, sourceRig: any?) -> (any, string?)

Construct a Clip Node from a .animation asset reference. Reads the clip bytes, retargets them onto the layout's target rig (when the layout carries a body), binds the result to the bone order via skeleton.bindClip, and records which bones the clip drives so evaluate overlays only those on the bind pose. matched == 0 (the clip drives none of these bones) is logged so a silent rest pose never goes unexplained.

typed/builtin//systems/anim/AnimGraph/Node/Clip/Clip/rewind

Clip.rewind()

Rewind the playhead to 0, clear finished, and resume playback.

typed/builtin//systems/anim/AnimGraph/Node/Clip/Clip/setPlaying

Clip.setPlaying(p: boolean)

Pause or resume the playhead. Any value that is not the boolean true becomes playing = false.

typed/builtin//systems/anim/AnimGraph/Node/Clip/Clip/update

Clip.update(dt: number)

Advance the playhead by dt * speed. Wraps at duration when looping is true; otherwise clamps and marks the clip finished / playing = false. No-op when not playing or already finished.

typed/builtin//systems/anim/AnimGraph/Node/Layer/Layer/destroy

Layer.destroy()

Cascade-destroy() base + overlay, then free this Layer's output buffer. A Layer owns both inputs (the graph is a tree), so destroying it frees the subtree. An input detached (set to nil) is skipped.

typed/builtin//systems/anim/AnimGraph/Node/Layer/Layer/evaluate

Layer.evaluate() -> any

Evaluate base + overlay, then per-bone blend overlay onto base by mask[bone] * weight (translation lerp, rotation nlerp, scale lerp) into the output buffer. With weight 0 (or an all-zero mask) the base passes through.

typed/builtin//systems/anim/AnimGraph/Node/Layer/Layer/new

Layer.new(layout: Layout, base: any, overlay: any, mask: { number }) -> any

Construct a Layer Node that blends overlay over base per the per-bone mask scaled by the layer weight. Allocates an output pose buffer.

typed/builtin//systems/anim/AnimGraph/Node/Layer/Layer/setWeight

Layer.setWeight(w: number)

Set the layer's global weight (0 = base only, 1 = full overlay where the mask is 1). The owner ramps this to fade the action in and out.

typed/builtin//systems/anim/AnimGraph/Node/Layer/Layer/update

Layer.update(dt: number)

Cascade update(dt) to the base and overlay sources. The Layer is the graph output, so it owns advancing both subtrees.

typed/builtin//systems/anim/AnimGraph/Node/Mixer/Mixer/destroy

Mixer.destroy()

Cascade-destroy() every input source, then free this Mixer's own blend layout and output buffer. A Mixer owns its inputs (the graph is a tree), so destroying it frees the subtree below it. An input whose source was detached (set to nil — e.g. a crossfade survivor handed back to the graph) is skipped.

typed/builtin//systems/anim/AnimGraph/Node/Mixer/Mixer/evaluate

Mixer.evaluate() -> any

Evaluate inputs in turn, then weighted-blend their pose buffers into the output buffer. Inputs with weight <= 0 are skipped.

typed/builtin//systems/anim/AnimGraph/Node/Mixer/Mixer/new

Mixer.new(layout: Layout, inputs: { MixerInput }) -> any

Construct a Mixer Node. Allocates an output pose buffer sized for the layout and the engine-side blend layout.

typed/builtin//systems/anim/AnimGraph/Node/Mixer/Mixer/setWeight

Mixer.setWeight(i: number, w: number)

Set or update an input's weight at index i. Out-of-range index is a no-op.

typed/builtin//systems/anim/AnimGraph/Node/Mixer/Mixer/update

Mixer.update(dt: number)

Cascade update(dt) to every input source that defines it.

typed/builtin//systems/anim/AnimGraph/Node/Node/destroy

Node.destroy()

Default :destroy — no resources to free. Subclasses override to release owned Channel/Buffer/Layout handles.

typed/builtin//systems/anim/AnimGraph/Node/Node/evaluate

Node.evaluate() -> any?

Default :evaluate — returns nil. Subclasses override and return a Buffer handle (caller MUST NOT destroy).

typed/builtin//systems/anim/AnimGraph/Node/Node/new

Node.new() -> Node

Allocate a bare Node table (no Channels, no Buffer). Subclasses typically wrap setmetatable(Node.new(), <Subclass>) and then set the subclass-specific fields.

typed/builtin//systems/anim/AnimGraph/Node/Node/update

Node.update(dt: number)

Default :update — no internal state to advance. Subclasses override to step playhead, ramp weights, etc.

typed/builtin//systems/anim/AnimGraph/rigResolve/R/parseBodyRig

R.parseBodyRig(body: EntityRef) -> any?

The parsed rig of a skinned body, read straight from the ECS — its ecs.Skeleton bones (rest pose + hierarchy) plus its ecs.RetargetProfile roles when present. Everything the graph needs is already in the ECS by this point; no asset is resolved and no document is parsed. A body whose Skeleton carries no bones returns nil. A body with no RetargetProfile is a non-humanoid rig — the returned rig simply has an empty role map, so the graph binds its own clips directly instead of retargeting.

typed/builtin//systems/anim/AnimGraph/rigResolve/R/parseFromClip

R.parseFromClip(ref: any, rigOverride: any?) -> any?

The parsed source rig a clip was authored on. ref is a .animation ref; pass rigOverride (a .rig ref) to force a specific source rig.

typed/builtin//systems/anim/AnimGraph/rigResolve/R/refId

R.refId(v: any) -> string?

The asset identity / guid behind a ref value (an AssetRef or a string).

typed/builtin//systems/anim/AnimGraph/rigResolve/R/restPose

R.restPose(parsedRig: any) -> { number }

The stride-10 bind pose (translation.xyz + rotation.xyzw + scale.xyz per bone, in rig order) the graph poses relative to. Undriven channels hold this; a clip overlays only the channels it drives.

typed/builtin//systems/characterController/characterController/physics/ceiling/M/cast

M.cast(x: number, y: number, z: number, height: number, skinWidth: number, selfId: string) -> any

Cast a short ceiling-detection ray upward from the character's head. The ray starts at (x, y + height - skinWidth, z) and travels up for skinWidth * 2.

typed/builtin//systems/characterController/characterController/physics/ground/M/cast

M.cast(x: number, y: number, z: number, skinWidth: number, maxDist: number, selfId: string) -> any

Cast a ground-detection ray downward from a position. Origin is raised by skinWidth so the ray starts above the feet, and the returned hit.distance is adjusted back to be relative to the feet (not the ray origin).

typed/builtin//systems/characterController/characterController/physics/ground/M/projectOnSlope

M.projectOnSlope(moveX: number, moveY: number, moveZ: number, normalX: number, normalY: number, normalZ: number) -> (number, number, number)

Project a movement vector onto the slope plane defined by a surface normal. Computes v - (v . n) * n — the component of v that lies in the plane orthogonal to n.

typed/builtin//systems/characterController/characterController/physics/ground/M/slopeAngle

M.slopeAngle(nx: number, ny: number, nz: number) -> number

Compute the slope angle (degrees) between a ground normal and world up. Returns 0 when the input is the zero vector.

typed/builtin//systems/characterController/characterController/physics/walls/M/castDirection

M.castDirection(x: number, y: number, z: number, dirX: number, dirZ: number, radius: number, skinWidth: number, selfId: string) -> any

Cast a horizontal wall-detection ray from (x, y, z) in direction (dirX, 0, dirZ). Ray length is radius + skinWidth.

typed/builtin//systems/characterController/characterController/physics/walls/M/castMultiHeight

M.castMultiHeight(x: number, y: number, z: number, dirX: number, dirZ: number, height: number, radius: number, skinWidth: number, selfId: string) -> any

Cast wall-detection rays at three heights (ankle, waist, shoulder) to handle uneven surfaces. Returns the closest hit across all three rays.

typed/builtin//systems/characterController/characterController/physics/walls/M/slideAlongWall

M.slideAlongWall(moveX: number, moveZ: number, normalX: number, normalZ: number) -> (number, number)

Compute a wall-slide direction given the desired horizontal movement and a wall normal. Strips the component of move that goes into the wall; returns the input unchanged when the movement isn't pressing into the wall (dot >= 0) or the normal is effectively zero in the XZ plane.

typed/builtin//tools/sc/shared/M/replaceWithAsset

M.replaceWithAsset(target: string, source: AssetRef<bundle|mesh>, opts: { [string]: any }?) -> string

typed/builtin//tools/sc/shared/M/spawnModel

M.spawnModel(name: string, source: AssetRef<bundle|mesh>) -> string
  • api
  • reference