OKHST-based color theme generator with WCAG and APCA contrast solving
Glaze generates light, dark, and high-contrast color schemes from a single hue/saturation seed. Relationships stay explicit: colors either define an absolute tone or depend on a named base through a tone delta and an optional contrast floor.
- OKHST color space — OKHSL with a contrast-shaped tone axis. Equal steps give equal WCAG contrast for neutrals and a useful approximation for chromatic colors. See OKHST in Glaze and the full OKHST specification.
- WCAG 2 + APCA contrast solving — automatic tone adjustment to meet a WCAG ratio or APCA Lc floor
- Unified dark mode — one tone space for light, dark, and high-contrast; dark is a single
100 − tinversion, no fitted curve - Mix colors — blend two colors with OKHSL or sRGB interpolation, opaque or transparent, with optional contrast solving
- Shadow colors — OKHSL-native shadow computation with automatic alpha, fg/bg tinting, and per-scheme adaptation
- Light + Dark + High-Contrast — all schemes from one definition
- Per-color hue override — absolute or relative hue shifts within a theme
- Multi-format output — native
rgb,hsl, andoklch, plus Tasty-compatibleokhslandokhst - CSS custom properties export — ready-to-use
--var: value;declarations per scheme - W3C DTCG export — spec-conformant
.tokens.json(2025.10) for Figma, Tokens Studio, Style Dictionary, and every DTCG tool - W3C DTCG Resolver-Module export — opt-in single-document
dtcgResolver()(sets + aschememodifier with a context per variant) for resolver tools such as Dispersa - Tailwind CSS v4 export —
@themeblock + dark / high-contrast overrides - Import/Export — serialize and restore theme configurations
- Create from hex/RGB — start from an existing brand color
- Zero dependencies — pure math, runs anywhere (Node.js, browser, edge)
- Tree-shakeable ESM + CJS — dual-format package
- TypeScript-first — full type definitions included
pnpm add @tenphi/glazenpm install @tenphi/glazeyarn add @tenphi/glazeimport { glaze } from '@tenphi/glaze';
glaze.configure({
modes: { dark: true, highContrast: true },
});
const defaultTheme = glaze(280, 80);
defaultTheme.colors({
surface: { tone: 97, saturation: 0.15 },
'surface-text': {
base: 'surface',
tone: '-1',
contrast: { apca: ['content', 'body'] },
},
border: {
base: 'surface',
tone: ['-8', '-16'],
inherit: false,
},
'accent-surface': { tone: 52, mode: 'fixed' },
'accent-surface-text': {
base: 'accent-surface',
tone: '+1',
contrast: 'AA',
mode: 'fixed',
},
});
const dangerTheme = defaultTheme.extend({ hue: 23 });
const palette = glaze.palette({ default: defaultTheme, danger: dangerTheme });
const tokens = palette.tokens({
prefix: { default: '', danger: 'danger-' },
});
// → {
// light: { surface: 'oklch(...)', 'danger-surface': 'oklch(...)', ... },
// dark: { surface: 'oklch(...)', 'danger-surface': 'oklch(...)', ... },
// lightContrast: { ... },
// darkContrast: { ... },
// }- A theme has one hue/saturation seed. Create status themes with
extend()so they inherit the same relationships while changing hue. - A color is a root or a dependency. Roots use an absolute
toneor'max'/'min'. Dependent colors name abaseand may use a signed tone delta such as'-8'plus acontrastfloor. - Tone is an authoring axis, not a contrast guarantee. Equal tone deltas are exact WCAG steps for neutrals. Chromatic colors can drift in rendered luminance, so Glaze measures contrast floors against the resolved colors.
contrastis a floor. A bare number or preset means WCAG;{ wcag }and{ apca }select the metric explicitly. The solver preserves the requested tone whenever it already passes.- Each color chooses its dark adaptation.
mode: 'auto'uses dark tone inversion (100 - t),fixedkeeps the authored side of the tone scale, andstaticskips scheme adaptation. - Tone windows bound ordinary schemes.
lightToneanddarkToneconfigure the light/dark render ranges. High-contrast variants use the full range. Values that accept[normal, highContrast]pairs can tighten deliberately in HC.
In Glaze, a scheme variant is one of light, dark, lightContrast, or
darkContrast. Export modes choose which variants are included; Tasty
states choose how those variants are activated in an application.
tasty()returns Tasty#tokenbindings, including its customokhsl()orokhst()serialization.tokens()andjson()return JavaScript data and default to nativeoklch()values.css()returns custom-property declarations.dtcg()/dtcgResolver()target design-token tooling.tailwind()emits a Tailwind CSS v4 theme.
- Start with the methodology to design a palette.
- Use migration and integration to wire it into an application or replace an existing color system.
- Keep the API reference nearby for every method and option.
- Read OKHST in Glaze for the product-level color model, or the full OKHST specification for its math.
AGENTS.md— source-tree orientation for contributors.