djEnterprises · The Lab
Classical music, played by a fluid simulation
Click anywhere to begin · drag the fluid while it plays
A real Navier–Stokes fluid on the GPU, choreographed note by note to a piano synthesized in this tab — over a live ten-body solar system.
Just for Fun · djEnterprises
A fluid simulation and a classical performance, both generated in this browser tab, wired to the same clock — over a live model of the solar system. Nothing here is pre-rendered: no audio files, no video, no libraries, and no fonts fetched at runtime. The only image the page loads is the djEnterprises mark.
Ten scores — seven from the public-domain canon, three djEnterprises originals — played on a piano that is synthesized from scratch every time you press play — a fundamental plus four slightly sharp partials, each dying faster than the one below it, a hammer thud on the attack, and a small synthesized hall around it. The left hand plays the harmony: a rolled broken chord under Für Elise, hymn blocks under the Ode, bass octaves under the Presto.
Sound: EDM remix is the other reading of the same scores — the same notes over a four-on-the-floor kick, offbeat saw bass, detuned-saw lead, hats, claps and sidechain ducking. Switch any time with the Sound button, or press S.
The three figuration tracks (Bach, the Moonlight Presto, Trepak) are engines playing each piece's characteristic pattern over its harmony, not transcriptions of the printed score. The others carry the actual theme. Everything here is public domain, or ours.
Each score loops a 32-bar shape that gets read twice over: as dynamics on the piano (piano → mezzo forte → pianissimo → forte) and as an arrangement in the remix (filtered intro → drop → breakdown → second drop). The choreography thins out and swells along with it either way.
The classic stable fluids method (Jos Stam, 1999) running on the GPU: semi-Lagrangian advection, vorticity confinement, a 20-iteration Jacobi pressure solve, then gradient subtraction for a divergence-free velocity field. Half-float double-buffered framebuffers, a 144² velocity grid and a 720² dye grid, with a soft tone curve and vignette in the display pass. It is an actual incompressible fluid, not a particle effect.
Those orbits behind the dye are not decoration: that is the SolarEclipse engine — the same ten-body Newtonian integrator from the other experiment in this lab, with real initial conditions and a real running date (bottom-left). The sun blooms on every beat.
Zoom it with the slider, a two-finger pinch on the stage, the scroll wheel, or −/+ — from inside Venus's orbit out past Neptune. Drive the planets from a quarter speed to eight times with [ and ], and put names on them with N. Zooming redraws the orbit rings by fast-forwarding the integrator, so a wide view really is thirty years of Newtonian motion.
The audio scheduler stamps every sound with an AudioContext time roughly 150 ms before it sounds. Each frame the render loop consumes whatever has come due and throws dye and force into the field: every left-hand bass note (or, in the remix, every kick) punches twin jets up from the floor, claps shear in from the walls, hats sparkle at the ceiling, and every melody note lands at an x position mapped from its pitch — so the right hand plays the screen like a keyboard. The audio clock is the only clock; nothing musical is timed off performance.now().
Five palettes — Nocturne (the original), Aurora, Ember, Mono ink and Neon — and they rotate on their own every five seconds, each one changing hue mapping, force and how long the dye lingers. Press 1–5 to pin the one you like; the Look button hands the palette back to the rotation.
Everything runs on your device. Nothing you do here is uploaded, and the page makes no network calls of its own — the only third-party request is djEnterprises' cookie-free analytics. Recording uses your browser's built-in WebM encoder and saves straight to your downloads; muting silences the recording too. The app needs WebGL and the Web Audio API, and it honors prefers-reduced-motion by cutting splat forces to 40% and switching the beat-brightness pulse off. On phones and low-core machines the dye grid starts one rung lower, and it drops again if frame times slip.
Share a setup by copying the URL — the current score and look ride along in the address bar.
This experiment needs WebGL.
Your browser or device isn't giving the page a WebGL context, so the fluid can't run. Try a current version of Chrome, Safari, Firefox or Edge with hardware acceleration on — or head back to the rest of the lab.