¿Qué hace Animate?
Crear vídeos animados cortos en código: un <canvas>, dibujado y musicalizado proceduralmente, determinista fotograma a fotograma, renderizado con un navegador headless y ffmpeg. La historia sigue una gramática estudiada de animación corta de alta calidad; el aspecto es un estilo —un kit enchufable elegido de styles/ o creado a partir de las referencias del usuario con new-style.md.
Requisitos: Node 18+, Playwright con Chromium (npm i -g playwright && npx playwright install chromium), ffmpeg en PATH. Verifícalos primero; si falta alguno, dile al usuario el comando de instalación y detente. Para voz en off, Python con faster-whisper (pip install faster-whisper) temporiza cada palabra; sin él, los tiempos de palabra se estiman.
Todas las rutas a continuación son relativas al directorio base de esta habilidad. Las piezas viven en el proyecto del usuario en pieces/<nombre>/ (crea pieces/ si es necesario); los estilos que el usuario crea viven en <proyecto>/styles/<nombre>/.
Innegociables
- No animar antes de que el storyboard esté aprobado. Los puntos de control existen porque una historia o apariencia incorrecta cuesta una reconstrucción completa.
- Mirar las referencias antes de dibujar nada —las del usuario, o el
sample.pngy demo del estilo. Luego verificar cada fotograma clave contra grammar/FRAME.md y la lista de verificación del estilo en suSTYLE.md. - Toda afirmación factual en pantalla se verifica con una búsqueda web y se lista con su fuente en el brief. Nunca afirmar "primero" sin una fuente.
- Archivo único, todo en código: un solo
index.html; todo se dibuja y sintetiza en código — sin archivos de imagen/audio/video, sin URIsdata:, sin URLs, sin fuentes web en el código.tools/build.mjslo impone. Dos excepciones opcionales, ambas propias del usuario: activos (capturas de pantalla y logotipos en<pieza>/assets/, incrustados por la compilación) y una pista musical (unida al exportar). Ver Activos y Música a continuación. - Determinista: solo aleatoriedad con semilla (
RNG(...)), el índice de ebulliciónBpara variación por paso. NuncaMath.random()ni tiempo de reloj. - El material de referencia se queda local. Nunca lo subas, copies su código o nombres a su artista en la salida publicada a menos que el usuario pida acreditarlo.
- "Hecho" se mide:
tools/review.mjspasa y has mirado las hojas de contacto. Reporta los números, no "se ve bien". - Pregunta con opciones. Usa AskUserQuestion con una opción recomendada por defecto, para que el usuario pueda responder con un clic.
El flujo
0. Toma de datos
Haz las preguntas de intake.md —solo aquellas que no puedas inferir. Para el aspecto, construye la galería (node tools/gallery.mjs <out.png> [<project>/styles], ~3s), muéstrala y pregunta: ¿cuál de estos, o muéstrame una referencia? Luego estudia las referencias tú mismo contra FRAME.md y la lista de verificación del estilo.
1. Verificación de historia (texto, rápido)
Elige el formato de grammar/FORMATS.md —el motor de la trama lo decide (una historia es una cronología unida por morphs; una misión corta al ritmo; una lista es un catálogo). Lee grammar/STORY.md. Verifica los hechos en la web. Luego muestra al usuario:
- la idea en una línea y el dispositivo narrativo ("la chispa gana un rayo cada era y termina siendo la respuesta")
- el formato y por qué, el estilo, la duración, BPM
- una tabla numerada de tiempos: tiempo, qué sucede, el puente hacia el siguiente tiempo, el papel del sonido (dónde está el silencio, dónde está el golpe más fuerte)
Pregunta: aprobar / cambiar tiempos / ángulo diferente. Revisa hasta que esté aprobado. Aquí es donde "Quería decir X, no Y" se detecta a bajo costo.
2. Verificación de apariencia (2–4 fotogramas de estilo)
Inicia la pieza en pieces/<nombre>/: copia piece.json y src/ de la demo del estilo (styles/<nombre>/demo/) —ya habla el kit del estilo y une eras con un morph— o de templates/beat-cut/ para una pieza que corta fuerte al ritmo (corcheas, una ráfaga de semicorcheas en fotogramas impares, una era por toma, encuadres desde cámaras), o templates/piece/ para el morph de papel recortado más simple. Establece "style" en piece.json, luego escribe brief.md y LOG.md desde cero (los de la plantilla son marcadores de posición).
- Un estilo incluido: lee su
STYLE.mdy demo y dibuja con su kit. - Las referencias del usuario: sigue new-style.md. Mide las referencias primero (
tools/measure/refs.mjs); los propios fotogramas de estilo de la pieza son los fotogramas emparejados, así que esto es una verificación: las hojas de comparación y los fotogramas juntos. Guarda la carpeta del estilo después de que la pieza esté aprobada (la pieza se convierte en su "probada en").
Dibuja 2–4 de los tiempos más diferentes como fotogramas a tamaño completo. Cada uno debe pasar FRAME.md y la lista de verificación del estilo. Renderízalos lado a lado con node tools/still.mjs pieces/<nombre> 2.25,9.75,16.5 look.png --scale 0.5 (o tools/storyboard.mjs con TIMELINE.board configurado para esos tiempos), y muestra la imagen. Pregunta: pulgar arriba por fotograma / cambiar el aspecto / probar otro estilo.
3. Verificación de storyboard (cada tiempo)
Dibuja cada tiempo con el aspecto aprobado. Llena TIMELINE.board con un tiempo clave por cada tiempo ({ t, title, sound, next }) y renderiza el tablero. Pide pulgar arriba/abajo por número de panel y notas; redibuja lo que esté abajo; repite. Los paneles son las propias funciones de escena del vídeo, por lo que no se redibuja nada después.
4. Construcción
- Escribe
pieces/<nombre>/brief.md(especificación, estilo, tiempos, puentes, plan de sonido, afirmaciones + fuentes). Mantén unLOG.md. - Anima las escenas: acciones temporizadas con
TT,ev(t, d),popS(t), escrituras progresivas (ver craft.md → Movimiento). Conecta eras, cámaras y puentes ensrc/bridges.js(formatos unidos por morph) o dejaBRIDGES = []para cortes directos. node tools/build.mjs pieces/<nombre>→index.html(el kit del estilo se incorpora desde"style"enpiece.json).- Prueba mosaicos mientras construyes:
node tools/tile.mjs pieces/<nombre> tile.png <fotogramas...>—míralos; haz mosaicos en cada morph y corte. - Musicaliza en
src/score.js(ver craft.md → Sonido). node tools/export.mjs pieces/<nombre> --share→ fotogramas,audio.wav, pistas,renders/final.mp4,renders/share.mp4(--formats 9:16,1:1,16:9para cada formato;--blur 4para desenfoque de movimiento en estilos de 1s). Itera la mezcla con--only-audio(re-renderiza la partitura y la remultiplexa, ~4× más rápido).node tools/review.mjs pieces/<nombre>→ hojas de contacto por toma, cuadrícula de cortes, cuadrícula de morphs, arco narrativo, ancla, texto (cortado / superpuesto / debajo de la interfaz del teléfono) y sonido (el momento más fuerte, el silencio antes, LUFS). Arregla hasta que pase, mira las hojas, escribe una tabla de APROBADO por toma enLOG.md. Confía en la verificación de texto sobre tu ojo: una etiqueta recortada se ve bien en una hoja de contacto.
5. Entrega
Envía renders/share.mp4. Di en pocas líneas: qué es, los números de las verificaciones, qué detectó y arregló la revisión, la toma más débil y qué no has verificado (por ejemplo, no puedes escuchar la partitura). Pregunta qué debería cambiar: historia, apariencia, transiciones, ritmo, sonido.
6. Aprendizaje
Después de cada ejecución, añade al final de LOG.md de la pieza. Si algo nuevo salió mal o funcionó, propón una regla de una línea para craft.md, el STYLE.md del estilo o un cambio de kit, y agrégala cuando el usuario esté de acuerdo.
Voz en off (opcional)
Pregunta en la toma de datos (pregunta 3). Con voz, la voz es el reloj: cada tiempo comienza ~0.3s después de que termina la oración anterior, y los momentos importantes caen en palabras habladas. El guion es el storyboard: una línea por tiempo.
- Escribe el guion en
pieces/<nombre>/voice/script.json:{ "lead": 1.2, "tail": 1.8, "lines": [{ "id": "open", "text": "Tal como se habla.", "after": 0.45 }, ...] }. Escribe los números y nombres como deben decirse. Mantenlo ≤ 3.5 palabras/s; da a una línea unaftermás largo donde la imagen necesite tiempo para asentarse (un conteo, un pie de foto, el silencio antes de la revelación). - Construir antes de que exista la voz:
node tools/voice.mjs pieces/<nombre> --scratchcrea una voz de temporización con el habla nativa del sistema operativo (nunca la envíes), para que toda la pieza pueda ser animada y revisada. - Las tomas: un archivo por línea, guardado como
voice/<id>.mp3con"file"establecido en la línea.- El conector de ElevenLabs (si el usuario lo tiene: Configuración de Claude → Conectores → ElevenLabs, iniciado sesión con OAuth, sin clave API): encuentra 2–3 narradores que encajen con su búsqueda de voz, genera una línea en cada uno (una variación cada uno, no cuatro), deja que el usuario elija, luego genera cada línea una vez con esa voz y modelo. El resultado de la generación da un enlace de descarga efímero por toma: guarda cada una en
voice/. Cuesta aproximadamente un crédito por carácter; di el total antes de la ejecución completa. Si el conector se agregó durante la sesión, sus herramientas pueden aparecer solo después de reiniciar la aplicación. - La grabación propia del usuario, un archivo por línea (o cortado de una toma).
- Nunca obtengas una voz de un sitio al que el usuario no haya señalado, y nunca clones una voz sin el consentimiento de su dueño.
- El conector de ElevenLabs (si el usuario lo tiene: Configuración de Claude → Conectores → ElevenLabs, iniciado sesión con OAuth, sin clave API): encuentra 2–3 narradores que encajen con su búsqueda de voz, genera una línea en cada uno (una variación cada uno, no cuatro), deja que el usuario elija, luego genera cada línea una vez con esa voz y modelo. El resultado de la generación da un enlace de descarga efímero por toma: guarda cada una en
node tools/voice.mjs pieces/<nombre>→voice/voice.wav(las líneas con sus pausas) yvoice.json(el inicio y fin de cada línea y palabra, oído en el audio por faster-whisper, localmente). La compilación lo inyecta comoVOICE.- En la cabecera:
VL(id)es una línea,VW(id, word, n)cuando comienza su n-ésimaword; los tiempos comienzan ent1 + 0.3de la línea anterior;TIMELINE.narrationproviene deVOICE.linesyDURATIONdeVOICE.duration. Señala escrituras y destellos en las palabras que los nombran. Pon el golpe de la recompensa en una pausa antes de la línea que lo nombra: un golpe bajo el habla se atenúa. piece.json:"voice": { "file": "voice/voice.wav", "music": -12 }. La exportación mezcla la voz sobre la partitura (la partitura amusicdB, atenuada aún más mientras la voz habla) a −14 LUFS. La revisión juzga el arco narrativo y la ventana de recompensa solo con la partitura (renders/audio-score.wav; una voz es más fuerte que cualquier golpe) y la voz con su verificación NARRATION.- Re-tomas y ediciones de guion: reemplaza el archivo de una línea (o edita su texto), vuelve a ejecutar voice.mjs, reconstruye: las escenas señaladas desde
VOICEse mueven con ella. Una palabra cambiada puede huérfana una señal que apunte a ella; verifica esos tiempos.
Música: pista propia del usuario (opcional)
Pregunta en la toma de datos (pregunta 6). Sin pista, la partitura se compone en código sobre una cuadrícula de 120 BPM. Con una:
- Colócala en la pieza:
pieces/<nombre>/audio/track.wav(WAV, MP3 o M4A), y enpiece.json:"music": { "file": "audio/track.wav", "start": 12.0, "gain": 0, "fade": 0.5 }(start= dónde en la canción comienza la pieza). node tools/beats.mjs pieces/<nombre>/audio/track.wav pieces/<nombre> --start 12 --dur <duración pieza>→beats.json: el tempo, el primer pulso, cada pulso y compás, los golpes más fuertes, el momento más fuerte y las caídas. Pasa--bpm 128si el usuario sabe el tempo; de lo contrario, verifica su línea de "otros tempos" (el doble / mitad / dos tercios del tiempo es el error habitual).- La compilación lo inyecta como
BEATS; la cabecera inicial leeBPMyGRID0de él, yonBeat(t)ajusta un tiempo a la cuadrícula de corcheas de la canción. Coloca cortes, morphs y señales enonBeat(...). La canción decide el arco: pon el giro en una caída (BEATS.quiet) y la recompensa en su golpe más fuerte (BEATS.loudest,BEATS.hits), no donde una partitura compuesta los habría puesto. - La partitura (
src/score.js) solo conserva efectos de sonido (to = 's'): la exportación reemplaza el bus de música con la pista, mezcla la pista de efectos encima y normaliza a −14 LUFS. La cuadrícula de revisión usaTIMELINE.gridOffset; su sección SOUND dice si el momento más fuerte cae en el acto de recompensa. - La vista previa del navegador aún reproduce la partitura compuesta (sin archivos de audio en la página); la exportación tiene la pista.
Activos: capturas de pantalla y logotipos reales (opcional)
Pregunta en la toma de datos (pregunta 7) cuando el tema es un producto. Entonces:
node tools/capture.mjs <url> pieces/<nombre>/assets/home.png [--selector "css"] [--full] [--dark] [--hide "css"]captura la pantalla del propio sitio del usuario (una página, una sección, el logotipo). Pregunta antes de capturar algo que no posean. Los archivos de logotipo que te den también van enassets/(PNG, SVG, JPG, WEBP).tools/build.mjsincrusta todo enassets/dentro deindex.html(la pieza sigue siendo un archivo, y el lienzo sigue siendo legible por las verificaciones);window.renderFrameaparece una vez que las imágenes están decodificadas, y todas las herramientas esperan por ello.- Dibújalas con
drawAsset('home.png', x, y, w, h, { fit: 'cover' | 'contain', r })dentro del propio encuadre del estilo (una foto de papel rasgado, un marco entintado, una tarjeta impresa) para que pertenezcan al aspecto.asset(name)devuelve la imagen. - Solo interfaz de producto real: anima las pantallas reales (recorta, acerca, revela, apunta a ellas con el héroe); nunca dibujes una pantalla falsa como si fuera el producto. Muestra colores de marca de muestra de las capturas.
Formatos: una pieza, varias formas (opcional)
Pregunta en la toma de datos (pregunta 2, selección múltiple). Lista en piece.json "formats": ["9:16", "1:1", "16:9"] (el primero es el principal). La cabecera inicial lee ?format= y establece W, H, SAFE y CX; las escenas colocan objetos con LX(fraction), LY(fraction) y los dimensionan con UNIT, y eligen una disposición diferente con PORTRAIT / WIDE donde una forma lo necesite (una columna de tres en 9:16, una fila de tres en 16:9). Nunca recortes un render de 9:16 a 16:9.
node tools/export.mjs pieces/<nombre> --formats 9:16,1:1,16:9 --share→renders/final.mp4(principal) yfinal-<ancho>x<alto>.mp4para los demás.- Revisa cada uno:
node tools/review.mjs pieces/<nombre> --format 16:9(ytile/still/textcheck/storyboardtambién aceptan--format). La verificación de texto es la más importante aquí: un título ancho que cabe en 16:9 puede salirse de 9:16.
Movimiento: resortes y desenfoque
- Resortes (
kit/core.js):springMove(t0, a, b, SPRING.snappy)mueve un valor con un pequeño rebasamiento y un asentamiento;springTrack([[t, v], ...])sigue un valor a través de muchos objetivos sin un salto. Ajustes predefinidos:snappy(UI),smooth(tarjetas, cámara),heavy(tipografía grande, logotipos),playful(mascotas). En forma cerrada, por lo que los fotogramas siguen siendo deterministas. Los estilos a 2 fotogramas los escalonan cada 2 fotogramas, como deben. - Desenfoque de movimiento:
export.mjs --blur 4promedia 4 sub-fotogramas por fotograma — solo para estilos a 1s (STYLE.ones: matemáticas, isométrico); los looks dibujados a mano a 2s son nítidos a propósito (export advierte).
Agentes paralelos (piezas largas)
Una pieza de 45–60s tiene 10–15 escenas; divide el trabajo: un agento escribe las funciones de las escenas, otro se asegura de que se adhieran al estilo. Ambos deben pasar FRAME.md. (Lo más simple: asigna 6 escenas cada uno y fusiona con git.)