Explicador animé (motion graphics 3D par code)
Tout est code : chaque partie de la vidéo est un monde 3D (escena/partes/<parte>.js) qui est une fonction pure du temps,
motor.js décide laquelle est visible et dessine les sous-titres karaoké, et render.mjs demande à Chrome headless chaque image.
Rien n'est édité à la main : si quelque chose ne va pas, on corrige le code et on re-rend.
Où tout se trouve : HOME3D = $EXPLICADORES_3D ou, si elle n'existe pas, ~/.explicadores-3d (créé par l'installateur). Là se trouvent
biblioteca/ (modèles 3D, vendor/ avec three.js, polices) et une copie de cette skill. SKILL_DIR = le dossier de ce SKILL.md.
| Fichier | Utilité |
|---|---|
nuevo.py <dossier> | Crée le projet avec le template (moteur, style, lib2d, three.js, police Fredoka, scripts de voix/timing/audio, une partie d'exemple, CONTRATO.md vierge et DECISIONES.md) |
render.mjs | --hoja, --probe a,b,c, --rango a,b, --mitad, --sub N, --rapido, --sin-gpu |
entregar.py <projet> <NOM> --ronda N [--escritorio] | Vidéo + audio, version mobile < 29 Mo, feuilles de révision toutes les 0,5 s et datos.txt (durée, LUFS, pic) |
revisar_hoja.py <projet> [--tramo a,b | --ronda N | --cuadros …] | Révision automatique en ~5 s et sans tokens : texte en double dans les fondus, halos, doubles (ressemblent à des yeux), blancs brûlés, taches, hors zone, sauts de luminosité |
ENCARGO_CONSTRUCTOR.md | Template de la mission courte de constructeur (une partie par agent) |
ENCARGO_REVISORES.md | Relecteurs A (rétention), B (données), D (image) sur la feuille et la vidéo |
Prérequis : Node 18+, npm install playwright-core dans le projet, Chrome (ou CHROME_PATH, ou
npx playwright install chromium), Python 3.10+ avec numpy et faster-whisper, et ffmpeg.
Règles de la maison
- Zéro donnée inventée : chaque chiffre avec sa source dans le CONTRAT avant de construire.
- Pas d'animaux ni d'objets avec des yeux, et pas de formes qui ressemblent à des yeux (voir « Erreurs typiques »).
- Style par défaut : un objet propre sur fond sombre avec halo chaud, caméra macro toujours en mouvement doux, mot-clé en doré, sous-titres karaoké de toute la narration, boucle sur la première image.
- Rythme : 3,0-3,2 mots/s, un changement de cadre toutes les ~3 s, rien d'immobile plus de 5 s, accroche avant 4,5 s.
- Durée : 15-30 s si isolé ; plus de 60 s seulement si c'est une partie d'une série avec nom et numéro.
Le flux
python SKILL_DIR/nuevo.py <sujet>-AAAA-MM(crée le dossier dans le répertoire courant). Ouvrir et tester l'affichage :npx http-server escena -p 8080(oupython -m http.serverdansescena/) et aller surlocalhost:8080.- Scénario avec la skill
guion: recherche avec sources, MAPA, Tour 0 (A ≥ 9, C ≥ 9, max. 2 tours) et arrêtGUION LISTO. Ne continue pas sans l'OK de l'utilisateur. - Voix (consomme des crédits ou du temps CPU, donc après l'OK) :
- ElevenLabs :
export ELEVENLABS_API_KEY=...(l'utilisateur la définit ; ne l'écris jamais dans un fichier) etpython scripts/voz_eleven.py [--voz <id>]→voz/tomas_eleven/. Plan gratuit = pas d'usage commercial et avec crédit. - Gratuit et local :
pip install kokoro soundfile(+espeak-ngdu système) etpython scripts/voz_local.py [--voz em_alex]→voz/tomas_local/. python scripts/verificar_voz.py(Whisper large-v3, une fois et en arrière-plan) marque les mots mal prononcés.python scripts/tiempos.py --tomas tomas_eleven(outomas_local) →voz/voz_completa.wav,escena/beats.js(seconde de chaque mot-clé, selonvoz/claves.json) etescena/palabras.js(karaoké).
- ElevenLabs :
- CONTRAT complet (
escena/CONTRATO.md) : parties avec leurs plagesB.*, ce qui est vu à chaque clé, panneaux exacts, données avec source, zone sûre, rythme. C'est la seule chose que lisent les constructeurs : ce qui n'y est pas, ils le devinent. Change dansmotor.jslePLAN(ordre des parties et transitions) etCLAVE(mots dorés du karaoké). - Modèles 3D : avant de modéliser, cherche dans la bibliothèque (skill
biblioteca,HOME3D/biblioteca/CATALOGO.md) et copie ce qui convient dansescena/modelos/. Ce qui manque est réalisé par un seul agent (modèle partagé, effortmedium, plafond 150 k) et signale avecmodelos/LISTO_<objet>.txt. - Constructeurs, avec
ENCARGO_CONSTRUCTOR.md:- une partie par agent (une scène de ≤ 15 s), en arrière-plan, maximum 3 à la fois ;
- mission courte : seulement sa partie, ses modèles avec l'API en une ligne et les règles ; le constructeur ne lit ni le moteur ni le CONTRAT complet ;
- avec le bloc « Erreurs typiques » et le « Plafond du constructeur » collés tels quels ;
- un constructeur frais par tour de corrections, ne jamais continuer à discuter avec un qui a déjà dépassé 40 tours ;
- ne jamais les laisser « attendre » un autre agent : d'abord le modèle partagé, puis les parties.
- Feuille avant le rendu :
node render.mjs --hoja(une image par beat : le scénario visuel) etpython SKILL_DIR/revisar_hoja.py .. ROUGE = corriger avec un agent fraislowavant de continuer. Ensuite relecteurs A, B et D sur la feuille (ENCARGO_REVISORES.md, Tour 1), avec la sortie derevisar_hoja.pycollée dans la mission de D. python scripts/audio.py→audio/mezcla.wavà -14 LUFS (musique et effets synthétisés ; éditeEFECTOSetCAMBIOSen haut du fichier).- Rendu pour itérer :
node render.mjs --rapido --sub 1. Ensuitepython SKILL_DIR/entregar.py . NOM --ronda 1etpython SKILL_DIR/revisar_hoja.py . --ronda 1avant d'envoyer à A et D (1 tour sur vidéo). - Rendu final, une seule fois :
node render.mjs --sub 6. Jamais deux rendus à la fois. python SKILL_DIR/entregar.py . NOM --ronda N --escritorioet livraison de la version mobile.- Contribuer à la bibliothèque (activé par défaut) : suivre « Contribuer de nouveaux modèles » de la skill
biblioteca(nuevos.py→ préparer →Les ajoute à la bibliothèque ? (O/n)). Si l'utilisateur a déjà dit non pour ce projet, ne pas demander.
Effort et modèle par rôle
Voir le tableau complet par harness dans AGENTS.md du dépôt. Résumé (noms de Claude Code ; sur d'autres harness utiliser
l'équivalent « rapide/moyen/profond ») :
| Rôle | Modèle | Effort |
|---|---|---|
| Session qui coordonne la vidéo | celui que tu utilises | medium |
| Chercheur de données et relecteur B | moyen (Sonnet) | high |
| Modèle 3D partagé | moyen | medium, plafond 150 k |
| Constructeurs de scènes | moyen | medium, plafond 40 tours / 120 k |
| Relecteurs A, C, D | moyen | medium (les petits modèles type Haiku contredisent les règles : non) |
| Petites corrections d'une scène | moyen | low |
max | jamais | prend énormément de temps et pense trop |
Budget de tokens et sessions
Le coût est tours × longueur de la conversation, pas ce qui est écrit. Règles :
- Une session fraîche par vidéo. Relève à 150 k de contexte : laisse
AVANCE.md(ce qui reste, ce qui suit, décisions) et continue dans une nouvelle session qui le lit. - Annonces seulement aux jalons :
GUION LISTO,VIDEO RÁPIDO LISTO,TERMINADOou quand tu es bloqué. Le reste est noté dansTIEMPOS.mdsans prévenir. - Pas de captures ni d'images dans la session principale : un sous-agent les regarde et répond en texte.
- Relecteurs avec budget : Tour 0 sur le MAPA max. 2 tours ; Tour 1 sur la feuille 1 ; sur la vidéo 1 tour seulement avec A et D. Deuxième tour seulement de la zone qui est restée en dessous de 8,5.
Plafond du constructeur (collé, tel quel, à la fin de chaque mission ; pour le modèle partagé, 150 k) :
Budget : maximum 40 tours et 120 k tokens de contexte. Quand tu atteins l'un des deux, écris
AVANCE.mddans ton dossier de travail (ce qui reste, ce qui manque, ce que tu as testé et échoué) et termine avec un résumé de 5 lignes ; un autre agent continuera à partir de là. Ne lis pas le moteur, le CONTRAT complet ni les parties des autres : ce dont tu as besoin est dans cette mission. Ne lis jamais un fichier complet de plus de 300 lignes : utilise des plages ou grep. Les captures, seulement avecnode render.mjs --probe <sec> --mitadet maximum 1 toutes les 5 tours. Avant de demander une capture, exécuterevisar_hoja.py(ne consomme pas de tokens). N'attends personne : si quelque chose manque, note-le dansAVANCE.mdet termine.
Erreurs typiques (collées, telles quelles, dans chaque mission de constructeur ; (auto) = détecté par revisar_hoja.py) :
- Texte en double dans les fondus (auto) : retire l'ancien panneau complètement avant que le nouveau n'entre (sortie < 0,15 s) ou utilise un cut sec ; jamais deux panneaux en même temps dans la même zone.
- Halos et auras (auto) : orbe, disque ou spot avec un éclat doux autour ressemble à un œil ou un soleil. Émissif plat, sans sprite radial ; si quelque chose brille, que ce soit allongé et sans anneau.
- Doubles (auto) : deux fenêtres, spots ou orbes de la même taille et luminosité ensemble ressemblent à des yeux. Tailles différentes, à des hauteurs différentes, ou un seul.
- Blancs brûlés (auto, avertissement) : rien en blanc pur avec bloom ; couleur de la palette, mat.
- Taches et points isolés (auto, avertissement) : particules seules, ombres derrière les panneaux, bords qui restent.
- Hors zone (auto) : rien en y < 215 ni en dessous de y = 1450 (karaoké) ; rien ne traverse un panneau.
- Sauts de luminosité (auto avec
--ronda) : lumière moyenne 60-90, sans sauts > 25 entre les plans.- Doublons : le même texte sur un panneau et en karaoké en même temps ; un seul panneau par idée.
- Visages et mains : personnes de dos ou 3/4 arrière ; la main entre de côté ou par le dos.
- Petits panneaux : tout >= 42 px (panneaux >= 52 px).
Rendu : où se passe le temps (mesuré sur un laptop 4 cœurs avec GPU intégré)
| Étape | Par image |
|---|---|
| Récupération de l'image depuis Chrome (JPEG, GPU via ANGLE) | ~0,07 s |
x264 slow CRF 16 (livraison) | +0,11 s |
--rapido (Quick Sync sur Windows/Intel ; x264 veryfast sur les autres ; CODEC_RAPIDO pour choisir) | +0,02-0,05 s |
Flou --sub 6 | +0,09 s |
Sans GPU (--sin-gpu) c'est ~40 % plus lent. Pas de transmission sur les matériaux et chaque partie < 80 ms par image.
Leçons qui coûtent un tour si on les oublie
update(t)est une fonction pure de t : le rendu demande des images individuelles et des sous-images. Pas deMath.random(utiliseE.azar(graine)) ni d'état entre les images. Protège t < 0.- Mouvements de caméra de ≥ 0,6 s avec inOutCubic : avec
--sub 6les coups de fouet sortent comme des fantômes. - Si un test sort avec des morceaux d'une autre image, un autre processus rendait en même temps : recommence-le.
- Le 404 de « Failed to load resource » à la fin du rendu est normal ; les vraies erreurs sont
pageerror. - Avec
scene.environment, three r186 utilisescene.environmentIntensity, pasenvMapIntensitydu matériau. - Particules de la bibliothèque (three.quarks) sont déterministes par temps : ne bouge pas le groupe, utilise sa
pos. - Panneau de réglages avec la souris :
?ajustes=1dans l'URL (voirbiblioteca/base/LEEME.md) ; le rendu ne le charge jamais. - Matériel réel (photos, séquences d'archive) : Wikimedia Commons et Internet Archive ont du domaine public et CC BY ; note les crédits dans la description.