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

chart-color-system

v0.7.3

Published

Contrast-, CVD-, and grayscale-audited categorical, sequential, and diverging chart palettes, with matched dash / decal / shape encodings.

Downloads

469

Readme

chart-color-system

Chart palettes that are audited before you ship them, not after someone files a bug.

Generates categorical, sequential, and diverging palettes and checks every one against WCAG non-text contrast, color-vision-deficiency simulation (deutan / protan / tritan / achromatopsia), and grayscale. Every color slot is paired 1:1 with a dash pattern, a decal, and a marker shape, so series stay identifiable when color fails.

Honesty note: past roughly six hues, no palette keeps colors reliably distinct under dichromacy. The CVD/ΔE floors are deliberately minimal at high N, and the redundant dash / decal / shape channels are what actually carry series identity there. This library tells you when that line is crossed instead of pretending it isn't.

For context on why this matters: of five widely used chart palettes, four fail the 3:1 WCAG non-text contrast floor on a white background at their worst slot — Tableau 10 at 1.61:1 (#EDC948), ColorBrewer Set2 at 1.38:1 (#FFD92F), Observable 10 at 1.91:1, and Material 700 at 1.66:1. Only IBM Carbon clears it, at 3.33:1.

Install

npm install chart-color-system culori

culori is a peer dependency so it dedupes against your copy.

Usage

import {
  solveCategorical,
  auditPalette,
  fromCss,
  dashScale,
  shapeScale,
} from "chart-color-system";

const background = fromCss("#ffffff");
const grid = fromCss("#e5e7eb");

const solved = solveCategorical({
  n: 8,
  posture: "comparative",  // "kpi" | "comparative" | "exploratory"
  background,
  grid,                    // colors are pushed away from your gridlines too
  locks: [],               // brand anchors in slot order; [] to solve freely
});

const report = auditPalette(solved.palette, background);

console.log(report.overall);            // "pass" | "warn" | "fail"
console.log(report.worstContrastVsBg);  // worst slot contrast vs. background
console.log(report.perVision);          // normal / deutan / protan / tritan / achromatopsia
console.log(solved.relaxations);        // which floors gave, and in what order

// Pair each slot with its non-color channels.
solved.palette.forEach((color, i) => {
  console.log(color.hex, dashScale[i], shapeScale[i]);
});

Auditing a sequential or diverging ramp? Pass true as the third argument so pairwise ΔE separation is skipped — gradient stops are meant to be perceptually close, and scoring them pairwise would flag every correct ramp as failing:

const ramp = sequentialRamp(fromCss("#f0f9ff"), fromCss("#0c4a6e"), 9);
const rampReport = auditPalette(ramp, background, true);

What's exported

| Area | Exports | |---|---| | Solvers | solveCategorical, sequentialRamp, divergingRamp, stableAssign | | Audit | auditPalette, simulateColor, contrastRatio | | CVD | simulateRgb, CVD_TYPES | | Color | fromCss, fromHsl, fromCssVar, deltaE, deltaL, cvdDeltaE | | Gamut | reduceToSrgb, oklchToRgb, oklchOf | | Constraints | POSTURE, THRESHOLDS, RELAXATION_ORDER, CVD_SEVERITY, PALETTE_SEED | | Encodings | dashScale, decalScale, shapeScale, MAX_SLOTS | | Version | PALETTE_VERSION |

Math is OKLab. The solver is seeded, so the same input always gives the same palette. The engine does no DOM work — the one exception is fromCssVar, which reads a custom property off a live element and is therefore browser-only.

The package version tracks PALETTE_VERSION: a version bump means the colors may have moved.

Interactive builder

Pick a chart type and an N, watch the audit update, and export the tokens: https://github.com/socraticstatic/Visualizations

Sponsor

If this saves you a week of arguing about chart colors: https://github.com/sponsors/socraticstatic

License

MIT © Micah Boswell

The palette engine in this package is MIT. The interactive builder application it was extracted from is proprietary and not included here.

Attribution

MIT requires the copyright and license text to travel with the code. If chart-color-system ships inside a commercial or enterprise product, also credit Micah Boswell — Chart Color System (https://socraticstatic.github.io/Visualizations/) in your documentation, about screen, or credits.