Even with the HUD from T1, the tree itself was 57 wordless icons: no way to
answer "does he know NestJS?" without clicking around.
Search palette (Cmd/Ctrl-K):
- New utils/search.ts — pure, 9 unit tests. Subsequence matching on short
fields ("wbrtc" finds WebRTC), plus tech-stack and company matching so
"Prisma" surfaces the projects using it and "Peraton" finds the role.
- Descriptions deliberately use substring, NOT subsequence matching. Over
long prose a subsequence match is almost always spurious — the first
version matched "Prisma" as p...r...i...s...m...a spread across an
unrelated sentence, which a test caught.
- Selecting a result flies the camera to that node and opens its modal.
- Built to the ARIA combobox pattern: input keeps focus and owns
aria-activedescendant, results are a listbox. Options intentionally have no
keyboard handler — making them focusable would break the pattern — so the
svelte-ignore there is documented rather than incidental.
On-canvas labels:
- A Text per node, hidden below LABEL_ZOOM_THRESHOLD and counter-scaled by
1/zoom so they stay a constant size on screen rather than ballooning.
- Threshold sits just above the settled desktop zoom, so the default view
stays a clean constellation and zooming in reveals labels. 'L' forces them
on at any zoom.
- Long labels truncate at 18 chars; full text is still in the tooltip/modal.
- Collision culling: labels are placed biggest-node-first, and any whose box
would overlap an already-placed label or someone else's node is dropped.
Dense clusters simply show fewer labels until you zoom further in. This is
purely presentational — no node coordinates changed.
Three bugs found during review:
- The entrance zoom tween only called updateParallax, so the label
counter-scale stayed frozen at its pre-zoom value (labels ended up at 1/4
size and effectively vanished). It now updates labels too, as does the
skip/reduced-motion path that sets scale directly.
- updateLabels forced alpha = 1, so labels appeared over nodes that had not
faded in yet — visible during the splash screen. Alpha now belongs to the
entrance and labels arrive with their node.
- animation.ts imported updateParallax only; it needed updateLabels as well.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>