Communitygithub.com

mhuot/promo-video-skill

Chaîne d'outils locale entièrement hors ligne pour produire une vidéo promotionnelle narrée d'environ 60 secondes, utilisant Kokoro TTS, HyperFrames, FFmpeg et la gouvernance OpenMontage. Inclut des modèles et une vidéo de démonstration produite par la compétence elle-même.

Qu'est-ce que promo-video-skill ?

Cette compétence fournit une chaîne d'outils locale et entièrement hors ligne pour qu'un agent IA codeur produise une vidéo promotionnelle narrée d'environ 60 secondes. Elle est agnostique quant à l'agent, fonctionnant avec Claude Code, GitHub Copilot CLI, Microsoft Scout, Google Antigravity, Cursor, Codex, Windsurf et d'autres, via un runbook en markdown simple ou un script d'installation. La compétence guide l'agent à travers un pipeline en plusieurs étapes, de la recherche et de la proposition à la narration, la composition et le rendu. Elle utilise Kokoro pour la synthèse vocale (TTS), HyperFrames pour la composition vidéo basée sur HTML/CSS/GSAP, FFmpeg pour le codage et la musique de fond, et OpenMontage pour la gouvernance du pipeline. Un principe clé est que le script est verrouillé en premier, et toutes les durées en aval sont dérivées de l'audio de narration mesuré, jamais deviné. La compétence met l'accent sur la vente du "pourquoi" (public, problème, transformation, preuve, appel à l'action) plutôt que sur l'explication du "comment". Elle comprend des modèles de composition, des scripts TTS, une aide à la prononciation des acronymes, et un schéma de journal des décisions. Une vidéo de démonstration, produite par la compétence elle-même, est incluse comme preuve de concept.

Compatible avec✓Claude Code✓Codex CLI✓Cursor✓Antigravity✓Windsurf
npx skills add mhuot/promo-video-skill

Demander à votre IA préférée

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

Documentation

Production de vidéo promotionnelle (chaîne d'outils locale)

Indépendant de l'agent : écrit pour tout agent IA codeur capable de lire des fichiers et d'exécuter des commandes shell — installé nativement pour Claude Code, GitHub Copilot CLI / Microsoft Scout et Google Antigravity via install.sh ; utilisable depuis Cursor, Codex, Windsurf et autres comme un runbook en markdown simple.

Chaîne d'outils démontrée pour la première fois par Idan Shimon (Microsoft, github.com/idanshimon) — son vidéo explicative de 58 secondes, produite par un agent IA utilisant cette pile localement à 0 $, est ce à partir de quoi cette compétence a été élaborée.

Ne pas supposer d'emplacement d'installation : définir PROMO_VIDEO_SKILL_DIR sur le répertoire contenant ce SKILL.md. Son répertoire scripts/ contient le script TTS, son aide à la prononciation des acronymes, et les dépendances TTS épinglées ; assets/ contient le squelette de composition, les modèles de composants spatiaux et le schéma du journal des décisions ; references/ contient l'amorçage de la chaîne d'outils (install.md) à effectuer une fois par machine.

Principe fondamental : le script est verrouillé en premier ; chaque nombre en aval est DÉRIVÉ de l'audio de narration mesuré, jamais deviné.

Promotion, pas explication : cette compétence vend le POURQUOI — public, problème, transformation, preuve, un seul appel à l'action. Le mécanisme ("comment ça marche") obtient au plus un temps, et seulement lorsque l'utilisateur le demande ; les demandes d'enseignement du fonctionnement appartiennent à la compétence complémentaire explainer-video.

Profils des outils

OutilEmplacementVersion éprouvéeLicenceRôleInvocation
OpenMontage~/OpenMontagecheckout juillet 2026AGPLv3 (outillage uniquement ; rien n'est livré dans la vidéo)Gouvernance du pipeline : ordre des étapes, journal des décisions, portes, discipline d'auto-révision post-renduLire son AGENT_GUIDE.md + pipeline_defs/animation.yaml ; vous (l'agent) êtes l'orchestrateur — aucun démon ne s'exécute
KokoroPyPIKokoro-82M (hexgrad), kokoro==0.9.4Code Apache-2.0 ; poids du modèle Apache-2.0TTS de narration, WAV mono 24 kHz par scèneEnvironnement virtuel Python 3.12 ; KPipeline(lang_code="a"), voix af_heart, paramètre speed
HyperFrames~/hyperframes0.7.57, compilé à partir des sourcesApache 2.0Composition HTML/CSS/GSAP → MP4 déterministe via Chrome headlessnode ~/hyperframes/packages/cli/dist/cli.js <cmd>
FFmpegSources ~/FFmpeg ; binaire dans un répertoire de buildgit master (ère N-125608)Build GPL (libx264 activé)Synthèse musicale (aevalsrc), encodage, QA ffprobe, loudness, packaging plateformeMettre le répertoire de build sur PATH avant les commandes hyperframes
bunnpm-global1.3.14—Compile le monorepo hyperframesnpm i -g bun (brew cask a échoué silencieusement une fois)
Node.jsnvm24.x (≥22 requis)—Exécute le CLI hyperframes—
Pythongéré par uv3.12—Inférence KokoroToujours un environnement virtuel (uv venv --python 3.12 .venv) ; propre black + pylint
espeak-ngHomebrew ou aptquelconqueGPLRepli G2P Kokoro (requis)macOS : brew install espeak-ng ; Debian/Ubuntu : sudo apt install espeak-ng
gsapfichier local3.x gsap.min.jsLicence standard GSAPAnimation temporelle dans la compositionCopier dans video/assets/ — JAMAIS de <script src> CDN (déterminisme hors ligne)

Vérification de l'environnement (une fois par machine)

export FFMPEG_BUILD_DIR="${FFMPEG_BUILD_DIR:-$HOME/ffbuild}"
export HYPERFRAMES_DIR="${HYPERFRAMES_DIR:-$HOME/hyperframes}"
export PATH="$FFMPEG_BUILD_DIR:$PATH"
node "$HYPERFRAMES_DIR/packages/cli/dist/cli.js" doctor

FFmpeg, FFprobe, Node et Chrome doivent tous réussir avant la production (les autres lignes de doctor sont des composants optionnels que cette compétence n'utilise pas). Si l'un des quatre échoue, suivre $PROMO_VIDEO_SKILL_DIR/references/install.md — l'amorçage complet une fois par machine : paquets système (macOS/Linux), clonage des outils source (y compris le checkout de référence OpenMontage), compilation de FFmpeg avec libx264 à partir des sources, construction du CLI HyperFrames, et conseils d'autorisation pour l'agent. Ne pas charger ce fichier lorsque doctor réussit déjà.

Chrome : le CLI utilise automatiquement un chrome-headless-shell mis en cache sous ~/.cache/puppeteer/ (téléchargement unique si absent). La première exécution TTS télécharge également les paquets Python et les poids Kokoro-82M. Après ces téléchargements uniques, la synthèse, la validation, le rendu et le packaging ont un chemin hors ligne.

Structure du projet (créer par vidéo, propre dépôt git, commits atomiques)

<projet>/
  .venv/                          # uv venv, python 3.12
  .gitignore                      # .venv/ __pycache__/ video/snapshots/ .DS_Store
  README.md                       # comment c'était fait + reproduction (écrire EN DERNIER)
  production/
    research/research-brief.md    # faits avec sources + tableau honnête des concurrents
    proposal.md                   # concept, liste des scènes, promesse de livraison, décision d'exécution
    script/script.md              # narration VERROUILLÉE
    scene_plan/scene-plan.md      # visuels par scène + notes de mouvement
    checkpoints/decision-log.json # ajout seul ; la clé est (catégorie, sujet)
    checkpoints/self-review.md    # preuves post-rendu
    assets/audio/                 # WAV kokoro + durations.json
    renders/                      # master + dérivés plateforme
    youtube/                      # metadata.md + thumbnail.jpg
  tools/tts_generate.py           # copier depuis cette compétence, éditer SCENE_NARRATIONS
  tools/tts_pronounce.py          # depuis scripts/, prononciation des acronymes (ne pas éditer)
  tools/pronunciation.local.json  # lexique optionnel du projet
  video/
    index.html                    # LA composition
    assets/gsap.min.js            # fichier local
    assets/audio/                 # copies des WAV (chemins relatifs à la composition)

Étape 1 — Recherche (d'abord hors ligne)

Explorer le propre dépôt/README/doc du sujet — en recherchant les résultats et les preuves (chiffres, adoption, résultats avant/après), pas l'architecture. Produire research-brief.md avec :

  • Bloc de positionnement (obligatoire — le script ne peut pas être verrouillé sans lui). Une phrase chacun : public (à qui cela s'adresse), problème (ce qu'ils ressentent aujourd'hui), transformation (ce qui change pour eux), différenciateur (la seule raison de choisir ceci). C'est le message ; chaque étape en aval le sert.
  • Faits sur le produit, chacun vérifié par rapport à la source — conservés seulement s'ils soutiennent un avantage (le test "et alors ?" : qu'est-ce que le spectateur en retire ?).
  • Un tableau des concurrents (faiblesse → comment le sujet y répond). Règle d'honnêteté : concéder de vrais points aux concurrents (un ✓ dans leur colonne achète de la crédibilité pour la vôtre).
  • Une liste "revendications autorisées pour le script".

Étape 2 — Proposition + décisions

Écrire proposal.md : reformuler le bloc de positionnement, concept de 5 à 7 scènes, cible ≈60s, promesse de livraison ("animé, pas un diaporama"), tableau de la chaîne d'outils. Enregistrer dans decision-log.json — commencer à partir du schéma vide à $PROMO_VIDEO_SKILL_DIR/assets/decision-log.json (champs : category, subject, selected, options_considered, rejected_because, confidence) : pipeline_selection, render_runtime_selection (enregistrer Remotion comme alternative envisagée — règle dure OpenMontage), composition_mode (atelier pour le travail héroïque), voice_selection, music_selection, output_profile, approval_gates, et cta_selection — EXACTEMENT un appel à l'action (mettre une étoile au dépôt / installer / regarder la démo / visiter le site) ; les vidéos promotionnelles meurent en terminant sur une liste de fonctionnalités au lieu d'une demande. Si le brief de l'utilisateur a fixé un choix, marquer approved_by: "user brief". Changé une décision plus tard ? AJOUTER une nouvelle entrée avec la même (catégorie, sujet) — ne jamais modifier l'ancienne.

Étape 3 — Script (le point de verrouillage)

~150-155 mots ≈ 60s à kokoro af_heart vitesse 1.1. Arc promotionnel (vendre le pourquoi) : accroche/enjeux/problème → révélation (nom + la transformation promise) → avantages dans le monde du spectateur → preuve (comparaison honnête, résultats réels) → aspiration → l'unique CTA du journal des décisions. Les fonctionnalités apparaissent uniquement comme preuve d'un avantage : chaque phrase doit passer le test "et alors ?" (qu'est-ce que le spectateur en retire ?) ou être réécrite. Au plus UN temps expliquant le fonctionnement, et seulement lorsque l'utilisateur le demande — enseigner le mécanisme est le travail de la compétence explainer-video. Voix : deuxième personne, présent, phrases courtes et percutantes ("vous livrez plus vite", pas "cela permet une livraison plus rapide"). Écrire les acronymes naturellement ("OID", "MCP", "IA") à la fois dans le script et le texte à l'écran — au moment de la synthèse, tools/tts_pronounce.py dérive la forme parlée (mot vs lettre par lettre) à partir de son lexique, et les acronymes inconnus sont épelés lettre par lettre et signalés. Classifier les termes du domaine dans un tools/pronunciation.local.json optionnel ({"NASA": "word", "ECG": "letters", "NGINX": "engine X"}). Éviter l'emphase en MAJUSCULES : un mot en majuscules est traité comme un acronyme. Budget de mots par scène ≈ sa part de 60s × 2,55 mots/s.

Étape 4 — Narration + dérivation du timing (l'astuce qui porte le système)

Créer l'environnement Python 3.12 du projet à partir des dépendances directes épinglées fournies, copier le modèle générique, et éditer SCENE_NARRATIONS uniquement :

uv venv --clear --python 3.12 .venv
uv pip install --python .venv/bin/python \
  -r "$PROMO_VIDEO_SKILL_DIR/scripts/tts-requirements.txt"
mkdir -p tools
cp "$PROMO_VIDEO_SKILL_DIR/scripts/tts_generate.py" tools/tts_generate.py
cp "$PROMO_VIDEO_SKILL_DIR/scripts/tts_pronounce.py" tools/tts_pronounce.py
PYTORCH_ENABLE_MPS_FALLBACK=1 .venv/bin/python tools/tts_generate.py
mkdir -p video/assets
curl -fL https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js \
  -o video/assets/gsap.min.js

La première synthèse télécharge les poids Kokoro-82M (~330 Mo) ; les exécutions ultérieures utilisent le cache et peuvent être hors ligne. Elle écrit les WAV par scène + durations.json. Si l'exécution imprime un AVERTISSEMENT d'acronyme inconnu, classifier ces jetons dans tools/pronunciation.local.json et réexécuter avant de dériver le timing.

Considérer 150-155 mots à la vitesse 1.1 comme une estimation de départ, pas un calibrage. Total >62s ? Augmenter la vitesse ou couper des mots, puis mesurer à nouveau.

Dériver la timeline (intervalle ≈0,3-0,5s entre les scènes) :

n_start[0] = 0.5                       # intro
scene_start[i] = n_start[i] - 0.15..0.4   # les visuels atterrissent juste avant la VO
n_start[i+1] = n_start[i] + dur[i] + 0.3..0.35
TOTAL = dernière n_end + 0.6..0.9 fin (fondu au noir)

Ces nombres vont à TROIS endroits qui doivent concorder : les data-start/data-duration des scènes, les valeurs <audio data-start>, et les constantes de timeline const S1..Sn en JS. Copier les WAV dans video/assets/audio/.

Étape 5 — Fond musical (aucun téléchargement)

Générer un pad synthétique déterministe avec le FFmpeg compilé à partir des sources. Définir TOTAL_SECONDS sur le total dérivé de la composition ; aucun échantillon externe ou référence privée n'est nécessaire :

TOTAL_SECONDS=60.5
FADE_SECONDS=3.5
FFMPEG_BIN="${FFMPEG_BUILD_DIR:-$HOME/ffbuild}/ffmpeg"
FADE_OUT_START="$(awk -v total="$TOTAL_SECONDS" -v fade="$FADE_SECONDS" \
  'BEGIN { printf "%.3f", total - fade }')"
mkdir -p production/assets/audio
"$FFMPEG_BIN" -hide_banner -y \
  -f lavfi \
  -i "aevalsrc=0.07*(sin(2*PI*110*t)+0.65*sin(2*PI*110.7*t)+0.45*sin(2*PI*164.81*t)+0.30*sin(2*PI*220.9*t)):s=48000:d=${TOTAL_SECONDS}" \
  -af "highpass=f=55,lowpass=f=1200,afade=t=in:st=0:d=2,afade=t=out:st=${FADE_OUT_START}:d=${FADE_SECONDS},pan=stereo|c0=c0|c1=c0" \
  -c:a pcm_s16le production/assets/audio/music-bed.wav

Le garder clairsemé ; mixé à data-volume="0.12..0.16" il se lit comme une atmosphère — pour l'énergie promotionnelle, se situer vers le haut de cette plage, jamais au-dessus de la narration. Copier le WAV dans video/assets/audio/ et utiliser une piste audio distincte.

Étape 6 — Création de la composition (contrat HyperFrames)

Commencer par $PROMO_VIDEO_SKILL_DIR/assets/composition-skeleton.html (il incorpore chaque règle ci-dessous) ; avant d'écrire du HTML, parcourir $HYPERFRAMES_DIR/skills/hyperframes-core/SKILL.md. Structure : index.html autonome, racine <div data-composition-id="X" data-start="0" data-duration="TOTAL" data-width="1920" data-height="1080">, scènes en tant que <section class="clip" data-start data-duration data-track-index="1">, UNE gsap.timeline({paused:true}) enregistrée de manière synchrone à window.__timelines["X"], positions des interpolations = S<i> + décalage_local.

Règles qui coûtent du temps de débogage réel — les respecter d'emblée :

  1. Chaque <video>/<audio> a besoin d'un id explicite et non vide. Dans HyperFrames, l'audio sans peut jouer dans un aperçu du navigateur mais rend le SILENCE (les erreurs de lint le signalent ; ne pas ignorer).
  2. Ne jamais mettre un transform: initial dans le CSS sur un élément interpolé par GSAP — utiliser tl.fromTo(el, {y:24, opacity:0}, {y:0, opacity:1, ...}) ; GSAP possède la transformée complète. (opacity: 0 seul dans le CSS est acceptable pour les révélations uniquement .to().)
  3. Le remplissage d'arrière-plan va sur un ENFANT plein écran (position:absolute; inset:0), jamais sur la racine (l'arrière-plan racine peut rendre en noir).
  4. Les éléments média sont des enfants directs de la racine, data-track-index sur des pistes audio distinctes (par ex. 7=VO, 8=musique).
  5. Pas de répétitions infinies (repeat: -1 interdit — utiliser fini, par ex. clignotement de curseur repeat: 9, yoyo: true), pas de Date.now/Math.random, pas de récupérations réseau, pas de scripts CDN.
  6. id unique partout ; animer uniquement les transformées/opacités (+ strokeDashoffset pour les dessins de lignes SVG).
  7. Éléments apparaissant au milieu d'une scène : état initial caché + interpolation à S<i>+décalage. fromTo a immediateRender donc les recherches avant l'interpolation montrent l'état from — c'est ce qui le rend sûr pour la recherche.
  8. Jetons de conception dans les variables CSS :root = le thème ; échanger ground/ink/accent + la pile de polices pour changer l'apparence. Utiliser une police que le moteur de rendu fournit (JetBrains Mono) — les polices système sont de toute façon substituées (les infos de lint indiquent le mappage).
  9. Garder le texte secondaire ≥ WCAG AA sur la couleur de fond — check ÉCHOUE les builds sur le contraste et imprime la couleur conforme à utiliser.
  10. Chevauchements/défilements intentionnels : marquer avec data-layout-allow-overflow/-overlap/-occlusion au lieu de laisser les résultats inexpliqués.

Conseil de motif de scène : montrer l'ÉTAT DE RÉSULTAT — le monde du spectateur amélioré (contraste avant/après, le problème disparu, le résultat à l'écran). Tirer les aperçus de soutien de l'interface utilisateur/domaine réel du sujet (fausse palette de recherche, terminal, arbre, table) comme preuve d'un avantage, pas d'une visite guidée du mécanisme. Les templates d'arc narratif ; les motifs ne doivent pas l'être. $PROMO_VIDEO_SKILL_DIR/assets/composition-skeleton.html a des annotations de motif structurées.

Skills associés