Que fait Enregistrement de vidéos de démonstration (gratuit, scripté) ?
Créez des vidéos de démonstration produit silencieuses de l'application réelle en scriptant un navigateur, puis en générant un fichier MP4. Gratuit et local : Playwright pilote l'application, ffmpeg crée la vidéo. Pas de SaaS payant, pas de narration, pas de clics humains. Le même script sert également de test de fumée UX et se rejoue lorsque l'interface utilisateur change — ce qui en fait la méthode durable pour produire de nombreuses démos de fonctionnalités.
Quand l'utiliser
- L'utilisateur souhaite une ou plusieurs vidéos de démonstration / présentation de fonctionnalités sans payer pour un outil.
- Le problème récurrent : "quelqu'un doit enregistrer l'écran pour chaque nouvelle fonctionnalité".
- Preuve visuelle rapide qu'une fonctionnalité fonctionne, de bout en bout, dans l'interface réelle.
Pas pour : les vidéos marketing fortement animées avec voix off (utilisez un véritable éditeur), ou tout ce qui nécessite une réaction humaine devant la caméra.
Structure
mint une session de connexion → piloter l'application avec Playwright (enregistre .webm) → ffmpeg → .mp4
Trois fichiers arrivent dans le dépôt cible sous demo/ (copiés depuis resources/) :
record.mjs— le moteur. Un bloc CONFIG (spécifique au dépôt) + une map FLOWS (une entrée par vidéo).polish.sh—.webm→.mp4, coupe le temps de connexion, légende incrustée optionnelle.run.sh— une commande : pointer le dev vers staging, enregistrer, polir, nettoyer.README.md— utilisation par dépôt.
Pour créer une nouvelle vidéo : copiez une entrée FLOWS, changez url + steps. C'est toute la boucle.
Liste de vérification de configuration (à faire une fois par dépôt)
- Installer les outils (une fois) :
npm install -D @playwright/test && npx playwright install chromium. Besoin deffmpeg(Homebrew). Pour les légendes incrustées, vous avez besoin d'un ffmpeg compilé aveclibfreetype; sinon, les légendes sont automatiquement ignorées et tout le reste fonctionne. - Découvrir les spécificités du dépôt et remplir le bloc CONFIG dans
record.mjs:- Commande de développement — comment l'application s'exécute localement (
npm run dev, souvent dans un sous-dossier commecongrats/). - Chemin du module client Supabase — généralement
src/integrations/supabase/client.ts. L'enregistreur l'importe dans la page pour se connecter (voir Astuce 1). - Quelle base de données utiliser pour l'enregistrement — utilisez staging, jamais la production (pas de données personnelles réelles). Trouvez son URL + clé anonyme/publique + clé service + une URL directe de la base. Dans cette organisation, elles se trouvent dans le fichier
.env.localdu dépôt d'audition (VETTED_SUPABASE_*pour VettedAI staging,STAGING_CONGRATS_SUPABASE_*pour Congrats staging). - Un email de connexion — un compte synthétique/de test qui possède des données pouvant être démontrées. Demandez toujours à l'utilisateur quel compte avant de créer une session (règle du projet : pas de test avec des utilisateurs réels sans autorisation).
- Routes — les chemins de liens profonds pour les flux que vous allez enregistrer.
- Commande de développement — comment l'application s'exécute localement (
- Pointer le serveur de développement local vers staging (voir Astuce 2).
- Créer un flux, exécuter
bash demo/run.sh <flow>, vérifier en extrayant des images (Astuce 8).
Astuces (les leçons durement apprises — à lire avant de déboguer)
1. Se connecter via le PROPRE client de l'application, pas en simulant localStorage
Supabase-js écrit sa session sous une clé/enveloppe non standard dans le navigateur ; injecter manuellement
localStorage['sb-<ref>-auth-token'] = JSON.stringify(session) semble correct mais le client ne la lira pas →
l'application redirige vers /login. À la place : créez une session côté serveur (generateLink admin → verifyOtp donne
access_token+refresh_token, sans mot de passe), puis dans la page importez le client Supabase de l'application
et appelez supabase.auth.setSession({access_token, refresh_token}). Cela écrit le stockage correct et la
session survit à la navigation. C'est l'étape la plus importante.
2. --mode staging peut être ignoré silencieusement → utilisez .env.development.local
vite-react-ssg dev (et certaines configurations) ignorent --mode pour le chargement des fichiers d'environnement, donc .env.staging n'est jamais chargé et
l'application reste pointée vers la production (vous verrez des requêtes vers l'hôte Supabase de production). Vite charge toujours automatiquement
.env.development.local en développement avec une priorité plus élevée que .env/.env.local. Ainsi run.sh copie votre configuration
staging dans .env.development.local pour l'enregistrement, puis le supprime à la sortie (sinon chaque futur
npm run dev serait silencieusement sur staging — un véritable piège). Les dépôts vite simples peuvent honorer --mode ; testez en observant
quel hôte Supabase l'application appelle.
3. Le schéma de staging peut être en retard sur le frontend → réconciliation additive ciblée
Une branche de staging peut manquer des colonnes récentes que le frontend sélectionne → la requête de données échoue avec une erreur 400
(column X does not exist) et l'écran s'affiche vide. Ne rejouez pas les migrations. Comparez les colonnes des
quelques tables que l'écran lit (staging vs production via information_schema.columns), et appliquez uniquement celles qui manquent
en tant que colonnes additives, nullables avec ALTER TABLE ... ADD COLUMN IF NOT EXISTS. Obtenez l'accord de l'utilisateur — c'est une modification de la base de staging.
4. Les données de départ peuvent être à la mauvaise échelle
Les scores/valeurs de départ synthétiques peuvent ne pas correspondre à ce que le formateur de l'interface utilisateur attend (par exemple, des scores stockés de 0 à 100 alors que l'interface
fait valeur/5*100 → "1392%"). Vérifiez la plage attendue du formateur par rapport aux valeurs réelles de la production ; réajustez les
données de départ si nécessaire (demandez d'abord — c'est une mutation de données).
5. Les vidéos Playwright n'affichent pas le curseur de la souris
Injectez une superposition de curseur factice via addInitScript (un point qui suit mousemove + grossit sur mousedown).
Le modèle le fait déjà. Déplacez la souris aux coordonnées réelles avant de cliquer pour qu'elle soit visible.
6. ffmpeg peut manquer drawtext
Les builds sans libfreetype génèrent une erreur sur les légendes incrustées. polish.sh détecte drawtext et ignore la légende s'il
manque — ne laissez pas un échec de légende bloquer le mp4.
7. Découpage automatique du temps de connexion/démarrage
L'enregistrement capture la connexion + le démarrage de l'application (secondes mortes). record.mjs mesure le temps de démarrage et écrit un
fichier .trim ; polish.sh le coupe (ffmpeg -ss).
8. Vérifiez par images, jamais par "ça a enregistré"
ffmpeg -ss <t> -i out.mp4 -frames:v 1 frame.png à quelques horodatages et regardez réellement. Les premiers essais
afficheront /login, un squelette, ou le mauvais onglet — les images sont comment vous le repérez.
9. Sécurité des données et de l'authentification
Enregistrez sur staging avec des données synthétiques (par exemple seed_…@test.vetted.com), jamais un vrai projet client
(données personnelles). Demandez toujours à l'utilisateur quel compte utiliser pour la connexion. Créer une session d'authentification est une action réelle — confirmez d'abord.
Créer un flux
Dans record.mjs, FLOWS est une map de { label, url, steps(page, ui) }. Les helpers ui couvrent la plupart des besoins :
ui.settle(what, [words])— attendre le contenu (réseau inactif + un mot qui prouve que l'écran est chargé)ui.scrollThrough(fraction, steps)— défilement fluide vers le bas et retourui.clickFirstCandidate()/ généralisé àui.clickFirst(selectors)— clic au mieux, jamais d'échecui.beat(ms)— une pause délibérée pour que la vidéo se lise bien
Gardez les flux légers en sélecteurs et au mieux (try/catch pour les clics) afin qu'un sélecteur manqué se dégrade en "encore une démo de défilement correcte" au lieu d'un crash. Espacez généreusement (800–1800ms de pause) ; une bonne démo silencieuse dure 15–35s.
Sortie + transmission
Le mp4 atterrit dans demo/output/ (gitignore). open demo/output/<flow>.mp4 pour le lire (un lien markdown relatif
ne se lit pas dans un IDE — il ouvre le fichier dans l'éditeur). Partagez le chemin ou utilisez open pour l'utilisateur.
Propagation de cette compétence (elle vit dans skill-master)
Cette compétence est canonique dans submodules/skill-master/.agent/skills/recording-demo-videos/ et liée symboliquement dans chaque
dépôt sous .agent/skills/. Après l'avoir modifiée, validez et poussez le sous-module d'abord, puis le pointeur du dépôt parent, et
exécutez /distribute-skill pour la propager dans les dépôts frères (demandez à l'utilisateur avant de pousser). Voir
la règle skill-master-submodule-sync.