Skip to content

Tokens

A reference for every token type in Brilliant's design system: what they look like, how they're generated, and when to use which. The seed template ships every section below populated; this page tells you what's in it.

Color tokens

Color tokens come from seeds. A seed is a single hex or OKLCH literal that, wrapped in color(...), the resolver expands into an 11-step ramp via the OKLCH color space:

red: color(oklch(63.7%, 0.237, 25.331))

Generates the primitive stops: red.50, red.100, red.200, red.300, red.400, red.500, red.600, red.700, red.800, red.900, red.950. The seed value IS the .500 stop.

Without color(...), the assignment is a single-value primitive (no ramp): red: #0080FF gives you $red only.

Primitive palette stops are fixed values, not mode-aware tones. $neutral.50 is always near-white in every mode; $neutral.950 is always near-black. If you want a color that flips with mode, wrap the primitive in boldness(...) to get the semantic, mode-aware role names.

Lightness scale

StopApprox lightnessTypical use
.5097%Subtle backgrounds
.10094%Light backgrounds
.20087%Hover states
.30080%Borders
.40071%Muted elements
.50062%Primary (the seed)
.60050%Hover on primary
.70042%Active states
.80036%Dark accents
.90029%Very dark
.95023%Darkest accents

Lower numbers = lighter. Higher numbers = darker.

Semantic role names (boldness)

Wrap a color(...) primitive in boldness(...) to expose mode-aware role names. The 9 boldness stops map to OKLCH lightness stops:

RoleMaps toIn light modeIn dark mode
hint.50very lightvery dark
faint.100lightdark
subtle.200hover lighthover dark
soft.300border lightborder dark
mid.500the seedthe seed
firm.600hover darkhover light
bold.700active darkactive light
strong.800dark accentlight accent
intense.900very darkvery light

boldness(color(...)) carries a theme.dark: mirror transform by default, reflecting low↔high (hint ↔ intense, faint ↔ strong, etc.) so the same role name reads correctly across themes (it also gets accessibility.high-contrast: outward(1) by default). You don't write these in the seed; they're the generator's defaults. Override them with an explicit transforms: { ... } arg, or opt out with transforms: none.

The .400 and .950 primitive stops are unused by the catalog's default boldness mapping but stay available to power users as raw primitive references.

What ships in the seed template

CategoryNames
Brand slotsprimary, secondary, tertiary, quaternary (defaults #0080FF / #FF3377 / #FF9900 / #FFDD00, the Brilliant logo palette). Hue-agnostic role slots, not named for what they are.
Neutralneutral (default oklch(55.6%, 0, 0))
Tailwind v4 palettes (21)red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose, slate, gray, zinc, stone

Each Tailwind palette is declared as an OKLCH literal matching Tailwind v4's source-of-truth, then wrapped in boldness(color(...)):

red: boldness(color(oklch(63.7%, 0.237, 25.331)))

This gives you both the primitive ramp (red.50..950) and the boldness roles (red.hint..intense).

Chrome aliases

The seed template ships with a set of chrome aliases under color.*. These are semantic role names that point at the underlying palettes, and they're the names that show up in the inspector picker:

AliasDefault referenceUse
color.surfaceneutral.hintPage backgrounds
color.surface.containerneutral.faintCard / container backgrounds
color.surface.container.highneutral.subtleElevated surfaces
color.on-surfaceneutral.strongText on surfaces
color.outlineneutral.softPrimary borders
color.outline.variantneutral.subtleSubtle borders
color.text.primaryneutral.boldBody text
color.text.secondaryneutral.firmSecondary text
color.text.disabledneutral.softDisabled text
color.text.displayprimary.firmHero / title color
color.text.display.altsecondary.firmHero callout variant
color.primary / on-primary / primary.containerprimary.mid / neutral.50 / primary.subtlePrimary role trio
color.secondary / on-secondary / secondary.containersecondary.mid / neutral.50 / secondary.subtleSecondary role trio
color.tertiary / on-tertiary / tertiary.containertertiary.mid / neutral.50 / tertiary.subtleTertiary role trio
color.quaternary / on-quaternary / quaternary.containerquaternary.mid / neutral.900 / quaternary.subtleQuaternary role trio (dark text: yellow is too bright for white)
color.success / on-success / success.containergreen.mid / neutral.50 / green.subtleSuccess role trio
color.error / on-error / error.containerred.mid / neutral.50 / red.subtleError role trio
color.warning / on-warning / warning.containerorange.mid / neutral.900 / orange.subtleWarning role trio
color.info / on-info / info.containerblue.mid / neutral.50 / blue.subtleInfo role trio
color.shadowneutral.950Default shadow cast (primitive, mode-immune)
color.glowneutral.50Default outer-glow color (primitive, mode-immune)

Each alias is a single line. Refs to a boldness(color(...)) semantic inherit that semantic's mode-awareness; refs to a primitive stop are mode-immune.

color.shadow: neutral.950 always resolves to a near-black hex, in every mode, because neutral.950 is a fixed primitive stop. Compare to color.text.primary: neutral.bold, which mirrors to a near-white in dark mode because neutral.bold carries the theme.dark: mirror transform from its boldness(color(...)) seed.

Custom palettes

Add your own palette by declaring a new color seed with any name:

acme_blue:   boldness(color(oklch(60%, 0.21, 230)))
acme_orange: boldness(color(#FF6A00))

Immediately produces acme_blue.50..950 (primitive stops) and acme_blue.hint..intense (mode-aware roles). References like color.cta: acme_blue.bold work normally.

Spacing tokens

The spacing declaration is an explicit list wrapped in tshirt(...) for semantic role names, with a none: 0 boundary stop:

spacing: tshirt(number([4, 8, 12, 16, 24, 32, 48, 64, 96, 128]),
                min: { none: 0 })

This produces both $spacing.1..10 (the raw list values by position) and $spacing.xs..6xl (t-shirt role names mapped to list positions, list[i] → role[i]), plus $spacing.none (0).

Like every number-backed scale (spacing, radius, font.size, font.weight, font.lineHeight, font.letterSpacing, stroke.width, visibility), spacing emits no bare token: always name a stop ($spacing.md, never $spacing). Only color seeds and font.family get a bare form.

T-shirt stopDefault value
spacing.none0
spacing.xs4
spacing.sm8
spacing.md12
spacing.lg16
spacing.xl24
spacing.2xl32
spacing.3xl48
spacing.4xl64
spacing.5xl96
spacing.6xl128

The seed template also ships negative overlap stops for pulling auto-layout children together (avatar stacks, badges biting into a card corner):

spacing.overlap.xs:  -2
spacing.overlap.sm:  -4
spacing.overlap.md:  -8
spacing.overlap.lg:  -16
spacing.overlap.xl:  -24
spacing.overlap.2xl: -32

Edit the list to rescale everything:

spacing: tshirt(number([8, 16, 24, ...]))   // each stop scaled up

density.compact shifts the t-shirt mapping down a notch automatically (md → lg's old position, etc.). accessibility.large-text shifts up. (These are the tshirt(...) generator defaults.)

Radius tokens

T-shirt scale with boundary stops. Radius opts out of mode transforms (transforms: none) so corners don't change with density or accessibility modes:

radius: tshirt(number([2, 4, 6, 8, 12, 16, 20, 24, 32, 40, 48, 64, 96]),
               min: { none: 0 }, max: { full: 9999 },
               transforms: none)
TokenDefault valueUse
radius.none0Sharp corners
radius.xs2Subtle rounding
radius.sm4Small (chips, badges)
radius.md6Default (cards, buttons)
radius.lg8Prominent rounding
radius.xl12Larger rounding
radius.2xl16Cards, panels
radius.3xl20Extra-large
radius.4xl24Hero containers
radius.5xl32Big blobs
radius.6xl40
radius.7xl48
radius.8xl64
radius.9xl96
radius.full9999Fully rounded (pills, circles)

Stroke width tokens

Boldness scale (uses the same 9-stop vocabulary as color tones):

stroke.width: boldness(number([0.5, 0.75, 1, 1.25, 1.5, 2, 2.5, 3, 4]),
                       min: { none: 0 },
                       max: { thick: 8, thicker: 16, thickest: 48 })
TokenDefault value
stroke.width.none0
stroke.width.hint0.5
stroke.width.faint0.75
stroke.width.subtle1
stroke.width.soft1.25
stroke.width.mid1.5
stroke.width.firm2
stroke.width.bold2.5
stroke.width.strong3
stroke.width.intense4
stroke.width.thick8
stroke.width.thicker16
stroke.width.thickest48

There's no bare $stroke.width form: number-backed scales emit no bare token, so always name a stop (e.g. $stroke.width.mid). A bare reference is flagged as a mistake.

Heads-up: Stroke width tokens can be bound from the inspector's thickness dropdown (it lists the canvas's stroke-width tokens), or via blueprint syntax (st[(#000,w($stroke.width.soft))]).

Visibility tokens

Boldness scale of opacity-ish values:

visibility: boldness(number([0.05, 0.10, 0.20, 0.40, 0.50, 0.60, 0.80, 0.90, 0.95]),
                     min: { invisible: 0 },
                     max: { opaque: 1 })
TokenDefault value
visibility.invisible0
visibility.hint0.05
visibility.faint0.10
visibility.subtle0.20
visibility.soft0.40
visibility.mid0.50
visibility.firm0.60
visibility.bold0.80
visibility.strong0.90
visibility.intense0.95
visibility.opaque1

Use for layered transparency overlays, scrim opacity, gradient stops, etc.

Font size tokens

T-shirt scale, Tailwind-aligned:

font.size: tshirt(number([12, 14, 16, 20, 24, 32, 36, 40, 48, 64, 80, 96, 128]),
                  transforms: { accessibility.large-text: shift(+1) })

The explicit transforms: overrides the t-shirt default (which would also shrink text under density.compact); only the large-text upshift is kept, since shrinking text by mode hurts readability.

TokenDefault value
font.size.xs12
font.size.sm14
font.size.md16
font.size.lg20
font.size.xl24
font.size.2xl32
font.size.3xl36
font.size.4xl40
font.size.5xl48
font.size.6xl64
font.size.7xl80
font.size.8xl96
font.size.9xl128

md is the body-text size; everything else multiplies up or down from there in spirit.

Font weight tokens

Standard 9-step weight scale, exposed via boldness:

font.weight: boldness(number([100, 200, 300, 400, 500, 600, 700, 800, 900]))
TokenValueCSS Equivalent
font.weight.hint100Thin
font.weight.faint200Extra Light
font.weight.subtle300Light
font.weight.soft400Normal
font.weight.mid500Medium
font.weight.firm600Semi Bold
font.weight.bold700Bold
font.weight.strong800Extra Bold
font.weight.intense900Black

There's no bare $font.weight form: number-backed scales emit no bare token, so always name a role stop (e.g. $font.weight.bold). A bare reference is flagged as a mistake.

Line height tokens

Looseness scale:

font.lineHeight: looseness(number([1.0, 1.25, 1.375, 1.5, 1.625, 2.0]))
TokenValueUse
font.lineHeight.none1.0Single-line, icons
font.lineHeight.tight1.25Headings
font.lineHeight.snug1.375Compact body
font.lineHeight.normal1.5Body text
font.lineHeight.relaxed1.625Comfortable reading
font.lineHeight.loose2.0Double-spaced

accessibility.large-text shifts mappings toward looser by one step.

Letter spacing tokens

Looseness scale:

font.letterSpacing: looseness(number([-0.05, -0.025, -0.0125, 0, 0.025, 0.1]))
TokenValueUse
font.letterSpacing.none-0.05Very tight (display)
font.letterSpacing.tight-0.025Tight (headings)
font.letterSpacing.snug-0.0125Slightly tight
font.letterSpacing.normal0Default
font.letterSpacing.relaxed0.025Wide
font.letterSpacing.loose0.1All-caps spacing

Font family tokens

Three families ship by default:

font.family:        Manrope
font.family.serif:  "Noto Serif"
font.family.mono:   monospace

Add more with separate primitive declarations:

font.family.display: "Fraunces"

Reference with the full dotted path ($font.family.mono). The font picker in the right toolbar sets fontFamily literally. To bind a family to a token, use a typography composite that has fontFamily set, or wire it through blueprint syntax.

Typography composites

The seed template ships these typography composites:

TokenfontSizefontWeightlineHeight
typography.display.lgfont.size.6xl (64)bold1.1
typography.display.md52bold1.1
typography.display.sm44bold1.15
typography.h1font.size.3xl (36)bold1.2
typography.h230bold1.25
typography.h3font.size.xl (24)firm1.3
typography.h4font.size.lg (20)firm1.35
typography.body.lg18softnormal
typography.body.mdfont.size.md (16)softnormal
typography.body.smfont.size.sm (14)softnormal
typography.buttonfont.size.sm (14)firmtight
typography.inputfont.size.md (16)soft1.4
typography.labelfont.size.sm (14)mid1.4
typography.captionfont.size.xs (12)soft1.4
typography.codefont.size.sm (14)softnormal (monospace family)
typography.editorial.lg / .md / .smsame scale as displayboldmatchedSerif (Noto Serif) variants for editorial headlines

Apply a composite via the Apply Typography Token palette command. It sets fontSize, fontWeight, fontFamily, and lineHeight on the selected text in one go, and binds the composite typographyTokenRef (clearing any individual font-property token bindings).

Shadow composites

Tailwind-aligned shadow elevations:

TokenLayers (visual feel)
shadow.2xsy:1, blur:0, opacity:0.05 (almost imperceptible)
shadow.xsy:1, blur:1, opacity:0.05 (very subtle)
shadow.smy:1, blur:2, opacity:0.05 (small lift)
shadow.md2-layer, y:2/y:4 (default elevation)
shadow.lg2-layer, y:4/y:10 (pronounced lift)
shadow.xl2-layer, y:10/y:20 (floating)
shadow.2xly:25, blur:50, opacity:0.25 (dramatic)
shadow.innery:2, blur:4 (inset feel)

Apply via the Apply Shadow Token palette command. Replaces existing drop shadows on the element; preserves inner shadows, glows, and blurs.

The canonical default.styles shape

The seed template's structure, condensed:

modes {
  theme:         [light, dark]
  density:       [comfortable, compact]
  accessibility: [standard, high-contrast, large-text]
}

// Brand and palette colors
primary:    boldness(color(#0080FF))
secondary:  boldness(color(#FF3377))
tertiary:   boldness(color(#FF9900))
quaternary: boldness(color(#FFDD00))
neutral:    boldness(color(oklch(55.6%, 0, 0)))
red:        boldness(color(oklch(63.7%, 0.237, 25.331)))
// ...21 Tailwind palettes total

// Geometry & motion
spacing:      tshirt(number([4, 8, 12, 16, 24, 32, 48, 64, 96, 128]),
                     min: { none: 0 })
radius:       tshirt(number([2, 4, 6, 8, 12, 16, 20, 24, 32, 40, 48, 64, 96]),
                     min: { none: 0 }, max: { full: 9999 },
                     transforms: none)
stroke.width: boldness(number([0.5, 0.75, 1, 1.25, 1.5, 2, 2.5, 3, 4]),
                       min: { none: 0 }, max: { thick: 8, thicker: 16, thickest: 48 })
visibility:   boldness(number([0.05, 0.10, 0.20, 0.40, 0.50, 0.60, 0.80, 0.90, 0.95]),
                       min: { invisible: 0 }, max: { opaque: 1 })

// Typography
font.family:        Manrope
font.family.serif:  "Noto Serif"
font.family.mono:   monospace
font.size:          tshirt(number([12, 14, 16, 20, 24, 32, 36, 40, 48, 64, 80, 96, 128]),
                          transforms: { accessibility.large-text: shift(+1) })
font.weight:        boldness(number([100, 200, 300, 400, 500, 600, 700, 800, 900]))
font.lineHeight:    looseness(number([1.0, 1.25, 1.375, 1.5, 1.625, 2.0]))
font.letterSpacing: looseness(number([-0.05, -0.025, -0.0125, 0, 0.025, 0.1]))

// Chrome aliases (semantic role names pointing at resolver outputs)
color.surface:                neutral.hint
color.surface.container:      neutral.faint
color.surface.container.high: neutral.subtle
color.on-surface:             neutral.strong
color.outline:                neutral.soft
color.outline.variant:        neutral.subtle
color.text.primary:           neutral.bold
color.text.secondary:         neutral.firm
color.text.disabled:          neutral.soft
color.text.display:           primary.firm
color.text.display.alt:       secondary.firm
color.primary:                primary.mid
color.on-primary:             neutral.50      // primitive ref → mode-immune
color.primary.container:      primary.subtle
// (mirror for secondary, tertiary, quaternary, success, error, warning, info)
color.shadow:                 neutral.950
color.glow:                   neutral.50

What's not built in

A few token types you might expect but Brilliant doesn't ship:

  • Animation tokens (duration, easing). Not yet. Could be added as user-defined primitives later.

  • Numeric tokens with units. Numbers are stored as plain doubles. No px/rem/em/% unit system.

Everything else is a custom token away. Pick a name, add it to your Styles/default.styles, and reference it.

We use cookies to understand how you use our site. Analytics cookies help us improve. You can accept them, reject them, or manage preferences.

Customize