A scrappy little hobby project that does one thing: play a video as your Wayland desktop wallpaper.
I built this for myself because I wanted animated wallpapers on Hyprland and nothing
out there did it quite the way I wanted. It works on any compositor that supports
zwlr_layer_shell_v1 (Sway, Hyprland, river, labwc,niri, …).
Fair warning: this is a personal project, not a polished product. It does what I need it to do, but it's far from feature-complete. See the limitations section below for what's missing.
| Layer | What happens |
|---|---|
| Decode | GStreamer decodes video in background threads. VAAPI hardware decoding is used automatically when available; software fallback otherwise. |
| Upload | Decoded frames are mapped directly from the GstBuffer and written to a GPU texture via wgpu no Vec allocation, no CPU-side copy. |
| Render | A full-screen quad is drawn onto a wlr-layer-shell surface using wgpu (Vulkan or OpenGL backend). A WGSL fragment shader handles the BGRA → RGBA swizzle. |
- Rust (edition 2024)
- GStreamer 1.x + base/good/bad plugins
- Wayland compositor with
zwlr_layer_shell_v1 - Vulkan or OpenGL-capable GPU (wgpu backend)
sudo pacman -S gstreamer gst-plugins-base gst-plugins-good gst-plugins-badFor VAAPI hardware decoding, also install:
# Arch
sudo pacman -S gst-plugin-va
cargo build --releaseThe binary is at target/release/q6w.
The project uses commit-based versioning. Each build includes the git commit hash in the version string (e.g., 0.1.0+84dddc3). You can check your version with:
q6w --versionA PKGBUILD is included for building Arch packages. The package version automatically uses the commit count.
To build and install locally:
makepkg -siFor AUR submission, generate .SRCINFO:
makepkg --printsrcinfo > .SRCINFOq6w --file <VIDEO>
| Flag | Description |
|---|---|
-f, --file <FILE> |
Path to the video file |
-a, --audio |
Enable audio playback (off by default) |
--volume <VOLUME> |
Audio volume, 0.0 – 1.0 (default: 1.0) |
--mute-on-window |
Mute audio when any window is focused or maximized (requires -a) |
--pause-on-window |
Pause video when any window is focused or maximized |
--no-pause-on-fullscreen |
Disable automatic pause when a window goes fullscreen |
--fps <FPS> |
Framerate limit (e.g. 30) |
--no-fallback-guard |
Allow software decoding above 1080p |
--license |
Print license info and source code links |
-V, --version |
Print version |
-h, --help |
Print help |
# basic play a video as wallpaper
q6w --file ~/Videos/wallpaper.mp4
# with audio at half volume
q6w --file ~/Videos/wallpaper.mp4 --audio --volume 0.5
# mute audio when windows are focused (unmute when wallpaper is visible)
q6w --file ~/Videos/wallpaper.mp4 --audio --mute-on-window
# pause video when windows are focused (resume when wallpaper is visible)
q6w --file ~/Videos/wallpaper.mp4 --pause-on-window
# disable fullscreen auto-pause (useful for multi-monitor setups)
q6w --file ~/Videos/wallpaper.mp4 --no-pause-on-fullscreen
# cap at 30 fps to save power
q6w --file ~/Videos/wallpaper.mp4 --fps 30src/
main.rs CLI entry point, Wayland connection setup
app.rs Wayland state & protocol Dispatch implementations
gst_pipeline.rs GStreamer decode pipeline (VAAPI → software fallback)
gpu_renderer.rs wgpu full-screen quad renderer (zero-copy upload)
This is a hobby project it scratches my itch, but it doesn't try to be everything. Here's what it doesn't do (yet, or maybe ever)
- No multi-monitor support: it renders on whatever output the compositor gives it; you can't pick a specific screen or set different videos per monitor.
- No playlist / shuffle: one video, looped. That's it.
- No runtime control: no IPC, no socket, no D-Bus. To change the video, kill it and start a new one.
- No image wallpapers: video only. Use
swaybgor similar for static images. - No X11: Wayland only, and specifically compositors with
zwlr_layer_shell_v1. - No graceful handling of GPU loss if your GPU resets, q6w will crash.
- Software decoding above 1080p is blocked by default: CPU and memory usage can
get extreme. You can override this with
--no-fallback-guard, but don't say I didn't warn you.
Pull requests are welcome if any of this bothers you enough to fix it.
Tested on my single-monitor(1920x1200@60hz) Arch Linux setup on debug profile with VAAPI enabled.
Sample file:
- 3840x2160 (4K UHD)
- 60 FPS
- H.264 (Main), ~140 Mbps
- ~700 MB, 43 seconds looped
Memory usage (RSS):
- 60 FPS: ~70–75 MB (stable after startup)
- 30 FPS cap: ~55–65 MB (stable)
Observed over ~1 hour runtime with no upward trend.
This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0-only).
Source code:
- GitHub: https://github.com/Sreehari425/q6w
- Codeberg (mirror): https://codeberg.org/sreehari425/q6w