Files
Nomarchy/docs/creating-themes.md
Bernardo Magri e7e89b8333 chore(theme): prune 9 dead templates, document the 2 that ship
themes/templates/ shipped 11 mustache templates, but
nomarchy-theme-set-templates only writes to a path when no file is
already there — and a careful trace shows 9 of the 11 outputs are
either preempted by an earlier write or never read at all:

  - kitty.conf.tpl, ghostty.conf.tpl
      → shadowed by the per-palette generators in
        themes/engine/files.nix added in 8d3ce2d.
  - hyprland.conf.tpl
      → shadowed by files.nix:100, which always writes
        ~/.config/nomarchy/current/theme/hyprland.conf from the
        palette/feature/nord fallback chain.
  - hyprlock.conf.tpl, alacritty.toml.tpl, btop.theme.tpl,
    chromium.theme.tpl, swayosd.css.tpl
      → output paths nothing reads. alacritty + swayosd are themed
        via Stylix / declarative HM options inline. btop reads from
        ~/.config/btop/themes/nomarchy.theme (loader.nix:72), not
        from the theme symlink. chromium is themed via the managed-
        policy module in core/system/browser.nix. hyprlock has no
        consumer of theme/hyprlock.conf anywhere in the tree.
  - hyprland-preview-share-picker.css.tpl
      → orphaned when the share-picker dir was deleted in 20de3d4.

obsidian.css.tpl and keyboard.rgb.tpl stay: the first is consumed by
nomarchy-theme-set-obsidian (copied into every Obsidian vault), the
second by nomarchy-theme-set-keyboard-asus-rog (sets the ROG
keyboard tint via asusctl).

Rewrote Step 6 of docs/creating-themes.md to describe the two live
templates by name and corrected a path bug ("~/.config/nomarchy/themed/"
→ "~/.config/nomarchy/themes/templates/" — the script actually reads
the latter).

`nix flake check --no-build` clean.
2026-05-22 17:59:15 +01:00

8.8 KiB

Creating a Nomarchy Theme

This guide walks through creating a new theme for Nomarchy from scratch.

Theme Directory Structure

Each theme lives in themes/palettes/<theme-name>/ with the following structure:

themes/palettes/my-theme/
├── colors.toml              # REQUIRED - Color palette definition
├── icons.theme              # REQUIRED - GTK icon theme name (single line)
├── light.mode               # Optional - Empty marker file for light themes
├── preview.png              # Optional - Preview image for the theme selector
├── backgrounds/             # Optional - Wallpaper images
│   ├── 1-primary.jpg        # Numbered prefix controls default order
│   ├── 2-alternate.png
│   └── ...
└── apps/                    # Optional - App-specific themed configs
    ├── btop.theme            # btop color theme
    ├── neovim.lua            # Neovim colorscheme plugin spec
    ├── vscode.json           # VS Code theme extension reference
    └── hyprland.conf         # Hyprland visual overrides (colors, decorations, animations)

Step 1: Create the Color Palette

Create colors.toml with all 24 required color fields. Every color must be a hex value with a # prefix.

# UI colors
accent = "#83b6af"
cursor = "#d3c6aa"
foreground = "#d3c6aa"
background = "#2d353b"
selection_foreground = "#d3c6aa"
selection_background = "#505a60"

# ANSI 16-color palette (color0-15)
# Normal colors
color0 = "#3c474d"    # Black
color1 = "#e68183"    # Red
color2 = "#a7c080"    # Green
color3 = "#d9bb80"    # Yellow
color4 = "#83b6af"    # Blue
color5 = "#d39bb6"    # Magenta
color6 = "#87c095"    # Cyan
color7 = "#868d80"    # White

# Bright colors
color8 = "#868d80"    # Bright Black
color9 = "#e68183"    # Bright Red
color10 = "#a7c080"   # Bright Green
color11 = "#d9bb80"   # Bright Yellow
color12 = "#83b6af"   # Bright Blue
color13 = "#d39bb6"   # Bright Magenta
color14 = "#87c095"   # Bright Cyan
color15 = "#868d80"   # Bright White

These colors are mapped to a Base16 palette automatically:

Base16 Slot Source Field Typical Role
base00 background Default background
base01 color0 Lighter background
base02 color8 Selection background
base03 color8 Comments, invisibles
base04 color7 Dark foreground
base05 foreground Default foreground
base06 color15 Light foreground
base07 color15 Lightest foreground
base08 color1 Red (errors, deletions)
base09 color3 Orange
base0A color3 Yellow (warnings)
base0B color2 Green (success, additions)
base0C color6 Cyan (info)
base0D color4 Blue (primary accent)
base0E color5 Magenta (keywords)
base0F color1 Brown (deprecated)

Step 2: Set the Icon Theme

Create icons.theme with a single line containing the GTK icon theme name:

Yaru-blue

Common options from the yaru-theme package: Yaru-blue, Yaru-purple, Yaru-red, Yaru-sage, Yaru-olive, Yaru-magenta, Yaru-yellow, Yaru-gray, Yaru-grey, Yaru-wartybrown.

Step 3: Add Backgrounds (Optional)

Place wallpaper images in a backgrounds/ directory. Use numbered prefixes to control the default selection order -- the first file alphabetically becomes the default wallpaper.

backgrounds/
├── 1-main-wallpaper.jpg     # Default wallpaper (first alphabetically)
├── 2-alternate.png          # Additional option
└── 3-minimal.jpg            # Another option

Supported formats: .jpg, .png, .jpeg.

If no backgrounds are provided, the system falls back to the catppuccin default wallpaper.

Step 4: Light Theme (Optional)

For light themes, create an empty light.mode marker file:

touch themes/palettes/my-theme/light.mode

This controls Stylix polarity (light vs dark) and affects GTK theming, browser color scheme, and other system-wide dark/light detection.

Step 5: App-Specific Configs (Optional)

These theme-specific files are automatically picked up by the respective application modules in features/apps/<app>/default.nix during theme switching.

apps/btop.theme

A btop color theme file. See existing themes for the format, or generate one from your palette colors.

apps/neovim.lua

A lazy.nvim plugin spec for the matching Neovim colorscheme:

return {
  { "sainnhe/everforest" },
  {
    "LazyVim/LazyVim",
    opts = {
      colorscheme = "everforest",
    },
  },
}

apps/vscode.json

VS Code theme extension reference:

{
  "name": "Everforest Dark",
  "extension": "sainnhe.everforest"
}

apps/hyprland.conf

Hyprland visual overrides for this theme. This can include custom border colors, gaps, decorations, blur, and animations. The file is sourced after the default settings, so values here override the defaults.

$activeBorderColor = rgb(d3c6aa)

general {
    col.active_border = $activeBorderColor
    gaps_in = 6
    gaps_out = 12
    border_size = 3
}

decoration {
    rounding = 10
    blur {
        enabled = true
        size = 5
        passes = 3
    }
}

Step 6: Template Variables

Nomarchy has a small template system that generates per-palette files from your colors.toml at nomarchy-theme-set time. Templates in themes/templates/*.tpl use placeholder syntax:

Syntax Example Value Description
{{ background }} #2d353b Color value as-is (with #)
{{ background_strip }} 2d353b Color value without #
{{ background_rgb }} 45,53,59 Color as decimal RGB

Every key from colors.toml is available as a template variable. The script (nomarchy-theme-set-templates) processes each template into ~/.config/nomarchy/current/theme/<name> only when no file is already there — so it acts as a fallback for palettes that don't ship the file themselves.

Two built-in templates ship:

Template Output Consumed by
obsidian.css.tpl ~/.config/nomarchy/current/theme/obsidian.css nomarchy-theme-set-obsidian copies it into every Obsidian vault
keyboard.rgb.tpl ~/.config/nomarchy/current/theme/keyboard.rgb nomarchy-theme-set-keyboard-asus-rog calls asusctl aura effect static

Everything else that used to ship a template (alacritty.toml.tpl, btop.theme.tpl, chromium.theme.tpl, ghostty.conf.tpl, hyprland.conf.tpl, hyprlock.conf.tpl, kitty.conf.tpl, swayosd.css.tpl, hyprland-preview-share-picker.css.tpl) has been removed: those apps are themed via Stylix, declarative Home-Manager options, or per-palette Nix generators in themes/engine/files.nix — the template path was always shadowed by an earlier write.

To add a custom template, drop a .tpl file in ~/.config/nomarchy/themes/templates/. User templates take priority over built-in ones.

Step 7: Preview Image (Optional)

Add a preview.png screenshot of the theme in action. This is displayed in the theme selector menu (nomarchy-menu theme).

Applying Your Theme

During development (runtime switch)

nomarchy-theme-set my-theme

This updates ~/.config/nomarchy/state.json, processes templates, and triggers a Home Manager rebuild.

Setting as default (Nix configuration)

In your home.nix:

{
  nomarchy.theme = "my-theme";
}

Then rebuild: env-update (or sys-update for system-wide changes).

Theme Discovery

The system automatically discovers themes by scanning themes/palettes/ for directories containing a colors.toml file. No registration step is needed -- just create the directory with a valid colors.toml and the theme is available.

Checklist

  • colors.toml with all 24 color fields
  • icons.theme with a valid GTK icon theme name
  • backgrounds/ with at least one numbered wallpaper
  • light.mode if it's a light theme
  • apps/neovim.lua with colorscheme plugin spec
  • apps/vscode.json with theme extension reference
  • apps/btop.theme with terminal monitor colors
  • apps/hyprland.conf if custom decorations/animations are desired
  • preview.png for the theme selector