index.html
01
Color Thief works in browsers and Node.js. Pick the method that fits your setup.
npm install colorthief
import { getColorSync, getPaletteSync } from 'colorthief';
const { getColor, getPalette } = require('colorthief');
`<script src="https://unpkg.com/colorthief@3/dist/umd/color-thief.global.js"></script>
<script> const color = ColorThief.getColorSync(img); </script>`<script type="module"> import { getColorSync } from 'https://unpkg.com/colorthief@3/dist/index.js'; </script>
02
The simplest way to use Color Thief. Extract the single dominant color from an image, synchronously.
const color = getColorSync(img); color.hex(); // '#e84393' color.textColor; // '#000000'
03
Extract a multi-color palette. Each color in the palette is a full Color object.
const palette = getPaletteSync(img, { colorCount: 8 }); palette.forEach(c => console.log(c.hex()));
04
Every extracted color is a rich object with format conversions, accessibility metadata, and contrast ratios.
`const color = getColorSync(img);
color.rgb() // { r, g, b } color.hex() // '#rrggbb' color.hsl() // { h, s, l } color.oklch() // { l, c, h } color.css() // 'rgb(255, 128, 0)' — also 'hsl' and 'oklch' color.array() // [r, g, b] color.toString() // '#rrggbb' — works in template literals color.textColor // '#ffffff' or '#000000' color.isDark // true/false color.isLight // true/false color.contrast // { white, black, foreground } color.population // raw pixel count color.proportion // 0–1 share of total`
05
Classify palette colors into six semantic roles: Vibrant, Muted, DarkVibrant, DarkMuted, LightVibrant, LightMuted. Each swatch includes text color recommendations.
const swatches = getSwatchesSync(img); swatches.Vibrant?.color.hex(); // '#e84393' swatches.DarkMuted?.titleTextColor.hex(); // '#ffffff'
06
OKLCH quantization produces more perceptually uniform palettes. Colors that "feel" evenly spaced to the human eye.
`// Default — quantize in sRGB const rgb = getPaletteSync(img, { colorCount: 8 });
// Perceptual — quantize in OKLCH const oklch = getPaletteSync(img, { colorCount: 8, colorSpace: 'oklch' });`
07
The quality option controls how many pixels are sampled. Lower values sample more pixels (slower, more accurate). Default is 10.
getPaletteSync(img, { quality: 1 }); // Every pixel getPaletteSync(img, { quality: 10 }); // Every 10th pixel (default) getPaletteSync(img, { quality: 50 }); // Every 50th pixel
08
The async API works on both browser and Node.js. With worker: true, quantization runs off the main thread.
`// Async (works in browser and Node.js) const palette = await getPalette(img, { colorCount: 6 });
// Offload to Web Worker (browser only) const palette = await getPalette(img, { colorCount: 6, worker: true });`
09
Progressively extract a palette in 3 passes. Show a rough result instantly, then refine it. Useful for large images where full extraction takes time.
for await (const { palette, progress, done } of getPaletteProgressive(img)) { updateUI(palette, progress); // progress: 0.06 → 0.25 → 1.0 }
10
Cancel in-flight extractions with a standard AbortSignal. Useful when the user navigates away before extraction completes.
`const controller = new AbortController(); controller.abort(); // cancel immediately
try { await getColor(img, { signal: controller.signal }); } catch (e) { console.log(e.name); // 'AbortError' }`
11
Build a Color object manually from RGB values. Useful for creating colors programmatically or working with known values.
const color = createColor(232, 67, 147, 1); color.hex(); // '#e84393' color.isDark; // false color.textColor; // '#000000' ${color}; // '#e84393' — toString() returns hex
12
Reactively watch a source and get palette updates whenever it changes. Works with <video>, <canvas>, and `` elements. For video, extraction runs on each animation frame (throttled) while playing, and on seek. For canvas, it polls via rAF. For images, it uses a MutationObserver to detect src changes.
`const controller = observe(videoElement, { throttle: 200, // ms between updates colorCount: 5, onChange(palette) { const dominant = palette[0]; document.body.style.background = dominant.css(); }, });
controller.stop(); // clean up`
Dominant