Smoke rounds 3-4 (owner feedback). Checkpoint during iteration.
Ambient (the big one): rewrote ambient.wgsl from translating gaussian blobs to a
METABALL field (r²/d² summed + smoothstep iso-surface) with 2-octave domain warp
— lobes fuse/stretch/split like an amoeba / lava lamp (the Cider motion that was
missing), faster clock, more contrast.
Surfaces made background-aware (translucent when the dynamic background is on):
- Search results view (root + toolbar), artist Network panel + its tab-row
header (transparent to avoid double-translucent compounding), JUMP TO bar
(JumpNavBar bar-bg passed in — can't import ShellState without a cycle).
- Discover toolbars + tab pill + BrowseHeaderTools; SearchResultsView toolbar.
- CircleAction (shared: playlist/album/artist/etc. action buttons) on-surface
secondary fill goes glass; playlist Sort dropdown; QbzSelect closed control.
- New app-background-bar-alpha knob (0.3, env QBZ_BG_BAR_ALPHA): thin bars go
MORE transparent than panels (surface-alpha 0.5).
- Content well: frosted tint (0.22) + 1px hairline border → distinct panel.
- Album/Artist header gradient auto-suppressed under the dynamic background
(they clashed); header text stays light on the dynamic backdrop.
- Discover carousel edge-fade "shadows" hidden when active (Carousel /
PlaylistCarousel / ArtistCarousel / PinnedCarousel).
Base: 76ea5a82. Prior checkpoint: 4e405338.
cc
The album header gradient was a fixed px that overshot the header/track-list divider on tall (description-bearing) headers; bind its height to the divider's y so it ends exactly at the header container's bottom at any size. Apply the same readable-text + gradient-to-boundary treatment to the artist page. And CircleAction gains an on-surface variant (theme-colored fill/border/icon) driven by the gradient toggle, so when the header gradient is off the action buttons are visible on light themes instead of white-on-white. Below-divider content untouched. Extends #491/#519.
cc
Slint cannot split the .slint compilation across crates, but a Slint LIBRARY
crate exposes its generated Rust types to dependent crates (verified with a
minimal proof). So:
- NEW crate `qbz-ui` (lib): owns the whole .slint tree + build.rs + bundled
translations; `slint::include_modules!()` + the generated types (AppWindow,
MiniPlayerWindow, all globals/structs) are re-exported. Translation domain is
now `qbz-ui` (the .po files renamed accordingly).
- `qbz-slint` (bin) -> renamed to `qbz` (package + `[[bin]] name = "qbz"`),
reclaiming the binary name from the retired Tauri app. It depends on `qbz-ui`
and does `pub use qbz_ui::*;` so existing `crate::AppWindow` / `crate::*State`
references resolve unchanged.
This splits the single ~20 GB rustc into two crates (UI/codegen vs the 75k LOC
of logic) — the foundation for lower build peak, incremental caching, and the
upcoming per-feature crate extraction.
Also fixed for the move: qbz-i18n bundled-.po include paths, the font/WGSL
`include_bytes!`/`include_str!` paths (-> ../../qbz-ui/ui/), workspace members,
dev scripts (`-p qbz`), and the CI workflows. `cargo check -p qbz` is green.
cc