Expand description
Theme-relative colorspace for perceptually uniform palette generation.
§Motivation
Terminal 256-color palettes have 240 extended colors (indices 16–255) that are hardcoded with fixed RGB values, completely ignoring the user’s base16 theme. This module implements jake-stewart’s proposal to generate those colors by trilinear interpolation in CIE LAB space using the 8 base ANSI colors as cube corners.
§Concept: Theme-Relative Color
Instead of addressing colors as absolute RGB values, this module lets you specify a position in a color cube whose corners are the user’s theme colors:
| Cube corner | ANSI color |
|---|---|
(0, 0, 0) | background (defaults to black) |
(1, 0, 0) | red |
(0, 1, 0) | green |
(1, 1, 0) | yellow |
(0, 0, 1) | blue |
(1, 0, 1) | magenta |
(0, 1, 1) | cyan |
(1, 1, 1) | foreground (defaults to white) |
A CubeCoord like (0.6, 0.2, 0.0) means “60% toward red, 20% toward
green, 0% blue” — the theme determines what that actually looks like on screen.
§Why CIE LAB?
LAB is a perceptually uniform colorspace: equal numerical distances correspond to equal perceived color differences. Interpolating in LAB (rather than RGB) ensures:
- Consistent brightness: blue shades at level 3 look as bright as green at level 3
- Smooth gradients: no muddy midpoints or perceptual jumps
- Hue preservation: interpolation follows natural color transitions
§Trilinear Interpolation
The 8 theme colors sit at the corners of a unit cube. For any point (r, g, b)
inside the cube, the color is computed by three nested linear interpolations in LAB:
- R-axis: Interpolate 4 edge pairs (bg→red, green→yellow, blue→magenta, cyan→fg)
- G-axis: Interpolate between the R-axis results to sweep across 2 faces
- B-axis: Interpolate between the G-axis results to fill the volume
At every grid point, the resulting color is a smooth blend of all 8 corner colors, weighted by proximity.
§Example
use standout_render::colorspace::{CubeCoord, Rgb, ThemePalette};
// Define a gruvbox-like palette (8 base colors)
let palette = ThemePalette::new([
Rgb(40, 40, 40), // black
Rgb(204, 36, 29), // red
Rgb(152, 151, 26), // green
Rgb(215, 153, 33), // yellow
Rgb(69, 133, 136), // blue
Rgb(177, 98, 134), // magenta
Rgb(104, 157, 106), // cyan
Rgb(168, 153, 132), // white
]);
// Resolve a theme-relative coordinate to an actual RGB color
let coord = CubeCoord::from_percentages(60.0, 20.0, 0.0).unwrap();
let color = palette.resolve(&coord);
// Generate a full 240-color extended palette (216 cube + 24 grayscale)
let extended = palette.generate_palette(6);
assert_eq!(extended.len(), 240);Structs§
- Cube
Coord - A position in the theme-relative color cube.
- Rgb
- A simple RGB color triplet.
- Theme
Palette - A set of 8 anchor colors that define a theme-relative color space.