Skip to content

M4: SVG symbols as <symbol>/<use>, hidden layers, metadata; Preserve Editing round trip (M4.39, M4.40) - #72

Merged
bflatastic merged 2 commits into
mainfrom
pr/m4-svg-symbols-editing
Oct 5, 2026
Merged

bflatastic merged 2 commits into
mainfrom
pr/m4-svg-symbols-editing

Conversation

@bflatastic

Copy link
Copy Markdown
Member

Part of M4 (Files). SVG export writes symbols as <symbol>/<use>, keeps hidden layers on Save and carries Dublin Core metadata. SVGs saved with Preserve Editing reopen exactly, or as plain SVG once another app has edited them.

  • M4.39: symbols, hidden layers, metadata.
    • Symbols: each symbol is written once as <symbol overflow="visible">, and each instance as a <use>.
      • Some instances can't share the definition without looking different from the canvas, so they are written as their own art:
        • instances stained by their fill;
        • scaled instances of symbols with strokes;
        • rotated or scaled instances of symbols with effects, brushes or live objects;
        • instances of symbols with pattern paints or unlinked masks.
      • Instances written as art are stained as on the canvas, and keep their patterns and masks on the page.
      • A symbol that contains itself stops at depth 8 instead of recursing forever.
      • The stain helper moves to vectorcraft_brush::{stain, instance_art}, shared with the renderer.
    • Hidden layers: a new SVG option hiddenLayers (listed in document.formats). Save, Save As and Save a Copy turn it on; exports leave hidden layers out. On import, a display:none group with an id comes back as a hidden layer or group.
    • Metadata: written through one Dublin Core list (dublin_core()), currently the format and title. File Info will fill in the other fields.
  • M4.40: Preserve Editing round trip.
    • What is stored: the native document goes inside <metadata> as CDATA, with a hash of the SVG markup around it. Re-indenting and line-ending changes don't change the hash.
    • On open: document.open restores the document exactly when the hash matches. Older SVGs without a hash are trusted, as before.
    • Edited elsewhere: an SVG another app edited, or one whose editing data is damaged, opens as plain SVG and says why in warnings (EDITING_STALE, EDITING_DAMAGED).
    • API: new vectorcraft_svg::editing().

docs/mcp.md covers the option and the round trip.

Known limits (these problems predate this PR):

  • The canvas doesn't draw opacity masks inside symbol art.
  • Live geometry effects inside symbol art aren't written to SVG or PDF.
  • Pattern paints on type inside symbols aren't pinned to the page.

Checks

Rebased onto 4cccbc2 (#71). cargo xtask ci passes all 7 steps (fmt, clippy, test, assets, brands, layers, wasm): 2,091 tests, 0 failed.

  • Nothing dropped:
    • every test name on main still exists (2,074 → 2,088), and no existing test changed;
    • command ids, UI_COMMANDS, menu entries and MCP tools are unchanged.
  • New tests:
    • <symbol>/<use> output and the cases written as art;
    • link mode writes no data: URLs;
    • hidden layers on Save and on import;
    • a live effect, a symbol and a pattern reopen exactly;
    • an externally edited file falls back to plain SVG;
    • the import fuzz test also mutates saved SVGs.

🤖 Generated with Claude Code

bflatastic and others added 2 commits October 5, 2026 09:03
…ore metadata

Symbol instances export as one <symbol> def per symbol and a <use> per
instance. An instance the def can't stand for exactly (stained by its fill,
or a transform under which the canvas paints differently: scaling with
strokes, effects or live objects, turning with effects or brushes, any move
with pattern paints or unlinked masks) is written as its own art, now
stained like the canvas and with its patterns and unlinked masks left on
the page. Symbols nested in themselves stop at a fixed depth.

New SVG option hiddenLayers keeps hidden layers as display:none groups;
document.save (and Save As / Save a Copy) turns it on unless told
otherwise, exports leave hidden layers out. Import shows display:none
layer groups to usvg and marks them hidden, so they reopen hidden
(groups a <use> refers to stay templates). File Info metadata goes through
one Dublin Core list. The symbol stain helper moves to vectorcraft-brush
so the renderer and the SVG writer share it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ted elsewhere

The editing data now sits in CDATA inside <metadata> with a hash of the
markup around that element (whitespace between tags and line endings
don't count). document.open restores the native document when the hash
matches (data written without a hash is trusted as before); when another
app changed the SVG, or the data can't be read, it imports the SVG and
says why in its warnings. vectorcraft_svg::editing reports the data and
whether it is intact; editing_data stays. Live effects, symbols and
patterns come back exactly; the import fuzz test now mutates saved SVGs
with editing data and hidden layers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant