Anuncio de video animado
Construye cada plano de un video de producto como una página HTML pequeña que anima material real del producto (capturas de pantalla, fotogramas de video, datos exportados, números reales), graba cada página en un MP4 limpio y entrega a la persona un documento de guion que le indica exactamente cómo unir los clips y qué decir. La persona une los clips y graba la locución en su propio editor (Camtasia, Premiere, CapCut...).
Por qué esto funciona mejor que grabar la pantalla de la aplicación real: cada plano está encuadrado, ritmado y ampliado para video; nada parpadea, carga o muestra datos privados; el texto es lo suficientemente grande para un teléfono; y un cambio ('haz esa línea más corta', 'zoom más lento') es una edición y una regrabación, no una nueva toma. Sigue pareciendo honesto porque los píxeles y los números son los del producto.
Flujo de trabajo
- Acordar la historia (un mensaje, luego a trabajar).
- Recopilar material real del producto.
- Construir una página por plano desde
assets/. - Verificar páginas con capturas de pantalla, corregir, repetir.
- Grabar clips con
scripts/record.cjs; verificar con hojas de contacto. - Escribir el documento de guion (
references/script-doc.md). - Audio y montaje preliminar: música (ElevenLabs, generada o propia;
references/music.md), una locución opcional de ElevenLabs (references/voiceover.md); vista previa conscripts/roughcut.py. - Enviar los clips, el documento y la vista previa; iterar sobre la retroalimentación plano por plano.
Coloca todo en una carpeta que la persona posea, por ejemplo video/ o video-scripts/:
<nombre>-anim/ páginas (un .html por plano), base.css, logo, subcarpetas frames/
<nombre>-clips/ MP4 grabados: 01-hook-anim.mp4, 02-setup-anim.mp4 ... + README.md
<nombre>-music/ WAV de fondo, vista previa del montaje, cuts.json
<Nombre>.md el documento de guion
1. Historia
Elige la duración (por defecto 30 s; ofrece un corte de 45–60 s a partir de los mismos clips) y el llamado a la acción.
Elige la forma del fotograma según dónde se publicará el anuncio y construye las páginas en ese tamaño (no 16:9 recortado más tarde; recortar pierde texto y la persona tiene que reencuadrar cada plano):
| Ubicación | Tamaño |
|---|---|
| Instagram Reels/Stories, TikTok, YouTube Shorts, Facebook Reels | 1080×1920 (9:16) |
| Feed de Instagram/Facebook | 1080×1350 (4:5) |
| Feed de LinkedIn o X | 1080×1080 (1:1) o 1080×1350 |
| YouTube, sitio web, página de aterrizaje, presentaciones, no especificado | 1920×1080 (16:9) |
Varias ubicaciones: construye para la principal y di en el documento cómo reencuadrar para las demás. Para vertical, mantén el texto fuera de los ~250 px superiores y ~350 px inferiores, donde la plataforma dibuja su propia interfaz de usuario. Luego, esboza 6–9 planos, una idea cada uno, en este arco:
- Enganche (≈3 s): el problema, en palabras del espectador. Una pregunta funciona ('¿Factura impaga después de 30 días? ¿Y ahora qué?').
- Configuración (≈4 s): lo poco que se necesita para empezar.
- Funcionalidades principales (2–3 planos, 4–5 s cada uno): el producto haciendo su trabajo, con el resultado apareciendo en pantalla.
- Prueba (≈3 s): un número real. Grande, simple, verdadero.
- Se adapta a tu flujo de trabajo (≈3 s): exportación, integración, intercambio.
- Tarjeta final (≈3 s): logotipo, promesa de una línea, botón CTA, URL.
Lidera con lo positivo. Muestra lo que el producto hace bien y lo fácil que es. No construyas un plano alrededor de los casos de fallo o soluciones alternativas del producto, ni siquiera uno inteligente; un anuncio que explica cómo la herramienta se las arregla cuando falla se lee como 'a menudo falla'. Una corrección rápida y segura por parte del usuario ('¿categoría incorrecta? haz clic, elige la correcto, listo') está bien; un plano sobre mecánicas de casos límite no lo está.
Si la persona no ha dicho nada, expón tu esquema y suposiciones en un mensaje corto y comienza a construir; es más barato cambiar un plano grabado que debatirlo en abstracto.
En ese mismo mensaje, pregunta sobre el audio (a menos que ya lo hayan dicho) y sigue construyendo mientras deciden; el audio no es necesario hasta el paso 7. Usa la herramienta de preguntas si la hay. Primero verifica si un MCP de ElevenLabs está conectado (herramientas como creative_generate_speech, creative_list_voices, un nodo tipo music); si lo está, lidera con él.
Música:
- ElevenLabs Music (recomendado cuando está conectado): generas una pista instrumental sincronizada con el corte en su cuenta de ElevenLabs. No conectado: escribes el prompt, ellos lo generan en elevenlabs.io/music y te envían el archivo.
- Generarlo aquí: una pista tranquila y libre de regalías hecha por
make_bed.py, gratis e instantánea. - Usar la propia: una pista que ya tienen o tienen licencia.
Locución:
- Voz de ElevenLabs (cuando está conectado): eliges una voz y generas la lectura, luego colocas cada línea en su señal. La persona aún puede grabar la suya propia después.
- Grabarla ellos mismos a partir de la lectura limpia en el documento (la opción predeterminada sin ElevenLabs).
ElevenLabs gasta créditos en su cuenta: primero cotiza (estimate_only) y di el costo en la pregunta. Si pidieron música sin especificar cuál, o llegas al paso 7 sin respuesta, genera la pista gratuita para que la vista previa tenga sonido y repite la pregunta en el mensaje final con el prompt de ElevenLabs ya escrito.
2. Material real
Busca en el repositorio del producto, carpetas de datos, exportaciones, bases de datos, accesorios de prueba y grabaciones. Para cada plano, recopila:
- Imágenes: capturas de pantalla de la interfaz de usuario real, o fotogramas extraídos de video real
(
ffmpeg -ss T -i in.mp4 -frames:v N frames/f%03d.jpg). Varios fotogramas generan movimiento. Para capturar una interfaz web (HTML local o una URL), usascripts/grab.cjs: vista completa más elementos nombrados a 3x, e imprime la caja de cada elemento para el encuadre:node <skill>/scripts/grab.cjs app.html <pages>/shots --size 1280x800 goal=.goal logo='header .logo'. Detrás de un inicio de sesión, pídele a la persona las capturas de pantalla en lugar de iniciar sesión. - Números: valores reales de la salida del producto (tiempos, recuentos, filas). Anota de dónde vino cada uno; va en el documento 'De dónde vienen los números'.
- Posiciones: coordenadas de las cosas a resaltar, en los píxeles de la imagen de origen (de la salida propia de la aplicación cuando sea posible, por ejemplo, cuadros de detección, o medidos al ver la imagen).
Los vacíos son normales; manéjalos abiertamente:
- No hay archivo de logotipo: recórtalo de una captura de pantalla de la interfaz de usuario real (encabezado, icono de la aplicación) o reconsérvelo exactamente a partir del CSS/SVG propio del producto. Dilo en el documento y pide el archivo real.
- Una pantalla necesaria no existe en lo que tienes (por ejemplo, un formulario de configuración): dibújala en el estilo propio del producto y etiqueta el plano como escenificado en el documento para que la persona pueda reemplazarlo con la pantalla real.
Nunca inventes una estadística. Si un momento debe ser escenificado (un enganche dramatizado), etiquétalo en el documento. Respeta la terminología propia del producto y las reglas de reclamos (por ejemplo, un producto que nunca debe llamar a sus números 'garantizados' u 'oficiales') — consulta los documentos/memoria del proyecto para conocer tales reglas antes de escribir el texto.
3. Construir páginas
Copia assets/base.css, assets/shot.js, assets/shot-template.html y assets/end-card.html
en la carpeta de páginas. shot.js contiene los ayudantes que usa cada página (show/hide, cursorTo,
click, typeText, countUp, frameTo, preload) y la reproducción automática; cárgalo antes del script propio de la página y
no copies los ayudantes en las páginas. Cada página:
- Es un escenario fijo en el tamaño elegido: establece
--w/--henbase.css(por ejemplo,1080px/1920px). Las plantillas están diseñadas para 16:9, por lo que reubica las posiciones para otras formas (apila paneles verticalmente para 9:16; en vertical, los títulos comienzan debajo de ~250 px, no en los 96 px de la plantilla). Tamaños de texto ≥ 26 px; títulos 80–100 px. Se verá en un teléfono. - Tiene una función
async function start()de nivel superior que contiene toda la línea de tiempo (await sleep(ms)entre ritmos).shot.jsla expone; con#manualen la URL espera, abierta normalmente se reproduce automáticamente una vez que las fuentes e imágenes están listas, para que la persona pueda obtener una vista previa haciendo doble clic. - Precarga cada imagen que intercambia más tarde (
preload(frames)en el nivel superior) para que nada aparezca en la cámara; el grabador y el verificador esperan por ellas. - Termina en un estado completo y mantenido (resultado mostrado, todo el texto activado) para que el editor pueda recortar en cualquier lugar cerca del final y mantener el último fotograma.
- Dibuja marcas en un
<svg viewBox='0 0 W H' preserveAspectRatio='xMidYMid slice'>dimensionado a la imagen de origen, para que las coordenadas de la aplicación caigan sin conversión y permanezcan alineadas cuando la forma del escenario recorta la imagen. - Se parece al producto: intercambia los tokens en
base.css(--accent,--hi,--ok,--ink, fuentes) por los colores y fuentes propios del producto. Para un producto con tema claro, también invierte el color del texto,.shade,.panely.bga versiones claras; un anuncio oscuro alrededor de una aplicación clara parece de otro producto. - Muestra capturas de pantalla de la interfaz de usuario en su tamaño de píxel nativo dentro de
.world(establece.world { transform-origin:0 0 }y la<img>a su tamaño CSS natural) y las encuadra conframeTo(x, y, scale), que coloca el punto de la captura de pantalla (x, y) en el centro del escenario; los cuadros degrab.cjsproporcionan los puntos. No usesobject-fit:cover, que recorta una captura de pantalla de manera impredecible cuando su forma no coincide con la del escenario. - Mantiene el texto del producto legible: el texto de la interfaz de usuario que termina por debajo de ~22 px en el escenario (una etiqueta de 14 px en una captura de pantalla que no está ampliada) es ilegible en un teléfono. Acércate a él, o reconstruye esa pieza (una tarjeta, una alerta) en el estilo propio del producto con su texto exacto en un tamaño legible, y di en el documento qué piezas fueron reconstruidas.
Patrones de plano que funcionaron:
| Patrón | Cómo |
|---|---|
| Producto en acción | Secuencia de fotogramas intercambiados en <img> cada 33–40 ms, cuadros/etiquetas dibujados por fotograma, una fila de resultado aparece en un panel lateral en el momento en que ocurre. |
| Acercarse al detalle | .world con transform-origin en el detalle, agrega .zoom (escala 1.5–1.6, 1.2 s ease). |
| El usuario realiza un paso | await cursorTo(boton) luego await click(boton): el cursor se desliza al centro medido del elemento, se ondula, el botón se presiona, luego el resultado. Escribe con typeText(el, texto) (55 ms por carácter; mantén cualquier cadena escrita por debajo de ~1 s). |
| Avanzar por fotogramas | Botones anterior/siguiente presionados al ritmo, lectura del número de fotograma, el fotograma decisivo marcado. |
| Dos vistas concuerdan | Dos imágenes lado a lado, el mismo momento marcado en ambas, una insignia que indica la concordancia. |
| Prueba | Las filas de la tabla se deslizan (separadas 120 ms), luego 2–3 tarjetas de estadísticas; cuenta el número héroe hacia arriba con countUp(el, n) (~700 ms). |
| Datos de salida | Lista de resultados y un panel de archivo/integración se completan en el mismo ritmo, con un indicador 'en vivo'. |
| Tarjeta final | Barrido de línea, logotipo, eslogan, botón CTA aparece, URL. |
Apunta el cursor a los elementos, nunca a coordenadas escritas a mano: cursorTo(el) mide el elemento
cuando el cursor se mueve, por lo que un zoom, un cambio de diseño u otra forma del escenario no puede dejarlo haciendo clic en el espacio vacío.
click(el) registra un error si la punta no está sobre el, y check.cjs falla en ello. Usa
cursorTo({x, y}) solo para un punto que no es un elemento. Toma una captura de pantalla de verificación en el momento
de cada clic: un clic que aterriza es lo único que los espectadores notan cuando está mal.
Muestra y oculta con show(el) / hide(el) de shot.js. .on usa !important, por lo que cualquier otra clase agregada junto a él para ocultar o mover el elemento no hace nada en silencio; siempre quita .on primero (eso es lo que hace hide). Para una salida personalizada, el.classList.replace('on', 'my-exit').
Mantén la línea de tiempo ágil: 0.3–0.7 s entre ritmos, ≈1 s para leer un título. Cada clip suele tener 4–8 s; un plano de avance paso a paso puede durar 15 s porque el editor lo recortará y acelerará.
Recorta cualquier cosa que la fuente haya grabado y que no deba mostrarse (fecha/hora de la cámara, barras de estado, nombres privados)
escalando .world ligeramente desde el borde opuesto (por ejemplo, scale(1.08) desde abajo).
No confíes en backdrop-filter para ocultar cosas: no se renderiza en la grabación de pantalla.
4. Verificar antes de grabar
node <skill>/scripts/check.cjs <directorio-paginas> <directorio-chk> hook:400:1500:3200 live:800:3000:6000
Toma capturas de pantalla en esos ms después de start() (deliberadamente no espera a start(); esperar
solo muestra el estado final) e imprime errores de página. Lee las capturas de pantalla. Verifica especialmente:
- las marcas se colocan en lo correcto (cuadro en la persona correcta, una línea en el borde delantero, no un pie trasero o un transeúnte; las pistas del detector pueden cambiar a otra persona en medio de la secuencia, por lo que une o corrige los cuadros manualmente);
- nada está cortado en los bordes, el texto no superpone el sujeto;
- cada número en la pantalla coincide con la fuente.
5. Grabar
node <skill>/scripts/record.cjs <directorio-paginas> <directorio-clips> hook=01-hook-anim=4200,setup=02-setup-anim=5000
pagina=nombreSalida=ms: graba durante ms (duración de la animación + ~1 s de final mantenido). Cada clip sale en el
tamaño de su página (--w×--h), 30 fps, H.264 CRF 16, silencioso. check.cjs y roughcut.py siguen el
mismo tamaño, por lo que no se necesitan ediciones de script para vertical o cuadrado. Necesita Chrome (o Chromium de Playwright) y Playwright
(npm i -g playwright una vez si pw.cjs no puede encontrarlo), además de ffmpeg.
Los clips se ejecutan durante los ms solicitados más ~0,3 s. El primer fotograma es la página antes del primer ritmo de start(),
por lo que los puntos de entrada suelen comenzar en 0,1–0,3 s; léelos de la hoja de contacto.
Verifica cada clip sin verlo:
bash <skill>/scripts/sheet.sh <directorio-clips>/03-live-anim.mp4 sheet.jpg 2
Lee la hoja de contacto: sincronización de cada ritmo, nada aplastado o cortado, último fotograma completo. Anota los segundos de entrada/salida de la parte útil de cada clip; van en la tabla de corte.
Nombra los clips NN-nombre-anim.mp4 en orden de historia (04b, 04c para alternativas) y escribe un breve
README.md en la carpeta de clips listándolos.
6. Documento de guion
Sigue references/script-doc.md. La tabla de corte (tiempo, clip, entrada-salida, velocidad, lo que ves,
inicio de locución, línea) es el corazón del mismo; el resto es lo que la persona necesita para terminar sin ti.
Locución: ~2,5 palabras por segundo, conversacional, una línea por plano, CTA dicho en voz alta
('Pruébalo gratis. Haz clic en el enlace o visita example.com.').
La mayoría de los videos sociales se ven silenciados, incluidos Reels y TikTok. Siempre dale a la tabla de corte una columna 'En pantalla' y haz que el texto en pantalla cuente la historia por sí mismo. Cuando haya una locución (Reels, TikTok, Shorts), también agrega subtítulos grabados en los pasos del editor, colocados en la zona segura vertical y colocados en planos cuyo título ya