关于 figma-implement-motion
该技能指导编码 Agent 将 Figma 动画转换为可运行代码,面向在代码仓库中实现设计动效的开发者。它通过节点 ID 关联动画数据与设计结构,并覆盖代码合并和时间线协调。
主要功能
- 01获取动画节点、关键帧与代码片段
- 02按节点 ID 匹配设计结构
- 03合并动效与页面元素
- 04协调多节点时间线
- 05适配 CSS 与 motion.dev 输出
适用场景
- 01将 Figma 原型动画实现到项目代码
- 02为设计中的多个动画节点同步时间线
MCP 相关
该技能要求连接 Figma MCP 服务,并结合 get_motion_context 与 get_design_context 获取动画和结构信息。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ figma/ mcp-server-guide --skill figma-implement-motion安装后在 Claude Code 中输入/figma-implement-motion确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/examples-and-anti-examples.mdframework-recommendations.mdgotchas.mdmotion-lint-rules.mdsvg-and-path-motion.mdunsupported-and-fallbacks.md详细介绍
实现动效
概述
此技能指导如何将 Figma 动画和过渡效果转换为可运行的代码(motion.dev、CSS keyframes 或特定框架的库)。
Figma 通过两种工具提供动效信息:
get_motion_context— 权威的动效工具。返回完整的动画节点清单、预先生成的代码片段(CSS@keyframes和 motion.dev)、代码片段不可用时的备用关键帧绑定,以及递归时间线协调提示(timelineCohorts)。动画数据及哪些节点包含动画的唯一真实来源。get_design_context— 设计的结构:布局、尺寸、资源、样式、Code Connect 提示、截图上下文,以及有时会出现在动画元素上的动效放置标记(data-node-id;对于拆分节点,还包括data-motion-keys/data-motion-wrapper-for/data-motion-transform-template)。它可能会将动画节点呈现为普通元素(div、p、span等)或动效元素(motion.div);不会内联动画值。
两者通过节点 ID 关联,整个工作流就是如此。 get_motion_context 会告知哪些节点包含动画,并提供关键帧值、缓动、时序和代码片段。get_design_context 会告知这些节点的外观和位置。对于 get_motion_context.nodes 中的每个节点,在设计上下文中找到匹配的 data-node-id,并将动效合并到该结构中——如果结构元素是普通元素,就添加或包装为 motion.{tag}。当设计上下文重用了 Figma 组件时,动效节点也可能包含 fallbackNodeId;只有在尝试匹配准确的 nodeId 后,才将其用作备用方案。
技能范围
- 当交付内容是用户代码库中的动效代码时,使用此技能。
- 如果用户要求直接在 Figma 中创建或编辑动画,请切换到 figma-use,并改用该技能。
- 此技能目前涵盖
get_motion_context输出的动画(代码片段和备用关键帧轨道,包括解析为这些形式的预设动效)。更广泛的交互式变体流程可能仍需在代码中处理特定于产品的状态。
先决条件
- 已连接并可访问 Figma MCP 服务。
- 从用户提供的 Figma URL 中解析出节点 ID。URL 格式:
https://figma.com/design/:fileKey/:fileName?node-id=1-2— 提取fileKey(/design/后的部分)和nodeId(node-id查询参数的值,例如42-15)。 - 目标代码库。动效输出格式会根据技术栈调整(参见框架建议)。
工具选择
实现动效时,同时使用这两种工具,并为其分配不同职责:
| 情况 | 工具 | 原因 |
|---|---|---|
| 理解静态结构、资源、样式、Code Connect 或视觉布局 | get_design_context | 提供组件或页面代码参考以及所需资源 URL,帮助你正确放置动画节点。 |
| 获取任意节点的动画数据 | get_motion_context | 专为动效设计,是时序、缓动、代码片段和关键帧的唯一真实来源。 |
节点带有动效标记(data-motion-keys、data-motion-wrapper-for) | 用标记确定拆分后的放置位置,用 get_motion_context 获取值 | 拆分标记会指出每个元素应应用哪些轨道;关键帧、缓动、时序和动画节点清单来自 get_motion_context。 |
当你需要在一次调用中获取后代节点的动效时,get_motion_context 接受 recursive: true(最多 500 个节点)。
必需工作流
第 1 步:确认静态设计上下文可用
get_design_context(fileKey=":fileKey", nodeId="<node-id>")
如果已针对该节点调用过 get_design_context,则重用其输出。否则,现在按常规方式调用。
将其用作权威结构——层级、尺寸、样式、资源、Code Connect 提示、截图上下文,以及其中可能包含的任何动效放置标记(第 3 步)。动画节点清单和动画值来自 get_motion_context(第 2 步)。
步骤 2:获取权威运动数据
get_motion_context(fileKey=":fileKey", nodeId="<node-id>", recursive=true)
响应结构(每个动画节点对应一项):
codeSnippets— 预生成的 CSS@keyframes和 motion.dev 字符串。**请直接使用。**不要根据备用轨道数据重新生成。textAnimations— 始终实现这些文本组动画。如果同时存在codeSnippets,则两者都要应用;代码片段不能替代textAnimations。- 使用
derivedTimingInfo:每组从startMs + orderPosition * staggerStepMs开始,并播放groupDurationMs。startMs已包含delayMs;不要重复添加。presetDurationMs覆盖整个错开序列,而非每个组。 - 根据
grouping和order计算orderPosition,不要总是使用字符索引(CENTER_OUT会让对称的字符对同时开始)。在 Motion.dev 中将毫秒转换为秒,并使提供的缓动效果适配groupDurationMs,包括弹簧效果。
- 使用
keyframeBindings— 已绑定的关键帧轨道,包括解析为轨道数据的预设运动;仅当两种代码片段格式都缺失时,才将其作为备用数据。motionSummary— 对动画逐字段进行的单行自然语言描述。仅在没有代码片段时提供(即代码生成无法将仅含关键帧绑定的运动表示为 CSS/motion.dev)。如果存在,请据此构建;只要有代码片段,就忽略它。fallbackNodeId— 用于匹配组件化设计上下文的可选备用 ID。如果nodeId是I4005:6111;30:8005这样的实例限定 ID,D2R 可能改为使用其底层组件 ID(例如4002:3957)渲染可复用组件主体。在这种情况下,如果精确查找nodeId失败,请查找fallbackNodeId对应的data-node-id。
递归响应还会包含 timelineCohorts——共享同一时间线的节点的顶层数组(不按节点区分):{ rootNodeId, durationMs, loopMode: 'once' | 'loop' | 'boomerang', memberNodeIds[] }。对于协调的多节点运动,应使用 durationMs(秒数为其除以 1000)和 loopMode,通过同一个共享生命周期驱动所有 memberNodeIds——不要根据兄弟节点顺序推断时间。
对 LLM 而言,重要的实现细节:
- 存在代码片段时,可能会省略
motionSummary、timelineDurationMs和transformOrigin,以缩小载荷——代码片段已包含时长和变换原点(motion.dev 的duration/style={{ transformOrigin }},或 CSS 的animation/transform-origin),且协同组包含durationMs。字段缺失绝不表示“没有动画”。 - 递归响应会去重完全相同的代码片段。代码片段可能会被替换为注释,指向首个具有相同运动效果的节点;请复用相同的组件、变体、类或常量,不要重复编写动画。
- MCP 服务会根据
clientFrameworks判断代码片段使用 CSS 还是 motion.dev;如果响应只包含一种代码片段格式,请将该格式适配到用户的技术栈,而不要认为另一种格式生成失败。
步骤 3:合并静态上下文和运动上下文
- 从
get_motion_context.nodes开始,而不是从静态 JSX 中可见的motion.*标签开始。返回的每个节点都带有动画。 首先通过精确的nodeId/data-node-id,将每个 motion 节点与get_design_context中的节点匹配。只有在没有精确匹配时,才尝试fallbackNodeId/data-node-id。只有在这两个 ID 都无法匹配后,才根据节点名称/类型和截图中的位置进行回退匹配。 - 精确 ID 匹配优先于
fallbackNodeId。fallbackNodeId指向 D2R 可能在可复用组件内部输出的底层组件 ID。该 ID 由该组件的所有实例共享。如果设计上下文中存在精确的nodeId,就在该节点上应用动画,并忽略回退 ID。这对根实例动画至关重要:同一组件的不同实例可以以不同方式旋转或移动;如果把动画应用到共享组件主体上,就会错误地让所有实例都动起来。 - 将每个 motion 节点应用到以
data-node-id为键匹配的设计上下文结构上。 匹配到的data-node-id是结构锚点,但不一定是最终接收动画的 DOM 元素。根据片段形状和位置标记,判断动画应应用到该元素本身、包装元素、内部元素,还是内联 SVG 路径。get_design_context可能已经输出值被移除的motion.{tag},也可能输出普通结构元素(div、p、span、组件根节点等)。如果它是普通元素,且片段的目标就是该元素本身,则将其转换为相应的motion.{tag},或添加一个 motion 包装元素,同时保留节点的文本、子元素、类名/样式、属性和data-node-id。请加载 references/examples-and-anti-examples.md,查看此合并步骤的示例。 - 组件化子节点的动画通常通过回退 ID 匹配。 当设计上下文将 Figma 实例提取为可复用的 React 组件时,该组件主体内的子节点通常具有底层组件 ID(
4002:3957),而 motion 上下文报告的是实时实例 ID(I4005:6111;30:8005)。在这种情况下,使用fallbackNodeId查找组件主体的data-node-id,但要让动画限定在当前实现的渲染实例上。如果有多个实例,且只有一个实例的根节点动画不同,精确 ID 匹配会将该实例的动画单独处理。 - 拆分节点带有
data-motion-keys/data-motion-wrapper-for标记——请参阅下文的 处理交错变换。 - 保留
display: contents包装元素——除非该组本身带有动画。 布局透明的组包装元素会以contents(Tailwindcontents)形式输出,通常还带有无效的absolute/inset-[…](这些属性对contents盒子不起作用)。对于_静态_组,保留display: contents,让子元素相对于最近的真实祖先定位——将包装元素的inset转换为定位盒会让子元素改为相对于更小的盒子定位,导致其渲染得过小或向内偏移。对于_带动画的_组(组节点本身带有 motion),display: contents无法承载变换——将其替换为真实的定位包装元素,并在该元素上应用组动画。在实现这种情况前,请加载 references/gotchas.md。 get_motion_context是完整的动画节点清单。 某些带动画的节点会渲染为普通(非motion)元素——组件实例根节点(普通定位<div>)、文本(<p>)、蒙版——但仍带有data-node-id。遍历 motion 响应中的每个节点,并将其动画应用到具有匹配data-node-id的元素上;必要时进行包装或转换。如果某个带动画的节点在输出中完全没有对应元素(例如,带动画的蒙版被扁平化为静态mask-image),不要悄悄将其丢弃——添加// TODO: <nodeId> motion unsupported注释,并在摘要中说明。- 如果节点出现在 motion 上下文中,但没有出现在静态 JSX 中,请添加表示该节点所需的元素——设计上下文代码仅供参考,并不包含完整的动画节点清单。
- 如果设计上下文与 motion 上下文存在冲突(时间、缓动或动画值),优先采用
get_motion_context。 - SVG 路径级动画:内联 SVG,并为真实的
<path>添加动画。 当get_motion_context指向矢量图的路径(PATH_TRIM、motion.path、stroke-dasharray),但设计上下文将其渲染为<img>时,请内联 SVG,并将片段应用到<path>,同时保留布局包装元素。有关此情况的完整操作说明(motion.path、pathLength="1"、包装元素与路径分层、CSS 路径裁切),请加载 references/svg-and-path-motion.md。
处理交错变换
同时具有静态基础变换和动画变换的节点会拆分到嵌套元素中,以便两者正确组合,而不是相互冲突:一个带有 data-motion-wrapper-for="<nodeId>" 的无 id motion.div(外层包装元素)包裹一个静态变换 div(例如 rotate-45 + hypot() 尺寸设置——或者由包装元素本身携带 data-motion-transform-template="<css>"),再包裹内层节点(data-node-id)。请保留 包装元素 > 静态变换 div > 内层节点 的嵌套结构——将它们合并会破坏尺寸设置和基础变换。
- 根据
data-motion-keys放置动画轨道。 包装元素的data-motion-keys(变换轨道——x/y/rotate/scaleX/scaleY/skewX)应放在外层包装元素上;内层元素的data-motion-keys应放在内层元素上。 - 重新应用
data-motion-transform-template。 如果包装元素携带该属性,请设置transformTemplate={(_, generated) => "<css> " + generated},使动画变换叠加在静态布局变换之上。 - 按静态基础变换调整动画变换(避免重复旋转)。
get_motion_context提供的是节点的_绝对_变换,其中已经包含这些 div 应用的静态基础变换。对于rotate-45基础变换上的[45, 125, 125]rotate片段,包装元素应动画化偏移量[0, 80, 80](= 绝对值 − 45),而不是绝对值——否则 45° 会应用两次,元素静止时会处于 90°。没有静态基础变换的轨道(例如从 0 开始的x/y)可原样传递。请参阅交错变换示例。 - 将布局变换与 Motion 变换分开。 对于每个动画化
rotate、scale或skew的motion.*元素,请确认它没有同时依赖-translate-x-1/2或-translate-y-1/2等 Tailwind 布局变换来实现居中或定位。这些实用类与 Motion.dev 写入行内样式的变换共用 CSStransform属性,因此 Motion 的变换可能会覆盖布局平移。如果两者都需要,请将元素拆分为静态布局包装元素(携带居中或定位变换)和内层motion.*元素(携带动画旋转/缩放/不透明度);或者在 Motion 本身中编码布局偏移(x: "-50%"),并确保每个关键帧都包含该偏移。
步骤 4:在代码中应用动画
- 片段中是否包含 motion.dev? 对于 React 目标,原样使用 motion.dev 代码。从
motion/react导入——除非代码库已经使用其他动画库(Framer Motion、React Spring、GSAP),此时应改用该库适配片段。适配到其他技术栈或选择库时,请加载 references/framework-recommendations.md。 - 是否包含 CSS 关键帧? 用于原生/非 React 目标,或代码库没有 React 动画库的情况。
- 没有片段(仅有 keyframe-bindings)? 根据
keyframeBindings+motionSummary构建等效的 motion.dev/CSS 动画,循环时间取自同一组动画的durationMs/loopMode,并读取结构化字段中的transformOrigin/ duration。这种情况较少见——通常会提供片段,包括针对 SwiftUI/iOS 的片段(它们使用 CSS 格式)。
步骤 5:验证
- 添加新的导入前,先检查组件现有的动画导入和惯例。如果用户已经使用 Framer Motion / React Spring / anime.js,应进行适配,而不是强行改用 motion.dev。
- 批量修改许多节点前,先抽查一个动画是否能端到端运行(重新加载、观察、迭代)。
- 加载 references/gotchas.md,其中介绍了 Figma 动画输出中发现的具体错误和边缘情况,并在生成的代码中修正这些问题。
关键规则
这些是通用原则。具体注意事项(旋转枢轴、HOLD 语义、颜色插值等)见分类后的参考资料。当此技能文本提到某个链接参考资料,且适用当前情况时,请先加载该文件再继续。
- 遵循工具输出的数值,而不是其布局。 保留
codeSnippets中的精确时序、缓动、关键帧数值和transformOrigin——存在代码片段时,不要根据keyframeBindings或结构化字段重新生成这些内容(重新生成会丢失自定义贝塞尔缓动、弹簧近似和过冲值的精度)。transformOrigin按元素分别设置:应用每个缩放/旋转节点自身的值——包括嵌套缩放节点,而不仅是外层包装节点——否则元素会以默认中心为枢轴,从错误的角落开始放大/旋转(参见按元素设置transformOrigin的示例)。但代码片段是单个节点的数据,不是可直接复制粘贴的模板:多个节点共用代码片段时,按规则 7 将其提取复用,而不是粘贴 N 次该代码块。 - 匹配用户现有的动效技术栈。 添加依赖前,先阅读组件的导入项和同级动画。如果用户已经使用 Framer Motion、React Spring、anime.js 或 GSAP,就根据其技术栈调整输出,而不是强行使用 motion.dev。
- 遵循
prefers-reduced-motion。 添加的任何动效都必须在@media (prefers-reduced-motion: reduce)下减弱或禁用——通常跳过animate(渲染初始/静止状态),或将时长缩短至接近零。这是无障碍方面的默认要求,不是可选项。 - 批量处理前,先端到端验证一个动画。 构建、重新加载,并观察完整的时间轴循环——确认每个动画节点都在其关键帧轨道指定的时间出现。“渲染时没有报错”不等于“渲染正确”。批量处理会放大动效问题——一个节点的缓动错误很容易发现;同一个错误出现在 20 个节点上,则可能要花数小时排查。
- 不要编造动效。 如果响应中某个节点没有动效数据,就让它保持静止。不要借用设计中其他地方的缓动/时长默认值,也不要因为组件其余部分有动画就自动为它添加动画。
- 下载资源并引用本地文件。
get_design_context/get_motion_context会返回有时效限制的资源 URL(/api/mcp/asset/...),通常是 SVG。使用curl -L将每个资源下载到项目中,并引用下载后的文件,或内联其内容(例如内联 SVG,并在 SwiftUI 中通过NSImage(data:)渲染)。不要在应用代码中引用临时资源 URL。对于 SVG 路径级动效,应内联 SVG 并直接为实际路径添加动画,而不是将其留在<img>后面。不要将下载的 SVG 文件作为图像传给Read工具:SVG 不是受支持的图像格式,读取可能失败或卡住。 - 提取重复动效以便复用——切勿为每个元素复制粘贴代码片段。 许多节点通常共用同一动画,只在延迟、偏移或目标值上有所不同。将共用动效只实现一次——创建可复用的动画组件,或使用按变化值参数化的
variants对象——通过映射数组(items.map(...))进行渲染,并将重复的字面值(时长、缓动数组、偏移量)提取为具名常量。动画的数值必须与代码片段完全一致(规则 1);代码则应保持 DRY。将同一个 transition 对象粘贴 15 次以上(本可精简为 150 行,却写成 800 行)属于低质量结果——精确度和可维护性都会纳入评估。
框架建议
规则 2 涵盖一般原则:优先使用用户现有的技术栈。若没有,则采用以下默认方案:
- React:motion.dev(
motion包)。工具会直接返回 motion.dev 代码,请直接使用。 - Vanilla / 非 React Web:CSS
@keyframes和animation简写,由工具直接返回。 - SwiftUI:原生
.animation(...)修饰符,由 CSS 代码片段转换而来(get_motion_context不会生成 SwiftUI 代码,但 SwiftUI/iOS 客户端仍会获得 CSS 格式;只有在没有代码片段时,才回退到keyframeBindings/motionSummary/ cohort)。仅使用真正的 SwiftUI API——没有任何修饰符可以直接接收 Figma/CSS 缓动参数,因此请加载 references/framework-recommendations.md,将缓动映射为对应的 SwiftUI 写法,并进行验证,不要凭空编造。这条路径仍在发展中;如有疑问,请与用户确认。
对于成熟的效果类别,优先使用库,而不是手写 CSS。 玻璃效果/玻璃拟态、彩纸效果、粒子系统、基于物理的交互以及滚动联动动效等效果,都有经过实战检验的库实现,它们处理跨浏览器差异、无障碍和性能问题的能力远胜于生成的关键帧。加载 references/framework-recommendations.md,查看完整的按效果类别划分的库表。将这些作为建议提出,而不是强制要求——由用户决定。
示例
需要实际示例或失败模式时,请加载 references/examples-and-anti-examples.md。其中涵盖简单的合并流程、需要添加 motion.* 的纯文本元素、交错的静态与动画变换、SVG 路径级动效,以及有关重建 DOM、节点 ID/位置漂移和缺少逐元素 transformOrigin 的反面示例。
参考资料
六篇深度解析,按需获取。一般性的前端问题(性能、单位、无障碍机制)已由上述关键规则处理——这些参考资料仅聚焦于 Figma 特有的信息。如果此技能在内联指令中提到其中某个文件,请先加载该文件,再继续处理任务的相应部分。
- references/examples-and-anti-examples.md — 完整示例与失败模式。在应用合并工作流、处理交错变换,或检查生成的实现是否重建了 DOM、调换了节点位置或丢弃了
transformOrigin时加载。 - references/gotchas.md — Figma 特有的动画问题及其修复方法。嵌套组上的旋转/缩放原点、HOLD 缓动语义、CUSTOM_SPRING 保留、独立轴缩放的歧义、颜色插值。排查意外的运行时行为时加载。始终同时加载 references/motion-lint-rules.md——问题条目会引用必须告知用户的具体 lint 规则。
- references/svg-and-path-motion.md — 实现针对 SVG 矢量路径的动画(内联资源、
motion.path、pathLength="1"、包装器与路径分层、CSS 路径裁剪)。当矢量片段针对的是路径而非包装器变换时加载。 - references/framework-recommendations.md — motion.dev、CSS 关键帧、SwiftUI 默认值,以及按效果类别划分的库表(玻璃、彩纸、粒子、物理效果、滚动联动)。手动实现效果前加载。
- references/unsupported-and-fallbacks.md — 当前无法从 Figma 干净导出的动画功能(文本动画、路径动画、蒙版/布尔运算、变体/过渡)。包含视频/lottie 回退方案指导。工具响应似乎不完整时加载。始终同时加载 references/motion-lint-rules.md——不支持功能条目会引用必须告知用户的具体 lint 规则。
- references/motion-lint-rules.md — lint 规则:已知导出限制(错误和警告),必须告知用户。生成动画代码时加载,以检查是否存在适用的限制。