diff options
| author | Danilo M. <danix@danix.xyz> | 2026-10-29 12:37:47 +0100 |
|---|---|---|
| committer | Danilo M. <danix@danix.xyz> | 2026-10-29 12:37:47 +0100 |
| commit | cc91156f9f564b2a3265ad530116a999ffe2122b (patch) | |
| tree | 68c97f00c36671b59ce6563ac91d55469a041ccd /desktop/modules/appearance/burn.frag | |
| parent | 4d1c5acf5748b9a9b9b40cfb6ee1118593bacecd (diff) | |
| download | quickshell-cc91156f9f564b2a3265ad530116a999ffe2122b.tar.gz quickshell-cc91156f9f564b2a3265ad530116a999ffe2122b.zip | |
wallpaper: burn the old picture away on Apply
swaybg has no transitions: wallp kills the running one and starts a new
one, which can show a frame of nothing in between. WallpaperSpread puts a
click-through surface on the bottom layer of each screen, above swaybg and
below every window, holding the old picture while wallp runs. A shader
burns it away over the new one: each pixel's threshold mixes its distance
from a random starting point with fractal noise, and a flame and char band
runs just ahead of the front. The surface goes once wallp has exited, or
at once if it failed, since a failed set may have left either picture.
Wallpapers.apply() announces each swap with the old path before wallp
runs, while current still names it. Sets from a terminal get no effect:
by the time wall_h changes, swaybg has already swapped.
The animation is linear, 3.5s: an ease spent its slow ends where nothing
was left to burn, and read as well under the 2.6s it was given. The
compiled .qsb is committed beside its source, since nothing builds it.
AGENTS.md gains the shader cache trap hit on the way: a running shell
keeps a shader by URL, so a recompiled .qsb under the same name is
ignored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Diffstat (limited to 'desktop/modules/appearance/burn.frag')
| -rw-r--r-- | desktop/modules/appearance/burn.frag | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/desktop/modules/appearance/burn.frag b/desktop/modules/appearance/burn.frag new file mode 100644 index 0000000..a5cb9c3 --- /dev/null +++ b/desktop/modules/appearance/burn.frag @@ -0,0 +1,60 @@ +// Copyright (C) 2026 Danilo M. <danix@danix.xyz> +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2 as +// published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// The old wallpaper burning away like a sheet of paper. A pixel goes once +// progress passes its threshold: its distance from where the fire started +// mixed with fractal noise, so the front is ragged at every scale. Just ahead +// of the front the paper glows and chars. Compiled with: +// qsb --qt6 -o burn.frag.qsb burn.frag +#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 progress; + float aspect; + vec2 origin; +}; +layout(binding = 1) uniform sampler2D source; + +float hash(vec2 p) { return fract(sin(dot(p, vec2(12.9898, 78.233))) * 43758.5453); } + +float noise(vec2 p) { + vec2 i = floor(p), f = fract(p); + vec2 u = f * f * (3.0 - 2.0 * f); + return mix(mix(hash(i), hash(i + vec2(1, 0)), u.x), + mix(hash(i + vec2(0, 1)), hash(i + vec2(1, 1)), u.x), u.y); +} + +float fbm(vec2 p) { + float v = 0.0, a = 0.5; + for (int i = 0; i < 5; i++) { v += a * noise(p); p *= 2.03; a *= 0.5; } + return v; +} + +void main() { + vec2 asp = vec2(aspect, 1.0); + float d = length((qt_TexCoord0 - origin) * asp) / length(max(origin, 1.0 - origin) * asp); + float t = mix(d, fbm(qt_TexCoord0 * asp * 5.0), 0.5); + float e = t - progress; + if (e <= 0.0) { fragColor = vec4(0.0); return; } + + // Front to intact paper: flame, then char, then the picture. + const float w = 0.05; + float k = clamp(e / w, 0.0, 1.0); + vec3 fire = vec3(1.6, 0.75, 0.2); + vec3 ash = vec3(0.07, 0.04, 0.02); + vec3 paper = texture(source, qt_TexCoord0).rgb; + vec3 col = k < 0.3 ? mix(fire, ash, k / 0.3) : mix(ash, paper, smoothstep(0.3, 1.0, k)); + float a = smoothstep(0.0, 0.004, e); + fragColor = vec4(col * a, a) * qt_Opacity; +} |
