Communitygithub.com

velxio/velxio_docs

Produire ou mettre à jour la vidéo promo/demo Velxio (et les GIFs produit) en pilotant la VRAIE application avec Playwright et en post-produisant avec Remotion — capture d'écran avec curseur visible, zooms sur les clics clés, légendes, cartes d'intro/outro.

Qu'est-ce que velxio_docs ?

Ce skill permet de créer ou mettre à jour la vidéo promotionnelle/démonstration du produit Velxio en automatisant l'application réelle via Playwright et en post-produisant avec Remotion. Il capture des séquences avec un curseur visible, des zooms centrés sur les interactions clés, des légendes synchronisées sur la musique, ainsi que des cartes d'intro et d'outro. Le pipeline se déroule en trois phases : enregistrement (pilotage de l'application de bout en bout), détection des battements musicaux (avec librosa pour synchroniser les zooms), et post-production Remotion (rendu vidéo H.264). Il gère automatiquement plus d'une dizaine de pièges connus (modal de démarrage, recherche de composants, vérificateur de circuit, curseur invisible, etc.). Le skill supporte également la création de vidéos de démonstration pour la galerie d'exemples, avec des prises de vue par exemple. Il est utilisé lorsque l'IA est sollicitée pour créer une vidéo promo, une animation produit, un GIF de workflow, ou pour re-rendre après des changements d'interface.

Compatible avec✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/velxio/velxio_docs/tree/HEAD/skills/velxio-promo-video

Demander à votre IA préférée

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

Documentation

Pipeline vidéo promo Velxio

Trois phases, toutes dans ce dépôt (velxio_docs ; /home/dave/velxio_docs sur la machine de dev) :

  1. Enregistrement — scripts/promo-record.mjs pilote le vrai produit en staging de bout en bout (projet vierge → sélection ESP32 → ajout 220R + LED → rotation de la résistance → câblage par clics sur les broches → écriture du sketch → Exécution → LED clignote), avec un curseur visible injecté + des ondulations de clic. Chaque étape enregistre {t, x, y, label} dans scripts/promo-events.json ; la vidéo brute est placée dans scripts/promo-raw.webm.
  2. Grille de battements — scripts/detect-beats.py (librosa) transforme la bande sonore en promo/src/beats.json (BPM, battements, kicks, snares).
  3. Post-production — promo/ est un projet Remotion. prepare.mjs copie la prise, coupe le démarrage pré-modal, supprime l'attente de compilation, et génère src/data.json. src/Promo.tsx rend la caméra (zooms centrés sur chaque battement, chaque impact ACCROCHÉ au battement musical le plus proche dans 0,34 s), des pastilles de légende, une carte d'intro PLEINE, l'outro velxio.dev, et la piste musicale avec fondus.

Commandes

cd /home/dave/velxio_docs
VELXIO_SHOTS_EMAIL='[email protected]' VELXIO_SHOTS_PASSWORD='<see memory vstaging-test-user>' \
  node scripts/promo-record.mjs          # prise (~2-4 min incl. compilation)
python3 scripts/detect-beats.py promo/public/soundtrack.mp3 --fps 30 \
  --out promo/src/beats.json        # seulement quand la piste change
cd promo && node prepare.mjs
CHROME=$(ls -d $HOME/.cache/ms-playwright/chromium-*/chrome-linux*/chrome | sort | tail -1)
npx remotion render src/index.ts promo out/velxio-demo.mp4 --codec h264 --browser-executable "$CHROME"

Copie publiée pour visualisation GitHub : media/velxio-demo.mp4 (commitée ; remplacer + pousser pour mettre à jour la même URL). promo/out/ est dans gitignore.

Procédure de validation (à NE PAS sauter)

Échantillonner les images AUX TEMPS DES BATTEMENTS depuis promo/src/data.json (champ ct), pas à des moments arbitraires — les battements se déplacent entre les prises :

ffmpeg -y -ss <ct> -i out/velxio-demo.mp4 -vframes 1 /tmp/beat.png

Vérifier : intro lisible, chaque zoom montre son sujet sans coupure, les légendes correspondent à ce qui est à l'écran, le curseur ne cache rien d'important, la LED finale est allumée.

Vidéos de démonstration de la galerie (mode basique)

Une vidéo courte par exemple de galerie — ouvrir, exécuter, filmer le fonctionnement — avec une carte d'intro divisée (logo + titre + carte à gauche, tout le circuit à droite), un tiers inférieur, l'outro et la bande sonore.

node scripts/gallery-scan.mjs                     # rafraîchir l'index des 406 exemples
node scripts/gallery-record.mjs [slug ...]        # prises 1080p (ignore les déjà faites)
node scripts/gallery-bbox.mjs [slug ...]          # mesurer l'emplacement du circuit
node scripts/gallery-render.mjs [slug ...]        # un mp4 par prise
  • L'ensemble de démos sélectionné se trouve dans GALLERY en haut de gallery-record.mjs ; les slugs proviennent de scripts/gallery-index.json (nom de fichier miniature = slug).
  • Les images fixes sont capturées avec deviceScaleFactor: 2 et recadrées au cadre du circuit : assez nettes pour remplir la moitié d'un cadre 1080p. Ne PAS zoomer l'application pour agrandir un petit circuit — le canevas ancre le zoom sur son centre et déplace le circuit hors écran ; réinitialiser la vue plutôt.
  • La passe de cadre a besoin d'un CONTEXTE FRAIS par exemple : un second chargement côté client de l'éditeur laisse le canevas vide et ne mesure rien.
  • Les exemples sans carte (catégories Digital / Analog) ne compilent jamais : Exécution reste désactivée et le moteur SPICE les pilote depuis le début.
  • Les cartes QEMU back-end (STM32, Raspberry Pi) n'émettent aucune ligne console "dans le navigateur". De plus, STM32 ne fonctionne pas du tout sur staging (libqemu-arm est un asset optionnel qui n'y est pas déployé) — compile en 3 s, ne démarre jamais.
  • Les prises brutes (promo/public/gallery/*.webm, ~3 Mo chacune) sont dans gitignore ; les images fixes du circuit et le JSON par prise sont commités pour qu'un nouveau rendu n'ait besoin que des prises.

Musique

promo/public/soundtrack.mp3 = Mixkit "House Vibez" par Lily J (assets.mixkit.co/music/745/745.mp3), Licence libre Mixkit Stock Music — gratuite pour usage commercial, pas d'attribution requise. 123 BPM. Remplacer le fichier et relancer detect-beats.py pour changer de piste ; tenir à jour la note de licence dans promo/public/ATTRIBUTION.md.

La piste commence par ~8 s d'intro : AUDIO_START dans Promo.tsx est le premier battement détecté, donc l'audio démarre à partir de là et la composition t=0 tombe sur un temps fort. Le volume est à 0,55 avec un fondu entrant de 0,9 s et un fondu sortant de 2,2 s sur l'outro.

Règles de style (issues de la relecture de David — à conserver)

  • La vidéo commence DIRECTEMENT dans l'éditeur avec la modale de template de carte déjà ouverte et le chat IA déjà minimisé. Pas de page d'accueil, pas de chargement, pas de clic de minimisation visible (l'enregistreur le fait par programme avant le début ; prepare.mjs coupe jusqu'à la marque start).
  • Titre d'intro sur une carte foncée PLEINE — jamais translucide sur l'interface.
  • Les zooms doivent CENTRER leur sujet : translation+échelle avec limites de bord (Promo.tsx), jamais de transformOrigin-sur-point (laisse le sujet sur un bord et le coupe, par exemple la carte ESP32).
  • Les battements d'ajout de composant utilisent un MAINTIEN COURT (~0,5 s) pour que le zoom se libère à temps pour VOIR où le composant a atterri.
  • Le battement de code centre tout le PANNEAU de l'éditeur (surcharge fx/fy 357,280) — jamais un éditeur recadré pendant que le code est écrit.
  • Après avoir cliqué sur Exécuter, GARER le curseur ailleurs (l'enregistreur le déplace à 700,620) pour que le spinner du bouton soit visible ; le battement Exécution zoome sur le groupe compilation/exécution à une échelle modérée (1,8).
  • Tourner la résistance à l'horizontale après placement (verticale par défaut chevauche ses propres fils à la caméra).
  • Le pointeur est une FLÈCHE style macOS, pas un point. Calcul du hotspot (issu du skill saas-product-demo) : la pointe est à (4,3) dans une viewBox 24x24, donc à une largeur de rendu W, l'élément est décalé de (-4W/24, -3W/24) — sans cela, chaque clic est décalé d'environ 6-8 px.
  • Les impacts de zoom tombent sur des battements musicaux (voir Musique ci-dessus) ; ne jamais laisser un impact dériver de plus de ~0,3 s de son clic juste pour tomber sur un battement.
  • Les battements dont la MODALE SE FERME au clic (choose-blank, add-*) ont besoin de lead: 0.45 : le pic doit arriver AVANT le clic pour que l'image montre encore la carte ouverte, et le relâchement révèle ensuite où le composant a atterri. Un pic sur le clic lui-même laisse le zoom posé sur une boîte de dialogue déjà fermée.

Pièges (chacun a coûté une prise ratée — tous gérés dans les scripts)

  1. / est la page marketing même connecté ; l'éditeur est /editor. Se connecter via fetch POST /api/auth/login dans la page d'abord.
  2. Sur un /editor frais, la superposition "Démarrer un nouveau projet" s'ouvre automatiquement (.new-project-overlay) et intercepte tout clic extérieur. Interagir d'abord avec elle, ou envoyer des clics programmatiques.
  3. Le champ de recherche du sélecteur GARDE la requête précédente — effacer avec Ctrl+A + Retour arrière avant de taper, sinon vous cherchez "esp32led".
  4. Cartes du sélecteur : faire correspondre le titre exact avec .component-picker-modal .card-name (les moteurs de texte génériques touchent les tokens Monaco derrière la modale). Les résultats sont anti-rebond — interroger jusqu'à 5 s. Les noms de carte sont exacts ("Resistor 220 Ω" avec le caractère style U+2126, pas "Resistor" ; vérifier /components-metadata.json).
  5. Les cartes NE se glissent PAS depuis leur corps — laisser la carte là où le sélecteur la dépose (près du bord droit du canevas) et placer les petites pièces RELATIVEMENT à son boundingBox en direct, à sa GAUCHE où il y a de l'espace.
  6. Clics sur les broches : utiliser les divs [data-pin-overlay="true"][title=<pin>] de l'application, en choisissant le candidat le plus proche de l'élément hôte (les titres entrent en conflit : broche de carte "2" vs broche de résistance "2"). Le calcul à partir des offsets de pinInfo échoue sur les pièces pivotées. Les broches ESP32 sont nommées '2','4','GND' (pas D2).
  7. Vérifier chaque fil posé en comptant les path[stroke="#1a1a1a"] (path de contour de chaque fil ; les fils n'ont pas de classe/attribut data). Réessayer une fois via Échap + re-clic.
  8. Le vérificateur de circuit BLOQUE Exécution pour une LED sans résistance en série (erreur 3,9e12 A). La démo doit câbler GPIO2 -> 220R -> LED A, GND -> LED C. Ne jamais livrer une prise qui a nécessité "Exécuter quand même".
  9. Le template vierge livre un sketch par défaut — Ctrl+A avant de taper le commentaire à l'écran, puis définir le sketch complet via monaco.editor.getModels()[0].setValue(...) (la frappe littérale lutte contre les parenthèses auto-fermantes de Monaco).
  10. Le toast "Vous aimez Velxio ? / Star sur GitHub" photobombe les prises de plus de ~5 min — le nettoyeur injecté le supprime chaque seconde.
  11. Playwright n'enregistre pas le curseur OS : la div #vx-cursor injectée + l'ondulation de clic (context.addInitScript) est le pointeur visible.
  12. L'attente de compilation est réelle (30 s à chaud - 5 min à froid) : l'enregistreur consigne run et sim-started ; prepare.mjs coupe cette plage. Le démarrage de la simulation est détecté par une ligne console "dans le navigateur" ; "guest crashed" = abandonner.
  13. Remotion rend avec le chromium de Playwright via --browser-executable (pas de téléchargement de navigateur groupé sur cette machine).

Dépôts de référence (examinés le 2026-08-15)

Deux skills Claude-Code pour le même genre, approche différente : ils COMPOSENT les films à partir de captures d'écran/interfaces schématiques avec un curseur synthétique — le nôtre ENREGISTRE le vrai produit. Les cloner pour monter en compétence :

  • github.com/noamdorr/saas-product-demo-video — films marketing de 20-45 s synchronisés sur les battements dans Remotion. À piquer : synchronisation SUR LES BATTEMENTS de la bande sonore (librosa detect-beats.py : coupures de scène sur les snares, événements intra-scène sur les kicks — notre vidéo est silencieuse, ajouter de la musique et aligner les zooms sur les battements est la plus grosse amélioration possible), le calcul du hotspot du curseur (la pointe de la flèche SVG est à 4,3 d'une boîte de 24 — important si nous échangeons notre curseur point contre une flèche), la vérification du budget de frappe, le playbook d'itération.
  • github.com/Vincentwei1021/video-shotcraft — 152 fiches de plans avec sources de démo + galerie (vincentwei1021.github.io/video-shotcraft), un template approuvé (Ink Press), des mouvements de caméra 2,5D, du design sonore et trois modes de fonctionnement (template / autonome / co-créé). À piquer : le vocabulaire des plans de réalisation et sa checklist de relecture finale ; il s'installe aussi comme plugin si un film cinématographique complet est un jour souhaité.

Liés

  • Pipeline de captures d'écran : scripts/shots.mjs (même dépôt) — scènes avec le panneau IA minimisé sauf s'il est le sujet.
  • GIFs : enregistrer un segment (Playwright recordVideo) et convertir avec ffmpeg deux passes de palette ; voir scripts/weather-media.mjs pour le motif zoom+recadrage (zone de recadrage depuis le boundingBox de l'élément).
  • Utilisateur de test staging : memory vstaging-test-user (s3-tester, pro).
  • Projet de démonstration cassé (station météo) est suivi dans project/docs-portal-2026-08/STATUS.md dans velxio-prod.

Skills associés