roundel
API reference

roundel/theme

Every export of roundel/theme, with its signature and doc comment: rgb256, toOklab, audit, fly, plus 3 types.

The theme (R4, R5): one map from token to style, flown once for the whole program.

A style is either a list of util.styleText format names — the user's own terminal palette, never checked or claimed — or a #rrggbb, which is truecolor at level 3 and falls back to the nearest of 256 or 16 colours below it. Every hex token is checked against the declared ground at 4.5:1 before it is flown — and so is the 256-colour entry it degrades to, at every level, so a theme that would not read on somebody's 256-colour terminal fails in CI on a truecolor one. Level 1 is not checked and cannot be: the basic sixteen are the user's own theme, and a ratio over them would be invented.

import { rgb256, toOklab, audit, … } from 'roundel/theme';

Functions

audit

Every token's verdict, as data — without throwing.

fly() refuses a theme that does not read, which is right at startup and useless while you are choosing colours: a caller who wants to know should not have to catch an exception and parse its message. So the judgement lives here and fly() is a filter over it, which also means the refusal and the report can never disagree about what passes.

Two rows per hex token — truecolor and 256 — because those are the two colours a terminal can actually be sent, and they are not the same colour. No row for 16: those values are the user's own terminal theme, so there is no ratio to report and a number there would be invented. A token given format names rather than a hex gets no row either, for the same reason: ['bold', 'red'] is the terminal's red.

function audit(theme?: Theme): ThemeFinding[];
ParameterType
theme (optional)Theme

Returns ThemeFinding[]

fly

Fly the theme: decide the colour level from the runtime once, check every hex token against the ground, and set what the tokens paint from now on. Call it at startup, with { json } when the run was asked for --json; a later call replaces the theme.

function fly(theme: Theme, rt: Runtime, opts?: ModeOptions): void;
ParameterType
themeTheme
rtRuntime
opts (optional)ModeOptions

Returns void

rgb256

The sRGB of a 256-palette index, which is ansi256 run backwards. Defined for 16–255 only, and that is the whole reason this check is possible: entries 0–15 are the user's terminal theme and entries 16–255 are not. Exported because it is the only honest way to ask "what will the terminal actually paint", which is a question a caller checking its own theme has as much right to ask as fly() does. The 6×6×6 cube and the 24-step grey ramp are the xterm values every terminal ships and none of them themes, so a contrast number over them is measured rather than invented — which is exactly what contrast.ts says cannot be done for the basic sixteen. ansi256 never returns below 16, so every paint it produces is knowable.

function rgb256(index: number): Hex;
ParameterType
indexnumber

Returns Hex

toOklab

sRGB 0–255 to OKLab. Björn Ottosson's matrices, written as straight-line arithmetic.

The first draft used map/reduce over two 9-element matrices, which read better and cost 2,766 bytes — ./theme grew 44% against a 6,300-byte budget, on a package whose whole claim is that each subpath is at or under the incumbent it replaces. Eighteen multiplies written out are a third of that. The matrices are not data anyone configures, so making them data bought nothing and charged for it.

Exported so the coefficients are pinnable. They were not, at first: nudging the first one from 0.4122214708 to 0.4022214708 left all 253 tests green, because everything downstream computed distance with the same corrupted matrix and the palette is coarse enough to absorb the error. A transform can only be checked against numbers from outside it, so theme.test.ts holds it to the five published reference values.

function toOklab(r: number, g: number, b: number): [number, number, number];
ParameterType
rnumber
gnumber
bnumber

Returns [number, number, number]

Types

Hex

type Hex = `#${string}`;

Style

type Style = Hex | readonly Format[];

Theme

A theme: a style per token, the ground the hex ones are checked against, and which WCAG level to hold them to.

conformance is the knob a team turns when AA is not enough — low vision, a projector, a policy that says AAA. It raises the floor for both jobs at once: the check that refuses a theme, and the search that picks the 256-colour substitute. Those two have to agree, or a caller asking for AAA gets a verdict at one standard and a colour chosen at another.

type Theme = Partial<Record<TokenName, Style>> & {
    ground?: Hex;
    conformance?: Conformance;
};

On this page