当客户向你展示一个精美的 Figma Make 原型,却无法提供设计文件时,你面临的是一个典型的二进制格式逆向工程挑战。Figma Make 作为 AI 驱动的原型设计工具,其输出文件采用未公开的二进制格式存储 React 应用程序代码。理解这一格式并构建可复用的解析器,不仅能够解决当下的代码提取需求,更能为类似场景提供可迁移的技术方案。
文件容器结构:ZIP 伪装下的双重压缩
Figma Make 的 .make 文件扩展名具有极强的误导性。十六进制分析显示,文件头部的四个字节 50 4B 03 04 正是标准 ZIP 格式的魔数签名。这意味着所有以 .make 为后缀的文件本质上都是 ZIP 归档,只是扩展名被刻意更换以增加逆向工程难度。
解压缩后,文件目录结构清晰且具有代表性。canvas.fig 作为核心二进制文件,通常占 2.3MB 左右,承载着应用程序的全部代码逻辑。meta.json 记录项目元数据,ai_chat.json 存储 AI 对话历史(体积可达 34MB),thumbnail.png 提供预览图像,而 images/ 目录包含约 110 个哈希命名且无扩展名的图像资源。理解这一目录结构是构建自动化解析流程的基础,因为后续的文件重建工作完全依赖于对原始目录结构的准确还原。
二进制格式解析:Kiwi 模式与双压缩机制
canvas.fig 文件的结构远比表面看起来复杂。文件头部的前九个字节为 66 69 67 2D 6D 61 6B 65 65,即 ASCII 字符串 fig-makee,这是 Figma Make 特有的魔数标识,与标准 Figma 设计文件的 fig-kiwi 头部形成区分。紧随其后的 12 字节偏移处开始,便是两个独立压缩的数据块。
第一个数据块使用 Deflate 压缩算法,解压后可获得约 59KB 的模式定义数据。这份模式文件包含 534 个类型定义,涵盖节点、颜色、向量、变换、字体等数据结构,以及本次解析最关心的 CODE_FILE 类型定义。模式文件的存在使得后续的数据解码成为可能,因为 Kiwi 二进制格式是一种紧凑但无自描述能力的编码方案,必须依赖外部模式定义才能正确解析字段含义。
第二个数据块采用 Zstandard 压缩算法,其魔数标识为 28 B5 2F FD。解压后数据体积从 2.2MB 膨胀至 29MB,这种高压缩比是 Zstandard 算法的典型特征。解码后的数据结构呈现为树形节点集合,共包含 159 个节点,其中 CODE_FILE 类型的节点正是我们寻找的源代码载体。
在工程实践中,解压缩环节的依赖选择直接影响解析器的可维护性。推荐使用 pako 处理 Deflate 压缩,该库提供了完整的 zlib/deflate 实现;fzstd 则是 JavaScript 生态中 Zstandard 算法的成熟实现;而 kiwi-schema 库负责将模式定义与二进制数据关联,完成最终的解码工作。这三个库的组合构成了解析器的核心依赖层。
组件树提取:CODE_FILE 节点的识别与解析
解码后的数据以 JSON 结构呈现,但字段命名采用紧凑的二进制编码风格。节点集合中,每一项包含 type 字段标识节点类型,name 字段记录文件名,而 sourceCode 字段则直接存储源代码文本。提取过程的工程化实现需要关注以下几个关键参数。
过滤策略应设定为:nodeChanges.filter(node => node.type === 'CODE_FILE' && node.sourceCode)。这一筛选条件能够精确识别包含源代码的节点,同时排除空节点或元数据节点。典型情况下,一次完整提取可获得 96 个源文件,涵盖 React 组件(.tsx)、TypeScript 工具函数(.ts)、CSS 样式文件、数据配置文件以及 React 自定义钩子。
文件分类逻辑建议采用启发式规则:根据文件名后缀分类 TypeScript/React 文件,根据文件内容特征识别 CSS 与配置文件。组件文件通常以 tsx 为扩展名且包含 JSX 语法或 React 导入语句;工具函数文件以 ts 为扩展名且不包含 JSX;样式文件包含 CSS 规则或 Tailwind 类名。这种分类机制为后续的目录结构重建提供了依据。
自动化重构:修复 AI 生成代码的特有模式
从提取的源代码到可运行的 React 应用程序,中间需要处理多个特定的修复场景。这些修复逻辑应当抽象为独立的转换管道,以便在未来的提取任务中复用。
版本化包导入是最常见的修复场景。Figma Make 生成的代码中,导入语句携带版本号,例如 import { Dialog } from '@radix-ui/react-dialog@1.1.6'。这种写法虽然明确但不符合标准 npm 语义,运行时会导致解析错误。修复策略为:使用正则表达式 /@([^@:]+)@[\d.]+/g 匹配并移除版本号片段,将导入语句标准化为 import { Dialog } from '@radix-ui/react-dialog'。
自定义资产导入需要特殊处理。Figma Make 使用 figma:asset/{hash} 格式引用图像资源,这种格式无法被浏览器或构建工具识别。转换逻辑应将 import heroImage from 'figma:asset/a1b2c3d4.png' 替换为 const heroImage = '/images/a1b2c3d4.png',同时确保目标目录存在且图像文件已添加正确扩展名。
图像资源的扩展名缺失是另一个需要处理的细节。ZIP 包内的 images/ 目录中的文件以哈希值命名且无扩展名,但浏览器和构建工具需要明确的扩展名才能正确处理资源类型。建议的修复策略是:扫描源代码中所有 figma:asset 引用,根据常见的图像 MIME 类型映射为 .png、.jpg 或 .svg 后缀,并批量重命名目标文件。
Tailwind CSS 的集成方式在 v4 版本发生了显著变化。早期版本使用 tailwindcss 直接集成,而 v4 需要通过 @tailwindcss/postcss 适配器。这一差异可能导致提取后的样式完全失效,因此解析器应当检测 Tailwind 配置并自动调整 PostCSS 配置或降级到 v3 兼容模式。
React StrictMode 的副作用在动画场景中尤为明显。Figma Make 广泛使用 Framer Motion 实现交互动画,而 StrictMode 会导致组件双挂载,破坏基于计时器的动画逻辑。解决方案是在最终输出中移除 <React.StrictMode> 包装器,或在开发阶段接受这一行为而在生产构建中保持严格模式。
解析器架构设计:可复用的提取流水线
基于上述技术分析,构建一个可复用的解析器需要清晰的模块划分。解压缩模块负责处理 ZIP 容器,输出原始二进制文件流。格式识别模块检测 fig-makee 魔数并验证文件结构完整性。双通道解压模块分别处理 Deflate 和 Zstandard 压缩块,输出模式数据与实际载荷。模式解析模块利用 kiwi-schema 库解码二进制数据为结构化节点集合。代码提取模块筛选 CODE_FILE 节点并提取 sourceCode 属性。后处理模块执行导入标准化、路径修复与扩展名补全。结构重建模块根据文件间导入关系推断目录结构并生成完整的项目骨架。
这一架构的优势在于模块间低耦合,任何单一环节的格式变更都不会导致整体解析器失效,只需更新对应模块即可。例如,若未来 Figma Make 改用其他压缩算法,只需替换双通道解压模块的实现;若模式定义发生结构性变化,只需更新模式解析模块对类型标识符的处理逻辑。
监控与容错:生产环境的必要考量
在持续集成环境中运行此类解析器时,需要建立完善的监控与容错机制。输入验证应包含文件大小上限(建议 50MB)、魔数签名验证以及 ZIP 结构完整性检查。处理超时应设置合理阈值(建议单文件处理不超过 60 秒),防止异常文件导致解析器挂起。错误日志应记录详细的堆栈信息与中间状态,便于后续问题定位与格式演进追踪。
对于格式可能发生的演进,建议在模式解析模块中实现向前兼容逻辑:当遇到未知类型标识符时,记录警告日志并跳过该节点,而非直接抛出异常导致整个解析流程中断。这种容错设计确保了解析器在面对 Figma Make 版本更新时的稳定性。
逆向工程的价值不仅在于解决当下问题,更在于积累可迁移的技术能力。Figma Make 的二进制格式解析涉及压缩算法识别、二进制协议分析、代码重构与自动化修复等多个技术维度,这些经验可以直接应用于其他专有格式的解析场景。构建可复用的解析器架构,本质上是在为未来的类似挑战预置解决方案。
资料来源
- Albert Sikkema: "Reverse-Engineering Figma Make: Extracting React Apps from Binary Files" (https://albertsikkema.com/ai/development/tools/reverse-engineering/2026/01/23/reverse-engineering-figma-make-files.html)
- GitHub: figma-make-extractor (https://github.com/albertsikkema/figma-make-extractor)