Tokens
Design tokens are the named decisions that power every visual property in your design system — colours, spacing, typography, radii, and more. Particles stores, versions, and distributes them so your team always works from a single source of truth.
What is a token?#
A token is a named design decision. Instead of hard-coding a colour value in ten different places, you create a token called color/primary and reference it everywhere. When your brand colour changes, you update the token once and every surface updates automatically.
In the Studio token editor, each token shows its name, type, current value, and a live preview — colour swatches for colour tokens, scale labels for spacing, and so on.
The four tiers#
Particles organises tokens into four tiers — what you are defining determines which tier you use:
Primitive — raw values
Primitives are your base palette. They hold an exact, final value with no references to other tokens. Think of them as your raw materials — brand colours, spacing scales, radii.
color/neutral-50 → #f9f9f7 color/neutral-900 → #1a1a18 spacing/1 → 0.25rem radius/md → 0.5rem
Semantic — design intent
Semantic tokens give a meaning to a primitive. Instead of saying "use neutral-900," you say "use background." This lets you swap the entire palette without changing any component references.
color/background → {color.neutral-900}
color/foreground → {color.neutral-50}
color/border → rgba(226, 226, 226, 0.12)Composition — bundled styles
Compositions bundle multiple properties into one named style — like a typography heading that includes font family, size, weight, and line height. Each property can reference another token or hold a raw value.
# Typography composition: "heading-1"
fontFamily → {font.sans}
fontSize → {spacing.8}
fontWeight → 700
lineHeight → 1.2When exporting to Tailwind v4, each composition token becomes a ready-to-use CSS class in your codebase — for example, .heading-1 applies all bundled typography properties at once.
Component — component-scoped tokens
Component tokens are the most specific tier: values tied to a particular UI component, such as button/background or card/padding. They reference a semantic token (or hold a structured value) so a single semantic change cascades to every component that uses it — without coupling components to raw primitives.
button/background → {color.primary}
button/radius → {radius.md}
card/padding → {spacing.4}The Studio shows a tier toggle at the top of the token tree — switch between Primitive, Semantic, Composition, and Component to focus on just the tier you are editing.
Token types#
Every token has a type that determines what kind of value it holds. 16 built-in types are created automatically when you set up a project:
| Type | What it defines | Example values |
|---|---|---|
| Color | Brand and UI colours | #b45309, rgb(99, 102, 241) |
| Typography | Font families, sizes, and weights | Inter, 1rem, 700 |
| Spacing | Padding, margin, and gap scales | 0.25rem, 1rem |
| Radii | Border-radius scales | 0.375rem, 0.5rem, full |
| Shadow | Box-shadow values | 0 1px 3px rgba(0,0,0,0.1) |
| Opacity | Transparency levels | 0.5, 0.8 |
| Border | Border width and style | 1px, 2px |
| Duration | Transition and animation timing | 150ms, 300ms |
| Z-index | Stacking order | 10, 50, 9999 |
| Elevation | Surface elevation / depth levels | 0, 1, 4, 8, 16 |
| Grid | Grid layout columns, gutters, margins | 12, 24px, 80px |
| Motion | Easing curves and animation presets | ease-in-out, ease-out |
| Line Height | Text line-height values | 1, 1.5, 2 |
| Letter Spacing | Text letter-spacing values | 0, 0.01em, 0.05em |
| Font Weight | Numeric font-weight values | 400, 500, 700 |
| Breakpoint | Responsive breakpoint widths | 640px, 768px, 1280px |
Need something custom? Under Project → Settings → Token types you can add project-specific types beyond the 16 built-ins.
Sub-groups#
Tokens within a type can be organised into named sub-groups — for example, grouping your neutral colours under color → neutral and your brand colours under color → brand. This produces clean CSS variable names like --color-neutral-50 and keeps your token tree scannable.
Create groups from the token editor by clicking the + button next to a type header. When creating a token, select its group from a dropdown.
Creating and editing tokens#
The token editor opens in read-only browse mode — editing (including creating a token) requires an active change. See Changes & governance.
In the Studio token editor, click New token and fill in:
| Field | Description |
|---|---|
| Name | The token name within its group (e.g. "500", "primary"). |
| Type | Choose from built-in types or custom types you have added. |
| Tier | Primitive (raw value), Semantic (references another token), Composition (bundled properties), or Component (component-scoped). |
| Group | Optional sub-group path. Omit for top-level tokens. |
| Value | A raw value for primitives, or the name of another token for semantics. |
| Description | Optional note explaining the token intent. |
| Tags | Searchable labels (e.g. "brand", "dark-mode"). |
The token form adapts based on the tier you select: primitive shows a plain value input, semantic shows a reference picker that only shows tokens of the same type, and composition shows a structured property grid.
Token policy
Projects can define a write-time token policy (Protection settings, org admins): a naming pattern with optional per-tier overrides, a required description, semantic-must-alias (semantic tokens must reference, never hold raw values), and an allowed-units list for dimension tokens like spacing, radii, and breakpoints. Saving a token that violates the policy fails with HTTP 422 POLICY_VIOLATION, listing each broken rule. Imports are never blocked by policy — the import diff carries a non-blocking policyWarnings list instead, so legacy files can land first and be cleaned up inside the governed editor.
How references resolve#
When you link one token to another — for example, {color.neutral-900} — the platform resolves the full chain automatically. A semantic token pointing to a primitive immediately shows the resolved value. Circular references are rejected on save.
Resolved values are recalculated every time you view or export tokens, so you never see a stale reference.
Make Scalable — refactor a flat set into tiers#
Inherited a token set that is one flat layer of hard-coded values — or a Figma file where every colour was created as a raw variable with no structure? Make Scalable turns it into a proper primitive → semantic system without rewriting anything by hand.
| Step | What happens |
|---|---|
| Extract primitives | Distinct raw values become cleanly-named primitives — colours as color.{family}.{shade}, dimensions as ordinal scales. Values are preserved exactly. |
| Re-point semantics | Tokens that carry intent (text, background, on-brand…) are pointed at the primitive of their value, in place — their name and id never change. |
It respects the structure you already have: tokens that were already primitives are kept verbatim — including your own family names like brand-lime-800 — and only genuine semantics are re-pointed. Nothing is renamed, deprecated, or deleted, and every rendered value stays identical, so the change is non-breaking.
Make Scalable is fully reviewable before it runs — every token shows its proposed target and you can retarget or skip any of them — and a single Revert last run restores the branch to its exact pre-migration state.
Where to run it
| Surface | How |
|---|---|
| Studio | A "Make Scalable" action in the token editor toolbar opens a review modal. |
| Figma plugin | A "Make Scalable" button in the token manager — review, apply, and your bound Figma variables follow by id. |
| CLI | particles restructure — preview the plan, then re-run with --apply; --revert restores the branch. |
Previews are always free, but applying Make Scalable, restructure, cutover, or a revert onto a protected main is rejected — run them on a change branch and merge through review, or as an org admin (audited as a hotfix).
Prefer to migrate onto a brand-new, cleanly named set instead of refactoring in place? That is a different flow — particles migrate --scalable — which mints the new set and rewrites your legacy tokens into deprecated aliases pointing at it. See the CLI reference for when to use which.
Tokenize Design — bootstrap tokens from a raw Figma file#
Make Scalable refactors a token set that already exists. Tokenize Design is the step before that — for a Figma file that never used variables at all, where every colour, spacing, radius, and font is a hard-coded raw value. It runs in the Figma plugin: scan the page (or just your selection), name everything into a clean primitive → semantic set, create the variables, and rebind the nodes — with rendered values preserved exactly.
| Step | What happens |
|---|---|
| Scan or read an image | Walk the page/selection for unbound raw values, or read a colour palette straight from a reference image with a vision model. |
| Name into a scalable set | Distinct values become cleanly-named primitives (color.{family}.{shade}, ordinal scales); usage infers semantics (text, background, border, effect). |
| Review | Rename or skip any row, merge near-identical colours, and see a live "create N · rebind M" tally before anything changes. |
| Create + rebind | Create the variables and rebind every matching node in scope — fills, strokes, effects, spacing, radius, stroke weight, font size & family. |
The rebind is value-driven: it binds every node whose value matches a new token, not just the ones the scan enumerated — so a palette read from an image still rebinds the matching layers on your canvas. Choose This page or Selected nodes for the rebind scope; a selection-scoped run never touches anything outside your selection.
Tokenize Design requires a Team plan or above. Variables are written into your project's own collection, and an optional “save to the project” step versions the new tokens so they round-trip with Pull and flow into your CLI, CI, and exports. The image/vision path uses Google Gemini; without a configured key the scan-based flow still works.
Accessibility & contrast#
Particles can compute WCAG contrast ratios between any two colour tokens. In the token detail form, tag a pair as foreground/background, and the Studio displays the contrast ratio with AA/AAA pass/fail badges. Failing pairs show the nearest compliant alternatives.
Your organisation admin can view a company-wide Accessibility Dashboard that aggregates all failing pairs across projects.
Figma variable scope#
Every token that maps to a Figma variable can carry a scope — a setting that controls which design properties the variable appears in. Scopes are stored alongside the token value and applied automatically when you pull tokens into Figma.
Scopes keep your variable picker tidy: a spacing token scoped to "gaps" will appear when setting auto-layout gaps but not when choosing fill colours — exactly where it belongs.
Where each token type appears in Figma
| Token type | Where it appears in Figma | Default |
|---|---|---|
| Color | Fills, text color, stroke color, shadow color | All fills |
| Spacing | Auto-layout gaps, width & height | Gaps |
| Radii | Corner radius | Corner radius |
| Opacity | Layer opacity | Opacity |
| Font Weight | Font weight | Font weight |
| Line Height | Line height | Line height |
| Letter Spacing | Letter spacing | Letter spacing |
| Typography | Font family, style, size, weight, line height, letter spacing, paragraph spacing | Font family |
| Shadow, Border, Composition | — | No scope (stored as text in Figma — variable binding is not supported for these types) |
Setting scopes in the Studio
Open any token in the token editor. When the token type supports scopes, a Figma scope field appears at the bottom of the inspector panel. Click the scope chips to toggle which properties are active — chips with a dot indicator are the recommended defaults for that type. Deselecting all chips falls back to the platform default on the next pull.
Setting scopes in the Figma plugin
The plugin token form includes the same scope chip selector. Changes are saved back to the platform with the token value. On the next Push, scope changes appear in the review diff alongside value changes — so you can tell a scope-only change apart from a value change in the confirmation dialog.
Scope auto-detection on import
When you import tokens from an external file, Particles automatically infers the right scope from the token's name and group path. For example, a colour token named background defaults to fills; a token named text defaults to text color. You can adjust any inferred scope after import.
Figma sync
When you Pull, scopes are applied to each Figma variable automatically. When you Push, both value changes and scope changes are tracked independently — each appears as a separate entry in the review dialog. If you edit a variable's scope directly in Figma's variables panel, the plugin detects the change and surfaces a notification banner, just like a value change.