Generate 3D Scene — Strategy Skill
Choose how to build a 3d_scene asset. Do not default to one pipeline for every
task: what the user specified about the scene's appearance matters more than the
scene type, and generative reconstruction is the least stable route here.
Decision
Ask first: did the user specify the scene's 3D appearance?
| Situation |
Prefer |
Why |
| Appearance not specified — no reference image, no described look |
Downloadable, licence-checked assets. Search the selected engine's own asset library for a usable scene or environment kit: UE5 (Fab / Marketplace, Quixel), Unity (Asset Store, packages), Godot (Asset Library), Blender (bundled assets, CC0 libraries), three.js (curated CC0 packs — see <REPO_PATH>/agent_skills/engine_context/three_js_api.md) |
Nothing constrains the look, so a licensed, artist-made scene is more shippable than anything generated, and it imports through a documented path. Record source and licence |
| Appearance specified — reference image or a described look |
Lay out the terrain/ground first, then add foreground objects (see Ground first, then objects below, and Scene construction code chain for the mechanised form) |
WorldPlay-style reconstruction is not yet stable enough to be the default. Ground + placed props is controllable, editable, and reproduces a requested look reliably |
| Appearance specified, the space is indoor/enclosed, and the user needs high fidelity |
WorldPlay-style reconstruction |
This is the one case where the reconstruction path earns its instability: an enclosed volume has no horizon or sky to break, and one reference image can carry the whole interior |
Prefer downloadable assets even when the appearance is specified, if a library
scene already matches the requested look — generation is not a goal in itself.
Do not silently switch strategies. State which row you selected and why, and if
the user asked for the reconstruction path outside the indoor high-fidelity case,
say that it is the unstable route before spending time on it.
If the user is unhappy with scene consistency
Reconstruction-based scenes commonly come back inconsistent: geometry drifting
between frames, depth stretched at occlusion boundaries, sky or background pulled
into a curtain, holes and non-continuous surfaces, and a look that shifts across
the scene. This is a known limitation of the current generate-then-reconstruct
chain, not a misconfiguration.
When the user raises it, briefly summarise the cause and offer the way out —
do not keep re-rolling the same generation:
- name the failure in one or two sentences (what is inconsistent, and that it
comes from video/depth reconstruction rather than a bad setting);
- recommend switching to ground-first composition, or to a downloadable library
scene, so the look is authored rather than inferred;
- keep only the parts of the reconstruction that were good, if any, as a
reference for the layout.
Scene type still decides the geometry strategy
Once the route is chosen, classify the space. If the task packet does not say,
infer from the reference image and requirement text: visible enclosing walls and
a finite volume → closed; ground that extends to the horizon or an open sky →
open.
| Scene type |
Geometry strategy |
Why |
| Closed / indoor / bounded (rooms, corridors, arenas with walls) |
WorldPlay-style reconstruction, when the fidelity bar justifies it |
One reference image can become multi-view footage, then a coherent scene mesh |
| Open / outdoor / unbounded (fields, roads, city blocks, terrain) |
Base plane or terrain + place objects |
Horizon and sky break depth-to-mesh; composition from ground + props is more controllable |
Closed scenes — WorldPlay / point-cloud → mesh
Use when the playable space is enclosed, high fidelity is required, and most of
the geometry should come from one visual reference.
Typical chain in this repo:
- Reference image (+ optional prompt / camera pose) → WorldPlay video frames
- Frames → WorldMirror depth / point cloud
- Point cloud → continuous mesh (
<REPO_PATH>/operators/gen_3d_scene, sky cull + tangent-plane faces)
- Export GLB / PLY under the
3d_scene output path
When to use this path:
- Interior rooms, caves, tunnels, small arenas with clear walls/ceiling and a
high-fidelity requirement — this is the only case where it is the recommended
default
- The reference already shows the layout the player should inhabit
- You need a single fused scene mesh rather than separately authored props
Watch-outs:
- Stability: this chain is the least reliable route in this Skill. Expect
inconsistency across the scene and be ready to fall back to ground-first
composition or a library scene
- Occlusion boundaries and sky/background still need the meshing guards in
gen_3d_scene (sky segmentation, tangent-plane continuity, normal-agreement cull)
- Do not expect clean infinite outdoor horizons from this path
Entry points: <REPO_PATH>/pipeline/assets_gen/gen_3d_scene/{run,eval,render}.py,
<REPO_PATH>/test/test_3D_scene_gen.py.
Ground first, then objects — plane / terrain + objects
The default route whenever the user specified a look, and the right route for
any large, ground-driven, or reusable-asset world.
Recommended strategy:
- Establish the terrain/ground first — flat plane, heightmap terrain, or a simple
road/ground kit mesh — so the scene's footprint and silhouette are settled
before anything is placed on it
- Generate or select individual foreground objects with
gen_3d_object
(buildings, props, characters, vehicles), or take them from the engine's asset
library
- Place those objects on the base surface according to the task layout
(spawn points, lanes, cover, landmarks)
- Keep the scene as a composed assembly (ground + instances), not one baked
WorldPlay mesh of the whole horizon
When to use this path:
- The user described or referenced a look and it is not an indoor high-fidelity case
- Outdoor maps, racing circuits, open battlefields, city blocks with sky
- Layout is defined by gameplay (lanes, spawn areas) more than by one photo
- You need editable / swappable props rather than a single reconstructed shell
Watch-outs:
- Do not feed a wide outdoor reference into WorldPlay and expect a clean
continuous mesh to the horizon — depth stretching and sky curtains are common
- Prefer explicit ground + object placement over trying to “fix” open-world
reconstruction with post-filters alone
Scene construction code chain — greybox first, then detail
The mechanised form of ground first, then objects. Use it when the layout
matters — gameplay space, a described site, anything that will be edited or
reviewed before it is dressed — and when you want the arrangement checked before
any generation is paid for.
Two stages, in this order:
- Greybox. Build terrain, place primitives, and validate. Nothing is
generated, so a wrong layout costs nothing to discard.
- Detail. Swap individual primitives for generated meshes and stage ground
textures, keeping the placement the greybox already proved.
Five concerns are separate values, so any one can be changed without the others:
| concern |
functions in <REPO_PATH>/operators/gen_3d_scene/funcs/terrain_code_edit.py |
| terrain |
flat hills slope bowl mound canyon, reshaped by flattened levelled_at graded carved terraced, and settled by baked |
| layout |
grid_spots ring_spots line_spots scatter_spots clustered_spots winding_spots arc_spots blocks_spots channel_spots spoke_lines, filtered by clear_circle clear_of clear_of_ways in_height_band on_high_ground on_low_ground on_slope fits, measured by crossing chained densified facing highest_spot lowest_spot contour_radius |
| structures |
ring_wall + gate_spots arch stairway stepped_tower ruin bridge columns road_network interchange water_along |
| sizing |
uniform_sizes varied_sizes graded_sizes tiered_heights stepped_sizes |
| materials |
GREYBOX_MATERIALS swap_material MATERIAL_TEXTURES |
Relief is written as one welded heightfield, not a box per tile: a grid of
boxes is a staircase with a vertical wall at every tile edge, which is what
makes a slope read as blocky. Ground shapes are driven by warped_noise
rather than by sine waves, since crossed sines put every crest on a regular
lattice and the layout filters built on them then fall into rows; warping
then reads the noise off a grid noise has itself displaced, which is what
gives slopes that run and hollows that are not circles. ridged_noise folds
each octave at zero for the opposite profile — narrow crests over broad
hollows — and is what puts a summit on high ground that a beacon can stand
on; hills(crest=...) mixes the two.
Every landform ends with baked: the height is sampled once onto the grid
the surface is written from and read back by interpolation. That is a cost
(a composed terrain is otherwise re-evaluated per sample) and a correctness
point (a prop is then validated against the ground the GLB carries, not
against a formula the exported mesh only samples).
The Two Stages Of A Template
<REPO_PATH>/operators/gen_3d_scene/funcs/terrain_code_template/ holds two
files, split by question rather than by scene:
| file |
question |
returns |
landforms.py |
what is the ground |
a Ground: terrain plus the measurements taken from it |
foreground.py |
what stands on it |
(terrain, props) |
The ground reports what the foreground needs — where a basin actually bottoms
out, what level a street network was graded to — so each measurement is
derived once, where it is known. A foreground that re-derived them would give
a second answer to the same question.
The foreground returns terrain as well because some of them cut the ground
they stand on: a pad under a hut, a level track. Every cut has to happen
before any prop is measured, or a prop is placed against ground that later
moves under it.
Landforms are classified by landform, not by level name, because the
terrain dictates the distribution — a settlement in a basin gathers on the
terraces, the same settlement on a ridge follows the high ground.
| landform |
ground |
circulation |
landmark |
the rest |
plains |
rippled, two roads crossing it |
the two roads |
watchtower |
way-station, field walls, copses |
hills |
ridged and terraced |
cairns between the tops and the hollows |
beacons |
farmsteads with yards, scrub |
basin |
dished and terraced |
a flight down the bank |
the lake hall |
hamlets on the treads, shore, jetty |
canyon |
meandering channel |
trail, switchback stair |
the rim bridge |
camp, talus, standing water |
walled_town |
terraced motte |
gates, streets, approach steps |
the keep |
blocks, market square, camp outside |
city |
graded streets, carved river |
streets, bridges, interchange |
interchange and tower core |
quarters, frontage, park |
Start from the nearest landform and override, rather than writing a scene from
nothing.
Four things separate a site that reads as a level from a scatter of blocks,
and every scene here owes all four. They are worth checking against by eye
before anything is generated, because no amount of detail added later
supplies one that is missing:
- circulation — a way through, whether that is paving, a stair, a bridge
or a line of cairns. Without one, whatever is placed is furniture.
- a landmark — one thing taller and more distinct than the rest. A
greybox has no texture and no lighting, so a silhouette is the only thing
that can anchor a view or give the site a scale.
- hierarchy — three sizes at least. A site of one-storey boxes has no
foreground and no background whatever the layout does.
- enclosure — something dividing the ground, so the open parts read as
chosen rather than as leftover: walls, hedges, blocks, terraces.
Typical chain:
from operators.gen_3d_scene.funcs import terrain_code_edit as te
from operators.gen_3d_scene.funcs.terrain_code_template import (
build_scene, foreground, landforms,
)
scene = build_scene("basin", size=70.0) # stage 1: the pair
problems = te.check_scene(scene) # must be empty before going on
te.write_scene(scene, "greybox.glb")
scene = te.swap_mesh(scene, "house-00", "model.glb", height=3.4) # stage 2
scene = te.swap_material(scene, "wall", [0.5, 0.47, 0.44])
te.stage_scene_textures(project_dir, scene)
To keep a landform and re-roll what stands on it, or put one settlement on a
different shape of ground, drive the two stages directly:
ground = landforms.hills(size=90.0, relief=5.0)
terrain, props = foreground.plains(ground) # the pairing is a default
scene = te.Scene("mixed", terrain, props)
Placement Rules Worth Knowing
ground_under rests a prop on the lowest ground under its whole
footprint, not the height at its centre. A wide base sampled only at the
centre leaves a corner hanging in the air on any slope.
fits measures the candidate's own turned footprint; clear_of is
given a bare position and cannot see how wide a building is. Use fits when
choosing size and position together.
pinned holds a run at one level while the ground falls away — a bridge or
a flyover deck. sloped spreads a climb along a run, for a ramp between
two levels. A ramp built from pinned would be a step.
- Paving is a run of short tiles from
path_tiles / paved, not one long
box, so it follows a bend and follows the ground. Grade the ground under
a whole network to one level (graded) or neighbouring slabs each rest on
their own patch and step against each other — a slab can sit further above
its neighbour than the slab is thick, which is a pothole every few metres.
- Order matters when reshaping ground: grade the streets, then carve the
river. In the other order the streets dam the channel at every crossing.
Do not skip check_scene, and do not loosen a template to silence it. It
reports props off the terrain, props inside one another, sizes that misread
against a 1.8 m person, and duplicate ids that would collapse two nodes on
export. Props that are meant to touch — road segments, a wall run, reeds in
the shallows — share a group and are exempt; that is the intended way to
express contact, not a larger tolerance.
Geometry is measured with the writer's own rotated_bounds and euler_matrix
from <REPO_PATH>/models/common/glb_writer.py. A checker that rotates or scales
differently from the writer will pass scenes that are wrong on disk.
Two behaviours worth knowing before using stage 2:
- A
mesh part is fitted into its box by one factor, so it fills only its
longest axis. Pass height= to swap_mesh whenever the mesh is not the same
shape as the block it replaces, or a figure dropped into a wide dais will be
scaled to the dais's width.
- Terrain dipping below zero (
bowl, canyon) is a landform, not a fault. The
tiles extend down to a shared floor so the ground stays solid.
Entry points:
python -m operators.gen_3d_scene.funcs.terrain_code_edit — write every
template as a GLB and print its problem count
python <REPO_PATH>/test/test_3d_scene_code.py — 40 tests, no weights, no GPU,
no network
python <REPO_PATH>/test/test_3d_scene_code.py --video — record a turntable
per landform for review
Review artifacts land in <REPO_PATH>/test_data/outputs/_test_3d_scene_code/,
recorded by <REPO_PATH>/test_data/outputs/_viewer_lib/scene_recorder.html. That
page is separate from recorder.html: a site is wide and flat, so it is framed
against both frustum axes and viewed from above, and it does not add a grid or
report sub-zero geometry as a fault.
Quick checklist
- Did the user specify the appearance? No → search the selected engine's
asset library for a downloadable, licence-checked scene; record source and
licence.
- Yes → terrain/ground first, then place foreground objects. For a layout
that matters, use the Scene construction code chain: greybox and
check_scene before anything is generated. Use the WorldPlay reconstruction
path only for an indoor/enclosed space that needs high fidelity, and say that
it is the unstable route.
- Classify closed vs open (from task text / reference) and apply the matching
geometry strategy.
- Write artifacts to the paths
<REPO_PATH>/pipeline/common/paths.py defines for 3d_scene.
- Visually check continuity (closed) or placement / scale on ground (open)
before accepting the asset. For a code-built scene,
check_scene must be
empty and the recorded turntable must show the landform it claims.
- If the user reports inconsistent scene quality, summarise the reconstruction
limitation and move to ground-first composition or a library scene rather than
regenerating repeatedly.
1---2name: 3d-scene3description: Generate 3D Scene — Strategy Skill4---5# Generate 3D Scene — Strategy Skill67Choose how to build a `3d_scene` asset. Do not default to one pipeline for every8task: what the user specified about the scene's appearance matters more than the9scene type, and generative reconstruction is the least stable route here.1011## Decision1213Ask first: **did the user specify the scene's 3D appearance?**1415| Situation | Prefer | Why |16|---|---|---|17| **Appearance not specified** — no reference image, no described look | **Downloadable, licence-checked assets.** Search the selected engine's own asset library for a usable scene or environment kit: UE5 (Fab / Marketplace, Quixel), Unity (Asset Store, packages), Godot (Asset Library), Blender (bundled assets, CC0 libraries), three.js (curated CC0 packs — see `<REPO_PATH>/agent_skills/engine_context/three_js_api.md`) | Nothing constrains the look, so a licensed, artist-made scene is more shippable than anything generated, and it imports through a documented path. Record source and licence |18| **Appearance specified** — reference image or a described look | **Lay out the terrain/ground first, then add foreground objects** (see *Ground first, then objects* below, and *Scene construction code chain* for the mechanised form) | WorldPlay-style reconstruction is **not yet stable enough** to be the default. Ground + placed props is controllable, editable, and reproduces a requested look reliably |19| **Appearance specified, the space is indoor/enclosed, and the user needs high fidelity** | WorldPlay-style reconstruction | This is the one case where the reconstruction path earns its instability: an enclosed volume has no horizon or sky to break, and one reference image can carry the whole interior |2021Prefer downloadable assets even when the appearance is specified, if a library22scene already matches the requested look — generation is not a goal in itself.2324Do not silently switch strategies. State which row you selected and why, and if25the user asked for the reconstruction path outside the indoor high-fidelity case,26say that it is the unstable route before spending time on it.2728### If the user is unhappy with scene consistency2930Reconstruction-based scenes commonly come back inconsistent: geometry drifting31between frames, depth stretched at occlusion boundaries, sky or background pulled32into a curtain, holes and non-continuous surfaces, and a look that shifts across33the scene. This is a known limitation of the current generate-then-reconstruct34chain, not a misconfiguration.3536When the user raises it, **briefly summarise the cause and offer the way out** —37do not keep re-rolling the same generation:38391. name the failure in one or two sentences (what is inconsistent, and that it40 comes from video/depth reconstruction rather than a bad setting);412. recommend switching to ground-first composition, or to a downloadable library42 scene, so the look is authored rather than inferred;433. keep only the parts of the reconstruction that were good, if any, as a44 reference for the layout.4546## Scene type still decides the geometry strategy4748Once the route is chosen, classify the space. If the task packet does not say,49infer from the reference image and requirement text: visible enclosing walls and50a finite volume → closed; ground that extends to the horizon or an open sky →51open.5253| Scene type | Geometry strategy | Why |54|---|---|---|55| Closed / indoor / bounded (rooms, corridors, arenas with walls) | WorldPlay-style reconstruction, when the fidelity bar justifies it | One reference image can become multi-view footage, then a coherent scene mesh |56| Open / outdoor / unbounded (fields, roads, city blocks, terrain) | Base plane or terrain + place objects | Horizon and sky break depth-to-mesh; composition from ground + props is more controllable |5758## Closed scenes — WorldPlay / point-cloud → mesh5960Use when the playable space is enclosed, high fidelity is required, and most of61the geometry should come from one visual reference.6263Typical chain in this repo:64651. Reference image (+ optional prompt / camera pose) → WorldPlay video frames662. Frames → WorldMirror depth / point cloud673. Point cloud → continuous mesh (`<REPO_PATH>/operators/gen_3d_scene`, sky cull + tangent-plane faces)684. Export GLB / PLY under the `3d_scene` output path6970When to use this path:7172- Interior rooms, caves, tunnels, small arenas with clear walls/ceiling **and** a73 high-fidelity requirement — this is the only case where it is the recommended74 default75- The reference already shows the layout the player should inhabit76- You need a single fused scene mesh rather than separately authored props7778Watch-outs:7980- Stability: this chain is the least reliable route in this Skill. Expect81 inconsistency across the scene and be ready to fall back to ground-first82 composition or a library scene83- Occlusion boundaries and sky/background still need the meshing guards in84 `gen_3d_scene` (sky segmentation, tangent-plane continuity, normal-agreement cull)85- Do not expect clean infinite outdoor horizons from this path8687Entry points: `<REPO_PATH>/pipeline/assets_gen/gen_3d_scene/{run,eval,render}.py`,88`<REPO_PATH>/test/test_3D_scene_gen.py`.8990## Ground first, then objects — plane / terrain + objects9192The **default route whenever the user specified a look**, and the right route for93any large, ground-driven, or reusable-asset world.9495Recommended strategy:96971. Establish the terrain/ground first — flat plane, heightmap terrain, or a simple98 road/ground kit mesh — so the scene's footprint and silhouette are settled99 before anything is placed on it1002. Generate or select individual foreground objects with `gen_3d_object`101 (buildings, props, characters, vehicles), or take them from the engine's asset102 library1033. Place those objects on the base surface according to the task layout104 (spawn points, lanes, cover, landmarks)1054. Keep the scene as a composed assembly (ground + instances), not one baked106 WorldPlay mesh of the whole horizon107108When to use this path:109110- The user described or referenced a look and it is not an indoor high-fidelity case111- Outdoor maps, racing circuits, open battlefields, city blocks with sky112- Layout is defined by gameplay (lanes, spawn areas) more than by one photo113- You need editable / swappable props rather than a single reconstructed shell114115Watch-outs:116117- Do not feed a wide outdoor reference into WorldPlay and expect a clean118 continuous mesh to the horizon — depth stretching and sky curtains are common119- Prefer explicit ground + object placement over trying to “fix” open-world120 reconstruction with post-filters alone121122## Scene construction code chain — greybox first, then detail123124The mechanised form of *ground first, then objects*. Use it when the layout125matters — gameplay space, a described site, anything that will be edited or126reviewed before it is dressed — and when you want the arrangement checked before127any generation is paid for.128129Two stages, in this order:1301311. **Greybox.** Build terrain, place primitives, and validate. Nothing is132 generated, so a wrong layout costs nothing to discard.1332. **Detail.** Swap individual primitives for generated meshes and stage ground134 textures, keeping the placement the greybox already proved.135136Five concerns are separate values, so any one can be changed without the others:137138| concern | functions in `<REPO_PATH>/operators/gen_3d_scene/funcs/terrain_code_edit.py` |139|---|---|140| terrain | `flat` `hills` `slope` `bowl` `mound` `canyon`, reshaped by `flattened` `levelled_at` `graded` `carved` `terraced`, and settled by `baked` |141| layout | `grid_spots` `ring_spots` `line_spots` `scatter_spots` `clustered_spots` `winding_spots` `arc_spots` `blocks_spots` `channel_spots` `spoke_lines`, filtered by `clear_circle` `clear_of` `clear_of_ways` `in_height_band` `on_high_ground` `on_low_ground` `on_slope` `fits`, measured by `crossing` `chained` `densified` `facing` `highest_spot` `lowest_spot` `contour_radius` |142| structures | `ring_wall` + `gate_spots` `arch` `stairway` `stepped_tower` `ruin` `bridge` `columns` `road_network` `interchange` `water_along` |143| sizing | `uniform_sizes` `varied_sizes` `graded_sizes` `tiered_heights` `stepped_sizes` |144| materials | `GREYBOX_MATERIALS` `swap_material` `MATERIAL_TEXTURES` |145146Relief is written as one welded `heightfield`, not a box per tile: a grid of147boxes is a staircase with a vertical wall at every tile edge, which is what148makes a slope read as blocky. Ground shapes are driven by `warped_noise`149rather than by sine waves, since crossed sines put every crest on a regular150lattice and the layout filters built on them then fall into rows; warping151then reads the noise off a grid noise has itself displaced, which is what152gives slopes that run and hollows that are not circles. `ridged_noise` folds153each octave at zero for the opposite profile — narrow crests over broad154hollows — and is what puts a summit on high ground that a beacon can stand155on; `hills(crest=...)` mixes the two.156157Every landform ends with `baked`: the height is sampled once onto the grid158the surface is written from and read back by interpolation. That is a cost159(a composed terrain is otherwise re-evaluated per sample) and a correctness160point (a prop is then validated against the ground the GLB carries, not161against a formula the exported mesh only samples).162163### The Two Stages Of A Template164165`<REPO_PATH>/operators/gen_3d_scene/funcs/terrain_code_template/` holds two166files, split by question rather than by scene:167168| file | question | returns |169|---|---|---|170| `landforms.py` | what is the ground | a `Ground`: terrain plus the measurements taken from it |171| `foreground.py` | what stands on it | `(terrain, props)` |172173The ground reports what the foreground needs — where a basin actually bottoms174out, what level a street network was graded to — so each measurement is175derived once, where it is known. A foreground that re-derived them would give176a second answer to the same question.177178The foreground returns terrain as well because some of them cut the ground179they stand on: a pad under a hut, a level track. **Every cut has to happen180before any prop is measured**, or a prop is placed against ground that later181moves under it.182183Landforms are classified by **landform, not by level name**, because the184terrain dictates the distribution — a settlement in a basin gathers on the185terraces, the same settlement on a ridge follows the high ground.186187| landform | ground | circulation | landmark | the rest |188|---|---|---|---|---|189| `plains` | rippled, two roads crossing it | the two roads | watchtower | way-station, field walls, copses |190| `hills` | ridged and terraced | cairns between the tops and the hollows | beacons | farmsteads with yards, scrub |191| `basin` | dished and terraced | a flight down the bank | the lake hall | hamlets on the treads, shore, jetty |192| `canyon` | meandering channel | trail, switchback stair | the rim bridge | camp, talus, standing water |193| `walled_town` | terraced motte | gates, streets, approach steps | the keep | blocks, market square, camp outside |194| `city` | graded streets, carved river | streets, bridges, interchange | interchange and tower core | quarters, frontage, park |195196Start from the nearest landform and override, rather than writing a scene from197nothing.198199Four things separate a site that reads as a level from a scatter of blocks,200and every scene here owes all four. They are worth checking against by eye201before anything is generated, because no amount of detail added later202supplies one that is missing:203204- **circulation** — a way through, whether that is paving, a stair, a bridge205 or a line of cairns. Without one, whatever is placed is furniture.206- **a landmark** — one thing taller and more distinct than the rest. A207 greybox has no texture and no lighting, so a silhouette is the only thing208 that can anchor a view or give the site a scale.209- **hierarchy** — three sizes at least. A site of one-storey boxes has no210 foreground and no background whatever the layout does.211- **enclosure** — something dividing the ground, so the open parts read as212 chosen rather than as leftover: walls, hedges, blocks, terraces.213214Typical chain:215216```python217from operators.gen_3d_scene.funcs import terrain_code_edit as te218from operators.gen_3d_scene.funcs.terrain_code_template import (219 build_scene, foreground, landforms,220)221222scene = build_scene("basin", size=70.0) # stage 1: the pair223problems = te.check_scene(scene) # must be empty before going on224te.write_scene(scene, "greybox.glb")225226scene = te.swap_mesh(scene, "house-00", "model.glb", height=3.4) # stage 2227scene = te.swap_material(scene, "wall", [0.5, 0.47, 0.44])228te.stage_scene_textures(project_dir, scene)229```230231To keep a landform and re-roll what stands on it, or put one settlement on a232different shape of ground, drive the two stages directly:233234```python235ground = landforms.hills(size=90.0, relief=5.0)236terrain, props = foreground.plains(ground) # the pairing is a default237scene = te.Scene("mixed", terrain, props)238```239240### Placement Rules Worth Knowing241242- `ground_under` rests a prop on the **lowest ground under its whole243 footprint**, not the height at its centre. A wide base sampled only at the244 centre leaves a corner hanging in the air on any slope.245- `fits` measures the **candidate's own turned footprint**; `clear_of` is246 given a bare position and cannot see how wide a building is. Use `fits` when247 choosing size and position together.248- `pinned` holds a run at one level while the ground falls away — a bridge or249 a flyover deck. `sloped` spreads a climb along a run, for a ramp between250 two levels. A ramp built from `pinned` would be a step.251- Paving is a run of short tiles from `path_tiles` / `paved`, not one long252 box, so it follows a bend and follows the ground. **Grade the ground under253 a whole network to one level** (`graded`) or neighbouring slabs each rest on254 their own patch and step against each other — a slab can sit further above255 its neighbour than the slab is thick, which is a pothole every few metres.256- Order matters when reshaping ground: grade the streets, **then** carve the257 river. In the other order the streets dam the channel at every crossing.258259**Do not skip `check_scene`, and do not loosen a template to silence it.** It260reports props off the terrain, props inside one another, sizes that misread261against a 1.8 m person, and duplicate ids that would collapse two nodes on262export. Props that are meant to touch — road segments, a wall run, reeds in263the shallows — share a `group` and are exempt; that is the intended way to264express contact, not a larger tolerance.265266Geometry is measured with the writer's own `rotated_bounds` and `euler_matrix`267from `<REPO_PATH>/models/common/glb_writer.py`. A checker that rotates or scales268differently from the writer will pass scenes that are wrong on disk.269270Two behaviours worth knowing before using stage 2:271272- A `mesh` part is fitted into its box by **one** factor, so it fills only its273 longest axis. Pass `height=` to `swap_mesh` whenever the mesh is not the same274 shape as the block it replaces, or a figure dropped into a wide dais will be275 scaled to the dais's width.276- Terrain dipping below zero (`bowl`, `canyon`) is a landform, not a fault. The277 tiles extend down to a shared floor so the ground stays solid.278279Entry points:280281- `python -m operators.gen_3d_scene.funcs.terrain_code_edit` — write every282 template as a GLB and print its problem count283- `python <REPO_PATH>/test/test_3d_scene_code.py` — 40 tests, no weights, no GPU,284 no network285- `python <REPO_PATH>/test/test_3d_scene_code.py --video` — record a turntable286 per landform for review287288Review artifacts land in `<REPO_PATH>/test_data/outputs/_test_3d_scene_code/`,289recorded by `<REPO_PATH>/test_data/outputs/_viewer_lib/scene_recorder.html`. That290page is separate from `recorder.html`: a site is wide and flat, so it is framed291against both frustum axes and viewed from above, and it does not add a grid or292report sub-zero geometry as a fault.293294## Quick checklist2952961. Did the user specify the appearance? **No** → search the selected engine's297 asset library for a downloadable, licence-checked scene; record source and298 licence.2992. **Yes** → terrain/ground first, then place foreground objects. For a layout300 that matters, use the *Scene construction code chain*: greybox and301 `check_scene` before anything is generated. Use the WorldPlay reconstruction302 path only for an indoor/enclosed space that needs high fidelity, and say that303 it is the unstable route.3043. Classify closed vs open (from task text / reference) and apply the matching305 geometry strategy.3064. Write artifacts to the paths `<REPO_PATH>/pipeline/common/paths.py` defines for `3d_scene`.3075. Visually check continuity (closed) or placement / scale on ground (open)308 before accepting the asset. For a code-built scene, `check_scene` must be309 empty and the recorded turntable must show the landform it claims.3106. If the user reports inconsistent scene quality, summarise the reconstruction311 limitation and move to ground-first composition or a library scene rather than312 regenerating repeatedly.