Corto animado: idea → guion → voz → MP4 terminado
El estilo: personajes planos en 2D tipo "cabeza de frijol" (dibujados a mano como "tarjetas" con contornos de ciruela) en un mundo 3D colorido con contornos de tinta negra, texturas pintadas, profundidad de campo y cámaras deslizantes. La salida es 1080x1920, 30 fps, exactamente tan larga como la pista de voz. La voz del usuario no se modifica. La música de fondo y los efectos de sonido se sintetizan y se sitúan al 50% del nivel de voz. Probado en "El Soldado Que Nunca Se Fue" (19.7 s, 8 tomas).
Reglas
- Las historias, personajes y tomas siempre son originales. Nunca recrees el video de otro creador toma por toma. Ofrece una versión original de la misma idea.
- No uses personas reales y nombradas como personajes, ni mascotas de marca o logotipos.
- Sin subtítulos a menos que el usuario lo pida. El texto diegético (un mensaje tallado, un cartel) está bien, y debe leerse correctamente (no reflejado).
- Nunca edites o reajustes la voz. La imagen se sincroniza con ella, y cada reacción visual cae entre 0 y 3 fotogramas antes de su palabra.
- Niveles de audio: la música de fondo se sitúa al 50% del nivel de voz (−6 dB, RMS con puerta). Los SFX se sitúan al 50% o ligeramente menos, con picos limitados para que ningún golpe sobresalga de la narración. Siempre mezcla con
mix.py, nunca a mano. No uses ducking o compresión que cambie esta proporción; solo una ganancia lineal más un limitador de picos en toda la mezcla. - Mantén informado al usuario con una lista de tareas. Envía una hoja de contactos de fotogramas fijos antes de la renderización larga.
Etapa 1: Recepción (siempre primero)
Si ya hay un archivo de audio adjunto, salta a la Etapa 4. Si también se dio un guion, úsalo para la sincronización. De lo contrario, haz una pregunta (AskUserQuestion o texto plano si esa herramienta no está disponible): "¿Desde dónde empiezas?"
- Voz lista: pídele que la suba, junto con el texto del guion si lo tiene (el guion hace que la sincronización sea exacta). Ve a la Etapa 4 cuando llegue.
- Tengo un guion, necesito la voz: ajusta el guion según la Etapa 3 si es necesario, devuélvelo con consejos de grabación, pide la subida y luego ve a la Etapa 4.
- Necesito ideas de video y un guion: ve a la Etapa 2. También pregunta la duración objetivo si no la han dicho. El valor predeterminado es 20-30 s; se permite 45-60 s.
Etapa 2: 10 ideas de video
Da exactamente 10 ideas en una sola respuesta, numeradas, y pide al usuario que responda con un número (o "más"). Cada idea incluye:
- Título (5-8 palabras, que generen curiosidad, ej. "El Soldado Que Nunca Se Fue").
- Frase gancho: la primera oración hablada, una paradoja presentada como hecho ("Un hombre vendió la Torre Eiffel. Dos veces.").
- El giro en una línea (la recompensa irónica que termina el video).
- Por qué se anima bien: los 2-3 grandes momentos visuales (un colapso, una revelación, una persecución).
- Verdad o leyenda: di claramente si es historia documentada, un relato disputado o folclore.
Lo que hace que una idea sea "perfecta" para este formato:
- Una historia sorprendente con una causa y efecto físicos que se puedan mostrar.
- Un personaje común claro, apuestas que escalan y un giro en la última línea.
- Un escenario que se pueda construir con formas 3D simples más tarjetas de dibujos animados (pueblos, puentes, barcos, castillos, desiertos, laboratorios, palacios).
- Mezcla las 10 entre épocas y temas: antiguo, medieval, 1800s, moderno, ciencia, animales, inventos, desastres, leyes extrañas, accidentes afortunados.
- Para cualquier cosa presentada como verdadera, verifica los hechos clave con una búsqueda web antes de ofrecerla. No presentes una leyenda viral como hecho. Si el usuario la quiere de todas formas, enmárcala como "la leyenda dice".
- Sin personas reales vivas como blanco de una broma, nada gráfico y nada político.
Etapa 3: Guion (después de que elijan)
Escribe solo la narración (sin acotaciones en el texto hablado), a un ritmo de aproximadamente 3.7 palabras/s: 20 s ≈ 75 palabras, 30 s ≈ 110, 60 s ≈ 220. Fórmula:
- Gancho (oración 1, sin introducción): el hecho absurdo.
- Escenario en 1-2 líneas: cuándo, dónde, quién, un detalle concreto.
- Escalada, 2-4 golpes, cada uno más grande. Otros dudan o se burlan. Usa una broma de exageración.
- Misterio o giro: "Pero cuando..." / "Verás," introduce el mecanismo real, a menudo con una analogía cotidiana.
- Giro / recompensa: corto, irónico y las últimas palabras del video. Usa inglés hablado sencillo, contracciones, oraciones de 8 a 15 palabras y números escritos como palabras. Nunca describas lo que el espectador ya ve.
Luego responde con:
- El guion en un bloque copiable, con el conteo de palabras y la duración estimada.
- Un plan visual de un párrafo (las tomas que animarás).
- Consejos de grabación: una voz de narrador constante y cálida; ElevenLabs funciona bien (voz de narrador grave, velocidad aprox. 1.05-1.1, estabilidad aprox. 45-55%). Mp3 o wav está bien. Deja pausas naturales al final de las oraciones. Exporta sin música.
- La petición: "Sube la voz cuando esté lista y haré el video completo." Conserva el texto final del guion. Impulsa la sincronización en la Etapa 4, por lo que no se necesita reconocimiento de voz. Si grabaron una versión cambiada, pide el texto final.
Etapa 4: Construir el video (después de subir la voz)
Haz todo desde aquí sin parar. Pregunta solo si la sincronización no se puede resolver.
4.0 Obtener el kit
El kit de código viene dentro de esta carpeta de habilidad en kit/ (motor, herramientas, ejemplo práctico, además de three.js r160 incluido y la librería toon.ts Pen de github.com/mromidev/claude-animated-shorts, ambos MIT). Localiza la carpeta con find / -name SKILL.md -path "*cartoon-audio-short*" 2>/dev/null y trata su kit/ como solo lectura.
Luego ejecuta bash <skill>/kit/tools/setup.sh ~/shorts/<slug>. Copia el motor y las herramientas en el proyecto, instala el three.js incluido, elimina los tipos de toon.ts con Node 22 module.stripTypeScriptTypes, y enlaza Playwright. No se necesita red. Si faltan los archivos incluidos, recurre a npm o un clon de git.
- Requisitos: Node 22.6+, Python 3 con numpy + Pillow, ffmpeg y Playwright con Chromium (
npm i -g playwright && npx playwright install chromiumsi falta). - Si los registros de paquetes están bloqueados, git a través de GitHub suele funcionar. Nunca deshabilites TLS ni evites el proxy.
- Chromium: usa el navegador de Playwright preinstalado con
--use-angle=swiftshader --enable-unsafe-swiftshader --ignore-gpu-blocklist. Eso da WebGL por CPU a aproximadamente 3-10 s por fotograma.
4.1 Sincronización
Ejecuta python3 timing.py voice.mp3 script.txt --out work.
- Con whisper o faster-whisper instalados, usa marcas de tiempo de palabras.
- De lo contrario, alinea frases del guion (divididas por puntuación) con segmentos de voz detectados por silencio, con un DP que empareja sílabas con duración y penaliza finales de oración dentro de un segmento y pausas largas dentro de una frase.
- Sin ASR y sin guion, pide el guion. Claude no puede oír audio.
- Verifica
work/phrases.json: las pausas deben caer al final de las oraciones. Fotogramas totales = round(duración × 30).
4.2 Plan de tomas (work/PLAN.md antes del código)
Haz una fila por toma: fotogramas, palabras, escenario, luz, movimiento de cámara, personajes/poses/expresiones, efectos y señal de SFX.
- El fotograma 0 ya es la imagen de gancho.
- Generalmente una toma por frase. Fusiona frases muy pequeñas en la siguiente toma.
- Ilustra cada oración literalmente. Los accesorios llevan las bromas.
- Varía los tamaños de toma: gancho MCU → revelación amplia → plano de dos → inserto de primer plano en el objeto clave → primer plano de reacción → movimiento de entorno para la recompensa.
- Usa la luz para los golpes: día para normal, dorado para declive o drama, azul noche para explicación. Un salto temporal obtiene un destello blanco de 6 fotogramas.
- La línea de giro obtiene un stinger (la música se detiene, golpe bajo, zoom-in con balanceo). La recompensa física de la última toma cae en la palabra final.
4.3 Mundo (web/main.js)
Mantén las secciones del motor: materiales toon, contracto de tinta, add/tbox, cielo, luces, tarjetas, objetivos de render/post, applyLight, drawActors, swapForNd, renderFrame. Reemplaza el mundo de ejemplo entre // ---------- world ---------- y // ---------- cards ----------, más las partes de la historia de worldState().
- Construye a partir de primitivas con texturas de lienzo pintadas (
paint.js: tablones, vigas, madera podrida, piedra, musgo/hiedra, hierba, tierra, yeso, tejas, mármol, pancartas, texto tallado). Escribe nuevos pintores en el mismo estilo plano con costuras oscuras. - Usa
tboxpara densidad de texel constante, un degradado toon de 2 pasos y niebla = color del horizonte. - Fondo: colinas (esferas medio enterradas), montañas (conos + tapas de nieve), cipreses/pinos, casas lejanas, carteles de nubes pintadas.
- Los elementos de escenario (colapsos, caídas, puertas) son grupos pivotados impulsados por progreso 0..1 desde
worldAt(f), con partes suavizadas y escalonadas. - El texto diegético curvo usa UVs planares. Verifica que no esté reflejado.
4.4 Reparto (web/roman.js → web/toon.js)
romanFront(p, outfitKey, opts)dibuja en un lienzo de diseño de 600x1000 con suelas en y=975. La tarjeta mide 2.25 m de alto, por lo que 1 unidad = 0.00225 m.- Añade atuendos a
OUTFITS(túnica/capa/armadura/casco/pelo/gorro/barba/delantal/vestido/toga) y nuevos sombreros y accesorios en el mismo estilo. - Poses de brazo: colgar, lanza, señalar, arriba, saludar, cadera, vientre, sien (+remolino), levantar, alcanzar (+levantar), mejilla, escudo, cruzar, pulgar.
- Expresiones: el conjunto FACE de toon.ts más ronquido, terco, entrecerrar. Extiende FACE para más.
- Reconstruye después de ediciones con
cat web/toonbase.js web/roman.js > web/toon.js. Renderiza una hoja de prueba de personajes antes de usar nuevos diseños. - Los carteles giran solo en guiñada, obtienen una mancha de contacto y una sombra probada alfa, y nunca son entintados por el pase mundial.
- Construye claves de tarjeta a partir de valores redondeados con
q()(para que el lienzo se redibuje solo en cambios visibles). - Una parte separada (p. ej., un casco levantado) es su propia tarjeta, alineada con
headCenter(seed): y = DECK + (partY − hc) × 0.00225.
4.5 Movimiento: suave y vivo (web/motion.js)
- Cámaras:
camFromKeys(keys, f, {kicks}). Usa deslizamientos smootherstep (18-45 f),easeOutpara revelaciones y latigazos, ypathvía puntos (Catmull-Rom) para movimientos curvos. Cada espera se mueve y nada está estático durante 4+ fotogramas. Usa 3-5° de balanceo en drama y sacudidas de 7 fotogramas en impactos. - Continuidad: prefiere movimientos continuos (retrocede desde un primer plano hacia el plano general, reenfoca, grúa a través de la cubierta, empuja hacia un objeto). Corte duro solo en saltos de lugar o tiempo, con un destello.
- Los personajes nunca se congelan: aplica
idle(f, seed)a cada tarjeta,blinkAtparpadeos y movimientos de cabeza en palabras estresadas. - Acciones: anticipación →
backsobreimpulso →springasentamiento. Un pisada es un chapuzón de 2 fotogramas + soplo de polvo + patada. Las risas son un balanceo alternado + movimiento. - Movimiento secundario: ondas de tela de pancarta, hojas/polvo/gotas/efectos Zzz, agua fluyendo. Algo siempre se mueve.
- Caminatas:
walk()da distancia + fase de paso. Pies plantados, balanceo 3-7%. - Lente: DOF en primeros planos y medios (cInf 8-14 px), enfoque en los ojos. Los planos generales son nítidos. Los reenfoques toman ~14 f.
4.6 Verificación de aspecto (antes de la renderización completa)
Renderiza fotogramas fijos en la mitad de cada toma más las transiciones y acciones clave: node render.mjs stills/a "5,40,..." luego python3 sheet.py stills/a stills/sheet_a.jpg. Mira la hoja y corrige estas trampas:
- Marco vertical estrecho: ancho horizontal medio = d·tan(hfov/2), con hfov = 2·atan(tan(vfov/2)·0.5625). A 4 m y fov 40 eso es ±0.8 m, así que coloca personajes en profundidad.
- Barandillas o postes a través de las caras (cámara dentro de la barandilla o ~2.5 m arriba). El camino de la cámara a través de casas, techos o arbustos. Accesorios en primer plano a menos de ~2 m. El héroe escondido detrás de un pilar.
- Texto reflejado. Una tarjeta de parte separada desplazada en la dirección equivocada.
- Materiales de extrusión: 0 = tapas, 1 = lados + parte superior.
- Tinta faltante: depura la salida de solo bordes. Radio de tinta ~2.5 px a 1080. El cielo cuenta como profundidad lejana, no una tarjeta. Envía la hoja al usuario con un resumen de una línea por toma, luego comienza la renderización completa.
4.7 Sonido (audio.py → pistas → mix.py)
Reescribe la tabla de señales para la historia; los sintetizadores se quedan. audio.py escribe solo pistas (music.wav, sfx.wav).
- Música: un bucle corto tipo marcha (bombo/caja, bajo pulsado, colchón de metal). Se detiene en la línea de giro, luego un zumbido bajo continúa.
- SFX en eventos (en fotogramas/30): whooshes en movimientos grandes, golpes en pisadas, retumbo + choque en colapsos, raspado en metal, campanilla en revelaciones, stinger en el giro, chirridos, chasquidos, chapoteo, ronquidos, hojas, ambiente de agua.
- Mezcla con
python3 mix.py voice.mp3 music.wav sfx.wav. Establece la música exactamente al 50% del RMS con puerta de la voz (−6 dB) y SFX al 50% con picos limitados a 0.7× el pico de la voz. Imprime los niveles medidos: confirma que la música muestra −6.0 dB vs voz y SFX está en o por debajo de eso. - Bloquea la sincronización de la imagen antes de hacer el sonido. Cualquier cambio de sincronización significa volver a ejecutar audio.py y mix.py.
4.8 Renderización + finalización
- Ejecuta
node render.mjs frames "0-<N-1>"con Bashrun_in_background, supervisado por un bucle Monitor que informa progreso y detecta errores o finalización del proceso.RESUME=1continúa después de una interrupción. No ejecutes Python pesado al mismo tiempo en máquinas pequeñas. - Ejecuta
bash finish.sh "Título". Aplica una ganancia lineal a aproximadamente −14 LUFS más un limitador de pico de −1 dBFS, codifica H.264 CRF 17 + AAC, ejecuta QA de congelación/negro y sonoridad, y escribeout/qa_sheet.jpg. Mira la hoja. Los tramos congelados ≥0.4 s o fotogramas negros necesitan una corrección. - Entrega el MP4 con SendUserFile y algunas líneas sobre lo que muestra cada toma. Ofrece subtítulos, ajustes o la siguiente idea de la lista.
Trampas del motor (guardadas en el kit; mantenlas si lo reconstruyes)
#include <fog_vertex>/<fog_fragment>van en sus propias líneas.- El pase final escribe
linearToOutputTexel(...)(los objetivos de render son HalfFloat lineales). - El pase de normal+profundidad intercambia materiales por malla: mundo → normal/profundidad, tarjetas → máscara probada alfa (rgb 0, a = profundidad), manchas/nubes/cielo ocultos, agua → normal plana. La niebla y las sombras están apagadas durante este.
- La tinta va solo en el lado cercano de saltos de profundidad. Las arrugas vienen del producto punto de la normal. Los vecinos de tarjeta se omiten. La tinta se desvanece a ~140-520 m.
- DOF: 48 muestras con una prueba de CoC por muestra (sin sangrado de primer plano).
- El sol viene de az/el por preajuste de luz. La cámara de sombra se centra en la acción de cada toma.
Arquitectura (referencia para editar el kit)
web/index.htmlcargamain.js(módulo ES) a través de un servidor HTTP local.main.js: renderizador, materiales toon, mundo, tarjetas (planos de CanvasTexture de 1200x2000, origen en las suelas), pases de color (RT muestras 4) → normal/profundidad → tinta+gradación (saturación, ganancia/lift...)