# 2026-07-08 - Material render to default (ROADMAP #27) ``` Type: log ``` ## Intent Implement [material-render.md](../interface/material-render.md): pay the HD-2D prototype's enumerated debts and flip the material render from an F3 preview to the default Bevy physical view. Frontend + assets + wiki only; no sim/save changes (the parallel building.md session owned the sim this day). ## The occlusion decision (debt 1) Three variants were screenshotted with the `MISALIGNED_SHOT=wide|close` harness and compared (session scratchpad `material/`): - `before_wide/close.png` — the landed prototype: 40 degree pitch, full walls. The wall row south of the core room hides the first interior tiles; the dark region south of the amber room reads as missing scene. - `pitch55_wide/close.png` — 55 degree pitch, full walls. Interiors improve slightly but the first tile behind every wall stays hidden, and the steeper camera flattens exactly what the material render is for: wall faces, prop billboards, and depth shrink toward a textured top-down map. - `after_cutaway_wide/close.png` — 40 degrees plus cutaway: structural blocks whose KNOWN north neighbor is open interior drop to a 0.34 parapet (doors to a 0.62 slab so a doorway still reads as a door). Strictly more earned interior is visible at the same depth feel; the previously hidden remembered/blueprint space south of the core room becomes legible. Verdict: **cutaway at the 40 degree pitch**. The rule is fog-gated — an unknown north neighbor keeps full wall height — so wall height never leaks whether unscouted space behind a wall is open (legibility law). Cutaway state is derived per frame in `restyle_3d` by handle-swapping between pooled full/cutaway meshes; nothing is mutated per tile. ## The other debts - **Top caps (debt 2):** every extruded box gets a `TilePart::Top` cap plane with a dedicated pooled material — concrete grain darkened per structural class (gunmetal for walls, near-black for rock, worn metal for door slabs, a crimson-tinged cap for security mass). No more side texture smeared across top faces. Caps ride the cutaway height. - **Palette sweep (debt 3):** a hue audit of `assets/pixellab/tiles/` found four tiles predating the clinical manifest suffix: door (24% purple), b1_ups (25%), b1_hvac_unit (13%), b1_switch (11%). Deterministic in-place remap: violet and dim magenta to desaturated gunmetal, bright magenta LEDs to sterile amber (machine presence, not decoration), saturated teal to gunmetal. Re-audit shows no stale bands anywhere in the b1 set (`palette_before_after.png` in the scratchpad; pixel-pipeline.md updated). - **Fog contract (debt/criterion 4):** the shot harness now runs `fog_audit_3d` on every material capture: it asserts unknown tiles have no visible geometry, visible non-seen surfaces are unlit model state, seen surfaces are lit, and person billboards are coverage-gated; it panics on any violation. Output from the landing run: `fog audit OK: 4608 tile entities (unknown=absent, model=unlit, seen=lit), 5 people billboards coverage-gated, material pool 37 handles`. - **Framing floor (criterion 5):** checked at min/default/max zoom (`final_zoom_min.png`, `after_cutaway_wide.png`, `final_zoom_max.png`). The old `[`/`]` bounds (0.15-2.5) failed at both ends — pixel soup close up, postage-stamp cluster in void at 2.5 — so the material zoom clamps tightened to 0.25-1.6. At 1.6 the full known extent frames with reach traces legible; at 0.25 tile art stays above native scale. - **Pooling (criterion 6):** already keyed (tile, fog, part) from the prototype; the cutaway pass extended it with pooled mesh handle swaps and the audit now prints the pool size as evidence (37 handles across ~4600 tile entities; no per-tile material creation in the frame loop). - **Default flip (criterion 7):** `RenderMode::default` is material; F3 flips to the flat sensorium and back (log lines and sidebar label updated); README and bevy.md updated. The sensorium remains byte-for-byte the digital dialect; the flip is frontend-only and never saved. Relation to views.md kept honest: views.md's digital-home default governs the full two-view mechanic and remains READY; this flip sets the *treatment* of the Bevy physical canvas per material-render.md, whose constitution line reads this as the real/material half of the same-frame contract. ## Verification `./tools/check.sh` green before and after rebase onto origin/main. Bevy launch check clean in both render modes (material default and F3 sensorium; the only ERROR line is the machine-local gilrs IOHIDManager gamepad noise). Flat-mode screenshot (`final_flat.png`) composition-identical to the pre-change sensorium; fog audit output recorded above; screenshots reviewed in this log. Cast-quality person art stays with ROADMAP #13 (spec debt 6 is explicitly out of scope until the sprite pass).