Figma
Integrate with Figma API for design automation and code generation. Use when extracting design tokens, generating React/CSS code from Figma components, syncing design systems, building Figma plugins, or automating design-to-code workflows. Triggers on Figma API, design tokens, Figma plugin, design-to-code, Figma export, Figma component, Dev Mode.
Specification
- Skill ID
- hoodini/ai-agents-skills/figma
- Publisher
- hoodini
- Repository
- ai-agents-skills
- Installs
- 0
- Files
- 1
- Synced
- Sep 23, 2026
How to use it
Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.
hoodini/ai-agents-skills/figmaInstalls these files- SKILL.md
What this skill tells the agent
Figma API Integration
Extract design data, generate code from components, and automate design workflows with Figma's API.
Quick Start
Authentication
const FIGMA_TOKEN = process.env.FIGMA_TOKEN;
const headers = {
'X-Figma-Token': FIGMA_TOKEN
};
// Get file
const response = await fetch(
`https://api.figma.com/v1/files/${FILE_KEY}`,
{ headers }
);File Key & Node IDs
// Extract from Figma URL: figma.com/file/FILE_KEY/Name?node-id=NODE_ID
const figmaUrl = 'https://www.figma.com/file/abc123/MyDesign?node-id=1%3A2';
const fileKey = figmaUrl.match(/file\/([^/]+)/)?.[1]; // abc123
const nodeId = new URL(figmaUrl).searchParams.get('node-id'); // 1:2Core API Endpoints
Get File
// Full file
GET https://api.figma.com/v1/files/:file_key
// Specific nodes (components)
GET https://api.figma.com/v1/files/:file_key/nodes?ids=1:2,1:3
// With geometry for SVG paths
GET https://api.figma.com/v1/files/:file_key?geometry=paths
// With plugin data
GET https://api.figma.com/v1/files/:file_key?plugin_data=sharedGet Components
// Get all components in a file
GET https://api.figma.com/v1/files/:file_key/components
// Get component sets (variants)
GET https://api.figma.com/v1/files/:file_key/component_sets
// Get team's published components
GET https://api.figma.com/v1/teams/:team_id/componentsExport Images
// Export nodes as images
GET https://api.figma.com/v1/images/:file_key?ids=1:2,1:3&format=png&scale=2
// Export as SVG
GET https://api.figma.com/v1/images/:file_key?ids=1:2&format=svg
// Response
{
"images": {
"1:2": "https://s3.amazonaws.com/...",
"1:3": "https://s3.amazonaws.com/..."
}
}Component Code Generation
Figma Node to React Component
interface FigmaNode {
id: string;
name: string;
type: string;
children?: FigmaNode[];
absoluteBoundingBox?: { x: number; y: number; width: number; height: number };
fills?: Fill[];
strokes?: Stroke[];
effects?: Effect[];
cornerRadius?: number;
paddingLeft?: number;
paddingRight?: number;
paddingTop?: number;
paddingBottom?: number;
itemSpacing?: number;
layoutMode?: 'HORIZONTAL' | 'VERTICAL' | 'NONE';
primaryAxisAlignItems?: string;
counterAxisAlignItems?: string;
characters?: string;
style?: TextStyle;
}
async function getComponentCode(fileKey: string, nodeId: string): Promise<string> {
const response = await fetch(
`https://api.figma.com/v1/files/${fileKey}/nodes?ids=${nodeId}`,
{ headers: { 'X-Figma-Token': process.env.FIGMA_TOKEN! } }
);
const data = await response.json();
const node = data.nodes[nodeId].document;
return generateReactComponent(node);
}
function generateReactComponent(node: FigmaNode): string {
const componentName = toPascalCase(node.name);
const styles = extractStyles(node);
const children = node.children?.map(child => generateJSX(child)).join('\n') || '';
return `
import React from 'react';
export function ${componentName}() {
return (
<div style={${JSON.stringify(styles, null, 2)}}>
${children}
</div>
);
}
`;
}
function extractStyles(node: FigmaNode): React.CSSProperties {
const styles: React.CSSProperties = {};
// Dimensions
if (node.absoluteBoundingBox) {
styles.width = node.absoluteBoundingBox.width;
styles.height = node.absoluteBoundingBox.height;
}
// Background
if (node.fills?.length) {
const fill = node.fills.find(f => f.visible !== false && f.type === 'SOLID');
if (fill?.color) {
styles.backgroundColor = rgbaToHex(fill.color);
}
}
// Border radius
if (node.cornerRadius) {
styles.borderRadius = node.cornerRadius;
}
// Padding
if (node.paddingLeft) styles.paddingLeft = node.paddingLeft;
if (node.paddingRight) styles.paddingRight = node.paddingRight;
if (node.paddingTop) styles.paddingTop = node.paddingTop;
if (node.paddingBottom) styles.paddingBottom = node.paddingBottom;
// Flexbox (Auto Layout)
if (node.layoutMode && node.layoutMode !== 'NONE') {
styles.display = 'flex';
styles.flexDirection = node.layoutMode === 'HORIZONTAL' ? 'row' : 'column';
styles.gap = node.itemSpacing;
// Alignment
const alignMap: Record<string, string> = {
'MIN': 'flex-start',
'CENTER': 'center',
'MAX': 'flex-end',
'SPACE_BETWEEN': 'space-between',
};
if (node.primaryAxisAlignItems) {
styles.justifyContent = alignMap[node.primaryAxisAlignItems] || 'flex-start';
}
if (node.counterAxisAlignItems) {
styles.alignItems = alignMap[node.counterAxisAlignItems] || 'flex-start';
}
}
return styles;
}
function generateJSX(node: FigmaNode): string {
const styles = extractStyles(node);
if (node.type === 'TEXT') {
return `<span style={${JSON.stringify(styles)}}>${node.characters || ''}</span>`;
}
if (node.type === 'VECTOR' || node.type === 'BOOLEAN_OPERATION') {
return `{/* Vector: ${node.name} - export as SVG */}`;
}
const children = node.children?.map(child => generateJSX(child)).join('\n') || '';
return `<div style={${JSON.stringify(styles)}}>${children}</div>`;
}Generate Tailwind CSS from Figma
function figmaToTailwind(node: FigmaNode): string {
const classes: string[] = [];
// Dimensions
if (node.absoluteBoundingBox) {
const { width, height } = node.absoluteBoundingBox;
classes.push(`w-[${Math.round(width)}px]`, `h-[${Math.round(height)}px]`);
}
// Background color
if (node.fills?.length) {
const fill = node.fills.find(f => f.visible !== false && f.type === 'SOLID');
if (fill?.color) {
const hex = rgbaToHex(fill.color);
classes.push(`bg-[${hex}]`);
}
}
// Border radius
if (node.cornerRadius) {
const radiusMap: Record<number, string> = {
4: 'rounded-sm', 6: 'rounded-md', 8: 'rounded-lg',
12: 'rounded-xl', 16: 'rounded-2xl', 9999: 'rounded-full'
};
classes.push(radiusMap[node.cornerRadius] || `rounded-[${node.cornerRadius}px]`);
}
// Padding
if (node.paddingLeft === node.paddingRight &&
node.paddingTop === node.paddingBottom &&
node.paddingLeft === node.paddingTop) {
classes.push(`p-[${node.paddingLeft}px]`);
} else {
if (node.paddingLeft) classes.push(`pl-[${node.paddingLeft}px]`);
if (node.paddingRight) classes.push(`pr-[${node.paddingRight}px]`);
if (node.paddingTop) classes.push(`pt-[${node.paddingTop}px]`);
if (node.paddingBottom) classes.push(`pb-[${node.paddingBottom}px]`);
}
// Flexbox
if (node.layoutMode && node.layoutMode !== 'NONE') {
classes.push('flex');
classes.push(node.layoutMode === 'HORIZONTAL' ? 'flex-row' : 'flex-col');
if (node.itemSpacing) classes.push(`gap-[${node.itemSpacing}px]`);
const justifyMap: Record<string, string> = {
'MIN': 'justify-start', 'CENTER': 'justify-center',
'MAX': 'justify-end', 'SPACE_BETWEEN': 'justify-between'
};
const alignMap: Record<string, string> = {
'MIN': 'items-start', 'CENTER': 'items-center', 'MAX': 'items-end'
};
if (node.primaryAxisAlignItems) classes.push(justifyMap[node.primaryAxisAlignItems]);
if (node.counterAxisAlignItems) classes.push(alignMap[node.counterAxisAlignItems]);
}
return classes.join(' ');
}Extract All Components from File
interface ComponentInfo {
key: string;
name: string;
description: string;
nodeId: string;
thumbnailUrl?: string;
}
async function getAllComponents(fileKey: string): Promise<ComponentInfo[]> {
const response = await fetch(
`https://api.figma.com/v1/files/${fileKey}/components`,
{ headers: { 'X-Figma-Token': process.env.FIGMA_TOKEN! } }
);
const data = await response.json();
return data.meta.components.map((comp: any) => ({
key: comp.key,
name: comp.name,
description: comp.description || '',More from hoodini
Use this skill in a project
Open any RiverX project, search the Skills panel for hoodini/ai-agents-skills/figma, and install it in one click.
