13 KiB
ash-wallpaper.sh — guide
Turns a color photo into an Ash wallpaper: the image is reduced to Ash-tinted greys (dark variant), while warm ember/gold highlights (sunsets, fire, lamps, skin tones) are selectively kept — the "Pleasantville" effect.
Quick start
tools/ash-wallpaper.sh photo.jpg # -> photo-ash.png
tools/ash-wallpaper.sh photo.jpg out.png # custom output path
Be realistic about the defaults. This is a ~50-line ImageMagick script, not an AI — it applies one fixed rule (keep warm, high-saturation pixels; ash everything else) to your photo. The default settings are tuned for the classic cases (fire, sunsets, lamps). For anything else, expect to tune: the samples below were all post-processed in 2–3 iterations of
HUE_MAX/SAT_MIN/SAT_MAX. A motif with little warm colour (e.g. a whale) simply has little to keep — no parameter will invent highlights that aren't in the source.
Requirements: ImageMagick 6.9+ or 7 (convert / magick). 4K input takes ~10s.
All knobs are environment variables read once per run — tune one, rerun,
compare.
How it works
- Hue band — the photo's HSL hue channel is thresholded: pixels with
hue ≤ HUE_MAXorhue ≥ HUE_MINform the "warm" band (reds, oranges, golds; the wrap-around at HUE_MIN catches pure crimson reds). - Saturation gate — inside that band, a saturation ramp decides how much
of the pixel survives: nothing below
SAT_MIN, everything fromSAT_MAX. This is what keeps dull, near-grey warmish pixels as ash. - Softening — the combined mask is blurred, then re-sharpened with
SENSITIVITYso highlights fade into the greys instead of showing hard cut-out edges. - Base — a desaturated copy is tinted along the Ash dark ramp
(
BASE_LOshadows →BASE_HIhighlights, default void → chalk). - Composite — the original photo, with saturation multiplied by
EMBER_BOOST, is laid over the base through the mask.
Parameters
| Variable | Default | Meaning |
|---|---|---|
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: 18–25%). |
SAT_MAX |
45% |
Saturation at which the highlight is fully kept. Pastel skies/candle-lit scenes peak below 45% — lower it (25–35%) to let soft colour through; raise it (55–70%) 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 |
#100f12 / #f3ede1 |
Endpoints of the grey ramp (void → chalk). Any colours work, 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; the originals are shown for comparison and credit.
Sunset over the sea
tools/ash-wallpaper.sh sunset.jpg
| Original | Ash |
|---|---|
![]() |
![]() |
Source: “Leigh-on-Sea beach sunset (Unsplash)” by Joshua Fuller, CC0.
Campfire close-up
tools/ash-wallpaper.sh campfire.jpg
| Original | Ash |
|---|---|
![]() |
![]() |
Source: “Closeup of raging flames in a large bonfire” by Nenad Stojkovic, CC BY 2.0.
Autumn foliage — warm-dominated scene
The whole park is bathed in warm orange, so ~90 % of the frame is "warm":
like the fireworks case below, the result stays close to the original. Narrow
the band (HUE_MAX=8%) to let only the saturated ember oranges through:
tools/ash-wallpaper.sh autumn.jpg
| Original | Ash |
|---|---|
![]() |
![]() |
Source: “Münster, Park Sentmaring – 2015 – 9923” by Dietmar Rabich, CC BY-SA 4.0.
City at night (ISS)
Street lamps glow soft yellow — the wide-band + soft-gate recipe from below:
HUE_MAX=17% SAT_MIN=8% SAT_MAX=60% SENSITIVITY=4x50% \
tools/ash-wallpaper.sh city.jpg
| Original | Ash |
|---|---|
![]() |
![]() |
Source: “Windy City of Lights (ISS070-E-105097)”, astronaut photograph, NASA/JSC Crew Earth Observations — public domain.
Redhead portrait
Only hair and lips keep their colour; skin stays close to bone:
SAT_MIN=18% EMBER_BOOST=150 tools/ash-wallpaper.sh portrait.jpg
| Original | Ash |
|---|---|
![]() |
![]() |
Source: “Woman redhead natural portrait 1” by dusdin (Flickr), cropped by Gridge, CC BY 2.0.
Candle light
A dark frame with a warm source — the ideal case; the flame and its glow stay, everything else turns to ash:
EMBER_BOOST=120 tools/ash-wallpaper.sh candles.jpg
| Original | Ash |
|---|---|
![]() |
![]() |
Source: “Alive” by Ranit Sanyal, CC BY 3.0.
Fairground at night
Neon rides: the white structure greys out, the warm cabin lighting and the red LED strips survive. Uses the night recipe:
HUE_MAX=17% SAT_MIN=8% SAT_MAX=60% SENSITIVITY=4x50% \
tools/ash-wallpaper.sh kirmes.jpg
| Original | Ash |
|---|---|
![]() |
![]() |
Source: “Nighttime ferris wheel gondolas … Pattaya fairground” by PattayaPatrol, CC BY-SA 4.0.
Rainy night in Moscow
Red neon and traffic-light reflections are all the colour left — the same night recipe as above:
HUE_MAX=17% SAT_MIN=8% SAT_MAX=60% SENSITIVITY=4x50% \
tools/ash-wallpaper.sh rain.jpg
| Original | Ash |
|---|---|
![]() |
![]() |
Source: “Late autumn rainy night in Moscow” by kishjar?, CC BY 4.0.
Humpback whale — the low-highlight case
A daylight scene with almost no warm colour: only 0.4 % of the frame sits in the warm band, so the result is (intentionally) almost fully grey. Nothing is broken — there is simply little for the script to keep:
tools/ash-wallpaper.sh whale.jpg
| Original | Ash |
|---|---|
![]() |
![]() |
Source: “Humpback Breaching” by NOAA National Marine Sanctuaries — public domain.
Fireworks — the negative case
Here the whole sky is lit red by smoke, so 96 % of the pixels are "warm" and
the mask covers everything: the image is barely greyscaled at all. When the
warm colour is the background rather than an accent, the effect has nothing to
work with. Pick a different shot, or narrow the band (HUE_MAX=8%) to keep
only the brightest sparks:
tools/ash-wallpaper.sh fireworks.jpg
| Original | Ash |
|---|---|
![]() |
![]() |
Source: “Anjuna Beach, Goa, New Year's Eve, Fireworks in the sky” by Vyacheslav Argenberg, CC BY 4.0.
How much of each frame survived
The share of pixels the warmth mask keeps (measured with the default gate; the night-recipe samples were run with a wider band). A quick way to read the samples above, and a useful sanity check when tuning your own photo:
| Motif | Warm-pixel share (default) | Result |
|---|---|---|
| Humpback whale | 0.4 % | almost fully ash |
| Fairground | 4.2 % | ash with neon accents |
| City at night (ISS) | 17.0 % | ash with a glowing street grid |
| Rainy night Moscow | 17.2 % | ash with red neon |
| Sunset | 19.6 % | ash with a warm horizon |
| Campfire | 40.6 % | dark ash, glowing flames |
| Redhead portrait | 47.1 % | ash with warm hair/lips |
| Candle light | 73.2 % | dark ash with a glowing flame |
| Autumn foliage | 90.0 % | barely greyed — warm is the scene |
| Fireworks | 96.4 % | barely greyed — warm is the scene |
Rule of thumb: below ~25 % the effect is pronounced; above ~70 % the script
has little to grey out and you should narrow HUE_MAX or pick another frame.
Recipes
# Warm sunset landscape, keep the drama
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
# Flatter, dimmer base ramp
BASE_LO=#1c1b1f BASE_HI=#e6dfd1 tools/ash-wallpaper.sh photo.jpg
Batch generation
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:
mkdir -p ~/.config/omarchy/backgrounds/ash-dark
cp photo-ash.png ~/.config/omarchy/backgrounds/ash-dark/
Troubleshooting
- Highlights cut with hard edges → lower the
SENSITIVITYcontrast (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_BOOSTtowards 100. - Image too bright/dark after tinting → adjust
BASE_LO/BASE_HIinstead of editing the photo.



















