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>
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
CustomPaintSVG 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.canvasschema; never an API to port.) - The card is two layers:
- SVG content — painted by the SVG renderer.
- 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 mode —
templatenames a component; clide lowers it to SVG (+ overlay anchors). - Primitive mode —
svg(inline) orsvgPath— arbitrary SVG, the escape hatch. One less invented format; external SVG / graphviz / mermaid render free. - Card size comes from the SVG
viewBox(orwidth/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), basicfill/stroke/stroke-width/opacity,rx/rycorners- 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 boxdata-description→ secondary caption linedata-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.show —
never a blank card.
Build sequence (D-103)
- T-320 — the SVG renderer (engine): parse + paint the bounded SVG subset.
- T-318 — envelope + template dispatch + the Flutter overlay (
data-*→ captions / lightbox) on top of the renderer. - 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
d2binary as a pql-style supporter tool, vs. vendor. - Graph (T-321): gated on the native graph subsystem (D-46 / T-323).