Wave Field
A field of 400 boxes rigged as one InstancedMesh, displaced every frame by a traveling sine wave computed in onFrame — the kind of per-tick math at scale that only makes sense outside the declarative props grammar. A low, raking camera skims across the grid so the wave reads as motion rather than a static height-map, each instance is tinted by a blue-to-magenta HSL ramp keyed to its current height, and fog matched to the dark backdrop turns it into the classic "wow shot."
How it works
primitiveadopts an imperative core. Per-instance matrices at 400-instance granularity aren't expressible throughargs/props, so theInstancedMeshis built with three's own API and mounted via{ primitive: null, object: field }— never disposed by the reconciler, the demo owns its lifecycle.onFrame: (root, delta, self) => ...runs the wave math every rendered frame, withselfbound to the adopted instance — see Animation & Loop. Precomputing each instance's x/z once and only touching y (and the color derived from it) per tick keeps the per-frame loop to onesin/cos/setHSLpass per box.frameloop: "always"is set explicitly, not left to the default: the wave is continuous, time-based motion with noStatebehind it, so"demand"would never callinvalidate()and the field would freeze on the first frame. SeeonFramevs. reactive props.- A low, raking camera reads the wave as motion. The camera sits outside one edge of the grid at
[0, 8, 20],lookAt-ing a point past the far edge — roughly a 17° angle off the horizon — instead of looking straight down. A top-down view of a height field reads as a static bump map; skimming across it low makes the traveling crest and trough visibly move through the frame. - The height ramp is per-instance color, not lighting. Every tick, each instance's
ymaps to a blue-to-magenta HSL tint (hsl(200, 70%, 55%)at the trough tohsl(320, 80%, 65%)at the peak) viaInstancedMesh.setColorAt(). The material is unlit (MeshBasicMaterial) on purpose: on a lit material,setColorAt's tint multiplies into the diffuse term, and the cool/dark end of the ramp collapsed toward black at grazing light angles — a real rendering defect, reproduced on GPU hardware, not just headless/CI. An unlit material rendersinstanceColoras-is, so the ramp stays legible everywhere in the field — which is also why this scene carries no lights. attachinference onfog. The{ fog: null, args: [...] }node has no explicitattach— its.isFogflag infers"fog", and since this node sits at the top ofscene, that attaches straight ontoroot.scene.fog. Same inference rule a mesh's geometry/material children use — see Attach inference. Its color matchesroot.scene.backgroundso the back rows dissolve into the backdrop instead of into a visibly different rectangle.onCreatedpoints the camera at the field and setsroot.scene.background— a one-time setup step that runs once the root exists, documented in theThreeOptionscontract.