AI Skill Report Card
Building Figma Plugins
Quick Start15 / 15
TypeScript// manifest.json { "name": "Brand Compliance Checker", "id": "brand-checker", "api": "1.0.0", "main": "code.js", "ui": "ui.html" } // code.ts figma.showUI(__html__, { width: 320, height: 240 }); figma.ui.onmessage = msg => { if (msg.type === 'check-brand-compliance') { const selection = figma.currentPage.selection; const violations = []; selection.forEach(node => { if (node.type === 'TEXT') { const fills = node.fills as Paint[]; if (!isApprovedBrandColor(fills[0])) { violations.push({ id: node.id, name: node.name, issue: 'Unapproved text color' }); } } }); figma.ui.postMessage({ type: 'violations', data: violations }); } };
Recommendation▾
Add specific error handling patterns with concrete examples of common Figma API errors and how to handle them
Workflow14 / 15
Progress:
- Set up TypeScript environment (
npm init,@figma/plugin-typings) - Define plugin manifest and core structure
- Implement main functionality using Figma API
- Build UI communication layer
- Test with Figma Dev Mode
- Package and publish to Community
1. Environment Setup
Bashnpm init -y npm install @figma/plugin-typings typescript npx tsc --init
2. Core API Patterns
TypeScript// Node traversal function traverseNode(node: SceneNode, callback: (node: SceneNode) => void) { callback(node); if ('children' in node) { node.children.forEach(child => traverseNode(child, callback)); } } // Selection handling const selection = figma.currentPage.selection; if (selection.length === 0) { figma.notify('Please select elements first'); return; } // UI communication figma.ui.postMessage({ type: 'data', payload: results }); figma.ui.onmessage = msg => { switch (msg.type) { case 'apply-tokens': applyDesignTokens(msg.tokens); break; } };
3. High-Value Automations
Brand Compliance Checker:
TypeScriptconst BRAND_COLORS = ['#FF6B35', '#004E89', '#FFFFFF']; const BRAND_FONTS = ['Inter', 'Roboto']; function checkCompliance(node: SceneNode) { const issues = []; if (node.type === 'TEXT') { if (!BRAND_FONTS.includes(node.fontName.family)) { issues.push('Non-brand font detected'); } } if ('fills' in node && node.fills !== figma.mixed) { const fills = node.fills as Paint[]; fills.forEach(fill => { if (fill.type === 'SOLID' && !isBrandColor(fill.color)) { issues.push('Unapproved color'); } }); } return issues; }
Design Token Applicator:
TypeScriptconst TOKENS = { 'primary-500': { r: 1, g: 0.42, b: 0.21 }, 'spacing-lg': 24, 'radius-md': 8 }; function applyToken(node: SceneNode, tokenName: string) { if (tokenName.includes('color') && 'fills' in node) { node.fills = [{ type: 'SOLID', color: TOKENS[tokenName] }]; } else if (tokenName.includes('spacing') && 'paddingLeft' in node) { const spacing = TOKENS[tokenName]; node.paddingLeft = node.paddingRight = spacing; node.paddingTop = node.paddingBottom = spacing; } }
4. Component Analysis
TypeScriptfunction exportComponentInventory() { const components = []; traverseNode(figma.root, node => { if (node.type === 'INSTANCE') { components.push({ name: node.mainComponent?.name, id: node.id, page: node.parent?.name, overrides: getOverrides(node) }); } }); return components; }
Recommendation▾
Include a complete HTML UI example to complement the TypeScript code snippets
Examples16 / 20
Example 1: SEO Alt-Text Generator Input: Selected images without alt text Output:
TypeScript// Generates descriptive alt text for selected images selection.forEach(node => { if (node.type === 'RECTANGLE' && node.fills) { const altText = generateAltText(node); node.setPluginData('alt-text', altText); figma.notify(`Added alt text: "${altText}"`); } });
Example 2: Brand Color Enforcement Input: Design with mixed colors Output: Automatically replaces non-brand colors with nearest brand-approved alternatives
Recommendation▾
Add more concrete input/output pairs showing actual node properties and transformations
Best Practices
- Batch operations: Process multiple selections efficiently
- Progress feedback: Use
figma.notify()for user feedback - Error handling: Wrap API calls in try-catch blocks
- Memory management: Clone nodes before major modifications
- Plugin data: Store metadata using
setPluginData()for persistence - TypeScript strict mode: Catch API misuse early
Common Pitfalls
- Don't modify nodes during traversal (clone first)
- Don't forget to handle mixed properties (
figma.mixed) - Don't assume selection exists (always check length)
- Don't block UI thread with heavy operations (use async/await)
- Don't forget manifest permissions for network requests
- Don't hardcode dimensions (use
figma.viewportfor responsive UI)
Testing & Publishing
TypeScript// Debug helper console.log(JSON.stringify(node, null, 2)); // Performance monitoring console.time('plugin-operation'); // ... your code console.timeEnd('plugin-operation');
Use Figma Dev Mode → Plugins → Development for testing. Publish through Figma Community with clear screenshots and usage instructions.