---
title: "Capability ceiling what the agent cannot author and the in-envelope fallback"
description: "Read this before promising anything that sounds like arbitrary-code rendering (voxels, custom shaders, hand-built meshes, rigged animation). The typed surface takes the agent FARTHER than raw code for game systems (netcode, physics, persistence, mobs, UI, audio) but LESS far for a few raw content primitives. Those few are listed here with the substitute that IS expressible. Each is a redirect, not"
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/capability-ceiling/
---

# Capability ceiling what the agent cannot author and the in-envelope fallback

## When to use

Read this before promising anything that sounds like arbitrary-code rendering
(voxels, custom shaders, hand-built meshes, rigged animation). The typed surface
takes the agent FARTHER than raw code for game systems (netcode, physics,
persistence, mobs, UI, audio) but LESS far for a few raw content primitives.
Those few are listed here with the substitute that IS expressible. Each is a
redirect, not a dead end: design to the fallback and the request ships.

## The five ceilings and what to use instead

1. Per-voxel / blocky mineable terrain at scale is not authorable.
   Use instead: procedural HEIGHTFIELD terrain (`terrain.patch.apply` generate,
   biome, erosion, scatter, then `terrain.artifacts.build`; see
   terrain-and-heightmaps). For a truly blocky world the only path is
   instantiating the `voxel_frontier` template WHOLE at project creation
   (`project_create_game` creationIntent `{ mode:"template",
   templateId:"voxel_frontier" }`); it cannot be edited as typed capabilities
   afterward and per-block entities breach the 1000-entity/collider runtime cap
   (`runtimePolicies` maxEntitiesPerTick). Do not attempt per-block set/place ops
   or spawn thousands of block entities; both fail-closed or stall physics.

2. Raw vertex/index buffers and marching-cubes meshes are not authorable.
   Use instead: parametric primitives plus CSG booleans through `model_save`
   (box/sphere/cylinder/capsule/cone/torus/plane, union/subtract/intersect; see
   model-authoring-parametric-csg), OR import a `gltf`/`glb`/`obj` asset
   (`primitiveType: "imported"`), OR take a fitting mesh from the catalog. There
   is no vertex-array field anywhere; `RenderableComponent.shape` is a fixed enum
   (`box`, `sphere`, `disc`, `capsule`, `billboard`, `mesh`, `plane`).

3. Custom shader code (WGSL/GLSL) is rejected by design.
   Use instead: the twelve ai_safe PBR ops (base color, metallic, roughness,
   emissive, alpha, double-sided, texture slots; see materials-and-looks). Any
   key like `shaderSource`, `wgsl`, `glsl`, `rawShader`, `fragmentShader`,
   `vertexShader` triggers `raw_shader_source_forbidden`. Never emit shader
   strings.

4. Procedural material networks beyond the small node catalog are not
   expressible. The graph ops themselves (`addCatalogNode`, `connectSockets`,
   `disconnectEdge`, `setNodeParameter` and friends) ARE ai_safe, the same
   alphabet the visual editor gets (authoring symmetry); only `replaceGraph`
   stays import-only, and `trustedOnly` nodes (`trusted.shader.plugin`) are
   rejected for every normal source. The ceiling is the CATALOG: an OpenPBR
   surface, output, color and float constants, texture sample, water depth,
   scalar math, color mix, and procedural noise. A look those nodes cannot
   express (custom lighting response, stylized ramps) is out of reach; for most
   looks the twelve PBR ops stay the shorter path (see materials-and-looks).

5. Skeletal animation authoring beyond clip playback is not expressible.
   Use instead: `AnimationStateComponent` to PLAY a named clip off a rigged
   imported model (`clipKey`, `playMode` loop/once/ping-pong, `speed`,
   `startTime`), plus transform animation authored as a `TimerComponent` firing a
   handler that patches a `TransformComponent` (bob, spin, scale). You cannot
   author or blend new skeletal clips; a walk cycle needs an imported rigged
   asset that already carries the clip.

## Related runtime ceilings

- Runtime block place/mine works only at SMALL N: `ctx.world.spawn`/`despawn` of
  entities under the 1000-entity/collider cap. A dozen placeable blocks is fine;
  a mineable voxel field is not.
- Instanced rendering is not a direct AI authoring primitive EXCEPT terrain
  `scatter` foliage, which bakes a `foliage_instance_buffer` the renderer
  instances. Scatter renders real geometry ONLY for the `grass`/`tall_grass`
  (blade tufts) and `rock`/`boulder` (deformed stone) keys; every other
  foliageKey, tree and flower keys included, renders as a small placeholder
  cone today (the `terrainDetailGeometry` fallback), and there is no
  mesh-backed scatter. Use scatter for grass and rock ground cover; a tree
  line is a modest number of placed model entities under the entity/collider
  cap, and do not spawn thousands of entities to fake instancing.
- Water is planar only (`WaterComponent`); there is no volumetric fluid or lava
  component. Approximate lava with a recolored water surface plus an emissive PBR
  material and a damage script.

## How to respond when a request exceeds the ceiling

Name the limit in one sentence, propose the in-envelope design, and build that.
Do not loop retrying a rejected op, and do not invent a tool name (there is no
`set_voxel`, no `create_shader`, no `author_animation`). A first-person survival
world with procedural terrain, mobs, inventory, health, day-night,
server-authoritative multiplayer, persistence, sound, and particles is fully
expressible; lead with that.

## Verify

- If unsure whether a capability exists, `engine_list_component_types` and
  `engine_get_component_schema` show the real component surface, and the action
  catalog shows the real tools. Absence there is the ceiling; trust it.
