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

Chromasync

A Rust CLI that generates consistent theme files for desktop apps and editors from a seed color or wallpaper image.

Seed/Wallpaper → OKLCH Palette → Template Rules → Theme Files

Install

cargo install --locked --path crates/chromasync-cli

Or build from source:

cargo build --release -p chromasync-cli

Usage

# Generate from a seed color
chromasync generate --seed "#ff6b6b" --template brutalist --mode dark \
  --targets kitty,alacritty,examples/targets/gtk.toml

# Generate from a wallpaper
chromasync wallpaper --image wallpaper.png --template materialish --mode light \
  --targets kitty,examples/targets/css.toml

# Preview palette and tokens without writing files
chromasync preview --seed "#4ecdc4" --template minimal --mode light

# Export tokens as JSON
chromasync tokens --seed "#7c3aed" --template terminal --mode dark --format json

# Batch multiple jobs from a manifest
chromasync batch --file jobs.toml

Output is written to ./chromasync by default.

Built-in Templates & Targets

TemplatesTargets
minimal, brutalist, terminal, materialishkitty, alacritty

Additional targets (GTK, Hyprland, CSS, Waybar, Foot, Ghostty, Editor) are available as declarative TOML specs under examples/targets/. Custom targets can be added to ~/.config/chromasync/targets/.

chromasync templates   # list available templates
chromasync targets     # list available targets

Documentation

An mdBook is included under book/:

mdbook serve --open       # preview locally

To regenerate book source from CLI metadata:

cargo run -p chromasync-docs -- generate

Development

cargo fmt --all --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace
cargo run -p chromasync-docs -- generate --check

Contributing

Pull requests from first-time or otherwise unvouched contributors are automatically closed until a maintainer vouches for the author. This is in place to reduce spammy or low-signal PRs.

If you want to contribute and are not yet vouched, open an issue describing the change you want to make or the area you want to work on. A maintainer can then comment vouch, vouch @user, lgtm, or lgtm @user on the issue or PR to add you to the trusted contributor list.

Maintainers can also comment unvouch or denounce to remove trust or explicitly block an account when needed. The trust list lives in .github/VOUCHED.td.

See the Packaging guide for release and packaging details.

Generate

The generate command creates theme files from a seed color. You provide a hex color, a template, and one or more targets — Chromasync resolves a full color palette, maps it to semantic tokens through the template, and writes output files for each target.

Basic usage

chromasync generate \
  --seed "#ff6b6b" \
  --template brutalist \
  --targets kitty

This writes kitty.conf into the default output directory (./chromasync/).

Options

FlagRequiredDefaultDescription
--seedyesSeed color in #RRGGBB format
--templateyesTemplate name or path to a .toml file
--targetsyesComma-separated list of target names or .toml paths
--modenodarkTheme mode: dark or light
--contrastnorelative-luminanceContrast strategy: relative-luminance or apca-experimental
--outputnochromasyncDirectory to write artifacts into

Choosing a template

Pass a built-in template by name:

--template minimal

Or point to a custom template file:

--template ./my-templates/warm-dark.toml

If the value contains /, ., or ends with .toml, it is treated as a file path. Otherwise it is looked up by name from built-in templates and installed packs.

List available templates with:

chromasync templates

Choosing targets

Targets can be built-in names (kitty, alacritty), paths to declarative target TOML files, or targets provided by packs. Mix them freely in a comma-separated list:

--targets kitty,alacritty,examples/targets/gtk.toml,examples/targets/css.toml

Declarative example targets for GTK, Hyprland, CSS, Waybar, Foot, Ghostty, and Editor ship under examples/targets/.

List available targets with:

chromasync targets

Output

Artifacts are written to the output directory, which is created if it does not exist. On success, each written file path is printed to stdout:

chromasync/kitty.conf
chromasync/gtk.css
chromasync/theme.css

Overwrite protection

Generate refuses to overwrite existing files. If an artifact already exists at the destination, the command fails before writing anything. Delete or move the existing output directory first, or use a different --output path.

Collision detection

If two targets would produce the same output file name, the command fails before writing anything.

Contrast strategies

The --contrast flag controls how Chromasync picks foreground colors that are readable against their backgrounds.

  • relative-luminance (default) — WCAG 2.0 luminance contrast ratio, targeting a minimum of 4.5:1.
  • apca-experimental — APCA (Advanced Perceptual Contrast Algorithm) for more perceptually uniform results. This is experimental and may change.

Examples

Generate a dark theme for multiple targets:

chromasync generate \
  --seed "#4ecdc4" \
  --template minimal \
  --mode dark \
  --targets kitty,alacritty,examples/targets/gtk.toml,examples/targets/hyprland.toml

Generate a light theme with APCA contrast into a custom directory:

chromasync generate \
  --seed "#7c3aed" \
  --template materialish \
  --mode light \
  --contrast apca-experimental \
  --targets examples/targets/editor.toml \
  --output ./my-theme

How it works

  1. The seed color is parsed and converted to OKLCH color space.
  2. Nine palette families are derived (primary, secondary, tertiary, neutral, neutral-variant, error, success, warning, info), each with 16 tone samples spanning black to white.
  3. The template maps each of 17 semantic tokens (like bg, accent, text) to a palette family and tone.
  4. Each target substitutes the resolved token hex values into its output template and produces one or more artifact files.

Generation is deterministic — the same seed, template, and mode always produce identical output.

Wallpaper

The wallpaper command creates theme files from a wallpaper image. Chromasync extracts up to three dominant colors from the image, builds a multi-seed palette where each seed drives a separate palette family, maps it to semantic tokens through the template, and writes output files for each target.

Basic usage

chromasync wallpaper \
  --image ~/wallpapers/mountain.png \
  --template brutalist \
  --targets kitty

This writes kitty.conf into the default output directory (./chromasync/).

Options

FlagRequiredDefaultDescription
--imageyesPath to a wallpaper image file
--templateyesTemplate name or path to a .toml file
--targetsyesComma-separated list of target names or .toml paths
--modenodarkTheme mode: dark or light
--contrastnorelative-luminanceContrast strategy: relative-luminance or apca-experimental
--outputnochromasyncDirectory to write artifacts into

Choosing a template

See Choosing a template in the generate guide. The --template flag works identically.

Choosing targets

See Choosing targets in the generate guide. The --targets flag works identically.

Output

Output behavior is identical to generate — see Output for details on overwrite protection and collision detection.

Color extraction

Instead of a single --seed color, the wallpaper command extracts colors from the image and uses them to build a richer palette.

Multi-seed palette construction

Extraction returns up to three dominant colors ranked by pixel count. Each seed drives a different palette family:

  • Seed 0 (most dominant) → primary family — also used as the base seed for all derived families (neutral, neutral-variant, error, success, warning, info).
  • Seed 1 (second most dominant) → secondary family, replacing the secondary family that would otherwise be derived from seed 0.
  • Seed 2 (third most dominant) → tertiary family, replacing the derived tertiary family.

If the image yields fewer than three seeds, the missing families remain derived from the primary seed, exactly as in generate.

Region labeling

Each extracted seed is labeled with its average spatial position in the image using a 3x3 grid: top-left, top-center, top-right, center-left, center, center-right, bottom-left, bottom-center, bottom-right.

Noisy image fallback

If no single color bucket accounts for at least 10% of visible pixels, the image is considered noisy. In this case, extraction returns a single seed computed as the average color of all visible pixels rather than attempting to separate clusters.

Contrast strategies

See Contrast strategies in the generate guide. The --contrast flag works identically.

Examples

Generate a dark theme for Kitty from a wallpaper:

chromasync wallpaper \
  --image ~/wallpapers/forest.jpg \
  --template minimal \
  --targets kitty

Generate a light theme for multiple targets:

chromasync wallpaper \
  --image ~/wallpapers/sunset.png \
  --template materialish \
  --mode light \
  --targets kitty,alacritty,examples/targets/gtk.toml,examples/targets/hyprland.toml

Generate with APCA contrast into a custom directory:

chromasync wallpaper \
  --image ~/wallpapers/abstract.png \
  --template brutalist \
  --contrast apca-experimental \
  --targets examples/targets/editor.toml \
  --output ./my-theme

How it works

  1. The image is loaded and downscaled to fit within 128x128 pixels (preserving aspect ratio) using triangle filtering.
  2. Each pixel is quantized to 4-bit color (shifting RGB channels right by 4 bits), grouping similar colors into buckets. Pixels with alpha below 16 are skipped.
  3. Buckets are sorted by pixel count. If the largest bucket holds less than 10% of visible pixels, the image is treated as noisy and a single average-color seed is returned.
  4. Otherwise, up to three seeds are taken from the largest buckets, each with a dominance score and a region label derived from the bucket’s average pixel position.
  5. The primary seed generates the full nine-family OKLCH palette. If a second or third seed exists, it replaces the secondary or tertiary family respectively.
  6. The template maps semantic tokens to the palette, and each target renders its output files — identical to the final steps of generate.

Batch

The batch command runs multiple generation jobs from a single TOML manifest. Each job can be seed-based or wallpaper-based with its own template, mode, targets, and output directory. Jobs are processed sequentially in manifest order.

Basic usage

chromasync batch --file themes.toml

Where themes.toml is a manifest defining one or more jobs.

Options

FlagRequiredDefaultDescription
--fileyesPath to a TOML batch manifest

Manifest format

A batch manifest is a TOML file containing a [[jobs]] array. Each entry defines one generation job.

[[jobs]]
name = "dark-terminal"
seed = "#4ecdc4"
template = "minimal"
mode = "dark"
targets = ["kitty", "alacritty"]
output = "dark-terminal"

[[jobs]]
name = "light-editor"
seed = "#7c3aed"
template = "materialish"
mode = "light"
contrast = "apca-experimental"
targets = ["targets/editor.toml"]
output = "light-editor"

The singular [[job]] form is also accepted as an alias.

Job fields

FieldRequiredDefaultDescription
nameno<unnamed>Label used in error messages
seedconditionallySeed color in #RRGGBB format
imageconditionallyPath to a wallpaper image
templateyesTemplate name or path to a .toml file
modenodarkTheme mode: dark or light
contrastnorelative-luminanceContrast strategy: relative-luminance or apca-experimental
targetsno[]List of target names or .toml paths
outputyesOutput directory for this job’s artifacts

Each job must define exactly one of seed or image. Defining both or neither is an error.

Path resolution

All relative paths in a manifest — image, template (when it looks like a file path), and targets entries — are resolved relative to the manifest file’s parent directory, not the working directory. This makes manifests portable: you can keep a manifest alongside its target specs and wallpapers and run it from any directory.

A value is treated as a file path if it contains a path separator (/), starts with an absolute path prefix, or ends with .toml. Otherwise it is looked up as a built-in name.

# Given a manifest at ~/themes/batch.toml:

[[jobs]]
image = "wallpapers/forest.jpg"          # resolves to ~/themes/wallpapers/forest.jpg
template = "minimal"                      # looked up as a built-in template name
targets = ["kitty", "targets/gtk.toml"]   # kitty = built-in, targets/gtk.toml = ~/themes/targets/gtk.toml
output = "forest-output"

Mixing seed and wallpaper jobs

A manifest can freely mix seed-based and wallpaper-based jobs. Seed jobs behave identically to generate and wallpaper jobs behave identically to wallpaper — see those guides for details on palette construction and color extraction.

[[jobs]]
name = "seed-job"
seed = "#4ecdc4"
template = "minimal"
targets = ["kitty", "alacritty"]
output = "seed-output"

[[jobs]]
name = "wallpaper-job"
image = "wallpaper.png"
template = "terminal"
contrast = "apca-experimental"
targets = ["targets/waybar.toml", "targets/foot.toml"]
output = "wallpaper-output"

Output

Each job writes its artifacts to its own output directory. On success, every written file path is printed to stdout. Output behavior per job is identical to generate — see Output for overwrite protection and collision detection.

Error handling

Batch execution is fail-fast: if any job fails, the remaining jobs are skipped. Errors include context about which job failed:

  • batch job 3 failed for output 'dark-theme' — wraps the underlying generation error with the 1-indexed job number and its output directory.
  • batch job 'my-job' must define exactly one of 'seed' or 'image' — validation error when a job defines both or neither source.
  • batch manifest 'path.toml' does not define any jobs — the manifest parsed successfully but the jobs array is empty.

Examples

A single manifest generating dark and light variants of the same seed:

[[jobs]]
name = "dark"
seed = "#ff6b6b"
template = "brutalist"
mode = "dark"
targets = ["kitty", "alacritty", "targets/gtk.toml"]
output = "coral-dark"

[[jobs]]
name = "light"
seed = "#ff6b6b"
template = "brutalist"
mode = "light"
targets = ["kitty", "alacritty", "targets/gtk.toml"]
output = "coral-light"

A manifest generating themes from multiple wallpapers:

[[jobs]]
name = "forest"
image = "wallpapers/forest.jpg"
template = "minimal"
targets = ["kitty", "targets/hyprland.toml", "targets/waybar.toml"]
output = "forest-theme"

[[jobs]]
name = "sunset"
image = "wallpapers/sunset.png"
template = "minimal"
mode = "light"
targets = ["kitty", "targets/hyprland.toml", "targets/waybar.toml"]
output = "sunset-theme"

[[jobs]]
name = "abstract"
image = "wallpapers/abstract.png"
template = "materialish"
contrast = "apca-experimental"
targets = ["targets/editor.toml", "targets/css.toml"]
output = "abstract-theme"

Run either manifest:

chromasync batch --file themes.toml

Templates

Templates are TOML files that map 17 semantic tokens to palette family and tone rules. When you run generate or wallpaper, the template controls which colors from the resolved palette end up as your background, text, accent, borders, and status colors. The same seed with different templates produces different-looking themes.

Listing templates

chromasync templates

This prints all discovered templates with their name, mode, source type, and file location.

Built-in templates

Chromasync ships with four templates, each available in dark and light modes:

NameDescription
minimalRestrained theme with subdued surfaces and a single clean accent
materialishSofter system-style theme with layered surfaces and calmer accents
terminalTerminal-oriented theme with deep backgrounds and crisp signal colors
brutalistHigh-contrast theme with louder borders and harder accent separation

Use them by name:

chromasync generate --seed "#4ecdc4" --template minimal --targets kitty

Template sources

Templates are discovered from multiple locations. When multiple sources provide the same name and mode, the highest-precedence source wins:

PrecedenceSourceLocation
0 (lowest)Built-inEmbedded in the binary
1Pack~/.local/share/chromasync/packs/*/templates/
2User config~/.config/chromasync/templates/
3 (highest)Filesystem pathDirect path passed to --template

When loading by name, Chromasync prefers the variant matching the requested --mode. If no exact mode match exists, it falls back to the other mode from the highest-precedence source.

If the --template value contains /, starts with an absolute path, or ends with .toml, it is loaded as a file path (precedence 3). Otherwise it is looked up by name.

Writing a custom template

A template is a TOML file with three top-level fields and exactly 17 token sections:

name = "my-theme"
mode = "dark"
description = "Optional description of what this template looks like."

[tokens.bg]
family = "neutral"
tone = 0.10
chroma = 0.008

[tokens.accent]
family = "primary"
tone = 0.68
chroma_scale = 0.95

# ... remaining 15 tokens

Top-level fields

FieldRequiredDescription
nameyesTemplate name used for lookup
modeyesdark or light
descriptionnoShort description shown by chromasync templates

Token rule fields

Each [tokens.<name>] section defines how one semantic token is resolved from the palette:

FieldRequiredDefaultDescription
familyyesPalette family to sample from
toneyesLightness level, 0.0 (black) to 1.0 (white)
chromanofamily base chromaAbsolute chroma override (must be ≥ 0.0)
chroma_scaleno1.0Multiplier applied to chroma (must be ≥ 0.0)

The final chroma for a token is:

final_chroma = (chroma OR family.base_chroma) * chroma_scale

All 17 tokens must be defined. Omitting any token is a validation error.

Semantic tokens

Every template must define all 17 tokens:

TokenRole
bgPrimary background
bg_secondarySecondary background (side panels, alternate rows)
surfaceInteractive surface (buttons, inputs)
surface_elevatedElevated surface (dialogs, tooltips, floating panels)
textPrimary text
text_mutedSecondary/muted text
borderRegular border
border_strongEmphasized border
accentPrimary accent (buttons, highlights)
accent_hoverAccent hover state
accent_activeAccent active/pressed state
accent_fgText on accent backgrounds
selectionText selection/highlight background
linkLink color
successSuccess state
warningWarning state
errorError state

Palette families

Nine families are available for token rules:

FamilyDescription
primaryMain accent, derived from the seed color
secondarySecondary accent, derived from the seed (or second wallpaper seed)
tertiaryTertiary accent, derived from the seed (or third wallpaper seed)
neutralDesaturated neutral tones, derived from the seed
neutral_variantSlightly chromatic neutral, derived from the seed
errorRed tones
successGreen tones
warningYellow tones
infoBlue tones

Tone

Tone is OKLCH lightness mapped to a 0.01.0 range:

  • 0.0 — black
  • 1.0 — white

Dark mode templates typically use low tones for backgrounds (0.04–0.15) and high tones for text (0.90–0.98). Light mode reverses this — high tones for backgrounds (0.88–0.98) and low tones for text (0.08–0.14). Accents sit in the middle range in both modes.

Chroma control

Use chroma to set an absolute saturation value, overriding the family’s base chroma. This is common for backgrounds where you want near-neutral surfaces regardless of the seed color:

[tokens.bg]
family = "neutral"
tone = 0.10
chroma = 0.008

Use chroma_scale to proportionally adjust the family’s base chroma. This preserves the seed’s character while tuning intensity:

[tokens.accent]
family = "primary"
tone = 0.68
chroma_scale = 0.95

A scale of 1.0 keeps the family chroma unchanged. Values above 1.0 boost saturation (the brutalist template uses up to 1.20 on accents). Values below 1.0 mute it.

You can combine both — chroma replaces the base, then chroma_scale multiplies the result.

Installing user templates

Drop .toml template files into:

~/.config/chromasync/templates/

All .toml files in this directory are auto-discovered. A user template with the same name and mode as a built-in template overrides it.

Contrast adjustment

After token resolution, Chromasync validates that text has sufficient contrast against bg and that accent_fg has sufficient contrast against accent. If contrast is insufficient, the resolver falls back to neutral light or dark alternatives. See Contrast strategies for details on the available algorithms.

Examples

A custom dark template using the tertiary family for links and secondary for selection:

name = "my-colorful"
mode = "dark"
description = "A more colorful theme using multiple palette families."

[tokens.bg]
family = "neutral"
tone = 0.08
chroma = 0.006

[tokens.bg_secondary]
family = "neutral"
tone = 0.12
chroma = 0.008

[tokens.surface]
family = "neutral_variant"
tone = 0.16
chroma = 0.012

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

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

[tokens.text_muted]
family = "neutral_variant"
tone = 0.72
chroma_scale = 0.65

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

[tokens.border_strong]
family = "primary"
tone = 0.42
chroma_scale = 0.50

[tokens.accent]
family = "primary"
tone = 0.70
chroma_scale = 1.10

[tokens.accent_hover]
family = "primary"
tone = 0.76
chroma_scale = 1.15

[tokens.accent_active]
family = "primary"
tone = 0.62
chroma_scale = 1.05

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

[tokens.selection]
family = "secondary"
tone = 0.32
chroma_scale = 0.70

[tokens.link]
family = "tertiary"
tone = 0.76
chroma_scale = 1.00

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

[tokens.warning]
family = "warning"
tone = 0.76
chroma_scale = 0.90

[tokens.error]
family = "error"
tone = 0.74
chroma_scale = 0.95

Use it with a file path:

chromasync generate \
  --seed "#e06c75" \
  --template ./my-colorful.toml \
  --targets kitty,alacritty

Or install it to ~/.config/chromasync/templates/my-colorful.toml and use it by name:

chromasync generate \
  --seed "#e06c75" \
  --template my-colorful \
  --targets kitty,alacritty

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

Targets

Targets are declarative TOML files that define how semantic color tokens are rendered into application-specific configuration files. When you run generate or wallpaper, each requested target produces one or more output files with your resolved colors substituted into format-specific templates. The same tokens with different targets produce a GTK stylesheet, a terminal config, a Hyprland color scheme, or any other format you define.

Listing targets

chromasync targets

This prints all discovered targets with their name, source type, and file location in tab-separated columns:

alacritty    built-in    alacritty
kitty        built-in    kitty
css          user-config /home/user/.config/chromasync/targets/css.toml
waybar       pack        catppuccin [/home/user/.config/chromasync/packs/catppuccin/targets/waybar.toml]

Built-in targets

Chromasync ships with two built-in targets compiled into the binary:

NameDefault artifactDescription
kittykitty.confKitty terminal emulator theme (foreground, background, cursor, selection, borders, tabs, 16-color ANSI palette)
alacrittyalacritty.tomlAlacritty terminal emulator theme (primary colors, cursor, selection, search, hints, 16-color ANSI palette)

Use them by name:

chromasync generate --seed "#4ecdc4" --template minimal --targets kitty,alacritty

Built-in targets cannot be overridden or extended by user-defined targets.

Target sources

Targets are discovered from multiple locations. When multiple sources provide the same name, the highest-precedence source wins:

PrecedenceSourceLocation
0 (highest)Built-inCompiled into the binary
1Pack~/.local/share/chromasync/packs/*/targets/ or other pack search locations
2User config~/.config/chromasync/targets/
3 (lowest)Filesystem pathDirect path passed to --targets

If the --targets value contains /, starts with an absolute path, or ends with .toml, it is loaded as a file path. Otherwise it is looked up by name.

Specifying targets

Pass a comma-separated list of target names or file paths to --targets:

chromasync generate \
  --seed "#89b4fa" \
  --template minimal \
  --targets kitty,gtk,/path/to/custom.toml

Duplicates in the list are silently deduplicated. Target names are trimmed of whitespace.

Writing a custom target

A target is a TOML file with a name, optional description, and one or more artifact definitions:

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 color values at generation time.

Top-level fields

FieldRequiredDescription
nameyesIdentifier matching [a-z0-9_-]+
descriptionnoHuman-readable description shown by chromasync targets
extendsnoName of another user-defined target to inherit from

Target names must not collide with built-in target names (kitty, alacritty).

Artifact fields

FieldRequiredDescription
file_nameyesOutput file name (no path separators, no . or ..)
templateyesTemplate content with {{...}} placeholders

A target must have at least one artifact unless it uses extends.

Placeholders

Placeholders use the syntax {{<value>}} or {{<value> | <transform>}}. They are replaced with resolved values at generation time.

Token values

Reference any of the 17 semantic tokens:

PlaceholderDescription
{{tokens.bg}}Primary background
{{tokens.bg_secondary}}Secondary background
{{tokens.surface}}Interactive surface
{{tokens.surface_elevated}}Elevated surface
{{tokens.text}}Primary text
{{tokens.text_muted}}Muted text
{{tokens.border}}Regular border
{{tokens.border_strong}}Strong border
{{tokens.accent}}Primary accent
{{tokens.accent_hover}}Accent hover state
{{tokens.accent_active}}Accent active state
{{tokens.accent_fg}}Text on accent backgrounds
{{tokens.selection}}Selection background
{{tokens.link}}Link color
{{tokens.success}}Success state
{{tokens.warning}}Warning state
{{tokens.error}}Error state

Context values

Reference generation context:

PlaceholderDescription
{{ctx.mode}}Theme mode (dark or light)
{{ctx.template_name}}Name of the template used
{{ctx.output_dir}}Output directory path
{{ctx.seed}}Seed color (if generation used one)

Context values do not support transforms.

Transforms

Transforms modify the output format of token values:

SyntaxOutputExample
{{tokens.bg}}#rrggbb (default hex)#1a1b26
{{tokens.bg | hex_no_hash}}rrggbb (hex without #)1a1b26
{{tokens.bg | rgba(FF)}}rgba(RRGGBBAA) (uppercase hex with alpha)rgba(1A1B26FF)

The rgba() transform accepts any two-digit hex alpha value. Use FF for full opacity or lower values like CC for transparency.

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-terminal"
extends = "base-terminal"

[[artifacts]]
file_name = "colors.txt"
template = """
fg={{tokens.text | hex_no_hash}}
bg={{tokens.bg | hex_no_hash}}
"""

Inheritance rules

  • The base target must be user-defined or from a pack — extending built-in targets (kitty, alacritty) is not allowed.
  • Chains are supported: target A can extend B, which extends C. Cycles are detected and rejected.
  • 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.

Installing user targets

Drop .toml target files into:

~/.config/chromasync/targets/

All .toml files in this directory are auto-discovered. Targets can also be distributed as part of a pack.

Validation

Chromasync validates targets at load time:

  • Target names must match [a-z0-9_-]+.
  • Target names must not collide with built-in target names.
  • Artifact file names must be non-empty with no path separators.
  • All placeholders must reference valid token or context names.
  • Transforms must be valid (hex_no_hash or rgba(XX)).
  • Unterminated placeholders (missing }}) are rejected.
  • Duplicate target names across sources of equal precedence are an error.

Examples

CSS custom properties

A target that outputs CSS custom properties for use in web projects:

name = "css"
description = "CSS design token target."

[[artifacts]]
file_name = "theme.css"
template = """
:root {
  --chromasync-bg: {{tokens.bg}};
  --chromasync-bg-secondary: {{tokens.bg_secondary}};
  --chromasync-surface: {{tokens.surface}};
  --chromasync-surface-elevated: {{tokens.surface_elevated}};
  --chromasync-text: {{tokens.text}};
  --chromasync-text-muted: {{tokens.text_muted}};
  --chromasync-border: {{tokens.border}};
  --chromasync-border-strong: {{tokens.border_strong}};
  --chromasync-accent: {{tokens.accent}};
  --chromasync-accent-hover: {{tokens.accent_hover}};
  --chromasync-accent-active: {{tokens.accent_active}};
  --chromasync-accent-fg: {{tokens.accent_fg}};
  --chromasync-selection: {{tokens.selection}};
  --chromasync-link: {{tokens.link}};
  --chromasync-success: {{tokens.success}};
  --chromasync-warning: {{tokens.warning}};
  --chromasync-error: {{tokens.error}};
}
"""

Hyprland with rgba transforms

Hyprland expects rgba() color values. The rgba(FF) transform outputs uppercase hex with an alpha suffix:

name = "hyprland"
description = "Hyprland window manager theme."

[[artifacts]]
file_name = "hyprland.conf"
template = """
$background = {{tokens.bg | rgba(FF)}}
$surface = {{tokens.surface | rgba(FF)}}
$text = {{tokens.text | rgba(FF)}}
$text_muted = {{tokens.text_muted | rgba(FF)}}
$accent = {{tokens.accent | rgba(FF)}}
$accent_hover = {{tokens.accent_hover | rgba(FF)}}
$border = {{tokens.border | rgba(FF)}}
$border_strong = {{tokens.border_strong | rgba(FF)}}
$shadow = {{tokens.bg | rgba(CC)}}

general {
    col.active_border = $accent $accent_hover 45deg
    col.inactive_border = $border
}

decoration {
    col.shadow = $shadow
    shadow_range = 12
    shadow_render_power = 3
}

group {
    col.border_active = $accent
    col.border_inactive = $border
    col.group_border = $border_strong
    col.group_border_active = $accent_hover
}

misc {
    background_color = $background
}
"""

Foot terminal with hex_no_hash

Foot expects bare hex values without the # prefix:

name = "foot"
description = "Foot terminal emulator theme."

[[artifacts]]
file_name = "foot.ini"
template = """
[colors]
foreground={{tokens.text | hex_no_hash}}
background={{tokens.bg | hex_no_hash}}
selection-foreground={{tokens.text | hex_no_hash}}
selection-background={{tokens.selection | hex_no_hash}}
urls={{tokens.link | hex_no_hash}}
regular0={{tokens.bg_secondary | hex_no_hash}}
regular1={{tokens.error | hex_no_hash}}
regular2={{tokens.success | hex_no_hash}}
regular3={{tokens.warning | hex_no_hash}}
regular4={{tokens.link | hex_no_hash}}
regular5={{tokens.accent | hex_no_hash}}
regular6={{tokens.selection | hex_no_hash}}
regular7={{tokens.text_muted | hex_no_hash}}
bright0={{tokens.surface_elevated | hex_no_hash}}
bright1={{tokens.error | hex_no_hash}}
bright2={{tokens.success | hex_no_hash}}
bright3={{tokens.warning | hex_no_hash}}
bright4={{tokens.accent_hover | hex_no_hash}}
bright5={{tokens.accent_active | hex_no_hash}}
bright6={{tokens.border_strong | hex_no_hash}}
bright7={{tokens.text | hex_no_hash}}
"""

Editor theme with context values

An editor theme target that uses {{ctx.mode}} to set the theme type dynamically:

name = "editor"
description = "VS Code editor theme."

[[artifacts]]
file_name = "theme.json"
template = """
{
  "name": "Chromasync {{ctx.mode}}",
  "type": "{{ctx.mode}}",
  "colors": {
    "editor.background": "{{tokens.bg}}",
    "editor.foreground": "{{tokens.text}}",
    "editor.selectionBackground": "{{tokens.selection}}",
    "editorCursor.foreground": "{{tokens.accent}}",
    "activityBar.background": "{{tokens.bg_secondary}}",
    "sideBar.background": "{{tokens.surface}}",
    "statusBar.background": "{{tokens.surface_elevated}}",
    "button.background": "{{tokens.accent}}",
    "button.foreground": "{{tokens.accent_fg}}",
    "textLink.foreground": "{{tokens.link}}"
  }
}
"""

GTK stylesheet

A GTK target mapping semantic tokens to @define-color variables with widget styling rules:

name = "gtk"
description = "GTK theme."

[[artifacts]]
file_name = "gtk.css"
template = """
@define-color window_bg_color {{tokens.bg}};
@define-color window_fg_color {{tokens.text}};
@define-color view_bg_color {{tokens.surface}};
@define-color headerbar_bg_color {{tokens.surface_elevated}};
@define-color accent_bg_color {{tokens.accent}};
@define-color accent_fg_color {{tokens.accent_fg}};
@define-color selection_bg_color {{tokens.selection}};
@define-color border_color {{tokens.border}};
@define-color link_color {{tokens.link}};
@define-color success_color {{tokens.success}};
@define-color warning_color {{tokens.warning}};
@define-color error_color {{tokens.error}};

window, dialog, popover {
  background-color: @window_bg_color;
  color: @window_fg_color;
}

headerbar {
  background-color: @headerbar_bg_color;
  border-color: @border_color;
}

button.suggested-action, button:checked {
  background-color: @accent_bg_color;
  color: @accent_fg_color;
}
"""

Using custom targets

Install a target to ~/.config/chromasync/targets/ and use it by name:

chromasync generate \
  --seed "#e06c75" \
  --template minimal \
  --targets kitty,foot,hyprland,gtk

Or reference a target file directly:

chromasync generate \
  --seed "#e06c75" \
  --template minimal \
  --targets kitty,/path/to/my-custom.toml

Preview

The preview command shows the resolved palette families and semantic tokens for a seed color and template without writing any files. It is a quick way to inspect what colors a particular seed and template combination produces before committing to a full generate run.

Usage

chromasync preview --seed "#ff6b6b" --template brutalist

Preview prints a plain-text summary to stdout and exits. No targets are invoked and no files are created.

Options

FlagRequiredDefaultDescription
--seedyesSeed color in #RRGGBB format
--templateyesTemplate name or path to a template TOML file
--modenodarkTheme mode: dark or light
--contrastnorelative-luminanceContrast heuristic: relative-luminance or apca-experimental

The --template flag accepts the same values as in generate — a built-in template name, a user-config template name, or a file path.

Output format

The output has three sections: a header with generation parameters, a palette families block, and a semantic tokens block.

Seed: #ff6b6b
Mode: dark
Template: brutalist
Contrast: relative-luminance
Template Source: built-in (brutalist-dark.toml)
Description: High-contrast theme with louder borders and harder accent separation

The header shows the seed, mode, template name, contrast strategy, where the template was loaded from, and its description (if any).

Palette families

Palette Families
primary         hue=12.34 chroma=0.123  0=#111111 10=#1a1a1a 20=#222222 ...
secondary       hue=45.67 chroma=0.098  0=#111111 10=#1a1a1a 20=#222222 ...
neutral         hue=12.34 chroma=0.008  0=#111111 10=#1a1a1a 20=#222222 ...
...

Each row shows a palette family with its hue and chroma values, followed by tone samples rendered as hex colors. This lets you see the full color ramp available to template rules.

Semantic tokens

Semantic Tokens
bg              #1a1a1a
bg_secondary    #202020
surface         #252525
surface_elevated #2a2a2a
text            #e0e0e0
text_muted      #a0a0a0
border          #404040
border_strong   #505050
accent          #ff6b6b
accent_hover    #ff5555
accent_active   #ff4444
accent_fg       #ffffff
selection       #ff6b6b
link            #6b9bff
success         #6bff6b
warning         #ffff6b
error           #ff6b6b

All 17 resolved tokens are listed with their final hex values. These are the exact colors that targets would substitute into output files during generate.

Comparing templates

Preview is useful for comparing how different templates interpret the same seed:

chromasync preview --seed "#4ecdc4" --template minimal
chromasync preview --seed "#4ecdc4" --template brutalist
chromasync preview --seed "#4ecdc4" --template terminal

Comparing modes

Check how dark and light modes differ for the same seed and template:

chromasync preview --seed "#4ecdc4" --template minimal --mode dark
chromasync preview --seed "#4ecdc4" --template minimal --mode light

Contrast strategies

The --contrast flag controls how Chromasync ensures readable foreground colors. The default relative-luminance uses WCAG 2.x contrast ratio (minimum 4.5:1). The apca-experimental option uses the APCA algorithm instead. Preview shows which strategy was used in the header so you can verify the resolved tokens meet your accessibility requirements.

chromasync preview \
  --seed "#4ecdc4" \
  --template minimal \
  --contrast apca-experimental

See Contrast strategies for details on the available algorithms.

Preview vs generate

previewgenerate
OutputText to stdoutFiles to disk
TargetsNot usedRequired (--targets)
Output directoryNot usedRequired (--output)
PurposeInspect colorsCreate theme files

Both commands use the same palette generation and token resolution pipeline, so the colors shown by preview are exactly what generate would produce.

Tokens

The tokens command exports the 17 resolved semantic color tokens as structured data. It runs the same palette generation and template resolution pipeline as generate but outputs the token values instead of rendering target artifacts. This is useful for feeding colors into scripts, custom tooling, or formats that Chromasync does not have a target for.

Usage

chromasync tokens --seed "#4ecdc4" --template minimal

The command prints the resolved tokens to stdout and exits. No files are written.

Options

FlagRequiredDefaultDescription
--seedyesSeed color in #RRGGBB format
--templateyesTemplate name or path to a template TOML file
--modenodarkTheme mode: dark or light
--contrastnorelative-luminanceContrast heuristic: relative-luminance or apca-experimental
--formatnojsonSerialization format: json

The --template flag accepts the same values as in generate — a built-in name, a user-config name, or a file path.

Output format

The default (and currently only) format is JSON. The output is a flat object with all 17 token names as keys and #RRGGBB hex strings as values:

{
  "bg": "#040303",
  "bg_secondary": "#090706",
  "surface": "#0E0A0A",
  "surface_elevated": "#1B1413",
  "text": "#F0E9E9",
  "text_muted": "#C4B3AF",
  "border": "#342521",
  "border_strong": "#533C36",
  "accent": "#E86C6C",
  "accent_hover": "#FA827F",
  "accent_active": "#CF5051",
  "accent_fg": "#010100",
  "selection": "#511718",
  "link": "#78AFEE",
  "success": "#8BAC55",
  "warning": "#D1A33C",
  "error": "#EC817A"
}

The JSON is pretty-printed with indentation. Token names use snake_case.

Semantic tokens

Every template resolves all 17 tokens. They are grouped by role:

Backgrounds and surfaces

TokenRole
bgPrimary background — the main canvas of the application
bg_secondarySecondary background — side panels, alternate rows, grouped sections
surfaceInteractive surface — buttons, inputs, cards
surface_elevatedElevated surface — dialogs, tooltips, floating panels, popovers

Text

TokenRole
textPrimary text — body copy, headings
text_mutedSecondary text — placeholders, captions, disabled labels

Borders

TokenRole
borderRegular border — input outlines, dividers, separators
border_strongEmphasized border — focused inputs, section boundaries

Accent

TokenRole
accentPrimary accent — buttons, highlights, active indicators
accent_hoverAccent hover state — slightly lighter or more saturated variant
accent_activeAccent active/pressed state — slightly darker or less saturated variant
accent_fgText on accent backgrounds — guaranteed readable against accent
TokenRole
selectionText selection or highlight background
linkHyperlink color

Status

TokenRole
successSuccess indicator — confirmations, passing checks
warningWarning indicator — caution states, degraded status
errorError indicator — failures, validation errors, destructive actions

Resolution pipeline

The tokens command runs the same pipeline as generate and preview:

  1. Palette generation — the seed color is converted to OKLCH and used to derive 9 palette families (primary, secondary, tertiary, neutral, neutral_variant, error, success, warning, info), each with 16 tone samples spanning black to white.

  2. Template loading — the template is loaded from built-in, user config, pack, or filesystem sources. Each template defines a rule for every token specifying which palette family and tone to sample, with optional chroma overrides.

  3. Token resolution — for each of the 17 tokens, the resolver looks up the rule’s palette family, computes the final chroma as (chroma OR family.base_chroma) * chroma_scale, and converts the OKLCH triplet (family hue, final chroma, rule tone) to a #RRGGBB hex color.

  4. Contrast adjustment — after all tokens are resolved, the resolver checks that text is readable against bg and that accent_fg is readable against accent. If a pair fails the contrast threshold, the resolver tries neutral light (tone=0.98) and dark (tone=0.06) fallbacks and picks the candidate with the best score. This ensures the exported tokens always meet accessibility requirements.

Contrast strategies

The --contrast flag selects the algorithm used in step 4:

StrategyAlgorithmMinimum threshold
relative-luminanceWCAG 2.0 relative luminance ratio4.5:1
apca-experimentalAPCA (Advanced Perceptual Contrast Algorithm)Score of 60

The default relative-luminance is the widely adopted WCAG standard. The apca-experimental option uses a perceptually uniform model that better accounts for how the eye perceives contrast at different luminance levels. It is marked experimental and may change in future versions.

See Contrast strategies for more details.

Scripting with tokens

Because tokens outputs structured JSON, it integrates well with tools like jq:

Extract a single token

chromasync tokens --seed "#4ecdc4" --template minimal | jq -r '.accent'
# #4CBDB5

Build a shell color palette

eval "$(chromasync tokens --seed "#4ecdc4" --template minimal \
  | jq -r 'to_entries[] | "CHROMASYNC_\(.key | ascii_upcase)=\(.value)"')"

echo "$CHROMASYNC_ACCENT"
# #4CBDB5

Generate a custom config file

chromasync tokens --seed "#4ecdc4" --template minimal \
  | jq -r '"cursor_color=\(.accent)\nforeground=\(.text)\nbackground=\(.bg)"' \
  > ~/.config/myapp/colors.conf

Compare dark and light tokens

diff <(chromasync tokens --seed "#4ecdc4" --template minimal --mode dark) \
     <(chromasync tokens --seed "#4ecdc4" --template minimal --mode light)

Tokens vs preview

Both commands resolve the same tokens from the same pipeline. The difference is in output format and detail:

tokenspreview
Output formatJSON (machine-readable)Plain text (human-readable)
Palette familiesNot shownShown with hue, chroma, and tone samples
MetadataNot shownSeed, mode, template source, contrast strategy
Use caseScripting, piping to other toolsQuick visual inspection

Use preview when you want to eyeball the colors. Use tokens when you need to feed them into another program.

Tokens vs generate

tokensgenerate
OutputToken values to stdoutArtifact files to disk
TargetsNot usedRequired (--targets)
PurposeExport raw color dataProduce app-specific config files

If you need output for a specific application, write a target instead of processing token JSON manually. Targets handle format-specific details like placeholder substitution and file naming.

MCP Server

The chromasync-mcp binary exposes Chromasync as a Model Context Protocol (MCP) server. This lets AI assistants generate themes, preview palettes, export tokens, and query available templates, targets, and packs — using the same pipeline as the CLI.

Running the server

The server communicates over stdio using JSON-RPC:

chromasync-mcp

It reads MCP requests from stdin and writes responses to stdout. Logs go to stderr and can be controlled with the RUST_LOG environment variable:

RUST_LOG=info chromasync-mcp

Configuring with Claude Code

Add to your Claude Code MCP settings (.claude/settings.json or project-level):

{
  "mcpServers": {
    "chromasync": {
      "command": "chromasync-mcp"
    }
  }
}

If the binary is not on your PATH, use the full path:

{
  "mcpServers": {
    "chromasync": {
      "command": "/path/to/chromasync-mcp"
    }
  }
}

Available tools

The server exposes 10 tools:

Theme generation

ToolDescription
generateGenerate theme artifacts from a seed color and write them to disk
wallpaperGenerate theme artifacts from a wallpaper image and write them to disk
batchExecute a TOML batch manifest containing multiple generation jobs

Inspection (read-only)

ToolDescription
previewPreview palette families and resolved semantic tokens for a seed color
export_tokensExport the 17 resolved semantic token hex values as JSON
generate_paletteGenerate the full OKLCH palette (9 families, 16 tones each) from a seed color

Discovery (read-only)

ToolDescription
list_templatesList all available templates with their name, mode, source, and location
list_targetsList all available render targets with their name, source, and location
list_packsList all discovered theme packs
pack_infoGet metadata, templates, and targets for a specific theme pack

Common parameters

Several tools share common parameters:

ParameterTypeDefaultDescription
seedstring(required)Seed color in #RRGGBB hex format
templatestring(required)Template name or path to a .toml file
modestring"dark"Theme mode: "dark" or "light"
contraststring"relative-luminance"Contrast strategy: "relative-luminance" or "apca-experimental"
targetsstring[](required for generation)Target names or paths to target TOML files
output_dirstring(required for generation)Directory to write artifact files into

Example interactions

Generate a theme

{
  "name": "generate",
  "arguments": {
    "seed": "#ff6b6b",
    "template": "brutalist",
    "mode": "dark",
    "targets": ["kitty", "alacritty"],
    "output_dir": "./my-theme"
  }
}

Returns a JSON array of written artifact paths.

Preview tokens without writing files

{
  "name": "preview",
  "arguments": {
    "seed": "#4ecdc4",
    "template": "minimal"
  }
}

Returns a human-readable summary of palette families and semantic tokens.

Export tokens as JSON

{
  "name": "export_tokens",
  "arguments": {
    "seed": "#7c3aed",
    "template": "terminal",
    "mode": "light"
  }
}

Returns the 17 semantic token hex values as a JSON object.

Discover available templates

{
  "name": "list_templates",
  "arguments": {}
}

Returns a JSON array with each template’s name, mode, description, source, and location.

Output format

  • Generation tools (generate, wallpaper, batch) return JSON arrays describing written files, including the target name, file name, and full path.
  • preview returns plain text with palette families and semantic tokens.
  • export_tokens and generate_palette return structured JSON.
  • Discovery tools (list_templates, list_targets, list_packs, pack_info) return JSON arrays or objects.

Overwrite protection

Like the CLI, the generate, wallpaper, and batch tools refuse to overwrite existing files. If an artifact already exists at the destination, the tool returns an error. Delete or move the existing output first, or use a different output_dir.

Building from source

cargo build --release -p chromasync-mcp

The binary is written to target/release/chromasync-mcp.

CLI Reference

This page is generated from the Clap command tree in chromasync-cli.

chromasync

Dynamic color engine and theme generator CLI

Usage: chromasync <COMMAND>

Commands:
  generate     Generate theme artifacts from a seed color
  wallpaper    Generate theme artifacts from a wallpaper image
  batch        Execute a batch manifest with multiple generation jobs
  templates    List the available templates and where they were loaded from
  packs        List the discovered theme packs
  pack         Inspect a discovered theme pack
  targets      List available renderer targets and where they were loaded from
  preview      Show palette families and resolved semantic tokens
  tokens       Export resolved semantic tokens
  completions  Generate shell completion scripts
  help         Print this message or the help of the given subcommand(s)

Options:
  -h, --help
          Print help

  -V, --version
          Print version

chromasync generate

Generate theme artifacts from a seed color

Usage: generate [OPTIONS] --seed <SEED> --targets <TARGETS>

Options:
      --seed <SEED>
          Seed color in #RRGGBB format

      --template <TEMPLATE>
          Template name or path to a template TOML file. Optional if targets specify preferred_template

      --mode <MODE>
          Theme mode to generate
          
          [default: dark]
          [possible values: dark, light]

      --contrast <CONTRAST>
          Contrast selection heuristic used when resolving readable foregrounds
          
          [default: relative-luminance]
          [possible values: relative-luminance, apca-experimental]

      --chroma <CHROMA>
          Chroma strategy used when generating palette families
          
          [default: normal]
          [possible values: subtle, normal, vibrant, muted, industrial]

      --targets <TARGETS>
          Comma-separated list of target names or target TOML paths to generate

      --output <OUTPUT>
          Output directory for generated artifacts
          
          [default: chromasync]

  -h, --help
          Print help

chromasync wallpaper

Generate theme artifacts from a wallpaper image

Usage: wallpaper [OPTIONS] --image <IMAGE> --targets <TARGETS>

Options:
      --image <IMAGE>
          Wallpaper image path

      --template <TEMPLATE>
          Template name or path to a template TOML file. Optional if targets specify preferred_template

      --mode <MODE>
          Theme mode to generate
          
          [default: dark]
          [possible values: dark, light]

      --contrast <CONTRAST>
          Contrast selection heuristic used when resolving readable foregrounds
          
          [default: relative-luminance]
          [possible values: relative-luminance, apca-experimental]

      --chroma <CHROMA>
          Chroma strategy used when generating palette families
          
          [default: normal]
          [possible values: subtle, normal, vibrant, muted, industrial]

      --targets <TARGETS>
          Comma-separated list of target names or target TOML paths to generate

      --output <OUTPUT>
          Output directory for generated artifacts
          
          [default: chromasync]

  -h, --help
          Print help

chromasync batch

Execute a batch manifest with multiple generation jobs

Usage: batch --file <FILE>

Options:
      --file <FILE>
          Path to a TOML manifest containing multiple jobs

  -h, --help
          Print help

chromasync templates

List the available templates and where they were loaded from

Usage: templates

Options:
  -h, --help
          Print help

chromasync packs

List the discovered theme packs

Usage: packs

Options:
  -h, --help
          Print help

chromasync pack

Inspect a discovered theme pack

Usage: pack <COMMAND>

Commands:
  info  Show metadata and assets for an installed pack
  help  Print this message or the help of the given subcommand(s)

Options:
  -h, --help
          Print help

chromasync pack info

Show metadata and assets for an installed pack

Usage: info <NAME>

Arguments:
  <NAME>
          Pack name from pack.toml

Options:
  -h, --help
          Print help

chromasync targets

List available renderer targets and where they were loaded from

Usage: targets

Options:
  -h, --help
          Print help

chromasync preview

Show palette families and resolved semantic tokens

Usage: preview [OPTIONS] --seed <SEED> --template <TEMPLATE>

Options:
      --seed <SEED>
          Seed color in #RRGGBB format

      --template <TEMPLATE>
          Template name or path to a template TOML file

      --mode <MODE>
          Theme mode to preview
          
          [default: dark]
          [possible values: dark, light]

      --contrast <CONTRAST>
          Contrast selection heuristic used when resolving readable foregrounds
          
          [default: relative-luminance]
          [possible values: relative-luminance, apca-experimental]

      --chroma <CHROMA>
          Chroma strategy used when generating palette families
          
          [default: normal]
          [possible values: subtle, normal, vibrant, muted, industrial]

  -h, --help
          Print help

chromasync tokens

Export resolved semantic tokens

Usage: tokens [OPTIONS] --seed <SEED> --template <TEMPLATE>

Options:
      --seed <SEED>
          Seed color in #RRGGBB format

      --template <TEMPLATE>
          Template name or path to a template TOML file

      --mode <MODE>
          Theme mode to resolve
          
          [default: dark]
          [possible values: dark, light]

      --contrast <CONTRAST>
          Contrast selection heuristic used when resolving readable foregrounds
          
          [default: relative-luminance]
          [possible values: relative-luminance, apca-experimental]

      --chroma <CHROMA>
          Chroma strategy used when generating palette families
          
          [default: normal]
          [possible values: subtle, normal, vibrant, muted, industrial]

      --format <FORMAT>
          Serialization format for token export
          
          [default: json]
          [possible values: json]

  -h, --help
          Print help

chromasync completions

Generate shell completion scripts

Usage: completions <SHELL>

Arguments:
  <SHELL>
          Shell to generate completions for
          
          [possible values: bash, elvish, fish, powershell, zsh]

Options:
  -h, --help
          Print help

Built-in Templates

NameModeDescriptionSource
brutalistdarkBuilt-in high-contrast dark theme with louder borders and harder accent separation.brutalist-dark.toml
brutalistlightBuilt-in high-contrast light theme with louder borders and harder accent separation.brutalist-light.toml
materialishdarkBuilt-in softer system-style dark theme with layered surfaces and calmer accents.materialish-dark.toml
materialishlightBuilt-in softer system-style light theme with layered surfaces and calmer accents.materialish-light.toml
minimaldarkBuilt-in restrained dark theme with subdued surfaces and a single clean accent.minimal-dark.toml
minimallightBuilt-in restrained light theme with paper surfaces and a single clean accent.minimal-light.toml
terminaldarkBuilt-in terminal-oriented dark theme with deep backgrounds and crisp signal colors.terminal-dark.toml
terminallightBuilt-in terminal-oriented light theme with bright backgrounds and crisp signal colors.terminal-light.toml

Built-in Targets

NameDefault Artifact
kittykitty.conf
alacrittyalacritty.toml