CLI tool
mczachurski/wallpapper avatar
mczachurski/wallpapper

wallpapper: building macOS dynamic wallpapers from a JSON manifest

:computer: Console application for creating dynamic wallpapers for macOS Mojave and newer

3,436 stars137 forksSwiftMIT

At a glance

What is it?
wallpapper is a Swift command line tool that compiles a folder of still images plus a JSON description into a single .heic dynamic wallpaper for macOS Mojave and newer. The manifest format is the whole interface, and it decides whether you get a solar, time or appearance driven wallpaper.
Who is it for?
Adopt wallpapper if you already have a set of still images and want one .heic file that macOS switches on its own, and you are comfortable writing the JSON manifest by hand. Do not adopt it if you need a GUI, batch processing of many wallpapers, or anything other than macOS Mojave and newer, since the output format is Apple's and the tool targets nothing else.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 24 days ago.
What is it written in?
Mainly Swift, according to GitHub's language statistics.

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

Editorial analysis

What wallpapper actually produces

macOS Mojave introduced dynamic wallpapers, which are single .heic files holding several images plus metadata that tells the system when to swap between them. Apple shipped a few of these with the OS. The README states that wallpapper is a console application for creating them, and that is the whole scope: it does not design images, retouch them, or install the result into the system wallpaper picker. It takes a folder of stills and a JSON file describing them and writes one .heic.

The audience is narrow and specific. You need a Mac running Mojave or newer, Xcode and Swift installed, and a set of images you have already prepared. If you are looking for a graphical wallpaper manager, this is not it. The README points readers to three articles on itnext.io for background on how dynamic wallpapers work, which suggests the author expects people to arrive already curious about the format rather than needing to be sold on it.

Three manifest types and what each one keys off

The JSON array is the entire configuration surface, and its shape selects the behaviour. For a solar wallpaper each entry carries altitude and azimuth, the angles of the Sun relative to the observer, so macOS can pick an image based on where the Sun is rather than what the clock says. To get those numbers the README suggests the companion wallpapper-exif binary or a public sun-angle calculator, and it notes that on the web page you enter the place where the photo was taken and the date.

A time wallpaper replaces those two fields with a time string such as "10:25:43", and the README says the hour is the part that matters most. The 1.7.4 release notes state that minutes are now taken into account, which means earlier versions rounded to the hour. An appearance wallpaper is the simplest: two entries, one marked isForLight and one isForDark, and it follows the system light or dark setting.

Across all three types, isPrimary marks the image shown after the .heic is created, and only one entry may carry it. isForLight and isForDark control what appears when the user picks the static Light or Dark option in System Settings. The README also notes that fileName can repeat across entries, so one image can serve several nodes.

Installing wallpapper and building a first wallpaper

The README gives two installation routes. The Homebrew route is two commands and pulls from the author's own tap. The manual route clones the repository, builds in release configuration, and copies both binaries into /usr/local/bin with sudo.

bash
brew tap mczachurski/wallpapper
brew install wallpapper

If you prefer to build from source, the README's manual sequence is:

bash
git clone https://github.com/mczachurski/wallpapper.git
cd wallpapper
swift build --configuration release
sudo cp .build/release/wallpapper /usr/local/bin
sudo cp .build/release/wallpapper-exif /usr/local/bin

There is also a build.sh script that uses swiftc instead of the Swift CLI and writes to .output. After either route, running wallpapper -h should print the option list: -o for the output file name (default output.heic), -i for the input JSON, -e to extract metadata from an existing .heic, and -q for output image quality, default 1.0.

A minimal appearance wallpaper needs two images in one folder and a JSON file beside them. The README's own example is:

json
[
  {
    "fileName": "1.png",
    "isPrimary": true,
    "isForLight": true
  },
  {
    "fileName": "2.png",
    "isForDark": true
  }
]

With that file saved as wallpaper.json in the same directory as the images, you point wallpapper at it with -i and let it write the default output name. The README does not spell out the exact invocation for this example, but the -i and -o options in the help output define the shape of the command. What you should end up with is a single .heic file you can open in System Settings and set as wallpaper.

Where the tool stops helping

The README is thin on failure modes, and that is itself the limitation. There is no documented validation step for the manifest: nothing says what happens if two entries carry isPrimary, if a fileName does not exist on disk, or if the solar angles are inconsistent with the images. You find out when the build fails or when macOS refuses the result.

The README does document one build problem and its fix. If the Swift build errors, it suggests downloading the full Xcode IDE rather than just the command line tools from the App Store, then running sudo xcode-select -s /Applications/Xcode.app/Contents/Developer and retrying the install. That is a real constraint on the toolchain, not on the tool.

More importantly, wallpapper is the wrong tool if you want anything other than a macOS dynamic wallpaper. It writes .heic, a format macOS uses for this purpose; there is no export path to a plain image sequence or to another platform's wallpaper system. And if you want to generate many wallpapers from many folders, the command line has no batch mode: the help output lists one -i input and one -o output, so scripting around it means one process per wallpaper.

How wallpapper compares to the manual route

The alternative most people reach for is building the .heic by hand with Apple's own tools, typically by extracting metadata from a stock dynamic wallpaper with wallpapper-exif, editing the plist, and reassembling the file. The README's own -e option exists for exactly that workflow: it takes a .heic file and extracts its metadata, and the 1.7.3 release notes mention outputting a plist file during that extraction.

The difference is where the description lives. In the manual route you edit a plist that mirrors Apple's internal structure, and you are responsible for every key. With wallpapper you write a small JSON array with human-readable field names, and the tool translates it. That is a real reduction in surface area, but it also means you cannot express anything the JSON schema does not cover. If Apple's format supports a field that wallpapper does not expose, the manual route can reach it and wallpapper cannot. For the three wallpaper types the README documents, the JSON route is shorter; for anything outside them, it is a dead end.

Maintenance, licensing and what to check before adopting

The repository is MIT licensed, which permits commercial and private use with the usual requirement to keep the licence and copyright notice. The LICENSE.md file sits at the top level alongside Package.swift, build.sh and the Sources directory. Nothing in the repository suggests any additional restriction, but as with any dependency you should read the actual licence text rather than a summary.

The release history is worth reading before you commit. Version 1.7.4 shipped on 2023-02-16 and its note concerns minutes in time wallpapers. Version 1.7.3 came on 2022-05-22 with plist output during metadata extraction, and 1.7.2 on 2021-06-30 fixed a compile issue in Xcode 13. The repository is not archived and its last push was on 2026-09-06, so the code is being touched, but the last tagged release predates that by more than three years. That gap matters if you are pinning a version: the release you install from Homebrew may be older than what is on master.

The upgrade cost is bounded by the manifest format. The JSON schema has been stable across the documented types, and the only behavioural change called out in the release notes is the time handling in 1.7.4. If you are upgrading from an earlier 1.7.x, check time-based manifests for entries whose minute values were previously ignored. Before adopting, confirm that your Swift toolchain builds the package, since the README's troubleshooting section exists precisely because that step fails for some users.

Editorial conclusion

Adopt wallpapper if you already have a set of still images and want one .heic file that macOS switches on its own, and you are comfortable writing the JSON manifest by hand. Do not adopt it if you need a GUI, batch processing of many wallpapers, or anything other than macOS Mojave and newer, since the output format is Apple's and the tool targets nothing else. Before committing, verify that your Xcode and Swift versions build the package, that your images share one resolution and aspect ratio, and that exactly one entry in the manifest carries isPrimary. The last release, 1.7.4, dates from 2023-02-16, so treat the manifest schema as fixed rather than evolving.

Frequently asked questions

What does wallpapper do?

It is a console application that creates the dynamic wallpapers introduced in macOS Mojave from a folder of images and a JSON description file. It writes a single .heic file that macOS can use as a wallpaper.

How do I install wallpapper on macOS?

The README gives two routes: brew tap mczachurski/wallpapper followed by brew install wallpapper, or cloning the repository and running swift build --configuration release and copying the two binaries into /usr/local/bin. Both require Xcode and Swift.

What kinds of dynamic wallpapers can wallpapper create?

Three. Solar wallpapers use altitude and azimuth per image, time wallpapers use a time string per image, and appearance wallpapers use two images marked isForLight and isForDark.

What is wallpapper-exif for?

It is the companion binary installed alongside wallpapper. The -e option on wallpapper takes a .heic file and extracts its metadata, and the 1.7.3 release notes mention outputting a plist file during that extraction.

Official sources

  1. Issues
  2. License: MIT
  3. mczachurski/wallpapper on GitHub
  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/mczachurski-wallpapper.svg)](https://hysenlabs.com/projects/mczachurski-wallpapper)