The forest replaces the graph
The author brought a working prototype from claude.ai: a single-file Three.js
page that draws a vault as a forest, with a spec and a decision log. The task
was to make it the site’s graph. Built on the branch forest-graph and merged
to master through PR #1 on 2026-10-19, with a feedback round still to come;
see forest.md for how it works now.
Decisions taken with the author
| Question | Decision |
|---|---|
| The vault’s ladder has four stages, the prototype had three | Potted is its own stage. The author updated the prototype and the docs during the session: a young tree on a nurse log, stump or boulder. |
| Where the forest goes | Both places: a live sidebar view centred on the current note, and the full explorer behind the expand button. |
| How the layout state is kept | Committed at the repo root and refreshed with npm run garden before each push. The deploy setup stays as it is. |
Taken without asking, because the facts settled them:
- The exporter is a Quartz emitter, not a vault parser. Working on the filtered content makes “published only” structural rather than a rule to remember.
- Links to unpublished notes are dropped, not shown as ghosts. The prototype turns every unresolved link into an unwritten seed. Here a link can be unresolved because its target is private, and a seed would advertise it.
- Dates come from frontmatter only. Filesystem dates are checkout times on Vercel.
How the work ran
Two agents built the exporter and the viewer in parallel worktrees against one
written contract for garden.json. Shared stage constants and the PRNG were
written first, so both sides used one copy. Then a review from four angles: the
layout engine, extraction and privacy, the viewer code, and the live site in a
browser. Each serious finding got an independent verifier. Two fix rounds and a
final check followed.
What the reviews caught
The defects worth remembering, because the design looked right on paper:
- A ghost could jump across the forest mid-season. Its grove followed a majority vote of linkers, so one new link flipped it. Ghosts now keep their id and grove within a season.
- An untagged note moved when it gained a link. Its footprint came from the inferred stage, which changes with links. The footprint now holds within a season.
- The forest never settled. On an unchanged vault it drifted about 3 units a year, and lag stayed near 0.25. The bridge pull acted as an external force on each grove. It now acts inside the grove.
- Local and Vercel builds gave different forests.
Math.sinandMath.cosdiffer in the last bit between Node 18 and Node 24, and the relaxation magnifies one bit. The layout now uses only exactly rounded arithmetic, and a golden hash test pins it. - The home note could not be opened from the forest. Its slug is the empty string, and the viewer tested slugs for truthiness.
- The sidebar often framed none of the current note’s neighbours. Real links run far across groves. The view now frames the nearest neighbours and puts markers at the edge for the rest.
What stayed open
- On an unchanged vault, lag stays bounded (0.05 to 0.14 on 2026-10-19) and the forest does not drift. But lag does not fall every season, and a few notes in the big Notes grove move 1 to 3 units a season. The cause is the local relaxation in the original force model, not the fixes.
- The overview reads more like a network of amber threads than a forest. The vault has hub notes whose links cross every grove. This is a look question for the author.
- Rename detection is not built. A renamed note is planted again.
- Two Quartz bugs that predate this work showed up in testing: the explorer script throws on folder and tag pages, and the theme toggle ignores its first click after an SPA navigation. Neither was touched.
Corrections
- The first exporter commit claimed that lag “settles at 0.05 to 0.09”. That held only for later seasons. The test that claimed settling was renamed to claim what holds: no drift, and bounded lag.