docs(ui): align architecture with retained runtime

This commit is contained in:
Erik 2026-07-10 16:57:44 +02:00
parent 00ab4a2a64
commit f98050854d
6 changed files with 109 additions and 70 deletions

View file

@ -76,19 +76,17 @@ and `~/.claude/projects/.../memory/` (the latter is browsable in
Obsidian via the `claude-memory/` junction in the repo root; see Obsidian via the `claude-memory/` junction in the repo root; see
`memory/reference_obsidian_vault.md`). `memory/reference_obsidian_vault.md`).
**UI strategy:** three-layer split — swappable backend (ImGui.NET + **UI strategy:** two coexisting presentation stacks over shared state,
`Silk.NET.OpenGL.Extensions.ImGui` for Phase D.2a, custom retail-look ViewModels, events, and commands. ImGui.NET +
toolkit for D.2b later) / stable `AcDream.UI.Abstractions` layer `Silk.NET.OpenGL.Extensions.ImGui` is the permanent
(ViewModels + Commands + `IPanel` / `IPanelRenderer`) / unchanged game `ACDREAM_DEVTOOLS=1` developer stack using `IPanel`/`IPanelRenderer`.
state. **As of Phase I, ImGui hosts every dev/debug panel** — Vitals, Retail gameplay UI is the independent retained `UiHost`/`UiRoot` tree in
Chat, Debug. The previous custom-StbTrueTypeSharp `DebugOverlay` was `AcDream.App/UI`, imported from LayoutDesc/DAT assets and bound by focused
deleted in I.2; `TextRenderer` + `BitmapFont` are kept alive controllers. The stable cross-stack seam is ViewModels/commands, not a backend
specifically for the future world-space HUD (D.6 — damage floaters, swap. `TextRenderer` + `BitmapFont` also serve D.6 world-space HUD elements
name plates) where ImGui can't reach into the 3D scene. D.2b remains where ImGui cannot reach the 3D scene. Plugin gameplay UI uses the BCL-only
the long-term retail-look path (panels reskinned one at a time using `AcDream.Plugin.Abstractions.IUiRegistry.AddMarkupPanel` contract; plugins
dat assets); ImGui persists forever as the `ACDREAM_DEVTOOLS=1` never import App or ImGui namespaces. Full design:
overlay. **All plugin-facing UI targets `AcDream.UI.Abstractions`
never import a backend namespace from a panel.** Full design:
[`docs/plans/2026-04-24-ui-framework.md`](docs/plans/2026-04-24-ui-framework.md). [`docs/plans/2026-04-24-ui-framework.md`](docs/plans/2026-04-24-ui-framework.md).
Memory cribs: `memory/project_chat_pipeline.md` (chat pipeline as of Memory cribs: `memory/project_chat_pipeline.md` (chat pipeline as of
Phase I), `memory/project_input_pipeline.md` (input pipeline as of Phase I), `memory/project_input_pipeline.md` (input pipeline as of

View file

@ -1674,7 +1674,7 @@ R5/R6 touches the action list. **Where:**
## #165 — Reconcile the UI design docs with the shipped D.2b shape ## #165 — Reconcile the UI design docs with the shipped D.2b shape
**Status:** OPEN **Status:** DONE (2026-07-10, retail UI fidelity Wave 0)
**Severity:** MEDIUM **Severity:** MEDIUM
**Filed:** 2026-07-02 **Filed:** 2026-07-02
**Component:** docs **Component:** docs
@ -1689,6 +1689,13 @@ R5/R6 touches the action list. **Where:**
**Acceptance:** both docs describe the two-stack reality; the plugin markup-vs-IPanel decision is written down. **Acceptance:** both docs describe the two-stack reality; the plugin markup-vs-IPanel decision is written down.
**Resolution:** `CLAUDE.md`, `acdream-architecture.md`, and
`2026-04-24-ui-framework.md` now describe the shipped two-stack architecture.
`IPanel`/`IPanelRenderer` is the permanent first-party ImGui devtools contract;
the retained `UiRoot` tree is gameplay UI; both share ViewModels/commands/state.
Plugin gameplay UI is explicitly `IUiRegistry.AddMarkupPanel` and remains
BCL-only.
--- ---
## #158 — Character window — deferred polish ## #158 — Character window — deferred polish

View file

@ -71,32 +71,38 @@ well-defined interfaces that the retail client never had.
└──────────────────────────────────────────────────────────────┘ └──────────────────────────────────────────────────────────────┘
``` ```
### UI Architecture (companion stack, spans Layers 1 & 5) ### UI Architecture (two coexisting presentation stacks)
The UI is split into its own three-layer stack with a swappable backend, The 2026-04-24 design began with a swappable renderer abstraction. D.2b proved
designed 2026-04-24. Full design: `docs/plans/2026-04-24-ui-framework.md`. that retail fidelity needs a retained LayoutDesc/DAT tree, while ImGui remains
valuable as permanent devtools. The current architecture therefore has two
presentation stacks over shared state, ViewModels, events, and commands. Full
history and the corrected contract live in
`docs/plans/2026-04-24-ui-framework.md`.
``` ```
┌─────────────────────────────────────────────────────────────┐ ┌─────────────────────────────────────────────────────────────┐
│ UI BACKEND (swappable) │ DEVELOPER UI
│ ImGui.NET + Silk.NET.OpenGL.Extensions.ImGui │ IPanel/IPanelRenderer → permanent ImGui devtools
(Phase D.2a, short-term) GAMEPLAY UI
or custom retail-look toolkit (Phase D.2b, later) LayoutDesc/DAT → UiRoot retained widgets + controllers
├─────────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────────┤
AcDream.UI.Abstractions (stable contract) SHARED CONTRACTS
│ ViewModels, Commands, IPanel, IPanelHost, IPanelRenderer │ ViewModels, commands, input actions, state/event services
│ ► plugin-facing UI API lives HERE, not in the backend │ ► one model and mutation path, two presentation projections
├─────────────────────────────────────────────────────────────┤ ├─────────────────────────────────────────────────────────────┤
│ Game state + events (unchanged) │ │ Game state + events (unchanged) │
│ IGameState / IEvents / WorldSession — UI only reads │ │ IGameState / IEvents / WorldSession — UI only reads │
└─────────────────────────────────────────────────────────────┘ └─────────────────────────────────────────────────────────────┘
``` ```
The backend is pluggable; ViewModels / Commands / `IPanelRenderer` are `AcDream.UI.Abstractions` owns backend-neutral ViewModels, commands, input,
stable across the swap. ImGui persists forever as the and the `IPanel`/`IPanelRenderer` devtools contract. `AcDream.App/UI` owns the
`ACDREAM_DEVTOOLS=1` devtools overlay regardless of which backend owns retained gameplay tree, LayoutDesc importer, window runtime, and panel
the game UI. The full UI design lives in controllers. Neither presentation stack owns independent game-state truth.
`docs/plans/2026-04-24-ui-framework.md`. Plugins register retained gameplay markup through the BCL-only
`AcDream.Plugin.Abstractions.IUiRegistry`; they do not import App or ImGui
assemblies.
--- ---

View file

@ -486,7 +486,8 @@ behavior. Estimated 1726 days focused work, 35 weeks calendar.
- **✓ SHIPPED — Importer dat-fidelity** (Fix A/B/C, 2026-06-26, same branch). **Boundary established: look = importer (font/justification/color from dat); state/behavior = runtime controller logic.** Fix A: justification property `0x14`/`0x15``UiText` Centered/RightAligned/VerticalJustify. Fix B: FontColor property `0x1B``UiText.DefaultColor`; character colors proved RUNTIME (no importer fix). Fix C: FontDid → per-element dat font via a resolver in `DatWidgetFactory`**STUDIO path only**; GameWindow passes `null` (Issue #157). Fix 4 (UIState-group activation): INVESTIGATED — no importer fix exists; the dat has no Visible encoding; runtime `gm*UI` is correct. - **✓ SHIPPED — Importer dat-fidelity** (Fix A/B/C, 2026-06-26, same branch). **Boundary established: look = importer (font/justification/color from dat); state/behavior = runtime controller logic.** Fix A: justification property `0x14`/`0x15``UiText` Centered/RightAligned/VerticalJustify. Fix B: FontColor property `0x1B``UiText.DefaultColor`; character colors proved RUNTIME (no importer fix). Fix C: FontDid → per-element dat font via a resolver in `DatWidgetFactory`**STUDIO path only**; GameWindow passes `null` (Issue #157). Fix 4 (UIState-group activation): INVESTIGATED — no importer fix exists; the dat has no Visible encoding; runtime `gm*UI` is correct.
- **✓ SHIPPED — Character window** (`LayoutDesc 0x2100002E`, `CharacterStatController`, 2026-06-26, same branch). **Visually user-confirmed 2026-06-26 — Attributes tab reads as retail.** Three tabs, header (name/heritage/PK), large-gold level number (dat font, `largeDatFont` 18px), "Total Experience (XP):" + "XP for next level:" captions, 9-row attribute list (icons + right-aligned values + Health/Stamina/Mana vitals), click-to-select (top/bottom selection bars + footer State-B "{Attr}: {value}" / "Experience To Raise: Infinity!" + affordability-gated raise triangles), centered footer. User noted "still needs some polish for later" — deferred to Issue #158. - **✓ SHIPPED — Character window** (`LayoutDesc 0x2100002E`, `CharacterStatController`, 2026-06-26, same branch). **Visually user-confirmed 2026-06-26 — Attributes tab reads as retail.** Three tabs, header (name/heritage/PK), large-gold level number (dat font, `largeDatFont` 18px), "Total Experience (XP):" + "XP for next level:" captions, 9-row attribute list (icons + right-aligned values + Health/Stamina/Mana vitals), click-to-select (top/bottom selection bars + footer State-B "{Attr}: {value}" / "Experience To Raise: Infinity!" + affordability-gated raise triangles), centered footer. User noted "still needs some polish for later" — deferred to Issue #158.
- **✓ SHIPPED — D.5.4 — Client object/item data model (foundation).** Shipped 2026-06-18 (`b506f53`..`a33e897`, 11 commits). Renamed `ItemRepository``ClientObjectTable` / `ItemInstance``ClientObject`; broadened the table to hold EVERY server object (retail `weenie_object_table` shape). `CreateObject` is now the canonical merge-upsert (`ClientObjectTable.Ingest`, retail `SetWeenieDesc` semantics) via a new Core.Net `ObjectTableWiring` (off GameWindow); `DeleteObject` evicts; `PlayerDescription` is a membership manifest (`RecordMembership`); live container-membership index (`GetContents`, retail `object_inventory_table`). `_liveEntityInfoByGuid` retired (selection/describe resolve from the one table). Root fix: the old enrich-existing-only `EnrichItem` dropped `CreateObject`s for items with no `PlayerDescription` stub — live-Coldeve 4/6 hotbar slots blank; items are now created, not dropped. **Crux resolved:** retail is TWO tables (`object_table` + `weenie_object_table`), NOT one — acdream's `WorldEntity` (3D system) + `ClientObjectTable` (data/UI) split was already architecturally faithful; the fix was the ingestion path, not a table unification. 2671 tests green. - **✓ SHIPPED — D.5.4 — Client object/item data model (foundation).** Shipped 2026-06-18 (`b506f53`..`a33e897`, 11 commits). Renamed `ItemRepository``ClientObjectTable` / `ItemInstance``ClientObject`; broadened the table to hold EVERY server object (retail `weenie_object_table` shape). `CreateObject` is now the canonical merge-upsert (`ClientObjectTable.Ingest`, retail `SetWeenieDesc` semantics) via a new Core.Net `ObjectTableWiring` (off GameWindow); `DeleteObject` evicts; `PlayerDescription` is a membership manifest (`RecordMembership`); live container-membership index (`GetContents`, retail `object_inventory_table`). `_liveEntityInfoByGuid` retired (selection/describe resolve from the one table). Root fix: the old enrich-existing-only `EnrichItem` dropped `CreateObject`s for items with no `PlayerDescription` stub — live-Coldeve 4/6 hotbar slots blank; items are now created, not dropped. **Crux resolved:** retail is TWO tables (`object_table` + `weenie_object_table`), NOT one — acdream's `WorldEntity` (3D system) + `ClientObjectTable` (data/UI) split was already architecturally faithful; the fix was the ingestion path, not a table unification. 2671 tests green.
- **☐ D.5.3 — Toolbar selected-object display (issue #140) + spell shortcuts.** Wire the B.4 `WorldPicker`/selection state → the two hidden meters (`0x100001A1` health / `0x100001A2` mana) + the stack slider (`0x100001A4`) + the object-name line, so the bar shows the player's currently-selected world object. Plus **spell shortcuts** — pinned *spells* (vs items) don't render their glyphs yet (`ToolbarController.Populate` skips `ObjectGuid==0`). Together these finish "the bar." (Click-to-use + the peace/war stance indicator landed in D.5.1.) - **Roadmap correction (2026-07-10):** the completion order is now the architecture-first campaign in `docs/superpowers/plans/2026-07-10-retail-ui-fidelity-completion.md`. Retail `gmToolbarUI` is object-only: preserve `ShortCutData.index_`, `objectID_`, and `spellID_`, but do not invent spell glyphs on this bar. `PlayerModule::favorite_spells_[8]` feeds separate spell bars.
- **☐ D.5.3 — Toolbar selected-object display (issue #141) + exact shortcut preservation.** Wire unified selection to the hidden mana meter (`0x100001A2`), stack entry (`0x100001A3`), stack slider (`0x100001A4`), and complete health/name behavior. Preserve all raw `ShortCutData` fields while keeping `gmToolbarUI` object-only, matching `UpdateFromPlayerDesc @ 0x004BF810`. The eight `favorite_spells_` lists belong to the separate spellbook/spell-bar phase. (Click-to-use + peace/war + health/name already landed.)
- **☐ D.5.5+ — Core panels.** Inventory (`gmInventoryUI`/`gmBackpackUI`), equipment/paperdoll (`gmPaperDollUI`/`gm3DItemsUI` + the `UiViewport` 3D doll), vendor, trade, spellbook. Research drop done (`docs/research/2026-06-16-*`). Depends on **D.5.4** (data model) + the item-slot/list/icon spine (D.5.1/D.5.2) + the **window manager** (Plan 2: open/close/z-order/persist + faithful grip/dragbar drag-resize) + the drag-drop spine wired (`UiRoot` has the chain; the per-cell accept/drop hooks are still stubs in `UiField`). Also deferred from D.5.1: drag/reorder + the `AddShortcut`/`RemoveShortcut` mutate wire. - **☐ D.5.5+ — Core panels.** Inventory (`gmInventoryUI`/`gmBackpackUI`), equipment/paperdoll (`gmPaperDollUI`/`gm3DItemsUI` + the `UiViewport` 3D doll), vendor, trade, spellbook. Research drop done (`docs/research/2026-06-16-*`). Depends on **D.5.4** (data model) + the item-slot/list/icon spine (D.5.1/D.5.2) + the **window manager** (Plan 2: open/close/z-order/persist + faithful grip/dragbar drag-resize) + the drag-drop spine wired (`UiRoot` has the chain; the per-cell accept/drop hooks are still stubs in `UiField`). Also deferred from D.5.1: drag/reorder + the `AddShortcut`/`RemoveShortcut` mutate wire.
- **D.6 — HUD.** **Radar/compass IMPLEMENTED 2026-07-10; live-world visual gate pending.** It is the retained retail `gmRadarUI` (`LayoutDesc 0x21000074`): a 120×140 circular radar (`0x06004CC1`) with N/E/S/W token sprites orbiting the face, a fixed bright-green player marker, and the coordinate footer (`0x06004CC0`). Projection is `radarPixelRadius / radarRange` with 75 m outdoor / 25 m indoor ranges — there is no 1.18 factor or scrolling compass strip. It lives in `AcDream.App/UI` beside the other imported retail panels. Remaining D.6: target name plate, damage floaters, and other world-space HUD elements through the raw `TextRenderer` path. See slice 06 §A.2, `docs/research/2026-07-10-retail-radar-pseudocode.md`, and the named `gmRadarUI` decomp. - **D.6 — HUD.** **Radar/compass IMPLEMENTED 2026-07-10; live-world visual gate pending.** It is the retained retail `gmRadarUI` (`LayoutDesc 0x21000074`): a 120×140 circular radar (`0x06004CC1`) with N/E/S/W token sprites orbiting the face, a fixed bright-green player marker, and the coordinate footer (`0x06004CC0`). Projection is `radarPixelRadius / radarRange` with 75 m outdoor / 25 m indoor ranges — there is no 1.18 factor or scrolling compass strip. It lives in `AcDream.App/UI` beside the other imported retail panels. Remaining D.6: target name plate, damage floaters, and other world-space HUD elements through the raw `TextRenderer` path. See slice 06 §A.2, `docs/research/2026-07-10-retail-radar-pseudocode.md`, and the named `gmRadarUI` decomp.
- **D.7 — Cursor manager.** OS + dat-sourced custom cursors (`FUN_0043c1c0` GDI HCURSOR builder pattern from slice 03). **(D.2b dependency.)** - **D.7 — Cursor manager.** OS + dat-sourced custom cursors (`FUN_0043c1c0` GDI HCURSOR builder pattern from slice 03). **(D.2b dependency.)**

View file

@ -1,11 +1,11 @@
# UI framework plan # UI framework plan
**Date:** 2026-04-24 (design), shipped 2026-04-25 **Date:** 2026-04-24 (design), shipped 2026-04-25
**Status:** **Phase D.2a shipped**`AcDream.UI.Abstractions` + ImGui backend **Status:** **Phase D.2a and the D.2b retained gameplay UI have shipped.**
+ `VitalsPanel` gated on `ACDREAM_DEVTOOLS=1`. Backend pivoted from ImGui remains the `ACDREAM_DEVTOOLS=1` developer stack. Retail gameplay UI is
`Hexa.NET.ImGui` to `ImGui.NET` + `Silk.NET.OpenGL.Extensions.ImGui` during the independent `UiHost`/`UiRoot` retained tree under `AcDream.App/UI`, built
first-light integration — see the pivot note below. Phase D.2b (custom from production LayoutDesc/DAT assets. The stable cross-stack seam is game
retail-look backend) remains design-only. state, ViewModels, and commands — not an `IPanelRenderer` backend swap.
**Owner:** lead engineer (erik) + Claude **Owner:** lead engineer (erik) + Claude
Captures the UI strategy agreed via discussion on 2026-04-24. Documents Captures the UI strategy agreed via discussion on 2026-04-24. Documents
@ -53,12 +53,12 @@ panel, skills, spellbook, fellowship, allegiance, trade, options, map,
quest log, tooltips — and a first-class plugin API so plugin authors can quest log, tooltips — and a first-class plugin API so plugin authors can
ship their own panels. ship their own panels.
## Strategy: two-phase, one stable interface ## Current strategy: two coexisting stacks, shared state contracts
``` ```
┌─────────────────────────────────────────┐ ┌─────────────────────────────────────────┐
UI backend ─ ImGui (short-term) │ ← swappable Developer UI ─ ImGui + IPanelRenderer │
─ Custom retail (later) Gameplay UI ─ UiRoot retained widgets
├─────────────────────────────────────────┤ ├─────────────────────────────────────────┤
│ ViewModels + Commands (per panel) │ ← stable contracts │ ViewModels + Commands (per panel) │ ← stable contracts
├─────────────────────────────────────────┤ ├─────────────────────────────────────────┤
@ -66,14 +66,16 @@ ship their own panels.
└─────────────────────────────────────────┘ └─────────────────────────────────────────┘
``` ```
- **Near term:** wire an ImGui-based overlay so we can iterate on game - **Developer stack:** `AcDream.UI.Abstractions` panels render through
logic fast — chat that actually sends + receives, inventory that `IPanelRenderer` on ImGui. This stack is permanent for diagnostics, packet
reflects real state, vitals bar that reads real HP/stam/mana. Looks inspection, settings development, and other devtools.
like a debugger, that's fine for now. - **Gameplay stack:** `UiHost` owns a retained `UiRoot` tree. `LayoutImporter`
- **Later:** replace the visual layer with a custom toolkit that uses builds retail windows from LayoutDesc/DAT assets and focused `gm*UI`-style
retail dat assets (icons, panels, fonts) and matches retail's feel. controllers bind runtime values and actions.
- **Always:** ViewModels and Commands stay stable across the swap. The - **Shared seam:** both stacks consume the same session state, ViewModels, and
game logic never learns which backend is drawing it. command/event services. A panel is ported to retained UI by binding those
shared models to its DAT-authored tree, not by implementing
`IPanelRenderer` a second time.
## Choice: Hexa.NET.ImGui for the short-term backend ## Choice: Hexa.NET.ImGui for the short-term backend
@ -158,7 +160,7 @@ public sealed record EquipItemCmd(uint ItemGuid, EquipSlot Slot);
Dispatched to an `ICommandBus` that routes to the appropriate subsystem Dispatched to an `ICommandBus` that routes to the appropriate subsystem
(`WorldSession.SendSelect`, `ChatService.Send`, etc.). (`WorldSession.SendSelect`, `ChatService.Send`, etc.).
### Layer 3 — UI backend ### Layer 3a — ImGui developer backend
New module: `src/AcDream.UI.ImGui/`. References `AcDream.UI.Abstractions`. New module: `src/AcDream.UI.ImGui/`. References `AcDream.UI.Abstractions`.
@ -168,11 +170,34 @@ New module: `src/AcDream.UI.ImGui/`. References `AcDream.UI.Abstractions`.
per frame. per frame.
- Keyboard / mouse / focus handled by ImGui natively. - Keyboard / mouse / focus handled by ImGui natively.
Later: `src/AcDream.UI.Retail/` references the same `AcDream.UI.Abstractions` This layer remains the permanent devtools surface. It is not the production
and implements the same `IPanel` / `IPanelHost` interfaces — but draws retail gameplay renderer.
with our own retained-mode toolkit + retail dat assets.
## Plugin API (must be backend-agnostic) ### Layer 3b — retained retail gameplay UI
`src/AcDream.App/UI/` contains the GL-free widget tree, LayoutDesc importer,
window runtime, and panel controllers. Rendering dependencies enter through
small sprite/font/viewport resolver seams. Controllers consume the same
ViewModels and command services used by the ImGui panels, while binding
behavior to existing retail element ids instead of procedurally redrawing the
panel through `IPanelRenderer`.
## Plugin UI API
The shipped plugin-facing gameplay UI contract is
`AcDream.Plugin.Abstractions.IUiRegistry.AddMarkupPanel`: a plugin provides
KSML-style markup and a binding object; the host builds it into the retained
`UiRoot` tree. `IPanel`/`IPanelRenderer` remains a first-party developer-panel
contract and is intentionally not referenced by `Plugin.Abstractions`.
This makes plugin gameplay panels independent of ImGui while allowing them to
share the retained input, window, and DAT-sprite runtime. Registrations made
before the GL host exists are buffered. In builds where retail UI is disabled,
they remain registered but have no gameplay surface; the long-term release
configuration enables retained gameplay UI.
The following was the original pre-D.2b proposal and remains historical
context, not the shipped plugin contract:
```csharp ```csharp
public interface IPanel public interface IPanel
@ -227,32 +252,34 @@ walk around / take damage / regen.
to equip, drag target for future move. to equip, drag target for future move.
- `CharacterPanel` — attributes, skills, XP. - `CharacterPanel` — attributes, skills, XP.
### Sprint 3 — Plugin API hardening ### Sprint 3 — Plugin API hardening (superseded shape)
- Document the `IPanel` contract. - Document the `IPanel` contract.
- Port the smoke plugin to register a demo panel via the API. - The shipped route is `IUiRegistry.AddMarkupPanel`, not plugin-owned
- Confirm plugins can subscribe to game events AND draw UI through the `IPanel` implementations.
same interface. - Confirm plugins can subscribe to game events and expose retained markup
bindings without referencing App or ImGui assemblies.
### Sprint 4+ — More panels ### Sprint 4+ — More panels
Spellbook, allegiance, fellowship, trade, map, quest log, options. Spellbook, allegiance, fellowship, trade, map, quest log, options.
Continue to expand `InventoryPanel` with drag-drop, split, appraise. Continue to expand `InventoryPanel` with drag-drop, split, appraise.
### Later — Custom retail-look backend ### D.2b — retained retail-look gameplay UI (shipped, expanding panel by panel)
`AcDream.UI.Retail` implements `IPanelRenderer` with our own toolkit + `AcDream.App/UI` imports LayoutDesc trees and draws retail DAT assets through
retail dat assets. Swap panels one at a time. ImGui overlay remains for the retained `UiRoot` runtime. ImGui remains available for devtools; shared
devtools. ViewModels and commands prevent duplicate game-state logic.
## Non-goals for this first pass ## Non-goals for this first pass
- **Not** going to theme ImGui to look retail. Waste of effort when we'll - **Not** going to theme ImGui to look retail. Waste of effort when we'll
swap the backend. Devtools aesthetic is fine. swap the backend. Devtools aesthetic is fine.
- **Not** porting retail's widget code. We use their ASSETS later, not - **Not** byte-porting Keystone internals that are unavailable. Observable
their widget implementation. widget behavior is recovered from the named client call sites, DAT
- **Not** building layout DSL / XAML-like markup. Panels register and properties, and live retail evidence.
draw procedurally, same as ImGui. - **Not** hand-authoring first-party gameplay layouts where retail LayoutDesc
data exists. KSML-style markup remains the plugin/extension layout surface.
## Alternatives considered ## Alternatives considered
@ -271,13 +298,13 @@ devtools.
**Mitigation:** code review every addition; if a feature only exists **Mitigation:** code review every addition; if a feature only exists
in ImGui and the retail toolkit can't express it, don't add it. in ImGui and the retail toolkit can't express it, don't add it.
- **Risk:** Swap to custom backend breaks a dozen panels simultaneously. - **Risk:** ImGui and retained controllers grow separate game-state truth.
**Mitigation:** swap one panel at a time, keep ImGui rendering the **Mitigation:** one session model/ViewModel and one command path per
rest until all are ported. subsystem; each surface is only a projection.
- **Risk:** Plugin authors write panels that only work in ImGui. - **Risk:** Plugin markup relies on App-only widget details.
**Mitigation:** smoke plugin registers a panel early; use it as a **Mitigation:** keep `IUiRegistry` BCL-only, resolve bindings by contract,
canary whenever backend changes. and use a smoke plugin as the retained-runtime canary.
- **Risk:** Hexa.NET.ImGui stops being maintained. - **Risk:** Hexa.NET.ImGui stops being maintained.
**Mitigation:** integration is small (<100 LOC), switching to **Mitigation:** integration is small (<100 LOC), switching to

View file

@ -532,7 +532,7 @@ Open the inventory panel — retail-skinned with the right font, icons, and
local lighting). local lighting).
- **C.3** — Palette range tuning (skin/hair/eye colors match retail). - **C.3** — Palette range tuning (skin/hair/eye colors match retail).
- **C.4** — Double-sided translucent polys. - **C.4** — Double-sided translucent polys.
- **D.2b** — Custom retail-look UI backend. **In progress:** vitals + chat + toolbar + inventory (window manager, B-Grid, B-Controller, B-Wire, drag-drop, container-switching) + paperdoll (equip slots, 3-D doll UiViewport, Slots toggle) + **Character window** (Attributes tab, visually confirmed 2026-06-26) + **UI Studio** (standalone panel previewer + 26-window retail dump + interactive click-routing + headless screenshot) + **importer dat-fidelity** (Fix A/B/C: justification, FontColor, per-element FontDid resolver [studio-only; #157 tracks live-game path]) are shipped. Next: D.5.3 selected-object bar + spell shortcuts; #158 Character window polish deferred. - **D.2b** — Custom retail-look UI backend. **In progress:** vitals + chat + toolbar + inventory (window manager, B-Grid, B-Controller, B-Wire, drag-drop, container-switching) + paperdoll (equip slots, 3-D doll UiViewport, Slots toggle) + **Character window** (Attributes tab, visually confirmed 2026-06-26) + **UI Studio** (standalone panel previewer + 26-window retail dump + interactive click-routing + headless screenshot) + **importer dat-fidelity** (Fix A/B/C: justification, FontColor, per-element FontDid resolver [studio-only; #157 tracks live-game path]) are shipped. Current campaign: shared retained-widget/window architecture, then selected-object mana/stack completion. **Retail correction:** the main toolbar is object-only; the eight favorite-spell lists drive separate spell bars. Execution plan: `docs/superpowers/plans/2026-07-10-retail-ui-fidelity-completion.md`.
- **D.3D.7** — AcFont + dat sprites + core panels reskinned + HUD orbs + - **D.3D.7** — AcFont + dat sprites + core panels reskinned + HUD orbs +
cursor manager. **D.6 radar/compass shipped 2026-07-10** through the retained cursor manager. **D.6 radar/compass shipped 2026-07-10** through the retained
UI architecture using the retail DAT layout and recovered runtime behavior; UI architecture using the retail DAT layout and recovered runtime behavior;