figma-implement-motion

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Implement Motion

实现动效

Overview

概述

This skill guides translation of Figma animations and transitions into runnable code (motion.dev, CSS keyframes, or framework-specific libraries).
Figma exposes motion through two tools:
  • get_motion_context
    — authoritative motion tool. Returns the complete animated-node inventory, precomputed code snippets (CSS
    @keyframes
    + motion.dev), fallback keyframe bindings when snippets are unavailable, and recursive timeline coordination hints (
    timelineCohorts
    ). Source of truth for animation data and which node IDs animate.
  • get_design_context
    — the design's structure: layout, sizing, assets, styling, Code Connect hints, screenshot context, and sometimes motion placement markers on animated elements (
    data-node-id
    , and on split nodes
    data-motion-keys
    /
    data-motion-wrapper-for
    /
    data-motion-transform-template
    ). It may render an animated node as a plain element (
    div
    ,
    p
    ,
    span
    , etc.) or a motion element (
    motion.div
    ); it does not inline the animation values.
The two are linked by node id, and that's the whole workflow.
get_motion_context
tells you which nodes animate and gives the keyframe values, easing, timing, and snippets.
get_design_context
tells you what those nodes look like and where they sit. For every node in
get_motion_context.nodes
, find the matching
data-node-id
in design context and merge the motion into that structure — adding or wrapping a
motion.{tag}
when the structural element is plain. When design context has reused a Figma component, the motion node may also include
fallbackNodeId
; use it only as a fallback after trying the exact
nodeId
.
本技能指导将Figma动画与过渡效果转换为可运行代码(motion.dev、CSS关键帧或框架专属库)。
Figma通过两个工具暴露动效信息:
  • get_motion_context
    —— 权威动效工具。返回完整的动画节点清单、预计算的代码片段(CSS
    @keyframes
    + motion.dev)、代码片段不可用时的备选关键帧绑定,以及递归时间线协调提示(
    timelineCohorts
    )。是动画数据及哪些节点ID包含动画的唯一可信来源
  • 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
失败后才使用它作为备选。

Skill Boundaries

技能边界

  • Use this skill when the deliverable is motion code in the user's repository.
  • If the user asks to create/edit animations inside Figma itself, switch to figma-use and follow that skill instead.
  • This skill currently covers animations as emitted by
    get_motion_context
    (snippets plus fallback keyframe tracks, including preset-authored motion resolved into those forms). Broader interactive variant flows may still need product-specific state handling in code.
  • 当交付物为用户仓库中的动效代码时,使用本技能。
  • 如果用户要求在Figma内部创建/编辑动画,请切换至figma-use并遵循该技能的指引。
  • 本技能目前涵盖
    get_motion_context
    输出的动画(代码片段加备选关键帧轨道,包括已解析为这些形式的预设动效)。更广泛的交互式变体流程可能仍需要代码中添加产品特定的状态处理。

Prerequisites

前置条件

  • Figma MCP server connected and accessible.
  • Node ID parsed from the Figma URL the user provides. URL format:
    https://figma.com/design/:fileKey/:fileName?node-id=1-2
    — extract
    fileKey
    (the segment after
    /design/
    ) and
    nodeId
    (the value of the
    node-id
    query parameter, e.g.
    42-15
    ).
  • Target codebase. Motion output format adapts to stack (see Framework Recommendations).
  • Figma MCP服务器已连接且可访问。
  • 已从用户提供的Figma URL中解析出节点ID。URL格式:
    https://figma.com/design/:fileKey/:fileName?node-id=1-2
    —— 提取
    fileKey
    /design/
    后的片段)和
    nodeId
    node-id
    查询参数的值,例如
    42-15
    )。
  • 目标代码库。动效输出格式会适配技术栈(参见框架推荐)。

Tool Choice

工具选择

For motion implementation, use both tools with distinct roles:
SituationToolWhy
Understanding static structure, assets, styles, Code Connect, or visual layout
get_design_context
Gives the component/page code reference and asset URLs you need to place animated nodes correctly.
Fetching animation data for any node
get_motion_context
Purpose-built for motion and the source of truth for timing, easing, snippets, and keyframes.
A node has motion markers (
data-motion-keys
,
data-motion-wrapper-for
)
Markers for split placement,
get_motion_context
for values
Split markers tell you which tracks go on which element; the keyframes/easing/timing and animated-node inventory come from
get_motion_context
.
get_motion_context
accepts
recursive: true
(capped at 500 nodes) when you need descendants' motion in one call.
对于动效实现,需结合使用两个工具,各自承担不同角色:
场景工具原因
了解静态结构、资源、样式、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个节点)。

Required Workflow

必选工作流

Step 1: Confirm static design context is available

步骤1:确认静态设计上下文可用

get_design_context(fileKey=":fileKey", nodeId="<node-id>")
If
get_design_context
has already been called for this node, reuse that output. If not, call it normally now.
Use it as the structure of record — hierarchy, sizing, styling, assets, Code Connect hints, screenshot context, and any motion placement markers it happens to include (Step 3). The animated-node inventory and animation values come from
get_motion_context
(Step 2).
get_design_context(fileKey=":fileKey", nodeId="<node-id>")
如果已针对该节点调用过
get_design_context
,则复用其输出。否则,立即正常调用。
将其作为记录结构——层级、尺寸、样式、资源、Code Connect提示、截图上下文,以及可能包含的任何动效放置标记(步骤3)。动画节点清单和动画值来自
get_motion_context
(步骤2)。

Step 2: Fetch authoritative motion data

步骤2:获取权威动效数据

get_motion_context(fileKey=":fileKey", nodeId="<node-id>", recursive=true)
Response shape (one entry per animated node):
  • codeSnippets
    — pre-generated CSS
    @keyframes
    and motion.dev strings. Use these directly. Do not regenerate them from fallback track data.
  • keyframeBindings
    — bound keyframe tracks, including preset-derived motion resolved into track data, included only as fallback data when both snippet formats are missing.
  • motionSummary
    — one-line-per-field natural-language description of the animation. Present only when there's no snippet (keyframe-bindings-only motion codegen couldn't express as CSS/motion.dev). Build from it when present; ignore it whenever a snippet exists.
  • fallbackNodeId
    — optional fallback id for matching componentized design context. If
    nodeId
    is an instance-qualified id such as
    I4005:6111;30:8005
    , D2R may render the reusable component body with the backing component id instead, such as
    4002:3957
    . In that case,
    fallbackNodeId
    is the
    data-node-id
    to look for if exact
    nodeId
    lookup fails.
Recursive responses also include
timelineCohorts
— a top-level array (not per-node) of nodes sharing one timeline:
{ rootNodeId, durationMs, loopMode: 'once' | 'loop' | 'boomerang', memberNodeIds[] }
. For coordinated multi-node motion, drive all
memberNodeIds
from one shared lifecycle using
durationMs
(÷1000 for seconds) and
loopMode
— don't infer timing from sibling order.
Implementation details that matter for LLMs:
  • When a snippet exists,
    motionSummary
    ,
    timelineDurationMs
    , and
    transformOrigin
    may be omitted to shrink the payload — the snippet already carries duration + transform-origin (motion.dev
    duration
    /
    style={{ transformOrigin }}
    , or CSS
    animation
    /
    transform-origin
    ) and the cohort carries
    durationMs
    . A missing field never means "no animation."
  • Recursive responses dedupe exact duplicate snippets. A snippet may be replaced with a comment pointing to the first node with identical motion; reuse the same component, variant, class, or constants instead of writing a second animation.
  • The MCP server infers CSS vs motion.dev snippets from
    clientFrameworks
    ; if the response only contains one snippet format, adapt that format to the user's stack rather than assuming the other format failed.
get_motion_context(fileKey=":fileKey", nodeId="<node-id>", recursive=true)
响应结构(每个动画节点对应一个条目):
  • codeSnippets
    —— 预生成的CSS
    @keyframes
    和motion.dev字符串。直接使用这些内容,不要从备选轨道数据重新生成。
  • keyframeBindings
    —— 绑定的关键帧轨道,包括已解析为轨道数据的预设动效,仅在两种代码片段格式均缺失时作为备选数据提供。
  • motionSummary
    —— 每个字段的单行自然语言动画描述。仅在无代码片段时呈现(仅含关键帧绑定的动效代码生成无法转换为CSS/motion.dev格式)。当存在时基于此构建;只要有代码片段存在,就忽略它。
  • fallbackNodeId
    —— 可选的备选ID,用于匹配组件化设计上下文。如果
    nodeId
    是实例限定ID(例如
    I4005:6111;30:8005
    ),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 vs motion.dev代码片段;如果响应仅包含一种代码片段格式,请适配该格式到用户的技术栈,而非假设另一种格式生成失败。

Step 3: Merge static and motion context

步骤3:合并静态与动效上下文

  • Start from
    get_motion_context.nodes
    , not from visible
    motion.*
    tags in the static JSX. Every returned node is animated. Match each motion node back to
    get_design_context
    by exact
    nodeId
    /
    data-node-id
    first. If and only if there is no exact match, try
    fallbackNodeId
    /
    data-node-id
    . Fall back to node name/type and screenshot position only after both ids fail.
  • Exact id match wins over
    fallbackNodeId
    .
    fallbackNodeId
    points at the backing component id that D2R may emit inside a reusable component. It is shared by every instance of that component. If the exact
    nodeId
    exists in design context, apply motion there and ignore the fallback. This is critical for root-instance animation: one instance can rotate or move differently from another instance of the same component, and applying that motion to the shared component body would animate all instances incorrectly.
  • Apply each motion node to the matching design-context structure, keyed by
    data-node-id
    .
    The matching
    data-node-id
    is the structural anchor, not always the final DOM element that receives motion. Use the snippet shape and placement markers to decide whether motion goes on that exact element, a wrapper, an inner element, or an inlined SVG path.
    get_design_context
    may already emit
    motion.{tag}
    with values stripped, or it may emit a plain structural element (
    div
    ,
    p
    ,
    span
    , component root, etc.). If it is plain and the snippet targets the element itself, convert it to the appropriate
    motion.{tag}
    or add a motion wrapper while preserving the node's text, children, classes/styles, attributes, and
    data-node-id
    . Load references/examples-and-anti-examples.md to see examples of this merging step.
  • Componentized child motion usually matches by fallback. When design context extracts a Figma instance into a reusable React component, children inside that component body often have backing component ids (
    4002:3957
    ) while motion context reports live instance ids (
    I4005:6111;30:8005
    ). In this case, use
    fallbackNodeId
    to find the component-body
    data-node-id
    , but keep the motion scoped to the rendered instance you are implementing. If there are multiple instances and only one has different root motion, exact id matching keeps that per-instance motion separate.
  • Split nodes carry a
    data-motion-keys
    /
    data-motion-wrapper-for
    marker — see Handling interleaved transforms below.
  • Preserve
    display: contents
    wrappers — unless the group itself animates.
    Layout-transparent group wrappers come through as
    contents
    (Tailwind
    contents
    ), usually alongside a dead
    absolute
    /
    inset-[…]
    (those do nothing on a
    contents
    box). For a static group, keep
    display: contents
    and let the children position against the nearest real ancestor — converting the wrapper's
    inset
    into a positioned box reparents the children to a smaller box, so they render too small / shifted inward. For an animated group (the group node itself has motion),
    display: contents
    can't carry a transform — replace it with a real positioned wrapper and apply the group motion there. Load references/gotchas.md before implementing this case.
  • get_motion_context
    is the complete animated-node inventory.
    Some animated nodes render as plain (non-
    motion
    ) elements — component instance roots (plain positioning
    <div>
    ), text (
    <p>
    ), masks — that still carry a
    data-node-id
    . Walk every node in the motion response and apply its motion to the element with the matching
    data-node-id
    , wrapping or converting as needed. If an animated node has no element at all in the output (e.g. an animated mask flattened into a static
    mask-image
    ), don't drop it silently — leave a
    // TODO: <nodeId> motion unsupported
    comment and call it out in your summary.
  • If a node appears in motion context but not in the static JSX, add the element needed to represent it — design-context code is a reference, not a complete animation inventory.
  • On conflict between design and motion context (timing/easing/animated values), prefer
    get_motion_context
    .
  • Path-level SVG motion: inline the SVG and animate the real
    <path>
    .
    When
    get_motion_context
    targets a vector's path (
    PATH_TRIM
    ,
    motion.path
    ,
    stroke-dasharray
    ) but design context renders it as an
    <img>
    , inline the SVG and apply the snippet to the
    <path>
    , keeping the layout wrapper. Load references/svg-and-path-motion.md for the full how-to for this case (motion.path,
    pathLength="1"
    , wrapper+path layering, CSS path-trim).
  • get_motion_context.nodes
    开始,而非静态JSX中可见的
    motion.*
    标签。返回的每个节点都是动画节点。首先通过精确
    nodeId
    /
    data-node-id
    将每个动效节点与
    get_design_context
    匹配。仅当没有精确匹配时,才尝试
    fallbackNodeId
    /
    data-node-id
    。仅当两个ID都匹配失败时,才退回到节点名称/类型和截图位置。
  • 精确ID匹配优先于
    fallbackNodeId
    fallbackNodeId
    指向D2R可能在可复用组件内部输出的基础组件ID。它由该组件的每个实例共享。如果设计上下文中存在精确
    nodeId
    ,则在该位置应用动效并忽略备选ID。这对于根实例动画至关重要:一个实例的旋转或移动方式可能与同一组件的另一个实例不同,将动效应用于共享组件主体会导致所有实例动画错误。
  • 将每个动效节点应用于匹配的设计上下文结构,以
    data-node-id
    为键
    。匹配的
    data-node-id
    是结构锚点,并非总是接收动效的最终DOM元素。使用代码片段结构和放置标记决定动效是应用于该精确元素、包装器、内部元素还是内联SVG路径。
    get_design_context
    可能已输出剥离值的
    motion.{tag}
    ,或输出普通结构元素(
    div
    p
    span
    、组件根等)。如果是普通元素且代码片段目标是元素本身,则将其转换为相应的
    motion.{tag}
    或添加动效包装器,同时保留节点的文本、子元素、类/样式、属性和
    data-node-id
    。加载references/examples-and-anti-examples.md查看此合并步骤的示例。
  • 组件化子节点动效通常通过备选ID匹配。当设计上下文将Figma实例提取为可复用React组件时,该组件主体内的子节点通常具有基础组件ID(
    4002:3957
    ),而动效上下文报告的是实时实例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
    转换为定位盒子会将子元素重新父级到更小的盒子,导致它们渲染过小/向内偏移。对于动画组(组节点本身包含动效),
    display: contents
    无法承载变换——将其替换为真实的定位包装器并在此处应用组动效。实现此案例前,请加载references/gotchas.md
  • get_motion_context
    是完整的动画节点清单
    。某些动画节点渲染为普通(非
    motion
    )元素——组件实例根(普通定位
    <div>
    )、文本(
    <p>
    )、遮罩——但仍带有
    data-node-id
    。遍历动效响应中的每个节点,将其动效应用于具有匹配
    data-node-id
    的元素,按需包装或转换。如果动画节点在输出中完全没有对应元素(例如,动画遮罩被扁平化为静态
    mask-image
    ),不要静默丢弃——留下
    // TODO: <nodeId> motion unsupported
    注释并在总结中指出。
  • 如果动效上下文中存在某个节点但静态JSX中没有,则添加表示该节点所需的元素——设计上下文代码是参考,而非完整的动画清单。
  • 当设计上下文与动效上下文存在冲突(时长/缓动/动画值)时,优先使用
    get_motion_context
  • 路径级SVG动效:内联SVG并动画真实
    <path>
    。当
    get_motion_context
    针对矢量路径(
    PATH_TRIM
    motion.path
    stroke-dasharray
    )但设计上下文将其渲染为
    <img>
    时,内联SVG并将代码片段应用于
    <path>
    ,同时保留布局包装器。加载references/svg-and-path-motion.md查看此案例的完整操作指南(motion.path、
    pathLength="1"
    、包装器+路径分层、CSS路径修剪)。

Handling interleaved transforms

处理交错变换

A node with both a static base transform and animated transforms is split across nested elements so the two compose correctly instead of fighting: an id-less
motion.div
carrying
data-motion-wrapper-for="<nodeId>"
(the OUTER wrapper) wraps a static-transform div (e.g.
rotate-45
+
hypot()
sizing — or the wrapper itself carries
data-motion-transform-template="<css>"
) which wraps the INNER node (
data-node-id
). Keep the
wrapper > static-transform div > inner
nesting — collapsing it breaks sizing and the base transform.
  • Place tracks by
    data-motion-keys
    .
    The wrapper's
    data-motion-keys
    (transform tracks —
    x
    /
    y
    /
    rotate
    /
    scaleX
    /
    scaleY
    /
    skewX
    ) go on the OUTER wrapper; the inner element's
    data-motion-keys
    go on the INNER element.
  • Re-apply a
    data-motion-transform-template
    .
    If the wrapper carries one, set
    transformTemplate={(_, generated) => "<css> " + generated}
    so the animated transform composes on top of that static layout transform.
  • Offset the animated transform by the static base (avoid double rotation).
    get_motion_context
    gives the node's absolute transform, which already includes whatever static base those divs apply. A
    rotate
    snippet of
    [45, 125, 125]
    over a
    rotate-45
    base means the wrapper animates the offset
    [0, 80, 80]
    (= absolute − 45), not the absolute — else the 45° applies twice and the element sits at 90° at rest. Tracks with no static base (e.g.
    x
    /
    y
    starting at 0) pass through unchanged. See the interleaved-transform example.
  • Keep layout transforms separate from Motion transforms. For every
    motion.*
    element that animates
    rotate
    ,
    scale
    , or
    skew
    , verify it does not also rely on Tailwind layout transforms such as
    -translate-x-1/2
    or
    -translate-y-1/2
    for centering/positioning. Those utilities share the CSS
    transform
    property that Motion.dev writes inline, so Motion's transform can erase the layout translate. If both are needed, split the element into a static layout wrapper carrying the centering/positioning transform and an inner
    motion.*
    element carrying animated rotate/scale/opacity, or encode the layout offset in Motion itself (
    x: "-50%"
    ) and keep it present for every keyframe.
同时包含静态基础变换和动画变换的节点会拆分为嵌套元素,以便两者正确组合而非冲突:一个无ID的
motion.div
带有
data-motion-wrapper-for="<nodeId>"
(外部包装器),包裹带有静态变换的div(例如
rotate-45
+
hypot()
尺寸——或包装器本身带有
data-motion-transform-template="<css>"
),后者再包裹内部节点(
data-node-id
)。保持
wrapper > static-transform div > inner
的嵌套结构——折叠会破坏尺寸和基础变换。
  • 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, 125, 125]
    且基础为
    rotate-45
    ,则包装器应动画偏移值
    [0, 80, 80]
    (=绝对−45),而非绝对值——否则45°会应用两次,元素静止时会处于90°。无静态基础的轨道(例如
    x
    /
    y
    从0开始)保持不变。参见交错变换示例。
  • 将布局变换与Motion变换分开。对于每个动画
    rotate
    scale
    skew
    motion.*
    元素,验证它是否还依赖Tailwind布局变换(例如
    -translate-x-1/2
    -translate-y-1/2
    )进行居中/定位。这些工具与Motion.dev内联写入的CSS
    transform
    属性共享,因此Motion的变换会覆盖布局平移。如果两者都需要,将元素拆分为带有居中/定位变换的静态布局包装器,以及带有动画旋转/缩放/透明度的内部
    motion.*
    元素,或者在Motion中编码布局偏移(
    x: "-50%"
    )并确保每个关键帧都存在该偏移。

Step 4: Apply the motion in code

步骤4:在代码中应用动效

  • motion.dev present in snippets? Use the motion.dev code verbatim for React targets. Import from
    motion/react
    — unless the codebase already uses another motion library (Framer Motion, React Spring, GSAP), in which case adapt the snippet to it. Load references/framework-recommendations.md when adapting to another stack or choosing a library.
  • CSS keyframes present? Use for vanilla/non-React targets, or when the codebase has no React motion library.
  • No snippets (keyframe-bindings-only)? Build equivalent motion.dev/CSS from
    keyframeBindings
    +
    motionSummary
    , taking loop timing from the cohort's
    durationMs
    /
    loopMode
    and reading
    transformOrigin
    / duration from the structured fields. Rare — snippets are normally present, including for SwiftUI/iOS (which get the CSS format).
  • 代码片段中包含motion.dev? 对于React目标,直接使用motion.dev代码。从
    motion/react
    导入——除非代码库已使用其他动效库(Framer Motion、React Spring、GSAP),此时需将代码片段适配为该库的格式。适配到其他技术栈或选择库时,请加载references/framework-recommendations.md
  • 包含CSS关键帧? 用于原生/非React目标,或代码库无React动效库时。
  • 无代码片段(仅含关键帧绑定)?
    keyframeBindings
    +
    motionSummary
    构建等效的motion.dev/CSS代码,从时间线组的
    durationMs
    /
    loopMode
    获取循环时长,并从结构化字段读取
    transformOrigin
    / 时长。这种情况很少见——通常会有代码片段,包括SwiftUI/iOS(获取CSS格式)。

Step 5: Validate

步骤5:验证

  • Read the component's existing motion imports/conventions before adding new ones. If the user already uses Framer Motion / React Spring / anime.js, adapt rather than forcing motion.dev.
  • Spot-check one animation runs end-to-end (reload, observe, iterate) before batching changes across many nodes.
  • Load references/gotchas.md, which covers specific bugs and edge cases seen in Figma motion output, and correct any such cases in the generated code.
  • 添加新导入前,先阅读组件现有的动效导入/约定。如果用户已使用Framer Motion / React Spring / anime.js,请适配而非强制使用motion.dev。
  • 在批量修改多个节点前,抽查一个动画是否能完整运行(重新加载、观察、迭代)。
  • 加载references/gotchas.md,其中涵盖Figma动效输出中出现的特定bug和边缘情况,并在生成代码中修正此类问题。

Critical Rules

关键规则

These are the general principles. Specific gotchas (rotation pivots, HOLD semantics, color interpolation, etc.) live in the categorized references. When a linked reference is mentioned in this skill text and the situation applies, load that file before continuing.
  1. Respect the tool's output's values, not its layout. Preserve the exact timing, easing, keyframe values, and
    transformOrigin
    from
    codeSnippets
    — don't regenerate them from
    keyframeBindings
    or the structured fields when snippets exist (regenerating loses fidelity on custom bezier easings, spring approximations, and overshoot values).
    transformOrigin
    is per element: apply each scaling/rotating node's own — including nested scalers, not just the outer wrapper — or the element pivots from the default center and grows/spins from the wrong corner (see the per-element-
    transformOrigin
    example). But the snippet is one node's data, not a copy-paste template: when many nodes share it, factor it per Rule 7 instead of pasting the block N times.
  2. Match the user's existing motion stack. Read the component's imports and any sibling animations before adding dependencies. If the user already has Framer Motion, React Spring, anime.js, GSAP — adapt the output to their stack rather than forcing motion.dev.
  3. Honor
    prefers-reduced-motion
    .
    Any motion added must soften or disable under
    @media (prefers-reduced-motion: reduce)
    — typically skip the
    animate
    (render the initial/resting state) or cut the duration to near-zero. This is an accessibility default, not an opt-in.
  4. Validate one animation end-to-end before batching. Build, reload, and watch one full timeline loop — confirm each animated node appears at the time its keyframe track says it should. "Renders without error" is not "renders correctly." Motion failures compound when you batch — a wrong easing on one node is easy to spot; the same bug across twenty nodes is hours of untangling.
  5. Don't fabricate motion. If a node has no motion data in the response, leave it static. Do not borrow easing/duration defaults from elsewhere in the design, and do not auto-animate "because the rest of the component is animated."
  6. Don't download an asset just to
    Read
    it.
    get_design_context
    /
    get_motion_context
    return assets as URLs (
    /api/mcp/asset/...
    ), often SVG. Reference the URL directly where the consumer fetches it (an
    <img src>
    , CSS
    background-image
    , an asset import), or
    curl
    one to inline its contents (e.g. inline the SVG and render via
    NSImage(data:)
    on SwiftUI). The important exception is path-level SVG motion: if the motion snippet targets a path inside an SVG asset, inline the SVG and animate the real path instead of leaving it behind an
    <img>
    . Don't download an asset and feed the file to the
    Read
    tool: SVG isn't a Read-able image format, so the read is rejected and wasted — and a file tool that doesn't detect SVG-as-image can stall the loop on it.
  7. Factor out repeated motion — never copy-paste the snippet per element. Many nodes usually share the same animation differing only by a stagger delay, offset, or target value. Implement the shared motion once — a reusable animated component or a
    variants
    object parameterized by the values that vary — render from a mapped array (
    items.map(...)
    ), and pull repeated literals (durations, easing arrays, offsets) into named constants. The animation's values stay verbatim from the snippet (Rule 1); the code stays DRY. The same transition object pasted 15+ times (800 lines that should be 150) is a low-quality result — fidelity and maintainability are both graded.
这些是通用原则。特定陷阱(旋转支点、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. 批量修改前先验证一个动画完整运行。构建、重新加载并观察一个完整的时间线循环——确认每个动画节点在关键帧轨道指定的时间出现。“无错误渲染”不等于“正确渲染”。批量修改时动效故障会叠加——一个节点的缓动错误容易发现;二十个节点的相同错误则需要数小时排查。
  5. 不要编造动效。如果响应中某个节点无动效数据,保持其静态。不要从设计的其他地方借用缓动/时长默认值,也不要“因为组件其他部分有动画”而自动添加动画。
  6. 不要仅为
    Read
    而下载资源
    get_design_context
    /
    get_motion_context
    以URL形式返回资源(
    /api/mcp/asset/...
    ),通常是SVG。直接在消费者获取资源的地方引用该URL(
    <img src>
    、CSS
    background-image
    、资源导入),或
    curl
    一个资源以内联其内容(例如,内联SVG并在SwiftUI上通过
    NSImage(data:)
    渲染)。重要例外是路径级SVG动效:如果动效代码片段针对SVG资源内的路径,内联SVG并动画真实路径,而非将其留在
    <img>
    后面。不要下载资源并将文件提供给
    Read
    工具:SVG不是可读取的图像格式,因此读取会被拒绝且浪费时间——无法检测SVG为图像的文件工具会在此处停滞循环。
  7. 提取重复动效——绝不为每个元素复制粘贴代码片段。许多节点通常共享相同的动画,仅在 stagger 延迟、偏移或目标值上有所不同。仅实现一次共享动效——一个可复用的动画组件或参数化的
    variants
    对象——从映射数组(
    items.map(...)
    )渲染,并将重复的字面量(时长、缓动数组、偏移)提取为命名常量。动画的严格保留代码片段中的内容(规则1);代码保持DRY(不重复)。将相同的过渡对象粘贴15+次(800行代码应精简为150行)是低质量结果——保真度和可维护性都会被评分。

Framework Recommendations

框架推荐

Rule 2 covers the general posture: prefer the user's existing stack. When none exists, defaults:
  • React: motion.dev (the
    motion
    package). The tool returns motion.dev code directly — use it.
  • Vanilla / non-React web: CSS
    @keyframes
    with
    animation
    shorthand, returned directly by the tool.
  • SwiftUI: Native
    .animation(...)
    modifiers, translated from the CSS snippet (
    get_motion_context
    emits no SwiftUI code, but SwiftUI/iOS clients still get the CSS format; fall back to
    keyframeBindings
    /
    motionSummary
    / cohort only when snippet-less). Use only real SwiftUI APIs — no modifier takes a Figma/CSS easing directly, so load references/framework-recommendations.md, map the easing to its SwiftUI equivalent, and verify rather than invent. This path is evolving; confirm with the user if unsure.
For established effect classes, prefer a library over hand-rolled CSS. Effects like glass/glassmorphism, confetti, particle systems, physics-based interactions, and scroll-linked motion have battle-tested library implementations that handle cross-browser quirks, accessibility, and performance far better than generated keyframes. Load references/framework-recommendations.md for the full library-by-effect-class table. Surface these as recommendations, not mandates — the user decides.
规则2涵盖了通用原则:优先使用用户现有的技术栈。当没有现有技术栈时,默认选择:
  • Reactmotion.dev
    motion
    包)。工具直接返回motion.dev代码——直接使用。
  • 原生 / 非React Web:CSS
    @keyframes
    +
    animation
    简写,工具直接返回。
  • SwiftUI:原生
    .animation(...)
    修饰符,从CSS代码片段转换而来(
    get_motion_context
    不输出SwiftUI代码,但SwiftUI/iOS客户端仍会获取CSS格式;仅当无代码片段时,才退回到
    keyframeBindings
    /
    motionSummary
    / 时间线组)。仅使用真实的SwiftUI API——没有修饰符直接接受Figma/CSS缓动,因此请加载references/framework-recommendations.md,将缓动映射为SwiftUI等效项并验证,而非自行发明。此路径仍在演进;如有疑问请与用户确认。
对于已确立的效果类别,优先使用库而非手动编写CSS。诸如玻璃态/毛玻璃、彩屑、粒子系统、基于物理的交互和滚动关联动效等效果,经过实战检验的库实现能更好地处理跨浏览器兼容性、无障碍和性能,远优于生成的关键帧。加载references/framework-recommendations.md查看按效果类别划分的完整库表。将这些作为建议而非强制要求——由用户决定。

Examples

示例

Load references/examples-and-anti-examples.md when you need worked examples or failure patterns. It covers the simple merge flow, plain text elements that need
motion.*
added, interleaved static+animated transforms, SVG path-level motion, and anti-examples for DOM rebuilding, node-id/position drift, and missing per-element
transformOrigin
.
需要已完成的示例或失败模式时,请加载references/examples-and-anti-examples.md。它涵盖了简单合并流程、需要添加
motion.*
的普通文本元素、交错静态+动画变换、SVG路径级动效,以及DOM重建、节点ID/位置偏移和缺失每个元素
transformOrigin
的反例。

References

参考资料

Six deep dives, fetched on demand. General frontend concerns (performance, units, accessibility mechanics) are handled by the critical rules above — these references focus on Figma-specific signal only. If this skill names one of these files in an inline instruction, load that file before continuing with that part of the task.
  • references/examples-and-anti-examples.md — worked examples and failure patterns. Load when applying the merge workflow, handling interleaved transforms, or checking whether a generated implementation has rebuilt the DOM, swapped node positions, or dropped
    transformOrigin
    .
  • references/gotchas.md — Figma-specific motion bugs and their fixes. Rotation/scale origin on nested groups, HOLD easing semantics, CUSTOM_SPRING preservation, independent axis scaling ambiguity, color interpolation. Load when troubleshooting unexpected runtime behavior. Always load references/motion-lint-rules.md alongside this file — gotcha entries reference specific lint rules that must be surfaced to the user.
  • references/svg-and-path-motion.md — implementing motion that targets an SVG vector path (inline the asset,
    motion.path
    ,
    pathLength="1"
    , wrapper+path layering, CSS path-trim). Load when a vector's snippet targets the path, not a wrapper transform.
  • references/framework-recommendations.md — motion.dev, CSS keyframes, SwiftUI defaults, library-by-effect-class table (glass, confetti, particles, physics, scroll-linked). Load before hand-rolling an effect.
  • references/unsupported-and-fallbacks.md — Figma motion features that don't export cleanly today (text animations, path animations, masks/booleans, variants/transitions). Includes video/lottie fallback guidance. Load when the tool response seems incomplete. Always load references/motion-lint-rules.md alongside this file — unsupported entries reference specific lint rules that must be surfaced to the user.
  • references/motion-lint-rules.md — Linting rules: known export limitations (errors and warnings) that must be surfaced to the user. Load when generating motion code to check whether any active limitations apply.
六个深度指南,按需获取。通用前端问题(性能、单位、无障碍机制)由上述关键规则处理——这些参考资料专注于Figma特定信号。如果本技能在 inline 指令中提及这些文件之一,请先加载该文件再继续任务的相应部分。
  • references/examples-and-anti-examples.md —— 已完成示例和失败模式。应用合并工作流、处理交错变换或检查生成的实现是否重建DOM、交换节点位置或丢失
    transformOrigin
    时加载。
  • references/gotchas.md —— Figma特定动效bug及其修复。嵌套组的旋转/缩放原点、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规则:必须向用户展示的已知导出限制(错误和警告)。生成动效代码时加载,检查是否存在任何适用的限制。