Extract dominant colors and palettes from images in the browser and Node.js.
npm install colorthiefOr load directly from a CDN:
<script src="https://unpkg.com/colorthief@3/dist/umd/color-thief.global.js"></script>import { getColorSync, getPaletteSync, getSwatches } from 'colorthief'; // Dominant color const color = getColorSync(img); color.hex(); // '#e84393' color.css(); // 'rgb(232, 67, 147)' color.isDark; // false color.textColor; // '#000000' // Palette const palette = getPaletteSync(img, { colorCount: 6 }); palette.forEach(c => console.log(c.hex())); // Semantic swatches (Vibrant, Muted, DarkVibrant, etc.) const swatches = await getSwatches(img); swatches.Vibrant?.color.hex();- TypeScript — full type definitions included
- Browser + Node.js — same API, both platforms
- Sync & async — synchronous browser API, async for Node.js and Web Workers
- Live extraction —
observe()watches video, canvas, or img elements and emits palette updates reactively - Web Workers — offload quantization off the main thread with
worker: true - Progressive extraction — 3-pass refinement for instant rough results
- OKLCH quantization — perceptually uniform palettes via
colorSpace: 'oklch' - Semantic swatches — Vibrant, Muted, DarkVibrant, DarkMuted, LightVibrant, LightMuted
- Rich Color objects —
.hex(),.rgb(),.hsl(),.oklch(),.css(), contrast ratios, text color recommendations - WCAG contrast —
color.contrast.white,color.contrast.black,color.contrast.foreground - AbortSignal — cancel in-flight extractions
- CLI —
colorthief photo.jpgwith JSON, CSS, and ANSI output - Zero runtime dependencies
| Function | Description |
|---|---|
getColorSync(source, options?) | Dominant color (sync, browser only) |
getPaletteSync(source, options?) | Color palette (sync, browser only) |
getSwatchesSync(source, options?) | Semantic swatches (sync, browser only) |
getColor(source, options?) | Dominant color (async, browser + Node.js) |
getPalette(source, options?) | Color palette (async, browser + Node.js) |
getSwatches(source, options?) | Semantic swatches (async, browser + Node.js) |
getPaletteProgressive(source, options?) | 3-pass progressive palette (async generator) |
observe(source, options) | Watch a source and emit palette updates (browser only) |
createColor(r, g, b, population) | Build a Color object from RGB values |
| Option | Default | Description |
|---|---|---|
colorCount | 10 | Number of palette colors (2–20) |
quality | 10 | Sampling rate (1 = every pixel, 10 = every 10th) |
colorSpace | 'oklch' | Quantization space: 'rgb' or 'oklch' |
worker | false | Offload to Web Worker (browser only) |
signal | — | AbortSignal to cancel extraction |
ignoreWhite | true | Skip white pixels |
| Property / Method | Returns |
|---|---|
.rgb() | { r, g, b } |
.hex() | '#ff8000' |
.hsl() | { h, s, l } |
.oklch() | { l, c, h } |
.css(format?) | 'rgb(255, 128, 0)', 'hsl(…)', or 'oklch(…)' |
.array() | [r, g, b] |
.toString() | Hex string (works in template literals) |
.textColor | '#ffffff' or '#000000' |
.isDark / .isLight | Boolean |
.contrast | { white, black, foreground } — WCAG ratios |
.population | Raw pixel count |
.proportion | 0–1 share of total |
import { getColorSync, getPaletteSync } from 'colorthief'; const img = document.querySelector('img'); const color = getColorSync(img); console.log(color.hex()); const palette = getPaletteSync(img, { colorCount: 5 });Accepts HTMLImageElement, HTMLCanvasElement, HTMLVideoElement, ImageData, ImageBitmap, and OffscreenCanvas.
import { observe } from 'colorthief'; // Watch a video and update ambient lighting as it plays const controller = observe(videoElement, { throttle: 200, // ms between updates colorCount: 5, onChange(palette) { updateAmbientBackground(palette); }, }); // Stop when done controller.stop();Works with <video>, <canvas>, and <img> elements. For images, it uses a MutationObserver to detect src changes. For video and canvas, it polls using requestAnimationFrame with throttle.
import { getColor, getPalette } from 'colorthief'; const color = await getColor('/path/to/image.jpg'); console.log(color.hex()); const palette = await getPalette(Buffer.from(data), { colorCount: 5 });Accepts file paths and Buffers. Uses sharp for image decoding.
npx colorthief-cli photo.jpgThe colorthief-cli package bundles everything needed (including sharp for image decoding), so it works immediately with no extra setup.
# Dominant color colorthief-cli photo.jpg # Color palette colorthief-cli palette photo.jpg # Semantic swatches colorthief-cli swatches photo.jpg# Default: ANSI color swatches colorthief-cli photo.jpg # ▇▇ #e84393 # JSON with full color data colorthief-cli photo.jpg --json # CSS custom properties colorthief-cli palette photo.jpg --css # :root { # --color-1: #e84393; # --color-2: #6c5ce7; # }colorthief-cli palette photo.jpg --count 5 # Number of colors (2-20) colorthief-cli photo.jpg --quality 1 # Sampling quality (1=best) colorthief-cli photo.jpg --color-space rgb # Color space (rgb or oklch)Stdin is supported — use - or pipe directly:
cat photo.jpg | colorthief-cli -Multiple files are supported. Output is prefixed with filenames, and --json wraps results in an object keyed by filename.
Note: If you already have
colorthiefandsharpinstalled in a project, you can also usecolorthiefdirectly as the command name (without the-clisuffix).
npm run build # Build all dist formats npm run test # Run all tests (Mocha + Cypress) npm run test:node # Node tests only npm run test:browser # Browser tests (requires npm run dev) npm run dev # Start local server on port 8080# 1. Make sure you're on master with a clean working tree git status # 2. Run the full test suite npm run build npm run test:node npm run test:browser # requires npm run dev in another terminal # 3. Preview what will be published npm pack --dry-run # 4. Tag and publish npm version <major|minor|patch> # bumps version, creates git tag npm publish # builds via prepublishOnly, then publishes git push && git push --tagsMIT - Lokesh Dhakar