|
|
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.
|
This guide covers visual debugging for the Donner editor stack, especially the Geode direct-texture path. Use it when the editor shows one-frame glitches, overlay jumps, stale drag content, checkerboard gaps, or a texture rendered at the wrong scale.
The rule of thumb is: get a live repro first, then narrow the failure to the lowest layer that can still explain the pixels.
The hard invariant for editor chrome is that the path overlay must match the shapes rendered below it in the same presented frame. During pan, zoom, drag, or async worker stalls, it is better for both content and chrome to show the same older transform than for fresh chrome to drift away from stale document pixels.
Visual editor bugs usually cross several layers. Treat each layer as a separate test boundary.
| Layer | What It Owns | Typical Bugs | Useful Proof |
|---|---|---|---|
| Input and viewport | Mouse state, pan, zoom, DPR, pane geometry | Wrong document point, resize race, zoom focal drift | .rnr frame data and viewport diagnostics |
| DOM and selection | Mutations, drag preview, selection bounds | Overlay lags live DOM, stale hit-test bounds | active drag diagnostics, selection label, source writeback |
| Compositor | Layer segmentation, cached raster payloads, compose offsets | Old element pops back, filtered layer offset, stale canvas epoch | compositor state, tile metadata, pixel crop comparisons |
| Async renderer | Worker scheduling, cancellation, result publication | Late result wins, rejected result leaves side effects | RenderCoordinator tests and frame history |
| Texture cache | GL/WGPU texture ownership and tile reuse | metadata-only tile aliases wrong payload, retired WGPU snapshot dies too early | GlTextureCache unit tests and texture handle diagnostics |
| Presenter | Tile rectangle mapping and overlay composition | right texture at wrong rect, overlay/current viewport mismatch | PresentedFrameComposer tests and captured frames |
| ImGui/backend | ImTextureID, bind groups, command buffers, framebuffer readback | raw handle reused, stale bind group, wrong texture through correct quad | WGPU backend audit plus replay screenshots |
Start by proving the actual pixels. Logs and inspector text are useful, but they are not enough for one-frame visual bugs.
Standard screenshot replay:
This is the default way to generate editor screenshots for QA debugging. The replay writes PNGs under --out-dir named gl_replay_frame_<N>_<explicit|left_mousedown_K>[_<crop>].png (do not guess names), and the JSON output lists the absolute path for each capture. Attach or display those generated PNGs when a user asks to see a repro.
Use --crop document-canvas for most canvas visual bugs. Use --crop full when the failure may involve ImGui chrome, pane layout, dialogs, sidebars, layer thumbnails, or framebuffer size. Use --crop render-pane when the bug is inside the center viewport but depends on pan/zoom chrome around the SVG canvas.
Do not use manual OS screenshots as the primary proof for editor visual bugs when a .rnr repro exists. The replay screenshot is deterministic, captures the same frame that tests can assert, and keeps MCP/replay verification aligned with the user's visible failure.
Use --print-diagnostics only after the bad pixels are already captured. It prints per-frame JSON from the replay harness, including canvas freshness, overlay dimensions, paint-order tiles, raster canvas size, tile offsets, drag translations, texture handles, metadata-only reuse, and drag-target flags.
When comparing before/after behavior, keep the same .rnr, --svg, --capture-frame, --crop, and pacing flags. For full-editor UI screenshots such as layer thumbnails, prefer --crop full and include the captured PNG in the response so the crop cannot hide the UI regression being investigated.
For timing-sensitive failures, run both paced and unpaced replays:
The shared replay API lives in donner/editor/repro/GlRnrReplay.{h,cc}. The CLI wrapper is //donner/editor/tests:editor_rnr_gl_replay.
Use it for:
The production Geode editor still presents direct WGPU textures. Framebuffer readback is a replay/test tool, not a production fallback.
Use donner/editor/tests:bitmap_golden_compare helpers for image assertions. Prefer identity checks when a bug is a one-frame pop or stale texture:
Crop aggressively. A small crop around the suspected element usually gives a more stable regression than comparing the whole editor canvas.
EditorShell::layerInspectorStatusForReadback() exposes test-only state for the replay harness. It is useful for proving presentation state:
If a visual frame is wrong but diagnostics look correct, suspect a lower backend layer: stale texture handle, bind group cache, command buffer lifetime, or framebuffer readback.
Enable View > Compositor Tile Overlay to inspect tile boundaries on the live canvas without opening a separate panel. The overlay uses the presenter's exact transformed tile quadrilaterals, so its borders remain aligned through pan, zoom, cached transforms, and active drags.
Tile labels begin with S, L, or I for segment, promoted layer, or immediate content, followed by the stable tile ID and generation. Teal marks segments, amber marks promoted layers, pink marks immediate content, and white marks the active drag target. A muted cached suffix identifies a metadata-only update that reused an existing texture payload.
Use the overlay to decide whether a defect originates before or after presentation:
The overlay is disabled by default and omitted from content-only captures.
Use focused tests before reaching for full replay tests:
Replay tests are valuable, but they are expensive and timing-sensitive. When the root cause is a policy or lifetime rule, put the primary regression at that layer and keep the replay as integration coverage.
Symptom: the path outline or selection chrome appears at a different position from the dragged content for one frame.
Check:
Useful proof:
Symptom: the document pane shows checkerboard behind some layers for one frame.
Check:
Useful proof:
Symptom: a tiny element or letter tile appears stretched across a large part of the document or viewport for one frame.
This is usually not a pure coordinate bug. A coordinate bug moves or scales the right payload. A wrong-scale texture splat often means the presenter supplied a large quad while the backend sampled a stale small texture.
Check:
Useful proof:
Symptom: after dragging one element, clicking or dragging another makes the first element appear at an old position for one frame.
Check:
Useful proof:
Use this sequence for new bugs: