Make it yours
wol-hue: themes from a picture
Turn a picture, a Base16 scheme or a colors.toml palette into an ordinary theme that always passes the contrast rules.
What it is
wol-hue reads a picture, picks its dominant and vivid colours, builds a palette in one of eight modes and writes it as a normal WolOS theme. It also imports Base16 and colors.toml palettes and saves looks you like.
Why
An average colour makes a muddy theme. Weighting by coverage and vividness, and moving anything unreadable until every contrast rule holds, gives a theme that looks like the picture and stays legible. Because the result is an ordinary theme, one writer restyles every app.
How
- From a picture:
wol-hue from-wallpaper ~/Pictures/dune.jpg(or Settings > Appearance > Theme from your wallpaper). You see a theme calledpicture-duneapplied to the whole desktop. - Adjust:
wol-hue adjust --temperature 20 --contrast 10moves the sliders on the active theme;--resetreturns. - Import a palette:
wol-hue import base16 scheme.yamlorwol-hue import colors colors.toml. - Keep a look:
wol-hue save "Desert day" --theme dune-day;wol-hue listshows saved ones.
If something goes wrong
| What you see | What to do |
|---|---|
| "The desktop picture couldn't be read. Choose another in Wallpaper." | The picture could not be decoded. Pick another. |
| A picture is refused | Pictures above 300 megapixels are refused; above 24 MP they are downscaled while reading. |
| The palette looks flat | Pictures with colour on under 6% of the frame get a grey or tinted ramp. Try another mode (--mode colorful, bright, pastel). |
| You want to undo | wol theme set <id> returns to any installed theme; Settings > Restore > Recent Changes has Undo. |
Related
Themes in every app · Plugin Maker and Theme Studio · Settings > Appearance
Reference
The theme maker from a picture. wol-hue turns a picture, or a palette from another tool, into an ordinary WolOS
theme: a folder $XDG_CONFIG_HOME/wolos/themes/<id>/ with theme.json (the 13 tokens, the 16
terminal colours and the wallpaper) and look.json (the colours before the sliders). It then
runs wol theme set <id>, the one path that restyles the shell and every app. It is a Crystal
program in hue/ (package wolos-hue, binary /usr/bin/wol-hue).
Why. ADR 0031 (themes v2) asks for theme-from-wallpaper that always passes the contrast
contract. A good palette needs more than an average colour: the picture's dominant colours by
coverage, vivid accents that a big muted background would drown, a background that really fills
the picture, and a separate path for grey and single-hue pictures. Writing a theme (and nothing
else) keeps one writer for app configuration: crates/core/src/theme/ renders GTK, Qt, compositor,
terminals and consoles from theme.json, so a picture theme looks exactly like a built-in one.
Crystal, because the lead chose it for this tool; no shards, only the standard library, gdk-pixbuf
(already on the desktop) for decoding and the TOML reader of wopkg/src/wopkg/toml.cr.
How it works
- Decode (
hue/src/hue/image.cr): gdk-pixbuf reads PNG, JPEG, WebP or AVIF (whatever loaders are installed). Above 24 MP the decoder downscales while reading (a 50 MP JPEG takes about 0.7 s end to end on the forge,spec/perf_spec.cr); above 300 MP the picture is refused. - Sample (
hue/src/hue/extract.cr): a Catmull-Rom downscale to 400 px on the long side, then every opaque pixel (alpha >= 128), with a step so at most ~50 000 are read. - Weight and quantise: pixels go to OKLab (published matrices); a pixel with OKLCH chroma above 0.04 gets 1 to 3 extra copies, graded over 0.16 of chroma; median cut in OKLab (lightness weighted 1.2x) splits the largest-volume box until 48 colours exist, sorted by pixel count.
Palette (
hue/src/hue/palette.cr), one of eight modes:Mode What it does normalMonochrome pictures (colour on under 6% of the frame, or one hue family) get a grey or tinted ramp; others keep their own accents, folded into hue bands that cover at least 2.5% of the picture monochromaticOne hue family around the picture's tint, slots kept apart by lightness analogousSix hues within 30 degrees of the most chromatic colour pastel,colorful,muted,brightThe picture's hues with the mode's lightness and chroma materialFixed neutral surfaces, accents tuned in HSL Background: the darkest (light themes: lightest) of the 12 most common colours, nudged by coverage (weight 0.6) and replaced when it is too mid-toned. Foreground: the opposite extreme, aiming at 7:1 contrast and never under 4.5:1. Accents 1-6 are matched to the red, green, yellow, blue, magenta and cyan hues by a global greedy assignment, then every accent is lifted to 4.5:1 against the background.
- Tokens (
hue/src/hue/theme.cr): surface from colour 0, text from 7, accent from 4, success/warning/danger from 2/3/1, the rest mixed.Theme.checkis the rule set ofshared::theme::validate(crates/shared/src/theme.rs); a background that cannot carry readable text is moved toward black or white until every rule holds. - Cache (
hue/src/hue/engine.cr):$XDG_CACHE_HOME/wolos/hue/<sha256>-<variant>-<mode>-v1.json, keyed by the file's content.
Commands
wol-hue from-wallpaper ~/Pictures/dune.jpg # dark, normal: theme picture-dune
wol-hue from-wallpaper dune.jpg --light --mode pastel --id dune-day
wol-hue adjust --temperature 20 --contrast 10 # the active theme; sliders are positions
wol-hue adjust dune-day --reset
wol-hue import base16 ~/schemes/ocean.yaml # classic or palette: form
wol-hue import colors ~/theme/colors.toml --wallpaper ~/Pictures/sea.png
wol-hue save "Desert day" --theme dune-day # $XDG_DATA_HOME/wolos/hue/looks/
wol-hue list
wol-hue apply "Desert day" # theme look-desert-day
--no-apply writes the folder without switching; --json prints the theme with dir, mode,
applied (and cached for pictures); --no-cache re-reads the picture. The twelve sliders and
their ranges: vibrance, temperature, tint, shadows, highlights -50..50; saturation -100..100;
contrast, brightness, black point, white point -30..30; hue shift -180..180; gamma 0.5..2. They run
in a fixed order in HSL (Color.adjust). Exit codes: 0 done, 1 failed (message says what), 2 usage.
Theme ids are a-z, 0-9 and - (64 at most), so a name from outside never leaves the themes
folder. The tool writes only its theme folder, its cache and its looks.
Tests
make -C hue spec (forge: cd wolos/hue && make && make spec): colour maths, the engine's unit
cases, every mode and variant on ten scenes drawn in code (spec/support/scenes.cr), the contrast
contract for all of them, Base16 and colors.toml import, the binary end to end with a stand-in
wol, and the 50 MP timing. spec/fixtures/golden.json holds 60 palettes (10 scenes x dark/light
x normal, monochromatic, pastel); make golden re-records it after a deliberate engine change
(bump Engine::CACHE_VERSION with it). crystal tool format --check src spec is clean.
Ported code: color.cr, extract.cr, palette.cr and imports.cr are MIT (see
THIRD-PARTY.md); the rest is GPL-2.0-or-later. The reference engine's
OKLab matrix has a wrong third row; Color.legacy_lms = true reproduces it only to compare against
palettes recorded with it.
Reference synced from wonderlandos/wolos docs/modules/hue.md.