Raxol. UI. Theming. Salience
(Raxol v2.6.1)
View Source
Salience-tier color solver: OKLCH colors leveled through a two-lobe Helmholtz-Kohlrausch apparent-lightness model.
Instead of hand-picking lightness per color, a palette is expressed as
(hue, chroma, tier) seeds. Each tier is an apparent-lightness contrast
delta away from the ground (background) lightness; the solver compensates
for the H-K effect (chromatic colors — especially blues — read darker than
their nominal OKLCH L suggests) so every color on one tier appears equally
bright to the eye.
The two-lobe formulation:
apparent_L = L - 0.14 * C * hue_factor(h)Tiers generalize to any ground: on dark grounds tiers solve up (lighter than ground), on light grounds down, chosen automatically by headroom. Deltas compress proportionally when the ground leaves too little headroom (mid-gray grounds), preserving tier ordering.
Ground lightness is a runtime input — pair with an OSC 11 background query to solve the palette against the terminal's actual background.
Summary
Functions
Apparent lightness of an OKLCH color under the two-lobe H-K model.
Converts a #rrggbb hex string (or any struct/map with integer r, g,
b components, e.g. Raxol.Style.Colors.Color) to {l, c, h} OKLCH.
Two-lobe H-K hue factor: warm cosine fundamental plus a Gaussian bump around blue (h = 255), clamped to [0.3, 1.2].
Converts OKLCH to a sRGB hex string, clamping L into displayable range
and shrinking chroma until the color fits the sRGB gamut.
Converts OKLCH to a gamut-mapped sRGB {r, g, b} tuple (0-255 per
channel), clamping L into displayable range and shrinking chroma until
the color fits the sRGB gamut.
The reference near-black ground OKLCH lightness the tier deltas were
derived against (0.2). Exposed so callers that need
a fallback ground (e.g. no OSC 11 detection) don't duplicate the number.
sRGB relative luminance (Rec. 709 coefficients) of a #rrggbb hex color,
per the WCAG contrast-ratio formula ((L1 + 0.05) / (L2 + 0.05)).
Converts sRGB components in 0.0..1.0 to {l, c, h} OKLCH
(h in degrees, 0.0 <= h < 360.0).
Solves a (C, h) seed on a salience tier against a ground lightness and
returns a hex color.
Nominal OKLCH L that lands a (C, h) color on a target apparent
lightness.
Solves a seed list into a palette map.
Apparent-lightness contrast delta for a tier.
Target apparent lightness for a tier against a ground, with headroom compression: when the ground leaves less than the full delta range on the chosen side, all deltas scale down proportionally (ordering preserved).
Tier names ordered by increasing contrast from ground.
Types
Functions
Apparent lightness of an OKLCH color under the two-lobe H-K model.
Converts a #rrggbb hex string (or any struct/map with integer r, g,
b components, e.g. Raxol.Style.Colors.Color) to {l, c, h} OKLCH.
Two-lobe H-K hue factor: warm cosine fundamental plus a Gaussian bump around blue (h = 255), clamped to [0.3, 1.2].
Converts OKLCH to a sRGB hex string, clamping L into displayable range
and shrinking chroma until the color fits the sRGB gamut.
Converts OKLCH to a gamut-mapped sRGB {r, g, b} tuple (0-255 per
channel), clamping L into displayable range and shrinking chroma until
the color fits the sRGB gamut.
@spec reference_ground() :: float()
The reference near-black ground OKLCH lightness the tier deltas were
derived against (0.2). Exposed so callers that need
a fallback ground (e.g. no OSC 11 detection) don't duplicate the number.
sRGB relative luminance (Rec. 709 coefficients) of a #rrggbb hex color,
per the WCAG contrast-ratio formula ((L1 + 0.05) / (L2 + 0.05)).
This is intentionally a different lens than apparent_lightness/3: the
H-K apparent-lightness model is the solver's internal notion of equal
brightness (used for tier uniformity/monotonicity), while relative
luminance is the external, standards-based check a caller can use for a
legibility floor that the solver's own model cannot self-certify.
Raises ArgumentError (with the malformed value in the message) when
hex isn't exactly 6 hex digits, optionally #-prefixed -- a
programming-error contract, not a runtime-input one: callers are
expected to pass already-resolved hex colors, not raw user input.
Converts sRGB components in 0.0..1.0 to {l, c, h} OKLCH
(h in degrees, 0.0 <= h < 360.0).
Solves a (C, h) seed on a salience tier against a ground lightness and
returns a hex color.
Options
:ground- ground (background) OKLCH lightness. Default0.2(the reference near-black ground the tier deltas were derived against).:polarity-:up(tiers lighter than ground),:down(darker), or:auto(default): whichever side of the ground has more headroom.
Examples
iex> Raxol.UI.Theming.Salience.solve(:differentiate, 0.13, 57)
"#c1712c"
iex> Raxol.UI.Theming.Salience.solve(:baseline, 0.0, 250)
"#b4b4b4"
Nominal OKLCH L that lands a (C, h) color on a target apparent
lightness.
Solves a seed list into a palette map.
Seeds are maps with :name, :h, :c, :tier (extra keys are ignored).
Returns %{name => hex}.
Apparent-lightness contrast delta for a tier.
Target apparent lightness for a tier against a ground, with headroom compression: when the ground leaves less than the full delta range on the chosen side, all deltas scale down proportionally (ordering preserved).
@spec tiers() :: [tier()]
Tier names ordered by increasing contrast from ground.