npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

web-color-extractor

v1.0.0

Published

High-performance, zero-dependency client-side dynamic color palette extractor using HTML5 Canvas, MMCQ algorithm, and Web Workers.

Downloads

28

Readme

web-color-extractor 🎨

High-performance, zero-dependency client-side dynamic color palette extraction library and React Hook for Web & PWAs. Powered by HTML5 Canvas, Modified Median Cut Quantization (MMCQ), and Web Workers.

TypeScript React License Web Workers


✨ Features

  • ⚡ Non-Blocking Web Worker Execution: Offloads heavy pixel sampling and 3D RGB quantization to background threads to guarantee smooth 60 FPS UI performance.
  • 🎨 7 Categorized Profile Tokens: Automatically categorizes colors into dominant, vibrant, lightVibrant, darkVibrant, muted, lightMuted, and darkMuted swatches.
  • ⚛️ First-Class React Integration: Includes the reactive useColorExtractor hook with loading and error states out of the box.
  • 🛡️ WCAG 2.1 Contrast Validator: Calculates relative luminance and contrast ratios according to W3C standards to auto-select accessible white vs. black text.
  • 📷 Universal Image Source Input: Accepts image URLs (string), HTMLImageElement, HTMLCanvasElement, file uploads (File), and Blob.
  • 📦 Zero External Dependencies: Lightweight and self-contained footprint for fast web load times.

📦 Installation

# Using npm
npm install web-color-extractor

# Using yarn
yarn add web-color-extractor

# Using pnpm
pnpm add web-color-extractor

🚀 Quickstart Guide

1. React Hook (useColorExtractor)

import React from 'react';
import { useColorExtractor } from 'web-color-extractor';

export function DynamicAlbumCard({ imageSrc }: { imageSrc: string }) {
  const { palette, loading, error, processTimeMs } = useColorExtractor(imageSrc, {
    maxColors: 10,
    useWorker: true,
  });

  if (loading) return <div>Extracting palette...</div>;
  if (error) return <div>Failed to extract palette</div>;

  return (
    <div
      style={{
        backgroundColor: palette?.darkVibrant?.hex || '#0f172a',
        color: palette?.vibrant?.hex || '#38bdf8',
        padding: '24px',
        borderRadius: '20px',
        transition: 'all 0.5s ease',
      }}
    >
      <h2>{palette?.vibrant?.hex}</h2>
      <p>Extraction finished in {processTimeMs} ms</p>
    </div>
  );
}

2. Vanilla JavaScript / Async API (extractPalette)

import { extractPalette } from 'web-color-extractor';

async function applyTheme(imageSource: string | File | HTMLImageElement) {
  const palette = await extractPalette(imageSource, {
    quality: 5,        // Downsample step (1 = highest quality, 5 = faster)
    maxColors: 10,     // Number of colors to quantize
    useWorker: true,   // Process MMCQ in Web Worker thread
    maxDimension: 300,  // Max canvas resolution before downsampling
  });

  console.log('Dominant Color:', palette.dominant?.hex);
  console.log('Vibrant Color:', palette.vibrant?.hex);
  console.log('Dark Vibrant:', palette.darkVibrant?.hex);
  console.log('All Quantized Swatches:', palette.allSwatches);

  // Apply to CSS custom properties
  document.documentElement.style.setProperty('--bg-dynamic', palette.darkVibrant?.hex || '#121826');
  document.documentElement.style.setProperty('--accent-dynamic', palette.vibrant?.hex || '#38bdf8');
}

📖 API Reference

extractPalette(source, options?)

Extracts a categorized ColorPalette asynchronously.

  • source: string | HTMLImageElement | HTMLCanvasElement | File | Blob
  • options: ExtractorOptions (Optional)

ExtractorOptions

| Option | Type | Default | Description | | :--- | :--- | :--- | :--- | | maxColors | number | 10 | Maximum number of colors to quantize. | | quality | number | 5 | Downsample step size: 1 samples every pixel, 5 samples every 5th pixel for speed. | | maxDimension | number | 300 | Max width/height dimension to scale canvas image down before processing. | | useWorker | boolean | true | Runs MMCQ algorithm inside a Web Worker thread if supported. | | alphaThreshold | number | 125 | Skips transparent/semi-transparent pixels (0-255). | | ignoreWhite | boolean | false | Ignores near-white background padding pixels. |


useColorExtractor(source, options?)

Custom React hook returning state object:

interface UseColorExtractorState {
  palette: ColorPalette | null;
  loading: boolean;
  error: Error | null;
  processTimeMs: number;
}

📊 Data Structures

ColorPalette

interface ColorPalette {
  dominant: ColorSwatch | null;     // Most frequent color
  vibrant: ColorSwatch | null;      // High saturation, balanced lightness
  lightVibrant: ColorSwatch | null; // High saturation, high lightness
  darkVibrant: ColorSwatch | null;  // High saturation, low lightness
  muted: ColorSwatch | null;        // Low saturation, balanced lightness
  lightMuted: ColorSwatch | null;   // Low saturation, high lightness
  darkMuted: ColorSwatch | null;    // Low saturation, low lightness
  allSwatches: ColorSwatch[];       // All quantized swatches ordered by population
}

ColorSwatch

interface ColorSwatch {
  rgb: [number, number, number]; // [r, g, b] (0-255)
  hex: string;                   // "#38BDF8"
  hsl: { h: number; s: number; l: number }; // h: 0-360, s: 0-100, l: 0-100
  population: number;            // Pixel count in bucket
  percentage: number;            // % of total image coverage
  isDark: boolean;               // True if luminance < 0.35
}

🛡️ Utilities

The library also exports standalone utility functions for WCAG accessibility and color conversions:

import { evaluateWCAG, getContrastRatio, rgbToHex, rgbToHsl } from 'web-color-extractor';

// Evaluate text contrast compliance for a background RGB
const wcag = evaluateWCAG([18, 24, 38]);
console.log(wcag.contrastRatio);       // e.g. 14.2:1
console.log(wcag.preferredTextColor);  // "#FFFFFF" or "#000000"
console.log(wcag.scoreAA);             // true
console.log(wcag.scoreAAA);            // true

🛠️ Local Development & Running the Showcase App

  1. Clone & Install Dependencies:

    cd web-color-extractor
    npm install
  2. Start Dev Server:

    npm run dev

    Open http://localhost:3000 to view the Material 3 showcase demo app.

  3. Build for Production:

    npm run build

📄 License

MIT License © Aakash Sakhalkar