GPGPU Name Particle Morph
A word is rasterized, sampled into target positions and handed to a pair of GPU ping-pong textures. Every particle carries its own spring, curl wander and pointer impulse. Type a different word and the same population is re-targeted; it scatters and finds the new letterforms.
How this is built
- Runtime
- Three.js r185, added as the route’s first runtime dependency. Its
GPUComputationRenderersupplies the float-texture ping-pong and dependency wiring; the route imports only the renderer, points, shader and math modules it uses so the bundler can drop the rest. WebGL2 is required, device pixel ratio is capped at 2, and context loss stops the loop and rebuilds the GPU graph if the browser restores the context. - Targets
- The submitted word is rasterized offscreen with the site’s existing Roboto Flex subset — a 34 200-byte woff2 (
public/fonts/roboto-flex-v1.woff2, measured on this repository 2026-09-02), and no new font is downloaded. Filled pixels are collected and rejection-sampled to exactly the requested particle count, then uploaded as a float texture. Width is set throughctx.fontStretchimmediately afterctx.font, because assigning the font resets the stretch. - Motion
- A velocity kernel combines a spring toward the target, a divergence-free curl perturbation, a Gaussian pointer repulsor and a radial scatter impulse; a position kernel integrates it at a fixed 1/60 s step with a 4-step frame ceiling. Particle count is live-switchable from 50,000 to 250,000, so its cost is visible in the HUD rather than hidden in a preset.
- Input and state
- The word field accepts 1–12 Basic Latin characters, matching the shipped font subset. Every mutation has a keyboard path: Enter submits the word, arrow keys change count, Space or Enter activates Scatter as the keyboard equivalent of pointer force, and the panel’s move handle takes the arrow keys. The word and count are written to
lab.gpgpu-name-morph.v1and the panel’s position tolab.gpgpu-name-morph.panel.v1, both inside a try/catch and both restored on the next visit; storage failure leaves the instrument running with defaults. Reset arms, then confirms, and returns all three to their defaults. - Reduced motion
- Under
prefers-reduced-motion: reducethere is no continuous loop. The simulation runs a discrete settling burst and presents one composed frame; typing or scattering triggers another burst. The preference is watched live and the HUD reports static. - Measurement
- The single requestAnimationFrame loop calls the shared metrics collector once per rendered frame; the HUD owns no loop of its own. Its averaging and percentile windows are declared in
lib/perf/frame-metrics.ts, which every route in the lab shares, so they are not restated here. KB transfer sums real navigation and resource entries.