Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Packs

Packs are self-contained theme collections that bundle templates and target specs into a single directory. They let you distribute complete theme kits — a template that defines the color mapping alongside targets that produce output for specific apps — as a unit that others can drop into their system and use by name.

Listing packs

chromasync packs

This prints all discovered packs with their name, version, and root directory.

To inspect a specific pack’s metadata, templates, and targets:

chromasync pack info aurora

Pack directory structure

A pack is a directory containing a pack.toml manifest and one or more subdirectories of templates and/or targets:

my-pack/
├── pack.toml
├── templates/
│   ├── my-theme-dark.toml
│   └── my-theme-light.toml
└── targets/
    ├── ghostty.toml
    └── waybar.toml

If no [templates] or [targets] sections are declared in pack.toml, Chromasync auto-discovers templates/ and targets/ subdirectories if they exist.

Manifest format

The pack.toml file declares the pack’s metadata and asset paths:

name = "my-pack"
version = "1.0.0"
description = "A complete theme kit for my setup."
author = "Your Name"
license = "MIT"
homepage = "https://example.com/my-pack"

[templates]
paths = ["templates"]

[targets]
paths = ["targets"]

Fields

FieldRequiredDescription
nameyesIdentifier matching [a-z0-9_-]+
versionyesVersion string (conventionally semver)
descriptionnoHuman-readable description
authornoCreator or maintainer
licensenoLicense identifier (e.g. MIT, Apache-2.0)
homepagenoURL to project or repository
[templates]noSection with paths = [...] listing template subdirectories
[targets]noSection with paths = [...] listing target subdirectories

Asset paths must be relative to the pack root. Parent directory references (..) are not allowed. A pack must contain at least one template or target directory.

Installing packs

There is no install command — drop the pack directory into one of the search locations:

LocationUse case
~/.config/chromasync/packs/Personal packs
~/.local/share/chromasync/packs/System-distributed packs
.chromasync/packs/Project-local packs (relative to working directory)

All three locations are scanned on every run. A pack with the same name must not appear in multiple locations.

Using pack templates and targets

Pack templates and targets are referenced by name, the same way as built-in ones. You do not need to qualify them with the pack name:

chromasync generate \
  --seed "#89b4fa" \
  --template catppuccin \
  --targets ghostty,waybar

If a pack template has the same name and mode as a built-in template, the pack version takes precedence. See the Template sources table for the full precedence order.

Writing pack templates

Pack templates use the same TOML format as any other template. See the Templates guide for the full schema. The template’s name field is what users pass to --template.

Writing pack targets

Pack targets are declarative TOML files that define output artifacts using {{tokens.<name>}} placeholders:

name = "my-app"
description = "Theme output for My App."

[[artifacts]]
file_name = "theme.conf"
template = """
foreground={{tokens.text}}
background={{tokens.bg}}
accent={{tokens.accent}}
"""

Each [[artifacts]] entry produces one output file. Placeholders are substituted with resolved hex values at generation time.

Placeholder transforms

Placeholders support transforms for different output formats:

SyntaxOutput
{{tokens.bg}}#rrggbb (default hex)
{{tokens.bg | hex_no_hash}}rrggbb (hex without #)
{{tokens.bg | rgba(FF)}}rgba(RRGGBBFF) (uppercase hex with alpha)

Target inheritance

A target can extend another user-defined target with the extends field. The child inherits all artifacts from the base and can add new ones or override existing ones by matching file_name:

name = "my-child"
extends = "my-base"

[[artifacts]]
file_name = "extra.conf"
template = """
color={{tokens.accent}}
"""

Inheritance rules:

  • The base target must be a user-defined or pack target — extending built-in targets (kitty, alacritty) is not allowed.
  • Chains are supported: target A can extend B, which extends C.
  • If a child artifact has the same file_name as a base artifact, the child’s version replaces it.
  • A target with extends can omit [[artifacts]] entirely to inherit the base unchanged under a new name.

Validation

Chromasync validates packs at discovery time:

  • Pack names must match [a-z0-9_-]+.
  • Duplicate pack names across search locations are an error.
  • All declared asset paths must exist and be relative.
  • Templates and targets within packs are validated the same way as standalone files.

Example: Catppuccin pack with Ghostty and Waybar targets

This example builds a complete pack that provides a Catppuccin-style template and targets for Ghostty and Waybar. It uses target inheritance to share a common terminal palette definition between terminal targets and a common GTK color block between GTK-based targets.

Directory layout

~/.config/chromasync/packs/catppuccin/
├── pack.toml
├── templates/
│   ├── catppuccin-dark.toml
│   └── catppuccin-light.toml
└── targets/
    ├── base-terminal.toml
    ├── ghostty.toml
    ├── base-gtk-colors.toml
    └── waybar.toml

pack.toml

name = "catppuccin"
version = "1.0.0"
description = "Catppuccin-inspired theme with Ghostty and Waybar targets."
author = "Your Name"
license = "MIT"

[templates]
paths = ["templates"]

[targets]
paths = ["targets"]

templates/catppuccin-dark.toml

name = "catppuccin"
mode = "dark"
description = "Catppuccin-inspired dark theme with pastel accents on deep surfaces."

[tokens.bg]
family = "neutral"
tone = 0.12
chroma = 0.014

[tokens.bg_secondary]
family = "neutral"
tone = 0.15
chroma = 0.016

[tokens.surface]
family = "neutral_variant"
tone = 0.19
chroma = 0.018

[tokens.surface_elevated]
family = "neutral_variant"
tone = 0.24
chroma = 0.020

[tokens.text]
family = "neutral"
tone = 0.92

[tokens.text_muted]
family = "neutral_variant"
tone = 0.70
chroma_scale = 0.60

[tokens.border]
family = "neutral_variant"
tone = 0.30
chroma_scale = 0.50

[tokens.border_strong]
family = "neutral_variant"
tone = 0.40
chroma_scale = 0.65

[tokens.accent]
family = "primary"
tone = 0.74
chroma_scale = 0.85

[tokens.accent_hover]
family = "primary"
tone = 0.80
chroma_scale = 0.90

[tokens.accent_active]
family = "primary"
tone = 0.66
chroma_scale = 0.80

[tokens.accent_fg]
family = "neutral"
tone = 0.12

[tokens.selection]
family = "primary"
tone = 0.30
chroma_scale = 0.45

[tokens.link]
family = "info"
tone = 0.76
chroma_scale = 0.88

[tokens.success]
family = "success"
tone = 0.72
chroma_scale = 0.82

[tokens.warning]
family = "warning"
tone = 0.78
chroma_scale = 0.80

[tokens.error]
family = "error"
tone = 0.70
chroma_scale = 0.85

templates/catppuccin-light.toml

name = "catppuccin"
mode = "light"
description = "Catppuccin-inspired light theme with pastel accents on warm surfaces."

[tokens.bg]
family = "neutral"
tone = 0.95
chroma = 0.010

[tokens.bg_secondary]
family = "neutral"
tone = 0.91
chroma = 0.012

[tokens.surface]
family = "neutral_variant"
tone = 0.87
chroma = 0.014

[tokens.surface_elevated]
family = "neutral_variant"
tone = 0.82
chroma = 0.016

[tokens.text]
family = "neutral"
tone = 0.14

[tokens.text_muted]
family = "neutral_variant"
tone = 0.40
chroma_scale = 0.58

[tokens.border]
family = "neutral_variant"
tone = 0.76
chroma_scale = 0.45

[tokens.border_strong]
family = "neutral_variant"
tone = 0.64
chroma_scale = 0.60

[tokens.accent]
family = "primary"
tone = 0.50
chroma_scale = 0.82

[tokens.accent_hover]
family = "primary"
tone = 0.56
chroma_scale = 0.88

[tokens.accent_active]
family = "primary"
tone = 0.44
chroma_scale = 0.78

[tokens.accent_fg]
family = "neutral"
tone = 0.96

[tokens.selection]
family = "primary"
tone = 0.84
chroma_scale = 0.30

[tokens.link]
family = "info"
tone = 0.48
chroma_scale = 0.85

[tokens.success]
family = "success"
tone = 0.50
chroma_scale = 0.80

[tokens.warning]
family = "warning"
tone = 0.56
chroma_scale = 0.78

[tokens.error]
family = "error"
tone = 0.52
chroma_scale = 0.82

targets/base-terminal.toml

This base target defines the 16-color terminal palette mapping. Terminal targets extend it and add their app-specific settings.

name = "base-terminal"
description = "Shared 16-color terminal palette. Not useful on its own — extend it."

[[artifacts]]
file_name = "colors.txt"
template = """
color0={{tokens.bg_secondary | hex_no_hash}}
color1={{tokens.error | hex_no_hash}}
color2={{tokens.success | hex_no_hash}}
color3={{tokens.warning | hex_no_hash}}
color4={{tokens.link | hex_no_hash}}
color5={{tokens.accent | hex_no_hash}}
color6={{tokens.selection | hex_no_hash}}
color7={{tokens.text_muted | hex_no_hash}}
color8={{tokens.surface_elevated | hex_no_hash}}
color9={{tokens.error | hex_no_hash}}
color10={{tokens.success | hex_no_hash}}
color11={{tokens.warning | hex_no_hash}}
color12={{tokens.accent_hover | hex_no_hash}}
color13={{tokens.accent_active | hex_no_hash}}
color14={{tokens.border_strong | hex_no_hash}}
color15={{tokens.text | hex_no_hash}}
"""

targets/ghostty.toml

Ghostty extends the base terminal palette. It overrides the colors.txt artifact with Ghostty’s config format (using palette=N syntax) and adds Ghostty-specific keys like cursor-color and selection colors.

name = "ghostty"
description = "Ghostty terminal theme, extends base-terminal."
extends = "base-terminal"

[[artifacts]]
file_name = "colors.txt"
template = """
background={{tokens.bg | hex_no_hash}}
foreground={{tokens.text | hex_no_hash}}
cursor-color={{tokens.accent | hex_no_hash}}
selection-background={{tokens.selection | hex_no_hash}}
selection-foreground={{tokens.text | hex_no_hash}}
palette=0={{tokens.bg_secondary | hex_no_hash}}
palette=1={{tokens.error | hex_no_hash}}
palette=2={{tokens.success | hex_no_hash}}
palette=3={{tokens.warning | hex_no_hash}}
palette=4={{tokens.link | hex_no_hash}}
palette=5={{tokens.accent | hex_no_hash}}
palette=6={{tokens.selection | hex_no_hash}}
palette=7={{tokens.text_muted | hex_no_hash}}
palette=8={{tokens.surface_elevated | hex_no_hash}}
palette=9={{tokens.error | hex_no_hash}}
palette=10={{tokens.success | hex_no_hash}}
palette=11={{tokens.warning | hex_no_hash}}
palette=12={{tokens.accent_hover | hex_no_hash}}
palette=13={{tokens.accent_active | hex_no_hash}}
palette=14={{tokens.border_strong | hex_no_hash}}
palette=15={{tokens.text | hex_no_hash}}
"""

Because the child’s colors.txt artifact has the same file_name as the base’s, it replaces the base version entirely. The result is a single file with Ghostty’s format. If you later added a Foot or WezTerm target, each could extend base-terminal the same way — overriding colors.txt with its own format while keeping the palette mapping consistent.

targets/base-gtk-colors.toml

This base target defines GTK @define-color variables. GTK-based targets extend it and add their own widget styles.

name = "base-gtk-colors"
description = "Shared GTK @define-color block. Extend to add widget styles."

[[artifacts]]
file_name = "style.css"
template = """
@define-color bg {{tokens.bg}};
@define-color bg_secondary {{tokens.bg_secondary}};
@define-color surface {{tokens.surface}};
@define-color surface_elevated {{tokens.surface_elevated}};
@define-color text {{tokens.text}};
@define-color text_muted {{tokens.text_muted}};
@define-color border {{tokens.border}};
@define-color border_strong {{tokens.border_strong}};
@define-color accent {{tokens.accent}};
@define-color accent_hover {{tokens.accent_hover}};
@define-color accent_active {{tokens.accent_active}};
@define-color selection {{tokens.selection}};
@define-color success {{tokens.success}};
@define-color warning {{tokens.warning}};
@define-color error {{tokens.error}};
"""

targets/waybar.toml

Waybar extends the base GTK colors. It overrides style.css to include both the color definitions and Waybar-specific widget rules in a single file.

name = "waybar"
description = "Waybar GTK CSS theme, extends base-gtk-colors."
extends = "base-gtk-colors"

[[artifacts]]
file_name = "style.css"
template = """
@define-color bg {{tokens.bg}};
@define-color bg_secondary {{tokens.bg_secondary}};
@define-color surface {{tokens.surface}};
@define-color surface_elevated {{tokens.surface_elevated}};
@define-color text {{tokens.text}};
@define-color text_muted {{tokens.text_muted}};
@define-color border {{tokens.border}};
@define-color border_strong {{tokens.border_strong}};
@define-color accent {{tokens.accent}};
@define-color accent_hover {{tokens.accent_hover}};
@define-color accent_active {{tokens.accent_active}};
@define-color selection {{tokens.selection}};
@define-color success {{tokens.success}};
@define-color warning {{tokens.warning}};
@define-color error {{tokens.error}};

* {
  border: none;
  border-radius: 0;
  font-family: monospace;
  font-size: 13px;
  min-height: 0;
}

window#waybar {
  background: @bg;
  color: @text;
}

tooltip {
  background: @surface_elevated;
  color: @text;
  border: 1px solid @border_strong;
}

#workspaces {
  background: @bg_secondary;
  margin: 4px 6px;
  padding: 0 4px;
  border: 1px solid @border;
  border-radius: 8px;
}

#workspaces button {
  padding: 0 10px;
  color: @text_muted;
  background: transparent;
  border-bottom: 2px solid transparent;
}

#workspaces button:hover {
  background: @surface;
  color: @text;
  box-shadow: inset 0 -2px @accent_hover;
}

#workspaces button.active {
  background: @surface;
  color: @accent;
  border-bottom-color: @accent;
}

#workspaces button.urgent {
  background: @accent_active;
  color: @text;
}

#clock,
#tray,
#cpu,
#memory,
#network,
#pulseaudio,
#battery {
  margin: 4px 6px;
  padding: 0 10px;
  background: @surface;
  color: @text;
  border: 1px solid @border;
  border-radius: 8px;
}

#battery.charging,
#battery.plugged {
  color: @success;
  border-color: @success;
}

#battery.warning:not(.charging) {
  color: @warning;
  border-color: @warning;
}

#battery.critical:not(.charging) {
  color: @error;
  border-color: @error;
  background: @selection;
}
"""

Generate the theme

With the pack installed, generate a Catppuccin Mocha-style dark theme using a lavender seed:

chromasync generate \
  --seed "#b4befe" \
  --template catppuccin \
  --mode dark \
  --targets ghostty,waybar \
  --output ~/.config/chromasync-themes/catppuccin-mocha

Or a Latte-style light theme with a pink seed:

chromasync generate \
  --seed "#ea76cb" \
  --template catppuccin \
  --mode light \
  --targets ghostty,waybar \
  --output ~/.config/chromasync-themes/catppuccin-latte

Copy the outputs to their final locations:

cp ~/.config/chromasync-themes/catppuccin-mocha/colors.txt \
   ~/.config/ghostty/themes/catppuccin-mocha

cp ~/.config/chromasync-themes/catppuccin-mocha/style.css \
   ~/.config/waybar/style.css