Chart Color System

io.github.socraticstatic由 GitHub 帳號 socraticstatic 發布v0.1.2更新於 Oct 24, 2026

Solve, audit and simulate colorblind-safe chart palettes. WCAG contrast, OKLab ΔE. Read-only.

已驗證Streamable HTTP可網頁執行資料與分析媒體與設計

概覽

AI 產生的概覽

一個遠端 MCP 伺服器,用 OKLab 色差與 WCAG 對比度計算來求解、稽核並模擬色盲友善的圖表配色。

可以做什麼
產生 1 至 12 色的分類圖表配色,可將品牌色依槽位鎖定為錨點,並回傳最差配對距離與完整無障礙稽核。稽核現有圖表顏色:在正常視覺及四種色覺缺陷下的兩兩 OKLab 色差,以及每個顏色相對於圖表背景的 WCAG 2.2 非文字對比度,給出通過/警告/失敗結論。模擬每個顏色在綠色盲、紅色盲、藍色盲及全色盲讀者眼中的樣子。建立均勻間隔的 OKLab 順序或發散色階,並附上背景對比度稽核。
適用情境
適合在為圖表和儀表板挑選或複核配色時使用,希望取得可辯護的無障礙數據而非憑感覺判斷;也適合需要說明配色在色盲讀者眼中效果時使用。
執行需求
遠端 streamable HTTP 端點;未宣告任何套件、帳號、API 金鑰或環境變數。助理需要能存取該託管端點的網路。
安裝前請注意
此伺服器被描述為唯讀,僅計算顏色值,不會修改圖表或資料。其結論僅供參考:README 指出所設定的色差門檻是刻意設低的底線而非感知保證,尤其在超過約六種色相時。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Chart Color System,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Web executable,透過 Streamable HTTP。 遠端服務在工作區中設定後即可從網頁執行環境執行。

交給代理程式安裝

把這段提示詞貼上到 Claude Code、Codex、Cursor 等代理程式,或 SourceWeft 對話中。代理程式會讀取該伺服器的安裝指南,先向你展示發布者、端點和登入方式,經你同意後再把它新增到你的客戶端。金鑰不會寫進任何命令。

閱讀 https://sourceweft.com/mcp/io.github.socraticstatic%2Fchart-color-system/install.md,並按其中說明把這個 MCP 伺服器接入我的客戶端。修改任何設定之前,先告訴我它的發布者、端點和登入方式,等我確認。不要把 API 金鑰寫進命令或我會提交的檔案;問我金鑰應從哪裡取得。

檢視代理程式所依據的安裝指南

其他 MCP 客戶端

把它新增到你客戶端的 mcpServers 設定中。

{
  "mcpServers": {
    "chart-color-system": {
      "type": "http",
      "url": "https://chart-color-mcp.vercel.app/mcp"
    }
  }
}

README

Chart Color & Encoding System

By Micah Boswell (socraticstatic). Copyright © 2026 Micah Boswell. All rights reserved.

A token-driven, math-backed palette system for ECharts dashboards. Generates categorical, sequential, and diverging palettes, and pairs every color slot with a matching dash, decal, and marker shape so meaning survives even when color fails. Categorical palettes are audited pairwise against WCAG contrast, color-vision deficiency (CVD) simulation, and grayscale. Sequential and diverging ramps are audited for background contrast and built for monotonic OKLab lightness (their grayscale-survival property); pairwise ΔE separation is intentionally not applied to ramps, whose stops are designed to be perceptually adjacent. Honesty note: past ~6 hues, no palette keeps colors reliably distinct under dichromacy — the configured CVD/ΔE floors in constraints.ts are deliberately minimal at high N, and the redundant dash/decal/shape encodings are what carry series identity.

Current version: 0.7.0 (PALETTE_VERSION in src/charts/version.ts; history in CHANGELOG.md).


Jobs To Be Done

Primary

  • JTBD-1 — Pick a palette I can defend (contrast + CVD + grayscale audited).
  • JTBD-2 — Charts stay readable for colorblind users (color + dash + decal + shape).
  • JTBD-3 — Same entity stays the same color everywhere.
  • JTBD-4 — Doesn't break when series count changes (graceful Top-N + Other).
  • JTBD-5 — Light and dark mode equally good.
  • JTBD-6 — Right chart-type encoding chosen automatically.
  • JTBD-7 — Prove it works before shipping (live QA harness).

Secondary

  • JTBD-8 — Per-user color pin (localStorage, scoped by entity ID).
  • JTBD-9 — Brand-locked anchor slots seed the optimizer.
  • JTBD-10 — Surface infeasibility with documented relaxation order.
  • JTBD-11 — Instant theme switch (precomputed cache).
  • JTBD-12 — Stay maintainable (no raw color literals; versioned palette; docs always current).

Out of scope (named, not built): multi-tenant solving, SSR/PDF export, telemetry, task-based usability study.


Architecture

text
  index.css tokens (HSL)         │         ▼  constraints.ts  ──────┐  brand/semantic locks ─┤  background + chrome  ─┼──►  optimizer (OKLab + CVD + gamut)  N + posture          ─┤              │  reserved slots       ─┘              ▼                                ordered slot list                                (color, dash, decal, shape)                                       │                                       ▼                          echartsTheme.ts adapter                                       │                                       ▼                          ECharts components (demo)                                       │                                       ▼                          QA harness (CVD / grayscale / contrast)

Deliverables

#DeliverableServes JTBD
1Token contract (src/index.css + tailwind.config.ts)1, 5, 9, 12
2Constraint config (src/charts/constraints.ts)1, 9, 10
3Palette optimizer (src/charts/palette/)1, 2, 4, 10
4Aligned encoding scales (src/charts/encoding.ts)2, 3, 6
5ECharts theme adapter (src/charts/echartsTheme.ts)5, 6, 11
6Demo route /charts7
7QA harness (CVD / grayscale / contrast / posture / N)2, 7, 10
8Test suite1, 2, 4, 12
9Override + versioning scaffolding8, 12
10This README.md12
11CHANGELOG.md12

Tiers

Tier 1 — Tokens & constraints

Semantic chart tokens in index.css (HSL, light + dark): surfaces, neutrals, status, anchors, states. Tailwind chart color group exposes them. constraints.ts defines ΔE thresholds, posture presets (kpi, comparative, exploratory), Top-N + Other overflow, and constraint-relaxation priority.

Tier 2 — Optimizer & encoding scales

  • palette/cvd.ts — Machado 2009 deutan/protan/tritan matrices.
  • palette/distance.ts — OKLab ΔE + worst-of-three CVD ΔE.
  • palette/gamut.ts — chroma-reduction gamut mapping into sRGB.
  • palette/categorical.ts — seeded farthest-point + simulated-annealing maximin solver.
  • palette/ramps.ts — monotonic-L OKLCH sequential and diverging ramps.
  • palette/assignment.ts — bipartite stable assignment when N changes.
  • encoding.ts — dashScale, decalScale, shapeScale indexed 1:1 with color.

Tier 3 — Adapter, demo, lifecycle

  • echartsTheme.ts reads CSS vars at runtime and emits an ECharts theme + helpers (buildLineSeries, buildBarSeries, buildVisualMap).
  • components/charts/EChart.tsx wraps echarts-for-react with atomic theme swap.
  • /charts is a constrained palette builder beside the chart preview: chart type, N, theme, vision preview, and fixtures are controlled from one place. Posture, palette family, and ramp shape are derived. The default N snap is capped to the runtime-probed safe max so out-of-the-box palettes clear every configured ΔE / CVD floor and WCAG 3:1 contrast with zero solver relaxations; the slider can be dragged past the safe cap into an educational range where the audit panel shows exactly which floors break.
  • Every render runs the accessibility audit (audit.ts): per-vision OKLab ΔE (normal + deutan + protan + tritan + achromatopsia) against per-mode thresholds, plus WCAG 2.2 SC 1.4.11 (≥ 3:1) contrast vs. background. Result is shown as a pass / warn / fail badge with per-vision detail.
  • setEntityColor(entityId, slotIndex) persists per-user pins in localStorage.
  • PALETTE_VERSION aligns with CHANGELOG.md.

Run

bash
npm installnpm run dev

Then open the preview and navigate to /charts.

Tests

bash
npx vitest run

Covers the palette primitives (stableAssign, sequentialRamp L-monotonicity, divergingRamp length, aligned encoding scales), solveCategorical property tests across N=2..8 (determinism, in-gamut sRGB, threshold-or-relaxation contract, lock-honoring), entity pins (permutation safety, collision bumping, paired remap of color/dash/decal/shape), URL state round-trips, and fixture determinism + messy-mode characteristics (nulls on lines, missing heatmap cells, diverging outliers).

Reading the accessibility harness

  • Overall verdict: pass (all modes pass + WCAG ≥ 3:1), warn (≤ 1 vision mode fails, contrast still passes), or fail.
  • Per-vision tiles: minimum pairwise ΔE under each simulation, vs. the configured threshold. Note the CVD and normal-vision thresholds (constraints.ts) are deliberately low floors, not perceptual guarantees — they exist to catch outright collisions while the dash/decal/shape scales carry identity at high N.
  • Worst contrast vs. background: WCAG 2.2 SC 1.4.11 ratio for non-text marks; threshold ≥ 3:1.
  • Best-practice rationale: one-line explanation of why this chart type has its specific limits, plus per-N warnings (e.g. "Pie charts above 5 slices misrepresent magnitudes").

Exporting a palette

The green Export palette button on /charts opens a tabbed dialog with five emitters from src/charts/paletteExport.ts:

  • CSS variables — :root (or .dark) block with --chart-bg, --chart-cat-N, --chart-seq-N, --chart-div-N, plus semantic positive/negative. When Compare is on with normal vision, Variant B is emitted under [data-chart-variant="b"].
  • Tailwind config — chart.cat/seq/div map that references the CSS vars above, paste-ready under theme.extend.colors.
  • ECharts theme — full registerTheme payload (color, backgroundColor, axis/legend/tooltip, sequential + diverging visualMap ramps).
  • Figma Tokens — Tokens Studio / W3C-style JSON with chart.{surface,semantic,categorical,sequential,diverging} and $metadata.generator.
  • SVG swatches — single-page printable sheet labeled with hex + slot index.

The Export audit report button (next to it) still produces the standalone HTML audit (charts + warnings + accessibility metrics, single-variant or A vs. B).

Palette builder

The only active builder controls live beside the chart preview. They update the rendered chart immediately, clamp N to the safe built-in range for the selected kind/theme, and clear any stale inline token overrides on load so built-in palettes remain compliant.

Coach tour

A coach tour auto-opens on first visit (localStorage["chart-tour-seen-v1"]) and walks through the chart-side builder controls and export flow. Replay it anytime via Take the tour in the page header.

Presets

The Presets panel ships 6 curated starters ("Finance KPI", "Analytics exploratory", "Board / comparative", "Marketing share", "Ops heatmap", "Variance / diverging") and lets you save your own named (kind, n, theme) configurations under localStorage["chart-palette-presets-v1"]. Color overrides are stored separately so presets stay solver-stable across palette updates. The Compare presets sub-panel lets you pick any two (curated, user, or the live builder state) and shows a side-by-side diff of chart kind, family, posture, N, recommended N, max N, and theme — differing rows highlighted in warning tint, ⚠ flags N above the kind's recommended ceiling.

Entity pins

The Entity pins panel (categorical charts) lets you lock a series to a specific slot — color, dash, decal, and shape together — so the same entity keeps the same identity across filters, reloads, and dashboards. "Auto" means "let the solver assign the next free slot in order"; picking Slot k writes the pin to localStorage["chart-entity-color-pins-v1"] via setEntityColor. Collisions (two entities pinning the same slot) are auto-resolved — the later entity is bumped to the next free slot and listed under "Collisions". Implements JTBD-3 ("keep the same entity the same color everywhere").

Benchmark vs. published systems

For categorical charts, a Benchmark vs. published systems table scores the current solver palette next to Tableau 10, IBM Carbon Categorical, ColorBrewer Set2, Observable 10, and Material 700 — using identical math (min pairwise ΔE in OKLab, worst-of-three CVD ΔE, worst contrast vs. your current background). ★ marks the winner per column.

Density preview

For categorical charts, the Density preview renders every slot at realistic chart-element sizes (11px legend swatch, 2px line stroke, 4px bar, 8px scatter dot, deterministic sparkline) against the active background — so you catch slots that vanish at small sizes before shipping.

Copy decision rationale

The Copy rationale button inside the Explain panel copies a paragraph-formatted decision summary (inputs · family · posture · N · solver/ramp note · relaxations · accessibility verdict) to the clipboard, ready to paste into a PR, ticket, or design spec.

Shareable deep links

The Copy share link button (next to Export) writes the current builder configuration — chart kind, N, theme, vision, compare flag, and Variant B — into the URL hash and copies a permalink to your clipboard. Anyone who opens the link lands on the exact same configuration. Brand-anchor color overrides stay per-user in localStorage and are intentionally excluded from the link.

Ready-to-paste code snippet

For categorical charts, the Ready-to-paste React + ECharts snippet panel emits a self-contained <KindChart>.tsx component with the audited palette, dashes, decals, shapes, and chrome tokens baked in. It depends only on echarts + echarts-for-react — no design-tool runtime — so engineers can ship the chart without adopting the whole token system. Show/hide, copy, or download as .tsx.

Semantic role audit

For categorical charts, the Semantic role audit scores each semantic token (positive, negative, target, forecast, muted, other) for WCAG ≥ 3:1 contrast vs. the chart background and for collisions with the current categorical palette under both normal and CVD vision. Surfaces the silent failure where a "positive" green KPI bar blends into a categorical series for deutan/protan viewers.

Vision matrix

The Vision matrix renders the current chart five times side-by-side — normal, deuteranopia, protanopia, tritanopia, and grayscale — using the same SVG color-matrix filters that back the single-mode preview. Scan all five at once instead of toggling, and you'll see immediately which series collapse for any audience.

Glossary

The collapsible Glossary panel at the bottom of /charts defines every term the tool surfaces (ΔE, OKLab, CVD, WCAG 2.2 SC 1.4.11, posture, anchor, decal, dash, shape, relaxation, Top-N + Other, stable assignment), each with a plain-language summary, a longer explanation, and a pointer to the source file that implements it.

Emphasis preview

For line, step-line, area, stacked-area, bar, stacked-bar, grouped-bar, and horizontal-bar kinds, the Emphasis preview lets you pick a hero series and renders the chart with that slot at full chroma while every other series collapses to --chart-muted. Use to verify the storytelling pattern (one entity in focus, the rest as context) holds up under the audited palette before handing the chart to engineering.

Insight callouts

For categorical charts, Insight callouts auto-generates plain-English observations about the palette's shape: most and least saturated slots (with multiplier vs. the average), hue families covered, tightest CVD pair, tightest normal-vision pair, tightest contrast-vs-background slot, and OKLab lightness spread (grayscale-survival proxy). Descriptive, not prescriptive.

Messy / realistic fixtures

The Fixtures toggle in the palette builder (synthetic / messy) swaps the underlying data behind line / step-line / area / stacked-area / bar / stacked-bar / grouped-bar / horizontal-bar / heatmap / diverging-bar / diverging-heatmap. Synthetic is smooth sine/cosine data with no missing values, ties, or outliers — pretty, and hides palette weaknesses. Messy mirrors real dashboards: long-tail magnitudes (first series dominates), one near-zero "dead" series, one spiky outlier series, ~6 % missing values, heavy hot spots + missing cells in heatmaps, and extreme outliers + near-midpoint ties in diverging. Both modes are deterministic via a seeded PRNG, so the same configuration always renders the same fixture. Use it to test palettes against the patterns that actually break them (near-zero stacks vanishing, tied middle series becoming indistinguishable, near-midpoint diverging cells merging into the ramp midpoint).


Documentation maintenance contract

Every change in this project must, in the same change:

  1. Update README.md if scope, architecture, deliverables, JTBD, dependencies, or run/usage changes.
  2. Add an entry under ## [Unreleased] in CHANGELOG.md (Added / Changed / Fixed / Removed / Security).
  3. Bump PALETTE_VERSION if constraints, anchors, or optimizer behavior change in a user-visible way.

This rule is persisted to project memory (mem://index.md).


Tech notes

  • Dependencies: culori, echarts, echarts-for-react.
  • Client-side only.
  • OKLab for math, HSL for CSS, hex/rgba into ECharts via the adapter.
  • Seeded PRNG → reproducible palettes.
  • Solver runs once per (theme, posture, N) at module init; cached.

Sponsor

If this system saves you a week of arguing about chart colors, you can support the work here: github.com/sponsors/socraticstatic


License

Copyright © 2026 Micah Boswell. Dual-licensed — see LICENSE.

The palette engine is MIT (LICENSE-MIT): src/charts/index.ts, src/charts/palette/**, constraints.ts, encoding.ts, audit.ts, version.ts. It ships to npm as chart-color-system. Palettes and tokens you generate with it — including anything from Export or Copy-snippet — are yours, no attribution required.

Everything else is proprietary (LICENSE-PROPRIETARY): the React application, its UI components, the demo harness, and the written content. No part may be copied, modified, or distributed without express written permission.

Building the package

bash
npm run build:lib     # → dist-lib/, an MIT-licensed, publishable package

The published version tracks PALETTE_VERSION, not the app version: a version bump means the colors may have moved.

Publishing with 2FA on

npm 11 defaults to auth-type=web, which bounces through a browser and fails on accounts using a passkey or an unavailable second factor. Use the terminal flow instead, which asks for username, password, and OTP directly:

bash
npm run login:npm     # npm login --auth-type=legacy

Then publish, passing the current OTP through to npm publish:

bash
npm run publish:lib -- --otp=123456

License & attribution

Dual-licensed: the palette engine is MIT; the application is proprietary, source-available (see LICENSE). If this ends up inside a commercial or enterprise product, credit Micah Boswell — Chart Color System (https://socraticstatic.github.io/Visualizations/) in your docs, about screen, or credits. For the engine that's the ask on top of MIT's required license preservation; for the application code it's a condition of any permitted commercial use.

來源:README.md,提交 6095ece

工具

4

solve_palette

Solve a chart palette

Generate a categorical chart palette of n colors (1-12) that maximizes perceptual separation under normal vision and colorblindness, with the given brand colors locked as anchors in slot order. Returns the palette, the worst pair distances, the engine's relaxation notes, a full accessibility audit against the background, and a link to open it in the app. Honest cap is 6 slots; above that the result says so.

輸入參數ngridanchorsposturebackground

audit_palette

Audit a chart palette

Audit existing chart colors for accessibility: pairwise OKLab separation under normal vision, deuteranopia, protanopia, tritanopia and achromatopsia, plus WCAG 2.2 non-text contrast (3:1) of every color against the chart background. Returns a pass / warn / fail verdict with the numbers behind it. Set ramp=true for sequential or diverging scales, whose steps are meant to be close.

輸入參數rampcolors必填background

simulate_palette

Simulate colorblind vision

Show what each color looks like to readers with deuteranopia, protanopia, tritanopia or achromatopsia (published Machado 2009 matrices), so an assistant can describe or render the palette as a colorblind reader sees it.

輸入參數modescolors必填

build_ramp

Build a sequential or diverging ramp

Build an evenly spaced perceptual (OKLab) color scale: sequential from start to end, or diverging from start through mid to end. Returns the steps and a background-contrast audit (pairwise separation is not judged for ramps).

輸入參數end必填midkind必填start必填stepsbackground

版本歷史

2
  1. v0.1.2最新Oct 4, 2026
  2. v0.1.1Sep 16, 2026

評分

已滿足適用檢查項的 90%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通必需25 分
  • 已宣告認證方式必需10 分
  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分

    請在儲存庫或註冊中心條目中宣告授權條款。