Recolor PNG, JPEG and WEBP wallpapers with built-in or custom color palettes while mapping each image's continuous lightness into the theme's tonal range.
See PALETTES.md for the supported palette and its colors.
Built-in themes: everforest-dark-medium, catppuccin-mocha, tokyo-night, gruvbox-dark-medium, nord, dracula, and rose-pine-moon.
Show example galleries
Derived previews use --palette-name-only; their current settings are defined
in scripts/regenerate-readme-images.sh and can be applied with
make readme-images without changing these paths.
| Original | Everforest Dark Medium |
|---|---|
![]() | |
| Catppuccin Mocha | Tokyo Night |
![]() | ![]() |
| Gruvbox Dark Medium | Nord |
![]() | ![]() |
| Dracula | Rosé Pine Moon |
![]() | ![]() |
| Original | Everforest Dark Medium | Everforest (accents ignored) |
|---|---|---|
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() |
cargo install --path .paletteer [OPTIONS] <--theme <THEME>|--theme-file <FILE>> <INPUT>...
| Argument | Required / default | Effect | Use case |
|---|---|---|---|
<INPUT>... |
Required; one or more | Recolors PNG, JPG, JPEG, or WebP files. Accepts individual files, directories, and expanded or quoted globs. Directories include immediate supported files only. | Process one image, batch a folder, or select files recursively with a quoted glob such as '**/*-forest.jpg'. |
-t, --theme <THEME> |
No default; required unless --theme-file is used |
Selects one of the built-in color palettes. | Use a bundled palette without maintaining a separate file. |
--theme-file <FILE> |
No default; required unless --theme is used |
Loads a custom TOML palette. Cannot be combined with --theme. |
Recolor with your own base and accent colors. |
-n, --normalize-name |
Optional; off | Lowercases the generated output stem and restricts it to a-z, 0-9, and -. |
Produce predictable, shell-friendly filenames from names containing spaces, punctuation, or uppercase characters. |
--palette-name-only |
Optional; off | Omits neutral, lambda, and mix settings from the output filename, leaving only the palette suffix. |
Keep filenames short when settings are tracked elsewhere. Different settings then resolve to the same output path. |
-f, --format <FORMAT> |
Optional; png |
Selects png, webp, or jpg output. PNG is lossless; JPEG discards alpha. |
Choose lossless output, smaller WebP files, or broadly compatible JPEG files. |
-q, --quality <1-100> |
Optional; 80 for WebP/JPEG |
Sets lossy encoding quality. Using it with PNG is an error. | Trade output size for visual quality when writing WebP or JPEG. |
--neutral-only |
Optional; off | Excludes accent colors and adds -neutral to the output filename. |
Produce a deliberately subdued, near-monochrome result. |
--lambda <0-1> |
Optional; 0.25 |
Weights the mapped theme lightness when selecting the nearest palette color. Non-default values add -lambda-<value> to the filename. |
Use 0 for hue/chroma-only matching or increase toward 1 to make palette lightness influence color assignment. |
--mix <0-1> |
Optional; 1 |
Blends the original Oklab color with the recolored result, including its theme-mapped lightness. Non-default values add -mix-<value> to the output filename. |
Use 0 for the original colors, an intermediate value such as 0.5 for a subtler result, or 1 for the full theme tonal range and chroma remap. |
-o, --overwrite |
Optional; off | Replaces an existing output only after the new image encodes successfully. | Regenerate images without deleting old outputs manually. |
-h, --help |
Optional | Prints the built-in CLI reference. | Check available arguments from the installed binary. |
Pass a TOML file with --theme-file:
name = "forest-dusk"
colors = ["#1b2428", "#556b62", "#d8c9aa"]
accents = ["#e67e80", "#a7c080", "#7fbbb3"]name becomes the output filename suffix and must contain only lowercase
letters, digits, and single hyphens. colors must contain at least one
#RRGGBB color. accents is optional and participates by default; use
--neutral-only to exclude it.
paletteer --theme-file examples/forest-dusk.toml --mix 0.9 wallpaper.jpgQuote recursive globs for consistent behavior across shells. Files whose names
already carry a built-in or currently selected custom palette suffix
(optionally followed by -neutral, -lambda-<value>, and -mix-<value>) are
skipped to prevent repeat recoloring.
Recoloring runs entirely in the
Oklab perceptual color space (via
the palette crate), where Euclidean distance approximates perceived color
difference. Each opaque pixel is converted from sRGB to Oklab, remapped, and
converted back; fully transparent pixels are skipped, and the per-pixel work is
parallelized with rayon.
The remap has two independent stages.
1. Lightness range mapping. The image's own lightness range — the minimum and maximum Oklab L over all opaque pixels — is affine-mapped onto the palette's lightness range. Every pixel's lightness is stretched or compressed by the same linear transform, so a dark theme pulls the whole image dark and the tonal contrast becomes the palette's. This is what makes a result feel like it belongs to the theme. Because the transform is continuous, gradients stay smooth and free of banding.
2. Chroma mapping. For each pixel the two nearest palette colors to its
mapped-lightness / original-chroma point are found using a lightness-weighted
squared distance λ·ΔL² + Δa² + Δb², where --lambda sets how much lightness
influences the match. The pixel's chroma (a, b) is then linearly interpolated
between those two palette colors by projecting it onto the segment between them.
Snapping to a single nearest color would posterize smooth hue gradients into
hard contours; interpolating between the nearest two keeps the transition
continuous while staying within the palette's colors.
The output pixel takes its lightness from stage 1 and its chroma from stage 2,
and --mix then linearly blends between the original Oklab color and this
recolored one (0 = original, 1 = full remap).
This project was developed with assistance from AI coding tools. The resulting code was reviewed and tested by the maintainer.












































