CLI tool
danyspin97/wpaperd avatar
danyspin97/wpaperd

wpaperd: a Wayland wallpaper daemon that skips GNOME and Hyprland

Modern wallpaper daemon for Wayland

621 stars49 forksRustGPL-3.0

At a glance

What is it?
wpaperd is a Rust wallpaper daemon for wlroots based Wayland compositors that renders with OpenGL ES, cycles images from a directory and reloads its TOML config on the fly. Its layer shell dependency is the defining constraint, since the project states plainly that it will not work on GNOME and is not supported on Hyprland.
Who is it for?
wpaperd suits someone running sway or another wlroots based compositor who wants per monitor wallpapers, directory cycling and a config they can edit and reload without restarting the daemon. It does not suit a GNOME user or a Hyprland user, because the project states it will not work on GNOME and is not supported on Hyprland.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 74 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What wpaperd does and which compositors it refuses

wpaperd is a wallpaper daemon for Wayland. It changes the current wallpaper either after a set amount of time or on command from a command line interface, and it renders the images with OpenGL ES so that transitions are hardware accelerated and the process stays light on resources.

The compositor support is the first thing to settle, and the project is blunt about it. wpaperd uses the wlr_layer_shell wayland protocol, which is available on all wlroots based compositors such as sway and hyprland, and on KDE. Therefore it will not work on GNOME. A second notice says that Hyprland does not behave like the other compositors, causing multiple issues, and that for this reason Hyprland is not supported by wpaperd.

Those two statements sit awkwardly next to each other, since hyprland is named as a wlroots based compositor in the first notice and then excluded in the second. The practical reading is that the layer shell dependency covers the wlroots family in general, but that Hyprland's behaviour with it breaks enough of wpaperd to be ruled out.

The remaining features are the ones a wallpaper daemon needs to be useful day to day: a different wallpaper for each display, picking from a directory, changing after a duration, several sorting methods, a flexible TOML configuration file, hot config reloading for all settings, a command line interface, configurable hardware accelerated transitions, several background modes, and low CPU and memory usage.

Building from source and installing the daemon and the cli

wpaperd is written in Rust, so a working Cargo installation is the first requirement. The listed dependencies are mesa, wayland-client and wayland-egl, plus rinstall as an optional dependency for installing wpaperd itself, and libdav1d as an optional dependency for loading avif images.

The build is three commands:

bash
$ git clone https://github.com/danyspin97/wpaperd
$ cd wpaperd
$ cargo build --release

Man pages are generated from scdoc sources:

bash
$ scdoc < man/wpaperd-output.5.scd > man/wpaperd-output.5

Installing both the daemon and the command line client is a single rinstall invocation:

bash
$ rinstall install --yes

Running the daemon is just:

bash
$ wpaperd

For startup, the documentation suggests adding a line to the sway configuration file, located in $HOME/.config/sway/config:

bash
# Assuming it has been installed in ~/.local/bin/wpaperd
exec ~/.local/bin/wpaperd -d

The Hyprland equivalent is an exec-once line:

bash
exec-once=~/.local/bin/wpaperd -d

The -d flag is what the daemon uses to detach. The repository also carries a nix/ directory with flake.nix and flake.lock, a contrib/ directory, an install.yml, a MAINTAINERS.md file, and a CHANGELOG.md, so packaging beyond the source build is at least partly handled. A repology badge is shown in the README, which indicates the daemon is packaged in at least some distribution repositories.

The TOML config: one section per display

The configuration file lives at XDG_CONFIG_HOME/wpaperd/config.toml, which defaults to ~/.config/wpaperd/config.toml. Each section represents a different display, and each can hold a set of keys.

The core keys are path, which points either at an image file or at a directory to pick wallpapers from, and duration, how long an image stays on screen before it changes. The duration accepts a human format such as 30s or 10m, parsed with the humantime crate, and it is only valid when path points to a directory.

Sorting takes ascending, descending or random, with random as the default, and it is also only valid for a directory path. The group key assigns several displays to the same group so they share a wallpaper when random sorting is used, and it must be a number.

The mode key decides what happens when the image size differs from the display resolution. fit shows the whole image with black corners in the empty space. fit-border-color behaves like fit but fills that space with the border colour of the image, which the documentation suggests for images with a solid coloured border. center centres the image and leaves out the corners that cannot fit. stretch shows the entire image by changing the aspect ratio. tile repeats the image horizontally and vertically.

The remaining keys are numeric or boolean and have defaults: transition-time in milliseconds, 300 by default, offset from 0.0 to 1.0 with 0.0 for tile and 0.5 for the other modes, queue-size at 10, initial-transition enabled by default, and recursive directory iteration enabled by default. The last key, exec, is a path to a script run every time the wallpaper changes, and the documentation line describing it is cut off mid sentence, so the exact contract of that script is not spelled out in what is published.

Cycling images and the queue-size gotcha

When path points to a directory, you move between images with the next and previous commands:

bash
$ wpaperctl next
$ wpaperctl previous

How those two commands behave depends on the sorting mode. With ascending or descending, wpaperd calculates the next wallpaper from the wallpaper name, so the order is the filename order. With random, it stores all the wallpapers it has shown in a queue, which is what lets next and previous work as expected rather than jumping randomly each time.

The queue has a constraint that trips people up. The documentation notes that the queue only works when the queue-size setting, which defaults to 10, is bigger than the number of available images in the folder. In practice, with the default queue-size of 10 this only bites if the folder holds ten or more images. If the queue stops working, setting queue-size above your image count is the fix, and it is a per display key.

Cycling can be suspended and resumed independently:

bash
$ wpaperctl pause
$ wpaperctl resume
$ wpaperctl toggle-pause

The reason to know about pause is the interaction with setting a wallpaper by hand. When you set a wallpaper, automatic cycling is paused. Calling next or previous resumes it. The previous command returns to the wallpaper that was showing before the set, and it does not walk back through earlier history. If you had explicitly called pause before the set, cycling stays paused until you call resume or toggle-pause.

Setting a wallpaper on one monitor

Setting a specific image is a one-liner through the same client:

bash
$ wpaperctl set /path/to/image.png
$ wpaperctl set /path/to/image.png DP-1  # specific monitor

The second form names the monitor, which is how you target one display out of a multi display setup when the config gives each display its own section.

The behaviour after a set is documented in four rules rather than left to be discovered. Automatic cycling is paused, calling next or previous resumes cycling, the previous command returns to the wallpaper that was showing before the set rather than going back in history, and an explicit pause before the set keeps cycling paused until you call resume or toggle-pause.

Image formats are handled by the image crate, so the supported list comes from that project rather than from wpaperd itself. AVIF is the exception that needs a build flag: to enable the avif format you build wpaperd with the avif feature, which requires libdav1d to be installed. That is the only format the documentation calls out as needing a special build, and it is a Cargo feature rather than a runtime option, so it has to be decided at compile time.

Why the daemon is split into three crates

The Cargo.toml at the root is a workspace with three members, cli, daemon and ipc, and resolver 2. That layout tells you the architecture without needing a design document.

The daemon is the long running process that owns the layer surface, renders with OpenGL ES and watches the configuration file for changes, which is what makes hot reloading possible for every setting. The cli is the short lived command line client that talks to it. The ipc member is the channel between them.

Splitting the IPC layer into its own crate is the interesting detail. It means wpaperctl and wpaperd share a typed protocol rather than agreeing on loose text, and it keeps the client buildable without pulling in the rendering stack. For a user this shows up as the practical separation between the two binaries, wpaperd and wpaperctl, which the documentation treats as separate installable pieces throughout.

The rest of the tree follows a normal Rust layout. The man/ directory holds the man page sources, including the scdoc input used to generate the output page. The nix/ directory holds the Nix flake, and the docs/ directory holds the project documentation. A .local/ directory at the top level is unusual, and the repository does not document what it holds.

Where wpaperd is the wrong choice

The compositor exclusions are the blunt fact of the matter. If your session runs on GNOME, this daemon does not work, and no amount of configuration changes that, because the dependency is on the wayland protocol rather than on a setting inside wpaperd. Hyprland users are in a similar position, except that the project frames it as Hyprland behaving differently rather than as a missing protocol.

The second wrong case is AVIF without planning ahead. Support for that format is a build feature, so a binary you compiled without it will not decode those images no matter what you point path at. The dependency list also assumes a Linux stack with mesa, wayland-client and wayland-egl already present, which is fine on a desktop but not on a minimal container.

The third is server or headless use. This is a wallpaper daemon for a Wayland session. There is no documented headless mode.

The fourth is documentation completeness. The exec key description is cut off, and the documentation does not explain how the daemon behaves when the configured path does not exist, or what happens to an in flight transition when the config is reloaded mid animation. Anyone who relies on hot reload to switch wallpaper sets during a presentation should test that path rather than assume it.

Compare that with the alternative approach of using a compositor built in wallpaper feature. Sway can set a background through its own configuration, which means no extra daemon, no IPC client and no separate process on your machine. The difference in approach is that wpaperd adds the parts a compositor does not do on its own: timed cycling with a queue, multiple sorting modes, per display grouping, hardware accelerated transitions between images and a TOML config with hot reload. If you only need a static background, a line in your sway config is less to run and less to break.

Licence, release cadence and the state of the tree

wpaperd is released under the GPL-3.0 licence, with the text in the LICENSE.md file at the repository root. The GPL is a strong copyleft licence, and a daemon that runs as your own user on your own machine does not usually trigger distribution obligations, but any redistribution of a modified binary does. Read the LICENSE.md file yourself for the exact terms rather than relying on the summary.

The release history is modest and the naming is descriptive. 1.2.1 on 2025-04-11 and 1.2.2 on 2025-05-13 are both labelled bugfix releases, and 1.3.0 on 2026-05-27 is a minor release.

The repository is not archived, and the last push was on 2026-08-10. That is a little over two months before the current date, so the code is being touched, but the gap between the 1.3.0 tag in May and the last push in August suggests a project maintained in bursts rather than on a fixed schedule. Treat it as a working utility rather than something with a predictable release cadence, and read the CHANGELOG.md before upgrading a setup you rely on.

The tree also carries MAINTAINERS.md, which tells you who to look for when something needs to be reported or fixed, and the presence of a Nix flake means you can pin a revision if you want a reproducible build.

Editorial conclusion

wpaperd suits someone running sway or another wlroots based compositor who wants per monitor wallpapers, directory cycling and a config they can edit and reload without restarting the daemon. It does not suit a GNOME user or a Hyprland user, because the project states it will not work on GNOME and is not supported on Hyprland. Before adopting it, confirm your compositor implements wlr_layer_shell, decide whether you need AVIF support and therefore whether libdav1d and the avif feature are needed, and set the queue-size value above your image count if you rely on next and previous with random sorting.

Frequently asked questions

Does wpaperd work on GNOME and Hyprland?

No. The project states that wpaperd will not work on GNOME because it depends on the wlr_layer_shell wayland protocol, and it also states that Hyprland is not supported by wpaperd because of compositor specific issues. It targets wlroots based compositors such as sway, and KDE.

How do I build and install wpaperd?

Clone the repository, run cargo build --release, then use rinstall install --yes to install both the wpaperd daemon and the wpaperctl client. The build needs a working Cargo installation plus mesa, wayland-client and wayland-egl.

Why does the previous command not work as expected with wpaperd?

With random sorting the history queue only functions when the queue-size setting, which defaults to 10, is larger than the number of images in the directory. Raise queue-size above your image count in the config.toml section for that display.

How do I enable AVIF images in wpaperd?

AVIF support is a compile time choice. Build wpaperd with the avif feature, which requires libdav1d to be installed, since the documentation describes the format as enabled by a build feature rather than a runtime option.

Where is the wpaperd configuration file and what does it contain?

The configuration lives at XDG_CONFIG_HOME/wpaperd/config.toml, which defaults to ~/.config/wpaperd/config.toml. Each section represents one display and can set path, duration, sorting, group, mode, transition-time, offset, queue-size, initial-transition, recursive and exec.

Official sources

  1. danyspin97/wpaperd on GitHub
  2. Issues
  3. License: GPL-3.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/danyspin97-wpaperd.svg)](https://hysenlabs.com/projects/danyspin97-wpaperd)

Was this useful?