vid-product-launch
Génère une vidéo narrative de lancement de produit au format MP4 à partir d'une description de produit et d'un contexte de lancement. Pipeline : animations HTML/CSS → Chromium sans tête (Playwright, image par image) → FFmpeg (H.264 MP4). Pas de React. Pas d'API vidéo IA. Pas de Python. Aucun coût d'exécution au-delà de Playwright + FFmpeg.
Règles essentielles (à lire avant chaque génération)
-
Le slogan n'est pas optionnel. Ne le sautez pas. C'est la promesse entière du produit en 4 à 6 mots. Si l'utilisateur ne l'a pas fourni, déduisez-en un à partir de la description — une distillation précise et à voix active. N'écrivez jamais "[slogan ici]" ou ne le laissez pas vide.
-
Le moment de la révélation doit être mérité. Les sections de teasing et de construction existent pour créer une tension. Si le nom du produit apparaît dans les 20% premiers de la vidéo, la narration s'effondre. Ne révélez jamais le nom du produit avant la section de révélation.
-
Taille de police du product_name : minimum 120 px pour 16:9, minimum 80 px pour 9:16. Le nom doit être le plus grand élément au moment de la révélation. S'il n'est pas dominant, la révélation échoue.
-
Une seule statistique de preuve. Pas une liste. Si l'utilisateur fournit plusieurs statistiques, choisissez la plus percutante. Une liste de 5 chiffres détruit l'effet. Un seul chiffre surdimensionné le crée.
-
Utilisez
window.renderFrame(t)— pas de CSS@keyframespour les transitions de scène. La recherche CSScurrentTimeest silencieusement ignorée pour les retours en arrière dans Chromium. La fonction renderFrame calcule directement les styles des éléments à partir des millisecondes. Playwright l'appelle une fois par image. -
Pas de
animation-delaysur AUCUN élément. Pas nécessaire avec renderFrame. Si vous écrivezanimation-delay, arrêtez-vous — vous utilisez la mauvaise architecture. -
window.__videoReady = trueuniquement à l'intérieur dedocument.fonts.ready.then(...). Ne jamais définir de manière synchrone. -
Exposez
window.__stopPreview(). La boucle d'aperçu rAF entre en conflit avec les appels evaluate/screenshot de Playwright. Le script de capture appelle__stopPreview()avant la boucle d'images. -
Utilisez
t < startMs(past <= startMs) dans les vérifications des limites de scène.t <= 0à l'image 0 rend la scène 1 noire. -
Body = dimensions exactes en pixels. La largeur et la hauteur sont des entiers. Pas de
%,vw/vh,rem. -
Lisez
references/scene-library.mdETreferences/style-presets.mdavant de générer DU HTML. -
Ne déversez jamais le HTML dans le chat. Enregistrez-le dans un fichier. Montrez uniquement le résumé.
-
Le canvas du grain de film DOIT être de 240 × 135, pas W × H. Définissez
width="240" height="135"sur l'élément canvas, puis étirez-le avecstyle="width:[W]px;height:[H]px". Le grain en pleine résolution à 1920 × 1080 est 64× plus lent — 8 Mo d'ImageData par image — et fera prendre des heures pour les exportations de 1800 images. -
La section de teasing DOIT être sombre (#000 ou quasi noir), quel que soit le ton. Les fonds blancs dans la section de teasing ressemblent à des diapositives de démonstration, pas à des vidéos de lancement de produit. L'arc narratif sombre-vers-clair (teasing sombre → construction sombre → révélation du produit) est la façon dont les vidéos de lancement créent le drame. Même les presets
minimaletenergeticdoivent utiliserbackground: #000pour les scènes de teasing-problème et de construction de tension. -
Chaque mot de teasing doit être son propre temps fort avec une taille de police de 200 px +. Mot par mot sur une seule ligne n'est pas assez percutant. Chaque mot du problème (par exemple "Recherche." / "Rédaction." / "Prospection." / "Répétition.") obtient 1 500 à 1 800 ms de temps d'écran à
font-size : 200 px ; font-weight : 900centré, un à la fois. Voir scene-library.md patterntease-words. -
La section de construction doit montrer un contenu qui raconte le problème — pas seulement des particules. Utilisez le pattern
terminal-card: 3 cartes apparaissent séquentiellement avec une animation de machine à écrire montrant le travail manuel effectué. Les cartes ontborder: 1px solid rgba(255,255,255,0.07), un accent de point bleu, du texte monospace. Les particules seules pendant 20 secondes, c'est du temps d'écran vide. -
Arrière-plan CSS Dot-grid sur les scènes sombres. Ajoutez
background-image: radial-gradient(circle, rgba(255,255,255,0.035) 1px, transparent 1px); background-size: 60px 60px;aux scènes de construction, révélation, preuve et CTA. Cela ne coûte rien en calcul et ajoute de la profondeur.
Étape 1 : Collecte des informations
Requis :
product_name— le nom du produit ou de la fonctionnalité lancéeproduct_description— 2-3 phrases : ce qu'il fait, à qui il s'adresse, avantage clé
Paramètres optionnels et valeurs par défaut :
| Paramètre | Valeur par défaut | Description |
|---|---|---|
| tagline | auto | 4-6 mots — la promesse principale du produit |
| problem_statement | déduit automatiquement | 1 phrase pour la section de teasing (le problème que le produit résout) |
| proof_stat | déduit automatiquement | Métrique unique (par exemple "500+ équipes", "10× plus rapide", "2 M$ économisés") |
| cta | auto | URL ou phrase d'action (par exemple "opendirectory.dev", "Rejoignez la liste d'attente") |
| launch_date | — | Chaîne de date ISO (active la scène du compte à rebours) |
| tone | cinématographique | cinématographique / énergique / minimal / émotionnel |
| duration | 60 | 30 / 60 / 90 (secondes) |
| aspect_ratio | 16:9 | 16:9 (1920 × 1080) / 9:16 (1080 × 1920) |
| letterbox | false | Barres noires cinématographiques 2.35:1 — 16:9 uniquement |
| music | — | Chemin vers le fichier audio (mp3/m4a/wav) |
| fps | 30 | Images par seconde (24, 30 ou 60) |
Si product_name ou product_description manque, demandez exactement :
"Pour créer la vidéo de lancement, j'ai besoin de deux choses :
- Nom du produit — comment s'appelle le produit ?
- Description du produit — 2-3 phrases : que fait-il, à qui s'adresse-t-il, quel est l'avantage principal ?
Facultatif : slogan (4-6 mots), statistique de preuve (un chiffre), CTA (URL ou phrase d'action), ton (cinématographique / énergique / minimal / émotionnel), durée (30 / 60 / 90 s)."
Si les deux sont présents → passez immédiatement à l'étape 2.
Étape 2 : Architecture interne (jamais montrée à l'utilisateur)
1. Déduire les paramètres manquants :
- slogan (s'il n'est pas fourni) : écrivez-en un à partir de la product_description. 4-6 mots. Voix active. Pas de remplissage ("L'avenir de…", "Présentation de…"). Déduisez la promesse la plus précise possible.
- problem_statement (s'il n'est pas fourni) : déduisez-le de la product_description. 1 phrase énonçant le problème. Ne mentionne jamais le nom du produit. Écrite pour que le public hoche la tête en signe de reconnaissance.
- proof_stat (s'il n'est pas fourni) : déduisez-le de la product_description. Si aucune statistique n'est disponible, utilisez un indicateur d'échelle crédible ("Approuvé par 500+ équipes", "De jours à minutes").
- cta (s'il n'est pas fourni) : utilisez le domaine du produit si déductible du product_name, ou "En savoir plus" comme phrase d'action.
2. Calculer le timing des sections à partir de duration :
| Section | 30s | 60s | 90s | Formule de début |
|---|---|---|---|---|
| Teasing | 0-5s | 0-10s | 0-15s | 0 ms |
| Construction | 5-12s | 10-30s | 15-40s | Fin du teasing |
| Révélation | 12-20s | 30-45s | 40-60s | Fin de la construction |
| Preuve | 20-25s | 45-55s | 60-75s | Fin de la révélation |
| CTA | 25-30s | 55-60s | 75-90s | Fin de la preuve |
Convertissez chaque limite en millisecondes. Assignez aux constantes :
TEASE_START_MS, TEASE_END_MS
BUILD_START_MS, BUILD_END_MS
REVEAL_START_MS, REVEAL_END_MS
PROOF_START_MS, PROOF_END_MS
CTA_START_MS, CTA_END_MS
3. Sélectionner les scènes par section :
- Teasing : Commence toujours par
blackout-opener(1500 ms). Ensuitetease-words(chaque mot-clé du problème comme son propre temps fort de 1600-1800 ms à 200 px +). Silaunch_dateest fourni, ajoutez éventuellementcountdown-cardà la fin du teasing. - Construction : Séquence
terminal-card(3 cartes montrant les tâches manuelles en cours de saisie) + ligne d'accent facultative. Durée ≥ 30 s obtient les 3 cartes. Durée = 30 s utilise 2 cartes. N'utilisez jamais de particules seules pendant plus de 5 s — l'écran doit montrer un contenu qui raconte le problème. - Révélation :
reveal-hero— toujours en premier dans cette section. Éventuellement suivi detagline-cardsi durée ≥ 60 s. - Preuve :
proof-statsi une statistique numérique est disponible. Sinonfeature-bullet. - CTA :
cta-card— toujours, toujours en dernier.
Nombres de scènes typiques : 30 s = 4 scènes, 60 s = 6-7 scènes, 90 s = 7-8 scènes.
4. Calculer le timing par scène :
Dans chaque section, divisez le temps de manière égale entre les scènes de cette section.
Exception : blackout-opener obtient toujours exactement les 1500 premières ms du Teasing.
5. Déterminer les dimensions en pixels :
16:9→ L=1920, H=10809:16→ L=1080, H=1920
6. Calcul du Letterbox (si activé, 16:9 uniquement) :
- Hauteur du contenu 2.35:1 = L / 2.35 = 1920 / 2.35 ≈ 817 px
- Hauteur de la barre = (H - 817) / 2 = (1080 - 817) / 2 ≈ 132 px
- Barre supérieure :
top: 0; height: 132px - Barre inférieure :
bottom: 0; height: 132px
7. Indicateurs d'effets cinématographiques (par preset) :
cinématographique: grain-de-film=ON (canvas 240 × 135, opacité 0.025), vignette=ON, fuite-de-lumière=ON (or chaud), dot-grid=ON sur les scènes sombresénergique: grain-de-film=OFF, vignette=OFF, dot-grid=ON, flash blanc à la révélationminimal: grain-de-film=ON (canvas 240 × 135, opacité 0.022), vignette=ON (subtile, 0.5 radial), dot-grid=ON, pas de fuite-de-lumière — couleur d'accent = #4B9FFF (bleu électrique)émotionnel: grain-de-film=ON (canvas 240 × 135, opacité 0.018, mélange de teinte chaude), vignette=ON (douce), fuite-de-lumière=ON (cuivre chaud), dot-grid=OFF
Tous les presets : les scènes de teasing et de construction utilisent TOUJOURS un fond sombre (#000 ou quasi noir), quel que soit le preset.
8. Intégrez window.__sfxTimeline dans le HTML (toujours — même quand aucune musique n'est fournie) :
Le script d'exportation lit ce tableau, synthétise chaque type d'effet sonore nativement avec FFmpeg aevalsrc/anoisesrc, et place les événements à des décalages millisecondes exacts en utilisant adelay. Aucun fichier audio externe requis.
Référence des types d'effets sonores :
| Type | Son | Durée | Remarques |
|---|---|---|---|
word-hit | Coup de poing sub (50 Hz) + clic transitoire (2.2 kHz) + salve de bruit | 180 ms | Un par mot de teasing — 3 couches via amix |
type-sequence | Clics de clavier mécanique à 15 Hz (enveloppe d'impulsion sin^30) | 1.9 s | Un par carte — s'exécute pendant toute la durée TYPE_DUR |
whoosh | Balayage de bruit à deux bandes (corps 1.1 kHz + air 4-8 kHz) | 700 ms | À la transition BUILD_CLOSE |
tension-riser | Grondement grave (250 Hz) + ton sub augmentant avec rampe t/2.8 | 2.9 s | Commence à BUILD_CLOSE + 700ms — atteint son maximum à REVEAL_START |
reveal-boom | Sub (45 Hz) + corps (90 Hz) + scintillement (4.5-11 kHz) + écho de 85 ms | 900 ms | Exactement à REVEAL_START — LE coup |
counter-tick | Clic harmonique (880 Hz + 440 Hz + 1760 Hz + 2640 Hz) | 80 ms | 3 temps — decrescendo 0.32 → 0.26 → 0.20 |
cta-chime | Accord de La majeur (440 + 554 + 659 + 880 Hz) + scintillement de cloche aecho | 1.2 s | Exactement à CTA_START |
Carte temporelle des effets sonores — calculez les valeurs ms à partir des constantes de section, ne les codez jamais en dur :
window.__sfxTimeline = [
// ── TEASING : un word-hit par temps de mot, le dernier plus fort ───────
{ ms: WORD_BEATS[0].start, sfx: 'word-hit', vol: 0.55 },
{ ms: WORD_BEATS[1].start, sfx: 'word-hit', vol: 0.55 },
{ ms: WORD_BEATS[2].start, sfx: 'word-hit', vol: 0.55 },
{ ms: WORD_BEATS[N].start, sfx: 'word-hit', vol: 0.65 }, // dernier mot plus fort
// ── CONSTRUCTION : type-sequence par carte (1.9 s, correspond à TYPE_DUR 1800 ms) ──
{ ms: CARDS[0].start + 180, sfx: 'type-sequence', vol: 0.28 },
{ ms: CARDS[1].start + 180, sfx: 'type-sequence', vol: 0.28 },
{ ms: CARDS[2].start + 180, sfx: 'type-sequence', vol: 0.28 },
// ── TRANSITION : whoosh puis montée de tension de 2.9 s culminant à REVEAL_START ───
{ ms: BUILD_CLOSE, sfx: 'whoosh', vol: 0.50 },
{ ms: BUILD_CLOSE + 700, sfx: 'tension-riser', vol: 0.35 },
// ── RÉVÉLATION : le coup cinématographique ─────────────────────────────
{ ms: REVEAL_START, sfx: 'reveal-boom', vol: 0.88 },
// ── PREUVE : tics harmoniques, decrescendo ────────────────────────────
{ ms: PROOF_START, sfx: 'counter-tick', vol: 0.32 },
{ ms: PROOF_START + 2200, sfx: 'counter-tick', vol: 0.26 },
{ ms: PROOF_START + 4400, sfx: 'counter-tick', vol: 0.20 },
// ── CTA : accord de La majeur atterrissant ─────────────────────────────
{ ms: CTA_START, sfx: 'cta-chime', vol: 0.62 },
];
Placez ce bloc immédiatement avant la boucle d'aperçu, après window.renderFrame.
Étape 3 : Génération HTML
Lisez references/scene-library.md ET references/style-presets.md avant d'écrire du code.
Utilisez les noms de classe CSS exacts, la structure HTML et les modèles renderFrame de ces fichiers.
Squelette HTML requis :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
[lien CDN de police depuis le preset de style]
<style>
:root {
[tous les jetons CSS du preset de style]
}
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
width: [L]px; height: [H]px;
overflow: hidden;
background: var(--bg);
font-family: var(--font-body);
position: relative;
}
.scene {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80px;
opacity: 0;
will-change: opacity, transform;
}
.scene-inner {
width: 100%;
max-width: 1200px;
}
[collez le CSS de chaque type de scène dans scene-library.md]
</style>
</head>
<body>
<!-- Éléments de superposition cinématographique — rendus au-dessus de toutes les scènes -->
[si grain-de-film : ON]
<canvas id="grain-overlay"
width="[L]" height="[H]"
style="position:fixed;inset:0;pointer-events:none;opacity:0.025;mix-blend-mode:overlay;z-index:50"></canvas>
[fin si]
[si vignette : ON]
<div id="vignette-overlay"
style="position:fixed;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]
[si fuite-de-lumière : ON]
<div id="light-leak"
style="position:fixed;inset:0;background:linear-gradient(135deg,rgba(255,220,140,0.5) 0%,rgba(255,255,255,0.3) 45%,transparent 70%);opacity:0;pointer-events:none;z-index:52"></div>
[fin si]
[si letterbox : ON]
<div id="lbox-top" style="position:fixed;top:0;left:0;width:[L]px;height:132px;background:#000;z-index:100"></div>
<div id="lbox-bot" style="position:fixed;bottom:0;left:0;width:[L]px;height:132px;background:#000;z-index:100"></div>
[fin si]
<!-- Scènes -->
[HTML de scène à partir des modèles de scene-library.md, un par scène sélectionnée]
<script>
window.__videoReady = false;
window.TOTAL_DURATION_MS = [duration * 1000];
// ── Constantes de timing des sections ─────────────────────────────────────
const TEASE_START_MS = [N];
const TEASE_END_MS = [N];
const BUILD_START_MS = [N];
const BUILD_END_MS = [N];
const REVEAL_START_MS =
…
[truncated for translation]