figma-implement-motion

Par figma · mcp-server-guide

Traduit les animations et mouvements Figma en code applicatif prêt pour la production. À utiliser lors de l'implémentation d'une animation ou d'un mouvement issu d'un design Figma — l'utilisateur mentionne « implémenter ce mouvement », « ajouter une animation depuis Figma », « animer ce composant », fournit une URL Figma dont le nœud est animé, ou lorsque `get_design_context` retourne des données de mouvement ou vous demande d'appeler `get_motion_context`.

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

Implémenter Motion

Aperçu

Cette skill guide la traduction des animations et transitions Figma en code exécutable (motion.dev, CSS keyframes, ou libraries spécifiques au framework).

Figma expose motion via deux tools :

  • get_motion_context — outil motion autoritaire. Retourne l'inventaire complet des nœuds animés, les extraits de code précompilés (CSS @keyframes + motion.dev), les liaisons de keyframe de secours quand les extraits ne sont pas disponibles, et les indices de coordination de timeline récursifs. Source de vérité pour les données d'animation et les ID de nœud qui s'animent.
  • get_design_context — la structure du design : layout, dimensionnement, assets, styling, indices Code Connect, contexte screenshot, et parfois marqueurs de placement motion sur les éléments animés (data-node-id, et sur les nœuds fragmentés data-motion-keys / data-motion-wrapper-for / data-motion-transform-template). Il peut afficher un nœud animé en tant qu'élément simple (div, p, span, etc.) ou élément motion (motion.div) ; il n'inline pas les valeurs d'animation.

Les deux sont liés par node id, et c'est tout le workflow. get_motion_context vous indique quels nœuds s'animent et fournit les valeurs keyframe, l'easing, le timing et les extraits. get_design_context vous indique à quoi ressemblent ces nœuds et où ils se situent. Pour chaque nœud dans get_motion_context.nodes, trouvez le data-node-id correspondant en contexte design et fusionnez le motion dans cette structure — en ajoutant ou enrobant un motion.{tag} quand l'élément structurel est simple. Quand le contexte design réutilise un composant Figma, le nœud motion peut aussi inclure fallbackNodeId ; utilisez-le uniquement en secours après avoir essayé l'exact nodeId.

Limites de la Skill

  • Utilisez cette skill quand le livrable est du code motion dans le repository de l'utilisateur.
  • Si l'utilisateur demande de créer/modifier des animations dans Figma lui-même, basculez vers figma-use et suivez cette skill à la place.
  • Cette skill couvre actuellement les animations émises par get_motion_context (extraits plus pistes keyframe de secours, incluant le motion créé par preset résolu dans ces formes). Les flux de variant interactifs plus larges peuvent encore nécessiter une gestion d'état spécifique au produit en code.

Prérequis

  • Serveur MCP Figma connecté et accessible.
  • Node ID analysé depuis l'URL Figma fournie par l'utilisateur. Format d'URL : https://figma.com/design/:fileKey/:fileName?node-id=1-2 — extrayez fileKey (le segment après /design/) et nodeId (la valeur du paramètre de requête node-id, par ex. 42-15).
  • Codebase cible. Le format de sortie motion s'adapte à la stack (voir Recommandations Framework).

Choix des Tools

Pour l'implémentation motion, utilisez les deux tools avec des rôles distincts :

Situation Tool Pourquoi
Comprendre la structure statique, les assets, les styles, Code Connect, ou le layout visuel get_design_context Fournit la référence de code du composant/page et les URLs des assets dont vous avez besoin pour placer correctement les nœuds animés.
Récupérer les données d'animation pour n'importe quel nœud get_motion_context Conçu pour motion et source de vérité pour le timing, l'easing, les extraits et les keyframes.
Un nœud a des marqueurs motion (data-motion-keys, data-motion-wrapper-for) Marqueurs pour le placement fragmenté, get_motion_context pour les valeurs Les marqueurs fragmentés vous indiquent sur quel élément vont les pistes ; les keyframes/easing/timing et l'inventaire des nœuds animés viennent de get_motion_context.

get_motion_context accepte recursive: true (plafonné à 500 nœuds) quand vous avez besoin du motion des descendants en un seul appel.

Workflow Requis

Étape 1 : Confirmer que le contexte design statique est disponible

get_design_context(fileKey=":fileKey", nodeId="<node-id>")

Si get_design_context a déjà été appelé pour ce nœud, réutilisez cette sortie. Sinon, appelez-le normalement maintenant.

Utilisez-le comme la structure de référence — hiérarchie, dimensionnement, styling, assets, indices Code Connect, contexte screenshot, et tous marqueurs motion qu'il pourrait inclure (Étape 3). L'inventaire des nœuds animés et les valeurs d'animation viennent de get_motion_context (Étape 2).

Étape 2 : Récupérer les données motion autoritaires

get_motion_context(fileKey=":fileKey", nodeId="<node-id>", recursive=true)

Forme de réponse (une entrée par nœud animé) :

  • codeSnippets — chaînes CSS @keyframes et motion.dev pré-générées. Utilisez-les directement. Ne les régénérez pas à partir des données de piste de secours.
  • keyframeBindings — pistes keyframe liées, incluant le motion dérivé de preset résolu en données de piste, inclus uniquement comme données de secours quand les deux formats d'extrait manquent.
  • fallbackNodeId — id de secours optionnel pour correspondre au contexte design componentisé. Si nodeId est un id qualifié d'instance comme I4005:6111;30:8005, D2R peut afficher le corps du composant réutilisable avec l'id du composant de support à la place, comme 4002:3957. Dans ce cas, fallbackNodeId est le data-node-id à chercher si la recherche exact nodeId échoue.

Les réponses récursives peuvent aussi inclure timelineCohorts : groupes d'IDs de nœuds animés qui partagent une racine timeline, une durée et un mode de lecture (once, loop, ou boomerang). Utilisez les cohorts pour garder les animations décalées ou multi-nœuds synchronisées au lieu d'inférer le timing partagé à partir de l'ordre des frères.

Détails d'implémentation qui importent pour les LLMs :

  • Quand les extraits existent, les keyframeBindings, timelineDurationMs, motionSummary bruts et transformOrigin par défaut peuvent être supprimés pour réduire la taille du payload. L'absence de keyframeBindings n'est pas un signal qu'il n'y a pas d'animation.
  • Les réponses récursives dédupliquent les extraits exactement dupliqués. Un extrait peut être remplacé par un commentaire pointant vers le premier nœud avec motion identique ; réutilisez le même composant, variant, classe ou constantes au lieu d'écrire une deuxième animation.
  • Le serveur MCP déduit les extraits CSS vs motion.dev de clientFrameworks ; si la réponse ne contient qu'un seul format d'extrait, adaptez ce format à la stack de l'utilisateur plutôt que de supposer que l'autre format a échoué.

Étape 3 : Fusionner le contexte statique et motion

  • Commencez par get_motion_context.nodes, pas à partir des tags visibles motion.* dans le JSX statique. Chaque nœud retourné est animé. Faites correspondre chaque nœud motion à get_design_context par nodeId / data-node-id exact en premier. Si et seulement s'il n'y a pas de correspondance exacte, essayez fallbackNodeId / data-node-id. Basculez vers le nom/type du nœud et la position du screenshot seulement après l'échec des deux ids.
  • La correspondance id exacte l'emporte sur fallbackNodeId. fallbackNodeId pointe vers l'id du composant de support que D2R peut émettre dans un composant réutilisable. Il est partagé par chaque instance de ce composant. Si l'exact nodeId existe en contexte design, appliquez le motion là et ignorez le secours. C'est critique pour l'animation root-instance : une instance peut tourner ou se déplacer différemment d'une autre instance du même composant, et appliquer ce motion au corps du composant partagé animerait toutes les instances incorrectement.
  • Appliquez chaque nœud motion à la structure du contexte design correspondante, indexée par data-node-id. Le data-node-id correspondant est l'ancre structurelle, pas toujours l'élément DOM final qui reçoit le motion. Utilisez la forme d'extrait et les marqueurs de placement pour décider si le motion va sur cet élément exact, un wrapper, un élément interne, ou un chemin SVG inliné. get_design_context peut déjà émettre motion.{tag} avec les valeurs supprimées, ou il peut émettre un élément structurel simple (div, p, span, racine de composant, etc.). S'il est simple et que l'extrait cible l'élément lui-même, convertissez-le en motion.{tag} approprié ou ajoutez un wrapper motion tout en préservant le texte, les enfants, les classes/styles, les attributs et le data-node-id du nœud. Chargez references/examples-and-anti-examples.md pour voir des exemples de cette étape de fusion.
  • Le motion des enfants componentisés correspond généralement par secours. Quand le contexte design extrait une instance Figma dans un composant React réutilisable, les enfants dans le corps du composant ont souvent des ids de composant de support (4002:3957) tandis que le contexte motion rapporte des ids d'instance en direct (I4005:6111;30:8005). Dans ce cas, utilisez fallbackNodeId pour trouver le data-node-id du corps du composant, mais gardez le motion limité à l'instance rendue que vous implémentez. S'il y a plusieurs instances et qu'une seule a un motion root différent, la correspondance id exacte garde ce motion par instance séparé.
  • Les nœuds fragmentés portent un marqueur data-motion-keys / data-motion-wrapper-for — voir Gérer les transforms interleaved ci-dessous.
  • Préservez les wrappers display: contents— sauf si le groupe lui-même s'anime. Les wrappers de groupe transparents pour le layout viennent comme contents (Tailwind contents), généralement aux côtés d'un absolute/inset-[…] mort (ceux ne font rien sur une boîte contents). Pour un groupe statique, gardez display: contents et laissez les enfants se positionner contre l'ancêtre réel le plus proche — convertir le inset du wrapper en boîte positionnée reparente les enfants vers une boîte plus petite, donc ils affichent trop petit / décalés vers l'intérieur. Pour un groupe animé (le nœud du groupe lui-même a du motion), display: contents ne peut pas porter un transform — remplacez-le par un wrapper réel positionné et appliquez le motion du groupe là. Chargez references/gotchas.md avant d'implémenter ce cas.
  • get_motion_context est l'inventaire complet des nœuds animés. Certains nœuds animés affichent comme des éléments simples (non motion) — racines d'instance de composant (div simple positioning), texte (<p>), masques — qui portent toujours un data-node-id. Parcourez chaque nœud dans la réponse motion et appliquez son motion à l'élément avec le data-node-id correspondant, enrobant ou convertissant au besoin. Si un nœud animé n'a aucun élément du tout dans la sortie (par ex. un masque animé aplati dans un mask-image statique), ne le supprimez pas silencieusement — laissez un commentaire // TODO: <nodeId> motion unsupported et signalez-le dans votre résumé.
  • Si un nœud apparaît en contexte motion mais pas dans le JSX statique, ajoutez l'élément nécessaire pour le représenter — le code du contexte design est une référence, pas un inventaire d'animation complet.
  • En cas de conflit entre le contexte design et motion (timing/easing/valeurs animées), préférez get_motion_context.
  • Motion SVG au niveau du chemin : inlinisez le SVG et animez le vrai <path>. Quand get_motion_context cible le chemin d'un vecteur (PATH_TRIM, motion.path, stroke-dasharray) mais que le contexte design l'affiche en tant que <img>, inlinisez le SVG et appliquez l'extrait au <path>, en gardant le wrapper de layout. Chargez references/svg-and-path-motion.md pour la procédure complète pour ce cas (motion.path, pathLength="1", wrapper+path layering, CSS path-trim).

Gérer les transforms interleaved

Un nœud avec à la fois un transform statique de base et des transforms animés est fragmenté sur des éléments imbriqués pour que les deux se composent correctement au lieu de se combattre : un motion.div sans id portant data-motion-wrapper-for="<nodeId>" (le wrapper EXTERNE) enveloppe un div de transform statique (par ex. rotate-45 + sizing hypot() — ou le wrapper lui-même porte data-motion-transform-template="<css>") qui enveloppe le nœud INTERNE (data-node-id). Gardez l'imbrication wrapper > static-transform div > inner — l'aplatir casse le dimensionnement et le transform de base.

  • Placez les pistes par data-motion-keys. Les data-motion-keys du wrapper (pistes transform — x/y/rotate/scaleX/scaleY/skewX) vont sur le wrapper EXTERNE ; les data-motion-keys de l'élément interne vont sur l'élément INTERNE.
  • Réappliquez un data-motion-transform-template. Si le wrapper en porte un, définissez transformTemplate={(_, generated) => "<css> " + generated} pour que le transform animé se compose sur ce transform layout statique.
  • Décalez le transform animé par la base statique (évitez la rotation double). get_motion_context donne le transform absolu du nœud, qui inclut déjà le transform statique de base que ces divs appliquent. Un extrait rotate de [45, 125, 125] sur une base rotate-45 signifie que le wrapper anime l'offset [0, 80, 80] (= absolu − 45), pas l'absolu — sinon le 45° s'applique deux fois et l'élément s'assoit à 90° au repos. Les pistes sans base statique (par ex. x/y commençant à 0) passent inchangées. Voir l'exemple interleaved-transform.
  • Gardez les transforms layout séparés des transforms Motion. Pour chaque élément motion.* qui anime rotate, scale, ou skew, vérifiez qu'il ne repose pas aussi sur les transforms layout Tailwind comme -translate-x-1/2 ou -translate-y-1/2 pour le centrage/positionnement. Ces utilitaires partagent la propriété CSS transform que Motion.dev écrit inline, donc le transform de Motion peut effacer le layout translate. Si les deux sont nécessaires, fragmentez l'élément en un wrapper layout statique portant le transform centrage/positionnement et un élément motion.* interne portant le rotate/scale/opacity animé, ou encodez l'offset layout dans Motion lui-même (x: "-50%") et gardez-le présent pour chaque keyframe.

Étape 4 : Appliquer le motion en code

  • motion.dev présent dans les extraits ? Utilisez le code motion.dev verbatim pour les cibles React. Importez de motion/react — sauf si la codebase utilise déjà une autre library motion (Framer Motion, React Spring, GSAP), auquel cas adaptez l'extrait. Chargez references/framework-recommendations.md quand vous adaptez à une autre stack ou choisirez une library.
  • CSS keyframes présent ? Utilisez pour les cibles vanilla/non-React, ou quand la codebase n'a pas de library motion React.
  • Pas d'extraits ? Utilisez keyframeBindings ou motionSummary comme données de secours pour construire des appels motion.dev équivalents ou des CSS keyframes. Normalement les extraits sont présents ; faites cela seulement quand les deux formats d'extrait manquent vraiment.

Étape 5 : Valider

  • Lisez les importations motion et conventions existantes du composant avant d'en ajouter de nouvelles. Si l'utilisateur utilise déjà Framer Motion / React Spring / anime.js, adaptez plutôt que de forcer motion.dev.
  • Vérifiez de bout en bout qu'une animation s'exécute (rechargez, observez, itérez) avant de regrouper les modifications sur plusieurs nœuds.
  • Chargez references/gotchas.md, qui couvre les bugs spécifiques à Figma motion et leurs fixes, et corrigez les cas pertinents dans le code généré.

Règles Critiques

Ce sont les principes généraux. Les gotchas spécifiques (pivots de rotation, sémantique HOLD, interpolation de couleur, etc.) vivent dans les références catégorisées. Quand une référence liée est mentionnée dans ce texte de skill et que la situation s'applique, chargez ce fichier avant de continuer.

  1. Respectez les valeurs de la sortie du tool, pas son layout. Préservez le timing exact, l'easing, les valeurs keyframe et transformOrigin des codeSnippets — ne les régénérez pas à partir de keyframeBindings quand les extraits existent (régénérer perd la fidélité sur les bezier easing personnalisés, les approximations spring et les valeurs d'overshoot). transformOrigin est par élément : appliquez le vôtre pour chaque nœud scaling/rotating — incluant les scalers imbriqués, pas juste le wrapper externe — ou l'élément pivote du center par défaut et grandit/tourne depuis le mauvais coin (voir l'exemple per-element-transformOrigin). Mais l'extrait est les données d'un nœud, pas un template copy-paste : quand plusieurs nœuds le partagent, factorisez-le par Règle 7 au lieu de coller le bloc N fois.
  2. Correspondez à la stack motion existante de l'utilisateur. Lisez les importations du composant et les animations frères avant d'ajouter des dépendances. Si l'utilisateur a déjà Framer Motion, React Spring, anime.js, GSAP — adaptez la sortie à leur stack plutôt que de forcer motion.dev.
  3. Honorer prefers-reduced-motion. N'importe quel motion ajouté doit s'adoucir ou se désactiver sous @media (prefers-reduced-motion: reduce) — généralement passer le animate (afficher l'état initial/repos) ou couper la durée à près de zéro. C'est une valeur par défaut d'accessibilité, pas un opt-in.
  4. Valider une animation de bout en bout avant de regrouper. Construisez, rechargez et regardez une boucle timeline complète — confirmez que chaque nœud animé apparaît à l'heure que sa piste keyframe dit qu'il devrait. « Affiche sans erreur » n'est pas « affiche correctement ». Les défaillances motion se cumulent quand vous regroupez — un mauvais easing sur un nœud est facile à voir ; le même bug sur vingt nœuds est des heures de démêlement.
  5. Ne fabriquez pas de motion. Si un nœud n'a pas de données motion dans la réponse, laissez-le statique. N'empruntez pas les defaults d'easing/duration d'ailleurs dans le design, et n'auto-animez pas « parce que le reste du composant est animé ».
  6. Ne téléchargez pas un asset juste pour le Read. get_design_context / get_motion_context retournent les assets comme URLs (/api/mcp/asset/...), souvent SVG. Référencez l'URL directement où le consommateur la récupère (un <img src>, CSS background-image, une importation d'asset), ou curl une pour inliner son contenu (par ex. inlinisez le SVG et affichez via NSImage(data:) sur SwiftUI). L'exception importante est le motion SVG au niveau du chemin : si l'extrait motion cible un chemin à l'intérieur d'un asset SVG, inlinisez le SVG et animez le vrai chemin au lieu de le laisser derrière un <img>. Ne téléchargez pas un asset et ne le passez pas au tool Read : SVG n'est pas un format d'image lisible, donc la lecture est rejetée et gaspillée — et un file tool qui ne détecte pas SVG-as-image peut bloquer la boucle dessus.
  7. Factorisez le motion répété — ne copiez-collez jamais l'extrait par élément. Plusieurs nœuds partagent généralement la même animation différant seulement par un délai de stagger, un offset ou une valeur cible. Implémentez le motion partagé une fois — un composant animé réutilisable ou un objet variants paramétrisé par les valeurs qui varient — rendez d'un array mappé (items.map(...)), et tirez les littéraux répétés (durées, tableaux easing, offsets) dans les constantes nommées. Les valeurs de l'animation restent verbatim de l'extrait (Règle 1) ; le code reste DRY. Le même objet transition collé 15+ fois (800 lignes qui devraient en être 150) est un résultat de basse qualité — la fidélité et la maintenabilité sont toutes deux évaluées.

Recommandations Framework

La Règle 2 couvre la posture générale : préférez la stack existante de l'utilisateur. Quand aucune n'existe, defaults :

  • React : motion.dev (le package motion). Le tool retourne le code motion.dev directement — utilisez-le.
  • Vanilla / web non-React : CSS @keyframes avec shorthand animation, retournés directement par le tool.
  • SwiftUI : Modifieurs natifs .animation(...) ; traduisez à partir des extraits, keyframeBindings, ou motionSummary (get_motion_context n'émet pas du code SwiftUI). Utilisez seulement les APIs SwiftUI réelles — il n'y a pas de modifier qui prend un type easing Figma/CSS directement, donc chargez references/framework-recommendations.md, mappez l'easing émis à son équivalent SwiftUI, et vérifiez plutôt que d'inventer une méthode. Ce chemin évolue ; confirmez avec l'utilisateur si doute.

Pour les classes d'effet établies, préférez une library plutôt que du CSS maison. Les effets comme glass/glassmorphism, confetti, systèmes de particules, interactions basées sur la physique et le motion lié au scroll ont des implémentations de library éprouvées en combat qui gèrent les quirks cross-browser, l'accessibilité et la performance bien mieux que les keyframes générés. Chargez references/framework-recommendations.md pour la table complète library-par-classe-d'effet. Présentez-les comme des recommandations, pas des mandats — l'utilisateur décide.

Exemples

Chargez references/examples-and-anti-examples.md quand vous avez besoin d'exemples travaillés ou de patterns de défaillance. Cela couvre le flux de fusion simple, les éléments texte simples qui ont besoin de motion.* ajouté, les transforms statique+animé interleaved, le motion SVG au niveau du chemin, et les anti-exemples pour la reconstruction DOM, la dérive node-id/position, et le transformOrigin manquant par élément.

Références

Six deep dives, récupérés sur demande. Les concerns générales du frontend (performance, unités, mécanique d'accessibilité) sont traitées par les règles critiques ci-dessus — ces références se concentrent seulement sur le signal spécifique à Figma. Si cette skill nomme l'un de ces fichiers dans une instruction inline, chargez ce fichier avant de continuer avec cette partie de la tâche.

  • references/examples-and-anti-examples.md — exemples travaillés et patterns de défaillance. Chargez quand vous appliquez le workflow de fusion, gérez les transforms interleaved, ou vérifiez si une implémentation générée a reconstruit le DOM, échangé les positions de nœud, ou supprimé transformOrigin.
  • references/gotchas.md — bugs de motion spécifiques à Figma et leurs fixes. Rotation/scale origin sur les groupes imbriqués, sémantique HOLD easing, préservation CUSTOM_SPRING, ambiguïté d'échelle d'axe indépendant, interpolation de couleur. Chargez quand vous résolvez un comportement runtime inattendu. Chargez toujours references/motion-lint-rules.md aux côtés de ce fichier — les entrées gotcha font référence à des règles lint spécifiques qui doivent être signalées à l'utilisateur.
  • references/svg-and-path-motion.md — implémenter le motion qui cible un chemin d'un vecteur SVG (inlinisez l'asset, motion.path, pathLength="1", wrapper+path layering, CSS path-trim). Chargez quand le snippet d'un vecteur cible le chemin, pas un wrapper transform.
  • references/framework-recommendations.md — motion.dev, CSS keyframes, defaults SwiftUI, table library-par-classe-d'effet (glass, confetti, particles, physics, scroll-linked). Chargez avant de coder en dur un effet.
  • references/unsupported-and-fallbacks.md — Fonctionnalités Figma motion qui ne s'exportent pas proprement aujourd'hui (text animations, path animations, masks/booleans, variants/transitions). Inclus la guidance fallback video/lottie. Chargez quand la réponse du tool semble incomplète. Chargez toujours references/motion-lint-rules.md aux côtés de ce fichier — les entrées unsupported font référence à des règles lint spécifiques qui doivent être signalées à l'utilisateur.
  • references/motion-lint-rules.md — Règles de linting : limitations d'export connues (erreurs et avertissements) qui doivent être signalées à l'utilisateur. Chargez quand vous générez du code motion pour vérifier si des limitations actives s'appliquent.

Skills similaires