dynamicAsset (asset type)
A prompt-driven, self-regenerating 3D asset. A <name>.dynamicAsset/ folder holds a text prompt.json; the asset's model is generated from that prompt by the @builtin::services.meshy text-to-3D…
This type is the reference example for the asset-type onChange
change-callback (the type-level analogue of a component's
onAssetReload). Read its behavior.luau to see the pattern end to end.
Folder shape
<name>.dynamicAsset/
├── prompt.json { "prompt": "a mossy stone golem" }
├── .metadata generation status + start date + last prompt
├── README.md
├── model/ (after first generation)
│ ├── model.glb the current generated mesh
│ └── model.json manifest (prompt, date, service handle)
└── versions/ (after the prompt changes at least once)
├── v1/
│ ├── model/model.glb
│ ├── prompt.json the prompt that produced this version
│ └── meta.json
└── v2/ …
Lifecycle
- Generate —
ref:generate("a mossy stone golem")writes the prompt, sets.metadata.generationStatus = "inflight"+generationStartedAt, and launches Meshy. The GLB is written straight intomodel/. - Status —
ref:status()reads the state from.metadata:status(empty/inflight/succeeded/failed),stage(live Meshy stage),prompt,startedAt,finishedAt,error,handle. Use it to find finished / failed / in-flight assets at a glance. - Edit the prompt → regenerate — writing
prompt.json(by hand,vfs.write,ref:setPrompt(...), or a pull) firesonChange. If the prompt actually changed, the currentmodel/is archived intoversions/v<N>/(incrementing) and a fresh generation starts.
Methods (AssetRef<dynamicAsset>)
| Method | What it does |
|---|---|
:generate(prompt?) | Generate/regenerate now (async). Returns the status table. |
:status() | Read generation status from .metadata. |
:getPrompt() / :setPrompt(text) | Read / set prompt.json (set triggers regeneration). |
:modelPath() | VFS path of the current GLB, or nil. |
:versions() | Archived version indices (oldest first). |
:spawn(name?, x?, y?, z?) | Spawn the current model into the scene. |
Setup
The Meshy service reads its key from the MESHY_API_KEY environment
variable (set before launching the engine). Without it, generation fails
with a clear message and :status().status == "failed". Get a key at
https://www.meshy.ai/api.
Usage
asset.create("dynamicAsset", "Golem")
local golem = asset.resolve("Golem", "dynamicAsset")
golem:generate("a mossy stone golem, low-poly")
-- … wait …
print(golem:status().status) -- "succeeded"
golem:spawn("golem", 0, 0, 0)
-- Change the prompt → archives v1, regenerates:
golem:setPrompt("a bronze golem, ornate")
print(golem:versions()) -- { 1 }
Notes
- Generation is async and can take minutes.
onChangereturns immediately; the model appears when:status().statusflips to"succeeded". onChangeis convergent: it only acts when the prompt differs from the last generated prompt and queues edits made mid-generation (pendingPrompt), so it never loops on its own writes.