diff options
| author | Craig Jennings <c@cjennings.net> | 2026-06-10 15:23:50 -0500 |
|---|---|---|
| committer | Craig Jennings <c@cjennings.net> | 2026-06-10 15:23:50 -0500 |
| commit | bb2aed2f4ea57bfd0468e683bc33e795a2bf4711 (patch) | |
| tree | aec090c00e4d010f040a740737da1ed2841e0fde /scripts/theme-studio/test-colormath.mjs | |
| parent | 28d822e31238206a0554291318cccaa022f2ea83 (diff) | |
| download | dotemacs-bb2aed2f4ea57bfd0468e683bc33e795a2bf4711.tar.gz dotemacs-bb2aed2f4ea57bfd0468e683bc33e795a2bf4711.zip | |
fix(theme-studio): derive box bevel colors from the face background
The released/pressed bevel was a flat translucent white/black overlay, which reads weaker than the box Emacs draws. reliefColors in colormath.js now ports Emacs 30's x_alloc_lighter_color: highlight = bg x1.2, shadow = bg x0.6, an additive boost for dark backgrounds, and the same-color fallback for pure black and white. boxCss takes the face's effective bg and derives both edges from it. Pressed swaps the pair, and the translucent pair remains only when no bg is known. Width stays 1px because dupre's :line-width -1 draws 1px lines in Emacs too. The gap was color strength, not width. Five node tests pin hand-computed fixtures from the C source, and a new #beveltest gate pins the wiring.
Diffstat (limited to 'scripts/theme-studio/test-colormath.mjs')
| -rw-r--r-- | scripts/theme-studio/test-colormath.mjs | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/scripts/theme-studio/test-colormath.mjs b/scripts/theme-studio/test-colormath.mjs index 58ce7829..992d35bc 100644 --- a/scripts/theme-studio/test-colormath.mjs +++ b/scripts/theme-studio/test-colormath.mjs @@ -13,6 +13,7 @@ import { srgb2oklab, oklab2oklch, oklch2oklab, oklch2hex, apca, deltaE, hex2rgb, rl, contrast, rating, hsv2rgb, rgb2hsv, rgb2hex, oklab2lrgb, inGamut, lrgb2hex, planeCell, paletteWarnings, + reliefColors, } from './colormath.js'; const close = (a, b, eps = 0.005) => Math.abs(a - b) <= eps; @@ -230,6 +231,37 @@ test('paletteWarnings: threshold is inclusive-exclusive at the boundary', () => assert.equal(paletteWarnings(pal, 0.007).warnings.length, 1, 'just above the pair distance'); }); +// Fixtures hand-computed from Emacs 30's xterm.c x_alloc_lighter_color +// (factor 1.2 / delta 0x8000 highlight, 0.6 / 0x4000 shadow, dark boost +// below brightness 48000/65535, same-color fallback adds delta). +test('reliefColors: dark mode-line bg gets the dark boost (Normal)', () => { + const { hl, sh } = reliefColors('#30343c'); + assert.equal(hl, '#71767f'); + assert.equal(sh, '#0f1116'); +}); + +test('reliefColors: grey75 brightness is above the boost limit (Normal)', () => { + const { hl, sh } = reliefColors('#bfbfbf'); + assert.equal(hl, '#e5e5e5'); // 1.2x only, no additive boost + assert.equal(sh, '#737373'); // 0.6x only +}); + +test('reliefColors: pure black hits the same-color fallback for the shadow (Boundary)', () => { + const { hl, sh } = reliefColors('#000000'); + assert.equal(hl, '#4d4d4d'); // boost lifts the highlight off black + assert.equal(sh, '#404040'); // 0.6x + boost still black -> fallback adds delta +}); + +test('reliefColors: pure white highlight saturates, shadow scales (Boundary)', () => { + const { hl, sh } = reliefColors('#ffffff'); + assert.equal(hl, '#ffffff'); // clamped, fallback also clamps to white + assert.equal(sh, '#999999'); +}); + +test('reliefColors: malformed hex returns null pair (Error)', () => { + assert.deepEqual(reliefColors('nonsense'), { hl: null, sh: null }); +}); + // Guards the one-source-of-truth contract: the page must carry colormath.js's // body (sans exports) verbatim, so the inlined copy and the tested module cannot // drift. Requires `python3 generate.py` to have run first. |
