@untheme/aurora
v0.2.1
Published
The reference untheme preset: a compact semantic vocabulary over eight generated tonal ramps, eight modifier axes, and a catalog of thirty-one theme variants.
Downloads
470
Readme
@untheme/aurora
The reference untheme preset: a compact semantic vocabulary over eight generated tonal ramps, eight modifier axes, and a catalog of thirty-one theme variants.
Aurora demonstrates the full token model — every value family the schema validates appears at least once (colors, dimensions, durations, font families and weights, numbers, cubic Béziers, stroke styles, borders, transitions, shadows, gradients, and typography) — with a token set small enough to keep in your head.
The model
Tokens come in three tiers:
- Ramps — eight functional tonal palettes (
primary,secondary,tertiary,error,success,warning,neutral,neutral-variant), each at the eleven Tailwind-style stops (primary-50…primary-950); the six accent ramps also carry muted and vivid chroma columns (primary-muted-500,primary-vivid-500, …) for the vibrancy axis. These are the only literal colors in the contract, generated from seed colors — see Regenerating below. - Roles — a small semantic vocabulary: per accent family a fill, its
text, a tinted container, and its text (
primary,on-primary,primary-container,on-primary-container, …); the surfaces (surface,on-surface,on-surface-muted,surface-container,surface-container-high,outline,outline-muted,scrim); and the contrast channels the axes cooperate through. Every role binds a ramp stop by reference. - System scales — a five-style type scale (
type-display…type-label, typography composites whose sizes arrive through sub-value references), shape radii (shape-sm…shape-full), a spacing scale (space-1…space-10), elevation shadows (elevation-none…elevation-high), motion (duration-*,easing-*, andtransition-*composites), state-layer opacities, strokes, borders, and the brand gradients.
Because roles reference ramps rather than literals, a theme variant rebinds only the 220 ramp values — every role and every modifier context follows automatically.
The axes
Eight modifier axes, composing in order:
| Axis | Contexts | Overrides |
| ---------- | ------------------------------------ | --------------------------------- |
| color | light / dark | color roles + channels |
| vibrancy | muted / balanced / vivid | accent roles → chroma channels |
| contrast | default / medium / high | shifted roles → contrast channels |
| text | sm / md / lg | type-scale sizes |
| density | compact / default / spacious | the spacing scale |
| radius | sharp / default / round | shape radii |
| depth | flat / default / deep | elevation shadows |
| motion | default / reduced / expressive | durations, delay, easing |
The base tokens are the default context of every axis, so each default
context is empty. The axes override disjoint token sets — apart from
color, vibrancy, and contrast, whose collisions are the point
(below) — so all 2,916 combinations stay coherent without being
individually authored. contrast follows vibrancy in order, so
accessibility wins their collision.
The contrast channels
What "higher contrast" means depends on the mode: in light, on-surface
pushes from stop 800 toward 950; in dark, from 200 toward 50. A context is a
single override map, so the contrast axis cannot say "950 if light, 50 if
dark" directly. It says it through reference indirection instead:
- The base defines a channel token per shifted role and level —
on-surface-medium-contrast,on-surface-high-contrast, … — holding the light scheme's targets. - The
coloraxis'sdarkcontext rebinds those channels to the dark scheme's targets, alongside the roles themselves. - The
contrastaxis'smedium/highcontexts override each shifted role with a mode-independent reference to its channel:on-surface: "{on-surface-high-contrast}".
Both axes override on-surface; contrast follows color in order, so
its reference wins, and the reference resolves through whatever the color
context set. One override, correct in either mode — axes cooperating through
late-bound references rather than a hand-authored context per combination.
The vibrancy axis reuses the same mechanism for chroma: accent roles
re-point at *-muted / *-vivid channels, and the color contexts rebind
each channel to its mode's stop in the matching chroma column.
Usage
import { defineUntheme } from "@untheme/core";
import { preset } from "@untheme/aurora";
import nord from "@untheme/aurora/themes/nord";
const ut = defineUntheme(
preset.use({
color: "dark",
vibrancy: "balanced",
contrast: "default",
text: "md",
density: "default",
radius: "default",
depth: "default",
motion: "default",
}),
);
ut.swap("vibrancy", "vivid"); // electric dark, by composition
ut.swap("contrast", "high"); // and accessible, contrast wins the collision
ut.apply(nord); // re-tint every role through the rampsThe package also exports AuroraTheme, AuroraLayer, and
AuroraInput — the contract types a consumer's own layers and
selections check against.
Themes
Thirty-one variants, one subpath export each (@untheme/aurora/themes/<id>).
The base palette is aurora itself — electric teal-green, violet, and
magenta on cold blue-grays — and it ships as a variant too, so a demo
can always apply its way back to the default.
Editor classics: ayu, catppuccin, cyberdream, dracula, everforest,
github, gruvbox, horizon, kanagawa, monokai, night_owl, nord,
one_dark, palenight, rose_pine, solarized, synthwave,
tokyo_night, vesper.
Nature and place: abyss, aurora, dune, ember, glacier, moss,
sakura.
Utility and print: graphite (grayscale identity with quietly hued
semantics), manuscript (sepia ink on paper), phosphor (CRT terminal
greens).
Modern open palettes: flexoki, oxocarbon.
Each file carries exactly the eight re-seeded ramps and nothing else.
Regenerating
src/ramps.ts and the files in src/themes/*.ts are generated literals —
the committed files are what builds and ships; no color math runs at
runtime. To change a palette, edit the seed hexes in scripts/seeds.json
and run:
pnpm generate && pnpm formatThe generator (scripts/generate.mjs) expands each seed into a tonal ramp
in OKLCH: the seed contributes hue and chroma, every ramp shares one
perceptual lightness ladder across the eleven stops, and a chroma curve
peaks at the middle and tapers toward both ends (out-of-gamut colors
reduce chroma until sRGB holds them). The base ramps and every theme seed
all eight ramps individually; semantic seeds (error, success,
warning) stay recognizably red, green, and amber across themes,
hue-shifted toward each theme's temperature.
Related
@untheme/kit— the authoring handle (define/configure/use) this preset is built with.@untheme/core— the runtime serviceusefeeds.@untheme/schema— the contract types and the validation the tests run against.
