wpaperd is the modern wallpaper daemon for Wayland. It dynamically changes the current wallpaper, either after a certain amount of time or via a command-line interface. It uses OpenGL ES to render the images and have beautiful hardware-accelerated transitions, while being easy on resources.
Notice: wpaperd uses wlr_layer_shell wayland protocol, which is available on all wlroots based compositors (sway, hyprland, ...) and on KDE. Therefore it won't work on GNOME.
Notice2: Hyprland does not behave like the other compositors, causing multiple issues to wpaperd. For this reason Hyprland is not supported by wpaperd.
wpaperd is written in Rust and requires a working Cargo installation. It also depends on:
mesawayland-clientwayland-eglrinstall (optional, for installing wpaperd)libdav1d (optional, for loading avif images)To install wpaperd, clone the repository and build the project:
$ git clone https://github.com/danyspin97/wpaperd
$ cd wpaperd
$ cargo build --release
Generate the man pages by running scdoc:
$ scdoc < man/wpaperd-output.5.scd > man/wpaperd-output.5
You can install both the daemon (wpaperd) and cli (wpaperctl) using rinstall:
$ rinstall install --yes
To run wpaperd, run the daemon:
$ wpaperd
If you want to automatically run it at startup, add this line to your sway configuration
(located in $HOME/.config/sway/config):
# Assuming it has been installed in ~/.local/bin/wpaperd
exec ~/.local/bin/wpaperd -d
Or in Hyprland:
exec-once=~/.local/bin/wpaperd -d
wpaperd uses the [image] create to load and display images. Have a look on its documentation for the supported formats.
Note: To enable avif format, build wpaperd with avif feature (requires libdav1d to be
installed.
When path is set to a directory, you can cycle the images by running the commands next and
previous using wpaperctl:
$ wpaperctl next
$ wpaperctl previous
When sorting is set to ascending and descending, wpaperd will use the wallpaper name to
calculate the next wallpaper accordingly. When sorting is set to random, it will store
all the wallpapers shown in a queue, so that the commands next and previous can work
as intended.
Notice: the queue only works when queue-size setting (which defaults to 10) is bigger
than the number of available images in the folder.
The cycling of images can also be paused/resumed by running the pause and resume commands, or just toggle-pause, using wpaperctl:
$ wpaperctl pause
$ wpaperctl resume
$ wpaperctl toggle-pause
You can set a wallpaper to a specific image using wpaperctl:
$ wpaperctl set /path/to/image.png
$ wpaperctl set /path/to/image.png DP-1 # specific monitor
When you set a wallpaper:
- Automatic cycling is paused
- Calling next or previous resumes cycling
- The previous command returns to the wallpaper that was showing before the set (it doesn't go back in history)
- If you explicitly called pause before set, cycling remains paused until you call resume or toggle-pause
The configuration file for wpaperd is located in XDG_CONFIG_HOME/wpaperd/config.toml
(which defaults to ~/.config/wpaperd/config.toml). Each section
represents a different display and can contain the following keys:
path, path to the image to use as wallpaper or to a directory to pick the wallpaper fromduration, how much time the image should be displayed until it is changed with a new one.
It supports a human format for declaring the duration (e.g. 30s or 10m), described
here.
This is only valid when path points to a directory. (Optional)sorting, choose the sorting order. Valid options are ascending, descending, and random,
with the default being random. This is only valid when path points to a directory. (Optional)group, assign multiple displays to same group to share the same wallpaper when using
random sorting; group must be a number. (Optional)mode, choose how to display the wallpaper when the size is different than the display
resolution:fit shows the entire image with black corners covering the empty space leftfit-border-color works like fit, but fill the empty space with the color of the border
of the image; suggested for images that have a solid color in their bordercenter centers the image on the screen, leaving out the corners of the image that couldn't fitstretch shows the entire image stretching it to fit the entire screen without leaving any
black corner, changing the aspect ratiotile shows the image multiple times horizontally and vertically to fill the screentransition-time, how many milliseconds should the transition run. (Optional, 300 by default).offset, offset the image on the screen, with a value from 0.0 to 1.0. (Optional, 0.0 by
default for tile mode and 0.5 for all the other modes)queue-size, decide how big the queue should be when path is set a directory and sorting is
set to random. (Optional, 10 by default)initial-transition, enable the initial transition at wpaperd startup. (Optional, true by default)recursive, recursively iterate the directory path when looking for available wallpapers;
it is only valid when path points to a directory. (Optional, true by default)exec, path to a script that will be executed every time the wallpaper changes; the script
will be called with the display and the new wallpaper as argument. (Optional)The section default will be used as base for the all the display configuration; the section
any will be used for all the displays that are not explictly listed. This allows to have a
flexible configuration without repeating any settings. wpaperd will check the configuration at
startup and each time it changes and provide help when it is incorrect.
This is the simplest configuration:
[DP-3]
path = "/home/danyspin97/github_octupus.png"
[DP-4]
path = "/home/danyspin97/Wallpapers"
duration = "30m"
This is a more complex configuration:
[default]
duration = "30m"
mode = "center"
sorting = "ascending"
[any]
path = "/home/danyspin97/default_wallpaper.png"
[DP-3]
path = "/home/danyspin97/Wallpapers"
["Dell Inc. DELL U2419H GY1VSS2"]
path = "/home/danyspin97/Wallpapers/1080p"
Another way to match a section to one or more displays is by using regex:
# Matches all displays that have the string "LG" in their description
["re:LG"]
# Matches all displays that are connected through display port (e.g. DP-1, DP-2)
["re:DP-\\d"]
If you're running sway, you can look for the available outputs and their ID (or description) by running:
$ swaymsg -t get_outputs
On Hyprland you can run:
$ hyprctl monitors
Output descriptions take priority over output IDs.
wpaperd creates a symlink in XDG_STATE_HOME/wpaperd/wallpapers
(.local/state/wpaperd/wallpapers by default) for each display that points to the current
wallpaper used. This is useful to integrate the current status with other components.
~ $ ls ~/.local/state/wpaperd/wallpapers
DP-3@ DP-4@
With the exec config parameter, wpaperd will execute a script every time the wallpaper changes.
This is an example script that can be used with pywal:
#!/bin/bash
display=$1
wallpaper=$2
echo "Display is : $display"
echo "Wallpaper path is: $wallpaper"
# Update Pywal
echo ":: Applying pywal with $wallpaper"
wal -q -i "$wallpaper"
source "$HOME/.cache/wal/colors.sh"
Since version 1.1, wpaperd support multiple transitions types, taken from gl-transition.
The transition can be changed at runtime and most of them are configurable, e.g. you can change
the direction of directional transition or the speed for dissolve transition, etc. Every
transition bring each own defaults, so you can just leave everything empty unless you want
to customize the transition. The default transition-time for each transition is different,
to provide a better experience out of the box.
To switch between available transitions, add the following to wpaperd configuration:
[default]
path = "/home/danyspin97/Wallpapers"
duration = "30m"
sorting = "ascending"
[default.transition.hexagonalize]
# default values for hexagonalize
# steps = 50
# horizontal-hexagons = 20.0
This is the list of available transitions with their own settings and defaults:
book-flip (2000)bounce (4000):shadow-colour: [0.0, 0.0, 0.0, 0.6]shadow-height: 0.075bounces: 3.0bow-tie-horizontal (1500)bow-tie-vertical (1500)butterfly-wave-scrawler (2000):amplitude: 1.0waves: 30.0color-separation: 0.3circle (3000)circle-crop (3000)bgcolor: [0.0, 0.0, 0.0, 1.0]circle-open (1500):smoothness: 0.3opening: truecolour-distance (2000):power: 5.0cross-warp (1000):cross-zoom (2000):strength: 0.4directional (1000):direction: [0.0, 1.0]directional-scaled (1000):direction: [0.0, 1.0]scale: 0.7directional-wipe (1000):direction: [1.0, -1.0]smoothness: 0.5dissolve (1000):line-width: 0.1spread-clr: [1.0, 0.0, 0.0]hot-clr: [0.9, 0.9, 0.2]intensity: 1.0pow: 5.0doom (2000):bars: 30amplitude: 2.0noise: 0.1frequency: 0.5drip-scale: 0.5doorway (1500):reflection: 0.4perspective: 0.4depth: 3.0dreamy (1500)dreamy-zoom (1500):rotation: 6.0scale: 1.2edge (1500):thickness: 0.001brightness: 8.0fade (300)film-burn (2000):seed: 2.31glitch-displace (1500)glitch-memories (1500)grid-flip (1500):size: [4, 4]pause: 0.1divider-width: 0.05bgcolor: [0.0, 0.0, 0.0, 1.0]randomness: 0.1hexagonalize (2000):steps: 50horizontal-hexagons: 20.0horizontal-close (2000)horizontal-open (2000)inverted-page-curl (2000)left-right (2000)linear-blur (800):intensity: 0.1mosaic (2000):endx: 2endy: -1overexposure (2000)pixelize (1500):squares-min: [20, 20]steps: 50polkan-dots-curtain (2000):dots: 20.0center: [0.0, 0.0]radial (1500):smoothness: 1.0rectangle (2000):bgcolor: [0.0, 0.0, 0.0, 1.0]ripple (1500):amplitude: 100.0speed: 50.0rolls (2000):rolls-type: 0rot-down: falserotate-scale-fade (1500):center: [0.0, 0.5]rotations: 1.0scale: 8.0back-color: [0.15, 0.15, 0.15, 1.0]rotate-scale-vanish (1500):fade-in-second: truereverse-effect: falsereverse-rotation: falsesimple-zoom (1500):zoom-quickness: 0.8$ claude mcp add wpaperd \
-- python -m otcore.mcp_server <graph>