Skip to content
Content
Skill

/figma-style-binding

Triggers on any visual property change in Figma — creating text, setting colors, adjusting spacing/padding/gap/radius. Enforces that ALL values bind to Figma Styles or Variables, never hardcoded. Includes post-write QA verification.

From plugin
claude2figma
2034 skills
Install
$ npx -y skills add senlindesign/claude2figma --skill figma-style-binding --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/figma-style-binding

Context preview

The summary Claude sees to decide when to auto-load this skill.

Triggers on any visual property change in Figma — creating text, setting colors, adjusting spacing/padding/gap/radius. Enforces that ALL values bind to Figma Styles or Variables, never hardcoded. Includes post-write QA verification.

SKILL.md

figma-style-binding.SKILL.md
name: figma-style-binding
description: "Triggers on any visual property change in Figma — creating text, setting colors, adjusting spacing/padding/gap/radius. Enforces that ALL values bind to Figma Styles or Variables, never hardcoded. Includes post-write QA verification."
disable-model-invocation: false

Style Binding + QA

Every visual value must come from the design system. Supplements `figma-generate-design`. Prerequisite: `figma-preflight` must have run this session.

---

Binding Hierarchy

For any visual property, follow this order. Stop at the first match.

1. Connected Library  →  search_design_system → import → apply
2. Local Style        →  Style Registry → apply by ID
3. Local Variable     →  Variable Registry → apply by ID
4. Gap found          →  Report to user, wait for decision

---

Text

Every text node must use `textStyleId`. Individual font properties (`fontSize`, `fontFamily`, etc.) are forbidden.

const style = await figma.getStyleByIdAsync("<id>");
await figma.loadFontAsync(style.fontName);
node.textStyleId = "<id>";

If no local style matches, search libraries via `search_design_system`. If no match anywhere:

⚠️ Text style gap: no style for "[role]". Available: [top 5]. Use closest, or add missing style?

---

Color Fills

Every fill/stroke must bind to a COLOR Variable (preferred, supports theming) or Paint Style.

// Variable binding (preferred)
const variable = await figma.variables.getVariableByIdAsync("<id>");
const fill = { type: "SOLID", color: { r: 0, g: 0, b: 0 } };
node.fills = [figma.variables.setBoundVariableForPaint(fill, "color", variable)];

// Paint Style binding
node.fillStyleId = "<id>";

Never use raw `{ r, g, b }` without a binding.

---

Spacing, Padding, Gap, Radius

Bind to FLOAT Variables. `layoutMode` must be set BEFORE `setBoundVariable`.

node.setBoundVariable("paddingTop", spacingVar);
node.setBoundVariable("paddingBottom", spacingVar);
node.setBoundVariable("paddingLeft", spacingVar);
node.setBoundVariable("paddingRight", spacingVar);
node.setBoundVariable("itemSpacing", spacingVar);
node.setBoundVariable("cornerRadius", radiusVar);

Spacing can fall back to raw values temporarily with user confirmation. Color and text cannot.

---

Forbidden / Required

| Forbidden | Required | |---|---| | `node.fontSize = 24` | `node.textStyleId = id` | | `node.fills = [{ type: "SOLID", color: { r: .2, g: .4, b: 1 } }]` | Variable or Style binding | | `node.paddingLeft = 16` | `node.setBoundVariable("paddingLeft", var)` | | `node.cornerRadius = 8` | `node.setBoundVariable("cornerRadius", var)` | | Creating a Button from scratch | `importComponentByKeyAsync` from library |

---

QA Verification

After every `use_figma` call that creates or modifies nodes, run this verification on the returned node IDs:

const nodeIdsToAudit = [/* paste returned IDs */];
const results = [];

for (const id of nodeIdsToAudit) {
  const node = await figma.getNodeByIdAsync(id);
  if (!node) { results.push({ id, status: "NOT_FOUND" }); continue; }

  const checks = [];

  if (node.type === "TEXT") {
    checks.push({ prop: "textStyleId", bound: !!node.textStyleId });
  }

  if ("fills" in node && Array.isArray(node.fills) && node.fills.length > 0) {
    const bound = !!node.fillStyleId || (node.boundVariables?.fills?.length > 0);
    checks.push({ prop: "fills", bound });
  }

  if ("layoutMode" in node && node.layoutMode !== "NONE") {
    for (const p of ["paddingLeft","paddingRight","paddingTop","paddingBottom","itemSpacing"]) {
      if (p in node) checks.push({ prop: p, bound: !!(node.boundVariables && p in node.boundVariables) });
    }
  }

  if ("cornerRadius" in node && node.cornerRadius > 0) {
    checks.push({ prop: "cornerRadius", bound: !!(node.boundVariables && "cornerRadius" in node.boundVariables) });
  }

  const failed = checks.filter(c => !c.bound);
  results.push({ id, name: node.name, type: node.type, status: failed.length === 0 ? "PASS" : "FAIL", failed: failed.map(c => c.prop) });
}

return { auditResults: results };

**If FAIL:** Fix each unbound property using the binding rules above, then re-audit. Do not proceed to the next design step until all pass.

**Report format:**

✅ All [N] nodes passed.
// or
❌ FAIL "Card" (FRAME) — paddingTop, cornerRadius unbound. Fixing...
Read more
Ships withclaude2figma

Design System compliance for AI-generated Figma designs. 4 skills, 3-step preflight, zero raw values. Quick start: Clone, copy skills to .claude/skills/, paste your Figma URL into CLAUDE.md, say "let's start". Full install guide below.

Get the whole plugin
Stats
203
Stars
17
Forks
Maintained
Maintenance
MIT
License
4mo ago
Last commit
4mo ago
Created

Repo: senlindesign/claude2figma

Other skills on claude2figma.