Introduction

crates-io downloads license dependency-status status-badge CodeBerg MatrixChat

If comming from v2, please check v3 breaking changes.

wallust is a command line tool for creating 16 color palettes, since it was the original intent of pywal, the tool that inspired the creation of wallust.

gif

Features

  • Includes man pages and completions!
  • Sets terminal colors on all (or the current, -u) active terminals:
  • Cache scheme palettes, overwritten by -w:
    • Linux: $XDG_CACHE_HOME or $HOME/.cache
    • MacOs: $HOME/Library/Caches
    • Windows: {FOLDERID_LocalAppData}
  • Read pywal/terminal-sexy colorschemes with wallust cs.
  • Built-in themes with wallust theme (compile time feature).
  • Optional Configuration file, wallust.toml:
    • wallust checks for ~/.config/wallust/wallust.toml for the config file, if not found it will use default implementations.
    • Configuration variables are avaliable as cli flags.
    • Optional templating with a subset of Jinja2 or pywal syntax if selected.
    • Configurable methods for backends, colorspaces, palettes and threshold.
    • OS dependant path:
      • Linux: $XDG_CONFIG_HOME or $HOME/.config
      • MacOs: $HOME/Library/Application Support
      • Windows: {FOLDERID_RoamingAppData}
MethodsDescription
BackendsHow to extract the colors from the image. (e.g pywal uses convert)
ColorSpaceGet the most prominent color, and sort them according to the Palette, configurable by a threshold
PaletteMakes a scheme palette with the gathered colors, (e.g. sets light background)

Installation

wallust can run on Linux, BSDs, MacOS and Windows.

Binary packages

Go to the releases and download the tar.gz file.

  • you have a binary for musl, so it works for most *nix platforms, or
  • a .exe for Windows users.
tar -xf wallust-TARGET.tar.gz

Distribution Packages

Arch User Repository (AUR)

Using an Arch based distro, you can use the wallust or wallust-git packages.

  • wallust fetches the latest stable version from static.crates.io. Prefer this package.
  • wallust-git fetches the latest unstable version from the master.

Either can be installed on an Arch based distro with the following commands:

git clone https://aur.archlinux.org/wallust.git # Or wallust-git.git
cd wallust # or wallust-git
makepkg -si

NetBSD

If you are using NetBSD, a native package is available from the official repositories. To install it, simply run:

pkgin install wallust

Nix

If you are using Nix, a native package is available.

Install it for your profile:

nix-env -iA nixos.wallust # change `nixos` for `nixpkgs`, if on a non-NixOS system

Try it with nix-shell

nix-shell -p wallust

Add the following Nix code to your NixOS Configuration, usually located in /etc/nixos/configuration.nix

  environment.systemPackages = [
    pkgs.wallust
  ];

If you are using flakes, you can directly use this repo to get the latest release:

First add this to your flake.nix

  inputs.wallust.url = "git+https://codeberg.org/explosion-mental/wallust?ref=master";

Then in your configuration.nix

  environment.systemPackages = [
    inputs.wallust.packages.${pkgs.system}.wallust
  ];

You can change ref to a tag version to get a stable release.

Building from source

Migration guide to v3

The last stable backwards compatible version is 2.10. V3 builds have the following breaking changes:

Cli

The usual, and shorter, wallust image.png, is deprecated. Instead, you should use wallust run image.png.

Regarding cli flags: --filter and -f will be replaced by --palette and -p, respectively.

wallust.toml

You can update your configuration file syntax with: wallust migrate

Old syntax:

[[entry]]
template = "zathurarc"
target = "~/.config/zathura/zathurarc"

[[entry]]
template = "dunst"
target = "~/.config/dunst/dunstrc"
...

New syntax:

[templates]
# usual dotted fields
dunst.template = 'dunstrc.monitor'
dunst.target = '~/.config/dunst/dunstrc'

# or inline
zathura = { template = 'zathura', target = '~/.config/zathura/zathurarc' }

# templated alias to src and target to dst
res.src = 'xres'
res.dst = '~/.config/Xresources'
res.pywal = true #enable pywal syntax

# inline with aliases, even more shorter!
glava = { src = 'glava/main.glsl', dst = '~/.config/glava/rc.glsl' }

# inline with pywal
test = { template = 'test.json', dst = '~/.config/complicated.json', pywal = true }

# directory usecase, all my pywal templates go here.
dir.template = "templates/"
dir.target = "~/.cache/wal/"
dir.pywal = true

This is a more shorter and simpler way. Inside the templates header, you can use the template and target attributes, also alias as src and dst respectively.

You can now declare directories as templates and targets non-recursively.

Deprecation of new_engine

The new_engine optional value has been stablished as the default engine and is no longer a valid variable. Now, if you want to enable pywal like syntax (meaning it's disabled by default), you do so by declaring pywal = true.

Rename filter -> palette

Just like with the cli, filter to palette rename has also affected the config:

Old syntax:

filter = dark16

New syntax:

palette = dark16

Templates

Following the name changes, variable name changes also have been applied: {{filter}} -> {{palette}}. Or, if pywal enabled, {filter} -> {palette}.

Variables has been reduced to the ones with no .method syntax like. This is because there has been included a runtime that can interpret filters. For example:

{{color0.rgb}}

is now written like:

{{color0 | rgb}}

In these lines, escaping {{ and }} has also changed, being avaliable literals as variables:

{{{{}}{{}}}}

is now written like:

{{ "{{}}" }}

To learn more about the new template syntax please read the man page man wallust.

Parameters

This is how to modify behaviour in wallust. Here you can find an explanation behind concepts that the program utilizes.

Alpha

Alpha value for templating (default: 100).

This value doesn't do anything other than represent the variable called alpha in templates. This is simply a left over of niche use cases.


To edit this value:

  • Config file: alpha = 50
  • Cli: wallust run image.png --alpha 50

Backend

Allows you to choose which method to use in order to parse the image.

BackendsDescription
FullRead and return the whole image pixels (more precision, slower)
ResizedResizes the image before parsing, mantaining it's aspect ratio
WalUses image magick convert to generate the colors, like pywal
ThumbFaster algo hardcoded to 512x512 (no ratio respected)
FastResizeA much faster resize algo that uses SIMD. For some reason it fails on some images where resized doesn't, for this reason it doesn't replace but rather it's a new option.
KmeansKmeans is an algo that divides and picks pixels all around the image, Requires more tweaking and more in depth testing but, for the most part, "it just werks".

To edit this value:

  • Config file: backend = "full"
  • Cli: wallust run image.png --backend full

Check Constrast

Ensures a "readable contrast". Should only be enabled when you notice an unreadable contrast frequently happening with your images. The reference color for the contrast is the background color. (default: disabled)


To edit this value:

  • Config file: check_contrast = true
  • Cli: wallust run image.png --check-contrast

color_space

What colorspace to use to gather the most prominent colors.

NameDescription
labUses Cie L a b color space. (mixed and ansi)
lchCIE Lch, you can understand this color space like LAB but with chrome and hue added, which Could help when sorting. (mixed)

There are two variants:

  • mixed, which mixes colors when collecting them into a histogram.
  • ansi, Tries to get a full color pallete similar to the one of a tty, this works best with ansidark palette.

Overview

Below, is a complete overview of all colorspaces variations:

Color SpaceDescription
LabUses Cie Lab color space
LabMixedVariant of lab that mixes the colors gathered, if not enough colors it fallbacks to usual lab (not recommended in small images)
LchCIE Lch, you can understand this color space like LAB but with chrome and hue added. Could help when sorting.
LchMixedCIE Lch, you can understand this color space like LAB but with chrome and hue added. Could help when sorting.
LchAnsiVariant of Lch which preserves 8 colors: black, red, green, yellow, blue, magenta, cyan and gray. This works best with 'darkansi' palette, allowing a constant color order.

To edit this value:

  • Config file: color_space = "lchmixed"
  • Cli: wallust run image.png --colorspace lchmixed

Fallback Generator

This field chooses a method to use when the gathered colors aren't enough:

NameDescription
interpolation(default) Tries to pick two colors and built gradients over them
complementaryUses the complementary colors of two colors, or more (if needed), colors.

To edit this value:

  • Config file: fallback_generator = "complementary"
  • Cli: wallust run image.png --fallback-generator complementary

Palette

Uses the colors gathered from color_space in a way that makes sense, resulting in a scheme palette.

NameDescription
ansidarkDark ansi colors, works best with lchansi and orders it's colors to preserve a constant tty like order: color0 -> black, color1 -> redish, color2 -> greenish, and so on.
darkDark colors dark background and light contrast. (16, comp, comp16)
harddarkSame as dark with hard hue colors. (16, comp, comp16)
lightLight bg dark fg. (16, comp, comp16)
softdarkVariant of softlight uses the lightest colors and a dark background could be interpreted as dark inversed. (16, comp, comp16)
softlightLight with soft pastel colors counterpart of harddark. (16, comp, comp16)

Palette Variations

There are some variants to the principal palettes schemes which you can use by appending the variant to the name e.g. 'dark16', 'lightcomp', 'harddarkcomp16' and so on, each palette indicates, in parenthesis, which variants are avaliable.

NameDescription
16Makes shades of colors, creating the ilusion of 16 different colors.
compStands for Complementary and completly changes the palette to it's complementary counterpart.
comp16Complementary palette with 16 shades, basically a combination of the above.

Overview

Below, is a complete overview of all palette schemes:

PaletteDescription
Dark8 dark colors, dark background and light contrast
Dark16Same as dark but uses the 16 colors trick
DarkCompThis is a dark variant that changes all colors to it's complementary counterpart, giving the feeling of a 'new palette' but that still makes sense with the image provided.
DarkComp1616 variation of the dark complementary variant
AnsiDarkThis is not a 'dark' variant, is a new palette that is meant to work with lchansi colorspace, which will maintain 'tty' like color order and only adjusting the colors acording to the theme. A possible solution for LS_COLORS and the like. Should workout with other colorspace, but the result may not be optimal.
HardDarkSame as dark with hard hue colors
HardDark16Harddark with 16 color variation
HardDarkCompcomplementary colors variation of harddark scheme
HardDarkComp16complementary colors variation of harddark scheme
LightLight bg, dark fg
Light16Same as light but uses the 16 color trick
LightCompcomplementary colors variation of light
LightComp16complementary colors variation of light with the 16 color variation
SoftDarkVariant of softlight, uses the lightest colors and a dark background (could be interpreted as dark inversed)
SoftDark16softdark with 16 color variation
SoftDarkCompcomplementary variation for softdark
SoftDarkComp16complementary variation for softdark with the 16 color variation
SoftLightLight with soft pastel colors, counterpart of harddark
SoftLight16softlight with 16 color variation
SoftLightCompsoftlight with complementary colors
SoftLightComp16softlight with complementary colors with 16 colors

To edit this value:

  • Config file: palette = darkcomp16
  • Cli: wallust run image.png --palette darkcomp16

Saturation

Color saturation, usually something higher than 50 increases the saturation and below decreases it (on a scheme with strong and vivid colors).

Possible values: 1 - 100 (default: disabled)


To edit this value:

  • Config file: saturate = 20
  • Cli: wallust run image.png --saturation 20

Threshold

Wallust automatically uses the best threshold, heuristically, if this variable isn't defined (default behaviour).

If you really want to define this variable, keep in mind the following. Thershold is the difference between similar colors , used inside the colorspace.

Each colorspace may have different results with different thresholds, meaning you should try which one works for you best.

An overall table looks like this:

NumberDescription
1Not Perceptible by human eyes.
1 - 2Perceptible through close observation.
2 - 10Perceptible at a glance.
11 - 49Colors are more similar than opposite.
100Colors are exact opposite.

To edit this value:

  • Config file: threshold = 10
  • Cli: wallust run image.png --threshold 18

Configuration File

While wallust can work out without a config file, it results useful to define constant options in a file than giving them each time as a cli flag. This is why all parameters are optional.

Without a config file, wallust will choose to default implementations, which are explained in detail in the parameters section.

That being said, you can start editing your config file.

Format

The chosen format for the config file is Tom's Obvious Minimal Language (TOML).

You can check the full specification here.

Structure

The config file is divided into two parts:

  • global space
  • templates space

Inside the global space you can define any parameter that you want.

To enter the templates space, however, requires a [templates] header. Below this, you can only define templates, which is explained in the next page.

Defining a template in the config file

Templates are optional and defined inside the [templates] header. Here it's recommended to use single quotes (') instead of double quotes (") since the first one, by the toml format, ignores backslashes (\) as escape codes, allowing you to define Widows like paths, e.g. 'C:\Users\Desktop\'.

template

A relative path that points to a file where wallust.toml is located, usually at ~/.config/wallust/templates. This file can also be a directory, which will be templated non-recursively (only the first recursion, like du ... --max-depth 1)

Check out templates section for more.

target

Absolute path in which to place a file with generated templated values. This field CAN expand the ~ as the $HOME enviromental variable. If template is a directory, this must correspond and be one.

pywal (optional)

Indicates to treat template as a pywal template, using {variable} syntax. (default: false)

This is mostly unstable.

While the implementation mostly works out, it isn't a garantee that it will work all the time. If you are making a new template, make sure you do it with the new syntax

Configuration Sample

Below is a simple example exahusting all possible cases (syntax wise) in the [templates] header. All the format is correct:

# Let's keep good old pywal look and feel
backend = "wal"
#color_space = "lch" # idc about this one..
#threshold = "20" # neither about this, since I read wallust does it automagically..
# classic look
palette = "dark16"
# let's keep the contrast very very very clear.
check_contrast = true

[templates]
# dunst templates
dunst.template = "dunstrc.monitor"
dunst.target = "~/.config/dunst/dunstrc"

# one liner for zathura
zathura = { template = 'zath', target = '~/.config/zathura/zathurarc' }

# even a shorter way
glava = { src = 'glava.glsl', dst = '~/.config/glava/rc.glsl' }

# or splited in the dotted syntax
res.src = "xres"
res.dst = "~/.config/Xresources"

# old times, good times, here I put old pywal templates. Seems unstable tho.
# NOTE THAT BOTH scr AND dst ARE DIRECTORIES!
pywal = { src = "templates/", dst = '~/.cache/wal/', pywal = true }

Templates

A template is simply a file that has placeholders in order to replace them with values. In wallust case, these values can range from either the colors generated, the image/theme served or the backend used. These values are represented by variables, which you can look up inside placeholders.

By using templates you can apply the colors to a program that uses a config file.

I've made some templates for some known programs at https://codeberg.org/explosion-mental/wallust-templates. If you have a template you want to share, that is the place.

Where?

The default templates directory is at CONFIG/wallust/templates, where CONFIG changes depending the platform wallust is ran at (e.g. $XDG_CONFIG_HOME in linux). Check out features section.

You can also change this in cli with --templates-dir.

Template Syntax

Here is an overview of the general syntax of a template.

You reference variables in the following syntax:

{{color0}}

For applying a filter you use the pipe character (|) like this:

{{background | strip}}

And if the filter requires an argument:

{{background | lighten(0.3)}}

Remember that filters require a valid type to apply to in these examples we are using colors, which can even be defined literally:

{{ "#4ff4ff" | lighten(0.3)}}

For both, being applied to or as an argument of a filter:

{{ color2 | blend("4ff4ff")}}

If you need to write a literal {{, that doesn't references any variable, you can write literals inside the delimiters:

{{ "{{" }} {{ "}}" }}

You can also use control flow expressions with {% %} delimiters:

{% if backend == "wal" %}
I am using the '{{backend}}' backend, getting a pywal like scheme.
{% elif backend == "fastresize" %}
This backend is called "{{palette}}" and, uses SIMD optimizations and is so fast!
{% else %}
I don't care about any other backends. Be happy!
{% endif %}

Or inline them:

{{ "I'm using the kmeans algo!" if backend == "kmeans" else "Some backend is in use" }}

Since mostly everything can be represented as a string (we've seen how colors are represented), indexing results very useful! The syntax for indexing is basically the Python one.

{# I'll hardcode a color based on the palette being used. #}
{% if palette[:4] == "dark" %}
somevariable = "#eeffbb"
{% else %}
somevariable = "#aabbee"
{% endif %}

And yes, you can comment inside your template, the comments won't be rendered in the final target file:

{# This won't be visible! #}

There are more control flow instructions, like the for loop:

{# This will generate color0 = .. to color18,
since `colors` contains background, foreground and cursor variables #}
{% for c in colors %}
color{{- loop.index }} = {{c-}}
{% endfor %}

You can add a minus sign (-) at the start or the end of the delimiters to supress vertical spacing (White space control with the minus sign -)

The syntax comes from the library being used, which is minijinja, a subset of the template engine 'Jinja2'.

You can read more at: Jinja2 official syntax and contrast features with the supported syntax at Compatibility of minijinja

Template Variables

The "color" type

These types are formated like as HEX rgb (e.g. '#0A0B0C') by default. However a color literal can be represented in multiple ways, like HEXA rgba (e.g. '#0A0B0CFF', where 'FF' is the transparency value) or HEX rgb without the leading '#' ('0a0b0c').

Avaliable values:

  • color0
  • color1
  • color2
  • color3
  • color4
  • color5
  • color6
  • color7
  • color8
  • color9
  • color10
  • color11
  • color12
  • color13
  • color14
  • color15
  • background
  • foreground
  • cursor

colors

Additionally, this variable (colors) returns a vector of all the presented colors in the following order:

Starts with color0 to color15, background, foreground and at the end, (index 18 if starting from 0), cursor.

MISCELLANEOUS

Other avaliable variables:

wallpaper

The full path to the current wallpaper, colorscheme file or the name of the theme in use.

backend

Current backend being used.

colorspace

Current colorspace being used.

palette

Current palette being used.

alpha

Default to 100, can be modified in the config file or with --alpha/-a.

alpha_dec

Instead of 0 to 100, displays it from 0.00 to 1.00.

Template Filters

The Jinja2 format calls them 'filters', making a distincion from 'functions'.

Currently I haven't implemented any function because I haven't found a usecase (yet?).

Filters that take an UNSIGNED INT

alpha_hexa

Displays alpha value as hexadecimal color code (e.g "{{ 100 | alpha_hexa }}" outputs 'FF'). This can only be used with numbers from 0 to 100, so you are free to use the variable alpha with this filter.

Filters that take the color type

Functions that only work with colors. These can be applied to a color, which can be the COLOR variables listed in "Variables" section, or a literal color like "#0A0B0C". These functions return a color in the mentioned format (hex rgb, like "#000000"), unless written otherwise (like rgb, rgba, the other filters that explicitly say it's output format). This allows to apply multiple filters at a time.

Note: If an 'alpha' value is mentioned, it's defined in the config file, as a cli flag and by default it's value is '100'.

hexa

Outputs the color in hexa format: e.g "#0A0B0CFF", where 'FF' is the alpha value. .

Note: This, internally uses alpha_hexa filter from above.

Example:

{{ color5 | hexa }}

rgb

Output the color in rgb, separated by comas. (e.g. "10,11,12")

xrgb

Output the color in xrgb, separated by slashes. (e.g "0A/0B/0C")

strip

Output the color in hex, just like by default, but removes the leading #. (e.g. "0A0B0C")

red

Outputs only the red value. (e.g. "10")

green

Outputs only the green value. (e.g. "11")

blue

Outputs only the blue value. (e.g. "12")

complementary

Returns the respective complementary color.

blend

Takes another color as input, to blend it for the filtered color.

Example:

{{ color2 | blend(color0) }}

lighten

Takes a float (decimal value) as input, from 0.1 to 1.0, that corresponds to the amount to lighten the color by.

Example:

{{ color0 | lighten(0.2) }}

darken

Takes a float (decimal value) as input, from 0.1 to 1.0, that corresponds to the amount to darken the color by.

saturate

Takes a float (decimal value) as input, from 0.1 to 1.0, that corresponds to the amount to saturate the color by.

Example

# zathurarc config sample
...

# colors
set default-bg     "{{background}}"
set default-fg     "{{foreground}}"

# make it a bit lighter than background
set statusbar-bg   "{{background | lighten(0.3)}}"

# make it darken by blending to a darken color
set statusbar-fg   "{{foreground | blend("#eeeeee")}}"

# use it's complementary
set inputbar-bg    "{{background | complementary}}"

Then you can add this file to ~/.config/wallust/templates and use the config file to template it. For example, zathura.template = 'zathurarc', and then define a target field, see config.

Pywal Template Compatibility

You can enable pywal like syntax in the config file with pywal = true. wallust (5)

The syntax is simple, but more variables are added given that it's engine and spec doesn't support runtime evaluation functions.

While the implementation is simple enough to be added in wallust, it's use is discoraged.

Syntax

The syntax logic is simply "Find and Replace" like:

somevariable = {color2}
anothervariable = {color8.rgb}

Don't forget to visit the full pywal spec

Variables

  • color0
  • color1
  • color2
  • color3
  • color4
  • color5
  • color6
  • color7
  • color8
  • color9
  • color10
  • color11
  • color12
  • color13
  • color14
  • color15
  • background
  • foreground
  • cursor

and it's variants, just append it to the variable name (e.g. color0.rgb, background.blue ...):

  • .rgb
  • .rgba
  • .xrgba
  • .strip
  • .red
  • .green
  • .blue

Miscellaneous variables below are also avaliable, these don't support the variants from above:

  • wallpaper
  • alpha
  • alpha_dec

Contribute!

Show some of your taste by adding a backend, colorspace, scheme palettes, and/or a custom theme.

Having design ideas or suggestios is also very welcome.

TODOs

Some food for thought.

  • wallust init, which will scan your system for common aplication in which there is an avaliable theme template at wallust-templates. If so, it will automatically fetch those templates, add it in your toml config and configure accorndingly. Make it interactive.

  • Allow to have more than 6 (MIN_COLS) passed to palettes. This requires some comunication to be exchanged between ColorSpace <-> Palette modules.

  • Learn more from "Material You" implementations, what I've seen is that it looses some colors and hues to mantain contrast.

  • Pulish code on colorspaces

  • Implement a 1 to 1 replica template engine for pywal (It seems that the pywal syntax for templating will remain standard)

For more, grep the src for TODO rg TODO

Packaging

Binary-based distros can grab the latest pre-compiled binary from the releases page.

Source-based distros, if they wish to build wallust from source, must ensure that the following dependencies are available:

  • Build Dependencies:
    1. Rust (cargo, rustc)
    2. make (or install man pages and completions manually)
  • Runtime Dependencies
    1. imagemagick is required only for the wal backend, such limiting should be mentined and considered an optional dependency, since all other backends work without it.

Makefile

Using make is optional if you know your way into cargo and can accept the job to manually install man pages, completions and the binary.

I've only added a Makefile to simplify installing these assets, as well as the binary. By default make uses native compilation, you can define your wished target like this:

Building

$ TARGET=x86_64-pc-windows-gnu make install CARGOFLAGS="--release --target=$TARGET"

Installing

# TARGET=x86_64-pc-windows-gnu make CARGOFLAGS="--release --target=$TARGET" RELEASE="target/$TARGET/release"

Don't forget that make by itself runs cargo in order to built the binary. It's common on projects that use make to split building in two steps, given that make install requires permissions to write on $DESTDIR$PREFIX.

helixoid

Zerogaku