mcpField
F
figma-implement-motion

figma-implement-motion

github.com/figma设计与 UI2.1k1.3k 次安装今天更新
代码仓库

关于 figma-implement-motion

该技能指导编码 Agent 将 Figma 动画转换为可运行代码,面向在代码仓库中实现设计动效的开发者。它通过节点 ID 关联动画数据与设计结构,并覆盖代码合并和时间线协调。

主要功能

  1. 01获取动画节点、关键帧与代码片段
  2. 02按节点 ID 匹配设计结构
  3. 03合并动效与页面元素
  4. 04协调多节点时间线
  5. 05适配 CSS 与 motion.dev 输出

适用场景

  1. 01将 Figma 原型动画实现到项目代码
  2. 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.md
framework-recommendations.md
gotchas.md
motion-lint-rules.md
svg-and-path-motion.md
unsupported-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(Tailwind contents)形式输出,通常还带有无效的 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 写入行内样式的变换共用 CSS transform 属性,因此 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 语义、颜色插值等)见分类后的参考资料。当此技能文本提到某个链接参考资料,且适用当前情况时,请先加载该文件再继续。

  1. 遵循工具输出的数值,而不是其布局。 保留 codeSnippets 中的精确时序、缓动、关键帧数值和 transformOrigin——存在代码片段时,不要根据 keyframeBindings 或结构化字段重新生成这些内容(重新生成会丢失自定义贝塞尔缓动、弹簧近似和过冲值的精度)。transformOrigin 按元素分别设置:应用每个缩放/旋转节点自身的值——包括嵌套缩放节点,而不仅是外层包装节点——否则元素会以默认中心为枢轴,从错误的角落开始放大/旋转(参见按元素设置 transformOrigin 的示例)。但代码片段是单个节点的数据,不是可直接复制粘贴的模板:多个节点共用代码片段时,按规则 7 将其提取复用,而不是粘贴 N 次该代码块。
  2. 匹配用户现有的动效技术栈。 添加依赖前,先阅读组件的导入项和同级动画。如果用户已经使用 Framer Motion、React Spring、anime.js 或 GSAP,就根据其技术栈调整输出,而不是强行使用 motion.dev。
  3. 遵循 prefers-reduced-motion。 添加的任何动效都必须在 @media (prefers-reduced-motion: reduce) 下减弱或禁用——通常跳过 animate(渲染初始/静止状态),或将时长缩短至接近零。这是无障碍方面的默认要求,不是可选项。
  4. 批量处理前,先端到端验证一个动画。 构建、重新加载,并观察完整的时间轴循环——确认每个动画节点都在其关键帧轨道指定的时间出现。“渲染时没有报错”不等于“渲染正确”。批量处理会放大动效问题——一个节点的缓动错误很容易发现;同一个错误出现在 20 个节点上,则可能要花数小时排查。
  5. 不要编造动效。 如果响应中某个节点没有动效数据,就让它保持静止。不要借用设计中其他地方的缓动/时长默认值,也不要因为组件其余部分有动画就自动为它添加动画。
  6. 下载资源并引用本地文件。 get_design_context/get_motion_context 会返回有时效限制的资源 URL(/api/mcp/asset/...),通常是 SVG。使用 curl -L 将每个资源下载到项目中,并引用下载后的文件,或内联其内容(例如内联 SVG,并在 SwiftUI 中通过 NSImage(data:) 渲染)。不要在应用代码中引用临时资源 URL。对于 SVG 路径级动效,应内联 SVG 并直接为实际路径添加动画,而不是将其留在 <img> 后面。不要将下载的 SVG 文件作为图像传给 Read 工具:SVG 不是受支持的图像格式,读取可能失败或卡住。
  7. 提取重复动效以便复用——切勿为每个元素复制粘贴代码片段。 许多节点通常共用同一动画,只在延迟、偏移或目标值上有所不同。将共用动效只实现一次——创建可复用的动画组件,或使用按变化值参数化的 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 规则:已知导出限制(错误和警告),必须告知用户。生成动画代码时加载,以检查是否存在适用的限制。

评论

支持 Markdown