vid-product-launch
Genera un video narrativo de lanzamiento de producto en formato MP4 a partir de una descripción del producto y su contexto de lanzamiento. Pipeline: Animaciones HTML/CSS → Chromium sin interfaz gráfica (Playwright, fotograma a fotograma) → FFmpeg (H.264 MP4). Sin React. Sin APIs de video con IA. Sin Python. Costo de ejecución cero más allá de Playwright + FFmpeg.
Reglas críticas (léelas antes de cada generación)
-
El eslogan no es opcional. No lo omitas. Es la promesa completa del producto en 4–6 palabras. Si el usuario no lo proporcionó, deriva uno de la descripción: una destilación precisa y en voz activa. Nunca escribas "[eslogan aquí]" ni lo dejes en blanco.
-
El momento de revelación debe sentirse merecido. Las secciones de provocación y construcción existen para crear tensión. Si el nombre del producto aparece en el primer 20% del video, la narrativa se derrumba. Nunca reveles el nombre del producto antes de la sección de Revelación.
-
Tamaño de fuente de product_name: mínimo 120px para 16:9, mínimo 80px para 9:16. El nombre debe ser el elemento más grande en el momento de la revelación. Si no es dominante, la revelación falla.
-
Una estadística de prueba. No una lista. Si el usuario proporciona múltiples estadísticas, elige la más sólida. Una lista de 5 números destruye el impacto. Un solo número sobredimensionado lo crea.
-
Usa
window.renderFrame(t)— ni@keyframesde CSS para transiciones de escenas. La búsqueda decurrentTimede CSS se ignora silenciosamente para búsquedas hacia atrás en Chromium. La función renderFrame calcula los estilos de los elementos directamente a partir de los milisegundos. Playwright la llama una vez por fotograma. -
Sin
animation-delayen NINGÚN elemento. No es necesario con renderFrame. Si escribesanimation-delay, detente — estás usando la arquitectura incorrecta. -
window.__videoReady = truesolo dentro dedocument.fonts.ready.then(...). Nunca lo establezcas de forma síncrona. -
Expón
window.__stopPreview(). El bucle de previsualización de rAF compite con las llamadas evaluate/screenshot de Playwright. El script de captura llama a__stopPreview()antes del bucle de fotogramas. -
Usa
t < startMs(not <= startMs) en las comprobaciones de límites de escenas.t <= 0en el fotograma 0 hace que la escena 1 se vea negra. -
Body = dimensiones exactas en píxeles. El ancho y el alto son números enteros. Sin
%,vw/vh,rem. -
Lee
references/scene-library.mdYreferences/style-presets.mdantes de generar CUALQUIER HTML. -
Nunca vuelques HTML en el chat. Guárdalo en un archivo. Muestra solo un resumen.
-
El canvas de grano de película DEBE ser de 240×135, no de W×H. Establece
width="240" height="135"en el elemento canvas, luego estíralo constyle="width:[W]px;height:[H]px". El grano a resolución completa en 1920×1080 es 64 veces más lento: 8 MB de ImageData por fotograma, lo que hará que las exportaciones de 1800 fotogramas lleven horas. -
La sección de provocación DEBE ser oscura (#000 o casi negra), independientemente del tono. Los fondos blancos en la sección de provocación se leen como diapositivas de demostración, no como videos de lanzamiento de productos. El arco narrativo de oscuro a claro (provocación oscura → construcción oscura → revelación del producto) es como los videos de lanzamiento crean drama. Incluso los ajustes preestablecidos
minimalyenergeticdeben usarbackground: #000para las escenas de problema de provocación y construcción de tensión. -
Cada palabra de provocación debe ser su propio compás con un tamaño de fuente de 200px o superior. Palabra por palabra en una sola línea no es lo suficientemente impactante. Cada palabra del problema (por ejemplo, "Investigar." / "Escribir." / "Contactar." / "Repetir.") obtiene 1500–1800 ms de tiempo en pantalla con
font-size: 200px; font-weight: 900centrado, una a la vez. Consulta el patróntease-wordsen scene-library.md. -
La sección de construcción debe mostrar contenido que narre el problema, no solo partículas. Usa el patrón
terminal-card: 3 tarjetas que aparecen secuencialmente con una animación de máquina de escribir que muestra el trabajo manual que se está realizando. Las tarjetas tienenborder: 1px solid rgba(255,255,255,0.07), acento de punto azul, texto monoespaciado. Las partículas solas durante 20 segundos son tiempo de pantalla vacío. -
Fondo CSS de cuadrícula de puntos en escenas oscuras. Agrega
background-image: radial-gradient(circle, rgba(255,255,255,0.035) 1px, transparent 1px); background-size: 60px 60px;a las escenas de construcción, revelación, prueba y CTA. No cuesta nada en términos de cómputo y agrega profundidad.
Paso 1: Recopilación de información
Requerido:
product_name— el nombre del producto o característica que se lanzaproduct_description— 2–3 oraciones: qué hace, para quién es, beneficio clave
Parámetros opcionales y valores predeterminados:
| Parámetro | Predeterminado | Descripción |
|---|---|---|
| eslogan | automático | 4–6 palabras — la promesa central del producto |
| declaración_del_problema | inferido automáticamente | 1 oración para la sección de provocación (el dolor que resuelve el producto) |
| estadística_de_prueba | inferido automáticamente | Métrica única (ej. "500+ equipos", "10× más rápido", "$2M ahorrados") |
| cta | automático | URL o frase de acción (ej. "opendirectory.dev", "Únete a la lista de espera") |
| fecha_de_lanzamiento | — | Cadena de fecha ISO (habilita la escena de tarjeta de cuenta regresiva) |
| tono | cinematográfico | cinematográfico / enérgico / minimalista / emocional |
| duración | 60 | 30 / 60 / 90 (segundos) |
| relación_de_aspecto | 16:9 | 16:9 (1920×1080) / 9:16 (1080×1920) |
| letterbox | falso | Barras negras cinematográficas 2.35:1 — solo 16:9 |
| música | — | Ruta al archivo de audio (mp3/m4a/wav) |
| fps | 30 | Fotogramas por segundo (24, 30 o 60) |
Si falta product_name o product_description, pregunta exactamente:
"Para crear el video de lanzamiento, necesito dos cosas:
- Nombre del producto — ¿cómo se llama el producto?
- Descripción del producto — 2–3 oraciones: ¿qué hace?, ¿para quién es?, ¿cuál es el beneficio clave?
Opcional: eslogan (4–6 palabras), estadística de prueba (un número), CTA (URL o frase de acción), tono (cinematográfico / enérgico / minimalista / emocional), duración (30 / 60 / 90 s)."
Si ambos están presentes → procede inmediatamente al Paso 2.
Paso 2: Arquitectura interna (nunca se muestra al usuario)
1. Deriva los parámetros faltantes:
- eslogan (si no se proporciona): Escribe uno a partir de la descripción del producto. 4–6 palabras. Voz activa. Sin relleno ("El futuro de…", "Presentando…"). Deriva la promesa más nítida posible.
- declaración_del_problema (si no se proporciona): Infiere a partir de la descripción del producto. 1 oración que indique el dolor. Nunca menciona el nombre del producto. Escrita para que la audiencia asienta con reconocimiento.
- estadística_de_prueba (si no se proporciona): Infiere a partir de la descripción del producto. Si no hay estadística disponible, usa un indicador de escala creíble ("Confiado por 500+ equipos", "De días a minutos").
- cta (si no se proporciona): Usa el dominio del producto si se puede inferir del nombre del producto, o "Más información" como frase de acción.
2. Calcula la sincronización de las secciones a partir de la duración:
| Sección | 30s | 60s | 90s | Fórmula de inicio |
|---|---|---|---|---|
| Provocación | 0–5s | 0–10s | 0–15s | 0ms |
| Construcción | 5–12s | 10–30s | 15–40s | Fin de provocación |
| Revelación | 12–20s | 30–45s | 40–60s | Fin de construcción |
| Prueba | 20–25s | 45–55s | 60–75s | Fin de revelación |
| CTA | 25–30s | 55–60s | 75–90s | Fin de prueba |
Convierte cada límite a milisegundos. Asigna a constantes:
TEASE_START_MS, TEASE_END_MS
BUILD_START_MS, BUILD_END_MS
REVEAL_START_MS, REVEAL_END_MS
PROOF_START_MS, PROOF_END_MS
CTA_START_MS, CTA_END_MS
3. Selecciona escenas por sección:
- Provocación: Siempre comienza con
blackout-opener(1500ms). Luegotease-words(cada palabra clave del problema como su propio compás de 1600–1800ms a 200px+). Si se proporcionalaunch_date, opcionalmente agregacountdown-cardal final de la provocación. - Construcción: Secuencia
terminal-card(3 tarjetas que muestran las tareas manuales que se escriben) + línea de acento de cierre opcional. Duración ≥ 30s obtiene las 3 tarjetas. Duración = 30s usa 2 tarjetas. Nunca uses solo partículas desnudas durante más de 5s: la pantalla debe mostrar contenido que narre el problema. - Revelación:
reveal-hero— siempre primero en esta sección. Opcionalmente seguido detagline-cardsi la duración ≥ 60s. - Prueba:
proof-statsi hay una estadística numérica disponible. De lo contrario,feature-bullet. - CTA:
cta-card— siempre, siempre al final.
Recuentos típicos de escenas: 30s = 4 escenas, 60s = 6–7 escenas, 90s = 7–8 escenas.
4. Calcula la sincronización por escena:
Dentro de cada sección, divide el tiempo por igual entre las escenas de esa sección.
Excepción: blackout-opener siempre ocupa exactamente los primeros 1500ms de la provocación.
5. Determina las dimensiones en píxeles:
16:9→ W=1920, H=10809:16→ W=1080, H=1920
6. Cálculo de letterbox (si está habilitado, solo 16:9):
- Altura del contenido 2.35:1 = W / 2.35 = 1920 / 2.35 ≈ 817px
- Altura de la barra = (H - 817) / 2 = (1080 - 817) / 2 ≈ 132px
- Barra superior:
top: 0; height: 132px - Barra inferior:
bottom: 0; height: 132px
7. Indicadores de efectos cinematográficos (por ajuste preestablecido):
cinematic: grano-de-película=ACTIVADO (canvas 240×135, opacidad 0.025), viñeta=ACTIVADA, fuga-de-luz=ACTIVADA (dorado cálido), cuadrícula-de-puntos=ACTIVADA en escenas oscurasenergetic: grano-de-película=DESACTIVADO, viñeta=DESACTIVADA, cuadrícula-de-puntos=ACTIVADA, flash blanco en la revelaciónminimal: grano-de-película=ACTIVADO (canvas 240×135, opacidad 0.022), viñeta=ACTIVADA (sutil, radial 0.5), cuadrícula-de-puntos=ACTIVADA, sin fuga-de-luz — color de acento = #4B9FFF (azul eléctrico)emotional: grano-de-película=ACTIVADO (canvas 240×135, opacidad 0.018, mezcla de tono cálido), viñeta=ACTIVADA (suave), fuga-de-luz=ACTIVADA (cobre cálido), cuadrícula-de-puntos=DESACTIVADA
Todos los ajustes preestablecidos: las escenas de provocación y construcción SIEMPRE usan fondo oscuro (#000 o casi negro), independientemente del ajuste preestablecido.
8. Incrusta window.__sfxTimeline en el HTML (siempre, incluso cuando no se proporciona música):
El script de exportación lee este array, sintetiza cada tipo de SFX de forma nativa con aevalsrc/anoisesrc de FFmpeg, y coloca los eventos en desplazamientos de milisegundos exactos usando adelay. No se requieren archivos de audio externos.
Referencia de tipos de SFX:
| Tipo | Sonido | Duración | Notas |
|---|---|---|---|
word-hit | Golpe grave (50Hz) + clic transitorio (2.2kHz) + ráfaga de ruido | 180ms | Uno por palabra de provocación — 3 capas vía amix |
type-sequence | Clics de teclado mecánico a 15Hz (envolvente de pulso sin^30) | 1.9s | Uno por tarjeta — se ejecuta durante toda TYPE_DUR |
whoosh | Barrido de ruido de dos bandas (cuerpo 1.1kHz + aire 4–8kHz) | 700ms | En la transición BUILD_CLOSE |
tension-riser | Retumbo bajo (250Hz) + tono grave que crece con rampa t/2.8 | 2.9s | Comienza en BUILD_CLOSE + 700ms — alcanza su punto máximo en REVEAL_START |
reveal-boom | Grave (45Hz) + cuerpo (90Hz) + brillo (4.5–11kHz) + eco de 85ms | 900ms | Exactamente en REVEAL_START — EL golpe |
counter-tick | Clic armónico (880Hz + 440Hz + 1760Hz + 2640Hz) | 80ms | 3 pulsos — decrescendo 0,32 → 0,26 → 0,20 |
cta-chime | Acorde de La mayor (440 + 554 + 659 + 880Hz) + brillo de eco de campana | 1.2s | Exactamente en CTA_START |
Mapa de sincronización de SFX: calcula los valores ms a partir de las constantes de sección, nunca los codifiques:
window.__sfxTimeline = [
// ── PROVOCACIÓN: un word-hit por pulso de palabra, el último más fuerte ───
{ ms: WORD_BEATS[0].start, sfx: 'word-hit', vol: 0.55 },
{ ms: WORD_BEATS[1].start, sfx: 'word-hit', vol: 0.55 },
{ ms: WORD_BEATS[2].start, sfx: 'word-hit', vol: 0.55 },
{ ms: WORD_BEATS[N].start, sfx: 'word-hit', vol: 0.65 }, // última palabra más fuerte
// ── CONSTRUCCIÓN: type-sequence por tarjeta (1.9s, coincide con TYPE_DUR 1800ms) ──
{ ms: CARDS[0].start + 180, sfx: 'type-sequence', vol: 0.28 },
{ ms: CARDS[1].start + 180, sfx: 'type-sequence', vol: 0.28 },
{ ms: CARDS[2].start + 180, sfx: 'type-sequence', vol: 0.28 },
// ── TRANSICIÓN: whoosh luego elevador de 2.9s que alcanza su punto máximo en REVEAL_START ──
{ ms: BUILD_CLOSE, sfx: 'whoosh', vol: 0.50 },
{ ms: BUILD_CLOSE + 700, sfx: 'tension-riser', vol: 0.35 },
// ── REVELACIÓN: el golpe cinematográfico ──────────────────────────────────
{ ms: REVEAL_START, sfx: 'reveal-boom', vol: 0.88 },
// ── PRUEBA: ticks armónicos, decrescendo ──────────────────────────────────
{ ms: PROOF_START, sfx: 'counter-tick', vol: 0.32 },
{ ms: PROOF_START + 2200, sfx: 'counter-tick', vol: 0.26 },
{ ms: PROOF_START + 4400, sfx: 'counter-tick', vol: 0.20 },
// ── CTA: acorde de La mayor que aterriza ──────────────────────────────────
{ ms: CTA_START, sfx: 'cta-chime', vol: 0.62 },
];
Coloca este bloque inmediatamente antes del bucle de previsualización, después de window.renderFrame.
Paso 3: Generación de HTML
Lee references/scene-library.md Y references/style-presets.md antes de escribir cualquier código.
Usa los nombres de clase CSS exactos, la estructura HTML y los patrones renderFrame de esos archivos.
Esqueleto HTML requerido:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
[enlace CDN de fuente del ajuste preestablecido de estilo]
<style>
:root {
[todos los tokens CSS del ajuste preestablecido de estilo]
}
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html, body {
width: [W]px; height: [H]px;
overflow: hidden;
background: var(--bg);
font-family: var(--font-body);
position: relative;
}
.scene {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 80px;
opacity: 0;
will-change: opacity, transform;
}
.scene-inner {
width: 100%;
max-width: 1200px;
}
[pega el CSS de cada tipo de escena en scene-library.md]
</style>
</head>
<body>
<!-- Elementos de superposición cinematográfica — renderizados sobre todas las escenas -->
[si grano-de-película: ACTIVADO]
<canvas id="grain-overlay"
width="[W]" height="[H]"
style="position:fixed;inset:0;pointer-events:none;opacity:0.025;mix-blend-mode:overlay;z-index:50"></canvas>
[fin si]
[si viñeta: ACTIVADA]
<div id="vignette-overlay"
style="position:fixed;inset:0;background:radial-gradient(ellipse at center,transparent 35%,rgba(0,0,0,0.65) 100%);pointer-events:none;z-index:51"></div>
[fin si]
[si fuga-de-luz: ACTIVADA]
<div id="light-leak"
style="position:fixed;inset:0;background:linear-gradient(135deg,rgba(255,220,140,0.5) 0%,rgba(255,255,255,0.3) 45%,transparent 70%);opacity:0;pointer-events:none;z-index:52"></div>
[fin si]
[si letterbox: ACTIVADO]
<div id="lbox-top" style="position:fixed;top:0;left:0;width:[W]px;height:132px;background:#000;z-index:100"></div>
<div id="lbox-bot" style="position:fixed;bottom:0;left:0;width:[W]px;height:132px;background:#000;z-index:100"></div>
[fin si]
<!-- Escenas -->
[HTML de escena de scene-library.md plantillas, una por escena seleccionada]
<script>
window.__videoReady = false;
window.TOTAL_DURATION_MS = [duration * 1000];
// ── Constantes de sincronización de secciones ──────────────────────────────────
const TEASE_START_MS = [N];
const TEASE_END_MS = [N];
const BUILD_START_MS = [N];
const BUILD_END_MS = [N];
const REVEAL_START_MS =
…
[truncado para traducción]