yt-film: películas narradas a partir de imágenes fijas
Una línea de producción para películas narrativas: el usuario crea ~150 imágenes fijas a partir de una guía que escribe Claude, Claude escribe el guion a partir de esas imágenes, una voz lo lee y el motor Python da vida a cada imagen al ritmo de las palabras. La película de referencia es el ejemplo Chadwick (examples/chadwick/, La hija de Carnegie: la mujer que pidió prestados millones como la hija secreta de Andrew Carnegie): sus imágenes, guion, voz, banda sonora, listas de tomas y el video de prueba de efectos de 70 segundos (examples/chadwick/video/chadwick_effects_test.mp4) muestran cada técnica.
REPO más abajo es la carpeta de este skill (donde está este archivo). PY es su Python: REPO/.venv/bin/python en macOS/Linux, REPO\.venv\Scripts\python.exe en Windows. Ejecuta siempre los comandos del motor con PY, desde la carpeta tools/ del proyecto. Si .venv no existe, configúralo primero: sigue el runbook de instalación (para Claude) en references/install.md paso a paso (pregunta antes de instalar globalmente; el usuario pega su propia clave API).
Reglas básicas
- Nunca renderices sin la aprobación del usuario. Compruébalo con
stills.py(una hoja de contactos en ~30 s). Los renders por lotes, las vistas previas, el final y la unión final toman minutos u horas: di qué vas a renderizar y cuánto tiempo puede llevar, y espera un sí. No vuelvas a renderizar nada que ya esté renderizado a menos que haya cambiado y el usuario lo quiera. - Pregunta las rutas del usuario una vez por proyecto: qué herramienta de imágenes (
references/image-generation.md), voz (Gemini TTS o la suya:references/voice.md), música (Lyria o la suya:references/music.md), su nicho y nombre del canal, y las tres opciones que hacen el canal suyo: el estilo de imagen (el abridor: gouache, editorial plano, negro, tiza, cómic, cuento, plano técnico, o el suyo propio; personajes o ninguno), el aspecto del motor (YTF_LOOK: gouache, clean, noir, chalk, comic, storybook, blueprint;look.jsonpara valores individuales) y el formato (story,explainer,countdown,rise-fall,storytime,kids,summary,case-study,news):references/art-styles.md,references/formats.md. No uses por defecto el estilo pastel de historia real del ejemplo; si el usuario no tiene preferencia, muestra las opciones en una tabla corta y recomienda una que encaje con su nicho. - El nicho del usuario es suyo: no lo dirijas hacia la historia ni hacia el tema del ejemplo. El ejemplo es una referencia de técnicas, no una plantilla de temas.
- Windows: las rutas con barras inclinadas funcionan; los trabajos largos se ejecutan en segundo plano; ajustes de velocidad en
references/performance.md. Nunca asumas herramientas solo de macOS. - Sin claves API en archivos que no sean
.env. Descarga fotos o archivos de sonido reales solo después de la aprobación del usuario (indica el archivo, la fuente, el tamaño y la licencia).
El stack
| Trabajo | Herramienta | Dónde |
|---|---|---|
| Investigación | búsqueda web, lista de hechos verificados con fuentes; marca lo que no se puede confirmar | OUTLINE.md |
| Imágenes | la herramienta de imágenes del usuario, a partir de la guía de Claude | IMAGE_GUIDE.md (+ IMAGE_PROMPTS.jsonl para la API), incoming/ |
| Guion | Claude, escrito a partir de la guía de imágenes, un pasaje ## por beat, notas [SHOTS: …] | SCRIPT.md |
| Voz | Gemini TTS (voz Orus, lee lento → 1.25x, pausas limitadas) o el audio del usuario mediante import_voice.py | tools/voice.py, tools/import_voice.py |
| Temporización de palabras | Whisper: mlx-whisper (Apple Silicon) o faster-whisper (Windows/Intel/Linux) | voice/<batch>_words.json |
| Música | Lyria (API Gemini), una seña por sección, o pistas con licencia del usuario | tools/music.py → audio/music/ |
| Motor de película | Python (OpenCV, Pillow, NumPy, SciPy), sin After Effects | tools/film.py, fx2.py, seq.py, signature.py, wr.py, kit.py |
| Listas de tomas | un archivo por lote en seq.py, sincronizado con los tiempos de palabra del lote | tools/<story>.py + tools/shots_bN.py |
| Renders | en paralelo, adaptados a la máquina, baja prioridad | tools/render_all.py |
| Final | la propia despedida animada del usuario (ejemplo: cta.py) | renders/cta.mp4 |
| Unión final | lotes + final, una banda sonora continua, −14 LUFS / −2 dBTP | tools/final.py |
| Doblajes | español + francés por defecto: traducción Gemini + TTS en fragmentos de ~3 minutos, ajustados a las ranuras en inglés | tools/dub.py |
| Miniaturas | la herramienta de imágenes del usuario, a partir de una guía | references/thumbnails.md |
Los proyectos viven en YTF_WORKSPACE (por defecto ~/yt-film-projects/<story>/), creado por PY REPO/scripts/new_project.py <story>, que copia el motor en tools/ y crea cada carpeta. Los ajustes están en .env (primero el proyecto, luego REPO): GEMINI_API_KEY, YTF_CHANNEL, nombres de voz/modelo, perillas de velocidad (.env.example las lista todas). engine/ytf.py encuentra las fuentes, la clave, Whisper y el arte compartido en cualquier SO.
El orden de trabajo
- Elige la historia si no se da: 3–5 candidatos con comprobaciones de huecos (
references/story-finding.md). Inicia el proyecto con su formato y aspecto:PY REPO/scripts/new_project.py <name> --format <format> --look <look>(escribe la plantilla del formato en OUTLINE.md,YTF_FORMATyYTF_LOOKen.env). Prueba un estilo nuevo en dos imágenes constills.pyantes de escribir la guía completa (references/art-styles.md, última sección). - Historia y hechos: investigación;
OUTLINE.mdcon fuentes. Marca cualquier cosa no confirmada y rodéala más tarde ("presuntamente"), nunca la afirmes como hecho. Decide el gancho (references/hooks.md: nunca del mismo tipo que las tres últimas películas del usuario). Luego escribe la columna vertebral al inicio deOUTLINE.md(references/storytelling.md): una pregunta que responde la película y 8–12 beats unidos por "así que" / "pero"; el primer acto equivocado o momento decisivo hacia el ~15% de la película; uno o dos pasajes de antecedentes por persona principal. Muéstraselo al usuario antes de la guía de imágenes. - Guía de imágenes primero (
references/image-guide.md, escrita para la ruta del usuario). Sigue la columna vertebral y la forma en que se narra la película (muestra, luego dibuja: cada fila del beat nombra la línea a la que sirve y qué se dibuja sobre ella o después). Apunta a ~150 imágenes: tarjeta de estilo, hojas de reparto, ~100 tomas de escena con cobertura (W amplio, M medio, F primer plano de cara como EDIT, D detalle, P punto de vista), 6 escenas con versiones_lines, 12 hojas de bocetos +_lines, ~10 objetos de historia en blanco ("bases": un cuaderno, un mapa antiguo, una tarjeta, un libro de contabilidad, un sobre, un telegrama, un periódico). Nombres de archivo exactos y carpetas. Reglas de consistencia:references/consistency.md. - Revisa las imágenes a medida que llegan los grupos (manos, caras, detalles de época, sin texto, forma: las imágenes llegan ~16:9 y se recortan al centro a 2:1, así que nada importante en la parte superior/inferior). Descargas manuales:
scripts/sort_images.py. Luego hojas cuadriculadas en px del motor (COLS=4 PY tools/egrid.py out.png IMG ...) y mapea las chimeneas, lámparas, velas, respiración y áreas tranquilas de cada imagen antes de escribir las tomas. - Guion a partir de las imágenes. Cada imagen generada se usa; mapea cada pasaje a sus tomas y ejecuta la comprobación de imágenes no usadas (ejemplo:
examples/chadwick/tools/script_check.py), luegoPY tools/story_check.py(fechas habladas, aperturas de cambio de escena, dónde cae el pasaje[DRIVE], cada costura de lote) y las comprobaciones enreferences/storytelling.md(repetición, 15%, pero/por tanto, sin explicaciones apiladas, 5–7 fechas habladas, muestra → dibuja). Sin límite de duración: cuenta la historia completa y sin prisas (~150 palabras por minuto; Chadwick: 1.780 palabras → 12 min). Termina con la línea de me gusta/suscripción del usuario. - Voz: Gemini (
voice.py --testprimero, luego lotes;--paceySPEEDSpara que cada lote esté a ~140–160 ppm) o el audio del usuario (import_voice.py --full | --passages | --batches). EstableceBATCHES(4–7 pasajes, ~65–100 s cada uno, corta a mitad de acto donde la historia se mueve; solo 2–3 cortes en los cambios de acto; nada reintroducido al inicio de un lote) yGAPS. Imprime las palabras de cada lote antes de escribir sus tomas (Whisper oye mal los nombres y escribe los números como dígitos: guíate por lo que escribió). - Música: 5–7 señas (
music.py, o los archivos del usuario enaudio/music/); mapea las señas a los lotes enMUSICdefinal.py. - Listas de tomas por lote con
seq.py(references/engine.md,examples/chadwick/tools/): un módulo de película (<story>.py, comochad.py) contiene la tablaLIVE(las capas vivas de cada imagen) y los ajustes del mapa; cadashots_bN.pytiene ~60 líneas deS.at(time, scene(...)/page(...)/drawin(...)/map_shot(...)). Comprueba cada uno conPY tools/stills.py bNy mira la hoja antes de renderizar nada. - Renders (con la aprobación del usuario):
PY tools/render_all.pyejecuta todos los lotes en paralelo, tantos a la vez como la memoria libre de la máquina permita (aproximadamente 1.5 GB por render; más a la vez es más lento una vez que la memoria se agota); después de correcciones,render_all.py b3 b7o--changed. Lánzalo en su propia ventana para que cerrar Claude no lo detenga, y siguereferences/performance.mdcuando un render sea lento o el ordenador se ralentice (Windows especialmente). Prueba una transición o efecto nuevo en dos fotogramas primero (un fallo tardío desperdicia el render). - Final una vez por canal (
references/cta.md), luego unión finalPY tools/final.py; comprueba duración, fps, volumen en el MP4 (−14 LUFS, pico ≤ −1.5 dB) y fotogramas de muestra (references/final-render.md). - Doblajes (
references/dubs.md) y miniaturas (references/thumbnails.md) si se desea.
El aspecto (el predeterminado del ejemplo; cada canal elige el suyo)
- El ejemplo: personas con cabeza de huevo (cabeza de huevo, dos ojos ovalados oscuros, boca de una línea, sin nariz/orejas/cejas, manos redondeadas simples) en un mundo real históricamente preciso; línea a tinta + gouache pastel mate; aspecto del motor
gouache. Otros canales eligen su propio estilo de imagen, personajes (o ninguno) y aspecto del motor (references/art-styles.md); las reglas a continuación se aplican a cualquier estilo. - El aspecto del motor determina las capas añadidas: grado, grano, viñeta, tinta, papel de etiqueta, acento, fuentes, sonido de dibujo (
engine/look.py:YTF_LOOK,look.json). Nunca codifiques un color o fuente en un archivo de tomas cuando el aspecto tenga uno (look.rgb("accent"),look.L.type_font); el aspecto de un canal debe cambiar en un solo lugar. - Sin 2.5D, sin recortes, sin video IA. Imágenes individuales con movimientos de cámara suaves (acercamientos, paneos, deriva lenta).
- Nunca sostengas una imagen demasiado tiempo: corta a la siguiente toma del momento (W→M→F→D→P) o a una página dibujada.
- Los explicadores de bocetos son dibujos reales, no iconos: extraídos del arte lineal de las hojas o dibujados por el motor donde el código lo hace bien (mapas precisos, rutas, marcas, figuras simples).
- Las bases en blanco se dibujan en vivo en su propio medio: grafito sobre papel, tiza en una pizarra, tinta con pincel, fotos de medios tonos imprimiéndose en un periódico, rutas de tinta en un mapa.
- Las líneas tienen significado: marcas de conteo para años, anillos de sonido, caminos de papel cayendo, líneas de humo, figuras tachadas.
- Las etiquetas (fechas, lugares, nombres) son texto escrito a nivel en la fuente de tipo del aspecto (máquina de escribir en
gouache), escritas una tecla a la vez con un clic suave. - La escritura sobre un objeto se asienta sobre las líneas reales de ese objeto en su ángulo; la impresión ilegible debajo se borra primero (
fx2.clean_text). - Contraste siempre: nada oscuro sobre oscuro. Las etiquetas eligen automáticamente crema/tinta con un halo. Nunca fuerces
color="ink"sin comprobar qué hay debajo. - El sprite de la herramienta es pequeño (escala 0.28) para que nunca robe el foco.
Animación característica (todo en código sobre las imágenes fijas)
engine/signature.py, engine/fx2.py, ayudantes de toma engine/wr.py, engine/seq.py. Una imagen fija de cada uno en examples/chadwick/look/; todas en movimiento en el video de prueba de efectos.
- Imágenes vivas (la imagen nunca se mueve; las capas viven sobre ella): humo de partículas de cada chimenea, respiración en el frío, llamas vivas y la luz que proyectan, las propias lámparas de la imagen encontradas y respirando (
fx2.lamps), nieve, lluvia, hojas cayendo, destellos. Sin distorsión de píxeles (sg.Flow) en humo, vapor, fuego o agua: mancha la pintura (look/flow_smear_avoid.png). - Caras que actúan, solo donde importa: sin parpadeo ni expresiones automáticas. Una cara actúa solo cuando una toma pasa
act=/talk=, y solo una cara con un par de ojos emparejados (sg.face_audit([...], out.jpg): actúa solo donde ambos ojos están rodeados de verde). Señales:blinks,glances,widen,mouth_fx,expr(sonrisa, mueca, ceño, o, risa, ojos cerrados, entrecerrar...),talk=(ta, tb), marcas de reacción (sweat,shake,!,?,zzz). Un puñado de beats reales por lote, nunca decoración. - Páginas de cómic en la pizarra en blanco (
sg.Comic): los bordes se entintan solos, cada viñeta se entinta y luego se pinta, la cámara visita las viñetas y se sumerge en la última. Dos por película (el gancho, el primer gran set piece). Cada viñeta dura ≥ 1.8 s. - Dibujos hechos en vivo (
fx2.Draw): un dibujo en una hoja se entinta en su orden de trazo (sprite de pluma y sonido), luego sus colores se lavan;card=Truepone primero un lavado crema suave en imágenes ocupadas. Una hoja nunca se muestra como una página de cuatro: cada dibujo aparece cuando el narrador lo nombra, unido por flechas y etiquetas cortas escritas. - La tarjeta explicadora (una base reutilizada): nombres escritos y tachados, un mecanismo como una cadena de dibujos con flechas, tres dibujos con tres palabras.
- Vocabulario de marcas, elegido por significado, nunca la misma marca cada vez: subrayado, tilde, cruz, corchete, líneas de movimiento, anillos de sonido, ruta (camino punteado + flecha), líder (punto, línea, etiqueta escrita), tally;
sg.Stamp(estampado de goma con golpe: FALSIFICADO, CERRADO, 14 AÑOS),sg.Tag(etiqueta de papel rasgado),sg.Inset,sg.Flip(tablero de persiana),sg.Pin,fx2.Counter(contador de dinero rodante). - Efectos con peso (unos pocos momentos sentidos por lote):
fx2.Lift(recorta un objeto de la imagen y lo anima,fill_from=clona y rellena el agujero),fx2.Tear(la imagen se rasga en dos), la transición("shatter", s, (cx, cy)),sg.Papers(papeles cayendo), fuego + golpe, sacudida + golpe, destellos de prensa + obturador,sg.Rays,sg.Haze. - El mapa viviente (
seq.map_shot): costas reales se entintan solas, el agua se lava, las fronteras se trazan con guiones, los lagos y pueblos se escriben, una ruta roja de viaje se dibuja con una flecha, los marcadores de eventos caen.