mirror of
https://github.com/Misterio77/Foundry.git
synced 2026-08-24 10:04:09 -05:00
feat(lib): add DynamicScheme + MD3 role layer (brick 4)
Port material-colors 0.4.2's DynamicColor engine for the rainbow scheme at standard contrast: contrast helpers (ratio_of_tones, lighter/darker, foreground_tone), the full getTone resolution (contrast curves, toneDeltaPair expansion, [50,60) avoidance, second-background), and all 49 MaterialDynamicColors roles (mono/fidelity branches collapsed since rainbow is neither). Validated bit-exact against matugen 4.0's colors output for #2B3975: 49/49 roles in dark AND light (98/98). Also matches the crate's own Rust test vectors for #0000FF (the one delta was a master-vs-0.4.2 version diff). Brick 4 of the pure-Nix matugen effort. Assisted-by: pi (opus-4.8)
This commit is contained in:
+315
@@ -0,0 +1,315 @@
|
|||||||
|
# DynamicScheme + MaterialDynamicColors role layer (brick 4), ported from
|
||||||
|
# material-colors 0.4.2 for the rainbow scheme at standard contrast (the
|
||||||
|
# config's settings). Rainbow is neither monochrome nor fidelity, so those
|
||||||
|
# branches collapse to the default case.
|
||||||
|
{lib}: let
|
||||||
|
h = import ./hct.nix {inherit lib;};
|
||||||
|
m = import ./math.nix {inherit lib;};
|
||||||
|
p = import ./palettes.nix {inherit lib;};
|
||||||
|
inherit (h) yFromLstar lstarFromY;
|
||||||
|
inherit (builtins) floor;
|
||||||
|
abs = m.abs;
|
||||||
|
|
||||||
|
clamp = lo: hi: x:
|
||||||
|
if x < lo
|
||||||
|
then lo
|
||||||
|
else if x > hi
|
||||||
|
then hi
|
||||||
|
else x;
|
||||||
|
round = x: floor (x + 0.5);
|
||||||
|
lerp = a: b: t: (1.0 - t) * a + t * b;
|
||||||
|
maxf = a: b:
|
||||||
|
if a > b
|
||||||
|
then a
|
||||||
|
else b;
|
||||||
|
minf = a: b:
|
||||||
|
if a < b
|
||||||
|
then a
|
||||||
|
else b;
|
||||||
|
between = lo: hi: x: x >= lo && x < hi;
|
||||||
|
|
||||||
|
# --- contrast ---
|
||||||
|
ratioOfYs = y1: y2: let
|
||||||
|
li = maxf y1 y2;
|
||||||
|
dk = minf y1 y2;
|
||||||
|
in (li + 5.0) / (dk + 5.0);
|
||||||
|
ratioOfTones = a: b: ratioOfYs (yFromLstar (clamp 0.0 100.0 a)) (yFromLstar (clamp 0.0 100.0 b));
|
||||||
|
lighter = tone: ratio:
|
||||||
|
if !(between 0.0 100.01 tone)
|
||||||
|
then -1.0
|
||||||
|
else let
|
||||||
|
darkY = yFromLstar tone;
|
||||||
|
lightY = ratio * (darkY + 5.0) - 5.0;
|
||||||
|
rc = ratioOfYs lightY darkY;
|
||||||
|
d = abs (rc - ratio);
|
||||||
|
in
|
||||||
|
if rc < ratio && d > 0.04
|
||||||
|
then -1.0
|
||||||
|
else let rv = lstarFromY lightY + 0.4; in
|
||||||
|
if rv < 0.0 || rv > 100.0
|
||||||
|
then -1.0
|
||||||
|
else rv;
|
||||||
|
darker = tone: ratio:
|
||||||
|
if !(between 0.0 100.01 tone)
|
||||||
|
then -1.0
|
||||||
|
else let
|
||||||
|
lightY = yFromLstar tone;
|
||||||
|
darkY = (lightY + 5.0) / ratio - 5.0;
|
||||||
|
rc = ratioOfYs lightY darkY;
|
||||||
|
d = abs (rc - ratio);
|
||||||
|
in
|
||||||
|
if rc < ratio && d > 0.04
|
||||||
|
then -1.0
|
||||||
|
else let rv = lstarFromY darkY - 0.4; in
|
||||||
|
if rv < 0.0 || rv > 100.0
|
||||||
|
then -1.0
|
||||||
|
else rv;
|
||||||
|
lighterUnsafe = tone: ratio: let x = lighter tone ratio; in
|
||||||
|
if x < 0.0
|
||||||
|
then 100.0
|
||||||
|
else x;
|
||||||
|
darkerUnsafe = tone: ratio: let x = darker tone ratio; in
|
||||||
|
if x < 0.0
|
||||||
|
then 0.0
|
||||||
|
else x;
|
||||||
|
tonePrefersLight = tone: (round tone) < 60.0;
|
||||||
|
toneAllowsLight = tone: (round tone) <= 49.0;
|
||||||
|
foregroundTone = bgTone: ratio: let
|
||||||
|
lt = lighterUnsafe bgTone ratio;
|
||||||
|
dt = darkerUnsafe bgTone ratio;
|
||||||
|
lr = ratioOfTones lt bgTone;
|
||||||
|
dr = ratioOfTones dt bgTone;
|
||||||
|
in
|
||||||
|
if tonePrefersLight bgTone
|
||||||
|
then
|
||||||
|
if lr >= ratio || lr >= dr || (abs (lr - dr) < 0.1 && lr < ratio && dr < ratio)
|
||||||
|
then lt
|
||||||
|
else dt
|
||||||
|
else if dr >= ratio || dr >= lr
|
||||||
|
then dt
|
||||||
|
else lt;
|
||||||
|
|
||||||
|
ccGet = cc: cl:
|
||||||
|
if cl <= -1.0
|
||||||
|
then cc.low
|
||||||
|
else if cl < 0.0
|
||||||
|
then lerp cc.low cc.normal (cl + 1.0)
|
||||||
|
else if cl < 0.5
|
||||||
|
then lerp cc.normal cc.medium (cl / 0.5)
|
||||||
|
else if cl < 1.0
|
||||||
|
then lerp cc.medium cc.high ((cl - 0.5) / 0.5)
|
||||||
|
else cc.high;
|
||||||
|
cc = low: normal: medium: high: {inherit low normal medium high;};
|
||||||
|
|
||||||
|
# --- role table (rec: roles reference each other) ---
|
||||||
|
highestSurface = s:
|
||||||
|
if s.isDark
|
||||||
|
then roles.surface_bright
|
||||||
|
else roles.surface_dim;
|
||||||
|
# defaults keep every role total: null background/curve/pair unless set
|
||||||
|
R = attrs:
|
||||||
|
{
|
||||||
|
isBackground = false;
|
||||||
|
background = null;
|
||||||
|
secondBackground = null;
|
||||||
|
contrastCurve = null;
|
||||||
|
toneDeltaPair = null;
|
||||||
|
}
|
||||||
|
// attrs;
|
||||||
|
tdp = subject: basis: delta: polarity: stayTogether: _: {inherit subject basis delta polarity stayTogether;};
|
||||||
|
|
||||||
|
roles = rec {
|
||||||
|
background = R {name = "background"; palette = "neutral"; isBackground = true; tone = s: if s.isDark then 6.0 else 98.0;};
|
||||||
|
on_background = R {name = "on_background"; palette = "neutral"; tone = s: if s.isDark then 90.0 else 10.0; background = _: background; contrastCurve = cc 3.0 3.0 4.5 7.0;};
|
||||||
|
surface = R {name = "surface"; palette = "neutral"; isBackground = true; tone = s: if s.isDark then 6.0 else 98.0;};
|
||||||
|
surface_dim = R {name = "surface_dim"; palette = "neutral"; isBackground = true; tone = s: if s.isDark then 6.0 else ccGet (cc 87.0 87.0 80.0 75.0) s.contrastLevel;};
|
||||||
|
surface_bright = R {name = "surface_bright"; palette = "neutral"; isBackground = true; tone = s: if s.isDark then ccGet (cc 24.0 24.0 29.0 34.0) s.contrastLevel else 98.0;};
|
||||||
|
surface_container_lowest = R {name = "surface_container_lowest"; palette = "neutral"; isBackground = true; tone = s: if s.isDark then ccGet (cc 4.0 4.0 2.0 0.0) s.contrastLevel else 100.0;};
|
||||||
|
surface_container_low = R {name = "surface_container_low"; palette = "neutral"; isBackground = true; tone = s: if s.isDark then ccGet (cc 10.0 10.0 11.0 12.0) s.contrastLevel else ccGet (cc 96.0 96.0 96.0 95.0) s.contrastLevel;};
|
||||||
|
surface_container = R {name = "surface_container"; palette = "neutral"; isBackground = true; tone = s: if s.isDark then ccGet (cc 12.0 12.0 16.0 20.0) s.contrastLevel else ccGet (cc 94.0 94.0 92.0 90.0) s.contrastLevel;};
|
||||||
|
surface_container_high = R {name = "surface_container_high"; palette = "neutral"; isBackground = true; tone = s: if s.isDark then ccGet (cc 17.0 17.0 21.0 25.0) s.contrastLevel else ccGet (cc 92.0 92.0 88.0 85.0) s.contrastLevel;};
|
||||||
|
surface_container_highest = R {name = "surface_container_highest"; palette = "neutral"; isBackground = true; tone = s: if s.isDark then ccGet (cc 22.0 22.0 26.0 30.0) s.contrastLevel else ccGet (cc 90.0 90.0 84.0 80.0) s.contrastLevel;};
|
||||||
|
on_surface = R {name = "on_surface"; palette = "neutral"; tone = s: if s.isDark then 90.0 else 10.0; background = highestSurface; contrastCurve = cc 4.5 7.0 11.0 21.0;};
|
||||||
|
surface_variant = R {name = "surface_variant"; palette = "neutral_variant"; isBackground = true; tone = s: if s.isDark then 30.0 else 90.0;};
|
||||||
|
on_surface_variant = R {name = "on_surface_variant"; palette = "neutral_variant"; tone = s: if s.isDark then 80.0 else 30.0; background = highestSurface; contrastCurve = cc 3.0 4.5 7.0 11.0;};
|
||||||
|
inverse_surface = R {name = "inverse_surface"; palette = "neutral"; tone = s: if s.isDark then 90.0 else 20.0;};
|
||||||
|
inverse_on_surface = R {name = "inverse_on_surface"; palette = "neutral"; tone = s: if s.isDark then 20.0 else 95.0; background = _: inverse_surface; contrastCurve = cc 4.5 7.0 11.0 21.0;};
|
||||||
|
outline = R {name = "outline"; palette = "neutral_variant"; tone = s: if s.isDark then 60.0 else 50.0; background = highestSurface; contrastCurve = cc 1.5 3.0 4.5 7.0;};
|
||||||
|
outline_variant = R {name = "outline_variant"; palette = "neutral_variant"; tone = s: if s.isDark then 30.0 else 80.0; background = highestSurface; contrastCurve = cc 1.0 1.0 3.0 4.5;};
|
||||||
|
shadow = R {name = "shadow"; palette = "neutral"; tone = _: 0.0;};
|
||||||
|
scrim = R {name = "scrim"; palette = "neutral"; tone = _: 0.0;};
|
||||||
|
surface_tint = R {name = "surface_tint"; palette = "primary"; isBackground = true; tone = s: if s.isDark then 80.0 else 40.0;};
|
||||||
|
|
||||||
|
primary = R {name = "primary"; palette = "primary"; isBackground = true; tone = s: if s.isDark then 80.0 else 40.0; background = highestSurface; contrastCurve = cc 3.0 4.5 7.0 7.0; toneDeltaPair = tdp primary_container primary 10.0 "Nearer" false;};
|
||||||
|
on_primary = R {name = "on_primary"; palette = "primary"; tone = s: if s.isDark then 20.0 else 100.0; background = _: primary; contrastCurve = cc 3.0 7.0 11.0 21.0;};
|
||||||
|
primary_container = R {name = "primary_container"; palette = "primary"; isBackground = true; tone = s: if s.isDark then 30.0 else 90.0; background = highestSurface; contrastCurve = cc 1.0 1.0 3.0 4.5; toneDeltaPair = tdp primary_container primary 10.0 "Nearer" false;};
|
||||||
|
on_primary_container = R {name = "on_primary_container"; palette = "primary"; tone = s: if s.isDark then 90.0 else 10.0; background = _: primary_container; contrastCurve = cc 4.5 7.0 11.0 21.0;};
|
||||||
|
inverse_primary = R {name = "inverse_primary"; palette = "primary"; tone = s: if s.isDark then 40.0 else 80.0; background = _: inverse_surface; contrastCurve = cc 3.0 4.5 7.0 7.0;};
|
||||||
|
|
||||||
|
secondary = R {name = "secondary"; palette = "secondary"; isBackground = true; tone = s: if s.isDark then 80.0 else 40.0; background = highestSurface; contrastCurve = cc 3.0 4.5 7.0 7.0; toneDeltaPair = tdp secondary_container secondary 10.0 "Nearer" false;};
|
||||||
|
on_secondary = R {name = "on_secondary"; palette = "secondary"; tone = s: if s.isDark then 20.0 else 100.0; background = _: secondary; contrastCurve = cc 4.5 7.0 11.0 21.0;};
|
||||||
|
secondary_container = R {name = "secondary_container"; palette = "secondary"; isBackground = true; tone = s: if s.isDark then 30.0 else 90.0; background = highestSurface; contrastCurve = cc 1.0 1.0 3.0 4.5; toneDeltaPair = tdp secondary_container secondary 10.0 "Nearer" false;};
|
||||||
|
on_secondary_container = R {name = "on_secondary_container"; palette = "secondary"; tone = s: if s.isDark then 90.0 else 10.0; background = _: secondary_container; contrastCurve = cc 4.5 7.0 11.0 21.0;};
|
||||||
|
|
||||||
|
tertiary = R {name = "tertiary"; palette = "tertiary"; isBackground = true; tone = s: if s.isDark then 80.0 else 40.0; background = highestSurface; contrastCurve = cc 3.0 4.5 7.0 7.0; toneDeltaPair = tdp tertiary_container tertiary 10.0 "Nearer" false;};
|
||||||
|
on_tertiary = R {name = "on_tertiary"; palette = "tertiary"; tone = s: if s.isDark then 20.0 else 100.0; background = _: tertiary; contrastCurve = cc 4.5 7.0 11.0 21.0;};
|
||||||
|
tertiary_container = R {name = "tertiary_container"; palette = "tertiary"; isBackground = true; tone = s: if s.isDark then 30.0 else 90.0; background = highestSurface; contrastCurve = cc 1.0 1.0 3.0 4.5; toneDeltaPair = tdp tertiary_container tertiary 10.0 "Nearer" false;};
|
||||||
|
on_tertiary_container = R {name = "on_tertiary_container"; palette = "tertiary"; tone = s: if s.isDark then 90.0 else 10.0; background = _: tertiary_container; contrastCurve = cc 4.5 7.0 11.0 21.0;};
|
||||||
|
|
||||||
|
error = R {name = "error"; palette = "error"; isBackground = true; tone = s: if s.isDark then 80.0 else 40.0; background = highestSurface; contrastCurve = cc 3.0 4.5 7.0 7.0; toneDeltaPair = tdp error_container error 10.0 "Nearer" false;};
|
||||||
|
on_error = R {name = "on_error"; palette = "error"; tone = s: if s.isDark then 20.0 else 100.0; background = _: error; contrastCurve = cc 4.5 7.0 11.0 21.0;};
|
||||||
|
error_container = R {name = "error_container"; palette = "error"; isBackground = true; tone = s: if s.isDark then 30.0 else 90.0; background = highestSurface; contrastCurve = cc 1.0 1.0 3.0 4.5; toneDeltaPair = tdp error_container error 10.0 "Nearer" false;};
|
||||||
|
on_error_container = R {name = "on_error_container"; palette = "error"; tone = s: if s.isDark then 90.0 else 10.0; background = _: error_container; contrastCurve = cc 4.5 7.0 11.0 21.0;};
|
||||||
|
|
||||||
|
primary_fixed = R {name = "primary_fixed"; palette = "primary"; isBackground = true; tone = _: 90.0; background = highestSurface; contrastCurve = cc 1.0 1.0 3.0 4.5; toneDeltaPair = tdp primary_fixed primary_fixed_dim 10.0 "Lighter" true;};
|
||||||
|
primary_fixed_dim = R {name = "primary_fixed_dim"; palette = "primary"; isBackground = true; tone = _: 80.0; background = highestSurface; contrastCurve = cc 1.0 1.0 3.0 4.5; toneDeltaPair = tdp primary_fixed primary_fixed_dim 10.0 "Lighter" true;};
|
||||||
|
on_primary_fixed = R {name = "on_primary_fixed"; palette = "primary"; tone = _: 10.0; background = _: primary_fixed_dim; secondBackground = _: primary_fixed; contrastCurve = cc 4.5 7.0 11.0 21.0;};
|
||||||
|
on_primary_fixed_variant = R {name = "on_primary_fixed_variant"; palette = "primary"; tone = _: 30.0; background = _: primary_fixed_dim; secondBackground = _: primary_fixed; contrastCurve = cc 3.0 4.5 7.0 11.0;};
|
||||||
|
|
||||||
|
secondary_fixed = R {name = "secondary_fixed"; palette = "secondary"; isBackground = true; tone = _: 90.0; background = highestSurface; contrastCurve = cc 1.0 1.0 3.0 4.5; toneDeltaPair = tdp secondary_fixed secondary_fixed_dim 10.0 "Lighter" true;};
|
||||||
|
secondary_fixed_dim = R {name = "secondary_fixed_dim"; palette = "secondary"; isBackground = true; tone = _: 80.0; background = highestSurface; contrastCurve = cc 1.0 1.0 3.0 4.5; toneDeltaPair = tdp secondary_fixed secondary_fixed_dim 10.0 "Lighter" true;};
|
||||||
|
on_secondary_fixed = R {name = "on_secondary_fixed"; palette = "secondary"; tone = _: 10.0; background = _: secondary_fixed_dim; secondBackground = _: secondary_fixed; contrastCurve = cc 4.5 7.0 11.0 21.0;};
|
||||||
|
on_secondary_fixed_variant = R {name = "on_secondary_fixed_variant"; palette = "secondary"; tone = _: 30.0; background = _: secondary_fixed_dim; secondBackground = _: secondary_fixed; contrastCurve = cc 3.0 4.5 7.0 11.0;};
|
||||||
|
|
||||||
|
tertiary_fixed = R {name = "tertiary_fixed"; palette = "tertiary"; isBackground = true; tone = _: 90.0; background = highestSurface; contrastCurve = cc 1.0 1.0 3.0 4.5; toneDeltaPair = tdp tertiary_fixed tertiary_fixed_dim 10.0 "Lighter" true;};
|
||||||
|
tertiary_fixed_dim = R {name = "tertiary_fixed_dim"; palette = "tertiary"; isBackground = true; tone = _: 80.0; background = highestSurface; contrastCurve = cc 1.0 1.0 3.0 4.5; toneDeltaPair = tdp tertiary_fixed tertiary_fixed_dim 10.0 "Lighter" true;};
|
||||||
|
on_tertiary_fixed = R {name = "on_tertiary_fixed"; palette = "tertiary"; tone = _: 10.0; background = _: tertiary_fixed_dim; secondBackground = _: tertiary_fixed; contrastCurve = cc 4.5 7.0 11.0 21.0;};
|
||||||
|
on_tertiary_fixed_variant = R {name = "on_tertiary_fixed_variant"; palette = "tertiary"; tone = _: 30.0; background = _: tertiary_fixed_dim; secondBackground = _: tertiary_fixed; contrastCurve = cc 3.0 4.5 7.0 11.0;};
|
||||||
|
};
|
||||||
|
|
||||||
|
# --- getTone: the DynamicColor contrast/tone resolution ---
|
||||||
|
getTone = role: s: let
|
||||||
|
cl = s.contrastLevel;
|
||||||
|
decreasing = cl < 0.0;
|
||||||
|
in
|
||||||
|
if role.toneDeltaPair != null
|
||||||
|
then let
|
||||||
|
pair = role.toneDeltaPair s;
|
||||||
|
roleA = pair.subject;
|
||||||
|
roleB = pair.basis;
|
||||||
|
delta = pair.delta;
|
||||||
|
polarity = pair.polarity;
|
||||||
|
stayTogether = pair.stayTogether;
|
||||||
|
bgTone = getTone (role.background s) s;
|
||||||
|
aIsNearer = polarity == "Nearer" || (polarity == "Lighter" && !s.isDark) || (polarity == "Darker" && s.isDark);
|
||||||
|
nearer =
|
||||||
|
if aIsNearer
|
||||||
|
then roleA
|
||||||
|
else roleB;
|
||||||
|
farther =
|
||||||
|
if aIsNearer
|
||||||
|
then roleB
|
||||||
|
else roleA;
|
||||||
|
amNearer = role.name == nearer.name;
|
||||||
|
dir =
|
||||||
|
if s.isDark
|
||||||
|
then 1.0
|
||||||
|
else -1.0;
|
||||||
|
nContrast = ccGet nearer.contrastCurve cl;
|
||||||
|
fContrast = ccGet farther.contrastCurve cl;
|
||||||
|
nInitial = nearer.tone s;
|
||||||
|
nTone0 =
|
||||||
|
if decreasing
|
||||||
|
then foregroundTone bgTone nContrast
|
||||||
|
else if ratioOfTones bgTone nInitial >= nContrast
|
||||||
|
then nInitial
|
||||||
|
else foregroundTone bgTone nContrast;
|
||||||
|
fInitial = farther.tone s;
|
||||||
|
fTone0 =
|
||||||
|
if decreasing
|
||||||
|
then foregroundTone bgTone fContrast
|
||||||
|
else if ratioOfTones bgTone fInitial >= fContrast
|
||||||
|
then fInitial
|
||||||
|
else foregroundTone bgTone fContrast;
|
||||||
|
# expand to satisfy delta
|
||||||
|
exp =
|
||||||
|
if (fTone0 - nTone0) * dir >= delta
|
||||||
|
then {n = nTone0; f = fTone0;}
|
||||||
|
else let f1 = clamp 0.0 100.0 (delta * dir + nTone0); in
|
||||||
|
if (f1 - nTone0) * dir >= delta
|
||||||
|
then {n = nTone0; f = f1;}
|
||||||
|
else {n = clamp 0.0 100.0 (0.0 - delta * dir + f1); f = f1;};
|
||||||
|
# avoid the [50,60) awkward zone
|
||||||
|
adj =
|
||||||
|
if between 50.0 60.0 exp.n
|
||||||
|
then
|
||||||
|
if dir > 0.0
|
||||||
|
then {n = 60.0; f = maxf exp.f (delta * dir + 60.0);}
|
||||||
|
else {n = 49.0; f = minf exp.f (delta * dir + 49.0);}
|
||||||
|
else if between 50.0 60.0 exp.f
|
||||||
|
then
|
||||||
|
if stayTogether
|
||||||
|
then (
|
||||||
|
if dir > 0.0
|
||||||
|
then {n = 60.0; f = maxf exp.f (delta * dir + 60.0);}
|
||||||
|
else {n = 49.0; f = minf exp.f (delta * dir + 49.0);}
|
||||||
|
)
|
||||||
|
else {n = exp.n; f = if dir > 0.0 then 60.0 else 49.0;}
|
||||||
|
else exp;
|
||||||
|
in
|
||||||
|
if amNearer
|
||||||
|
then adj.n
|
||||||
|
else adj.f
|
||||||
|
else let
|
||||||
|
answer0 = role.tone s;
|
||||||
|
in
|
||||||
|
if role.background == null
|
||||||
|
then answer0
|
||||||
|
else let
|
||||||
|
bgTone = getTone (role.background s) s;
|
||||||
|
desired = ccGet role.contrastCurve cl;
|
||||||
|
answer1 =
|
||||||
|
if ratioOfTones bgTone answer0 >= desired && !decreasing
|
||||||
|
then answer0
|
||||||
|
else foregroundTone bgTone desired;
|
||||||
|
answer2 =
|
||||||
|
if role.isBackground && between 50.0 60.0 answer1
|
||||||
|
then
|
||||||
|
if ratioOfTones 49.0 bgTone >= desired
|
||||||
|
then 49.0
|
||||||
|
else 60.0
|
||||||
|
else answer1;
|
||||||
|
in
|
||||||
|
if role.secondBackground == null
|
||||||
|
then answer2
|
||||||
|
else let
|
||||||
|
bgt1 = getTone (role.background s) s;
|
||||||
|
bgt2 = getTone (role.secondBackground s) s;
|
||||||
|
upper = maxf bgt1 bgt2;
|
||||||
|
lower = minf bgt1 bgt2;
|
||||||
|
lightOption = lighter upper desired;
|
||||||
|
darkOption = darker lower desired;
|
||||||
|
prefersLight = tonePrefersLight bgt1 || tonePrefersLight bgt2;
|
||||||
|
availables = builtins.filter (x: abs (x - (-1.0)) > 1.0e-12) [lightOption darkOption];
|
||||||
|
in
|
||||||
|
if ratioOfTones upper answer2 >= desired && ratioOfTones lower answer2 >= desired
|
||||||
|
then answer2
|
||||||
|
else if prefersLight
|
||||||
|
then (if lightOption < 0.0 then 100.0 else lightOption)
|
||||||
|
else if builtins.length availables == 1
|
||||||
|
then builtins.head availables
|
||||||
|
else (if darkOption < 0.0 then 0.0 else darkOption);
|
||||||
|
|
||||||
|
mkScheme = isDark: sourceHex: let
|
||||||
|
src = h.hctFromHex sourceHex;
|
||||||
|
in {
|
||||||
|
inherit isDark;
|
||||||
|
contrastLevel = 0.0;
|
||||||
|
sourceColorHct = src;
|
||||||
|
palettes = p.rainbowPalettes {inherit (src) hue chroma;};
|
||||||
|
};
|
||||||
|
|
||||||
|
colorOf = roleName: s: let
|
||||||
|
role = roles.${roleName};
|
||||||
|
tone = getTone role s;
|
||||||
|
in
|
||||||
|
s.palettes.${role.palette}.tone tone;
|
||||||
|
in {
|
||||||
|
inherit roles mkScheme getTone colorOf;
|
||||||
|
|
||||||
|
# all role colors for a source hex + mode
|
||||||
|
colorsFor = isDark: sourceHex: let
|
||||||
|
s = mkScheme isDark sourceHex;
|
||||||
|
in
|
||||||
|
lib.mapAttrs (n: _: colorOf n s) roles;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user