MCPcopy
hub / github.com/lokesh/color-thief

github.com/lokesh/color-thief @v3.4.0 sqlite

repository ↗ · DeepWiki ↗ · release v3.4.0 ↗
194 symbols 462 edges 38 files 23 documented · 12%
README

Color Thief

Extract dominant colors and palettes from images in the browser and Node.js.

npm version npm bundle size types

Install

npm install colorthief

Or load directly from a CDN:

<script src="https://unpkg.com/colorthief@3/dist/umd/color-thief.global.js"></script>

Quick Start

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();

Features

  • 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 extractionobserve() 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 contrastcolor.contrast.white, color.contrast.black, color.contrast.foreground
  • AbortSignal — cancel in-flight extractions
  • CLIcolorthief photo.jpg with JSON, CSS, and ANSI output
  • Zero runtime dependencies

API at a Glance

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

Options

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'
gamut 'srgb' Output gamut: 'srgb', 'display-p3', or 'auto' (browser only)
worker false Offload to Web Worker (browser only)
signal AbortSignal to cancel extraction
ignoreWhite true Skip white pixels

Color Object

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(…)' — a P3 color's default .css() is color(display-p3 …)
.array() [r, g, b]
.gamut 'srgb' or 'display-p3'
.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

Browser

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.

Wide-gamut (Display P3)

By default colors are read and reported in sRGB. For P3-tagged / wide-gamut images, pass gamut to preserve the extra saturation:

// Force P3: read the image through a P3 canvas, report P3 colors
const palette = await getPalette(img, { gamut: 'display-p3' });
palette[0].css();            // 'color(display-p3 0.92 0.2 0.14)'
palette[0].gamut;            // 'display-p3'

// Auto: report P3 only when the image actually uses out-of-sRGB colors,
// otherwise behave exactly like sRGB
const auto = await getPalette(img, { gamut: 'auto' });

.rgb(), .array(), and .hex() always return sRGB (gamut-mapped when the color is P3), so existing rgb(...) strings keep working. The wide-gamut values live in .css() and .oklch(); use .rgb('display-p3') for the raw P3 components. Falls back to sRGB where P3 canvas support is unavailable. Node output is sRGB for now.

Live extraction with observe()

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.

Node.js

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.

CLI

Quick start

npx colorthief-cli photo.jpg

The colorthief-cli package bundles everything needed (including sharp for image decoding), so it works immediately with no extra setup.

Commands

# Dominant color
colorthief-cli photo.jpg

# Color palette
colorthief-cli palette photo.jpg

# Semantic swatches
colorthief-cli swatches photo.jpg

Output formats

# 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;
# }

Options

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 colorthief and sharp installed in a project, you can also use colorthief directly as the command name (without the -cli suffix).

Links

Contributing

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

Releasing

# 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 --tags

License

MIT - Lokesh Dhakar

Extension points exported contracts — how you extend this code

Quantizer (Interface)
(no doc) [4 implementers]
src/types.ts
ValidatedOptions (Interface)
(no doc)
src/pipeline.ts
ObserveOptions (Interface)
(no doc)
src/observe.ts
SyncExtractionOptions (Interface)
(no doc)
src/sync.ts
SwatchTarget (Interface)
(no doc)
src/swatches.ts
CliArgs (Interface)
(no doc)
src/cli.ts
NodeLoaderOptions (Interface)
(no doc)
src/loaders/node.ts
Color (Interface)
(no doc) [2 implementers]
src/types.ts

Core symbols most depended-on inside this repo

createColor
called by 41
src/color.ts
array
called by 28
src/types.ts
imgPath
called by 26
test/node-test.js
img
called by 19
test/cli-test.js
run
called by 19
test/cli-test.js
srgbToLinear
called by 19
src/color-space.ts
push
called by 19
src/quantizers/mmcq.ts
getPalette
called by 18
src/api.ts

Shape

Function 109
Method 52
Interface 19
Class 14

Languages

TypeScript100%

Modules by API surface

src/quantizers/mmcq.ts27 symbols
src/types.ts22 symbols
src/color.ts21 symbols
src/color-space.ts17 symbols
src/cli.ts15 symbols
src/observe.ts9 symbols
src/api.ts9 symbols
src/loaders/browser.ts8 symbols
test/node-test.js7 symbols
src/sync.ts7 symbols
src/pipeline.ts7 symbols
src/loaders/node.ts7 symbols

Dependencies from manifests, versioned

@types/node20.11.0 · 1×
chai4.2.0 · 1×
chai-as-promised7.1.1 · 1×
cypress15.18.0 · 1×
http-server14.1.1 · 1×
mocha11.7.6 · 1×
mustache3.0.1 · 1×
sharp0.34.5 · 1×
tsup8.0.0 · 1×
typescript5.3.0 · 1×

For agents

$ claude mcp add color-thief \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact