Fluid Figures
Taking an AI Studio particle demo that stopped at 9 and turning it into a meditative 10,000-particle countdown art piece.

Cool phase (10) — 10,000 instanced spheres in deep violet/cyan forming crisp extruded digits.


An AI Studio export with a particle physics engine that was genuinely good — 10,000 instanced spheres with spring forces and bloom — but stopped at "9" with no way forward. The recon revealed a solid foundation buried under fake AI, unused dependencies, and a dead-end UX. A late-night /grill-me session locked in the vision: strip everything, extend the countdown 10→0, add a convergence finale, and let it run as a meditative art piece with no UI.
The first build got the structure right but the physics wrong — weak springs and aggressive noise made the digits unreadable. A full physics rewrite (spring stiffness 0.05→0.12, noise amplitude 0.14→0.008, scatter transitions replaced with smoothstep morphing) made particles actually hold their shapes. Shipped at 2 AM with an evolving cool-to-hot color palette, slow camera drift, and a quiet "Again?" restart.
Timeline
Exported a particle countdown from AI Studio and it stopped at nine. Literally — the app generates 10,000 instanced spheres that form "10" with spring physics, you click "Next," they explode and reconverge into "9," and then… nothing. Next button disabled. Dead end. The "AI" text input that says "alter the physics" is three if/else statements matching hardcoded strings. No Gemini API is ever called. Six unused dependencies in package.json, including the Gemini SDK that never gets imported. Classic AI Studio export: visually impressive for 30 seconds, then you've seen everything. Ran a full recon — the particle physics engine is genuinely solid. 10,000 instanced spheres with per-frame spring forces, Perlin-ish noise displacement, friction damping, and mouse repulsion. Bloom post-processing from @react-three/postprocessing makes it glow. The foundation is worth building on. So I ran a /grill-me and locked in the design: strip the fake AI, strip the overlay, extend the countdown 10→0, add a convergence finale where everything collapses to a single bright point, add an evolving color palette from cool indigo to white-hot amber, add a slow camera drift, and let the whole thing run itself. No UI. No chrome. Just particles and time.
Built the full 10→0 countdown with morphing transitions and color evolution — and the digits were unreadable. Particles scattered into vague blobs within seconds of forming. The spring force (0.05) was too weak to hold shape against the noise displacement (amplitude 0.14 per frame). Transition explosions with scatter forces up to 35 launched particles off-screen, and the soft springs couldn't pull them back fast enough to reconverge before the next number. The finale stuttered — particles oscillated around origin instead of settling cleanly, and the CSS fade overlapped with the convergence, creating a jarring flash. Rewrote the physics from scratch. Thinned the strokes from 0.35 * S to 0.18 * S so particles actually trace digit shapes. Tripled the spring stiffness from 0.05 to 0.12 so particles hold formation. Dropped noise amplitude from 0.14 to the 0.008–0.033 range — breathing, not jittering. Killed the scatter/reconverge transition entirely and replaced it with direct smoothstep morphing between digit shapes. Shallow z-depth (0.15 instead of 0.5) keeps the 2D digit readable from the camera. 560 lines of single-file TypeScript, all per-frame CPU physics. Shipped the same night — two commits at 2:17 AM.
Before pushing Fluid Figures to GitHub, I ran a launch pass and found the entire 3D engine bundled into a single 1.17MB monster chunk. Vite threw chunk-size warnings because Three.js, @react-three/fiber, and @react-three/postprocessing were all lumped together with the simulation code. Added a manualChunks split in vite.config.ts targeting vendor-three — the app bundle instantly collapsed to 189.75KB (60KB gzip), leaving the 973KB Three.js runtime isolated in a vendor chunk that browsers can cache permanently. Wrapped the canvas in a <main> semantic landmark for accessibility, captured a 3.9MB demo GIF alongside two screenshots, wrote a 46-line README, and added the MIT license. Shipped 14 files and 3,334 lines across two clean commits at 2:17 AM. From a broken AI Studio zip that died at nine to a zero-chrome WebGL art piece live on GitHub in one evening.