A bristle-by-bristle ink brush paints bamboo on rice paper that wicks and bleeds.
The brush is a tuft of 72 simulated hairs that trails behind the hand and spreads with pressure, so a light touch draws a hairline from the long central hairs and a full press lays down the whole belly. Every hair carries its own ink and drags a track across the paper, marking only fibers that stand above a threshold that rises as it runs dry, which is how fast or long strokes break into the white streaks of dry brush. The paper is a mat of random fibers: wet ink wicks along them cell by cell in feathery fingers while the carbon lags behind the water and locks on as it soaks in. The autopilot paints bamboo the classic way, pale segmented stalks, dark nodes and twigs, and leaves that press in and lift to a point, then an enso that runs dry as it closes.
Try it. Drag to paint. Move slowly to press harder and quickly for a lighter, drier line (a pen's pressure is used directly). Pick dark, medium or pale ink with the chips or keys 1 to 3, change the brush size with [ and ], press C for new paper, and B to watch it paint again.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build an ink brush that paints like a Chinese or Japanese sumi brush, 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 paper grid with one cell per 1.5 pixels. Store ink density per cell in a Float32Array and give each cell a random "tooth" height between 0 and 1 (smoothed noise plus a few hundred random line segments as fibers).
- Model the brush as about 60 bristles. Give each one a fixed offset inside a teardrop: a distance back from the tip and a sideways offset, plus an ink load starting at 1.
- Each frame, work out where every bristle is: the tuft trails behind the direction the mouse is moving, and its length and width grow with pressure. Use the mouse speed for pressure (slow means a heavier press).
- For each bristle, walk the line from its previous position to its new one and add ink to the cells it crosses, using up a little of its load each time.
- Dry brush: a bristle only marks a cell when the cell's tooth is above a threshold that rises as the bristle's load drops. Long or fast strokes then break up into streaks.
- Draw the grid into an ImageData: warm off-white paper darkened by 1 - exp(-k * ink), then drawImage it to the screen.
Once that works, make it beautiful:
- Let central hairs touch first, so light pressure makes a hairline and full pressure a wide stroke, and taper the stroke when the mouse is released by letting the brush travel a little further while the pressure fades.
- Add wet ink: each mark also adds water, and water spreads to neighbor cells (faster along fibers) carrying some ink, so strokes bleed softly into the paper.
- Add dark, medium and pale ink buttons; pale ink carries more water and bleeds further.
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 an autopilot that paints bamboo leaves, pen pressure support, or a red seal stamp to sign the painting.