io-svg

star 2.5k

Guides work on SVG import into the Grida Canvas Rust engine (grida crate). Covers crates/grida/src/import/svg/, the grida_dev svg-to-grida CLI, cross-boundary FBS codec tests (Rust encode → TS decode), SVG fixture authoring, and known SVG import limitations (text model, filters, transforms). Use when adding SVG feature support, fixing import bugs, authoring SVG test fixtures, debugging cross-boundary codec failures, or investigating what SVG elements map to which Grida node types.

gridaco By gridaco schedule Updated 4/26/2026

name: io-svg description: > Guides work on SVG import into the Grida Canvas Rust engine (grida crate). Covers crates/grida/src/import/svg/, the grida_dev svg-to-grida CLI, cross-boundary FBS codec tests (Rust encode → TS decode), SVG fixture authoring, and known SVG import limitations (text model, filters, transforms). Use when adding SVG feature support, fixing import bugs, authoring SVG test fixtures, debugging cross-boundary codec failures, or investigating what SVG elements map to which Grida node types.

SVG I/O — Rust SVG Import Pipeline

Crate: crates/grida/src/import/svg/

When to Use This Skill

  • Adding support for new SVG elements or attributes
  • Fixing SVG-to-Grida conversion bugs (wrong transform, wrong paint, etc.)
  • Authoring new SVG test fixtures in fixtures/test-svg/L0/
  • Debugging cross-boundary codec failures (Rust encodes ≠ TS decodes)
  • Understanding what SVG features are supported vs. dropped
  • Investigating text import fidelity

Architecture

.svg bytes
  → usvg::Tree::from_data()   — parse + resolve (third_party/usvg/)
  → packed_scene::*           — usvg::Tree → Grida scene graph
  → pack::*                   — pack nodes into IPackedSceneDocument
  → io::archive::pack()       — produce .grida ZIP

Key design: SVG import is Rust-only. There is no TypeScript path for SVG→Grida.

The TypeScript cross-boundary test (fbs-svg-cross-boundary.test.ts) decodes .grida files that were generated by Rust via svg-to-grida, not a TS converter.


Key Files

Path Role
crates/grida/src/import/svg/packed_scene.rs Core conversion: usvg nodes → Grida nodes
crates/grida/src/import/svg/pack.rs Packs converted nodes into scene document
crates/grida/src/import/svg/from_usvg.rs High-level entry: bytes → scene
crates/grida/src/formats/svg/sanitize.rs Pre-processing / sanitization
crates/grida_dev/src/main.rs svg-to-grida subcommand
fixtures/test-svg/L0/ Committed SVG fixtures
fixtures/test-svg/.generated/ Gitignored, generated .grida outputs
packages/grida-canvas-io/__tests__/fbs-svg-cross-boundary.test.ts TS-side codec test

Common Tasks

Orient before touching code

  1. Read crates/grida/AGENTS.md for crate conventions and commands.
  2. Read docs/wg/feat-svg/text-import.md before touching text conversion — the text model is intentionally limited and the design is documented there.
  3. Grep for the relevant element in packed_scene.rs.

Add support for a new SVG element or attribute

  1. Find where usvg exposes the element in third_party/usvg/src/.
  2. Add the mapping in packed_scene.rs (the main convert_* functions).
  3. Add a minimal SVG fixture to fixtures/test-svg/L0/ that exercises the feature.
  4. Run the cross-boundary cycle (see below) to verify Rust→TS round-trip.

Run the cross-boundary codec cycle

# Step 1: Rust encodes all L0 SVG fixtures → .grida files
cargo run -p grida_dev -- svg-to-grida fixtures/test-svg/L0

# Step 2: TS decodes the .grida files and runs assertions
pnpm vitest run fbs-svg-cross-boundary --reporter=verbose

Outputs land in fixtures/test-svg/.generated/ (gitignored).

For custom SVG files:

cargo run -p grida_dev -- svg-to-grida path/to/svgs -r

Run SVG reftests

# W3C SVG test suite (requires separate download — see docs/wg/feat-svg/testing.md)
cargo run -p grida_dev --release -- reftest path/to/w3c-suite/

# resvg test suite
cargo run -p grida_dev --release -- reftest path/to/resvg-test-suite/

See crates/grida_dev/TESTING.md for full reftest flags.

Rust tests for SVG

cargo test -p grida
cargo test -p grida svg        # filter to SVG tests only

SVG Feature Coverage

Fully supported

  • Basic shapes: <rect>, <circle>, <ellipse>, <line>, <polyline>, <polygon>, <path>
  • Groups <g> with transforms
  • Fills and strokes (solid color, linear gradient, radial gradient)
  • Clip paths and masks
  • Filters: drop-shadow, blur, color-matrix, lighting, compositing primitives
  • Opacity and blend modes
  • <use> / <defs> (resolved by usvg)
  • Text: one Grida TextSpanNodeRec per usvg TextChunk (see text model below)
  • Stroke dash arrays
  • Nested transforms

Text model (important)

SVG text is chunk-based: <text>GroupNodeRec, each TextChunkTextSpanNodeRec.

What is lost: inline style variation within a line, per-character x/y lists, baseline-shift, text-decoration per span, text-on-path.

This matches Figma's SVG import fidelity. See docs/wg/feat-svg/text-import.md for full details before changing text conversion.

Known gaps / unsupported

  • <pattern> fill (partially tracked in docs/wg/feat-svg/pattern.md)
  • <textPath> (text on path)
  • Animations (<animate>, SMIL)
  • CSS stylesheets inside SVG

Fixture Conventions

  • Committed fixtures live in fixtures/test-svg/L0/ — one file per feature.
  • Naming: <feature>.svg (e.g. stroke-dasharray.svg, transforms-nested.svg).
  • Keep fixtures minimal — isolate one feature per file.
  • Generated outputs in .generated/ are gitignored; regenerate on demand with svg-to-grida.

Cross-Boundary Test Conventions

When fixing a codec bug found via the cross-boundary test:

  1. Add a targeted it(...) assertion in fbs-svg-cross-boundary.test.ts — one assertion per bug.
  2. Do NOT use snapshot comparisons — assert the specific field that was wrong.
  3. If the feature is a known limitation (e.g. scale/skew in transforms), mark the test it.fails(...) with a comment explaining why.

Verification After Changes

# Rust check + tests
cargo check -p grida --all-targets
cargo test -p grida

# Cross-boundary cycle
cargo run -p grida_dev -- svg-to-grida fixtures/test-svg/L0
pnpm vitest run fbs-svg-cross-boundary
Install via CLI
npx skills add https://github.com/gridaco/grida --skill io-svg
Repository Details
star Stars 2,524
call_split Forks 136
navigation Branch main
article Path SKILL.md
More from Creator