mcpField
F
figma-generate-design

figma-generate-design

github.com/openai设计与 UI28.4k2.9k 次安装18 周前更新
代码仓库

关于 figma-generate-design

此技能通过组合已发布的设计系统组件、变量和样式,在 Figma 中创建或更新整页界面。它适用于根据源码或描述制作界面,而非从 Figma 生成代码。

主要功能

  1. 01发现可复用的组件、变量和样式
  2. 02使用导入的设计系统组件组装界面
  3. 03逐步构建页面框架与各个区块
  4. 04覆盖组件的文本属性
  5. 05在制作过程中验证结构和外观

适用场景

  1. 01根据应用源码创建 Figma 界面
  2. 02使用现有设计系统更新界面
  3. 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.TXT
maintainers.yml
agents/
openai.yaml
assets/
figma-small.svg
icon.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 应用构建屏幕时,同时运行两种方法可获得最佳效果:

  1. 并行执行:
    • 使用此技能的工作流(use_figma + 设计系统组件)开始构建屏幕
    • 运行 generate_figma_design,捕获正在运行的 Web 应用的像素级精准屏幕截图
  2. **两者完成后:**更新 use_figma 的输出,使其与 generate_figma_design 捕获的像素级精准布局一致。该截图提供了准确的间距、尺寸和视觉样式参考,而 use_figma 输出则包含正确的组件实例,并与设计系统关联。
  3. **确认效果良好后:**删除 generate_figma_design 的输出——它仅用作视觉参考。

这样可以兼顾两者的优势:generate_figma_design 能精准还原布局,而 use_figma 会生成与设计系统关联且可更新的正确组件实例。

此工作流仅适用于 generate_figma_design 可以捕获运行中页面的 Web 应用。对于非 Web 应用(iOS、Android 等)或更新现有屏幕,请使用下方的标准工作流。

必需工作流

请按顺序执行以下步骤,不要跳过。

步骤 1:了解屏幕

开始操作 Figma 前,先了解要构建的内容:

  1. 如果根据代码构建,请阅读相关源文件,了解页面结构、各个区块以及所用组件。
  2. 找出屏幕中的主要区块(例如:页眉、主视觉区、内容面板、定价网格、常见问题手风琴、页脚)。
  3. 列出每个区块涉及的 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 步:更新现有屏幕

更新现有屏幕而非从头创建时:

  1. 使用 get_metadata 检查现有屏幕结构。
  2. 确定哪些区块需要更新,哪些可以保留。
  3. 对每个需要修改的区块:
    • 按 ID 或名称定位现有节点
    • 如果设计系统组件已更改,则替换组件实例
    • 根据需要更新文本内容、变体属性或布局
    • 移除已弃用的区块
    • 添加新区块
  4. 每次修改后使用 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 中的错误恢复流程:

  1. 遇到错误时停止 — 不要立即重试。
  2. 仔细阅读错误消息,了解出了什么问题。
  3. 如果错误不明确,请调用 get_metadata 或 get_screenshot 检查当前文件状态。
  4. 根据错误消息修复脚本。
  5. 重试修正后的脚本 — 这是安全的,因为失败的脚本具有原子性(脚本报错时不会创建任何内容)。

由于此技能采用增量方式(每次调用处理一个分区),错误自然会限定在单个分区内。之前成功调用所创建的分区会保持不变。

最佳实践

  • 构建前始终先搜索。 设计系统中很可能已有你需要的组件、变量或样式。手动构建和硬编码值应是例外,而非常规做法。
  • 广泛搜索。 尝试同义词和部分词语。例如,“NavigationPill”可能可以通过“pill”、“nav”、“tab”或“chip”找到。对于变量,可搜索“color”、“spacing”、“radius”等。
  • 优先使用设计系统令牌,而非硬编码值。 使用变量绑定设置颜色、间距和圆角;使用文本样式设置排版;使用效果样式设置阴影。这样屏幕就会与设计系统保持关联。
  • 优先使用组件实例,而非手动构建。 实例会保持与源组件的关联,并在设计系统更新时自动更新。
  • 逐个分区进行操作。 每次 use_figma 调用最多构建一个主要分区。
  • 每次调用都返回节点 ID。 后续组合分区和错误恢复时会用到它们。
  • 每完成一个分区后都进行视觉验证。 使用 get_screenshot 尽早发现问题。
  • 遵循现有规范。 如果文件中已有屏幕,请沿用其命名、尺寸和布局模式。

评论

支持 Markdown