Repository navigation
Native windows plan: fizzy's backend between SDL and dvui, and the drag's glass in Liquid Glass - #226
Merged
Merged
Conversation
… the drag's glass in Liquid Glass What Liquid Glass does, as measured on macOS 26.5 (public styles frost; a private variant is a lens that refracts across windows; containers merge glass within one window, over Metal too); the drag's bubble and drop zones as one overlay of Liquid Glass on macOS 26, and the simpler path elsewhere; fizzy's backend owning its native windows (SDL3 adopts windows fizzy makes) so title bar drags, live resize and glass leave SDL patches and runtime method swaps; and keeping up with SDL's releases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s from opaque to glass, screen-edge tiling The user's principle (Liquid Glass as much as possible where the OS has it, private API when stable and built to fall back, every platform as close as it can, opaque through glass underneath); the overlay marked built and on by default; Fable's 2026-10-04 backend review folded in — one WindowChrome per window, SDL patches only where SDL owns the path (replacing the first draft's adopted-windows plan, kept as a fallback), the backend cleanup first, packages, peer-or-palette, colour, and a backlog of what else it found; materials from opaque to glass across platforms, the main window on the same material, accessibility; screen-edge tiling done by fizzy, since the OS only tiles windows the window server drags. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tive forms of every glass surface The user's design: one slider from clear refracting glass through blur and the window's colour to opaque in the window's colour, for everything drawn as glass; every glass surface in two forms on it — in-app (the shader, kept: the web and every platform without native window glass, tuned to look like macOS's glass) and native (the OS's glass in the OS's own style, for surfaces that are OS windows, and NSMenu for context menus on macOS). The native way along it as built in #227 (a two-layer crossfade between Liquid Glass variants, the window's colour under the glass so it keeps its shine, flat colour only at the top), and why the aimed bubble is lit in that colour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
foxnne
force-pushed
the
claude/native-windows-plan
branch
from
October 5, 2026 17:48
f91b1c9 to
15457e8
Compare
…ch platform's own glass, the in-app glass behind it From three studies (Windows, Linux, the in-app glass against Apple's): one vocabulary of roles (window, transient, carry, drop, scrim), the slider and each platform's policy probe; one pure mapping module; each platform's realization in its own style — Liquid Glass on macOS 26, DWM's Mica/Acrylic/Smoke along the slider the way Windows Terminal maps its opacity on Windows 11, the compositor's blur region (ext-background-effect-v1, KDE's older protocol) on Linux where offered and opaque where not, the in-app glass on the web — what to skip on each, Windows composition as a phase 2; the in-app glass tuned to Apple's (an inward bevel pull that folds and magnifies, which is a shader change in four copies), and the rules that keep it small. The native frost now fades out toward the edges, its rim the clear lens. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s the library's first plugin consumer The user's candidate: pixi's corner glass buttons and its colour-dropper magnifier as one liquid layer — the orb pinching off the magnifier button, floating round the pointer with pixi's pixel zoom and crosshair in its middle and a refracting rim, merging with the buttons — and what the library needs for it: glass outside drags with groups, content over the glass from any code, a magnifier look, motion from core, all reachable from a plugin through core. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s built, compact toolbar corners Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…up windows that fizzy draws The user's decision (2026-10-06): a context menu is an OS popup window with fizzy's own menu drawn in it — Liquid Glass on macOS 26 (vibrancy before), DWM Acrylic on Windows 11, the compositor's blur region on Linux — not NSMenu or a Win32 menu, and not an overlay inside the main window. The plan gains the section: SDL popup windows parented to where the menu opens (an xdg_popup on Wayland), the menu copied out of the frame as floats copy theirs, input mapped back, the display as the menu's screen; the open questions (keyboard focus, dismissal, several displays). Steps renumbered with it as step 6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ding on their window
foxnne
force-pushed
the
claude/native-windows-plan
branch
from
October 6, 2026 15:43
5fa3f51 to
fb8ab97
Compare
This was referenced Oct 8, 2026
foxnne
marked this pull request as ready for review
October 8, 2026 13:38
This was referenced Oct 8, 2026
foxnne
added a commit
that referenced
this pull request
Oct 8, 2026
Part of #226 (`docs/NATIVE_WINDOWS_PLAN.md`) ## What changes Adds `docs/WINDOWS_LINUX_GLASS_PLAN.md`, the research behind the plan's Windows Phase 2 and its Linux blur region. It takes apart what the macOS pop-out and Liquid Glass work rest on, piece by piece per OS, and how Windows and Linux can supply each piece, with sources. The findings: - No OS but macOS 26 merges or refracts glass. Elsewhere fizzy keeps the shape (LiquidField's smooth union) and the OS supplies only the blur: - **Windows:** the visual layer's host backdrop, clipped to the field's outline. - **Wayland:** `ext-background-effect-v1` (GNOME 51, Plasma 6.7, niri), with `org_kde_kwin_blur` as the fallback for older Plasma. - Carried views on Windows go into one overlay per display. - X11 is deprioritised. - Step 0 for both platforms: the SPIR-V and DXIL glass programs predate #227. The plan's Windows decisions stand: the slider along DWM's backdrop types, one activation group, an Acrylic carry window, and the drop zones in the app's glass. Per-shape glass through Windows.UI.Composition is still the plan's "Phase 2, only with a go-ahead". Steps 3 (Windows menus as Acrylic popups) and 4 (the Linux blur) are built in the two PRs stacked on this one. This is a cloud session's research. Its claims marked **(spike)** were not run. ## SDK impact - [x] None ## Verified Docs only. ## Follow-ups The two step PRs stacked on this one. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude <noreply@anthropic.com>
foxnne
added a commit
that referenced
this pull request
Oct 8, 2026
Part of #226 ## What changes Two pieces pixi's dropper magnifier (fizzyedit/pixi#3) needs to be a clear liquid orb over its zoom, with no frost and strong refraction: native Liquid Glass on macOS, the app's glass everywhere else. And the SDK release that ships them, so the orb can be tried against `main` as soon as this merges. **`core.native_glass.offered`** - The app publishes each frame whether the OS draws glass declared outside a view drag (`publishOffered`, from `Popout.beginFrame`'s `nativeGlass()`). - A plugin that sees it declares its glass with `native_glass.add`. Fizzy's overlay of Liquid Glass already stays up while any glass is declared. - Pixi declares a clear piece (`frost = 0`, the lens alone) over a zoom it draws in the window, so the OS's lens refracts the window beneath. - Off macOS 26, or with native glass off, `offered()` is false. **`LiquidField.drawPicture` / `pictureMargin` / `lens`, and `glass_look.forLens`** - The app's glass as a lens over a picture the plugin drew. The middle is the picture as it is, with no frost, colour or lift; the rim bends and lights it. - It reads no capture, so the middle stays pixel-exact. - On the web, where no look is published, it is the earlier glass. `pictureMargin` says how far past the shapes the picture should reach for that glass's rim, at the strongest shape lens. **Tried and dropped:** pixi tried the drop zones' frosted glass with its zoom laid over it. On a Mac it read as a thick grey border or a flat rim. **Merged with main** (#234–#236, #239, #240). ## SDK impact - [ ] None - [ ] Core-only or additive: reaches plugins at the next SDK release - [ ] Fingerprint moved: recorded in `sdk/src/version.zig`, `sdk_version` untouched, PR labelled `sdk` - [x] SDK release: bumps `sdk_version`, lists the `sdk` PRs since the last `sdk-v*` tag `sdk_version` goes 0.2.17 → 0.2.18 (ef95301). Since `sdk-v0.2.17` this release carries: - this PR's core additions; - #223, #224 and #227's core (the one-slider glass, `glass_look`, `core.native_glass`, `core.screens`'s menus and dialogs). The fingerprint has not moved, so installed plugins keep loading. Merging tags `sdk-v0.2.18` and, per #240, asks the store plugins to repin. ## Verified - `zig test core/gfx/glass_look.zig`: 13 pass. - `zig fmt --check` and `zig ast-check` on the changed files. - `tests/integration.zig` compiles `drawPicture` and checks `pictureMargin`. - CI: Linux, macOS, Windows, integration and the Windows cross-build on this head. - [x] macOS: pixi's orb tried locally against this branch by the maintainer, who approved it. - [ ] Windows: - [ ] Linux: - [ ] Web: ## Follow-ups - pixi#3 repinned to `sdk-v0.2.18` once it's tagged. - The orb pinching off pixi's sample button and merging with it (the plan's next step for this consumer). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Euk6iCavQdW7MG5FN2vvFw --------- Co-authored-by: Claude <noreply@anthropic.com>
1 of 4 tasks
foxnne
added a commit
that referenced
this pull request
Oct 8, 2026
…=1 (#237) Part of #226 (`docs/NATIVE_WINDOWS_PLAN.md`, "Linux — the compositor's blur"); step 4 of `docs/WINDOWS_LINUX_GLASS_PLAN.md` (#236). ## What changes With `FIZZY_BLUR_BEHIND=1`, on a Wayland compositor that blurs, the window's base goes translucent at the window opacity over the desktop's blur, as it already does over macOS's vibrancy and Windows' Acrylic. Elsewhere, and without the switch, nothing changes: the window stays opaque. - **`platform/wayland_blur.zig`:** binds `ext-background-effect-v1` (GNOME 51, Plasma 6.7, niri) or KDE's `org_kde_kwin_blur`. - It uses SDL's own libwayland-client (`RTLD_NOLOAD`), with both protocols declared by hand, on an event queue of its own. - The region is sent only when it changes, and it lands with the commit the frame's present makes. - "No blur" is an empty region on the ext protocol, and the blur object unset and released on KDE's protocol (KWin blurs the whole window behind an empty one). - The first probe logs what it found. - **`platform/blur_region.zig`** (std-only, unit tested): steps the rounded frame into rectangles. - **`linux_titlebar.blurBehind` and `Editor.tick`:** the blur covers the frame inside the shadow's margin while the window is translucent, and is square when maximized. Off by default until someone sees it on a desktop that blurs. ## SDK impact - [x] None ## Verified - [x] Linux, Ubuntu 26.04 / GNOME 50 (aarch64 UTM VM, native Wayland, `FIZZY_BLUR_BEHIND=1 WAYLAND_DEBUG=client`). GNOME 50 has neither protocol, so this covers the "absent" path only: - one `get_registry` on fizzy's own unnamed queue; - the log line `ext-background-effect-v1 absent, org_kde_kwin_blur absent`; - no `wl_display.error`; - fizzy alive after 12 s, window opaque. - [x] Protocol details: - opcodes checked against wayland.app (`ext-background-effect-v1`) and plasma-wayland-protocols' `blur.xml`; - KWin's empty-region-means-whole-window rule read in `src/plugins/blur/blur.cpp` on `Plasma/6.6`. Master only takes a non-empty region. - [x] A stub compositor speaking both protocols, in the cloud session that wrote this: the region applied on commit, unchanged frames sent nothing, cleared when opaque, KDE's unset, nothing asked when capabilities = 0. - [x] `fizzy-blur-region-tests` (5 tests). - [x] Gates: `zig build`, `test`, `test-integration`, `check-web`, `test-sdk-version`, and the Windows and Linux cross-builds. - [ ] Not seen where the blur would actually show: GNOME 51, Plasma 6.7+, or Plasma ≤6.6 (KDE's protocol and the "off" path). Please try one of those before this goes default-on: - the blur sits inside the frame, not in the shadow margin; - the corners line up; - maximized is square and full; - opacity 1 gives no blur. - [ ] macOS / Windows / Web: no change there (the code is `comptime`-gated to Linux; it builds on all of them). Relies on the `envSwitch` fix (#235, merged): before it, `FIZZY_BLUR_BEHIND` read as `FIZZY_POPOUT`. ## Follow-ups - Default-on once seen on GNOME 51 or Plasma. - Wayland popups (menus and dialogs as `xdg_popup`s) are the other half of step 4, not built. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
foxnne
added a commit
that referenced
this pull request
Oct 8, 2026
Part of #226 (`docs/NATIVE_WINDOWS_PLAN.md`, Phase 2); step 5 of `docs/WINDOWS_LINUX_GLASS_PLAN.md` (#236). ## What changes Adds `spikes/windows-composition/`, a standalone Windows program answering the four questions the plan's Phase 2 (the drag's glass as an overlay over the desktop's blur) waits on. Nothing in fizzy changes. The research doc's step 5 records the answers. How it works: - **It uses fizzy's own pins** of fizzyedit/SDL and zigwin32. - **The window is fizzy's kind:** a transparent SDL window presenting on D3D12 through the fork's topmost DirectComposition target. - **Under it:** a Windows.UI.Composition target that isn't topmost, holding the host backdrop, cut to a pill (∪ an orbiting circle) that sweeps across the window. Five modes: - no clip; - a rounded-rect clip; - a Direct2D path rebuilt every frame; - an AlphaMask effect over a swapchain the app presents; - the app's picture hosted in composition's own tree (the fallback for question 1). - **An overlay over the whole display** tries four click-through styles. - **WinRT is bound by hand.** Every GUID and vtable slot was read from the OS's own WinMetadata with System.Reflection.Metadata, and each is cited in `src/winrt.zig`. `IGeometrySource2D` and `IGraphicsEffect` are COM objects written in Zig. At about 1,700 lines this is over CONTRIBUTING's 800-line guide. It's throwaway code in `spikes/`, built by nothing else. ## SDK impact - [x] None ## Verified Windows 11 ARM VM (`fizzy-win11`, build 26300, D3D12 on WARP, 60 Hz), aarch64-windows-gnu, driven by `SendInput`. Offsets were measured from screenshots: the clip's glass against the red box SDL presents round the pill, six samples per run, with a direction mark telling lead from lag. 1. **Two targets on one HWND: yes.** `CreateDesktopWindowTarget(hwnd, FALSE)` on SDL's claimed window succeeds and draws under SDL's picture. Static, the two align to the pixel. 2. **Path clip rebuilt every frame: works and is antialiased** (1–2 px). Composition calls `GetGeometry` once per frame. With SDL's VSYNC present the clip **leads** the picture by the present queue: | SDL present | Clip delay | Glass vs SDL's rim | |---|---|---| | VSYNC (frames in flight 1 or 2) | 0 | ~2.2 frames ahead (35 ms) | | VSYNC | 1 | 1.3 frames ahead | | VSYNC | **2** | **0 ±0.5 px** | | MAILBOX / IMMEDIATE | 0 | **0 ±0.5 px** | So fizzy either gives composition the shape from as many frames back as the present queue is deep (measured, not assumed), or has the fork present through a frame-latency waitable swapchain. 3. **Effect-graph mask: yes.** D2D's AlphaMask with a `CompositionEffectSourceParameter` over `CreateCompositionSurfaceForSwapChain` shows the glass exactly where the presented mask is. 4. **Overlay:** | Style | Same-thread click | Another process | Tree shows | |---|---|---|---| | `TRANSPARENT \| LAYERED` | passes | passes | yes | | `TRANSPARENT \| LAYERED`, alpha 255 | passes | passes | yes | | `TRANSPARENT` alone | blocked | blocked | yes | | `HTTRANSPARENT` | passes | **blocked** (though `WindowFromPoint` says it passes) | yes | A drag under the layered overlay keeps its capture (30/30 motion events). `SDL_SetWindowOpacity(0.6)` (layered) leaves both SDL's picture and the composition tree drawing. - [ ] **The blur on a hardware GPU.** The VM draws the host backdrop black. Run it, press `3` (path) with the backdrop on, and check the blur and the edge, at clip delay 0 and 2 (`D`). - [ ] **The present queue's depth at 60/120/144 Hz** on hardware, and Windows 11 23H2/24H2. - [ ] macOS / Linux / Web: n/a (Windows only; not part of fizzy's build). ## Follow-ups - If the blur holds on hardware: the overlay (step 6), with the clip delayed by the measured present-queue depth, or a waitable swapchain in the SDL fork. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
foxnne
added a commit
that referenced
this pull request
Oct 8, 2026
…#238) Part of #226 (`docs/NATIVE_WINDOWS_PLAN.md`); step 3 of `docs/WINDOWS_LINUX_GLASS_PLAN.md` (#236). ## What changes With floats as windows (`FIZZY_POPOUT=1` on Windows), menus and dialogs now leave the main window as they do on macOS (`viewports.menus`). Each one is a borderless window owned by the window it opens from, never activated, and dressed by DWM (`win32_titlebar.viewportMenuChrome`): - Acrylic (`DWMSBT_TRANSIENTWINDOW`, the material of Windows 11's own menus); - DWM's rounded corners and shadow; - no border, no system menu, no DWM transitions. DWM draws a never-activated window's backdrop as its solid fallback, so the menu's window is kept looking active (`WM_NCACTIVATE`). An owned window isn't carried when its owner moves, so a menu's window rides on nothing and is placed each frame. ## SDK impact - [x] None ## Verified Windows 11 ARM VM (`fizzy-win11`, WARP, aarch64-windows-gnu Debug), driven with real input (`SendInput`) and checked against the window list (`EnumWindows` plus DWM attributes) and screenshots: - [x] The File and Help menus and the "Unsaved changes" dialog each open in a window of their own: - owned by the main window and directly above it in the z-order; - `WS_EX_NOACTIVATE`, no `WS_SYSMENU`; - backdrop type Acrylic (3), corner preference round; - the main window stays the foreground window. - [x] The first click on an item acts: New File opens `untitled-1`, and Open Files opens the Open dialog. A temporary log showed the press arriving on the menu's window and mapping into the menu's dvui subwindow, not what lies under it. - [x] The dialog's window hides when the main window is minimized and comes back on restore. - [x] Gates: `zig build`, `test`, `test-integration`, `check-web`, `test-sdk-version`, and the Windows and Linux cross-builds. - [ ] **The look on a hardware GPU.** The VM's DWM draws every backdrop as its fallback, so these need a real machine: - Acrylic rather than a solid colour; - rounded corners and a shadow; - whether the `WM_NCACTIVATE` trick keeps the Acrylic. - [ ] A menu opened over a float's window. Not exercised; creating a float needs a view drag. - [ ] macOS / Linux / Web: unchanged (`viewports.menus` was already on for macOS, and this is the Windows branch). Seen while testing, not caused by this change: - A menu closes when fizzy is deactivated. My harness's own process start deactivated it, which made a later click fall through to the main window. - A dialog drifts a few pixels left over each minimize/restore. It does the same drawn in-window (`FIZZY_NATIVE_DIALOGS=0`). ## Follow-ups - NATIVE_WINDOWS_PLAN's Phase 1 on Windows: the slider along DWM's backdrop types, one activation group, and a policy probe. - Caption buttons in a Windows float's header (in `app/layout/Floats.zig`). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A plan, as you asked:
docs/NATIVE_WINDOWS_PLAN.md. It covers strengthening fizzy's control of its native windows, getting the drag's glass to look and merge like Control Center's on macOS 26, and keeping up with SDL as it moves. Docs only.What Liquid Glass does, measured with throwaway AppKit programs on macOS 26.5:
_variant11) is a clear lens: a drop of water. It refracts across windows, which is how Control Center's tiles refract the desktop. Pop-out and settings fixes: a restored float stays in front, picker drags float off the desktop, menus keep off the edge, settings scroll steady, the carried view is always a window (Liquid Glass on macOS 26) #224 now uses it for the carried bubble, gated on macOS 26.NSGlassEffectContainerViewmerges glass views with a liquid bridge, over Metal content too, but only within one window.The drag's glass on macOS 26: one overlay window per screen during a drag, holding the bubble's head and tail and every drop-zone bubble as glass views in one container. They merge and refract as Liquid Glass. The app's windows draw none of the drag while it shows.
Other platforms: over a window the drag is the app's own glass, merging as it did before #224. Outside every window it is a carry window with a simple material.
The backend as the layer between SDL and dvui:
SDL_PROP_WINDOW_CREATE_COCOA_WINDOW_POINTER,..._WIN32_HWND_POINTER, …). Fizzy can make its ownNSWindowand view, so title bar drags (where the float-over-title-bar bug lives), live resize and the glass hierarchy become fizzy's code. That replaces SDL patches and runtime method swaps.Updated 2026-10-05:
WindowChromeper OS window;Steps:
FIZZY_NATIVE_GLASS=1Open questions:
🤖 Generated with Claude Code