A fast wallpaper fetcher and rotator written in Zig.
Download a fresh set of wallpapers, skip junk you already have, rotate them on a timer, and hook into your desktop without dragging in a pile of runtime dependencies.
wallfetch started as a simple idea: grab a lot of good-looking wallpapers into one folder without having to babysit shell one-liners.
It grew into something more useful than that.
Now it is a small Zig CLI that focuses on a few things that matter in day-to-day use:
- getting wallpapers quickly
- not redownloading the same content forever
- behaving nicely when the network is flaky
- fitting into a normal Linux desktop setup
- staying lightweight and easy to own
The project is meant to feel like a real tool, not a demo binary that happens to compile once and then ruins your afternoon.
Repository: https://github.com/theHamdiz/wallfetch
It pulls wallpaper candidates from online sources and downloads them with concurrency tuned for network throughput, not just CPU usage.
Each download can retry with exponential backoff, so a temporary failure does not kill the whole run.
It can hash files and avoid keeping the same content twice, even when filenames differ.
You can ask for a mood instead of a random grab bag.
Current categories include:
curateddarkminimalanimenatureabstractspacecity
It can install a user-level systemd timer so your wallpaper rotates in the background without sudo and without turning your machine into a science fair project.
Desktop integration is optional.
- KDE: uses
plasma-apply-wallpaperimageif it exists - Niri: uses
swwwif it exists
If those tools are not present, wallfetch still handles downloading, selecting, and rotation logic just fine.
This project is built around a few simple rules:
- fast first
- zero external runtime dependency in the core downloader
- safe file handling
- good defaults
- clean CLI output
- no sudo for normal usage
That last one matters.
A normal zig build -Doptimize=ReleaseFast installs the binary to the usual Zig output path and to ~/.local/bin, so it is easy to run as a regular user as long as that directory is in your PATH.
.
├── build.zig
├── README.md
└── src/
└── main.zig
The build script compiles the project and installs it in two places:
zig-out/bin/wallfetch~/.local/bin/wallfetch
That gives you the normal Zig workflow plus a user-friendly install target.
This is the actual application:
- argument parsing
- interactive prompts
- downloading
- retries
- hashing and deduplication
- wallpaper selection
- desktop integration
- systemd timer installation
zig build -Doptimize=ReleaseFastThat mode is chosen on purpose. wallfetch is built for runtime speed first.
If your shell does not already include ~/.local/bin in PATH, add it once:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrcfish_add_path $HOME/.local/binDownload 100 wallpapers with defaults:
wallfetch --yesDownload dark wallpapers and skip files you already have:
wallfetch --yes --category dark --count 100 --existing skipDownload into a custom folder:
wallfetch --yes --dest ~/.local/share/backgroundsRotate a wallpaper from the folder and apply it if possible:
wallfetch rotate --yes --dest ~/.local/share/backgrounds --apply --backend autoInstall the user timer so rotation happens automatically every 20 minutes:
wallfetch install-timer --yes --dest ~/.local/share/backgrounds --backend auto --apply --interval-minutes 20
systemctl --user daemon-reload
systemctl --user enable --now wallfetch-rotate.timerDefault command if you do not specify one.
wallfetch [options]
wallfetch download [options]Pick a wallpaper from disk and optionally apply it.
wallfetch rotate [options]Apply a chosen wallpaper to a supported desktop backend.
wallfetch apply [options]Write the user-level systemd unit and timer for wallpaper rotation.
wallfetch install-timer [options]--yes, -y
--dest <dir>
--state-dir <dir>
--count <n>
--category <name>
--width <px>
--height <px>
--pages <n>
--concurrency <n>
--retries <n>
--existing <skip|overwrite>
--backend <auto|kde|niri|none>
--interval-minutes <n>
--index <n>
--dry-run
--verbose
--no-dedup-scan
--apply
A few useful notes:
--existing skipis the sane everyday default--verboseis for when you want the chatter--dry-runis there when you do not trust anything yet, which is honestly healthy--backend autotries to do the sensible thing
If plasma-apply-wallpaperimage is available, wallfetch can tell KDE to switch the wallpaper directly.
If swww is available, wallfetch can use it as the wallpaper backend.
If you only want to download and rotate selections without applying them, use:
--backend noneThis matters more than it sounds.
wallfetch does not write straight into the final file and hope for the best. The intended behavior is:
- download to a temporary path
- verify or hash when needed
- move into place
That keeps partial downloads from pretending to be valid wallpapers.
The project is aimed at throughput.
That means:
- concurrency is tuned for network-heavy work
- retries are built in
- existing files can be skipped early
- content hashing helps avoid silent duplication
ReleaseFastis the default build mode for a reason
This is not trying to win a smallest-binary contest. It is trying to get work done quickly and reliably.
The core program is designed to avoid runtime dependency bloat.
Desktop wallpaper application is the only place where the outside world naturally leaks in:
- KDE needs KDE's wallpaper tool
- Niri generally relies on
swww - systemd timer installation obviously assumes systemd if you want timer support
So the right way to think about it is:
- downloader core: self-contained
- desktop adapters: optional
The repo represents the full tool, not just one isolated version bump.
The way to think about its evolution is roughly this:
- v1: get wallpapers into a folder
- v2: make it safer, cleaner, and more pleasant to use
- v3: add better throughput, smarter deduplication, categories, rotation, and desktop integration
So while the current feature set is the most complete one, the project itself is the whole story: a wallpaper tool that kept getting sharper instead of bloating into nonsense.
Make sure ~/.local/bin is in your PATH.
Check that plasma-apply-wallpaperimage exists on your system.
Check that swww is installed and running.
Run:
systemctl --user daemon-reload
systemctl --user enable --now wallfetch-rotate.timerZig's build APIs do move around. If that happens, fix the build script first before assuming the application code is broken. The current build.zig avoids fragile compile-step fields that have changed between releases.
If you want to improve the downloader, UI, desktop adapters, or source selection logic, great. Small focused pull requests are welcome.
Good tooling ages well when people keep trimming the stupid parts off it.
MIT