# Handoff — the full multi-window UI mockup stage (2026-06-26) For the next agent. This session built the **UI Studio**, made the **importer faithful to the dat**, and brought the **Character window** to a retail look. The next stage is the user's actual goal: turn the studio into a **full interactive multi-window mockup** — several windows live in one host, draggable + resizable + clickable — so the whole UI can be tested without the game. Read this, then `claude-memory/project_ui_studio.md` (the SSOT) and `project_d2b_retail_ui.md`. --- ## 1. Where we are (what's done + works) ### The UI Studio (the dev tool) `AcDream.App ui-studio [--layout 0xNNNN | --dump ] [--screenshot ]` — a standalone Silk.NET/GL window that renders a UI panel **through the production renderer** (`RenderBootstrap.Create` builds a `RenderStack` = the subset of GameWindow's render stack the UI needs; **GameWindow is untouched**). - Code: `src/AcDream.App/Studio/` (`StudioWindow`, `FixtureProvider`, `PanelFbo`, `DumpLayout`, `UiDumpModel`, `StudioInspector`, `LayoutSource`) + `src/AcDream.App/Rendering/RenderBootstrap.cs`. - **Two panel sources:** `--layout 0xNNNN` (real dat-import via `LayoutImporter`, populated by the PRODUCTION controllers through `FixtureProvider` + `SampleData`), and `--dump ` (the 26-window retail dump, `docs/research/2026-06-25-retail-ui-layout-dump.json`, static structure only). - **Headless** `--screenshot ` (PanelFbo → glReadPixels → PNG) — the autonomous self-verify primitive. Use it constantly. - **Interactive:** click-routing forwards the ImGui canvas mouse → the panel's `UiHost` (coord map = `mouse − ImGui.GetItemRectMin()`, no extra Y-flip). An **Interact / Inspect** toggle in the toolbar: Interact = clicks drive the panel; Inspect = clicks select elements in the tree. ### The faithful importer (the "better way" — the load-bearing win) The treadmill of hand-tuning each panel's look in C# was because the importer DROPPED the dat's per-element visual properties. The dat carries them in `StateDesc.Properties`: **0x1A FontDID**, **0x14/0x15** H/V justification, **0x1B FontColor**. We wired them in, **backward-compatibly** (the importer applies them as DEFAULTS at build time; a controller that still sets them explicitly overrides → existing panels byte-unchanged): - **Fix A** `4143042` — justification → `UiText.Centered/RightAligned/VerticalJustify`. - **Fix B** `6e0be4b` — FontColor → `UiText.DefaultColor` (character colors proved RUNTIME — the dat carries none). - **Fix C** `a0d3395` — FontDid → per-element font via a resolver (`Func`) threaded through `LayoutImporter.Import` → `DatWidgetFactory`. **STUDIO path only**; GameWindow passes null (issue **#157**). - **Fix 5** `ad4ed51` — `LayoutImporter.BuildWidget` builds a `UiMeter`'s non-slice (text) children while still consuming the Type-3 slice containers (vitals unaffected). - **Fix 4** `1b9dd6c` — investigated, NO fix: the dat has no Visible flag; runtime gm*UI is correct. **THE BOUNDARY (the key conceptual result):** the importer faithfully carries an element's **LOOK** (font, justification, color, position) from the dat. **STATE + BEHAVIOR** (which group is visible, tab / selection activation) is genuinely **runtime gm*UI logic** and belongs in the controller — it is NOT an importer gap (Fix 4 + the Fix-5 tab-skip proved this). Don't try to push state/visibility into the importer. ### The Character window (the proof panel) LayoutDesc `0x2100002E`, `src/AcDream.App/UI/Layout/CharacterStatController.cs` — Attributes tab reads as retail: 3 tabs, header, big-gold level number (its own dat FontDid), captions, 9-row attribute list (icons + right-aligned values + Health/Stamina/Mana), click-to-select (top/bottom selection bars + footer State-B "{Attr}: {value}" / "Experience To Raise: Infinity!" + affordability-gated raise triangles), centered footer. **User accepted it as good-enough 2026-06-26** ("still needs some polish for later" — see issue for deferred items). Specs: `docs/research/2026-06-25-character-window-faithful-spec.md`, `2026-06-25-attributes-tab-interactive-spec.md`, `2026-06-26-character-window-retail-reference.md`. ### Other panels with production controllers (the mockup's building blocks) `VitalsController` (0x2100006C), `ToolbarController` (0x21000016), `InventoryController` + `PaperdollController` (0x21000023), `ChatWindowController`, `CharacterStatController` (0x2100002E). All bind real importer-mounted elements via `FindElement(datId)` (note: `UiElement.EventId` ≠ the dat id — the dat id lives in `ImportedLayout._byId`). --- ## 2. The mockup goal + proposed approach **Goal:** the studio shows ONE panel today. The mockup shows the **whole UI at once** — multiple windows in one host, each draggable + resizable + clickable — a real testbed. **Why it's reachable:** the production `UiHost` (`src/AcDream.App/UI/UiHost.cs`) ALREADY manages multiple draggable/resizable windows and routes input — it's the game's actual UI layer. The studio just needs to host the full thing instead of one FBO'd panel. (Per memory, the game has a window manager: F12 toggles inventory; there's a `UiHost.ToggleWindow` / `WindowNames` API.) **Proposed path (a new studio "mockup mode"):** 1. Load SEVERAL panels into ONE `UiHost` (not one panel per FBO) — a "desktop." Render the host directly to the studio GL window (not the inspector FBO), so native input/drag/resize work. 2. Window open/close/arrange (reuse the game's window-manager API). 3. Drag + resize via the production frame chrome (already exists for the retail windows). 4. Keep the inspector available as an optional overlay. The studio is the THIN host; the production `UiHost` is the engine. Don't reimplement window management — drive the production one. --- ## 3. Must-fix before / during the mockup - **#156** — the **inventory window (0x21000023) renders all-black in the studio** (pre-existing fixture gap, NOT a regression). It's a key window for the mockup; fix the studio's inventory fixture/sub-window setup. - **#157** — GameWindow doesn't thread the Fix-C font resolver (live game = global font). Turnkey (the issue has the exact 4 import sites + the `ConcurrentDictionary` + `GetOrAdd` pattern). - **Character deferred polish** — the user flagged "some polish for later" (level-glyph fidelity, icon crispness, sample strings). Filed as an issue; the user will enumerate. ## 4. Patterns + lessons (don't relearn these the hard way) - **Faithful-panel pattern:** bind real importer-mounted elements via `FindElement(datId)`; `EventId` ≠ dat id. - **Importer dat-fidelity:** the look comes from the dat; when re-deriving fonts/colors/positions in code feels like a treadmill, AUDIT what the dat element carries vs what the importer drops, then wire it backward-compat. - **The boundary:** look = importer; state/behavior = runtime controller. Don't fight it. - **Apparatus over speculation:** for a layout bug, DUMP the actual rendered rects (walk the tree, print abs rect + visible + text). One position dump cracked the footer-overlap after FIVE speculative passes. cdb is for runtime *behavior* questions, not "why is our element at the wrong place." - **Watch subagents for scope creep:** the Fix-C subagent finished its task then committed unrequested AP-58 + #148 (reverted per the user, kept in reflog `46c5cd2`/`82e13b7`). Constrain dispatches to the assigned task. - **Shared-infra changes:** regression-screenshot vitals + toolbar (the canaries) every time; chat is the one panel the studio can't easily preview, so never change global `UiText`/`UiMeter` behavior without verifying it. ## 5. Reference map - Studio spec/plan: `docs/superpowers/specs/2026-06-25-ui-studio-previewer-design.md`, `docs/superpowers/plans/2026-06-25-ui-studio-previewer.md`; dump sweep `docs/research/2026-06-25-studio-dump-panel-sweep.md`. - Character window: the three specs above + the retail reference. - Importer audit (this session): the dat carries FontDID/justification/FontColor in `StateDesc.Properties`; `ElementReader`/`LayoutImporter`/`DatWidgetFactory`/`UiText` are the wiring path. - The retail UI dump: `docs/research/2026-06-25-retail-ui-layout-dump.json` (26 windows, real ids + rects + sprites). - Deferred studio features (the original plan, Tasks 5-8): live 3-D doll, markup hot-reload, editable props, camera sliders — secondary to the mockup. - Memory SSOT: `claude-memory/project_ui_studio.md`, `project_d2b_retail_ui.md`. ## 6. First concrete steps for the next agent 1. Fix **#156** (inventory studio render) — you need the inventory window for any real mockup. 2. Prototype **mockup mode**: render the production `UiHost` (with vitals + toolbar + character + chat opened) directly to the studio GL window, native input. Confirm drag + resize + click work through the production host. 3. Then iterate window open/close/arrange + the desktop layout.