The Parametric EQ has a tab of its own since #370, but Play is in the
sound FX's tab. A tab that can float keeps both in view. There is one
editor per kind, so the kind's pane is lent to the window and given
back on Dock, the way fullscreen moves the game view.
- A right-click on a document's tab opens a menu with Float and Close.
`DocumentTab` passes the press to `TabStrip`'s new `onMenu`.
- `FloatWindow` sits on the overlay. Its title bar moves it, its lower
right corner sizes it, Dock and the x close it. A press brings it to
the front.
- `floating.ts` is the pure part: where a window opens, held whole on
the screen, sized down to 320 x 200. Nothing of it is remembered.
- One window per kind. Another document of that kind opens there and
closes the one it had. Its tab, if it had one, leaves the row.
- When the row showed the kind, it shows the nearest document whose
kind is not in a window, else the scene (`neighbourOf`).
- Delete, Copy and Paste go to the window pressed last, and back to
the tab showing after a press in the editor (`keyTab`).
- Previews tick and redraw for a kind in a window as for the tab
showing. Fullscreen hides the windows. Loading a project or signing
out closes them.
- Only documents float, Scene and Game stay in the row.
- Hooks: `floatWindows`, `floatDocument`, `keyTarget`.
Tests:
- Unit documents: 16 green, 5 new. Counter-check: `neighbourOf`
without the window check turns its test red.
- e2e 44 (melektaus-atx, after steps 1-12 and 37): ALL PASSED,
505 checks in the chain, 6 new for float, move, size, another
texture, keys, Dock and x.
- Gate (melektaus-atx): CHECK EXIT 0, 274 files, 4236 tests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On the WSL runner every __gm.pixelAt costs about 7 ms, three times as
much as on stein2. Each call renders the whole stage into a fresh
render texture and stalls until the GPU hands one pixel back. pixelRow
and several checks read hundreds of pixels that way. Module 05 spent
36.8 of its 40 s on these reads, module 04 11.3 of 20 s.
- stagePixels in src/ui/render.ts renders once around all points and
reads them in one go. Only whole pixels at resolution 1 take that
path. Anything else stays point by point.
- The hook __gm.pixels(points) exposes it, and pixelRow uses it.
- The loops in e2e 04, 05, 14 and 44 read their grids in one call.
- The old comment in pixelRow said a wider frame comes back resampled.
That is not true. The colours match exactly, so the comment is gone.
Measured on the RTX (d3d12) and on stein2 (Intel, Vulkan): diff 0 at
10 680 points on each GPU. One screen row takes 4 to 18 ms instead of
2.4 to 9.9 s. The six affected modules need 32 s instead of 139 s
under WSL, faster than on stein2.
The rest of the gap is in Chromium's GPU process. perf puts three
quarters of its time in the drivers (NVIDIA D3D12, Mesa d3d12, dxg).
Four browser and Mesa settings were measured, none helped.
Tests:
- ./check.sh on melektaus-atx: 195 files, 2827 tests, CHECK EXIT 0 (+4)
- e2e 1-16,30,37,44,58 under WSL: ALL PASSED, 587 checks
- counter-check: a wrong index in stagePixels fails the unit test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>