quickshell: accent keeps its punch, only its hue is corrected

Targeting a fixed saturation was the wrong variable. The generator gets
the accent's STRENGTH right — it scales it to the palette, so a cyan
scheme whose base05 is 55ffff wants a vivid accent and one whose base05
is the cream f1e2b6 wants a quiet one. Forcing S=0.60 is what made the
amber bar shout with a sharp orange logo in a row of muted cream.

What the generator gets wrong is the HUE: it fills each slot
independently, so on wallhaven-5y39p9 every accent slot comes back
orange except base0D, which comes back blue-grey. Accent now takes the
hue from whichever slot carries the most chroma and keeps base0D's own
saturation and lightness. 5y39p9 becomes a muted tan; k8dqr6 goes back
to its rose instead of the coral the last rule picked; the rest are
unchanged or nudged a few degrees.

Wallpaper button idles at base05 like every other opener in the column,
instead of being the one dim icon that brightened on hover.
This commit is contained in:
rope 2026-08-30 17:07:04 +01:00
parent 33f419c658
commit bd320a34d9

View file

@ -572,32 +572,41 @@ in
// and every status colour below is harmonised toward it, so a // and every status colour below is harmonised toward it, so a
// bad pick tints the whole bar rather than just the highlights. // bad pick tints the whole bar rather than just the highlights.
// //
// NOT pal.base0D on its own. The generator fills each slot // Two things have to be right, and the generator only gets one
// independently and is free to hand that one a colour from // of them wrong at a time:
// outside the rest of the palette's family: on the amber
// wallhaven-5y39p9 every accent slot comes back orange
// (H=0.08) except base0D, which comes back blue-grey (8590ae,
// H=0.62) that was a blue NixOS logo in an otherwise amber
// bar. So audition all six and take whichever sits nearest a
// good accent saturation.
// //
// Nearest 0.6, not "the most saturated": max picks the neon // HUE it fills each slot independently and can hand base0D a
// fe5162 (S=0.99) on wallhaven-k8dqr6, near enough to `err` // colour from outside the rest of the palette's family. On the
// that errors stop reading as errors. On a monochrome // amber wallhaven-5y39p9 every other accent slot comes back
// wallpaper every slot collapses to the same value, so the // orange (H=0.08) while base0D comes back blue-grey (8590ae,
// choice stops mattering rather than going wrong. // H=0.62): a blue NixOS logo in an amber bar. So the hue is
readonly property real accentSat: 0.60 // taken from whichever slot carries the most chroma, which is
// the one actually holding the wallpaper's colour.
//
// STRENGTH how loud the accent is against the ink. That the
// generator gets right, because it scales it to the palette:
// a cyan scheme whose base05 is 55ffff wants a vivid accent,
// and one whose base05 is the cream f1e2b6 wants a quiet one.
// Overriding it with a fixed target made that amber bar shout.
// So saturation and lightness stay base0D's own.
//
// Net effect: base0D's punch, corrected onto the palette's hue.
// Where base0D is already the carrier the accent is unchanged.
readonly property color accent: { readonly property color accent: {
const slots = [pal.base09, pal.base0A, pal.base0B, const slots = [pal.base09, pal.base0A, pal.base0B,
pal.base0C, pal.base0D, pal.base0E]; pal.base0C, pal.base0D, pal.base0E];
let best = Qt.color("#" + pal.base0D); let carrier = Qt.color("#" + pal.base0D);
let bestD = Math.abs(best.hslSaturation - accentSat); let best = -1;
for (let i = 0; i < slots.length; i++) { for (let i = 0; i < slots.length; i++) {
const c = Qt.color("#" + slots[i]); const c = Qt.color("#" + slots[i]);
const d = Math.abs(c.hslSaturation - accentSat); // Chroma, not hslSaturation: saturation reads high for
if (d < bestD) { best = c; bestD = d; } // a pale wash, and a wash is exactly what has no hue
// worth trusting.
const ch = Math.max(c.r, c.g, c.b) - Math.min(c.r, c.g, c.b);
if (ch > best) { best = ch; carrier = c; }
} }
return best; const base = Qt.color("#" + pal.base0D);
return Qt.hsla(carrier.hslHue, base.hslSaturation, base.hslLightness, 1);
} }
// Status colours: fixed hues, pulled toward the theme. // Status colours: fixed hues, pulled toward the theme.
@ -4205,9 +4214,13 @@ in
anchors.centerIn: parent anchors.centerIn: parent
text: "image" text: "image"
font.pixelSize: 18 font.pixelSize: 18
color: bar.activeDropdown === wallDropdown ? Theme.accent // base05 flat, like every other opener in the
: wallMa.containsMouse ? Theme.base05 : Theme.base04 // column. It used to idle at base04 and brighten on
Behavior on color { ColorAnimation { duration: Theme.animFade } } // hover, which made it the one dim icon in a row of
// bright ones; and no other opener accents itself
// while its dropdown is up, because the open panel
// already says which one it is.
color: Theme.base05
} }
MouseArea { MouseArea {