- Shipped
- September 17, 2026 at 7:43 PM UTC
- Author
- Kamo
- Commit
- 905fba8
Everything about a popup tool window that MOVES - re-packing the row, trading places with a strip click, stepping out of a row behind, a drag, a seam pull, taking and leaving the maximized pane - was costing a layout pass and a full React re-render of every open window's contents per frame. Measured in the dock harness with eight windows open (headless Chrome, before/after, three runs each): - one strip click: 12-14 layout passes -> 1, script time 87-104ms -> 44-52ms - a 40-move title-bar drag: 168 re-renders of window CONTENTS -> 0, and 86 forced layout reads -> 3 - backdrop-filter layers actually painted: 8 of 8 -> 5 of 8 (only the windows standing behind) Every window ends at the same pixel, and every transition travels the same path over the same frames: dock->float, float->dock, dock->maximized and maximized->dock all sampled identical endpoints, identical moving-frame counts and identical largest step. The only pixel difference at rest is the subpixel antialiasing phase on glyph edges in docked windows - same positions, same stroke weight (2649 vs 2643 ink pixels), same edge energy (5.47 vs 5.53). What changed: - A docked window is placed by `translate` instead of `left`/`top`, with the hover lift folded in. The other three regimes keep `left`/`top` and no translate at all, and the hand-off is exact because all of `left`, `top` and `translate` already share one transition clock: two ramps on one curve sum to the ramp between the endpoints. Deliberately no `will-change` - it bought nothing either probe could see and costs a compositor layer per window for the session. - `relayoutWindows` answers the SAME array when nothing moved. It always answered the same windows and a fresh array, so every one of the fifteen-odd callers of `store.relayout()` - including the scrollbar sync that runs 120ms after any DOM mutation anywhere in the document - re-rendered every reader of the window list. - `useToolWindowsStable()`: the window list with its geometry ignored. The seven tool bodies, the three unread bridges and the achievement watcher all read it for one boolean apiece and none has ever read a box, so a height-seam drag no longer re-renders every message list on screen. - `useToolWindowActions()`: the callbacks, by identity, so a caller that only dispatches is not re-rendered by a window moving. - `readViewport()` holds its right-edge measurement between the events that can change it. The render-phase call in ToolDock was flushing a dirty layout sixty times a second during a drag. - `DockedToolWindow` and `ToolWindowBody`: a memo boundary per window and per tool, with every callback bound once for the window's life. Memoized `MaximizedTabStrip`, `MaximizedTab`, `ChatNavigatorPanel`, `DockSnapIndicator`, `HexHeadSpring` and `HexHeadPopover` too. - The strip veil's `backdrop-filter` is `visibility: hidden` when the window is not behind. It transitions discretely, so the fade still plays in full before the layer stops being painted. - The hexhead throw loop no longer ticks React state per frame; the comet trails run their own animation frame and write SVG attributes, so a throw stops re-rendering the whole stage. - The title-bar arrival sweep takes itself down when it finishes instead of parking off-frame for the session, and the shell's framer keyframes are memoized - three of the five branches return a keyframe ARRAY, so a re-render mid-swap used to restart the cross-dissolve. `dockRenderCost.test.tsx` pins all of it as counts; the relayout identity case fails on HEAD.