Changelog — The remocn agent skill, rebuilt
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/skill-changelogRender it locally
Renders the MP4 on your machine with the Remotion CLI.
$ pnpm dlx remotion render skill-changelog out/skill-changelog.mp4 --scale=2 --crf=15 --x264-preset=slower --jpeg-quality=95The prompt
Reconstructed draftA reconstruction of the prompt this video was generated from.
We just rebuilt the remocn agent skill itself — it went from one giant SKILL.md to a proper structured reference with a references folder (anatomy, design, motion-principles, anti-patterns, archetypes, per-component docs). Make a meta changelog video about that change for our own audience. Start with a hero beat that builds out the new file tree on screen, then a changelog-style list of what actually got added, then roll up some proof numbers — like 124 components, 9 archetypes, 5 guides — and close on a calm remocn wordmark. Give it its own look, separate from our other videos — warm accent color, flat near-black grid, something closer to a docs/IDE aesthetic. Use remocn components for the build and rolling-number beats.
The code
The exact source the AI wrote — the same files the install command puts in your project.
import React, { type CSSProperties, type ReactNode } from "react";
import {
AbsoluteFill,
Easing,
interpolate,
spring,
useCurrentFrame,
useVideoConfig,
} from "remotion";
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 { DynamicGrid } from "@/components/remocn/dynamic-grid";
import { RollingNumber } from "@/components/remocn/rolling-number";
// ---------------------------------------------------------------------------
// Fonts — bind to the CSS variables the remocn components read.
// ---------------------------------------------------------------------------
const { fontFamily: SANS_FAMILY } = loadSans("normal", {
subsets: ["latin"],
weights: ["400", "500", "600", "700", "800"],
});
const { fontFamily: MONO_FAMILY } = loadMono("normal", {
subsets: ["latin"],
weights: ["400", "500", "700"],
});
const SANS =
"var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif";
const MONO = "var(--font-geist-mono), ui-monospace, SFMono-Regular, monospace";
// ---------------------------------------------------------------------------
// Palette — one warm accent (Claude/agent) on a flat near-black doc surface.
// ---------------------------------------------------------------------------
const BG = "#0a0a0a";
const INK = "#fafafa";
const FAINT = "rgba(250,250,250,0.50)";
const DIM = "rgba(250,250,250,0.32)";
const HAIR = "rgba(250,250,250,0.10)";
const SURFACE = "#141414";
const ACCENT = "#D97757"; // warm — the agent accent
const GREEN = "#5fcf80"; // muted semantic — Added
const BLUE = "#6aa8f5"; // muted semantic — Changed
// ---------------------------------------------------------------------------
// Scene timings (frames @ 30fps). Transitions overlap adjacent scenes.
// ---------------------------------------------------------------------------
const S_OPEN = 78; // positioning — "the skill, rebuilt"
const S_BEFORE = 82; // problem — one monolithic file
const S_TREE = 168; // hero — the new structure builds as a file tree
const S_CHANGES = 132; // change list — what got added
const S_STATS = 120; // proof — rolling numbers
const S_OUTRO = 120; // CTA — wordmark + tagline
const T_X = 14; // neutral crossfade
const T_ZOOM = 16; // push deeper into the structure
const T_OUT = 18; // settle into the outro
export const SKILL_CHANGELOG_DURATION =
S_OPEN +
S_BEFORE +
S_TREE +
S_CHANGES +
S_STATS +
S_OUTRO -
(T_X + T_ZOOM + T_X + T_X + T_OUT);
// ---------------------------------------------------------------------------
// Reveal — frame-driven fade + offset + blur clear. Deterministic.
// ---------------------------------------------------------------------------
const Reveal: React.FC<{
children: ReactNode;
delay?: number;
duration?: number;
y?: number;
x?: number;
blur?: number;
display?: CSSProperties["display"];
}> = ({
children,
delay = 0,
duration = 20,
y = 16,
x = 0,
blur = 8,
display = "block",
}) => {
const frame = useCurrentFrame();
const p = interpolate(frame, [delay, delay + duration], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.out(Easing.cubic),
});
return (
<div
style={{
display,
opacity: p,
transform: `translate(${(1 - p) * x}px, ${(1 - p) * y}px)`,
filter: p < 1 ? `blur(${(1 - p) * blur}px)` : undefined,
}}
>
{children}
</div>
);
};
// ---------------------------------------------------------------------------
// Eyebrow — a small accent-dotted label chip.
// ---------------------------------------------------------------------------
const Eyebrow: React.FC<{ children: string; delay?: number }> = ({
children,
delay = 0,
}) => (
<Reveal delay={delay} y={10} blur={6} duration={16} display="inline-block">
<div
style={{
display: "inline-flex",
alignItems: "center",
gap: 9,
padding: "7px 15px 7px 12px",
borderRadius: 999,
border: `1px solid ${HAIR}`,
background: "rgba(255,255,255,0.03)",
fontFamily: SANS,
fontSize: 16,
fontWeight: 600,
color: FAINT,
}}
>
<span
style={{
width: 8,
height: 8,
borderRadius: "50%",
background: ACCENT,
}}
/>
{children}
</div>
</Reveal>
);
// ===========================================================================
// Scene 1 — Positioning. State what this is.
// ===========================================================================
const OpenScene: React.FC = () => (
<AbsoluteFill
style={{
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
gap: 22,
}}
>
<Eyebrow delay={2}>Skill update · remocn</Eyebrow>
<Reveal delay={12} y={20} blur={12} duration={24}>
<h1
style={{
margin: 0,
fontFamily: SANS,
fontWeight: 700,
fontSize: 68,
letterSpacing: "-0.02em",
color: INK,
textAlign: "center",
lineHeight: 1.05,
}}
>
The agent skill,
<br />
<span style={{ color: ACCENT }}>rebuilt.</span>
</h1>
</Reveal>
<Reveal delay={26} y={14} blur={8} duration={20}>
<p
style={{
margin: 0,
fontFamily: SANS,
fontWeight: 500,
fontSize: 24,
color: FAINT,
textAlign: "center",
}}
>
Restructured, and a lot more detailed.
</p>
</Reveal>
</AbsoluteFill>
);
// ===========================================================================
// Scene 2 — Problem. It used to be one monolithic file.
// ===========================================================================
// Deterministic line widths for the "crammed" monolith doc (no randomness).
const MONO_LINES = [
96, 72, 88, 54, 91, 67, 83, 60, 94, 49, 79, 86, 58, 90, 64, 81, 71, 95, 52,
87, 75, 62, 92, 56,
];
const BeforeScene: React.FC = () => (
<AbsoluteFill
style={{
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
gap: 30,
}}
>
<Reveal delay={2} y={14} blur={8} duration={18}>
<h2
style={{
margin: 0,
fontFamily: SANS,
fontWeight: 600,
fontSize: 34,
color: INK,
textAlign: "center",
}}
>
It used to live in <span style={{ color: ACCENT }}>one file</span>.
</h2>
</Reveal>
<Reveal delay={10} y={30} blur={12} duration={22}>
<div
style={{
width: 420,
height: 300,
borderRadius: 16,
background: SURFACE,
border: `1px solid ${HAIR}`,
overflow: "hidden",
boxShadow: "0 24px 60px rgba(0,0,0,0.45)",
}}
>
{/* file header */}
<div
style={{
display: "flex",
alignItems: "center",
gap: 9,
padding: "13px 18px",
borderBottom: `1px solid ${HAIR}`,
}}
>
<span
style={{ width: 8, height: 8, borderRadius: "50%", background: ACCENT }}
/>
<span style={{ fontFamily: MONO, fontSize: 15, color: FAINT }}>
SKILL.md
</span>
<span
style={{
marginLeft: "auto",
fontFamily: MONO,
fontSize: 12,
color: DIM,
}}
>
everything
</span>
</div>
{/* crammed lines */}
<div
style={{
padding: "14px 18px",
display: "flex",
flexDirection: "column",
gap: 7,
}}
>
{MONO_LINES.map((w, i) => (
<div
key={i}
style={{
height: 5,
width: `${w}%`,
borderRadius: 3,
background: "rgba(250,250,250,0.13)",
}}
/>
))}
</div>
</div>
</Reveal>
</AbsoluteFill>
);
// ===========================================================================
// Scene 3 — Hero. The new structure builds itself as a file tree.
// ===========================================================================
type Row = {
prefix: string;
name: string;
dir?: boolean;
note?: string;
fresh?: boolean; // newly added → accent
};
const TREE: Row[] = [
{ prefix: "", name: "skills/remocn/", dir: true },
{ prefix: "├─ ", name: "SKILL.md" },
{ prefix: "└─ ", name: "references/", dir: true },
{ prefix: " ├─ ", name: "anatomy.md", note: "strategy · beats · quality bar", fresh: true },
{ prefix: " ├─ ", name: "design.md" },
{ prefix: " ├─ ", name: "motion-principles.md" },
{ prefix: " ├─ ", name: "anti-patterns.md" },
{ prefix: " ├─ ", name: "archetypes/", dir: true, note: "9 recipes", fresh: true },
{ prefix: " └─ ", name: "components/", dir: true, note: "one file each", fresh: true },
];
const TreeRow: React.FC<{ row: Row; delay: number }> = ({ row, delay }) => {
const frame = useCurrentFrame();
const p = interpolate(frame, [delay, delay + 16], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
easing: Easing.out(Easing.cubic),
});
const nameColor = row.fresh ? ACCENT : row.dir ? INK : FAINT;
return (
<div
style={{
display: "flex",
alignItems: "center",
height: 34,
opacity: p,
transform: `translateX(${(1 - p) * -12}px)`,
filter: p < 1 ? `blur(${(1 - p) * 5}px)` : undefined,
}}
>
<span
style={{
fontFamily: MONO,
fontSize: 21,
color: DIM,
whiteSpace: "pre",
}}
>
{row.prefix}
</span>
<span
style={{
fontFamily: MONO,
fontSize: 21,
fontWeight: row.dir ? 600 : 400,
color: nameColor,
}}
>
{row.name}
</span>
{row.note && (
<span
style={{
marginLeft: 14,
fontFamily: SANS,
fontSize: 13.5,
fontWeight: 500,
color: row.fresh ? "rgba(217,119,87,0.85)" : DIM,
padding: "3px 10px",
borderRadius: 999,
background: row.fresh ? "rgba(217,119,87,0.12)" : "transparent",
border: row.fresh ? "1px solid rgba(217,119,87,0.25)" : "none",
}}
>
{row.note}
</span>
)}
</div>
);
};
const TreeScene: React.FC = () => (
<AbsoluteFill
style={{
alignItems: "center",
justifyContent: "center",
flexDirection: "column",
gap: 34,
}}
>
<Reveal delay={2} y={14} blur={8} duration={18}>
<h2
style={{
margin: 0,
fontFamily: SANS,
fontWeight: 600,
fontSize: 34,
color: INK,
textAlign: "center",
}}
>
Now it has a <span style={{ color: ACCENT }}>structure</span>.
</h2>Showing the first 400 of 797 lines. View the full file on GitHub.