Communitygithub.com

motionkit

Crea películas de motion graphics escribiendo código con el motor canvas motionkit: copia el movimiento (timing, diseño, desplazamiento) de un video de referencia con tus propias palabras y arte, o construye una nueva película al ritmo de una canción a partir de 44 movimientos prefabricados con banda sonora sintetizada. También genera títulos animados transparentes y superposiciones y los coloca en una línea de tiempo de EditMax mediante las herramientas MCP de EditMax. Úsalo para

¿Qué es motionkit?

motionkit es un motor de canvas que permite a desarrolladores y creadores generar películas de motion graphics completamente desde el código, usando JavaScript. El skill está diseñado para plataformas como Claude Code y EditMax, y se integra con herramientas MCP para colocar los resultados directamente en una línea de tiempo de edición. El usuario escribe un script que define fotogramas (30 fps, 1920x1080), y el motor se encarga del renderizado (a 60 fps con ffmpeg), la síntesis de banda sonora y la sincronización. Incluye 44 movimientos prefabricados (como transiciones, animaciones de texto, efectos de partículas y gráficos), así como la capacidad de analizar el tempo de una canción real para sincronizar cortes. El skill también puede generar títulos animados con fondo transparente (en formato .mov ProRes 4444) para superponer sobre metraje existente. Está optimizado para flujos de trabajo donde se necesita

Compatible con✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/SkidGod4444/motionkit/tree/HEAD/skills/motionkit

Preguntar en tu IA favorita

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

Documentación

¿Qué hace motionkit?

Una película es una página más un script cuyo renderFrame(f) dibuja el fotograma f (30 por segundo, 1920x1080) y nada más. Chrome oculto avanza los fotogramas, ffmpeg codifica (el mp4 se duplica a 60 fotogramas por segundo con alta calidad, aproximadamente 4 a 5 MB por segundo de película) y la banda sonora se sintetiza.

Dónde están las cosas

  • Motor: la carpeta engine/ junto a este archivo (movimientos, renderizador, sonido, comprobaciones, fuentes). Llámalo $E y usa su ruta completa. Léelo; nunca coloques películas en él (la configuración añade su propio node_modules allí, lo cual es esperado).
  • Carpeta de trabajo: la carpeta en la que el usuario está trabajando. Las películas (<nombre>.html, <nombre>.js), assets/, ref/ y out-<nombre>/ van allí, y todos los comandos se ejecutan desde allí. Una página encuentra lib.js, moves.js y fonts/ en el motor por sí misma. Si la carpeta de trabajo es un repositorio git, añade out-*/ y ref/ a su .gitignore.

Primero: configuración (una vez por máquina)

  1. Ejecuta sh $E/setup.sh. Solo comprueba: bun, ffmpeg con ffprobe, python3, uv, un navegador Chromium (Chrome, Chromium o Edge; CHROME_PATH lo sobrescribe) y el único paquete del motor.
  2. Si imprime Ready, continúa. Si solo falta el engine package (normal en una instalación nueva), ejecuta sh $E/setup.sh --install sin preguntar: solo obtiene un paquete en la propia carpeta del skill. Si una herramienta o el navegador están MISSING, muéstrale al usuario esa lista y los comandos de instalación que imprimió, y pregunta una vez antes de instalar software en su máquina.
  3. Si responde que sí, ejecuta sh $E/setup.sh --install (Homebrew en macOS, los instaladores oficiales de bun y uv), luego vuelve a ejecutar la comprobación. Las líneas que dicen run this yourself necesitan la contraseña del usuario (sudo en Linux) o una descarga manual: nunca las ejecutes; dale al usuario el comando exacto y espera. Si una instalación falla, dale al usuario el comando único para que lo ejecute él mismo.
  4. Demuéstralo que funciona: desde la carpeta de trabajo ejecuta bun $E/build.ts hello y confirma que existe out-hello/hello.mp4.

Probado solo en macOS; indícalo si el usuario está en Linux o Windows.

Ejemplos de trabajo para copiar: $E/hello.js (una película sobre una cuadrícula de ritmo, cada sonido de clips, escenario dibujado en código), $E/title.js (un título transparente para superponer sobre metraje), $E/moves-demo.js (cada movimiento una vez).

Construir una película: primero los clips

Declara cada uso de un movimiento una vez como un clip. La imagen, el sonido y la comprobación del tiempo de lectura provienen de esa única línea.

const M = window.MOVES, B = M.brand, G = M.grid(120);          // 120 bpm: un pulso son 15 fotogramas, un compás 60
const K = { line: M.clip("words", G.bar(1) + 2, 10, { text: "Copia el movimiento.", x: 960, y: 590, size: 110, fam: B.display, stretch: B.wide, weight: 600, color: B.paper, until: G.bar(2) }) };
// en una escena:  K.line.draw(X, f)          K.line.on(f) es verdadero mientras deba ser visible
window.timeline = () => ({ fps: 30, total: TOTAL, bpm: G.bpm, sections: [[0, "intro"], [4, "build"], [8, "drop"], [24, "outro"]], cues: M.cues(), captions: M.captions() });

Para una película de lanzamiento o producto, lee primero «Películas de lanzamiento y producto» a continuación. Inicia una película con bun $E/new.ts <nombre>: escribe <nombre>.html y <nombre>.js en la carpeta de trabajo, copiados del ejemplo hello. Reescribe los clips, las escenas y el texto. bun $E/build.ts <nombre> luego hace, en orden: línea de tiempo, banda sonora (sound.py), comprobación de sonido, comprobación de tiempo de lectura (lint.py), renderizado, unión, comprobación de sincronía (sync.py) y escribe out-<nombre>/<nombre>.mp4. Una línea de tiempo sin bpm obtiene una banda sonora más simple de audio.py (solo cortes). Cambios de línea de tiempo: sound: "fx" (solo sonidos de movimientos, sin música), sound: "none", alpha: true (fondo transparente, salida .mov; consulta la sección de EditMax).

Anatomía de un script de película

$E/hello.js es el modelo; léelo una vez. Qué es cada parte:

  • Globales de lib.js: W, H (1920, 1080), X (el contexto del canvas), clamp, lerp, TAU, hash, noise, txt(ctx, text, x, y, size, weight, color, fam, italic, align), rr (rectángulo redondeado), vignette(strength, innerRadius).
  • M.clip(move, start, length, options): start y length son fotogramas; length es cuánto tiempo tarda el movimiento en reproducirse, no cuánto tiempo permanece. Devuelve { draw(ctx, f), t(f) (0..1 durante el movimiento), on(f), o (las opciones) }. Después de su duración, un clip sigue dibujando su estado final: no se oculta. Ocúltalo terminando la escena, o con if (K.x.on(f)), donde on es verdadero desde start hasta until (para siempre sin until). Para mostrar un movimiento de texto terminado dentro del from de una transición, dibújalo en t = 1: M.words(ctx, 1, K.line.o). Los efectos de un solo disparo (burst, glitchCut) también necesitan K.x.t(f) < 1.
  • Formas de llamada dentro de un clip: las transiciones toman from y to en las opciones; los envoltorios (punch, shake, sweep, smear) toman draw. Todo lo demás (pathDraw, burst, bars, chart, callout, logoDraw, bounce, ticker) solo toma opciones. mesh y parallax son fondos: llámalos directamente, M.mesh(ctx, f / 240, { colors }), donde t es solo un número que crece lentamente.
  • Opciones de texto: x es el centro de la línea (align: "center" es el predeterminado), y la línea base. stretch: B.wide da el corte ancho, stretch: null lo desactiva. Nada mide ni ajusta el texto por ti: con un tamaño de 150 ancho, 13 caracteres abarcan aproximadamente 1340 px, así que renderiza un fotograma fijo y verifica que cada línea quepa dentro del marco con margen.
  • Tabla de escenas: [primer fotograma, draw(f), drawAfterFinish(f)]. renderFrame restablece el estado del contexto (mantén esa línea), dibuja la escena actual, luego grano y viñeta, luego la tercera ranura para cualquier cosa que deba permanecer limpia (logotipos).
  • window.ready: una promesa que el renderizador espera: Promise.all([M.fonts(), M.levels("out-<nombre>/levels.json"), M.load({ ... })]). M.levels solo se necesita para M.eq y es seguro antes de que el archivo exista.
  • Línea de tiempo: sections son [pulso, nombre]; una película corta puede usar solo [[0, "intro"], [8, "drop"], [16, "outro"]], y cada inicio de drop recibe el medio pulso silencioso (mantén o mute: clips allí). sync enumera los fotogramas donde un corte y un golpe de bajo deben coincidir: usa el primer fotograma de cada escena a partir del drop. El «cambio» se evalúa en comparación con la diferencia habitual de fotograma a fotograma de la película, por lo que si una transición termina exactamente en un fotograma de sincronía, no deja ningún cambio allí y la comprobación imprime NO CHANGE: añade un destello corto o inicia el siguiente movimiento en ese fotograma. cuts es cada inicio de escena.
  • Colores: lee todo de M.brand (B). M.rgba(B.ink, 0.7) da un color con una opacidad, M.mix(a, b, t) un color entre dos. M.setBrand cambia M.brand en su lugar; llámalo antes de declarar cualquier clip y establece accentOnDark también (el acento usado en fondos oscuros; no sigue a accent). Para una fuente sin corte ancho, establece wide: null.
  • Duración: el tiempo de lectura establece el mínimo: una línea de 3 palabras necesita aproximadamente 1.3 s después de haber aparecido, así que una línea por compás a 120 bpm. La banda sonora se ejecuta aproximadamente medio segundo después del último fotograma y se corta allí; termina en una sección outro para que el corte caiga en su cola.
  • Resultados de la construcción: build.ts sale con 0 incluso cuando una comprobación falla; los fallos se imprimen como líneas WARNING: con el detalle arriba. Trata cada advertencia como un fallo: lee la salida (filtra las líneas de progreso frame n/total), corrige, reconstruye hasta que no haya ninguna. Los fotogramas fijos se escriben como out-<nombre>/fNNNN.jpg; léelos. bun $E/pure.ts <nombre> confirma que los fotogramas se renderizan igual solos y después de otros fotogramas.
  • sound.py necesita numpy y siempre se ejecuta a través de uv run; los otros scripts de Python solo usan la biblioteca estándar.

Películas de lanzamiento y producto: muestra el producto

Una película de palabras grandes sobre un fondo se lee como básica. Las películas de lanzamiento que funcionan mantienen el producto en pantalla en un mundo visual único con profundidad y una cámara que se mueve lentamente, usan texto breve y pequeño, y mantienen las tomas durante 2 a 6 segundos (unos pocos compases), no un corte por pulso. Para una película de lanzamiento o producto NO empieces desde hello:

  1. Decide primero el aspecto: un mundo de fondo, un color de acento, una familia tipográfica. Dilo al usuario en dos líneas.
  2. Storyboard de 6 a 8 tomas de cosas reales: la pantalla o salida real del producto, comandos reales, código real, resultados reales. Nunca dibujes una interfaz que el producto no tenga, nunca inventes números y nunca uses el logotipo de otra empresa. Los pies de foto son etiquetas pequeñas (txt, mono, abajo a la izquierda), no titulares.
  3. Construye primero una toma principal, renderiza fotogramas fijos y compárala con una película de lanzamiento real antes de construir el resto.

La página debe cargar stage.js después de moves.js (las páginas creadas por new.ts lo hacen). Comienza renderFrame con M.frame(); M.reset(X);. Piezas del escenario (todas en MOVES):

piezaqué es
backdrop(ctx, f, { base, lights[], streak })casi negro con piscinas lentas de luz: el mundo en el que todo se asienta
glass(ctx, x, y, w, h, { r, top, bottom, rim, shadow })un panel redondeado oscuro con un borde de luz y una sombra suave
camera(ctx, cam, draw) con cam(a, b, t, ease)mira un punto de una escena más grande: { x, y, zoom, rot }; comienza macro-cerca y retrocede, o deriva lentamente
tilt(ctx, draw, { depth, focus, blur, fog, top, height, width, cx, roll })dibuja una escena de fotograma completo como un plano inclinado hacia atrás, el borde lejano más pequeño, más oscuro y desenfocado
tiles(ctx, f, { cells: [{ draw(ctx, t), label, bg, len, hold }], cols, x, y, w, gap })una cuadrícula de pantallas pequeñas, cada una reproduciendo un movimiento en vivo (nunca pongas una transición dentro de un mosaico)
term(ctx, f, { x, y, size, lines: [{ text, at, speed, prompt, mark: "ok" o "run", color }] })líneas de terminal que se escriben o aparecen en su fotograma
code(ctx, { lines[], x, y, size, lead, hot, shown })JavaScript con color de sintaxis discreto y una línea iluminada
wave(ctx, { peaks, x, y, w, h, played, beats[], blocks[] })la forma de una banda sonora real con un cabezal de reproducción, marcas de pulso y clips en un carril

Las piezas del escenario no generan sonido propio: añade señales manualmente a la línea de tiempo, { f, kind, gain } con tipos como type, tick, pop, ding.

Cortar a una canción real

  1. El usuario proporciona el archivo de música y debe tener el derecho de usarlo; indícalo y pon el crédito que solicite una licencia en la tarjeta final. Nunca descargues una canción de un sitio de streaming.
  2. uv run $E/beats.py <archivo> imprime el tempo y qué tan fuerte es cada compás. Elige un extracto que comience en un compás con un cambio de sección unos compases después, luego uv run $E/beats.py <archivo> --from <segundos> --len <segundos> --out beats.json escribe beats.json y beats.js.
  3. Carga beats.js en la página antes del script de la película. Escribe cada inicio de escena como un número de pulso: const b = (n) => window.BEATS.frames[n]. Corta en los compases (cada 4 pulsos), donde la pista cambia.
  4. En la línea de tiempo establece music: { file, from }, sound: "fx" (los sonidos propios de los movimientos permanecen, en silencio, bajo la música) o "none", un bpm y sync: [fotogramas de los cortes reales]. La construcción mezcla la pista a -16 LUFS, desvanece su final y verifica que cada corte tenga un golpe de bajo dentro de un fotograma. No añadas destellos solo para pasar esa verificación.

Movimientos para EditMax (un clip en la línea de tiempo de un editor de video)

Usa esto cuando el usuario está editando en EditMax y quiere un movimiento en el corte: un título animado sobre metraje, una tarjeta de introducción o cierre, un ritmo cinético entre tomas. Necesita dos cosas en la misma sesión del agente: un shell (para renderizar) y las herramientas MCP de EditMax (inspect_timeline, import_media, ...; configuradas desde la pestaña Agents de EditMax). El chat interno de la aplicación de EditMax rechaza comandos de shell, por lo que no puede ejecutar este skill: indícalo y dile al usuario que conecte un agente como Claude Code. Si faltan las herramientas de EditMax o no responden, renderiza el clip de todos modos y dale al usuario la ruta del archivo para arrastrar.

1. Elige la ruta. Prefiere las herramientas propias de EditMax cuando cubran el movimiento, porque el texto permanece editable en la aplicación:

deseadouso
un título o tercio inferior que se desvanece, desliza, aparece, escribe o limpiaadd_text / add_lower_third + set_text_animation
una disolución, empuje, deslizamiento, cortinilla o iris entre dos clipsset_transition
un clip que se mueve, escala o desvaneceset_keyframe, set_clip_transform, set_clip_fades
cualquier otra cosa: golpe, revuelo, solapa dividida, rueda de palabras, tachado, resaltado, dibujo de trayectoria o logotipo, gráficos, contadores, ráfagas, secuencias de múltiples movimientos, una introducción o cierre completorenderiza un clip con este skill

2. Lee el proyecto. inspect_timeline: anota el tamaño del fotograma, la velocidad de fotogramas, las pistas y el tiempo donde va el movimiento. Este motor renderiza 1920x1080 a 30 fotogramas por segundo. Un proyecto 16:9 de otro tamaño lo escala limpiamente. Para un proyecto vertical o cuadrado, di claramente que el clip se encuadrará en formato carta o deberá escalarse y recortarse con set_clip_transform, y que un título nativo puede ser mejor.

3. Renderiza.

  • Superposición (se coloca sobre el metraje): bun $E/new.ts <nombre> --overlay, modelado en $E/title.js. La línea de tiempo tiene alpha: true y sound: "fx"; la construcción escribe out-<nombre>/<nombre>.mov (ProRes 4444 con un fondo transparente). Reglas: limpia el fotograma (X.clearRect), nunca lo rellenes; sin grain, vignette, mesh, parallax ni transiciones de fotograma completo; coloca una sombra suave o una placa debajo del tipo para que se lea sobre cualquier metraje; mantén el tipo dentro del 90% central del fotograma; desvanécelo al final.
  • Fotograma completo (introducción, cierre, una tarjeta entre tomas): bun $E/new.ts <nombre>, modelado en $E/hello.js; la construcción escribe out-<nombre>/<nombre>.mp4.
  • Sonido (establece sound: en la línea de tiempo): déjalo fuera para la banda sonora completa (una introducción o cierre independiente); "fx" para solo los sonidos que hacen los movimientos (cualquier cosa que se reproduzca sobre metraje, voz o la música del usuario); "none" para silencio. Pregunta cuál quiere el usuario si la edición ya tiene música.
  • Construye, corrige cada WARNING y lee fotogramas fijos antes de continuar.

4. Coloca el archivo en algún lugar que dure. EditMax referencia los archivos importados, no los copia. Copia el archivo terminado fuera de out-<nombre>/ a una carpeta que el usuario conserve (pregunta una vez; sugiere ~/Movies/Motions/) e importa desde allí.

5. Colócalo sin mover el corte del usuario. insert_clip con un tiempo es un desgarro…

…[truncado para traducción]

Skills relacionados