# roundel/theme

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

Source: https://roundel.interlace.tools/docs/api/theme

<!-- Generated by scripts/api-reference.ts from the built dist/*.d.ts. Do not edit; run `npx tsx scripts/api-reference.ts`. -->

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.

```ts
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.

```ts
function audit(theme?: Theme): ThemeFinding[];
```

| Parameter | Type |
| :-- | :-- |
| `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.

```ts
function fly(theme: Theme, rt: Runtime, opts?: ModeOptions): void;
```

| Parameter | Type |
| :-- | :-- |
| `theme` | `Theme` |
| `rt` | `Runtime` |
| `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.

```ts
function rgb256(index: number): Hex;
```

| Parameter | Type |
| :-- | :-- |
| `index` | `number` |

**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.

```ts
function toOklab(r: number, g: number, b: number): [number, number, number];
```

| Parameter | Type |
| :-- | :-- |
| `r` | `number` |
| `g` | `number` |
| `b` | `number` |

**Returns** `[number, number, number]`

## Types

### Hex

```ts
type Hex = `#${string}`;
```

### Style

```ts
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.

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