# `Colour`

A colour in sRGB with its alpha, each channel from 0 to 255, written `#1e6fd9`, or `#1e6fd980` when it isn't opaque. `colour`'s operations convert, mix and compare colours.

[Media and visual](types.md#media-and-visual); not ordered; since Jadpo 0.1.0.

## Make one

Build one from its fields, `Colour { red: ...  green: ...  blue: ... }`.

`text.parse(raw, as: Colour)` reads one from its text; text that isn't one at all fails `malformed`, such as `1e6fd9`, `#1e6fd` or `#1e6fd9f`.

These operations give one: `colour.from_hsl`, `colour.from_oklch`, `colour.mix` and `colour.with_lightness`.

## Fields

| Field | Type |
|---|---|
| `red` | `Int` |
| `green` | `Int` |
| `blue` | `Int` |
| `alpha` | `Int` |

## Text, JSON and storage

`text.from` writes its canonical text, the one form `text.parse` reads back. JSON sends its canonical text as a string.

| Text | JSON |
|---|---|
| `#000000` | `"#000000"` |
| `#ffffff` | `"#ffffff"` |
| `#1e6fd9` | `"#1e6fd9"` |
| `#1e6fd980` | `"#1e6fd980"` |
| `#00000000` | `"#00000000"` |

It is stored in 4 columns, each named for the field, `_` and its suffix. This is `#1e6fd9`:

| Column | Type | Holds |
|---|---|---|
| `<field>_red` | `smallint` | `30` |
| `<field>_green` | `smallint` | `111` |
| `<field>_blue` | `smallint` | `217` |
| `<field>_alpha` | `smallint` | `255` |

## Shown to people

`text.format(value, locale:)` shows it to people in their locale.

With `locale: Locale.en_gb`:

| Value | Shown |
|---|---|
| `#000000` | `#000000` |
| `#ffffff` | `#ffffff` |
| `#1e6fd9` | `#1e6fd9` |
| `#1e6fd980` | `#1e6fd980` |
| `#00000000` | `#00000000` |

## Operations

- `colour.contrast(a: Colour, b: Colour) -> Decimal`: WCAG 2's contrast ratio between `a` and `b`, from 1.00 to 21.00, rounded down to 2 places, so `>= 4.5` never passes a ratio below it. Alpha isn't read: WCAG 2 defines contrast for opaque colours.
- `colour.from_hsl(hue: Angle, saturation: Percentage, lightness: Percentage) -> Colour`: The colour of a CSS Color 4 HSL hue, saturation and lightness, the percentages clamped to 0% to 100%: `colour.from_hsl(120deg, 100%, 25%)` is `#008000`.
- `colour.from_oklch(lightness: Percentage, chroma: Decimal, hue: Angle) -> Colour`: The colour of an OKLCH lightness, chroma and hue, clipped into sRGB, the lightness clamped to 0% to 100% and the chroma to 0 or more: `colour.from_oklch(62.8%, 0.2577, 29.23deg)` is `#ff0000`.
- `colour.mix(a: Colour, b: Colour, ratio: Percentage) -> Colour`: `a` and `b` mixed in OKLCH as CSS's `color-mix(in oklch, a, b ratio)` mixes them: `ratio` of `b`, the rest of `a`, the hue the shorter way round, with their alphas.
- `colour.with_lightness(value: Colour, lightness: Percentage) -> Colour`: `value` with its OKLCH lightness set to `lightness`, its chroma, hue and alpha kept, clipped into sRGB.

Like every standard type, it also has the contract's own operations: `text.parse`, `text.from`, `text.format`, `json.read`, `json.write` and `==`. It isn't ordered, so `<` and sorting don't take it. [Every standard type meets one contract](../topics/every-standard-type-meets-one-contract.md) says how they work.
