Que fait remotion-ffmpeg-skill ?
ffmpeg-skill mesure → Remotion dessine → ffmpeg-skill vérifie et livre. Les scripts se trouvent dans scripts/ à côté de ce fichier ; exécutez-les avec python3 <chemin-du-skill>/scripts/<nom>.py. --help sur un script affiche la liste complète des options ; references/timeline.md décrit le format de la timeline et les options que chaque composition accepte.
Ce skill dépend de ffmpeg-skill (situé à côté de ce skill, dans ~/.claude/skills/ffmpeg-skill, ou via FFMPEG_SKILL_DIR). Il n'exécute jamais directement de commande ffmpeg/ffprobe : la mesure, la vérification et la livraison passent par les scripts de ffmpeg-skill, donc leurs garanties s'appliquent.
Options partagées (tous les scripts) : --json (un objet JSON sur stdout ; à privilégier), --dry-run (planifier, sans rien écrire), --overwrite (la seule façon de remplacer une sortie existante), --timeout SECONDES.
Workflow (dans cet ordre)
- Projet une fois. Pas encore de projet Remotion :
init.py ./motion --install(copie le modèle, exécutenpm install; le navigateur headless de Remotion se télécharge lors du premier rendu). Un projet existant issu de ce skill : réutilisez-le. - Mesurer.
analyze.py SOURCE [--captions FICHIER.srt] [--beats] -o SOURCE.timeline.json. Lisez le résumé et leswarnings: une source VFR ou HDR doit être corrigée avec ffmpeg-skill avant le dessin (color.py --to-sdr, une exportation à fréquence d'images constante) — Remotion effectue le rendu en SDR sur une grille d'images fixes. N'écrivez ni ne modifiez jamais manuellement les nombres de la timeline ; refaites une mesure à la place (--threshold,--min-silencepour une pièce silencieuse). - Prévisualiser des images fixes.
still.py --project ./motion --comp NOM --timeline TL --at 1.5 --at 6et visualisez les PNG : placement des sous-titres, zoom avant, couleurs. Peu coûteux ; à faire avant un rendu complet. - Rendre.
render.py --project ./motion --comp NOM --timeline TL [--options look.json] -o SORTIE.mp4(--fast= prévisualisation en demi-taille,--frames 0-89= une plage,--codec prores -o master.mov= un master). Il vérifie la sortie par rapport à la timeline (nombre d'images, fps, taille, audio) et se termine avec un code d'erreur en cas de non-concordance.- Format : dessinez dans le format de livraison final.
--aspect 9:16pour Reels / TikTok / Shorts (1:1,4:5,16:9aussi) ;--fit blur(par défaut lorsque le format change : contenu dans une copie floutée),contain(barres) oucover(recadrage — vérifiez d'abord le sujet sur l'image fixe). Ne faites jamais un rendu en 16:9 et laissez un modèle 9:16 le recadrer : les sous-titres perdent leurs bords.pipeline.py --platformchoisit le format à partir du modèle ffmpeg-skill pour vous. - Polices : les sous-titres en japonais/chinois/coréen reçoivent automatiquement la police CJK trouvée par ffmpeg-skill sur la machine (installée dans le projet, donc pas de tofu) ;
--font-file F.ttfutilise une police spécifique ; la ligne de rapportfont :indique quelle police a été utilisée, ou qu'aucune n'a été trouvée. - Couche pour application de montage :
--overlay --keep-graphics(Captioned / PeakPulse, format source) dessine les graphiques seuls sous forme de ProRes 4444 transparent.graphics.movet les compose sur la source non modifiée avec ffmpeg-skilloverlay.py; transmettez le.movà quelqu'un qui finalise dans Premiere / Resolve / Final Cut. Ce n'est pas plus rapide qu'un rendu normal.
- Format : dessinez dans le format de livraison final.
- Livrer.
deliver.py SORTIE.mp4 --platform youtube|reels|tiktok|shorts|x|...exécute le modèle de livraison de ffmpeg-skill et sa tablecheck.py. Les lignes de format peuvent être corrigées sans risque ; les lignes de jugement (durée, format) modifient le contenu — demandez. Mentionnez les AVERTISSEMENTS, ne les poursuivez pas. Aucune destination nommée : sautez cette étape et dites-le. - Regarder. Pas terminé tant que la réponse ne nomme pas la planche contact écrite par render.py (
Regard : CHEMIN) et ne dit pas ce qu'elle montre. Mécanique (vérifier et rapporter) : le texte est là où il a été demandé, les repères apparaissent à leur heure, rien n'est coupé par le cadre. Jugement (dites ce que vous voyez, l'utilisateur décide) : texte sur un visage, une coupe qui tombe mal. Pas de visionneuse d'image :Regard : CHEMIN (pixels non inspectés)— ne prétendez jamais avoir regardé. Pas de planche contact (look_errordans le résultat, par exemple un FFmpeg sansdrawtext) : regardez les images destill.pyà la place et transmettez la correction nommée par l'erreur.
Les fichiers d'options sont vérifiés avant le rendu : une clé inconnue ou un mauvais type est refusé (kind: input) au lieu de ne rien faire silencieusement.
MCP : mcp/server.py expose les mêmes outils (schémas depuis scripts/_contract.py, contract --json les affiche).
Tout en une seule fois : pipeline.py SOURCE --project ./motion --comp NOM [--captions F] [--platform P] exécute les étapes 2→4→5 avec les mêmes vérifications et s'arrête dès la première étape échouée.
Demande → script / composition
| Demande | Exécution |
|---|---|
| « sous-titres animés / légendes sur cette vidéo » | analyze.py --captions → render.py --comp Captioned |
| « couper les silences / coupure / resserrer cette discussion » (avec animation) | analyze.py → render.py --comp Jumpcut (sous-titres recalés si fournis) |
| « graphiques qui réagissent à l'audio / frappent sur le rythme / sur les coupes » | analyze.py [--beats] → render.py --comp PeakPulse (impulsions sur les temps lorsque la grille a été mesurée) |
| « sous-titres karaoké / les mots s'allument au fur et à mesure qu'ils sont prononcés » | analyze.py --words MOTS.json [--captions F.srt] → render.py --comp Karaoke (timings des mots depuis un moteur vocal local, whisper JSON ; sans SRT, les repères sont groupés à partir des mots) |
| « tiers inférieurs / titres nominatifs / titres de chapitres » | render.py --comp Titled --options avec lowerThirds / sceneTitles — le texte vient de l'utilisateur ; demandez-le, n'inventez jamais de noms |
| « vidéo des meilleurs moments / moments forts » | analyze.py --highlights N [--target S] → render.py --comp Highlights (classement par énergie audio : candidats, dites-le) |
| « couper sur le rythme / montage musical » | analyze.py --beats [--highlights N] → render.py --comp BeatMontage (audio continu, coupes image tous les beatsPerCut temps mesurés ; coupes de scène si aucune grille fiable) |
| « pour YouTube / Reels / TikTok ... » | pipeline.py --platform (effectue le rendu dans le format du modèle, puis livre et vérifie), ou render.py --aspect + deliver.py --platform |
| « vertical / 9:16 / carré » | render.py --aspect 9:16 (ou 1:1, 4:5) |
| « sous-titres japonais » / une police spécifique | rien de plus pour CJK (police automatique) ; --font-file pour une police choisie |
| « donne-moi les graphiques en tant que couche séparée » | render.py --overlay --keep-graphics |
| « changer la couleur / la police / la taille des sous-titres / le zoom » | un JSON --options (references/timeline.md), refaire le rendu |
| plusieurs clips (« intro + discours + outro ») | analyze.py A.mp4 B.mov C.mp4 (ou pipeline.py avec plusieurs entrées) : ffmpeg-skill join.py normalise et les assemble, puis tout est mesuré sur le fichier assemblé |
| « prévisualisation » / « montre-moi une image » | still.py |
| un nouveau type de graphique | ajoutez une composition dans src/ du projet qui lit Props depuis src/timeline.ts ; effectuez le rendu avec --comp VotreId (render.py rapporte alors les nombres mesurés sans attente intégrée) |
| coupe simple / recadrage / redimensionnement / volume sans graphiques | pas ce skill : utilisez ffmpeg-skill directement |
| quelque chose s'est cassé | doctor.py [--project DOSSIER] |
Ce que ce skill décide et ce qu'il ne décide pas
- Décide (mécanique) : durée, fps et taille de la composition (depuis l'analyse) ; où tombent les coupes (depuis les silences mesurés) ; quand les repères apparaissent (depuis le fichier de sous-titres) ; quand les impulsions frappent (depuis les pics mesurés) ; si un rendu correspond à sa timeline.
- Ne décide pas : les noms, titres et noms de chapitres (les tiers inférieurs et titres de scène sont le texte de l'utilisateur — demandez) ; quels mots un sous-titre dit — le texte du repère est dessiné exactement comme écrit, jamais raccourci ou paraphrasé, même pour « le faire tenir » (proposez une
captionSizeplus petite à la place) ; ce qui compte comme un moment fort ; si un rendu est bon. Ceux-ci appartiennent à l'utilisateur ou à l'agent appelant. - N'invente jamais de données. Pas de sous-titres sans fichier de sous-titres chronométré provenant de l'utilisateur ou d'un moteur de synthèse vocale local ; pas de grille de rythme que
--beatsn'a pas mesurée.
Règles qui évitent les échecs de travail
- Licence Remotion : gratuite pour les particuliers et les organisations à but lucratif avec jusqu'à 3 employés ; les grandes entreprises ont besoin d'une licence Remotion entreprise (https://www.remotion.dev/license). Si l'utilisateur est clairement une grande entreprise, dites-le une fois.
- Conservez les originaux de l'utilisateur : les sources sont liées dans
public/media/du projet, jamais modifiées ; les sorties ne remplacent jamais un fichier existant sans--overwrite. - Sous-titres CJK : la police automatique provient de la détection de polices de ffmpeg-skill ; lorsque le rapport indique qu'aucune police n'a été trouvée, installez-en une (Noto Sans CJK) ou passez
--font-file— du tofu dans la planche contact est un échec. Les lignes japonaises sont coupées entre les phrases, pas à l'intérieur des mots. - Vitesse (mesurée sur une machine Linux à 2 cœurs, tous les cœurs — valeur par défaut de render.py) : environ 2,6× la durée du clip pour 1080p30 (30 s ont pris 80 s). Prévisualisez avec
still.pyet--fastavant un rendu complet de longs métrages ; informez l'utilisateur du temps prévu avant de lancer un long rendu.--concurrencyau-dessus du nombre de cœurs est refusé par Remotion. - Les packages Remotion dans un projet doivent tous être de la même version ; le modèle les fige. Ne mélangez pas une version
remotiondifférente. - Un rendu qui échoue à la vérification est un échec : rapportez les lignes échouées depuis
--json, ne le livrez pas.