| name | scena-app-builder |
| description | Use when an LLM needs to build, verify, debug, or iterate on a scena application, scene recipe, viewer, CAD inspection workflow, digital twin, product configurator, dashboard, documentation renderer, or agent verification loop using public scena CLI/schema/docs instead of repo internals. |
Scena App Builder
Core Rule
Build through public surfaces first: schema discovery, scene recipes, CLI
validation, render introspection, verification, diagnostics, and repair. Do not
read src/ or guess private Rust APIs unless the user explicitly asks for
library development or a Rust-only integration.
The success condition is machine-verifiable output, not a PNG that merely
exists. A render is complete only after the appropriate introspection or
verification report says it is complete.
Start Here
- Use a binary built with the agent-facing features.
For an installed CLI:
cargo install scena --features agent
From a local checkout:
cargo run --bin scena --features agent -- <command>
agent enables the complete app-builder surface through scene-host, which
already enables inspection. Defaults stay empty.
Before selecting a backend or feature-gated workflow, inspect the compiled
feature set and distinguish static planning data from current hardware:
scena --version
scena capabilities --json
scena capabilities --live --json
Only probe.status:"measured" is live hardware evidence. Treat
static_no_device as a compiled contract and stop on a nonzero structured
unavailable report. The live command is headless: it measures readback but
does not prove window or browser presentation.
- Discover the current contract:
scena schema get scena.scene_recipe.v1
If scena is not installed but you are inside the repository, use:
cargo run --bin scena --features agent -- schema get scena.scene_recipe.v1
- Start from a template when possible. Read the machine catalog rather than
guessing names or scraping an error:
scena examples agent list
Use its kebab-case canonical names. Historical underscore inputs are aliases
whose manifests include a migration note. product_configurator maps to the
authored product-configurator-starter; product-configurator is the imported
material-variant workflow.
scena examples agent get primitive-scene --out target/scena-agent/primitive-scene > target/scena-agent/primitive-scene.manifest.json
The command prints an scena.agent_smoke_template.v1 manifest to stdout and
writes the actual recipe, expectations, and artifacts under --out. Read the
manifest files[], required_features[], and commands[]; do not validate
the manifest as if it were the recipe. Set RECIPE to the recipe file named in
the manifest files[]; for the command above:
RECIPE=target/scena-agent/primitive_scene/recipe.json
Installed templates are portable from any working directory. Their imported
fixtures and licensed studio HDR are package-embedded, and template defaults do
not overwrite an explicitly authored scene.environment.
For an operator-owned external model library, choose the narrowest existing
directory and repeat it on every recipe-aware command:
scena policy recipe --allow-root /srv/models
scena validate-recipe "$RECIPE" --full --allow-root /srv/models
scena recipe render "$RECIPE" --introspect --out frame.png --allow-root /srv/models
Do not invent an unsandboxed mode. Inspect the returned policy.allowed_roots
and stop if the canonical operator root is absent or a resource is still denied.
- Validate before rendering:
scena validate-recipe "$RECIPE" --full
- Render with introspection, not just capture:
scena recipe render "$RECIPE" --introspect --out frame.png
This emits scena.render_introspection.v1. Add --verify when the recipe has
an expect block and you need the combined recipe build/capture/introspection/
verification result.
Asset-or-recipe verbs dispatch parsed recipes through the complete
policy-aware SceneHost build. If any import is rejected, stop on the nonzero
scena.recipe_build_result.v1; never retry only imports[0] as a raw asset.
For beauty renders, add --gpu; CPU remains the default, and the report
capabilities.backend / gpu_device fields say which backend actually ran.
- Make the output presentable when the user will look at it.
Use the ergonomic recipe fields first unless the task is intentionally flat,
technical, or unlit. These fields route to the same Rust helpers a Rust user
would call, so they are safer than hand-tuned low-level values:
"materials": [
{ "id": "body", "preset": "chrome", "roughness": 0.06 }
],
"lights": [
{ "id": "studio", "kind": "studio_rig", "preset": "studio_rig" }
],
"cameras": [
{
"id": "camera",
"kind": "perspective",
"lens": "portrait",
"framing": { "preset": "three_quarter_front_right",
Use product_studio for product/model screenshots, cad_studio for technical
CAD/documentation scenes, and industrial_studio for dashboard or live-state
views. Add explicit scene.background, scene.environment, or scene.grid
only when you need to override the preset.
Prefer material.preset (chrome, metal, rough_metal,
brushed_steel, plastic, clearcoat_plastic, satin, leather,
rubber, matte, clear_glass, frosted_glass) before raw PBR fields.
Use base_color as an optional preset tint, then add scalar overrides such as
roughness only when needed. Prefer named color constants such as orange,
gray, light_gray, dark_gray, charcoal, studio_backdrop,
warm_white, and cool_white instead of ad hoc hex values when one matches.
Prefer camera.lens and camera.framing over manual camera distances.
scene.environment:{ "preset":"studio" } or "neutral_studio" uses the
bundled HDRI presets through the same asset policy as other recipe assets.
Use "studio" (the real Poly Haven studio HDR) when a low-roughness
material.preset:"chrome" subject must read as product chrome; chrome is
mirror-like, so the environment must provide structured softbox reflections and
the subject sphere must be densely tessellated (segments>=256, rings>=192).
scene.grid.under_bounds defaults to true; leave it on for auto-sized floors.
Use studio or neutral_gray for product/model inspection, dark_studio for
dashboards and status views, white/transparent for documentation exports,
and custom only when the user gives a color. The default environment is flat;
the packaged studio preset gives reflections and better material response
without requiring a repository-relative HDR path. Import real
glTF/GLB assets for realistic products or twins; primitives are best for
functional scenes, CAD plates, diagrams, charts, and tests. For visible
primitive boxes or cylinders in product-style scenes, add a small bevel or
fillet value so edges catch light; unsupported primitive kinds reject those
fields instead of ignoring them. For large scenes with repeated distant parts,
author explicit high/low geometry resources and add node lods[] thresholds so
small-on-screen parts render with cheaper geometry; scena switches among those
declared resources and does not invent simplifications.
Use quality:"high" / anti_aliasing:"msaa4" for smooth geometry edges.
For product-style floor reflections, enable scene.grid.reflection; it is a
verified structured floor-reflection preset that does not require material SSR.
If it matters, add expect_quality.reflection and treat
reflection_structure_missing as a real render-quality failure.
For hero chrome product stills, prefer
scene.environment:{ "preset":"studio" } with a high-tessellation sphere (segments>=256, rings>=192) before tuning the material.
Do not expect a chrome material to look silver in an empty or smooth dark
environment. Add expect_quality.reflection.target with
min_bright_fraction and min_dark_fraction so flat-black or flat-gray chrome
fails with reflection_chrome_read_missing.
For hero product/studio reflections that must mirror neighboring scene
geometry, add
render.screen_space_reflections:{strength,roughness,horizon_fraction,fade}.
It mirrors rendered scene content in screen space for the floor band and
high-metallic/low-roughness materials such as chrome. Screen-edge and occluded
material samples fade back to the environment-lit material. Use bare
expect_quality.reflection for floor/reflection-surface checks, or add
expect_quality.reflection.target:{kind:"node",id:"..."} when a specific
chrome/mirror subject is load-bearing.
For portable recipe-authored glass, use scalar material fields only:
transmission_factor, , , , and
. Do not use or ;
recipes reject them until the GPU/WebGL2 texture-binding budget supports those
roles. If glass output is load-bearing, render with , add
, and inspect the native-resolution image.
Use only for hero captures or fine glossy/texture
details; it renders at N× resolution and downsamples, so cost grows with N^2.
Do not put large captures plus into the default iteration loop:
on CPU or lavapipe this can take minutes. First prove the recipe at
; use or higher only for final GPU-device hero
renders after the composition is already accepted.
For visible floor grids, set around - and
use on hero stills so grid lines have enough
native-resolution coverage without softening the whole image like .
Add when grid-line quality is
load-bearing; then emits
for a sufficiently reconstructed grid or fails with .
For softer studio highlights or a partial penumbra, add an area softbox light:
. This is a
finite-emitter softbox with LTC-style specular evaluation and deterministic
soft-shadow visibility on CPU and HeadlessGpu. Use , ,
or for the intended emitter shape. When the soft shadow matters, add
targeting the receiver so
must emit and will fail point-like emitters
with .
For hero shots where the subject should pop from the background, add
. Use a
small and a textured or structured background, then add
with a focal and optional
; compares against a same-backend
no-DoF baseline and emits or actionable failures such
as and .
ok:true proves the requested content rendered and passed checks. It does not
mean the image is aesthetically good. Inspect the rendered image when visual
quality matters.
For A/B comparison cards and contact sheets, keep the comparison controlled.
Do not use scene.preset or auto-framing if each panel must share the same
view; those helpers are for single hero frames and may reposition panels.
Use one fixed camera/look-at, fixed capture size, fixed environment/background,
and vary exactly one field per panel (camera.lens, light preset,
environment.preset, render.auto_exposure, or material preset). An
auto-exposure comparison needs genuinely different scene luminance per panel;
four presets on the same metal ball under one IBL can converge visually even
though all presets are working.
Before accepting any user-facing render, do a native-resolution composition
review in explicit "what is wrong?" mode. Check the full frame, not only crops:
declared objects visible and correctly placed, no stale/extra content, labels
readable and attached, no helper lines over solid objects, objects grounded when
intended, materials/lights not black-crushed or blown out, and camera framing
appropriate for the app. If you find a problem, add the matching deterministic
expectation (expect_grounded, expect_helper_occluded, expect_occlusion,
expect_transform, expect_separation, expect_quality, etc.) or record a
new verifier gap; never treat the critic pass as a silent green gate.
- If it fails, diagnose from structured JSON:
scena inspect "$RECIPE"
scena diagnose "$RECIPE" --visibility --handle <handle>
scena repair "$RECIPE" --from diagnosis.json
The repair positional is an enforced target, not a label. A raw asset must
pass asset doctor and a recipe must complete policy-aware validation/build
before the report is planned. If repair returns asset_doctor,
scene_recipe_validation, or recipe_build_result, correct or authorize the
target first. Never supply a second positional target.
Workflow Selection
- Basic scene or app shell: read
references/recipe-loop.md.
- CAD inspection, digital twin, configurator, dashboard, documentation, web
viewer, interaction, or guided tour: read
references/app-patterns.md.
- Blank frame, wrong color, missing asset, bad pick, tiny object, cropped
labels, validation failure, or non-converging repair: read
references/debugging.md.
Load only the reference needed for the task.
Verification Rules
- For static scenes, require
render_introspection.ok == true and verify the
expected object is visible at a reasonable size.
- For material/configurator work, use appearance expectations; pixel change
alone is not enough.
- For animation or digital twins, sample time/state changes and verify the
named target changes as expected.
- For interactive viewers, use synthetic pick/hover/select verification.
- For CAD/docs overlays, verify measurements/callouts/section boxes render and
overlays are not cropped, tiny, or crossed by leader/dimension lines.
- For objects that must sit on a floor or grid, add
expect_grounded with the
target node, plane_y, and tolerance; treat ground_contact_missing as a
real placement failure.
- For depth-tested helper lines, grids, or wireframes that must stay behind a
subject, add
expect_helper_occluded; treat
helper_layer_overdraws_subject as a real render-layer failure.
- For overlapping solid objects whose depth order matters, add
expect_occlusion with front, back, and optional tolerance_pixels.
Use high-contrast opaque front/back materials; the current verifier is a
native-resolution color probe and fails closed with
object_depth_order_color_ambiguous when the colours cannot be separated.
Treat object_depth_order_mismatch as a real occlusion/depth failure.
- For GPU or hero renders, add
expect_backend with
{"backend":"headless_gpu","gpu_device":true} so CPU fallback fails
verification instead of silently weakening the proof. Treat
backend_expectation_mismatch as a real backend/capability failure; checked
render_antialiasing_active, render_supersample_active, and
render_reconstruction_active entries confirm the requested quality knobs
were actually active.
- For cutaways, clipping planes, and section-box views, add
expect_clipping
with active_clipping_planes, section_box_active, and
section_box_inverted. Treat clipping_plane_count_mismatch,
section_box_missing, and section_box_inversion_mismatch as real
composition failures.
- For configurators and product renders with material variants, add
expect_state entries for each load-bearing import variant. Omit
for the default variant, or set it to the exact
expected variant name. Treat as a real
state/variant failure.
Direct Verification Commands
Use these when the recipe manifest or task asks for a dedicated verifier:
scena verify appearance "$RECIPE" --expect appearance-expectation.json --out appearance.png
scena verify animation "$RECIPE" --clip <clip-name> --times 0,1 --expect-change
scena verify interaction "$RECIPE" --expect interaction-expectation.json
For a local checkout, prefix each command with:
cargo run --bin scena --features agent --
Scope Boundaries
Keep application/domain logic in the host:
- no CAD kernel, DXF/DWG/B-rep parsing, constraints, or feature recognition;
- no physics, simulation, particle lifetime integration, robotics, PLC logic,
pricing rules, SKU logic, networking, or document model;
- no hidden render loop owned by scena. The host ticks time and owns state.
When the user asks for out-of-scope behavior, build the visual/rendering layer
that scena owns and clearly state what the host/kernel/simulation must provide.