Skip to content

M4: SVG Options, area type and gradients in SVG export, ids and names, SVGZ (M4.26–M4.30) - #68

Merged
bflatastic merged 5 commits into
mainfrom
pr/m4-svg-export-options
Oct 5, 2026
Merged

bflatastic merged 5 commits into
mainfrom
pr/m4-svg-export-options

Conversation

@bflatastic

Copy link
Copy Markdown
Member

Part of M4 (Files). SVG export gets Illustrator's SVG Options, line-accurate area type, faithful gradients, ids and names that survive the round trip, and SVGZ in and out. This ports an earlier session's work onto current main and reconciles it with #10 and the M3 SVG export work.

  • M4.26: SVG Options in the engine, a dialog and MCP.
    • Where options go: document.export, serialize and save, and file.saveAs / file.saveCopy, take SVG options flat or as svg: {…}.
    • The options: styling (4 modes), outlineText, images (embed/link), objectIds (Layer Names / Minimal / Unique), decimals 1–7, minify, responsive, useArtboards, range: "all", preserveEditing and metadata.
    • Validation: junk options are rejected, and document.formats lists each option with its default.
    • Dialog: svgOptions (file.export.svg, and Save As / Save a Copy to .svg) has a code view and remembers the last choices. It starts with Internal CSS and Responsive on.
    • Model: ExportOptions gains Deserialize, an ObjectIds enum and ImageMode. New fields: DocState.save_options and UiState.svg_options.
    • Warnings: SVG warnings reach export results (Encoded carries warnings).
    • Linked images are named by their content key.
  • M4.27: area type and rich text in SVG export.
    • One <tspan> per laid-out line and style run (per word on justified lines), plus fewerTspans.
    • Combined with SVG export: area type keeps its wrapped lines and alignment #10: centred and right-aligned lines without tabs keep text-anchor.
    • Baseline shift is written as a relative dy; spaces where a line wraps are dropped.
  • M4.28: SVG gradient export fidelity.
    • Character gradients export as url(#…) over the layout bounds.
    • Identical gradients share one definition, and swatch names become ids.
    • Midpoints are written as data-vc-midpoint stops that come back on import (Gradient::expanded()).
  • M4.29: object ids and names survive the SVG round trip. Export writes data-name; import reads data-name, inkscape:label, serif:id and aria-label.
  • M4.30: SVGZ read and write.
    • svgz is a writable format and works through open, place, paste, save, export and Export for Screens.
    • Gzip moved from the engine into the svg crate (is_svgz, compress, text_of), and decompression stops at 512 MB.

docs/mcp.md and docs/control-protocol.md cover the options and the dialog. MCP's export format list gains svgz.

Checks

Rebased onto 2df7edd (#67). cargo xtask ci passes all 7 steps (fmt, clippy, test, assets, brands, layers, wasm): 2,015 tests, 0 failed.

  • Nothing dropped:
    • every test name on main still exists (1,981 → 2,012);
    • command ids, UI_COMMANDS, menu entries and MCP tools are kept (two UI commands and svgz added).
  • Changed tests, with reasons:
    • SVGZ is now writable: formats_query_lists_readers_writers_and_options, export_tool_lists_engine_formats_and_options, opens_every_readable_format.
    • object_ids is now an enum: prop_svg::all_options, options_decimals_minify_responsive_artboard, full_document_roundtrip_is_stable.
    • Names now come back exactly: groups_and_names_roundtrip.
    • styling_modes_roundtrip is extended to cover entities.
  • Dialog: covered by headless frame tests.

🤖 Generated with Claude Code

bflatastic and others added 5 commits October 5, 2026 07:55
document.export, serialize and save, and the Save As / Save a Copy UI
commands, take the SVG options flat or as svg: {…}: styling
(presentation, style, entities, css), outlineText, images (embed or
link; linked files are written next to the SVG), objectIds (layerNames,
minimal, unique), decimals 1–7, minify, responsive, useArtboards and
range "all" (one SVG per artboard), preserveEditing (the SVG reopens as
the full document) and metadata. Unknown keys are rejected and
document.formats lists every option with its default. Results carry the
SVG writer's warnings.

Save writes SVG to an .svg path and Save again reuses its options.
Export As SVG and Save As / Save a Copy to .svg open SVG Options (first
use: Internal CSS and Responsive, then the last-used choices) with a
read-only code view. Save a Copy no longer retargets the document.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every laid-out line of type is written at its own position (wraps,
indents, tabs, hyphenation and all caps as on the canvas): a positioned
tspan per style run and, on justified lines, per word. Centred and
right-aligned lines are anchored at their centre or right end, so they
stay aligned in a viewer whose font differs. Leading comes from the
layout's baselines, baseline shift is written as dy, horizontal scale as
textLength, vertical scale as the size, tracking and manual kerning as
letter-spacing. The fewerTspans option (engine and dialog) writes one
positioned tspan per line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Character gradients on live type export as url(#…) spanning the
laid-out text (point, area, on-path and outlined type, as on the
canvas); character stroke gradients span the text grown by half the
weight. Identical gradients share one def, and a swatch gradient takes
the swatch's name as its id. Midpoints are written as extra stops marked
data-vc-midpoint, which import turns back into midpoints.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Layer Names writes readable ids plus data-name with the original name
whenever the id differs; Minimal writes only the ids definitions need;
Unique prefixes every id and CSS class with a content hash, so SVGs
inlined in one page never collide. Import names objects and layers from
data-name, inkscape:label, serif:id or aria-label.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
svgz is a writable format with the SVG options (document.export,
serialize, save, Export for Screens): exactly the SVG export, gzipped.
SVGZ is recognised by its extension or the gzip magic bytes and opens,
places and pastes like SVG (clipboard.importSvg takes dataBase64 of SVG
or SVGZ); Export As SVG or Save As to a .svgz name writes it
compressed. Gzip lives in the svg crate (pure-Rust flate2, builds for
wasm) and unpacking stops at 512 MB.

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