# pxstud.io Lua scripting API — Color

> Part of the pxstud.io Lua scripting reference, whose overview (https://pxstud.io/docs/scripting.md) explains its conventions. The option groups and types it refers to are in https://pxstud.io/docs/scripting/option-groups.md and https://pxstud.io/docs/scripting/types.md. Everything in one file: https://pxstud.io/llms-full.txt. The whole site's index: https://pxstud.io/llms.txt.

### Color
Color math without hand-rolled hex parsing and RGB mixing. Colors in are "#rrggbb" / "#rrggbbaa" strings or { r, g, b, a } tables (0-255, a optional); colors out are { r, g, b, a } tables unless the name says hex. Mixing and adjusting default to OKLab, a perceptual space where equal steps look equal; `space` can be "oklab", "oklch", "rgb" or "hsl". Results are clamped to sRGB by reducing chroma, so hue and lightness hold. Lists (ramp, shades) are built in one call.

#### `app.color.adjust(c, opts?)` — pure
Changes a color's lightness, chroma, hue, saturation or alpha, absolutely or relatively. The result is gamut-clamped to sRGB by reducing chroma (lightness and hue are kept), not by clipping channels.

- `c` (color) — A color: "#rrggbb", "#rrggbbaa" or { r, g, b, a }.
- `opts` (table, optional) — Absolute keys set a value; the d-prefixed keys add to it (the set is applied first, then the delta). Omitted keys keep the color's own value.
  - `lightness` (number) — Set the lightness: OKLab/OKLCH L (0 black - 1 white), or HSL lightness with space = "hsl".
  - `chroma` (number ≥ 0) — Set the OKLCH chroma (colorfulness, 0 = gray; sRGB tops out near 0.32). Not available with space = "hsl".
  - `hue` (number) — Set the hue angle in degrees (wraps around 360).
  - `saturation` (number 0–1) — Set the saturation 0-1: HSL saturation with space = "hsl"; otherwise chroma as a fraction of the most chroma sRGB allows at that lightness and hue.
  - `alpha` (number 0–255) — Set the alpha, 0-255.
  - `dLightness` (number) — Add to the lightness (negative darkens).
  - `dChroma` (number) — Add to the chroma.
  - `dHue` (number) — Rotate the hue by this many degrees.
  - `dSaturation` (number) — Add to the saturation (0-1 scale).
  - `dAlpha` (number) — Add to the alpha (0-255 scale).
  - `space` (string; default "oklab") — "oklab" | "oklch" (the same here) | "hsl". "rgb" has no lightness or hue axis and is rejected.

Returns (table): { r, g, b, a }, each 0-255.

#### `app.color.contrast(a, b)` — pure
WCAG contrast ratio between two colors (alpha ignored), from 1 (identical) to 21 (black on white). 4.5 is the usual minimum for readable text.

- `a` (color) — A color: "#rrggbb", "#rrggbbaa" or { r, g, b, a }.
- `b` (color) — A color: "#rrggbb", "#rrggbbaa" or { r, g, b, a }.

Returns (number): The ratio, 1-21.

#### `app.color.darken(c, amount, space?)` — pure
Shortcut for app.color.adjust(c, { dLightness = -amount }).

- `c` (color) — A color: "#rrggbb", "#rrggbbaa" or { r, g, b, a }.
- `amount` (number) — Subtracted from the lightness (OKLab L units, 0-1).
- `space` (string, optional) — Where lightness is measured: "oklab" (default), "oklch" or "hsl".

Returns (table): { r, g, b, a }, each 0-255.

#### `app.color.distance(a, b)` — pure
Euclidean distance between two colors in OKLab (alpha ignored). 0 = identical; black to white is 1; about 0.02 is barely noticeable.

- `a` (color) — A color: "#rrggbb", "#rrggbbaa" or { r, g, b, a }.
- `b` (color) — A color: "#rrggbb", "#rrggbbaa" or { r, g, b, a }.

Returns (number): The distance, 0 or more.

#### `app.color.hex(c, withAlpha?)` — pure
A color as a lowercase hex string.

- `c` (color) — A color: "#rrggbb", "#rrggbbaa" or { r, g, b, a }.
- `withAlpha` (boolean, optional) — true for "#rrggbbaa"; default "#rrggbb".

Returns (string): "#rrggbb", or "#rrggbbaa" with withAlpha.

#### `app.color.lighten(c, amount, space?)` — pure
Shortcut for app.color.adjust(c, { dLightness = amount }).

- `c` (color) — A color: "#rrggbb", "#rrggbbaa" or { r, g, b, a }.
- `amount` (number) — Added to the lightness (OKLab L units, 0-1).
- `space` (string, optional) — Where lightness is measured: "oklab" (default), "oklch" or "hsl".

Returns (table): { r, g, b, a }, each 0-255.

#### `app.color.mix(a, b, t, space?)` — pure
Blends two colors (alpha too) in a perceptual space; OKLab by default, which avoids the muddy midpoints of RGB mixing.

- `a` (color) — A color: "#rrggbb", "#rrggbbaa" or { r, g, b, a }.
- `b` (color) — A color: "#rrggbb", "#rrggbbaa" or { r, g, b, a }.
- `t` (number) — 0 = a, 1 = b; clamped to 0-1.
- `space` (string, optional) — Interpolation space: "oklab" (default), "oklch" (hue travels the short way round), "rgb" or "hsl".

Returns (table): { r, g, b, a }, each 0-255.

#### `app.color.nearest(c, palette)` — pure
The palette entry closest to c by OKLab distance (alpha ignored). Ties go to the earlier entry.

- `c` (color) — A color: "#rrggbb", "#rrggbbaa" or { r, g, b, a }.
- `palette` (table) — A non-empty list of colors.

Returns (number): The 1-based index into palette.

#### `app.color.parse(c)` — pure
Normalizes any accepted color to { r, g, b, a } (a = 255 when the input has none).

- `c` (color) — A color: "#rrggbb", "#rrggbbaa" or { r, g, b, a }.

Returns (table): { r, g, b, a }, each 0-255.

#### `app.color.ramp(stops, n, space?)` — pure
A gradient sampled into a list of n colors, first to last stop, both endpoints included. One call regardless of n.

- `stops` (table) — A list of colors, or of { color =, pos = } with pos 0-1 (stops without pos are spaced evenly). Needs at least one.
- `n` (number) — How many colors to return, 1-4096. 1 returns the first stop.
- `space` (string, optional) — Interpolation space: "oklab" (default), "oklch" (hue travels the short way round), "rgb" or "hsl".

Returns (table): A list of n { r, g, b, a } colors.

#### `app.color.shades(base, n, opts?)` — pure
A shadow-to-highlight list of n colors around base, for shading. The base sits at index floor(n / 2) + 1 (the middle for odd n) and is returned exactly. With f running from -1 (darkest) through 0 (base) to +1 (lightest), shade i has OKLab lightness L + f * spread / 2 (clamped to 0-1), hue H + f * hueShift, and chroma C * (1 - 0.4 * f^2) so the extremes stay inside sRGB (anything still outside loses chroma, never lightness). Alpha is kept. Lightness is monotonic along the list.

- `base` (color) — A color: "#rrggbb", "#rrggbbaa" or { r, g, b, a }.
- `n` (number) — How many colors to return, 1-4096.
- `opts` (table, optional)
  - `spread` (number; default 0.5) — Total OKLab lightness range, shadow to highlight (the base is the middle: half the spread down, half up). Clamped to 0-1.
  - `hueShift` (number; default 8) — Degrees the hue turns at the extremes: shadows by -hueShift, highlights by +hueShift, scaling linearly to 0 at the base.

Returns (table): A list of n { r, g, b, a } colors, darkest first.
