Que fait Motion Ad Studio (auto-améliorant) ?
Créez une publicité de motion design verticale de 20 à 40 secondes qu'un motion designer senior signerait : image 0 déjà en mouvement, un objet porteur tout au long du film, des transitions coupées en plein mouvement et adaptées à la vélocité, et chaque clic, atterrissage, chute et whoosh verrouillé sur un mot parlé ou un temps musical. Le film est une seule page HTML (timeline GSAP + fonctions pures du temps). Il est rendu image par image en MP4, et des scripts le vérifient avant que quiconque ne le regarde. Les effets sonores sont placés à partir de la propre liste d'événements du film, de sorte que la synchronisation audio est garantie par construction plutôt qu'à l'oreille.
À chaque exécution : lisez references/lessons.md et references/runs.md EN PREMIER. Terminez par la Rétrospective (étape 13).
La compétence ne s'améliore que si vous écrivez les leçons.
0. Prévol (toujours)
python scripts/preflight.py [--elevenlabs-mcp yes] # passez yes si VOUS avez des outils ElevenLabs connectés
Les chemins utilisés ci-dessous : scripts/..., references/... et templates/... sont relatifs au dossier de cette compétence
($SKILLS/motion-ad-studio). $MOTIONMAXXING est le dossier du moteur ($SKILLS/motionmaxxing ; preflight l'affiche), et
$SEAM_GATE est le script optionnel de seam gate que preflight trouve (ou passez --seam-gate FILE).
| Besoin | Pourquoi | Si manquant |
|---|---|---|
| Moteur motionmaxxing (Apache-2.0) | render.mjs (images → MP4), look.py vérifie, lint.mjs lint design, runtime/vendor/gsap.min.js | git clone https://github.com/Tejashmakwana/motionmaxxing à côté de cette compétence, ou définissez MOTIONMAXXING |
| ffmpeg + ffprobe, Node 18+, Chrome/Chromium/Edge | rendu, sondage, mixage | installez ; définissez CHROME_PATH si Chrome n'est pas trouvé automatiquement |
| Python 3.9+ avec numpy + Pillow | beats, synthèse, mixage, feuilles | pip install numpy pillow |
| faster-whisper (optionnel) | timestamps de mots pour le verrouillage sur les mots | pip install faster-whisper, ou tout aligneur qui donne les heures de début/fin des mots |
| Seam gate (optionnel) | prouve que chaque transition est adaptée à la vélocité | HyperFrames motion-doctrine + patches/seam-gate-camera-overlap.patch |
| ElevenLabs (optionnel, recommandé) | VO expressive, musique composée, SFX personnalisés | voir la section suivante |
ElevenLabs est optionnel : notifiez l'utilisateur une fois, ne bloquez jamais
Si preflight affiche l'AVIS (pas de clé API et vous n'avez pas d'outils ElevenLabs), relayez-le à l'utilisateur dans sa langue avant l'étape audio, en un court message, et laissez-le choisir :
- connecter : il ajoute une
ELEVENLABS_API_KEYou connecte le serveur MCP ElevenLabs. Relancez preflight. - continuer : construisez le film complet avec le chemin sans clé ci-dessous. Dites une fois dans la note de livraison qu'ElevenLabs améliorerait la qualité de la VO et de la musique. Ne demandez plus dans le même projet. Si vous ne pouvez pas demander (exécution par lots ou non interactive), continuez sans et mettez la recommandation dans NOTE.md.
| Couche | Avec ElevenLabs | Sans (livré quand même) |
|---|---|---|
| Voix-off | TTS avec balises d'émotion, 2 prises, choisissez-en une | l'enregistrement de l'utilisateur (meilleur), ou une voix guide TTS locale/OS ; ou un film mené par la musique sans VO |
| Musique | musique générée pour la durée du film, drop sur le payoff | scripts/synth_bed.py (procédurale, grille de beats exacte), ou un morceau dont l'utilisateur a les droits |
| SFX | 1-3 échantillons hero (fouet, whoosh, frappe) | scripts/mix_events.py synthétise chaque SFX localement |
| Temps des mots | speech-to-text avec timestamps (ou timestamps TTS) | scripts/words.py (local faster-whisper) |
Détails, prompts, coûts de crédit et règles de licence : references/audio-providers.md.
Pipeline
-
Espace de travail.
python scripts/new_film.py <projet>copie le kit one-take, le runtime GSAP et les polices locales. Rendez une image fixe de la démo intacte pour prouver la chaîne d'outils :node $MOTIONMAXXING/scripts/render.mjs <projet>/film/index.html --still 1.2,16.4 <projet>/stills. -
Kit de marque. Obtenez les fichiers logo officiels de l'utilisateur et recadrez chacun à son alpha bbox. Si un porteur doit s'ancrer dans le logo, mesurez les rectangles des sous-glyphes. Prenez les couleurs en comptant les
#hexdans le CSS du site et les polices en woff2 locales (scripts/fetch_fonts.py). Utilisez le canal CTA que la marque utilise réellement. Ne redessinez jamais et n'approximons pas un logo : demandez-le. -
Une idée + un nouveau style. Écrivez une seule idée que seule cette marque pourrait filmer. Le test de couverture du logo : cachez le logo et le film doit encore pointer vers cette marque. Écrivez trois directions, éliminez-en deux, et choisissez un style DIFFÉRENT de la dernière ligne de
references/runs.md. -
Hook. Écrivez 3 variantes de moins de 12 mots (question, négation, spécificité, histoire) et choisissez-en une. L'image 0 est déjà occupée et en mouvement, le hook est à l'écran dès l'image 1, et rien n'apparaît en fondu depuis le noir.
-
Voix-off. Écrivez environ 2,5 mots/s (30 s ≈ 70-75 mots). Si le TTS prend en charge les balises d'émotion, marquez chaque ligne ([curieux] [confiant] [énergique] [enjoué] [chaleureusement]). Générez ou enregistrez-la, coupez les longues pauses, ajustez la durée avec
atempo≤ 1.1, puis obtenez les temps des mots :python scripts/words.py audio audio/vo.wav --lang <code>. Whisper vous donne UNIQUEMENT les TEMPS. Le texte des sous-titres provient toujours du script approuvé. -
Musique. Générez (durée + BPM + "drop à "), licencez un morceau, ou exécutez
python scripts/synth_bed.py --bpm 120 --dur 32 --drop 15.8 --out audio/bed.wav. Obtenez la grille avecpython scripts/beats.py audio/music.mp3 audio/beats.json(synth_bed écrit un.beats.jsonexact). Coupez la tête de la musique pour que le drop tombe sur le mot de la VO du payoff : beat film k = premier_beat - coupe + k·période. -
STORYBOARD.md + ledger.json (
templates/one-take/contient un exemple rempli). Incluez :- la spécification de la page, l'idée et les trois directions ;
- une feuille de rythme (étirement / t / énergie 0-10 / chemin / musique) ;
- une carte de timing : chaque événement avec le mot
w(i)ou le beatbeat(k)auquel il est verrouillé ; - la VO et la liste des données illustratives ;
- le ledger : une ligne par jointure (axe de sortie/entrée + direction, temps de coupe).
-
Construction. Copiez les motifs du kit (
references/one-take-kit.md) :- horloges
w(i)/we(i)/beat(k); - ordre par image
tl.seek → PRE (caméras, ancres mobiles) → curseurs (lecture des rects live) → UP (UI qui suit); - caméra 3D avec keyframes et un moteur de curseur qui cible les rects DOM live ;
- mise à jour de texte/frappe/classe en tant que fonctions pures de t ;
- événements
sfx()et whooshes dérivés de la caméra.
Contrat dont le rendu a besoin :
#mainportedata-composition-id="main" data-width data-height data-duration.window.__seek / __duration / __timelines / __events / __player / __ready / __playerReady / __renderReady. Films de style montage (scènes superposées, UI plate, porteur de logo) :references/montage-kit.md. - horloges
-
Regardez-le. Rendez 15-20 images fixes (
node $MOTIONMAXXING/scripts/render.mjs ... --still t1,t2,... stills), regroupez-les (python scripts/sheet.py stills sheet.jpg 6 220) et effectuez un passage de vision : une ligne par image, puis une liste de défauts. Corrigez et répétez 2-3 passages.- La vérité géométrique (ce qui est où, visible, son opacité) provient de
node scripts/probe.mjs index.html "t1,t2" "#a,#b". - La vérité textuelle provient d'un recadrage en pleine résolution : la vision interprète mal les textes arabes et CJK réduits comme des "coquilles" qui n'existent pas.
- La vérité géométrique (ce qui est où, visible, son opacité) provient de
-
Seam gate (recommandé). Servez le dossier du film sur localhost, puis exécutez
node "$SEAM_GATE" verify --ledger ledger.json --url http://127.0.0.1:<port> --comp-url http://127.0.0.1:<port>/index.html. L'objectif est 0 ÉCHEC. Les lignes où un coup de caméra one-take maintient les deux fenêtres à l'écran nécessitent"overlap": "camera"plus le patch danspatches/. Arrêtez le serveur ensuite. Voirreferences/qa-gates.md. -
Mixage. Chaque SFX vit dans
window.__events({t, type:'sfx', name, gain, dur?, speed?}).- Exportez-les avec
node $MOTIONMAXXING/scripts/render.mjs index.html --still <t> ev, qui écritev/events.json. - Mixage :
python scripts/mix_events.py --events ev/events.json [--vo vo.wav --vo-at 0.10] [--music bed.wav --music-trim s] --dur <s> --out audio/mix.wav [--music-db -24] [--tp -2.5] [--whip/--whoosh/--typing samples] [--lift t0:t1:dB] [--fade t]. - Niveaux : VO à -18 dBFS RMS, musique à -30 avec ducking sous la VO, whooshes alignés en pic sur l'image la plus rapide de la caméra, loudnorm deux passes à -14 LUFS / TP ≤ -1.
- Exportez-les avec
-
Rendu + vérifications + livraison.
- Rendu :
node $MOTIONMAXXING/scripts/render.mjs index.html <NOUVEAU-nom>.mp4 --audio ../audio/mix.wav --crf 17 --grain 0.03. Utilisez un nouveau nom de sortie pour chaque tentative : deux rendus dans le même fichier le corrompent. ffmpeg -v error -i x.mp4 -f null -ne doit rien afficher. Ensuite, exécutezpython $MOTIONMAXXING/scripts/look.py x.mp4 --out look --expect <dur> --expect-audio(G0/G2/G3/G5 PASS) etnode $MOTIONMAXXING/scripts/lint.mjs index.html.- Livraison : le master 9:16, un recadrage 4:5 (
crop=1080:1350:0:200une fois la mise en page vérifiée), 2-3 PNG de couverture, NOTE.md (idée, carte de timing, données réelles vs illustratives, sources audio + licences, numéros des vérifications, quoi améliorer) et un dossierproject/(film + audio + scripts). - Nettoyage : arrêtez les serveurs et le Chrome headless orphelin.
- Rendu :
-
Rétrospective (OBLIGATOIRE, avant votre réponse finale). Ajoutez une règle datée + pourquoi dans
references/lessons.md. Ajoutez une ligne àreferences/runs.md(date, type de produit, style, durée, numéros des vérifications, verdict quand connu). Patchez ce fichier, un script ou le kit si une étape a changé. Lorsque l'utilisateur réagit plus tard, enregistrez le verdict. Les leçons ne contiennent que la méthode, jamais les noms de clients ou les données privées.
Barre de qualité
- Hook : formulation réelle du client ou un fossé de curiosité. Image 0 en mouvement, le hook lisible dès l'image 1, pas de fondu depuis le noir.
- Continuité : un porteur à travers le film (curseur, puce, marque logo), pas de fondus enchaînés, et 2-3 types de transitions répétés. Les coupes ont lieu en plein mouvement et sont adaptées à la vélocité. Gardez une direction actuelle : pour "suivant", les films RTL font voyager le contenu de gauche à droite et les films LTR de droite à gauche. Les vecteurs réservés sont dépensés pour le sens.
- Verrouillage du timing : chaque clic, chute et atterrissage repose sur
w(i)oubeat(k), et le drop musical repose sur un mot de la VO. Les whooshes dérivent de la vélocité de la caméra. La carte de timing liste chaque événement et à quoi il est verrouillé. - Pas de vacillement inactif : chaque temps mort a un mouvement de caméra avec une intention, une révélation en plusieurs étapes ou une UI live. Le calme n'appartient qu'avant un payoff.
- Zones de sécurité (1080×1920) :
- Placements Meta payants : texte lisible en y 270-1250 et x 60-960 (les 120 px de droite sont les boutons) ;
- Reels/TikTok organiques : gardez le bas 320-370 px libre ;
- mettez le rail de sous-titres sous les panneaux UI, jamais sur un compositeur ;
- les mots du rail illustrent déjà ce que l'image montre.
- Fin : wordmark plus un CTA dans le canal réel de la marque. Maintenez la fin 0,6-1,4 s et gardez le plan final ≤ 25 % du film.
- Honnêteté : déclarez les données illustratives dans NOTE.md. N'inventez jamais de performances, de prix ou de témoignages.
- Objectifs : look.py G0/G2/G3/G5 PASS, énergie de mouvement ≥ 5/255 de changement de luminance moyen (les films UI sombres se situent près de 2), synchronisation des coupes ≥ 35 % (le benchmark pro mesuré), -14 LUFS ± 0,5 avec pic réel ≤ -1 dBTP, 0 erreurs de décodage.
Notes de plateforme
- Tâches en arrière-plan sur Windows git-bash : appelez
node.exe, pas l'aliasnodewinpty ("stdin n'est pas un tty"). - Une importation ESM d'un chemin Windows absolu nécessite
file:///C:/.... - Chrome headless fuit à partir d'exécutions interrompues. À la fin, listez les navigateurs démarrés avec
--headless=newet--remote-debugging-port=0dont le parent a disparu, et tuez la racine avec son arbre. - Vitesse de rendu : UI plate ≈ 4 min pour 35 s à 1080×1920. Un monde 3D ≈ 4-5 min à ~4 fps, mais seulement si le nombre de couches 3D reste petit.
Fichiers
scripts/:preflight.py: dépendances et avis ElevenLabs ;new_film.py: structurer un projet ;fetch_fonts.py: woff2 local ;words.py: temps des mots ;beats.py: grille de beats et drop ;synth_bed.py: musique sans clé ;mix_events.py: mixage piloté par les événements ;sheet.py: planche contact ;probe.mjs: géométrie live.
templates/one-take/: le film complet one-take avec caméra 3D comme démo exécutable (produit fictif, texte arabe RTL), avec STORYBOARD.md et ledger.json.references/:research.md: étude du paysage, compétences amont, notes de sécurité, spécifications de plateforme ;lessons.md,runs.md: la mémoire auto-apprenante ;audio-providers.md,one-take-kit.md,montage-kit.md,qa-gates.md.
patches/seam-gate-camera-overlap.patch: règle optionnelle de seam gate pour les films caméra one-take.