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.
typed/builtin//modules/api/engine/lsp/lsp/search
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
retrotool 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 Errored → Pending).
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.
typed/builtin//modules/tools/M/search
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
nameis the tool's<toolbox>.<tool>identity; invoke it with theuse_toolMCP tool (toolbox+tool+ positionalargs), the form each entry'sexamplesare 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:
- clear chord per-tick fire flags, Gestures per-tick deltas, Surface per-frame device-class flags, Virtual button edges + drag deltas
- 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.
- advance Axes smoothing, Chords window aging, Rebind timeouts, Gestures time-based recognition (long-press) + pinch/pan deltas
- drain
__zero_input.events()once (first tick of the frame only) - feed each event into State (held-time), Chords (state machines), Input (lastInputType tracking — Phase 9), Gestures (contact tracks + discrete recognition), Surface (device-class flags)
- 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)
- dispatch action handlers (Zin.actions.bind / onPressed / onReleased / onChanged / onHeld — Phase 9)
- 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 returningdxaxis = "y"→ scalar binding returningdyValues are not normalised to[-1, 1]— mouse delta is a physical pixel count. UseZin.axes.definewithsmoothing/deadzoneto 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 deltaaxis = "x"→ scalar binding returning0(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 syntheticemit:KeyFaction carrying both the kbm key binding and the touchButton, so the emulation floor drivesKeyFstraight from this button through the same binding/emulation path every other control uses.label/zone/iconset the button's presentation (seeZin.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.keyis 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, dndListfrom,topayload, ...) without unwrappingdatamanually. - callbackId: the original id, useful for shared handlers.
- captures: the pattern's
string.matchcaptures, expanded positionally soapp: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 round → tostring.
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 = falseto 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