Guide 05
Tokens, export & preview
The generator's real output is not a picture of a palette. It is a set of named values that a codebase can consume without anyone retyping a hex code.
Name by role, never by appearance
--blue-600 is a primitive. It describes what the colour is. --color-action-primary is a semantic token. It describes what the colour does. Components should only ever reference semantics, because the day marketing decides the brand is green, a primitive named --blue-600 holding a green value is worse than no name at all.
A three-tier structure holds up well in practice:
- Primitives —
--violet-500,--neutral-950. Raw values, no opinions, never referenced by a component. - Semantics —
--surface-1,--text-muted,--border-strong,--action-primary-hover. Theme-aware aliases pointing at primitives. - Component tokens —
--button-bg,--input-border. Optional, and only worth adding when a component genuinely needs to diverge.
Two naming habits that prevent pain later: put the state at the end (--action-primary-hover, not --hover-action-primary) so tokens sort together alphabetically, and never encode the theme in the name (--surface-dark is a dead end the moment you add a third theme).
HEX, RGB or HSL — pick per use, not per project
| Notation | Strengths | Weaknesses | Use when |
|---|---|---|---|
HEX #7C5CFF | Compact, universally understood, pastes into any design tool | Unreadable as a relationship; no alpha without 8-digit form | Handoff, documentation, anything a designer will read |
RGB rgb(124 92 255) | Direct alpha via the slash syntax; matches canvas and image pipelines | Hard to adjust by hand meaningfully | Overlays, shadows, anything needing transparency |
HSL hsl(252 100% 68%) | Human-editable; lightness and saturation ramps are obvious | Not perceptually uniform across hues | Generated ramps, quick manual tweaks, theming maths |
OKLCH oklch(0.64 0.22 288) | Perceptually even lightness; better gradient interpolation | Needs a modern browser; less familiar to review | New projects on evergreen browsers only |
Curiosityjivar emits all four for every token, so the choice stays a per-file decision rather than a migration.
What a CSS export should look like
:root {
/* primitives */
--violet-500: #7C5CFF;
--violet-600: #6B49F2;
--neutral-50: #F7F8FC;
--neutral-950: #0A0B14;
/* semantics — light */
--surface-1: var(--neutral-50);
--text-strong: var(--neutral-950);
--action-primary: var(--violet-500);
--action-primary-hover: var(--violet-600);
}
:root[data-theme="dark"] {
--surface-1: #141726;
--text-strong: #EEF0F8;
--action-primary: #8F73FF;
--action-primary-hover: #A288FF;
}
The same data exported as JSON is what feeds contrast regression tests, native app builds and documentation pages. Keep one source of truth and generate every format from it; two hand-maintained copies will diverge within a month.
Copy behaviour that does not annoy people
Small details decide whether a copy button gets used. Copy the value only — no trailing semicolon, no quotes, no token name unless the user asked for it. Confirm the action visibly and briefly, with a status message that assistive technology announces rather than a colour change alone. Let the user switch notation before copying instead of copying the wrong format and forcing a conversion. And support copying a whole group at once, because nobody wants to click twenty-four buttons.
What a live preview is actually for
A row of swatches tells you very little. Colours only reveal their problems in context: at the size they will be used, adjacent to the colours they will sit next to, behind the type you will actually set. A useful preview therefore needs to include the four situations where palettes fail.
- Dense text on a surface — a full paragraph, not a heading, at your real body size.
- A 1px border between two surfaces — the fastest way to see whether your border token is doing anything at all.
- An interactive element in every state — default, hover, focus, active, disabled, rendered simultaneously rather than one at a time.
- A destructive action next to a primary one — where semantic red meets brand colour, and where the two most often clash.
The preview on our home page is deliberately narrow in scope: it proves the tokens are internally consistent, not that they suit your product. Treat it as a first filter. The real test is pasting the export into your own codebase and looking at a page you already know well — you will spot a wrong border colour in a familiar layout in seconds, and never in a demo.
Versioning the palette
Tokens are code. Commit them, review changes in pull requests, and write down why a value moved. A colour changed "because it looked better" is impossible to defend six months later when someone asks whether they can change it back. A colour changed "to raise the input border from 2.4:1 to 3.1:1" answers itself. See contrast and accessibility for the checks worth automating.