get_figma_styles
Extract style data and CSS from Figma design nodes using file URLs to analyze design elements and generate code for development workflows.
Instructions
根据Figma URL获取节点的样式数据
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| generateCSS | No | 是否生成CSS代码 | |
| url | Yes | Figma文件URL,可以包含node-id参数指定特定节点 |
Implementation Reference
- src/index.ts:294-326 (handler)Handler method in the main server class that processes the 'get_figma_styles' tool request, delegates to FigmaStyleExtractor, optionally generates CSS, and formats the JSON response.private async handleGetStyles(args: any) { const { url, generateCSS = false } = args; const styleData = await this.styleExtractor.getStylesFromUrl(url); let cssCode = ''; if (generateCSS && styleData.styles.length > 0) { const cssRules = styleData.styles.map(style => { const selector = `.${style.nodeName.toLowerCase().replace(/\\s+/g, '-')}`; const css = this.styleExtractor.generateCSS(style); return css ? `${selector} {\\n ${css}\\n}` : ''; }).filter(rule => rule); cssCode = cssRules.join('\\n\\n'); } return { content: [ { type: 'text', text: JSON.stringify({ success: true, data: { fileInfo: styleData.fileInfo, styles: styleData.styles, globalStyles: styleData.globalStyles, ...(cssCode && { generatedCSS: cssCode }), }, }, null, 2), }, ], }; }
- src/style-extractor.ts:88-122 (handler)Core handler function in FigmaStyleExtractor that parses the Figma URL, fetches file/node data, identifies target nodes, extracts styles using helper methods, and returns structured ComponentStyles.async getStylesFromUrl(figmaUrl: string): Promise<ComponentStyles> { try { const urlInfo = this.figmaService.parseUrl(figmaUrl); const { fileId, nodeId } = urlInfo; const file = await this.figmaService.getFile(fileId); let targetNodes: FigmaNode[] = []; if (nodeId) { // 获取特定节点 const node = await this.figmaService.getNode(fileId, nodeId); if (node) { targetNodes = [node]; } } else { // 获取整个文件的主要组件 targetNodes = this.extractMainComponents(file.document); } const styles = targetNodes.map(node => this.extractNodeStyle(node)); return { fileInfo: { fileId, fileName: file.name, lastModified: file.lastModified, }, styles, globalStyles: file.styles, }; } catch (error) { throw new Error(`获取样式数据失败: ${error instanceof Error ? error.message : '未知错误'}`); } }
- src/index.ts:75-93 (schema)Input schema and metadata for the 'get_figma_styles' tool as registered in the ListTools response.{ name: 'get_figma_styles', description: '根据Figma URL获取节点的样式数据', inputSchema: { type: 'object', properties: { url: { type: 'string', description: 'Figma文件URL,可以包含node-id参数指定特定节点', }, generateCSS: { type: 'boolean', description: '是否生成CSS代码', default: false, }, }, required: ['url'], }, },
- src/index.ts:200-201 (registration)Switch case registration that routes 'get_figma_styles' tool calls to the handleGetStyles method.case 'get_figma_styles': return await this.handleGetStyles(args);
- src/style-extractor.ts:127-242 (helper)Key helper function that extracts detailed style properties (fills, strokes, effects, text, etc.) from a single Figma node into the StyleData structure.private extractNodeStyle(node: FigmaNode): StyleData { const style: StyleData = { nodeId: node.id, nodeName: node.name, nodeType: node.type, }; // 位置和尺寸 if (node.absoluteBoundingBox) { style.position = { x: node.absoluteBoundingBox.x, y: node.absoluteBoundingBox.y, width: node.absoluteBoundingBox.width, height: node.absoluteBoundingBox.height, }; } // 填充样式 if (node.fills && node.fills.length > 0) { style.fills = node.fills.map(fill => ({ type: fill.type, color: fill.color ? { r: Math.round(fill.color.r * 255), g: Math.round(fill.color.g * 255), b: Math.round(fill.color.b * 255), a: fill.color.a || 1, } : undefined, gradientStops: fill.gradientStops?.map((stop: any) => ({ color: { r: Math.round(stop.color.r * 255), g: Math.round(stop.color.g * 255), b: Math.round(stop.color.b * 255), a: stop.color.a || 1, }, position: stop.position, })), })); } // 描边样式 if (node.strokes && node.strokes.length > 0) { style.strokes = node.strokes.map(stroke => ({ type: stroke.type, color: stroke.color ? { r: Math.round(stroke.color.r * 255), g: Math.round(stroke.color.g * 255), b: Math.round(stroke.color.b * 255), a: stroke.color.a || 1, } : undefined, })); } // 描边粗细 if (node.strokeWeight !== undefined) { style.strokeWeight = node.strokeWeight; } // 圆角 if (node.cornerRadius !== undefined) { style.cornerRadius = node.cornerRadius; } // 效果(阴影、模糊等) if (node.effects && node.effects.length > 0) { style.effects = node.effects.map(effect => ({ type: effect.type, visible: effect.visible !== false, radius: effect.radius, color: effect.color ? { r: Math.round(effect.color.r * 255), g: Math.round(effect.color.g * 255), b: Math.round(effect.color.b * 255), a: effect.color.a || 1, } : undefined, offset: effect.offset ? { x: effect.offset.x, y: effect.offset.y, } : undefined, })); } // 文本样式 if (node.style) { style.textStyle = { fontFamily: node.style.fontFamily, fontSize: node.style.fontSize, fontWeight: node.style.fontWeight, letterSpacing: node.style.letterSpacing, lineHeight: node.style.lineHeightPx, textAlign: node.style.textAlignHorizontal, }; // 如果有文本颜色信息 if (node.fills && node.fills.length > 0 && node.type === 'TEXT') { const textFill = node.fills[0]; if (textFill.color) { style.textStyle.textColor = { r: Math.round(textFill.color.r * 255), g: Math.round(textFill.color.g * 255), b: Math.round(textFill.color.b * 255), a: textFill.color.a || 1, }; } } } // 约束 if (node.constraints) { style.constraints = { vertical: node.constraints.vertical, horizontal: node.constraints.horizontal, }; } return style; }
- src/style-extractor.ts:3-81 (schema)TypeScript interfaces defining the structure of extracted style data (output schema).export interface StyleData { nodeId: string; nodeName: string; nodeType: string; position?: { x: number; y: number; width: number; height: number; }; fills?: Array<{ type: string; color?: { r: number; g: number; b: number; a: number; }; gradientStops?: Array<{ color: { r: number; g: number; b: number; a: number }; position: number; }>; }>; strokes?: Array<{ type: string; color?: { r: number; g: number; b: number; a: number; }; }>; strokeWeight?: number; cornerRadius?: number; effects?: Array<{ type: string; visible: boolean; radius?: number; color?: { r: number; g: number; b: number; a: number; }; offset?: { x: number; y: number; }; }>; textStyle?: { fontFamily?: string; fontSize?: number; fontWeight?: number; letterSpacing?: number; lineHeight?: number; textAlign?: string; textColor?: { r: number; g: number; b: number; a: number; }; }; constraints?: { vertical: string; horizontal: string; }; } export interface ComponentStyles { fileInfo: { fileId: string; fileName: string; lastModified: string; }; styles: StyleData[]; globalStyles?: Record<string, any>; }