Ink drops, combs and styluses on a size bath, then a print pulled onto paper.
Every patch of ink is a closed polyline, and every gesture is an exact map of the plane from Jaffer and Lu's mathematical marbling: a drop pushes all earlier ink outward by p -> c + (p - c) * sqrt(1 + r^2/|p - c|^2), a comb shifts points along its travel by z * exp(-d/L) where d is the distance to the nearest tine, and circular strokes rotate by an amount that fades away from the stylus path. Because drops never overlap what they displace, painting the inks oldest first is always right. The maps are applied a little each frame as the comb sweeps, and the polylines are refined by mapping the exact midpoints of bending segments, so edges stay sharp however far the ink is stretched. The autopilot floats a stone pattern, combs it into arches, chevrons, bouquets or nonpareil, then lays a sheet on the bath and lifts a mirrored print.
Try it. Tap to drop the chosen ink (hold to let it spread wider) and drag to rake with a stylus, a hand comb or a swirl. The buttons run the classic patterns on the current bath; Pull print lays the paper down, and tapping the print starts a fresh bath. Keys: 1 to 6 pick an ink, S, C and W pick a tool, P pulls a print, N starts a new bath.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build a digital paper marbling toy 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.
The trick is to treat each blob of ink as a closed polygon and to move its points with exact formulas (from Jaffer and Lu's "Mathematical Marbling"), rather than simulating fluid.
Start simple:
- Make a canvas that fills the window, stays sharp on high-DPI screens, and has a warm cream background (the size bath).
- Keep an array of inks, each a color and a list of about 300 points on a circle.
- When I click, add a new drop at the click point with radius r. Before adding it, move every point p of every existing ink with p' = c + (p - c) * sqrt(1 + r^2 / |p - c|^2), where c is the click point. This pushes old ink outward into rings without ever overlapping the new drop.
- Draw the inks oldest first as filled polygons. Because drops never overlap what they push aside, this order is always correct.
- When I drag, apply a tine line: every point moves along the drag direction by z * exp(-d / L), where d is its distance to the line through the drag, z is the drag length and L is about 8 pixels.
Once that works, make it beautiful:
- Stretched polygons get jagged. After each move, wherever two neighbouring points end up far apart, insert new points by moving the original midpoint through the same formula (not by averaging the moved points).
- Add a comb: several parallel tines at once, using the distance to the nearest tine.
- Give it a palette of five classic marbling inks and a thin darker edge on each ink, plus a faint paper grain overlay.
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 circular swirl strokes, animating the comb so the pattern drags behind it, or a 'pull a print' button that shows the mirrored pattern on paper.