A century of lichens colonizing a granite boulder, as a time-lapse you can scrub.
Lichens spread from their margins at a nearly constant few millimeters a year, so every patch of rock belongs to whichever thallus reaches it first. A multi-source Dijkstra over a 16-neighbor stencil computes, in the background, the year each cell was colonized and by whom, which makes scrubbing through 140 years instant. Species differ only in their speed fields and layer: slow map lichens with black prothallus borders where neighbors meet, ring lichens whose centers die after a few decades, foliose sunburst and shield lichens whose speed varies with angle so the front breaks into lobes that can creep over crustose neighbors, and capped fruticose tufts drawn as little shrubs. The granite (feldspar, quartz and clustered biotite grains from domain-warped Worley noise, weathered toward grey with stains, faint algae, cracks, rain streaks and relief) and the lichens are shaded per pixel, with fruiting cups crowding the older centers.
Try it. Drag the timeline to scrub through the years, or press Space to play and pause. Pick a species from the chips (or press 1 to 5) and tap the rock to land a spore in the current year: the future is solved again with the newcomer. Press R for a new boulder.
Paste this into Claude Code, Codex or any coding agent to get a simple version running, then take it wherever you like.
Build a time-lapse of lichens colonizing a rock 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 stays sharp on high-DPI screens (scale by devicePixelRatio).
- Paint a granite texture into an ImageData on a grid at half the canvas resolution: for each pixel find the nearest of a set of jittered grid points (Worley noise), and give each grain a mineral color (off-white feldspar, pink feldspar, smoky grey quartz) plus a little random speckle and a few black flakes.
- Lichens grow outward at a steady rate, so treat the colony as a race: place 20 seeds with a species and a start year, then run Dijkstra's algorithm from all of them at once over the grid. The cost to enter a cell is one over that species' growth speed there. Record for every cell the year it was reached and which seed got there first; a cell that is already taken blocks the others.
- Draw a frame for any year by coloring the cells whose recorded year has passed with their species' color, and play the year forward with requestAnimationFrame.
Once that works, make it beautiful:
- Use 16 neighbors (including knight moves) in Dijkstra so the patches grow round instead of octagonal, and multiply each species' speed by smooth noise so the edges are irregular.
- For a leafy species, multiply the speed by 1 + 0.3 * sin(lobes * angle around its seed) so the front breaks into lobes.
- Draw a thin black line where two crustose patches meet, like a real map lichen, and shade each patch by its age so young margins look thin.
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 draggable timeline to scrub through the years, ring lichens whose centers die back, or clicking to drop a new spore in the current year.