feat(shell): app-wide dynamic album-art background ("modo Cider")
Opt-in album-art background composited behind the whole shell, wgpu-tier
only. Appearance mode picker: Off | Ambient (GPU shader) | Blurred art.
- ambient.wgsl: new calm, low-energy album-colored scene (mode 7), drifting
mesh-gradient of the primary/secondary/accent triad, no beat/transient.
Registered in shader_underlay SHADER_SOURCES[5] + render_frame idx math.
- state.slint: AppearanceState app-background {modes,mode-index,available,
dim,surface-alpha}; ImmersiveState.app-shader-mode (derived 1->7);
ShellState.app-background-active (mode>0 && wgpu && has-track).
- visualizer.rs: drain renders shader-mode when immersive OPEN, else
app-shader-mode (7=ambient) into the same shader-texture sink.
- AppShell: background layer at root z-bottom (Ambient=shader texture,
Blurred=ImmersiveAtmosphere) + tunable dark scrim; shell chrome surfaces
go translucent when active; viz-should-run extended to drive the drain.
- Whole-shell translucency: Sidebar/HeaderBar/PlayerBar(Small)/QueueSidebar/
LyricsSidebar/SidebarNowPlayingDock + AppShell content well/frame/column.
- ui_prefs: persisted `app_background` (off|ambient|blurred), String-key
pattern; appearance-select("app-background") write-back.
- Live-tunable knobs QBZ_BG_DIM / QBZ_BG_SURFACE_ALPHA (seeded at startup)
so the look is dialed in one smoke session without a rebuild.
- i18n: 8 locales for the picker + warning; reduce-motion / D4 (no-track ->
opaque theme) handled via derived active flag.
Design + signed decisions: qbz-nix-docs/specs/2026-07-16-app-wide-dynamic-background.md
cc
This commit is contained in:
23 files changed
+483
-21
No files matched your search
@@ -3236,6 +3236,25 @@ export global AppearanceState {
|
||||
in-out property <bool> immersive-panels-collapsed: true;
|
||||
in-out property <bool> immersive-fps-collapsed: true;
|
||||
|
||||
// --- APP-WIDE DYNAMIC BACKGROUND ("modo Cider") ------------------------
|
||||
// Album-art background composited behind the WHOLE shell. Opt-in, wgpu-tier
|
||||
// only. 0 = Off, 1 = Ambient (GPU shader scene 7), 2 = Blurred art (the
|
||||
// ImmersiveAtmosphere blurred-cover look). Persisted in ui_prefs
|
||||
// (`app_background`) via appearance-select("app-background", i).
|
||||
in-out property <[string]> app-background-modes: [@tr("Off"), @tr("Ambient"), @tr("Blurred art")];
|
||||
in-out property <int> app-background-mode-index: 0;
|
||||
// False on the femtovg-GL / software tiers (no wgpu underlay, and
|
||||
// reduce-motion is forced ON there → the effect would freeze). Seeded from
|
||||
// Rust (= use_gpu_renderer); gates the whole picker row.
|
||||
in-out property <bool> app-background-available: false;
|
||||
// Live-tunable look knobs, seeded from Rust env at startup (QBZ_BG_DIM /
|
||||
// QBZ_BG_SURFACE_ALPHA) so the appearance can be dialed in a single smoke
|
||||
// session without recompiling, then baked to constants. `dim` = extra dark
|
||||
// scrim over the background for legibility; `surface-alpha` = translucency
|
||||
// of the shell chrome when the background is active.
|
||||
in-out property <float> app-background-dim: 0.28;
|
||||
in-out property <float> app-background-surface-alpha: 0.55;
|
||||
|
||||
// Callbacks. Unwired in this replica — the Rust side may bind them
|
||||
// later. Kept generic (key + value) so the controller can dispatch.
|
||||
callback appearance-bool(string /* key */, bool /* value */);
|
||||
@@ -3965,6 +3984,16 @@ export global ShellState {
|
||||
// "viz-toggle"). When off, the spectrum band collapses and the sidebar
|
||||
// content reclaims the space; the FFT tap idles (AppShell viz-should-run).
|
||||
in-out property <bool> large-visualizer-on: true;
|
||||
|
||||
// --- APP-WIDE DYNAMIC BACKGROUND (derived) -----------------------------
|
||||
// Active only when a mode is picked, the wgpu tier allows it, AND a track is
|
||||
// loaded — so with nothing playing the shell restores its opaque theme
|
||||
// surfaces (D4). Shell chrome reads this to go translucent; AppShell reads
|
||||
// it to mount the background layer.
|
||||
out property <bool> app-background-active:
|
||||
AppearanceState.app-background-mode-index > 0
|
||||
&& AppearanceState.app-background-available
|
||||
&& NowPlayingState.has-track;
|
||||
}
|
||||
|
||||
// Authenticated user, for the header user element.
|
||||
@@ -4054,6 +4083,14 @@ export global ImmersiveState {
|
||||
// 0->1->2->3->0 with the 'g' key.
|
||||
in property <image> shader-texture;
|
||||
in-out property <int> shader-mode: 0;
|
||||
// App-wide dynamic-background scene selector, kept SEPARATE from
|
||||
// `shader-mode` so opening the immersive overlay (which force-resets
|
||||
// shader-mode to 0 in main.rs) does NOT clobber the app-wide background.
|
||||
// 0 = none, 7 = Ambient (ui/shaders/ambient.wgsl). The drain renders this
|
||||
// scene into `shader-texture` when the immersive overlay is CLOSED (see
|
||||
// visualizer.rs); the AppShell root Image binds the same `shader-texture`.
|
||||
// Derived: Ambient (mode 1) → 7, everything else → 0. No Rust setter needed.
|
||||
out property <int> app-shader-mode: AppearanceState.app-background-mode-index == 1 ? 7 : 0;
|
||||
// False on the femtovg-GL / software renderer tiers (no wgpu underlay →
|
||||
// shader scenes would render black). Seeded from Rust at startup; gates
|
||||
// the picker rows and the `g` cycle in ImmersiveView.
|
||||
|
||||
Reference in new issue
Block a user