Wallpaper

I’m particular about my desktop wallpaper. 🤦🏻‍♂️ It can’t be too bright or distracting; I want to focus on my work. But it can’t be too dull or boring; I also want to feel inspired.

The approach taken by the folks designing the Raycast wallpapers caught my attention, so I tried it! Beyond what they had done, I wanted to use the colors from Solarized and to support both light and dark modes.

I’m inordinately pleased with these results. You can click either image here to download a macOS dynamic desktop image that will switch between them based on your system preferences.

Make your own

Better yet, here’s the Swift script I used, thanks to a bunch of tricks from the internet. You can tweak the gradient stops and run this from the command line (no need to launch Xcode) to play around and make something that works for you.

Have fun!

#!/usr/bin/swift

import AVFoundation
import SwiftUI

// https://nshipster.com/macos-dynamic-desktop/
// https://harshil.net/blog/dynamic-wallpapers-in-macos-catalina
struct DynamicDesktop {
    let light: CGImage
    let dark: CGImage

    init(light: CGImage, dark: CGImage) {
        self.light = light
        self.dark = dark
    }

    func write(to url: URL) {
        let encoder = PropertyListEncoder()
        encoder.outputFormat = .binary

        let tag = CGImageMetadataTagCreate(
            "http://ns.apple.com/namespace/1.0/" as CFString,
            "apple_desktop" as CFString,
            "apr" as CFString,
            .string,
            try! encoder.encode(["l": 0, "d": 1]).base64EncodedString() as CFString
        )!

        let metadata = CGImageMetadataCreateMutable()
        CGImageMetadataSetTagWithPath(metadata, nil, "xmp:apr" as CFString, tag)

        let destination = CGImageDestinationCreateWithURL(url as CFURL, AVFileType.heic as CFString, 2, nil)!
        CGImageDestinationAddImageAndMetadata(destination, light, metadata, nil)
        CGImageDestinationAddImage(destination, dark, nil)
        CGImageDestinationFinalize(destination)
    }
}

// We want to draw angular gradients, which only SwiftUI has. (CoreGraphics can
// only do linear and radial ones.) So we use this trick to turn a SwiftUI View
// into an image: https://stackoverflow.com/a/76083393
func render<Content>(_ content: Content) async -> CGImage where Content: View  {
    return await MainActor.run {
        return ImageRenderer(content: content).cgImage!
    }
}

// https://www.raycast.com/blog/making-a-raycast-wallpaper
func raycast(_ stops: Gradient.Stop...) -> any View {
    return Rectangle()
        .fill(.conicGradient(stops: stops, center: UnitPoint(x: 0.5, y: 0.75)))
        .frame(width: 5120, height: 2880)
        .blur(radius: 800, opaque: true)
}

// https://ethanschoonover.com/solarized/#the-values
enum Solarized: Int {
    case base03  = 0x002b36
    case base02  = 0x073642
    case base01  = 0x586e75
    case base00  = 0x657b83
    case base0   = 0x839496
    case base1   = 0x93a1a1
    case base2   = 0xeee8d5
    case base3   = 0xfdf6e3
    case yellow  = 0xb58900
    case orange  = 0xcb4b16
    case red     = 0xdc322f
    case magenta = 0xd33682
    case violet  = 0x6c71c4
    case blue    = 0x268bd2
    case cyan    = 0x2aa198
    case green   = 0x859900

    var color: Color {
        Color(red: component(16), green: component(8), blue: component(0))
    }

    private func component(_ shift: Int) -> CGFloat {
        CGFloat((self.rawValue >> shift) & 0xff) / 0xff
    }
}

let desktop = DynamicDesktop(
    light: await render(raycast(
        Gradient.Stop(color: Solarized.base1.color, location: 0),
        Gradient.Stop(color: Solarized.base3.color, location: 0.75),
        Gradient.Stop(color: Solarized.green.color, location: 0.8),
        Gradient.Stop(color: Solarized.base1.color, location: 0.85)
    )),
    dark: await render(raycast(
        Gradient.Stop(color: Solarized.base03.color, location: 0),
        Gradient.Stop(color: Solarized.base01.color, location: 0.75),
        Gradient.Stop(color: Solarized.green.color, location: 0.8),
        Gradient.Stop(color: Solarized.base03.color, location: 0.85)
    ))
)

desktop.write(to: URL(fileURLWithPath: CommandLine.arguments[1]))