asset
The asset namespace — the engine's Luau API reference for asset.
The asset namespace — 33 functions.
asset/create
asset.create(typeName: string, name: string, opts: table?) -> table
[Library] Instance a new asset of an existing registered type: runs that type's onCreate(name, opts) behavior hook (or clones its template/ skeleton when it has none) and writes the produced files to the mode-aware destination (/zero/source/<name>.<type>/ in edit, the copy-on-write /zero/runtime/assets/<type>/<name>/ store in play). Returns the instance descriptor { typeName, name, dest, mode, files }; raises on bad arguments or a failing onCreate.
globals/asset/add_tag
globals/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.
globals/asset/categories
globals/asset/categories() -> { string }
List every asset category the engine currently recognises.
Use to discover valid type argument values for the rest of
asset.*.
globals/asset/containerize
globals/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.
globals/asset/containing
globals/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.
globals/asset/create
globals/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.
globals/asset/deps
globals/asset/deps(ref: RefArg, type: string?) -> DepsResult
Return the asset's outbound dependency graph — every other asset recorded as a content dependency of it.
globals/asset/describe
globals/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.
globals/asset/exists
globals/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).
globals/asset/get_field
globals/asset/get_field(ref: RefArg, key: string) -> any
Read one top-level field from the asset's .metadata.
globals/asset/guid
globals/asset/guid(ref: RefArg, type: string?) -> string
Return the guid for an asset.
globals/asset/has_field
globals/asset/has_field(ref: RefArg, key: string) -> boolean
True when the asset's .metadata carries the named field.
globals/asset/has_tag
globals/asset/has_tag(ref: RefArg, tag: string) -> boolean
True when the asset's .metadata.tags contains tag.
globals/asset/identity
globals/asset/identity(ref: RefArg, type: string?) -> string
Return the canonical identity for an asset.
globals/asset/import
globals/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.
globals/asset/inspect
globals/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.
globals/asset/list
globals/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.
globals/asset/list_field_values
globals/asset/list_field_values(key: string) -> { any }
Distinct values seen for the named field across every
asset's .metadata.
globals/asset/list_fields
globals/asset/list_fields() -> { string }
Distinct top-level field keys observed across every asset's
.metadata. Useful for tooling discovering custom keys in use.
globals/asset/meta
globals/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.
globals/asset/metadata
globals/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).
globals/asset/preview
globals/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").
globals/asset/ref
globals/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).
globals/asset/remove_field
globals/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.
globals/asset/remove_tag
globals/asset/remove_tag(ref: RefArg, tag: string)
Remove a tag from the asset's .metadata.tags. No-op when
the tag isn't present.
globals/asset/resolve
globals/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.
globals/asset/set_field
globals/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.
globals/asset/set_metadata
globals/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.
globals/asset/source
globals/asset/source(ref: RefArg, type: string?) -> string
Return the VFS source path for an asset.
globals/asset/tags
globals/asset/tags(ref: RefArg) -> { string }
Convenience read of the .metadata.tags array.
globals/asset/typeRef
globals/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.
globals/asset/validate
globals/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.
globals/asset/warmup
globals/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).