Palettes¶
This page is the catalog. For how to call the resolver — palette(),
color(), YAML shorthand, errors, smart defaults, scoring, anti-patterns —
see Palette resolver.
Families¶
Every palette belongs to one of five families. The family determines how the resolver treats the palette and what kind of data it's for.
| Family | Purpose | Used for |
|---|---|---|
sequential |
Ordered magnitude (light → dark) | Continuous numeric data without a midpoint |
diverging |
Signed values around a midpoint | Continuous numeric data with a meaningful zero or center |
categorical |
Unordered categories | Discrete enums where each value is its own identity |
scaffold |
UI structural framing | Canvas, borders, dividers, axis text — not data encoding |
tone |
Role tokens | Negative / positive / warning semantics |
Scaffolds and tones use named slots (canvas, solid, text, …), not
numbered stops. The other three families use ordered stops.
Sequential¶
Use for ordered magnitude — light at the low end, dark at the high end.
All sequential palettes ship 11 stops and downsample evenly: pass steps=N
to get N evenly-spaced stops from the spine.
WCAG note. Dark-end stops will fail WCAG AA (4.5:1) against
#222 body text. For table cell backgrounds, use
palette(name, surface="table") — see
Palette resolver
— which carves the spine at the contrast boundary and returns
AA-safe stops. Or set an explicit text_color override on dark cells.
dft-seq-blue — default sequential¶
Single-hue blue. Default for continuous numeric data without a midpoint.
Other sequential hues¶
Same 11-stop architecture, different hue anchor. Pick by editorial fit; all share the WCAG dark-end caveat above.
| Palette | Reads as | Light end | Mid (step 6) | Dark end |
|---|---|---|---|---|
dft-seq-amber |
Honey → deep amber | #f6edde |
#a2781a |
#2e1f00 |
dft-seq-brown |
Cream → warm brown (pairs with cream theme) | #f3eee6 |
#9b785e |
#341911 |
dft-seq-gray |
Pure achromatic (magnitude without hue) | #eeeeee |
#808080 |
#222222 |
dft-seq-green |
Single-hue green | #e4f3ea |
#44926e |
#002a19 |
dft-seq-purple |
Single-hue purple | #f5eaf8 |
#9b6ba8 |
#32113a |
dft-seq-rust |
Cream-peach → terracotta → deep rust | #fdeae3 |
#b96648 |
#3e1000 |
dft-seq-teal |
Teal / turquoise | #dff3f5 |
#00919d |
#00272b |
Diverging¶
Use for signed values around a midpoint — temperature anomalies, profit/loss, deviations from a baseline. All diverging palettes ship 11 stops with a neutral midpoint at step 6. Even-N downsamples auto-skip the midpoint (no gray middle); odd-N include it.
When to use which¶
| Situation | Palette |
|---|---|
| Default CVD-safe diverging | dft-div-blue-red |
| Political-sensitivity (avoid red/blue) | dft-div-orange-teal |
| Financial loss/gain (red negative, green positive) | dft-div-crimson-green — must pair with icon + label |
| Climate / atmospheric data (conventional sunset ramp) | dft-div-sunset |
| Scientific visualization (Moreland 2009) | dft-div-coolwarm |
dft-div-blue-red — default¶
Symmetric blue-to-red about a light midpoint. CVD-safe at common subset counts.
Other diverging palettes¶
| Palette | Low extreme | Mid | High extreme | Notes |
|---|---|---|---|---|
dft-div-orange-teal |
#4c1f00 |
#e4e4e4 |
#003634 |
Symmetric, fully CVD-safe; non-politically-loaded |
dft-div-crimson-green |
#540a31 |
#e4e4e4 |
#00481d |
Engineered red↔green CVD pass via lightness asymmetry; icon + label required |
dft-div-sunset |
#125a56 |
#eceada |
#a01813 |
Paul Tol multi-hue ramp; CVD-safe; conventional in climate work |
dft-div-coolwarm |
#3b4cc0 |
#dddddd |
#8b0000 |
Moreland 2009; canonical in ParaView/VTK and scientific viz |
Categorical¶
Use for unordered categories — series in a multi-line chart, slices in a
stacked bar, items in a legend. Categorical palettes ship a fixed number of
slots; steps=N returns the first N. There is no interpolation: stops are
what you get.
editorial-10 — default for editorial themes¶
Quieter ten-color set designed for cycling — the engine fills slots in
order without a human picker. Default for the shipped default and
cream themes.
Slot progression — what comes out at each cardinality:
- Slots 1–2 — two blues at different lightnesses (brand anchor + lighter sibling). A 2-series chart reads as a single-hue lightness pair, not max-contrast.
- Slots 3–4 — paired neutrals (warm
sand+ coolgray). A 3- or 4-series chart adds a temperature break without introducing a new hue. - Slots 5–6 — muted second/third hues (
plum,green) at low chroma. - Slot 7 — first saturated warm (
gold). Reserved for cardinality 7+ or the highlight role. - Slots 8–10 — earth + cool + anchor (
rust,teal,charcoal).
Reach for editorial-10 (over vivid-10) when:
- The dashboard is meant to read as editorial — calmer, lower-chroma, fewer competing hues.
- Charts often have 2–4 series. Editorial-10's first four slots are two blues + two neutrals; most charts will live in slots 1–4 and feel quiet by default.
- Cross-chart palette consistency matters and you'd rather not hand-pin per chart.
Stay on vivid-10 when:
- The dashboard genuinely needs 6+ visually-distinct categories on a single chart and editorial restraint isn't a goal.
- The product surface is brand-default rather than editorial.
Companion palette — editorial-10-dark¶
Direct labels at line endpoints (or segment names on stacked bars) need to read a notch darker than the mark they ink, so the label reads as authored ink rather than just a duplicate of the series color. editorial-10-dark is the dark companion that provides those label colors.
Pairing is positional: stop N in editorial-10-dark is the dark companion of stop N in editorial-10. Each stop drops L by ~0.10 in OKLCH, with a small chroma bump so the darker tone keeps perceptual punch. Slot 10 (charcoal) is the exception — it equals its base stop, because charcoal-base already sits at the ink-band floor (L≈0.30) and has no meaningful darker twin.
| Slot | editorial-10 |
editorial-10-dark |
|---|---|---|
| 1 | #3164a3 denim |
#0e4786 |
| 2 | #779bc9 sky |
#557daf |
| 3 | #ad9c7f sand |
#917d5a |
| 4 | #7a8895 gray |
#5b6b7a |
| 5 | #8a576f plum |
#6f3854 |
| 6 | #5c7b5c green |
#3a603b |
| 7 | #d49656 gold |
#b46e0f |
| 8 | #ae6349 rust |
#944123 |
| 9 | #609f9e teal |
#2a807f |
| 10 | #232f3a charcoal |
#232f3a |
The two files are edited together. A regression test pins the per-slot pairing contract (same hue family, dark stop has lower L — except the consolidated charcoal slot) so accidental drift between the two surfaces fails CI.
These are direct-label colors, not body-text or axis-label colors. They're designed to ink labels that sit on or beside a chart mark — not labels that float on open canvas. A few stops (slot 2 sky, slot 3 sand, slot 7 gold, slot 9 teal) clear WCAG 3:1 graphic contrast against the cream canvas but fall short of the AA 4.5:1 body-text bar. That's the cycling-palette chroma envelope; the dark companion sharpens the label-on-mark contrast without trying to be a body-text palette.
Companion palette — editorial-10-light¶
Light states need the opposite treatment from direct-label ink: a mark should stay recognizably tied to its series color, but sit above the base color by roughly the same lightness distance that editorial-10-dark sits below it. editorial-10-light is the moderate light companion for that job.
Pairing is positional: stop N in editorial-10-light is the light companion of stop N in editorial-10. Each stop is lifted in OKLCH L above its base and cuts chroma so the lighter mark does not become louder. The lift is directional, not a strict mirror of the editorial-10-dark drop (gold is tuned down to L≈0.80 by eye so the light band reads evenly rather than carrying a lightness outlier).
| Slot | editorial-10 |
editorial-10-light |
|---|---|---|
| 1 | #3164a3 denim |
#6682a6 |
| 2 | #779bc9 sky |
#a5b9d3 |
| 3 | #ad9c7f sand |
#c6bdac |
| 4 | #7a8895 gray |
#9ea6ad |
| 5 | #8a576f plum |
#9b7d8a |
| 6 | #5c7b5c green |
#839583 |
| 7 | #d49656 gold |
#dab696 |
| 8 | #ae6349 rust |
#b88c7d |
| 9 | #609f9e teal |
#9bbcbb |
| 10 | #232f3a charcoal |
#3c4349 |
Companion palette — editorial-10-ghost¶
De-emphasis states need a stronger fade: out-of-focus marks should recede behind the highlighted member while keeping their hue identity. editorial-10-ghost is the pale companion for dim-the-chorus patterns.
Pairing is positional: stop N in editorial-10-ghost is the ghost companion of stop N in editorial-10. It uses the same derivation as vivid-10-ghost: preserve hue, lift slots 1-9 to OKLCH L≈0.86, and cut chroma to 32%. Slot 10 charcoal stays lower at L≈0.80 — lifted toward the ghost band but kept a notch below it so it stays distinct from gray-ghost.
| Slot | editorial-10 |
editorial-10-ghost |
|---|---|---|
| 1 | #3164a3 denim |
#c1d3e9 |
| 2 | #779bc9 sky |
#c6d2e2 |
| 3 | #ad9c7f sand |
#d6d0c7 |
| 4 | #7a8895 gray |
#cdd2d6 |
| 5 | #8a576f plum |
#decbd3 |
| 6 | #5c7b5c green |
#cad4c9 |
| 7 | #d49656 gold |
#e2cdb9 |
| 8 | #ae6349 rust |
#e6cac1 |
| 9 | #609f9e teal |
#c2d6d5 |
| 10 | #232f3a charcoal |
#babec3 |
editorial-10-light and editorial-10-ghost are companion palettes, not standalone categorical cycles. They deliberately have lower pairwise separation than editorial-10; use them alongside a base-color focus mark, not as the primary series cycle.
Companion palette — editorial-10-ink¶
Single-series chart marks (bar fills, line strokes, area fills, table inline-bars) need a deeper ink than direct labels — dark enough to read as "considered ink on the page" rather than as the chart system's anchor blue, with hue identity preserved across slots so themes can pick a chromatic ink that ties to their canvas. editorial-10-ink is that companion: the symmetric opposite of editorial-10-ghost at the dark end of the perceptual scale.
Pairing is positional: stop N in editorial-10-ink is the ink companion of stop N in editorial-10. All ten stops sit in a tight OKLCH L band (0.30–0.36) with chroma preserved from the base palette — slot identity is carried by hue, not by lightness.
| Slot | editorial-10 |
editorial-10-ink |
|---|---|---|
| 1 | #3164a3 denim |
#1b3659 |
| 2 | #779bc9 sky |
#203c65 |
| 3 | #ad9c7f sand |
#443924 |
| 4 | #7a8895 gray |
#2d383f |
| 5 | #8a576f plum |
#4a2a3a |
| 6 | #5c7b5c green |
#263d2a |
| 7 | #d49656 gold |
#523500 |
| 8 | #ae6349 rust |
#53291d |
| 9 | #609f9e teal |
#143e3e |
| 10 | #232f3a charcoal |
#232f3a |
Themes pick a subset of these stops by inlining hexes into style.charts.single_series_palette — they don't reference the palette name directly. Today the shipped themes use one stop each (editorial → sky-ink slot 2, cream → sand-ink slot 3); the rhythm-palette work that grows those lists for cross-chart visual variety is tracked separately.
single_series_palette — ink for single-series charts¶
palette (categorical, above) is the color source for charts with a color: channel — Dataface indexes into it once per distinct series value. single_series_palette is the separate ink source for charts that have no color: channel at all: a plain single-metric bar, line, or area. There's no series to pick a slot by value, so Dataface assigns each single-series chart a slot by its position in the face — the compiler walks the face tree in reading order and hands out single_series_palette[0], single_series_palette[1], and so on, wrapping back to the start once the list is exhausted. Two single-series bar charts on the same board get two different inks; the same chart re-rendered always gets the same ink, because the slot comes from tree position, not from data.
Set it at the theme or face level under style.charts, as either an explicit hex list or a palette name (expanded to that palette's stops at validation time):
style: charts: single_series_palette: editorial-10-ink # or an explicit list: # single_series_palette: ["#1b3659", "#203c65", "#443924"]
A chart-local style.color.static or style.color.categorical override always wins over the rhythm slot — use it when one specific chart needs to break from the cycle (e.g. to match an established brand color for that metric).
vivid-10 — general-purpose ten-color¶
Blue-led, with chroma-pushed cool leads over an earth-and-neutral expansion
after the first five hues. The default categorical palette for the stark
theme; editorial-10 (above) is the default for the editorial and cream
themes.
vivid-10-dark, vivid-10-light, vivid-10-ghost, and vivid-10-ink ship as
positional companions — same ten slots, slot-by-slot. Use them for
chart-emphasis patterns: the dark twin inks direct labels a notch darker
than the line they belong to, the light twin provides a moderate lighter
state, the ghost twin fades out-of-focus series in dim-the-chorus
highlighting, and the ink twin drops every slot into a tight dark band for
single-series marks (consumed by the vivid-family themes).
hero-6 — single dominant series¶
A six-color hero-blue-versus-neutrals palette for charts where one series should dominate. Slot 1 is the only saturated color; slots 2–6 are gray/brown neutrals that step into warmth.
Contract. The hero blue is both the most saturated and the darkest color in the palette — that's the perceptual rule that makes slot 1 win. Don't reorder; the support neutrals are designed to lie behind it.
Tonal monochrome — category-6-tonal-*¶
Single-hue categorical palettes for editorial / brand-restrained
dashboards. Five hues ship: blue, green, purple, orange, brown — each
anchored on a vivid-10 slot so they coordinate with the default
categorical system.
| Palette | Anchor color | Reads as |
|---|---|---|
category-6-tonal-blue |
#0375c4 |
All-blue |
category-6-tonal-green |
#00875a |
All-green |
category-6-tonal-purple |
#9650a8 |
All-purple |
category-6-tonal-orange |
#b74c1f |
All-orange |
category-6-tonal-brown |
#9a642b |
All-brown (cream-theme companion) |
Contract — 4 strict-safe + 2 extended. Every tonal palette ships 6 stops with a layered contract:
| Slots | Role | CVD safety |
|---|---|---|
| 0–3 (core) | strict-safe | Color alone sufficient; pairwise CVD ΔE ≥ 11 |
| 4–5 (extended) | form-redundant only | Below the strict gate. Require dash, marker, or pattern redundancy when used in a chart |
The 6-stop cap is structural: at fixed hue, English's color vocabulary
saturates around 4–5 stops ("two blues that are 'just blue'"), and CVD
simulation collapses adjacent stops. If a chart needs 7+ categories, use
vivid-10 instead.
When to use. Editorial / branded dashboards where chromatic restraint matters more than category count. Small-multiples and KPI tiles where the color budget is tight. Charts with direct labels or stable category order — the legend reads via labels, not by glance. Avoid for many-slice pies, dense scatters, or stacked bars with more than four segments.
Brown ↔ cream bridge. category-6-tonal-brown's extended slots (4–5)
are deliberately hue-shifted to overlap the dft-creams scaffold region.
On the cream theme, slot 5 visually merges with the surrounding chrome —
that's the design intent. Use slot 5 only with form redundancy on cream
backgrounds.
Compatibility palettes¶
| Palette | Use |
|---|---|
tableau |
Tableau-style 10-color set. Retained for users who want the familiar Tableau hues instead of vivid-10. |
Scaffold¶
Scaffolds are UI structural framing — canvas, borders, dividers, axis
labels, table stripes, secondary text. Not data encoding. Address
them through named aliases (chrome.canvas, chrome.ink, etc.) rather
than by integer slot.
dft-grays — neutral chrome¶
Twelve steps from near-white to near-black. The darkest step, void, is
the near-black canvas for dark themes; stark and other light themes use
the lighter steps for chrome.
dft-creams — warm chrome¶
Same twelve-step shape as dft-grays, in warm cream tones. Default
chrome for the cream theme.
Tone¶
Tone palettes encode role semantics — info, negative, positive, warning. Six
named slots per palette: bg, subtle, border, solid, solid-hover,
text. Address them through color(), not palette().
Contract. All tone slots are designed so canonical pairs (text-on-bg, solid-on-white) pass WCAG AA. Tone color alone is insufficient communication — always pair with icon + label per the standard accessibility discipline.
info — blue / information / neutral status¶
Informational notes, neutral status messages, non-error callouts.
| Alias | Hex | Role |
|---|---|---|
bg |
#e7f4ff |
Very light blue background |
subtle |
#d6ecff |
Secondary fill or hover-on-bg |
border |
#6bb9f8 |
Mid-tone divider / outline |
solid |
#008cdd |
Canonical "information" fill |
solid-hover |
#0070b3 |
Darker variant for button hover state |
text |
#003659 |
AA-contrast text color on .bg and on white |
negative — red / stop / bad¶
Critical errors, destructive actions, losses. Western convention: red = stop/bad.
| Alias | Hex | Role |
|---|---|---|
bg |
#ffedec |
Very light peach tint for surface backgrounds |
subtle |
#ffdbd8 |
Hover-on-bg or secondary fill |
border |
#e79491 |
Mid-tone divider / outline |
solid |
#94001e |
Canonical "this is negative" fill |
solid-hover |
#6e0014 |
Darker variant for button hover state |
text |
#4b000a |
AA-contrast text color on .bg and on white |
positive — green / go / good¶
Successful actions, gains, completions. Western convention: green = go/good.
| Alias | Hex | Role |
|---|---|---|
bg |
#e3f8e9 |
Very light green background |
subtle |
#cff2da |
Secondary fill / hover-on-bg |
border |
#82cb9b |
Mid-tone divider / outline |
solid |
#00884d |
Canonical "all good" fill |
solid-hover |
#006d3c |
Darker variant for button hover state |
text |
#003e20 |
AA-contrast text color on .bg and on white |
warning — amber / caution¶
Pay attention — something needs input, nothing's broken. Western convention: amber = caution.
| Alias | Hex | Role |
|---|---|---|
bg |
#fff3e5 |
Very light cream-amber background |
subtle |
#ffe7ca |
Secondary fill / hover-on-bg |
border |
#f0b871 |
Mid-tone divider / outline |
solid |
#e69812 |
Canonical "pay attention" fill |
solid-hover |
#c68100 |
Darker variant for button hover state |
text |
#643f00 |
AA-contrast text color on .bg and on white |
Further reading¶
- Palette resolver — how to call
palette()/color()from Python or YAML, plus error semantics and the anti-pattern list. - Tonal foundations — the neutral-frame thinking that pairs with the chrome scaffolds.