ink ladder: base03/base04 derive from base05, shared with hyprland
base03/base04/base05 were three independent slots off the wallpaper, not one ink at three strengths. On wallhaven-k8dqr6 the raw ladder is red, blue and cream; on 5y39p9 base03 is a saturated gold against pale cream. That is why muted labels read as a second accent and why the shell frame never quite matched the window border beside it. base04 and base03 are now base05 mixed toward base00. The two factors and the mix live in settings/ui.nix and are used by all three consumers: Theme.qml, theming.nix's hypr.lua (applied at runtime) and hyprland.nix's build-time fallback. Same trick base01/base02 already used for surfaces. Verified on 5y39p9: hypr.lua now emits aca888 / 727761 from base05 f1e2b6 against base00 0a1f1c, matching what inkStep computes in the shell.
This commit is contained in:
parent
1dc6886b56
commit
b5372d46f3
4 changed files with 78 additions and 15 deletions
|
|
@ -101,6 +101,13 @@ in
|
||||||
c = config.lib.stylix.colors;
|
c = config.lib.stylix.colors;
|
||||||
rgb = hex: "rgb(${hex})";
|
rgb = hex: "rgb(${hex})";
|
||||||
rgba = hex: a: "rgba(${hex}${a})";
|
rgba = hex: a: "rgba(${hex}${a})";
|
||||||
|
# Build-time fallback for the border colours, until theme-apply first
|
||||||
|
# runs and hyprctl-evals the theme's own hypr.lua. Same two mixes as
|
||||||
|
# settings/theming.nix and quickshell's Theme.qml — see ui.nix. Not
|
||||||
|
# c.base04/c.base03: those are independent slots off the wallpaper and
|
||||||
|
# land in unrelated hues from the ink the shell frame is drawn in.
|
||||||
|
ink4 = ui.mixHex c.base05 c.base00 ui.inkMuted;
|
||||||
|
ink3 = ui.mixHex c.base05 c.base00 ui.inkFaint;
|
||||||
in {
|
in {
|
||||||
# Stylix's Hyprland target injects settings.{general,decoration,group,misc}
|
# Stylix's Hyprland target injects settings.{general,decoration,group,misc}
|
||||||
# as top-level keys, which render as hl.general()/hl.decoration()/… in Lua
|
# as top-level keys, which render as hl.general()/hl.decoration()/… in Lua
|
||||||
|
|
@ -149,8 +156,8 @@ in
|
||||||
# any palette. NOT base0D — a wallpaper-derived scheme can hand
|
# any palette. NOT base0D — a wallpaper-derived scheme can hand
|
||||||
# base0D and base03 the same value (this one does: both 3fa8ab),
|
# base0D and base03 the same value (this one does: both 3fa8ab),
|
||||||
# which left active and inactive windows indistinguishable.
|
# which left active and inactive windows indistinguishable.
|
||||||
"col.active_border" = rgb c.base04;
|
"col.active_border" = rgb ink4;
|
||||||
"col.inactive_border" = rgb c.base03;
|
"col.inactive_border" = rgb ink3;
|
||||||
};
|
};
|
||||||
|
|
||||||
decoration = {
|
decoration = {
|
||||||
|
|
@ -169,13 +176,13 @@ in
|
||||||
|
|
||||||
group = {
|
group = {
|
||||||
# Same base04/base03 ramp as general.col.* above.
|
# Same base04/base03 ramp as general.col.* above.
|
||||||
"col.border_active" = rgb c.base04;
|
"col.border_active" = rgb ink4;
|
||||||
"col.border_inactive" = rgb c.base03;
|
"col.border_inactive" = rgb ink3;
|
||||||
"col.border_locked_active" = rgb c.base05;
|
"col.border_locked_active" = rgb c.base05;
|
||||||
groupbar = {
|
groupbar = {
|
||||||
text_color = rgb c.base05;
|
text_color = rgb c.base05;
|
||||||
"col.active" = rgb c.base04;
|
"col.active" = rgb ink4;
|
||||||
"col.inactive" = rgb c.base03;
|
"col.inactive" = rgb ink3;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -563,11 +563,26 @@ in
|
||||||
readonly property color base00: "#" + pal.base00
|
readonly property color base00: "#" + pal.base00
|
||||||
readonly property color base01: Qt.lighter(base00, 1.7) // card
|
readonly property color base01: Qt.lighter(base00, 1.7) // card
|
||||||
readonly property color base02: Qt.lighter(base00, 2.4) // hover / chip / track
|
readonly property color base02: Qt.lighter(base00, 2.4) // hover / chip / track
|
||||||
// ── Ink, wallpaper-derived: base05 primary, base04 muted,
|
// ── Ink: ONE colour at three strengths. base05 is the
|
||||||
// base03 disabled (also the border colour).
|
// wallpaper's ink; base04 and base03 are that same colour mixed
|
||||||
readonly property color base03: "#" + pal.base03
|
// toward base00 — not stylix's own base03/base04, which are
|
||||||
readonly property color base04: "#" + pal.base04
|
// independent slots off the image and land in unrelated hues.
|
||||||
|
// On wallhaven-k8dqr6 the raw ladder is red (base03), blue
|
||||||
|
// (base04) and cream (base05): three colours for one ramp, so
|
||||||
|
// a muted label read as a second accent rather than as quieter
|
||||||
|
// text. Same reasoning as base01/base02 above.
|
||||||
|
//
|
||||||
|
// The two mixes live in settings/ui.nix and are used verbatim
|
||||||
|
// by settings/theming.nix for hyprland's window borders, so the
|
||||||
|
// shell frame and the window borders stay the same colour.
|
||||||
readonly property color base05: "#" + pal.base05
|
readonly property color base05: "#" + pal.base05
|
||||||
|
function inkStep(t) {
|
||||||
|
return Qt.rgba(base05.r + (base00.r - base05.r) * t,
|
||||||
|
base05.g + (base00.g - base05.g) * t,
|
||||||
|
base05.b + (base00.b - base05.b) * t, 1);
|
||||||
|
}
|
||||||
|
readonly property color base04: inkStep(${toString ui.inkMuted})
|
||||||
|
readonly property color base03: inkStep(${toString ui.inkFaint})
|
||||||
// The one themed accent: active, focused, selected, filled —
|
// The one themed accent: active, focused, selected, filled —
|
||||||
// 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.
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
# target not listed here — walls/wallpaper.png remains its image.
|
# target not listed here — walls/wallpaper.png remains its image.
|
||||||
{ config, pkgs, lib, inputs, ... }:
|
{ config, pkgs, lib, inputs, ... }:
|
||||||
let
|
let
|
||||||
|
ui = import ./ui.nix; # shared ink ladder (inkMuted / inkFaint / mixHex)
|
||||||
isDesktop = lib.elem config.networking.hostName [ "FredOS-Gaming" "FredOS-Macbook" ];
|
isDesktop = lib.elem config.networking.hostName [ "FredOS-Gaming" "FredOS-Macbook" ];
|
||||||
homeDir = "/home/fred";
|
homeDir = "/home/fred";
|
||||||
stateLink = "${homeDir}/.local/state/quickshell-theme";
|
stateLink = "${homeDir}/.local/state/quickshell-theme";
|
||||||
|
|
@ -282,14 +283,21 @@ let
|
||||||
#
|
#
|
||||||
# One line, not pretty-printed: hyprctl joins its argv into the request
|
# One line, not pretty-printed: hyprctl joins its argv into the request
|
||||||
# string, so keeping the payload free of newlines keeps it intact.
|
# string, so keeping the payload free of newlines keeps it intact.
|
||||||
hyprLua = s: pkgs.writeText "hypr.lua" ("hl.config({" + lib.concatStringsSep "," [
|
# Borders take the DERIVED ink, not s.base04/s.base03 — quickshell's
|
||||||
''general={["col.active_border"]="rgb(${s.base04})",["col.inactive_border"]="rgb(${s.base03})"}''
|
# Theme.qml runs the same two mixes, and the shell frame sits directly
|
||||||
|
# against these borders. Reading the raw slots here is what left the two
|
||||||
|
# outlines a visible shade apart.
|
||||||
|
hyprLua = s: let
|
||||||
|
ink4 = ui.mixHex s.base05 s.base00 ui.inkMuted;
|
||||||
|
ink3 = ui.mixHex s.base05 s.base00 ui.inkFaint;
|
||||||
|
in pkgs.writeText "hypr.lua" ("hl.config({" + lib.concatStringsSep "," [
|
||||||
|
''general={["col.active_border"]="rgb(${ink4})",["col.inactive_border"]="rgb(${ink3})"}''
|
||||||
''decoration={shadow={color="rgba(${s.base00}99)"}}''
|
''decoration={shadow={color="rgba(${s.base00}99)"}}''
|
||||||
(''group={["col.border_active"]="rgb(${s.base04})",''
|
(''group={["col.border_active"]="rgb(${ink4})",''
|
||||||
+ ''["col.border_inactive"]="rgb(${s.base03})",''
|
+ ''["col.border_inactive"]="rgb(${ink3})",''
|
||||||
+ ''["col.border_locked_active"]="rgb(${s.base05})",''
|
+ ''["col.border_locked_active"]="rgb(${s.base05})",''
|
||||||
+ ''groupbar={text_color="rgb(${s.base05})",''
|
+ ''groupbar={text_color="rgb(${s.base05})",''
|
||||||
+ ''["col.active"]="rgb(${s.base04})",["col.inactive"]="rgb(${s.base03})"}}'')
|
+ ''["col.active"]="rgb(${ink4})",["col.inactive"]="rgb(${ink3})"}}'')
|
||||||
''misc={background_color="rgb(${s.base00})"}''
|
''misc={background_color="rgb(${s.base00})"}''
|
||||||
] + "})");
|
] + "})");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,4 +13,37 @@
|
||||||
# hyprland decoration.rounding = radius
|
# hyprland decoration.rounding = radius
|
||||||
{
|
{
|
||||||
radius = 20;
|
radius = 20;
|
||||||
|
|
||||||
|
# ── Ink ladder ────────────────────────────────────────────────────────
|
||||||
|
# base05 is the wallpaper's ink. base04 and base03 are THAT colour mixed
|
||||||
|
# toward the background, not stylix's own base03/base04: those are three
|
||||||
|
# independent slots off the image and routinely land in unrelated hues —
|
||||||
|
# on walls/wallhaven-k8dqr6 the raw ladder is red (base03), blue (base04)
|
||||||
|
# and cream (base05). Mixing gives one colour at three strengths, which is
|
||||||
|
# the same trick quickshell's Theme.base01/base02 already use for surfaces.
|
||||||
|
#
|
||||||
|
# Read by settings/quickshell.nix (Theme.qml), settings/theming.nix
|
||||||
|
# (hypr.lua, applied at runtime) and settings/hyprland.nix (the build-time
|
||||||
|
# fallback), so the shell frame and hyprland's window borders are the same
|
||||||
|
# colour rather than two slots that happen to be near each other.
|
||||||
|
inkMuted = 0.30; # base04 — secondary text, hyprland's active border
|
||||||
|
inkFaint = 0.55; # base03 — disabled text, hyprland's inactive border
|
||||||
|
|
||||||
|
# Mix two "rrggbb" strings. t = 0 keeps `a`, t = 1 lands on `b`.
|
||||||
|
mixHex = a: b: t:
|
||||||
|
let
|
||||||
|
digits = "0123456789abcdef";
|
||||||
|
val = ch: {
|
||||||
|
"0"=0; "1"=1; "2"=2; "3"=3; "4"=4; "5"=5; "6"=6; "7"=7;
|
||||||
|
"8"=8; "9"=9; "a"=10; "b"=11; "c"=12; "d"=13; "e"=14; "f"=15;
|
||||||
|
"A"=10; "B"=11; "C"=12; "D"=13; "E"=14; "F"=15;
|
||||||
|
}.${ch};
|
||||||
|
byte = s: i: val (builtins.substring i 1 s) * 16
|
||||||
|
+ val (builtins.substring (i + 1) 1 s);
|
||||||
|
chan = i:
|
||||||
|
let
|
||||||
|
n = builtins.floor (byte a i + (byte b i - byte a i) * t + 0.5);
|
||||||
|
hi = n / 16;
|
||||||
|
in builtins.substring hi 1 digits + builtins.substring (n - hi * 16) 1 digits;
|
||||||
|
in chan 0 + chan 2 + chan 4;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue