@grida/svg-editor
A clean SVG editor — open a file, edit it, save it, and the diff is exactly the change you made. The demo below is the whole editor; the cards under it isolate one feature each. For the editor wired into a full product, see the editor seam demo.
selecttool: cursorselection: —This page is a harness, not just a gallery.
Each fixture below is paired with the interaction it is meant to exercise — line endpoints, path vertices, text runs, group scope, the CSS cascade. But the editor cannot yet be locked to that interaction: there is no capability profile, so every tool and command stays live in every card. The fixtures are written now so that fixture + behavior-constraint line up once that profile lands. See the directory README.md for the proposal and roadmap.
Fixtures
Each card mounts an isolated editor on a fixture that targets one interaction surface. Click an element to see its chrome; the relevant element is pre-selected where it helps.
Shapes — every primitive
rect, rounded rect, circle, ellipse, line, polyline, polygon, path — one of each. Every shape is its own Policy Class with distinct resize semantics.
Harness note — A future 'shapes only' profile would gate which primitives the insert tools can author and select.
Path — vector content edit
A single path (cubic + smooth-cubic segments), pre-selected. Press Enter or the lasso (Q) to drop into content-edit and reveal the vertex / tangent chrome.
Harness note — A 'path editing' profile would lock to content-edit on this node and suppress select-mode transforms.
Line — the 2-point exception
<line> has no bbox resize — it has exactly two endpoints. The pre-selected diagonal shows endpoint handles, not eight corner/edge handles.
Harness note — A 'line only' profile would constrain interaction to the two endpoints — the canonical fixture + constraint pairing.
Text & tspan
One <text> with multiple <tspan> runs and a second baseline via dy. Double-click to edit inline. Inline edit is single-flat-run today; tspan / multi-line is the open behavior this fixture probes.
Harness note — A 'text only' embed is exactly the kind of locked profile this harness wants and the package can't yet express.
Groups & transform
A rotated <g> nesting a translated one. The pre-selected group shows a rotation-aware bbox; Enter descends scope into the children.
Harness note — Profiles intersect with structure here: 'no structural edits' would keep selection + transform but disable group / ungroup / reorder.
Nested <svg> — a viewport within a viewport
An inner <svg> with its own x/y origin and its own viewBox establishes an independent user-space coordinate system (SVG 2 §7.2). The editor parses, preserves, and renders it; a node inside the inner viewport is pre-selected.
Harness note — Translating a node inside an inner viewport now projects the delta into that viewport's frame, so it moves correctly. Still open: getCTM stops at the nearest viewport, so HUD chrome for a node spanning the inner-viewport boundary is unresolved. See packages/grida-svg-editor/docs/geometry.md and the nested-svg notes in src/dom.ts.
Symbol & use — one source, many instances
A <symbol> defines the geometry once; each <use> instantiates it. The color on each instance flows into currentColor inside the symbol, so the shared pin recolors per instance. The big one is pre-selected — its chrome is the instance box, not the symbol.
Harness note — Editing a <use> is its own Policy Class: move / scale the instance vs. edit the shared symbol. How the editor surfaces that split — and per-instance paint overrides — is the open question. editor.defs.symbols is the registry.
CSS — cascade beyond color
A document <style> block drives fill and geometry (rotate, translate) — not just paint. Selection chrome reads world geometry, so CSS transforms are the open question this harness exists to settle.
Harness note — Not yet decided: how the editor cooperates with the cascade. This card is the surface for choosing the behavior, not a finished feature.