# Handoff — D.2b inventory window finish (Stage 1) shipped + visually confirmed; slot-art + paperdoll next **Date:** 2026-06-21 (after B-Wire) **From:** the session that shipped **B-Wire** (inventory wire layer) **and Stage 1 of the inventory window finish** (scroll + frame + vertical resize + 102-slot grid), both visually confirmed at the live gate. **Branch:** `claude/hopeful-maxwell-214a12`, tip **`1be7e65`** (+ this docs commit). `main` is a clean ff ancestor — ff `main` + branch fresh, or continue this branch. **Line numbers drift — grep the symbol.** --- ## 0. What shipped this session (all committed, build + full suite green, VISUALLY CONFIRMED) Full suite green (`--no-build`, with the client running): **Core.Net 334 / App 543 / UI 425 / Core 1530**, 0 failures. ### B-Wire — inventory wire layer (`b56087b`→`7c006d1`) The burden bar now reads the server's wire `EncumbranceVal` (PropertyInt 5). Root cause was **delivery, not binding**: login PD dropped the player's int table, live `0x02CD` was unparsed, and `ObjectTableWiring` gated non-UiEffects ints out. Plus the full inventory wire pass (DropItem 0x001B / GetAndWieldItem 0x001A / NoLongerViewingContents 0x0195 builders; ViewContents 0x0196 / SetStackSize 0x0197 / InventoryRemoveObject 0x0024 parsers; 0x0022 + 0x00A0 field fixes). Spec/plan `docs/superpowers/{specs,plans}/2026-06-21-d2b-inventory-wire*.md`. Detail: the B-Wire SHIPPED entry in `claude-memory/project_d2b_retail_ui.md`. ### Inventory window finish Stage 1 (`366af0c`→`1be7e65`) Spec/plan `docs/superpowers/{specs,plans}/2026-06-21-d2b-inventory-window-finish*.md`. - **Scroll** — `UiItemList` clip+scroll via the shared `UiScrollable`; gutter scrollbar `0x100001C7` bound like `ChatWindowController`; mouse-wheel. - **Frame** — wrapped in the 8-piece bevel chrome (`UiNineSlicePanel`), like vitals/chat/toolbar. - **Vertical resize** — bottom-edge only (horizontal blocked); the grid + sub-window + scrollbar + backdrop stretch, paperdoll + side-bags pinned; scrollbar thumb reflects view/content. - **102-slot grid** — contents grid pads empty frames to the main-pack capacity (default 102); side-bag column pads to 7. --- ## 1. Read first - This doc. - `claude-memory/project_d2b_retail_ui.md` — the **Stage 1 SHIPPED** entry + DO-NOT-RETRY (updated this session). - `docs/ISSUES.md` — the **OPEN** "Inventory + equipment slots show the wrong empty-slot background art" issue (the immediate next task) + the two **SHIPPED** entries. - `docs/architecture/retail-divergence-register.md` — AP-52 (side-bag 7 fallback), AP-53 (main-pack 102 fallback), AP-54 (resize approximation), AP-51 (main-pack icon, still open). - `docs/research/2026-06-16-equipment-paperdoll-deep-dive.md` — for Stage 2 (paperdoll). - `.layout-dumps/uiitem-0x21000037.txt` — the UIItem cell template states (for the correct empty-slot sprite). --- ## 2. Key discoveries (durable, non-obvious — DO-NOT-RETRY) 1. **Grid cells must be `Anchors = None`.** `UiElement.DrawSelfAndChildren` runs `ApplyAnchor` on every child AFTER `OnDraw`; with default `Left|Top` anchors it captured each cell's scroll-0 position and reset `Top` to it every frame, fighting `UiItemList.LayoutCells`' scroll offset → the grid "escaped the window" when scrolled. `AddItem` now sets `cell.Anchors = None` so `LayoutCells` is the sole authority. **The unit tests missed it by calling `LayoutCells` in isolation, never the draw traversal** — the regression test now drives the `ApplyAnchor` interaction. (Fix `14ea938`.) 2. **Scroll reuses `UiScrollable` + a whole-row logical clip (no GL scissor)** — mirrors `UiText.cs:198` (`cell.Visible = top >= 0 && top + h <= Height`). The gutter scrollbar `0x100001C7` is a factory Type-11 `UiScrollbar` inheriting base `0x2100003E`; bind its `Model` to `grid.Scroll` + the same scrollbar sprite ids the chat scrollbar uses. 3. **Vertical-resize cascade via anchors.** Frame: `Resizable=true; ResizeX=false; ResizableEdges=Bottom`. The stretch elements (grid `0x100001C6`, its sub-window `0x100001CF`, scrollbar `0x100001C7`, backdrop `0x100001D0`, + the content root) get `Anchors=Left|Top|Bottom` (fixed width, height tracks parent); paperdoll `0x100001CD` + side-bag `0x100001CE` pinned `Left|Top`. `ComputeAnchoredRect`: Top|Bottom ⇒ `h = parentH − mB − mT`. 4. **Capacity-padding pattern.** The contents grid + side-bag column pad empty `UiItemSlot`s up to the pack capacity (player `ItemsCapacity` default 102; `ContainersCapacity` default 7) after the loose-item loop in `InventoryController.Populate`. Padding changed several existing tests' counts (intended — update, don't revert). 5. **DO-NOT auto-kill the client.** The user manages client lifecycle: launch with a **plain `dotnet run --no-build`** (no `Get-Process … CloseMainWindow/Stop-Process` preamble). If a rebuild is blocked by a running client (`MSB3021`/`MSB3027` "locked by AcDream.App"), **ASK the user to close it** — do not kill it. (`feedback_dont_kill_clients_before_launch`.) This overrides the CLAUDE.md graceful-close snippet. --- ## 3. Current visual state (F12, `ACDREAM_RETAIL_UI=1`) Renders correctly + confirmed: 8-piece bevel frame; vertical bottom-edge resize (expand-only, 372..560 px); contents grid clips to its panel, scrolls (wheel + gutter scrollbar), shows the full **102-slot** main pack (items + empty frames); side-bag column with bags + empty slots; vertical burden bar; backdrop covers the window. **Known-wrong (next task):** - **Empty-slot background art is wrong** — inventory + side-bag empty cells use the TOOLBAR empty sprite (`UiItemSlot.EmptySprite = 0x060074CF`); paperdoll equip slots show a generic blue `UiDatElement` border. (User-flagged.) - **Main-pack cell has no backpack icon** (AP-51, placeholder `tex=0`). --- ## 4. What's next (build order) **(a) FIX the empty-slot background art — RECOMMENDED NEXT (the OPEN ISSUE).** Inventory + side-bag empty cells should use the retail pack-slot frame, not the toolbar's `0x060074CF`. Find the correct sprite from the UIItem cell template `0x21000037` (`.layout-dumps/uiitem-0x21000037.txt`) empty state; set it on the cells `InventoryController` creates (an `EmptySprite` override per slot kind, or a controller-set default distinct from the toolbar's). The paperdoll equip slots' per-slot silhouettes are Sub-phase C (below). Small, self-contained; brainstorm → spec → plan as usual. **(b) Main-pack backpack icon (AP-51).** The main-pack cell (`m_topContainer 0x100001C9`) should show the equipped-backpack art. Pin the backpack RenderSurface DID (or the equipped-pack `CreateObject` icon path). **(c) Sub-phase C — paperdoll.** The 3D character doll via a Core→App `IUiViewportRenderer` seam (`UiViewport`, Type `0xD`) + the `0x10000032` `UiItemSlot` registration so equip slots draw per-slot silhouettes. Research: `2026-06-16-equipment-paperdoll-deep-dive.md`. The heaviest piece. **(d) Deferred polish:** container-switching (select a side pack → show its 24-slot contents via the already-parsed `ViewContents 0x0196`); the side-bag column scrollbar (`0x100001CB`, inert — 7 fit); shrink-below-default resize (currently expand-only); the selected-target bar + stack split slider (per the wiki notes the user pasted). B-Drag (drag items between slots) also remains. Each gets the full brainstorm → spec → plan → execute flow. --- ## 5. New-session prompt (paste into a fresh session) > Continue acdream's D.2b retail-UI inventory arc. **Read > `docs/research/2026-06-21-d2b-inventory-finish-handoff.md` first.** B-Wire + the inventory window > finish Stage 1 (scroll, 8-piece frame, vertical resize, 102-slot grid) shipped + visually confirmed > on `claude/hopeful-maxwell-214a12` (tip `1be7e65`; `main` is a clean ff ancestor). **Next: fix the > wrong empty-slot background art** — inventory + side-bag empty cells use the toolbar empty sprite > `0x060074CF`; they need the retail pack-slot frame from the UIItem cell template `0x21000037` (see > `.layout-dumps/uiitem-0x21000037.txt`). Then the main-pack backpack icon (AP-51), then Sub-phase C > (paperdoll `UiViewport` doll + `0x10000032` per-slot equip silhouettes). Use the full brainstorm → > spec → plan → subagent/inline flow. **DO NOT auto-kill the running client** — launch with plain > `dotnet run --no-build`; if a rebuild is locked by a running client, ask the user to close it.