Anuncio Animado Sobre Narración
Principio
Lo que se escucha = lo que se ve. La narración establece los tiempos. Se graba primero, Whisper asigna un tiempo a cada palabra, y todo texto, escena, notificación y efecto se inserta en la palabra correspondiente. En el código no hay números de fotograma: se escribe at: 'clientes' y el tiempo se obtiene de public/words.json. Grabación nueva = npm run vo, y el video se alinea solo.
Ningún segundo en pantalla se queda quieto. Un segundo sin movimiento = el espectador desplaza.
Reglas de Hierro
- No puedes oír. El dueño del negocio es el único oído. Cualquier verificación de audio tuya es numérica (
silencedetect,ffprobe, retranscripción). No está permitido escribir "el audio está bien" sin citar la salida. - Primero se limpian los silencios, luego se transcribe. Whisper se equivoca en los tiempos cerca del silencio.
prep-vo.shhace ambos en el orden correcto. - Después de un cambio en el audio, se ejecuta
npm run vode nuevo. Sin esto, toda la sincronización se desvía. - El video termina cuando termina la narración + 8 fotogramas (
DURATIONentime.ts).render-all.shimprime la duración de cada archivo frente a la narración. Si son diferentes, algo se ha cortado. - Texto solo entre y=260 y y=1570. Por encima y por debajo, Instagram lo cubre.
validate()detiene el renderizado con una explicación si el texto sale de esta área o es más ancho de 1000px. - Los efectos están por debajo de la voz. Constantes en
Ad.tsx: narración 1.15, música 0.22, cada efecto se multiplica porSFX = 0.38. "Los efectos están fuertes" = cambiar un número. - Stills antes de mp4.
npm run checkrenderiza 10 fotogramas enout/stills. Revisar todos (Leer los PNG) antes del renderizado completo. - Solo contenido real. Números, pagos y mensajes de clientes: lo que realmente sucedió. Está permitido ocultar nombres, pero no inventar resultados. También por la política de Meta y porque la gente detecta falsificaciones.
- Hebreo: Las fuentes (Rubik, Heebo, variables, OFL) ya están en la plantilla y se cargan con
delayRender. La raíz está endirection: rtl. Los números dentro de una etiqueta recibendirection: ltr.
Instalación Inicial del Proyecto
cp -R ~/.claude/skills/animated-voiceover-ad/template ~/ads/<nombre-del-anuncio>
cd ~/ads/<nombre-del-anuncio>
npm install
npm run setup # Efectos y música de Mixkit
Se necesita: Node 18+, ffmpeg, whisper-cli (brew install ffmpeg whisper-cpp) y el modelo whisper en ~/.whisper/models/ggml-large-v3-turbo.bin (si falta, words.mjs imprime un comando de descarga).
El Pipeline
| Paso | Qué hacer |
|---|---|
| 1. Guión | Según references/script-formula.md. Cada oración se asigna de antemano a una escena. Mostrar al dueño del negocio antes de que grabe. |
| 2. Grabación | En teléfono o QuickTime, un archivo. ¿Se equivocó? Pausa un segundo y comienza la oración de nuevo. Luego se elimina la toma mala (ver references/audio.md). |
| 3. Limpieza y Transcripción | npm run vo -- recording.m4a. Imprime todas las palabras con tiempos. Mostrar la transcripción al dueño del negocio y corregir palabras que Whisper haya transcrito mal directamente en public/words.json (solo la w). |
| 4. Dirección | Editar solo src/Ad.tsx: KTS (texto cinético), notificaciones, SCENES. Cada tiempo = palabra, ['aún', 2] para la segunda aparición. Detalle de los componentes en references/scenes.md. |
| 5. Verificación | npm run check (tsc + stills). Revisar cada still. |
| 6. Renderizado | npm run render. Cada música en MUSICS (Root.tsx) = archivo separado en out/, para pruebas A/B. |
| 7. Correcciones | Cada comentario del dueño del negocio = un cambio fijo: otra palabra en at, volumen, until. No reescribir la escena completa. |
Variantes para Anuncios Pagados
- Música: Ya incorporada, 3 composiciones.
- Diferentes aperturas: Los primeros 3 segundos son cruciales. Grabar 2-3 hooks diferentes como archivos separados, unir cada uno al cuerpo con
ffmpeg concat, ejecutarnpm run voen cada unión y renderizar en carpetas separadas. TodoAd.tsxpermanece igual mientras las palabras del cuerpo sean idénticas. - Subtítulos completos:
CAPTIONS = trueenAd.tsx. Una línea, dividida según la puntuación. Útil porque la mayoría de las visualizaciones en anuncios pagados son sin sonido.
Problemas Conocidos
| Problema | Solución |
|---|---|
La palabra "X" no se encontró en la narración | El mensaje sugiere palabras cercanas. En hebreo, Whisper pega o separa prefijos (ו/ה/ל/ב). Usar la palabra tal como aparece en words.json. |
| El renderizado muestra código antiguo | Bundle antiguo en $TMPDIR/remotion-webpack-bundle-*. render-all.sh lo elimina. |
| TypeScript 7 instalado | Remotion necesita [email protected]. |
delayRender se atasca | --timeout=180000 (ya en render-all). |
| El sello se encoge antes de aterrizar | overshootClamping: true en su spring (ya implementado). |
| Las palabras se pegan después de limpiar silencios | Aumentar stop_duration en prep-vo.sh a 0.35. |
| Segundo "aburrido" | Agregar una línea de KT, notificación o efecto en esa palabra. Ningún segundo sin evento. |
La Demo en la Plantilla
La plantilla viene con una narración de demostración (voz TTS, public/vo.wav + public/words.json) y un Ad.tsx sincronizado con ella, para que se pueda ver todo funcionando antes de grabar: npm install && npm run setup && npm run check. En un anuncio real: npm run vo -- recording.m4a sobrescribe ambos, y luego se escribe Ad.tsx de nuevo según el guión.