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

57 lines
2.9 KiB
Markdown

---
id: LSN-0033
ticket: deferred-overlay-and-primitive-composition
title: Debug Primitives Should Be a Final Overlay, Not Part of Game Composition
created: 2026-04-18
tags: [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.