Donner SVG 0.8.0
0.8.0 ยท ebf353960.8.0 main
SVG editor and embeddable C⁠+⁠+⁠20 engine.
Loading...
Searching...
No Matches
Project Roadmap

Status: Active Updated: 2026-10-14

Summary

Donner is now positioned as Donner SVG Editor & Engine: an SVG editor application plus the rendering, geometry, parsing, and authoring engine needed to build SVG tooling.

After v0.1 established the static rendering baseline, a large body of work landed covering renderer abstraction, a complete software rasterizer, text shaping, and all 17 SVG filter primitives. This is collected as v0.5, skipping intermediate milestones that were overtaken by the pace of development.

The next release target is v0.8: Donner SVG Editor & Engine. Its scope is everything completed since v0.5, plus the editor showcase work needed to demonstrate Donner deriving a new composition from its own splash: a complete Layers panel, shape cut/copy/paste, a tuned Pen tool, text creation, text-to-outline conversion, viewport SVG export, and optional editor overlay export. The broader production-quality v1.0 milestone remains the follow-up release for animation, scripting, multiplayer editing, diagramming, an embeddable runtime, conformance completion, parser hardening, and ecosystem integration.


v0.1: Static Rendering Baseline (shipped)

Core static SVG path/shape rendering and CSS cascade foundation. Established the ECS architecture, XML parser, CSS parser, and Skia-based renderer.


v0.5: Rendering Engine (shipped)

Renderer abstraction, software rasterizer, text rendering, and filter effects.

Renderer Architecture

  • Renderer interface abstraction: RendererInterface split from the original full-Skia renderer with RendererDriver traversing a flat render tree. Enables future backend swaps. (design)
  • tiny-skia software renderer: Full software rasterizer (fill, stroke, gradients, patterns, shaders, lowp/highp pipeline) as an alternative to Skia. All render operations within 1.5x of Skia performance.

Text Rendering

  • Phases 1-5: stb_truetype font loading, glyph outlines, TextLayout, WOFF2 support, dominant-baseline.
  • Phase 6: Optional HarfBuzz text shaping tier (--config=text-full).
  • <textPath> element support for text rendered along arbitrary paths.
  • (design)

SVG Filter Effects

  • All 17 SVG filter primitives implemented in the current tiny-skia backend; the former full-Skia path provided native SkImageFilter lowering before its removal.
  • Float-precision filter pipeline with SIMD optimizations (NEON): Gaussian blur, morphology, color matrix, turbulence, convolution, blend, composite, lighting, displacement map, component transfer, flood, offset, merge, tile.
  • All 23 filter benchmarks within 1.5x of Skia; 21 of 23 are faster.
  • (perf)

Infrastructure

  • Auto-detect font backends, crash handling hardening.
  • Filter and render benchmark suites with perf regression tests (1.5x threshold enforcement).
  • resvg test suite integration for golden image validation.

v0.8: Donner SVG Editor & Engine (next release)

Focus: rebrand Donner around the editor and engine, release the accumulated editor/Geode/path work, and use the editor live to style and record the v0.8 showcase.

Release Positioning

  • Product name: Donner SVG Editor & Engine.
  • Public story: Donner is both a native SVG editor and a reusable C++ SVG engine.
  • Showcase story: the canonical donner_splash.svg is styled live in Donner Editor and the authoring session is screen recorded under operator direction.
  • Reproducibility story: an automated composition generated through Donner's text-to-outlines and viewport-export paths is a CI smoke fixture and starting sample, not the final art direction.
  • Compatibility story: the generated fixture does not depend on system fonts because its visible SVG lettering is converted to path outlines.
  • Usability story: the editor can perform the basic shape authoring operations needed to create the splash without source-pane surgery or external design tools.

Completed Work Included in v0.8

The release collects all completed editor/toolkit work since v0.5, including:

  • In-tree Donner Editor application, source pane, selection, undo, save, and structured command plumbing.
  • Editor source focus, source-reference links, style chips, and source/canvas selection sync.
  • Geode editor path as the default direction for editor performance work.
  • Fluid editor canvas rendering: composited presentation, immediate rendering, viewport-bounded rendering, overview infill, telemetry, and frame/memory profiler improvements.
  • Direct overlay rendering requirements: path overlay must match the presented document pixels in the same frame.
  • Path authoring and boolean path operations: Pen tool fixes, pathfinder backed by in-tree PathOps, compound path unbundle, and selection/drag stability fixes.
  • Group-aware editor groundwork and the Layers panel design for SVG group/shape hierarchy.

Showcase-Gating Scope

The editor capabilities and automated fixture needed for the v0.8 showcase are implemented. Release QA, operator-directed styling, screen recording, and packaging remain:

  • Shape cut/copy/paste: duplicate, cut, and paste selected SVG shapes/groups with source sync, undo, selection restoration, default paste offset, Paste in Front, and deterministic ID handling.
  • Tuned Pen tool: path creation that supports line/curve anchors, close/cancel, live preview, immediate bounds/overlay updates, root-contained source insertion, and undo/redo.
  • Complete Layers panel: replace the tree view with an editable group/shape hierarchy. Show previews and stable names at each tier and sync selection with canvas/source.
  • Text authoring UI: create and edit short SVG text from the editor.
  • Convert Text to Outlines: convert selected <text> into deterministic path geometry using Donner text layout and glyph outlines.
  • Viewport SVG export: export the current editor viewport as cropped SVG.
  • Overlay SVG export: optional export of selected path outlines, bounds, and handles as vector editor chrome.
  • Automated showcase fixture: generate a derived splash from donner_splash.svg, add SVG, convert it to outlines, select the outlined letters, and export the viewport with overlay enabled without checking generated variants into the repository root. This proves the workflow, not the final composition.
  • Reproducibility: preserve the generator, automated test, and manual checklist needed to recreate the temporary showcase output on demand.
  • Rebrand updates: update public docs, release notes, and user-facing labels to Donner SVG Editor & Engine.
  • Live showcase recording: style the release-facing composition in Donner Editor under operator direction, screen record the authoring session, and review its legibility, pacing, composition, and editor UI clarity.

v0.8 Release Criteria

  • The automated fixture generates from the canonical donner_splash.svg, then parses and renders in Donner without changing the canonical source or adding root-level derivatives.
  • The editor can cut/copy/paste representative showcase shapes without losing source/canvas sync or selection/undo state.
  • The Pen tool can author and close a path for the showcase with bounds and overlay matching the rendered path in the same visible frame.
  • The complete Layers panel can navigate the splash from document to groups to individual shapes with previews, names, expansion state, and synchronized canvas/source selection.
  • The visible SVG lettering in the generated fixture is path geometry, not live <text>.
  • The fixture export includes the selected outlined SVG letters and editor overlay chrome when the overlay variant is requested.
  • The release-facing showcase is styled live in the editor and screen recorded under operator direction; it is not required to match the automated fixture.
  • The editor can perform the live showcase workflow without external design tools or source-pane surgery.
  • Existing editor responsiveness regressions for zoom, drag, selection, and overlay lockstep remain covered by tests.
  • The roadmap, README/release notes, and Doxygen-facing docs use the new product positioning.

See v0_8_showcase for the current implementation summary and v0_8_showcase_retrospective for the implementation retrospective.


v1.0: Production Release (future)

The production-quality milestone that follows the v0.8 Donner SVG Editor & Engine release.

Focus: interactive editing, multiplayer editing, diagramming, conformance, parser hardening, an embeddable runtime, and ecosystem integration.

SVG Animation

The declarative timeline, interpolation, motion paths and interactive editor Preview are merged to main and ship in v0.8. Presentation coverage and qualification remain in progress; see the animation design and support matrix and #1239.

  • Phases 1-9: timing model, interpolation engine, sandwich composition, attribute targeting, <animate>, <animateTransform>, <animateMotion>, <set>, event-based timing.
  • Lottie playback (probable): Play back Lottie animations (the JSON-based After Effects export format, .json/.lottie) on an ECS-free timeline and interpolation module that the SVG animation system and the Donner Tiny runtime also use. Lottie is the dominant interchange format for production vector animation, and runtimes such as ThorVG and dotLottie demonstrate the demand.

Composited Rendering

  • Layer-based caching architecture for animation and editing performance.

Interactivity

  • Phases 1-6: EventSystem with SpatialGrid-accelerated hit testing, event dispatch (mouse, pointer), CSS cursor property, DonnerController public API (addEventListener, elementFromPoint, findIntersectingRect, getWorldBounds), incremental spatial index updates.

Incremental Invalidation

  • Partial computed tree invalidation: When DOM mutations occur, only invalidate the affected subtree of the computed style/layout tree rather than recomputing the entire document. CSS restyling performs differential updates: identify which elements' computed styles are affected by a change and re-resolve only those, propagating inherited property changes down the affected subtree.

Interactive SVG Editing

Production editor scope: a hybrid structured/freeform SVG editor workflow beyond the v0.8 showcase.

  • Import donner-editor: Shipped in #529. The editor lives in-tree at donner/editor (EditorApp, donner/editor/app) with its own test suite under donner/editor/tests.
  • Structured editing API: Shipped in #598. SVGDocument::setElementAttribute, insertElement, removeElement, and setElementTextContent return an ApplySourceEditResult whose XMLMutation stream drives incremental re-render through the ECS (donner/svg/tests/SVGInvalidation_tests.cc).
  • Partial re-parsing: Shipped in #598. XMLIncrementalParser and XMLDocument::applySourceEdit reparse the smallest affected subtree (ReparseScope::Subtree) and splice the result into the live document, widening to a document-scoped reparse only when the local parse fails.
  • Reverse serialization: Shipped in #598. Canvas and DOM operations emit byte-level XMLSourceDeltas through XMLSourceStore, and DocumentSyncController::mirrorSourceDeltas replays them into the source pane in place, preserving the surrounding text and formatting. See structured_source_editing.
  • Invalid-region tolerance: Shipped in #531. DocumentSyncController::syncParseErrorMarkers surfaces parse diagnostics as source-pane markers, and selection and document state survive transiently invalid source, covered by DocumentSyncControllerTest.PartialOpeningTagEditPreservesSelectionWhileInvalid and the editor state-machine fuzzer.

Multiplayer Editing

Real-time multi-user editing of one SVG document, modeled on Excalidraw's collaboration design: element-level highest-version-wins reconciliation over a relay that only forwards end-to-end encrypted messages. Local and remote changes both flow through the structured editing API, so collaboration attaches at that mutation seam instead of introducing a second document model. This section does not gate the v1.0 release criteria.

  • Per-element versioning: Each element carries a stable collaboration ID, a monotonically increasing version, and a random versionNonce that changes with every version bump. Any edit to an element's attributes, style, text content, or position in the tree bumps its version. Element granularity is a deliberate tradeoff: concurrent edits to different attributes of one element keep only the winning version, and per-attribute versioning is a possible refinement. The collaboration ID is separate from the SVG id attribute, and collaboration state records the collaboration ID that each IRI reference (href, url(#...)) targets. Concurrent edits that produce duplicate id values are repaired deterministically by renaming one element and rewriting only the references bound to it.
  • Deterministic reconciliation: Merging incoming state takes the union of element IDs. For the same ID the higher version wins, equal versions break ties by the lower versionNonce, and equal nonces break ties by the editing peer's unique session ID, so every peer converges without a coordinating server. Deletions are tombstones retained in collaboration state until every active peer has acknowledged them. Session membership is itself versioned collaboration state: a peer that leaves, or stops acknowledging for longer than a documented retention window, is retired by a membership update, so tombstone storage stays bounded. Compacting acknowledged tombstones advances a session epoch; a peer whose state predates that epoch, including a retired peer that rejoins, resynchronizes from current state instead of merging its stale copy. On replay of its unsent edits, updates to elements that existed before its last sync but are absent from the current state are rejected and reported as conflicts, while elements it created after that sync are inserted, so a deleted element is never resurrected. The saved SVG never contains deleted elements.
  • Tree ordering: SVG is a tree whose document order is paint order, unlike Excalidraw's flat element list. Each element records its parent ID and a fractional index among its siblings, so concurrent inserts and reorders merge without renumbering. Equal indices are ordered by collaboration ID, and invalid or colliding indices are repaired deterministically. Reparenting is an ordinary versioned update. Cycle and missing-parent repair runs on the complete merged state, not in arrival order: within each parent cycle, the element whose winning record sorts lowest under the reconciliation order (version, versionNonce, peer ID) is detached to the document root, and an element whose parent is missing is detached the same way, so every peer reaches the same tree.
  • Incremental application: Remote updates apply through the same structured edits and incremental invalidation as local edits, never a full document reparse, and the source pane mirrors them through reverse serialization.
  • Relay and encryption: A stateless relay scopes messages to a room and forwards encrypted payloads without decrypting or ordering them. The room key travels only in the share link's URL fragment, which browsers never send to the server. The native editor and the WebAssembly build use the same protocol.
  • Presence: Cursors, selections, and in-progress gestures travel on a volatile channel that is never persisted or recorded in undo history.
  • Undo: Undo is per user. Undoing a local change emits a new versioned edit instead of rewinding shared state, and it skips elements a peer has changed since.
  • Local-first persistence: Each peer holds a full copy, keeps editing while offline, and reconciles on reconnect. The saved file stays plain SVG; collaboration metadata (versions, nonces, fractional indices, tombstones) lives in session or workspace state, not in exported markup.
  • Trust boundary: Remote payloads are untrusted input. They pass the same parsers, resource limits, and secure processing mode as file open, with message size caps, schema validation, and no external resource loading on a peer's behalf. Fuzzers cover payload decoding and reconciliation.

Diagramming

Structured diagramming as sugar over real SVG. Diagram semantics (nodes, ports, connectors, layout constraints) live in a Donner XML namespace attached to ordinary SVG shapes, so any SVG viewer renders the diagram and a tool that drops the namespace keeps the picture, losing only the diagram editing semantics. This section does not gate the v1.0 release criteria.

  • Diagram namespace: Namespaced metadata on real <g>, <rect>, <path>, and <text> elements describing node types, connection points, and connector endpoints. The metadata is re-validated against the geometry on load.
  • Diagram editing: Shape libraries, connectors that follow their endpoints with obstacle-avoiding routing and waypoints, auto-layout, and templates.
  • Mermaid-compatible mode: A Mermaid text view of the representable subset of the diagram. Edits in either view update the other; layout and styling that Mermaid cannot express stay in the Donner namespace, and the Mermaid parser follows the same resource limits and fuzzing as other parsers.

Parser Improvements

  • ParseWarning type: Shipped in #459. ParseDiagnostic carries a DiagnosticSeverity (Warning/Error) and non-fatal warnings flow through the zero-cost ParseWarningSink; the vector<ParseError> pattern and the ParseError type are gone. See parser_diagnostics.
  • Source location audit: Shipped in #459 (#442). Every parser entry point takes an explicit warning sink, subparser ranges are remapped into parent coordinates by ParseWarningSink::mergeFromSubparser, and range correctness is covered by per-parser tests plus DiagnosticRenderer caret/tilde output.
  • Full source ranges: Shipped in #459. SourceRange (donner/base/FileOffset.h) is a half-open [start, end) span of FileOffset values carried by every ParseDiagnostic.
  • CSS parser update: Consider making the CSS parser streaming, potentially using C++20 coroutines (co_await). Reduce places where we tokenize to a vector. Add support for source ranges and incremental updates matching the XML parser's capabilities. Partially shipped: the tokenizer is pull-based with no vector<Token> materialization and declarations and rules carry SourceRanges (0019, which rejected coroutine token generation by measurement); incremental CSS updates are not implemented.
  • XML parser conformance: Shipped in #462. Name tokens are validated against the XML 1.0 NameStartChar/NameChar productions in XMLParser.cc (#304).
  • CSS3 gap closure: Audit CSS3 property and selector support against the properties used by SVG2. Close gaps in selectors, cascading, specificity, shorthand expansion, and value parsing for properties referenced by the SVG2 spec.

Entity Lifecycle

  • Node removal cleanup: Shipped in #596. NodeLifetimeComponent tracks detached-root metadata and NodeLifetimeCollector destroys detached subtrees once no public handle or render snapshot retains them, with detached-node diagnostics counters and the //donner/benchmarks:dom_lifetime_perf_capture budget. See dom_element_lifetime.

DOM Support

  • SVG2 DOM gap analysis: Audit current DOM implementation against the full SVG2 DOM specification. Identify missing interfaces, attributes, and methods across all element types.
  • Close DOM gaps: Implement missing DOM interfaces and properties identified by the audit, prioritizing those needed for interactive editing and JavaScript integration.

Conformance & Testing

  • SVG2 conformance pass: Audit the pinned latest SVG2 Editor's Draft and close applicable gaps across chapters, tables, algorithms, and interfaces. See audit and suite design.
  • donner-svg-suite: Reusable full resvg superset plus SVG2 SVG/PNG cases, sharing a C++ GoogleTest/pixelmatch harness and native animation/input scenarios with autonomous triage.
  • 90% code coverage: Achieve and maintain >=90% line coverage across all production code. Identify under-covered subsystems and add targeted tests.
  • Animation test suite: Comprehensive test coverage for the animation system (Phases 1-9), including timing edge cases, interpolation correctness, and event-based triggers.
  • Update resvg test suite: Shipped in #500. Vendored the post-Great-Rename linebender/resvg-test-suite, migrated all test entries with a rename-map codemod, and introduced a reason-string Skip/RenderOnly/WithThreshold API. Follow-up feature gaps and bugs tracked in resvg_feature_gaps.md.
  • Enable text resvg tests: Shipped as part of the v0.5 text-rendering work: 37 e-textPath-* tests passing plus per-character positioning, letter-spacing, baseline-shift, writing-mode, and alignment-baseline coverage. Remaining gaps (e.g. bidi, complex emoji) tracked in the feature-gaps doc.
  • Add Donner to resvg test harness: Prepare and execute Donner backend integration with automated pixel comparison and agent triage; upstream contribution has a separate submission review. See suite design.

SVG Feature Gaps

  • <symbol> refX/refY units: Shipped in #638. SymbolComponent stores refX/refY as Lengthd, and the left/center/right and top/center/bottom keywords map to 0%/50%/100% resolved against the symbol's viewBox (#318).
  • <marker> attribute units: Shipped in #636. MarkerComponent stores refX/refY/markerWidth/markerHeight as unresolved Lengthd so percentages and keywords resolve against the referencing viewport at render time (#316).
  • <clipPath> <use> support: Shipped in v0.5. <use> children referencing path/shape elements inside <clipPath> now resolve correctly per CSS Masking spec (#238).

Security

  • AI-assisted security pass: Shipped across the input-bounding series (#1033, #1035, #1036, #1037, #1038, #1044, #1053), which bounded base parsing, CSS parsing and selector work, SVG runtime payloads and reference work, external resource admission, glyph decoding, CLI input, and renderer geometry materialization. Fuzzers now cover the surfaces called out here, including CSS, animation timing (ClockValueParser, AnimateValue, AnimateTransformValue), edit/patch paths (XMLParser_structured, EditorStateMachine, ShapeClipboardPaste, ViewportSvgExportRoundTrip), and external references (UrlLoader, SandboxedFileResourceLoader, ImageLoader); .github/workflows/fuzz.yml runs a scheduled sanitizer-backed mutation lane on top of per-PR corpus replay.

Optional Extensions

  • JavaScript support: Identify a small embeddable JavaScript engine and integrate as an optional feature (similar to how filters are optional). Enable scripted SVG content for interactive applications.

Optimization

  • Performance profiling: Profile end-to-end render paths and identify remaining bottlenecks. Target hot paths in parsing, style resolution, layout, and rasterization.
  • Code size reduction: Audit binary size contributions by subsystem. Reduce template bloat, eliminate dead code, and ensure optional features (text, filters, JS) compile out cleanly.
  • Memory usage: Reduce peak and steady-state memory consumption. Audit ECS component sizes, pixmap allocations, and intermediate buffers in filter/render pipelines.
  • Compile time: Reduce build times. Audit heavy template instantiations, consider explicit template instantiation, forward declarations, and pimpl patterns where header fan-out is excessive.
  • SVG engine build profiles: A minimal-footprint SVG engine tier that strips text, filters, animation, and JavaScript, producing the smallest possible binary for embedded/constrained environments. Each feature is independently opt-in through build flags (CMake options / Bazel configs), so users can compose exactly the feature set they need. Document the size impact of each optional module and provide pre-defined profiles: tiny (core rendering only), standard (current default), full (everything including JS). The tiny engine profile keeps the SVG DOM and CSS cascade; the Donner Tiny runtime below drops the SVG stack entirely.

Embeddable Runtime: Donner Tiny

A small embeddable vector runtime in ThorVG's class, built from Donner's renderer layer instead of its SVG document stack. Donner Tiny does not parse SVG; SVG content goes through the SVG engine in any of its build profiles, so there is only one SVG front end to keep conformant. This section does not gate the v1.0 release criteria.

  • Renderer core: Factor a renderer core out of the current renderer backend interface: paths, paints, clips, and transforms, with no SVG components or ECS types. tiny-skia and Geode implement it, and the SVG renderer is built on it.
  • Canvas-style 2D API: An immediate-mode path, paint, gradient, clip, and transform API over the renderer core, comparable to an HTML canvas 2D context.
  • Lottie player (probable): Play Lottie animations through the same runtime, using the ECS-free Lottie module shared with the Lottie item under SVG Animation.
  • Backends: tiny-skia software rendering by default, with its SIMD paths and no external dependencies; Geode as an optional GPU backend for hosts that already own a GPU device.
  • Footprint target: Measure the minimal Donner Tiny build against ThorVG's minimal build and target the same size class, using LTO, dead-section elimination, and per-module size accounting published with each release.
  • Embedding surface: A stable C++ API plus a C API for language bindings, with WebAssembly and embedded targets. Consumers do not depend on the SVG parser, CSS engine, or ECS.
  • ThorVG comparison: Publish a reproducible comparison against ThorVG covering binary size, render time, memory use, and output quality for the shared vector-drawing and Lottie feature set.

Ecosystem

  • Comparison with other SVG libraries: Publish a detailed comparison of Donner against lunasvg and resvg, covering feature support, conformance, performance, API design, binary size, and build complexity. Include reproducible benchmarks and conformance test results.

Documentation

  • Design docs -> developer docs: Convert all shipped design documents into developer-facing architecture documentation. Remove planning/status artifacts, focus on how-it-works descriptions for contributors and embedders.
  • In-code documentation cleanup: Review and update code comments, Doxygen annotations, and API documentation across public headers. Ensure all public APIs have clear documentation ready for consumption.
  • Embedding guide: End-to-end guide for integrating Donner into applications, covering build configuration, feature toggles, rendering setup, and common workflows.

v1.0 Release Criteria

  • All v1.0 issues closed.
  • SVG2 conformance report published with known limitations documented.
  • Stable API surface for rendering, editing, and authoring operations.
  • At least 90% code coverage across production code.
  • CSS3 gap analysis complete, all SVG2-referenced properties supported.
  • Performance and binary-size profiles documented.
  • Release documentation complete for embedders.

Future Work (post-v1.0)

  • Game-runtime suitability profile (latency, frame pacing, memory budgets).

Architecture

flowchart TD
  A[Core Parser + DOM + CSS Cascade] --> B[Computed Style + Layout]
  B --> C[Rendering Instance Graph]
  C --> D[Renderer Backend Interface]
  RC --> E1[tiny-skia Software Backend]
  RC --> E2[Geode GPU Backend]
  T[Donner Tiny: Canvas 2D API + Lottie Player] --> RC[Renderer Core]
  D --> RC

  A --> F[Partial Re-parse / Live Patch Engine]
  F --> C

  C --> G[Animation Scheduler]
  C --> H[Filter Graph]
  C --> I[Text Shaping/Layout]

  C --> J[Editor Services]
  J --> J1[Spatial Index / Hit Testing]
  J --> J2[Event System]
  J --> J3[Structured Editing API]
  J3 --> J4[Multiplayer Sync]

  K[Optional Extensions] --> K1[JavaScript Runtime]
  K1 --> C

Design Documents

Document Status
Renderer Interface Shipped (Phases 1-2a)
Text Rendering Shipped (Phases 1-6)
Filter Performance Shipped (all 17 primitives, within 1.5x)
v0.5 Release Shipped
Editor Fluid Canvas Rendering v0.8 scope
Editor Group Layers v0.8 showcase scope
v0.8 Showcase Next release
External SVG References Design