/bw-song-ad — Anuncio cantado en dibujos animados blanco y negro hasta versión final
2026-10-18, elaborado con el proyecto "おひさまパンツ" H-OHI-023a. Referencia: WhiteHat MRR en X (densidad ósea, dibujos animados blanco y negro, ~4 minutos). La reacción del autor: "La canción es increíblemente buena, una locura". El vídeo de referencia no es un jingle corto, sino que canta casi textualmente el guion de un VSL de formato largo.
Orden (no alterar)
Letra → Canción (Suno) → Sincronización carácter a carácter → División en escenas → Tabla de personajes → Keyframes → Animación → Exportación de fondo → Remotion → Revisión. La canción es el reloj. Si se crea la imagen primero, no coincidirá con los tiempos de la canción y habrá que rehacerlo todo.
S=~/.agents/skills/bw-song-ad
AD=<carpeta_del_proyecto>/<ID_del_anuncio> # lyrics.md / captions.txt / song/ / shots.py / keys/ / clips/ / remotion/
cp -R $S/remotion $AD/remotion && cd $AD/remotion && NODE_USE_ENV_PROXY=1 npm install
0. Revisar primero el inventario
Si ya hay imágenes o vídeos anteriores de la misma marca, úsalos primero (consulta la tabla de inventario ASSETS.md de la marca; añade los nuevos recursos creados). Si es necesario generar contenido, informa de antemano "X imágenes, Y vídeos, aproximadamente Z créditos". Esta vez: 61 imágenes (~15 créditos), 61 vídeos Grok (~265 créditos).
1. Letra (lyrics.md) — Modelo de reference/lyrics.md
- Canta cada párrafo del flujo del VSL. No se riman. Estructura equivalente a la referencia: Inicio del profesional → "No es así" ×3 → Algo más importante → La causa no está donde se cree → Aliados y villanos dentro del cuerpo → Antes funcionaba → Ahora el villano gana → El problema empieza aquí (cadena de abandono) → El mercado solo ofrece lo mismo → Pero algo cambió (solución) → Artículo (sin registro) → Inventario → "Ya no necesitas..." ×3 → "Tranquilo. Toca abajo"
- Todo en hiragana. Los números también en hiragana (Suno se desvía con kanji y números).
- No se canta el nombre del producto (se muestra en la etiqueta en pantalla). Sin precios. Las promesas dentro del ámbito de la página del producto.
- Mostrar antes de componer.
2. Canción (Suno · Playwright)
- Solo el login lo hace la persona. Luego, en
suno.com/create?mode=CUSTOMse inyecta la letra, el estilo y el título para crear. - Estilo (que funciona):
1930s vintage upbeat jazz, old cartoon soundtrack, swing, clarinet, muted trumpet, ragtime piano, brushed snare, upright bass, warm female vocal, Japanese, clear diction, storytelling sung melody - Cada vez salen 2 canciones. Transcribe ambas con whisper y compáralas con la letra; elige la que no se desvíe.
- Descarga: en la página de la canción, More options → Download → MP3 → "Unlock & Download" (usa 1 crédito gratuito).
cdn1.suno.aida 403; el m4a de reproducción está encriptado. No se extrae el blob del navegador para evitar consumir créditos. - Colocar en
song/song.mp3.
3. Texto de subtítulos (captions.txt)
- 1 párrafo de la letra = 1 línea. Dentro de la línea, separar con
/(1 bloque = texto que aparece una vez en pantalla; máximo ~12 caracteres). - Convertir a japonés legible con kanji y kana (la letra está en hiragana, pero los subtítulos deben usar notación normal).
- Donde se quieran 2 líneas, usar
|(ejemplo:Toca el botón de abajo|para leer el artículo).
4. Sincronización carácter a carácter
uv run --python 3.12 --with openai-whisper python $S/scripts/align.py $AD
→ $AD/cap_events.json (tiempo de inicio y fin de cada bloque) y $AD/line_starts.json (inicio del canto de cada línea).
- No usar los tiempos por línea de whisper-cli. Si el inicio real del canto es a los 4.9 segundos pero whisper-cli lo trata como 0 segundos, y además divide uniformemente dentro de la línea, los subtítulos avanzan aunque no se cante.
- Cuando la canción se detiene (más de 0.8 segundos), ocultar el subtítulo.
- Si la tasa de coincidencia baja del 80%, la canción está desviada o captions.txt no coincide con la letra.
5. División en escenas (shots.py)
- Incluye
STYLE(descripción del estilo visual común a todos los planos) ySHOTS = [(número de línea, qué plano dentro de esa línea, escena, movimiento), ...]. - Cada plano de 2 a 5 segundos. Las líneas largas se dividen en 2 o 3 planos. En 3 minutos y medio, aproximadamente 60 planos.
- No animar todo el metraje largo: mezclar planos de imagen fija con cámara lenta; así se reduce a la mitad la generación de vídeos.
- Personajes: Profesor (bob, delantal) / Mamá (moño bajo, rayas) / Niño (pelo liso) / Dos mensajeros dentro del cuerpo (mono rayado, gorra) / Villano (bola negra, cuernos, esponja y pajita) / Producto (estampado real).
6. Tabla de personajes y keyframes (Higgsfield gpt_image_2_5 · 9:16 · 1 imagen 0.25 créditos)
- Primero crear 1 tabla de personajes. Luego, para todos los planos siguientes, pasar 2 imágenes como referencia: la tabla de personajes + 1 viñeta de referencia.
- Al inicio del prompt, añadir
STYLE: black and white 1930s rubber-hose cartoon, thick clean ink lines, cross-hatching, grayscale only, vintage Fleischer-era look, slightly grainy film, soft dark round vignette, no text. python3 $S/scripts/make_reqs.py $AD image→ enviar de 12 en 12 congenerate_image_batch.- Vestir al niño (en ropa interior o pañal se rechaza por nsfw). Si la viñeta de referencia muestra ropa interior, también se rechaza.
- El producto debe incluir el estampado real en el prompt (si sale un estampado inexistente, rehacer).
- Revisar todo en una hoja de contactos: estilo visual, sin texto, conforme a la tabla de personajes.
7. Animación (Grok Imagine grok_video_v15_lite · 720p · solo start_image · 1 segundo ≈ 1 crédito)
python3 $S/scripts/make_reqs.py $AD video→ enviar de 12 en 12 congenerate_video_batch. Duración: tiempo asignado + 0.5 segundos (3 a 8 segundos).- Prompt: "Mueve esta imagen: . Manteniendo el mismo estilo, composición y personajes, movimiento elástico de rubber-horse, parpadeo de película, cámara fija, sin cortes, sin texto nuevo".
- Si falla y devuelve un preset, incluir
declined_preset_iden los parámetros y reintentar. - Revisar todos los fotogramas finales ordenadamente. Si el producto se gira o deforma el estampado, usar solo los segundos antes de que ocurra (SRC_MAX) o hacer un bucle de la parte frontal.
8. Exportación de fondo (sin texto)
python3 $S/scripts/bg.py $AD # → $AD/bg.mp4 (1080x1920 · 30fps) y shot_starts.json
- Los cambios de plano se sincronizan con el inicio del canto de cada línea (line_starts.json). El primer plano comienza en el segundo 0.
- Para la introducción sin canto (primeros segundos), se puede rellenar con planos rápidos de escenas fuertes (villano, inundación, sellos aplastantes, etc.).
9. Remotion ($AD/remotion)
- Colocar
public/bg.mp4(fondo),public/song.mp3ysrc/data.json:python3 $S/scripts/make_data.py $AD --hook-end 29.3 --cta 192.9 --brand 44,46,47,50 --hook-top "Para mamás en el entrenamiento del baño" --hook-main "El pañal no se quita" --hook-mark "La verdadera razón" --brand-name "<nombre del producto>" --keys "<palabras clave en amarillo, separadas por comas>" - Elementos a incluir (en
src/SongAd.tsx):- Hook superior: tarjeta de papel (marco negro grueso, sombra desplazada, ligeramente inclinada) que muestre "para quién + de qué trata" en el primer segundo. Ejemplo: "Para mamás en el entrenamiento del baño / El pañal no se quita La verdadera razón".
- Subtítulos: esquinas redondeadas negras, texto blanco en negrita, que aparezca con un rebote. Solo las palabras clave en amarillo (el único color dentro del blanco y negro).
- Etiqueta del producto: solo en los planos donde aparece el producto, pequeña en la parte superior.
- CTA: desde el último "Toca abajo" hasta el final, 3 flechas amarillas que caen rebotando hacia abajo + "Toca el botón de abajo|para leer el artículo".
- Exportación (en este Mac, Chrome sin interfaz se cae solo → usar
chrome-wrap.sh, fuera del sandbox):
cd $AD/remotion && NODE_USE_ENV_PROXY=1 npx remotion render src/index.ts SongAd out/<ID_del_anuncio>.mp4 --browser-executable=./chrome-wrap.sh --concurrency=6 --crf=20
- Entrega: recodificar con
-crf 23 -movflags +faststart(el granulado blanco y negro pesa; 3 minutos y medio ≈ 200 MB).
10. Revisión (obligatoria antes de abrir)
- Leer una hoja de contactos con 24 fotogramas por segundo aproximadamente: comprobar que los subtítulos no se desvíen de la canción / que no aparezcan en silencios / que el estampado del producto no se deforme / que las flechas CTA estén dentro de la pantalla / que no haya texto adicional.
- Revisar los primeros 3 segundos por separado (que el hook se entienda de un vistazo).
- Crear una página de vista previa en HTML y abrirla. El nombre del anuncio debe ser el nombre emitido por AdLab (H-XXX-000a) directamente como nombre de archivo.
Puntos problemáticos (medidos en esta ocasión)
- Subtítulos desviados desde el principio: el inicio del canto era a los 4.9 segundos, pero whisper-cli lo consideró desde el segundo 0 → resuelto con
align.py(word_timestamps de openai-whisper + difflib para alinear caracteres). - nsfw en keyframes: niños en ropa interior o imágenes de referencia con ropa interior → vestir al niño / la referencia se describe solo con el texto del estilo.
- Producto girado y deformado: Grok suele girarlo. Usar solo los segundos donde está de frente.
- Exceso de contenido: 61 imágenes + 61 vídeos para un solo anuncio. La próxima vez, reducir a la mitad usando inventario y planos fijos con cámara lenta.
- Último carácter largo se va a la siguiente línea → usar
|para especificar la línea.
Relacionado: reference/lyrics.md (modelo y ejemplo de letra), /zackd-ad (tipo animación 3D), AdLab (registrar hipótesis antes de crear).