From 2edfb9088176258ab7468479811c28d8b326a9de Mon Sep 17 00:00:00 2001 From: Ivan Cheung Date: Tue, 23 Jun 2026 02:10:23 +0000 Subject: [PATCH] docs(sgcr): document octilinear/ring/annotations in the skill + README; plugin 0.12.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - diagram-recipes flow.md: agent-facing docs for engine:"sgcr" routing:"octilinear" and layout:"ring" modes, and the annotations overlay (anchors/layers/patch ops); corrected the by-construction list (arrowheads may now share a point; endpoints are strict on-edge). - sgcr/README.md: annotations (P10) section. - plugin 0.11.4 → 0.12.0 so the updated skill ships. --- .../src/client/renderers/sgcr/README.md | 12 ++++++++++ plugin/.claude-plugin/plugin.json | 2 +- plugin/skills/diagram-recipes/flow.md | 24 ++++++++++++++++--- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/packages/viewer/src/client/renderers/sgcr/README.md b/packages/viewer/src/client/renderers/sgcr/README.md index 980cb1c..6f4d89c 100644 --- a/packages/viewer/src/client/renderers/sgcr/README.md +++ b/packages/viewer/src/client/renderers/sgcr/README.md @@ -127,6 +127,18 @@ is what "diagonal" means. Pass via `SGCROptions` (`{ routing }`, `{ layout }`). incoming chords can stack arrowheads) the viewer runs `checkInvariants` and **falls back to layered** if the ring isn't clean. Output is reported as `routing: "octilinear"` (chords are diagonal). +## Annotations (overlay layer) + +`placeAnnotations(layout, annotations)` (`annotate.ts`) overlays callouts/badges/icons/notes on a +**frozen** layout — each anchored to a node, an edge midpoint, or a point — placed in the free space +the layout already reserves, reusing the checker's exact predicates so it's accepted only when clear of +every node/edge/label/other annotation, and **deferred** (signalled back) when there's no room rather +than stacked into clutter. Supports toggleable **layers**, **priority**, and compass **preference**. +The executable proof is **P10** (annotation-overlap), checked when `layout.annotations` is present. +Wired into the viewer: a `flow` spec carries `annotations: [...]`, rendered as a pan/zoom overlay with a +per-layer toggle; `addAnnotation`/`removeAnnotation` patch ops add them to a living diagram. See +`docs/superpowers/specs/2026-06-22-sgcr-annotations-design.md`. + ## Determinism & order-invariance - **Deterministic:** no RNG anywhere; all ordering uses stable sorts seeded by id; integer grid. Same input → byte-identical output (verified on 3000 graphs). diff --git a/plugin/.claude-plugin/plugin.json b/plugin/.claude-plugin/plugin.json index f86e8fe..6aec327 100644 --- a/plugin/.claude-plugin/plugin.json +++ b/plugin/.claude-plugin/plugin.json @@ -2,7 +2,7 @@ "name": "termchart", "displayName": "termchart", "description": "A live canvas your AI draws on. Instead of walls of text, your agent pushes rich, native visuals to a browser tab / iPad / second screen in real time — React Flow graphs (architecture, sequence, call-graph, ER/class, state machine, PR-review, journeys, recursion trees), Vega-Lite charts (incl. scientific + Big-O), Mantine UI dashboards & product comparisons, deep-code walkthroughs, markdown, and split panes — with animated edges and live status overlays (toasts, progress bars, loaders). Deterministic Mermaid→ASCII/Unicode is the terminal fallback. Ships persona recipes, a showcase gallery, fullscreen panes, and a collapsible sidebar. Adds /termchart commands + skills, backed by the termchart CLI.", - "version": "0.11.4", + "version": "0.12.0", "author": { "name": "Ivan Cheung" }, diff --git a/plugin/skills/diagram-recipes/flow.md b/plugin/skills/diagram-recipes/flow.md index 1d2bd8c..58be4e7 100644 --- a/plugin/skills/diagram-recipes/flow.md +++ b/plugin/skills/diagram-recipes/flow.md @@ -48,9 +48,11 @@ too-big graph never shrinks to an unreadable thumbnail — it opens at a readabl ### Layout engine — `engine:"sgcr"` (opt-in, ungrouped only) The default layout is dagre. Set `"engine": "sgcr"` on a `flow` spec to use the -**Slotted Grid + Orthogonal Channel Routing** engine, where node–node overlap, edges-over-nodes, -collinear-edge overlap, and arrowhead stacking are impossible *by construction* (see -`packages/viewer/src/client/renderers/sgcr/README.md`). **Scope today**: +**Slotted Grid + Orthogonal Channel Routing** engine, where node–node overlap, edge-over-node, +collinear-edge overlap, label-on-node, and off-/inside-node arrow endpoints are impossible *by +construction* and re-proved from the output geometry (P1–P10; see +`packages/viewer/src/client/renderers/sgcr/README.md`). Deterministic + order-invariant: same graph → +byte-identical layout. **Scope today**: - **Ungrouped graphs only.** If the spec uses `group` / `groups` / `lanes:true` / `tiers:true`, the viewer silently falls back to dagre — the push lint emits an `sgcr-skipped-grouped` warning @@ -59,6 +61,22 @@ collinear-edge overlap, and arrowhead stacking are impossible *by construction* on large graphs can exceed the screen. The lint emits an `sgcr-overflow` warning when that canvas would visibly spill the reference viewport — split into `panes` or trim nodes. +**Routing & layout modes** (opt-in, on the `flow` spec, with `engine:"sgcr"`): + +- **`"routing": "octilinear"`** — straighten orthogonal bends into clean diagonals (≈95% fewer bends). + Good for fan-out meshes (microservices, data lineage, neural nets). High-degree nodes pack their + edges to a shared point rather than ballooning the node. Still node-clear by construction. +- **`"layout": "ring"`** — draw a cycle as a loop (nodes on a circle) instead of a line with a + wrap-around back-edge. For state machines / lifecycles / process loops. Provably clean for simple + cycles; the viewer auto-falls-back to the layered layout for general cyclic graphs. + +**Annotations** (`"annotations": [...]`, SGCR only) — overlay callouts/badges/notes on toggleable +layers, placed in the diagram's free space, overlap-free (P10), deferred (not stacked) when there's no +room. Each: `{ id, anchor, text, layer?, color?, priority?, prefer? }` where `anchor` is +`{node:"id"}`, `{edge:"id"}` (give that edge an explicit `id`), or `{at:{x,y}}`. Use distinct `layer` +names (e.g. `"risk"`, `"latency"`, `"owner"`) — the viewer shows a per-layer toggle. Example: +`"annotations":[{"id":"r1","anchor":{"node":"pay"},"text":"SLO gate","layer":"risk"}]`. + ### `flow` (React Flow) `content` is `{ nodes:[{id,data:{label},type?}], edges:[{source,target,label?}], direction?, height?, legend? }`.