Claude-code-plugins figma-core-workflow-a
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/figma-pack/skills/figma-core-workflow-a" ~/.claude/skills/jeremylongshore-claude-code-plugins-figma-core-workflow-a && rm -rf "$T"
manifest:
plugins/saas-packs/figma-pack/skills/figma-core-workflow-a/SKILL.mdsource content
Figma Core Workflow A -- Design Token Extraction
Overview
The primary workflow for Figma API integrations: extracting design tokens (colors, typography, spacing) from a Figma file and converting them to CSS custom properties, JSON tokens, or Tailwind config.
Prerequisites
- Completed
setupfigma-install-auth - A Figma file with published styles or variables
andFIGMA_PAT
env vars setFIGMA_FILE_KEY
Instructions
Step 1: Fetch Styles from a File
import { FigmaClient } from './figma-client'; const client = new FigmaClient(process.env.FIGMA_PAT!); const fileKey = process.env.FIGMA_FILE_KEY!; // GET /v1/files/:key -- returns styles map in response const file = await client.getFile(fileKey); // file.styles is a map: nodeId -> { key, name, style_type, description } // style_type: "FILL" | "TEXT" | "EFFECT" | "GRID" const colorStyles = Object.entries(file.styles) .filter(([, s]) => s.style_type === 'FILL') .map(([nodeId, s]) => ({ nodeId, name: s.name })); const textStyles = Object.entries(file.styles) .filter(([, s]) => s.style_type === 'TEXT') .map(([nodeId, s]) => ({ nodeId, name: s.name })); console.log(`Found ${colorStyles.length} color styles, ${textStyles.length} text styles`);
Step 2: Resolve Style Values from Nodes
// Fetch the actual nodes to get fill colors and text properties const styleNodeIds = colorStyles.map(s => s.nodeId); const nodesResponse = await client.getFileNodes(fileKey, styleNodeIds); interface DesignToken { name: string; type: 'color' | 'typography' | 'spacing'; value: string; } const tokens: DesignToken[] = []; for (const [nodeId, nodeData] of Object.entries(nodesResponse.nodes)) { const node = nodeData.document; const styleName = colorStyles.find(s => s.nodeId === nodeId)?.name; if (node.fills?.[0]?.type === 'SOLID' && node.fills[0].color) { const { r, g, b, a } = node.fills[0].color; // Figma colors are 0-1 floats; convert to 0-255 const hex = '#' + [r, g, b].map(v => Math.round(v * 255).toString(16).padStart(2, '0') ).join(''); tokens.push({ name: styleName ?? node.name, type: 'color', value: a !== undefined && a < 1 ? `rgba(${Math.round(r*255)}, ${Math.round(g*255)}, ${Math.round(b*255)}, ${a.toFixed(2)})` : hex, }); } }
Step 3: Extract Typography Tokens
// Fetch text style nodes const textNodeIds = textStyles.map(s => s.nodeId); const textNodes = await client.getFileNodes(fileKey, textNodeIds); for (const [nodeId, nodeData] of Object.entries(textNodes.nodes)) { const node = nodeData.document; const styleName = textStyles.find(s => s.nodeId === nodeId)?.name; if (node.style) { tokens.push({ name: styleName ?? node.name, type: 'typography', value: JSON.stringify({ fontFamily: node.style.fontFamily, fontSize: `${node.style.fontSize}px`, fontWeight: node.style.fontWeight, lineHeight: node.style.lineHeightPx ? `${node.style.lineHeightPx}px` : 'normal', letterSpacing: node.style.letterSpacing ? `${node.style.letterSpacing}px` : '0', }), }); } }
Step 4: Generate CSS Custom Properties
function tokensToCss(tokens: DesignToken[]): string { const lines = [':root {']; for (const token of tokens) { const varName = `--${token.name.toLowerCase().replace(/[\s/]+/g, '-')}`; if (token.type === 'color') { lines.push(` ${varName}: ${token.value};`); } else if (token.type === 'typography') { const t = JSON.parse(token.value); lines.push(` ${varName}-family: ${t.fontFamily};`); lines.push(` ${varName}-size: ${t.fontSize};`); lines.push(` ${varName}-weight: ${t.fontWeight};`); } } lines.push('}'); return lines.join('\n'); } import { writeFileSync } from 'fs'; writeFileSync('src/styles/tokens.css', tokensToCss(tokens)); console.log(`Generated ${tokens.length} tokens to src/styles/tokens.css`);
Step 5: Use Variables API (Enterprise)
// GET /v1/files/:key/variables/local (Tier 2, requires file_variables:read) const vars = await client.getLocalVariables(fileKey); // vars.meta.variables: Record<variableId, Variable> // vars.meta.variableCollections: Record<collectionId, Collection> for (const [id, variable] of Object.entries(vars.meta.variables)) { const collection = vars.meta.variableCollections[variable.variableCollectionId]; console.log(`${collection.name}/${variable.name}: ${variable.resolvedType}`); // resolvedType: "COLOR" | "FLOAT" | "STRING" | "BOOLEAN" // Each variable has values per mode for (const [modeId, value] of Object.entries(variable.valuesByMode)) { const modeName = collection.modes.find(m => m.modeId === modeId)?.name; console.log(` ${modeName}: ${JSON.stringify(value)}`); } }
Output
- Design tokens extracted from Figma styles or variables
- CSS custom properties file generated
- Color values converted from Figma's 0-1 float format to hex/rgba
- Typography properties mapped to CSS-compatible values
Error Handling
| Error | Cause | Solution |
|---|---|---|
Empty map | File has no published styles | Publish styles in Figma first |
node in response | Node was deleted | Filter nulls before processing |
| 403 on variables endpoint | Not Enterprise plan | Use styles endpoint instead |
| Color looks wrong | Forgot 0-1 to 0-255 conversion | Multiply by 255 before hex |
Resources
Next Steps
For asset export, see
figma-core-workflow-b.