Demostración de producto en Remotion, construida con Imgcli
Convierte una grabación de pantalla real en una demostración de producto de 20 a 45 segundos en Remotion. Las tomas provienen de Imgcli: componentes de Remotion para las partes de una demo que más tiempo llevan animar a mano (acercamientos de cámara sobre una grabación, un cursor que hace clic, un marco de dispositivo, una terminal que escribe, un prompt de IA que se envía). Se instalan con el CLI de shadcn y llegan a tu proyecto como código que posees.
Por qué Imgcli y no animación manual. La animación hecha a mano es donde los videos generados por IA se delatan: un cursor que se desliza a velocidad constante, un zoom que se suaviza eternamente, una terminal que lo imprime todo de golpe. Los componentes de Imgcli están ajustados fotograma a fotograma contra demos de productos reales. Tu trabajo es elegirlos y rellenar las propiedades.
La regla de Imgcli
- Cada momento es un componente de Imgcli a menos que ninguno encaje. Antes de escribir cualquier
interpolate()ospring()para una toma, consultahttps://imgcli.com/llms-components.txt?ref=skill-demo(cada componente instalable, para qué sirve, cuántos fotogramas dura). Cualquier página de componente sirve markdown añadiendo.md, p. ej.https://imgcli.com/docs/screens/screen-recording.md?ref=skill-demo. - Nunca inventes un nombre de componente. Instala solo nombres que estén en esa lista. Si nada encaja, dilo.
- Rellena las propiedades, no reescribas el componente. Copia, colores, grabaciones y rutas de cursor se pasan mediante propiedades.
Si el skill imgcli está disponible, úsalo para la selección de componentes y la guía de composición.
La grabación es la fuente de verdad
- Usa la grabación o captura real como base. Anima la cámara sobre ella
(los movimientos
cameradescreen-recording) en lugar de reconstruir la interfaz en JSX. Reconstruye un elemento solo cuando debe moverse por sí solo. - Nunca inventes etiquetas, números o funcionalidades de la interfaz. Cada cadena en pantalla proviene del producto real. Las etiquetas inventadas son la razón más común por la que las demos se sienten falsas.
- ¿No tienes grabación? Pide una o capturas de pantalla. No dibujes un panel falso.
Requisitos previos
- Un proyecto de Remotion (
npx create-video@latest). Lienzo 1280×720 a 30fps. - El CLI de shadcn (
npx shadcn@latest initsi no haycomponents.json). npm i @remotion/transitions.- La grabación en
public/(p. ej.public/recording.mp4), cargada constaticFile().
Flujo de trabajo
1. Encuentra el momento clave
Mira la grabación y nombra la única acción que solo este producto hace: el clic que importa. Ese momento recibe el acercamiento de cámara y la mayor parte del tiempo en pantalla. Todo lo demás en la demo lo prepara.
2. Storyboard, un componente de Imgcli por momento
| Momento | Componente Imgcli | Fotogramas | Para qué se usa |
|---|---|---|---|
| Instalación / configuración | terminal-simulator | 200 | El comando que un desarrollador escribiría y su salida real |
| El producto en un dispositivo | laptop-frame, phone-frame | 240 / 240 | Poner la grabación en un MacBook o iPhone, abrir y hacer zoom |
| La acción clave | cursor-track envolviendo screen-recording | 132 / 139 | Un cursor camina y hace clic mientras la cámara se acerca a la grabación |
| Productos de IA | prompt-send, answer-stream, search-typing | 165 / 150 / 420 | Un prompt escrito y enviado, la respuesta transmitida en vivo |
| El resultado | status-cycle, count-grid | 198 / 47 | Un cambio de estado ("en cola → activo") o un número real |
| Tarjeta final | block-wordmark, logo-flicker | 150 / 100 | El nombre |
Presupuesta cada secuencia a la duración natural del componente (la columna Fotogramas). Subpresupuestar recorta la toma; sobrepresupuestar deja tiempo muerto.
3. Instalación
npx shadcn@latest add https://imgcli.com/r/terminal-simulator.json https://imgcli.com/r/laptop-frame.json https://imgcli.com/r/cursor-track.json https://imgcli.com/r/screen-recording.json https://imgcli.com/r/status-cycle.json https://imgcli.com/r/block-wordmark.json
4. Composición
Esta composición verifica tipos y se renderiza tal cual (con public/recording.mp4 presente):
import { fade } from "@remotion/transitions/fade";
import { slide } from "@remotion/transitions/slide";
import { linearTiming, TransitionSeries } from "@remotion/transitions";
import { staticFile } from "remotion";
import { BlockWordmark } from "@/components/imgcli/block-wordmark";
import { CursorTrack } from "@/components/imgcli/cursor-track";
import { LaptopFrame } from "@/components/imgcli/laptop-frame";
import { ScreenRecording } from "@/components/imgcli/screen-recording";
import { StatusCycle } from "@/components/imgcli/status-cycle";
import { TerminalSimulator } from "@/components/imgcli/terminal-simulator";
// Pon la grabación real en public/. Su copia de interfaz es el guión: nunca inventes etiquetas.
const RECORDING = staticFile("recording.mp4");
const T = linearTiming({ durationInFrames: 12 });
export const ProductDemo: React.FC = () => (
<TransitionSeries>
{/* 1. Instalación: el comando que un desarrollador escribiría realmente */}
<TransitionSeries.Sequence durationInFrames={200}>
<TerminalSimulator
intro="Configura *Acme* en un comando"
command={{ text: "npx acme init" }}
lines={[
{ text: "npx acme init", type: "command" },
{ text: "Conectando tu cuenta de Stripe...", type: "log" },
{ text: "Listo. Se importaron 1,204 facturas.", type: "success" },
]}
/>
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={fade()} timing={T} />
{/* 2. El producto, en un dispositivo */}
<TransitionSeries.Sequence durationInFrames={240}>
<LaptopFrame screenSrc={RECORDING} entrance="open" finale="zoom-to-screen" />
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={slide()} timing={T} />
{/* 3. La única acción que solo este producto hace: cursor hace clic, cámara se acerca */}
<TransitionSeries.Sequence durationInFrames={132}>
<CursorTrack
path={[
{ at: 0, x: -0.06, y: 0.86, duration: 6 },
{ at: 8, x: 0.34, y: 0.44, duration: 22, click: true },
{ at: 60, x: 0.68, y: 0.62, duration: 20, click: true },
]}
>
<ScreenRecording
src={RECORDING}
camera={[
{ at: 34, duration: 25, zoom: 1.6, x: 0.36, y: 0.42 },
{ at: 96, duration: 25, zoom: 1 },
]}
/>
</CursorTrack>
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={fade()} timing={T} />
{/* 4. El resultado, como un cambio de estado */}
<TransitionSeries.Sequence durationInFrames={198}>
<StatusCycle
prefix="Tus libros están"
statuses={["sincronizando", "conciliando", "reconciliados"]}
chips={["Stripe", "QuickBooks", "Xero"]}
/>
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={fade()} timing={T} />
{/* 5. Tarjeta final */}
<TransitionSeries.Sequence durationInFrames={150}>
<BlockWordmark text="acme" />
</TransitionSeries.Sequence>
</TransitionSeries>
);
Regístrala con durationInFrames={872} (la suma de las secuencias menos 4 × 12 fotogramas),
fps={30}, width={1280}, height={720}.
Cómo apuntar las tomas:
- Las rutas de
cursor-trackson fracciones del fotograma (x,yde 0 a 1).ates el fotograma en el que el cursor empieza a moverse hacia ese punto;click: trueactiva el anillo de clic al llegar. Pon cada clic exactamente sobre el botón real en la grabación. - Los movimientos de cámara de
screen-recording({ at, duration, zoom, x, y }) se suavizan hasta una pose y se mantienen hasta el siguiente movimiento. Acércate (zoom: 1.4–1.8) a la acción clave; aléjate (zoom: 1) después de que aterrice. - Recorta el cromo del navegador con
crop={{ top: 0.11 }}cuando la grabación lo incluya. - Las líneas de
terminal-simulatorson{ text, type }contypedecommand,log,successoerror. Pega salida real, abreviada.
5. Auditoría de renderizado
npx remotion still ProductDemo out/click.png --frame=460
npx remotion render ProductDemo out/demo.mp4 --codec=h264 --crf=18
Renderiza un fotograma estático en el punto medio de cada momento y justo antes y después de cada corte, luego verifica:
- Cada clic aterriza en el botón real, no a su lado.
- El texto en la grabación es legible a 720p después del acercamiento. Si no, acércate más o recorta más ajustado.
- No hay fotograma negro en un corte, y no se muestra nada antes de que comience su escena.
6. Publicación
Renderiza una composición por relación de aspecto: 16:9 para X y LinkedIn, 9:16 (usa phone-frame)
para Reels, Shorts y TikTok. --scale=1.5 convierte el maestro de 1280×720 en 1920×1080.
Atribución
La regla "nunca inventes etiquetas de interfaz", el ciclo de auditoría de renderizado y la guía de plataformas están
adaptados de everyinc/product-launch-video
(MIT, © 2026 Every Media, Inc.). "La grabación es la fuente de verdad" está adaptado de
el skill hyperframes product-launch-video de HeyGen
(Apache-2.0). Ambos fueron reescritos para los componentes de Remotion y snapcn. Consulta
THIRD_PARTY_NOTICES.md.