Vidéo publicitaire animée
Créez chaque plan d'une vidéo produit sous forme d'une petite page HTML qui anime du véritable contenu du produit (captures d'écran, images vidéo, données exportées, chiffres réels), enregistrez chaque page en MP4 propre, et remettez à l'utilisateur un document de script qui lui indique exactement comment assembler les clips et quoi dire. L'utilisateur assemble les clips et enregistre la voix off dans son propre éditeur (Camtasia, Premiere, CapCut...).
Pourquoi cela fonctionne mieux qu'un enregistrement d'écran de l'application réelle : chaque plan est cadré, rythmé et zoomé pour la vidéo ; rien ne scintille, ne charge ou n'affiche de données privées ; le texte est suffisamment grand pour un téléphone ; et une modification ("raccourcis cette ligne", "ralentis le zoom") se fait par une édition et un réenregistrement, pas par un nouveau tournage. Cela reste honnête car les pixels et les chiffres sont ceux du produit lui-même.
Workflow
- Convenir de l'histoire (un message, puis c'est parti).
- Rassembler le matériel réel du produit.
- Construire une page par plan à partir de
assets/. - Vérifier les pages avec des captures d'écran, corriger, répéter.
- Enregistrer les clips avec
scripts/record.cjs; vérifier avec les planches contact. - Rédiger le document de script (
references/script-doc.md). - Audio et montage brut : musique (ElevenLabs, générée, ou leur propre fichier ;
references/music.md), une voix off optionnelle ElevenLabs (references/voiceover.md) ; aperçu avecscripts/roughcut.py. - Envoyer les clips, le document et l'aperçu ; itérer sur les retours plan par plan.
Placez le tout dans un dossier appartenant à l'utilisateur, par exemple video/ ou video-scripts/ :
<nom>-anim/ pages (un .html par plan), base.css, logo, dossiers frames/
<nom>-clips/ MP4 enregistrés : 01-hook-anim.mp4, 02-setup-anim.mp4 ... + README.md
<nom>-music/ WAV de fond, aperçu du montage brut, cuts.json
<Nom>.md le document de script
1. Histoire
Choisissez la durée (par défaut 30 s ; proposez une version de 45 à 60 s à partir des mêmes clips) et l'appel à l'action.
Choisissez le format d'image en fonction de l'endroit où la publicité sera diffusée, et construisez les pages à cette taille (pas un recadrage 16:9 ultérieur ; le recadrage fait perdre du texte et l'utilisateur doit recadrer chaque plan) :
| Emplacement | Taille |
|---|---|
| Instagram Reels/Stories, TikTok, YouTube Shorts, Facebook Reels | 1080×1920 (9:16) |
| Fil Instagram/Facebook | 1080×1350 (4:5) |
| Fil LinkedIn ou X | 1080×1080 (1:1) ou 1080×1350 |
| YouTube, site web, page d'atterrissage, présentations, non spécifié | 1920×1080 (16:9) |
Plusieurs emplacements : construisez pour l'emplacement principal et indiquez dans le document comment recadrer pour les autres. Pour le format vertical, gardez le texte en dehors des ~250 px du haut et ~350 px du bas, là où la plateforme affiche sa propre interface. Esquissez ensuite 6 à 9 plans, une idée chacun, selon cet arc :
- Accroche (≈3 s) : le problème, dans les mots du spectateur. Une question fonctionne ("Facture impayée après 30 jours ? Et maintenant ?").
- Mise en place (≈4 s) : le peu qu'il faut pour commencer.
- Fonctionnalités principales (2–3 plans, 4–5 s chacun) : le produit en action, avec le résultat qui apparaît à l'écran.
- Preuve (≈3 s) : un chiffre réel. Grand, simple, vrai.
- S'adapte à votre workflow (≈3 s) : exportation, intégration, partage.
- Carte de fin (≈3 s) : logo, promesse en une ligne, bouton CTA, URL.
Mettez en avant les points positifs. Montrez ce que le produit fait bien et à quel point c'est facile. Ne construisez pas de plan autour des cas d'échec ou de solutions de contournement du produit, même astucieuses ; une publicité qui explique comment l'outil s'en sort quand il se trompe donne l'impression qu'il se trompe souvent. Une correction rapide et confiante par l'utilisateur ("mauvaise catégorie ? cliquez, choisissez la bonne, c'est fait") est acceptable ; un plan sur les mécanismes des cas particuliers ne l'est pas.
Si l'utilisateur n'a rien dit, énoncez votre plan et vos hypothèses en un court message et commencez à construire ; il est moins coûteux de modifier un plan enregistré que d'en débattre dans l'abstrait.
Dans ce même message, demandez au sujet de l'audio (sauf s'il l'a déjà précisé), et continuez à construire pendant
qu'il se décide ; l'audio n'est nécessaire qu'à l'étape 7. Utilisez l'outil de question s'il existe. Vérifiez d'abord
si un MCP ElevenLabs est connecté (outils comme creative_generate_speech,
creative_list_voices, un type de nœud music) ; si c'est le cas, commencez par là.
Musique :
- ElevenLabs Music (recommandé quand connecté) : vous générez un fond instrumental calé sur le montage sur leur compte ElevenLabs. Pas connecté : vous écrivez le prompt, ils le génèrent sur elevenlabs.io/music et renvoient le fichier.
- Générée ici : un fond calme et libre de droits réalisé par
make_bed.py, gratuit et instantané. - Apportez la leur : un morceau qu'ils ont déjà ou dont ils ont la licence.
Voix off :
- Voix ElevenLabs (quand connecté) : vous choisissez une voix et générez la lecture, puis placez chaque ligne à son repère. L'utilisateur peut toujours enregistrer la sienne plus tard.
- Enregistrement par eux-mêmes à partir du texte clair dans le document (par défaut sans ElevenLabs).
ElevenLabs dépense des crédits sur leur compte : estimez d'abord le coût (estimate_only) et indiquez-le dans
la question. S'ils ont demandé de la musique sans préciser laquelle, ou si vous arrivez à l'étape 7 sans réponse,
générez le fond gratuit pour que l'aperçu ait du son, et répétez la question dans le message final avec
le prompt ElevenLabs déjà rédigé.
2. Matériel réel
Regardez dans le dépôt du produit, les dossiers de données, les exportations, les bases de données, les fixtures de test et les enregistrements. Pour chaque plan, collectez :
- Images : captures d'écran de l'interface réelle, ou images extraites d'une vidéo réelle
(
ffmpeg -ss T -i in.mp4 -frames:v N frames/f%03d.jpg). Plusieurs images créent du mouvement. Pour capturer une interface web (HTML local ou URL), utilisezscripts/grab.cjs: vue complète plus éléments nommés à 3x, et il affiche la boîte de chaque élément pour le cadrage :node <skill>/scripts/grab.cjs app.html <pages>/shots --size 1280x800 goal=.goal logo="header .logo". Derrière une connexion, demandez les captures d'écran à l'utilisateur plutôt que de vous connecter. - Chiffres : valeurs réelles issues des données du produit (temps, compteurs, lignes). Notez d'où vient chaque donnée ; cela apparaît dans le document dans la section "D'où viennent les chiffres".
- Positions : coordonnées des éléments à mettre en évidence, dans les pixels de l'image source (à partir de la sortie propre de l'application si possible, par exemple les boîtes de détection, ou mesurées en visualisant l'image).
Les lacunes sont normales ; gérez-les ouvertement :
- Pas de fichier logo : recadrez-le à partir d'une capture d'écran réelle de l'interface (en-tête, icône d'application) ou reconstruisez-le exactement à partir du CSS/SVG du produit. Mentionnez-le dans le document et demandez le fichier réel.
- Un écran nécessaire n'existe pas dans ce que vous avez (par exemple un formulaire de configuration) : dessinez-le dans le style du produit, et étiquetez le plan comme "reconstitué" dans le document afin que l'utilisateur puisse le remplacer par l'écran réel.
N'inventez jamais une statistique. Si un moment doit être reconstitué (une accroche dramatisée), étiquetez-le dans le document. Respectez la terminologie propre du produit et les règles de revendication (par exemple, un produit qui ne doit jamais qualifier ses chiffres de "garantis" ou "officiels") — vérifiez les documents/mémoire du projet pour ces règles avant d'écrire le texte.
3. Construire les pages
Copiez assets/base.css, assets/shot.js, assets/shot-template.html et assets/end-card.html
dans le dossier des pages. shot.js contient les fonctions utilitaires utilisées par chaque page (show/hide, cursorTo,
click, typeText, countUp, frameTo, preload) et la lecture automatique ; chargez-le avant le script
propre de la page et ne copiez pas les utilitaires dans les pages. Chaque page :
- Est une scène fixe à la taille choisie : définissez
--w/--hdansbase.css(par exemple1080px/1920px). Les modèles sont conçus pour le 16:9, donc repositionnez les éléments pour d'autres formats (empilez les panneaux verticalement pour le 9:16 ; en vertical, les titres commencent en dessous de ~250 px, pas à 96 px comme dans le modèle). Tailles de texte ≥ 26 px ; titres 80–100 px. La vidéo sera regardée sur un téléphone. - A une fonction asynchrone de premier niveau
async function start()qui contient toute la chronologie (await sleep(ms)entre les battements).shot.jsl'expose ; avec#manualdans l'URL elle attend, ouverte normalement elle se lance automatiquement une fois les polices et les images prêtes, afin que l'utilisateur puisse prévisualiser en double-cliquant. - Précharge chaque image qu'elle affiche plus tard (
preload(frames)au niveau supérieur) pour que rien n'apparaisse subitement à l'enregistrement ; l'enregistreur et le vérificateur les attendent. - Se termine sur un état figé et complet (résultat affiché, tout le texte présent) pour que le monteur puisse couper n'importe où vers la fin et maintenir la dernière image.
- Dessine les marques dans un
<svg viewBox="0 0 W H" preserveAspectRatio="xMidYMid slice">dimensionné à l' image source, afin que les coordonnées de l'application s'insèrent sans conversion et restent alignées lorsque le format de la scène recadre l'image. - Ressemble au produit : remplacez les variables dans
base.css(--accent,--hi,--ok,--ink, polices) par les couleurs et polices propres du produit. Pour un produit au thème clair, inversez également la couleur du texte,.shade,.panelet.bgen versions claires ; une publicité sombre autour d'une application claire donne l'impression qu'il s'agit d'un produit différent. - Affiche les captures d'écran de l'interface à leur taille réelle en pixels à l'intérieur de
.world(définissez.world { transform-origin:0 0 }et la<img>à sa taille CSS naturelle) et les cadre avecframeTo(x, y, scale), qui place le point (x, y) de la capture au centre de la scène ; les boîtes degrab.cjsfournissent les points. Pas deobject-fit:cover, qui recadre une capture de manière imprévisible lorsque son format ne correspond pas à celui de la scène. - Garde le texte du produit lisible : un texte de l'interface qui finit en dessous de ~22 px sur la scène (un label de 14 px dans une capture qui n'est pas zoomée) est illisible sur un téléphone. Zoomez dessus, ou reconstruisez cette partie (une carte, une alerte) dans le style propre du produit avec son texte exact à une taille lisible, et mentionnez dans le document quelles parties ont été reconstruites.
Schémas de plans qui ont fonctionné :
| Schéma | Comment faire |
|---|---|
| Produit en action | Séquence d'images échangées dans <img> toutes les 33–40 ms, boîtes/étiquettes dessinées par image, une ligne de résultat apparaît dans un panneau latéral au moment où cela se produit. |
| Zoom sur le détail | .world avec transform-origin sur le détail, ajoutez .zoom (échelle 1.5–1.6, 1.2 s ease). |
| L'utilisateur effectue une étape | await cursorTo(button) puis await click(button) : le curseur glisse jusqu'au centre mesuré de l'élément, ondule, le bouton appuie, puis le résultat. Tapez avec typeText(el, text) (55 ms par caractère ; gardez toute chaîne tapée en dessous de ~1 s). |
| Parcourir les images | Boutons Précédent/Suivant pressés en rythme, affichage du numéro d'image, l'image décisive marquée. |
| Deux vues concordent | Deux images côte à côte, le même moment marqué dans les deux, un badge indiquant la concordance. |
| Preuve | Lignes de tableau qui glissent (120 ms d'écart), puis 2–3 cartes de statistiques ; comptez le chiffre principal avec countUp(el, n) (~700 ms). |
| Données en sortie | Liste de résultats et un panneau fichier/intégration se remplissent en même temps, avec un indicateur "en direct". |
| Carte de fin | Balayage de ligne, logo, slogan, bouton CTA qui apparaît, URL. |
Pointez le curseur sur les éléments, jamais sur des coordonnées tapées à la main : cursorTo(el) mesure l'élément
au moment où le curseur se déplace, donc un zoom, un réagencement ou un autre format de scène ne peut pas le laisser cliquer
sur l'espace vide. click(el) enregistre une erreur si la pointe n'est pas sur el, et check.cjs échoue dessus. Utilisez
cursorTo({x, y}) uniquement pour un point qui n'est pas un élément. Prenez une capture de vérification au moment
chaque clic : un clic qui atterrit est la seule chose que les spectateurs remarquent quand c'est faux.
Affichez et masquez avec show(el) / hide(el) de shot.js. .on utilise !important, donc toute autre
classe ajoutée à côté pour masquer ou déplacer l'élément ne fait rien silencieusement ; enlevez toujours .on en premier
(c'est ce que fait hide). Pour une sortie personnalisée, el.classList.replace('on', 'my-exit').
Gardez la chronologie dynamique : 0.3–0.7 s entre les battements, ≈1 s pour lire un titre. Chaque clip dure généralement 4–8 s ; un plan de parcours peut durer 15 s car le monteur le coupera et l'accélérera.
Recadrez tout ce qui est incrusté dans la source et ne doit pas apparaître (date/heure de la caméra, barres d'état, noms
privés) en zoomant légèrement .world depuis le bord opposé (par exemple scale(1.08) depuis le bas).
Ne comptez pas sur backdrop-filter pour masquer des éléments : il ne rend pas dans le screencast.
4. Vérifier avant l'enregistrement
node <skill>/scripts/check.cjs <pages-dir> <chk-dir> hook:400:1500:3200 live:800:3000:6000
Prend des captures d'écran à ces ms après start() (il n'attend délibérément pas start() ; attendre
ne montrerait que l'état final) et affiche les erreurs de page. Lisez les captures d'écran. Vérifiez surtout :
- les marques se trouvent sur la bonne chose (la boîte sur la bonne personne, une ligne sur le bord d'attaque, pas sur un pied qui traîne ou un passant ; les pistes de détection peuvent passer à quelqu'un d'autre en milieu de séquence, donc assemblez ou corrigez les boîtes à la main) ;
- rien n'est coupé sur les bords, le texte ne chevauche pas le sujet ;
- chaque chiffre à l'écran correspond à la source.
5. Enregistrer
node <skill>/scripts/record.cjs <pages-dir> <clips-dir> hook=01-hook-anim=4200,setup=02-setup-anim=5000
page=nomFichier=ms : enregistrer pendant ms (durée de l'animation + ~1 s de fin figée). Chaque clip sort à la
taille de sa page (--w×--h), 30 fps, H.264 CRF 16, silencieux. check.cjs et roughcut.py suivent la
même taille, donc aucune modification de script n'est nécessaire pour le vertical ou le carré. Nécessite Chrome (ou le Chromium de Playwright) et Playwright
(npm i -g playwright une fois si pw.cjs ne le trouve pas), ainsi que ffmpeg.
Les clips durent le nombre de ms demandé plus ~0.3 s. La première image est la page avant le premier battement de start(),
donc les points d'entrée commencent généralement à 0.1–0.3 s ; lisez-les sur la planche contact.
Vérifiez chaque clip sans le regarder :
bash <skill>/scripts/sheet.sh <clips-dir>/03-live-anim.mp4 sheet.jpg 2
Lisez la planche contact : timing de chaque battement, rien d'écrasé ou de coupé, dernière image complète. Notez les secondes d'entrée et de sortie de la partie utile de chaque clip ; elles iront dans le tableau de montage.
Nommez les clips NN-nom-anim.mp4 dans l'ordre de l'histoire (04b, 04c pour les alternatives) et écrivez un court
README.md dans le dossier des clips les listant.
6. Document de script
Suivez references/script-doc.md. Le tableau de montage (temps, clip, entrée–sortie, vitesse, ce que vous voyez,
début VO, ligne) est le cœur du document ; le reste est ce dont l'utilisateur a besoin pour terminer sans vous.
Voix off : ~2.5 mots par seconde, conversationnel, une ligne par plan, CTA dit à voix haute
("Essayez-le gratuitement. Cliquez sur le lien, ou visitez exemple.com.").
La plupart des vidéos sociales sont regardées en mode muet, y compris les Reels et TikTok. Donnez toujours au tableau de montage une colonne "À l'écran" et faites en sorte que le texte à l'écran raconte l'histoire par lui-même. Lorsqu'il y a une voix off (Reels, TikTok, Shorts), ajoutez également des sous-titres incrustés dans les étapes du monteur, placés dans la zone de sécurité verticale et déposés sur les plans dont le titre est déjà ...
... [tronqué pour la traduction]