Skip to content
Beta Multi-model support (OpenAI, Gemini, and more) launching soon.

brand-theme-scaffolder

Installable Ships in design-system-manager — or copy the raw skill below.
Open Claude.ai

Paste into Claude Code, Claude.ai, the desktop app, or the browser extension — ⌘/Ctrl+V.

ExperimentalNo security review

Brand Theme Scaffolder

Scaffold a new brand theme as a thin semantic override layer on top of a shared base token set. The output is a DTCG-compliant brand file that changes only what the new brand requires, leaving primitive and component tokens shared across all brands.

Usage

/brand-theme-scaffolder <base-tokens-path> --brand <brand-slug> --primary <hex> [--secondary <hex>] [--font-family '<stack>'] [--radius sharp|soft|rounded|pill] [--platform sitecore|optimizely|umbraco|headless]

Examples:

  • /brand-theme-scaffolder tokens/ --brand nova --primary #0F4C81 — minimal brand override
  • /brand-theme-scaffolder tokens/ --brand nova --primary #0F4C81 --secondary #00A86B --radius rounded --platform sitecore
  • /brand-theme-scaffolder tokens/ --brand acme --primary #E63946 --font-family 'Inter, sans-serif' --platform headless

Phase 1 — Base Token Discovery

Read the existing base semantic token set:

ls <base-tokens-path>/semantic/

Parse each semantic token file to build a complete inventory of:

  • All semantic color tokens and their current values
  • Typography semantic tokens (font-family assignments)
  • Border radius semantic tokens
  • All action.* tokens (these are the primary brand identifiers)

If no tokens/base/semantic/ or tokens/semantic/ directory exists, run design-token-generator first to establish the base architecture.


Phase 2 — Brand Color Generation

From the --primary hex value, generate the brand's full primitive color scale:

Scale generation using oklch (perceptually uniform):

  1. Convert --primary hex to oklch: L C H
  2. Keep the hue H constant across all stops.
  3. Generate 10 stops (50–900) by interpolating lightness:
    • 50: L=97%
    • 100: L=94%
    • 200: L=87%
    • 300: L=76%
    • 400: L=64%
    • 500: L = provided primary's lightness (anchor)
    • 600: L=42%
    • 700: L=34%
    • 800: L=25%
    • 900: L=17%
  4. Verify WCAG AA contrast for action-primary text-on-background combinations. Adjust the semantic pointer (action-primary → brand.600 instead of brand.500) if the 500 stop fails 4.5:1 contrast against white.

If --secondary is provided, generate a second 10-stop scale using the same method.


Phase 3 — Generate Brand Primitive File

Create tokens/core/colors-<brand-slug>.json with the generated scale:

{
  "core": {
    "color": {
      "<brand-slug>": {
        "50":  { "$value": "<oklch or hex>", "$type": "color" },
        "100": { "$value": "...", "$type": "color" },
        "200": { "$value": "...", "$type": "color" },
        "300": { "$value": "...", "$type": "color" },
        "400": { "$value": "...", "$type": "color" },
        "500": { "$value": "<--primary hex>", "$type": "color" },
        "600": { "$value": "...", "$type": "color" },
        "700": { "$value": "...", "$type": "color" },
        "800": { "$value": "...", "$type": "color" },
        "900": { "$value": "...", "$type": "color" }
      }
    }
  }
}

Include $description on each token: "Brand Nova — blue 500 — primary action color".


Phase 4 — Generate Brand Semantic Override File

Create tokens/brands/<brand-slug>/semantic/color.json. This file only declares tokens that differ from the base. Every token must alias the brand's own primitive scale, not hard-coded values.

Minimum required overrides (always):

{
  "semantic": {
    "color": {
      "action": {
        "primary":            { "$value": "{core.color.<brand-slug>.500}", "$type": "color" },
        "primary-hover":      { "$value": "{core.color.<brand-slug>.600}", "$type": "color" },
        "primary-active":     { "$value": "{core.color.<brand-slug>.700}", "$type": "color" },
        "primary-disabled":   { "$value": "{core.color.<brand-slug>.200}", "$type": "color" },
        "primary-focus-ring": { "$value": "{core.color.<brand-slug>.400}", "$type": "color" }
      }
    }
  }
}

If --secondary was provided, also override:

"action": {
  "secondary":       { "$value": "{core.color.<brand-slug>-secondary.500}", "$type": "color" },
  "secondary-hover": { "$value": "{core.color.<brand-slug>-secondary.600}", "$type": "color" }
}

Phase 5 — Typography Override (if --font-family provided)

Create tokens/brands/<brand-slug>/semantic/typography.json:

{
  "semantic": {
    "typography": {
      "font-family-primary": {
        "$value": "<provided stack>",
        "$type": "fontFamily"
      }
    }
  }
}

Note in the output: if the brand uses a Google Font or custom web font, a @font-face or <link> to the font CDN must be added to the HTML <head> separately — tokens cannot load fonts.


Phase 6 — Border Radius Override (if --radius provided)

Map --radius flag to semantic overrides:

Flag value border-radius-sm border-radius-md border-radius-lg
sharp {core.border-radius.none} {core.border-radius.xs} {core.border-radius.sm}
soft {core.border-radius.sm} {core.border-radius.md} {core.border-radius.lg}
rounded {core.border-radius.lg} {core.border-radius.xl} {core.border-radius.2xl}
pill {core.border-radius.full} {core.border-radius.full} {core.border-radius.full}

Create tokens/brands/<brand-slug>/semantic/border-radius.json with these overrides.


Phase 7 — Token Diff Report

After writing all brand files, generate a diff report showing exactly what changes from base:

## Brand: <brand-slug> — Token Diff from Base

### Changed (semantic overrides)
| Token path | Base value | Brand value |
|-----------|-----------|-------------|
| semantic.color.action.primary | #3b82f6 | #0F4C81 |
| ... | | |

### Unchanged (inherited from base)
<n> tokens inherited without override

### New tokens (brand-only additions)
<list any tokens not in base>

### Contrast check
| Pairing | Ratio | WCAG AA (4.5:1) | WCAG AA Large (3:1) |
|---------|-------|-----------------|---------------------|
| action.primary on white | x.xx:1 | ✅/❌ | ✅/❌ |
| text.default on surface.page | x.xx:1 | ✅/❌ | ✅/❌ |

Phase 8 — Theme Switcher Integration

Generate a theme-switcher.<js|ts> snippet in dist/brands/<brand-slug>/:

// theme-switcher.ts
type Brand = '<brand-a>' | '<brand-b>' | '<brand-slug>';

export function setBrand(brand: Brand): void {
  document.documentElement.dataset.brand = brand;
  localStorage.setItem('preferred-brand', brand);
}

export function restoreBrand(): void {
  const saved = localStorage.getItem('preferred-brand') as Brand | null;
  if (saved) setBrand(saved);
}

Platform-specific integration notes:

  • Sitecore: Set data-brand on <body> in the SXA main layout Razor file from a site-level configuration item field.
  • Optimizely: Inject data-brand via a custom IContentRenderer or via a site-specific global settings content type.
  • Umbraco: Render data-brand from the site root node's property in _Layout.cshtml.
  • Headless: Set data-brand in _app.tsx (Next.js) or the root layout component (Astro) from an environment variable or site config.

Phase 9 — Style Dictionary Config Update

Print instructions to add the new brand to the existing Style Dictionary config (or generate a new build-tokens.js entry if one exists). See token-transform-pipeline skill for full pipeline setup.


Reference files

  • reference.md — Contrast ratio calculation method, oklch scale generation algorithm, per-platform data-brand injection patterns
Technical details
Plugin
design-system-manager
Author
Dakota Smith
Skill name
brand-theme-scaffolder
Maturity
experimental
Security review
No security review
Owners
  • design
  • engineering
Argument hint
<base-tokens-path> --brand <brand-slug> --primary <hex> [--secondary <hex>] [--font-family '<family stack>'] [--radius sharp|soft|rounded|pill] [--platform sitecore|optimizely|umbraco|headless]
Allowed tools
  • Read
  • Write
  • Edit
  • Glob
  • Bash(node *)
  • Bash(ls *)
Source
plugins/design-system-manager/skills/brand-theme-scaffolder/SKILL.md

Edit this skill on GitHub — opens GitHub's web editor. No git knowledge needed.