Files
clide/docs/design/drawing-card-schema.md
T
jpmschweitzerandClaude Opus 4.8 e2d9542fe8 docs(design): drawing-card wireframe set + SVG-substrate schema (T-317)
Seven Frame0 wireframes for the conversation drawing-card family — image
annotation, icon glyph, svg, d2, compare, graph, and the core dispatch
shell — plus the draft JSON schema refined from them. Schema follows the
SVG-substrate model (D-103): document envelope, bounded SVG subset, a
data-* Flutter overlay for captions/lightbox, templates lower to SVG.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 22:18:53 +02:00

4.9 KiB

Drawing-card JSON schema (T-317 / D-91 / D-103) — draft

Status: draft for build, SVG-substrate model (D-103), refined from the T-317 wireframe set, 2026-06-28.

Model — what this is, and what it is NOT

  • SVG is the substrate. The card's primitive / scene-graph layer is SVG; the clide-owned CustomPaint SVG renderer (T-320) is the engine the rest builds on (D-103).
  • It is not the HTML Canvas 2D API and not a third-party package. SVG is a document format we render ourselves — "own the rendering stack" holds. ("HTML <canvas>" in D-91 was only a mental model, chosen to reject Obsidian's .canvas schema; never an API to port.)
  • The card is two layers:
    1. SVG content — painted by the SVG renderer.
    2. A thin Flutter overlay — the clide chrome that is not content (per-object label/description captions, lightbox affordance), anchored to SVG elements via data-* attributes.
  • Display-only (D-78); re-rendered from the document. The graph template is the live-widget exception (below).

Document envelope

{
  "card":     { "label": "Build pipeline", "description": "…" },  // optional caption (overlay)
  "template": "icon",                                            // optional → template sugar
  "…template fields…": "…",
  "svg":      "<svg viewBox='0 0 480 360'>…</svg>"               // primitive mode = raw SVG
  // or "svgPath": "diagram.svg"
}
  • Template modetemplate names a component; clide lowers it to SVG (+ overlay anchors).
  • Primitive modesvg (inline) or svgPath — arbitrary SVG, the escape hatch. One less invented format; external SVG / graphviz / mermaid render free.
  • Card size comes from the SVG viewBox (or width/height); the painter scales to the pane width.

Primitive layer = a bounded SVG subset

The renderer supports the subset our templates + d2 / graphviz / mermaid emit — not a full SVG engine:

  • shapes: rect, line, polyline, polygon, circle, ellipse, path
  • text (incl. the bundled Phosphor font for glyphs)
  • image (href → resolved path; raster)
  • g + transform (translate / scale), basic fill / stroke / stroke-width / opacity, rx/ry corners
  • Out of scope unless a template needs it (decide then): filters, animations, rich gradients, foreignObject, scripting.

color everywhere is an arbitrary value (hex / named) — content, not a clide SurfaceTokens token (D-7 governs clide chrome, not rendered content).

Overlay (clide chrome, layered over the SVG)

Flutter widgets anchored to SVG elements that carry:

  • data-label → themed caption beneath the element's bounding box
  • data-description → secondary caption line
  • data-lightbox (on <image>) → click-to-zoom affordance

Templates emit these attributes; raw-SVG authors may add them. The icon template's data-label is also the bridge to the interaction-zone choice list.

Templates (lower to SVG + overlay)

template lowers to ticket
image <image href> + data-lightbox + caption attrs T-316
icon <text font=Phosphor> glyphs at 10,11,12,13,14,15,18,20,24,32,48 + hero 52; per-item data-label/data-description/color T-313
compare two+ <image> side by side in a <g>, per-image data-lightbox + captions T-319
svg identity — the source is the SVG T-320
d2 compile d2 → SVG → render T-494
graph exception — hosts the live native graph subsystem widget (D-46 / T-323), not static SVG T-321

CLI / transport (D-6 parity)

clide draw --file doc.json (or inline JSON). Flutter-free handler validates, publishes on a draw MessageBus channel; the Claude extension injects the card — mirroring image.show. The shipped image show (T-249/T-252) stays as convenience and migrates onto this card later (D-91). --stdin deferred (T-315); --file is the path.

Error contract

Unknown template, unparseable / unsupported SVG, bad href / glyph / color → honest IpcError (userError / notFound), surfaced like image.shownever a blank card.

Build sequence (D-103)

  1. T-320 — the SVG renderer (engine): parse + paint the bounded SVG subset.
  2. T-318 — envelope + template dispatch + the Flutter overlay (data-* → captions / lightbox) on top of the renderer.
  3. Templates: image / icon (T-316 / T-313) → compare (T-319) → d2 (T-494) → graph (T-321, after the graph subsystem T-323).

Open decisions (resolve before the relevant step)

  • SVG subset boundary (T-320): now the substrate — bound it to what our templates + d2 / graphviz emit; expand deliberately.
  • D2 compiler (T-494): shell out to a d2 binary as a pql-style supporter tool, vs. vendor.
  • Graph (T-321): gated on the native graph subsystem (D-46 / T-323).