Skip to content
A dark crypto portfolio screen, a context menu, an accordion and a filled button, labeled with the tokens they read: bg/primary, brand/base and static/static-white-0, with the cursors of a client, a developer and a designer

Tokens

The tokens you design with are the values that ship.

Every color, space, radius and type step lives once as a token. One source generates CSS, SwiftUI, Compose and Flutter, so nobody retypes a hex and nobody guesses a spacing step.

Architecture

Two token levels, and you only ever touch one of them.

Every design system that survives a rebrand has this shape. Most files skip the second level, which is why changing a brand color in them means opening every screen.

Level 1, primitive

Primitives are the raw scale.

A ramp of brand steps, a neutral ramp, the state colors. They carry no meaning, and no component ever reads one directly. This is the level you edit when the brand changes.
Change the primitive
  1. colors/bluepurple/50
  2. colors/bluepurple/100
  3. colors/bluepurple/200
  4. colors/bluepurple/300
  5. colors/bluepurple/400
  6. colors/bluepurple/500
  7. colors/bluepurple/600
  8. colors/bluepurple/700
  9. colors/bluepurple/800
  10. colors/bluepurple/900
  11. colors/bluepurple/950

Level 2, semantic

Semantic tokens are the layer above.

They say what a value is for rather than what it is, and they are the only thing components bind to. Move a primitive and every alias pointing at it follows, in both modes and on both platform mirrors.
The brand aliases and the step of colors/bluepurple each points at in light and dark mode
AliasLightDark
brand/lightercolors/bluepurple/50colors/bluepurple/950
brand/lightcolors/bluepurple/100colors/bluepurple/900
brand/basecolors/bluepurple/500colors/bluepurple/400
brand/darkcolors/bluepurple/700colors/bluepurple/300
brand/darkercolors/bluepurple/800colors/bluepurple/200

colors/bluepurple/500 points to brand/base

Button fill, links, focus ring

Mode
One exception worth knowing. On-color tokens map to static black and static white and do not flip with the theme, because a label on a filled button stays legible in both modes only if it refuses to follow them.

Follow any token from the raw scale to the pixel it lands on.

Each row is one chain: one value, read from primitive to alias to the place it actually renders. Point at a row with a mouse, or tab to it, and the rest step back.

PrimitiveSemantic aliasWhere it lands
colors/blue/500brand/baseButton fill, links, focus ring
colors/gray/950text/strong-950Headlines and body copy
colors/gray/50bg/weak-50Cards, wells, quiet surfaces
colors/red/500state/error/base-500Field errors and destructive actions
static/static-white-0text/on-color/strongLabels on a filled button, both modes

Output

Each platform gets its tokens in the language it already speaks.

A token is not useful until it arrives in a form the platform already understands. The translation is part of the build, so what lands is idiomatic rather than converted.

One source token

brand/base

Light {colors.blue.500}, Dark {colors.blue.400}, #155DFC / #2B7FFF

spacing/4

Foundations, a 4pt base, 16

motion/duration/fast

Motion, on the standard easing, 120ms

  1. CSS custom properties

    var(--ap-brand-base)

    #155DFC, and #2B7FFF under the dark block

    var(--ap-space-4)

    16px

    var(--ap-duration-fast)

    120ms

    Both modes as scoped blocks, ready for a class or a media query.

  2. SwiftUI

    Color.apBrandBase

    Color(red: 0.082, green: 0.365, blue: 0.988)

    AppetiteSpacing.space4

    16 as CGFloat

    AppetiteMotion.durationFast

    0.12 seconds

    Color extensions, and type on Dynamic Type anchors rather than fixed point sizes.

  3. Jetpack Compose

    AppetiteTheme.colors.brandBase

    Color(0xFF155DFC)

    Space4

    16.dp

    DurationFast

    120 milliseconds

    Color objects and a ready Material 3 typography object, so the theme arrives wired.

  4. Flutter

    apBrandBase

    Color(0xFF155DFC)

    apSpace4

    16.0

    apDurationFast

    Duration(milliseconds: 120)

    Color constants and text styles shaped for ThemeData.

The source is W3C DTCG, a public standard rather than a private schema. It comes in the file you buy, compiled with Style Dictionary to CSS, SwiftUI, Compose and Flutter. If you ever stop using this system, your values leave with you in a format other tools can read. That is deliberate.

Your next rebrand is one edit.

One-time payment, Lifetime updates, Unlimited client projects