project-demo-video
Construisez la vidéo de démonstration sous forme de code afin de pouvoir la re-rendre en quelques minutes après toute modification. Tout ce qui est à l'écran est réel : l'application en cours d'exécution, la sortie réelle des commandes, les fichiers sources réels. Rien n'est une maquette.
Cette compétence est rédigée pour qu'un agent de codage moins performant puisse la suivre étape par étape. Suivez les phases dans l'ordre. Chaque phase a une ligne Fait quand : ne passez pas à la suivante tant qu'elle n'est pas vraie. Copiez les fichiers de templates/ au lieu de les réécrire.
Installation : copiez l'intégralité de ce dossier (SKILL.md et templates/) vers le dossier des compétences de l'agent, par exemple ~/.claude/skills/project-demo-video/, ou pointez simplement l'agent vers SKILL.md.
Ce que vous produisez
| Sortie | Remarques |
|---|---|
<nom>-voiced.mp4 | 1920×1080, 30 ips, H.264 + AAC, sous-titres incrustés, avec voix |
<nom>-captions-only.mp4 | même image, piste audio silencieuse (l'utilisateur peut choisir celle-ci ou enregistrer sa propre voix) |
<nom>.srt | sous-titres sous forme de fichier, même texte que la narration |
thumbnail.png | 1280×720 |
narration.md, shotlist.md | script avec horodatages réels ; chaque scène avec sa source |
frames/ | les images de contrôle qualité que vous avez réellement examinées |
repo/ | fichiers du projet modifiés ou nouveaux, reflétés à leurs chemins dans le dépôt |
COPY_LIST.md, README-snippet.md, REPORT.md | quoi copier où, une section README "Voir le fonctionnement", ce qui est fait et ce qui est risqué |
0. Règles à ne pas enfreindre
- Source en lecture seule. N'écrivez jamais, ne validez jamais et ne poussez jamais depuis les vrais dépôts de l'utilisateur. Travaillez dans une copie (
robocopy/cp, en excluantnode_modules,.git, les artefacts de build), puis exécuteznpm cià cet endroit. Conservez les modifications qui méritent d'être conservées dans le dossier de sortie, en reflétant les chemins du dépôt, plusCOPY_LIST.md. Un autre outil ou une autre personne effectue le travail git. - Soyez honnête à l'écran. Tout ce qui est simulé (un appareil, un connecteur, un paiement, un modèle) est étiqueté comme simulé dans la vidéo. Ne sous-entendez jamais de matériel, de déploiements ou d'utilisateurs qui n'existent pas. Copiez le propre tableau "réel vs simulé" du projet ; si le README est erroné, dites-le dans le rapport et ne répétez pas l'affirmation.
- Pas de secrets à l'écran ou dans les fichiers livrés : jetons, clés API, contenus de
.env, clés privées, e-mails réels. Les jetons de développement que le projet documente (par exempleBearer dev-alice) sont acceptables. Lorsque vous montrez du code, choisissez des plages de lignes qui excluent les secrets. - Aucune mention de l'outil d'IA qui a écrit le code, ou de son fournisseur, dans les images, la narration, les sous-titres ou les documents livrés, sauf indication contraire de l'utilisateur. Un identifiant de modèle d'exécution qui fait partie de la configuration du produit peut apparaître comme nom de modèle. Vérifiez avec
grep -riavant de terminer. - Respectez les règles du concours. Lisez la limite de durée (généralement "moins de 3:00" ; visez 2:50) et la règle de technologie requise. La vidéo doit montrer la technologie requise en fonctionnement réel, pas seulement la mentionner.
- Niveau gratuit, pas de déploiements, pas d'achats. Ne déployez pas, ne créez pas de ressources cloud et ne dépensez pas d'argent. Si une étape nécessite un identifiant ou un enregistrement de l'utilisateur, demandez-le une fois, clairement, et continuez avec tout le reste.
- Demandez à l'utilisateur uniquement les identifiants, ses propres enregistrements ou un choix qui lui appartient vraiment (par exemple, quelle voix). Décidez de tout le reste vous-même et dites ce que vous avez décidé.
1. Prérequis (vérifiez, ne présumez pas)
node --version # 22+ (24 recommandé ; les fichiers .mjs doivent être en JavaScript pur, pas de casts TypeScript)
- Dans la copie du projet :
@playwright/test(avec Chromium installé) etffmpeg-staticdoivent exister. Vérifiez :node -e "import('@playwright/test').then(async m=>{const b=await m.chromium.launch();console.log(b.version());await b.close()})"etnode -e "import('ffmpeg-static').then(m=>console.log(m.default))". Si manquants et que le projet interdit les nouvelles dépendances, placez-les dans un dossier d'outils séparé et pointez vers celui-ci. - Parole : Windows PowerShell avec
System.Speech(intégré). Sur macOS, utilisezsay, sur Linuxespeak-ng; vous devez alors adaptertemplates/lib/tts.mjs(seulssynthAllettts.ps1sont spécifiques au système d'exploitation). - Aucun
ffproben'est livré avec ffmpeg-static : mesurez les durées à partir des en-têtes WAV (wavSecondsdanstemplates/lib/tts.mjs) et du chronométrage de l'enregistreur. - Remarques sur le shell Windows : privilégiez les outils Write et Edit pour tout fichier contenant des barres obliques inverses, des expressions régulières ou
$. La réécriture en lignepython -c/heredoc du JS corrompt silencieusement les échappements. Lesleepau premier plan est bloqué dans certains agents : attendez avecuntil grep -q "done" log; do sleep 10; done.
2. Phases
Phase A : Exigences et carte de preuve
Lisez la page des règles, le README, les propres documents du projet et toutes les notes sur le scénario. Écrivez un tableau dans vos notes :
| Le jury doit être convaincu que | Où la vidéo le prouve | Scène |
|---|---|---|
| la technologie requise est appelée dans le code | appel réel visible : journal des requêtes, terminal, extrait de code | ... |
| l'expérience fonctionne | application s'exécutant dans un navigateur | ... |
| ce qui est réel vs simulé | le propre tableau du projet | ... |
Fait quand chaque ligne a une scène.
Phase B : Espace de travail
- Copiez le dépôt dans un dossier temporaire, puis installez :
npm ci. - Copiez
templates/dans la copie sousvideo/(conservez la structure :video/lib,video/pages,video/scenes,video/final.mjs,video/narration.mjs, ...). Ajoutez aux scriptspackage.json:"video:final": "node video/final.mjs". N'ajoutez aucune dépendance. - Ajoutez
video/out/à.gitignoredans la copie.
Phase C : Test à blanc de la vraie application et chasse aux bugs (faites ceci avant d'enregistrer quoi que ce soit)
Démarrez l'application comme le ferait un jury (npm run demo ou la commande du README) sur son port par défaut documenté, de sorte que chaque commande affichée à l'écran soit littérale. Pilotez-la avec un petit script Playwright, prenez des captures d'écran à 1920×1080 après chaque étape de l'histoire et examinez-les. Vérifiez :
- connexion, panneaux vides, bannières d'erreur rouges, erreurs de console ;
- chaque état dont l'histoire a besoin se rend réellement (la première exécution du projet de référence montrait un échec de connexion, une boîte de réception vide et une vue clé manquante, tous cachés par une ancienne ébauche de vidéo) ;
- texte dupliqué ou coupé.
Corrigez les vrais bugs dans la copie, de manière minimale, exécutez les propres vérifications du projet (npm run verify, tests, typecheck) et enregistrez chaque correction pour COPY_LIST.md. Si l'application n'a aucun moyen d'afficher le trafic filaire, ajoutez un petit crochet optionnel (un journal des requêtes) plutôt que d'en simuler un.
Fait quand toute l'histoire s'exécute proprement deux fois de suite et que les vérifications du projet réussissent.
Phase D : Storyboard et narration
- Choisissez les scènes. Histoire de référence (environ 2:50) :
| Scène | Durée | Montre |
|---|---|---|
| accroche | 12 s | un changement se répercute sur plusieurs engagements (carte animée) |
| démarrage | 6 s | la commande unique qui démarre tout, sortie réelle |
| sim (l'application) | 60 s | 8-10 temps ; journal des requêtes ouvert sur 2 temps |
| terminal(e) de preuve | 17-30 s | client officiel ou CLI contre le même serveur ; vérifications d'authentification |
| visite du code | 16 s | 3-4 extraits réels qui prouvent la technologie requise |
| architecture, pile cloud, réel vs simulé | 30 s | diagramme, source de la pile, tableau d'honnêteté, carte open-source |
| fermeture | 12 s | slogan, liens du dépôt, crédits de construction, pied de page "X est simulé" |
- Écrivez
video/narration.mjs:scenes = [{ id, title, segs: [{ id, text }] }]. Chaquesegest une ligne parlée et un sous-titre (textest affiché textuellement). Règles : environ 2,4 mots par seconde ; nombre total de mots parlés 330-380 ; une idée par ligne ; pas plus d'environ 12 mots sur une carte à l'écran ; casse de phrase ; pas de battage publicitaire. - Ajoutez des indices de prononciation dans la table
saypour le moteur de synthèse vocale uniquement (acronymes épelés, "Alexa+" comme "Alexa plus") ; ne modifiez jamais le texte du sous-titre. Fait quand la narration se lit comme une histoire qu'un étranger comprend et que chaque ligne de la carte de preuve est parlée ou montrée.
Phase E : Adaptation des modèles
Modifiez uniquement ce qui est spécifique au projet :
| Fichier | Modification |
|---|---|
video/narration.mjs | vos scènes et lignes |
video/scenes/sim.mjs | les étapes de votre application : quoi taper ou cliquer, sélecteurs, les zooms de la caméra (lens(...), zoomWire) |
video/scenes/static.mjs | commandes du terminal (CMD), codeBlocks (fichier + regex de la première ligne + nombre de lignes + regex de surbrillance), appels de page d'accroche/fermeture |
video/proofs.mjs, video/proof-auth.mjs | les vraies commandes qui prouvent vos affirmations ; elles n'impriment que les codes d'état et les noms d'erreur |
video/pages/*.html | texte, couleurs, tuiles, boîtes de diagramme, lignes de tableau, liens |
video/lib/overlay.mjs | sélecteurs SIM_CSS pour la mise en page de votre application (voir Règles de mise en page), la source de données du ticker |
video/final.mjs | la constante LIMIT et l'ordre des scènes (l'ordre vient de narration.mjs) |
video/thumbnail.mjs, video/docs.mjs | titres et la table SHOT |
Ne modifiez pas lib/recorder.mjs, lib/director.mjs, lib/tts.* sauf si quelque chose est cassé.
Phase F : Capture de la sortie de preuve réelle
node video/proofs.mjs démarre un nouveau serveur, exécute les vraies commandes (inspecteur officiel ou CLI client, vérifications d'authentification, sortie d'installation/démarrage) et enregistre ce qu'elles ont imprimé dans video/out/proofs.json. Les scènes de terminal rejouent cette sortie capturée dans un terminal HTML à une taille lisible. Règles : montrez le texte réel de la commande (raccourcissez uniquement le chemin du package) ; tronquez visiblement les sorties très longues (une ligne "... N lignes ..." atténuée) et mettez "Exécution enregistrée" dans le pastille ; n'imprimez jamais de jetons ; formatez joliment le JSON et dites-le si vous le faites.
Phase G : Audio de la narration
Par défaut (aucun compte requis) : node video/final.mjs --rate 2 crée un WAV par ligne avec la voix Windows intégrée (Microsoft Zira) et mesure chaque longueur. Le débit 1 donne environ 150 s de parole pour le script de référence, le débit 2 environ 139 s, le débit 3 est trop rapide. Choisissez le débit le plus lent qui maintient l'ensemble de la vidéo sous la limite.
Voix humaine optionnelle : voir l'annexe A. Tout ce qui suit fonctionne de la même manière avec l'une ou l'autre.
Phase H : Enregistrement et assemblage
node video/final.mjs --rate 2 # tout : tts, preuves, enregistrement de toutes les scènes, assemblage des deux montages
node video/final.mjs --rate 2 --reuse-proofs # sauter la réexécution des preuves
node video/final.mjs --scenes sim,close --reuse-tts --reuse-proofs # réenregistrer certaines scènes uniquement
node video/final.mjs --assemble-only # remux (sous-titres, audio) sans réenregistrement
node video/final.mjs --tts-dir video/out/tts-human --name my_video --single # construire à partir d'un autre dossier audio
Une exécution complète prend 6 à 10 minutes ; exécutez-la en arrière-plan et interrogez le journal. Le script échoue si le total est de 180 s ou plus. Visez 170 s.
Important : si vous modifiez le texte de la narration ou la voix, les durées changent, donc chaque scène doit être réenregistrée (les marques proviennent des durées). Changer uniquement les visuels d'une scène signifie --scenes <id> --reuse-tts.
Phase I : Contrôle qualité (ne sautez jamais, ne faites jamais confiance au journal)
- Extrayez les images à la fin de chaque ligne de narration du MP4 final :
ffmpeg -ss <marqueFin-0.3> -i final.mp4 -frames:v 1 image.png(la timeline est dansvideo/out/timeline.json). Examinez-les. Vérifiez la lisibilité en 1080p, les espaces vides, le texte coupé, la position et la taille des sous-titres, la synchronisation (l'événement de sous-titre est à l'écran), pas de secret, pas de mention du fournisseur, étiquettes d'honnêteté présentes. ffmpeg -i final.mp4 -af volumedetect -f null -: moyenne d'environ -22 dB, maximum inférieur à 0 dB.- Durée sous la limite dans les deux montages ; les deux fichiers ont un flux vidéo et un flux audio.
grep -ril "<mots du fournisseur>" video/pages video/narration.mjs <documents de sortie>ne renvoie rien sauf un identifiant de modèle autorisé.- Exécutez à nouveau les vérifications du projet (
npm run verify; e2e si l'interface a changé). - Corrigez et re-rendez jusqu'à ce que tout réussisse.
Phase J : Livrables
Générez narration.md et shotlist.md avec node video/docs.mjs <dossierSortie> (horodatages réels). Copiez les MP4, SRT, vignette (node video/thumbnail.mjs <png>), les images de contrôle qualité et les fichiers du dépôt modifiés (tous les fichiers différents entre l'original et votre copie, à leurs chemins de dépôt). Écrivez COPY_LIST.md (corrections de bugs en premier, puis nouveaux fichiers, messages de validation suggérés, "exécutez build et vérifiez après copie"), README-snippet.md (commande d'exécution, fichier d'entrée :ligne, fichier client :ligne, fichier de compétence, lien d'espace réservé de la vidéo) et REPORT.md (fait, ce que l'utilisateur doit faire, risques). Dites clairement ce que vous n'avez pas pu vérifier (par exemple, vous n'avez pas pu écouter la voix).
3. Comment fonctionne le pipeline (lisez avant de le modifier)
Enregistreur (lib/recorder.mjs). Le recordVideo de Playwright limite le débit binaire et brouille les petits textes, donc celui-ci utilise le screencast Chromium : les images JPEG (qualité 92) sont horodatées à leur arrivée, écrites sur le disque et encodées à un débit constant de 30 ips avec libx264 crf 17. Les écrans statiques produisent peu d'images ; la dernière image est conservée. Les horodatages proviennent d'une même horloge (performance.timeOrigin + performance.now()), la même que celle utilisée par le réalisateur.
Réalisateur (lib/director.mjs). Chaque ligne de narration est un segment. d.seg(id, actions, {tail}) enregistre l'heure de début, exécute les actions à l'écran, puis attend que la ligne ait fini de jouer plus tail * 0.45 secondes (les queues sont coupées globalement pour respecter la limite). Les marques (id, début, fin, texte) sont sauvegardées dans video/out/<scene>.marks.json. Comme l'audio est ensuite placé aux marques enregistrées, l'image et la voix ne peuvent pas dériver. Règle pour un temps : effectuez l'action à l'intérieur du segment et assurez-vous que l'action se termine avant la narration ; si la ligne est plus courte que l'action, divisez-la en deux lignes (c'est pourquoi un temps d'histoire est devenu sim9 et sim10).
Audio (final.mjs). Chaque WAV est retardé à son début global avec adelay, mixé avec amix=normalize=0, limité avec alimiter, et complété avec apad=whole_dur=<total> (sans le complément, -shortest coupe la fin de la vidéo).
Sous-titres. Les repères sont le texte de la narration divisé aux fins de phrase (les décimales telles que "2.0" sont protégées) et aux virgules lorsqu'il dépasse 82 caractères, avec un temps divisé proportionnellement à la longueur. Le fichier .srt est livré. La version incrustée utilise un fichier ASS généré avec PlayResX: 1920, PlayResY: 1080 et une taille de police 36. N'incrustez pas un SRT avec force_style : libass le redimensionne par rapport à un canevas de 288 pixels de haut et le texte sort environ quatre fois trop grand.
Superposition (lib/overlay.mjs), injectée uniquement dans la page de l'application enregistrée (l'application elle-même n'est pas modifiée)...
[... tronqué pour la traduction ...]