diff --git a/docs/superpowers/plans/2026-06-07-render-unification-outdoor-as-cell.md b/docs/superpowers/plans/2026-06-07-render-unification-outdoor-as-cell.md index 13605a5f..330fdbbe 100644 --- a/docs/superpowers/plans/2026-06-07-render-unification-outdoor-as-cell.md +++ b/docs/superpowers/plans/2026-06-07-render-unification-outdoor-as-cell.md @@ -20,14 +20,37 @@ (The plan's Task 3 fixture sketch had `InsideSide=0`; the shipped test uses the correct `InsideSide=1` — building interior at Y>5 is the negative half-space. `OutdoorCellNode` flips it so the outdoor camera passes the side test.) -- **NEXT: Task 2 + Phase 3 together, INLINE** (not subagent — deeply-contextual GameWindow - render-loop surgery, ends at the visual gate; CLAUDE.md warns against subagent - integration here). Task 2 (build the node each frame) shares the render-loop region with - the Phase 3 cutover, so they're one chunk: extract `GatherNearbyBuildingCells`, resolve - `viewerRoot` to the node outdoors, repoint exit portals to the node in `Build`, unified - draw path, then (after the user's visual gate) delete `BuildFromExterior` / `DrawPortal` / - `OutsideView` / `DrawLandscapeThroughOutsideView`. Do this with fresh context. -- Tree clean; HEAD `c5b4f77`; baselines App 214 / Core 1331-4-1. +- **Task 2 — build the outdoor node each frame — DONE** (`d01fe30`). Additive: `_outdoorNode` + built each outdoor frame from nearby building-entrance portals (Chebyshev ≤1), with an + `[outdoor-node]` probe (ACDREAM_PROBE_FLAP) reporting the live portal count. Not yet rooted + → behaviour unchanged. App.Tests 214/214, build green. (Insertion: `GameWindow.cs` just + before the branch at the old line ~7341; `playerLb` is in scope there.) + +- **NEXT — THE CUTOVER FLIP (the remaining risky, launch-gated chunk), INLINE.** Now fully + de-risked by reading the draw path: + - The shell pass is a **safe no-op** for the synthetic node id — `DrawEnvCellShells` → + `_envCells.Render(pass, {id})` renders nothing for an id with no prepared geometry + (`RetailPViewRenderer.cs:190-202`). So **no explicit shell-exclusion is needed.** + - Indoor→outdoor terrain **already works** via the existing `OutsideView` → terrain-slice + path (`DrawInside` → `DrawLandscapeThroughOutsideView`, `RetailPViewRenderer.cs:79,138`). + The ONLY new piece is the **outdoor-ROOT** case: when `DrawInside` is rooted at the + outdoor node, the node's full-screen view region must become an `OutsideView` slice so + terrain draws full-screen. → Read `ClipFrameAssembler` (how `pvFrame.OutsideView` becomes + `OutsideViewSlices`; how a full-screen region maps to a no-clip terrain slice), then in + `PortalVisibilityBuilder.Build` (or `DrawInside`): when the root is the outdoor node + (`SeenOutside` + outdoor id), `AddRegion(frame.OutsideView, )`. + - Then flip: `viewerRoot = _outdoorNode` when outdoors; `clipRoot = viewerRoot` always + (drop the `playerIndoorGate && viewerRoot != null` gate at `GameWindow.cs:~7346`). This + routes EVERY frame through `_retailPViewRenderer.DrawInside` (the `else` outdoor block + becomes dead — leave it for the post-visual-gate delete). + - **Build → launch (`ACDREAM_PROBE_FLAP` only) → USER VISUAL GATE** at the cottage. Then + delete `BuildFromExterior` / `DrawPortal` / the dead `else` block / `OutsideView`-only + plumbing (Task 7) + cleanup (Phase 4). + - **WARNING:** this is coordinated surgery (Build + ClipFrameAssembler + GameWindow) that + ends at a launch + visual gate; a first attempt rarely renders right. Do it with adequate + context headroom (the dead-zone regression came from rushing a render change before a + visual gate). Verify the [outdoor-node] probe shows real portals FIRST. +- Tree clean; HEAD `d01fe30`; baselines App 214 / Core 1331-4-1. **Baselines that must hold:** build 0 errors; App.Tests 210 pass; Core.Tests 1331 pass / 4 fail (pre-existing) / 1 skip. Run the client per CLAUDE.md "Running the client"; `+Acdream` spawns at the Holtburg/Arcanum cottage. Launch logs are UTF-16. Use `ACDREAM_PROBE_FLAP` only (NOT `ACDREAM_PROBE_SHELL`).