关于 figma-generate-design
此技能通过组合已发布的设计系统组件、变量和样式,在 Figma 中创建或更新整页界面。它适用于根据源码或描述制作界面,而非从 Figma 生成代码。
主要功能
- 01发现可复用的组件、变量和样式
- 02使用导入的设计系统组件组装界面
- 03逐步构建页面框架与各个区块
- 04覆盖组件的文本属性
- 05在制作过程中验证结构和外观
适用场景
- 01根据应用源码创建 Figma 界面
- 02使用现有设计系统更新界面
- 03用组件库组装多区块布局
MCP 相关
需要 Figma MCP 服务,并使用 `use_figma` 构建界面。技能还说明通过 `search_design_system` 查找设计资源,并用 `get_metadata` 和 `get_screenshot` 验证结果。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ openai/ skills --skill figma-generate-design安装后在 Claude Code 中输入/figma-generate-design确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSE.TXTmaintainers.ymlagents/openai.yamlassets/figma-small.svgicon.svg详细介绍
根据设计系统构建 / 更新屏幕
使用此技能,在 Figma 中创建或更新整页屏幕时,复用已发布的设计系统——包括组件、变量和样式,而不是使用硬编码值绘制基本图形。关键在于:Figma 文件很可能已发布了设计系统,其中的组件、颜色 / 间距变量以及文本 / 效果样式都对应着代码库中的 UI 组件和设计令牌。找到并使用它们,而不是用十六进制颜色绘制方框。
强制要求:在调用任何 use_figma 之前,必须先加载 figma-use。该技能包含重要规则(颜色范围、字体加载等),这些规则适用于你编写的每个脚本。
使用此技能调用 use_figma 时,始终传入 skillNames: "figma-generate-design"。 这是一个日志参数,不会影响执行。
技能范围
- 当交付内容是由设计系统组件实例组成的 Figma 屏幕(新建或更新)时,使用此技能。
- 如果用户希望根据 Figma 设计生成 代码,请切换到 figma-implement-design。
- 如果用户希望创建 可复用的新组件或变体,请直接使用 figma-use。
- 如果用户希望编写 Code Connect 映射,请切换到 figma-code-connect-components。
前置条件
- 必须已连接 Figma MCP 服务
- 目标 Figma 文件必须包含已发布的设计系统及其组件(或可访问团队资源库)
- 用户应提供以下任一信息:
- 要在其中操作的 Figma 文件 URL / 文件 key
- 或提供要操作的文件的相关信息(Agent 可以查找页面)
- 要构建 / 更新的屏幕的源代码或描述
使用 generate_figma_design 的并行工作流(仅限 Web 应用)
根据可在浏览器中渲染的 Web 应用构建屏幕时,同时运行两种方法可获得最佳效果:
- 并行执行:
- 使用此技能的工作流(use_figma + 设计系统组件)开始构建屏幕
- 运行
generate_figma_design,捕获正在运行的 Web 应用的像素级精准屏幕截图
- **两者完成后:**更新 use_figma 的输出,使其与
generate_figma_design捕获的像素级精准布局一致。该截图提供了准确的间距、尺寸和视觉样式参考,而 use_figma 输出则包含正确的组件实例,并与设计系统关联。 - **确认效果良好后:**删除
generate_figma_design的输出——它仅用作视觉参考。
这样可以兼顾两者的优势:generate_figma_design 能精准还原布局,而 use_figma 会生成与设计系统关联且可更新的正确组件实例。
此工作流仅适用于 generate_figma_design 可以捕获运行中页面的 Web 应用。对于非 Web 应用(iOS、Android 等)或更新现有屏幕,请使用下方的标准工作流。
必需工作流
请按顺序执行以下步骤,不要跳过。
步骤 1:了解屏幕
开始操作 Figma 前,先了解要构建的内容:
- 如果根据代码构建,请阅读相关源文件,了解页面结构、各个区块以及所用组件。
- 找出屏幕中的主要区块(例如:页眉、主视觉区、内容面板、定价网格、常见问题手风琴、页脚)。
- 列出每个区块涉及的 UI 组件(按钮、输入框、卡片、导航标签、手风琴等)。
步骤 2:查找设计系统——组件、变量和样式
你需要从设计系统中找到三类内容:组件(按钮、卡片等)、变量(颜色、间距、圆角)和 样式(文本样式、阴影等效果样式)。如果设计系统中已有设计令牌,就不要硬编码十六进制颜色或像素值。
2a:发现组件
首选:先检查现有屏幕。 如果目标文件已包含使用同一设计系统的屏幕,请跳过 search_design_system,直接检查现有实例。只需调用一次 use_figma 遍历现有框架的实例,即可获得精确、权威的组件映射:
const frame = figma.currentPage.findOne(n => n.name === "Existing Screen");
const uniqueSets = new Map();
frame.findAll(n => n.type === "INSTANCE").forEach(inst => {
const mc = inst.mainComponent;
const cs = mc?.parent?.type === "COMPONENT_SET" ? mc.parent : null;
const key = cs ? cs.key : mc?.key;
const name = cs ? cs.name : mc?.name;
if (key && !uniqueSets.has(key)) {
uniqueSets.set(key, { name, key, isSet: !!cs, sampleVariant: mc.name });
}
});
return [...uniqueSets.values()];
只有在文件中没有可供参考的现有屏幕时,才使用 search_design_system。使用时,应广泛搜索——尝试多个术语和同义词(例如“按钮”“输入框”“导航”“卡片”“手风琴”“页眉”“页脚”“标签”“头像”“开关”“图标”等)。使用 includeComponents: true 聚焦于组件。
在映射中包含组件属性——你需要了解每个组件公开了哪些 TEXT 属性,以便覆盖文本。创建一个临时实例,读取其 componentProperties(以及嵌套实例的属性),然后移除临时实例。
包含属性信息的组件映射示例:
Component Map:
- Button → key: "abc123", type: COMPONENT_SET
Properties: { "Label#2:0": TEXT, "Has Icon#4:64": BOOLEAN }
- PricingCard → key: "ghi789", type: COMPONENT_SET
Properties: { "Device": VARIANT, "Variant": VARIANT }
Nested "Text Heading" has: { "Text#2104:5": TEXT }
Nested "Button" has: { "Label#2:0": TEXT }
2b:发现变量(颜色、间距、圆角)
先检查现有屏幕(与组件相同)。或者使用 search_design_system 并设置 includeVariables: true。
警告:变量发现有两种不同的方法——请勿混淆。
use_figma搭配figma.variables.getLocalVariableCollectionsAsync()——仅返回当前文件中定义的本地变量。如果返回结果为空,并不意味着不存在变量。此 API 无法查看远程或已发布的库变量。search_design_system搭配includeVariables: true——搜索所有已关联的库,包括远程和已发布的库。这是发现设计系统变量的正确工具。绝不能仅因
getLocalVariableCollectionsAsync()返回空结果,就断定“不存在变量”。 在决定创建自己的变量之前,务必同时运行search_design_system并设置includeVariables: true,检查库变量。
查询策略: search_design_system 会匹配变量名称(例如“Gray/gray-9”“core/gray/100”“space/400”),而非类别。请并行运行多个简短、简单的查询,而不是一个复合查询:
- 基元颜色: “gray”“red”“blue”“green”“white”“brand”
- 语义颜色: “background”“foreground”“border”“surface”“text”
- 间距/尺寸: “space”“radius”“gap”“padding”
如果初次搜索没有结果,请尝试更短的片段或不同的命名惯例——各个库差异很大(例如,“grey”与“gray”、“spacing”与“space”、“color/bg”与“background”)。
检查现有屏幕绑定的变量,以获得最权威的结果:
const frame = figma.currentPage.findOne(n => n.name === "Existing Screen");
const varMap = new Map();
frame.findAll(() => true).forEach(node => {
const bv = node.boundVariables;
if (!bv) return;
for (const [prop, binding] of Object.entries(bv)) {
const bindings = Array.isArray(binding) ? binding : [binding];
for (const b of bindings) {
if (b?.id && !varMap.has(b.id)) {
const v = await figma.variables.getVariableByIdAsync(b.id);
if (v) varMap.set(b.id, { name: v.name, id: v.id, key: v.key, type: v.resolvedType, remote: v.remote });
}
}
}
});
return [...varMap.values()];
对于库变量(remote = true),请使用 figma.variables.importVariableByKeyAsync(key) 按键导入。对于本地变量,请直接使用 figma.variables.getVariableByIdAsync(id)。
绑定模式详见 variable-patterns.md。
2c:发现样式(文本样式、效果样式)
使用 search_design_system 并设置 includeStyles: true,搜索“标题”“正文”“阴影”“立体效果”等术语。也可以检查现有屏幕使用的样式:
const frame = figma.currentPage.findOne(n => n.name === "Existing Screen");
const styles = { text: new Map(), effect: new Map() };
frame.findAll(() => true).forEach(node => {
if ('textStyleId' in node && node.textStyleId) {
const s = figma.getStyleById(node.textStyleId);
if (s) styles.text.set(s.id, { name: s.name, id: s.id, key: s.key });
}
if ('effectStyleId' in node && node.effectStyleId) {
const s = figma.getStyleById(node.effectStyleId);
if (s) styles.effect.set(s.id, { name: s.name, id: s.id, key: s.key });
}
});
return {
textStyles: [...styles.text.values()],
effectStyles: [...styles.effect.values()]
};
使用 figma.importStyleByKeyAsync(key) 导入库样式,然后通过 node.textStyleId = style.id 或 node.effectStyleId = style.id 应用。
详情请参阅 text-style-patterns.md 和 effect-style-patterns.md。
第 3 步:先创建页面包装框架
不要将分区构建为页面顶层子节点,再稍后重新设定其父节点——在不同的 use_figma 调用之间使用 appendChild() 移动节点会悄然失败,并产生孤立框架。正确做法是先创建包装框架,然后直接在其中构建每个分区。
在单独的 use_figma 调用中创建页面包装框架。将其放置在远离现有内容的位置,并返回其 ID:
// Find clear space
let maxX = 0;
for (const child of figma.currentPage.children) {
maxX = Math.max(maxX, child.x + child.width);
}
const wrapper = figma.createFrame();
wrapper.name = "Homepage";
wrapper.layoutMode = "VERTICAL";
wrapper.primaryAxisAlignItems = "CENTER";
wrapper.counterAxisAlignItems = "CENTER";
wrapper.resize(1440, 100);
wrapper.layoutSizingHorizontal = "FIXED";
wrapper.layoutSizingVertical = "HUG";
wrapper.x = maxX + 200;
wrapper.y = 0;
return { success: true, wrapperId: wrapper.id };
第 4 步:在包装框架内构建各个区块
这是最重要的一步。 一次构建一个区块,每个区块单独使用一次 use_figma 调用。在每个脚本开头,通过 ID 获取包装框架,并将新内容直接追加到其中。
const createdNodeIds = [];
const wrapper = await figma.getNodeByIdAsync("WRAPPER_ID_FROM_STEP_3");
// Import design system components by key
const buttonSet = await figma.importComponentSetByKeyAsync("BUTTON_SET_KEY");
const primaryButton = buttonSet.children.find(c =>
c.type === "COMPONENT" && c.name.includes("variant=primary")
) || buttonSet.defaultVariant;
// Import design system variables for colors and spacing
const bgColorVar = await figma.variables.importVariableByKeyAsync("BG_COLOR_VAR_KEY");
const spacingVar = await figma.variables.importVariableByKeyAsync("SPACING_VAR_KEY");
// Build section frame with variable bindings (not hardcoded values)
const section = figma.createFrame();
section.name = "Header";
section.layoutMode = "HORIZONTAL";
section.setBoundVariable("paddingLeft", spacingVar);
section.setBoundVariable("paddingRight", spacingVar);
const bgPaint = figma.variables.setBoundVariableForPaint(
{ type: 'SOLID', color: { r: 0, g: 0, b: 0 } }, 'color', bgColorVar
);
section.fills = [bgPaint];
// Import and apply text/effect styles
const shadowStyle = await figma.importStyleByKeyAsync("SHADOW_STYLE_KEY");
section.effectStyleId = shadowStyle.id;
// Create component instances inside the section
const btnInstance = primaryButton.createInstance();
section.appendChild(btnInstance);
createdNodeIds.push(btnInstance.id);
// Append section to wrapper
wrapper.appendChild(section);
section.layoutSizingHorizontal = "FILL"; // AFTER appending
createdNodeIds.push(section.id);
return { success: true, createdNodeIds };
每个区块构建完成后,先使用 get_screenshot 验证,再继续下一步。仔细检查是否有文字被裁切(行高导致内容被截断)以及元素重叠——这些是最常见的问题,乍看之下也很容易被忽略。
使用 setProperties() 覆盖实例文本
组件实例自带占位文本(“Title”“Heading”“Button”)。使用你在第 2 步中发现的组件属性键,通过 setProperties() 覆盖这些文本——这比直接操作 node.characters 更可靠。完整用法请参阅 component-patterns.md。
对于公开了自身 TEXT 属性的嵌套实例,请在嵌套实例上调用 setProperties():
const nestedHeading = cardInstance.findOne(n => n.type === "INSTANCE" && n.name === "Text Heading");
if (nestedHeading) {
nestedHeading.setProperties({ "Text#2104:5": "Actual heading from source code" });
}
只有对于不受任何组件属性管理的文本,才回退到直接使用 node.characters。
仔细查看源代码中的默认值
将代码组件转换为 Figma 实例时,请检查源代码中组件的默认 prop 值,而不只是查看显式传入的值。例如,对于没有 variant prop 的 <Button size="small">Register</Button>,请检查组件定义,确认默认值为 variant = "primary"。选错变体(例如选择 Neutral 而非 Primary)会导致视觉效果不正确,而且很容易被忽略。
哪些内容应手动构建,哪些应从设计系统导入
| 手动构建 | 从设计系统导入 |
|---|---|
| 页面包装框架 | 组件:按钮、卡片、输入框、导航等 |
| 区块容器框架 | 变量:颜色(填充、描边)、间距(内边距、间隔)、圆角 |
| 布局网格(行、列) | 文本样式:标题、正文、说明文字等 |
| 效果样式:阴影、模糊等 |
如果设计系统中存在变量,绝不要硬编码十六进制颜色或像素间距。 使用 setBoundVariable 设置间距和圆角,使用 setBoundVariableForPaint 设置颜色。使用 node.textStyleId 应用文本样式,使用 node.effectStyleId 应用效果样式。
第 5 步:验证整个屏幕
组合完所有区块后,对整个页面框架调用 get_screenshot,并与源内容进行比较。使用有针对性的 use_figma 调用修复问题,不要重建整个屏幕。
为每个区块单独截图,不要只截取整个页面。 降低分辨率的整页截图会掩盖文本截断、颜色错误以及未被覆盖的占位文本。按节点 ID 截取每个区块,以发现以下问题:
- 文字被裁切——行高或框架尺寸导致下行部、上行部或整行内容被截断
- 内容重叠——由于尺寸不正确或缺少自动布局,元素相互叠加
- 仍然显示占位文本(“Title”“Heading”“Button”)
- 布局尺寸错误导致内容被截断
- 组件变体错误(例如使用 Neutral 按钮而非 Primary 按钮)
第 6 步:更新现有屏幕
更新现有屏幕而非从头创建时:
- 使用
get_metadata检查现有屏幕结构。 - 确定哪些区块需要更新,哪些可以保留。
- 对每个需要修改的区块:
- 按 ID 或名称定位现有节点
- 如果设计系统组件已更改,则替换组件实例
- 根据需要更新文本内容、变体属性或布局
- 移除已弃用的区块
- 添加新区块
- 每次修改后使用
get_screenshot验证。
// Example: Swap a button variant in an existing screen
const existingButton = await figma.getNodeByIdAsync("EXISTING_BUTTON_INSTANCE_ID");
if (existingButton && existingButton.type === "INSTANCE") {
// Import the updated component
const buttonSet = await figma.importComponentSetByKeyAsync("BUTTON_SET_KEY");
const newVariant = buttonSet.children.find(c =>
c.name.includes("variant=primary") && c.name.includes("size=lg")
) || buttonSet.defaultVariant;
existingButton.swapComponent(newVariant);
}
return { success: true, mutatedNodeIds: [existingButton.id] };
参考文档
如需了解详细的 API 模式和注意事项,请按需查阅 figma-use 中的参考文档:
- component-patterns.md — 按键导入、查找变体、setProperties、文本覆盖、使用实例
- variable-patterns.md — 创建/绑定变量、导入库变量、作用域、别名、发现现有变量
- text-style-patterns.md — 创建/应用文本样式、导入库文本样式、字号阶梯
- effect-style-patterns.md — 创建/应用效果样式(阴影)、导入库效果样式
- gotchas.md — 布局陷阱(HUG/FILL 交互、counterAxisAlignItems、尺寸设置顺序)、填充/颜色问题、页面上下文重置
错误恢复
遵循 figma-use 中的错误恢复流程:
- 遇到错误时停止 — 不要立即重试。
- 仔细阅读错误消息,了解出了什么问题。
- 如果错误不明确,请调用
get_metadata或get_screenshot检查当前文件状态。 - 根据错误消息修复脚本。
- 重试修正后的脚本 — 这是安全的,因为失败的脚本具有原子性(脚本报错时不会创建任何内容)。
由于此技能采用增量方式(每次调用处理一个分区),错误自然会限定在单个分区内。之前成功调用所创建的分区会保持不变。
最佳实践
- 构建前始终先搜索。 设计系统中很可能已有你需要的组件、变量或样式。手动构建和硬编码值应是例外,而非常规做法。
- 广泛搜索。 尝试同义词和部分词语。例如,“NavigationPill”可能可以通过“pill”、“nav”、“tab”或“chip”找到。对于变量,可搜索“color”、“spacing”、“radius”等。
- 优先使用设计系统令牌,而非硬编码值。 使用变量绑定设置颜色、间距和圆角;使用文本样式设置排版;使用效果样式设置阴影。这样屏幕就会与设计系统保持关联。
- 优先使用组件实例,而非手动构建。 实例会保持与源组件的关联,并在设计系统更新时自动更新。
- 逐个分区进行操作。 每次
use_figma调用最多构建一个主要分区。 - 每次调用都返回节点 ID。 后续组合分区和错误恢复时会用到它们。
- 每完成一个分区后都进行视觉验证。 使用
get_screenshot尽早发现问题。 - 遵循现有规范。 如果文件中已有屏幕,请沿用其命名、尺寸和布局模式。