@sebastienrousseau/dotfiles
Version:
The Trusted Shell Platform — Universal dotfiles managed by Chezmoi. Features Bash & Zsh for macOS, Linux & WSL. Rust modern tooling & enterprise-grade security.
231 lines (150 loc) • 10.7 kB
Markdown
---
render_with_liquid: false
---
{% raw %}
# Theming Guide
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.
## How Themes Work
Wallpapers are the source of truth. The system discovers wallpapers from two locations:
1. **System wallpapers** — platform-native (macOS `/System/Library/Desktop Pictures/`, Linux `/usr/share/backgrounds/`)
2. **Custom wallpapers** — user-provided in `~/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 `{{ $t := index .themes .theme }}`.
## Switching Themes
### Interactive Picker
```bash
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.
### Direct Switch
```bash
dot theme tahoe-dark
```
Sets the theme immediately. Regenerates configs and reloads running applications.
### Rebuild Themes
```bash
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.
### Under the Hood: dot-theme-sync
`dot-theme-sync` handles the full switching pipeline:
1. Writes the new theme name into `.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.
2. Runs a targeted `chezmoi apply` on theme-dependent config files only -- much faster than a full apply.
3. Signals running applications to reload and coordinates browser-facing theme state:
```bash
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
```
## What Changes
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 |
## Dark/Light Toggle
```bash
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.
## Theme Families
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.
### Rebuilding themes
When wallpapers change (new system update, new custom wallpapers), regenerate:
```bash
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
```
## What works without wallpapers
Theme switching is a two-tier system:
**Core (always works)** — ships in the repo, no setup needed:
- Terminal colors (Ghostty, Alacritty, Kitty, WezTerm, tmux)
- Editor themes (Neovim colorscheme, VS Code)
- macOS dark/light mode and accent color
- Linux GNOME color-scheme, GTK theme, icon theme
- Browser color mode (Safari, Chrome, Firefox)
**Wallpapers (optional)** — user-provided, enhances the theme:
- Desktop wallpaper matched to the active theme
- Requires `~/Pictures/Wallpapers/` with files named `macos-NAME-dark.heic`
If no wallpapers are present, `dot theme` applies all core changes and skips the wallpaper step. No errors, no manual config.
## Wallpapers (optional)
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]`.
### Wallpaper guidelines
- **Resolution**: 6016x6016 recommended (matches Apple's native resolution)
- **Format**: `.heic` preferred on macOS, `.png`/`.jpg` also supported
- **Brightness**: dark/light pairs targeting a golden ratio (1.618) relationship give balanced contrast across displays
### Platform behavior
| 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.
### Using your OS default wallpapers
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.
## Build Artifacts
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.
## Troubleshooting
### Theme switch did not apply
Run a full apply to force all configs:
```bash
dot-theme-sync --full
```
### Ghostty did not reload
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:
```bash
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.
### Neovim did not change colors
`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 looks wrong
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`.
### macOS accent or appearance did not update
`dot-theme-sync` applies macOS appearance using `osascript` and accent via:
```bash
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.
### Browser theme did not change
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:
```bash
ln -sf ~/.config/firefox/user.js ~/.mozilla/firefox/<profile>/user.js
```
### tmux shows old colors
Tmux reloads via `source-file`. If TPM plugins override colors, run:
```bash
tmux source-file ~/.config/tmux/tmux.conf
```
### Checking the active theme
```bash
grep '^theme = ' ~/.dotfiles/.chezmoidata.toml
```
This prints the current theme name. Cross-reference with `dot theme list` for available options.
{% endraw %}