From 9408c062d2222158d7c6291d439172c39a19a14b Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 26 Jun 2026 12:17:27 +0200 Subject: [PATCH] docs: deep handoff for the multi-window UI mockup stage Covers: what's done (UI Studio, faithful importer Fix A/B/C/4/5, Character window), the look-vs-runtime boundary, the mockup goal + approach (host the production UiHost live), must-fix issues (#149 inventory, #150 GameWindow fonts), patterns/lessons, reference map, and first concrete steps. For the next agent. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../2026-06-26-mockup-stage-handoff.md | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 docs/research/2026-06-26-mockup-stage-handoff.md diff --git a/docs/research/2026-06-26-mockup-stage-handoff.md b/docs/research/2026-06-26-mockup-stage-handoff.md new file mode 100644 index 00000000..523c274c --- /dev/null +++ b/docs/research/2026-06-26-mockup-stage-handoff.md @@ -0,0 +1,126 @@ +# 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 **#150**). +- **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 + +- **#149** — 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. +- **#150** — 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 **#149** (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.