diff options
| author | Danilo M. <danix@danix.xyz> | 2026-09-29 13:04:00 +0200 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-09-29 13:04:00 +0200 |
| commit | ae193343b9633eb79287c4e2589b95c02f538e48 (patch) | |
| tree | 4035fb4f38394d7e2000732977a020b3f3c00c90 | |
| parent | 700f4be432e2c0f54fd6708b6a085b1fb9dd6108 (diff) | |
| download | quickshell-ae193343b9633eb79287c4e2589b95c02f538e48.tar.gz quickshell-ae193343b9633eb79287c4e2589b95c02f538e48.zip | |
feat(sound): fake frost on the album-art scrim
The art background is opaque, so Hyprland's blur behind the OSD cannot
show through it; making the art translucent to let it through would
also thin the scrim that keeps light covers legible. Fake the frosted
glass instead: a faint top-down sheen in Theme.text and a fixed grain,
painted once by a Canvas and masked to the panel's rounded corners.
The grain is a Canvas rather than a ShaderEffect because a shader needs
a compiled .qsb beside it; the Canvas repaints only on resize.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| -rw-r--r-- | desktop/modules/sound/Osd.qml | 40 |
1 files changed, 40 insertions, 0 deletions
diff --git a/desktop/modules/sound/Osd.qml b/desktop/modules/sound/Osd.qml index 2894d35..dfcf876 100644 --- a/desktop/modules/sound/Osd.qml +++ b/desktop/modules/sound/Osd.qml @@ -132,6 +132,46 @@ Scope { color: Qt.alpha(Theme.base, 0.82) } + // Frost on the scrim, faked: a faint top-down sheen and fixed + // grain. The art is opaque, so the compositor's frosting cannot + // show here without costing the scrim its legibility. + Rectangle { + anchors.fill: bgArt + visible: bgEffect.visible + radius: bgMask.radius + gradient: Gradient { + GradientStop { position: 0.0; color: Qt.alpha(Theme.text, 0.08) } + GradientStop { position: 0.6; color: "transparent" } + } + } + + // ponytail: grain painted once with Canvas; a ShaderEffect would + // animate or scale better but needs a compiled .qsb beside it. + Canvas { + anchors.fill: bgArt + visible: bgEffect.visible + layer.enabled: true + layer.effect: MultiEffect { + maskEnabled: true + maskSource: bgMask + maskThresholdMin: 0.5 + maskSpreadAtMin: 1.0 + } + onPaint: { + if (width <= 0 || height <= 0) return; + const ctx = getContext("2d"); + const img = ctx.createImageData(width, height); + for (let i = 0; i < img.data.length; i += 4) { + const v = Math.random() * 255; + img.data[i] = v; + img.data[i + 1] = v; + img.data[i + 2] = v; + img.data[i + 3] = 14; + } + ctx.putImageData(img, 0, 0); + } + } + HoverHandler { onHoveredChanged: root.hovered = hovered } |
