Themes
Theme System Architecture
A modular, compositor-agnostic theming engine with dual-mode support: DIY (static themes) and DMS (dynamic Material You from wallpaper).
Two-Tiered Architecture
Tier 1: Global Defaults (Catppuccin Mocha)
When modules.theme.active = null, the system uses Catppuccin Mocha as the universal fallback. Every app renders correctly and looks polished out of the box.
- Palette: Catppuccin Mocha (community standard, wide tooling support)
- Fonts: JetBrains Mono (terminal) + Inter (UI)
- Terminals: Alpha defaults to
0.85on all five configurable terminals
Tier 2: Active Theme (Decoration)
When modules.theme.active is set to a theme name, the theme module populates modules.theme.colors and modules.theme.fonts. Apps react to these via mkIf blocks that override the Catppuccin defaults.
Desktop Modes
The theme system supports two operating modes, controlled by modules.desktop.dms.enable / modules.desktop.diy.enable:
| Mode | Behavior | Theme Source |
|---|---|---|
DIY (modules.desktop.diy.enable = true) | Per-app, user-chosen static themes | modules.theme.apps.<app>.theme |
DMS (modules.desktop.dms.enable = true) | Dynamic Material You from wallpaper | matugen (auto-generated) |
DIY Mode
Each app’s theme is individually selectable. Terminals default to "matugen", neovim defaults to "catppuccin", rofi defaults to "autumnal".
modules.theme.apps.foot.theme = "catppuccin"; # force catppuccin
modules.theme.apps.rofi.theme = "gemini"; # pick a rofi theme
DMS Mode (Dynamic Material Shell)
All apps are forced to "matugen" — colors are generated from the current wallpaper by the matugen tool. Templates in config/matugen/templates/ render Material You color palettes into per-app config files:
| App | Template | Output |
|---|---|---|
| foot | foot.ini | ~/.config/foot/dank-colors.ini |
| kitty | kitty.conf | ~/.config/kitty/dank-colors.conf |
| alacritty | alacritty.toml | ~/.config/alacritty/dank-colors.toml |
| ghostty | ghostty.conf | ~/.config/ghostty/dank-colors.conf |
| wezterm | wezterm.lua | ~/.config/wezterm/dank-colors.lua |
| rofi | rofi.rasi | ~/.config/rofi/themes/dank-colors.rasi |
| niri | niri.colors.kdl | ~/.config/niri/dms/colors.kdl |
| tmux | tmux.conf | ~/.config/tmux/dank-colors.conf |
| firefox | firefox.css | userChrome.colors.css |
Matugen runs at session start (hey.hooks.startup."15-matugen") and on wallpaper changes via DMS’s dynamic theming.
DMS Theme Modes
DMS has two theme source modes, toggled in DMS Settings (Mod+Comma) or via DankDash (Mod+Y):
| Mode | Source | Background | matugen |
|---|---|---|---|
| Hex mode | Manually-picked accent color | Solid/gradient from hex | Generates palette from hex |
| Image mode | Wallpaper image file | The actual image displayed | Extracts dominant colors from image |
In hex mode, changing “wallpaper” only changes the accent color — the background is always a gradient, never an image. Use image mode (select an image file) for actual wallpaper pictures.
DMS Config Locations
| Path | Purpose |
|---|---|
~/.config/DankMaterialShell/settings.json | GUI settings (theme, layout, transparency, wallpaper fill mode) |
~/.config/DankMaterialShell/plugin_settings.json | Plugin toggles |
~/.cache/DankMaterialShell/dms-colors.json | Generated Material You palettes (dark + light variants) |
~/.cache/DankMaterialShell/cache.json | File browser paths, wallpaperLastPath |
~/.config/niri/dms/colors.kdl | Niri compositor colors (generated by matugen) |
~/.config/niri/dms/layout.kdl | Niri layout/window rules (managed by DMS) |
~/.config/matugen/config.toml | Matugen template mapping (generated by nix) |
~/.local/share/hey/info.json | Host profile info + default wallpaper path (imported by matugen) |
Niri DMS Config & Git Skip-Worktree
Why We Need These Files
The NixOS desktop module for the Niri window manager (niri.nix) links and expects the configuration files in config/niri/dms/ (such as colors.kdl, layout.kdl, outputs.kdl) to exist at build time. Without these baseline files present in the repository, a fresh system bootstrap or compile of the Niri desktop configuration will fail due to missing target links.
Why We Do Not Track Modifications
These configuration files are modified dynamically at runtime by DMS (Dynamic Menu System/Dynamic Monitor Setup) and Matugen (the Material You palette generator) to automatically change color schemes, window rules, and monitor layout options.
To prevent these local dynamic updates from constantly showing up as unstaged changes in git status or polluting your commits, we ignore changes to them.
How to Skip Worktree (Ignore Local Modifications)
To stop Git from tracking changes to the committed baseline configuration files under config/niri/dms/, use the Git skip-worktree index flag:
# Ignore local changes to the dms configuration files
git update-index --skip-worktree config/niri/dms/*
This ensures the repository retains a working default configuration, but Git will ignore any dynamic modifications made by DMS/Matugen on your active workspace.
Restoring Tracking & Updating Baselines
If you make intentional changes to the default baseline configurations and want to save them back to the repository:
# 1. Temporarily restore tracking:
git update-index --no-skip-worktree config/niri/dms/*
# 2. Add and commit your changes:
git add config/niri/dms/
git commit -m "chore(niri): update baseline dms configurations"
# 3. Mark them as skipped again:
git update-index --skip-worktree config/niri/dms/*
Listing Marked Files
To see which files are currently marked with the skip-worktree flag:
git ls-files -v | grep ^S
Terminal Transparency
All five configurable terminals expose an alpha option controlling background opacity:
| Terminal | Option | Default | Applied via |
|---|---|---|---|
| foot | modules.desktop.term.foot.alpha | 0.85 | [colors-dark] INI section |
| kitty | modules.desktop.term.kitty.alpha | 0.85 | background_opacity |
| alacritty | modules.desktop.term.alacritty.alpha | 0.85 | window.opacity |
| ghostty | modules.desktop.term.ghostty.alpha | 0.85 | background-opacity |
| wezterm | modules.desktop.term.wezterm.alpha | 0.85 | window_background_opacity |
| st | (hardcoded) | 0.93 | Xresources st.alpha |
Foot in DMS/matugen mode: the matugen template includes alpha=0.85 directly. In DIY/non-matugen mode, alpha is set via cfg.alpha in the generated [colors-dark] section.
Override per host:
modules.desktop.term.kitty.alpha = 0.78;
Rofi Theming
Rofi is themed differently in each mode:
DIY Mode
The active theme is selected via modules.theme.apps.rofi.theme. Available .rasi theme files live in modules/themes/config/rofi/:
| Theme | Key colors | Alpha |
|---|---|---|
autumnal | dark warm leaves | bg: 0.85, bg-alt: 0.80 |
gemini | catppuccin-inspired | bg: 0.90, bg-alt: 0.60 |
cyberpunk | neon pink/cyan | bg: 0.90, bg-alt: 0.80 |
matrix | green-on-black | bg: 0.90, bg-alt: 0.80 |
config.theme.x11 | catppuccin-like (X11) | bg: 0.85, bg-alt: 0.75 |
DMS Mode
A config.theme.rasi symlink points to @import "themes/dank-colors.rasi" — the matugen-generated Material You palette. The rofi window uses transparency: "real" + background-color: transparent, and container elements carry opacity: 0.85 for the translucent effect.
Integration Levels
System Level
- GTK & QT (Kvantum): Centralized in
modules/theme/default.nix - Compositors (Hyprland, Niri): Border, gap, and shadow colors applied via per-WM theme modules
- Fonts: Unified
modules.theme.fontssubmodule —mono,sans,terminalaliases consumed by all apps
App Level (Reactive)
- Terminals: Default to Catppuccin, override to active theme hex values when a theme is active
- Shell (Zsh): Prompt selectable via
modules.theme.apps.zsh.prompt—starship,matrix,p10k - Tmux: Theme selectable via
modules.theme.apps.tmux.theme; status bar transparency defaults totrue - Rofi: Centralized theme selection with per-mode dispatch
- Startpage (
packages/startpage): Uses Catppuccin design tokens directly in CSS custom properties; light/dark toggle persisted in localStorage
Available Themes
Theme presets are stored as single modular Nix files under modules/themes/presets/ and are automatically loaded at evaluation time:
| Theme | File Path | Description |
|---|---|---|
| Catppuccin | modules/themes/presets/catppuccin.nix | Community standard (Mocha/Latte) |
| Alucard | modules/themes/presets/alucard.nix | Dark fantasy palette |
| Autumnal | modules/themes/presets/autumnal.nix | Warm autumn tones |
Each theme defines 16 ANSI colors + semantic types (bg, fg, highlight, cursor, border, panelbg, etc.).
Adding a New Theme
- Create
modules/themes/presets/<name>.nix - Define
mkIf (cfg.active == "<name>") - Populate
modules.theme.colors(ANSI + Types spec) andmodules.theme.fonts - The preset is automatically picked up and loaded by the modular autoloader.
- Optionally add a rofi
.rasifile inmodules/themes/config/rofi/
Roadmap
- Live Reloading: Seamless theme transitions without session restart via
hey hook reload
Completed Refactoring Wins
- Standardized Color Submodule: Strictly typed Nix submodules to catch missing color or font keys at evaluation time.
- Catppuccin-First Strategy: Unified catppuccin standard baseline styling when no active theme is set.
- Modularized
apps.nix: Split the monolithic apps file into highly focused specialized modules undermodules/themes/apps/.