Files
omarchy-ash-theme/tools/ash-wallpaper.md
T

189 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# `ash-wallpaper.sh` — guide
Turns a color photo into an **Ash** wallpaper: the image is reduced to
Ash-tinted greys, while warm *ember/gold* highlights (sunsets, fire, lamps,
skin tones) are selectively kept — the "Pleasantville" effect.
## Quick start
```sh
tools/ash-wallpaper.sh photo.jpg # -> photo-ash-dark.png AND photo-ash-light.png
DARK=1 tools/ash-wallpaper.sh photo.jpg # only the dark variant
LIGHT=1 tools/ash-wallpaper.sh photo.jpg # only the light variant
```
Requirements: ImageMagick 6.9+ or 7 (`convert` / `magick`). 4K input takes ~10s
per run (the mask is computed once, both variants share it).
All knobs are environment variables read once per run — tune one, rerun,
compare.
## How it works
1. **Hue band** — the photo's HSL hue channel is thresholded: pixels with
`hue ≤ HUE_MAX` or `hue ≥ HUE_MIN` form the "warm" band (reds, oranges,
golds; the wrap-around at HUE_MIN catches pure crimson reds).
2. **Saturation gate** — inside that band, a saturation ramp decides how much
of the pixel survives: nothing below `SAT_MIN`, everything from `SAT_MAX`.
This is what keeps dull, near-grey warmish pixels as ash.
3. **Softening** — the combined mask is blurred, then re-sharpened with
`SENSITIVITY` so highlights fade into the greys instead of showing hard
cut-out edges.
4. **Base** — a desaturated copy is tinted along the Ash grey ramp
(`BASE_LO` shadows → `BASE_HI` highlights).
5. **Composite** — the original photo, with saturation multiplied by
`EMBER_BOOST`, is laid over the base through the mask.
## Parameters
| Variable | Default | Meaning |
|---|---|---|
| `DARK` / `LIGHT` | off | Set to `1` to render **only** that variant. Without them, both are written. |
| `HUE_MAX` | `13%` | Upper edge of the warm band, in percent of the hue circle (360°). `13%` ≈ 47°, so reds, orange, ember and gold survive; yellows from ≈47° and all greens/blues fall out. |
| `HUE_MIN` | `94%` | Lower edge of the wrap-around band (`≥ 338°`). Catches deep crimson/cherry reds whose hue sits just below 360°. |
| `SAT_MIN` | `12%` | Saturation (HSL) below which a pixel becomes full grey, no matter its hue. Raise to make the image more monochrome (e.g. muted/desaturated photos: `1825%`). |
| `SAT_MAX` | `45%` | Saturation at which the highlight is fully kept. Pastel skies/candle-lit scenes peak below 45% — lower it (`2535%`) to let soft colour through; raise it (`5570%`) to keep only the most saturated embers. |
| `SENSITIVITY` | `8x45%` | `-sigmoidal-contrast` applied to the mask: `contrast x midpoint`. Higher contrast → crisper, more cut-out-looking highlights; lower (e.g. `3x50%`) → dreamier, feathered bleed. The midpoint shifts the whole mask: `>50%` = only the most certain warm pixels, `<50%` = more generous. |
| `EMBER_BOOST` | `130` | Saturation multiplier (%) on the surviving pixels, so the remaining embers read against all that ash. `100` = untouched colours, `160+` = intense glow. Applied to *all* channels of those pixels, so already-saturated fire can clip — reduce if it looks neon. |
| `BASE_LO` / `BASE_HI` | preset ramps | Exact endpoints of the grey ramp (dark: `#100f12 → #f3ede1`, light: `#b7ae98 → #f2ecdf`). Any colour works, e.g. `BASE_LO=#1c1b1f BASE_HI=#e6dfd1` for a flatter panel→bone ramp. |
### Where the Ash palette sits in the hue wheel
For reference when widening/narrowing the band (hue in IM percent ≈ degrees/360):
| Colour | Hex | Hue | In band at defaults? |
|---|---|---|---|
| blood | `#c15c46` | 11° (3%) | ✅ |
| rust | `#a86a48` | 21° (6%) | ✅ |
| ember | `#e0914f` | 27° (8%) | ✅ |
| gold | `#d6b46a` | 41° (11%) | ✅ |
| pure yellow | — | 60° (17%) | ❌ (needs `HUE_MAX=17%`) |
| moss | `#8f9a5c` | 69° (19%) | ❌ |
| steel | `#7c9aa1` | 187° (52%) | ❌ |
| rot | `#b47e99` | 330° (92%) | ❌ (needs `HUE_MIN=88%` — usually you *don't* want this) |
| violet | `#a585ac` | 292° (81%) | ❌ |
## Samples
Freely-licensed photos from Wikimedia Commons, run through the script (900 px
previews). Each entry lists the exact command; both variants come from a
single run.
### Sunset over the sea
```sh
tools/ash-wallpaper.sh sunset.jpg
```
| Dark | Light |
|---|---|
| ![sunset dark](../images/samples/ash-sunset-dark.jpg) | ![sunset light](../images/samples/ash-sunset-light.jpg) |
Source: [“Leigh-on-Sea beach sunset (Unsplash)”](https://commons.wikimedia.org/wiki/File:Leigh-on-Sea_beach_sunset_(Unsplash).jpg)
by Joshua Fuller, CC0 — no attribution required, given anyway.
### Campfire close-up
```sh
tools/ash-wallpaper.sh campfire.jpg
```
| Dark | Light |
|---|---|
| ![campfire dark](../images/samples/ash-campfire-dark.jpg) | ![campfire light](../images/samples/ash-campfire-light.jpg) |
Source: [“Closeup of raging flames in a large bonfire”](https://commons.wikimedia.org/wiki/File:Closeup_of_raging_flames_in_a_large_bonfire._-_Flickr_-_shixart1985.jpg)
by Nenad Stojkovic, [CC BY 2.0](https://creativecommons.org/licenses/by/2.0/).
### Autumn foliage
```sh
tools/ash-wallpaper.sh autumn.jpg
```
| Dark | Light |
|---|---|
| ![autumn dark](../images/samples/ash-autumn-dark.jpg) | ![autumn light](../images/samples/ash-autumn-light.jpg) |
Source: [“Münster, Park Sentmaring 2015 9923”](https://commons.wikimedia.org/wiki/File:M%C3%BCnster,_Park_Sentmaring_--_2015_--_9923.jpg)
by Dietmar Rabich, [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/).
### City at night (ISS)
Street lamps glow soft yellow — the wide-band + soft-gate recipe from below:
```sh
HUE_MAX=17% SAT_MIN=8% SAT_MAX=60% SENSITIVITY=4x50% \
tools/ash-wallpaper.sh city.jpg
```
| Dark | Light |
|---|---|
| ![city dark](../images/samples/ash-city-dark.jpg) | ![city light](../images/samples/ash-city-light.jpg) |
Source: [“Windy City of Lights (ISS070-E-105097)”](https://commons.wikimedia.org/wiki/File:Windy_City_of_Lights_(153622).jpg),
astronaut photograph, NASA/JSC Crew Earth Observations — public domain.
### Redhead portrait
Only hair and lips keep their colour; skin stays close to bone:
```sh
SAT_MIN=18% EMBER_BOOST=150 tools/ash-wallpaper.sh portrait.jpg
```
| Dark | Light |
|---|---|
| ![portrait dark](../images/samples/ash-redhead-dark.jpg) | ![portrait light](../images/samples/ash-redhead-light.jpg) |
Source: [“Woman redhead natural portrait 1”](https://commons.wikimedia.org/wiki/File:Woman_redhead_natural_portrait_1.jpg)
by dusdin (Flickr), cropped by Gridge, [CC BY 2.0](https://creativecommons.org/licenses/by/2.0/).
## Recipes
```sh
# Warm sunset landscape, keep the drama (writes BOTH dark and light)
tools/ash-wallpaper.sh sunset.jpg
# Night city: street lamps are soft yellow-orange, need a wider + softer gate
HUE_MAX=17% SAT_MIN=8% SAT_MAX=60% SENSITIVITY=4x50% tools/ash-wallpaper.sh city.jpg
# Portrait: only eyes/lips/warm skin glow, everything else ash
SAT_MIN=18% EMBER_BOOST=150 tools/ash-wallpaper.sh portrait.jpg
# Almost pure grey with faint traces of ember
SAT_MIN=20% SAT_MAX=70% EMBER_BOOST=100 tools/ash-wallpaper.sh photo.jpg
# Light-themed desktop
LIGHT=1 tools/ash-wallpaper.sh beach.jpg
```
## Batch generation
```sh
for f in ~/Pictures/vacation/*.jpg; do
tools/ash-wallpaper.sh "$f"
done
```
## Using the results
Drop the generated files into the theme or user backgrounds folder — Omarchy
cycles through them with `Super+Ctrl+Space`:
```sh
mkdir -p ~/.config/omarchy/backgrounds/ash-dark
cp photo-ash-dark.png photo-ash-light.png ~/.config/omarchy/backgrounds/ash-dark/
```
## Troubleshooting
- **Highlights cut with hard edges** → lower the `SENSITIVITY` contrast
(first number), e.g. `4x45%`.
- **A warm object disappears** → its hue is outside the band (check the table
above) or its saturation is below `SAT_MIN`.
- **Grey areas look slightly tinted/brown** → those pixels are just inside the
band; raise `SAT_MIN`.
- **Fire/embers look clipped and neon** → lower `EMBER_BOOST` towards 100.
- **Image too bright/dark after tinting** → adjust `BASE_LO`/`BASE_HI` instead
of editing the photo.