Block town
Esta carpeta contiene el kit completo: la ciudad, el reparto, cómo se mueven, el renderizador, la voz, los sonidos, la configuración de música y los pasos desde una idea hasta un video vertical terminado. La carpeta del skill es el directorio que contiene este archivo; se le llama SKILL en adelante. Los episodios viven fuera de ella (el usuario nombra la carpeta), llamada EPISODE en adelante. Usa rutas absolutas.
Lee antes de construir: docs/ROBLOX_LOOK.md (el mundo, el reparto, la utilería, cómo se hacen los planos), docs/RENDER.md (el renderizador Three.js, la capa de vida, etiquetas, pantallas de teléfono y utilería impresa), docs/SCRIPT.md (cómo se escribe la historia), docs/VOICE.md (voz y música), docs/SOUND.md (efectos de sonido, ElevenLabs, la mezcla de voz estable). docs/PROMPTS.md tiene un prompt para cada etapa. docs/GUIDE.md es el manual original del aspecto de bloques: el mapa, pose(), los movimientos y las reglas de cámara siguen vigentes.
Cómo se hace un video (desde ep05)
Blender construye y posa todo desde el código Python del episodio; Three.js dibuja los fotogramas finales. El renderizador propio de Blender solo se usa para hojas de diseño y fotogramas fijos de planos.
episode.py ──(Blender: construye la ciudad, posa cada fotograma, capa de vida)──> horneado: scene.glb + anim.bin + materials.json
──(Three.js en Chrome headless)──> EPISODE/frames/f_####.jpg (~0.1-0.15 s por fotograma)
──(finish.py: subtítulos, voz nivelada, efectos de sonido, música)──> EPISODE/<nombre>.mp4 y <nombre>_music.mp4
Un episodio de 66 segundos toma aproximadamente 10-12 minutos desde los fotogramas hasta los MP4 terminados (con Blender EEVEE tomaba unas 3 horas).
Nunca
- Sin elementos del catálogo de Roblox, modelos descargados, ni imágenes, historias o audio de otros creadores. Todo en la imagen se construye con código o se dibuja con
blockworld/pictures.py. Los videos virales pueden estudiarse para aprender la técnica, nunca reutilizarse. - Sin llamadas a APIs de pago sin el consentimiento del usuario. Fish Audio (voz) y ElevenLabs (efectos de sonido) cuestan dinero: di cuánto costará una ejecución primero.
sfx_gen.pyverifica los créditos restantes y se detiene antes de la reserva; nunca aumentes la reserva ni repitas generaciones para 'reintentar' sin preguntar. Pregunta antes de descargar cualquier cosa. - Sin música ni clips de voz de referencia en este kit. La música solo proviene de un archivo que el usuario proporcione, y solo en la copia
_music.mp4. Si ese archivo se extrajo del video de otro creador, di claramente que el_music.mp4no debe publicarse: publica el<nombre>.mp4limpio y agrega la canción en el selector de sonidos de TikTok. - No cambies los ocho personajes recurrentes (colores, cabello, ropa):
blockworld/town.py. - No cambies un episodio que ya está en progreso a otro aspecto visual.
- Sin gráficos abstractos sin explicación. Un rayo, una línea o un brillo entre dos figuras pequeñas no le dice nada al espectador (ep05: el rayo 'regalando todas las barras' se leyó como 'una línea azul'). Muestra la cosa en sí misma: barras volando de una etiqueta, un contador bajando, una pantalla de teléfono que lo dice.
El aspecto
Los episodios nuevos usan el aspecto Roblox: build_town(..., style="roblox"). Cabezas redondas con caras anime, cabello en capas, ropa impresa, plástico brillante, estados de ánimo sol / niebla / lluvia, subtítulos karaoke de 3 palabras. El aspecto bloque anterior (cabezas cúbicas, colores planos) sigue ahí para episodios que empezaron con él: build_town(...) sin style da el aspecto bloque, así que siempre escribe style="roblox" en un episodio nuevo.
Barra de calidad (lo que el usuario rechazó o pidió)
- Nada es estático nunca. Renderiza con la capa de vida (
BT_LIFE=1, el valor predeterminado enrender_threejs.sh): respiración, miradas, cambios de peso, un rebote en cada corte, bamboleo de cámara y acercamientos, árboles meciéndose, nubes a la deriva, etiquetas flotantes, ruedas de carga girando, anillos Wi-Fi pulsantes, barras de señal rebotando. Un plano donde solo la cámara se mueve lentamente es un plano débil: dale su propia acción. - Las etiquetas y burbujas nunca se tapan ni se cortan. La capa de vida las dibuja sobre todo, las eleva por encima del cabello y las mantiene dentro del área segura de TikTok (x 5-85 %, y por encima de los subtítulos). Verifica que dos etiquetas no se superpongan entre sí (aún no es automático).
- Cada pantalla parece un teléfono real:
big_phone(screen=...)con una imagen depictures.py(barra de estado, 'Sin servicio', diseño de aplicaciones, una mano sosteniéndolo), nunca una caja blanca con texto 3D. Los teléfonos sostenidos con la mano muestran una pantalla de bloqueo. - La utilería se lee al tamaño de un teléfono: un mapa de papel es un mapa real dibujado (
paper_map()), un letrero está completamente en el encuadre (aleja la cámara: un letrero de 10 unidades necesita ~25 unidades de distancia en 9:16). - La voz nunca baja.
finish.json{"voice": "vo/voice_level.wav", "loudness": "static"}: la narración se nivela oración por oración y la mezcla recibe una ganancia fija, así que los efectos fuertes no pueden hacer que la voz baje. Medida: la sonoridad a corto plazo debe mantenerse dentro de ±1 dB de -14 LUFS durante todo el video. - Sin efectos apilados o agresivos. Un sonido por momento; nada más largo que el momento; no dos sonidos de 'error' en menos de medio segundo.
Haz un episodio: siete puertas
Detente después de cada puerta, muestra el resultado y espera al usuario. Cuando haya una elección creativa real, ofrece dos o tres opciones y di cuál recomiendas.
| Puerta | Qué haces | Muéstrale al usuario |
|---|---|---|
| 1 Regla | Tres reglas (de la idea del usuario o de las pruebas de docs/SCRIPT.md), cada una con un estado de ánimo y una idea de punto de referencia | una tabla |
| 2 Guion | EPISODE/script.txt (una oración por línea) y EPISODE/SCRIPT.md: opciones A y B, tabla de ritmos, puntuaciones del crítico | el guion |
| 3 Voz | vo.py, words.py, voice_check.py (toma gratuita de Fish), level_voice.py | vo/voice.wav, sus números |
| 4 Diseños | EPISODE/design/episode.py: un fotograma fijo de cada nuevo punto de referencia, utilería, disfraz y personaje; EPISODE/pictures.json y pictures.py para cada pantalla de teléfono y utilería impresa | DESIGN_SHEET.jpg + las pantallas |
| 5 Fotogramas fijos | EPISODE/episode.py con cada plano; check; fotogramas fijos; arreglar; contact_sheet.py | CONTACT_SHEET.jpg |
| 6 Hook | los primeros ~15 s: render_threejs.sh EPISODE 0 F1, señales de sonido, finish.py | el MP4 |
| 7 Video completo | render_threejs.sh EPISODE, sonidos, finish.py (archivo limpio + archivo de música); con aprobación, la toma de voz de pago | ambos MP4 |
Los detalles de las puertas están en docs/PROMPTS.md (el prompt 1 ejecuta todo). Copia examples/ep05-wifi para empezar: es un episodio terminado hecho de esta manera, con su hoja de diseño, 42 planos, imágenes de teléfono, señales y configuración.
Una toma final de pago es una nueva grabación: ejecuta words.py y level_voice.py de nuevo, luego check, y re-renderiza (los planos siguen los tiempos de las palabras). Así que aprueba el ritmo de la toma gratuita en la puerta 3, pero haz la toma de pago antes de la puerta 6 si el usuario quiere publicar.
Comandos
# voz (puerta 3)
python3 SKILL/blockworld/vo.py EPISODE # una toma en la voz 'Roblox' de Fish (vo_config.json)
python3 SKILL/blockworld/vo.py EPISODE --post-only # rehacer ajuste / presencia / tempo en la toma guardada, sin nueva llamada
python3 SKILL/blockworld/words.py EPISODE # tiempos de palabras -> vo/times.json
python3 -I SKILL/blockworld/voice_check.py EPISODE # ritmo, pausas, brillo contra los rangos virales
python3 -I SKILL/blockworld/level_voice.py EPISODE # cada oración a un nivel -> vo/voice_level.wav
# imágenes para utilería (puerta 4)
python3 -I SKILL/blockworld/pictures.py EPISODE # EPISODE/pictures.json -> EPISODE/pictures/*.png
# planos (puertas 4-5): Blender, siempre a través de run.py con --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 [plano ...]
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 fotograma fijo numerado por plano -> CONTACT_SHEET.jpg
# fotogramas finales (puertas 6-7): Three.js
bash SKILL/blockworld/render_threejs.sh EPISODE # todos los fotogramas -> EPISODE/frames/ (~10 min para 66 s)
bash SKILL/blockworld/render_threejs.sh EPISODE F0 F1 # solo F0..F1 (el hook, un plano rehecho)
# efectos de sonido (puertas 6-7): ver docs/SOUND.md
python3 -I SKILL/blockworld/sfx_gen.py --credits # créditos restantes de ElevenLabs
python3 -I SKILL/blockworld/sfx_gen.py el-tag-pop ep07-... # generar sonidos nombrados desde sfx/ELEVENLABS_LIST.md
python3 -I SKILL/blockworld/cues.py EPISODE cues_spec.json # señales por palabra ('decir': 'se congeló') -> EPISODE/cues.json
# finalización (puertas 6-7)
python3 -I SKILL/blockworld/finish.py EPISODE # subtítulos + voz + efectos (+ música) -> los MP4
checkno renderiza nada: ejecuta cada plano, imprime la tabla de planos y advierte sobre planos de más de 2.5 s.- Verificaciones automáticas de fotogramas fijos (
blockworld/stillcheck.py, desde ep08): llama afocus(personaje, etiqueta, ...)en cada plano.checkystillsluego informan caras bloqueadas (por un poste, una persona, una etiqueta o el propio brazo del personaje), caras debajo de la banda de subtítulos, etiquetas fuera del área segura (x 5-85 %, entre la barra superior de TikTok y los subtítulos), etiquetas que se tapan entre sí, y cualquier cosa a menos de 1 unidad del lente. Los resultados van aEPISODE/still_check.txt. Arregla cada línea antes de mostrar los fotogramas fijos, y luego aún míralos: no juzga el encuadre ni si la imagen cuenta la línea. - 60 fps con desenfoque de movimiento (opcional):
finish.json"render_fps": 240, "blur": 4renderiza 240 fotogramas por segundo y promedia cada 4 en un fotograma de 60 fps. Aproximadamente 1.6 min de renderizado por segundo de video. - Giro de color (opcional):
finish.json"grade": {"word": 24, "ramp": 0.5, "saturation": 0.6, "brightness": -0.05, "cool": 0.1, "vignette": true}atenúa la imagen más fría, más oscura y más plana desde esa palabra del guion (el giro de la historia). Los subtítulos no se gradúan.finish.py EPISODE --plaintambién escribe<nombre>_plain.mp4(30 fps, sin desenfoque, sin grado) para una comparación lado a lado. - ep08 (
episodes/ep08-price-tags-10s) es la prueba de 10 segundos de esto, con planos de ~1 s. stillsescribe dos imágenes de Blender a medio tamaño por plano (al 30 % y 85 % de su duración) enEPISODE/stills/. UsaBT_LIFE=1para que las etiquetas se coloquen como las coloca el render final. Mira cada fotograma fijo antes de mostrar alguno.render_threejs.shse ejecuta en segundo plano si tus comandos expiran (aproximadamente 10 minutos para 66 s). Instala los dos paquetes npm en el primer uso (blockworld/threejs/) y necesita Chrome o Chromium (CHROME=/rutapara elegir). Guarda su horneado enEPISODE/threejs/; bórralo yframes/después de que el usuario acepte el video.- Después de cualquier cambio en
episode.py, una pieza de escenario o una imagen: vuelve a ejecutarrender_threejs.sh(el horneado lee el código; no se almacena nada en caché entre ejecuciones). render_all.sh(fotogramas de Blender EEVEE) se conserva solo para comparaciones: aproximadamente 3-6 s por fotograma.- El hook:
render_threejs.sh EPISODE 0 F1dondeF1es el fotograma justo antes del primer corte después de ~15 s, luegofinish.py(usa los fotogramas que existen), y renombra el MP4 para que el video completo no lo sobrescriba. - Mira fotogramas en todo el video (al menos uno por plano) y mide la sonoridad antes de darlo por terminado. Si no puedes escuchar, dilo claramente y enumera qué revisaste en su lugar.
Qué va dónde
| Ruta | Qué |
|---|---|
blockworld/town.py | la calle, el reparto, pose(), luz, cámara, build_town(style=...) |
blockworld/roblox.py | el aspecto Roblox: rchar, plástico, estados de ánimo, rule_sign, giant_clock, puddles |
blockworld/rprops.py | utilería lista: etiquetas de barra de señal y fichas de barra voladoras, teléfonos con pantallas reales y una mano, imágenes iluminadas e impresas, mapa de papel doblado, póster, fajín, sombrero de copa, autobús, puerta, viga, paloma, torre Wi-Fi |
blockworld/pictures.py, blockworld/pictures/ | dibuja pantallas de teléfono, pantallas de bloqueo y mapas desde pictures.json; las imágenes predeterminadas del kit |
blockworld/anim.py | ayudantes de temporización de palabras, tarjetas (etiquetas, burbujas), stand, walk, el corredor |
blockworld/life.py | la capa de vida (BT_LIFE=1): movimiento inactivo, cámara, balanceo de escena, ruedas giratorias, colocación de etiquetas |
blockworld/threejs/ | el renderizador: bake.py (lado Blender), scene.html + capture.mjs (lado Three.js) |
blockworld/render_threejs.sh | hornear + dibujar, la forma normal de hacer fotogramas finales |
blockworld/vo.py, words.py, voice_check.py, level_voice.py | voz, tiempos de palabras, verificación de voz, nivelación |
blockworld/sfx_gen.py, sfx/ELEVENLABS_LIST.md | efectos de sonido ElevenLabs: el generador y la lista de prompts |
blockworld/finish.py | subtítulos, voz, efectos de sonido (también bucles de fondo), música, la mezcla estable, los MP4 |
blockworld/cues.py | listas de señales por palabra -> cues.json |
sfx/ | efectos de sonido: el conjunto Pixabay (sfx/CREDITS.md); los sonidos de ElevenLabs llegan aquí como el-*.mp3 / epNN-*.mp3 una vez generados (ninguno todavía hasta ep05) |
examples/ep05-wifi | el episodio completo desarrollado (aspecto Roblox, renderizador Three.js) |
examples/ep00-roblox-look, examples/ep01-intro | demos cortos del aspecto Roblox y el aspecto bloque |