[Major Feature] Hybrid Scene Serialization — declarative scene-graph snapshot (test oracle + save/load) with raster escape-hatch #349

Open
opened 2026-07-11 00:04:09 +00:00 by john · 0 comments
Owner

Tracking issue for the Proposal: Hybrid Scene Serialization wiki page (Design Phase).

One-paragraph summary

McRogueFace is retained-mode: a frame is a pure function of (UIDrawable tree + assets). Instead of rasterizing to PNG (profiling showed ~96.6% of a screenshot-per-frame workload is spent in PNG DEFLATE, stbi_zlib_compress), walk the tree and serialize each node's type + properties + asset references — SVG-analogous, capturing render inputs not outputs. Cheap (memcpy-of-properties, no rasterization), tiny (KB not MB), deterministic, and diffable. Procedural textures (render-texture/composite/hsl_shift/shader outputs) escape-hatch to a referenced QOI/TGA sidecar. Rasterize on demand by replaying the scene file back through the engine ("lazy rasterization"), so frequent capture is nearly free.

Why it's two features in one

  1. Cheap deterministic test oracle — structural diff (f3.x: 100→104) beats pixel-diffing for layout/logic regressions; immune to GPU/AA/driver/backend flakiness.
  2. Scene save/load — round-trips to Python constructor kwargs; usable for authoring, persisting UI, and reproducible bug-report snapshots.

Governing distinction (scope boundary)

Records render inputs, not outputscomplements raster screenshots, does not replace them. It is blind to rendering bugs (wrong shader/blend/z-order/clip/atlas offset). Raster capture stays the tool for visual/shader correctness.

Proposed increments (see wiki Migration Path — purely additive)

  • Recursive serialize()/to_dict() on UIDrawable: Frame/Caption/Sprite first (tree walk already exists in ImGuiSceneExplorer)
  • New entry point, e.g. automation.snapshot_scene(path)
  • Grid + layers: sparse/RLE cell state (reuse DiscreteMap byte path)
  • Raster escape-hatch: detect non-asset textures → export QOI/TGA sidecar + reference
  • Replayer: load scene file → rebuild tree via Python API → optional rasterize-on-demand
  • Structural-diff test-oracle helper for tests/

Dependencies / relationships

  • #347 (renderer parity SFML vs SDL2/WebGL) — replay fidelity across backends leans on this.
  • #255 (perf umbrella) — parent.
  • #345 (profiling rig) — motivated this; supplies the PNG-cost evidence.
  • Prereqs that help: QOI/TGA fast-encode support in automation.screenshot() (raster escape-hatch needs a fast lossless encoder).

Status

Design Phase — needs review/approval before implementation per the wiki proposal process. No prior issue or proposal covered scene serialization (confirmed 2026-07-10); this is novel to the project.

Tracking issue for the **[Proposal: Hybrid Scene Serialization](https://dev.ffwf.net/forgejo/john/McRogueFace/wiki/Proposal:-Hybrid-Scene-Serialization)** wiki page (Design Phase). ## One-paragraph summary McRogueFace is retained-mode: a frame is a pure function of `(UIDrawable tree + assets)`. Instead of rasterizing to PNG (profiling showed ~96.6% of a screenshot-per-frame workload is spent in PNG DEFLATE, `stbi_zlib_compress`), walk the tree and serialize each node's type + properties + asset references — SVG-analogous, capturing render **inputs** not **outputs**. Cheap (memcpy-of-properties, no rasterization), tiny (KB not MB), deterministic, and diffable. Procedural textures (render-texture/composite/hsl_shift/shader outputs) escape-hatch to a referenced QOI/TGA sidecar. Rasterize on demand by replaying the scene file back through the engine ("lazy rasterization"), so frequent capture is nearly free. ## Why it's two features in one 1. **Cheap deterministic test oracle** — structural diff (`f3.x: 100→104`) beats pixel-diffing for layout/logic regressions; immune to GPU/AA/driver/backend flakiness. 2. **Scene save/load** — round-trips to Python constructor kwargs; usable for authoring, persisting UI, and reproducible bug-report snapshots. ## Governing distinction (scope boundary) Records render **inputs, not outputs** → **complements** raster screenshots, does not replace them. It is **blind to rendering bugs** (wrong shader/blend/z-order/clip/atlas offset). Raster capture stays the tool for visual/shader correctness. ## Proposed increments (see wiki Migration Path — purely additive) - [ ] Recursive `serialize()`/`to_dict()` on `UIDrawable`: Frame/Caption/Sprite first (tree walk already exists in `ImGuiSceneExplorer`) - [ ] New entry point, e.g. `automation.snapshot_scene(path)` - [ ] Grid + layers: sparse/RLE cell state (reuse `DiscreteMap` byte path) - [ ] Raster escape-hatch: detect non-asset textures → export QOI/TGA sidecar + reference - [ ] Replayer: load scene file → rebuild tree via Python API → optional rasterize-on-demand - [ ] Structural-diff test-oracle helper for `tests/` ## Dependencies / relationships - **#347** (renderer parity SFML vs SDL2/WebGL) — replay fidelity across backends leans on this. - **#255** (perf umbrella) — parent. - **#345** (profiling rig) — motivated this; supplies the PNG-cost evidence. - Prereqs that help: QOI/TGA fast-encode support in `automation.screenshot()` (raster escape-hatch needs a fast lossless encoder). ## Status Design Phase — **needs review/approval before implementation** per the wiki proposal process. No prior issue or proposal covered scene serialization (confirmed 2026-07-10); this is novel to the project.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
john/McRogueFace#349
No description provided.