Vidéo 100 % avec du code (Remotion + audio local)
Ordre de travail (ne pas modifier l'ordre)
- Histoire d'abord (méthode HyperFrames
story.md) : la seule chose, 3 storylines, accroche dans les 2 premières secondes, beats avec pourcentages, « tells » de vidéo générée interdits (tout entre de manière égale, flotter sans cause, cartes en rangée, logo flottant). ÉcrireSCRIPT.mdavec des timecodes. - Voix → durées réelles →
timeline.json(scènes, début de chaque ligne, événements, sections musicales). L'audio et la vidéo lisent le même JSON. - Audio master (musique + SFX + voix avec ducking, −15,5 LUFS, pic ≤ −1 dBTP).
- Scènes dans Remotion, une composition
Filmavec<Sequence>par scène ; vérifier les trames de contrôle (contact sheet) avant de rendre. - Rendu par scène (
--frames=a-b --muted) → concat → mux avec ffmpeg → QC avec trames extraites.
Moteur
npx create-video@latest --yes --blank --no-tailwind <dir>;npx remotion add @remotion/transitions @remotion/media @remotion/effects @remotion/noise @remotion/paths @remotion/shapes @remotion/motion-blur @remotion/fonts.- Sandbox sans GPU : dans
remotion.config.ts→Config.setBrowserExecutable(<chrome-headless-shell>),Config.setChromiumOpenGlRenderer("swangle"),setConcurrency(2),setCrf(18),setPixelFormat("yuv420p"). - Polices : packages
@fontsource[-variable]/*(npm arrive ; Google Fonts non). Attendredocument.fonts.load()avecdelayRenderavant de capturer (glyphes éàèùêëïô). - Règles Remotion : tout dérive de
useCurrentFrame();interpolateavec clamp ;random(seed)de Remotion ; rien de CSStransition/animation,Math.random,Date, timers,useFrame. - Coût mesuré (2 CPU, 1080p) : scène vide ≈0,1 s/t ; 2000 sprites canvas ≈0,7 s/t ;
filter: blur()plein écran ≈2,5 s/t. Particules : forme fermée (position = f(seed, i, t)), sprites radiales pré-floutées,globalCompositeOperation: "lighter". - Un court de 3 min (5400 trames, 1080×1920) a pris ~1 h 30 sur 2 CPU. Sauvegarder le bundle (
npx remotion bundle) et rendre à partir de celui-ci.
Kit réutilisable (ne vient pas dans ce dépôt ; sert de liste de pièces à construire)
anim.ts (easings par rôle, spring fermé, keyedState, clignement, drift), Camera2D.tsx (couches avec parallaxe/dolly), Particles.tsx (pluie, lucioles, poussière, étoiles, grain), City.tsx (ville néon procédurale + reflets), Text.tsx (kinétique, néon, sous-titres mot par mot, titre variable), Post.tsx (vignette, flash, letterbox, rayons), character/Mia.tsx (rig : pose + expression + visèmes A–H/X + clignement + respiration + rim light + accessoire), character/Lucero.tsx, Flat.tsx (monde plat au crayon avec boil), ChatScreen.tsx, lipsync.ts. Scripts dans tools/ : voice.py, make_voices.py, asr.py, make_timeline.py, make_audio.py, render_all.sh, assemble.sh, sheet.py.
Personnages
- Rig = paramètres numériques (pose, expression, visème) mélangeables par trame ; préréglages d'expression ; transitions avec
keyedState(anticipation → action → settle). Tête guide, corps suit ; clignement toutes les 2–5 s semé ; ne jamais bouger tout à la fois avec la même courbe. - Lip-sync : Rhubarb
-r phonetic -f jsonsur WAV 22 kHz mono 16 bit → cues A–H/X → mélanger les paramètres de bouche entre les cues (blend 50 ms). Intensité d'ouverture ×0,7 pour les murmures. - Fiche de personnage (expressions, visèmes, poses) en tant que still AVANT d'animer.
Voix (français, local)
- Kokoro-82M ONNX (
kokoro-onnx, voixef_dora,em_alex,em_santa, langes-419) et Piper (piper-tts,es_MX-claude-high,es_AR-daniela-high). Modèles dans GitHub releases (thewh1teagle/kokoro-onnx, k2-fsa/sherpa-onnx). - Enfants : +4…+6 demi-tons avec
rubberband -p N -F(formants). Graves : −4. « Voix faite de plusieurs » : couche −2 st (26 %) + couche +0,3 st retardée de 12 ms (18 %) + réverb large. - Vérifier toujours avec ASR (Parakeet-TDT 0.6B v3 via sherpa-onnx ≥ 2.0) : WER contre le texte ; régénérer ou réécrire la phrase si > 5 %. Vérifier AVANT d'appliquer les effets (la réverb confond le détecteur de langue de l'ASR). Les horodatages mot par mot de l'ASR alimentent les sous-titres.
- Si l'utilisateur a sa propre voix (p. ex. ElevenLabs), on remplace le WAV de chaque ligne et on régénère les cues/timeline sans toucher aux scènes.
Musique et SFX
- Composer MIDI avec
pretty_midipar sections (bpm, progression, instruments GM) →fluidsynth -ni -g 0.6 -r 48000 -F out.wav MuseScore_General_Full.sf3 in.mid→ pedalboard (HPF, compresseur, réverb) → pyloudnorm. - Synchronisation visuelle = même arithmétique des beats (trames par beat = fps·60/bpm, calculer chaque beat depuis son index).
- SFX avec cause à l'écran ; placer le pic 1 trame après l'image ; alterner les prises ; synthétiser avec numpy ce qui n'existe pas (bourdonnements, pluie, crayon, scintillement, impact sub).
- Mixage : voix −20 dBFS RMS, musique −8 dB sous la voix (ducking 120 ms / 700 ms), SFX −4 dB, master −15,5 LUFS, pic 0,6. Vérifier avec un spectrogramme (
ffmpeg showspectrumpic) qu'aucun lit (pluie) ne couvre la voix.
Direction (des compétences lues : Remotion, HyperFrames, iart-ai motion/kinetic/webgl, nolanx, anatomy, isometric-ops, taste-skill)
- Un mouvement par beat ; arrivées avec longue queue (
bezier(0.16,1,0.3,1)), sorties 40–50 % plus courtes ; camérainOut; titres immobiles une fois arrivés ; 3–5 types de transition avec cause ; couper à la trame la plus rapide. - Parallaxe : fond 0.1–0.3×, milieu 0.5–0.7×, avant 1–1.5× avec blur. Plan drone = pile de plans imbriqués avec échelle logarithmique (fenêtre → façade → pâté de maisons → carte → nuages → planète).
- Isométrique : une seule projection ; ombres plates 15–30 % ; haut plus clair.
- Typographie : 2 familles max ; titres 4–9 % de la hauteur ; stagger lettres 20–40 ms, mots 40–70 ms ; polices variables pour poids/largeur.
- Vertical : contenu clé dans les 80 % centraux ; sous-titres dans la zone inférieure sécurisée (≥ 110 px) ; texte ≥ 44 px ; sous-titres mot par mot pour que ce soit compréhensible sans son.