插件安装: 在执行设置或更新命令之前,如果此技能位于 HyperFrames 插件内部,请遵循 插件执行规则。独立安装则遵循下面的更新说明。
首先,使此技能保持最新——在运行前与用户确认:
npx hyperframes skills update figma。如果一切已是最新,则快速执行无操作;否则,它将刷新此技能及其依赖的核心领域技能,以便你在依赖它们之前获得最新版本。
Figma → HyperFrames
将用户的 Figma 工作成果带入合成。按能力划分(设计规格 §2):
| 阶段 | 内容 | 传输方式 | 接口 |
|---|---|---|---|
| 1 | 静态资源 | REST | hyperframes figma asset |
| 2 | 品牌令牌/样式 | REST | hyperframes figma tokens |
| 3 | 组件 → HTML | REST | hyperframes figma component |
| 4 | 动作 → GSAP | 可选连接器 | 使用其动作上下文 |
| 5 | 着色器 | 连接器 / 手动导出 | 使用它或本地导出 |
REST 在可用的地方被广泛使用(适用于批量操作、无头环境)。一个兼容的 Figma 连接器对于动作和着色器数据是可选的;如果没有,则要求进行本地导出。每条路径都会将资产冻结在本地,以确保渲染结果是确定性的。故事板重建通过 REST 组合第一阶段的资产导出,并结合由代理驱动的时间轴组装——无需连接器。现有的冻结资产、清单记录和绑定不受路由更改的影响——拆分仅更改下一个导入使用的凭据。
认证——两个凭据,作用域明确
预检——在首次调用 CLI 之前,检查令牌是否存在: shell 环境变量 ([ -n "$FIGMA_TOKEN" ]) 或 项目 .env 文件(CLI 会自动加载它——.env 中的条目视为已配置)。如果两者都不存在,不要运行命令去收集错误——先引导用户完成一次性设置,然后停止并等待:
- figma.com/settings → 安全 → 个人访问令牌 → 生成新令牌。
- 作用域——此集成永远只需要只读访问权限(它从不写入 Figma):文件内容:只读 + 文件元数据:只读。如果你将在非企业计划上运行
tokens,请额外添加 库内容:只读——已发布样式的回退会命中/v1/files/:key/styles,如果没有此作用域则会返回 403(旧版设置文本遗漏了这一点)。可选地添加 变量:只读 用于品牌变量——仅限企业版;没有它时,tokens命令会自动降级为已发布的样式(这是预期行为,并非错误——请明确告知)。现在,403 错误会明确指出缺失的作用域;429 错误会自动重试(每分钟限制,遵守Retry-After头)。 - 让用户在 shell 配置文件或项目
.env中设置FIGMA_TOKEN;切勿要求他们将令牌粘贴到对话中。
在引导过程中,也请一口气说清楚预期:每次导入都会生成一个带有记录来源的本地冻结文件——渲染永远不会调用 Figma,重新运行命令仅重新导入 Figma 中已更改的部分,一个令牌即可用于其 Figma 账户可以查看的每个文件的资产、品牌令牌和组件。
- 阶段 4–5(动作/着色器): 一个兼容的 Figma 连接器,其授权与令牌分开。如果它不可用或未经过身份验证,请要求用户连接它或提供本地导出,然后停止。
- 明确说明失败的阶段需要哪个凭据——切勿将此拆分描述为损坏。
BAD_TOKEN(401) 中途出现 → 令牌已过期/被撤销;重新生成。FORBIDDEN(403) → 消息明确指出了缺少的作用域(例如,样式回退需要library_content:read)——添加它,或者该文件对账户不可见。REQUIRES_ENTERPRISE(变量上的 403) → 不是失败:样式回退已运行。RATE_LIMITED(429) → 客户端已使用退避重试(这适用于每次读取——资产、令牌、样式、节点树、版本——重试存在于共享请求路径中;遵守Retry-After,上限为 60 秒);如果仍然出现,等待一分钟或每个调用减少导入的节点数量。
速率限制意识(规格 §2.1): 连接器配额因 Figma 计划而异——批量请求父级帧,除非要求否则跳过验证截图,并缓存原始响应以便重新派生不会消耗第二次调用。REST 是每分钟计数的(10+ 次/分钟,按端点分桶)——批量操作下表现良好,遇到 429 则回退。
路由
使用 parseFigmaRef 解析用户的 Figma 链接(URL、fileKey:nodeId、纯 fileKey)。然后根据意图:
- “使用此图层 / Logo / 图像” → 资产 (CLI)
- “提取我的品牌 / 颜色 / 令牌” → 令牌 (CLI)
- “从此帧构建场景” → 组件 (CLI)
- “导入此动画 / 动作” → 动作 (使用可用的连接器,见下方)
- 故事板片段 / 场景帧序列 → 故事板 (见下方)
- 着色器填充/效果 → 着色器 (见下方)
向用户叙述每个步骤——在每个命令之前说明你将要从 Figma 提取什么;之后,说明工件落在了哪里(冻结路径 / sidecar 文件 / 组件目录)、合成了什么变化以及下一步操作(预览、添加打印变量、重新导入以链接绑定)。用户永远不必问“成功了吗?”或“现在怎么办?”。
资产(阶段 1 — CLI)
hyperframes figma asset '<url-or-fileKey:nodeId>' [更多引用……] [--format svg|png|jpg|pdf] [--scale 2] [--description "..."] [--entity "..."]
通过 REST 渲染,清理 SVG,冻结到 .media/images/ 目录,将来源信息追加到清单,重新生成 .media/index.md(共享媒体使用清单),并输出一个 <img> 片段。每个 fileKey:nodeId:format:scale:version 组合是幂等的。对于矢量/Logo 优先使用 SVG(可缩放、可动画化),对于光栅保真度使用 PNG --scale 2。始终传递 --description "<它是什么>"(它将成为索引行和 <img alt> 的内容);对于有名称的品牌标记添加 --entity "<名称>",以便后续媒体使用的 resolve --entity 可以找到它们(实体命中可跨图像/图标匹配)。
在一次请求中批量处理多个节点——传递同一文件的多个引用(空格分隔或逗号连接):hyperframes figma asset 'KEY:1-2' 'KEY:3-4' 'KEY:5-6'。所有节点将在单个 /v1/images 调用中渲染,这是 Figma 应对每分钟速率限制的解决方案——在提取整个帧的资产时,优先于 N 个单独的命令。--description/--entity 适用于批处理中的每个节点,因此请将具有相同目的的节点分批处理。429 错误同样会自动以退避方式重试。
令牌(阶段 2 — CLI)
hyperframes figma tokens <fileKey>
将变量导入为合成品牌变量条目 + figma-tokens.json sidecar 文件 + 绑定索引记录 (.media/figma-bindings.jsonl)。变量在上游受企业版限制:在其他计划上,该命令会降级为已发布样式的元数据(值在组件导入时解析)。将打印的条目添加到合成中的 data-composition-variables。
当同时需要令牌和组件时,先导入令牌——这允许组件颜色链接到品牌变量而不是烘焙重复值。
非企业版变量路径(经过现场测试): REST 变量受企业版限制,但兼容的连接器可能提供变量定义。当 tokens 报告 REQUIRES_ENTERPRISE 且连接器可用时,检索父场景的变量一次,将原始响应缓存到 .media/figma-cache/,并使用它来构建绑定索引。REST 节点树的 boundVariables 提供每个属性的 VariableID;按节点和属性将它们连接,然后写入 .media/figma-bindings.jsonl 行({kind:"binding", figmaId, sourceFileKey, compositionVariableId: "figma:<name>", version})以及合成变量条目。其后的所有下游处理(组件 var() 解析、刷新、运行时 CSS 变量)都是已有的机制。向用户说明:“通过 Figma 连接器获取令牌——企业版计划可以直接通过 hyperframes figma tokens 获得。”
运行时将每个声明的合成变量定义为 CSS 自定义属性(文档根元素 + 子组合宿主),因此当变量默认值更改时,导入的 var(--slug, literal) 填充会重新着色——更新 data-composition-variables 中的一个值即可重新品牌化所有导入的组件,而无需重新导入任何内容。hyperframes render --variables '<json>' 可在渲染时覆盖它们。
组件(阶段 3 — CLI)
hyperframes figma component '<url-or-fileKey:nodeId>'
节点树 → 精确匹配 Figma 几何形状的可编辑 HTML,打包为 compositions/components/<name>/ 下的注册表项。矢量/布尔运算通过第一阶段导出自动栅格化。绑定传递(规格 §7.1,仅精确 ID——绝不做值匹配):
- 静态保真度自检(对于主要内容为强制要求): 导入后,渲染片段并与 Figma 本身的像素进行比较——
figma asset <same node> --format png是真实依据。文本是已知的偏差轴:比其行高短的 Figma 文本框具有垂直修剪的边界(映射器会为此类情况输出text-box-trim;如果没有它,测量的偏差在 70px 字体上约为 6px)。如果比较显示映射器未覆盖的偏差,请报告——不要静默地手动调整片段。 - 填充绑定到已导入的令牌 →
var(--slug, #literal)— 品牌刷新传播。 - 绑定到未知的令牌 → 字面量 +
data-figma-unresolved标志。命令会告诉你;向用户提供选项:在源文件(或库文件)上运行tokens,然后重新导入组件以链接它们。对于每个未知库,只问一次是哪个文件——永远不要猜测,也永远不要通过十六进制颜色值匹配。
动作(阶段 4 — 连接器辅助)
使用信标: 连接器辅助阶段没有 CLI 触点,因此在开始和结束时触发技能信标(匿名、需同意、绝不失败):开始时运行 npx hyperframes events --skill=figma-motion,结束时运行 npx hyperframes events --skill=figma-motion --event=skill_completed --outcome=success|error。对着色器(figma-shaders)和故事板(figma-storyboard)同样如此。
没有等效的 REST 端点。当兼容的连接器可用时,使用它并将其输出传递给 @hyperframes/core/figma 中的纯辅助函数;否则要求本地导出:
- 在一次递归请求中检索父帧的动作上下文,而不是每个元素一个请求。将原始 JSON 保存在项目旁边 (
.media/figma-cache/),以便重新翻译的成本为零。 - 使用
@hyperframes/core/figma中的motionContextToDocs(rawResponse, { selectorFor, repeat })将其标准化为MotionDoc——切勿手动转录关键帧编号。该辅助函数机械地编码了经过现场测试的解码规则:它解析 motion.dev 代码段(可靠的编码——CSS 代码段会延长持续时间且可能不一致;因此被忽略),剥离循环包裹的尾部关键帧(时间约等于 0.9999→1 的亚毫秒段是循环的即时重置,而非创作的动作——包裹由repeat重启实现),并逐字保留贝塞尔缓动函数。selectorFor必须返回来自阶段三组件导入的 ID——不要从节点名称派生选择器。 2b. 在宣布完成之前,必须对照真实情况进行验证:通过可用的连接器导出群组的根帧,并运行node <SKILL_DIR>/scripts/verify-motion.mjs --reference <export.mp4> --render <render.mp4> --crop WxH+X+Y——它比较运动能量增量(静态导入保真度会抵消),当最小动作 PSNR 低于 15dB 时判定为失败(校准:忠实 ≈ 20+,偏差 ≈ 5)。根据渲染实际卡片边缘测量--crop,不要猜测。失败意味着需要重新检查翻译,而不是调整阈值。 motionToGsap(doc)→emitTimelineScript(spec)→ 在 GSAP + CustomEase CDN 标签之后注入为<script>。默认暂停,有限次数,以字面键注册在window.__timelines上。- 无法翻译的轨道(着色器驱动、不支持的属性、复杂遮罩)→ 通过连接器导出,冻结为 MP4,然后嵌入为
<video class="clip">。例外: 着色器驱动的轨道——Figma 的导出路径会将着色器扁平化为基本颜色(见下方的着色器部分),因此在那里烘焙会静默地丢失着色器;请改为要求用户进行本机 Figma 导出。始终说明你使用了哪条路径以及原因。命名缓动函数在映射集之外时,会回退到线性缓动——映射表位于motionEase.ts中;当触发回退时向用户标记。 - 在宣布完成之前运行
npx hyperframes check。
着色器(阶段 5 — 主要是手动的)
Figma 的连接器渲染路径不执行着色器(它们会扁平化为基本颜色),并且着色器源代码仅对库已发布的样式(付费完整席位)可达。默认路径:要求用户在本机 Figma 中导出着色器帧(PNG 或动作 MP4),然后将其作为阶段一的资产/剪辑导入。不要尝试通过连接器像素捕获着色器——它会静默地产生错误结果。
故事板(场景帧的片段 → 动画)
首要规则:故事板帧是关键帧,而非幻灯片。 包含相同元素的两个帧描述了该元素随时间变化的状态——在状态之间动画化元素本身;切勿将帧作为静态图像序列播放。在四个连续帧中以递减 y 绘制的 Logo 是一个通过四个关键帧上升的单一元素。将故事板帧逐帧播放是失败模式;重建它们所隐含的元素时间线才是任务。
故事板文件遵循一种你可以机械解析的语法——不要靠肉眼判断,要解码:
- 场景单元:在片段内部,每个帧大小的节点都是一个场景——包括命名的 FRAME 和松散的、全帧的 RECTANGLE(设计师会将静态图像直接粘贴到片段中)。按尺寸筛选(≈ 合成宽高比,例如 >1400×900),而不是按节点类型或名称。
- 顺序 = x 位置(如果条带换行则为行优先)。按
absoluteBoundingBox.x对场景排序。 - 比较相邻帧:从前两个场景中完全相同的元素(相同的
nodeId或在场景之间具有相同name的 Font/Text/Image 图层)开始。对于每个元素,将其属性值(x、y、宽度、高度、旋转、填充、描边、文本内容、混合模式、不透明度)收集到状态向量中。何时通过名称匹配: 仅在元素是 Font/Text/Image 容器并且名称在所有场景中完全相同时才匹配name。对于所有其他类型或名称不匹配的情况,精确匹配nodeId。 关键点:如果同一nodeId出现在两个场景中,则它是同一个元素——即使名称不同。如果nodeId不存在/无法获取,则退化到仅使用name匹配 Font/Text/Image(名称模糊匹配,但分数低;在输出中说明此回退)。绝不通过视觉哈希或图标/形状的裁剪图像匹配。 - 构建时间线:
- 随时间变化的属性变为 GSAP 关键帧。
- 保持不变(或第一帧中不存在)的属性被省略。
- 分布关键帧的时间和缓动函数(默认均匀分布 + 默认缓动效果)。
- 输出精确的
MotionDoc数组(包括selectorFor给出的过渡对象选择器)。
- 回退:如果由于任何原因解码失败(少于 2 个场景、无匹配元素、解析错误),不要尝试通过构建 GSAP 循环来强制生成动画——提供简短的诊断并停止。好的结果看起来像 {reconstructed: true, timelineCount: N, elementCount: M} ——失败看起来像 {reconstructed: false, reason: ""}。从不说“帧是幻灯片”,因为那是由设计方法决定的。
叙事示例:
“找到 6 个故事板帧(从作品集页眉移动到脚注)。检测到 3 个品牌元素… 为页眉/页脚过渡重建了时间线。查看结果:在项目中运行 Composition Player。”