flux.
Thousands of particles drifting through a noise-driven vector field you sculpt in real time with the cursor. Runs entirely in the browser with no build step and zero dependencies.

flux is a generative flow-field studio that runs entirely in the browser with no build step and no dependencies. Thousands of particles are advected through a seedable 3D Perlin noise field that you sculpt in real time with the cursor, then rendered as glowing neon trails on a single 2D canvas. The whole thing is roughly 1.2k lines of dependency-free vanilla JavaScript, HTML and CSS, wired together as plain IIFE modules.
The core is a fixed particle pool advected through a vector field. Each frame every particle samples the field at its position to get an acceleration, integrates velocity with damping and a speed cap, and draws a single line segment from its old position to its new one. A low-alpha background repaint each frame fades older segments into long flowing trails, and particle color is mapped to instantaneous speed through a precomputed 256-entry palette ramp, so the field reads as a velocity map rather than a flat cloud.
The field itself is a self-contained 3D Perlin noise implementation seeded by a mulberry32 PRNG, with time fed into the z axis so the field evolves smoothly instead of looping. Six interchangeable field generators (flow, vortex, gravity, magnetic, ripple, spiral) each return an acceleration for a given particle, and the cursor injects a radial force within an adjustable influence radius whose polarity flips between attract and repel on click. Because the noise is seedable, reseeding is deterministic and shareable.
Rendering leans on the 2D canvas additive composite mode (globalCompositeOperation 'lighter') for an optional bloom that makes overlapping particles glow like neon, with device-pixel-ratio scaling capped at 2 to stay sharp without melting fill rate. The architecture is deliberately framework-free: a single live state object in main.js is the only source of truth, the UI mutates it directly, and the render loop reads it every frame, so there is no diffing, no reconciliation, and no bundler.
Around the simulation sits a surprisingly complete feature set built on raw browser APIs. Full configuration is serialized to base64 and encoded into the URL hash for shareable permalinks, with the last session mirrored to localStorage; live canvas capture to a downloadable .webm clip uses MediaRecorder over canvas.captureStream; and an optional audio-reactive mode pulls microphone input through the Web Audio AnalyserNode to drive the field's energy. A kiosk URL flag strips the HUD and starts auto-pilot for a full-bleed ambient display.