Pigment rides a shallow-water layer, pools at the edges and granulates on paper.
A grid simulation in the spirit of Curtis et al.'s 'Computer-Generated Watercolor'. Water sits inside a wet mask and flows between neighbors through virtual pipes driven by surface height, carrying suspended pigment that settles into the paper's valleys (granulation) and dries where it lands. Evaporation is fastest at the rim of a wash, so water keeps flowing outward and leaves the dark edges of real watercolor, while a capillary layer wicks moisture through the fibers so damp areas creep and bloom. Every cell mixes its pigments with Kubelka-Munk absorption and scattering coefficients and composites the glaze over procedurally generated cold-press paper.
Try it. Drag to paint with the selected pigment. Pick pigments and brushes from the tray or with keys 1-8, W (wet), B (dry brush), C (clear water), T (blot with a tissue), D (hair dryer), N (new sheet), [ and ] (brush size), and A (autopilot). Right-click or Shift-drag drops clear water into a wash for a bloom.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build a small watercolor simulator with JavaScript and the HTML canvas element. 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 and a simulation grid about 200 cells wide (each cell a few pixels). Keep per-cell data in Float32Arrays: water depth, a wet flag, and suspended and deposited pigment for each of three pigments.
- Generate a paper height map once: random noise blurred at a few scales and summed, so the paper has a cold-press tooth.
- Painting: while the mouse is down, mark cells under a round brush as wet, raise their water depth, and add suspended pigment of the selected color.
- Each frame, let water flow between neighboring wet cells in proportion to the difference in their water level (plus a little of the paper height), never onto dry cells. Move suspended pigment along with the water.
- Let suspended pigment settle into the deposited layer slowly, faster where the paper is low (that is granulation). Evaporate water every frame; when a cell runs dry, everything still suspended deposits there.
- Draw each cell by putting the deposited plus suspended pigment over a warm paper white into an ImageData at grid resolution, then drawImage it scaled up with smoothing.
Once that works, make it beautiful:
- Evaporate faster near the rim of a wet area (blur the wet mask to find it). Water flows outward to replace it and carries pigment, which gives real watercolor's dark edges.
- Mix colors with Kubelka-Munk: give each pigment absorption K and scattering S per RGB channel, add them up weighted by amount, compute the layer's reflectance and transmittance, and composite over the paper. Blue over yellow then makes green, like a real glaze.
- Add a clear water brush; dropping water into a half-dry wash should push pigment into a bloom.
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 a capillary layer so washes creep through the paper fibers, a dry brush that only catches the paper's peaks, or an autopilot that paints a landscape.