esoc-color 0.1.0

OKLab/OKLCH color system — perceptual color math, CVD simulation, palettes, gamut clipping
Documentation
  • Coverage
  • 100%
    65 out of 65 items documented0 out of 43 items with examples
  • Size
  • Source code size: 34.55 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 835.33 kB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 17s Average build duration of successful builds.
  • all releases: 17s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Slush97/esolearn
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • Slush97

esoc-color

Perceptual color math for data visualization. OKLab/OKLCH conversions, palettes, color scales, color-vision-deficiency simulation, WCAG contrast, and gamut clipping. Zero external dependencies.

The core type is Color#[repr(C)] linear RGBA in f32, designed to upload directly to GPU buffers without conversion. All perceptual operations (mixing, gradients, distance) happen in OKLab space, so blends look the way humans perceive them rather than the way sRGB averages them.

Install

[dependencies]
esoc-color = "0.1"

What's in here

  • OKLab / OKLCH — round-trip conversions following Björn Ottosson's reference matrices.
  • Palettes — built-in tab10 (categorical), viridis (sequential), rdbu (diverging), plus sequential / diverging / categorical builders for custom maps.
  • ColorScale[0, 1] → Color lookup with helpers for generating GPU 1D textures.
  • CVD simulation — protanopia, deuteranopia, tritanopia (Viénot/Brettel/Mollon matrices), with severity interpolation.
  • WCAG contrastcontrast_ratio, meets_aa, meets_aaa, and a text_color_on(bg) helper that picks black or white for legibility.
  • Gamut clipping — keep OKLCH colors inside the sRGB gamut without hue shifts.

Example

use esoc_color::{Color, ColorScale};
use esoc_color::contrast::text_color_on;

let scale = ColorScale::viridis();
let mid = scale.map(0.5);

let bg = Color::from_srgb8(0x1f, 0x77, 0xb4);
let label = text_color_on(bg); // Color::WHITE or Color::BLACK

Design notes

Linear RGB is the storage format because it's what shaders want. The sRGB encode/decode helpers are explicit (Color::from_srgb8, Color::to_srgb8) so it's always obvious where the gamma boundary is. Palette::sample interpolates in OKLab, not RGB — straight-line interpolation in linear or sRGB produces muddy mid-tones, which is why most matplotlib-style colormaps look wrong when naively lerped.

License

MIT OR Apache-2.0