Vidéo teaser
Produisez une bande-annonce de qualité lancement (~30-45 s) d'une application en cours d'exécution : storyboard, tournage en pilotant l'interface réelle, montage avec ffmpeg, et livraison d'un MP4 accompagné d'un GIF pour le README.
Le résultat doit ressembler à une vidéo produit, pas à un enregistrement d'écran. La différence réside dans la mise en scène, le cadrage et le rythme, pas dans la résolution.
Les implémentations de référence se trouvent dans reference/ ; ce sont des modules ESM fonctionnels, pas du pseudo-code. Installez-les dans un répertoire temporaire, jamais dans le projet :
cp -r <skill>/reference/* "$SCRATCH/" && cd "$SCRATCH" && npm install
export TEASER_BASE_URL="https://the-app.example.com"
reference/package.json déclare "type": "module" et les trois dépendances. Chaque script lit TEASER_BASE_URL, donc rien n'est codé en dur pour une application particulière.
Avant toute chose : les deux règles strictes
1. Ne jamais déclencher d'effets secondaires réels sans consentement explicite et détaillé.
Filmer une application réelle signifie cliquer sur de vrais boutons. Certains envoient des emails, publient publiquement, facturent de l'argent ou soumettent des formulaires à des tiers. Avant de toucher à l'application :
- Énumérez chaque action de votre storyboard qui quitte la machine.
- Dites à l'utilisateur exactement ce que chacune fait et combien de fois, puis obtenez son accord sur le compte.
- Privilégiez un mode qui s'arrête avant l'étape irréversible (un aperçu, un dry-run, une porte de confirmation que vous pouvez filmer puis décliner).
Il n'existe pas de sonde en lecture seule contre un système en direct. Un clic « diagnostique » qui atterrit dans une session déjà en cours s'exécute pour de vrai. Si vous déboguez pourquoi une action n'a pas fonctionné, supposez que votre prochain clic fonctionnera, et soyez prêt.
Si quelque chose se déclenche que vous n'aviez pas prévu : arrêtez le processus à sa source immédiatement (tuez la session/le worker, pas seulement le bouton UI, qui pourrait ne pas faire effet), vérifiez l'état arrêté en le relisant, et informez l'utilisateur clairement dans votre message final — compte inclus.
2. Considérez que chaque image est publique et pleine de données personnelles.
Les comptes réels contiennent des noms, emails, adresses et documents. Décidez de la politique avec l'utilisateur en amont :
- Cadrer autour (par défaut) — composez des plans qui excluent l'identité. Rognez les éléments persistants (barres latérales, avatars, menus de compte) à l'étape ffmpeg.
- Masquer avant de filmer — utilisez
page.evaluatepour unvisibility: hiddensur les cartes problématiques avant que la caméra ne tourne. Ne filmez jamais en espérant couper autour après. - Utiliser un compte de démonstration prérempli — le plus propre quand il en existe un.
Passez en revue chaque image du montage final en pleine résolution avant de livrer. Pas le contact sheet — les images elles-mêmes.
Workflow
1. Reconnaissance et storyboard
Prenez d'abord des captures d'écran authentifiées de chaque écran candidat (reference/scout.js). Regardez-les. Ensuite, rédigez un tableau de storyboard : séquence, plan, ce que le spectateur doit ressentir, et durée. Un plan sans fonction assignée est coupé avant d'être filmé.
L'arc qui fonctionne : tension (le problème) → révélation (le produit) → preuve (il fait vraiment la chose) → ampleur (les résultats) → confiance (là où il tourne) → conclusion.
Notez dans le storyboard quels écrans contiennent des données personnelles et lesquels sont sûrs.
2. Préparation de la scène
Organisez avant de filmer, jamais après :
- Choisissez des vues où les données sont les plus belles — graphiques complets, listes actives, noms reconnaissables, compteurs non nuls. Ne filmez jamais un spinner, un état vide, ou un graphique à moitié rendu.
- Réglez délibérément l'état de l'interface (largeurs de panneaux, réduit/développé, filtres, position de défilement) via
localStoragedans un script d'initialisation ou unpage.evaluateavant le tournage. - Masquez les notifications, bannières et barres de cookies hors caméra.
- Laissez les données se stabiliser :
networkidleplus quelques secondes.
3. Tournage
Utilisez le screencast CDP (Page.startScreencast), pas un enregistrement d'écran. Il capture la page hors-écran à ~100 ips, donc rien de ce que l'utilisateur fait n'apparaît dans le cadre et la machine reste utilisable. Playwright pilote ; CDP filme. reference/rig.js l'implémente.
- Un seul sujet par plan. Cadrez la chose, pas « toute l'application ».
- Les mouvements de caméra proviennent d'un défilement scripté avec easing à l'intérieur de la page (
cameraScroll), jamais d'un filtre. Voir l'avertissement sur zoompan ci-dessous. - Le curseur est un acteur : utilisez le curseur SVG injecté (
cursorClick) qui glisse avec un easing et s'abaisse lors du clic, ou masquez-le. Pas de dérive oisive. - Répétez chaque prise, extrayez les images, regardez-les, ajustez, puis filmez pour de bon.
Filmer une fenêtre externe (un navigateur que l'application ouvre elle-même, une application de bureau) nécessite une capture du système d'exploitation — gdigrab/x11grab/avfoundation (recordDesktop dans le rig). Cela capture tout ce qui est à l'écran, y compris le travail personnel de l'utilisateur. Avertissez l'utilisateur, demandez-lui de s'éloigner, et passez en revue le résultat image par image ; supprimez-le s'il a capturé quelque chose de privé.
4. Cartes-titres
HTML/CSS animé filmé dans le navigateur, pas des images statiques. Injectez le balisage de la carte dans une page vierge sur la propre origine de l'application pour que ses polices web et sa palette se résolvent, puis enregistrez en screencast. Récupérez la police d'affichage réelle de la page en direct (getComputedStyle) et fixez une pile mono connue plutôt que de la deviner.
Adaptez le langage de mouvement de l'application (ses propres courbes d'easing et durées). Chargez la compétence frontend-design avant de les concevoir si le projet n'a pas de style de carte établi.
5. Montage
reference/build.js normalise chaque segment à une taille/ips commune, puis enchaîne avec des fondus enchaînés. Gardez des coupes toutes les ~2,5-4 s. Donnez de l'espace au moment de révélation à vitesse normale tout en compressant la routine autour.
6. Révision, puis livraison
- Générez un contact sheet et des images en pleine résolution par seconde.
- Lisez les images pour détecter des données personnelles, des panneaux coupés, et du texte illisible.
- Vérifiez la durée et les dimensions avec une sonde.
- Livrez un MP4 ainsi que, pour les README, un GIF optimisé par palette (GitHub ne lit pas en ligne un MP4 commité). Gardez le GIF sous ~10 Mo.
- Laissez-le sans son sauf demande contraire ; vous ne pouvez pas licensier de musique. Dites-le.
Spécificités durement acquises
N'utilisez jamais zoompan pour des zooms avant. Il recalcule le zoom par image et arrondit la fenêtre de recadrage aux pixels entiers, donc l'image saute d'avant en arrière — cela donne l'impression d'un tremblement de terre. Utilisez des plans fixes plus un défilement réel dans la page. Si vous devez absolument avoir un zoom avant, pré-échelonnez la source 4x d'abord, et vérifiez avec une mesure de delta d'image (reference/jitter.js) : un plan fixe verrouillé doit avoir un delta moyen bien inférieur à 1,0 ; un tremblement visible donne 3+.
Le screencast cesse d'émettre des images lorsque l'animation se stabilise. Une carte dont l'animation se termine après 1,2 s produit un clip de 1,2 s. Comblez avec tpad=stop_mode=clone:stop_duration=N et coupez à la longueur souhaitée avec -t.
Assemblez des images avec horodatage, pas un taux fixe. Les images du screencast arrivent avec metadata.timestamp ; écrivez une liste de concaténation ffmpeg avec des durées réelles par image, puis rééchantillonnez à 60 ips constantes. Supposer un intervalle fixe produit des saccades.
ffmpeg-static comme dépendance de développement, résolue par le chemin du module. Ne dépendez jamais de ffmpeg dans le PATH. (ffprobe n'est pas dans ce paquet — analysez la sortie stderr de ffmpeg -i à la place.)
Capture authentifiée : connectez-vous une fois en mode Headed, sauvegardez storageState, réutilisez-le pour chaque prise (reference/login.js). Les sessions expirent — terminez le tournage le même jour ou relancez-le. Initialisez également toutes les préférences UI localStorage à cet endroit.
Localhost depuis une origine déployée est bloqué par la politique d'accès au réseau local de Chrome. Si la page doit atteindre un service local, lancez avec --disable-features=LocalNetworkAccessChecks,PrivateNetworkAccessChecks,BlockInsecurePrivateNetworkRequests.
Rognez les éléments persistants à un décalage fixe. Filmez à une largeur de fenêtre 1920 + railWidth, puis crop=1920:1080:railWidth:0 pour enlever la barre latérale et atterrir exactement sur du 1080p.
Livrables
Signalez le chemin, la durée et les dimensions ; indiquez clairement ce qui est encore nécessaire de la part de l'utilisateur (musique, téléchargement vidéo natif GitHub) ; et divulguez tout ce qui s'est passé pendant le tournage qu'il voudrait savoir.