prometeu-runtime/discussion/lessons/DSC-0028-deferred-overlay-and-primitive-composition/LSN-0033-debug-primitives-should-be-a-final-overlay-not-part-of-game-composition.md
bQUARKz 73cf96ed6c
All checks were successful
Intrepid/Prometeu/Runtime/pipeline/pr-master This commit looks good
housekeep
2026-04-18 16:31:23 +01:00

2.9 KiB

id ticket title created tags
LSN-0033 deferred-overlay-and-primitive-composition Debug Primitives Should Be a Final Overlay, Not Part of Game Composition 2026-04-18
gfx
runtime
render
frame-composer
overlay
primitives
hud
debug

Context

After FrameComposer.render_frame() became the canonical game-frame entrypoint, immediate gfx.* primitive writes were no longer stable. Scene-backed composition could rebuild the framebuffer after draw_text(...) or other debug primitives had already written to it.

DSC-0028 resolved that conflict by moving gfx.* primitives into a deferred overlay/debug stage outside FrameComposer, drained only after canonical game composition and fades are complete.

Key Decisions

Debug Overlay Must Stay Outside the Canonical Game Pipeline

What: FrameComposer keeps ownership of canonical game composition, while debug/text/primitive commands are captured separately and drained later as a final overlay.

Why: Game composition and debug overlay have different purposes. The first must remain canonical and deterministic; the second must remain opportunistic, screen-space, and independent from scene or sprite semantics.

Trade-offs: The renderer needs a second deferred path, but the game pipeline no longer depends on transient debug state.

Final Visual Ordering Matters More Than Immediate Writes

What: Overlay/debug commands are drained after scene composition, sprite composition, and fades, with parity between scene-bound and no-scene frame paths.

Why: The stable user-visible contract is that debug primitives appear on top. Immediate writes were only an implementation detail, and they stopped preserving that contract once frame composition became deferred and canonical.

Trade-offs: This changes primitive semantics from "write now" to "show at frame end," but it produces the behavior users actually rely on.

Patterns and Algorithms

  • Separate canonical composition state from debug-overlay state even when both reuse the same raster backend.
  • Capture primitives as commands first, then drain them at the final stage where visual priority is unambiguous.
  • Preserve the same overlay semantics whether a scene is bound or not.
  • Keep implementation reuse internal while maintaining a clear semantic boundary in the public model.

Pitfalls

  • Treating debug primitives as part of HUD or scene composition will eventually couple tooling/debug behavior to gameplay pipeline rules.
  • Draining overlay before fades or before final frame composition breaks the visible "always on top" contract.
  • Reusing FrameComposer storage for overlay state collapses the ownership split that prevents these bugs.

Takeaways

  • Immediate framebuffer writes are not a reliable contract once final composition is orchestrated elsewhere.
  • Debug primitives work best as a dedicated final overlay layer.
  • Ownership separation is what keeps debug behavior stable while the canonical render pipeline evolves.