three.js Lab piece 02 · verified playthrough, desktop + mobile

Ashfall Station

A six-wheel survey rover, a cooling ash plain and a volcano that keeps throwing. Log the three sensor rings and get back to the station pad before the bombardment finds you. Authored end to end by AI agents — concept pack, Blender-sculpted rover and station, hand-written three.js, and a physics stack built on Rapier instead of the lab's usual cannon-es. This piece is the pilot that decided that question.

Play it now

WASD / arrows / touch · park inside a ring and hold still to log it · ~2.1 MB world + 6 MB sampled instruments

▶  Play

The concept is the contract

Seven sheets came before any authoring — key art, an orthographic turnaround of the rover, three zone sheets, a prop sheet and a material callout board. Twenty-three named elements became inventory rows, every row a real Blender asset. The pack is also where the honest notes live: the key art paints the rover dust-brown while the turnaround paints it orange, so the turnaround was declared authoritative and the key art kept only for mood.

Ashfall Station key art
Key art — the fissured plain, the station on its hill, the volcano still working
Ashfall Station live in the engine
The same station live in the engine: baked cabin, radome, guyed weather mast, the rover on its pad

Nine rounds of gray boxes

The whole drive ran and was won as flat-gray primitives before any Blender time, and the blockout is where this piece earned its physics. Nine defect rounds, each traced to a root cause: a mirrored wheel axle that made the left and right sides fight each other and held a 20 kN rover to walking pace; a crater rim the rover simply drove over at 16 m/s and fell out of the world; and a stop at the first sensor that pitched the rover onto its roof, where a six-wheeler has no traction and can never recover. The fixes — a real rim wall, a low centre of mass, and a self-righting assist — all ship inside the finished game.

gray blockout drive
Blockout: 55 obstacle colliders, telegraphed bomb rings, the HUD bearing indicator
the finished drive
The finished drive across the same terrain — the blockout's collision geometry, unchanged

One mesh, drawn and collided

The ash plain is a single Blender-displaced grid, and the engine builds its physics trimesh from that mesh's own vertices at load rather than from a second copy of the height function. Collider-visual parity is true by construction: the shipped selftest measures the worst vertex against the authoring formula and reports 0.00 cm. The rover's wheels get the same treatment — their rendered tyre radius is measured rotation-invariantly (an axis-aligned box measures tread phase on a lugged wheel, not radius) and fitted to the collider radius to 0.00 cm.

rover turnaround sheet
The turnaround sheet — the contract for the hero asset
rover Blender render
Audit round 4: a 19.2k-tri detail sculpt baked onto the 5.2k-tri shipped hull

Rapier vs cannon-es, measured

The piece exists to answer one question, so the answer was measured rather than asserted: the same scene shape in both engines — this piece's own terrain on the same 110 × 110 grid, the same deterministic spawns, the same 1/60 fixed step, 600 steps with 60 discarded as warmup. The cannon-es heightfield column is included deliberately, because comparing only against its known-weak Trimesh would have been a strawman. Two bugs in the benchmark harness itself were found and fixed before the numbers were trusted; both are written up in the ledger.

Dynamic bodiesRapier (trimesh)cannon-es (trimesh)cannon-es (heightfield)
300.38 ms/step76.9 ms/step (197×)3.2 ms/step (8.3×)
1201.02 ms/step309.0 ms/step (321×)13.0 ms/step (12.8×)
3002.76 ms/step971.1 ms/step (325×)27.1 ms/step (9.8×)
Resting penetration0.11–0.21 cm0.15–0.18 cm0.11–0.17 cm

Contact quality was a wash — Rapier is not more accurate here, it is one to two orders of magnitude faster for the same result. The surprise was tunnelling: dropping a 0.55 m ball straight into the same terrain, Rapier held at every speed up to 1208 m/s with continuous collision detection switched off, while cannon-es punched through at 72 m/s and again at 403 m/s even with four substeps. On this piece CCD is cheap insurance; Rapier's speculative contacts are what actually do the work. The shipped selftest asserts the requirement — no tunnelling with CCD on — and merely logs the CCD-off result, because an assert that "CCD off must tunnel" would have encoded a wrong assumption.

Measured, honestly

MeasurementValueConditions
World payload (22 glbs)2.06 MB (from 11.98 MB raw)gltf-transform prune + dedup + quantize + resize + webp
Largest single glb1.19 MB (the ash plain)budget ≤ 6 MB; terrain skips quantize so its collider vertices stay exact
Draw calls / on-screen triangles132 calls · 114k trianglesRENDERSTATS console line; budget ≤ 300 / ≤ 600k — 289 calls before the marker rings were merged and the boulders instanced
Terrain collider24,642 tris from the drawn meshworst vertex vs the authoring height function: 0.00 cm
Wheel collider-visual parity0.00 cm on the worst of sixrotation-invariant tyre radius vs collider r = 0.42 m
Defect rounds, each with a root cause9 blockout + 8 game-assemblyaxle mirroring · drive sign · rim escape · roof-pitch softlock · invisible walls · ramp-shaped colliders
Physics step cost in-game0.4–1.0 ms/step~60 dynamic + 57 static colliders, Rapier 0.20.0
Audio4 sampled instruments + 2 ambience bedspad-bowed drone, vibraphone, timpani, taiko; wind and fire stems; first-gesture unlock
Known nitrim-wall texture repeats visiblythe crater wall tiles the ash set at a grazing angle; accepted at driving distance

Real engine features, earned

Raycast vehicle, six wheels

Rapier's DynamicRayCastVehicleController with three axles, speed-tapered steering lock and rear-axle counter-steer that fades out with speed — a 6×6 resists yaw like a tracked vehicle without it.

Trimesh terrain from the visual mesh

The drawn glb's own vertices become the collider at load, so there is no second surface to drift out of sync.

CCD on the hazard

Lava bombs fly ballistically at ~60 m/s with continuous collision detection and an event-queue impact, telegraphed 4.5 s ahead by a ground ring.

Never-stranded recovery

A rover on its roof has no traction; after 2.2 s inverted and stopped it rights itself, and leaving the bowl respawns at the last grounded pose.

Instanced dressing

54 boulders and the crust plates draw as InstancedMesh with each node's baked dequantization transform folded into the instance matrices.

Sampled-instrument score

A bowed-pad drone that tightens with damage and heat, vibraphone for sensor pings, timpani and taiko for impacts — every voice a sample, ducked under stingers.

engine 4200 N × 4 wheelstop 13 m/s steer lock 0.72 rad, −62% at speed rear counter-steer 0.45, fades by 12 m/s CoM ballast 1200 kg @ −0.55 m middle-axle side friction 0.30 bomb telegraph 4.5 s · blast 5.5 m self-right after 2.2 s ACESFilmic · exposure 1.06