Vidéo explicative constructiviste · Workflow
Un axe temporel principal, trois avals en dérivent.
① Script ② TTS (axe temporel) ③ Variations BGM ④ Produit final
Texte → Piste vocale (axe principal) → Musique LMMS (niveaux) → Remotion (images + pistes intégrées) + couverture
│ ▲
└──── Points de transition temporelle ────┘
- Le nombre d’images est déterminé par le débit naturel de la TTS (et non l’inverse, où l’on comprimerait le débit).
- Les points de variation de la BGM coïncident avec les points de changement de niveau de la voix-off.
- Le produit final est aligné sur la piste vocale comme référence ; la BGM ne fait que jouer un rôle de fond.
0. Démarrage : Lire d’abord le contrat de chemin (cette étape est obligatoire)
Ce skill ne cherche pas lui-même les outils ; tous les chemins proviennent du contrat écrit par le skill de configuration d’environnement :
$VW_CONTRACT (par défaut ~/.config/ideaform/toolchain.json)
CONTRACT="${VW_CONTRACT:-$HOME/.config/ideaform/toolchain.json}"
source "$(dirname "$CONTRACT")/env.sh" # Exporte VW_NODE / VW_VENV / VW_FFMPEG / …
Trois vérifications obligatoires avant de commencer :
- Le fichier de contrat existe-t-il ? Non → demandez à l’utilisateur d’exécuter d’abord le skill
ideaform-setup. schema_versionest-elle une version reconnue par ce skill ? Incompatible → demandez de réexécuter le skill de configuration d’environnement.verified_atest-ellenull? Oui → avertissez l’utilisateur que « l’environnement n’a pas passé la validation de fumée » ; réparez d’abord avant de continuer. De plus,tools.lmms.stkdir_okdoit êtretrue, sinon la BGM sera totalement silencieuse sans message d’erreur.
Référence rapide des champs clés :
| Usage | Champ du contrat |
|---|---|
| Exécuter le script TTS (edge-tts dans venv) | tools.venv.python |
| Synthétiser audio/vidéo | tools.ffmpeg.path / tools.ffprobe.path |
| Rendre les images | tools.remotion.project / tools.remotion.browser.resolved |
| Rendre la BGM | tools.lmms.apprun |
| Déposer les fichiers temporaires (doit être un grand disque) | tmpdir |
⚠️
tmpdirdans le contrat n’est pas optionnel. Le/tmplocal n’a que 10 Mo ; le packaging Remotion / pip y écrivent →ENOSPC. Chaque commande Remotion doit être accompagnée deTMPDIR.
⚠️ Ne jamais faire de
resolve(résolution de liens symboliques) pour les chemins. Les chemins d’outils hébergés contiennent des liens symboliques ; résoudre l’interpréteur venv ferait perdre le contexte venv, et tous les paquets ne pourraient pas être importés. Voir racine du dépôtdocs/03-ContratDeChemin.md.
1. Aperçu des quatre étapes
| Étape | Ce qu’elle fait | Entrée | Sortie (tout dans l’espace de travail) | Référence |
|---|---|---|---|---|
| ① Script | Transforme l’entrée utilisateur en script hiérarchisé | Entrée utilisateur | script.md + paroles.txt (avec niveaux marqués) | references/stage1-script.md |
| ② TTS (axe temporel) | Mesure le débit naturel → crée l’axe temporel → produit la piste vocale | paroles.txt | plan.json / timeline.ts / voice.wav | references/stage2-tts.md |
| ③ Variations BGM | Limites des niveaux → plan de variation → piste LMMS | plan.json + annotations de niveaux | bgm-plan.json / bgm.wav | references/stage3-bgm.md |
| ④ Produit final | Remotion : agence les images + intègre les pistes + rend + couverture | timeline.ts + pistes + bgm-plan.json | final.mp4 + cover.png | references/stage4-render.md · references/cover.md |
L’uniformité stylistique est gérée par references/constructivist-style.md : images et couverture partagent la même palette / police / grille, donc cohérence naturelle.
2. Étape 1 · Script (la hiérarchisation est obligatoire)
L’utilisateur donne une entrée (un thème / un matériau / une idée orale). Les sorties sont :
script.md— script complet, avec niveaux de discours explicitement marquésparoles.txt— une ligne par phrase parlée, pour la TTS
La hiérarchisation n’est pas pour faire joli : c’est l’entrée de l’étape 3. Sans annotation de niveaux, la variation de la BGM n’a pas de point d’appui.
## Niveau 1 · Introduction
Ceci est le premier niveau de « Le script est l’axe temporel ».
La piste vocale est l’axe temporel principal de toute la chaîne de production.
## Niveau 2 · Développement
Le nombre d’images est déterminé par elle, et non l’inverse.
...
- Une phrase = une unité sémantique. Ne pas mettre deux choses dans une seule phrase (la TTS découpe par phrase ; si vous en mettez deux, cela allongera le slot).
- Pour une phrase, 8–30 caractères recommandés ; trop longue → coupez ; trop courte → fusionnez.
- Terminer les phrases par un point ou un point d’interrogation pour aider la TTS à couper.
Détails dans references/stage1-script.md.
3. Étape 2 · TTS (axe temporel) (Ordre impératif)
"$VW_VENV/bin/python" skills/ideaform/scripts/make-tts-track.py \
--lines paroles.txt --fps 30 --audio \
--plan-out out/plan.json --ts-out out/timeline.ts
D’abord la piste, ensuite l’axe temporel. L’axe temporel se crée à partir du débit réel de la TTS :
① Écrire les paroles
② make-tts-track.py --lines paroles.txt --fps 30 --audio ← Mesure le débit naturel, crée l’axe temporel
③ Utiliser le TOTAL_FRAMES de sortie pour écrire la composition Remotion ← Le nombre d’images est ainsi déterminé
④ Puis rendre
Conséquence d’un contre-exemple (testé) : Si l’on écrit d’abord 43 codes temporels fixes par plan, la TTS naturelle totalise 212,90 s, alors que la vidéo ne fait que 174,80 s → compression forcée à 1,218x. Cette concession était totalement évitable.
Le même script peut aussi faire l’inverse (quand un SRT existe déjà et que les codes temporels sont fixes, on utilise un réglage à deux vitesses), mais c’est un palliatif, pas l’option préférée. Voir references/stage2-tts.md.
⚠️ Il est interdit de demander à l’utilisateur « Combien de minutes pour le produit final ? » La durée = débit × quantité de paroles ; c’est une sortie, pas une entrée ; au démarrage, on ne doit ni demander ni donner d’option comme « version standard X minutes ». On indique seulement : « D’après ce script, durée mesurée de X min Y s ». Si l’utilisateur veut plus/moins long → on modifie le script, pas la durée. (2026-10-15, projet Guihua, noté E16)
Sorties : dans plan.json, chaque élément a start/end/dur/frameStart/frameEnd ; timeline.ts peut être directement copié dans le projet Remotion comme src/timeline.ts.
4. Étape 3 · Variations BGM (l’âme de ce workflow)
Point clé : chaque fois que le discours entre dans un nouveau niveau, la musique change de forme — mais pas de morceau.
# ① Convertir les niveaux du script en numéros de repères, marquer la fonction narrative de chaque niveau
"$VW_VENV/bin/python" skills/ideaform/scripts/bgm-plan.py \
--plan out/plan.json \
--layers "1:present,4:develop,6:resolve" \
--key "La mineur" --out out/bgm-plan.json
# ② Générer le projet LMMS selon bgm-plan.json et le rendre (via composer.py de electronic-music-production)
# Le rendu utilise tools.lmms.apprun du contrat ; bpm et timeline lp1pos doivent respecter les mmp_hints
Six fonctions narratives (une par niveau) :
| Fonction | Intention | Ce qui change |
|---|---|---|
present | Présenter · Introduire | Seulement le motif, une seule voix, espaces vides |
develop | Développer · Approfondir | +basse +rythme, motif en séquence |
intensify | Souligner · Conflit | Toutes les voix, octave supérieure, accords empruntés, dynamique accrue |
contrast | Contrast · Tournant | Changement de texture sans augmenter le volume : retrait de couches, changement de timbre, modulation modale |
resolve | Conclure · Retour | Réduction, retour à la tonalité principale, augmentation de la valeur du motif |
sustain | Maintenir · Transition | Rien (quand le niveau n’a pas changé, ne pas varier au hasard, cela diluerait le contraste) |
Règles impératives :
- Les éléments identitaires ne doivent pas changer — cellule de motif, centre tonal, tempo de base. Changer ce serait changer de morceau, pas varier.
- Chaque section doit modifier au moins 1 élément formel ;
bgm-plan.mdliste les « preuves de variation » pour chaque section. Si entre deux sections consécutives les preuves sont vides, cela signifie qu’une annotation de niveau manque. - Le point de variation doit tomber sur la frontière entre niveaux de discours (on peut utiliser
--lead-inpour que la musique commence légèrement avant).
Méthode complète et mise en œuvre côté LMMS voir references/stage3-bgm.md.
5. Étape 4 · Produit final
5.1 Images : Axe temporel principal = piste vocale
cp out/timeline.ts <projetRemotion>/src/timeline.ts # Nombre d’images / limites des scènes dérivées des CUES
cd <projetRemotion>
export TMPDIR="$VW_TMPDIR" # ★ Obligatoire
npx remotion studio # Donner d’abord un aperçu à l’utilisateur
Ne pas écrire manuellement les numéros d’images pour les limites de scène ; dérivez-les des CUES :
export const SCENES = {
s1: { from: 0, dur: CUES[2].start },
s2: { from: CUES[2].start, dur: CUES[4].start - CUES[2].start },
} as const;
Schémas structurels / voies de signalisation / mécanismes → génération déterministe, jamais d’images IA.
L’IA pour la chimie des structures hallucinera forcément des liaisons et l’erreur sera invisible — ce type de contenu doit être reproductible et vérifiable.
Utiliser scripts/gen-structures.py : SMILES → dessin déterministe RDKit → composants Remotion pilotés par images.
python3 scripts/gen-structures.py --tsv structures.tsv --out structures
# → svg/*.svg + components/*.tsx (avec animations) + manifest.json
# → Vérification hors ligne des formules (RDKit CalcMolFormula) ; en cas de non-correspondance, sortie non nulle, peut être enchaîné avec `&&`
- Utiliser les options officielles RDKit (
useBWAtomPalette/singleColourBonds/setSymbolColour), ne pas faire de post-traitement regex des couleurs SVG — c’est réinventer la roue et ça casse à chaque mise à jour de RDKit (voir cahier d’erreurs E20). - Les composants générés utilisent les variables CSS
--mol-dash/--mol-textpour animer les traits ; l’extérieur doit fournircolor. - Pour des visualisations moléculaires plus larges (grille / surlignage du squelette / conformation 3D / interactions protéine-ligand), chercher d’abord un skill existant (voir §7), ne pas les forcer dans cette chaîne vidéo.
5.2 Intégration des pistes audio (deux options, A par défaut)
A. Intégration Remotion (recommandée) — Utiliser <Audio> dans la composition ; le mp4 rendu aura la piste audio intégrée :
<Audio src={staticFile("voice.wav")} />
<Audio src={staticFile("bgm.wav")} volume={0.1694} />
Ne pas inventer la valeur volume ; utiliser le RMS mesuré en inverse :
bash scripts/mix-av.sh --plan-only --voice voice.wav --bgm bgm.wav --drop 9
# Voix RMS = -23,46 dBFS BGM RMS = -17,04 dBFS
# → BGM doit être réduit de -15,42 dB → volume = 0,1694
B. Post-synthèse (vidéo déjà rendue / besoin de redoubler) :
bash scripts/mix-av.sh --video silent.mp4 --voice voice.wav --bgm bgm.wav --out final.mp4
⚠️ Option B : obligatoire d’utiliser explicitement
-map 0:v:0 -map 1:a:0. Le mp4 de Remotion contient une piste AAC silencieuse intégrée ; sans-map, ffmpeg la sélectionne automatiquement → le produit final a code de sortie 0, durée correcte, peut être lu, mais n’a pas de son.mix-av.shinclut déjà ce-map.
5.3 Rendu et couverture
export TMPDIR="$VW_TMPDIR"
npx remotion render <CompositionId> out/video.mp4 --concurrency=3
npx remotion still Cover out/cover.png --props='{...}' # Couverture : composition statique, pas d’animation
- Rendu par segments pour les longues vidéos : un seul rendu de 7 minutes peut échouer par manque de mémoire.
--frames=A-Bpar segment →concat -c copypour une fusion sans perte. - Couverture : utiliser une composition statique avec
durationInFrames={1}; ne pas utiliseruseCurrentFramedans les composants (en mode still, elle est toujours 0 ; la valeur initiale de l’animation rendrait les éléments invisibles). - Voir
references/cover.mdpour le format de la couverture, etreferences/constructivist-style.mdpour les normes stylistiques.
6. Livraison sans inspection visuelle : chaque étape doit passer le validateur
Le modèle ne voit pas les images, n’entend pas les sons. Donc « rendu réussi » ≠ « images correctes, son correct ». Chaque étape utilise des mesures numériques réelles ; si ce n’est pas bon, refuser la livraison :
# Auto-diagnostic audio (piste TTS, BGM) : crête / RMS / écrêtage / écart de durée
# Auto-diagnostic image : pixel par rapport à la couleur / pureté du couloir / comptage de pixels de texte
# --layout doit être correct : cover=format couverture ; scene=scène vidéo (par défaut).
# L’échantillonnage dépend du format ; utiliser le mauvais, même une couverture correcte sera jugée fausse (voir 05-Dépannage D2).
python3 scripts/verify-video.py cover out/cover.png --layout cover
# Auto-diagnostic final : nombre d’images / durée / débit de la piste audio (éviter piste silencieuse)
# Ordre de localisation de ffprobe : VW_FFPROBE → contrat de chemin toolchain.json → système
VW_FFPROBE="$VW_FFPROBE" python3 scripts/verify-video.py video out/final.mp4 --frames 732 --fps 30
Un script qui échoue retourne un code de sortie non nul ; il peut être enchaîné directement dans un pipeline &&.
Référence rapide des critères courants :
| Objet | Critère | Seuil |
|---|---|---|
| Audio | Non silencieux | Crête > 1000 et RMS > 100 |
| Audio | Pas d’écrêtage | Échantillons à pleine échelle < 0,01 % |
| Audio | Alignement temporel | Écart par rapport au plan < 50 ms |
| Couverture | Dimensions | 1920×1080 |
| Couverture | Rendu de texte | Pixels d’encre dans la zone de texte > 300 |
| Couverture | Axe ne traverse pas le texte | Pixels rouges dans la zone de titre < 60 |
| Produit final | Nombre d’images | Strictement égal à la valeur planifiée |
| Produit final | Piste audio non silencieuse | Débit > 64000 bps |
| BGM | Niveau de fond | 8–12 dB en dessous de la voix-off |
7. Autres capacités en complément de ce skill
| Besoin | À utiliser |
|---|---|
| Détection d’environnement / installation manquante / contrat | ideaform-setup (ponctuel) |
| Skill existant pour un nouvel outil open-source (récolte GitHub → sécurité → mise en place) | scripts/harvest-skills.py <nomOutil> de ideaform-setup |
| Graphisme déterministe de structures chimiques / schémas de voies | scripts/gen-structures.py de ce skill (RDKit → SVG → composants Remotion) |
| Visualisation moléculaire plus large (grille / surlignage squelette / conformation 3D / protéine-ligand) | Skill externe existant : molecule-visualization de synthetic-sciences/openscience (Apache-2.0), ghutchis/chem-skill (MIT) |
Format de projet LMMS, paramètres de plugin, enveloppes eldata | electronic-music-production + ses references/05 |
| Composition musicale (harmonie, motif, composition sans audition, émergence) | references/06–10 de electronic-music-production |
| Syntaxe Remotion et détails de rendu | remotion-best-practices |
| Méthode complète d’inspection sans visuel au niveau pixel | headless-visual-verify |
| Pièges WSL (/mnt, récupération gh, chemin audio) | wsl-pitfalls |
8. Liste de livraison
Une fois la vidéo terminée, l’espace de travail doit contenir :
<espace de travail>/
├── script.md Script hiérarchisé
├── paroles.txt Paroles à dire
├── out/
│ ├── plan.json Axe temporel principal (secondes/images de chaque repère)
│ ├── timeline.ts Axe temporel directement utilisable dans Remotion
│ ├── voice.wav Piste vocale master
│ ├── bgm-plan.json Plan de variation + bgm-plan.md (preuves de variation)
│ ├── bgm.wav Piste BGM
│ ├── video.mp4 Images silencieuses (ou produit final avec pistes intégrées)
│ ├── final.mp4 ★ Produit final
│ └── cover.png ★ Couverture
└── .tts/ Cache TTS (gardé ; une nouvelle exécution ne prend que quelques secondes)
Avant livraison, il est obligatoire d’exécuter toutes les vérifications de la section 6 et de rapporter honnêtement quels tests ont réussi et lesquels n’ont pas été effectués.
9. Auto-évolution : enregistrer chaque problème rencontré
Ce workflow est un skill composite modifiable — en l’utilisant, il doit de plus en plus s’adapter à votre rythme de production :
- Quand vous rencontrez un problème et le résolvez → inscrivez-le dans la racine du dépôt
docs/06-CahierDerreurs.md(format six colonnes, numérotation continue). ⚠️ Ne pas créer dedocs/séparé sousskills/ideaform/— ce serait un deuxième cahier, avec des numéros en conflit avec l’original (2026-10-15 rencontré, noté E19). - Si un problème est définitivement résolu (pas contourné) par script/documentation → mettez à jour l’état de cette entrée en « Guéri » et précisez la méthode.
- Si un même type de problème se reproduit une deuxième fois → n’écrivez pas une troisième entrée ; intégrez directement la défense dans le script (validateur / valeur par défaut / contrat).
- Introduire un nouvel outil open-source → d’abord récolter, puis agir :
harvest-skills.py <nomOutil>pour chercher un skill existant dans la communauté (avec protection de fork, il n’écrase pas vos modifications locales) ; ce n’est que si aucun skill acceptable n’est trouvé que vous écrivez le vôtre. Les problèmes rencontrés avec un skill récolté sont également enregistrés. - Avant la fin d’une session, vérifiez : y a-t-il quelque chose de « réparé mais pas enregistré » ?