Functional Weave
Code in TypeScript

charts.palette

A categorical palette of n colour-blind-safe colours for chart series: Okabe-Ito or Paul Tol's bright scheme.

1.0.0 · published 2026-10-03 by charlie · Anterra

Pinned by 12 tests, run in TypeScript, Python and Rust.

What it does

The colours for a chart's series: `palette("okabe-ito", 3, false)` is `["#e69f00", "#56b4e9", "#009e73"]`. Both schemes are published sets chosen to stay distinguishable to people with the common colour-vision deficiencies (protanopia, deuteranopia) as well as to everyone else, which the default rainbow palettes of many chart libraries are not.

- `okabe-ito`, 8 colours: orange, sky blue, bluish green, yellow, blue, vermillion, reddish purple, black (Okabe and Ito, "Color Universal Design"). The published list starts with black; here black is moved to the end, so the first series are coloured and black stays free for axes and text until the eighth series. Otherwise the order and values are as published. - `tol-bright`, 7 colours: blue, red, green, yellow, cyan, purple, grey, in Paul Tol's default order.

For example

  • palette(okabe-ito, 3, false) → #e69f00, #56b4e9, #009e73 three Okabe-Ito colours start with orange, not black
  • palette(okabe-ito, 8, false) → #e69f00, #56b4e9, #009e73, #f0e442, #0072b2, #d55e00, #cc79a7, #000000 all eight Okabe-Ito colours, black last
  • palette(okabe-ito, 1, false) → #e69f00 one colour

The function

The same function in TypeScript, Python and Rust, pinned by the same tests. Pick your language; the choice follows you around the registry.

export function palette(scheme: string, count: number, cycle: boolean): readonly string[]
schemestringokabe-ito (8 colours) or tol-bright (7 colours)
countinthow many colours, 0 or more
cycleboolrepeat the scheme when count is larger than it; otherwise that is an error
returnsstring[]lowercase "#rrggbb", in the scheme's order

Your code names it in one line, in the file that uses it

import { palette } from "#fune/charts.palette@^1";
impl/typescript.ts · 26 lines · open · raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

import { PALETTES } from "./charts_palette_data.ts";  ← this capability’s own data, compiled from data/palettes.json into the same file by fune build

/**
 * The first `count` colours of a named categorical scheme, in its order.
 *
 * A scheme has a fixed number of colours chosen to stay distinguishable to
 * people with colour-vision deficiencies; asking for more is an error unless
 * `cycle` says repeating them is acceptable, because a ninth series silently
 * reusing the first colour is a misleading chart.
 */
export function palette(scheme: string, count: number, cycle: boolean): readonly string[] {
  const colours = PALETTES.filter((c) => c.scheme === scheme)
    .slice()
    .sort((a, b) => a.position - b.position)
    .map((c) => c.hex);
  if (colours.length === 0) throw new RangeError(`unknown palette "${scheme}"; use okabe-ito or tol-bright`);
  if (!Number.isInteger(count) || count < 0) {
    throw new RangeError(`count must be a whole number of at least 0, received ${count}`);
  }
  if (count > colours.length && !cycle) {
    throw new RangeError(`palette "${scheme}" has only ${colours.length} colours; pass cycle to repeat them`);
  }
  const out: string[] = [];
  for (let i = 0; i < count; i++) out.push(colours[i % colours.length]);
  return out;
}

Install

fune build

With that line in your source, in a TypeScript project (language typescript in fune.project), fune build resolves it and nothing else, pins them in fune.lock, downloads only the TypeScript package of each, and builds the code above into your project’s .fune/build, one readable file per capability with a header linking back here. Or pin a range in fune.project and build in one step:

fune add charts.palette
Download for TypeScript charts.palette-1.0.0-typescript.fune · 8,652 bytes sha256 a019b87ea0362e76fe2098b0a55701b2d1e0b5671dea331510511b6ab2834e07

The manifest, vectors and README with only the TypeScript implementation. Install it without the registry with fune add ./charts.palette-1.0.0-typescript.fune, or fetch it from a terminal with fune pull charts.palette@1.0.0:typescript.

The whole function, every language, is one file too: charts.palette-1.0.0.fune, 10,984 bytes, sha256 ddf253584a9c2cad154b151e0ff42da0782096c9ab4744064ea04fc36c25b126. It installs into a project of any language.

Customise it in your app

The seams this capability offers. Put a marker directly above a function of your own and fune build wires it into the built code; the package on the registry is not changed, the built file’s header lists it under CUSTOMISED, and fune hooks lists every hook in the project. How hooks work.

before — your function gets the arguments and returns them, changed or not, or throws to refuse the call.

// fune: before charts.palette

after — your function gets the result and the arguments, and returns the final result.

// fune: after charts.palette

replace — it requires no other capability, so there is no dependency to replace.

step — your function runs at a numbered point inside the function’s body, receives the in-scope values it names as parameters, and may return replacements. List the points with fune show charts.palette --steps.

// fune: step charts.palette after <n|label>

Tests

A version published now needs at least 8 tests for every function, and one that expects the error for each function that throws; the registry refuses it otherwise. fune verify --all runs each case in TypeScript, Python and Rust, and a project runs them again with fune verify. This page lists the cases; it does not run them. The exact JSON is vectors.json.

CaseArgumentsExpected
three Okabe-Ito colours start with orange, not black okabe-ito, 3, false → #e69f00, #56b4e9, #009e73
all eight Okabe-Ito colours, black last okabe-ito, 8, false → #e69f00, #56b4e9, #009e73, #f0e442, #0072b2, #d55e00, #cc79a7, #000000
one colour okabe-ito, 1, false → #e69f00
zero colours is an empty list okabe-ito, 0, false →
all seven of Tol's bright scheme in his order tol-bright, 7, false → #4477aa, #ee6677, #228833, #ccbb44, #66ccee, #aa3377, #bbbbbb
two of Tol's bright scheme tol-bright, 2, true → #4477aa, #ee6677
cycling repeats from the start okabe-ito, 10, true → #e69f00, #56b4e9, #009e73, #f0e442, #0072b2, #d55e00, #cc79a7, #000000, #e69f00, #56b4e9
cycling Tol's scheme past its seventh colour tol-bright, 9, true → #4477aa, #ee6677, #228833, #ccbb44, #66ccee, #aa3377, #bbbbbb, #4477aa, #ee6677
exactly the scheme's size needs no cycle tol-bright, 7, false → #4477aa, #ee6677, #228833, #ccbb44, #66ccee, #aa3377, #bbbbbb
more colours than the scheme has, without cycle, is an error okabe-ito, 9, false → error: palette "okabe-ito" has only 8 colours
Show the other 2 tests
CaseArgumentsExpected
an unknown scheme is an error rainbow, 3, false → error: unknown palette "rainbow"
a negative count is an error okabe-ito, -1, false → error: count must be a whole number of at least 0

More from the author

The colours are data (`data/palettes.json`, one row per colour with its position and name), not code. They describe fixed published schemes rather than rules that change over time, so the file has no `effective` columns and is never pruned.

Asking for more colours than a scheme has is an error unless `cycle` is true: a ninth series quietly reusing the first colour makes two series look like one. With `cycle`, colours repeat from the start. All hex is lowercase `#rrggbb`.

Sources: M. Okabe and K. Ito, "Color Universal Design (CUD): How to make figures and presentations that are friendly to colorblind people" (2002, rev. 2008), https://jfly.uni-koeln.de/html/color_blind/ (RGB 0-255 values: black 0,0,0; orange 230,159,0; sky blue 86,180,233; bluish green 0,158,115; yellow 240,228,66; blue 0,114,178; vermillion 213,94,0; reddish purple 204,121,167); B. Wong, "Points of view: Color blindness", Nature Methods 8, 441 (2011); P. Tol, "Colour Schemes" (SRON technical note SRON/EPS/TN/09-002, 2021), https://sronpersonalpages.nl/~pault/ (bright: #4477AA, #EE6677, #228833, #CCBB44, #66CCEE, #AA3377, #BBBBBB).

Files

PathBytes
README.md1,961
data/palettes.json1,217
impl/python.py944
impl/rust.rs1,291
impl/typescript.ts1,184
vectors.json1,841