vid-sizzle-reel
Génère une bande-annonce dynamique ou une vidéo hype à partir d'actifs de marque et de messages clés. Pipeline : Composition HTML HyperFrames (timelines GSAP) → Chromium sans affichage → FFmpeg H.264 MP4. Pas de Runway. Pas de Pika. Pas d'API vidéo AI. Zéro coût d'exécution au-delà de Node.js + FFmpeg.
Différenciation par rapport à vid-product-launch :
vid-product-launchraconte une histoire narrative — un seul dévoilement progressif, cinq sections, arc de tensionvid-sizzle-reelcrée de l'énergie et de l'excitation — coupes rapides, la musique en premier, pas d'histoire unique
Règles critiques (à lire avant chaque génération)
-
Écrivez vous-même les messages clés — ou demandez à l'utilisateur de les écrire. Ce sont les phrases exactes qui apparaissent à l'écran. "L'IA va trouver" produit du remplissage. 3 à 5 lignes percutantes constituent tout le contenu d'une bande-annonce.
-
Le nom de la marque apparaît UNIQUEMENT dans la section Land. Le Cold Open et le Build créent de la tension sans nommer la marque. La section Land est la récompense.
-
Déclarez le motif rythmique dans un commentaire en haut du script avant d'écrire du HTML. Format :
// RYTHME : flash-sequence | Cold[0-5s] : stat | Build[5-40s] : msg(1.5s)|flash|... | Peak[40-55s] : ... | Land[55-60s] : logo+CTA. Chaque décision de timing est vérifiée par rapport à cela. -
Construisez d'abord la disposition finale en CSS — pas encore de GSAP. Positionnez chaque élément à son moment le plus visible en CSS statique. Ajoutez ensuite les entrées GSAP avec
gsap.from()et les sorties avecgsap.to(). Ne positionnez jamais à l'état de départ animé. -
class="clip"sur chaque élément temporisé. Requis par HyperFrames. Sans cela, l'élément est invisible pour le lecteur. -
data-start,data-duration,data-track-indexsur chaque clip. Aucune exception. Les clips sur la même piste ne peuvent pas se chevaucher — utilisez des index de pistes différents. -
Pas de
Math.random(). HyperFrames nécessite des compositions déterministes. Utilisez un PRNG basé sur une graine (mulberry32) pour toute valeur pseudo-aléatoire. -
Toutes les timelines GSAP commencent par
{ paused: true }et s'enregistrent danswindow.__timelines["comp-id"]. Le lecteur HyperFrames contrôle la lecture — n'appelez jamaistl.play(). -
Jamais
position: absolutesur les conteneurs.scene-content. Utilisezwidth:100%; height:100%; padding:Npx; display:flex. Réservezposition:absoluteuniquement pour les éléments décoratifs. -
Musique : élément
<audio>séparé avecdata-track-index. La vidéo doit êtremuted playsinline. Ne mettez jamais d'audio dans un élément<video>. -
Lisez
references/cut-patterns.mdETreferences/tone-presets.mdavant de générer du HTML. -
Ne déversez jamais de HTML dans le chat. Sauvegardez dans un fichier. Affichez uniquement le résumé.
Étape 1 : Réception
Requis :
key_messages— 3 à 5 lignes percutantes à afficher à l'écran (l'utilisateur doit les écrire)
Paramètres optionnels et valeurs par défaut :
| Paramètre | Valeur par défaut | Description |
|---|---|---|
| brand_assets | aucun | URL/chemin du logo, couleurs de la marque (hex), captures d'écran clés |
| tone | energetic | energetic / cinematic / emotional / professional |
| music | aucun | Chemin du fichier, ou chaîne BPM/genre (ex. "128bpm electronic") |
| duration | 60 | 30 / 60 / 90 secondes |
| aspect_ratio | 9:16 | 9:16 (1080x1920) / 16:9 (1920x1080) |
| cut_style | auto | fast (1-2s) / cinematic (3-5s) — auto dérive de tone |
| end_card | auto | Logo + tagline + URL CTA pour la section Land |
cut_style par défaut automatique : energetic → fast ; professional → fast (2s) ; cinematic → cinematic ; emotional → mixed
Si key_messages est manquant, demandez exactement :
"Pour générer la bande-annonce, j'ai besoin de vos messages clés — les phrases exactes qui s'afficheront à l'écran. Donnez-moi 3 à 5 lignes percutantes. C'est la chose la plus importante que vous écrivez pour cette vidéo.
Exemples : 'Utilisé par plus de 500 équipes de croissance' / 'De jours à minutes' / 'Fonctionne avec Claude, Codex, Gemini'
Utile aussi : ambiance (energetic/cinematic/emotional/professional), durée (30/60/90s), couleurs de marque ou URL du logo."
Si key_messages sont présents → passez à l'Étape 2 immédiatement.
Étape 2 : Installer HyperFrames
Installez les compétences HyperFrames (première fois seulement — ignorez si déjà installé) :
npx skills add heygen-com/hyperframes
Vérifiez l'environnement :
node --version # doit être >= 22
ffmpeg -version # doit être présent
Scaffoldez le projet :
npx hyperframes init sizzle-[slug] --example kinetic-type --non-interactive
cd sizzle-[slug]
Slug : kebab-case à partir du nom de marque de end_card ou du premier key_message, max 25 caractères.
Étape 3 : Architecture interne (jamais montrée à l'utilisateur)
1. Dérivez le timing des coupes à partir de duration + cut_style :
| Section | 30s | 60s | 90s |
|---|---|---|---|
| Cold Open | 0-5s | 0-5s | 0-8s |
| Build | 5-25s | 5-40s | 8-65s |
| Peak | 25-28s | 40-55s | 65-80s |
| Land | 28-30s | 55-60s | 80-90s |
Convertissez chaque limite en millisecondes. Calculez la durée par scène à partir de cut_style :
fast: 1.2s-1.8s par message (utilisez 1.5s par défaut)cinematic: 3.5s-5.0s par message (utilisez 4.0s par défaut)mixed: 2.0s-4.0s variable selon l'énergie de la section
2. Mappez les key_messages aux scènes :
- Cold Open (1 scène) : une statistique ou une question impactante — PAS de nom de marque, suscite l'intrigue
- Build : une scène par key_message
- Peak : répétez le message le plus fort à double échelle, ou combinez 2 messages en flash rapide
- Land : nom de la marque + tagline + URL CTA
3. Détectez la synchronisation sur le rythme si musique fournie :
npx hyperframes tts --analyze-beats [music-file]
Si indisponible, calculez à partir du BPM : beat_ms = 60000 / BPM. Alignez les coupes sur chaque 2ème temps.
4. Sélectionnez le préréglage d'ambiance — lisez references/tone-presets.md pour les jetons CSS.
5. Déclarez le motif rythmique — écrivez un commentaire en haut du script :
// RYTHME : flash-sequence
// Cold Open [0-5000ms] : stat
// Build [5000-40000ms] : msg-1(1500ms)|flash|msg-2(1500ms)|flash|msg-3(1500ms)|flash|msg-4(1500ms)|flash|build-accum(10000ms)
// Peak [40000-55000ms] : msg-fort(1200ms)|flash|msg-2e(1200ms)|flash|HOLD(5600ms)
// Land [55000-60000ms] : logo+tagline+cta
6. Déterminez les dimensions en pixels :
9:16→ L=1080, H=1920 (par défaut — Instagram Reels, TikTok, YouTube Shorts)16:9→ L=1920, H=1080
Étape 4 : Composition HTML HyperFrames
Lisez references/cut-patterns.md et la compétence HyperFrames (/hyperframes) avant d'écrire du code.
Squelette HTML requis :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
[lien CDN de police depuis le préréglage d'ambiance]
<style>
:root {
[tous les jetons CSS du préréglage d'ambiance]
}
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
</style>
</head>
<body>
<div
data-composition-id="sizzle-[slug]"
data-width="[L]"
data-height="[H]"
style="position:relative;width:[L]px;height:[H]px;overflow:hidden;background:var(--bg)"
>
[si cut-flash: true]
<div id="cut-flash"
style="position:absolute;inset:0;background:var(--cut-flash-bg);opacity:0;pointer-events:none;z-index:200"></div>
[fin si]
[si film-grain: true]
<canvas id="grain-overlay"
width="240" height="135"
style="position:absolute;inset:0;width:[L]px;height:[H]px;pointer-events:none;opacity:0.022;mix-blend-mode:overlay;z-index:50"></canvas>
[fin si]
[si vignette: true]
<div id="vignette-overlay"
style="position:absolute;inset:0;background:radial-gradient(ellipse at center,transparent 35%,rgba(0,0,0,0.65) 100%);pointer-events:none;z-index:51"></div>
[fin si]
<!-- Scènes — un div par scène -->
<div id="scene-cold"
class="clip"
data-start="0"
data-duration="5"
data-track-index="0"
style="position:absolute;inset:0;opacity:0"
>
<div class="scene-content" style="width:100%;height:100%;padding:120px;display:flex;flex-direction:column;align-items:center;justify-content:center;box-sizing:border-box">
[contenu du cold open — une statistique ou une phrase impactante, pas de nom de marque]
</div>
</div>
[un div par scène Build, data-start incrémenté de la durée de coupe]
[scène(s) Peak]
[scène Land — nom de marque + tagline + CTA]
[si musique fournie]
<audio id="music"
class="clip"
data-start="0"
data-duration="[durée_totale]"
data-track-index="10"
data-volume="0.85"
src="[chemin_musique]"
></audio>
[fin si]
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js"></script>
<script>
// ── DÉCLARATION DU RYTHME ──────────────────────────────────────────────────────
// RYTHME : [flash-sequence | cinematic-hold | beat-sync | mixed]
// Cold Open [0-Nms] : ...
// Build [N-Nms] : ...
// Peak [N-Nms] : ...
// Land [N-Nms] : ...
// ── PRNG BASÉ SUR GRAINE (pour grain uniquement — pas d'autres valeurs aléatoires) ───────────────────
function mulberry32(seed) {
return function() {
seed |= 0; seed = seed + 0x6D2B79F5 | 0;
let t = Math.imul(seed ^ seed >>> 15, 1 | seed);
t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
return ((t ^ t >>> 14) >>> 0) / 4294967296;
};
}
[si film-grain: true]
// ── GRANULATION DE FILM (cinématique/émotionnelle uniquement) ───────────────────────────────────
const grainCanvas = document.getElementById('grain-overlay');
const grainCtx = grainCanvas ? grainCanvas.getContext('2d') : null;
// Grain mis à jour par le ticker GSAP (pas de capture par trame — HyperFrames gère cela)
[fin si]
// ── TIMELINE GSAP ───────────────────────────────────────────────────────────
const tl = gsap.timeline({ paused: true });
// ── COLD OPEN ───────────────────────────────────────────────────────────────
[tweens d'entrée et de sortie du cold open — voir cut-patterns.md pour le motif exact]
// ── SECTION BUILD ───────────────────────────────────────────────────────────
[tweens par message — flash-sequence ou cinematic-hold depuis cut-patterns.md]
// ── SECTION PEAK ─────────────────────────────────────────────────────────────
[tweens du peak — même motif que build mais timing plus serré]
// ── SECTION LAND ─────────────────────────────────────────────────────────────
[entrées du land — logo, tagline, CTA. Pas de sortie — tient jusqu'à la fin]
// ── ENREGISTREMENT DE LA TIMELINE ────────────────────────────────────────────────────
window.__timelines = window.__timelines || {};
window.__timelines["sizzle-[slug]"] = tl;
</script>
</div>
</body>
</html>
Règles de qualité de conception :
- Statistique du cold open : taille de police ≥160px pour 16:9, ≥100px pour 9:16
- Messages clés : taille de police ≥80px — lisibles en un coup d'œil
- Section Land, nom de marque : ≥120px pour 16:9
- Toutes les couleurs proviennent des variables de jetons prédéfinies — pas de hex libre sauf
var(--accent)hex littéral à l'intérieur de canvasfillStyle scene-contentutilise toujourspadding + flex— jamaisposition:absolutesur le conteneur de contenuclass="clip"sur chaque élément avecdata-start
Étape 5 : Auto-QA (corrigez chaque échec avant l'Étape 6)
Contenu :
-
key_messages— chaque phrase apparaît exactement une fois, pas de doublons - Le nom de la marque apparaît UNIQUEMENT dans la section Land (pas dans cold open, build ou peak)
- Le cold open ne contient NI nom de marque NI nom de produit — seulement une statistique ou phrase impactante
- La section Land contient : nom de marque + tagline + URL CTA (trois éléments minimum)
- L'URL CTA de end_card est présente sur l'image finale
Contrat HyperFrames :
-
class="clip"sur chaque élément avecdata-start -
data-start,data-duration,data-track-indexsur chaque clip -
data-composition-idsur le div de composition racine -
window.__timelines["sizzle-[slug]"] = tlenregistré - Toutes les timelines commencent par
{ paused: true } - Pas de
Math.random()— PRNG basé sur graine uniquement - Pas d'appels
tl.play()outl.resume()
GSAP / Disposition :
-
gsap.from()pour toutes les entrées (DE hors écran VERS position CSS) -
gsap.to()pour toutes les sorties (DE position CSS VERS hors écran) - Pas de
position:absolutesur les conteneurs.scene-content - Motif rythmique déclaré en commentaire en haut du script
Timing des coupes :
- Ambiance
fast: durée moyenne de coupe ≤ 2.0s - Ambiance
cinematic: durée moyenne de coupe ≥ 3.0s - Le flash de coupe se déclenche à chaque limite de coupe pour l'ambiance
energetic(60ms, opacité 0→1→0) - Les clips sur la même piste ne se chevauchent PAS (vérifiez tous les regroupements
data-track-index)
Effets sonores :
-
window.__sfxTimelineprésent et placé avant l'enregistrement de la timeline -
word-hitpar message clé -
whooshà la transition Build → Peak -
cta-chimeau début du Land - Aucun effet sonore ne se déclenche avant 500ms
Étape 6 : Linting, Rendu, Sortie
npx hyperframes lint
npx hyperframes inspect --json
Corrigez toutes les erreurs de lint. Corrigez toutes les erreurs d'inspection (débordement de texte, clips s'échappant des conteneurs). Ensuite, effectuez le rendu :
npx hyperframes render --output sizzle/[slug]/sizzle-reel.mp4
Sortie :
## Bande-annonce : [nom de marque depuis end_card]
Ambiance : [tone] | Durée : [N]s | Style de coupe : [cut_style] | Format : [ratio]
Rythme : [motif déclaré]
Sections
Cold Open [0-Ns] : [statistique ou phrase impactante]
Build [N-Ns] : [N messages clés listés]
Peak [N-Ns] : [message le plus fort à l'échelle maximale]
Land [N-Ns] : [nom de marque] + "[tagline]" + [URL CTA]
Fichiers
Source : sizzle/[slug]/index.html
Sortie : sizzle/[slug]/sizzle-reel.mp4
Timeline d'effets sonores (à intégrer dans chaque composition)
Le même système d'effets sonores synthétisés par FFmpeg que vid-product-launch. Placez window.__sfxTimeline immédiatement avant l'enregistrement de la timeline GSAP.
Référence des types d'effets sonores pour la bande-annonce :
| Type | Son | Durée | Placement |
|---|---|---|---|
word-hit | Coup de poing grave (50Hz) + clic transitoire (2.2kHz) + bruit | 180ms | Un par début de scène key_message |
whoosh | Balayage de bruit à deux bandes (1.1kHz corps + 4-8kHz air) | 700ms | À la limite Build → Peak |
cta-chime | Accord majeur A (440+554+659+880Hz) + scintillement de cloche aecho | 1.2s | Exactement au début du Land |
window.__sfxTimeline = [
// un word-hit par key_message (calculé à partir des temps de début de scène)
{ ms: MSG_1_DEBUT_MS, sfx: 'word-hit', vol: 0.50 },
{ ms: MSG_2_DEBUT_MS, sfx: 'word-hit', vol: 0.50 },
{ ms: MSG_3_DEBUT_MS, sfx: 'word-hit', vol: 0.50 },
// ... répétez pour chaque message
{ ms: PEAK_DEBUT_MS - 700, sfx: 'whoosh', vol: 0.55 },
{ ms: LAND_DEBUT_MS, sfx: 'cta-chime', vol: 0.65 },
];
Calculez toutes les valeurs ms à partir des limites de section déclarées dans le motif rythmique.
Références
Consultez references/cut-patterns.md pour les motifs de coupe par style de coupe et section.
Consultez references/tone-presets.md pour les jetons CSS complets (couleurs, polices, tailles, dégradés) par préréglage d'ambiance.
Documentation générée par la compétence vid-sizzle-reel.