Theme Sync
The unique Domphy story: one theme system, two renderers. @domphy/ui buttons switch a color family and a light/dark surface on the demo container's dataTone — the exact same State is read inside the three() scene to recolor the mesh material, the scene background, and the fog through themeColorToken(). Edit the code below live.
How it works
- One
State, two consumers.activeColoranddarkSurface(toState) are read by the container'sdataToneattribute and by the scene's reactive props — that's the actual bridge, not automatic DOM-to-WebGL context propagation. See Scene Grammar for the pierced-prop / reactive-value rules. themeColorToken(l, tone, color)returns a concrete token string (e.g."#4a7ff4") instead of avar(--…)CSS reference — exactly what ameshStandardMaterial.coloror aTHREE.Color/THREE.Fogconstructor needs, since neither understands CSS custom properties.- Function-prop rule 7. Any non-event function value on a scene node (
color: (l) => ...) subscribes a Domphy listener and re-applies the prop on change — see the function-prop rules in the grammar doc. That's what makes the mesh recolor the instant a button is clicked. - Reactive
argsreconstructs. The background{ color: null, attach: "background" }and{ fog: null }nodes have no nested prop path to poke, so theirargsis a function — a shallow change there tears down and rebuilds the instance (locked in the grammar's reconcile semantics), which is the only way to update them. - The listener has no DOM context.
themeColorToken()'s automaticdataTone/dataThemetree-walk needs aListenerwith.elementNode, which is how@domphy/corewires it for ordinary DOM style/attribute props. The listener athree()reactive prop hands your function is a bareHandlerwithout.elementNode, so it never inherits tone context from an ancestor on its own — sharing oneStateis what actually keeps DOM and scene in sync. button({ color })(@domphy/ui) accepts the sameThemeColorunionthemeColorTokendoes, so each swatch button is itself colored by the family it selects.