Drift Visualiser
Interactive mathematical visualisation built with Canvas 2D, adaptive quality controls, and real-time input mapping.
OVERVIEW
A client-side flow-field visualisation where thousands of particles are carried through a time-varying curl-noise landscape. The field is divergence-free by construction, so the motion reads as a fluid rather than as points on a vector grid: lanes braid, eddies form and dissolve, and nothing pools or vanishes. Five live controls reshape the field while it runs, the pointer bends flow locally, and a tap emits an impulse burst. There are no backend calls — the whole piece is deterministic math seeded from a number you can change and share.
ARCHITECTURE
The renderer is a Canvas 2D plugin registered against the shared generative-art runtime. Particle advection runs off the main thread in a dedicated worker that exchanges position buffers as transferable objects, so the simulation cost does not compete with paint. The plugin owns the curl-noise field, a fixed-modulus trail ring, depth layering and the bloom hotspot pass; the runtime owns the canvas, the animation loop, theme sync, a shared canvas budget and an adaptive quality controller. Trail history is written and read against a constant ring modulus so stored samples keep their temporal meaning while the display budget moves independently. A startup policy ramps particle count, trail depth and effects over the first seconds of life, and a scroll-pressure valve sheds work while the page is moving. Control state hydrates from the URL query string, then local storage, then defaults, and mirrors every change back to both. The surface mounts lazily behind a deferred-mount boundary with chunk-load retry, and an error boundary degrades it to a static frame rather than a blank canvas.
SYSTEM ARCHITECTURE
┌────────────────────────────────────────────────────────────────────────────┐
│ SLIDERS · PRESETS · POINTER · TAP IMPULSE · SCROLL · REDUCED MOTION │
└────────────────────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────────────────┐
│ GENERATIVE-ART RUNTIME (canvas 2D plugin) │
├────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ CONTROL + INPUT STATE │ │
│ │ Clamped params · presets · normalised pointer / scroll │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ CURL-NOISE ADVECTION (worker) │ │
│ │ Divergence-free field · fBm octaves · transferable buffers │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ TRAIL RING + LAYER COMPOSITE │ │
│ │ Fixed-modulus history · depth layers · bloom hotspot pass │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────┐ │
│ │ ADAPTIVE QUALITY GOVERNOR │ │
│ │ Startup ramp · particle budget · stride · scroll relief │ │
│ └────────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────────────────┐
│ ANIMATED FLOW SCULPTURE + SHAREABLE LINK + PNG EXPORT │
└────────────────────────────────────────────────────────────────────────────┘FUNCTIONALITY
FLOW FIELD
- Divergence-free curl noise, so particles are carried like a fluid instead of drifting down a gradient
- Layered fractal octaves that add finer structure without breaking the field's large-scale coherence
- Continuous time progression through the noise volume, so the field evolves rather than looping
- A deterministic seed that reproduces an exact field from a number
LIVE CONTROLS
- Five sliders mapped onto the field itself: Turbulence, Speed, Density, Complexity and Seed
- Balanced, Calm and Wild presets that jump straight to characterised parameter sets
- Pointer movement bends local flow, and a tap emits an impulse burst into the field
- Pause, reset, a copyable share link, and PNG export of the current frame
RENDERING
- Depth-layered strokes with per-layer alpha and width, drawn through a batching pass
- A bloom hotspot pass rendered on a reduced-scale offscreen surface to keep fill cost bounded
- Theme-reactive palette switching driven by the root class and palette mutations
- A fixed-modulus trail ring, so history stays temporally coherent while the visible trail budget moves
PERFORMANCE & RESILIENCE
- Particle advection offloaded to a worker with transferable buffers, keeping simulation off the paint path
- A startup ramp that raises particle count, trail depth and effects gradually instead of at once
- Scroll-pressure relief and an adaptive stride that shed work while the page is in motion
- Reduced-motion damping and a shared canvas budget that caps concurrent heavy animations
- Lazy mount with chunk-load retry and an error boundary that falls back to a static frame
HOW IT WORKS
On mount the runtime sizes a canvas to its container and the device pixel ratio, then seeds a particle field scaled to the viewport area. Each frame the worker samples a curl-noise field — the curl of a fractal potential, which is divergence-free by construction — and advects every particle along it, returning positions as transferable buffers so the main thread never blocks on the simulation. The plugin appends each position into a trail ring written against a constant modulus, so a slot always means the same number of frames ago even as the visible trail budget changes. Points are grouped into depth layers, stroked with per-layer alpha and width, and a reduced-scale offscreen surface accumulates the glow hotspots before compositing. Pointer position bends the local field and a tap injects an impulse; scroll drives the rate at which the field advances through its noise volume. A startup policy holds particle count, trail depth and effects below their targets for the first seconds and lifts them gradually, while a frame-time monitor and a scroll-pressure valve shed work when the page is moving. Every control change is clamped, written into both the URL and local storage, and applied on the next frame without restarting the simulation.
STEP-BY-STEP GUIDE
- Open the Drift tab and let the field settle into its braided lanes.
- Drag Turbulence to move the field from smooth laminar drift into chaotic eddies.
- Raise Complexity to layer more fractal octaves into the flow, and Density to add particles and glow.
- Move the pointer across the canvas to bend local flow, then tap to emit an impulse burst.
- Try the Balanced, Calm and Wild presets to jump between characterised parameter sets.
- Change the Seed to regenerate a completely different field from the same settings.
- Copy the link to share the exact configuration, or save a PNG of the current frame.
OUTCOMES
- Gives visitors a tactile flow-field artwork they can steer directly with pointer and scroll.
- Turns abstract noise fields into visible motion, making mathematical behaviour easy to feel.
- Adds an interactive break in the portfolio without asking the visitor to configure anything.
- Adapts to the current theme and viewport so the piece feels integrated with the page.