overlays : graphiques synchronisés avec la voix, placés dans Premiere
Deux compétences, un atelier
Ici (overlays) : placer et éditer | Atelier (motion-design) : fabriquer |
|---|---|
transcription, chronologie du .prproj, plan écrit avec des ancres de phrase | le SEUL projet Remotion : motion-design/src/, compositions de superpositions dans src/illustration/ (BrandedVideo, LowerThirdTrack, Screencast, Scene, FondAnime) |
sourcing : photos, b-rolls, GIF (gifs.py), captures web, cartes e-mail (mail-cards.py) | public/ : polices, scenes/<video>/ (médias de scène), sfx/ (sons) |
enregistrement de démos de sites (screencast-record.py) | thème (src/illustration/theme.ts), palette sonore (reference/sound-palette.md, scripts/make-sfx.py, scripts/son.py) |
render-segments.py, screencast-render.py, montage-tella.py : lancer le rendu DANS l'atelier, puis tout placer dans le XML Premiere | musique, mix |
Les deux dossiers doivent être voisins (<skills>/overlays et <skills>/motion-design) : les scripts trouvent l'atelier via ../motion-design. Un nouveau composant de scène s'écrit dans motion-design/src/illustration/scenes/ ; un nouveau son va dans les recettes de synthèse de l'atelier. Installation (une fois par machine, installation du plugin) : bash "${CLAUDE_PLUGIN_ROOT}/install.sh" --data "${CLAUDE_PLUGIN_DATA}". À la main, avec les quatre dossiers de compétence copiés côte à côte : bash install.sh depuis la racine du kit. Après une mise à jour du plugin, le lien node_modules de l'atelier est perdu : relancer la ligne de configuration. Détails : INSTALL.md du kit.
Règle d'or éditoriale (paramètre par défaut, à adapter à la chaîne)
La vidéo est portée par la voix. Les graphiques ne racontent pas ce qui est dit : ils ancrent ce qu'on ne ferait que ressentir autrement (un nom propre, une citation, un lieu, un titre, un nombre), ou ils MONTENT ce dont on parle (un document, un site, un diagramme).
Deux niveaux d'habillage :
- léger : 1 premium par chapitre + 1 tier inférieur toutes les 45 à 60 s, en dehors de l'intro (0-30 s) et de la conclusion ;
- dense (démo, vidéo d'enquête ou tutoriel) : scènes animées sur 60 à 70 % de l'image, chaque scène synchronisée avec les mots, aucune scène sans mouvement pendant plus de 3 s. La tête parlante garde sa place.
Demandez le niveau souhaité s'il n'est pas précisé. Ne pas animer par défaut : l'intro (les téléspectateurs décident s'ils restent), une anecdote intime (l'animation tue l'émotion), une question qui crée du suspense, la conclusion et l'appel à l'action, une liste d'adjectifs.
Un écart par rapport au script qui a été dit à l'écran (un nombre, un terme, une approximation) est corrigé À L'ÉCRAN : le montage brut le signale dans son rapport, le plan met la bonne valeur sur la voix, sans demander une nouvelle prise.
Règle zéro : la chronologie de référence est celle du projet Premiere, jamais celle du montage brut
L'ordre est TOUJOURS : montage brut (rough-cut) -> le moniteur examine et modifie le montage dans Premiere -> superpositions. Entre les deux, les coupes bougent, des plans sont supprimés, la durée change : les temps calculés sur le montage brut arrivent 30 s à 1 min plus tard et les éléments se retrouvent après la fin de la vidéo.
Arrêt obligatoire après le montage brut, même si l'utilisateur a dit « montage brut puis superpositions, c'est à vous » : livrer le XML du montage brut, puis attendre que l'utilisateur dise qu'il l'a validé dans Premiere. Avant cela, pas de plan, pas de temps, pas de placement. Seul ce qui ne dépend d'aucun temps peut avancer (sourcing d'images et de GIF).
python3 scripts/timeline-from-prproj.py "/path/clip.MOV" --list # quelles séquences contiennent le clip
python3 scripts/timeline-from-prproj.py "/path/clip.MOV" --sequence "Derush_v1"
# -> <clip>_transcription.json (mots dans le temps de la SEQUENCE) + <clip>_timeline.json (carte clip -> séquence)
Il lit les clips de la séquence choisie (ticks = 254016000000/s) et reporte les mots de <clip>_Derush_vN_work/words_premiere.json (la transcription du projet, déjà réalignée par le montage brut). Plusieurs séquences portent le clip : il refuse de deviner (code 2), demandez laquelle. Plusieurs clips dans une seule séquence : passez-les tous, dans l'ordre (A.MOV B.MOV --sequence "...") ; chaque entrée de chronologie et chaque mot porte media, et les sorties prennent le nom du premier clip. Un mot coupé net reste s'il COMMENCE dans le clip (au moins 80 ms avant la coupe) ; un mot vraiment coupé casse l'ancre qui le vise : déplacer l'ancre au mot précédent + offset. Vérifiez que le dernier élément placé reste avant la vraie fin de la séquence.
Ne jamais réutiliser un cuts_final.json ou une carte du montage brut. Sans projet Premiere (clip seul) :
python3 scripts/transcribe.py "/path/clip.mp4" (whisper.cpp local, environ 5 min pour 15 min de métrage sur Apple Silicon).
Quand l'utilisateur rend le montage, lancez d'abord la comparaison : les changements qu'il a faits dans Premiere sont le retour le plus fiable. Comparez sa séquence avec le XML du montage brut, transformez chaque écart récurrent en correction, vérification ou règle, et seulement ensuite écrivez le plan de superpositions. Quand l'utilisateur valide le montage final, faites de même avec le XML de superpositions livré : ce qu'il a supprimé, déplacé (plus de 2 images), redimensionné ou ajouté (ses propres plans collés sur V1 ne comptent pas) devient une correction, une vérification ou une règle. Rien supprimé ni déplacé signifie que la méthode de cette livraison est bonne : gardez-la.
Pipeline
0. (Optionnel) b-rolls
Un dossier Brolls/ à côté du clip, fichiers nommés NN_description_K.mp4 (numéro, description, variante) :
python3 scripts/match-brolls.py "/path/clip.mp4" # -> <clip>_broll-script.json à compléter
Pour chaque b-roll : la variante (file), le temps (timecode MM:SS, vérifié dans la transcription), durationSec (null = durée native). Placé sur V2. Lancez-le AVANT les démos de sites (--force écrase le fichier). Regardez une planche contact des variantes avant de choisir (3 images par variante) : un nom de fichier ment souvent (« street-photography-portrait » était un plan de drone d'une ville de nuit). Ne placez jamais un b-roll sur une phrase que le locuteur ne montre pas littéralement, et aucun son de superposition pendant qu'un b-roll joue.
0 bis. (Optionnel) photos d'illustration
Pour une vidéo qui cite des personnes, des œuvres, des livres, des lieux :
- Manifeste à partir du script de la vidéo : entités dans l'ordre d'apparition ->
illustrations-manifest.json:Le script de référence peut être dans n'importe quel format (texte, Markdown, un document) : il donne l'orthographe correcte et les choses à montrer.{"version": 1, "dest": "Illustrations", "items": [ {"n": 1, "categorie": "reference", "nom": "Prénom Nom", "sujet": "portrait", "url": "https://...", "fallback_urls": [], "note": "source: ..."}]} - URLs : sources gratuites d'abord (Wikimedia Commons, sites officiels, musées en libre accès), puis
python3 scripts/serp_images.py "Nom Titre" --num 5 --min-width 1200(Google Images via SerpAPI, cléSERPAPI_API_KEY). Vérifiez que l'image est la bonne (regardez la vignette, pas seulement le titre de la page ; les pages de lots aux enchères sont un piège). Vérifiez les droits si la vidéo est vendue. - Téléchargement :
python3 scripts/source-illustrations.py illustrations-manifest.json->Illustrations/NN-catégorie-nom-sujet.ext(octets vérifiés, largeur mesurée ; exit 1 si les URL manquent). - Timing :
python3 scripts/match-photos.py "/path/clip.mp4"-><clip>_photos-script.json, temps préremplis par une recherche floue du nom dans la transcription (la reconnaissance vocale déforme les noms propres). Vérifiez TOUJOURS chaque temps à la main par rapport à la transcription (la correspondance floue peut prendre une mention tardive au lieu de la première) ;enabled: falsesupprime une photo. Les photos vont sur V3, avec priorité sur les b-rolls (un b-roll qui chevauche une photo est supprimé du XML et journalisé).
Traitement des photos : jamais de recadrage (ratio natif, une verticale reste verticale) ; une photo repose sur un fond uni avec une marge sur les quatre côtés (environ 86 % du cadre), pas un contain plein écran qui touche les bords haut et bas. Pas de .webp dans le manifeste (Premiere le lit comme un média de longueur nulle en XML : convertir avec sips -s format jpeg). Une photo de moins de 800 px de large paraîtra floue : render-segments.py imprime un avertissement LOW RES, listez-les avant de livrer. Une couverture de livre montrée par une scène est l'image de l'éditeur prise sur le web (leur site, une maquette HD), jamais une image tirée des propres plans du locuteur.
Quand le locuteur MONTRE un objet, rien ne le couvre. Analysez la transcription pour « ici », « comme vous pouvez le voir ici », « celui-ci », « regardez » près de la mention d'une œuvre : le locuteur tient le livre ou l'appareil photo devant l'objectif. Pas de photo plein écran sur cette fenêtre (un monteur a supprimé chaque couverture de ce type dans un montage livré) ; la couverture va avant ou après la démonstration, ou pas du tout.
0 ter. GIF et memes (un basique, pas une option)
Un GIF toutes les 2 à 4 min, sur des moments d'humeur ou d'auto-dérision (« ça pousse très fort », « j'invente tout »), jamais dans l'intro, jamais pour illustrer une phrase technique littéralement. Une scène gif (superposition, cadre blanc, boucle) qui arrive sur le mot, avec son effet sonore.
python3 scripts/gifs.py chercher "c'est un bug" --planche gifs-sheet.jpg # liste + planche contact numérotée
python3 scripts/gifs.py prendre <id> --nom bug --public <video> # source MP4 + les données de la scène
Regardez la planche contact AVANT de choisir (un titre GIPHY ne dit pas ce qui est montré ; chercher en anglais fonctionne souvent mieux). prendre télécharge le MP4 (jamais le .gif) dans Illustrations/gifs/, garde gifs.json (source de chaque GIF), le copie dans motion-design/public/scenes/<video>/gifs/ et imprime les data de la scène gif (src, srcW, srcH, loopSec). Clé GIPHY_API_KEY (gratuite). Un GIF réutilise souvent une œuvre protégée : sur une vidéo qui est vendue, abstenez-vous.
1. Fréquence d'images et format du clip (CRITIQUE)
ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate,width,height -of csv=p=0 "/path/clip.mp4"
render-segments.py lit le taux et la taille du clip quand le JSON ne les donne pas. Un JSON à 30 sur un clip à 60 décale tout par un facteur de 2. À 29,97, n images de séquence durent n x 1,001 / 30 s, et chaque rendu doit couvrir son clip (tailFrames et le composant TenirFin s'en chargent). Un clip est écrit dans le taux de son MEDIA : Premiere lit <in> à 29,97 (le taux du <file>), pas dans le <rate> du clip ; le script écrit in = round(t x fps x 1000/1001) avec <ntsc>TRUE.
Vertical 9:16 (reel) : même pipeline, même JSON. Le tier inférieur détecte le vertical et monte au-dessus de la zone de légende ; les photos restent entières (une bande sur le fond) ; un b-roll 16:9 reçoit une échelle qui remplit la largeur. Règles reel (d'après la comparaison des livraisons avec le montage final) : photos de 2 à 3 s (défaut 2,5), tier inférieur aussi long que sa photo de portrait associée et commençant avec elle, pas de b-roll de stock sauf demande, pas de couverture pendant que le locuteur montre l'objet. Rendez toujours UN tier inférieur en tant qu'image fixe et compositez-le sur un cadre gris pour vérifier la disposition verticale avant la série.
2. Lire avant de proposer
Lisez la transcription EN ENTIER. Repérez : les noms de personnes (tier inférieur « nom »), les titres d'œuvres (« oeuvre »), les lieux (« lieu »), les termes ou mouvements (« term »), les citations fortes (premium quote-full), les annonces de partie (section-title ou carte de chapitre), les nombres marquants (scène stat), les documents, les échanges et les sites dont on parle (scènes de preuve, démos). Chaque nom, œuvre ou livre cité est MONTRÉ quelque part (une scène suspendue, une photo, une carte) ou la raison pour laquelle il ne l'est pas est écrite. Lisez le contenu de chaque diagramme dans les PROPRES mots du locuteur (relisez dans la transcription), jamais une interprétation : un diagramme erroné (un profil placé au mauvais niveau d'un entonnoir) vient d'une paraphrase.
3. Chaque premium est conçu en une phrase
« Ce que je veux voir : la phrase en grand, en italique, une règle d'accent sur la gauche, l'attribution en petit. » Si la description est « texte qui apparaît », ce n'est pas un premium : tier inférieur, ou rien.
4. Catalogue de base
| Type | Composant / genre | Piste | Données | Durée |
|---|---|---|---|---|
motion (premium plein écran) | quote-full | V5 opaque | text, author?, source? | 10-14 s |
lower-third | lower-third-nom | V6 alpha | name, years?, tag? | 6 s |
lower-third | lower-third-oeuvre | V6 | title, author, year? | 6 s |
lower-third | lower-third-lieu | V6 | place, date | 6 s |
lower-third | lower-third-term | V6 | term, subtitle? | 6 s |
section-title | V6 | eyebrow?, title | 4 s | |
scene | voir « Scènes animées » | V5 / V6 / V7 | data, cues | suit la voix |
Un nom et son œuvre cités dans les 10 s : un seul tier inférieur « nom » avec l'œuvre dans tag. Une citation du locuteur lui-même : quote-full sans author (sa voix signe). Les animations se terminent par un fondu automatique sur les 18 dernières images.
5. Temps sur le mot (CRITIQUE)
Jamais d'estimation : cherchez le mot dans <clip>_transcription.json et prenez son start. L'élément apparaît au début du mot (un tier inférieur peut le précéder d'au plus 0,5 s ; se synchroniser sur le début de la PHRASE est perçu comme une annonce qui arrive trop tôt). render-segments.py refuse un segment sans temps valide et vérifie chaque temps par rapport à la transcription (OK / WARN / UNKNOWN). Vérifiez aussi la fréquence d'images dans le JSON (étape 1).
6. Présenter le plan avant d'écrire
| # | Temps | Dur | Type | Composant | Pourquoi |
|---|--------|------|-------------|-------------------|----------------------------------|
| 1 | 01:24 | 6 s | lower-third | lower-third-nom | 1ère mention de Prénom Nom |
| 2 | 02:14 | 12 s | motion | quote-full | Citation pivot de la partie 1 |
Attendez l'approbation avant d'écrire le JSON et de lancer le rendu.
7. Rendu et importation
(cd ../motion-design && npm ci) # une fois
python3 scripts/render-segments.py "/path/clip.mp4" # tout : rendus + XML
python3 scripts/render-segments.py "/path/clip.mp4" --lower-thirds-only