MCPInstall

figma-implement-motion

Translates Figma motion and animations into production-ready application code. Use when implementing animation/motion from a Figma design — user mentions "implement this motion", "add animation from Figma", "animate this component", provides a Figma URL whose node is animated, or when getdesigncontext returns motion data or instructs you to call getmotioncontext.

Installs
1.3K
Last 24h
+13
Trending rank
#7427
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/figma/mcp-server-guide --skill figma-implement-motion
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads figma-implement-motion automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

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.

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.

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).

Tool Choice

For motion implementation, use both tools with distinct roles:

SituationToolWhy
Understanding static structure, assets, styles, Code Connect, or visual layoutget_design_contextGives the component/page code reference and asset URLs you need to place animated nodes correctly.
Fetching animation data for any nodeget_motion_contextPurpose-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 valuesSplit 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.

Required Workflow

Step 1: Confirm static design context is available

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).

Step 2: Fetch authoritative motion data

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.
  • textAnimations — Always implement these text-group animations. If codeSnippets are also present, apply both; the snippet does not replace textAnimations.
    • Use derivedTimingInfo: each group starts at startMs + orderPosition * staggerStepMs and plays for groupDurationMs. startMs already includes delayMs; do not add it again. presetDurationMs covers the full staggered sequence, not each group.
    • Compute orderPosition from grouping and order, not always the character index (CENTER_OUT starts symmetric pairs together). Convert milliseconds to seconds for Motion.dev, and fit the supplied easing into groupDurationMs, including springs.
  • 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.

Step 3: Merge static and motion context

  • 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).

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.

Step 4: Apply the motion in code

  • 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).

Step 5: Validate

  • 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.

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. Download assets and reference local files. get_design_context / get_motion_context return assets as expiring URLs (/api/mcp/asset/...), often SVG. Download each asset into the project with curl -L and reference the downloaded file, or inline its contents (e.g. inline the SVG and render via NSImage(data:) on SwiftUI). Do not reference the temporary asset URLs in application code. For path-level SVG motion, inline the SVG and animate the real path instead of leaving it behind an <img>. Don't pass downloaded SVG files to the Read tool as images: SVG isn't a supported image format, so the read can fail or stall.
  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.

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.

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

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.

FAQ

What does the figma-implement-motion skill do?

Translates Figma motion and animations into production-ready application code. Use when implementing animation/motion from a Figma design — user mentions "implement this motion", "add animation from Figma", "animate this component", provides a Figma URL whose node is animated, or when getdesigncontext returns motion data or instructs you to call getmotioncontext.

How do I install figma-implement-motion?

Run npx skills add https://github.com/figma/mcp-server-guide --skill figma-implement-motion in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/figma-implement-motion/ (personal) or .claude/skills/figma-implement-motion/ (project).

Which AI agents can use figma-implement-motion?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is figma-implement-motion safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains figma-implement-motion?

It is published by figma in figma/mcp-server-guide. It has 1,255 recorded installs.

More from figma/mcp-server-guide

View all →

figma-use

figma/mcp-server-guide

MANDATORY prerequisite — you MUST invoke this skill BEFORE every usefigma tool call. NEVER call usefigma directly without loading this skill first. Skipping it causes common, hard-to-debug failures. Trigger whenever the user wants to perform a write action or a unique read action that requires JavaScript execution in the Figma file context — e.g. create/edit/delete nodes, set up variables or tokens, build components and variants, modify auto-layout or fills, bind variables to properties, or inspect file structure programmatically.

OfficialFrontend & Design9.2K installs

figma-generate-design

figma/mcp-server-guide

Use this skill alongside figma-use when the task involves translating an application page, view, or multi-section layout into Figma. Triggers: 'write to Figma', 'create in Figma from code', 'push page to Figma', 'take this app/page and build it in Figma', 'create a screen', 'build a landing page in Figma', 'update the Figma screen to match code', 'convert this modal/dialog/drawer/panel to Figma'. This is the preferred workflow skill whenever the user wants to build or update a full page, modal, dialog, drawer, sidebar, panel, form, dashboard, list, table, card, header, message preview, or other composed product UI in Figma from code or a description—even when the user calls that composed UI a component. Discovers design system components, variables, and styles from Code Connect files, existing screens, and library search, then imports them and assembles views incrementally section-by-section using design system tokens instead of hardcoded values.

OfficialFrontend & Design6K installs

implement-design

figma/mcp-server-guide

Translates Figma designs into production-ready code with 1:1 visual fidelity. Use when implementing UI from Figma files, when user mentions "implement design", "generate code", "implement component", "build Figma design", provides Figma URLs, or asks to build components matching Figma specs. Requires Figma MCP server connection.

OfficialFrontend & Design5.9K installs

figma-generate-library

figma/mcp-server-guide

Build or update a professional-grade design system in Figma from a codebase. Use when the user wants to create variables/tokens, build component libraries, create individual components with proper variant sets and variable bindings, set up theming (light/dark modes), document foundations, or reconcile gaps between code and Figma. Also use when the user asks to create or generate any component in Figma — even a single one — since components require proper variable foundations, variant states, and design token bindings to be production-quality. This skill teaches WHAT to build and in WHAT ORDER — it complements the figma-use skill which teaches HOW to call the Plugin API. Both skills should be loaded together.

OfficialFrontend & Design4.4K installs

figma-implement-design

figma/mcp-server-guide

Translates Figma designs into production-ready application code with 1:1 visual fidelity. Use when implementing UI code from Figma files, when user mentions "implement design", "generate code", "implement component", provides Figma URLs, or asks to build components matching Figma specs. For Figma canvas writes via usefigma, use figma-use.

OfficialFrontend & Design4K installs

figma-create-new-file

figma/mcp-server-guide

Always use this skill when the user wants to create a new Figma Design, FigJam, or Slides file. You MUST invoke this skill BEFORE every createnewfile tool call.

OfficialFrontend & Design3.5K installs

Popular frontend & design skills

View category →

setup-matt-pocock-skills

mattpocock/skills

Configure this repo for the engineering skills: set up its issue tracker, triage label vocabulary, and domain doc layout. Run once before first use of the other engineering skills.

Frontend & Design1.1M installs

frontend-design

anthropics/skills

Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.

OfficialFrontend & Design1M installs

hyperframes-animation

heygen-com/hyperframes

All animation knowledge for HyperFrames — atomic motion rules, multi-phase scene blueprints, scene transitions, broader motion-design techniques, AND the seven runtime adapters (GSAP default, plus Lottie, Three.js, Anime.js, CSS keyframes, Web Animations API, TypeGPU). Use for any motion or animation task: pick 2-4 rules and compose, or load a blueprint, or look up runtime-specific API (e.g. GSAP eases / Lottie player / Three.js mixer). Also covers auditing an existing composition's choreography (animation map) and 24 named text-animation effects. HyperFrames-native: single paused timeline, seek-safe, deterministic.

prototype

mattpocock/skills

Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like.

Frontend & Design999.2K installs

hyperframes-core

heygen-com/hyperframes

The HyperFrames composition contract — build one renderable project. Use for composition structure, the data- timing attributes, class="clip", tracks, sub-compositions, variables, framework-owned media playback, deterministic-render rules, and validation. Read before writing composition HTML.

Frontend & Design930.5K installs

vercel-react-best-practices

vercel-labs/agent-skills

React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.

OfficialFrontend & Design843.1K installs