A theme injector tool that applies Material Design 3 color palettes to various configuration files.
tinct is a command-line utility that generates themed configuration files based on Material Design 3 color specifications. It reads color themes from JSON files and injects the appropriate color values into template files, producing themed output files for various applications.
- Material Design 3 compliant color generation using official algorithms
- Wallpaper-based color extraction — extract source colors from images with multiple scheme types
- Support for light and dark themes
- Template-based theme injection with parallel processing (10x faster)
- Color preview functionality
- Configurable via TOML files with algorithm parameters
contrast_levelfor accessibilitycolor_harmonymodes (md3, analogous, complementary, triadic, split-complementary)
- Support for post-processing hooks
- Modular architecture for easy extensibility
- Smart color generation from single seed color
- Consistent alpha values (0.0-1.0 range)
- Format-preserving color filters
- HSL-based color adjustments
- Simplified theme format - no more dark/light nesting
git clone https://github.com/lonerOrz/tinct.git
cd tinct
cargo build --release{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
tinct.url = "github:lonerOrz/tinct";
};
outputs =
inputs@{
self,
flake-utils,
nixpkgs,
...
}:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = import nixpkgs {
inherit system;
};
in
{
devShells.default = pkgs.mkShell {
packages = [ inputs.tinct.packages.${system}.tinct ];
};
}
);
}Basic usage:
tinct --theme <theme-name>With custom options:
tinct -t MyTheme -c config.toml -m light -pOptions:
-c, --config: Path to the TOML config file (defaults to~/.config/tinct/config.toml)-t, --theme: Path to theme.json file or theme name in themes/ folder-s, --seed: Seed color for generating palette (e.g.,"#7aa2f7")-i, --image: Path to wallpaper image for color extraction (PNG/JPG/WebP)-m, --mode: Theme mode override (dark/light, defaults to dark)-p, --preview: Show color preview instead of processing templates--scheme-type: Color scheme for image extraction (tonal-spot, vibrant, faithful, muted, dysfunctional, content, fruit-salad, rainbow, monochrome)--skip-sequences: Skip sending ANSI escape sequences to update terminal colors--log-level: Logging level (quiet/normal/verbose, defaults to normal)
tinct supports simplified theme formats using Material Design 3 color generation.
The simplest format uses only a seed color to generate the complete Material Design 3 palette.
{
"seed": "#7aa2f7"
}You can also specify override colors directly. The Primary color will be used as the seed.
{
"Primary": "#7aa2f7",
"Secondary": "#bb9af7",
"Tertiary": "#9ece6a"
}Combine seed with color overrides for precise control.
{
"seed": "#7aa2f7",
"Primary": "#7aa2f7",
"Secondary": "#bb9af7",
"Tertiary": "#9ece6a",
"Error": "#f7768e",
"Surface": "#1a1b26",
"Background": "#1a1b26"
}Available override options:
| Field | Description | Example |
|---|---|---|
seed |
Seed color for palette generation | "#7aa2f7" |
Primary |
Override primary color | "#7aa2f7" |
Secondary |
Override secondary color | "#bb9af7" |
Tertiary |
Override tertiary color | "#9ece6a" |
Error |
Override error color | "#f7768e" |
Surface |
Override surface color | "#1a1b26" |
Background |
Override background color | "#1a1b26" |
SurfaceVariant |
Override surface variant | "#24283b" |
Outline |
Override outline color | "#565f89" |
OutlineVariant |
Override outline variant | "#b4b5b9" |
Shadow |
Override shadow color | "#000000" |
Scrim |
Override scrim color | "#00000080" |
InverseSurface |
Override inverse surface | "#ebdbb2" |
InverseOnSurface |
Override inverse on surface | "#3c3836" |
InversePrimary |
Override inverse primary | "#7aa2f7" |
Note: Color names support both lowercase ("primary") and PascalCase ("Primary").
You can adjust the color generation algorithm in your config.toml:
[algorithm]
hue_shift = 0 # Rotate hue by degrees (-180 to 180)
saturation_adjustment = 0 # Adjust saturation percentage (-100 to 100)
contrast_level = 0.0 # MD3 contrast level (-1.0 to 1.0)
color_harmony = "md3" # Harmony mode (md3, analogous, complementary, triadic, split-complementary)Algorithm parameters:
| Parameter | Range | Default | Effect |
|---|---|---|---|
hue_shift |
-180 ~ 180 | 0 |
Rotates all colors' hue |
saturation_adjustment |
-100 ~ 100 | 0 |
Adjusts color saturation (chroma) |
contrast_level |
-1.0 ~ 1.0 | 0.0 |
MD3 contrast level for accessibility |
color_harmony |
see below | md3 |
Secondary/tertiary hue relationships |
Color Harmony modes:
| Mode | Description | Secondary Hue | Tertiary Hue |
|---|---|---|---|
md3 |
Material Design 3 standard | MD3 hue table (2-20°) | MD3 hue table (5-40°) |
analogous |
Close, harmonious colors | +15° | +30° |
complementary |
Opposite colors | +180° | +180° |
triadic |
Evenly spaced | +120° | +240° |
split-complementary |
Split opposite | +150° | +210° |
Examples:
# Warm Gruvbox theme
[algorithm]
hue_shift = 15
saturation_adjustment = 10
# Cool Nord theme
[algorithm]
hue_shift = -10
saturation_adjustment = -20
# High saturation theme
[algorithm]
saturation_adjustment = 50Extract colors from wallpaper images using the [image] section:
[image]
scheme_type = "vibrant" # Color extraction schemeScheme types:
| Scheme | Pipeline | Description |
|---|---|---|
tonal-spot |
Wu + WSMeans + Score | MD3 standard, balanced |
vibrant |
K-means + Chroma | High saturation colors |
faithful |
K-means + Count | Area-dominant colors |
muted |
K-means + Muted | Low saturation, subtle |
dysfunctional |
K-means + Dysfunctional | 2nd most dominant family |
content |
Wu + Score | MD3 Content variant |
fruit-salad |
Wu + Score | MD3 Fruit Salad variant |
rainbow |
Wu + Score | MD3 Rainbow variant |
monochrome |
Wu + Score | MD3 Monochrome variant |
Priority chain: CLI --scheme-type > config [image].scheme_type > default (tonal-spot)
Notes:
hue_shift = 30rotates colors 30° toward orangesaturation_adjustment = 50increases saturation by 50%saturation_adjustment = -50decreases saturation by 50% (more muted)lightness_adjustmentis not supported (would break MD3 contrast ratios)
Gruvbox Dark:
{
"seed": "#b8bb26",
"error": "#fb4934",
"surface": "#282828",
"background": "#282828"
}Nord:
{
"seed": "#88c0d0",
"error": "#bf616a",
"surface": "#2e3440",
"background": "#2e3440"
}Dracula:
{
"seed": "#bd93f9",
"error": "#ff5555",
"surface": "#282a36",
"background": "#282a36"
}In tinct's template files, you can use the following color formats to reference colors from your theme.
Available color roles include:
primary- Primary brand coloron_primary- Text/icon color that appears on top of primaryprimary_container- Container color matching the primaryon_primary_container- Text/icon color that appears on top of primary containersecondary- Secondary brand coloron_secondary- Text/icon color that appears on top of secondarysecondary_container- Container color matching the secondaryon_secondary_container- Text/icon color that appears on top of secondary containertertiary- Tertiary brand coloron_tertiary- Text/icon color that appears on top of tertiarytertiary_container- Container color matching the tertiaryon_tertiary_container- Text/icon color that appears on top of tertiary containererror- Error state coloron_error- Text/icon color that appears on top of errorerror_container- Container color matching the erroron_error_container- Text/icon color that appears on top of error containerbackground- Background coloron_background- Text/icon color that appears on top of backgroundsurface- Surface coloron_surface- Text/icon color that appears on top of surfacesurface_variant- Variant surface coloron_surface_variant- Text/icon color that appears on top of surface variantsurface_container_lowest- Lowest level surface containersurface_container_low- Low level surface containersurface_container- Standard surface containersurface_container_high- High level surface containersurface_container_highest- Highest level surface containerinverse_surface- Inverse surface colorinverse_on_surface- Text/icon color for inverse surfaceinverse_primary- Inverse primary colorsurface_dim- Dimmed surface colorsurface_bright- Bright surface coloroutline- Outline/border coloroutline_variant- Variant outline colorshadow- Shadow colorscrim- Scrim overlay color
For each color role, you can use the following format attributes:
| Attribute | Example Placeholder | Output Example |
|---|---|---|
| Hex complete | {{colors.primary.default.hex}} |
#ff5722 |
| Hex stripped | {{colors.primary.default.hex_stripped}} |
ff5722 |
| Hex8 complete | {{colors.primary.default.hex8}} |
#ff5722ff |
| Hex8 stripped | {{colors.primary.default.hex8_stripped}} |
ff5722ff |
| RGB | {{colors.primary.default.rgb}} |
rgb(255, 87, 34) |
| RGBA | {{colors.primary.default.rgba}} |
rgba(255, 87, 34, 1.0) |
| Red | {{colors.primary.default.red}} |
255 |
| Green | {{colors.primary.default.green}} |
87 |
| Blue | {{colors.primary.default.blue}} |
34 |
| Alpha | {{colors.primary.default.alpha}} |
1.0 |
| HSL | {{colors.primary.default.hsl}} |
hsl(14, 100%, 57%) |
| HSLA | {{colors.primary.default.hsla}} |
hsla(14, 100%, 57%, 1.0) |
| Hue | {{colors.primary.default.hue}} |
14 |
| Saturation | {{colors.primary.default.saturation}} |
100 |
| Lightness | {{colors.primary.default.lightness}} |
57 |
tinct supports a modular filter system to transform color values:
| Filter | Example Placeholder | Output Example |
|---|---|---|
| Set Alpha | {{colors.primary.default.rgba | set_alpha: 0.5}} |
rgba(255, 87, 34, 0.5) |
| Lighten | {{colors.primary.default.rgb | lighten: 10}} |
Lightened RGB color |
| Darken | {{colors.primary.default.rgb | darken: 10}} |
Darkened RGB color |
| Saturate | {{colors.primary.default.rgb | saturate: 10}} |
More saturated RGB color |
| Desaturate | {{colors.primary.default.rgb | desaturate: 10}} |
Less saturated RGB color |
Note: If you want to use transparency in rgba(), you need to reference the .red, .green, .blue components separately, otherwise it will generate invalid CSS.
{{mode}}→"dark"or"light"{{is_dark}}→"true"or"false"{{is_light}}→"true"or"false"
- Hex Colors
.primary-button {
background-color: {{colors.primary.default.hex}};
color: {{colors.on_primary.default.hex}};
}- RGB Colors
.surface-background {
background-color: {{colors.surface.default.rgb}};
border: 1px solid {{colors.outline.default.hex}};
}- RGBA Colors (with components)
.semi-transparent-overlay {
background-color: rgba(
{{colors.surface.default.red}},
{{colors.surface.default.green}},
{{colors.surface.default.blue}},
0.8
);
}- HSL Colors
.accent-element {
background-color: {{colors.tertiary.default.hsl}};
}- Stripped Hex
.styled-border {
border-color: #{{colors.outline.default.hex_stripped}};
}- Conditional Styling
@media (prefers-color-scheme: {{mode}}) {
body {
background-color: {{colors.background.default.hex}};
}
}These formats allow you to flexibly use various color representations in your templates to accommodate the requirements of different application configuration files.
BSD 3-Clause License
If you find
tinctuseful, please give it a ⭐ and share! 🎉
