Notes on the making of a gallery that repaints itself.
Concept
Most galleries protect paintings from change. STRATA does the opposite: the artwork exists only as a seed — a single 32-bit integer — and the painting is re-performed from it on every visit. The plaque is honest. Edition No. 4821-C is not a picture of anything stored anywhere; it is what the mathematics does when asked politely, twice the same way.
Technique
The seed feeds mulberry32, a tiny hand-rolled PRNG, which shuffles a permutation table for seeded 2D value noise. Summed over octaves (fBm) and scaled, the noise becomes a direction field: sample any point, receive an angle. A few thousand particles are advected through it — ask, step, ask again — each leaving a low-alpha stroke on a Canvas 2D surface that is never cleared, so pigment accumulates like sediment. Color is assigned at birth from a second, coarser noise read, which is why each palette settles into geological bands rather than confetti.
Performance is mostly one trick: strokes are batched by ink and width into single beginPath() calls, so a frame costs about eighteen stroke() calls instead of thousands. Development front-loads nine simulation substeps per frame and eases down to one; after the label flips to "on view," the field offsets drift almost imperceptibly so the surface never fully dies. devicePixelRatio is capped at 2, and the whole loop halts on document.hidden.
The lighting is CSS: radial-gradient spotlight cones that breathe on an 9-second cycle, an SVG feTurbulence grain overlay, and a cursor lamp — a soft radial gradient in mix-blend-mode: screen that brightens whatever it crosses. The process diagram is live, not looped video: 117 SVG arrows re-aimed every frame by the same fBm function that paints Room I. Under prefers-reduced-motion, paintings fast-forward to their finished state in chunked frames and every ambient animation stands down.
Iteration passes
Pass one built the engine and hung the show, then a review — done the way the audience actually sees it, screenshots at 1440×900 and 390×844 plus a delayed frame to prove the ambient motion reads — caught a header that ghosted over scrolled content and a mobile layout that buried the painting under paragraphs of wall text. Pass two drove the live page with a pointer instead of trusting the code: it gave the hero frame a cursor-tilt so the commission reads as a hung object, kept Room II's six canvases breathing instead of freezing solid, and caught a real bug where the wall's next-arrow was clicking straight past every painting to the end. Pass three did the unglamorous work — contrast-checked every shade of ink against gallery black, gave the standing collection's prev/next buttons a disabled state at each true edge, and named this file's rule out loud: fix what the photograph and the screen reader both show, not what the code intends.