|
|
Donner SVG Editor & Engine
SVG-native editor and embeddable SVG2 + CSS3 engine in C++20, with GPU (WebGPU) and compact CPU renderers, built for correctness, security, and performance.
|
Directories | |
| app | |
| gui | |
| repro | |
Files | |
| AsyncRenderer.h | |
| AsyncRenderer owns a svg::Renderer and runs compositor rendering plus any final presentation snapshot handoff on a dedicated worker thread so heavy renders don't block the UI thread. | |
| AsyncSVGDocument.h | |
| AsyncSVGDocument is the editor-owned wrapper around svg::SVGDocument that gates DOM mutations through the CommandQueue and provides the snapshot hand-off to the render thread described in the M1.5 design note in docs/design_docs/0020-editor.md. | |
| AttributeWriteback.h | |
| Builds a TextPatch that updates an SVG element's attribute in the source text. This is the bridge between a canvas tool mutation (e.g. a drag that changes transform) and the source pane. | |
| CanvasScrollbars.h | |
| Geometry for the render pane's emulated canvas scrollbars. The canvas pane never window-scrolls (an ImGui window scrollbar would move the in-pane overlay chrome - toolbar, perf HUD - instead of the document), so the pane draws its own scrollbars that represent the document extent relative to the viewport and pan the canvas when dragged. | |
| ClipboardInterface.h | |
| Abstract clipboard interface used by the editor's text-editor core (see 0051-text_editor_refactor.md). Decouples copy/cut/paste from ImGui so headless unit tests can inject an in-memory implementation instead of requiring an ImGui context. | |
| CommandQueue.h | |
| CommandQueue is the per-frame EditorCommand queue described in the "AsyncSVGDocument: single-threaded command queue" section of docs/design_docs/0020-editor.md. It accumulates editor-initiated DOM mutations on the UI thread and coalesces them at flush time. | |
| CompositedPresentation.h | |
| CompositorDebugPanel.h | |
| Read-only diagnostic panel that exposes the live compositor's composite state - every tile (background, foreground, segments, layers) the renderer blits to produce the final frame, displayed in paint order with a thumbnail per tile. | |
| DialogPresenter.h | |
| DisclosureChevron.h | |
| Shared tree-disclosure chevron used by both the inspector tree and the LayersPanel so the two trees present one consistent disclosure style. | |
| DocumentSave.h | |
| DocumentSyncController.h | |
| DragCoalesce.h | |
| Drag coalesce policy: decides whether the editor should forward the current mouse position to the backend as a kMove pointer event, or drop it and wait for the in-flight response. | |
| EditorApp.h | |
| EditorApp is the editor's top-level shell - the mutation-seam frontend that tools and the main loop interact with. Owns the AsyncSVGDocument, the active selection, and (eventually) the active tool dispatcher. | |
| EditorCommand.h | |
| EditorCommand is the discriminated union of every UI-thread→DOM mutation in the M2 scope of the editor. New tools (path, node-edit, etc.) extend this variant in their own follow-up milestones - one new case per logical operation, NOT one per ECS write. | |
| EditorDockLayout.h | |
| EditorInputBridge.h | |
| EditorParseOptions.h | |
| EditorSampleCatalog.h | |
| EditorShell.h | |
| EditorShellInternal.h | |
| EditorShellLayout.h | |
| EditorShellPresentation.h | |
| EditorShell's direct-to-framebuffer presentation seam: converting cached GL/WGPU tiles and the immediate overlay snapshot into presented pixels. On Geode/WGPU builds this draws the checkerboard, document tiles, and selection chrome straight onto the window framebuffer (no intermediate texture); the tile-geometry helpers are backend-neutral. | |
| EditorTheme.h | |
| Donner editor design language (design doc 0054): a single source of truth for the editor chrome's palette, spacing grid, rounding, and control metrics. Replaces the scattered color literals and ad-hoc PushStyleVar values that previously lived per-widget across the editor tree. | |
| EmbeddedSvgIcon.h | |
| FileDialogState.h | |
| Pure, platform-independent bookkeeping for the editor's native file dialogs: default-directory memory and an in-process recent-files list. | |
| FillStrokeWidget.h | |
| Geometry, hit-testing, and drawing for the toolbar Fill/Stroke widget. | |
| FlashDecorations.h | |
| FocusView.h | |
| FrameCostBreakdown.h | |
| FrameMissTelemetry.h | |
| GlTextureCache.h | |
| ImGuiBackendIncludes.h | |
| ImGuiClipboard.h | |
| Production ClipboardInterface implementation backed by ImGui's clipboard functions (ImGui::GetClipboardText / SetClipboardText). | |
| ImGuiIncludes.h | |
| ImGuiInternalIncludes.h | |
| InMemoryClipboard.h | |
| Header-only in-memory implementation of ClipboardInterface. Stores a single std::string in the object - no OS / ImGui interaction. | |
| KeyboardShortcutPolicy.h | |
| LayerInspectorDiagnostics.h | |
| LayersPanel.h | |
| LayersPanel is the user-facing Layers panel UI. It renders the flat LayerTreeModel row list as an ImGui tree with disclosure chevrons, per-row preview thumbnails, and selection that stays synchronized with the canvas and source panes. | |
| LayerTreeModel.h | |
| LayerTreeModel is the pure, ImGui-free, value-snapshot model behind the user-facing Layers panel. | |
| LockState.h | |
| Layer-lock state shared between the Layers panel (which draws the lock affordance and toggles it) and EditorApp's edit-gating path (which drops geometry-changing and destructive mutations targeting a locked element). | |
| MenuBarPresenter.h | |
| NativeDialogCoordinator.h | |
| Bridges the pure FileDialogState bookkeeping with the platform NativeFileDialog panels. The editor shell holds one of these and asks it to present open/save dialogs; the coordinator seeds the dialog with the remembered directory, records the chosen file for directory memory and recents, and registers it with the OS recent-documents list. | |
| NativeFileDialog.h | |
| Platform-native file open/save dialogs. On macOS these present NSOpenPanel / NSSavePanel with a UTType filter for .svg, seeded from a remembered default directory, and register chosen files with the OS recent-documents list. On other platforms the functions report unavailable so callers fall back to the in-editor ImGui modal. | |
| NativeWindowChrome.h | |
| Native window chrome integration for the editor's title bar. | |
| OverlayRenderer.h | |
| OverlayRenderer draws editor chrome (currently selection path outlines) directly into the renderer's existing framebuffer using the canvas primitives RendererInterface already exposes. It is not a separate compositing layer and not a fabricated SVG subtree - chrome and document share one render target so there is no subpixel drift between them. | |
| PenTool.h | |
| Release-quality path authoring tool. PenTool creates source-backed <path> elements from document-space clicks: a plain click places a line anchor (M/L), a click-drag places a smooth Bezier anchor (C) whose outgoing handle follows the mouse while the incoming handle mirrors it through the anchor, and Alt/Option during the drag breaks that symmetry to author a corner with mismatched handles. Shift constrains the next anchor to 0/45/90 degrees from the previous one, clicking near the first anchor closes the contour with Z (dragging on close shapes the closing anchor's handles), and the whole pen session collapses into a single undoable command on finalize (close, Enter/double-click or Escape commit, or a tool switch). | |
| PinchEventMonitor.h | |
| Platform-specific render-pane pinch gesture capture. On macOS this installs a local magnify-event monitor and feeds synthetic zoom scroll events into the existing editor queue. | |
| PresentationRenderScheduler.h | |
| PresentedFrameComposer.h | |
| ReferenceFanout.h | |
| RenderCoordinator.h | |
| RenderPaneGesture.h | |
| Headless classification for render-pane scroll gestures. main.cc feeds raw GLFW scroll events into this helper so tests can cover pan vs. zoom routing without depending on ImGui or GLFW. | |
| RenderPanePresenter.h | |
| RopeSimulation.h | |
| RotateCursorSet.h | |
| SamplePickerPresenter.h | |
| SelectionAabb.h | |
| SelectionTransformHandles.h | |
| SelectTool.h | |
| SelectTool is the editor's first and (in this milestone) only tool. It dispatches three different gestures off onMouseDown: | |
| ShapeClipboardCommands.h | |
| Pure shape-clipboard command helpers, decoupled from ImGui and from the editor shell so they can be unit-tested headlessly (see donner/editor/tests/ShapeClipboard_tests.cc). | |
| ShapeClipboardPayload.h | |
| ShapeClipboardPayload is the structured representation of a shape-clipboard copy. The editor serializes the selected element subtrees to SVG fragment text and pairs that text with the metadata needed to paste deterministically (document-space bbox at copy time, source element ids, and whether the copy came from a whole-group selection). | |
| SidebarPresenter.h | |
| SoftWrap.h | |
| SourceDiagnostics.h | |
| SourceDiagnosticsPanel.h | |
| SourceEditIntent.h | |
| SourceSelection.h | |
| SourceStructuralMove.h | |
| SourceSync.h | |
| Helpers for keeping the source pane, command queue, and DOM parse state in sync when editor-owned code writes bytes back into the text buffer. | |
| StyleSourceAnnotations.h | |
| TextBuffer.h | |
| TextEditor.h | |
| TextEditorCore.h | |
| Headless editing substrate for the ImGui TextEditor widget. | |
| TextFormatBarPresenter.h | |
| TextFormatBarPresenter renders a contextual floating text-formatting bar below the canvas tool palette. The bar is shown only while text styling is in context: when the canvas selection is a single <text> element or an in-canvas text editing session is active. It offers a searchable font-family picker (each known family previewed in its own face, with a free-text fallback for families the editor lacks), a font-size combo with drag and preset behavior, and Bold/Italic/Underline toggles. | |
| TextInspectorPanel.h | |
| TextInspectorPanel renders text-specific property controls in the editor inspector area. It is shown only when the selection is exactly one <text> element. Content edits are debounced into a single undoable command (committed on focus loss or after a short idle), while the style/position attributes are written through the SetAttribute mutation seam. | |
| TextPatch.h | |
| The TextPatch type and applyPatches function form the editor's canvas-to-text writeback sideband. When a tool mutates an attribute via EditorApp::applyMutation, it also produces a TextPatch that describes the corresponding byte-level splice in the source text. The main loop drains pending patches after flushFrame() and before rendering the source pane. | |
| TextTool.h | |
| TextTool is the editor's text-authoring tool, following the standard design-tool contract: a click on existing text opens an in-canvas editing session on that element with the caret at the clicked character, a click-drag on empty canvas draws a text box, and a double-click on empty canvas starts point text (a plain click on empty canvas creates nothing - it only commits any active session). Typing, Enter (hard line break), Backspace/Delete, and caret movement edit the live <text> element through the DOM mutation seam; box text wraps greedily to the box width using the engine's measured character geometry. Cmd/Ctrl+B/I/U toggle bold, italic, and underline on the element. Escape, clicking away, or switching tools commits the session as a single undoable operation (an empty session on a newly created element deletes it, leaving the document unchanged; emptying an existing element deletes it as an undoable edit). | |
| TextToOutlines.h | |
| Pure text-to-outline conversion helper, decoupled from ImGui and from the editor shell so it can be unit-tested headlessly (see donner/editor/tests/TextToOutlines_tests.cc). | |
| Tool.h | |
| Tool is the abstract interface for editor pointer tools (Select, future Path, future Node-edit, etc.). Tools observe the editor state via the EditorApp& parameter and produce DOM mutations exclusively by calling EditorApp::applyMutation() - they never touch the DOM directly. | |
| ToolbarIconSet.h | |
| Toolbar tool icons, rendered from embedded two-tone SVG art through Donner. Black cores and white halos are preserved so the toolbar and OS cursors use one contrast system on every surface (see donner/editor/art/STYLE.md). | |
| ToolKeybinding.h | |
| Canonical editor tool identity plus its industry-standard single-key shortcut and display label. Kept as a tiny pure header (no ImGui, no EditorShell) so the toolbar tooltip text and the keyboard shortcut handler share one source of truth and the mapping can be unit-tested without a live ImGui/GL context. | |
| TracyWrapper.h | |
| Conditional Tracy profiling macros for the editor. When ENABLE_TRACY is defined, the real Tracy profiler client is included; otherwise the macros expand to no-ops so editor code can be instrumented unconditionally. | |
| TransformSyntaxPreserving.h | |
| Transform transform= writeback that preserves the author's chosen function syntax. Forward transform edits (inspector fields and canvas drags) used to canonicalize every author form into matrix(a,b,c,d,e,f) via donner::toSVGTransformString. This module re-expresses an edited Transform2d in the author's original function list where the edit is representable as an update to that list (a rotation change on rotate(45) writes rotate(60), a move updates translate(x, y), and so on), falling back to matrix() only when the edit cannot be represented in the author's structure. | |
| UndoTimeline.h | |
| ViewportGeometry.h | |
| ViewportInteractionController.h | |
| ViewportState.h | |
| ViewportState is the single source of truth for the editor render pane's screen↔document coordinate mapping. See docs/design_docs/0025-2-editor_ux.md for the full design rationale; this header is the public API. | |
| ViewportSvgExport.h | |
| Viewport SVG export. | |
| XmlAutocomplete.h | |
The Donner editor is a browser-based and desktop SVG editor built on top of the Donner SVG engine. The interactive editor parses and renders in-process through the selected Renderer backend.
The editor uses the shared Graphite design language documented in Editor Design Language. EditorTheme owns surfaces, text, Signal Teal interaction state, semantic colors, spacing, radii, and fixed control dimensions. Custom canvas chrome reads the active theme instead of introducing widget-local colors.
When extending the UI:
The source pane is collapsed on startup behind the left reveal rail. Source-navigation commands open it automatically. Transform controls use responsive Position, Size, and Rotation rows; the advanced matrix remains available through its disclosure. Numeric fields drag to adjust and enter text mode on a simple click-release. Tool and cursor SVGs use black cores with white halos so they remain legible over light and dark content. The toolbar exposes only ready tools; unfinished path editing remains hidden until its interaction is complete.
New text inherits the current fill. Selecting or editing one text element opens a compact floating font toolbar below the canvas tools. Point-text frames use stable font em-box height, reveal on pointer movement, and fade while typing. Frame resize keeps its preview on the UI thread and performs DOM rewrap and source writeback once on release; text and select handles share the same dimensions.
Text input is coalesced into one document synchronization per UI frame. Active move chrome uses gesture-owned bounds instead of rewalking selected path geometry, and cached drag pixels are matched to live selections by entity identity. Source reveal preserves the canvas center and keeps the existing full-document raster when a pane-bounded raster would be larger. CSS source annotations run against an isolated source snapshot and are applied only after revision validation.
The editor target applies a Geode transition internally, so no --config=geode flag is needed for the desktop editor.
editor_impl is the untransitioned implementation target and inherits the command-line renderer backend. It is primarily useful for backend debugging.
The editor uses the backend-agnostic Renderer wrapper (donner/svg/renderer/Renderer.h). The public desktop editor target selects Geode at build time with a Bazel transition; the editor WASM config also selects Geode by default. No runtime flags or C++ code branches are needed:
| Target / config | Backend |
|---|---|
| //donner/editor | Geode - WebGPU + Slug |
| --config=editor-wasm | Geode - browser WebGPU |
| //donner/editor:editor_impl | Inherits command-line renderer flag |
Desktop presentation is also selected at build time:
Run an Inspector UI mutation campaign under AddressSanitizer with a disposable corpus:
The //donner/editor/tests:inspector_ui_fuzzer target replays the checked-in seed files once. Use the _bin target with a writable corpus directory when mutation fuzzing is required.