motion-design : l'atelier (Remotion, thème, sons, musique)
Tout est local et déterministe : même code = même MP4. Aucune image ou vidéo générée par IA.
La stack
| Pièce | Outil | Où |
|---|---|---|
| Animation | Remotion 4.0.529 (React / TSX), versions épinglées dans package.json | src/ ; npx remotion add <package> pour un module supplémentaire |
| Thème | couleurs, polices, tailles, marges | src/illustration/theme.ts (lu par les constantes C et F de src/illustration/scenes/kit.tsx), polices dans public/fonts/ |
| Modules Remotion | transitions, effets, gsap, three, noise, paths, shapes, motion-blur, light-leaks, starburst, rough-notation, captions, layout-utils, lottie | package.json |
| Compositions graphiques | BrandedVideo (scènes plein écran), LowerThirdTrack (tiers-inférieurs, titres de sections), Screencast (démos de site), Scene (catalogue de scènes), ControleTexte (vérification de texte), FondAnime (fond animé en boucle ; son grain est fabriqué par scripts/make-grain.py) | src/illustration/, déclarées par Compositions.tsx, câblées dans src/Root.tsx |
| Signaux partagés | temps clés en secondes, lus par l'animation ET par le son | src/<projet>/cues.json |
| Musique | une partition écrite en Python sur un synthé numpy (scripts/synth.py : piano électrique FM, pad, basse, percussion, craquement de vinyle, reverb) | music/<projet>.py, modèle : music/example_pad.py |
| Effets sonores | palette synthétisée : lire reference/sound-palette.md avant tout son. Recettes de synthèse scripts/make-sfx.py -> public/sfx/*.wav + palette.json ; vocabulaire gestuel scripts/son.py (un plan nomme un geste, jamais un fichier ; les listes sont une carte placée par élément par défaut, son.LISTES ; son.releve : une liste numérotée des sons d'une vidéo, à vérifier par numéro) ; scripts/palette-import.py (une palette d'enregistrements réels, mêmes noms de fichiers, se rabat sur la palette par défaut) ; scripts/sfx.py (quelques sons supplémentaires : obturateur, tick de mise au point, whoosh) | scripts/ |
| Mixage | musique + effets sonores + voix, musique atténuée sous la voix, loudness cible EBU R128, limiteur de crête vrai à -1.5 dBTP (limiteur suréchantillonné, seulement quand il dépasse) | scripts/mix.py |
| Vérifications | équilibre tonal par octave, loudness | scripts/ltas.py, mix.py |
Licences. Remotion est gratuit pour les particuliers et les entreprises de moins de 3 employés ; au-delà, une licence d'entreprise est requise (remotion.pro). Lisez son LICENSE.md avant d'utiliser le kit commercialement dans une grande entreprise.
Les polices Inter et Source Serif 4 sont sous licence OFL (public/fonts/OFL-*.txt) ; les sons et la musique d'exemple sont synthétisés ici, sans droits tiers. Musique trouvée ailleurs : vérifiez sa licence (pas de CC-BY-NC sur une chaîne monétisée).
Installation, et ce que fait la ligne node_modules
Le plugin s'installe une fois avec :
bash "${CLAUDE_PLUGIN_ROOT}/install.sh" --data "${CLAUDE_PLUGIN_DATA}"
(Claude Code remplace les deux variables par des chemins réels quand il lit ce fichier.) Pourquoi un dossier de données : le dossier du plugin est remplacé à chaque mise à jour, et node_modules pèse environ 1 Go. Donc npm ci s'exécute une fois dans le dossier de données du plugin (${CLAUDE_PLUGIN_DATA}), qui survit aux mises à jour, et skills/motion-design/node_modules est un lien symbolique vers celui-ci. Si node_modules manque après une mise à jour du plugin (le nouveau dossier plugin n'a pas de lien), relancez la ligne ci-dessus : elle ne fait que ce qui manque et relie à nouveau en une seconde.
Installation manuelle (les quatre dossiers skills/ copiés côte à côte dans ~/.claude/skills/) : bash install.sh depuis la racine du kit ; node_modules est alors un dossier normal installé par npm ci. Côté Python : python3 -m pip install numpy scipy soundfile pillow, et brew install ffmpeg. Détails et vérification de toute la chaîne : INSTALL.md du kit.
Exécutez chaque commande de cette compétence depuis le dossier de l'atelier (skills/motion-design).
Pipeline d'une vidéo motion-design complète
- Cadrez-la : durée, format (1920x1080 à 30 ips par défaut ; 1080x1920 pour un reel vertical ; 1080x1080 pour un carré), utilisation, contraintes de plateforme. Écrivez
src/<projet>/cues.json: les temps clés pilotent à la fois l'image et le son. - Animez : une composition par livrable dans
src/<projet>/, déclarée danssrc/Root.tsx, props typées avec zod. Tout dérive deuseCurrentFrame(): jamais d'animation CSS libre, jamais deMath.random()(random(graine)ounoise2D). Utilisez uniquement les couleurs et polices du thème. - Vérifiez l'image sans attendre un rendu :
npx remotion still src/index.ts <Id> out.png --frame=Nsur les images clés, puis une planche contact du MP4 (ffmpegtile). Jugez à la taille d'un téléphone : l'image réduite à 390 px de large doit rester lisible. - Voix-off (si nécessaire) : enregistrée par l'utilisateur (WAV 48 kHz), placée avec
--voice-at. Le kit ne clone pas les voix. - Musique et effets sonores :
python3 music/<projet>.py <durée> music.wav; sons viason.py, placés aux mêmes instants que l'image (le plan appelleson.releve(...)pour écrire la liste numérotée à écouter) ; vérifiez avecpython3 scripts/ltas.py music.wav(pas de trou plus profond qu'environ 6 dB par rapport à une pente douce). - Mixage :
python3 scripts/mix.py --music ... --sfx ... [--voice ... --voice-at s] --lufs -16 --out public/audio/<projet>_mix.wav(-14 pour un reel, -16 pour YouTube ;--sfx-voix-ref -22remet à l'échelle les effets sonores sur la voix réelle). - Rendu :
npx remotion render src/index.ts <Id> out.mp4 --props='{"audio":"audio/<projet>_mix.wav"}' --codec=h264 --crf=16 --audio-bitrate=320k. - Livrez sans écraser un livrable existant (suffixe
-v2), avec un aperçu.
Rendu placé dans Premiere (graphiques)
- Pas de logo dans une scène, un graphique plein écran ou un tier-inférieur : cela charge l'image pour rien.
- Un fichier destiné à une séquence en 29.97 ips doit couvrir TOUT son clip : n images de séquence durent n x 1.001 / 30 s. Les compositions de
src/illustration/acceptenttailFrames: le composantTenirFin(src/illustration/tenir-fin.tsx) joue l'animation sur sa durée, puis tient la dernière image ; les animations de sortie ne bougent pas. La compétenceoverlays'sscripts/render-segments.pycalculetailFrames. - Les compositions graphiques sont rendues par
scripts/render-segments.py,scripts/screencast-render.pyetscripts/montage-tella.pyde la compétenceoverlays(dossier de travail = cet atelier, images PNG, 4 cœurs), jamais à la main en dehors d'une vérificationremotion still. Les médias appelés viastaticFilevont danspublic/scenes/<video>/.
Personnalisez-le (changez le thème)
Le kit est livré avec un thème neutre : accent bleu #2F5BEA, Inter et Source Serif 4, un fichier de thème, src/illustration/theme.ts. Pour utiliser votre propre marque :
- Couleurs :
src/illustration/theme.ts(color: base, contrast, inkSoft, muted, surface, line, accent, accentDark, accentWash, darkBg, paperWarm) ; les scènes le lisent viaC. L'accent et ses teintes claires sont encore codés en dur à quelques endroits :grep -rn "#6B8CFF\|rgba(47,91,234\|rgba(214,224,252" src/(rehauts danspreuves.tsx,Screencast.tsx, les variantesPALETTESdecompositions/FondAnime.tsx), pour correspondre au nouvel accent. Un seul accent, utilisé comme signal, jamais comme remplissage. - Polices : placez les fichiers
.woff2danspublic/fonts/, puis changez les noms de fichiers et les noms de famille dans les listes de chargement (src/illustration/scenes/kit.tsx,compositions/BrandedVideo.tsx,compositions/LowerThirdTrack.tsx,compositions/Screencast.tsx) et danstheme.ts(font.display,font.sans). Vérifiez que la police a des chiffres et des accents (un sous-ensemble "latin-ext" seul n'a ni chiffres ni lettres de base, et tout tombe sur Georgia). Nom de famille sans chiffre (ou entre guillemets en CSS). - Courbe d'animation :
easeStddansscenes/kit.tsxetEASINGdansscripts/make-sfx.pyvont ensemble (le son suit la courbe de l'image). - Vérifiez :
npx tsc --noEmit, puis unremotion stillde chaque composition (citation, tier-inférieur, carte de section, nombre...), puis--forcelors de la prochaine exécution derender-segments.py(son cache suit déjà le code desrc/illustration/).
Ajouter une scène ou un son
- Scène : un composant dans
src/illustration/scenes/opaque.tsx(plein écran) oualpha.tsx(incrustation), son contratdataen commentaire au-dessus, une ligne dans le registrescenes/Scene.tsx, une ligne dans le catalogue de la compétenceoverlays. Chaque instant provient descues. Vérifiez :remotion stillà plusieurs images, l'incrustation compositée sur une image du clip. - Son :
reference/sound-palette.md, "Ajouter ou modifier un son".
Piège des dossiers synchronisés
Si l'atelier vit dans un dossier synchronisé (Dropbox, iCloud, Drive...), une autre machine peut renvoyer une ancienne version d'un fichier et renommer la bonne "copie conflictuelle". Symptôme : Could not find composition with ID .... Réflexe : find . -name '*copie conflictuelle*' -not -path './node_modules/*', comparez, gardez la version la plus récente. Le cache webpack (node_modules/.cache) peut aussi entrer en conflit : supprimez-le, Remotion le reconstruit. Mieux : gardez node_modules hors de la synchronisation.