Habilidad de Producción Visual con Remotion
Construida a partir de experiencia real de producción creando el video de lanzamiento de SureCart 4.2. Autor: Chandresh Vaghanani
Antes de Comenzar — 2 Preguntas (No Negociables)
Haz estas 2 preguntas antes de escribir cualquier código. Mantenlo casual — un mensaje, dos preguntas. No las omitas incluso si el usuario dice "solo hazlo" o "empieza ya". Estos 10 segundos evitan horas de retrabajo.
Antes de empezar — dos cositas:
1. ¿Fondo claro u oscuro? (o comparte tu sitio web/captura y lo obtendré de ahí)
2. ¿Tienes una captura o maqueta del producto? (totalmente opcional — puedo construir sin una)
Eso es todo. No más preguntas a menos que el usuario ofrezca más información.
Qué hacer con las respuestas:
- Si comparten una maqueta/captura — extrae color de fondo, color de acento, estilo de fuente, texto de la UI. Úsalo.
- Si comparten una URL de sitio web — obténla, extrae lo mismo. No adivines.
- Si responden solo claro/oscuro — continúa con los Valores Predeterminados de Respaldo Sin Información a continuación.
- Si omiten ambas preguntas — continúa con los Valores Predeterminados de Respaldo Sin Información a continuación. No preguntes de nuevo.
Otros activos (logotipo, música, colores adicionales) — acéptalos si se ofrecen, pero nunca los conviertas en un bloqueante.
Valores Predeterminados de Respaldo Sin Información
Cuando la información de marca no está disponible, el instinto de la IA es reducir las fuentes y agregar relleno. Ese instinto es incorrecto para video. Aplica estos en su lugar:
Estos se activan automáticamente cuando no se proporciona maqueta, captura o sitio web. Aseguran un resultado profesional incluso sin información de marca.
Diseño
justifyContent: "center"+alignItems: "center"en cada escena de AbsoluteFill — sin excepcionesmarginTop: -50para desplazar el contenido ligeramente por encima del centro real- Ancho de maqueta/tarjeta: 1200px (usa el extremo superior — llena el marco)
- Relleno del contenedor: máximo 40px — nunca más
- El contenido debe ocupar al menos el 75% de la altura de 1080px. Si no es así, aumenta los tamaños de fuente o reduce los espacios.
Tamaños de fuente (respaldo — extremo superior del rango)
| Elemento | Tamaño de respaldo |
|---|---|
| Titular principal | 140px |
| Subtítulo | 56px |
| Cuerpo / descripción | 36px |
| Etiqueta / píldora | 22px |
| Texto de contenido de tarjeta | 28px |
Colores (paleta de respaldo — segura y profesional)
- Fondo:
#0a0a0f(casi negro, neutro) - Acento:
#6366f1(índigo — legible, moderno, no específico del producto) - Texto:
#ffffff - Texto atenuado:
rgba(255,255,255,0.55) - Fondo de tarjeta:
rgba(255,255,255,0.06)
Estos son SOLO PUNTOS DE PARTIDA. En el momento en que el usuario comparta colores de marca, reemplázalos por completo.
Qué NO hacer sin información de marca
- NO uses colores neón/ciber — eso es una estética personal, no una coincidencia de marca
- NO uses
paddingTop: 120y lo llames "centrado" — está alineado arriba con espacio muerto - NO elijas
fontSize: 32para un titular porque "se ve limpio" — es ilegible en video
Regla #1 — El Lienzo NO es un Sitio Web
Este es el error más común en videos de Remotion generados por IA.
El lienzo de Remotion es 1920×1080px. Diseña para llenarlo, no como una página web.
⚠️ Estos son MÍNIMOS. Escribir
fontSize: 18para texto del cuerpo es un ERROR, no una elección de estilo. Cualquier valor por debajo de la columna mínima significa que el texto es ilegible en una pantalla 1080p. Trata estos números como errores de tipo — deben corregirse antes de continuar.
| Elemento | MÍNIMO (límite inferior) | Rango Recomendado |
|---|---|---|
| Titular principal | 80px | 100–160px |
| Subtítulo | 40px | 48–72px |
| Cuerpo / descripción | 28px | 32–40px |
| Etiqueta / píldora / insignia | 18px | 20–24px |
| Texto de contenido de tarjeta | 22px | 24–32px |
Reglas:
- El contenido debe sentirse como que llena la pantalla
- Tarjetas de maqueta:
width: 1100–1200px, centradas - Relleno del contenedor: máximo 48px — NO 80–120px como una página web
- Si el texto se siente "demasiado grande para estar cómodo" — probablemente sea correcto para video
Regla #2 — Todas las Animaciones DEBEN Usar useCurrentFrame()
// CORRECTO
const frame = useCurrentFrame();
const opacity = interpolate(frame, [0, 20], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
// PROHIBIDO — no se renderizará correctamente
// CSS: transition: opacity 1s ease
// Tailwind: animate-fade-in
// CSS @keyframes
Incluye siempre extrapolateLeft: "clamp" y extrapolateRight: "clamp" en cada llamada a interpolate() a menos que necesites explícitamente valores sin límites. Olvidar esto hace que los valores se salgan de su rango y crea errores sutiles.
Regla #3 — Determinismo
// PROHIBIDO — valor diferente en cada pase de renderizado
const x = Math.random() * 100;
// CORRECTO — mismo valor cada vez, cada fotograma
import { random } from "remotion";
const x = random("particle-x-1") * 100; // semilla de cadena = determinista
Regla #4 — Activos
import { staticFile } from "remotion";
import { Img } from "remotion"; // NO <img> nativo
import { Audio } from "@remotion/media";
// Usa siempre staticFile() para cualquier cosa en la carpeta public/
<Audio src={staticFile("bg-music.mp3")} />
<Img src={staticFile("logo.png")} /> // <Img> asegura que el activo se cargue antes de que se renderice el fotograma
// Las URLs remotas no necesitan staticFile() pero requieren CORS
Regla #5 — Reproducción de Vista Previa Suave
Agrega premountFor={30} en componentes <Sequence> para que los componentes pesados se precarguen 30 fotogramas antes de su tiempo:
<Sequence from={90} durationInFrames={120} premountFor={30}>
<HeavyScene />
</Sequence>
Recetas de Easing
import { Easing } from "remotion";
// Entrada de UI nítida (ease-out fuerte, sin sobreimpulso) — la mayoría de las animaciones de entrada
Easing.bezier(0.16, 1, 0.3, 1)
// Transición editorial lenta (ease-in-out equilibrado) — transiciones de ambiente
Easing.bezier(0.45, 0, 0.55, 1)
// Sobreimpulso juguetón — elementos saltarines/divertidos
Easing.bezier(0.34, 1.56, 0.64, 1)
// Spring — sin rebote (entradas de maquetas, tarjetas, UI)
spring({ frame, fps, config: { damping: 200 } })
// Spring — enérgico con ligero rebote (elementos contundentes)
spring({ frame, fps, config: { damping: 20, stiffness: 200 } })
// Spring — saltarín/juguetón
spring({ frame, fps, config: { damping: 8 } })
Compuertas de Diseño Previas — Ejecutar ANTES de Escribir Cualquier Layout de Escena
Estas no son sugerencias. Ejecuta las tres compuertas antes de escribir el primer <div> de cualquier escena. Si alguna compuerta falla, cambia el diseño — nunca parches con dimensiones fijas o contenido adicional.
Compuerta 1 — Llenado del Lienzo (ambos ejes, obligatorio)
Eje horizontal:
dead_side = (1920 − content_width) / 2
DEBE ser ≤ 300px. Si > 300px → el contenido es demasiado estrecho. Amplíalo o cambia el diseño.
Eje vertical:
fill_h = content_height / 1080
DEBE ser ≥ 0.80. Si < 0.80 → el contenido es demasiado corto. Cambia la forma del diseño.
⚠️ Si la altura falla, NO lo arregles estableciendo una altura fija en tarjetas o contenedores. Una altura fija crea un vacío dentro de la tarjeta — el espacio muerto se mueve dentro del elemento en lugar de eliminarse. La única solución real es cambiar la forma del diseño (Compuerta 2).
Ejemplo real de fallo — 3 tarjetas de características cortas:
| Versión | content_width | dead_side | content_height | fill_h | Veredicto |
|---|---|---|---|---|---|
| v1: tarjetas de 3 columnas (365px) | 1151px | 384px | 416px | 38% | ❌ ambos ejes fallan |
v2: height: 720px forzado | 1542px | 189px | 864px | 80% | ✅ horizontal, ❌ visual (vacío en tarjeta) |
| v3: filas horizontales (1400px) | 1400px | 260px | 916px | 85% | ✅ ambos ejes pasan |
Compuerta 2 — Tabla de Decisión de Selección de Layout
El volumen de contenido determina la forma del layout. Elige el layout de esta tabla ANTES de escribir código.
| Elementos | Contenido por elemento | Layout correcto | Por qué |
|---|---|---|---|
| 3–5 elementos | icono + nombre + 1 línea | Filas horizontales (1400px de ancho) | Contenido corto se apila verticalmente → llena la altura naturalmente |
| 3 elementos | icono + nombre + 2–3 líneas | Tarjetas de 3 columnas (mín. 1100px de ancho) | Suficiente contenido para llenar la altura de la tarjeta sin vacío |
| 2 elementos | sustancial | Tarjetas grandes lado a lado o pantalla dividida | |
| 1 elemento | cualquier cosa | Héroe de pantalla completa |
Si el layout natural para tu contenido deja cualquier eje por debajo del umbral después de la Compuerta 1 — ese layout es incorrecto. Elige una fila diferente en esta tabla.
Nunca elijas el layout por estética o instinto predeterminado. El ajuste del contenido primero. La estética después.
Compuerta 3 — Límite de Densidad de Contenido
Máximo por elemento: icono + nombre + 1 línea corta. Parada dura. Sin viñetas. Sin subsecciones. Sin párrafos. Sin segundas líneas de descripción.
Un espectador tiene ~5 segundos por escena. Lee 1 línea. No lee 4 viñetas.
Si el contenido se siente escaso y quieres agregar más para llenar espacio — eso es la Compuerta 2 diciéndote que la forma del layout es incorrecta, no que falta contenido.
Llena el espacio vacío con TAMAÑO (fuentes más grandes, iconos más grandes, espacios más grandes entre elementos) — nunca con más contenido.
Reglas Universales de Escena
-
Alineación vertical —
justifyContent: "center"+marginTop: -40a-60(ligeramente por encima del centro real = sensación moderna y premium. NO alineado arriba con relleno.)❌ INCORRECTO — alineado arriba, deja espacio vacío abajo:
<AbsoluteFill style={{ display: "flex", flexDirection: "column", paddingTop: 110 }}> <h1>Headline</h1> <p>Subtext</p> {/* gran vacío abajo */} </AbsoluteFill>✅ CORRECTO — centrado verticalmente, ligeramente por encima del punto medio:
<AbsoluteFill style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", marginTop: -50 }}> <h1>Headline</h1> <p>Subtext</p> {/* el contenido llena el marco — sin espacio muerto */} </AbsoluteFill> -
Llenado del lienzo — ejecuta las Compuertas de Diseño Previas antes de escribir esta escena. La Compuerta 1 verifica tanto el ancho (
dead_side ≤ 300px) como la altura (fill_h ≥ 0.80) juntos. La Compuerta 2 selecciona la forma del layout de la tabla de decisión. La Compuerta 3 limita el contenido por elemento. Las tres compuertas viven en la sección de Compuertas de Diseño Previas arriba — reemplazan la antigua verificación solo de ancho que estaba aquí. -
z-index del titular — siempre
zIndex: 20en el contenedor del titular para que la maqueta nunca se superponga al texto -
Desbordamiento del titular — siempre
whiteSpace: "nowrap"en el texto del titular (evita que se envuelva detrás de la maqueta) -
Sin
overflow: hiddenen AbsoluteFill — recorta el cursor y elementos SVG. Quítalo o coloca el cursor fuera. -
Retención de 15 fotogramas — cada escena debe tener al menos 15 fotogramas de retención completamente visible al FINAL antes de que se active la transición. Nunca comiences una transición mientras una animación aún se está reproduciendo en la escena saliente.
-
Fuente — usa una fuente consistente en todo. Recomendada: Plus Jakarta Sans a través de
@remotion/google-fonts. Peso máximo disponible: 800 (escribirfontWeight: 900se renderiza como 800). -
Color — máximo 2–3 colores de marca. Un fondo oscuro, un acento primario, blanco/blanco atenuado para texto. Consistente en todas las escenas.
Jerarquía Tipográfica
// Supertítulo / Etiqueta píldora
{ fontSize: 20, letterSpacing: "4px", textTransform: "uppercase", fontWeight: 600 }
// Titular principal
{ fontSize: 112, fontWeight: 800 } // rango: 100–160px
// Subtexto / descripción
{ fontSize: 36, opacity: 0.7 } // rango: 32–40px
// Línea de confianza / insignias pequeñas
{ fontSize: 26, opacity: 0.5 } // rango: 24–28px
Configuración de Fuente
import { loadFont } from "@remotion/google-fonts/PlusJakartaSans";
// Llama al nivel superior — debe cargarse antes del renderizado
const { fontFamily } = loadFont("normal", {
weights: ["400", "600", "800"],
subsets: ["latin"],
});
Para otras fuentes: instala a través de @remotion/google-fonts/FontName o coloca .woff2 en public/ y usa loadFont de @remotion/fonts.
Plantilla de Estructura de Escena
Cada escena sigue este orden fijo de capas (abajo → arriba):
<AbsoluteFill style={{ background: brandBg }}