video-interaction-mapper

Par figma · mcp-server-guide

Cette compétence doit être utilisée lorsque l'utilisateur demande d'analyser un enregistrement d'écran et de mapper les états d'interaction dans Figma. Se déclenche pour des requêtes telles que « mettre des frames vidéo dans Figma », « extraire les états de mon enregistrement », « mapper les interactions d'une vidéo vers Figma », « analyser cet enregistrement d'écran », « créer un storyboard à partir de ma vidéo », « décomposer cette interaction dans Figma », « annoter les états UI dans mon enregistrement », ou « extraire les moments clés de cette vidéo dans Figma ». Se déclenche également lorsque l'utilisateur fait référence à un fichier vidéo (.mp4, .mov, .webm, .avi) en lien avec Figma, une revue de design, une analyse d'interaction, des prototypes ou des états UI. La compétence extrait les moments visuels clés d'une vidéo, déduit les déclencheurs d'interaction, et construit un storyboard Figma Design annoté en utilisant les annotations natives de Figma et des captures d'écran importées comme assets.

npx skills add https://github.com/figma/mcp-server-guide --skill video-interaction-mapper

Mappage d'interactions vidéo

Convertir un enregistrement UI en storyboard Figma annoté et statique. Extraire les états avant/après importants, déduire ce qui a déclenché chaque changement, puis placer des captures d'écran propres, des marqueurs d'interaction bleus et des annotations concises dans un fichier Figma Design.

Entrées et outils requis

Commencer par :

  • Un chemin de fichier vidéo local (.mp4, .mov, .webm, ou .avi).
  • ffmpeg et ffprobe disponibles sur la machine.
  • Python avec Pillow installé.
  • Outils Figma MCP disponibles : create_new_file, use_figma, upload_assets, et get_screenshot ou get_design_context.

Exécuter les fichiers regroupés dans scripts/ en tant qu'assistants de workflow exécutables. Ils font partie de l'implémentation du skill, pas du matériel de référence. Les lire ou les modifier seulement lors du débogage, de l'adaptation à un environnement inhabituel, ou de la modification du skill lui-même.

Utiliser un fichier Figma Design (figma.com/design/...) comme cible. Le code API Plugin généré crée des pages et des cadres avec remplissage d'image, ce sont des opérations de fichier Design. Si l'utilisateur fournit une URL FigJam ou Slides, demander un fichier Design ou en créer un nouveau.

Avant tout appel use_figma, charger le skill de guidance API Figma s'il est disponible (figma-use). Avant de créer un nouveau fichier Figma, charger le skill de guidance de création de fichier s'il est disponible (figma-create-new-file). Passer skillNames: "figma-use,video-interaction-mapper" sur les appels use_figma quand le client supporte ce paramètre.

Workflow

1. Valider et préparer

Confirmer que le chemin vidéo existe, puis vérifier ffmpeg -version. Si Pillow est manquant, l'installer dans l'environnement Python actif :

pip install Pillow --break-system-packages -q

Effectuer l'analyse locale avant de créer ou modifier le fichier Figma. Créer un fichier Figma uniquement après que key_moments.json, upload_manifest.json et les scripts Figma générés soient prêts, sauf si l'utilisateur demande explicitement de créer le fichier en premier. Cela évite de laisser des pages partielles quand l'analyse locale des cadres change.

2. Reconnaître rapidement la timeline

Commencer par une passe de reconnaissance basse résolution et une feuille de contact :

python <SKILL_DIR>/scripts/extract_key_frames.py \
  --input "<video_path>" \
  --output /tmp/vim_frames_<timestamp>/ \
  --mode scout

La passe scout extrait à 1 fps par défaut, redimensionne les cadres à 640 px de large, évalue les changements de scène, écrit <output_dir>/frames_manifest.json et crée <output_dir>/contact_sheet.jpg. Inspecter d'abord la feuille de contact pour identifier les moments d'interaction probables.

Utiliser l'extraction plus lente complète seulement quand la passe scout est insuffisante :

python <SKILL_DIR>/scripts/extract_key_frames.py \
  --input "<video_path>" \
  --output /tmp/vim_frames_<timestamp>/full_frames/ \
  --mode full \
  --max-width 1600

Pour les très longues vidéos, demander s'il faut se concentrer sur une plage de temps spécifique avant de traiter l'enregistrement entier. Pour trop de cadres clés, relancer l'extraction avec un --scene-threshold plus élevé, comme 0.4.

3. Analyser les moments clés

Lire frames_manifest.json et inspecter contact_sheet.jpg ou les cadres extraits pertinents. Pour chaque transition significative, identifier :

  • Changement visuel : modal, tiroir, menu déroulant, infobulle, snackbar, superposition, navigation, contenu chargé, état sélectionné, état de validation, focus d'entrée ou position de défilement.
  • Déclencheur : clic, tap, entrée clavier, survol, défilement, balayage, soumission de formulaire, auto/minuteur ou déclencheur inconnu quand la cause est ambiguë.
  • Coordonnées de la cible d'interaction et du résultat quand visibles et utiles.

Utiliser des coordonnées normalisées de 0 à 1 par rapport à la capture d'écran. Des valeurs de type pourcentage comme 45 ou 94 sont acceptées par le script Figma généré et converties en 0.45 ou 0.94. Les coordonnées sont des métadonnées machine pour le placement des marqueurs uniquement. Ne pas inclure les valeurs de coordonnées dans le texte d'annotation visible, les étiquettes de moment ou les résumés utilisateur.

N'ajouter les coordonnées de marqueur que quand le point atterrit sur un élément ou un état UI clairement visible. Si une cible est déduite, entre des contrôles visibles, ou basée principalement sur la position du curseur, la marquer avec inferred: true, uncertain: true, visible: false, ou confidence: "medium"/"low". Le script généré supprime les marqueurs pour ces points par défaut pour que le canevas ne montre pas d'impulsion confiante sur une UI vide. Si la cible ou le résultat ne peuvent pas être localisés utilement, définir interaction à null.

Utiliser confidence: "high" ou omettre confidence uniquement quand le marqueur doit être dessiné. Utiliser show_marker: true seulement quand un point incertain vaut quand même la peine d'être marqué ; le marqueur généré utilise un style alternatif pour ces marqueurs incertains forcés.

Viser 5 à 15 moments clés. Prioriser les scores de scène élevés et les états véritablement différents par rapport aux minuscules décalages visuels.

Écrire l'analyse vers <output_dir>/key_moments.json en tant que tableau. Quand on utilise le flux scout, fournir d'abord les timestamps ; résoudre les fichiers de cadre haute qualité à l'étape suivante.

[
  {
    "moment_index": 1,
    "timestamp_s": 3.4,
    "before_timestamp_s": 3.2,
    "after_timestamp_s": 3.4,
    "trigger": "Click",
    "trigger_emoji": "",
    "short_label": "Dropdown menu opens",
    "annotation": "The account avatar is activated. A menu appears below it with profile, billing, and sign-out actions.",
    "interaction": {
      "target_frame": "before",
      "target": {
        "x": 0.91,
        "y": 0.08,
        "label": "Account avatar",
        "confidence": "high"
      },
      "result_frame": "after",
      "result": {
        "x": 0.86,
        "y": 0.2,
        "label": "Opened account menu"
      },
      "annotation": "Activating the avatar opens the account menu."
    }
  }
]

Garder les annotations lisibles pour l'humain : Target: Account avatar, pas une étiquette avec un suffixe de coordonnée brute. Les coordonnées restent cachées en JSON et n'apparaissent que sous forme de placement de marqueur visuel.

Si un marqueur est dessiné, l'annotation Figma native est attachée à ce nœud marqueur plutôt qu'au cadre de capture d'écran. Si un marqueur est supprimé parce que le point est incertain ou non visible, l'annotation reste attachée au cadre de capture d'écran pertinent.

4. Résoudre les cadres sélectionnés

Si key_moments.json utilise des timestamps, extraire uniquement les cadres avant/après sélectionnés à plus haute qualité :

python <SKILL_DIR>/scripts/resolve_moment_frames.py \
  --video "<video_path>" \
  --moments-file /tmp/vim_frames_<timestamp>/key_moments.json \
  --output /tmp/vim_frames_<timestamp>/key_moments_resolved.json \
  --frames-dir /tmp/vim_frames_<timestamp>/selected_frames/ \
  --max-width 1600

Utiliser key_moments_resolved.json dans les étapes suivantes. Si une extraction complète a déjà produit des valeurs précises before_frame_path et after_frame_path, cette étape peut être ignorée.

5. Préparer les ressources de capture d'écran téléchargeables

Compresser et redimensionner les captures d'écran avant/après pour le téléchargement :

python <SKILL_DIR>/scripts/prepare_upload_frames.py \
  --manifest /tmp/vim_frames_<timestamp>/frames_manifest.json \
  --moments-file /tmp/vim_frames_<timestamp>/key_moments_resolved.json \
  --output /tmp/vim_frames_<timestamp>/upload_manifest.json

Le script écrit des JPEGs optimisés sous <output_dir>/upload_assets/ et crée upload_manifest.json. Les valeurs par défaut sont 1 440 px de large pour les enregistrements en paysage et 900 px de large pour les enregistrements en portrait à qualité JPEG 75. Il enregistre les dimensions d'image, la qualité JPEG réelle, la taille du fichier et si chaque ressource rentre dans le budget de téléchargement.

6. Générer les fichiers d'appel Figma

Générer les scripts API Plugin autonomes :

python <SKILL_DIR>/scripts/generate_figma_calls.py \
  --prepared /tmp/vim_frames_<timestamp>/upload_manifest.json \
  --output-dir /tmp/vim_frames_<timestamp>/figma_calls/

Cela écrit :

  • figma_storyboard.js : un appel de création de storyboard combiné.
  • figma_apply_fills_template.js : un modèle de passe de remplissage pour les hashes d'image téléchargés.
  • figma_manifest.json : ordre d'exécution et instructions de téléchargement.
  • run_manifest.json : statut reprendre, moments sélectionnés, téléchargements attendus, ID de nœud, hashes d'image, statut de remplissage et statut de vérification.

Le JavaScript généré n'embarque pas les bytes d'image et n'appelle pas figma.createImage. Le script de storyboard crée tous les conteneurs de capture d'écran, étiquettes, annotations natives et surimpression de marqueurs en un appel, puis retourne uploadTargets contenant les ID de nœud Figma et les chemins JPEG locaux. Dans un nouveau fichier vierge, le script réutilise et renomme la page par défaut au lieu de créer une deuxième page.

7. Exécuter dans Figma et télécharger les ressources

Créer un nouveau fichier Figma Design ou ouvrir le fichier Design cible maintenant. Exécuter les fichiers générés dans figma_manifest.json :

  1. Lire figma_storyboard.js.
  2. Appeler use_figma contre le fichier Design cible avec le contenu JavaScript complet.
  3. Sauvegarder le JSON de résultat si pratique, puis mettre à jour le manifest d'exécution :
python <SKILL_DIR>/scripts/update_run_manifest.py \
  --run-manifest /tmp/vim_frames_<timestamp>/figma_calls/run_manifest.json \
  --storyboard-result /tmp/vim_frames_<timestamp>/storyboard_result.json

Pour chaque élément uploadTargets retourné :

  • Appeler upload_assets avec la fileKey cible, count: 1, nodeId et scaleMode: "FILL".
  • POSTer le fichier local à target.path vers l'URL de téléchargement retournée.
  • Enregistrer { "nodeId": "...", "imageHash": "...", "scaleMode": "FILL" } dans un fichier JSON de téléchargements.

Générer et exécuter la passe de remplissage :

python <SKILL_DIR>/scripts/update_run_manifest.py \
  --run-manifest /tmp/vim_frames_<timestamp>/figma_calls/run_manifest.json \
  --uploads-file /tmp/vim_frames_<timestamp>/uploaded_images.json \
  --write-fill-script /tmp/vim_frames_<timestamp>/figma_calls/figma_apply_fills.js

Exécuter figma_apply_fills.js une fois avec use_figma. Cette passe de remplissage d'image-hash explicite est préférée car elle rend les captures d'écran téléchargées dans les conteneurs générés de manière fiable.

8. Vérifier

Exécuter get_screenshot, download_assets ou get_design_context pour vérifier que :

  • Les captures d'écran sont visibles et non vierges.
  • Les anneaux de marqueur bleu sont assis sur les emplacements de cible/résultat prévus.
  • Les annotations natives utilisent des étiquettes humaines et n'exposent pas les valeurs de coordonnées.
  • Les cibles ambiguës ou déduites sont supprimées sauf si explicitement forcées avec show_marker: true.

Mettre à jour run_manifest.json avec les artefacts de vérification quand disponibles :

python <SKILL_DIR>/scripts/update_run_manifest.py \
  --run-manifest /tmp/vim_frames_<timestamp>/figma_calls/run_manifest.json \
  --verification-screenshot /tmp/vim_frames_<timestamp>/figma_storyboard.png \
  --verification-notes "Screenshots and markers verified"

Attentes de sortie

La disposition du storyboard est de gauche à droite :

[Title block]

[Before] [After]   [Before] [After]   [Before] [After]
moment 1           moment 2           moment 3

"Before state"     "01 Dropdown menu opens"
                   Annotation text...

Les surimpression d'anneau/point bleu montrent les emplacements de cible et de résultat quand les coordonnées sont disponibles et confiantes. Les annotations natives Figma s'attachent aux nœuds marqueur quand les marqueurs existent ; sinon elles s'attachent aux nœuds de capture d'écran avant/après pertinents. Les étiquettes d'annotation doivent nommer l'élément UI ou le changement d'état, jamais les pourcentages de coordonnées brutes.

Rapporter en retour :

  • Le nombre de moments clés mappés.
  • L'URL du fichier Figma.
  • Tous les moments dont le déclencheur était ambigu.
  • Tout téléchargement ou cadre qui a échoué.
  • Le statut de vérification et tout marqueur déduit/incertain.

Cas limites

  • Vidéo longue : demander une plage de temps ou avertir que le traitement peut prendre plus longtemps.
  • Trop de moments : augmenter --scene-threshold ou garder manuellement les 5 à 15 transitions les plus significatives.
  • Enregistrement mobile : garder la largeur par défaut du portrait de 900 px pour que le texte reste lisible sans ressources surdimensionnées.
  • Absence de preuve de déclencheur : utiliser Unknown trigger au lieu de deviner.
  • Échec du téléchargement de ressource : réessayer le téléchargement d'un upload_assets individuel cible ; le conteneur de capture d'écran généré reste dans le fichier et peut être réutilisé.
  • upload_assets réussit mais les images ne s'affichent pas : exécuter la passe de remplissage générée avec les hashes d'image retournés.
  • upload_assets n'est pas disponible : avertir que le chemin de repli est plus lent car il doit embarquer les données d'image directement dans les appels use_figma.

Skills similaires