Use GLSL shaders or videos as your live desktop wallpaper.
| Shade with a GLSL shader | Shade with a video |
|---|---|
![]() |
![]() |
./bin/ShadeYourDesktop \
--fs assets/matrix.glsl \
--t0 assets/glyph.png |
./bin/ShadeYourDesktop \
--video path/to/video.mp4 |
- Runs Shadertoy-style fragment shaders (
mainImage) behind your desktop icons - Plays videos as a looping wallpaper (any format FFmpeg can decode)
- Up to 4 image textures (
iChannel0–iChannel3) for shaders - Synced to the display refresh rate, so it stays light on CPU/GPU
Platform: macOS. The code builds on Windows, but putting the window behind the desktop icons isn't implemented there yet.
brew install ffmpeg cmake
git clone https://github.com/bbbbx/ShadeYourDesktop.git
cd ShadeYourDesktop
git submodule update --init extern/glfw extern/ProgramOptions.hxx
cmake . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j 8
./bin/ShadeYourDesktop --fs=assets/voronoi.glslPress Ctrl+C in the terminal to stop it. The wallpaper window has no title bar, so it can't be closed any other way.
ShadeYourDesktop [options]
-V, --video Video file name
--fs Fragment shader file name
--t0 texture 0 file name
--t1 texture 1 file name
--t2 texture 2 file name
--t3 texture 3 file name
-h, --help Help message
Pass option values with a space or =, for example --fs shader.glsl or --fs=shader.glsl.
Run a shader:
./bin/ShadeYourDesktop --fs assets/appolloian.glslRun a shader that samples a texture:
./bin/ShadeYourDesktop --fs assets/matrix.glsl --t0 assets/glyph.pngPlay a video:
./bin/ShadeYourDesktop --video path/to/video.mp4Run a shader on a video. The current video frame is bound to iChannel0:
./bin/ShadeYourDesktop --video path/to/video.mp4 --fs my_video_effect.glslWith no options, it runs a built-in color gradient shader.
| Shader | Textures |
|---|---|
assets/appolloian.glsl |
– |
assets/minecraft.glsl |
– |
assets/voronoi.glsl |
– |
assets/matrix.glsl |
--t0 assets/glyph.png |
Shaders use GLSL 330. Write a Shadertoy-style mainImage function and the main() entry point is generated for you:
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
vec3 col = 0.5 + 0.5 * cos(iTime + uv.xyx + vec3(0, 2, 4));
fragColor = vec4(col, 1.0);
}You can write your own void main() instead, and write to fragColor.
These inputs are available:
| Name | Type | Description |
|---|---|---|
iTime |
float |
Seconds since start |
iResolution |
vec2 |
Framebuffer size in pixels |
iChannel0–iChannel3 |
sampler2D |
Textures from --t0–--t3. With --video, iChannel0 is the current video frame. |
v_uv |
vec2 |
Normalized screen coordinates, 0–1 |
iMouse |
vec2 |
Constant vec2(1). Mouse input isn't supported. |
u_time, u_resolution and u_mouse are aliases for iTime, iResolution and iMouse, so some The Book of Shaders examples also work.
Images are loaded flipped, so their origin is at the bottom left like fragCoord. Video frames are not flipped, so sample them with uv.y = 1.0 - uv.y.
Only single-pass shaders are supported. Shadertoy's Buffer A–D, iMouse, iFrame, iDate and audio inputs are not available.
Video playback needs FFmpeg's shared libraries (avformat, avcodec, swscale, avutil).
With Homebrew (recommended):
brew install ffmpegFrom source, using the bundled submodule:
git submodule update --init --recursive
cd extern/FFmpeg
mkdir build
./configure --prefix=$(pwd)/build --disable-doc --disable-programs --disable-static --enable-shared
make -j8
make installThis installs to extern/FFmpeg/build. If configure reports nasm/yasm not found or too old, run brew install nasm and try again.
CMake looks for FFmpeg through two cache variables:
| Variable | Default |
|---|---|
FFmpeg_INCLUDE |
/opt/homebrew/include |
FFmpeg_LIB |
/opt/homebrew/lib |
The defaults work for Homebrew on Apple Silicon. For other locations, pass them explicitly:
# Homebrew on an Intel Mac
cmake . -B build -DFFmpeg_INCLUDE=$(brew --prefix)/include -DFFmpeg_LIB=$(brew --prefix)/lib
# FFmpeg built from source
cmake . -B build -DFFmpeg_INCLUDE=$(pwd)/extern/FFmpeg/build/include -DFFmpeg_LIB=$(pwd)/extern/FFmpeg/build/libThen build:
cmake --build build -j 8 --config ReleaseThe executable is written to bin/. If FFmpeg isn't installed in a standard location, the dynamic loader must be able to find its shared libraries (.dylib on macOS, .dll on Windows) at runtime.
No accelerated colorspace conversion found from yuv420p to rgbais an informational FFmpeg message, not an error. On Apple Silicon, a NEON fast path is still used when the video width is a multiple of 16 and its height is even.- A shader fails to compile. The compiler log and the full generated source are printed, and the program exits. The line numbers in the log count from the top of the generated source, which starts with about 20 lines of prepended declarations.

