如果你是一名游戏或应用开发者,正在使用 Cocos Creator 构建项目,那么你一定经历过这样的场景:UI 设计师在 Figma 上完成了一套精美的界面设计,然后你需要手动将里面的图标、按钮、背景图一张张导出为 PNG 或 JPG,再拖拽到 Cocos Creator 的资源管理器里,最后还要调整尺寸、设置九宫格、配置 SpriteFrame。这个过程不仅枯燥,而且一旦设计稿有更新,所有工作都得重来一遍。
更令人头疼的是,当你尝试使用 Codex、Claude Code、Cursor 或 OpenCode 这类 AI 编程助手来加速开发时,它们能帮你生成逻辑代码,却无法帮你处理这些繁琐的“切图”和资源导入工作。AI 写代码再快,你依然被卡在手动搬运资源的环节。
这篇文章要解决的,正是这个横亘在设计与开发之间的效率断层。我们将介绍一种方法,实现Figma 设计稿到 Cocos Creator 项目的自动化导入。核心价值在于:将设计师的 Figma 文件与开发者的 Cocos Creator 项目直接打通,实现“设计即资源”。更新设计稿后,只需一键同步,所有切图、资源引用甚至部分 UI 结构都能自动更新,彻底告别重复的手动操作。
下面,我们将从原理、工具选择、详细配置到实战示例,完整拆解这套自动化流程。
1. 为什么需要自动化导入?不仅仅是“省事”
在深入技术细节前,我们先明确自动化导入解决的几个核心痛点:
- 版本同步灾难:设计师微调了一个按钮的颜色或尺寸,开发者需要重新导出、替换、检查所有引用该资源的地方,极易遗漏或出错。
- 资源管理混乱:手动导入的图片命名随意,散落在不同目录,导致项目资源结构难以维护。
- 开发流程割裂:AI 编程助手(如 Codex)擅长处理结构化代码逻辑,但对非结构化的资源处理无能为力。自动化导入补齐了这块短板,让 AI 辅助的开发流程更加完整。
- 协作成本高昂:设计评审后,需要专门的时间进行“资源交付”和“导入”,沟通成本高。
因此,自动化导入的目标不仅是“快”,更是为了建立一套可靠、可追溯、可协作的资产管道。它让设计师的修改能无缝、准确地反映在开发环境中,是团队敏捷开发的基础设施。
2. 核心原理:连接 Figma API 与 Cocos Creator 工作流
整个自动化流程的核心,是利用 Figma 开放的 REST API 作为桥梁。
[Figma 设计文件] --(API 请求)--> [自动化脚本/工具] --(生成资源文件)--> [Cocos Creator 项目资源目录]- 获取设计数据:通过 Figma API,使用文件 ID 和个人访问令牌 (Personal Access Token),可以获取到设计文件中所有节点的详细信息,包括位置、尺寸、填充(颜色、图片)、导出设置等。
- 解析与过滤:脚本需要解析这些数据,识别出哪些节点是需要作为图片资源导出的(例如,使用了图片填充的矩形、或标记为“导出”的组件)。同时,可以根据图层命名规则(如以
icon/、btn/开头)进行筛选和分类。 - 下载与处理:通过 API 获取图片的下载 URL,批量下载到本地。然后根据 Cocos Creator 的资源规范进行处理,例如:
- 重命名:将 Figma 图层名转换为适合文件系统的名称。
- 格式转换:确保为 PNG(支持透明)或 JPG。
- 目录映射:根据图层结构或命名规则,将图片存放到 Cocos Creator 项目的特定目录下(如
assets/textures/ui)。
- 生成元数据(可选但推荐):除了图片本身,还可以生成一份 JSON 文件,记录资源在 Figma 中的原始信息(如节点ID、尺寸、位置),甚至可以根据简单的规则尝试生成 Cocos Creator 的
.prefab或.scene的初始结构,极大提升 UI 搭建速度。
市面上已有一些开源工具或插件尝试实现此流程,但完整度不一。接下来,我们将基于一个更可控、更灵活的方案——使用Node.js 脚本来构建这套管道。
3. 环境准备与前置条件
在开始编写脚本前,请确保你的开发环境满足以下要求:
- 操作系统:Windows 10/11, macOS 或 Linux。本文示例基于 Node.js,跨平台兼容。
- Node.js:版本 16 或以上。这是运行我们自动化脚本的引擎。
- Cocos Creator:版本 3.x。确保项目已创建并打开过。
- Figma 账号:拥有对目标设计文件的“可以查看”或更高权限。
- 网络:能够正常访问 Figma API (
api.figma.com)。
你需要从 Figma 获取两个关键信息:
- Personal Access Token:登录 Figma -> 点击右上角头像 ->
Settings-> 左侧Account-> 找到Personal access tokens区域 -> 点击Create new token。为其命名(如CocosAutoImport),并保存生成的令牌字符串。此令牌等同于你的密码,请勿泄露。 - File Key:在 Figma 中打开你的设计文件,浏览器地址栏的 URL 格式为
https://www.figma.com/file/<FILE_KEY>/文件名。其中<FILE_KEY>就是所需的文件 ID。
4. 项目结构与核心脚本拆解
我们将创建一个简单的 Node.js 项目来实现自动化导入。项目结构如下:
figma-to-cocos-tool/ ├── package.json ├── config.json ├── src/ │ ├── index.js # 主入口脚本 │ ├── figma-service.js # 封装 Figma API 调用 │ └── cocos-processor.js # 处理下载和 Cocos 资源生成 └── output/ # 下载图片的临时目录(可配置)4.1 初始化项目与安装依赖
首先,创建项目目录并初始化package.json。
mkdir figma-to-cocos-tool cd figma-to-cocos-tool npm init -y安装必要的依赖包:
axios或node-fetch:用于发起 HTTP 请求到 Figma API。fs-extra:提供比原生fs模块更强大的文件操作功能。sharp:一个高性能的图片处理库,可用于格式转换、缩放等(可选,但推荐)。
npm install axios fs-extra sharp4.2 编写配置文件 (config.json)
将敏感信息和项目配置放在配置文件中,避免硬编码。
{ "figma": { "personalAccessToken": "你的-Figma-Personal-Access-Token", "fileKey": "你的-Figma-文件Key" }, "cocos": { "projectAssetsPath": "/绝对路径/到/你的Cocos项目/assets", "textureBaseDir": "textures/ui", "allowedFormats": ["PNG", "JPG"] }, "export": { "scale": 1, "format": "PNG", "useAbsoluteBounds": false, "outputDir": "./output" }, "filter": { "layerNameStartsWith": ["icon/", "btn/", "img/"], "minWidth": 4, "minHeight": 4 } }重要提醒:
personalAccessToken和fileKey必须替换为你自己的。cocos.projectAssetsPath需要指向你 Cocos Creator 项目的assets文件夹的绝对路径。filter配置用于筛选需要导出的图层,可以根据你的设计规范调整。
4.3 封装 Figma API 服务 (src/figma-service.js)
这个模块负责与 Figma API 交互,获取文件数据和图片下载链接。
// src/figma-service.js const axios = require('axios'); class FigmaService { constructor(accessToken, fileKey) { this.accessToken = accessToken; this.fileKey = fileKey; this.baseURL = 'https://api.figma.com/v1'; this.client = axios.create({ baseURL: this.baseURL, headers: { 'X-Figma-Token': this.accessToken } }); } // 获取文件结构树 async getFile() { try { const response = await this.client.get(`/files/${this.fileKey}`); return response.data; } catch (error) { console.error('获取 Figma 文件失败:', error.message); throw error; } } // 获取图片资源列表(需要先发起导出请求) async getImageUrls(nodeIds, options = {}) { const { format = 'PNG', scale = 1 } = options; try { // 注意:此 API 返回的是图片的映射表,key 为 node id, value 为 url const response = await this.client.get(`/images/${this.fileKey}`, { params: { ids: nodeIds.join(','), format, scale } }); return response.data.images; // 一个对象,如 { "1:23": "https://..." } } catch (error) { console.error('获取图片URL失败:', error.message); throw error; } } } module.exports = FigmaService;4.4 编写 Cocos 资源处理器 (src/cocos-processor.js)
这个模块负责下载图片、处理文件名、并复制到 Cocos Creator 项目目录。
// src/cocos-processor.js const fs = require('fs-extra'); const path = require('path'); const axios = require('axios'); const sharp = require('sharp'); // 用于图片处理 class CocosProcessor { constructor(config) { this.config = config; } // 清洗文件名,使其符合文件系统规范 sanitizeFileName(name) { return name.replace(/[\/\\:*?"<>|]/g, '_').replace(/\s+/g, '_'); } // 根据图层名决定存放的子目录 resolveTargetDir(layerName) { const { textureBaseDir } = this.config.cocos; let subDir = ''; if (layerName.startsWith('icon/')) { subDir = 'icons'; } else if (layerName.startsWith('btn/')) { subDir = 'buttons'; } else if (layerName.startsWith('img/')) { subDir = 'images'; } else { subDir = 'others'; } // 构建完整目标路径 return path.join(this.config.cocos.projectAssetsPath, textureBaseDir, subDir); } // 下载单张图片并保存 async downloadAndProcessImage(imageUrl, nodeId, layerName) { const sanitizedName = this.sanitizeFileName(layerName || nodeId); const fileName = `${sanitizedName}.${this.config.export.format.toLowerCase()}`; const targetDir = this.resolveTargetDir(layerName); const tempFilePath = path.join(this.config.export.outputDir, fileName); const finalFilePath = path.join(targetDir, fileName); // 确保目录存在 await fs.ensureDir(targetDir); await fs.ensureDir(this.config.export.outputDir); console.log(`下载中: ${layerName} -> ${finalFilePath}`); try { // 1. 下载图片到临时目录 const response = await axios({ method: 'GET', url: imageUrl, responseType: 'stream' }); const writer = fs.createWriteStream(tempFilePath); response.data.pipe(writer); await new Promise((resolve, reject) => { writer.on('finish', resolve); writer.on('error', reject); }); // 2. (可选) 使用 sharp 进行处理,例如统一转换为 PNG if (this.config.export.format === 'PNG') { await sharp(tempFilePath).png().toFile(finalFilePath); } else { // 如果不是 PNG,直接复制(或做其他处理) await fs.copy(tempFilePath, finalFilePath); } // 3. 清理临时文件 await fs.remove(tempFilePath); console.log(`✓ 已完成: ${finalFilePath}`); return { success: true, path: finalFilePath, nodeId, layerName }; } catch (error) { console.error(`✗ 处理失败 ${layerName}:`, error.message); return { success: false, error: error.message, nodeId, layerName }; } } } module.exports = CocosProcessor;4.5 编写主入口脚本 (src/index.js)
这是脚本的“大脑”,负责协调整个流程:获取数据 -> 过滤节点 -> 获取图片URL -> 批量处理。
// src/index.js const FigmaService = require('./figma-service'); const CocosProcessor = require('./cocos-processor'); const config = require('../config.json'); const fs = require('fs-extra'); async function main() { console.log('🚀 开始 Figma 到 Cocos Creator 的自动化导入流程...\n'); // 1. 初始化服务 const figmaService = new FigmaService(config.figma.personalAccessToken, config.figma.fileKey); const cocosProcessor = new CocosProcessor(config); // 2. 确保输出目录存在 await fs.ensureDir(config.export.outputDir); // 3. 获取 Figma 文件数据 console.log('正在获取 Figma 文件结构...'); const fileData = await figmaService.getFile(); const document = fileData.document; // 4. 递归遍历文档树,收集需要导出的节点 const nodesToExport = []; function traverse(node, parentName = '') { if (!node) return; const layerName = node.name ? `${parentName}/${node.name}`.replace(/^\//, '') : ''; // 应用过滤规则 const shouldExport = node.type === 'RECTANGLE' || node.type === 'FRAME' || node.type === 'COMPONENT' || node.type === 'INSTANCE' || node.type === 'VECTOR' || node.type === 'ELLIPSE' || node.type === 'POLYGON' || node.type === 'STAR' || node.type === 'LINE' || node.type === 'BOOLEAN_OPERATION' || node.type === 'TEXT'; if (shouldExport) { // 检查是否满足自定义过滤条件(如图层名前缀、最小尺寸) const meetsFilter = config.filter.layerNameStartsWith.some(prefix => layerName.startsWith(prefix)) || (node.absoluteBoundingBox && node.absoluteBoundingBox.width >= config.filter.minWidth && node.absoluteBoundingBox.height >= config.filter.minHeight); if (meetsFilter) { nodesToExport.push({ id: node.id, name: layerName, type: node.type }); } } // 递归遍历子节点 if (node.children) { for (const child of node.children) { traverse(child, layerName); } } } traverse(document); console.log(`找到 ${nodesToExport.length} 个待导出节点。`); if (nodesToExport.length === 0) { console.log('没有找到符合过滤条件的节点,请检查 config.json 中的 filter 配置。'); return; } // 5. 获取这些节点的图片导出 URL console.log('正在向 Figma 请求图片导出链接...'); const nodeIds = nodesToExport.map(n => n.id); const imageUrlMap = await figmaService.getImageUrls(nodeIds, { format: config.export.format, scale: config.export.scale }); // 6. 下载并处理每一张图片 console.log('\n开始下载并处理图片...'); const results = []; for (const node of nodesToExport) { const imageUrl = imageUrlMap[node.id]; if (!imageUrl) { console.warn(`⚠️ 未获取到节点 ${node.name} (ID: ${node.id}) 的图片URL,可能该节点无可视内容。`); continue; } const result = await cocosProcessor.downloadAndProcessImage(imageUrl, node.id, node.name); results.push(result); } // 7. 生成一份导入报告(可选) const successCount = results.filter(r => r.success).length; const failCount = results.length - successCount; console.log(`\n🎉 导入完成!成功: ${successCount}, 失败: ${failCount}`); if (failCount > 0) { console.log('失败的节点:'); results.filter(r => !r.success).forEach(r => { console.log(` - ${r.layerName}: ${r.error}`); }); } // 8. (高级) 生成资源映射 JSON 文件,供后续自动化创建 UI 使用 const assetManifest = results.filter(r => r.success).map(r => ({ figmaNodeId: r.nodeId, figmaLayerName: r.layerName, cocosPath: path.relative(config.cocos.projectAssetsPath, r.path).replace(/\\/g, '/') // 统一为 Unix 路径 })); const manifestPath = path.join(config.cocos.projectAssetsPath, config.cocos.textureBaseDir, 'figma-import-manifest.json'); await fs.writeJson(manifestPath, assetManifest, { spaces: 2 }); console.log(`\n📁 资源清单已生成: ${manifestPath}`); } main().catch(console.error);5. 运行与效果验证
5.1 运行脚本
在项目根目录下,执行以下命令:
node src/index.js如果一切配置正确,你将在控制台看到类似以下的输出:
🚀 开始 Figma 到 Cocos Creator 的自动化导入流程... 正在获取 Figma 文件结构... 找到 15 个待导出节点。 正在向 Figma 请求图片导出链接... 开始下载并处理图片... 下载中: icon/home -> /Users/.../your-cocos-project/assets/textures/ui/icons/home.png ✓ 已完成: /Users/.../your-cocos-project/assets/textures/ui/icons/home.png 下载中: btn/primary -> /Users/.../your-cocos-project/assets/textures/ui/buttons/primary.png ✓ 已完成: /Users/.../your-cocos-project/assets/textures/ui/buttons/primary.png ... 🎉 导入完成!成功: 15, 失败: 0 📁 资源清单已生成: /Users/.../your-cocos-project/assets/textures/ui/figma-import-manifest.json5.2 在 Cocos Creator 中验证
- 打开你的 Cocos Creator 项目。
- 在资源管理器中,导航到
assets/textures/ui/目录(或你在配置中指定的目录)。你应该能看到按类别(icons,buttons等)整理好的图片资源。 - 选中任意一张图片,在属性检查器中,可以正常预览,并且可以将其拖拽到场景中作为
Sprite组件的SpriteFrame使用。 - 如果生成了
figma-import-manifest.json,你可以打开它查看资源映射关系,这为后续自动化创建 UI 节点提供了数据基础。
5.3 实现“两步”自动化
文章标题提到的“只需两步”,在实际操作中可以简化为:
- 第一步(一次性配置):运行
npm install安装依赖,填写config.json中的 Figma Token、文件 Key 和 Cocos 项目路径。 - 第二步(每次同步):运行
node src/index.js。
你可以将第二步命令添加到package.json的scripts中,例如:
{ "scripts": { "sync-figma": "node src/index.js" } }之后每次同步,只需要运行:
npm run sync-figma6. 常见问题与排查思路
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
运行脚本报错Error: getaddrinfo ENOTFOUND api.figma.com | 网络问题,无法访问 Figma API。 | 检查网络连接,尝试在浏览器中打开https://api.figma.com/v1/(会返回错误,但能测试连通性)。 | 配置网络代理或检查防火墙设置。 |
控制台输出获取 Figma 文件失败: Request failed with status code 404 | Figma 文件 Key 错误,或 Token 无权限访问该文件。 | 1. 核对config.json中的fileKey。2. 在 Figma 中确认 Token 所属账号对该文件有查看权限。 | 1. 复制正确的 File Key。 2. 使用文件所有者账号的 Token,或在 Figma 中邀请该 Token 所属账号进入文件。 |
控制台输出获取 Figma 文件失败: Request failed with status code 403 | Personal Access Token 无效或已过期。 | 登录 Figma 设置页,检查 Token 是否被删除或重置。 | 重新生成一个 Token 并更新到config.json。 |
| 脚本运行成功,但 Cocos Creator 中看不到新图片 | 1. 图片被下载到了错误目录。 2. Cocos Creator 未刷新资源管理器。 | 1. 检查脚本输出的文件路径是否正确指向了项目的assets子目录。2. 查看 output/临时目录是否有文件。 | 1. 修正config.json中的cocos.projectAssetsPath。2. 在 Cocos Creator 资源管理器中右键点击父目录,选择“刷新”。 |
| 导出的图片尺寸不对或模糊 | Figma API 导出时的scale参数设置不当。 | 检查config.json中export.scale的值。Figma 默认导出为 1x。 | 对于需要高清显示的图片,可以尝试设置scale: 2或scale: 3,但需注意文件体积会增大。 |
| 导出了大量不需要的图层 | 过滤规则 (filter) 太宽松或设计文件图层命名不规范。 | 1. 查看nodesToExport数组里收集到的节点名。2. 检查 Figma 设计稿,确认图层是否按约定命名(如 icon/xxx)。 | 1. 调整config.json中的filter.layerNameStartsWith,使其更精确。2. 与设计师约定图层/组件的命名规范。 |
运行时报错Cannot find module 'sharp' | sharp库安装失败,可能与系统环境有关。 | 查看npm install时的错误日志。 | 1. 尝试安装sharp的预编译版本:npm install --platform=darwin --arch=x64 sharp(根据你的系统调整)。2. 如果不需图片处理,可以注释掉 cocos-processor.js中使用sharp的代码,直接复制文件。 |
7. 最佳实践与工程建议
- 设计规范先行:与 UI/UX 设计师共同制定 Figma 图层/组件命名规范(如
ui/icon/arrow,ui/button/primary)。这是实现精准过滤和自动分类的前提。 - Token 安全管理:切勿将包含真实 Token 的
config.json提交到 Git 等版本控制系统。应该使用config.example.json作为模板,将真实配置放在本地或通过环境变量注入。
然后在脚本中通过# 例如,在运行脚本前设置环境变量 export FIGMA_TOKEN="your_token_here" node src/index.jsprocess.env.FIGMA_TOKEN读取。 - 集成到 CI/CD:可以将此脚本集成到团队的持续集成流程中。例如,在每日构建或设计稿更新后自动触发,确保开发环境资源始终与设计稿同步。
- 生成预制体(Prefab)元数据:上述脚本只导入了图片。你可以扩展它,利用 Figma API 返回的节点位置、尺寸、父子关系信息,生成一个描述 UI 结构的 JSON。然后编写另一个脚本,读取这个 JSON 并调用 Cocos Creator 的扩展 API(需在 Cocos Creator 编辑器内运行)来自动创建或更新
.prefab文件。这将把自动化从“资源导入”提升到“界面搭建”。 - 处理更新与删除:当前脚本是“覆盖式”导入。更完善的方案需要对比本次和上次导入的资源清单,找出新增、修改和删除的文件,并对 Cocos 项目中的资源进行相应操作(删除废弃资源需谨慎)。
- 错误处理与日志:在生产环境中,需要更完善的错误处理、重试机制和日志记录,方便排查问题。
- 与 AI 开发工具结合:这正是标题中提到的 Codex/Claude Code/Cursor 的价值所在。你可以将这套自动化流程的配置、脚本维护、甚至扩展开发(如生成 Prefab)任务,交给 AI 编程助手。你只需要用自然语言描述需求,AI 可以帮助你编写、调试和优化这些脚本代码,让你更专注于业务逻辑本身。
8. 总结与后续方向
通过本文,我们构建了一个从 Figma 到 Cocos Creator 的自动化资源导入管道。它不仅仅是一个“省时间”的工具,更是连接设计流水线与开发流水线的关键桥梁。
核心收获:
- 原理清晰:基于 Figma API,程序化获取设计数据。
- 流程可控:通过 Node.js 脚本,你可以完全自定义过滤、处理和输出逻辑。
- 落地性强:提供了完整的、可运行的代码示例,你可以直接基于此进行修改以适应自己的项目。
- 扩展性高:此框架为后续的自动化 UI 搭建、设计版本管理打下了基础。
你可以继续深化的方向:
- 开发 Cocos Creator 编辑器插件:将脚本集成到 Cocos Creator 编辑器内,提供图形化界面(GUI)来配置 Token、选择文件、设置过滤规则,一键同步。
- 支持更多资源类型:除了图片,还可以尝试导出 SVG(矢量图)、颜色变量、文本样式等,并在 Cocos 中做相应转换。
- 双向同步:这是一个更高级的设想,将 Cocos 中调整的布局数据反馈回 Figma,但这需要非常严谨的设计数据模型映射。
将重复性工作自动化,是工程师提升价值的必经之路。从手动切图到一键同步,你节省的不仅是时间,更是减少了上下文切换,降低了人为错误的风险,让团队协作更加流畅。现在,你可以让 AI 编程助手去处理更复杂的游戏逻辑,而资源同步这种“脏活累活”,就交给自动化脚本吧。