diff options
Diffstat (limited to 'scripts/theme-studio/README.md')
| -rw-r--r-- | scripts/theme-studio/README.md | 67 |
1 files changed, 63 insertions, 4 deletions
diff --git a/scripts/theme-studio/README.md b/scripts/theme-studio/README.md index 044ccc2e..caee7b24 100644 --- a/scripts/theme-studio/README.md +++ b/scripts/theme-studio/README.md @@ -42,7 +42,9 @@ The runner regenerates the page, runs the Python templating tests (`test-colormath.mjs`, including the inline-integrity check), a syntax check of the spliced page script, and the browser hash gates in headless Chrome (`#selftest`, `#cursortest`, `#readouttest`, `#deltatest`, `#oklchtest`, -`#planetest`). It exits non-zero on any failure. The browser gates need a +`#planetest`, `#locktest`, `#sorttest`, `#mocktest`, `#contrasttest`, +`#safetest`, `#healtest`, `#familytest`, `#counttest`, `#baseedittest`, +`#roundtriptest`). It exits non-zero on any failure. The browser gates need a Chromium-family browser; without one they report SKIPPED rather than passing silently. The pure color math and the extracted picker logic (`planeCell`, `paletteWarnings`) live in `colormath.js` so they are unit-tested directly in @@ -65,10 +67,11 @@ Node; the DOM glue is covered by the browser hash gates. Three tiers of faces, plus the palette: -- **Palette** — named colors. Add by hex or with the in-page color picker +- **Palette** — named colors, shown grouped into hue *families* (see Color + families below). Add by hex or with the in-page color picker (saturation/value square, hue slider, palette reuse chips, live contrast - readout, and an any / AA+ / AAA legibility mask). Remove, rename, reorder with - arrows or drag. The colors serving as background and foreground are locked. + readout, and an any / AA+ / AAA legibility mask). Remove and rename per chip; + the colors serving as background and foreground are locked. The picker also shows perceptual readouts beside the WCAG ratio: the OKLCH coordinates (lightness, chroma, hue°) and the APCA Lc contrast against the @@ -92,6 +95,62 @@ Three tiers of faces, plus the palette: per face, shown in a live mock Emacs buffer. - **Package faces** — per-package face tables with a live preview (below). +## Color families + +The palette is displayed as **families**: colors grouped into vertical columns by +their actual color, dark at the top and light at the bottom, columns arranged left +to right. Grouping is derived from the hex on every render — never from the name — +so renaming a color to anything never moves it between columns. The flat palette +underneath is unchanged (export stays a flat `[hex, name]` list); families are a +view over it, and the per-chip rename/remove still work. + +- **Grouping.** Chromatic colors bucket by their nearest perceptual hue (red, + orange, yellow, green, teal, blue, purple, pink). Near-neutrals — grays, the + background and foreground ramps — collapse into one neutral column ordered by + lightness, using a lightness-scaled chroma threshold so a faint pale tint keeps + its hue while a faint mid gray reads as neutral. Columns sort by hue; the ground + strip (the `bg` and `fg` assignments) pins first, neutrals next. (Hue-adjacent + warm colors like olive-greens and golds can still share a column — a known + limitation, since by hue they really are adjacent.) +- **The count control** under each chromatic column sets how many steps sit on + each side of the family's base (its most-saturated color). Setting N regenerates + the family as a symmetric base ±N tonal ramp via `ramp()` — lighter and darker + steps on the base's hue with chroma easing toward the extremes — *replacing* the + column's current colors. N=0 collapses to the base alone. +- **Editing a base** recolors the whole family: change a base color and the family + regenerates from it at the same count. +- **References follow.** When a regenerate changes a step's hex, any face assigned + to that step is re-pointed to the new hex. A step *removed* by lowering the count + leaves its references showing "(gone)" — visible and recoverable, never a silent + jump to a different color. + +The standalone ramp generator is gone; fanning a color into a ramp is now "add the +color, then raise its column's count." + +## Background-contrast safety + +Keep background tints readable. Works in OKLCH; the pure math is in `app-core.js` +(`fgSetFor`, `floor`, `lMax`), the DOM in `app.js`. + +**Worst-case contrast.** A background overlay sits behind many foregrounds at +once, so one fg/bg contrast pair is the wrong number. For the covered overlay +faces — `region`, `hl-line`, `highlight`, `lazy-highlight`, `isearch` — the +contrast cell shows the *worst-case floor*: the lowest contrast over the face's +foreground set (the syntax-token colors plus the default foreground), naming the +*limiting foreground* that sets it. A tint that clears the default text but fails +the darkest token reads FAIL, with that token named. Package faces and the other +UI rows keep their single-pair readout. + +The verdict is WCAG: AA (4.5) by default, AAA (7) selectable. APCA Lc stays a +picker-only diagnostic and does not drive PASS/FAIL. + +**Safe lightness.** In the OKLCH picker, the "safe for" selector picks one +covered face. The Chroma×Lightness plane then shades the lightness band too light +to keep that face readable over its foreground set, with the L_max ceiling as the +band's lower edge. If even pure black can't satisfy the target (a foreground is +too dark), the whole plane shades; that is a true finding about the foreground, +not a tool bug. + ## Package faces Pick an application from the dropdown to edit its faces. Each row has a |
