---
name: build-color-system
description: From selected base color swatches, build a complete design system color palette with shade ramps, status/alert colors, neutral scale, and semantic tokens for light and dark modes — all as Figma variables with canvas swatches.
---

# Build Color System

Generate a full design-system color palette from a set of user-selected base color swatches. The output includes primitive shade ramps, a harmonious neutral scale, status/alert colors, and semantic tokens with light/dark mode support — all created as Figma variables and visualized as labeled canvas swatches.

## Running this with Claude and the Figma MCP

Written for Figma's built-in agent, adapted for Claude (Claude Code, Claude Desktop or claude.ai) connected to the official Figma MCP server.

- **Get the file.** If you don't have a Figma link, ask for one. The file key is the segment after `/design/`; a `node-id=1-2` parameter means node `1:2`.
- **Start a session.** Call `create_session` with the file key before any other Figma tool, and pass the returned session ID on every later call.
- **Read before writing.** `get_metadata` shows the structure and the user's current selection, `get_variable_defs` lists the variables on a node, `search_design_system` finds published components, variables and styles, and `get_screenshot` shows what's on the canvas.
- **Write with `use_figma`.** It runs Plugin API JavaScript in the file. Load the `figma-use` skill first (plus `figma-generate-library` when you create variables, styles or components) and list them in `skillNames`. Scripts use top-level `await` and `return` everything they create: nothing persists between calls, so pass node and variable IDs forward as string literals. Colors are 0–1, not 0–255. Switch pages with `await figma.setCurrentPageAsync(page)`, at most once per call; for multi-page work, run one call per page in parallel. `figma.notify()` isn't available.
- **Ask, then wait.** Wherever a step says to ask the user, ask in chat (in Claude Code, use the AskUserQuestion tool) and wait for the answer before building.
- **Clear helper fills.** `figma.createAutoLayout()` frames start with a white fill. Set `fills = []` on rows and wrappers that should be transparent, or they show up as white bars (most visibly in dark-mode previews).
- **Check the result.** After a build step, take one screenshot (`await node.screenshot()` inside `use_figma`, or `get_screenshot`) and fix only what's wrong.

## Prerequisites

The user must select one or more filled rectangles (or shapes) on the canvas representing their base brand colors before invoking this skill.

## Workflow

### Step 1 — Extract Base Colors and Validate Names

Read the fill color from each selected layer (`get_metadata` lists the current selection; read the fills with a `use_figma` script). Log the hex value, RGB, and convert to HSL for each.

**Check layer names:** If the selected layers have descriptive names (not default names like "Rectangle 1", "Frame 2", etc.), use those names for the color ramps. If any layers have default/generic names, suggest that the user rename them before proceeding. Explain that the layer names will become the variable group names throughout the system (e.g., a layer named "Sage" becomes `sage/50`, `sage/100`, etc.). Offer to proceed with auto-generated names based on the hue if the user prefers not to rename.

### Step 2 — Ask About Palette Tone

Before generating any colors, ask the user to describe the desired saturation character of the palette. Present options like:
- **Muted / Earthy** — low saturation, dusty and soft (peak sat ~20-30%)
- **Balanced** — moderate saturation, clear but not loud (peak sat ~40-50%)
- **Vibrant** — high saturation, bold and energetic (peak sat ~60-75%)

Use their answer to calibrate the saturation curve for all generated ramps, including status colors. This prevents the back-and-forth of generating colors that are too bright or too dull.

### Step 3 — Generate Primitive Shade Ramps

For each base color, generate an 11-step shade ramp: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950.

- Step 50 is near-white with a hint of the hue
- Step 500 is close to the base color's lightness
- Step 950 is near-black with a hint of the hue
- Saturation follows the tone the user chose in Step 2

Generate a **neutral ramp** (same 11 steps) that is warm- or cool-tinted to complement the base palette's overall temperature.

### Step 4 — Derive Status & Alert Colors

Create colors for four statuses: **Success**, **Warning**, **Error**, **Info**.

**Step 4a — Map base colors to statuses:**

Ask the user which of their base colors (if any) should map directly to a status role. Present the base colors alongside the four statuses and ask them to assign any natural fits. For example: "Your sage green seems like a natural fit for Success, and your cream for Warning — does that work, or would you assign them differently?"

For statuses the user maps to a base color, **reuse that base color's ramp directly** — no new primitive ramp is created. The semantic tokens simply alias the existing primitives.

**Step 4b — Fill gaps for unmapped statuses:**

For any status that doesn't map to an existing base color (commonly Error, sometimes Info), analyze the existing palette to identify a complementary hue:
- Look at the hue distribution of the base colors and find a hue that fills a gap without clashing
- **Match the saturation character** chosen in Step 2 — new status ramps must feel like they belong in the same family

Before generating the new ramp(s), ask the user: "Your palette doesn't include a red/rose tone for Error. Would you like to pick a specific hue, or should I choose one that complements your existing colors?" If they want to choose, let them provide a color or describe what they want. If they defer, proceed with your best judgment and generate the ramp.

For status colors that get their own ramp, generate the same 11-step shade scale.

### Step 5 — Create Variable Collections

Create two variable collections:

**Primitives** (single mode called "Default"):
- One COLOR variable per shade step per ramp (e.g., `sage/500`, `cream/200`, `error/700`)
- Do NOT create primitive variables for status colors that alias an existing base ramp — those are handled at the semantic layer

**Semantic** (two modes: "Light" and "Dark"):
- Each semantic variable aliases a primitive variable, switching which primitive it points to per mode
- Set `scopes` on every variable you create (for example `FRAME_FILL` and `SHAPE_FILL` for backgrounds, `TEXT_FILL` for text, `STROKE_COLOR` for borders). The default exposes each variable in every property picker.
- Semantic token categories to include:

| Category | Tokens |
|----------|--------|
| Background | `bg/primary`, `bg/secondary`, `bg/tertiary`, `bg/inverse` |
| Surface | `surface/default`, `surface/raised`, `surface/overlay` |
| Text | `text/primary`, `text/secondary`, `text/tertiary`, `text/inverse`, `text/on-accent` |
| Border | `border/default`, `border/strong`, `border/subtle` |
| Brand accents | For each base color: `{color}/default`, `{color}/subtle`, `{color}/strong` |
| Status | For each status: `status/{status}/default`, `status/{status}/subtle`, `status/{status}/strong`, `status/{status}/text`, `status/{status}/border` |

**Light/dark mapping pattern:**
- Light mode uses lighter primitives for backgrounds (50-200) and darker for text (700-900)
- Dark mode inverts: darker primitives for backgrounds (800-900) and lighter for text (200-400)
- Accent defaults shift one step lighter in dark mode for visibility

### Step 6 — Build Canvas Swatches

Create a visual reference frame on the canvas containing:

1. **Title and description** explaining the palette
2. **Primitive ramp rows** — each base color and neutral gets a labeled horizontal row of 11 swatches, each bound to its primitive variable
3. **Status & Alert section** — only ramps that are unique (not aliased to a base color), with a note explaining which base colors are reused
4. **Semantic token preview** — grouped by category, showing light and dark swatch pairs side by side, labeled with the token name

Use auto-layout for all sections. Swatches should be 64×64px with 8px corner radius. Label each step number below its swatch.

### Step 7 — Summary

Report what was created:
- Number of primitive variables
- Number of semantic variables
- Which status colors reuse base ramps vs. have their own
- Remind the user to publish the file as a library to make variables available across files
