Communitygithub.com

Generador de videos 2D TSX para VidTSX

Genera archivos de video 2D TSX listos para producción para VidTSX (basado en Remotion) a partir de una descripción de toma, escena o video. Úsalo siempre que el usuario quiera crear o generar un video VidTSX, una toma o escena 2D TSX, un clip animado, una tarjeta de título o un gráfico en movimiento renderizado.

¿Qué es Generador de videos 2D TSX para VidTSX?

Esta habilidad está diseñada para generar archivos TSX listos para renderizar en VidTSX a partir de descripciones de video, tomas o escenas. Se basa en Remotion y se enfoca exclusivamente en gráficos animados 2D, excluyendo trabajo 3D (three.js). El flujo de trabajo es simple: para una sola toma, genera el archivo TSX directamente; para solicitudes complejas, primero confirma el desglose. El archivo de salida contiene solo código de componente, sin comentarios externos. Las reglas de corrección son estrictas para evitar fallos en el render: toda la animación debe basarse en fotogramas usando `useCurrentFrame()` e `interpolate()`, los rangos de entrada de `interpolate` deben ser estrictamente crecientes, se debe usar `Easing.bezier()` en lugar de sintaxis envolvente, y se deben seguir importaciones específicas para `chroma-js` (importación de namespace) y `@remotion/paths` (solo funciones reales). También incluye preset de dimensiones (horizontal, vertical, cuadrado), seis presets de estilo (minimalista, memphis, neo-brutalismo, glassmorfismo, neón, corporativo), y un proceso de verificación obligatorio: renderizar al menos un fotograma y revisarlo visualmente para detectar errores de diseño, recorte o superposición antes de considerar completa la toma.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/gbax316/shorts-director/tree/main/.claude/skills/vidtsx-2d-generator

Preguntar en tu IA favorita

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

Documentación

Generador de videos 2D VidTSX

Genera archivos TSX 2D listos para producción para VidTSX a partir de una descripción de una toma o video. Los archivos son composiciones de Remotion que VidTSX renderiza fotograma por fotograma, por lo que la corrección es más importante que la creatividad: un solo rango de interpolate no monótono o un useState fuera de lugar harán que el render falle.

Esta habilidad cubre gráficos animados 2D. El trabajo 3D (@remotion/three / React Three Fiber) está fuera del alcance.

Cómo usar esta habilidad

  1. Toma única clara → genera el archivo .tsx directamente.
  2. Solicitud compleja, de múltiples tomas o visualmente ambigua → primero confirma el desglose de tomas o la dirección visual en un mensaje corto, luego genera. No preguntes en exceso; una confirmación de una línea es suficiente.
  3. Entrega como un archivo .tsx real, no como código en línea. Estos componentes TSX siempre superan las 20 líneas y el usuario edita estos archivos directamente. Por defecto, una toma por archivo (atómico, fácil de editar) a menos que el usuario solicite un único entregable combinado.
  4. El archivo contiene solo el código del componente — los comentarios de sección estructural a continuación son bienvenidos, pero no fences de markdown, ni explicaciones en prosa dentro del archivo.
  5. Rendérizalo y míralo antes de darlo por terminado — consulta Verificar el render. Una toma sobre la que solo has razonado no está terminada; un fotograma estático (y, para revelaciones/desplazamientos, fotogramas en cada punto clave) es el estándar.

Especificación de salida

Presets de dimensiones

FormatoAnchoAltoCaso de uso
horizontal19201080YouTube, presentaciones
vertical10801920TikTok, Reels, Shorts
cuadrado10801080Feed de Instagram

Valores predeterminados

  • Formato: horizontal (1920×1080)
  • Duración: 5 segundos
  • FPS: 30
  • Estilo: minimalista (ver references/style-presets.md)

Estructura de archivo obligatoria

Cada archivo generado sigue este esqueleto. Los comentarios de sección etiquetados son intencionales: mantienen la navegabilidad en archivos grandes.

import React from 'react';
import {
  useCurrentFrame,
  useVideoConfig,
  interpolate,
  Easing,
  AbsoluteFill,
  Sequence,
} from 'remotion';

// =============================================================================
// CONFIGURACIÓN DE LA COMPOSICIÓN
// =============================================================================
export const compositionConfig = {
  id: 'NombreDelComponente', // Solo PascalCase — SIN guiones ni guiones bajos
  durationInSeconds: 5,
  fps: 30,
  width: 1920,
  height: 1080,
};

// =============================================================================
// CONSTANTES DE ESTILO
// =============================================================================
const COLORS = {
  primary: '#6366f1',
  secondary: '#8b5cf6',
  accent: '#06b6d4',
  background: '#0f0f23',
  text: '#ffffff',
} as const;

const TYPOGRAPHY = {
  fontFamily: 'Inter, system-ui, sans-serif',
} as const;

const EASINGS = {
  easeOut: Easing.bezier(0.33, 1, 0.68, 1),
  easeIn: Easing.bezier(0.32, 0, 0.67, 0),
  easeInOut: Easing.bezier(0.37, 0, 0.63, 1),
  overshoot: Easing.bezier(0.34, 1.56, 0.64, 1),
} as const;

// =============================================================================
// DATOS PREGENERADOS (calculados una vez a nivel de módulo, NO durante el render)
// =============================================================================
const seededRandom = (seed: number): number => {
  const x = Math.sin(seed * 9999) * 10000;
  return x - Math.floor(x);
};

// =============================================================================
// COMPONENTE PRINCIPAL
// =============================================================================
const NombreDelComponente: React.FC = () => {
  const frame = useCurrentFrame();
  const { fps, durationInFrames, width, height } = useVideoConfig();

  return (
    <AbsoluteFill style={{ backgroundColor: COLORS.background }}>
      {/* Contenido */}
    </AbsoluteFill>
  );
};

export default NombreDelComponente;

Reemplaza NombreDelComponente por un nombre en PascalCase que describa la toma, establece el bloque COLORS según el preset de estilo elegido y configura width/height/durationInSeconds/fps según la solicitud.


Reglas de corrección

Estas no son preferencias de estilo — son lo que hace que un render tenga éxito. VidTSX (a través de Remotion) renderiza cada fotograma llamando al componente en un número de fotograma fijo. No hay bucle de eventos, ni persistencia entre fotogramas, ni tiempo de reloj de pared. Cualquier cosa que asuma estas cosas se romperá.

La animación se basa en fotogramas, siempre

  • Impulsa todo el movimiento desde useCurrentFrame() + interpolate().
  • Nunca uses useState, useEffect, setTimeout, setInterval o animaciones/transiciones CSS. No encajan en el modelo fotograma por fotograma y producen una salida rota o no determinista.
  • Para cualquier cosa aleatoria o procedimental, usa seededRandom (o una función con semilla equivalente) para que cada render de un fotograma dado sea idéntico. Pre-genera arreglos de partículas/aleatorios a nivel de módulo, nunca dentro de la función de render — recalcular por fotograma causa parpadeo.
  • Escalonar las animaciones para que los elementos entren en secuencia en lugar de todos a la vez. Se ve mejor y es el aspecto esperado.

interpolate — los rangos de entrada deben ser estrictamente crecientes

El rango de entrada de interpolate debe ser estrictamente monótonamente creciente. Valores duplicados o descendentes lanzan un error en tiempo de ejecución.

// ✅ Correcto
interpolate(frame, [0, 30, 60], [0, 1, 0]);

// ❌ Lanza error — el rango de entrada desciende
interpolate(frame, [60, 30, 0], [0, 1, 0]);

Para invertir un mapeo, invierte el rango de salida, nunca el rango de entrada:

// ✅ Correcto — mapea 0→100, 1→0
interpolate(value, [0, 1], [100, 0]);

// ❌ Incorrecto
interpolate(value, [1, 0], [100, 0]);

Para temporización basada en índices, asegúrate de que startFrame < endFrame y siempre aplica clamp:

const startFrame = index * 30;
const endFrame = startFrame + 30;
interpolate(frame, [startFrame, endFrame], [0, 1], {
  extrapolateLeft: 'clamp',
  extrapolateRight: 'clamp',
});

Siempre pasa extrapolateLeft: 'clamp' y extrapolateRight: 'clamp' a menos que se desee genuinamente un valor no acotado — sin ellos, los valores se disparan más allá de su rango antes/después de los fotogramas clave.

Easing — usa Easing.bezier(), nunca sintaxis envolvente

Las formas envolventes como Easing.out(Easing.cubic) fallan. Define bezieres con nombre una vez (ver el bloque EASINGS en el esqueleto) y haz referencia a ellos:

// ❌ Falla
Easing.out(Easing.cubic);
Easing.in(Easing.quad);

// ✅ Correcto
interpolate(frame, [0, 30], [0, 1], {
  easing: EASINGS.easeOut,
  extrapolateRight: 'clamp',
});

chroma-js — solo importación de namespace

// ✅ Correcto
import * as chroma from 'chroma-js';
const color = chroma('#00bfff').brighten(0.5).hex();

// ❌ Incorrecto — "chroma is not a function"
import chroma from 'chroma-js';

@remotion/paths — solo existen las funciones reales

Estos helpers no existen y nunca deben usarse: makeCircle(), makeRect(), makeTriangle(), makeLine(), makePie(), makePolygon(), makeEllipse(), makeStar().

Solo estas importaciones son válidas:

import { evolvePath, getLength, getPointAtLength, getTangentAtLength } from '@remotion/paths';

Escribe cadenas de ruta SVG a mano y anímalas con evolvePath:

const circlePath = 'M 50 10 A 40 40 0 1 1 49.99 10 Z';
const rectPath = 'M 0 0 L 100 0 L 100 50 L 0 50 Z';
const linePath = 'M 0 0 L 100 100';

const { strokeDasharray, strokeDashoffset } = evolvePath(progress, rectPath);

ID de la composición

compositionConfig.id es solo PascalCase — sin guiones, sin guiones bajos (ej. ProductReveal, no product-reveal ni product_reveal).


Diseño

Zonas seguras

  • 10% superior: reservar para la interfaz de usuario de la plataforma.
  • 15% inferior: reservar para subtítulos/botones.
  • Mantén el contenido principal entre 25%–75% verticalmente.

Ayudante de centrado

const centered: React.CSSProperties = {
  position: 'absolute',
  top: '50%',
  left: '50%',
  transform: 'translate(-50%, -50%)',
};

Tipografía

ElementoTamañoPeso
Titulares72–120px700–900
Subtitulares36–48px500–700
Cuerpo28–36px400–500

Siempre establece margin: 0 en elementos de texto — los valores predeterminados del navegador desplazan los diseños del centro.


Presets de estilo

En este repositorio, el valor predeterminado es la marca de la casa, no un preset. Las tomas importan COLORS, GRADIENT, RADIUS, SHADOW, EASINGS de remotion/src/brand.ts y FONT_HEADLINE, FONT_DISPLAY, FONT_BODY, FONT_MONO de remotion/src/fonts.ts en lugar de los bloques locales COLORS/TYPOGRAPHY del esqueleto, y siguen brand.md. FONT_HEADLINE (Instrument Serif) tiene un solo peso: nunca le des fontWeight. Las tomas se sitúan en el fondo día a menos que su compositionConfig diga ground: 'night'; los componentes del kit (lib/shorts.tsx, BrandBg) toman sus colores de él, así que usa useGround() de brand.ts para cualquier color que establezcas tú mismo.

Cuando el usuario nombre un estilo, carga su paleta y características de references/style-presets.md e inserta el objeto COLORS en el esqueleto. Los seis presets son: minimalista, memphis, neo-brutalismo, glassmorfismo, neón/cyberpunk y corporativo. Si no se nombra ningún estilo, usa la marca de la casa anterior.


Verificar el render (no saltar)

Una toma no está terminada hasta que la hayas visto. Después de escribir el .tsx, renderiza al menos un fotograma estático y ábrelo — nunca entregues una toma sobre la que solo has razonado. El render tiene éxito y los números se ven bien, pero el texto se desborda de su tarjeta, una imagen está recortada con el recorte incorrecto, un elemento está fuera de la pantalla o dos cosas se superponen. Solo una captura de pantalla detecta estos problemas.

  • Renderiza un fotograma estático (ej. node scripts/render-all.mjs --still --scale=1 <ShotId>) y lee el PNG.
  • Para revelaciones basadas en tiempo (elementos que entran en un momento clave, desplazamientos, fases escalonadas), un solo fotograma al 60% de la duración no es suficiente — renderiza el clip completo y extrae fotogramas en cada momento clave (ffmpeg -ss <t> -i out/<id>.mp4 -frames:v 1 f.jpg), o renderiza fotogramas estáticos en varios desplazamientos. Verifica el estado en cada momento clave, no solo un fotograma.
  • Verifica específicamente: las imágenes encajan en su espacio (sin contenido importante recortado; prefiere objectFit: contain sobre un fondo que coincida para imágenes reales heterogéneas), el texto no está recortado ni desbordado, nada está fuera del área segura, y cada elemento animado es realmente visible cuando debería serlo.
  • Si se compone sobre otro metraje, también verifica un fotograma de la salida final horneada, no solo la toma aislada.

Corrige lo que revele la captura de pantalla, luego vuelve a renderizar y mira de nuevo. Trata "Lo rendericé y se ve correcto" — con el fotograma mostrado — como el estándar para dar por terminado.


Salida final

Genera el archivo .tsx completo y nada más dentro de él — sin markdown circundante, sin comentarios antes o después del código en el propio archivo. Una nota corta de una línea en el chat al entregar el archivo está bien.

Individual skills in this repo

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

gbax316/make-ai-short

Build a GENERATIVE-pixels vertical short (1080×1920, ~35-40s) end-to-end — a recurring locked character animated by a fal video model (Seedance 1.5 Pro default) under a philosophical/story VO, composited in Remotion with word-synced captions, SFX audition, seamless frame-0==last-frame loop. Use when the user wants to "make an AI video short", "make an ai short", "make a blue-man video", or any short where the pixels come from a VIDEO MODEL — not TSX animation (that is make-short) and not layered collage (that is make-vox). Defers model choice re-litigating to ai-shorts/IDEAS.md, TSX crash rules to vidtsx-2d-generator, SFX taste to suggest-sfx + brand §7. For a NEW short (writers' room, dialogue skits, documentaries, mixed render paths), start with shorts-director, which calls this track as an engine.

gbax316/shorts-director

Directs a faceless vertical short from idea to finished, mastered file, and gets better with every run. Picks a format, writes the episode in a writers' room (three premises judged as the buyer), voices it, gates on an animatic, then decides beat by beat how each moment is made: drawn in code in Remotion, a cut-out from a generated still, a generated clip, or one of the engine tracks. Modes: series, writers-room, produce, sound, finish, bakeoff, effects (/effects), improve (the learning loop after every short). Formats so far: character skit with dialogue and synced mouths, photoreal mini documentary with sourced figures. Triggers on "make a short", "next episode", "make a video about X", "faceless video", "reel for this offer". Do NOT trigger for editing an existing video file, for a pure code-drawn explainer with no writers' room (make-short), or for collage (make-vox).

Skills relacionados