A third row in open_subpaths.svg: a filled and stroked path that is only
0.001 short stays one layer, and an open triangle with
paint-order="stroke" puts its stroke layer under its fill layer.
SVG fills every subpath as if it were closed; the import filled only
subpaths that close themselves (a z, or an end within 1e-6 of the
start). Logos exported from PDF round relative coordinates to three
decimals, so their outlines end about 0.001 short of where they started
and most of their letters came in empty.
A filled path now has its open subpaths closed before it becomes a
vector network: an end within 1/1000 of the path's size snaps onto the
start, any other open subpath of two or more segments gets a closing
segment. Stroke-only paths are unchanged. A filled and stroked path
with a really open subpath becomes a fill layer (closed) under a stroke
layer (open), so the stroke stays open as SVG draws it.
SVG import comes in editable and looking right: groups named from their
ids with transforms baked into the layers (rotated, scaled and skewed
groups, viewBox scaling and <use> offsets used to be lost); rectangles,
ellipses and lines recognised and kept as those shapes; gradients with
exact handles, reflect/repeat and focal points; patterns as image fills;
clip paths and masks as vector, luminance and alpha masks; shadow and
blur filter chains as drop shadows, inner shadows and layer blurs; blend
modes; text as text layers (it used to vanish); images and nested SVG
images. What can't be represented is reported as import warnings
(file.import / file.open warnings, figcraft-cli info notes). Linked
files are never read, and documents nested too deep for the parser are
refused instead of crashing.
Pasted SVG is recognised after XML declarations, comments and doctypes
and lands centred in the view (file.import center). SVG export writes
vector masks as clip paths and alpha/luminance masks as the mask layer
drawn, so masks survive a round trip.
Tests: a corpus of 21 synthetic SVG files with hand-worked expected
pixels (158 probes), structure checks and export round trips; unit tests
for shape recognition, paints, filters, structure, mask export; hostile
input and byte-mangled corpus fuzzing; engine file command tests.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>