Creador de Videos con Remotion
Crea videos programáticos usando Remotion: componentes de React que se renderizan a video. Esta habilidad codifica el estilo visual de Skill Stack y las lecciones aprendidas al crear contenido explicativo.
Propósito
Crear contenido de video de formato corto (10-60 segundos) que explique conceptos de Skill Stack con una estética distintiva inspirada en risografía. Los videos son código, por lo que están versionados, son reproducibles e infinitamente editables.
Cuándo Usar Esta Habilidad
- Crear videos explicativos para conceptos de Skill Stack
- Construir contenido animado para redes sociales (vertical 9:16, cuadrado 1:1, apaisado 16:9)
- Visualizar flujos de trabajo técnicos o revelación progresiva
- Cualquier video donde la sincronización precisa y la tipografía importen
No para:
- Edición de video en vivo (usa herramientas de video tradicionales)
- Gráficos 3D complejos (Remotion está enfocado en 2D)
- Gráficos rápidos de una sola vez (usa Figma o Canva)
Configuración del Proyecto
Inicio Rápido
# Crear nuevo proyecto Remotion
npx create-video@latest my-video
# Instalar dependencias
cd my-video && npm install
# Agregar Google Fonts
npm install @remotion/google-fonts
# Iniciar estudio
npm run start # Abre http://localhost:3000
Estructura de Archivos
my-video/
├── src/
│ ├── Root.tsx # Definiciones de composición
│ ├── Main.tsx # Componente de video principal
│ └── components/ # Elementos reutilizables
├── package.json
├── remotion.config.ts
└── out/ # Videos renderizados
Configuración de Composición (Root.tsx)
Crea siempre múltiples relaciones de aspecto para cada video:
import { Composition, Folder } from "remotion";
import { MyVideo } from "./MyVideo";
export const RemotionRoot = () => (
<>
<Folder name="MyVideo">
<Composition
id="MyVideo-Vertical"
component={MyVideo}
durationInFrames={600} // 20 segundos a 30fps
fps={30}
width={1080}
height={1920} // 9:16
/>
<Composition
id="MyVideo-Square"
component={MyVideo}
durationInFrames={600}
fps={30}
width={1080}
height={1080} // 1:1
/>
<Composition
id="MyVideo-Landscape"
component={MyVideo}
durationInFrames={600}
fps={30}
width={1920}
height={1080} // 16:9
/>
</Folder>
</>
);
Estilo Visual: Risografía de Skill Stack
Paleta de Colores
const C = {
paper: "#FAF8F5", // Fondo cálido blanco roto
coral: "#D4694A", // Acento, CTA, resaltados
teal: "#1E4D4D", // Encabezados, estados seleccionados
ink: "#1C1C1C", // Texto del cuerpo
muted: "#666666", // Texto secundario
dimmed: "#AAAAAA", // Texto terciario, deshabilitado
white: "#FFFFFF", // Tarjetas, contenedores
};
Tipografía
import { loadFont as loadInter } from "@remotion/google-fonts/Inter";
import { loadFont as loadPlayfair } from "@remotion/google-fonts/PlayfairDisplay";
import { loadFont as loadJetBrains } from "@remotion/google-fonts/JetBrainsMono";
// Texto del cuerpo, etiquetas de UI
const { fontFamily: inter } = loadInter("normal", {
weights: ["400", "500", "600"],
subsets: ["latin"],
});
// Titulares, citas, texto emocional
const { fontFamily: playfair } = loadPlayfair("normal", {
weights: ["400", "500", "600", "700"],
subsets: ["latin"],
});
// Código, contenido técnico, nombres de habilidades
const { fontFamily: mono } = loadJetBrains("normal", {
weights: ["400", "500"],
subsets: ["latin"],
});
Guía de Tamaños de Fuente
Tamaños mínimos legibles para video:
| Elemento | Cuadrado (1080) | Vertical (1080w) | Apaisado (1920w) |
|---|---|---|---|
| Titulares | 64-84px | 64-84px | 72-96px |
| Nombres de habilidades | 36-40px | 36-40px | 40-48px |
| Texto del cuerpo | 28-32px | 28-32px | 32-36px |
| Etiquetas | 24-28px | 24-28px | 28-32px |
| Anotaciones | 22-24px | 22-24px | 24-28px |
Lección clave: Siempre más grande de lo que piensas. El video comprime los detalles.
Superposición de Granulado
const GrainOverlay: React.FC = () => {
const frame = useCurrentFrame();
return (
<AbsoluteFill
style={{
pointerEvents: "none",
opacity: 0.04,
mixBlendMode: "multiply",
}}
>
<svg width="100%" height="100%">
<defs>
<filter id="grain">
<feTurbulence
type="fractalNoise"
baseFrequency="0.8"
numOctaves="4"
seed={Math.floor(frame / 4)} // Animar granulado
/>
</filter>
</defs>
<rect width="100%" height="100%" filter="url(#grain)" />
</svg>
</AbsoluteFill>
);
};
Patrones de Animación
Herramientas Principales
import {
useCurrentFrame,
useVideoConfig,
AbsoluteFill,
interpolate,
spring,
Sequence,
} from "remotion";
Fundido de Entrada/Salida
const fadeIn = interpolate(frame, [0, 30], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const fadeOut = interpolate(frame, [150, 180], [1, 0], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
// Combinar para opacidad de escena
<div style={{ opacity: fadeIn * fadeOut }}>
Animaciones Spring (Resorte)
const { fps } = useVideoConfig();
// Entrada suave
const entrance = spring({
frame: frame - 20, // Retrasar por 20 fotogramas
fps,
config: { damping: 100 }, // Suave, sin rebote
});
// Selección con rebote
const selectPulse = spring({
frame: frame - 15,
fps,
config: { damping: 12, stiffness: 100 }, // Con rebote
});
// Aplicar a transformación
<div style={{
opacity: interpolate(entrance, [0, 1], [0, 1]),
transform: `translateY(${interpolate(entrance, [0, 1], [20, 0])}px)`,
}}>
Efecto Máquina de Escribir
const ScenePrompt: React.FC<{ frame: number }> = ({ frame }) => {
const text = "Tu texto de prompt aquí";
const charsToShow = Math.floor(frame / 2); // 15 caracteres/seg a 30fps
const visibleText = text.slice(0, charsToShow);
const isTyping = charsToShow < text.length;
const cursorBlink = Math.floor(frame / 18) % 2 === 0;
return (
<div>
"{visibleText}
{(isTyping || cursorBlink) && (
<span style={{
backgroundColor: C.coral,
marginLeft: 4,
opacity: cursorBlink ? 1 : 0,
}}>
{"\u00A0"}
</span>
)}
{!isTyping && '"'}
</div>
);
};
Animación de Lista Escalonada
const ITEMS = ["item-1", "item-2", "item-3"];
{ITEMS.map((item, i) => {
const delay = i * 25; // 25 fotogramas entre cada uno
const s = spring({
frame: Math.max(0, frame - delay - 20),
fps,
config: { damping: 100 },
});
return (
<div
key={item}
style={{
opacity: interpolate(s, [0, 1], [0, 1]),
transform: `translateY(${interpolate(s, [0, 1], [20, 0])}px)`,
}}
>
{item}
</div>
);
})}
Guías de Temporización de Escenas
Cálculos de Duración
- 30 fps = 30 fotogramas por segundo
- 10 segundos = 300 fotogramas
- 20 segundos = 600 fotogramas
Lecciones Aprendidas de Ritmo
Demasiado rápido es el error #1. Los espectadores necesitan tiempo para:
- Notar un cambio de escena
- Leer el texto
- Procesar el significado
- Prepararse para el siguiente cambio
Duraciones mínimas de escenas:
| Tipo de Escena | Mínimo | Cómodo |
|---|---|---|
| Texto de máquina de escribir | 3-4 seg | 5-6 seg |
| Lista apareciendo | 4-5 seg | 6-8 seg |
| Selección/resaltado | 3-4 seg | 5 seg |
| Diagrama técnico | 4-5 seg | 6-8 seg |
| Remate/CTA | 2-3 seg | 3-4 seg |
Patrón de Superposición de Escenas
Las escenas deben fundirse, no cortar abruptamente:
// Temporización de escenas para video de 20 segundos (600 fotogramas)
{frame < 200 && <ScenePrompt frame={frame} />}
{frame >= 160 && frame < 340 && <SceneScan frame={frame - 160} />}
{frame >= 300 && frame < 460 && <SceneSelect frame={frame - 300} />}
{frame >= 420 && frame < 560 && <SceneLoad frame={frame - 420} />}
{frame >= 520 && <ScenePunchline frame={frame - 520} />}
La superposición de 40 fotogramas (1.3 segundos) crea fundidos suaves cuando se combina con interpolaciones de fadeIn/fadeOut.
Flujo de Trabajo
Fase 1: Storyboard
Antes de codificar, define:
- Mensaje principal - ¿Qué es lo único que los espectadores deben aprender?
- Desglose de escenas - 4-6 escenas, cada una con una idea
- Duración total - 10-20 segundos para redes sociales, 30-60 para explicativos
- Contenido del texto - Palabras exactas para cada escena
Fase 2: Andamiaje
- Crear composición con la duración adecuada
- Construir componentes de escena con contenido placeholder
- Configurar temporización básica (rangos de escenas)
- Probar que todas las escenas aparecen
Fase 3: Estilo
- Aplicar paleta de colores y fuentes
- Agregar superposición de granulado
- Asegurar que los tamaños de fuente sean legibles
- Probar en teléfono (vertical) y escritorio (apaisado)
Fase 4: Animar
- Agregar fadeIn/fadeOut a cada escena
- Agregar animaciones spring para entradas
- Ajustar la temporización - casi siempre necesita ser más lenta
- Probar reproducción completa varias veces
Fase 5: Renderizar
# Renderizar composición específica
npx remotion render MyVideo-Square out/square.mp4
# Renderizar todos los formatos
npx remotion render MyVideo-Vertical out/vertical.mp4
npx remotion render MyVideo-Square out/square.mp4
npx remotion render MyVideo-Landscape out/landscape.mp4
Errores Comunes
❌ Problemas de Centrado
Problema: El contenido aparece en la esquina superior izquierda.
Solución: Usa AbsoluteFill con flexbox, no position: absolute.
// ✅ Correcto
<AbsoluteFill style={{
justifyContent: "center",
alignItems: "center",
}}>
// ❌ Incorrecto
<div style={{ position: "absolute", left: "50%", top: "50%" }}>
❌ Fuentes Pequeñas
Problema: Texto legible en el estudio, ilegible en el teléfono.
Solución: Mínimo 28px para texto del cuerpo, 64px para titulares.
❌ Demasiado Rápido
Problema: No se puede leer el texto antes de que desaparezca.
Solución: Duplica tu estimación de duración inicial. Cada escena necesita 4-8 segundos como mínimo.
❌ Cortes Bruscos
Problema: Transiciones abruptas entre escenas.
Solución: Superposición de escenas por 30-50 fotogramas con fadeIn/fadeOut.
❌ Sin Soporte de Relación de Aspecto
Problema: El video se ve mal en diferentes plataformas.
Solución: Crea las tres composiciones (vertical, cuadrada, apaisada) desde el principio.
Integración de Subtítulos
Remotion tiene soporte de primera clase para subtítulos. Tres opciones según el costo:
Opción 1: Whisper Nativo (Recomendado - Gratuito)
npm install @remotion/captions @remotion/install-whisper-cpp
npx @remotion/install-whisper-cpp --model large-v3-turbo
import { transcribe } from "@remotion/captions";
const result = await transcribe({
inputPath: "/path/to/audio.mp3",
model: "large-v3-turbo",
language: "en",
});
// result.captions = [{ text: "Hello", startTime: 0, endTime: 0.5 }, ...]
Opción 2: API ZapCap ($0.10/min)
Para procesamiento por lotes sin configuración de modelo local.
Opción 3: API Submagic ($0.69/min)
Plantillas de subtítulos "virales" preestilizadas, pero caras.
Detalles completos del flujo de trabajo: Consulta references/caption-workflow.md
Recursos de la Comunidad
Discord
Discord de Remotion - Más de 6,000 miembros. Canales #help y #showcase activos. El creador (Jonny Burger) responde directamente.
Plantillas Clave para Estudiar
| Plantilla | Caso de Uso | Enlace |
|---|---|---|
| TikTok | Video social vertical | remotion-dev/template-tiktok |
| Audiogram | Clips de podcast | remotion-dev/template-audiogram |
| GitHub Unwrapped | Video basado en datos | remotion-dev/github-unwrapped |
| claude-remotion-kickstart | Flujo de trabajo asistido por IA | Starter comunitario para Claude + Remotion |
Paquetes Esenciales
# Subtítulos
npm install @remotion/captions @remotion/install-whisper-cpp
# Gráficos
npm install @remotion/skia # Gráficos vectoriales 2D
npm install @remotion/three # 3D con Three.js
npm install @remotion/lottie # Animaciones Lottie
# Renderizado
npm install @remotion/lambda # Renderizado serverless en AWS
npm install @remotion/player # Incrustar en aplicaciones web
Lista completa de recursos: Consulta references/community-resources.md
Recursos Incluidos
references/what-is-a-skill.tsx- Componente de ejemplo completo del video "What Is A Skill"references/caption-workflow.md- Guía completa de integración de subtítulos (Whisper, ZapCap, Submagic)references/community-resources.md- Plantillas, paquetes, ruta de aprendizaje
Habilidades Relacionadas
- video-caption-creation - Subtítulos y hashtags para el video renderizado
- youtube-scriptwriting - Para guiones de video explicativo más largos
- social-content-creation - Reutilizar conceptos de video para publicaciones estáticas
Historial de Versiones
-
v1.1 (2026-01-22): Integración de subtítulos y comunidad
- Agregado flujo de trabajo de Whisper nativo mediante
@remotion/captions - Agregados ajustes preestablecidos de estilo de subtítulos (mínimo, negrita, karaoke, marca)
- Agregados recursos comunitarios (Discord, plantillas, paquetes)
- Nuevos archivos de referencia:
caption-workflow.md,community-resources.md - Comparación de costos: Whisper (gratuito) vs ZapCap ($0.10/min) vs Submagic ($0.69/min)
- Agregado flujo de trabajo de Whisper nativo mediante
-
v1.0 (2026-01-21): Creación inicial de la habilidad
- Estilo visual de risografía
- Patrones de animación (spring, interpolate, máquina de escribir)
- Guías de temporización (aprendidas de la iteración "demasiado rápido")
- Patrón de superposición de escenas
Los videos son código. Versiona, itera y construye una biblioteca de componentes reutilizables.