PinePaper SVG Compatibility Guide

Reference for what survives an SVG ↔ PinePaper round-trip. Last verified against v0.5.0-beta.

TL;DR — round-trip score: 8/10

PinePaper imports SVG via Paper.js (project.importSVG) and exports via project.exportSVG. Static geometry, fills, strokes, and transforms round-trip reliably. Animations are emitted via the animated SVG (SMIL) export path, which is a separate flow from import. The combination is “good enough” for designers moving artwork between Illustrator/Inkscape/Figma and PinePaper.

Quick reference

Feature class Round-trip Notes
Path elements (<path>) ✅ Solid Bezier curves preserved exactly
Basic shapes (rect, circle, ellipse, line, polygon, polyline) ✅ Solid Expanded to paths on import
Group elements (<g>) ✅ Solid Nested groups preserved
Fill colors (hex, rgb, rgba) ✅ Solid
Stroke colors, widths, line caps, joins ✅ Solid Dash patterns also preserved
Transforms (translate, scale, rotate, matrix) ✅ Solid Baked into geometry on import
Opacity (opacity and fill-opacity) ✅ Solid
Text elements (<text>) ⚠️ Imports as PointText Font fallback to system; complex <tspan> may flatten
viewBox ⚠️ Read on import (v0.5+), not always re-emitted Stored in item.data.svgViewBox for future use
id attributes ⚠️ Root id captured (v0.5+); child ids may drop Stored in item.data.svgId
Image elements (<image> with href) ⚠️ Loads as raster Cross-origin URLs may fail
Linear/radial gradients ⚠️ Imported correctly, may flatten on re-export Paper.js gradient support is incomplete
Patterns (<pattern> fills) ❌ Drop to solid Not supported by Paper.js import
CSS classes / inline <style> blocks ❌ Drop Class-based styling not parsed
Filters (blur, drop-shadow, etc.) ❌ Drop SVG filter primitives not imported
Masks (<mask> and clip-path) ⚠️ Partial Simple cases work, complex masks fall through
SMIL animations (<animate>, <animateTransform>, <animateMotion>) ❌ Dropped on import But PinePaper CAN emit them on export via animated SVG path
Foreign objects (<foreignObject>) ❌ Drop HTML in SVG not supported
Symbol / use elements (<symbol> + <use>) ⚠️ May expand or drop Depends on Paper.js handling

What v0.5 added

The v0.5 SVG polish pass added metadata preservation to importSVG. When you import an SVG, the following metadata is now stored on the imported item’s data object:

item.data.svgId               // The SVG root <svg id="..."> attribute
item.data.svgViewBox          // The viewBox attribute, e.g. "0 0 200 100"
item.data.svgIntrinsicWidth   // The width attribute (may be "100", "100px", "100%")
item.data.svgIntrinsicHeight  // The height attribute
item.data.svgSource           // The original SVG markup (if < 64KB)

This metadata is available for inspection but not yet used by the export path. The plan for v0.6 is to use it to round-trip imported SVGs back through the export with their original viewBox and id intact.

What works exceptionally well

Path geometry

SVG path data — M, L, C, Q, A, Z commands — round-trips with exact bezier handle preservation. A complex illustration imported from Illustrator and re-exported should be visually identical.

Group hierarchy

Nested <g> elements preserve their structure. A group containing groups containing paths will have the same nesting after import.

Transforms

SVG transform attributes (translate(x, y), scale(s), rotate(deg, cx, cy), matrix(a, b, c, d, e, f)) are baked into the geometry on import — Paper.js applies the transform to the path coordinates so the resulting item is at the final position with no transform left to apply. This is lossless for visual geometry but loses the transform decomposition (you can’t separate the rotation from the translation post-import).

Fills and strokes

Solid colors, opacities, line widths, line caps, line joins, and dash patterns all round-trip cleanly via Paper.js’s native style handling.

Known limitations

CSS-styled SVGs

SVGs that rely on a <style> block or external CSS for styling will lose those styles on import. Workaround: use the SVG editor’s “convert styles to attributes” or “inline styles” option before exporting.

SMIL-animated SVGs

PinePaper does NOT import SMIL animations from existing SVG files. If you import an SVG that contains <animate> elements, the animations are dropped and the static state is preserved. PinePaper CAN emit SMIL animations on export (via app.exportEngine.exportAnimatedSVG()), but this is a one-way flow.

SVG filters

<filter> primitives like Gaussian blur, drop shadow, color matrix, etc. are not parsed. The visual filter effect is lost. Workaround: bake the filter into a raster (export the SVG as PNG with the filter applied, then import the PNG into PinePaper instead).

Patterns

SVG <pattern> fills (e.g. cross-hatching, repeating textures) drop to solid colors. Use PinePaper’s GeneratorRegistry instead — it has 30+ pattern generators that produce native canvas geometry.

Text rendering

Text elements import as PinePaper PointText items, but font fallback is naive — if the SVG references a font that’s not loaded in the browser, it falls back to the system font. Complex <tspan> structures may flatten.

Cross-origin images

<image> elements with href="https://..." URLs may fail to load due to CORS policy. Use data URIs (href="data:image/png;base64,...") or import the image separately into PinePaper’s Add tab.

Migration notes

If you have an SVG that uses unsupported features and you want it to import cleanly into PinePaper:

  1. In your SVG editor (Illustrator, Inkscape, Figma):

    • Convert text to outlines if you don’t need editable text
    • Bake filters and effects into raster images
    • Replace pattern fills with solid colors or generated PNG textures
    • Inline any external CSS styles
    • Remove SMIL animations (PinePaper has its own animation system)
  2. After importing into PinePaper:

    • Manually re-add any features dropped during import using PinePaper’s native systems
    • Use the GeneratorRegistry for patterns
    • Use the FilterSystem for blur / glow / color effects
    • Use the keyframe animation system for motion

File reference for developers

File Purpose
js/PinePaper.js (importSVG method) Public SVG import entry point with metadata preservation
js/ExportEngine.js (exportSVGWithCSS, animated SVG path) SVG export including animated SVG (SMIL) variant
js/core/SMILExporter.js Animated SVG export — converts PinePaper keyframes to SMIL
js/MapSystem.js (exportSVG method) Map-specific SVG export with optimized output

Testing

For the SVG round-trip integration tests, see __tests__/v05-svg-roundtrip.test.js. The test pins down which features import correctly so future regressions are caught at commit time.

Last updated

2026-04-09 — round-trip audit pass for v0.5.0-beta release. Verified against:

  • Inkscape 1.3 export samples
  • Adobe Illustrator SVG export samples
  • Hand-coded SVG fixtures