# Montage vlog en local — guide complet pour Claude Code (Mac)

> Objectif : refaire sur ton Mac, avec ton Claude local, exactement le montage fait sur le serveur les 25–26 août 2026 : **son « micro studio »**, **captions mot par mot**, **textes POV** sur clips muets, **musique de fond avec ducking**, **textes pour les réseaux** — sans rien envoyer sur un serveur.
>
> Ce document est écrit pour être **suivi tel quel par Claude** : chaque étape a ses commandes. Donne-lui ce fichier et dis : *« Lis MONTAGE-VLOG.md, installe ce qui manque, puis fais le montage de la vidéo dans a-traiter »*.

---

## 0. Ce que contient le kit

```
~/vlogs/
├── kit/
│   ├── MONTAGE-VLOG.md          ← ce guide
│   ├── CLAUDE.md                ← à copier dans ~/vlogs/ (Claude le lit automatiquement)
│   ├── install.sh               ← installe tout (macOS)
│   ├── enhance.py               ← son : nettoyage + voix studio
│   ├── captions.py              ← captions mot par mot (Whisper + ASS + ffmpeg)
│   ├── pov.py                   ← clip muet : textes POV, ouverture, signature, (musique)
│   ├── musique.py               ← musique de fond sous une voix, avec ducking
│   ├── fonts/Montserrat-ExtraBold.ttf
│   ├── exemples/declinaisons.json   ← déclinaisons POV du clip sayn.food (modèle)
│   ├── exemples/mots.json           ← format des captions (extrait)
│   └── docs/vendakia-base-commerciale.md ← ce qu'on a le droit de promettre sur Vendakia
├── a-traiter/                   ← dépose ici les vidéos brutes
└── <sujet>/                     ← un dossier par vidéo (source.mp4 + rendus/)
```

Tout repose sur **ffmpeg** (montage, encodage, incrustation), **Python 3.11** avec **DeepFilterNet 3** (nettoyage de voix par IA), **faster-whisper** (transcription horodatée), **Pillow** (rendu des textes POV). Pas de serveur, pas de Node, pas de Remotion nécessaires (voir §8).

---

## 1. Installation (une fois) — macOS

### 1.1 Automatique

```bash
mkdir -p ~/vlogs && cd ~/vlogs
unzip ~/Downloads/kit-montage-vlog.zip        # crée ~/vlogs/kit
cp kit/CLAUDE.md ~/vlogs/CLAUDE.md
cd kit && chmod +x install.sh && ./install.sh
```

`install.sh` fait, dans l'ordre : Homebrew → `ffmpeg` (avec libass) et `uv` → un Python 3.11 isolé dans `kit/venv311` → les paquets Python épinglés → la police → un test d'import. Relançable sans risque.

### 1.2 À la main (si le script coince)

```bash
brew install ffmpeg uv
cd ~/vlogs/kit
uv venv --python 3.11 venv311
uv pip install --python venv311/bin/python "torch==2.1.2" "torchaudio==2.1.2" "numpy<2" pillow "faster-whisper>=1.1"
uv pip install --python venv311/bin/python "deepfilternet==0.5.6"
curl -fL -o fonts/Montserrat-ExtraBold.ttf "https://github.com/JulietaUla/Montserrat/raw/master/fonts/ttf/Montserrat-ExtraBold.ttf"
venv311/bin/python -c "import df, faster_whisper, PIL, numpy, torch; print('OK', torch.__version__)"
```

**Pourquoi ces versions précises**

| Dépendance | Version | Raison |
|---|---|---|
| Python | **3.11** | DeepFilterNet n'a pas de binaire pour 3.12/3.13 (il faudrait compiler du Rust). |
| torch / torchaudio | **2.1.2** | DeepFilterNet 0.5.6 importe `torchaudio.backend`, supprimé en 2.2. Plus récent = `ModuleNotFoundError`. |
| numpy | **< 2** | torch 2.1 est compilé contre numpy 1.x. |
| deepfilternet | 0.5.6 | Dernière version publiée ; binaires macOS arm64 disponibles. |
| faster-whisper | ≥ 1.1 | Modèle `turbo` (large-v3-turbo) rapide sur CPU. Téléchargé au premier usage (~1,6 Go). |
| ffmpeg | ≥ 6 | Filtres utilisés : `subtitles` (libass), `compand`, `deesser`, `loudnorm`, `afftdn`, `sidechaincompress`, `overlay`. Le ffmpeg de Homebrew les a tous. |

Tout tourne sur CPU. Ordres de grandeur sur un Mac récent : nettoyage voix ≈ 20× temps réel, transcription ≈ 2× temps réel, rendu vidéo 1440×2560 @ 60 ≈ 5× temps réel (15 s → ~1 min 20).

---

## 2. Organisation du travail

1. La vidéo brute va dans `~/vlogs/a-traiter/`.
2. Claude crée `~/vlogs/<sujet>/`, y déplace la vidéo sous `source.mp4`, et ne la modifie **jamais**.
3. Tout ce qui est produit va dans `~/vlogs/<sujet>/` (`rendus/`, `mots.json`, `declinaisons.json`, `textes.md`).
4. Toujours lancer les scripts avec **`~/vlogs/kit/venv311/bin/python`** (pas `python3`).

Commande utile au début — **comprendre la vidéo** (durée, résolution, y a-t-il de la voix ?) :

```bash
ffprobe -v error -show_entries format=duration:stream=codec_type,width,height,r_frame_rate,channels -of default=noprint_wrappers=1 source.mp4
ffmpeg -v info -i source.mp4 -vn -af ebur128=framelog=quiet -f null - 2>&1 | grep -E "^\s+I:"   # -70 LUFS = muet
ffmpeg -v error -y -i source.mp4 -vf "fps=12/DUREE,scale=240:-2,tile=6x2" -frames:v 1 grille.jpg   # 12 vignettes
```

---

## 3. Le son — `enhance.py` (vlog parlé)

```bash
cd ~/vlogs/<sujet>
~/vlogs/kit/venv311/bin/python ~/vlogs/kit/enhance.py source.mp4 --studio
```

Produit dans `source_enhance/` : `_classique`, `_ia`, **`_studio`**, **`_studio-max`** (chacun en `.wav` 48 kHz pour le montage, `.m4a` pour écouter, et `.mp4` = même vidéo, image copiée sans réencodage, avec la piste traitée).

Ce que fait chaque chaîne :
- **classique** — ffmpeg seul : coupe-bas 80 Hz, débruitage léger (`afftdn`), **expandeur** (`compand`) calé automatiquement sur le plancher de bruit mesuré (10ᵉ percentile des RMS 50 ms + 6 dB, plafonné 4 dB sous la parole la plus douce) qui atténue les traînes d'écho entre les mots, EQ anti-« boîte » (−3,5 dB à 350 Hz), présence (+2 dB à 3,2 kHz), dé-esseur, compression 3:1, normalisation **−16 LUFS** en 2 passes.
- **ia** — **DeepFilterNet 3** (supprime bruit et une bonne partie de la réverbération), puis finition douce.
- **studio / studio-max** — à partir de l'IA : **basses reconstruites** (shelf `bass` g=6 / g=9 à **f=320 Hz** — le filtre atteint son plein gain bien sous sa fréquence, à 115 Hz il ne faisait rien), creux à 440 Hz, présence, air, compression 4:1 / 5:1, limiteur −1 dB, −16 LUFS. **L'utilisateur veut `studio-max`** (voix radio, beaucoup de basses).

Mesures obtenues sur le vlog du 25/08 (téléphone dans une pièce qui résonne) : écart voix ↔ pauses 14 dB à l'origine → 25 dB (classique) → **39 dB** (IA/studio).

Options : `--gate-db N` force le seuil de l'expandeur ; `--pf` active le post-filtre DeepFilterNet (plus agressif).

---

## 4. Les captions mot par mot — `captions.py`

```bash
V=~/vlogs/kit/venv311/bin/python; K=~/vlogs/kit
$V $K/captions.py transcrire source_enhance/source_studio-max.wav mots.json            # Whisper turbo, français
#   → relire mots.json (noms propres ! « Vandakia » → « Vendakia »), corriger à la main
$V $K/captions.py rendre source.mp4 source_enhance/source_studio-max.wav mots.json rendus/<sujet>-captions.mp4
```

- `mots.json` : `{"mots": [{"start": 0.21, "end": 0.77, "text": "What's"}, …]}`. Pour corriger : modifier `text` ; pour supprimer : enlever l'entrée ; pour couper un mot en deux : deux entrées qui se partagent l'intervalle.
- Style (en tête de `captions.py`) : **un mot à la fois**, capitales, Montserrat ExtraBold 116 px (espace 1080×1920, mis à l'échelle), contour noir 8 px, placé à ~70 % de la hauteur (sous le visage), petit « pop » 78 → 100 % en 90 ms. Un mot reste affiché jusqu'au suivant (ou 0,25 s après sa fin si la pause dépasse 0,6 s). Les mots longs sont réduits pour tenir dans la largeur.
- Le rendu se fait **à la résolution et la cadence de la source** (défaut). `--hauteur 1920 --fps 30` seulement si demandé. `--preset fast --crf 21` pour aller plus vite.
- `captions.py ass mots.json sortie.ass` génère juste le fichier de sous-titres (utile pour un montage dans une autre appli).

---

## 5. Clip muet → textes POV — `pov.py`

Pour un b-roll sans voix (ex. sayn.food : le chef, l'équipe, les plats). Un JSON décrit les déclinaisons :

```json
{
  "source": "source.mp4",
  "sortie": "rendus",
  "grade": "eq=contrast=1.04:saturation=1.12",
  "musiques": {},
  "declinaisons": [
    {"slug": "le-chef-nous-gate", "musique": null,
     "ouverture": {"debut": 8.9, "duree": 1.0},
     "textes": [
       {"style": "pov", "texte": "POV : quand on a un business de healthy food dans la startup studio", "debut": 0.0, "fin": 6.3},
       {"style": "pov", "texte": "le chef nous gâte.", "debut": 6.35, "fin": 12.9},
       {"style": "cta", "texte": "sayn.food", "sous": "Commande en ligne", "debut": 12.95, "fin": 99}
     ]}
  ]
}
```

```bash
$V $K/pov.py declinaisons.json                       # toutes les déclinaisons
$V $K/pov.py declinaisons.json --seulement le-chef-nous-gate
```

- **Repérer les coupes** avant d'écrire les temps : `ffmpeg -i source.mp4 -vf "select='gt(scene,0.25)',showinfo" -an -f null - 2>&1 | grep -o "pts_time:[0-9.]*"`. Puis vérifier avec des vignettes : la détection marque le début des plans, mais il faut regarder.
- **Structure qui marche** : accroche POV sur les premiers plans → chute à l'arrivée du sujet (les plats) → signature (`cta`) sur le dernier plan.
- **`ouverture`** : 1 s d'un plan de la source placé avant le montage → première image et vignette différentes par déclinaison (il poste les versions en décalé pour voir laquelle devient virale : sans ça, doublons). Les temps des textes sont décalés automatiquement ; celui qui démarre à 0 couvre l'ouverture.
- **`"musique": null`** → piste silencieuse (il ajoute un son dans Instagram). Pour incruster une musique : `"musiques": {"fete": {"fichier": "/chemin/fete.mp3", "debut": "auto", "lufs": -14}}` et `"musique": "fete"` ; `"auto"` saute l'intro.
- Styles (`STYLES` en tête de `pov.py`) : `pov` = boîtes blanches arrondies par ligne, texte noir, en haut à 15,5 % (zone sûre TikTok) ; `cta` = grand texte blanc à contour noir à 60 % + sous-ligne. Surchargeables dans le JSON (`"styles": {"pov": {"y": 0.2}}`).
- Sortie : `rendus/<slug>.mp4` (résolution/cadence source) + `rendus/<slug>-720p.mp4` (aperçu léger).

---

## 6. Musique de fond sous une voix — `musique.py`

```bash
$V $K/musique.py --voix source_enhance/source_studio-max.wav --musique ~/Music/titre.m4a --sortie rendus/<sujet>-musique --video source.mp4 --debut 15 --niveau -24 --ducking 8
```

Boucle la musique si elle est plus courte, fondus, **ducking** (`sidechaincompress` : la musique descend quand la voix parle ; ~13 dB sous la voix dans les pauses), mix normalisé −16 LUFS, remux dans la vidéo sans réencoder l'image. `--debut 15` = on démarre la musique à sa 15ᵉ seconde. La musique doit être **un fichier local** : YouTube bloque les téléchargements automatisés — `yt-dlp -f "bestaudio[ext=m4a]/bestaudio" URL` depuis le Mac fonctionne en général.

---

## 7. Les textes pour publier

Rédiger à partir de la transcription (`mots.json` ou l'audio). Règles :
- **Instagram** : accroche en 1ʳᵉ ligne, sauts de ligne, appel à commenter, **5 hashtags max** (limite officielle). **TikTok** : court, 5 hashtags max. **YouTube Shorts** : titre ≤ 100 caractères, 3 hashtags. **LinkedIn** : 1ʳᵉ ligne = tout se joue avant « voir plus », pas de lien dans le post (le mettre en premier commentaire), 3–5 hashtags.
- **Voix collective** : « on », « nous », « notre » — jamais « je » ni « tu/ton » (le public peut être en « vous »).
- **« la startup studio »**.
- **sayn.food** : angle insider (« un des projets de la startup studio… le chef nous gâte »), pas « livraison à Dakar ».
- **Vendakia** : uniquement ce qui est dans `kit/docs/vendakia-base-commerciale.md` — licence à vie 50 000 FCFA payée une fois, 100 crédits IA/mois inclus, 20 crédits offerts à l'inscription, jamais « gratuit », pas de formule mensuelle ; l'offre de lancement expirait le 31/08/2026 → demander le tarif en vigueur avant de citer un prix.

---

## 8. Et Remotion ?

**Pas nécessaire** pour ce qui est décrit ici : ffmpeg + Pillow + libass couvrent captions, textes POV, ouverture, signature, musique. Remotion (vidéo programmée en React, rendue par Chrome headless) devient intéressant pour des **animations plus riches** : typographie cinétique, transitions, compteurs, logo animé, templates réutilisables.

Si tu veux l'ajouter un jour :

```bash
brew install node            # Node 18+
cd ~/vlogs && npx create-video@latest remotion-overlays   # choisir « Blank »
```

Façon de l'intégrer sans casser la chaîne : Remotion rend **un calque transparent** (`--codec prores --prores-profile 4444` ou `--codec vp8 --pixel-format yuva420p`) de la taille de la vidéo, puis ffmpeg l'incruste : `ffmpeg -i source.mp4 -i calque.mov -filter_complex "[0:v][1:v]overlay=0:0" …`. Les temps des mots de `mots.json` se passent à la composition Remotion en `props`. Compter des rendus nettement plus longs qu'avec ffmpeg seul.

---

## 9. Dépannage

| Symptôme | Cause / remède |
|---|---|
| `ModuleNotFoundError: torchaudio.backend` | torchaudio trop récent → `uv pip install --python venv311/bin/python "torch==2.1.2" "torchaudio==2.1.2"`. |
| `deepfilterlib` veut compiler / Rust | Python ≠ 3.11 → recréer le venv : `uv venv --python 3.11 venv311`. |
| Sortie IA vide / « mesure de loudness dégénérée » | Pas de voix dans l'extrait (DeepFilterNet supprime tout ce qui n'est pas de la parole) : normal pour un clip muet ; utiliser `pov.py`. |
| ffmpeg tué sans message pendant `pov.py` | Manque de mémoire : ne jamais faire un `trim` de la source dans le même graphe que le montage complet ; le script utilise une entrée séparée `-ss/-t` pour l'ouverture — garder ça. |
| Captions décalées | Rendre avec la **même piste audio** que celle transcrite (la voix traitée), et ne pas couper la vidéo entre transcription et rendu. |
| Mots coupés (« l » / « 'IA ») ou ponctuation seule | `captions.py` les recolle ; si un cas passe, corriger dans `mots.json`. |
| « Vandakia », « vendre » pour « vend de », « vos devs » pour « vos DM » | Erreurs Whisper typiques : relire la transcription, corriger les noms propres. |
| Vidéo refusée par Instagram/TikTok | S'assurer qu'il y a une piste audio (même silencieuse : `pov.py` l'ajoute) et `-movflags +faststart` (les scripts le font). |
| Whisper lent | Modèle `--modele small` pour un brouillon, `turbo` pour la version finale. |

---

## 10. Comment lancer Claude dessus

```bash
cd ~/vlogs && claude
```

Exemples de demandes qui suffisent :
- « Nouvelle vidéo dans a-traiter, c'est un vlog parlé sur Vendakia : son studio-max, captions mot par mot, textes réseaux. »
- « Nouvelle vidéo dans a-traiter, clip muet pour sayn.food : 4 déclinaisons POV angle studio + une sans texte, ouvertures différentes, pas de musique. »
- « Reprends la déclinaison 2 avec cette phrase exacte : … »

Claude lit `~/vlogs/CLAUDE.md` automatiquement (préférences, règles, pièges) et ce guide pour le détail.
