首页
/ 10分钟实现Figma自动化:Cursor Talk To Figma MCP工作流定制指南

10分钟实现Figma自动化:Cursor Talk To Figma MCP工作流定制指南

2026-02-05 04:18:43作者:董灵辛Dennis

你是否还在为Figma设计稿的重复操作浪费时间?手动调整数百个组件、逐一更新文本内容、反复导出资产?本文将带你通过Cursor Talk To Figma MCP(Model Context Protocol)实现设计流程全自动化,从环境搭建到复杂工作流编写,让你彻底摆脱重复性劳动。

读完本文你将获得:

  • 从零搭建Figma自动化开发环境
  • 掌握15+核心API的参数配置与实战应用
  • 构建3个企业级自动化工作流(组件批量生成、设计系统同步、多语言版本导出)
  • 学会调试与性能优化技巧
  • 获取可直接复用的8个自动化脚本模板

一、技术原理与环境准备

1.1 MCP协议工作原理

Cursor Talk To Figma MCP基于Model Context Protocol协议,通过WebSocket(Web套接字)实现本地服务与Figma插件的双向通信。其核心架构包含三个部分:

flowchart LR
    A[Figma Plugin] <-->|WebSocket| B[Local Server]
    B <--> C[Automation Scripts]
    C --> D[Command Queue]
    B --> E[Response Handler]
    E --> A
  • 通信层:使用WebSocket建立持久连接,支持命令实时传输与响应
  • 命令层:定义20+原子操作(创建、修改、查询、删除设计元素)
  • 应用层:通过组合原子操作实现复杂工作流

1.2 环境要求与依赖

环境/工具 版本要求 作用
Node.js ≥18.0.0 运行时环境
Bun ≥1.2.5 高性能JavaScript运行时(推荐)
Figma Desktop ≥116.2.0 设计工具
Git 任意版本 代码管理
TypeScript ≥5.0.0 类型检查

1.3 快速安装指南

# 克隆仓库
git clone https://gitcode.com/gh_mirrors/cu/cursor-talk-to-figma-mcp.git
cd cursor-talk-to-figma-mcp

# 安装依赖
bun install

# 构建项目
bun run build

# 启动服务(默认端口:8787)
bun run start

注意:首次运行需在Figma中安装对应插件,并在插件设置中启用"允许本地连接"选项

二、核心API详解与实战

2.1 设计元素操作API

创建类命令

create_frame - 创建自动布局容器

// 创建响应式卡片容器
await server.call("create_frame", {
  x: 100,
  y: 100,
  width: 320,
  height: 480,
  name: "Product Card",
  layoutMode: "VERTICAL",
  paddingTop: 24,
  paddingRight: 24,
  paddingBottom: 24,
  paddingLeft: 24,
  itemSpacing: 16,
  primaryAxisAlignItems: "SPACE_BETWEEN",
  fillColor: { r: 1, g: 1, b: 1, a: 1 },
  strokeColor: { r: 0.9, g: 0.9, b: 0.9, a: 1 },
  strokeWeight: 1
});

参数说明:

  • layoutMode: 布局方向(NONE/HORIZONTAL/VERTICAL)
  • primaryAxisAlignItems: 主轴对齐方式,设置为SPACE_BETWEEN时itemSpacing失效
  • layoutSizingHorizontal: 水平尺寸模式(FIXED/HUG/FILL)

create_text - 创建文本节点

// 创建带样式的价格标签
await server.call("create_text", {
  x: 0,
  y: 0,
  text: "$29.99",
  fontSize: 24,
  fontWeight: 700,
  fontColor: { r: 0.1, g: 0.1, b: 0.1, a: 1 },
  name: "Price Tag",
  parentId: "FRAME_ID" // 父容器ID
});

查询类命令

get_selection - 获取当前选择

// 获取当前选中元素信息
const selection = await server.call("get_selection");
console.log("Selected elements:", selection);

返回示例:

{
  "nodes": [
    {
      "id": "1:2",
      "name": "Product Card",
      "type": "FRAME",
      "absoluteBoundingBox": {
        "x": 100,
        "y": 100,
        "width": 320,
        "height": 480
      }
    }
  ]
}

get_local_components - 获取本地组件库

// 获取所有本地组件
const components = await server.call("get_local_components");
// 筛选按钮组件
const buttons = components.filter(c => c.name.includes("Button"));

2.2 高级操作API

批量操作命令

delete_multiple_nodes支持一次删除多个节点,比循环调用delete_node效率提升80%:

// 批量删除选中的临时节点
const selection = await server.call("get_selection");
const nodeIds = selection.nodes.map(node => node.id);
await server.call("delete_multiple_nodes", { nodeIds });

样式与主题API

// 获取所有文本样式
const styles = await server.call("get_styles");
const textStyles = styles.filter(style => style.type === "TEXT");

// 应用样式到节点
await server.call("set_text_style", {
  nodeId: "TEXT_NODE_ID",
  styleId: textStyles.find(s => s.name === "Body 1")?.id
});

三、企业级自动化工作流实战

3.1 电商产品卡片批量生成器

需求分析

设计团队需要为50个SKU创建产品卡片,包含图片、标题、价格、评分等元素,传统方法需手动操作50次×8个元素=400次点击。

实现方案

sequenceDiagram
    participant Script
    participant Server
    participant Figma
    Script->>Server: 读取产品数据(JSON)
    loop 产品数据迭代
        Script->>Server: 创建卡片容器(create_frame)
        Script->>Server: 创建标题文本(create_text)
        Script->>Server: 创建价格文本(create_text)
        Script->>Server: 设置星级评分(create_component)
        Script->>Server: 应用自动布局(set_layout)
    end
    Server->>Figma: 批量执行命令
    Figma-->>Server: 返回结果
    Server-->>Script: 输出执行报告

核心代码

// 产品数据
const products = [
  { id: 1, name: "无线蓝牙耳机", price: 299, rating: 4.8, image: "headphones.png" },
  // ...49个产品数据
];

// 卡片模板配置
const CARD_TEMPLATE = {
  width: 300,
  height: 420,
  padding: 16,
  spacing: 12,
  columns: 5, // 每行5个卡片
  rowGap: 24,
  colGap: 24
};

async function generateProductCards() {
  // 获取画布信息
  const docInfo = await server.call("get_document_info");
  const startX = 50;
  const startY = 50;
  
  let currentX = startX;
  let currentY = startY;
  
  for (let i = 0; i < products.length; i++) {
    const product = products[i];
    
    // 创建卡片容器
    const card = await server.call("create_frame", {
      x: currentX,
      y: currentY,
      width: CARD_TEMPLATE.width,
      height: CARD_TEMPLATE.height,
      name: `Product_${product.id}`,
      layoutMode: "VERTICAL",
      paddingTop: CARD_TEMPLATE.padding,
      paddingRight: CARD_TEMPLATE.padding,
      paddingBottom: CARD_TEMPLATE.padding,
      paddingLeft: CARD_TEMPLATE.padding,
      itemSpacing: CARD_TEMPLATE.spacing,
      fillColor: { r: 1, g: 1, b: 1, a: 1 },
      strokeColor: { r: 0.95, g: 0.95, b: 0.95, a: 1 },
      strokeWeight: 1,
      cornerRadius: 8
    });
    
    // 创建产品标题
    await server.call("create_text", {
      parentId: card.id,
      text: product.name,
      fontSize: 16,
      fontWeight: 600,
      name: "Product Name"
    });
    
    // 创建价格文本
    await server.call("create_text", {
      parentId: card.id,
      text: ${product.price}`,
      fontSize: 20,
      fontWeight: 700,
      fontColor: { r: 0.9, g: 0.2, b: 0.2, a: 1 },
      name: "Price"
    });
    
    // 布局定位计算
    currentX += CARD_TEMPLATE.width + CARD_TEMPLATE.colGap;
    if ((i + 1) % CARD_TEMPLATE.columns === 0) {
      currentX = startX;
      currentY += CARD_TEMPLATE.height + CARD_TEMPLATE.rowGap;
    }
  }
  
  return { 
    success: true, 
    count: products.length,
    message: `成功生成${products.length}个产品卡片`
  };
}

// 执行生成
const result = await generateProductCards();
console.log(result.message);

执行效果

通过此脚本,原本需要2小时的手动工作可在30秒内完成,且保证所有卡片样式100%一致,后续修改只需更新模板配置即可批量应用。

3.2 设计系统自动同步工具

痛点解决

开发团队与设计团队使用不同的设计规范源,导致前端实现与设计稿存在偏差。本工具实现从Figma设计系统到CSS变量的自动转换与同步。

实现流程

mindmap
  root((设计系统同步))
    数据提取
      获取颜色样式
      获取文本样式
      获取组件尺寸
    数据转换
      颜色RGBA转Hex
      尺寸单位转换
      样式命名标准化
    代码生成
      CSS变量文件
      Style Dictionary配置
      文档生成
    部署同步
      Git提交
      CI/CD触发
      通知团队

核心代码

// 提取Figma样式并转换为CSS变量
async function syncDesignSystem() {
  // 1. 获取所有样式
  const styles = await server.call("get_styles");
  
  // 2. 分类处理样式
  const colorStyles = styles.filter(s => s.type === "FILL");
  const textStyles = styles.filter(s => s.type === "TEXT");
  const effectStyles = styles.filter(s => s.type === "EFFECT");
  
  // 3. 转换颜色样式为CSS变量
  let cssVariables = ":root {\n";
  
  // 处理颜色
  colorStyles.forEach(style => {
    // 标准化命名(PascalCase转kebab-case)
    const varName = style.name
      .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
      .toLowerCase();
    
    // 转换颜色格式(RGBA -> HEX)
    const color = style.paints[0].color;
    const hexColor = rgbaToHex(color);
    
    cssVariables += `  --color-${varName}: ${hexColor};\n`;
  });
  
  // 处理文本样式
  textStyles.forEach(style => {
    const varName = style.name.toLowerCase().replace(/\s+/g, '-');
    cssVariables += `  --text-${varName}-font-size: ${style.fontSize}px;\n`;
    cssVariables += `  --text-${varName}-font-weight: ${style.fontWeight};\n`;
    cssVariables += `  --text-${varName}-line-height: ${style.lineHeight};\n`;
  });
  
  cssVariables += "}\n";
  
  // 4. 写入CSS文件
  await Bun.write("./design-tokens.css", cssVariables);
  
  // 5. 生成同步报告
  return {
    colors: colorStyles.length,
    textStyles: textStyles.length,
    effects: effectStyles.length,
    file: "design-tokens.css",
    timestamp: new Date().toISOString()
  };
}

// 颜色转换工具函数
function rgbaToHex(color) {
  const r = Math.round(color.r * 255);
  const g = Math.round(color.g * 255);
  const b = Math.round(color.b * 255);
  const a = Math.round(color.a * 255);
  
  return `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}${a === 255 ? '' : a.toString(16).padStart(2, '0')}`;
}

// 执行同步
const syncResult = await syncDesignSystem();
console.log(`同步完成: ${syncResult.colors}个颜色, ${syncResult.textStyles}个文本样式`);

3.3 多语言版本自动导出工作流

业务需求

为支持国际化,需要为6种语言导出对应版本的设计稿,并确保文本内容与布局适配不同语言的长度变化。

实现要点

  • 文本内容多语言替换
  • 自动调整文本框宽度(避免英文溢出、中文过宽)
  • 按语言分组导出设计稿
  • 生成翻译对照表

核心代码片段

// 多语言配置
const LANGUAGES = {
  zh: { name: "中文", code: "zh-CN", dir: "ltr" },
  en: { name: "英文", code: "en-US", dir: "ltr" },
  ja: { name: "日文", code: "ja-JP", dir: "ltr" },
  ar: { name: "阿拉伯文", code: "ar-SA", dir: "rtl" },
  fr: { name: "法文", code: "fr-FR", dir: "ltr" },
  es: { name: "西班牙文", code: "es-ES", dir: "ltr" }
};

// 翻译数据
const translations = {
  "welcome.title": {
    zh: "欢迎使用我们的产品",
    en: "Welcome to our product",
    ja: "当社の製品をご利用いただきありがとうございます",
    ar: "مرحبًا بك في منتجاتنا",
    fr: "Bienvenue sur notre produit",
    es: "Bienvenido a nuestro producto"
  },
  // ...更多翻译项
};

// 语言切换函数
async function switchLanguage(langCode) {
  // 获取所有文本节点
  const textNodes = await server.call("get_nodes_by_type", { type: "TEXT" });
  
  // 记录翻译状态
  const translationStats = {
    total: textNodes.length,
    translated: 0,
    skipped: 0,
    errors: []
  };
  
  // 设置进度更新回调
  let progress = 0;
  const total = textNodes.length;
  
  for (const node of textNodes) {
    try {
      // 检查节点是否有翻译标识
      if (node.name.startsWith("i18n:")) {
        const key = node.name.replace("i18n:", "").trim();
        
        // 获取翻译文本
        if (translations[key] && translations[key][langCode]) {
          const translatedText = translations[key][langCode];
          
          // 更新文本内容
          await server.call("set_text_content", {
            nodeId: node.id,
            text: translatedText
          });
          
          // 根据语言调整文本框宽度
          if (["ja", "zh"].includes(langCode)) {
            // 东亚语言宽度调整
            await server.call("resize_node", {
              nodeId: node.id,
              width: node.width * 0.9 // 缩小10%
            });
          } else if (langCode === "ar") {
            // 阿拉伯语(从右到左)
            await server.call("set_text_alignment", {
              nodeId: node.id,
              alignment: "RIGHT"
            });
          }
          
          translationStats.translated++;
        } else {
          translationStats.skipped++;
        }
      } else {
        translationStats.skipped++;
      }
      
      // 更新进度
      progress++;
      if (progress % 10 === 0) {
        console.log(`进度: ${Math.round((progress/total)*100)}%`);
      }
    } catch (error) {
      translationStats.errors.push({
        nodeId: node.id,
        nodeName: node.name,
        error: error.message
      });
    }
  }
  
  return {
    language: langCode,
    stats: translationStats,
    timestamp: new Date().toISOString()
  };
}

// 批量导出所有语言版本
async function exportAllLanguages() {
  const exportResults = {};
  
  // 创建导出目录
  await Bun.write("./exports", { type: "dir" });
  
  for (const [code, lang] of Object.entries(LANGUAGES)) {
    console.log(`正在导出${lang.name}版本...`);
    
    // 切换语言
    const switchResult = await switchLanguage(code);
    console.log(`翻译完成: ${switchResult.stats.translated}/${switchResult.stats.total}`);
    
    // 导出为PDF
    const exportResult = await server.call("export_frame", {
      nodeId: "PAGE_ID",
      format: "PDF",
      path: `./exports/${code}_version.pdf`
    });
    
    exportResults[code] = {
      success: true,
      file: exportResult.file,
      size: exportResult.size,
      translationStats: switchResult.stats
    };
  }
  
  // 生成翻译报告
  generateTranslationReport(exportResults);
  
  return exportResults;
}

// 执行多语言导出
const exportResults = await exportAllLanguages();
console.log("多语言版本导出完成:");
console.log(exportResults);

四、高级技巧与最佳实践

4.1 性能优化策略

优化方法 适用场景 性能提升 实现难度
命令批处理 大量独立操作 60-80% ★★☆
连接复用 多脚本并发执行 40-50% ★☆☆
结果缓存 重复查询操作 70-90% ★★☆
选择性更新 部分元素修改 30-40% ★★★

命令批处理示例

// 未优化:每次调用单独发送
for (let i = 0; i < 100; i++) {
  await server.call("create_rectangle", { x: i*10, y: 0, width: 8, height: 8 });
}

// 优化后:批量发送命令
const commands = [];
for (let i = 0; i < 100; i++) {
  commands.push({
    action: "create_rectangle",
    params: { x: i*10, y: 0, width: 8, height: 8 }
  });
}

await server.call("batch_commands", { commands });

4.2 错误处理与调试

完整错误处理框架

async function safeExecute(command, params, retries = 3) {
  try {
    // 添加超时控制
    const timeoutPromise = new Promise((_, reject) => 
      setTimeout(() => reject(new Error("Command timeout")), 10000)
    );
    
    // 并行执行命令与超时检查
    const result = await Promise.race([
      server.call(command, params),
      timeoutPromise
    ]);
    
    return { success: true, data: result };
  } catch (error) {
    // 重试逻辑(针对网络错误)
    if (retries > 0 && isNetworkError(error)) {
      console.log(`命令执行失败,剩余重试次数: ${retries}`);
      await new Promise(resolve => setTimeout(resolve, 1000)); // 等待1秒后重试
      return safeExecute(command, params, retries - 1);
    }
    
    // 错误分类与日志
    const errorType = categorizeError(error);
    logError({
      timestamp: new Date(),
      command,
      params,
      error: {
        message: error.message,
        stack: error.stack,
        type: errorType
      }
    });
    
    return {
      success: false,
      error: {
        message: error.message,
        type: errorType
      }
    };
  }
}

// 使用示例
const result = await safeExecute("create_frame", {
  x: 100, y: 100, width: 300, height: 200
});

if (!result.success) {
  if (result.error.type === "CONNECTION_ERROR") {
    // 处理连接错误
  } else if (result.error.type === "VALIDATION_ERROR") {
    // 处理参数验证错误
  }
}

调试工具推荐

  • MCP协议调试面板:监控所有命令与响应
  • Figma Dev Mode:实时查看节点ID与属性
  • Bun Inspector:脚本性能分析与断点调试

4.3 安全与权限控制

在多人协作环境中,建议实现以下安全措施:

  1. 命令白名单:限制第三方脚本只能调用指定API
// 安全配置
const SECURITY_CONFIG = {
  allowedCommands: [
    "get_selection", "create_text", "set_text_content",
    // 仅允许安全的查询和修改命令,禁止删除和导出操作
  ],
  rateLimit: {
    windowMs: 60000, // 1分钟
    maxRequests: 100 // 最多100次请求
  }
};

// 安全中间件
function securityMiddleware(command, params, userId) {
  // 1. 命令权限检查
  if (!SECURITY_CONFIG.allowedCommands.includes(command)) {
    throw new Error(`命令 ${command} 被禁止执行`);
  }
  
  // 2. 速率限制检查
  const now = Date.now();
  const windowStart = now - SECURITY_CONFIG.rateLimit.windowMs;
  
  // 清理过期记录
  userRequests[userId] = userRequests[userId]?.filter(
    reqTime => reqTime > windowStart
  ) || [];
  
  // 检查是否超过限制
  if (userRequests[userId].length >= SECURITY_CONFIG.rateLimit.maxRequests) {
    throw new Error("请求过于频繁,请稍后再试");
  }
  
  // 记录请求时间
  userRequests[userId].push(now);
  
  return true;
}
  1. 输入验证:严格校验所有参数
// 参数验证schema
const CREATE_FRAME_SCHEMA = z.object({
  x: z.number().min(0).max(10000),
  y: z.number().min(0).max(10000),
  width: z.number().min(10).max(5000),
  height: z.number().min(10).max(5000),
  name: z.string().max(100),
  // 其他参数验证...
});

// 使用验证
function validateParams(command, params) {
  const schemaMap = {
    create_frame: CREATE_FRAME_SCHEMA,
    // 其他命令schema...
  };
  
  if (schemaMap[command]) {
    return schemaMap[command].safeParse(params);
  }
  
  // 未知命令默认拒绝
  return { success: false, error: "未知命令" };
}

五、常见问题与解决方案

5.1 连接问题

问题 可能原因 解决方案
WebSocket连接失败 Figma插件未启动 确保Figma已安装插件并启用
连接超时 端口被占用 更换端口:bun run start --port=8888
命令无响应 协议版本不匹配 更新插件与本地服务到最新版本

5.2 性能问题

症状:执行包含100+命令的脚本时响应缓慢

解决方案

  1. 启用命令压缩:bun run start --compress
  2. 分阶段执行:每50个命令为一组,组间等待500ms
  3. 使用批量API替代循环单个调用

5.3 兼容性问题

Figma API变更处理

// 版本兼容层
async function getDocumentInfo() {
  try {
    // 尝试调用新版本API
    return await server.call("get_document_info_v2");
  } catch (error) {
    if (error.message.includes("not found")) {
      // 回退到旧版本API
      const legacyResult = await server.call("get_document_info");
      // 转换为新版本数据格式
      return transformLegacyDocumentInfo(legacyResult);
    }
    throw error;
  }
}

六、总结与未来展望

Cursor Talk To Figma MCP通过将设计操作原子化、协议化,为设计自动化提供了强大的技术基础。本文介绍的三个企业级工作流只是冰山一角,其真正价值在于释放设计团队的创造力——将重复劳动交给机器,专注于创意与体验设计。

未来发展方向

  1. AI辅助设计生成:结合GPT等模型实现自然语言转设计
  2. 实时协作编辑:多用户同时操作的冲突解决机制
  3. AR/VR设计支持:3D空间中的设计自动化

资源获取

  • 本文所有代码:项目仓库 /examples 目录
  • 自动化脚本模板:8个常用场景的完整实现
  • API文档:bun run docs 生成本地文档

下期预告:《Figma插件开发指南:从MCP协议到自定义UI》

点赞+收藏+关注,获取更多设计自动化实战技巧!如有任何问题或需求,请在评论区留言。

登录后查看全文
热门项目推荐
相关项目推荐