Block town
Ce dossier est le kit complet : la ville, le casting, leurs déplacements, le moteur de rendu, la voix, les sons, les paramètres musicaux et les étapes allant d'une idée à une vidéo verticale finie. Le dossier de la compétence est le répertoire qui contient ce fichier ; il est appelé SKILL ci-dessous. Les épisodes vivent en dehors (l'utilisateur nomme le dossier), appelé EPISODE ci-dessous. Utilisez des chemins absolus.
À lire avant de construire : docs/ROBLOX_LOOK.md (le monde, le casting, les accessoires, comment les plans sont réalisés), docs/RENDER.md (le moteur de rendu Three.js, la couche de vie, les étiquettes, les écrans de téléphone et les accessoires imprimés), docs/SCRIPT.md (comment l'histoire est écrite), docs/VOICE.md (voix et musique), docs/SOUND.md (effets sonores, ElevenLabs, le mix vocal stable). docs/PROMPTS.md contient un prompt pour chaque étape. docs/GUIDE.md est le manuel original du look Block : la carte, pose(), les mouvements et les règles de la caméra s'appliquent toujours.
Comment une vidéo est fabriquée (depuis ep05)
Blender construit et pose tout à partir du code Python de l'épisode ; Three.js dessine les images finales. Le propre moteur de rendu de Blender est réservé aux fiches de design et aux arrêts sur image.
episode.py ──(Blender : construire la ville, poser chaque image, couche de vie)──> bake : scene.glb + anim.bin + materials.json
──(Three.js dans Chrome headless)──> EPISODE/frames/f_####.jpg (~0,1-0,15 s par image)
──(finish.py : sous-titres, voix nivelée, effets sonores, musique)──> EPISODE/<nom>.mp4 et <nom>_music.mp4
Un épisode de 66 secondes prend environ 10-12 minutes des images aux MP4 finis (Blender EEVEE prenait environ 3 heures).
Jamais
- Pas d'articles du catalogue Roblox, de modèles téléchargés, de séquences, d'histoires ou d'audio provenant d'autres créateurs. Tout ce qui se trouve dans l'image est construit en code ou dessiné par
blockworld/pictures.py. Les vidéos virales peuvent être étudiées pour leur savoir-faire, jamais réutilisées. - Pas d'appels API payants sans l'accord de l'utilisateur. Fish Audio (voix) et ElevenLabs (effets sonores) coûtent de l'argent : dites d'abord combien coûtera une exécution.
sfx_gen.pyvérifie les crédits restants et s'arrête avant la réserve ; ne jamais augmenter la réserve ni boucler les générations pour « réessayer » sans demander. Demandez avant de télécharger quoi que ce soit. - Pas de musique ni d'extraits de voix de référence dans ce kit. Musique uniquement à partir d'un fichier fourni par l'utilisateur, et uniquement dans la copie
_music.mp4. Si ce fichier a été extrait de la vidéo d'un autre créateur, dites clairement que le_music.mp4ne doit pas être publié : publiez le<nom>.mp4propre et ajoutez la chanson dans le sélecteur de son de TikTok. - Ne modifiez pas les huit personnages récurrents (couleurs, cheveux, vêtements) :
blockworld/town.py. - Ne passez pas un épisode déjà en cours à un autre style.
- Pas de graphiques abstraits non expliqués. Un faisceau, une ligne ou une lueur entre deux petites figures n'apprend rien au spectateur (le « donnant toutes les barres » d'ep05 a été lu comme « une ligne bleue »). Montrez la chose elle-même : des barres sortant d'une étiquette, un compteur qui descend, un écran de téléphone qui le dit.
Le style
Les nouveaux épisodes utilisent le style Roblox : build_town(..., style="roblox"). Têtes rondes avec visages anime, cheveux en couches, vêtements imprimés, plastique brillant, ambiances soleil/brouillard/pluie, sous-titres karaoké de 3 mots. L'ancien style Block (têtes cubiques, couleurs unies) est toujours présent pour les épisodes qui ont commencé avec : build_town(...) sans style donne le style Block, alors écrivez toujours style="roblox" dans un nouvel épisode.
Barre de qualité (ce que l'utilisateur a rejeté ou demandé)
- Rien n'est jamais statique. Rendez avec la couche de vie (
BT_LIFE=1, la valeur par défaut dansrender_threejs.sh) : respiration, regards, transferts de poids, rebond à chaque coupe, tremblement de caméra et zooms avant, arbres qui se balancent, nuages qui dérivent, étiquettes flottantes, spinners de chargement qui tournent, anneaux Wi-Fi pulsants, barres de signal qui rebondissent. Un plan où seule la caméra bouge est un plan faible : donnez-lui sa propre action. - Les étiquettes et les bulles ne sont jamais couvertes et jamais coupées. La couche de vie les dessine par-dessus tout, les soulève au-dessus des cheveux, et les maintient dans la zone de sécurité TikTok (x 5-85 %, y au-dessus des sous-titres). Vérifiez que deux étiquettes ne se chevauchent pas (pas encore automatique).
- Chaque écran ressemble à un vrai téléphone :
big_phone(screen=...)avec une image depictures.py(barre d'état, « Pas de service », disposition des apps, une main qui le tient), jamais une boîte blanche avec du texte 3D. Les téléphones tenus à la main affichent un écran de verrouillage. - Les accessoires se lisent à la taille d'un téléphone : une carte en papier est une vraie carte dessinée (
paper_map()), un panneau est entièrement dans le cadre (reculez la caméra : un panneau de 10 studs nécessite ~25 studs de distance en 9:16). - La voix ne faiblit jamais.
finish.json{"voice": "vo/voice_level.wav", "loudness": "static"}: la narration est nivelée phrase par phrase et le mix reçoit un gain fixe, donc les effets forts ne peuvent pas faire baisser la voix. Mesurez : la loudness à court terme doit rester dans ±1 dB de -14 LUFS pour toute la vidéo. - Pas d'effets superposés ou agressifs. Un son par moment ; rien de plus long que le moment ; pas deux sons « d'erreur » en moins d'une demi-seconde.
Fabriquer un épisode : sept portes
Arrêtez-vous après chaque porte, montrez le résultat, et attendez l'utilisateur. Là où il y a un véritable choix créatif, proposez deux ou trois options et dites laquelle vous recommandez.
| Porte | Ce que vous faites | Montrez à l'utilisateur |
|---|---|---|
| 1 Règle | Trois règles (à partir de l'idée de l'utilisateur ou des tests de docs/SCRIPT.md), chacune avec une ambiance et une idée de point de repère | un tableau |
| 2 Script | EPISODE/script.txt (une phrase par ligne) et EPISODE/SCRIPT.md : option A et B, tableau des beats, scores du critique | le script |
| 3 Voix | vo.py, words.py, voice_check.py (prise Fish gratuite), level_voice.py | vo/voice.wav, ses chiffres |
| 4 Designs | EPISODE/design/episode.py : un arrêt sur image de chaque nouveau point de repère, accessoire, costume et personnage ; EPISODE/pictures.json et pictures.py pour chaque écran de téléphone et accessoire imprimé | DESIGN_SHEET.jpg + les écrans |
| 5 Arrêts sur image | EPISODE/episode.py avec chaque plan ; check ; arrêts sur image ; correction ; contact_sheet.py | CONTACT_SHEET.jpg |
| 6 Accroche | les premières ~15 s : render_threejs.sh EPISODE 0 F1, indices sonores, finish.py | le MP4 |
| 7 Vidéo complète | render_threejs.sh EPISODE, sons, finish.py (fichier propre + fichier musique) ; sur approbation, la prise vocale payante | les deux MP4 |
Les détails des portes se trouvent dans docs/PROMPTS.md (le prompt 1 exécute l'ensemble). Copiez examples/ep05-wifi pour commencer : c'est un épisode terminé fabriqué de cette manière, avec sa fiche de design, 42 plans, images de téléphone, indices et paramètres.
Une prise finale payante est un nouvel enregistrement : exécutez à nouveau words.py et level_voice.py, puis check, et re-rendu (les plans suivent les temps des mots). Approuvez donc le timing de la prise gratuite à la porte 3, mais effectuez la prise payante avant la porte 6 si l'utilisateur souhaite publier.
Commandes
# voix (porte 3)
python3 SKILL/blockworld/vo.py EPISODE # une prise dans la voix "Roblox" de Fish (vo_config.json)
python3 SKILL/blockworld/vo.py EPISODE --post-only # refaire le resserrement/présence/tempo sur la prise sauvegardée, sans nouvel appel
python3 SKILL/blockworld/words.py EPISODE # temps des mots -> vo/times.json
python3 -I SKILL/blockworld/voice_check.py EPISODE # rythme, pauses, luminosité par rapport aux plages virales
python3 -I SKILL/blockworld/level_voice.py EPISODE # chaque phrase à un niveau -> vo/voice_level.wav
# images pour les accessoires (porte 4)
python3 -I SKILL/blockworld/pictures.py EPISODE # EPISODE/pictures.json -> EPISODE/pictures/*.png
# plans (portes 4-5) : Blender, toujours via run.py avec --factory-startup
blender -b --factory-startup --python-exit-code 1 -P SKILL/blockworld/run.py -- EPISODE check
BT_LIFE=1 blender -b --factory-startup --python-exit-code 1 -P SKILL/blockworld/run.py -- EPISODE stills [plan ...]
blender -b --factory-startup --python-exit-code 1 -P SKILL/blockworld/run.py -- EPISODE frame 12.5
python3 -I SKILL/blockworld/contact_sheet.py EPISODE # un arrêt sur image numéroté par plan -> CONTACT_SHEET.jpg
# images finales (portes 6-7) : Three.js
bash SKILL/blockworld/render_threejs.sh EPISODE # chaque image -> EPISODE/frames/ (~10 min pour 66 s)
bash SKILL/blockworld/render_threejs.sh EPISODE F0 F1 # seulement F0..F1 (l'accroche, un plan refait)
# effets sonores (portes 6-7) : voir docs/SOUND.md
python3 -I SKILL/blockworld/sfx_gen.py --credits # crédits ElevenLabs restants
python3 -I SKILL/blockworld/sfx_gen.py el-tag-pop ep07-... # générer des sons nommés à partir de sfx/ELEVENLABS_LIST.md
python3 -I SKILL/blockworld/cues.py EPISODE cues_spec.json # indices par mot ("dire" : "gelé") -> EPISODE/cues.json
# finition (portes 6-7)
python3 -I SKILL/blockworld/finish.py EPISODE # sous-titres + voix + effets (+ musique) -> les MP4
checkne rend rien : il exécute chaque plan, affiche le tableau des plans et prévient des plans de plus de 2,5 s.- Vérifications automatiques des arrêts sur image (
blockworld/stillcheck.py, depuis ep08) : appelezfocus(personnage, étiquette, ...)dans chaque plan.checketstillssignalent alors les visages bloqués (par un poteau, une personne, une étiquette ou le propre bras du personnage), les visages sous la bande de sous-titres, les étiquettes en dehors de la zone de sécurité (x 5-85 %, entre la barre supérieure de TikTok et les sous-titres), les étiquettes qui se chevauchent, et tout ce qui se trouve à moins de 1 stud de l'objectif. Les résultats vont dansEPISODE/still_check.txt. Corrigez chaque ligne avant de montrer les arrêts sur image, puis regardez-les quand même : cela ne juge pas le cadrage ni si l'image illustre la phrase. - 60 fps avec flou de mouvement (optionnel) :
finish.json"render_fps": 240, "blur": 4rend 240 images par seconde et moyenne chaque groupe de 4 en une image 60 fps. Environ 1,6 min de rendu par seconde de vidéo. - Virage couleur (optionnel) :
finish.json"grade": {"word": 24, "ramp": 0.5, "saturation": 0.6, "brightness": -0.05, "cool": 0.1, "vignette": true}atténue l'image vers le froid, le sombre et le plat à partir de ce mot du script (le tournant de l'histoire). Les sous-titres ne sont pas modifiés.finish.py EPISODE --plainécrit aussi<nom>_plain.mp4(30 fps, pas de flou, pas de virage) pour une comparaison côte à côte. - ep08 (
episodes/ep08-price-tags-10s) est le test de 10 secondes de ces éléments, avec des plans d'environ 1 s. stillsécrit deux images Blender demi-taille par plan (à 30 % et 85 %) dansEPISODE/stills/. UtilisezBT_LIFE=1pour que les étiquettes soient placées comme lors du rendu final. Regardez chaque arrêt sur image avant d'en montrer un.render_threejs.shs'exécute en arrière-plan si vos commandes expirent (environ 10 minutes pour 66 s). Il installe les deux packages npm lors de la première utilisation (blockworld/threejs/) et nécessite Chrome ou Chromium (CHROME=/pathpour choisir). Il conserve son bake dansEPISODE/threejs/; supprimez-le ainsi queframes/après que l'utilisateur a accepté la vidéo.- Après toute modification de
episode.py, d'un décor ou d'une image : réexécutezrender_threejs.sh(le bake lit le code ; rien n'est mis en cache entre les exécutions). render_all.sh(images Blender EEVEE) est conservé uniquement pour les comparaisons : environ 3-6 s par image.- L'accroche :
render_threejs.sh EPISODE 0 F1oùF1est l'image juste avant la première coupe après ~15 s, puisfinish.py(elle utilise les images existantes), et renommez le MP4 pour que la vidéo complète ne l'écrase pas. - Regardez les images sur toute la vidéo (au moins une par plan) et mesurez la loudness avant de déclarer la vidéo terminée. Si vous ne pouvez pas écouter, dites-le clairement et listez ce que vous avez vérifié à la place.
Ce qui va où
| Chemin | Quoi |
|---|---|
blockworld/town.py | la rue, le casting, pose(), lumière, caméra, build_town(style=...) |
blockworld/roblox.py | le look Roblox : rchar, plastique, ambiances, rule_sign, giant_clock, puddles |
blockworld/rprops.py | accessoires prêts : étiquettes de barre de signal et jetons de barre volante, téléphones avec vrais écrans et une main, images éclairées et imprimées, carte en papier pliée, affiche, écharpe, haut-de-forme, bus, porte, faisceau, pigeon, tour Wi-Fi |
blockworld/pictures.py, blockworld/pictures/ | dessine les écrans de téléphone, les écrans de verrouillage et les cartes à partir de pictures.json ; les images par défaut du kit |
blockworld/anim.py | aides au timing des mots, cartes (étiquettes, bulles), stand, walk, le coureur |
blockworld/life.py | la couche de vie (BT_LIFE=1) : mouvement d'inactivité, caméra, balancement de la scène, spinners, placement des étiquettes |
blockworld/threejs/ | le moteur de rendu : bake.py (côté Blender), scene.html + capture.mjs (côté Three.js) |
blockworld/render_threejs.sh | bake + dessin, la manière normale de faire les images finales |
blockworld/vo.py, words.py, voice_check.py, level_voice.py | voix, temps des mots, vérification vocale, nivellement |
blockworld/sfx_gen.py, sfx/ELEVENLABS_LIST.md | effets sonores ElevenLabs : le générateur et la liste des prompts |
blockworld/finish.py | sous-titres, voix, effets sonores (y compris les boucles de fond), musique, le mix stable, les MP4 |
blockworld/cues.py | listes d'indices par mot -> cues.json |
sfx/ | effets sonores : l'ensemble Pixabay (sfx/CREDITS.md) ; les sons ElevenLabs arrivent ici sous la forme el-*.mp3 / epNN-*.mp3 une fois générés (aucun pour l'instant à partir d'ep05) |
examples/ep05-wifi | l'épisode complet travaillé (look Roblox, moteur de rendu Three.js) |
examples/ep00-roblox-look, examples/ep01-intro | courtes démos du look Roblox et du look Block |