Figma M3 Variables
Complete workflow for managing Variables in Figma using Google Material Design 3 three-tier inheritance (Ref → Sys → Comp).
MANDATORY prerequisite: Read the figma-use skill before any use_figma call.
Always pass skillNames: "figma-m3-variables" to every use_figma call.
0. General Rules (apply to every workflow)
- Inspect before Write — Before each operation, run a read-only
use_figmato confirm current state, then proceed with writes. - ALL_SCOPES is forbidden — Set explicit scopes based on token role (see token-spec.md).
- Always set WEB code syntax — Format is fixed:
var(--{prefix}-{layer}-{name}), e.g.var(--md-sys-color-primary). - Return all IDs — Every create/modify script must
returnall affected variable IDs and node IDs. - Token prefix is fixed once confirmed — Use the same prefix throughout the entire session; mixing prefixes is not allowed.
use_figmacalls are strictly sequential — Never run twouse_figmacalls in parallel.- Prefer Comp bindings — Bind design nodes to
comptokens when a matching component token exists. Usesysonly for shared page-level primitives or when no component token exists yet; never bindrefdirectly. - Dry-run before broad writes — For any operation touching more than one node, first return a binding plan and wait for confirmation unless the user explicitly says to auto-apply without review.
- On error, stop and read the error message, fix it, then retry — never retry blindly.
Automation boundary
This skill can bind Variables through the Figma Plugin API, but it is not a background sync service.
- Single target: If the user provides a URL/node-id or a current selection and asks to apply Variables, run Workflow A and bind after presenting the proposed mapping.
- Created target: If Workflow B or D creates Variables/components, bind the new target nodes as part of that workflow after the mapping is known.
- Batch target: If the user asks to apply Variables to a selection, component set, page, or many components, run Workflow E. Batch work defaults to dry-run plus confirmation.
- No target: If the user only asks whether Variables exist or whether naming is correct, inspect or audit only. Do not bind anything.
- Ambiguous target: Ask for the node-id, selection scope, component set, page, or batch scope before writing.
Layer naming philosophy (Ref / Sys / Comp)
Three layers have different naming jobs. When creating, applying, or auditing Variables, enforce this split:
| Layer | Role | Naming rule |
|---|---|---|
Reference (ref) |
Raw values only (hex, px, weight). | Primitive, scale, or value — a name must read as “what number or swatch is this?” with no component, screen, or layout region. |
System (sys) |
Product-wide semantics shared by many components. | Shared, semantic — roles like primary, error, inset, gap — no names tied to one component’s structure or anatomy. |
Component (comp) |
Bind real UI to Sys. | Component and structure — button, input, card, bottom-bar, container/padding-horizontal, etc. |
Reference — intuitive value naming (good)
- Colors: palette steps or hue steps, e.g.
ref/color/red/50,ref/palette/primary/40— the name reflects the color scale, not where it is used. - Sizes / spacing: the value is in the name, e.g.
ref/size/12→ 12px,ref/spacing/16→ 16 — not roles like “bottom bar” or “button”. - Radius, type:
ref/radius/12,ref/type/size/14— still primitive.
Reference — forbidden
- Any segment that names a component or pattern (e.g.
button,input,card,fab,chip,dialog). - Any segment that names a layout region or screen part (e.g.
bottom-bar,top-app-bar,navigation-bar,sheet). - Spacing that encodes where it is used instead of how much it is, e.g.
ref/spacing/bottom-bar/paddingorref/spacing/button/padding-h— those belong in Comp (and may alias Sys generic spacing).
System — good
- Semantics reused across the product:
sys/color/primary,sys/color/on-primary,sys/spacing/inset-horizontal-md,sys/spacing/gap-inline-sm,sys/shape/corner-full. - Names describe role, not a specific component’s internal layout.
System — forbidden
- Component-specific or anatomy tied to one component: e.g.
sys/spacing/button-padding-h,sys/color/top-app-bar-surface,sys/size/navigation-bar-height— push the component name to Comp; keep Sys generic (e.g.inset-horizontal-md,surface-container).
Component — where structure lives
- Only here:
comp/filled-button/...,comp/text-field/...,comp/navigation-bar/...,container/padding-horizontal,with-icon/icon-label-gap, etc. Comp tokens alias Sys (and Sys aliases Ref).
Detailed naming patterns, WEB examples, and the Filled Button walkthrough with corrected Ref/Sys names are in references/token-spec.md §1 and §4.
Workflow A: Apply Existing Variables to a Component
Trigger: User provides a Figma URL + node-id, current selection, or one component and requests Variables to be applied.
Steps
Inspect variables and target anatomy — List all variable collections and variables in the file, then inspect the target node tree names, node types, fills, strokes, radius, layout, text children, and existing
boundVariables:const cols = await figma.variables.getLocalVariableCollectionsAsync(); const result = []; for (const c of cols) { const vars = []; for (const id of c.variableIds) { const v = await figma.variables.getVariableByIdAsync(id); if (v) vars.push({ name: v.name, id: v.id, type: v.resolvedType, scopes: v.scopes }); } result.push({ collection: c.name, id: c.id, modes: c.modes.map(m => m.name), variables: vars }); } return result;Evaluate tokens and target:
- Variables exist and naming follows M3 three-tier structure → proceed to Step 3
- Variables are missing or incomplete → switch to Workflow B
- Target is an instance → bind only instance-supported overrides; prefer binding the main component when the user wants library-wide changes
- Target already has bindings → preserve correct bindings and only propose replacements for mismatches
Match component requirements — Based on component type and anatomy, find corresponding tokens from the Comp layer using token-spec.md §4-§5. Return a binding plan with:
- Node ID and node name
- Property to bind
- Current value / existing bound variable
- Proposed variable name and ID
- Confidence (
exact,inferred,needs-review) Present the plan for confirmation unless the user explicitly requested immediate apply.
Bind — Execute:
- Background / foreground color:
figma.variables.setBoundVariableForPaint(paint, "color", variable)→ assign the resulting paint back to the node - Stroke color: same helper on each solid stroke paint, then assign the resulting strokes back to the node
- Corner radius:
node.setBoundVariable("topLeftRadius", variable)× all 4 corners - Padding:
node.setBoundVariable("paddingLeft" | "paddingRight" | "paddingTop" | "paddingBottom", variable) - Gap:
node.setBoundVariable("itemSpacing", variable) - Text color: same as above (
setBoundVariableForPainton the text node's fills) - Typography:
node.setBoundVariable("fontFamily" | "fontSize" | "fontWeight" | "lineHeight" | "letterSpacing", variable)when matching text tokens exist - Width / height / opacity: bind only when the token semantics are explicit and the node property is intended to be tokenized
- Background / foreground color:
Validate — Inspect
boundVariables, return affected variable IDs and node IDs, then callget_screenshotto confirm visual correctness.
Workflow B: Create Variables (none exist in the file)
Trigger: No M3 three-tier Variables found in the file, or user explicitly requests creation.
Steps
Discover design guidelines — Run the same discovery check as Workflow D Step 1.
- Guidelines found → summarize and confirm with the user before deriving token values.
- No guidelines found → run the same AskQuestion flow as Workflow D Step 1 Path B to gather visual style preferences. Use the answers to inform Ref token values (palette colors, shape radius, spacing scale) in Step 4.
Ask for prefix — Use AskQuestion to let the user choose (e.g.
md,dd,bd, or custom).Ask for Collection structure — Use AskQuestion:
- Three separate collections (recommended):
{Prefix} · Reference,{Prefix} · System,{Prefix} · Component · {ElementName} - Single collection: one collection using group prefixes to distinguish the three layers
- Three separate collections (recommended):
Inspect — Confirm there are no duplicate collection names in the current file.
Create Variables — Follow the token list in token-spec.md, using values informed by the design guidelines gathered in Step 1:
- Ref layer: stores raw values (hex colors, numbers); scope set to
[](hidden, not shown in picker) - Sys layer: aliases (
VARIABLE_ALIAS) pointing to Ref; scope set by role - Comp layer: aliases pointing to Sys; scope set by role
- Ref layer: stores raw values (hex colors, numbers); scope set to
Bind — Once Variables are created, run Workflow A Step 4 to bind them to target nodes.
Validate — Call
get_screenshotto confirm visual correctness, and report the variable counts for each of the three-tier collections.
Ref Layer Scope Rule
Ref layer variables must not appear in the designer's picker. Their scope must be set to [] (empty array).
Workflow C: Audit Existing Variables
Trigger: User requests a check, audit, or asks "is the naming correct?".
Steps
Inspect — Read all collections, variables, scopes, code syntax, and valuesByMode.
Apply audit-rules.md — Check each violation type, including alias direction, scope, WEB syntax, modes, type/property compatibility, and Ref/Sys naming, then compile a list of issues.
Report — Present as a table or list:
- Violating variable names
- Violation type
- Suggested fix
Ask whether to fix — After presenting the issues, use AskQuestion: "Do you want to automatically fix the above issues?" If the user agrees, execute fix scripts for each item.
Validate after fix — Inspect again to confirm zero violations remain.
Workflow D: Design Components from Existing Variables
Trigger: User wants the AI to understand existing tokens and use them to create or update components.
Steps
Discover design guidelines — Before doing anything else, inspect the file for an existing design system or style guide. Run the following script:
const pages = figma.root.children.map(p => p.name); const paintStyles = await figma.getLocalPaintStylesAsync(); const textStyles = await figma.getLocalTextStylesAsync(); const effectStyles = await figma.getLocalEffectStylesAsync(); const components = figma.root.findAllWithCriteria({ types: ['COMPONENT', 'COMPONENT_SET'] }); return { pages, paintStyleCount: paintStyles.length, textStyleCount: textStyles.length, effectStyleCount: effectStyles.length, componentCount: components.length, paintStyles: paintStyles.map(s => ({ name: s.name, description: s.description })), textStyles: textStyles.map(s => ({ name: s.name, fontSize: s.fontSize, fontName: s.fontName })), };Evaluate the result and branch:
Path A — Design guidelines exist (paint styles ≥ 3 OR text styles ≥ 2 OR components ≥ 5, OR a page name contains "guideline / style / brand / design system / foundation / principle"):
- Scan those pages and existing components for visual patterns
- Summarize findings to the user before proceeding:
- Color palette: primary, secondary, neutral, semantic (error/success) hues
- Shape language: fully rounded / slightly rounded / sharp corners (infer from component radii)
- Typography scale: heading sizes, body sizes, font families
- Spacing rhythm: common padding/gap values
- Visual tone: minimal / expressive / corporate / playful (infer from density and color saturation)
- Ask the user: "I found the following design guidelines. Does this match your intent before I start building?" — present the summary and wait for confirmation or corrections.
Path B — No design guidelines found (counts are all low and no guideline page exists):
- Inform the user: "I couldn't find any design guidelines in this file."
- Use AskQuestion to gather the following (may be split into multiple questions):
- Product type — What kind of product is this? (e.g. consumer app, enterprise tool, e-commerce, dashboard, marketing site)
- Visual style — Which direction best describes the desired aesthetic?
- Minimal & clean (lots of whitespace, subtle shadows, neutral palette)
- Bold & expressive (strong colors, large typography, dynamic shapes)
- Corporate & trustworthy (conservative palette, structured layout, formal typography)
- Playful & friendly (rounded shapes, vibrant colors, casual typography)
- Custom — user describes in their own words
- Shape preference — Fully rounded (pill) / Slightly rounded / Sharp / Follow M3 defaults
- Color preference — Any brand colors or preferred palette? (hex codes or descriptions)
- Reference products / brands — Any existing apps or websites to reference?
- Summarize the collected preferences and confirm with the user before proceeding.
Inspect variables — List all variables, analyze the three-tier structure and token semantics (
primary,on-primary,container-shape, etc.).Understand semantic mapping:
**/color/primaryor**/container/background-color→ component background**/color/on-primaryor**/label-text/color→ component foreground text**/shape/**or**/container/shape→ corner radius**/padding-horizontal/**/padding-vertical→ padding**/spacing/**or**/gap→ gap- Cross-reference these mappings against the design guidelines confirmed in Step 1 — if the token values conflict with the guidelines, flag it to the user.
Identify variants and states — Before building, analyze the component type and propose which variants and interaction states are applicable. Use AskQuestion (multi-select) to let the user choose:
Variants (structural differences — become Component Set properties):
- Refer to the component's typical variant dimensions in token-spec.md § 7
- Examples:
Size(Small / Medium / Large),Style(Filled / Outlined / Text),Leading icon(True / False)
Interaction states (visual overrides — become additional Component Set properties or separate frames):
- Always include:
Default - Suggest based on component type (see token-spec.md § 7):
Hovered— container color lightens/darkens by state layer opacityFocused— typically adds a focus ring or outlinePressed— deeper state layer overlayDisabled— reduced opacity or dedicated disabled tokensError— replaces primary color tokens with error tokensSuccess— replaces primary color tokens with success/positive tokens
Present the proposed list and ask: "Which variants and states would you like to include?"
Plan state tokens — For each selected state, determine whether existing Comp tokens cover it or new state-specific tokens are needed:
- If the file already has tokens like
…/container/background-color/hovered→ reuse them - If not → add them following the naming convention in token-spec.md § 7 before proceeding
- Disabled state: always needs a dedicated token (opacity or color override); do not reuse Default tokens
- If the file already has tokens like
Build the component — Based on the token mappings, confirmed design guidelines, and selected variants/states:
- If only
Defaultstate (no variants) → create a single Frame / Component and bind variables using Workflow A Step 4 - If variants or multiple states are selected → create a Component Set: one Component node per variant × state combination, each with appropriate token bindings; refer to the Phase 3 rules in the
figma-generate-libraryskill for Component Set structure - Name each variant frame descriptively, e.g.
State=Hovered, Size=Medium - Ensure visual decisions (radius, spacing, color) are consistent with the design guidelines from Step 1
- If only
Validate — Call
get_screenshotto confirm the component looks correct, token colors resolve properly, and all selected states are visually distinct.
Workflow E: Batch Apply Variables to Existing Components
Trigger: User asks to apply Variables to multiple selected nodes, a component set, a page, or all matching components.
Steps
Define scope — Confirm the batch scope before writing:
- Current selection
- One Component Set
- Current page
- Components matching a name pattern If the scope is broad or ambiguous, ask before continuing.
Inspect batch candidates — Read all candidate nodes and existing local Variables. For each candidate, collect node type, component/variant names, visible children, layout properties, paint/stroke/radius/text properties, and existing
boundVariables.Classify components — Match candidates to known component families from token-spec.md §5:
- Exact: name and anatomy match a known component pattern
- Inferred: anatomy suggests a pattern but naming is imperfect
- Unknown: no reliable token mapping
Build a dry-run plan — Return a table grouped by component:
bind: safe exact matchesreview: inferred matches requiring confirmationskip: unknown nodes, missing tokens, type mismatches, or already-correct bindings Include counts for nodes scanned, bindings proposed, already-correct bindings, skipped nodes, and missing tokens.
Confirm — Ask before applying unless the user explicitly said to auto-apply. Never silently bind
reviewitems in batch mode; only bind exact matches automatically after confirmation.Apply — Run one sequential
use_figmawrite script that:- Re-fetches each node and variable by ID
- Verifies the node and variable still exist
- Verifies variable type is compatible with the target property
- Preserves correct existing bindings
- Applies supported bindings only
- Returns applied, skipped, and failed items with node IDs and variable IDs
Validate — Re-inspect
boundVariablesfor changed nodes and callget_screenshot. Report any failures with the exact reason and suggested next action.
Division of Responsibility with Other Skills
| Skill | Responsibility |
|---|---|
figma-use |
Underlying Plugin API rules (colors 0–1, return, page switching, etc.) — must be read first |
figma-m3-variables (this skill) |
Creating, applying, batch-binding, auditing, and reverse-engineering M3 Variables in Figma |
design-system-governance |
Code-side token governance (CSS/SCSS tokens) — complements this skill |
figma-generate-library |
Full multi-phase design system build; refer to its Phase 3 when Workflow D involves component creation |
Reference Documents
- token-spec.md — M3 three-tier naming rules, component token lists, and scope reference table
- audit-rules.md — Audit violation type definitions and fix guidelines