1 Commits

Author SHA1 Message Date
8c394eaaf2 fix light mode negation, improve oklch dist calc efficiency 2025-12-10 02:37:35 -08:00
4 changed files with 53 additions and 9 deletions

View File

@@ -54,6 +54,7 @@ def register_parser(subparsers: _SubparserType) -> None:
# particularly good measure of perceptual distinction, so we'd prefer the
# former.
parser.add_argument(
"-l",
"--l-base",
type=int,
default=20,
@@ -82,7 +83,7 @@ def register_parser(subparsers: _SubparserType) -> None:
parser.add_argument(
"--term-fg-gap",
type=int,
default=60,
default=65,
help="Terminal foreground lightness gap (default: 60)",
)

View File

@@ -16,6 +16,8 @@ L_max: int = parameters.get("L_max", 98)
L_step: int = parameters.get("L_step", 5)
L_points: list[int] = list(range(L_min, L_max+1))
# L-space just affects accuracy of chroma max
L_space = np.arange(0, 100 + L_step, L_step)
monotone_C_map = parameters.get("monotone_C_map", {})

View File

@@ -98,7 +98,7 @@ def generate_scheme_groups(
metric_map = {
"wcag": lambda mc,ac: ac.contrast(mc, method='wcag21'),
"oklch": lambda mc,ac: mc.distance(ac, space="oklch"),
"oklch": oklch_distance,
"lightness": lambda mc,ac: abs(mc.coords()[0]-ac.coords()[0])*100,
}
@@ -131,6 +131,9 @@ def generate_scheme_groups(
("distance", distance),
("l_base", l_base),
("l_step", l_step),
("fg_gap", fg_gap),
("grey_gap", grey_gap),
("term_fg_gap", term_fg_gap),
]
# note how selection_bg steps up by `l_step`, selection_fg steps down by
@@ -157,7 +160,7 @@ def generate_scheme_groups(
accent_pairs = [
("black", f"f{{{{{biome}.l{l_base}}}}}"),
("grey", f"f{{{{{biome}.l{l_base+grey_gap}}}}}"),
("white", f"f{{{{{biome}.l{l_base+term_fg_gap-l_step}}}}}"),
("white", f"f{{{{{biome}.l{l_base+term_fg_gap-2*l_step}}}}}"),
]
for color_name, mb_accent in accent_color_map.items():
aL = int(100*accent_colors[mb_accent].coords()[0])
@@ -184,29 +187,42 @@ def generate_scheme(
term_color_map: dict[str, str],
vim_color_map: dict[str, str],
) -> str:
l_sys = l_base
l_app = l_base + l_step
term_bright_offset = 10
# negate gaps if mode is light
if mode == "light":
l_step *= -1
fg_gap *= -1
grey_gap *= -1
term_fg_gap *= -1
term_bright_offset *= -1
meta, _, mt, ac = generate_scheme_groups(
mode, biome, metric, distance,
l_base, l_step,
l_sys, l_step,
fg_gap, grey_gap, term_fg_gap,
full_color_map
)
_, term, _, term_norm_ac = generate_scheme_groups(
mode, biome, metric, distance,
l_base + l_step, l_step,
l_app, l_step,
fg_gap, grey_gap, term_fg_gap,
term_color_map
)
_, _, _, term_bright_ac = generate_scheme_groups(
mode, biome, metric, distance,
l_base + l_step + 10, l_step,
l_app + term_bright_offset, l_step,
fg_gap, grey_gap, term_fg_gap,
term_color_map
)
_, _, vim_mt, vim_ac = generate_scheme_groups(
mode, biome, metric, distance,
l_base + l_step, l_step,
l_app, l_step,
fg_gap, grey_gap, term_fg_gap,
vim_color_map
)

View File

@@ -1,3 +1,4 @@
import math
from types import GenericAlias
from argparse import ArgumentParser, _SubParsersAction
@@ -6,5 +7,29 @@ from coloraide import Color
_SubParsersAction.__class_getitem__ = classmethod(GenericAlias)
_SubparserType = _SubParsersAction[ArgumentParser]
def oklch_distance(mc: Color, ac: Color) -> float:
return mc.distance(ac, space="oklch")
def oklch_distance(xc: Color, yc: Color) -> float:
"""
Compute the distance between two colors in OKLCH space.
Note: `xc` and `yc` are presumed to be OKLCH colors already, such that
`.coords()` yields an `(l, c, h)` triple directly rather than first
requiring conversion. When we can make this assumption, we save roughly an
order of magnitude in runtime.
1. `xc.distance(yc, space="oklch")`: 500k evals takes ~2s
2. This method: 500k evals takes ~0.2s
"""
l1, c1, h1 = xc.coords()
l2, c2, h2 = yc.coords()
rad1 = h1 / 180 * math.pi
rad2 = h2 / 180 * math.pi
x1, y1 = c1 * math.cos(rad1), c1 * math.sin(rad1)
x2, y2 = c2 * math.cos(rad2), c2 * math.sin(rad2)
dx = x1 - x2
dy = y1 - y2
dz = l1 - l2
return (dx**2 + dy**2 + dz**2)**0.5