A sealed chamber of four thousand particles, every one launched at exactly the same speed. They do nothing but collide — and within seconds their speeds settle into the Maxwell–Boltzmann distribution, a lopsided bell that no rule imposed and chance alone assembled.
Kinetic is a fictional physics-demonstration cabinet for a museum of statistical mechanics. Its single job: prove that temperature is not a property you set but a shape that emerges. Start a gas with one speed — the least random state imaginable — and let equal-mass elastic collisions redistribute the energy. The distribution of speeds you cannot avoid reaching is Maxwell–Boltzmann, and the width of that bell is the temperature. The audience is anyone who has been told "heat is random motion" and wanted to watch the randomness organise itself.
Argued from the subject: a cold instrument chamber, with speed read as heat — slow particles cool blue, fast particles glowing orange.
The two accents are reserved for strokes, particles and the histogram bars. Body copy uses the derived glass-ink #D6DEE6 and its dimmer #A3AEBA so text always clears 4.5:1 on the chamber ground — the bright blue and orange never carry a sentence.
The display face — a precise, slightly mechanical grotesque that suits an instrument panel. The wordmark is filled with a blue→orange gradient so the title itself runs cold-to-hot: the colour argument stated in one word.
Every number, label and readout. A fixed-width mono keeps the live statistics — mean speed, most-likely speed, collisions per second — twitching in place instead of reflowing, the way a real gauge would.
three.js, one InstancedMesh of 4,000 spheres. Each particle carries position and velocity in flat typed arrays. Every frame the simulation integrates motion, reflects particles off the six chamber walls, then resolves collisions.
The collision solver is the heart of it. Checking all pairs would be sixteen million tests per frame; instead a uniform spatial-hash grid (a cell-linked list rebuilt each tick) means each particle only tests neighbours in its own and 13 forward cells. Two overlapping particles of equal mass exchange the velocity component along the line joining their centres — the exact elastic result, which conserves both momentum and kinetic energy. Because energy is conserved, the root-mean-square speed never changes; only its distribution does.
The signature is that distribution assembling itself. All particles begin at one speed — the histogram is a single spike. Collisions immediately start trading energy: a head-on pair can leave one particle nearly stopped and the other racing. Speeds fan out, and the count in each speed-bin climbs toward the analytic Maxwell–Boltzmann curve f(v) ∝ v²·e^(−v²/2a²), drawn live from the gas's own measured energy so the overlay always matches. Colour is mapped from speed through the same cold-blue→hot-orange ramp, so the chamber visibly warms at its edges as the fast tail grows.
At rest the gas is already thermalised: a headless warm-up runs ~200 collision ticks before the first frame, so the opening thumbnail shows the finished bell. The Reset · one speed button re-launches every particle at the identical speed and lets you watch the spread happen in real time. Guards throughout: DPR capped at 2, resize refits the camera and the histogram canvas, the loop pauses on document.hidden with a clamped delta on resume, a WebGL context-loss listener swaps in a static SVG bell, and prefers-reduced-motion renders one settled, thermalised frame with no rotation and no loop.
The first headless run surfaced two initialisation-order crashes — the scene-setup ran before the colour-ramp and camera constants existed — plus a collisions-per-second counter that read NaN on any frame that measured zero elapsed time (Infinity × 0). Restructured so all simulation state is declared before the warm-up runs, and guarded the rate against zero-dt frames. On the render itself: the speed→colour ramp saturated too early, so the whole gas read as one warm haze that hid the slow core. Pulled the ramp bounds outward so the bulk of the distribution sits cold blue and only the genuine fast tail glows orange. Demoted the promise line to mono so it stops competing with the wordmark for weight.
Made the analytic overlay honest: the Maxwell–Boltzmann curve is computed from the gas's own measured energy every frame rather than a fixed constant, so it tracks tiny fluctuations and the bars visibly breathe around it. Added the dashed most-probable-speed marker as a second-read detail — once thermalised it sits exactly under the histogram peak, at √2·a. Gave the whole chamber a near-imperceptible rotational drift so the box reads three-dimensional in a static thumbnail without distracting from the sorting. Tuned the warm-up tick count so the resting bell is crisp, not still-settling.
At 375px the histogram panel drops to a full-width dock at the bottom and the intro paragraph is hidden so the masthead never collides with it; headless probes confirm the nav and wordmark stay inside the viewport with a clean scroll width. Verified prefers-reduced-motion takes the no-loop path and still renders a fully thermalised chamber (identical successive frames, most-likely speed 2.45). Focus rings confirmed on the reset button and every link, DPR capped at 2, and the collision grid holds frame rate with 4,000 particles. Removed one ornament per the Chanel rule — the faint floor grid on the chamber's base face, invisible under the particle density and no longer earning its place. Final copy read for voice and specificity.