---
title: "Asset acquisition strategy"
description: "When a build needs a mesh, material, texture, audio clip, or other content asset, acquire it in this order and fall through only when the earlier tier genuinely lacks a fit:"
engineVersion: v1.0.234
date: 2026-09-28
license: "(c) Gessa, proprietary. Cite with attribution to https://gessa.ai/docs/. Terms: https://gessa.ai/terms/."
canonical: https://gessa.ai/docs/knowledge/playbooks/asset-acquisition-strategy/
---

# Asset acquisition strategy

When a build needs a mesh, material, texture, audio clip, or other content
asset, acquire it in this order and fall through only when the earlier tier
genuinely lacks a fit:

1. **Catalog first.** Search the asset library for published, conditioned
   content that matches the need. Catalog assets load instantly, carry
   preview/collision/LOD conditioning, and cost nothing to reuse. A close
   thematic match that needs a material tint or scale change still beats a
   fresh generation.
2. **Smart asset packages second.** When the need is a coherent set (a themed
   room, a vehicle with wheels and colliders, a furniture family), apply a
   canonical smart asset package rather than assembling pieces one by one.
   Packages apply atomically through the backend service, are idempotent to
   replay, and stay repairable.
3. **Generation last.** Mint a new asset only when the catalog and packages
   genuinely lack the concept. Generation spends the player's credits, takes
   wall-clock time, and produces unconditioned output that may need further
   passes. When generating, be specific about style, scale, and intended
   placement so one generation suffices.

## Generation is async and best-effort, so never bet a prop on it

Model and audio generation are GPU worker-pool jobs
(`generation_create_job` -> a job that a worker must claim and run; see the
`asset.model.*` and `asset.audio.*` capabilities, `backendKind: "worker_pool"`).
That corridor can be COLD: if the pool has no worker when the job runs, the job
retries its small attempt budget and then terminates failed ("Generating asset
failed"). Treat a generation job as a request that MAY not land, not a promise
that will:

1. **Quote or read the dispatch result.** `generation_quote_job` and the
   `generation_create_job` result carry `dispatch.budgetBlocked` and
   `dispatch.capacityBlocked`. A blocked dispatch means the job will not run;
   do not sit polling a job that was refused at creation.
2. **Poll for terminal status, do not assume success.** After creating a job,
   read `generation_get_job` until it reaches a terminal state. A `failed`
   status is a real outcome to handle, not a transient to retry forever.
3. **Have an in-envelope fallback ready BEFORE you generate.** When a model job
   fails or the pool is cold, the always-available routes still ship the build:
   take a fitting mesh from the CATALOG, COMPOSE the prop from primitive parts
   as one prefab subtree (see composed-props-from-primitives), or import a
   `gltf`/`glb`/`obj`. Image and texture generation via the external synchronous
   provider (`backendKind: "external_sync"`) does not depend on the GPU pool and
   is the more reliable generation lane when you only need a texture.

Do NOT leave a textureless `billboard` RenderableComponent as the "prop" when a
mesh generation fails: a billboard with no material renders as a grey quad, not
a tree. Fall back to composition or the catalog instead (the create tool teaches
this at the boundary).

Signals that the earlier tier was skipped too eagerly: multiple generations of
near-identical primitives, generating an asset whose name closely matches a
catalog entry, or minting single-use variants of a package the project already
applied.

This is advisory strategy, not policy: the kernel never enforces an
acquisition order, and a run with explicit user direction ("generate me a
fresh one") follows the user.
