ipc/ui: support custom transition shaders and animation config - #371
Open
markg85 wants to merge 1 commit into
Open
ipc/ui: support custom transition shaders and animation config#371markg85 wants to merge 1 commit into
markg85 wants to merge 1 commit into
Conversation
Author
|
A little later then intended but that's resolved. |
markg85
force-pushed
the
wallpaper_shader_transition
branch
from
July 19, 2026 22:12
91317e1 to
1ec1728
Compare
Author
|
@vaxerski This and it's companion PRs are ready for review.
I can rebase this against master if you want. Though i prefer to have feedback in it's current state as this is far easier for me to test/run then to swap to master. |
markg85
marked this pull request as ready for review
July 19, 2026 22:19
markg85
force-pushed
the
wallpaper_shader_transition
branch
2 times, most recently
from
July 22, 2026 15:33
885252e to
5fde1a9
Compare
Adds the shader_path request (hyprpaper_wallpaper v2) so a custom fragment shader can be supplied per wallpaper apply, and an existing monitor wallpaper now transitions to the new path instead of replacing outright. - IPC::CWallpaperObject stores and forwards the shader path. - CConfigManager::getAnimationConfig reads fadeLayersIn/fadeLayersOut (enabled + duration) from hyprland.conf, cached per name. - CWallpaperTarget::transitionTo / replaceImmediate delegate to the image element; CUI reuses the existing target when one already exists for the monitor, animating only when an animation config is enabled. - Example custom shaders under shaders/ (circle-reveal, diagonal-wipe).
markg85
force-pushed
the
wallpaper_shader_transition
branch
from
August 16, 2026 00:08
5fde1a9 to
356667c
Compare
Author
|
Review this please. |
Author
|
It's becoming hard to keep this working, please review! I want to merge this for the next release if possible. @vaxerski |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
AI DISCLAIMER
Yes, I used AI. I could not do the GL bits on my own (C/C++ background here, not game dev) so I kinda trust AI to do the right thing there. I did let it review itself and let another model review it too. I'm fairly confident the code is of a good quality. If it has errors then I would've made those too. I did also review all the other non-GL code and in all honestly did caught a few issues you don't even see anymore (like stat'ing the shader every frame... Ouch. The code in my opinion looks good. I'm also running this right here and now. I'm obviously going to gladly handle feedback and suggestions!
Wallpaper transition demo
I've been wanting to have this feature ever since I moved to Hyprland. At first I had build this before the wallpaper logic was shader based so that work was completely lost on my end. And now I rebuild it with the current hyprland logic, and it is buttery smooth! My intent here is to et hyprland do it's default thing and only provide a custom shader animation at the moment of transitioning. That is also why I did not provide a shader path configuration setting. To me it seemed just fine to only have this in the hyprctl path. This would allow someone like @mylinuxforwork to enjoy smooth transitions rendered on the GPU instead of these "performant" cpu tricks that have been used thus far.
Note! This is written against tag v0.8.4, not master!
Consider this a draft!This commit also contains 2 example shader. I'm guessing those should be left out for the final version but for now they serve as demo of specifically the duration handling. Below in this post also the
circle revealshader.Usage
The fields, in order:
stretch,cover,contain,tile.fragshaderIf you leave off the fourth argument, hyprpaper uses its built-in transition shader, which is a plain crossfade.
Where the duration comes from
The transition length is read from your hyprland config, not the shader:
hyprpaper parses those two lines. The actual transition runs for the larger of the two durations. The bezier name at the end is ignored as that should probably be handled in the shader itself which i didn't change. A shader can finish its visual effect sooner than that and then hold the final frame (see below).
Interrupting a transition
If you send a new wallpaper command while a transition is still running, hyprpaper does not snap or flicker. It renders the current blended frame into an off-screen framebuffer, uses that as the new start texture, and begins a fresh transition to the new target. You can chain wallpapers as fast as you like.
The shader contract
A custom shader is GLSL ES 3.00 (
#version 300 es). It is compiled once and cached. hyprpaper stats the file at the start of each transition and recompiles only when the mtime changed, so editing the shader and reissuing the command picks up the change.The host sets these uniforms every frame:
Two vertex attributes come in:
posandtexcoord, both in 0..1. The fragment shader readsv_texcoord. Write tolayout(location = 0) out vec4 fragColor.One GLES gotcha: you cannot initialize a uniform with a default value in the shader.
u_durationis always 0 unless the host sets it, which it does every frame. So if your shader wants its own visual length that differs from the host duration, declare aconst floatand remapprogressagainstu_durationyourself.The simplest possible shader is just
mix(texture(tex1, v_texcoord), texture(tex2, v_texcoord), progress).A shader can override its own visual length
The host transition lasts
u_durationseconds. If your effect should complete in, say, half a second regardless of that, pick a constant and compress progress:When
progressreaches 1.0 the host stops the transition. So if your effect finishes early, the remaining frames just hold the final state until the host duration elapses. The circle reveal below does exactly that.Full example: circle reveal
This reveals the new wallpaper outward from a random point. The visual sweep finishes in 0.5 seconds; after that it holds the new image until the host duration ends. It also handles cover and contain fit modes so neither texture gets stretched oddly.
Things to keep in mind
progressis the only value that changes meaningfully frame to frame. Treateverything else as constant per transition.
randomPixelis regenerated at the start of each transition. Use it orignore it.
contain, sample coordinates can fall outside 0..1. Decide what you wantthere. This example paints it black.
transition.