aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-09-29 13:04:00 +0200
committerDanilo M. <danix@danix.xyz>2026-09-29 13:04:00 +0200
commitae193343b9633eb79287c4e2589b95c02f538e48 (patch)
tree4035fb4f38394d7e2000732977a020b3f3c00c90
parent700f4be432e2c0f54fd6708b6a085b1fb9dd6108 (diff)
downloadquickshell-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.qml40
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
}