Culori Color Library
Culori is a comprehensive and general-purpose JavaScript color library, currently at stable version 4.0.2. It provides extensive functionality for working with colors across numerous color spaces, including conversions, interpolation, color difference calculations (like CIEDE2000 and DIN99), and blending functions. The library differentiates itself by offering up-to-date support for the color spaces defined in the CSS Color Module Level 4 specification, ensuring compliance with modern web standards. Culori maintains a relatively active release cadence, with recent updates focusing on bug fixes and alignment with CSS specifications, such as precise XYZ to Oklab conversions and correct reference ranges for Lab/Lch modes. Its modular design allows for tree-shaking, optimizing bundle sizes by only including necessary color space definitions and utility functions.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'l')
cause Attempting to access properties of a color object (e.g., `l` for lightness) where the input color was malformed, invalid, or the `converter` failed to parse it, resulting in an `undefined` or incomplete color object.fixAlways check the output of parsing or conversion functions. Use a type guard or nullish coalescing (e.g., `parsedColor?.l`) and ensure input color strings or objects are valid before accessing their properties. -
SyntaxError: Malformed color string
cause Providing a syntactically incorrect or malformed color string to `culori`'s parser, especially after v4.0.0's stricter CSS spec alignment. This can also occur if component ranges are incorrect (e.g., `oklch(70% 0..1 156)` instead of `oklch(70% 0.1 156)`).fixReview the input color string for correct CSS color syntax as per the CSS Color Module Level 4 specification. Ensure component ranges (e.g., L, C, H, alpha) and numerical formats are valid and adhere to `culori` v4's stricter parsing rules. -
Module not found: Error: Can't resolve 'culori/css'
cause Attempting to import specific color space functions from a `culori/css` sub-bundle. While this path existed for certain exports in older versions, most primary color space functions are now directly exported from the main `culori` package in v4.fixFor most use cases, update your import statements to directly import functions from the main `culori` package (e.g., `import { oklch } from 'culori';`). Only use sub-paths if explicitly documented for specific advanced use cases. -
Build error: 'x' is not exported from 'culori'
cause Trying to import a symbol (e.g., a function or color space) that is either not a named export from the `culori` package, or was renamed/removed in a newer major version, or you're attempting a default import for a named export.fixConsult the `culori` API documentation for the correct named exports in your installed version. Ensure you are using `import { symbol } from 'culori';` for named exports and not `import symbol from 'culori';`.
Warnings
- breaking Culori v4.0.0 introduced significant changes to how color strings are parsed, converted, and serialized, impacting parsing of alpha components (now clamped to `[0, 1]`), clamping of L values in Lab/Lch/Oklab/Oklch, and numeric ranges for HSL/HWB syntaxes. Missing components are now serialized as `0` in legacy and `none` in modern syntaxes for better CSS spec alignment.
- gotcha The XYZ <-> Oklab conversion matrices were updated in v4.0.2 to precisely match those used in the `css-color-4` specification. This could lead to subtle numerical shifts in Oklab color values if previous versions were used and your application relies on pixel-perfect color matching.
- gotcha Prior to v4.0.2, the `toGamut()` function could crash with less descriptive error messages when the target color space lacked lightness and chroma components. It now throws a more useful error, which can expose previously hidden configuration issues.
- gotcha In v3.3.0, the sRGB inverse transfer function was updated to match the latest CSS spec. While technically a bug fix improving accuracy, this means sRGB conversions might yield slightly different (more correct) numerical results compared to earlier versions, potentially affecting applications sensitive to exact color calculations.
- gotcha Versions 3.1.2 and 3.1.3 addressed critical compatibility issues with various bundlers and the presence of non-ASCII identifiers in the source code. Projects using older bundlers (e.g., Webpack 4) or specific build configurations might encounter build failures or incorrect tree-shaking if these fixes are not present.
Install
-
npm install culori -
yarn add culori -
pnpm add culori
Imports
- converter
const converter = require('culori').converter;import { converter } from 'culori'; - rgb
import { RGB } from 'culori';import { rgb } from 'culori'; - interpolate
import interpolate from 'culori';
import { interpolate } from 'culori'; - oklch
import { oklch } from 'culori/css';import { oklch } from 'culori';
Quickstart
import { converter, rgb, oklch, interpolate, inGamut, clampGamut } from 'culori';
// 1. Convert colors between different color spaces
const parse = converter(); // Creates a universal color parser/converter
const redRgbString = 'rgb(255, 0, 0)';
const redOklch = parse(redRgbString, 'oklch');
console.log(`Red in Oklch: { l: ${redOklch.l.toFixed(3)}, c: ${redOklch.c.toFixed(3)}, h: ${redOklch.h?.toFixed(2) || 'N/A'} }`);
// 2. Interpolate between two colors in the Oklch space
const color1 = { mode: 'oklch', l: 0.5, c: 0.1, h: 60 }; // Yellow-ish
const color2 = { mode: 'oklch', l: 0.8, c: 0.15, h: 280 }; // Purple-ish
const interpolateOklch = interpolate([color1, color2], 'oklch');
const midColor = interpolateOklch(0.5); // Get the color at 50% interpolation
console.log(`Interpolated mid-color (Oklch): { l: ${midColor.l.toFixed(3)}, c: ${midColor.c.toFixed(3)}, h: ${midColor.h?.toFixed(2) || 'N/A'} }`);
// 3. Check if a color is within a specific gamut (e.g., sRGB)
const brightGreen = { mode: 'rgb', r: 0, g: 1.5, b: 0.5 }; // Out of gamut
const isBrightGreenInSrgb = inGamut('rgb')(brightGreen);
console.log(`Is bright green {r:0, g:1.5, b:0.5} in sRGB gamut? ${isBrightGreenInSrgb}`);
// 4. Clamp a color to a specific gamut (sRGB)
const clampedGreen = clampGamut('rgb')(brightGreen);
console.log(`Clamped green to sRGB: rgb(${Math.round(clampedGreen.r * 255)}, ${Math.round(clampedGreen.g * 255)}, ${Math.round(clampedGreen.b * 255)})`);
// 5. Create an Oklch color and convert it to an sRGB string for CSS output
const cssBlue = oklch(70, 0.15, 240); // A light blue Oklch color
const toRgbString = converter('rgb'); // Get a converter that outputs RGB objects
const cssBlueRgb = toRgbString(cssBlue);
const cssOutput = `rgb(${Math.round(cssBlueRgb.r * 255)}, ${Math.round(cssBlueRgb.g * 255)}, ${Math.round(cssBlueRgb.b * 255)})`;
console.log(`Oklch color ${JSON.stringify(cssBlue)} as CSS RGB string: ${cssOutput}`);