// Matrix conversions behind lib/color.ts, kept apart from its object API and // clamping rules. Internal - nothing here is re-exported from the package. // Units are native: sRGB and linear components 0-1, OKLab L 0-1, hue in degrees. /** Applies the sRGB transfer function in reverse, giving linear light. */ export function srgbToLinear(c: number): number { return c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4 } /** Applies the sRGB transfer function, giving an encoded component. */ export function linearToSrgb(c: number): number { return c <= 0.0031308 ? c * 12.92 : 1.055 * c ** (1 / 2.4) - 0.055 } // Matrices are Björn Ottosson's reference values, https://bottosson.github.io/posts/oklab/. export function linearRgbToOklab(r: number, g: number, b: number): [number, number, number] { const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b) const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b) const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b) return [ 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s, 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s, 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s, ] } export function oklabToLinearRgb(L: number, a: number, b: number): [number, number, number] { const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3 const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3 const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3 return [ 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s, -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s, -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s, ] } /** Converts OKLCh to encoded sRGB components, without clamping. */ export function oklchToSrgb(L: number, chroma: number, hue: number): [number, number, number] { const radians = (hue * Math.PI) / 180 const linear = oklabToLinearRgb(L, chroma * Math.cos(radians), chroma * Math.sin(radians)) return [linearToSrgb(linear[0]), linearToSrgb(linear[1]), linearToSrgb(linear[2])] }