Communitygithub.com

JaviMaligno/agilabs-video-studio

Construye las escenas de un video explicativo de artículo en Remotion: escribe src/timeline.ts desde un guión aprobado, selecciona y configura componentes de animación (Counter, BarCompare, FlowDiagram, KeyQuote, StatGrid), agrega un componente personalizado con un frameState probado, mantén el área segura vertical y revisa los fotogramas renderizados visualmente. Úsalo al componer, cambiar o depurar las escenas de un video creado con este plugin.

¿Qué es agilabs-video-studio?

Este skill permite a un agente de IA (como Claude Code, Cursor o Codex) construir y depurar videos explicativos de artículos utilizando Remotion. El agente escribe el archivo `src/timeline.ts` a partir de un guión aprobado, donde define una secuencia ordenada de escenas de tipo `intro`, `anim` y `outro`. Las escenas `anim` utilizan componentes de animación predefinidos (Counter, BarCompare, FlowDiagram, KeyQuote, StatGrid) que se sincronizan automáticamente con las líneas de narración. El skill también guía al agente para crear componentes personalizados siguiendo un proceso paso a paso: primero se implementa un `frameState` puro con pruebas, luego se dibuja el componente en React, se registra en el catálogo y opcionalmente se agrega una muestra en la galería. Todo el flujo está diseñado para mantener el contenido dentro del área segura vertical (1080x1920) y asegurar que cada fotograma renderizado coincida con lo esperado, verificando visualmente los PNG generados. El skill incluye reglas de linting para validar duración, velocidad de subtítulos y nombres de componentes, lo que garantiza calidad consistente en la producción de videos.

Compatible con~Claude Code✓Codex CLI~Cursor
npx skills add https://github.com/JaviMaligno/agilabs-video-studio/tree/HEAD/skills/explainer-animation

Preguntar en tu IA favorita

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

Documentación

Animación explicativa

Un video es una lista ordenada de escenas en src/timeline.ts. Tres tipos:

  • intro: la tarjeta de enganche. Su primera línea es el enganche, se muestra grande y sus palabras se iluminan a medida que se pronuncian (sirve como su propio subtítulo).
  • anim: un componente de animación del registro, sincronizado con las líneas de narración de la escena.
  • outro: la tarjeta de cierre con la insignia de AGILabs, javieraguilar.ai y el título del artículo de SETTINGS.articleTitle.

Escribir la línea de tiempo

import type { Cuts } from './types.ts';
import { L, anim, intro, outro, say, videos } from './narrate.ts';

const build = (): Cuts => ({
  main: [
    intro('hook', [say(0.4, 'EN hook line.', 'ES hook line.')]),
    anim(
      'result',
      'BarCompare',
      { bars: [{ label: L('With the reason', 'Con el porqué'), value: 14, display: '14/20', highlight: true },
               { label: L('Without it', 'Sin él'), value: 4, display: '4/20' }], max: 20 },
      [say(0.3, 'First line.', 'Primera línea.'), say(0, 'Second line.', 'Segunda línea.')],
      { min: 4 },
    ),
    outro('outro', [say(0.4, 'More at javieraguilar.ai.', 'Más en javieraguilar.ai.')]),
  ],
});

export const VIDEOS = videos(build);
export const TIMELINE = VIDEOS.en.main;
  • say(at, en, es, spoken?): una línea de narración. at es el segundo más temprano de la escena en que puede comenzar; las líneas nunca se superponen (espacio de 0.35 s), y la escena dura hasta que su última línea termina más 0.8 s, o min. spoken ({ en?, es? }) es lo que lee el TTS cuando difiere del texto del subtítulo (ver narration).
  • Pulsos. El tiempo de inicio de cada línea en una escena es un pulso. Los componentes reproducen el paso i en el pulso i (la barra i crece, el nodo i aparece, el mosaico i aparece), así que escribe una línea por paso que quieras revelar. Antes de TTS, los pulsos provienen de una estimación de duración; después de npm run tts provienen del audio real, por lo que debes volver a revisar los fotogramas después de narrar.
  • L(en, es): una etiqueta bilingüe en pantalla. Una cadena de texto simple se usa para ambos idiomas.
  • Los identificadores de escena deben ser únicos: las claves de línea (<escena>-01, ...) nombran los archivos de audio.
  • opts.chapter en anim se almacena en la escena pero aún no es dibujado por ningún componente.
  • Ejecuta npm run lint después de cada cambio: verifica la longitud contra targetSeconds (±20 %), las señales de subtítulos con menos de 0.8 s o más de 17 caracteres/s, y los nombres de componentes que faltan en el registro.

Catálogo de componentes

Todos los componentes reciben t, beats, dur, lang y vertical de la escena; las props que aparecen a continuación provienen de la línea de tiempo. Los números mostrados en pantalla usan la forma exacta del artículo: prefiere display / value como cadena sobre el texto calculado siempre que el artículo escriba "14/20", "0.0018" o "83 %".

ComponenteUsoProps
CounterUna cifra principal que cuenta hacia arriba, con etiqueta debajovalue: number, label: Label, prefix?, suffix?, decimals? (0-8), beat? (índice del pulso en que comienza el conteo, por defecto 0)
BarCompare2-5 barras horizontales que crecen una por pulso; la resaltada en el degradado de acentobars: { label: Label; value: number; display?: string; highlight?: boolean; at?: number }[], max? (tope de escala, por defecto el valor más grande), unit? (se añade cuando no hay display)
FlowDiagramCajas y flechas que aparecen en orden; una arista broken es discontinua y atenuada, con un espacionodes: { id; label: Label; at?: number }[], edges: { from; to; label?: Label; broken?: boolean }[], layout: 'vertical' | 'horizontal' (usa vertical para el corte 9:16)
KeyQuoteLa frase clave, palabra por palabra, palabras enfatizadas en el acento con subrayadotext: Label, emphasis?: string[] (palabras o frases, coinciden ignorando mayúsculas y puntuación), beat?
StatGrid2-4 mosaicos de cifras que aparecen uno por pulsostats: { value: string; label: Label; at?: number }[]

at en una barra, nodo o mosaico lo fija a un segundo de la escena en lugar de su propio pulso. Los pasos sin un pulso o at siguen 0.6 s después del anterior. Cada componente está ajustado para que termine al final de la escena: el último fotograma siempre muestra el estado final.

Para ver la biblioteca completa: npm run studio y abre Gallery-vertical, o renderiza fotogramas de ella.

Agregar un componente personalizado

Cuando el guión marque una escena como "bespoke" (personalizada):

  1. Estado primero, con una prueba. Escribe src/anim/<Nombre>.state.ts con el tipo de props y un frameState(props, t, beats, dur) puro que devuelva números y cadenas simples. Sin importaciones de Remotion ni React allí. Constrúyelo sobre src/anim/steps.ts (sceneTime, stepTimes, fit, progress, beatAt, easeOutCubic) para que sea total: valores finitos en cualquier t, campos de progreso dentro de [0, 1], nada visible antes de su primer pulso, el estado final en t = dur.
  2. Agrega un caso a CASES en test/anim.test.ts (y una prueba de su propio comportamiento), luego ejecuta npm test. Verifica el estado en t < 0, cada pulso, dur y más allá de dur, con pulsos faltantes, tardíos y muy cortos.
  3. Dibújalo en src/anim/<Nombre>.tsx: llama a frameState, dibuja dentro de <Stage vertical={...}>, usa los tokens de marca de src/brand.ts (C, GRADIENT, alpha) e Inter. Sin nuevos colores ni fuentes.
  4. Regístralo en ANIMS en src/anim/index.ts. Mantén ANIMS como un objeto literal simple de nombres: npm run lint los lee del código fuente.
  5. Opcionalmente agrega una muestra a src/Gallery.tsx. Si es reutilizable, pertenece de nuevo a la plantilla del plugin.

Imágenes generadas. La mayoría de las escenas deben dibujarse en código (SVG y CSS a partir de los tokens de marca). Si una escena realmente necesita una imagen generada (un fondo, una imagen base, un momento texturizado), un modelo de imagen puede crearla, por ejemplo la generación de imágenes de Codex CLI. Guárdala en public/, cárgala con staticFile(), mantenla dentro de la paleta de marca y verifica el fotograma.

Área segura vertical (1080x1920)

  • La interfaz de la plataforma cubre aproximadamente los ~220 px superiores y los ~380 px inferiores; mantén 72 px en los lados.
  • Las animaciones se dibujan solo dentro del escenario: desde y = 280 (debajo de la insignia de AGILabs) hasta y = 1280 (encima de las dos filas de subtítulos), 936 px de ancho. Stage / stageOf() te dan ese recuadro.
  • Los subtítulos se colocan debajo del escenario, como máximo dos filas de ~32 caracteres, dentro de ~900 px.

Fotogramas: míralos

Renderiza fotogramas y Lee cada PNG antes de renderizar el video. Una compilación o verificación de lint limpia no muestra desbordamiento, texto recortado o un número incorrecto.

npx remotion still src/index.ts Main-EN-vertical out/stills/f0150.png --frame=150

Toma un fotograma por escena una vez que su último paso se haya reproducido, más uno cada ~3 s (cada 90 fotogramas a 30 fps). Verifica: insignia de AGILabs y nada más como marca, nada fuera del área segura, ningún texto desbordando su recuadro, cada cifra igual al artículo, y el subtítulo en pantalla coincidiendo con lo que la animación muestra en ese momento.

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

Skills relacionados