Motion Ad Studio (de autoaprendizaje)
Crea un anuncio vertical con gráficos en movimiento de 20 a 40 segundos que un diseñador de motion senior firmaría: el fotograma 0 ya está en movimiento, un objeto portador recorre todo el video, las transiciones ocurren en medio del movimiento y con velocidad emparejada, y cada clic, aterrizaje, caída y whoosh está sincronizado con una palabra hablada o un tiempo musical. El video es una sola página HTML (línea de tiempo GSAP + funciones puras del tiempo). Se renderiza fotograma a fotograma a MP4, y los scripts lo verifican antes de que nadie lo vea. Los efectos de sonido se colocan desde la propia lista de eventos del video, por lo que la sincronización de audio se mantiene por construcción, no al oído.
Cada ejecución: lee references/lessons.md y references/runs.md PRIMERO. Termina con la Retrospectiva (paso 13).
La habilidad mejora solo si escribes las lecciones de vuelta.
0. Verificación previa (siempre)
python scripts/preflight.py [--elevenlabs-mcp yes] # pasa yes si TIENES herramientas de ElevenLabs conectadas
Las rutas usadas a continuación: scripts/..., references/... y templates/... son relativas a la carpeta de esta habilidad ($SKILLS/motion-ad-studio). $MOTIONMAXXING es la carpeta del motor ($SKILLS/motionmaxxing; el preflight la imprime), y $SEAM_GATE es el script opcional de seam-gate que el preflight encuentra (o pasa --seam-gate FILE).
| Necesidad | Por qué | Si falta |
|---|---|---|
| motor motionmaxxing (Apache-2.0) | render.mjs (fotogramas → MP4), look.py verifica, lint.mjs revisa diseño, runtime/vendor/gsap.min.js | git clone https://github.com/Tejashmakwana/motionmaxxing junto a esta habilidad, o configura MOTIONMAXXING |
| ffmpeg + ffprobe, Node 18+, Chrome/Chromium/Edge | renderizar, probar, mezclar | instala; configura CHROME_PATH si Chrome no se encuentra automáticamente |
| Python 3.9+ con numpy + Pillow | ritmos, cama sintética, mezcla, hojas | pip install numpy pillow |
| faster-whisper (opcional) | marcas de tiempo de palabras para sincronización palabra-a-palabra | pip install faster-whisper, o cualquier alineador que proporcione tiempos de inicio/fin de palabra |
| seam gate (opcional) | prueba que cada transición tiene velocidad emparejada | HyperFrames motion-doctrine + patches/seam-gate-camera-overlap.patch |
| ElevenLabs (opcional, recomendado) | voz expresiva, música compuesta, SFX personalizados | consulta la siguiente sección |
ElevenLabs es opcional: notifica al usuario una vez, nunca bloquees
Si el preflight imprime el AVISO (sin clave API y sin herramientas de ElevenLabs), transmíteselo al usuario en su idioma antes del paso de audio, en un mensaje corto, y permite que elija:
- conectar: el usuario agrega una
ELEVENLABS_API_KEYo conecta el servidor MCP de ElevenLabs. Vuelve a ejecutar el preflight. - continuar: construye el video completo con la ruta sin clave a continuación. Di una vez en la nota de entrega que ElevenLabs mejoraría la calidad de la voz y la música. No preguntes de nuevo en el mismo proyecto. Si no puedes preguntar (ejecución por lotes o no interactiva), continúa sin él y pon la recomendación en NOTE.md.
| Capa | Con ElevenLabs | Sin él (aún se entrega) |
|---|---|---|
| Voz en off | TTS con etiquetas de emoción, 2 tomas, elige una | la grabación propia del usuario (mejor), o una voz guía local/OS TTS; o un video liderado por música sin VO |
| Música | música generada para la duración del video, caída en el clímax | scripts/synth_bed.py (procedural, cuadrícula de ritmo exacta), o una pista para la que el usuario tenga los derechos |
| SFX | 1-3 muestras destacadas (látigo, whoosh, tecleo) | scripts/mix_events.py sintetiza cada SFX localmente |
| Tiempos de palabra | reconocimiento de voz a texto con marcas de tiempo (o marcas de TTS) | scripts/words.py (faster-whisper local) |
Detalles, indicaciones, costos de crédito y reglas de licencia: references/audio-providers.md.
Flujo de trabajo
-
Espacio de trabajo.
python scripts/new_film.py <proyecto>copia el kit de una sola toma, el runtime de GSAP y las fuentes locales. Renderiza un fotograma del demo sin modificar para probar la cadena de herramientas:node $MOTIONMAXXING/scripts/render.mjs <proyecto>/film/index.html --still 1.2,16.4 <proyecto>/stills. -
Kit de marca. Obtén los archivos oficiales del logotipo del usuario y recorta cada uno a su bbox alfa. Si un portador acoplará en el logotipo, mide los rects de subglifos. Toma los colores contando
#hexen el CSS del sitio y las fuentes como woff2 locales (scripts/fetch_fonts.py). Usa el canal de CTA que la marca realmente utiliza. Nunca redibujes ni aproximes un logotipo: pídelo. -
Una idea + un nuevo estilo. Escribe una sola idea que solo esta marca podría filmar. La prueba de cubrir el logotipo: oculta el logotipo y el video debería seguir apuntando a esta marca. Escribe tres direcciones, mata dos y elige un estilo DIFERENTE de la última fila de
references/runs.md. -
Gancho. Escribe 3 variantes de menos de 12 palabras (pregunta, negación, especificidad, historia) y elige una. El fotograma 0 ya está ocupado y en movimiento, el gancho está en pantalla para el fotograma 1 y nada aparece desde negro.
-
Voz en off. Escribe aproximadamente 2.5 palabras/s (30 s ≈ 70-75 palabras). Si el TTS admite etiquetas de emoción, marca cada línea ([curioso] [seguro] [enérgico] [con humor] [cálidamente]). Genera o grábala, recorta las pausas largas, ajusta la duración con
atempo≤ 1.1, luego obtén los tiempos de palabra:python scripts/words.py audio audio/vo.wav --lang <código>. Whisper te da SOLO TIEMPOS. El texto de los subtítulos siempre proviene del guion aprobado. -
Música. Genera (duración + BPM + "caída en <s clímax>"), licencia una pista o ejecuta
python scripts/synth_bed.py --bpm 120 --dur 32 --drop 15.8 --out audio/bed.wav. Obtén la cuadrícula conpython scripts/beats.py audio/music.mp3 audio/beats.json(synth_bed escribe un.beats.jsonexacto). Recorta el inicio de la música para que la caída coincida con la palabra de la VO del clímax: tiempo de film beat k = primer_beat - recorte + k·período. -
STORYBOARD.md + ledger.json (
templates/one-take/tiene un ejemplo completo). Incluye:- la especificación de la página, la idea y las tres direcciones;
- una hoja de ritmo (tramo / t / energía 0-10 / ruta / música);
- un mapa de tiempos: cada evento con la palabra
w(i)o el tiempobeat(k)al que está sincronizado; - la VO y la lista de datos ilustrativos;
- el ledger: una fila por costura (eje de salida/entrada + dirección, tiempo de corte).
-
Construcción. Copia patrones del kit (
references/one-take-kit.md):- relojes
w(i)/we(i)/beat(k); - orden por fotograma
tl.seek → PRE (cámaras, anclas móviles) → cursores (leen rects en vivo) → UP (UI que sigue); - cámara 3D con fotogramas clave y un motor de cursor que apunta a rects DOM en vivo;
- actualizadores de escritura/texto/clase como funciones puras de t;
- eventos
sfx()y whooshes derivados de la cámara.
Contrato que necesita el renderizador:
#mainllevadata-composition-id="main" data-width data-height data-duration.window.__seek / __duration / __timelines / __events / __player / __ready / __playerReady / __renderReady. Videos estilo montaje (escenas en capas, UI plana, portador de logotipo):references/montage-kit.md. - relojes
-
Míralo. Renderiza 15-20 fotogramas (
node $MOTIONMAXXING/scripts/render.mjs ... --still t1,t2,... stills), conjúntalos en una hoja (python scripts/sheet.py stills sheet.jpg 6 220) y ejecuta una pasada de visión: una línea por fotograma, luego una lista de defectos. Corrige y repite 2-3 pasadas.- La verdad geométrica (qué está dónde, visible, su opacidad) proviene de
node scripts/probe.mjs index.html "t1,t2" "#a,#b". - La verdad del texto proviene de un recorte a resolución completa: la visión lee mal el árabe y CJK reducidos como "errores tipográficos" que no existen.
- La verdad geométrica (qué está dónde, visible, su opacidad) proviene de
-
Seam gate (recomendado). Sirve la carpeta del video en localhost, luego ejecuta
node "$SEAM_GATE" verify --ledger ledger.json --url http://127.0.0.1:<puerto> --comp-url http://127.0.0.1:<puerto>/index.html. El objetivo es 0 FALLOS. Las filas donde un giro de cámara de una sola toma mantiene ambas ventanas en pantalla necesitan"overlap": "camera"más el parche enpatches/. Detén el servidor después. Consultareferences/qa-gates.md. -
Mezcla. Cada SFX vive en
window.__events({t, type:'sfx', name, gain, dur?, speed?}).- Extráelos con
node $MOTIONMAXXING/scripts/render.mjs index.html --still <t> ev, que escribeev/events.json. - Mezcla:
python scripts/mix_events.py --events ev/events.json [--vo vo.wav --vo-at 0.10] [--music bed.wav --music-trim s] --dur <s> --out audio/mix.wav [--music-db -24] [--tp -2.5] [--whip/--whoosh/--typing samples] [--lift t0:t1:dB] [--fade t]. - Niveles: VO a -18 dBFS RMS, música a -30 con ducking bajo la VO, whooshes alineados al pico del fotograma más rápido de la cámara, loudnorm de dos pasadas a -14 LUFS / TP ≤ -1.
- Extráelos con
-
Render + puertas + entrega.
- Render:
node $MOTIONMAXXING/scripts/render.mjs index.html <NUEVO-nombre>.mp4 --audio ../audio/mix.wav --crf 17 --grain 0.03. Usa un nuevo nombre de salida para cada intento: dos renders en un archivo lo corrompen. ffmpeg -v error -i x.mp4 -f null -debe imprimir nada. Luego ejecutapython $MOTIONMAXXING/scripts/look.py x.mp4 --out look --expect <dur> --expect-audio(G0/G2/G3/G5 PASS) ynode $MOTIONMAXXING/scripts/lint.mjs index.html.- Entrega: el master 9:16, un recorte 4:5 (
crop=1080:1350:0:200una vez que el diseño esté verificado), 2-3 PNG de portada, NOTE.md (idea, mapa de tiempos, datos reales vs ilustrativos, fuentes de audio + licencias, números de puerta, qué mejorar) y una carpetaproject/(video + audio + scripts). - Limpieza: detén servidores y Chrome headless huérfano.
- Render:
-
Retrospectiva (OBLIGATORIA, antes de tu respuesta final). Añade una regla fechada + por qué a
references/lessons.md. Agrega una fila areferences/runs.md(fecha, tipo de producto, estilo, duración, números de puerta, veredicto cuando se sepa). Parchea este archivo, un script o el kit si un paso cambió. Cuando el usuario reaccione más tarde, registra el veredicto. Las lecciones solo contienen método, nunca nombres de clientes ni datos privados.
Barra de calidad
- Gancho: fraseo real del cliente o una brecha de curiosidad. Fotograma 0 en movimiento, el gancho legible para el fotograma 1, sin aparecer desde negro.
- Continuidad: un portador a través del video (cursor, chip, marca del logotipo), sin fundidos cruzados, y 2-3 tipos de transición repetidos. Los cortes ocurren en medio del movimiento y con velocidad emparejada. Mantén una dirección actual: para "siguiente", los videos RTL viajan contenido izquierda→derecha y los videos LTR derecha→izquierda. Los vectores reservados se gastan en significado.
- Bloqueo de tiempo: cada clic, caída y aterrizaje se sitúa en
w(i)obeat(k), y la caída de la música se sitúa en una palabra de la VO. Los whooshes se derivan de la velocidad de la cámara. El mapa de tiempos lista cada evento y a qué está sincronizado. - Sin vibración ociosa: cada pausa tiene un movimiento de cámara con intención, una revelación escenificada o una UI en vivo. La quietud solo pertenece justo antes de un clímax.
- Zonas seguras (1080×1920):
- Ubicaciones pagadas de Meta: texto legible en y 270-1250 y x 60-960 (los 120 px de la derecha son botones);
- Reels/TikTok orgánicos: mantén despejados los 320-370 px inferiores;
- coloca el carril de subtítulos debajo de los paneles de UI, nunca sobre un compositor;
- las palabras del carril de caída ya muestra la imagen.
- Final: marca registrada más una CTA en el canal real de la marca. Mantén el final 0.6-1.4 s y que el último plano sea ≤ 25 % del video.
- Honestidad: declara datos ilustrativos en NOTE.md. Nunca inventes afirmaciones de rendimiento, precios o testimonios.
- Objetivos: look.py G0/G2/G3/G5 PASS, energía de movimiento ≥ 5/255 de cambio de luminancia media (los videos de UI oscura rondan 2), sincronización de corte ≥ 35 % (el punto de referencia profesional medido), -14 LUFS ± 0.5 con pico verdadero ≤ -1 dBTP, 0 errores de decodificación.
Notas de plataforma
- Trabajos en segundo plano en Windows git-bash: llama a
node.exe, no al aliasnodede winpty ("stdin is not a tty"). - Una importación ESM de una ruta absoluta de Windows necesita
file:///C:/.... - Chrome Headless tiene fugas de ejecuciones interrumpidas. Al final, lista los navegadores iniciados con
--headless=newy--remote-debugging-port=0cuyo padre se haya ido, y mata la raíz con su árbol. - Velocidad de render: UI plana ≈ 4 min por 35 s a 1080×1920. Un mundo 3D ≈ 4-5 min a ~4 fps, pero solo si el recuento de capas 3D se mantiene pequeño.
Archivos
scripts/:preflight.py: dependencias y aviso de ElevenLabs;new_film.py: andamio de un proyecto;fetch_fonts.py: woff2 local;words.py: tiempos de palabra;beats.py: cuadrícula de ritmo y caída;synth_bed.py: música sin clave;mix_events.py: mezcla basada en eventos;sheet.py: hoja de contactos;probe.mjs: geometría en vivo.
templates/one-take/: el demo completo de cámara 3D de una sola toma como un proyecto ejecutable (producto ficticio, copia en árabe RTL), con STORYBOARD.md y ledger.json.references/:research.md: encuesta del panorama, habilidades ascendentes, notas de seguridad, especificaciones de plataforma;lessons.md,runs.md: la memoria de autoaprendizaje;audio-providers.md,one-take-kit.md,montage-kit.md,qa-gates.md.
patches/seam-gate-camera-overlap.patch: regla de seam-gate opt-in para videos de cámara de una sola toma.