Physics simulation · the model and its test are the same code
Drop a marble down the printed chute. In your browser.
The exact geometry that printed on 2026-08-02, running in a physics engine.
The same code is the QA gate: what you play with here is the test the part passed,
and the log below is the actual gate run, not a retelling.
Where this is right now
The simulation verdict is a model, not a fact. One spiral chute exists physically;
the browser marble and the real marble have not yet been compared. The first physical run
calibrates this page: if they disagree, the simulation gets fixed and the correction stays here.
The chute, live
Interactive: drag to orbit the view, press Drop Marble. Same engine, same
timestep, same geometry as the gate run below.
The QA run, verbatim
The simulation and gate live in the public crackle repo, sim/: sim_core.mjs steps the physics, qa_sim.mjs is the gate. This is the log the gate produced when it judged the chute. Every assertion carries the
number it measured. If a run fails, the part is quarantined before anyone prints it.
[qa_sim] assets/spiral_chute_snapshot.stl
[qa_sim] tris=149472 bbox z 0.0..235.3mm crestR=20.4mm helix zone z 58.8..178.8mm exitZ<35.3mm descentDir=-theta
[qa_sim] drop at [-1.6, -12.3, 213.1]mm speed=100mm/s dt=1/480 marble=O16 scenario=chute feed=gutter
[qa_sim] turns=3.54 maxR(zone)=10.3mm vs crest 20.4mm (margin 10.1mm) descent=0.75s exit@0.91s stall=0.0s lowestZ=34.6mm
[qa_sim] PASS: ORBIT: marble stays captive, descends, exits.
-- the sorter, fed down the middle as a funnel would --
[qa_sim] /tmp/s_16_12.stl
[qa_sim] tris=131040 bbox z 0.0..203.1mm crestR=20.5mm helix zone z 50.8..154.3mm exitZ<30.5mm descentDir=-theta
[qa_sim] drop at [13.4, -5.5, 184.7]mm speed=100mm/s dt=1/480 marble=O12 scenario=sorter expect=shaft feed=axis
[qa_sim] turns=0.00 maxR(zone)=0.0mm vs crest 20.5mm (margin 20.5mm) descent=n/as exit@n/as stall=0.0s lowestZ=109.9mm <- run ENDED at the centre-drop flag, so this depth is where the WATCHER stopped, NOT where the marble stopped
[qa_sim] outcome=SHAFT (expected SHAFT)
[qa_sim] PASS: SORT: a O12 marble falls through the crest into the shaft.
[qa_sim] /tmp/s_16_12.stl
[qa_sim] tris=131040 bbox z 0.0..203.1mm crestR=20.5mm helix zone z 50.8..154.3mm exitZ<30.5mm descentDir=-theta
[qa_sim] drop at [13.4, -5.5, 184.7]mm speed=100mm/s dt=1/480 marble=O16 scenario=sorter expect=ride feed=axis
[qa_sim] turns=2.01 maxR(zone)=10.3mm vs crest 20.5mm (margin 10.2mm) descent=0.73s exit@0.79s stall=0.1s lowestZ=31.1mm
[qa_sim] outcome=RIDE (expected RIDE)
[qa_sim] PASS: SORT: a O16 marble rides the spiral past the crest.
engine rapier3d 0.19.3 deterministic fixed-step (dt=1/480), CCD on, trimesh of the printed part (149,472 tris)
provenance friction 0.5 / restitution 0.15 are ASSUMED glass-on-PLA constants, not measured; captivity verdict held across friction 0.3-0.7 x entry 0-300 mm/s; timings indicative until the physical run calibrates them
run date 2026-08-02 · same code as the viewer above (single bundle, node + browser bit-identical)