Éditeur vidéo par client
Moteur et flux pour éditer comme un éditeur humain : comprendre le contenu, couper avec précision, appliquer le look du client,
vérifier et livrer. Le moteur n'a pas de style propre : tout le visuel provient de clients/<CLIENT>/look.py.
SKILL_DIR = dossier de cette compétence. Outils : engine/reel.py, tools/{takes.py, words.py, media.sh},
modèles dans templates/, looks de départ dans looks/.
Prérequis (vérifier la première fois ; installer ce qui manque)
ffmpeg,python3,node/npx· macOS :avconvertetsips(fournis avec le système) pour HDR→SDR et photos HEIC.- HyperFrames (rendu et bibliothèque SFX) :
npx hyperframes skills update general-video(installe aussimedia-use). - watch (voir/transcrire des vidéos et télécharger des liens Instagram/TikTok/YouTube avec yt-dlp) : compétence
watchde github.com/bradautomates/claude-video, moteur local WhisperX (gratuit) :setup.py --engine localet--backend whisperx. - whisper CLI (fenêtres de vérification) :
uv tool install --python 3.12 openai-whisper --with setuptools. - MFA (alignement des mots ±20 ms) :
brew install --cask miniforge,conda create -n mfa -c conda-forge montreal-forced-aligner -y,conda run -n mfa mfa model download acoustic french_mfaet… dictionary french_mfa(autre langue : son modèle).
Structure des dossiers (base de travail, p. ex. ~/Documents/VIDEOS/)
clients/<CLIENT>/
├── style.md guide du client (templates/style.md) — à lire TOUJOURS avant d'éditer
├── look.py le style traduit en options du moteur (de looks/natif.py ou looks/donnees.py)
├── refs/ vidéos de référence + feuilles de frames + analyses
├── marque/ logo, couleurs, polices, musique propre
└── projets/<AAAA-MM-JJ_nom>/
├── brut/ contenu de l'utilisateur — NE JAMAIS modifier ni supprimer
├── broll/ prises de soutien (optionnel)
├── script.md script ou notes (optionnel ; prévaut sur style.md pour ce projet)
├── travail/ media/ (converti), mfa/, gt/, et un dossier par vidéo avec config.py + takes.json
└── final/ uniquement les livrables : <client>_<sujet>_v1.mp4 · corrections = v2, v3 sans supprimer les précédentes
L'utilisateur ne crée pas de dossiers : il dit "nouveau projet de , le contenu est dans " et ici on crée
projets/<date_nom>/ et on déplace le brut (demander d'abord si le brut est en dehors de la base et s'il ne veut pas le déplacer).
Flux
0 · Nouveau client → analyser les références et écrire style.md
- Télécharger/lire les références (liens avec
watch, qui utilise yt-dlp) dansrefs/. Idéal ~5. - Pour chacune, mesurer : accroche (3 premières s), coupes/min (
ffmpeg -vf "select='gt(scene,0.3)',showinfo"→ compter), sous-titres (police ou la gratuite la plus proche, taille, position, couleur, surlignages, animation), couleur/look, cartes et animations, son (musique, SFX, voix), cadrage, structure, CTA. Feuille de frames :fps=16/dur,scale=270:480,tile=8x2. - Écrire
style.md(modèle) uniquement avec les motifs vus dans ≥ 2 références ; séparer mesuré d'inféré ; ne pas copier de phrases ni de marques d'autrui. Si les références se contredisent, demander laquelle prioriser. - Créer
look.pydepuis le look de départ le plus proche et l'ajuster au guide. Afficher le guide + les stills de test et attendre l'approbation avant d'éditer.
1 · Comprendre le brut
- Lire
style.mdetscript.md. Tester chaque fichier (ffprobe: durée, rotation,color_transfer). watchsur chaque brut avecWATCH_WHISPERX_LANGUAGE=fret--out-dir travail/watch: ce qui est dit, quelles prises sont utilisables, les reprises, ce qu'il NE FAUT PAS couper. Cette transcription est la seule complète : elle est réutilisée pour MFA.- Croiser avec le script : quelles parties du script n'ont pas été filmées ou ont été improvisées → prévenir l'utilisateur.
- Plusieurs clips courts sans voix (événements) : feuille de frames par clip, classer par thème et proposer des regroupements (une vidéo par thème + des bonus + un récap général) avant d'éditer.
2 · Préparer les médias
media.sh video <brut> travail/media/<nom>.mp4 [vertical|horizontal]— convertit le HDR (iPhone/DJI) en SDR en un seul passage, images clés toutes les 1 s, 30 ips. Ne pas recompresser plusieurs fois : chaque passage perd en détails.- Photos :
media.sh photo <photo> travail/media/<nom>.mp4 2.5. Audio pour aligner :media.sh audio.
3 · Aligner les mots (vidéos avec voix)
corpus/a.wav+corpus/a.txt(texte brut dewatch) →conda run -n mfa mfa align --clean <corpus ABSOLU> french_mfa french_mfa <sortie ABSOLUE>(chemins absolus ou échec ; sans--beam).words.py textgrid … words.jsonetwords.py show words.json.- Mots avec
~(durée > 1 s) cachent des pauses ou des reprises ; les longs trous sans texte peuvent être des reprises quewatchn'a pas transcrites. Vérifier avec une fenêtre isolée : couper 3–15 s de l'audio,whisper --model small --language fr --word_timestamps True,words.py whisper … <offset>. MFA peut dériver de plusieurs secondes là où il y a eu du bruit ou des reprises.
4 · Sélectionner les prises → takes.json → takes.py
- Pour chaque phrase, choisir la meilleure prise (généralement la dernière) ; supprimer les reprises, les faux départs, les tics de langage, les instructions à l'éditeur ("je veux que celle-ci soit une autre vidéo") et ce qui ne sert pas l'objectif. Respecter la durée maximale.
- Spans par début de mot :
(début du 1er, début du dernier + 0.2). Si la fin tombe avant le début du dernier mot, elle le mange.word_fixcorrige les mots que MFA a mal positionnés (avec les temps de la fenêtre isolée). - Texte :
phrases/wordscorrigent ce que l'ASR a mal compris (noms, marques : "Claude" pas "Klaus", "IA" pas "ella"). python3 $SKILL_DIR/tools/takes.py travail/<video>/takes.json travail/<video>→ imprime la durée et le texte final. Lire le texte complet : vérifier qu'aucun dernier mot de tronçon ne manque ni qu'aucun mot coupé ne dépasse.
5 · Assembler la vidéo
travail/<video>/:config.py(detemplates/config.py),media → ../media(symlink),media.sh sfx travail/<video>,hyperframes.jsonminimal ({"paths": {"assets": "assets"}}).- Dans
edit(e): cartes/POV/CTA, b-roll et sons ancrés aux mots (e.word_t(None, "mot")). Cartes sur les bords : avec le zoom, le visage s'élargit. Un événement visible tous les ≤ 3 s (le moteur ajoute des auto-punches si nécessaire). python3 $SKILL_DIR/engine/reel.py travail/<video>→npx hyperframes check travail/<video>(0 erreurs ; les avertissements de "fichier volumineux / piste dense / imbriqué" sont normaux dans ce moteur).
6 · Vérifier avant de rendre
npx hyperframes snapshot travail/<video> --at <t1,t2,…> --no-end -o <chemin ABSOLU>sur chaque carte, accroche et CTA. Vérifier : rien ne cache le visage, les textes ne se coupent pas mal, les couleurs sont correctes, les sous-titres lisibles.- Afficher les stills à l'utilisateur et attendre l'approbation (sauf si le style est déjà approuvé et qu'il dit "rends").
7 · Rendu et livraison
npx hyperframes render --quality delivery -o …/raw.mp4danstravail/<video>→media.sh final raw.mp4 final/<client>_<sujet>_v1.mp4(−14 LUFS). Supprimer uniquement leraw.mp4intermédiaire qui vient d'être créé.- Vérifier avec
watch --detail transcript: texte complet et sans répétitions. Si le début "manque", vérifier les 3 premières secondes avec whisper avant de conclure (la transcription complète omet parfois le démarrage).
Leçons (ne pas répéter)
- Le HDR sans conversion paraît délavé ; convertir avec
avconvertune seule fois. - Enregistrer en 4K s'il y a des zooms : du 1080p agrandi de 13–22 % semble flou. Avertir le client.
- Une phrase corrigée avec plus de mots ne peut pas répartir le même temps : un sous-titre de durée 0 reste collé.
- Les émojis dans le texte à l'écran ne sont pas toujours rendus : les éviter.
snapshot -oavec un chemin relatif écrit à côté du projet : utiliser des chemins absolus.- Un même fichier utilisé dans deux parties de la vidéo → des clés différentes dans
takes.json(IDs uniques). - Ne pas télécharger la bibliothèque SFX dans un dépôt (licence Pixabay de media-use) : elle est copiée par projet avec
media.sh sfx. - Les corrections du client sur une seule vidéo (p. ex. "pas de sons dans la 07") vont dans son
config.py(SFX = {"card": None, "broll": None, "cut": None}etsfx: Nonedans les cartes), sans modifier leindex.html(perdu à la reconstruction).