Loading...
Loading...
Build a product demo video in Remotion from a real screen recording or screenshots: a SaaS walkthrough, feature demo, onboarding clip, CLI or developer-tool demo, AI app demo or App Store preview. Uses snapcn's Remotion components (@snapcn/screen-recording, cursor-track, laptop-frame, phone-frame, terminal-simulator, prompt-send, answer-stream, status-cycle) so the camera push, clicks, device frames and typed commands come pre-built instead of hand-animated. Triggers: product demo, demo video, remotion demo, product walkthrough, feature demo video, screen recording to video, app demo, SaaS demo, CLI demo, "turn my screen recording into a demo video".
npx skill4agent add shadcn-labs/snapcn remotion-product-demointerpolate()spring()https://snapcn.dev/llms-components.txt?ref=skill-demo.mdhttps://snapcn.dev/docs/screens/screen-recording.md?ref=skill-demo@snapcn/<name>npx skills add snapcndev/snapcn --skill snapcnscreen-recordingcameranpx create-video@latestnpx shadcn@latest initcomponents.jsonnpm i @remotion/transitionspublic/public/recording.mp4staticFile()| Beat | snapcn component | Frames | Use it for |
|---|---|---|---|
| Install / setup | | 200 | The command a developer would type, and its real output |
| The product on a device | | 240 / 240 | Put the recording on a MacBook or iPhone, open and zoom in |
| The key action | | 132 / 139 | A cursor walks and clicks while the camera pushes in on the recording |
| AI products | | 165 / 150 / 420 | A prompt typed and sent, the answer streaming back |
| The result | | 198 / 47 | A state change ("queued → live") or one real number |
| End card | | 150 / 100 | The name |
npx shadcn@latest add @snapcn/terminal-simulator @snapcn/laptop-frame @snapcn/cursor-track @snapcn/screen-recording @snapcn/status-cycle @snapcn/block-wordmarkpublic/recording.mp4import { 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/snap-cn/block-wordmark";
import { CursorTrack } from "@/components/snap-cn/cursor-track";
import { LaptopFrame } from "@/components/snap-cn/laptop-frame";
import { ScreenRecording } from "@/components/snap-cn/screen-recording";
import { StatusCycle } from "@/components/snap-cn/status-cycle";
import { TerminalSimulator } from "@/components/snap-cn/terminal-simulator";
// Put the real recording in public/. Its UI copy is the script — never invent labels.
const RECORDING = staticFile("recording.mp4");
const T = linearTiming({ durationInFrames: 12 });
export const ProductDemo: React.FC = () => (
<TransitionSeries>
{/* 1. Install: the command a developer would actually type */}
<TransitionSeries.Sequence durationInFrames={200}>
<TerminalSimulator
intro="Set up *Acme* in one command"
command={{ text: "npx acme init" }}
lines={[
{ text: "npx acme init", type: "command" },
{ text: "Connecting your Stripe account...", type: "log" },
{ text: "Ready. 1,204 invoices imported.", type: "success" },
]}
/>
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={fade()} timing={T} />
{/* 2. The product, on a device */}
<TransitionSeries.Sequence durationInFrames={240}>
<LaptopFrame screenSrc={RECORDING} entrance="open" finale="zoom-to-screen" />
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={slide()} timing={T} />
{/* 3. The one action only this product does: cursor clicks, camera pushes in */}
<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. The result, as a state change */}
<TransitionSeries.Sequence durationInFrames={198}>
<StatusCycle
prefix="Your books are"
statuses={["syncing", "matching", "reconciled"]}
chips={["Stripe", "QuickBooks", "Xero"]}
/>
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={fade()} timing={T} />
{/* 5. End card */}
<TransitionSeries.Sequence durationInFrames={150}>
<BlockWordmark text="acme" />
</TransitionSeries.Sequence>
</TransitionSeries>
);durationInFrames={872}fps={30}width={1280}height={720}cursor-trackxyatclick: truescreen-recording{ at, duration, zoom, x, y }zoom: 1.4–1.8zoom: 1crop={{ top: 0.11 }}terminal-simulator{ text, type }typecommandlogsuccesserrornpx remotion still ProductDemo out/click.png --frame=460
npx remotion render ProductDemo out/demo.mp4 --codec=h264 --crf=18phone-frame--scale=1.5tap-throughcheckout-pushprompt-divebuild-outvault-countscreen-wallclaude mcp add snapcn -- npx -y @snapcn/mcp@latest SNAPCN_API_KEY=YOUR_KEYcomponents.jsonproduct-launch-videoTHIRD_PARTY_NOTICES.md