01 / Your base colors

A palette with a purpose

1–6 colors. Use unique lowercase names and six-digit HEX values. The first color also tints the neutral ramp.

02 / Interface roles

Choose your pairings

CSS and JSON tokens are ready.

A small interface study

Make room for good ideas.

Clear roles bring consistency to every surface, label, and action.

Accent with text

Body text on surface 16.90:1 · Meets the 4.5:1 normal-text threshold

Button text on accent 7.91:1 · Meets the 4.5:1 normal-text threshold

Contrast is calculated from these two opaque color pairs. This is not an accessibility certification.

brand-50 #f4f6fd
brand-100 #e9eefb
brand-200 #c9d4f6
brand-300 #9db2ee
brand-400 #5c7fe3
brand-500 #2654d9
brand-600 #2047b8
brand-700 #19378d
brand-800 #112662
brand-900 #0a1536
leaf-50 #f6f8f7
leaf-100 #edf2ef
leaf-200 #d2ded7
leaf-300 #adc4b7
leaf-400 #779c88
leaf-500 #497b60
leaf-600 #3e6952
leaf-700 #2f503e
leaf-800 #21372b
leaf-900 #121f18
clay-50 #fbf7f5
clay-100 #f8efec
clay-200 #edd6cf
clay-300 #deb6a8
clay-400 #c8856e
clay-500 #b65c3e
clay-600 #9b4e35
clay-700 #763c28
clay-800 #52291c
clay-900 #2e1710
neutral-50 #f6f6f7
neutral-100 #edeeef
neutral-200 #d3d4d8
neutral-300 #b0b2b8
neutral-400 #7b7f89
neutral-500 #4f5461
neutral-600 #434753
neutral-700 #34363f
neutral-800 #24262c
neutral-900 #141518
white #ffffff
black #000000
CSS

:root {
  --color-brand-50: #f4f6fd;
  --color-brand-100: #e9eefb;
  --color-brand-200: #c9d4f6;
  --color-brand-300: #9db2ee;
  --color-brand-400: #5c7fe3;
  --color-brand-500: #2654d9;
  --color-brand-600: #2047b8;
  --color-brand-700: #19378d;
  --color-brand-800: #112662;
  --color-brand-900: #0a1536;
  --color-leaf-50: #f6f8f7;
  --color-leaf-100: #edf2ef;
  --color-leaf-200: #d2ded7;
  --color-leaf-300: #adc4b7;
  --color-leaf-400: #779c88;
  --color-leaf-500: #497b60;
  --color-leaf-600: #3e6952;
  --color-leaf-700: #2f503e;
  --color-leaf-800: #21372b;
  --color-leaf-900: #121f18;
  --color-clay-50: #fbf7f5;
  --color-clay-100: #f8efec;
  --color-clay-200: #edd6cf;
  --color-clay-300: #deb6a8;
  --color-clay-400: #c8856e;
  --color-clay-500: #b65c3e;
  --color-clay-600: #9b4e35;
  --color-clay-700: #763c28;
  --color-clay-800: #52291c;
  --color-clay-900: #2e1710;
  --color-neutral-50: #f6f6f7;
  --color-neutral-100: #edeeef;
  --color-neutral-200: #d3d4d8;
  --color-neutral-300: #b0b2b8;
  --color-neutral-400: #7b7f89;
  --color-neutral-500: #4f5461;
  --color-neutral-600: #434753;
  --color-neutral-700: #34363f;
  --color-neutral-800: #24262c;
  --color-neutral-900: #141518;
  --color-white: #ffffff;
  --color-black: #000000;

  --role-surface: var(--color-neutral-50);
  --role-text: var(--color-neutral-900);
  --role-accent: var(--color-brand-600);
  --role-on-accent: var(--color-white);
}
JSON token map
JSON

{
  "version": 1,
  "model": "encoded-srgb-mix",
  "colors": {
    "brand-50": "#f4f6fd",
    "brand-100": "#e9eefb",
    "brand-200": "#c9d4f6",
    "brand-300": "#9db2ee",
    "brand-400": "#5c7fe3",
    "brand-500": "#2654d9",
    "brand-600": "#2047b8",
    "brand-700": "#19378d",
    "brand-800": "#112662",
    "brand-900": "#0a1536",
    "leaf-50": "#f6f8f7",
    "leaf-100": "#edf2ef",
    "leaf-200": "#d2ded7",
    "leaf-300": "#adc4b7",
    "leaf-400": "#779c88",
    "leaf-500": "#497b60",
    "leaf-600": "#3e6952",
    "leaf-700": "#2f503e",
    "leaf-800": "#21372b",
    "leaf-900": "#121f18",
    "clay-50": "#fbf7f5",
    "clay-100": "#f8efec",
    "clay-200": "#edd6cf",
    "clay-300": "#deb6a8",
    "clay-400": "#c8856e",
    "clay-500": "#b65c3e",
    "clay-600": "#9b4e35",
    "clay-700": "#763c28",
    "clay-800": "#52291c",
    "clay-900": "#2e1710",
    "neutral-50": "#f6f6f7",
    "neutral-100": "#edeeef",
    "neutral-200": "#d3d4d8",
    "neutral-300": "#b0b2b8",
    "neutral-400": "#7b7f89",
    "neutral-500": "#4f5461",
    "neutral-600": "#434753",
    "neutral-700": "#34363f",
    "neutral-800": "#24262c",
    "neutral-900": "#141518",
    "white": "#ffffff",
    "black": "#000000"
  },
  "roles": {
    "surface": "neutral-50",
    "text": "neutral-900",
    "accent": "brand-600",
    "on-accent": "white"
  }
}

From base colors to reusable interface roles

A color converter translates a single color between formats. This tool builds a small design palette: each named seed becomes ten repeatable steps, a tinted neutral ramp supports surfaces, and role aliases separate the purpose of a color from its numeric shade. Use the exact same inputs to reproduce the same outputs.

Build and export a palette

  1. Edit a base color or add up to six colors. Names start with a lowercase letter and contain letters, numbers, or hyphens.
  2. Assign surface, body text, accent, and accent text roles. Review both contrast ratios before using the palette.
  3. Copy CSS into your stylesheet, or download the JSON map for your own token pipeline. JSON here is a simple documented map, not a claim of compatibility with a design-token interchange standard.

The color math, without hidden randomness

Steps 50, 100, 200, 300, and 400 mix each encoded sRGB channel with 95%, 90%, 75%, 55%, and 25% white. Step 500 keeps the seed. Steps 600, 700, 800, and 900 mix with 15%, 35%, 55%, and 75% black. Each channel rounds to the nearest byte only when emitted as HEX.

The neutral seed uses 90% gray and 10% of the first base color. The gray channel is 0.2126R + 0.7152G + 0.0722B on encoded sRGB bytes. This tinting formula is distinct from the linear-light relative luminance used for contrast. The ramps are not perceptually uniform, and numbered steps do not guarantee equal visual spacing.

Reading contrast warnings

Contrast uses sRGB linearization and the relative-luminance ratio (lighter + 0.05) / (darker + 0.05). The warning compares the unrounded result with 4.5:1 for ordinary text; displayed ratios round to two decimals. Review your real text sizes, focus states, disabled states, imagery, and color use separately. Transparent colors are outside this tool’s scope.

Will role changes alter my base palette?

No. Roles point to existing tokens. If a renamed or removed color was assigned to a role, that role falls back to its default token and the status explains the change. Invalid colors or duplicate names clear the export until corrected. Neutral, white, black, role, constructor, and prototype are reserved names.

References: W3C text contrast guidance and CSS custom properties .