Brik Design System
Getting Started

Library Architecture

BDS sources tokens from two logical libraries — the Foundations Library (universal, agnostic) and per-client Brand Kit Libraries — composed by Style Dictionary into the shipped CSS bundle.

A Library is the authoritative source of token definitions for a scope. BDS uses two:

  • Foundations Library — universal, brand-agnostic. Owns math scales (typography / spacing / elevation / motion), grayscale primitives, system messaging primitives, and base semantic tokens that have a sensible default before any brand applies.
  • [Client] Brand Kit Library — one per client. Owns brand color primitives (poppy / tan / etc. for Brik; whatever palette the client has), brand semantic overrides (light + dark), and any client-specific mode picks.

"Library" is a logical concept, implementation-agnostic. Today both libraries are Figma files managed via the Tokens Studio plugin. If the storage layer changes (raw DTCG JSON, Penpot, etc.), the Library distinction still holds — it's a role, not a tool.

What each Library owns

LibraryPrimitivesSemantic tokensModes
Foundations--color-grayscale-*, --color-system-*, --font-size-*, --space-*, --border-radius-*, --shadow-*, motion primitives, annotationUniversal defaults (--text-primary, --surface-primary, --background-positive, etc.)borderwidth, spacing, typography, elevation, breakpoint, radius, icon
Brand Kit (per client)Brand color family ramps (--color-poppy-*, --color-tan-*, etc.)Brand overrides on the same canonical names (--background-brand-primary, --text-brand-primary, plus service-line semantics where applicable)color (light / dark) per brand

Foundations Library MUST NOT carry brand-specific values. That's the failure pattern brik-bds#712 retired — the deleted primitives/value.{brand, theme.brik, theme.blue} groups were brand-specific tokens sitting in Foundations. If a token would change per client, it belongs in a Brand Kit, not in Foundations.

How the libraries compose

Both libraries flow through the same Style Dictionary pipeline, into the same dist/tokens.css bundle, scoped to different CSS Layers:

┌──────────────────────────┐         ┌────────────────────────────┐
│  Foundations Library     │         │  [Client] Brand Kit Library│
│  (Figma — Tokens Studio) │         │  (Figma — Tokens Studio)   │
└────────────┬─────────────┘         └────────────────┬───────────┘
             │ pull-variables.js                      │ pull-variables.js
             │ (channel id)                           │ (channel id)
             ▼                                        ▼
   design-tokens/foundations.json        design-tokens/brand-kits/{slug}.json
             │                                        │
             └──────────── merge-tokens-studio.js ────┘


              design-tokens/tokens-studio.json   (composed snapshot)

                              │ Style Dictionary

              tokens/figma-tokens.css            (Foundations → @layer bds-tokens)
              tokens/figma-tokens-dark.css       (Foundations dark mode)
              tokens/theme-{client}.css          (Brand Kit → @layer client-theme)

                              │ build-dist-tokens.js

                       dist/tokens.css           (shipped to consumers)

Pull procedure

Open the Foundations and Brand Kit Figma files, start the Claude MCP plugin in each, and run:

# One command — pulls both Libraries, merges, and rebuilds CSS
./scripts/figma-pull-tokens.sh \
  --foundations=<foundations-channel-id> \
  --brand-kit=<brand-kit-channel-id>

Channel IDs are persisted to ~/.figma-channels (JSON) so you only need to pass them once per Figma session. Subsequent runs read the saved IDs:

./scripts/figma-pull-tokens.sh   # uses ~/.figma-channels

To pull a single Library without touching the other:

./scripts/figma-pull-tokens.sh --foundations=<channel-id>
./scripts/figma-pull-tokens.sh --brand-kit=<channel-id>

To merge without pulling (e.g., after manually editing a Library file):

npm run merge:tokens-studio
npm run build:all-tokens

Channel IDs are short, single-use tokens emitted by the Claude MCP plugin when a Figma file is opened. They expire when the Figma session closes. Never commit a channel ID — it's session-scoped, not configuration.

When to add a Brand Kit

ScenarioLibrary decision
New client onboarding (Vale / Renew / Memphis / etc.)Create a new Brand Kit Library in Figma. Set up brand color primitives + brand semantic overrides + dark mode. Emit theme-{client}.css.
Brand refresh on an existing clientUpdate the client's Brand Kit Library only. Foundations doesn't change. Pull → rebuild → ship the regenerated theme-{client}.css.
New universal token (math scale, system color, base semantic)Add to Foundations Library. Affects every brand. Coordinate via PR + Chromatic.
New brand-specific concept (service-line, audience-scoped color, custom dimension)Add to the relevant Brand Kit Library as a brand-specific semantic token (e.g., --background-service-marketing). Foundations stays untouched.

Drift signals

  • A new token name shaped --brand-{tier} or --theme-{name}-* shows up in dist/tokens.css → Library boundary violation. Move it to Brand Kit (or retire if redundant).
  • A consumer hand-overrides a primitive in their local globals.css instead of updating their Brand Kit Library → drift. The override belongs in the Brand Kit so it propagates to anyone consuming the same brand.
  • A "demo" or "structural" color sits in Foundations → boundary violation. Demo content belongs in a Brand Kit (or stories), never in canonical Foundations.

On this page

💬