Communitygithub.com

product-demo-video

Cette compétence est utilisée lorsque l'utilisateur demande de « créer une vidéo de démonstration produit », « réaliser une vidéo de démo d’application », « produire une vidéo d’annonce de fonctionnalité », « faire une démo SaaS », « créer une vidéo de parcours UI », « animer des captures d’écran produit en démo », « ajouter un curseur/clic animé sur une capture d’écran » ou « zoomer sur une partie d’une UI ». Elle couvre la transformation de captures d’écran ou maquettes statiques (pas d’enregistrement d’écran) en une démo animée propre : cadres d’appareil/navigateur, curseur animé + effet de clic, zoom/pan sur l’UI focale, annotations callout, rythme des étapes, transitions entre écrans et légendes de fonctionnalités.

Qu'est-ce que product-demo-video ?

La compétence `product-demo-video` permet de transformer des captures d'écran ou maquettes statiques de produits en vidéos de démonstration animées et soignées, sans avoir recours à un enregistreur d'écran. Idéale pour les démos d'applications SaaS, les annonces de fonctionnalités ou les parcours d'intégration, elle génère des animations précises et reproductibles : un curseur synthétique se déplace sur un chemin fluide (smoothstep), un effet de clic (ripple) se déclenche au moment précis, puis un zoom (2× maximum) isole la zone d'intérêt, accompagné d'une annotation callout et d'une légende de fonctionnalité. L'ensemble est basé sur Remotion (React), où chaque valeur d'animation (position du curseur, échelle du zoom, opacité des légendes) est une fonction pure de `useCurrentFrame()`, garantissant une absence de jitter et une reproduction à l'identique même après changement des captures. La compétence inclut des composants pour encadrer les écrans dans un navigateur ou un mobile, un système de curseur + ripple, une transition de zoom à la Ken Burns, des annotations et légendes, ainsi que des transitions standardisées entre écrans (push, cross-zoom, crossfade, match-cut). Le livrable est un projet Remotion complet, exportable en MP4 ou GIF, avec des scripts de vérification (rendu d'images clés puis encodage final).

Compatible avec~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/playlikeboy/videos-skill/tree/HEAD/.claude/skills/product-demo-video

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Vidéo de Démonstration Produit

Transformez des captures d'écran ou maquettes statiques de produit en une démo animée et soignée — sans enregistreur d'écran, sans curseur réel tremblant, sans dérive de version UI. Encadrez chaque écran, faites glisser un curseur synthétique jusqu'au pixel exact, faites onduler le clic, puis zoomez sur la partie importante et légendez la fonctionnalité. Parce que l'entrée est statique et le mouvement est du code, chaque valeur est déterministe et se re-rend à l'identique lorsque la capture d'écran change.

Quand l'utiliser

  • Démo d'application / SaaS, annonce de fonctionnalité, parcours d'intégration (15–90 s).
  • Montrer un chemin de clics à travers une UI dont vous n'avez que des captures d'écran ou maquettes.
  • Mettre en évidence une région focale d'un tableau de bord dense (zoom sur région + callout).

Pourquoi les captures d'écran surpassent les enregistrements d'écran

Enregistrement d'écranPiloté par capture d'écran (cette compétence)
Le vrai curseur dérive, dépasse, trembleLe curseur suit un chemin fluide jusqu'à une cible exacte
Réenregistrer toute la prise pour corriger une étapeÉchanger un PNG, re-rendre le même code
L'UI change en cours de prise, la souris chercheChaque écran est un actif propre et final
Difficile de zoomer sans pixellisationExporter les captures en 2× (DPR 2) → zooms nets

Capturez les entrées à deux fois la taille d'affichage (retina / deviceScaleFactor: 2) pour qu'un zoom 2× reste net. Voir references/screenshot-demo.md pour un script de capture Playwright.

La boucle de démo

Chaque démo suit le même rythme, répété par fonctionnalité. Tenez assez longtemps pour lire, déplacez-vous avec intention, posez le clic, révélez le résultat.

TempsDuréeRôle
Poser sur l'écran0,5–1 sLaisser le spectateur s'orienter avant tout mouvement
Le curseur se déplace vers la cible0,4–0,8 sMouvement fluide (ease-in-out), pas linéaire
Ondulation du clic + changement d'état0,2–0,3 sRetour tactile ; l'écran réagit sur la même image
Zoom sur la région focale1–2 s entrée, tenir 2–4 s2× est le point idéal — assez de détails, garde le contexte
Légender la fonctionnalitétenir avec le zoomUne phrase de bénéfice, ex. « Export en un clic »

Bougez la caméra ou le curseur, rarement les deux à la fois — deux mouvements simultanés divisent l'attention.

Encadrer la capture d'écran

Une capture d'écran brute ressemble à un rapport de bug ; une capture encadrée ressemble à un produit. Enveloppez chaque écran dans un chrome de navigateur ou d'appareil sur un fond de marque.

// Cadre de navigateur — déposez une capture, obtenez une fenêtre crédible
const BrowserFrame = ({ url, children }) => (
  <div style={{ borderRadius: 12, overflow: "hidden", background: "#1e1e22",
                boxShadow: "0 40px 80px rgba(0,0,0,.35)" }}>
    <div style={{ height: 40, display: "flex", alignItems: "center", gap: 8, padding: "0 14px" }}>
      {["#ff5f57", "#febc2e", "#28c840"].map((c) => (
        <span key={c} style={{ width: 12, height: 12, borderRadius: "50%", background: c }} />
      ))}
      <div style={{ marginLeft: 12, flex: 1, height: 24, borderRadius: 6, background: "#2b2b30",
                    color: "#9aa", fontSize: 13, display: "flex", alignItems: "center", padding: "0 10px" }}>
        {url}
      </div>
    </div>
    <div style={{ background: "#fff" }}>{children}</div>
  </div>
);

Mettez une URL réelle dans la barre d'adresse (authenticité), ajoutez une ombre douce et un arrière-plan en dégradé. Pour le mobile, passez à un cadre de téléphone avec une encoche et des coins arrondis. Gardez le style du cadre dans un seul objet thème pour que chaque écran corresponde.

Curseur animé + ondulation de clic (le mouvement principal)

Pilotez la position à partir de l'image actuelle, jamais à partir d'une transition CSS ou d'une horloge murale — un rendu vidéo a besoin que chaque image soit une fonction pure du numéro d'image, sinon le curseur se désynchronise et scintille.

import { useCurrentFrame, interpolate, spring, useVideoConfig } from "remotion";

// Trajet fluide de `from` à `to` entre startFrame et startFrame+dur
const useCursor = (from, to, startFrame, dur) => {
  const frame = useCurrentFrame();
  const t = interpolate(frame, [startFrame, startFrame + dur], [0, 1],
    { extrapolateLeft: "clamp", extrapolateRight: "clamp", easing: (x) => x * x * (3 - 2 * x) }); // smoothstep
  return { x: from.x + (to.x - from.x) * t, y: from.y + (to.y - from.y) * t };
};

export const Cursor = ({ from, to, startFrame, dur, clickAt }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const { x, y } = useCursor(from, to, startFrame, dur);

  // L'ondulation s'étend une fois, à l'image du clic
  const since = frame - clickAt;
  const showRipple = since >= 0 && since < 18;
  const r = spring({ frame: since, fps, config: { damping: 18 }, durationInFrames: 18 });

  return (
    <>
      {showRipple && (
        <div style={{ position: "absolute", left: x, top: y, transform: "translate(-50%,-50%)",
          width: 12 + r * 60, height: 12 + r * 60, borderRadius: "50%",
          border: "2px solid rgba(80,140,255,.9)", opacity: 1 - r }} />
      )}
      <svg width="28" height="28" viewBox="0 0 28 28"
           style={{ position: "absolute", left: x, top: y, filter: "drop-shadow(0 2px 3px rgba(0,0,0,.4))" }}>
        <path d="M3 2 L3 21 L9 15 L13 24 L16 23 L12 14 L20 14 Z" fill="#fff" stroke="#222" strokeWidth="1.4" />
      </svg>
    </>
  );
};

Le curseur utilise smoothstep pour accélérer depuis l'arrêt et décélérer jusqu'à la cible (un curseur linéaire semble robotique). Déclenchez l'ondulation et le changement d'état de l'écran sur la même image clickAt pour que la cause et l'effet correspondent. Voir references/screenshot-demo.md pour la composition complète gérant plusieurs clics sur plusieurs écrans.

Zoom sur une région (Ken Burns pour UI)

Pour zoomer sur un élément focal, mettez à l'échelle l'écran et définissez transform-origin au centre de cet élément, afin que le zoom converge vers lui plutôt que vers le centre du cadre.

const ZoomToRegion = ({ target, scale = 2, startFrame, dur, children }) => {
  const frame = useCurrentFrame();
  const s = interpolate(frame, [startFrame, startFrame + dur], [1, scale],
    { extrapolateLeft: "clamp", extrapolateRight: "clamp", easing: (x) => 1 - Math.pow(1 - x, 3) }); // easeOutCubic
  return (
    <div style={{ transform: `scale(${s})`, transformOrigin: `${target.x}px ${target.y}px`,
                  willChange: "transform" }}>
      {children}
    </div>
  );
};

Limitez le zoom à environ 2× (au-delà de 3× perd le contexte et désoriente). Maintenez l'état zoomé 2–4 s — assez longtemps pour lire le détail — puis revenez en arrière avant de passer à l'écran suivant. Associez le zoom à un callout, jamais brut.

Annotations callout et légendes de fonctionnalités

Annotez l'inflexion, puis laissez-la disparaître. Un callout est une étiquette + un connecteur (flèche, cercle ou soulignement) qui pointe vers l'élément focal.

  • Mettez en évidence l'élément avec un anneau doux ou un fond assombri (box-shadow: 0 0 0 9999px rgba(0,0,0,.45) découpe un trou de projecteur).
  • Légendez un bénéfice par temps — une courte phrase nominale (« Analytics en temps réel »), pas une phrase. Entrez au zoom, sortez avant l'étape suivante.
  • Gardez les légendes dans le tiers inférieur et dans la zone de sécurité titre pour qu'elles survivent aux recadrages en 9:16.

Voir references/annotation-and-transitions.md pour les masques de projecteur, les connecteurs fléchés et une piste de légendes typées.

Transitions entre écrans

Entre les étapes, déplacez les écrans avec un langage cohérent. Choisissez-en un et tenez-vous-y :

TransitionSensationUtilisation
Pousser / glisserMouvement avant "étape suivante"Parcours linéaires
Zoom croiséÉlan, comme une appSauter dans une vue détaillée
Fondu enchaînéCalme, neutreChanger de contexte (paramètres → tableau de bord)
Coupe franche sur un élément partagéSans coutureMême carte persiste entre les écrans

Maintenez l'écran sortant jusqu'à ce que son clic se résolve, puis transitionnez — ne coupez jamais en plein mouvement. Voir references/annotation-and-transitions.md.

Liste de vérification de sortie

  • Entrées capturées en 2× (DPR 2) ; les zooms restent nets en 2×.
  • Chaque valeur de curseur/zoom est une fonction pure de useCurrentFrame() — pas de transitions CSS pour l'état animé.
  • Le curseur se déplace sur un chemin fluide (smoothstep) ; l'ondulation et le changement d'état se déclenchent sur la même image de clic.
  • Chaque écran est encadré (navigateur/appareil) avec une URL réelle et un thème cohérent.
  • Un mouvement à la fois (caméra ou curseur) ; zoom ≤ 2×, maintenu 2–4 s.
  • Une légende de bénéfice par temps, dans le tiers inférieur zone de sécurité titre ; les transitions utilisent un langage cohérent.

Livrer et vérifier (images clés rendues → MP4)

Aide empaquetée (scripts/) : assemblez vos images clés avec scripts/contact-sheet.sh sheet.png f-hook.png f-mid.png f-end.png, puis vérifiez l'encodage avec scripts/probe-mp4.sh out.mp4 [LxH] [fps]. Voir scripts/README.md.

C'est un niveau lourd : le livrable est un MP4, pas une page live. La démo ingère les actifs de l'utilisateur — captures d'écran/maquettes, logo optionnel — donc la vérification porte surtout sur la bonne image s'est-elle chargée et se trouve-t-elle dans le cadre.

Contrat de sortie :

  • Un projet Remotion avec la composition enregistrée (<Composition> + zod schema + defaultProps) ; chaque valeur de curseur/zoom/transition est une fonction pure de useCurrentFrame() (pas de transitions CSS, minuteries, Date.now()).
  • Les captures d'écran chargées via staticFile(), verrouillées avec delayRender/continueRender pour que le PNG 2× (et toute police web) soit présent avant que l'image ne soit rendue — sinon l'écran apparaît vide en pleine démo.
  • Livrable = le out/*.mp4 rendu plus le projet (re-rendre lorsque la capture d'écran change).

Boucle de vérification — rendu d'images clés → inspection → encodage. Des PNG bon marché d'abord, la vidéo seulement une fois qu'ils sont corrects.

# Images clés exactes AVEC LES PROPS QUE VOUS ALLEZ LIVRER (chemins réels des captures), pas defaultProps
npx remotion still ProductDemo out/f-settle.png --frame=15  --props=demo.json   # écran cadré, avant mouvement
npx remotion still ProductDemo out/f-click.png  --frame=90  --props=demo.json   # curseur sur la cible + ondulation
npx remotion still ProductDemo out/f-zoom.png   --frame=150 --props=demo.json   # zoomé sur la région focale + légende
# image finale = durationInFrames - 1 (npx remotion compositions le lit)

Inspectez chaque PNG pour la fidélité (capture correcte chargée ; curseur sur le pixel exact ; ondulation de clic et changement d'état sur la même image ; texte de légende correct) ET les artefacts (image vide/non chargée, écran hors cadre, zoom pixélisé ou dépassant le cadre, légende hors du tiers inférieur zone de sécurité titre, mauvais rapport hauteur/largeur ou letterbox).

# Seulement après que les images clés sont propres :
npx remotion render ProductDemo out/demo.mp4 --props=demo.json
npx remotion render ProductDemo out/demo.gif --props=demo.json --codec=gif   # preuve dans le README du premier écran

Traitement par lot (un modèle, plusieurs produits) : lorsque vous ré-adaptez la démo par produit, vérifiez les props d'UN produit représentatif via des images clés avant de rendre le catalogue en lot — attrapez un bug d'image vide ou hors cadre une fois, pas N fois.

Avant de terminer :

  1. Les images clés se rendent proprement au repos / clic / fin — pas d'erreurs, les captures sont bien chargées (pas vides).
  2. Le curseur atterrit sur la cible exacte ; ondulation + changement d'état sur la même image ; texte de légende correct et dans le tiers inférieur zone de sécurité titre.
  3. Tout mouvement est piloté par image — pas de transitions CSS / minuteries / Date.now() / Math.random().
  4. Les props livrées (chemins réels des captures) s'affichent correctement, pas seulement defaultProps.
  5. MP4 complet encodé et lisible ; (optionnel) GIF rendu pour le README.

Fichiers de référence

  • references/screenshot-demo.md — une démo Remotion complète et exécutable : capture d'écrans en 2× avec Playwright, les composants de cadre navigateur/téléphone, une composition multi-étapes qui déplace un curseur sur plusieurs écrans avec ondulations de clic, et une commande de rendu.
  • references/annotation-and-transitions.md — masques de projecteur, connecteurs de callout fléchés/circulaires, une piste de légendes de fonctionnalités typées, et les quatre transitions entre écrans avec implémentations pilotées par image et notes de zone de sécurité multi-aspect (16:9 / 9:16).

Individual skills in this repo

This repo contains 6 individual skills — each has its own dedicated page.

animated-infographic

This skill should be used when the user asks to "make an animated infographic", "create an infographic video", "build an infographic animation", "animate an explainer infographic", "do a sequenced reveal of icons and stats", "animate icons with key numbers and connectors", or "lay out a designed infographic that animates in sequence". Covers infographic layout & visual hierarchy, staggered element reveals, animating icons/pictograms, key-number counters, connectors/flow, and section pacing. For heavy charting (bar chart race, charts from a CSV) use the chart-animation skill instead.

brand-motion-guidelines

This skill should be used when the user asks to "write motion guidelines", "create a brand motion system", "define easing and timing tokens", "document our animation principles", "build a motion language like Slack/IBM/Klarna", "set up entrance/exit/transition rules", or "add a reduced-motion / accessibility section". It outputs a fill-in-ready brand motion guidelines document.

explainer-video

This skill should be used when the user asks to "make an explainer video", "turn this into a short explainer", "write a script and storyboard for a product video", "produce a how-it-works/onboarding video", "sync narration and captions", or "build a 30–90s animated explainer". Covers script→storyboard→scene build→narration/caption sync→edit→polish.

presentation-video

This skill should be used when the user asks to "make an animated presentation", "turn a pitch deck into a video", "convert slides/a deck to video", "make a presentation video", "build a deck video", "narrate a slide deck as a video", or "auto-advance slides synced to a voiceover". Covers rebuilding slides as motion graphics with staggered build reveals, slide-to-slide transitions, and timing locked to per-slide narration.

shot-composition

This skill should be used when the user asks to "compose a frame", "set up a grid", "plan shot composition", "place the focal point", "decide where elements enter and exit", "add a parallax/camera move", "adapt a layout for 16:9 / 9:16 / 1:1", or "keep content inside safe areas". Covers grids, safe areas, focal hierarchy, and 2D/3D camera framing.

whiteboard-animation

This skill should be used when the user asks to "make a whiteboard animation", "draw-on explainer", "VideoScribe style", "hand-drawn explainer video", "animate a sketch being drawn", "do a doodle/scribe video", "show a hand drawing the illustration", or "animate handwriting appearing on a whiteboard". Covers SVG stroke draw-on, a marker hand that follows the path tip, staggered reveal, erase/wipe transitions, and narrated export.

Skills associés