// Figma design system integration with API automation, design tokens, and
| name | moai-domain-figma |
| version | 4.1.0 |
| created | "2025-11-18T00:00:00.000Z" |
| updated | 2025-11-19 |
| status | stable |
| description | Figma design system integration with API automation, design tokens, and component libraries for scalable design infrastructure. Enhanced MCP integration, error handling, and performance optimization. |
| allowed-tools | ["Read","Bash","WebFetch","mcp__figma__get_design_context","mcp__figma__get_screenshot","mcp__figma__get_variable_defs","mcp__figma__export_components","mcp__context7__resolve-library-id","mcp__context7__get-library-docs"] |
| stability | stable |
Enterprise design system architecture with Figma API, design tokens, and automation
Primary Agent: design-expert, component-designer Stack: Figma API 2025+, MCP integration, design tokens, component libraries, design-to-code automation Keywords: figma, design-system, design-tokens, components, design-to-code, mcp, automation Updated: Enhanced MCP tool patterns, error handling, performance optimization (v4.1.0)
| Tool | Purpose | Use Cases |
|---|---|---|
get_design_context | Retrieve design metadata + generated code | Component generation, design inspection |
get_screenshot | Export design as PNG/SVG | Asset export, visual documentation |
get_variable_defs | Extract design tokens/variables | Token syncing, design system export |
export_components | Batch export multiple components | Library generation, code scaffolding |
Design systems connect design and development with MCP automation:
Use when output of one call feeds into the next:
// Step 1: Get design context (metadata + generated code)
const context = await mcp__figma__get_design_context({
nodeId: "689:1242",
clientLanguages: "typescript",
dirForAssetWrites: "./src/generated/figma-assets" // REQUIRED!
});
// Step 2: Get screenshot based on context
const screenshot = await mcp__figma__get_screenshot({
nodeId: context.nodeId,
format: "png",
scale: 2
});
// Step 3: Extract variables from context
const tokens = context.variables || [];
When to use: Design inspection โ Asset export โ Token extraction
Use for independent requests to reduce total execution time (20-30% speedup):
// Fetch multiple independent resources in parallel
const [context, variables, screenshot] = await Promise.all([
mcp__figma__get_design_context({
nodeId: "689:1242",
clientLanguages: "typescript",
dirForAssetWrites: "./src/generated/figma-assets"
}),
mcp__figma__get_variable_defs({
fileId: "abc123xyz",
teamId: "team-456"
}),
mcp__figma__get_screenshot({
nodeId: "689:1242",
format: "svg"
})
]);
// All requests complete simultaneously
console.log("Parallel execution time: ~3-4s vs sequential 9-12s");
Speedup calculation:
Skip unnecessary calls based on requirements:
// Only call what you need
const config = {
needsCode: true,
needsAssets: false,
needsTokens: true
};
const requests = [];
// Conditionally add only required calls
if (config.needsCode || config.needsAssets) {
requests.push(
mcp__figma__get_design_context({
nodeId: "689:1242",
clientLanguages: "typescript",
dirForAssetWrites: config.needsAssets ? "./assets" : undefined
})
);
}
if (config.needsTokens) {
requests.push(
mcp__figma__get_variable_defs({
fileId: "abc123xyz"
})
);
}
const results = await Promise.all(requests);
Benefit: Reduce API calls by 30-50% based on actual needs
dirForAssetWrites (CRITICAL - Common Error Source)
// โ WRONG: Will cause 400 Bad Request
const context = await mcp__figma__get_design_context({
nodeId: "689:1242",
clientLanguages: "typescript"
// Missing dirForAssetWrites!
});
// โ
CORRECT: Specify asset output directory
const context = await mcp__figma__get_design_context({
nodeId: "689:1242",
clientLanguages: "typescript",
dirForAssetWrites: "/tmp/figma-assets" // Required even if not using assets
});
Why: MCP tool needs to know where to write exported assets (even if not used)
// NodeId examples (format: "parent-id:component-id")
const validNodeIds = [
"689:1242", // Simple component
"0:1", // Page/root
"689:1242:5678", // Nested instance
"I123:456:789" // Copy instance
];
// Validation pattern
function validateNodeId(nodeId: string): boolean {
// Format: alphanumeric:digit, optionally nested
return /^[a-zA-Z0-9]+:[0-9]+(:[0-9a-zA-Z:]+)?$/.test(nodeId);
}
if (!validateNodeId(nodeId)) {
throw new Error(`Invalid nodeId format: ${nodeId}`);
}
// Auto-detect from project context
function detectFramework(projectPath: string): string {
const packageJson = require(`${projectPath}/package.json`);
if (packageJson.dependencies?.react) {
return packageJson.dependencies.typescript ? "typescript" : "javascript";
}
if (packageJson.dependencies?.vue) {
return "typescript"; // Vue 3 + TS recommended
}
if (packageJson.dependencies?.["@angular/core"]) {
return "typescript"; // Angular always TS
}
return "typescript"; // Default
}
// Usage
const clientLanguages = detectFramework("./");
const context = await mcp__figma__get_design_context({
nodeId: "689:1242",
clientLanguages, // Auto-detected
dirForAssetWrites: "./src/generated"
});
// Error symptoms:
// - 400 Bad Request
// - "dirForAssetWrites is required"
// - Asset export fails silently
// Solution
try {
const context = await mcp__figma__get_design_context({
nodeId: "689:1242",
clientLanguages: "typescript",
dirForAssetWrites: "./src/generated/figma-assets" // Add this!
});
} catch (error) {
if (error.message.includes("dirForAssetWrites")) {
console.error("Missing dirForAssetWrites parameter");
// Provide default asset directory
return await mcp__figma__get_design_context({
nodeId: "689:1242",
clientLanguages: "typescript",
dirForAssetWrites: "/tmp/figma-assets" // Fallback
});
}
throw error;
}
Do NOT call in sequence unless necessary - Use parallel calls instead:
// โ INEFFICIENT: Sequential calls
const screenshot1 = await mcp__figma__get_screenshot({nodeId: "id1"});
const vars1 = await mcp__figma__get_variable_defs({fileId: "file1"});
const screenshot2 = await mcp__figma__get_screenshot({nodeId: "id2"});
const vars2 = await mcp__figma__get_variable_defs({fileId: "file1"});
// Total time: 16-20s (sequential)
// โ
EFFICIENT: Parallel calls grouped by type
const [screenshots, variables] = await Promise.all([
Promise.all([
mcp__figma__get_screenshot({nodeId: "id1"}),
mcp__figma__get_screenshot({nodeId: "id2"})
]),
mcp__figma__get_variable_defs({fileId: "file1"})
]);
// Total time: 3-4s (parallel)
Benefits: 4-5x faster for batch operations
// Exponential backoff for rate-limited requests
async function callWithBackoff(
fn: () => Promise<any>,
maxRetries = 3,
initialDelay = 1000
): Promise<any> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (error.status === 429) { // Rate limited
const delay = initialDelay * Math.pow(2, attempt);
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
throw new Error(`Max retries exceeded`);
}
// Usage
const screenshot = await callWithBackoff(() =>
mcp__figma__get_screenshot({nodeId: "689:1242"})
);
// Cache metadata with different TTLs based on change frequency
const cacheConfig = {
metadata: { ttl: 72 * 3600 }, // Design rarely changes (72h)
variables: { ttl: 24 * 3600 }, // Tokens updated daily (24h)
screenshots: { ttl: 6 * 3600 }, // Visual assets change frequently (6h)
components: { ttl: 48 * 3600 } // Component structure stable (48h)
};
// Implementation
const cache = new Map();
async function getWithCache(key: string, fetcher: () => Promise<any>, ttl: number) {
const cached = cache.get(key);
const now = Date.now();
if (cached && (now - cached.timestamp) < (ttl * 1000)) {
console.log(`Cache hit for ${key}`);
return cached.value;
}
const value = await fetcher();
cache.set(key, { value, timestamp: now });
return value;
}
// Usage
const variables = await getWithCache(
`variables:abc123`,
() => mcp__figma__get_variable_defs({fileId: "abc123"}),
cacheConfig.variables.ttl
);
// Process components in optimal batch sizes (10-20 per batch)
async function exportComponentsBatch(
nodeIds: string[],
batchSize = 15
): Promise<any[]> {
const results = [];
for (let i = 0; i < nodeIds.length; i += batchSize) {
const batch = nodeIds.slice(i, i + batchSize);
// Parallel requests within batch
const batchResults = await Promise.all(
batch.map(nodeId =>
mcp__figma__get_design_context({
nodeId,
clientLanguages: "typescript",
dirForAssetWrites: "./src/generated"
})
)
);
results.push(...batchResults);
// Small delay between batches to respect rate limits
if (i + batchSize < nodeIds.length) {
await new Promise(resolve => setTimeout(resolve, 100));
}
}
return results;
}
// Usage: Export 150 components in 10 parallel requests
const allComponents = await exportComponentsBatch(
Array.from({length: 150}, (_, i) => `component:${i}`)
);
import * as fs from "fs";
import * as path from "path";
interface DesignSystemConfig {
figmaFileId: string;
figmaTeamId?: string;
outputDir: string;
componentNodeIds: string[];
clientLanguages: "typescript" | "javascript";
}
async function syncDesignSystem(config: DesignSystemConfig) {
const {figmaFileId, outputDir, componentNodeIds, clientLanguages} = config;
console.log(`Starting design system sync for ${componentNodeIds.length} components...`);
// Phase 1: Extract design tokens
console.log("Phase 1: Extracting design tokens...");
const variables = await mcp__figma__get_variable_defs({
fileId: figmaFileId,
teamId: config.figmaTeamId
});
const tokensOutput = path.join(outputDir, "tokens.json");
fs.writeFileSync(tokensOutput, JSON.stringify(variables, null, 2));
console.log(`โ Tokens exported to ${tokensOutput}`);
// Phase 2: Generate component code (parallel batch processing)
console.log("Phase 2: Generating component code...");
const components = await exportComponentsBatch(componentNodeIds, 15);
const componentsDir = path.join(outputDir, "components");
fs.mkdirSync(componentsDir, {recursive: true});
components.forEach((component, index) => {
const componentFile = path.join(
componentsDir,
`${component.componentName || `Component-${index}`}.ts`
);
fs.writeFileSync(componentFile, component.generatedCode || "");
});
console.log(`โ Generated ${components.length} components`);
// Phase 3: Export visual assets (parallel)
console.log("Phase 3: Exporting visual assets...");
const screenshots = await Promise.all(
componentNodeIds.slice(0, 10).map(nodeId => // Limit to 10 for performance
mcp__figma__get_screenshot({
nodeId,
format: "png",
scale: 2
})
)
);
const assetsDir = path.join(outputDir, "assets");
fs.mkdirSync(assetsDir, {recursive: true});
screenshots.forEach((screenshot, index) => {
const assetFile = path.join(assetsDir, `component-${index}.png`);
fs.writeFileSync(assetFile, screenshot.imageData);
});
console.log(`โ Exported ${screenshots.length} component previews`);
// Phase 4: Generate documentation
console.log("Phase 4: Generating documentation...");
const docMarkdown = generateComponentDocs(components, variables);
const docsFile = path.join(outputDir, "COMPONENTS.md");
fs.writeFileSync(docsFile, docMarkdown);
console.log(`โ Documentation generated at ${docsFile}`);
console.log(`\nDesign system sync complete!`);
console.log(`Output directory: ${outputDir}`);
}
// Helper function
function generateComponentDocs(components: any[], tokens: any[]): string {
let md = "# Auto-Generated Component Documentation\n\n";
md += `Generated: ${new Date().toISOString()}\n\n`;
md += "## Design Tokens\n\n";
tokens.forEach(token => {
md += `- \`${token.name}\`: ${token.value}\n`;
});
md += "\n## Components\n\n";
components.forEach((comp, i) => {
md += `### ${comp.componentName || `Component ${i}`}\n`;
md += `Path: \`${comp.nodePath}\`\n`;
md += "```typescript\n";
md += comp.generatedCode?.substring(0, 200) + "...\n";
md += "```\n\n";
});
return md;
}
// Extract tokens from Figma and export to multiple formats
async function exportTokens(figmaFileId: string, outputDir: string) {
const variables = await mcp__figma__get_variable_defs({
fileId: figmaFileId
});
// Format 1: CSS Custom Properties
let cssContent = ":root {\n";
variables.forEach(token => {
cssContent += ` --${token.name}: ${token.value};\n`;
});
cssContent += "}\n";
fs.writeFileSync(path.join(outputDir, "tokens.css"), cssContent);
// Format 2: JSON (for JavaScript)
const jsonTokens = Object.fromEntries(
variables.map(token => [token.name, token.value])
);
fs.writeFileSync(
path.join(outputDir, "tokens.json"),
JSON.stringify(jsonTokens, null, 2)
);
// Format 3: SCSS Variables
let scssContent = "";
variables.forEach(token => {
scssContent += `$${token.name}: ${token.value};\n`;
});
fs.writeFileSync(path.join(outputDir, "tokens.scss"), scssContent);
console.log(`โ Exported ${variables.length} tokens in 3 formats`);
}
Last Updated: 2025-11-19 Format: Markdown | Language: English Status: Stable (v4.1.0) Version: 4.1.0
v4.1.0 (2025-11-19)
v4.0.0 (2025-11-18)