Liesegang precipitation grows the concentric bands of a polished agate slab.
An outer electrolyte seeps into a gel-filled cavity in volcanic rock and reacts with an inner one; the product precipitates when it crosses a nucleation threshold, and each new band soaks up product around it, so bands appear rhythmically with spacing that grows geometrically (the Jablczynski law, shown live as the spacing ratio). Because the ions come from the wall, the reaction-diffusion-precipitation equations are solved along the exact Euclidean distance from the noisy cavity wall, with each level set's length as the geometric factor, which keeps every band a sharp continuous ring that follows each bump and folds into fortification angles at cusps. Every band that nucleates starts a new chalcedony layer colored from one agate family, the precipitate darkens into iron-oxide lines, and whatever the front has not reached when the run ends crystallizes into druzy quartz.
Try it. Click for a new geode from one of six agate families. Drag the diffusion slider from fine onyx lines to bold, widely spaced bands and the threshold slider to change how readily bands nucleate (arrow keys work too), and drag across the slab to move the polishing light.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Grow the bands of a polished agate with JavaScript and the HTML canvas element, using Liesegang precipitation chemistry. Put everything in a single index.html file with no libraries or build step, so I can open it directly in a browser.
Start simple:
- Make a canvas that fills the window, stays sharp on high-DPI screens (scale by devicePixelRatio), and resizes with the window. Paint it near black.
- Solve the chemistry in one dimension first: 200 cells along the depth from a wall. Keep four arrays: a (outer ions), b (inner ions), c (dissolved product), d (precipitate). Start with b = 1 everywhere, hold a = 10 at the wall, and each step (dt = 0.2): diffuse a with D = 1, b with D = 0.05 and c with D = 0.5; react r = 0.3 a b, removing r from a and b and adding it to c; where c is above a threshold of 0.4, move c into d at rate c; where d already exists, move (c - 0.05) times 10 d into d.
- Plot d as a strip and watch bands appear with growing gaps.
Once that works, make it beautiful:
- Draw a lumpy cavity from a few overlapping circles plus noise, compute each pixel's distance to the wall, and color it by the 1D solution at that depth, so the bands follow the wall like real agate.
- Give each band its own color from a carnelian palette, darken the precipitate into thin iron lines, and fill whatever the front never reached with grey crystal facets.
- Animate the front moving inward, and add sliders for the product diffusion and the threshold.
Explain the key ideas in short code comments. When you're done, tell me how to open it and suggest three directions I could take it next, such as more agate color families, a moving polish highlight on the slab, or measuring the band spacing ratio to check the Jablczynski law.