Gessa Docs
Recipes

Recipe

Asset to instances model prefab instance authoring chain

This is the whole path from one base asset to placed content: get a renderable asset, wrap it in a reusable prefab, and instance it once or thousands of times. Read model-authoring-parametric-csg first if you are building the shape itself; read asset-acquisition-strategy first if the catalog might already have it.
engine v1.0.234since action-catalog.v1.0.232, model-authoring, instance-set.v1, rendering.v1Copy for LLM

Use this for

turning one base asset into placed content; building a reusable prefab and dropping instances of it; scattering many copies of one box, sphere or plane across a scene (mesh and cylinder instance kinds render as boxes today); the full model to prefab to instance chain; placing a generated or catalog asset many times

Not for

authoring raw vertex or voxel geometry (see capability-ceiling); baking a parametric model into renderable mesh on the agent surface (no server bake action exists, see the seam note below); bulk fan-out of a multi-entity prefab in one call (no such verb on the authoring surface)

Pairs with: Model authoring parametric primitives and CSG for custom meshes, Asset acquisition strategy, Materials and looks PBR surfaces color metalness and textures, Terrain and heightmaps procedural generation biomes and foliage

Step 0: get an asset that actually renders

An entity renders a mesh through a RenderableComponent with shape: "mesh" and an assetId that points at a model asset. The renderer streams that asset's mesh variant, so the model asset must CARRY a mesh variant. Three ways to get one:

  1. Generate it. generation_create_job (generation.job.create) with a model capability and target.importOnSuccess: true runs the provider and, on success, finalizes a project asset that already carries the mesh variant. This is the reliable agent path to a fresh custom object. Model, image, texture, and audio are the wired modalities; image-to-model capabilities turn a generated image into a mesh.
  2. Reuse the catalog. A published catalog model already carries its variant, conditioning, and colliders. Prefer this when a close match exists (see asset-acquisition-strategy).
  3. Author it parametrically. model_save (project.asset.model_document.save) writes a ModelAuthoringDocument of primitives plus CSG onto the model asset's rendering.model slice. IMPORTANT SEAM: model_save writes only that authored slice and leaves the mesh variant untouched, and there is no agent-callable server action that bakes the parametric document into a mesh variant. So a model whose only content is a model_save document does not render on its own yet; it is a durable authoring artifact awaiting a bake. For a shape that must render now from the agent surface alone, generate or reuse instead, or use a primitive shape (box, sphere, capsule, ...) directly on the RenderableComponent with no mesh asset at all (a cylinder or cone is not a RenderableComponent shape; it exists only inside a model).

Step 1: reference the asset from an entity

project_add_component a RenderableComponent: { "type": "RenderableComponent", "shape": "mesh", "assetId": "<model asset id>", "visible": true }. Set a materialRef to skin it (see materials-and-looks). For a plain primitive, use shape: "box" (or another primitive) and omit assetId.

Step 2: compose a reusable prefab

A prefab is a named, reusable entity subtree. Author it directly with project_create_prefab (project.prefab.create): the request carries the full entities array inline (at least one, a rootLocalId, each entity a localId/name/components record). Put the RenderableComponent (and a TransformComponent, scripts, colliders) on the root entity so every instance inherits them. You do not need live scene entities to make a prefab; the inline entities array IS the prefab body. project_update_prefab and project_delete_prefab round it out.

Step 3a: instance the prefab once

project_create_entity (project.entity.create) with prefabId set (a uuid or the prefab key) creates one prefab-instance entity in a world. Its effective components resolve from the prefab, with per-instance componentOverrides layered on top. This is the single-instance path. Note: it places the prefab root as one instance entity; it does not expand a multi-entity prefab subtree into separate graph entities, and there is no one-call bulk prefab fan-out on the authoring surface. For many prefab instances, issue several project_create_entity calls. The instanceSet path below does not draw meshes today (see its note).

Step 3b: instance one primitive many times (the scale path)

RENDER TRUTH TODAY: the aggregate renderer draws a palette kind with geometry box, sphere or plane as that primitive, and draws every cylinder and every mesh kind (whatever its meshAssetId) as a unit box. So an InstanceSet does NOT place copies of a model yet. For repeated models (trees, rocks, props), place model entities within the entity budget instead (the renderer batches identical meshes where eligible); for grass and ground cover on terrain, use a terrain scatter (see terrain-and-heightmaps). Use the InstanceSet aggregate for many copies of a box, sphere or plane (a voxel field, crates, markers) instead of thousands of entities:

  1. Create the resource: project_create_asset (project.asset.create) with assetKind: "instanceSet".
  2. project_apply_instance_set_patch (instance_set.patch.apply) with a configure op: layout: "free" (scattered transforms) or layout: "grid" (dense voxels), and a palette of kinds with geometry box, sphere or plane (plus optional materialAssetId, tint). The schema also accepts cylinder, and mesh with a meshAssetId, but both render as boxes today.
  3. Fill it in the same tool with populate (explicit instances for free, or cells for grid), scatterInstances (seeded scatter of N over a region), or fill (a grid box region). One call carries the whole batch; you do not author one entity per instance.
  4. Place the aggregate: put an InstanceSetComponent { "type": "InstanceSetComponent", "instanceSetAssetId": "<the instanceSet asset id>", "enabled": true } plus a TransformComponent on an entity. The renderer lowers the whole set to instanced draws per kind and physics to one aggregate collider, so the scene stays inside the per-entity complexity budget that thousands of real entities would blow.

When mesh kinds do render, the meshAssetId in the palette will obey the same rule as Step 0: a variant-bearing asset (generated or catalog), not a bare model_save document.

Pitfalls

  • A model_save-only model has no mesh variant; wiring its id into a RenderableComponent renders nothing. Generate or reuse for a mesh that must show now.
  • An instanceSet palette kind with geometry mesh or cylinder renders as a box today, whatever its meshAssetId; do not promise a forest or a rock field from it.
  • RenderableComponent.shape must be mesh when you pass an assetId; leaving a primitive shape ignores the mesh.
  • project_create_prefab needs at least one entity and a rootLocalId that names a real localId in the entities array.
  • Free layout uses instances (transforms); grid layout uses cells (integer coordinates). Mixing them per op is silently one or the other; match the layout you configured.
  • Bulk placement of a full behaving prefab (subtree plus scripts) is not one call; the instanceSet path multiplies primitive GEOMETRY, not prefab behavior.

Verify

  • project_get_graph_snapshot to confirm the model asset, the prefab, the instance entity's prefabId, or the entity's InstanceSetComponent (instanceSetAssetId, layout).
  • qa_capture_renderer_viewport to confirm the instances actually render (this is where a missing mesh variant shows up as an empty capture).
Was this helpful?Report an issueContact support

On this page