The dotfiles ship a wallpaper-driven theme system that generates terminal color palettes directly from wallpaper images using K-Means clustering in CIELAB color space. One command changes the terminal, editor, window manager, GTK, desktop environment, wallpaper, and browser-facing color mode in under a second.
Themes are not hand-crafted — they are extracted from whatever wallpapers are available on the system.
Wallpapers are the source of truth. The system discovers wallpapers from two locations:
/System/Library/Desktop Pictures/, Linux /usr/share/backgrounds/)~/Pictures/Wallpapers/ (custom overrides system)extract-theme.py extracts dominant colors from each wallpaper using K-Means clustering in CIELAB color space, then generates a full terminal palette (16 ANSI colors, accent, bg/fg, panel, border) with WCAG contrast enforcement.
rebuild-themes.sh orchestrates discovery → extraction → assembly into .chezmoidata/themes.toml. Themes are cached in ~/.cache/dotfiles/themes/ and only regenerated when wallpapers change.
The theme key in .chezmoidata.toml controls the active theme. Every template references the active theme’s data through ``.
dot theme
Opens an fzf picker listing every paired wallpaper theme (themes that have both -dark and -light variants). Two columns: WALLPAPER name and SOURCE (System or Custom). The current theme is marked with ✓ and ◀. Select one and press Enter.
dot theme tahoe-dark
Sets the theme immediately. Regenerates configs and reloads running applications.
dot theme rebuild # incremental (uses cache for unchanged wallpapers)
dot theme rebuild --force # full regeneration
dot theme rebuild --list # discover wallpapers without rebuilding
Discovers wallpapers from system + custom paths, runs K-Means extraction in parallel (4 jobs), caches generated themes in ~/.cache/dotfiles/themes/, and writes .chezmoidata/themes.toml. Custom wallpapers override system wallpapers on name collision.
dot-theme-sync handles the full switching pipeline:
.chezmoidata.toml (and chezmoi.toml if present).
If those files drift, dot-theme-sync now resynchronizes them before rendering because chezmoi.toml [data] overrides the source data file.chezmoi apply on theme-dependent config files only – much faster than a full apply.dot-theme-sync # Reload current theme
dot-theme-sync macos-wave-light # Switch to a new theme
dot-theme-sync --full # Full chezmoi apply instead of targeted
Each theme switch touches these applications:
| Application | Mechanism | What Changes |
|---|---|---|
| Ghostty | chezmoi apply + macOS app-support sync + DBus reload-config or runtime signal fallback |
Background, foreground, all 16 ANSI colors, cursor |
| Tmux | chezmoi apply + source-file |
Status bar colors, pane borders, mode indicators |
| Niri | chezmoi apply + load-config-file IPC |
Window borders, focus ring, inactive tint |
| Desktop (macOS) | osascript + defaults write + killall |
System appearance (Light/Dark), accent color, highlight color; forces SystemUIServer/Dock/cfprefsd refresh |
| Wallpaper (macOS) | osascript System Events |
Desktop wallpaper set across all displays |
| Wallpaper (Linux) | gsettings / dms / swaybg / feh |
HEIC auto-converted to PNG; picture-uri and picture-uri-dark set separately |
| Desktop (Linux/GNOME) | chezmoi apply + gsettings |
Theme name, icon theme, color scheme preference |
| Safari / Chrome / Edge | Native browser appearance follows desktop theme | Browser chrome stays aligned when using the default/native browser theme |
| Firefox | chezmoi apply on ~/.config/firefox/user.js |
Website color scheme preference follows the active dot theme; link that file into a Firefox profile to enforce it |
| DMS | sed -i on settings.json + IPC |
Stock theme mapped to accent family, dark/light mode |
| Neovim | --remote-expr Lua eval over socket |
Colorscheme, style variant, background mode |
| VS Code | chezmoi apply on settings.json |
workbench.colorTheme value |
| Alacritty | chezmoi apply |
Full color block regeneration |
| Kitty | chezmoi apply |
Full color block regeneration |
| WezTerm | chezmoi apply |
Color scheme in Lua config |
dot theme toggle
Toggles between the dark and light variant of the current theme family. A theme named macos-tahoe-dark toggles to macos-tahoe-light, and vice versa.
Available themes depend on your system. Run dot theme list to see what’s discovered. On macOS Sonoma, you’ll see ~150+ themes from system wallpapers. Custom wallpapers in ~/Pictures/Wallpapers/ add more.
When wallpapers change (new system update, new custom wallpapers), regenerate:
dot theme rebuild # Regenerate (uses cache for unchanged wallpapers)
dot theme rebuild --force # Force full regeneration
dot theme rebuild --list # List discovered wallpapers without rebuilding
Theme switching is a two-tier system:
Core (always works) — ships in the repo, no setup needed:
Wallpapers (optional) — user-provided, enhances the theme:
~/Pictures/Wallpapers/ with files named macos-NAME-dark.heicIf no wallpapers are present, dot theme applies all core changes and skips the wallpaper step. No errors, no manual config.
Wallpapers are not shipped in the repo. Each user sources their own and places them in ~/Pictures/Wallpapers/:
macos-tahoe-dark.heic
macos-tahoe-light.heic
The naming convention is macos-NAME-APPEARANCE.heic (or .jpg/.png). The theme picker marks themes with matching wallpapers as [W].
.heic preferred on macOS, .png/.jpg also supported| Platform | Wallpaper support | Mechanism |
|---|---|---|
| macOS | .heic, .jpg, .png |
osascript (all desktops) |
| Linux (GNOME) | .png, .jpg (.heic auto-converted) |
gsettings picture-uri + picture-uri-dark |
| Linux (Wayland) | .png, .jpg (.heic auto-converted) |
swaybg, feh, or Niri/DMS IPC |
| WSL | Not applicable | No compositor; terminal colors still apply |
On Linux, .heic files are automatically converted to .png using magick, heif-convert, or convert (whichever is available). The .png is cached and only regenerated when the source .heic changes.
If you don’t provide custom wallpapers, your OS keeps its current desktop wallpaper. The theme still applies all color changes (terminal, editor, accent, dark/light mode). This is the expected default for most users.
All build caches (Cargo, Go, pip, uv, Zig) are redirected to /tmp/builds/ via environment variables in mise.toml and cargo/config.toml. The directory is created on shell init via fish/conf.d/env.fish. Build artifacts are cleared on reboot.
Run a full apply to force all configs:
dot-theme-sync --full
Ghostty reloads via DBus (com.mitchellh.ghostty / reload-config). If DBus is unavailable, the fallback sends SIGUSR2 to the main process and also matches the macOS app bundle path when needed. Verify Ghostty is running:
pgrep -x ghostty
On macOS, Ghostty may also read ~/Library/Application Support/com.mitchellh.ghostty/config. dot-theme-sync now mirrors the regenerated XDG config into that location before reloading so the app-support override cannot keep an older palette active.
dot-theme-sync finds Neovim server sockets at /tmp/nvim*/0 and $XDG_RUNTIME_DIR/nvim.*.0. If Neovim runs with a custom --listen path, the auto-discovery misses it. Restart Neovim to pick up the new theme from the regenerated config.
GTK theme names must match installed themes exactly. Catppuccin themes use names like catppuccin-mocha-blue-standard+default. Install the matching GTK theme package or fall back to Adwaita-dark / Adwaita.
dot-theme-sync applies macOS appearance using osascript and accent via:
defaults write -g AppleAccentColor -int <value>
dot-theme-sync now kills cfprefsd, SystemUIServer, Dock, and System Settings after writing accent/highlight defaults to force an immediate refresh. If the UI still does not update, close and reopen System Settings.
Safari, Chrome, and Edge are coordinated through the desktop theme, so custom browser themes can override what dot-theme-sync is trying to align. Switch those browsers back to their native/default theme if you want them to track macOS or GTK automatically.
Firefox uses the managed file at ~/.config/firefox/user.js. Link that file into your active Firefox profile as user.js if you want dot-theme-sync to control website prefers-color-scheme behavior:
ln -sf ~/.config/firefox/user.js ~/.mozilla/firefox/<profile>/user.js
Tmux reloads via source-file. If TPM plugins override colors, run:
tmux source-file ~/.config/tmux/tmux.conf
grep '^theme = ' ~/.dotfiles/.chezmoidata.toml
This prints the current theme name. Cross-reference with dot theme list for available options.