Agent Skills — Claude Code makes the video
Install this video
Adds the full composition, its remocn dependencies, and the prompt to your Remotion project via the shadcn registry.
$ pnpm dlx shadcn@latest add kapishdima/remocn-demo/agent-skillsRender it locally
Renders the MP4 on your machine with the Remotion CLI.
$ pnpm dlx remotion render agent-skills out/agent-skills.mp4 --scale=2 --crf=15 --x264-preset=slower --jpeg-quality=95The prompt
Reconstructed draftA reconstruction of the prompt this video was generated from.
Make a meta demo video about the remocn agent skill itself — the pitch is basically "you ask Claude Code to make a video and it does." Show it as if Claude Code just received a prompt like "/remocn make a great demo video", briefly working through the skill, and then producing a polished remocn showcase as the result: a zoomed-in terminal typing the install command, the component's source getting scanned top to bottom in a glass code block, then a handful of component examples blurring in one after another — checkbox, input, drawer, alert-dialog, select, sheet. Add a GitHub stars beat and a quick X followers overview, use plain white text dividers between sections, and close on the remocn wordmark. Build the whole thing with remocn components.
The code
The exact source the AI wrote — the same files the install command puts in your project.
import React, { type ReactNode } from "react";
import { AbsoluteFill, Easing, Sequence, interpolate, spring, useCurrentFrame, useVideoConfig } from "remotion";
import { demoAsset } from "@/lib/demo-assets";
import {
TransitionSeries,
linearTiming,
type TransitionPresentation,
type TransitionPresentationComponentProps,
} from "@remotion/transitions";
import { loadFont as loadSans } from "@remotion/google-fonts/Manrope";
import { loadFont as loadMono } from "@remotion/google-fonts/GeistMono";
import { RemocnUIProvider } from "@/lib/remocn-ui";
import { ClaudeCode } from "@/components/remocn/claude-code";
import { Backdrop } from "@/components/remocn/backdrop";
import { KineticCenterBuild } from "@/components/remocn/kinetic-center-build";
import { ShortSlideDown } from "@/components/remocn/short-slide-down";
import { TerminalSimulator } from "@/components/remocn/terminal-simulator";
import { GlassCodeBlock } from "@/components/remocn/glass-code-block";
import {
BlurIn,
type BlurInDirection,
} from "@/components/remocn/blur-in";
import { useBlurInTransition } from "@/components/remocn/use-blur-in-transition";
import { Checkbox } from "@/components/remocn/checkbox";
import { useCheckboxTransition } from "@/components/remocn/use-checkbox-transition";
import { Input } from "@/components/remocn/input";
import { useInputTransition } from "@/components/remocn/use-input-transition";
import { Drawer } from "@/components/remocn/drawer";
import { useDrawerTransition } from "@/components/remocn/use-drawer-transition";
import { AlertDialog } from "@/components/remocn/alert-dialog";
import { useAlertDialogTransition } from "@/components/remocn/use-alert-dialog-transition";
import { Select } from "@/components/remocn/select";
import { useSelectTransition } from "@/components/remocn/use-select-transition";
import { Sheet } from "@/components/remocn/sheet";
import { useSheetTransition } from "@/components/remocn/use-sheet-transition";
import { GitHubStars, SAMPLE_STARGAZERS } from "@/components/remocn/github-stars";
import { XFollowersOverview } from "@/components/remocn/x-followers-overview";
// Bind the fonts the remocn components read from CSS variables.
const { fontFamily: SANS } = loadSans("normal", {
subsets: ["latin"],
weights: ["400", "600", "700", "800"],
});
const { fontFamily: MONO } = loadMono("normal", {
subsets: ["latin"],
weights: ["400", "700"],
});
// ---------------------------------------------------------------------------
// Palette — remocn dark with the Claude terracotta as the through-line tying
// the "request" frame to the video it produces.
// ---------------------------------------------------------------------------
const ACCENT = "#D97757";
const INK = "#FAFAFA";
const PAGE = "#0B0B0C";
// ---------------------------------------------------------------------------
// Scene timings (frames @ 30fps). Transitions overlap consecutive scenes.
// ---------------------------------------------------------------------------
const S_PROMPT = 292; // Claude Code: type request → think → "produce" the video
const S_TERMINAL = 82; // zoomed terminal typing the install command
const S_CODE = 134; // glass code block — scan top→bottom, pull back, then hold
const S_DIV = 58; // text divider between product blocks
const S_SHOWCASE = 228; // six component examples, blur-in transitions
const S_AI = 110; // "works with your AI" — stacked avatar group
const S_GH = 130; // github-stars fly-through
const S_XF = 300; // x-followers overview — trimmed to exit just after the total settles (no dead air)
const S_OUTRO = 120; // closing wordmark + install pill (from the typography demo)
const T_HANDOFF = 24; // CC → video: "render complete, here it is"
const T_FADE = 16;
const T_BF = 16; // blur-fade between the back-half scenes
const T_RISE = 18;
export const AGENT_SKILLS_DURATION =
S_PROMPT +
S_TERMINAL +
S_CODE +
S_DIV +
S_SHOWCASE +
S_AI +
S_DIV +
S_GH +
S_DIV +
S_XF +
S_OUTRO -
(T_HANDOFF + T_FADE + 7 * T_BF + T_RISE);
// ===========================================================================
// Shared helpers
// ===========================================================================
// ===========================================================================
// Scene 1 — the request: Claude Code types the skill command, then thinks and
// "produces" the video. The thinking phase is the new feature being demoed.
// ===========================================================================
const PromptScene: React.FC = () => (
<AbsoluteFill style={{ background: "transparent" }}>
<ClaudeCode
title="Claude Code v2.0.0"
userName="you"
model="Opus 4.8 • Max"
cwd="~/code/remocn-demo"
placeholder='Try "/remocn ..."'
prompt="/remocn make a greate demo video for my product"
accentColor={ACCENT}
thinking
thinkingVerbs={[
"Thinking",
"Reading the brief",
"Composing scenes",
"Animating",
"Rendering",
]}
thinkingActivity={[
"Loading skill: remocn",
"Reading components catalog — 70+ components",
"Composing scenes — title, install, showcase",
"Wiring kinetic transitions @ 1280×720 · 30fps",
"✓ Rendered demo.mp4",
]}
thinkingLineStagger={24}
/>
</AbsoluteFill>
);
// ===========================================================================
// Scene 2 — install: a zoomed terminal typing the shadcn command. The camera
// is pinned to the typing cursor — it starts on the left of the line and dollies
// right as each character appears.
// ===========================================================================
const INSTALL_CMD = "npx shadcn add @remocn/terminal-simulator";
const TerminalZoomScene: React.FC = () => {
const frame = useCurrentFrame();
// Terminal geometry (matches terminal-simulator's internal 900×480 window,
// centred on the 1280×720 stage).
const TERM_FONT = 20;
const CHAR_W = TERM_FONT * 0.6; // monospace advance ≈ 0.6em
const WIN_LEFT = (1280 - 900) / 2; // 190
const WIN_TOP = (720 - 480) / 2; // 120
const TEXT_START_X = WIN_LEFT + 20 + (CHAR_W + 8); // content pad + "$ "
const LINE_HEIGHT = Math.round(TERM_FONT * 1.6); // 32
const CURSOR_Y = WIN_TOP + 40 + 20 + LINE_HEIGHT / 2; // chrome + pad + half line
const LINE_START = 10; // terminal-simulator's first line begins at frame 10
const CHARS_PER_FRAME = 1;
// Camera: maximum zoom, cursor pinned to a fixed screen point.
const Z = 2.8;
const TARGET_X = 640; // screen X the cursor rides on
const TARGET_Y = 360;
const revealed = interpolate(
frame,
[LINE_START, LINE_START + INSTALL_CMD.length / CHARS_PER_FRAME],
[0, INSTALL_CMD.length],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp" },
);
const cursorX = TEXT_START_X + revealed * CHAR_W;
const tx = TARGET_X - Z * cursorX;
const ty = TARGET_Y - Z * CURSOR_Y;
return (
<AbsoluteFill style={{ background: PAGE, overflow: "hidden" }}>
<div
style={{
position: "absolute",
left: 0,
top: 0,
width: 1280,
height: 720,
transform: `translate(${tx}px, ${ty}px) scale(${Z})`,
transformOrigin: "0 0",
}}
>
<TerminalSimulator
lines={[{ text: INSTALL_CMD, type: "command", delay: 0 }]}
prompt="$"
title="~/code/remocn-demo"
fontSize={TERM_FONT}
charsPerFrame={CHARS_PER_FRAME}
chunkSize={1}
/>
</div>
</AbsoluteFill>
);
};
// ===========================================================================
// Scene 3b — the component's code in a glass block (no gradient aura behind it,
// so the photographic backdrop refracts through the glass instead).
// ===========================================================================
const COMPONENT_CODE = `import { TerminalSimulator } from "@/components/remocn";
export function BuildScene() {
return (
<TerminalSimulator
lines={[{ text: "npm run build", type: "command" }]}
/>
);
}`;
const CodeScene: React.FC = () => {
const frame = useCurrentFrame();
const codeLines = COMPONENT_CODE.split("\n");
const n = codeLines.length;
const STAGGER = 10; // frames between each line's reveal
const PULL = 24; // zoom-out duration
// Glass-block geometry on the 1280×720 stage (880×420, centred).
const BLOCK_LEFT = (1280 - 880) / 2; // 200
const BLOCK_TOP = (720 - 420) / 2; // 150
const BODY_TOP = BLOCK_TOP + 1 + 40 + 20; // ring + chrome + body padding
const LINE_FS = 18;
const GAP = 4;
const lineH = (l: string) =>
l.trim() === "" ? LINE_FS * 0.8 : LINE_FS * 1.55;
// Per-line vertical centres, accounting for the short blank-line spacer.
const lineCenters: number[] = [];
let yy = BODY_TOP;
for (const l of codeLines) {
lineCenters.push(yy + lineH(l) / 2);
yy += lineH(l) + GAP;
}
const ANCHOR_WORLD_X = BLOCK_LEFT + 25; // start of the line-number gutter
const ANCHOR_SCREEN_X = 110;
const TARGET_Y = 360;
const Z_IN = 2.6;
// Camera scans top→bottom, tracking the line currently revealing, and holds
// on the second-to-last line (index n-2).
const lp = interpolate(frame, [0, (n - 2) * STAGGER], [0, n - 2], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const i0 = Math.floor(lp);
const i1 = Math.min(i0 + 1, n - 1);
const currentLineY =
lineCenters[i0] + (lineCenters[i1] - lineCenters[i0]) * (lp - i0);
const pinnedX = ANCHOR_SCREEN_X - Z_IN * ANCHOR_WORLD_X;
const pinnedY = TARGET_Y - Z_IN * currentLineY;
// On the second-to-last line, pull the zoom back to the standard centred view.
const qPull = interpolate(
frame,
[(n - 2) * STAGGER, (n - 2) * STAGGER + PULL],
[0, 1],
{
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.inOut(Easing.cubic),
},
);
const scale = Z_IN + qPull * (1 - Z_IN);
const tx = (1 - qPull) * pinnedX;
const ty = (1 - qPull) * pinnedY;
return (
<AbsoluteFill style={{ background: "transparent" }}>
<AbsoluteFill
style={{
opacity: qPull,
background:
"radial-gradient(120% 120% at 50% 55%, rgba(11,11,12,0.2) 0%, rgba(11,11,12,0.62) 100%)",
}}
/>
<div
style={{
position: "absolute",
left: 0,
top: 0,
width: 1280,
height: 720,
transform: `translate(${tx}px, ${ty}px) scale(${scale})`,
transformOrigin: "0 0",
}}
>
<GlassCodeBlock
code={COMPONENT_CODE}
title="terminal-simulator.tsx"
width={880}
height={420}
fontSize={LINE_FS}
staggerFrames={STAGGER}
aura={false}
/>
</div>
</AbsoluteFill>
);
};
// ===========================================================================
// Divider scenes — white text between the product blocks (no accent colour),
// alternating kinetic-center-build and short-slide-down.
// ===========================================================================
const DividerScrim: React.FC = () => (
<AbsoluteFill
style={{
background:
"radial-gradient(120% 120% at 50% 50%, rgba(11,11,12,0.25) 0%, rgba(11,11,12,0.72) 100%)",
}}
/>
);
const useDividerFadeOut = (): number => {
const frame = useCurrentFrame();
return interpolate(frame, [S_DIV - 10, S_DIV], [1, 0], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
};
const DividerKinetic: React.FC<{ text: string }> = ({ text }) => (
<AbsoluteFill style={{ background: "transparent", opacity: useDividerFadeOut() }}>
<DividerScrim />
<KineticCenterBuild
text={text}
fontSize={92}
color={INK}
fontWeight={800}
entryOffset={70}
speed={1.25}
/>
</AbsoluteFill>
);
const DividerSlide: React.FC<{ text: string }> = ({ text }) => (
<AbsoluteFill style={{ background: "transparent", opacity: useDividerFadeOut() }}>
<DividerScrim />
<ShortSlideDown
text={text}
fontSize={84}
color={INK}
fontWeight={800}
speed={1.2}
/>
</AbsoluteFill>
);
// ===========================================================================
// Showcase — six component examples on a light "app card", each revealed with a
// dynamic blur-in (no captions). The blur-in carries the transition.
// ===========================================================================
const SHOW_STEP = 36; // frames between each component's entrance
const SHOW_PER = 48; // each component's on-screen window
const AppCard: React.FC<{ children: ReactNode }> = ({ children }) => (
<div
style={{
position: "relative",
width: 800,
height: 480,
borderRadius: 20,
overflow: "hidden",
background: "#ffffff",
boxShadow: "0 50px 120px rgba(0,0,0,0.55)",
}}
>
{children}
</div>
);
const BlurItem: React.FC<{ dir: BlurInDirection; children: ReactNode }> = ({
dir,
children,
}) => {
const style = useBlurInTransition(
[
{ at: 2, state: "revealed", duration: 14 },
{ at: SHOW_PER - 16, state: "hidden", duration: 14 },
],
{ direction: dir, distance: 44, blur: 16 },
);
return (
<AbsoluteFill style={{ alignItems: "center", justifyContent: "center" }}>
<BlurIn style={style} display="block">
{children}
</BlurIn>
</AbsoluteFill>
);
};
// Each example drives its own state animation via its transition hook (the
// checkbox checks, the input types, the drawer/sheet/dialog/select open), and
// the whole card blurs in/out around it.
const OPEN_AT = 6;
const OPEN_DUR = 18;
const ShowCheckbox: React.FC = () => {
const style = useCheckboxTransition([
{ at: 0, state: "unchecked" },
{ at: 10, state: "checked", duration: 16 },
]);Showing the first 400 of 1062 lines. View the full file on GitHub.