The converged variant read as two arrows feeding one point; the two- complete-arrows variant as two arrows next to each other, not coherent. Owner withdrew the double-shaft idea entirely (2026-09-15); dashed was already rejected 2026-09-14. Both relation types draw the same plain single arrow again. Kept: CanvasEdge.type plumbing from the snapshot (the next differentiator will need it) and the ArrowGeom named type. Removed: followsEdgeGeometry, the gap constants, the zoom-drift edge-path rebuild (edges are back to a single loop in buildGeometry), the ⟹ legend entry, and the glyph tests. Vision doc records the withdrawal and keeps the still-valid constraints. Gates: tsc, 429/429 tests, lint, build. Live: canvas coverage 0.477, no console errors, no legend remnants.
46 lines
3.4 KiB
Markdown
46 lines
3.4 KiB
Markdown
# Vision — The edge glyph: follows vs supports
|
|
|
|
Ideation settled 2026-09-14. **WITHDRAWN 2026-09-15**: both shipped variants of
|
|
the double-shaft glyph (tails converging on a shared head; two complete arrows
|
|
offset ±half-gap) were rejected by the owner live — the first "two arrows
|
|
feeding one point", the second "two arrows next to each other, not coherent".
|
|
Dashed was already rejected 2026-09-14 (dash patterns crawl under the constant
|
|
screen-space stroke width). **The relation still needs a differentiator —
|
|
approach open.** The constraints below that are NOT glyph-specific still stand.
|
|
Companion: `vision.md` § "Edges" (the relation types) and § "Rendering".
|
|
|
|
One line (withdrawn): the two relation types become visually distinct —
|
|
**`follows` renders as a double-shaft arrow** (two parallel tails side by
|
|
side, the implication glyph ⟹), **`supports` stays a single line**. Arrows
|
|
keep their existing direction: prerequisite → dependent.
|
|
|
|
---
|
|
|
|
## Why double-shaft (DECIDED 2026-09-14)
|
|
|
|
- **Semantically exact.** `follows` means prerequisite ⇒ successor — derivability. The implication glyph *is* the relation; nothing encodes "derivable from" more literally.
|
|
- **Weight where the structure is.** The DAG backbone (`follows`) gets the heavy glyph; the majority relation (`supports` is over half of all edges) stays light. The structural skeleton reads first.
|
|
- **Shape survives everything color can't.** Cluster regions already own the color channel; a shape code collides with nothing and survives colorblindness.
|
|
- **Scale-stable.** Pure geometry degrades nowhere — see the rejected alternative below.
|
|
|
|
## Why not dashed (rejected 2026-09-14)
|
|
|
|
Dash patterns break under our **constant screen-space stroke width**: the dash array is re-projected across zoom levels, so the pattern pops and crawls instead of scaling cleanly (the same class of artifact as the non-integer blur radii). And with `supports` the *majority* relation, dashes would dominate the canvas rather than mark the exception. Dashed = wrong twice.
|
|
|
|
## Geometry
|
|
|
|
The renderer is the custom 2D canvas; edges draw in the edge layer with shafts + arrowheads from `arrowGeometry` (sigma-style head, prerequisite → dependent). For `follows`:
|
|
|
|
- Both shafts offset along the edge normal by a **fixed screen-space gap**.
|
|
- **REVISED 2026-09-15 (owner rejected the first cut):** the converged variant — two tails merging into one shared arrowhead — read as two arrows feeding a single point, not as parallel strokes. The glyph is two **complete regular arrows** (own shaft + own head each) translated ±half-gap along the normal: parallel shafts AND parallel heads, nothing converges.
|
|
- The gap is proportional to the constant stroke width — a constant visual ratio at every zoom level.
|
|
- **No LOD collapse (withdrawn 2026-09-14).** The earlier idea of collapsing to a single shaft below a stroke-width threshold assumed width shrinks with zoom — it doesn't; stroke width is constant on screen, so the double shaft renders identically at every zoom level. Simpler than proposed: nothing to gate.
|
|
|
|
## Legend and scope
|
|
|
|
- Add a legend entry to the existing graph legend: `⟹ follows · → supports`.
|
|
- Main graph view only. The plan-block renderer (dagre) is untouched — the plan DAG is single-relation, so there is nothing to distinguish there.
|
|
|
|
## Lane
|
|
|
|
lh-graph's renderer files (`graph-canvas.ts`, `graph-view.tsx`). Not assigned, not scheduled. |