UI Bridge
A left-side @domphy/ui control panel (radius/tube inputs, a material-color select, a wireframe switch) drives a three() torus on the right through a single RecordState. The DOM controls and the scene graph both subscribe to it with the exact same (l) => state.get(key, l) contract — Domphy doesn't distinguish "a listener owned by a DOM node" from "a listener owned by a THREE.Mesh".
How it works
- One
RecordState, two consumers:controls.get("radius", l)is read both inside an<input>'svaluefunction and inside the mesh'sargsfunction — per-key reactivity, so changingtubenever re-runs thecolorsubscription. See Reactivity. argsas a function reconstructs: the torus'sargs: (l) => [radius, tube, 32, 96]re-reads the state on every change; becauseargsshallow-diffs, dragging radius/tube throws away the oldTHREE.TorusGeometryand builds a new one — seeargsreconstruction.color/wireframeare rule-7 reactive props: unlikeargs, these are ordinary scene props whose value is a function — dispatched asfn(listener, root), re-applied to the samemeshStandardMaterialinstance in place, no reconstruction. See function-prop rules.- Controlled inputs, same as any Domphy form:
value/checkedread through the listener,onInputwrites back with.set(...)— the standard Domphy controlled-input pattern, just feeding a 3D scene instead of another DOM node. card()+formGroup()compose on a plainfieldsetfor the panel:card()places a heading/content/footer grid,formGroup({ layout: "vertical" })lines up each<label>above its control.onCreated: sets a fixed scene background andcamera.lookAt(0, 0, 0)once — doctor's theme-color rules govern the DOM around the canvas, not the rendered scene itself.