The problem
Alt-tab and multiple monitors are how we've juggled windows for 30 years. I wanted something spatial: zoom out, see every window at once; zoom into one, work in it for real; zoom back out. Like a map for your desktop.
On Linux there's niri and driftwm (they're compositors). On Windows you can't replace the compositor — so the question was: can you do this on top of Windows, with the real windows, in a single exe?
Attempt 1 (and why it fails)
The naive idea: capture every window, hide the originals off-screen, and draw the captures on a fullscreen surface. When the user "dives" into one, show the real window again.
This breaks immediately. The moment a window is fully occluded or moved off the visible desktop, DWM stops compositing it — Windows.Graphics.Capture then returns black or stale frames. Your beautiful canvas fills with black tiles.
The park & swap trick
The fix is to never fully hide a window:
- Each window is captured with Windows.Graphics.Capture (FreeThreaded frame pool, poll-based) into a persistent D3D11 texture.
- The window is "parked" in a 2px-tall visible strip at the bottom of the primary monitor. 2px is enough that DWM keeps compositing it, so the capture stays live — but it's invisible behind the canvas.
- The canvas is a borderless fullscreen D3D11 swapchain. Each window is a 1:1-pixel textured quad placed in world space; pan/zoom is just a camera transform. A D2D/DWrite overlay draws labels, a world-anchored dot grid, the minimap, docks.
- When you zoom past a threshold (or double-click), the real HWND is moved onto its quad's screen rect and given focus. Now you're typing into the actual window — no input simulation, no proxying. Pull back (a thumb-button press) and it returns to the park strip.
So there are two states per window: parked (you see its live texture on the canvas) and swapped-in (you see and use the real window). The transition is a SetWindowPos.
Things that bit me
- IsBorderRequired(false) and the borderless-capture path black out capture on some Windows builds — removed.
- CopySubresourceRegion with content-sized copies + a drain-to-newest loop also produced black tiles; a single TryGetNextFrame + full CopyResource is the proven path.
- Added a constant-buffer field the pixel shader reads, but only bound the cbuffer to the vertex stage — every tile came out alpha=0 (invisible). If a shader stage reads a cbuffer, bind it to that stage.
Result
A single 559 KB exe (statically linked, no .NET/redist), ~3300 lines in one translation unit. Idle-throttled so it doesn't cook the GPU. It has grown search-and-fly, sticky notes, a minimap, an app launcher, named workspaces.
Demo + download: https://github.com/13auth/spatial-canvas
Happy to answer questions about the capture/compositing pipeline.












