Skip to content
PaletteViva
Appearance

Color system builder

A palette is a list of colours. A color system is what a product can actually consume: names that mean something, states that follow from a fill, and a token file you can commit. This takes the palette you already have on this device and arranges it into both, in the browser, with every figure measured rather than asserted.

Reading the working palette from this device…

What this does with your palette

The builder reads the working palette — the same list every tool on this site reads and writes, kept on your device and never uploaded. It then does three things:

  1. Assign roles. Each of your colours is offered a role, and you can change any of them. Whatever you set wins: only roles you have not touched are inferred, so your decisions are never overridden.
  2. Derive the states. Each interactive fill gets hover, active, disabled and selected colours, taken from the tonal scale of the colour behind it and measured against that mode's background.
  3. Export. The finished system is copied out as DTCG JSON, SCSS variables or a Tailwind v4 theme block, in both light and dark.

The same assignment produces both themes. Neutrals take opposite ends of their scale and fills walk toward whichever end the mode can read, so you author once and light and dark follow rather than drifting apart.

What a semantic role is, and why the names are fixed

A role names a job, not a colour. There are exactly twelve, and they are the same twelve in every system because they are the jobs a product interface keeps asking for:

  • primary — the main interactive fill
  • onPrimary — what sits on that fill, chosen for readability
  • accent — the secondary fill, for emphasis that is not the main action
  • success, warning, danger — status fills
  • background — the page behind everything
  • surface — cards, panels and anything raised above the page
  • text — body copy
  • textMuted — secondary and supporting copy
  • border — dividers and outlines
  • focusRing — the keyboard focus indicator

The point of naming them this way is that text never holds a hex literal in your codebase. Change the palette, re-export, and every component that referenced text updates together. A component that hardcodes #1f2937 does not do that, which is the failure this page is for.

Every value also carries where it came from — your own colour, a step on its tonal scale, or a system fallback — and the builder shows that beside the hex. If your palette cannot fill a role, it is named rather than quietly invented.

States are derived, not picked

An interactive fill needs a hover, a pressed state, a disabled state and a selected state. Choosing four more colours by hand per fill is where most systems stop being consistent. Here they come from the same tonal scale as the fill itself: hover and active take the adjacent steps along the walk from wherever the fill landed, and disabled steps to a fixed lightness that is meant to sit back from the page.

Each derived state is then measured against the mode's background and shown with its ratio, labelled with what it was measured against. Selected is deliberately honest rather than adjusted: it is the fill itself, measured as it is, so you can see whether your primary colour clears the contrast threshold without leaving the builder.

If a role has no fill, it has no states to derive, and the builder says so instead of inventing a default.

What you get to take away

  • DTCG JSON. A W3C Design Tokens draft document: one group per mode, the twelve roles as flat $type/$value token objects, with provenance in $description. Nothing that is not in the draft, so another tool does not have to skip anything.
  • SCSS. A variable per role per mode — $color-light-primary — plus a $paletteviva-system map pair a codebase can iterate over.
  • A Tailwind v4 theme. An @theme block that leads with the semantic roles, then adds each source colour's tonal scale under the name you gave it, with its measured contrast on white in a comment.

If you have not chosen between those formats, HEX, RGB, HSL and OKLCH explained covers the colour side of the same question.

Where to go next

If you have no palette yet, palette from image extracts one from a photograph, logo or screenshot, and the working palette is where that list lives — add colours by hand, rename them, and see the tonal scales and accessibility studio for them. To check a specific pairing before you commit to it, the contrast checker reports WCAG verdicts for any two colours, and the color converter gives you a colour's values in every space the scales are built in.