per-pixel wave reveal mask for lock screen overlay layers

This commit is contained in:
Damocles 2026-04-18 11:35:51 +02:00
parent e4b257d760
commit e2f8accbc1
3 changed files with 59 additions and 33 deletions

View file

@ -27,10 +27,13 @@ stdenvNoCC.mkDerivation {
mkdir -p $out/share/nova-shell mkdir -p $out/share/nova-shell
cp -r shell/shell.qml shell/modules shell/services shell/applets shell/lock shell/assets $out/share/nova-shell/ cp -r shell/shell.qml shell/modules shell/services shell/applets shell/lock shell/assets $out/share/nova-shell/
# Compile fragment shader to Qt RHI format # Compile fragment shaders to Qt RHI format
qsb --qt6 \ qsb --qt6 \
-o $out/share/nova-shell/modules/hex_wave.frag.qsb \ -o $out/share/nova-shell/modules/hex_wave.frag.qsb \
shell/modules/hex_wave.frag shell/modules/hex_wave.frag
qsb --qt6 \
-o $out/share/nova-shell/modules/reveal_mask.frag.qsb \
shell/modules/reveal_mask.frag
mkdir -p $out/bin mkdir -p $out/bin
makeWrapper ${lib.getExe quickshell} $out/bin/nova-shell \ makeWrapper ${lib.getExe quickshell} $out/bin/nova-shell \

View file

@ -13,9 +13,7 @@ WlSessionLockSurface {
color: S.Theme.base00 color: S.Theme.base00
// Wave progress drives blur/dim/hex overlay reveal
property real _unlockFade: 1 property real _unlockFade: 1
readonly property real _waveProgress: (root.width > 0 ? Math.max(0, Math.min(1, _hexWave.wavePhase / root.width)) : 0) * _unlockFade
// Clear desktop screenshot - visible immediately // Clear desktop screenshot - visible immediately
ScreencopyView { ScreencopyView {
@ -25,12 +23,23 @@ WlSessionLockSurface {
opacity: _unlockFade opacity: _unlockFade
} }
// Blurred screenshot - fades in as wave passes // Overlay group: blur + dim + hexes, revealed per-pixel by wave position
Item {
anchors.fill: parent
opacity: _unlockFade
layer.enabled: true
layer.effect: ShaderEffect {
property real uPhase: _hexWave.wavePhase
property real uWidth: root.width
fragmentShader: Quickshell.shellPath("modules/reveal_mask.frag.qsb")
}
// Blurred screenshot
ScreencopyView { ScreencopyView {
anchors.fill: parent anchors.fill: parent
captureSource: root.screen captureSource: root.screen
visible: S.Modules.lock.screenshot ?? true visible: S.Modules.lock.screenshot ?? true
opacity: root._waveProgress
layer.enabled: true layer.enabled: true
layer.effect: MultiEffect { layer.effect: MultiEffect {
@ -41,19 +50,19 @@ WlSessionLockSurface {
} }
} }
// Dim overlay - fades in with wave // Dim overlay
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
color: Qt.rgba(S.Theme.base00.r, S.Theme.base00.g, S.Theme.base00.b, 0.4) color: Qt.rgba(S.Theme.base00.r, S.Theme.base00.g, S.Theme.base00.b, 0.4)
opacity: root._waveProgress
} }
// Hex wave - fades in with wave progress // Hex wave
C.HexWaveBackground { C.HexWaveBackground {
id: _hexWave id: _hexWave
anchors.fill: parent anchors.fill: parent
running: root.lock.secure running: root.lock.secure
opacity: root._waveProgress * 0.4 opacity: 0.4
}
} }
// Keyboard input via TextInput - engages Qt's full input pipeline including // Keyboard input via TextInput - engages Qt's full input pipeline including
@ -242,13 +251,6 @@ WlSessionLockSurface {
duration: 300 duration: 300
easing.type: Easing.InCubic easing.type: Easing.InCubic
} }
NumberAnimation {
target: _hexWave
property: "opacity"
to: 0
duration: 300
easing.type: Easing.InCubic
}
} }
PropertyAction { PropertyAction {

View file

@ -0,0 +1,21 @@
#version 440
layout(location = 0) in vec2 qt_TexCoord0;
layout(location = 0) out vec4 fragColor;
layout(std140, binding = 0) uniform buf {
mat4 qt_Matrix;
float qt_Opacity;
float uPhase;
float uWidth;
};
layout(binding = 1) uniform sampler2D source;
void main() {
vec4 tex = texture(source, qt_TexCoord0);
float x = qt_TexCoord0.x * uWidth;
// Soft reveal edge: fully visible 200px behind wave, fades out 50px ahead
float mask = 1.0 - smoothstep(uPhase - 200.0, uPhase + 50.0, x);
fragColor = tex * mask * qt_Opacity;
}