/bw-song-ad — Publicité chantée en cartoon noir et blanc, prête à livrer
2026-10-18, procédure créée avec H-OHI-023a (おひさまパンツ). Référence : WhiteHat MRR sur X (densité osseuse, cartoon noir et blanc, ~4 min). La réaction de la personne : « La chanson est trop fire, c’est un dieu ». La vidéo de référence n’est pas un simple jingle mais un script VSL long format presque entièrement chanté.
Ordre (à ne pas modifier)
Paroles → Chanson (Suno) → Alignement lettre par lettre → Découpage en scènes → Fiche personnage → Images clés → Animation → Export du fond → Remotion → Contrôle qualité. La chanson fait office d’horloge. Si on crée les images en premier, elles ne correspondent pas aux blancs de la chanson et tout est à refaire.
S=~/.agents/skills/bw-song-ad
AD=<dossier du projet>/<ID de la pub> # lyrics.md / captions.txt / song/ / shots.py / keys/ / clips/ / remotion/
cp -R $S/remotion $AD/remotion && cd $AD/remotion && NODE_USE_ENV_PROXY=1 npm install
0. Vérifier d’abord les stocks
S’il existe déjà des images ou vidéos produites pour la même marque, les utiliser en priorité (consulter le tableau des stocks ASSETS.md de la marque ; ajouter les nouveaux éléments après création). Quand une génération est nécessaire, indiquer au préalable « N images, M vidéos, environ X crédits ». Référence pour cette procédure : 61 images pour ~15 crédits, 61 vidéos Grok pour ~265 crédits.
1. Paroles (lyrics.md) — modèle de reference/lyrics.md
- Chanter le déroulement du VSL par paragraphe. Pas de rimes. Enchaînement 1:1 avec la référence : Introduction du métier → « Ce n’est pas ça »×3 → Quelque chose de plus important → La cause n’est pas là où on pense → Alliés et ennemis dans le corps → Avant ça marchait → Maintenant les ennemis gagnent → Le problème, c’est à partir de là (chaîne d’inaction) → Le rayon ne propose que les mêmes choses → Mais ça a changé (solution) → Article (pas d’inscription) → Stock → « Tu n’as plus besoin de… »×3 → « Tout va bien. Appuie en bas ».
- Tout en hiragana. Les chiffres aussi en hiragana (Suno déraille avec les kanji et les chiffres).
- Ne pas chanter le nom du produit (il apparaît sur l’étiquette à l’écran). Pas de prix. Les promesses se limitent à la page produit.
- Montrer avant de composer.
2. Chanson (Suno, Playwright)
- Connexion par la personne uniquement. Ensuite, envoyer les paroles, le style et le titre sur
suno.com/create?mode=CUSTOMpuis cliquer sur Create. - Style (qui marche) :
1930s vintage upbeat jazz, old cartoon soundtrack, swing, clarinet, muted trumpet, ragtime piano, brushed snare, upright bass, warm female vocal, Japanese, clear diction, storytelling sung melody - 1 génération donne 2 pistes. Faire un relevé complet des deux avec whisper et les comparer aux paroles ; garder celle qui ne dévie pas.
- Téléchargement : sur la page de la piste, More options → Download → MP3 → « Unlock & Download » (utiliser le quota gratuit une fois).
cdn1.suno.airenvoie 403, le m4a de lecture est chiffré. Ne pas extraire le blob du navigateur pour éviter le compteur. - Placer dans
song/song.mp3.
3. Texte des sous-titres (captions.txt)
- 1 paragraphe des paroles = 1 ligne. Séparer les groupes dans la ligne par
/(1 groupe = 1 apparition à l’écran, environ 12 caractères max). - Réécrire en japonais lisible mélangeant kanji et kana (les paroles sont en hiragana, mais les sous-titres utilisent l’écriture normale).
- Pour un affichage sur 2 lignes, utiliser
|(ex. :Appuie sur le bouton|en bas pour lire l’article).
4. Alignement lettre par lettre
uv run --python 3.12 --with openai-whisper python $S/scripts/align.py $AD
→ Génère $AD/cap_events.json (temps d’entrée et de sortie de chaque groupe) et $AD/line_starts.json (début de chaque ligne chantée).
- Ne pas utiliser les timings ligne par ligne de whisper-cli. L’intro (quelques secondes sans chant) est traitée comme si le chant commençait à 0 s, et les lignes sont également réparties, ce qui fait que les sous-titres avancent alors qu’on ne chante pas.
- Pendant les silences de plus de 0,8 s, les sous-titres disparaissent.
- Si le taux de correspondance est inférieur à 80 %, la chanson dévie ou
captions.txtne correspond pas aux paroles.
5. Découpage en scènes (shots.py)
- Définir
STYLE(description visuelle commune à tous les plans) etSHOTS = [(numéro de ligne, n° du plan dans la ligne, scène, mouvement), …]. - 1 plan = 2 à 5 secondes. Pour les longues lignes, diviser en 2 ou 3 plans. Pour 3 min 30, environ 60 plans.
- Ne pas transformer tout le long-métrage en vidéo : mélanger des plans fixes avec un léger zoom permet de réduire de moitié la génération vidéo.
- Personnages : Professeur (bob, tablier) / Maman (chignon bas, rayures) / Enfant (coupe au bol) / Deux messagers dans le corps (combinaison rayée, casquette) / Méchant (sphère noire, cornes, éponge et paille) / Produit (motif réel).
6. Fiche personnage et images clés (Higgsfield gpt_image_2_5, 9:16, 0,25 crédit par image)
- Créer d’abord une fiche personnage, puis pour tous les plans suivants, fournir la fiche personnage + une image de référence (2 images) via
image_references. - Commencer chaque prompt par
STYLE:black and white 1930s rubber-hose cartoon, thick clean ink lines, cross-hatching, grayscale only, vintage Fleischer-era look, slightly grainy film, soft dark round vignette, no text python3 $S/scripts/make_reqs.py $AD image→ Lancergenerate_image_batchpar lots de 12.- Habiller l’enfant (sous-vêtements ou couche = NSFW et rejeté). Si l’image de référence montre des sous-vêtements, elle seule suffit à faire rejeter.
- Écrire le motif réel du produit dans le prompt (si un motif inexistant apparaît, recommencer).
- Tout vérifier dans une planche contact : style, pas de texte, conforme à la fiche personnage.
7. Animation (Grok Imagine grok_video_v15_lite, 720p, start_image uniquement, 1 s ≈ 1 crédit)
python3 $S/scripts/make_reqs.py $AD video→ Lancergenerate_video_batchpar lots de 12. Durée = durée de la partie + 0,5 s (3 à 8 s).- Prompt : « Anime cette image : . Garde le même style, composition et personnage, mouvements de caoutchouc rebondissants, scintillement du film, caméra fixe, pas de coupe, pas de nouveau texte. »
- En cas d’échec avec retour d’un preset, ajouter
declined_preset_idaux params et relancer. - Voir toutes les dernières images côte à côte. Si le produit tourne et que le motif se déforme, n’utiliser que les secondes avant la déformation (
SRC_MAX), ou faire un mouvement de va-et-vient sur la partie de face.
8. Export du fond (sans texte)
python3 $S/scripts/bg.py $AD # → $AD/bg.mp4 (1080×1920, 30 ips) et shot_starts.json
- Les changements de plan sont calés sur les débuts de ligne chantée (line_starts.json). Le premier plan commence à 0 s.
- Pour l’intro sans chant, une option est d’enchaîner rapidement des scènes fortes (méchant, inondation, coup de tampon, etc.) pour la remplir.
9. Remotion ($AD/remotion)
- Placer
public/bg.mp4(fond),public/song.mp3,src/data.json:python3 $S/scripts/make_data.py $AD --hook-end 29.3 --cta 192.9 --brand 44,46,47,50 --hook-top "Aux mamans en plein apprentissage de la propreté" --hook-main "La couche ne s’enlève pas" --hook-mark "La vraie raison" --brand-name "<Nom du produit>" --keys "<mots-clés à mettre en jaune, séparés par des virgules>" - Éléments affichés (
src/SongAd.tsx) :- Accroche du haut : carte en papier (gros cadre noir, ombre décalée, légèrement inclinée) pour faire comprendre « à qui » et « de quoi » dès la première seconde. Ex. : « Aux mamans en plein apprentissage de la propreté / La vraie raison pour laquelle la couche ne s’enlève pas ».
- Sous-titres : coins arrondis noirs avec texte blanc en gras, apparaissant en rebondissant. Les mots-clés sont en jaune (seule couleur dans le noir et blanc).
- Étiquette produit : uniquement sur les plans où le produit apparaît, en haut en petit.
- CTA : du dernier « Appuie en bas » jusqu’à la fin, trois flèches jaunes qui descendent en rebondissant + « Appuie sur le bouton | en bas pour lire l’article ».
- Export (ce Mac fait planter Chrome headless seul → utiliser
chrome-wrap.sh, hors sandbox) :
cd $AD/remotion && NODE_USE_ENV_PROXY=1 npx remotion render src/index.ts SongAd out/<ID de la pub>.mp4 --browser-executable=./chrome-wrap.sh --concurrency=6 --crf=20
- Livraison finale : ré-encoder avec
-crf 23 -movflags +faststart(le bruit du noir et blanc alourdit le fichier ; ~200 Mo pour 3 min 30).
10. Contrôle qualité (obligatoire avant ouverture)
- Lire la planche contact toutes les ~1 s (24 images) : vérifier que les sous-titres ne sont pas décalés par rapport à la chanson / qu’ils n’apparaissent pas pendant les silences / que le motif du produit ne se déforme pas / que les flèches CTA restent dans le cadre / qu’il n’y a pas de texte superflu.
- Vérifier séparément les 3 premières secondes (l’accroche est-elle immédiatement compréhensible ?).
- Créer une page de prévisualisation HTML et l’ouvrir. Le nom de la pub est celui attribué par AdLab (H-XXX-000a), utilisé tel quel comme nom de fichier.
Points bloquants rencontrés (mesures de cette procédure)
- Sous-titres décalés dès le début : le chant commençait à 4,9 s mais whisper-cli partait de 0 s → résolu avec
align.py(word_timestamps d’openai-whisper + difflib pour l’alignement des caractères). - NSFW sur les images clés : enfant en sous-vêtements / image de référence avec sous-vêtements → habiller l’enfant / décrire l’image de référence dans le prompt de style.
- Produit qui tourne et se déforme : Grok a tendance à tourner sur le côté. N’utiliser que les secondes de face.
- Trop de contenu : 61 images + 61 vidéos pour une seule pub. La prochaine fois, diviser par deux en utilisant les stocks et des plans fixes zoomés.
- Dernier caractère d’un long mot qui passe à la ligne → utiliser
|pour spécifier la coupure.
Liens connexes : reference/lyrics.md (modèle et exemple de paroles), /zackd-ad (type animation 3D), AdLab (enregistrer l’hypothèse avant de créer).