A pine grows for a century under a simulated climate, one sanded ring per year.
A climate model plays out wet and dry years (persistent noise plus a slow multi-decadal swing), insect outbreaks, windstorms and fires that come more often in dry years with more fuel built up. Each year the trunk adds a ring whose width follows the moisture and the tree's age, with pale earlywood darkening into latewood. A hot fire kills the cambium on one side: the face chars, woundwood lips roll in from both edges, and the healed catface leaves a charcoal pocket that the rings curl around. A storm tilts the tree, so later rings grow wider on one side, and branches leave knots that run out from the pith. Every ring is stored as radii per angle and the slice is rendered per pixel by binary search over the years, with rays, resin canals, heartwood and bark, re-rendering only the growing edge each frame.
Try it. Click a ring (or a year on the timeline) to read its year and what happened. Hover the slice for a magnifying loupe. Press Drought, Fire or Storm (or D, F, W) to force one next year, hold Fast or Space to fast-forward, and press R for a new tree.
Per-pixel rendering with binary search over ring radii
Climate-driven growth with fire scars and wound closure
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build a tree trunk cross-section that grows ring by ring under a simulated climate, 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, scales by devicePixelRatio and resizes with the window, on a dark slate background.
- Simulate a climate: each year a moisture value is 0.5 times last year's plus random noise. The ring width is a base width times exp(0.3 * moisture), times an age factor so young trees grow faster.
- Store each ring as an array of radii, one per angle (say 360 angles), so rings can be irregular. Add a little smooth noise per angle so the trunk is not a perfect circle.
- Draw the rings from the outside in as filled closed paths, alternating a pale earlywood color and a thin dark latewood band at the end of each ring. Add a new ring every half second.
- Under the slice, draw a timeline with one bar per year showing the moisture, so dry years line up with narrow rings.
Once that works, make it beautiful:
- Render the wood per pixel instead: for each pixel, find its angle and radius, binary search the ring arrays for the year it belongs to, and color it by its position inside the ring, with a sharp latewood edge and fine noise for the grain.
- Add bark outside the newest ring, a darker heartwood core, and a soft drop shadow so it looks like a sanded slice on a table.
- Let me click a ring to highlight it and show its year, and add buttons that force a drought next year.
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 fire scars that heal over, a leaning tree that grows eccentric rings, or a magnifying loupe that re-renders the wood at high resolution.