Communitygithub.com

Lob0Garou/opus-visual-motion-engine

Pipeline disciplinada para gráficos en movimiento: video/UI renderizado por código, seek(t) determinista, QA automático de renderizado, exportación MP4 — funciona con modelos solo de texto.

¿Qué es opus-visual-motion-engine?

Opus Visual Motion Engine es una pipeline disciplinada para la creación de gráficos en movimiento y videos generados por código, diseñada para funcionar incluso con modelos de lenguaje que solo procesan texto. Su enfoque principal es la calidad basada en gates aplicados antes y después del renderizado, no en el gusto subjetivo. El sistema soporta la creación de videos, motion graphics, tipografía cinética, páginas web, dashboards, diagramas y visualización de datos, utilizando una arquitectura determinista donde `render(t)` es el único controlador de estado. Esto garantiza que `seek(x)` siempre reproduzca el mismo fotograma independientemente del historial de renderizado. La pipeline incluye un template de composición HTML que maneja la captura y exportación, un sistema de QA automatizado (`qa.mjs`) que verifica colisiones, contraste, animaciones y errores, y un flujo de trabajo estructurado en pasos secuenciales: planificar, construir desde la plantilla, renderizar, QA, corregir y exportar. Es ideal para desarrolladores y creadores de contenido que buscan resultados consistentes y de alta calidad en animaciones y videos generados por código.

Compatible con✓Claude Code~Codex CLI~Cursor
npx skills add Lob0Garou/opus-visual-motion-engine

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Opus Visual Motion Engine

Una pipeline disciplinada para entregables visuales: planificar → construir desde la plantilla → renderizar → QA → corregir → exportar. La calidad proviene de los gates aplicados antes y después del renderizado, no del gusto. Sigue los pasos en orden. No te saltes ningún paso porque la tarea "parezca simple".

Las rutas a continuación son relativas al directorio de este skill (la base skill_resources que se te proporcionó). Llámalo $SKILL.

0. Leer primero (incondicional)

Antes de escribir cualquier código, lee las referencias que coinciden con el entregable. Son autoritativas en su tema:

EntregableLeer
video, motion graphic, explicativo, video de productoreferences/video-generation.md, references/motion-design.md, references/javascript-animation.md
tipografía cinética / pieza liderada por textoel conjunto de video anterior + references/typography.md
página de aterrizaje, dashboard, maqueta, UIreferences/visual-design.md, references/typography.md
diagrama, esquema, visualización de datosreferences/visual-design.md §4
decisiones de encuadre / cámarareferences/cinematography.md
duraciones y easingreferences/animation-primitives.md
música o voz para sincronizarSKILL.md §10 + references/video-generation.md §6

Los ejemplos prácticos están en examples/*.md. Lee el más cercano al briefing.

1. Planificar antes del código (escribirlo)

Escribe el plan en tu respuesta (o en un PLAN.md junto al archivo de salida) antes de crear el HTML. Un plan que existe solo en tu cabeza no cuenta.

UI / página

  1. Mensaje principal: una oración. ¿Qué debe entender el espectador en 3 segundos?
  2. Dirección nombrada: un nombre, 4–6 tokens hexadecales con significados asignados, tipografías con roles, tratamiento de formas. Derívalo de la industria del tema, los materiales y el lenguaje vernáculo. Una juguetería y un dashboard fintech nunca comparten una dirección.
  3. Jerarquía: etiqueta cada bloque como PRIMARY / SECONDARY / TERTIARY. Solo PRIMARY recibe el único gesto audaz.
  4. Progresión de secciones: una línea por sección, indicando su función y cómo realiza la transición a la siguiente.
  5. Matemáticas previas al renderizado: ancho del texto ≈ caracteres × 0.55 × font-size (sans) o × 0.5 (serif); ancho de la caja = max(título_caracteres × 8, subtítulo_caracteres × 7) + 24 a 14px; ajuste de fila = Σanchos + espacios ≤ contenedor. Traza cada conector contra cada caja. Si se cruza con uno, enruta un camino en forma de L.

Video / motion graphic

  1. Mensaje central: una oración. Si necesita dos, hay dos videos.
  2. Tiempos clave: 3–7. Cada tiempo clave responde "¿qué sabe ahora el espectador?"
  3. Tarjeta de escena por tiempo clave: inicio/fin (s), composición, cámara, tamaños de texto, primitivas (2–4), salida. Usa la plantilla en references/motion-design.md §2.
  4. Momento insignia: nombra el ÚNICO fotograma donde se muestra el mecanismo, no se etiqueta (por ejemplo, ruido filtrado en señal). Si la historia solo funciona con sus leyendas, rediseña el tiempo clave.
  5. Línea de tiempo global: marcas de tiempo absolutas. La SALIDA de una escena se completa antes de que la siguiente escena ocupe el espacio. Establece DURATION en el final real (10–20s por defecto; 30–45s solo con narración).

Una escena sin tarjeta no pertenece al video.

2. Construir desde la plantilla (video)

Copia assets/composition-template.html junto al entregable y completa los bloques EDIT. No reescribas los bloques ENGINE. Ya proporcionan:

  • un #stage de 1920×1080 (cambia STAGE_W/H para 1080×1920 o 1080×1080), ajustado a cualquier ventana;
  • window.DURATION, window.seek(t), window.render(t), window.SCENES: el contrato de captura/exportación (QA captura cada escena de SCENES);
  • at(), ease.*, lerp, mulberry32 (PRNG con semilla), y layer() para la visibilidad de escenas más EXIT;
  • ayudantes de audio audioAt(t, "rms"|"low"), since(t, list), hit(t, list, dur) que leen window.AUDIO (§10) y devuelven 0 sin él;
  • un reproductor de vista previa (espacio, ←/→, Inicio/Fin) que se desactiva automáticamente durante la captura y con movimiento reducido;
  • tokens de color en las 3 capas requeridas (claro, con protección prefers-color-scheme, [data-theme]).

Para páginas, escribe un HTML normal de un solo archivo siguiendo §6.

3. Tiempo determinista (video)

  • render(t) es el único controlador de estado. Cada posición, opacidad, tamaño, número y dashoffset se calcula a partir de t en segundos. seek(x) renderiza el mismo fotograma sin importar lo que se haya renderizado antes.
  • t está en segundos. Limita t a [0, DURATION], nunca a [0, 1]: limitar segundos a 0..1 congela silenciosamente toda la línea de tiempo.
  • Prohibido: setTimeout, setInterval, animaciones/transiciones CSS como línea de tiempo, Math.random() sin semilla, Date.now() en estado. requestAnimationFrame solo puede avanzar el reloj de reproducción y llamar a render(clock). La plantilla ya hace esto.
  • Aleatoriedad: genera en tiempo de construcción a partir de mulberry32(semilla), nunca dentro de render.
  • El dibujo SVG necesita los tres: pathLength="1", stroke-dasharray="1", y stroke-dashoffset de 1 a 0. Sin dasharray, la línea aparece completamente dibujada desde el fotograma 0.
  • Los spans de inline-block se tragan los espacios finales. Pon el espaciado en margin-right.

4. Gramática del movimiento

Cinco movimientos, cada uno con un trabajo. Si un movimiento no es ninguno de estos, elimínalo.

  • ENTER: una secuencia orquestada por página o escena, en orden de lectura, hermanos escalonados 60–120ms. Desvanecer hacia arriba en cada sección es el sello de IA.
  • EMPHASIS: un elemento a la vez: un aumento de escala (≤1.2), un brillo o un cambio de color que tenga significado.
  • TRANSITION: un cambio de estado. La parte que cambia se mueve; todo lo demás permanece quieto. 0.2–0.6s.
  • CAMERA: una escala/traslación a nivel de escenario, como máximo una vez por escena, 0.8–1.2s, nunca durante una lectura de texto.
  • EXIT: 0.3–0.5s, completamente completado. Ningún elemento sobrevive en estado intermedio a través de un límite de escena, excepto un ancla de continuidad deliberada que persiste idéntica o morph (el mismo objeto cambiando de estado, que es la transición más fuerte disponible).

Las transiciones tienen significado: corte duro = cambio de categoría, morph = lo mismo cambiando, paneo = recorrido. Nunca un crossfade predeterminado en todas partes. Las duraciones y easings están en references/animation-primitives.md. Los vecinos que se mueven juntos obtienen duraciones diferentes o un desplazamiento.

5. Decisión del stack

SituaciónStack
micromovimiento de páginatransiciones CSS en transform/opacity, 0.2–0.6s; bucles ≤2s dentro de @media (prefers-reduced-motion: no-preference)
video / motion graphic / tipo cinéticoplantilla + vanilla render(t) (por defecto)
>6 pistas escalonadas u orquestación de morph SVGGSAP UMD fijado, UNA línea de tiempo maestra en pausa, seek(t) → tl.seek(t)
gráficosSVG en línea (por defecto) o Chart.js UMD con animation:false, colores hex (canvas no puede leer variables CSS)
arte generativop5.js con randomSeed/noiseSeed
3D, solo cuando 3D es el mensajeThree.js UMD fijado; cámara scripteada en render(t)

Usa el stack más simple que alcance el resultado. Los scripts externos deben ser versiones fijadas exactas de cdnjs.cloudflare.com o cdn.jsdelivr.net. Inlinea todo lo demás. Cada fuente obtiene una pila de respaldo real.

6. Base técnica (no negociable)

  1. Único .html con CSS y JS en línea, menos de 16 MB, imágenes/datos como URI data:.
  2. Colores como tokens :root; capa oscura bajo @media (prefers-color-scheme: dark) protegida por :root:not([data-theme="light"]) y repetida bajo :root[data-theme="dark"]; fondo body explícito.
  3. meta viewport con viewport-fit=cover; relleno env(safe-area-inset-*); height:100% en html/body, nunca 100vh; bloques anchos se desplazan dentro de su propio overflow-x:auto; las cuadrículas usan minmax(0,1fr).
  4. Los números calculados mostrados pasan por Math.round, toFixed o Intl.NumberFormat. Los contadores deben aterrizar exactamente en el valor final.
  5. Accesibilidad: contraste ≥4.5:1 (≥3:1 para texto ≥24px), foco visible, prefers-reduced-motion respetado (la plantilla muestra el fotograma final establecido).
  6. Tipo legible: en un fotograma de video 1080p, ningún texto por debajo de 20px (H/54). En páginas móviles, ningún texto del cuerpo por debajo de 14px.
  7. El almacenamiento del navegador nunca mantiene el estado de la línea de tiempo. Cuando se use almacenamiento, envuélvelo en try/catch.

7. Evitar diseño genérico de IA

Cuando el briefing deje libertad, nunca la gastes en estos valores predeterminados (qa.mjs señala varios de ellos automáticamente):

SelloCorrección
crema #F4F1EA-ish + serif de exhibición + acento terracota #D97757-ishuna paleta tomada de los propios materiales del tema
casi negro + un acento ácido, usado independientemente del temapermitido solo cuando la dirección lo justifica por escrito
tarjetas redondeadas idénticas, un radio en todas partes, la misma sombra suavetokens de radio por jerarquía; tarjeta solo para objetos delimitados
degradados como decoración, degradados púrpura, glassmorphismrellenos planos; un degradado como máximo, solo para una propiedad física continua
cejas en MAYÚSCULAS con tracking, meta strings con punto medio, "→" en enlacesminúscula; elimina etiquetas que repiten el contenido
Inter / fuente del sistema por defectotipografías elegidas para este tema, con una pila de respaldo
una sola palabra acentuada en un titularpermitido SOLO cuando el color de acento es un token semántico utilizado para el mismo significado en otra parte de la pieza (por ejemplo, coral = ruido)
héroe genérico: titular + subtítulo + CTA + captura de pantallaabre con la cosa más característica en el mundo del tema
todo centrado, el mismo ritmo de cuadrícula en cada secciónun sistema de alineación por sección; varía el ritmo
todo animándose a la vez, 300ms en todas partesel mapa de duraciones + escalonamiento (§4)

Gasta la audacia en un lugar, luego elimina un accesorio.

8. Renderizado + QA (obligatorio antes de entregar)

Ejecuta el QA automatizado. Renderiza el archivo sin interfaz gráfica y escribe evidencia más un veredicto. Necesita Node ≥18. La primera ejecución en una copia nueva del skill necesita npm install en $SKILL/scripts (saltar si scripts/node_modules existe).

node "$SKILL/scripts/qa.mjs" ruta/al/entregable.html

En DSH en Windows, ejecútalo con la herramienta pwsh usando el mismo comando. Opciones: --step 0.25 (una cuadrícula más fina para escenas rápidas), --out <dir>, --mode page|video.

Modo video (automático cuando existen DURATION + seek) captura un fotograma cada paso y verifica: APIs prohibidas, determinismo en revisitas fuera de orden, una línea de tiempo congelada, aire muerto, espacios casi vacíos, un fotograma final inestable, colisiones de texto, texto sobre otros gráficos, recorte, contraste, tamaño mínimo de letra, líneas dash-offset que nunca se dibujan, bucles con movimiento reducido, errores de consola/página y sellos de plantilla. Modo página renderiza escritorio 1440, móvil 390 y esquema oscuro, y verifica las mismas reglas de diseño más el desbordamiento horizontal en móvil.

Las salidas se colocan en qa-<nombre>/: report.md (veredicto y hallazgos), report.json (cobertura de tinta por fotograma y cambio), contact-sheet.png (cada fotograma en una imagen), moments.png (la entrada, el medio y el final de cada escena, tomados de window.SCENES), key_000..100.png, y frames/.

  • Pasa el momento insignia y cualquier punto de sincronización explícitamente: --at 5.4,9.1.
  • Las capas deliberadas (tipo cinético apilado a propósito, un título sobre material de archivo) van dentro de un elemento con data-qa-allow-overlap. Eso omite las comprobaciones de colisión y texto sobre gráficos solo para ese subárbol. Nunca lo uses para silenciar una colisión accidental.
  • Una ADVERTENCIA font significa que la familia de primera elección no se cargó y el texto está en un respaldo. Arréglelo antes de juzgar el diseño, porque cada ancho está mal.

Código de salida 0 = sin FALLO. FALLO es bloqueante. Cada ADVERTENCIA está corregida o justificada en una línea en tu crítica.

9. Bucle de crítica

  1. Si tu modelo puede leer imágenes: abre contact-sheet.png, luego cualquier key_*.png que parezca incorrecta. Juzga los píxeles, no tus intenciones.
  2. Si tu modelo es solo texto: usa report.md más la tabla por fotograma en report.json. coverage < 0.015 significa que el fotograma se lee vacío. Un diff de 0 en una escena significa que nada se mueve. Un pico en diff marca un corte. Verifica cada tarjeta de escena y sus marcas de tiempo contra estos números.
  3. Responde cada pregunta con una observación concreta, no con "✓":
    • Composición: en cada fotograma clave, ¿dónde aterriza primero el ojo? ¿Ese es el mensaje?
    • Jerarquía: ¿PRIMARY es inconfundible? ¿Hay exactamente una cosa en movimiento que importa por fotograma?
    • Mecanismo: ¿el momento insignia muestra la idea con las leyendas eliminadas?
    • Continuidad: ¿todas las transiciones son limpias, sin nada en estado intermedio en un límite y los anclajes idénticos o en morph?
    • Tiempo: ¿hay desplazamientos, sin duraciones predeterminadas, y tiempo de lectura ≥1.2s por cada 8 palabras?
    • Tipografía / contraste / densidad: tamaños según el plan, ≤5 elementos compitiendo por fotograma, legible en modo oscuro?
    • Narrativa: ¿podría un espectador repetir el mensaje central después de una visualización?
  4. Corregir → re-ejecutar qa.mjs → re-criticar. Repetir hasta que el QA pase y la crítica no tenga elementos abiertos.
  5. Pregunta final, respondida honestamente: "¿Esto parece diseñado intencionalmente, o meramente generado?" Si "generado": nombra qué es genérico, revisa el plan (§1) y reconstruye. Un primer renderizado casi nunca es el entregable. Espera 2–3 generaciones.

10. Sincronización de audio (cuando hay música o voz)

Nunca adivines el tiempo de oído. Convierte el audio en datos y deja que render(t) los lea:

node "$SKILL/scripts/audio-data.mjs" music.mp3 --inject composition.html   # escribe window.AUDIO en el HTML
  • AUDIO.beats (una cuadrícula espaciada uniformemente al tempo estimado), AUDIO.onsets (golpes, notas, sílabas), y por fotograma AUDIO.rms / AUDIO.low (0..1; low es la banda de kick/bajo <150 Hz).
  • Conduce el movimiento con los ayudantes de la plantilla: hit(t, AUDIO.beats, 0.2) para un pulso de golpe (EMPHASIS), audioAt(t, "low") para escala reactiva a golpes, since(t, AUDIO.onsets) para revelaciones por golpe. Pon los cortes de escena en los beats: elige los inicios de escena de AUDIO.beats.
  • La sincronización es exacta por fotograma por construcción: un pulso aterriza en el primer fotograma en o después de su beat (≤1 fotograma, ≤33 ms a 30 fps). Si el audio comienza más tarde que t=0, pasa --offset <s>.
  • Los niveles se verifican antes de que nadie escuche. Las muestras recortadas salen con código 1. Un pico de muestra por encima de −1 dBFS advierte, porque la codificación AAC lo recortará. Sonoridad fuera de −18..−12 LUFS se informa (las plataformas normalizan a aproximadamente −14).
  • --bpm anula la detección automática de tempo.
  • --inject agrega window.AUDIO a <script id="audio-data">.
  • Usa --test-only para obtener un resumen de la canción sin inyectar.

El audio nunca está en el HTML renderizado. La exportación de video mezcla el audio original con la salida renderizada en un paso posterior.

11. Exportación de video (MP4, H.264)

Cuando el QA pase y la crítica esté completa, renderiza el video final:

node "$SKILL/scripts/export-video.mjs" composition.html

Requisitos: FFmpeg en PATH (ejecuta ffmpeg -version para verificar). El script:

  1. Renderiza la composición desactivando la vista previa interactiva (--headless).
  2. Captura fotogramas en la frecuencia de cuadros estándar (30 fps, o --fps 60).
  3. Codifica H.264 con perfil de máxima compatibilidad: -pix_fmt yuv420p -profile:v high -level:v 4.0 -crf 18.
  4. Aplica --audio file.mp3 para multiplexar el audio desde la fuente original. Sin él, el video no tiene sonido.
  5. Escribe el resultado como composition-video.mp4 junto al archivo de entrada.

El paso --mux-only reemplaza el audio en un video ya renderizado sin volver a capturar fotogramas. Útil para ajustes de pista de voz sin tocar el diseño visual.

Salida de video: 1920×1080 (o la resolución configurada en la plantilla), 30 fps por defecto, duración exacta de DURATION. Los metadatos del archivo se escriben con creation_time desde la fecha de construcción.

12. Almacenamiento de entregables y versionado

Cada ejecución exporta contact-sheet y reportes a qa-<nombre>/ y el video a *-video.mp4. Nunca sobrescribas manualmente: deja que qa.mjs y export-video.mjs gestionen sus directorios. Si un entregable necesita múltiples iteraciones, usa archivos de entrada con nombres diferentes o mueve las salidas anteriores a un subdirectorio archive/.

Los activos de referencia (references/, assets/) son de solo lectura. Si cambias la plantilla o las reglas, hazlo en tu propia bifurcación.


Opus Visual Motion Engine v3.2 - Disciplina sobre opinión.

Skills relacionados