Communitygithub.com

Remotion Compose

Turns a natural-language video brief into a complete, ready-to-preview Remotion composition - extracts duration, scenes, brand colors, aspect ratio, and real copy; plans the frame budget; and writes data-driven React/TypeScript using useCurrentFrame, interpolate, spring, AbsoluteFill, and Sequence, registered in Root.tsx. Use when someone says

Remotion Compose 是什么?

Remotion Compose is a Cursor agent skill that turns a natural-language video brief into a complete, ready-to-preview Remotion composition - extracts duration, scenes, brand colors, aspect ratio, and real copy; plans the frame budget; and writes data-driven React/TypeScript using useCurrentFrame, interpolate, spring, AbsoluteFill, and Sequence, registered in Root.tsx. Use when someone says.

兼容平台~Claude Code~Codex CLICursor
npx skills add https://github.com/SkillMedev/tutorial-video-studio/tree/main/skills/remotion-compose

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Remotion Compose 是做什么的?

You turn a natural-language brief into a complete, ready-to-preview Remotion composition - real React/TypeScript with frame-driven animation. The output is a .tsx file in src/compositions/, registered in src/Root.tsx, that the user can immediately scrub in Studio or hand to remotion-render.

Trigger on any request to create, generate, animate, or "write the video code for" a product demo, walkthrough, feature callout, or marketing animation - including "build a 20-second video showing X."

Step 1 - Extract the brief

Do not start coding until you have these. Ask in one compact batch; fill obvious gaps with sensible defaults rather than stalling:

  1. Duration in seconds, and fps (default 30 - the standard for product and marketing video, and half the render cost of 60. Reach for 60fps only when animating fine cursor motion or scrolling UI where 30 visibly stutters).
  2. Scenes - what happens, in order. Push for a beat list: "logo, then three features, then a CTA" beats "a demo of my app."
  3. Brand - primary/accent/background hex colors, and the font (a @remotion/google-fonts family name).
  4. Aspect ratio / platform - 16:9 landscape (1920×1080), 9:16 vertical (1080×1920) for social, or 1:1 square (1080×1080).
  5. Copy - the actual headlines/feature names/CTA text. Never invent product claims; ask for the real words.

Convert seconds to frames everywhere: durationInFrames = seconds * fps. Typical total lengths: 15-60s for a social/product demo, 6-15s for an ad cut.

Step 2 - Build a scene plan

One <Composition> per video, one component per scene, stitched on the timeline with <Sequence>. Lay out the frame budget before writing code:

Total: 20s @ 30fps = 600 frames
  Intro (logo)        frames   0-90    (Sequence from=0   durationInFrames=90)
  Feature 1           frames  90-240   (Sequence from=90  durationInFrames=150)
  Feature 2           frames 240-390   (Sequence from=240 durationInFrames=150)
  Feature 3           frames 390-540   (Sequence from=390 durationInFrames=150)
  CTA outro           frames 540-600   (Sequence from=540 durationInFrames=60)

Pacing thresholds while budgeting:

  • Give any beat that carries text at least 2 seconds (60 frames at 30fps) - enter animation plus hold. A headline needs roughly 150-200ms of hold per word to be readable; a 6-word headline wants ~1s of hold after it lands.
  • Enter animations: 10-20 frames. Cross-fades and exits: 12-15 frames. Longer reads as sluggish, shorter as a glitch.
  • No scene shorter than ~45 frames unless it is a deliberate flash cut.

<Sequence from={F}> shifts a child's local clock so inside that component useCurrentFrame() starts at 0. Animate each scene as if it begins at frame 0.

Step 3 - Core API reference

  • useCurrentFrame() - the current frame (the clock). Everything animates as a function of this.
  • useVideoConfig() - { fps, width, height, durationInFrames }.
  • interpolate(frame, [inFrames], [outValues], opts) - linear mapping. Always pass { extrapolateLeft: "clamp", extrapolateRight: "clamp" } for enter/exit so values do not run past their range.
  • spring({ frame, fps, config }) - physics-based 0→1 (overshoots slightly). Use for anything that should feel alive (pops, slides, scale-ins).
  • AbsoluteFill - a full-frame absolutely-positioned div; the base layer of every scene.
  • Sequence - time-shifts and time-bounds children (the scene scheduler).
  • Series / Series.Sequence - back-to-back scenes without computing from offsets by hand.
  • Img, staticFile - see Step 6.

Step 4 - spring() vs interpolate()

Use spring() when…Use interpolate() when…
The motion should feel physical - pops, bounces, scale-ins, slide-insYou need precise, linear control between exact frames
You want a natural settle/overshootFades (opacity 0→1), color shifts, progress bars, anything timed-to-the-frame
Entrances of cards, logos, badgesCross-fades and exits where overshoot would look wrong

Pattern - drive a transform with a spring, an opacity with interpolate:

const { fps } = useVideoConfig();
const frame = useCurrentFrame();
const pop = spring({ frame, fps, config: { damping: 200 } });   // 0 → 1, lively
const opacity = interpolate(frame, [0, 15], [0, 1], { extrapolateRight: "clamp" });
const scale = interpolate(pop, [0, 1], [0.8, 1]);

damping: 200 is the workhorse config - a quick settle with barely-there overshoot. Lower damping (~10-20) bounces visibly; use it only when bounce is the point.

Step 5 - Standard product-demo structure

Encode this shape unless the brief says otherwise: logo/brand intro → N feature callouts → CTA outro. Make it data-driven (Step 6) so variants are free.

// src/compositions/ProductDemo.tsx
import {
  AbsoluteFill, Sequence, useCurrentFrame, useVideoConfig,
  interpolate, spring,
} from "remotion";
import { loadFont } from "@remotion/google-fonts/Inter";

const { fontFamily } = loadFont();

export type Feature = { title: string; body: string };
export type ProductDemoProps = {
  brand: string;
  colors: { bg: string; fg: string; accent: string };
  logoText: string;
  features: Feature[];
  cta: string;
};

const Intro: React.FC<{ text: string; colors: ProductDemoProps["colors"] }> = ({ text, colors }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const s = spring({ frame, fps, config: { damping: 200 } });
  const scale = interpolate(s, [0, 1], [0.7, 1]);
  const opacity = interpolate(frame, [0, 12], [0, 1], { extrapolateRight: "clamp" });
  return (
    <AbsoluteFill style={{ backgroundColor: colors.bg, justifyContent: "center", alignItems: "center" }}>
      <h1 style={{ fontFamily, fontSize: 120, color: colors.fg, transform: `scale(${scale})`, opacity }}>
        {text}
      </h1>
    </AbsoluteFill>
  );
};

const FeatureCallout: React.FC<{ feature: Feature; colors: ProductDemoProps["colors"] }> = ({ feature, colors }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const slide = spring({ frame, fps, config: { damping: 200 } });
  const x = interpolate(slide, [0, 1], [-60, 0]);
  const opacity = interpolate(frame, [0, 15], [0, 1], { extrapolateRight: "clamp" });
  return (
    <AbsoluteFill style={{ backgroundColor: colors.bg, justifyContent: "center", paddingLeft: 160 }}>
      <div style={{ transform: `translateX(${x}px)`, opacity }}>
        <div style={{ fontFamily, fontSize: 32, color: colors.accent, fontWeight: 700, letterSpacing: 2 }}>
          {feature.title.toUpperCase()}
        </div>
        <div style={{ fontFamily, fontSize: 64, color: colors.fg, maxWidth: 1100, marginTop: 16 }}>
          {feature.body}
        </div>
      </div>
    </AbsoluteFill>
  );
};

const Outro: React.FC<{ cta: string; colors: ProductDemoProps["colors"] }> = ({ cta, colors }) => {
  const frame = useCurrentFrame();
  const opacity = interpolate(frame, [0, 18], [0, 1], { extrapolateRight: "clamp" });
  return (
    <AbsoluteFill style={{ backgroundColor: colors.accent, justifyContent: "center", alignItems: "center" }}>
      <h2 style={{ fontFamily, fontSize: 84, color: colors.bg, opacity }}>{cta}</h2>
    </AbsoluteFill>
  );
};

export const ProductDemo: React.FC<ProductDemoProps> = ({ colors, logoText, features, cta }) => {
  const intro = 90;
  const per = 150;
  const outro = 60;
  return (
    <AbsoluteFill>
      <Sequence durationInFrames={intro}>
        <Intro text={logoText} colors={colors} />
      </Sequence>
      {features.map((f, i) => (
        <Sequence key={i} from={intro + i * per} durationInFrames={per}>
          <FeatureCallout feature={f} colors={colors} />
        </Sequence>
      ))}
      <Sequence from={intro + features.length * per} durationInFrames={outro}>
        <Outro cta={cta} colors={colors} />
      </Sequence>
    </AbsoluteFill>
  );
};

Register it in src/Root.tsx, computing durationInFrames from the same numbers and supplying defaultProps:

<Composition
  id="ProductDemo"
  component={ProductDemo}
  durationInFrames={90 + 3 * 150 + 60}
  fps={30}
  width={1920}
  height={1080}
  defaultProps={{
    brand: "Acme",
    colors: { bg: "#0B0B0F", fg: "#FFFFFF", accent: "#6C5CE7" },
    logoText: "Acme",
    features: [
      { title: "Fast", body: "Ship in seconds, not sprints." },
      { title: "Simple", body: "One prompt, one video." },
      { title: "Yours", body: "Your brand, your copy." },
    ],
    cta: "Start free →",
  }}
/>

For vertical/social, set width={1080} height={1920}; for square, 1080×1080. Keep the components identical - only the canvas changes.

Step 6 - Data-driven props & static assets

The composition above is fully data-driven: every word and color is a prop. That is the point - variants (new copy, new palette, localized text) need no re-prompting; just pass different props (remotion-render does this from a JSON file for batches).

Static assets (logos, screenshots, audio) live in public/assets/ and are referenced with staticFile() - never an import or a raw path:

import { Img, staticFile } from "remotion";
<Img src={staticFile("assets/logo.png")} />

Step 7 - Output

Save the finished file to src/compositions/<VideoName>.tsx, register it in src/Root.tsx, and tell the user to preview with npx remotion studio (http://localhost:3000). Then hand off: "Scrub it in Studio. Tell me what to change - too fast, wrong color, different copy - and I'll edit and re-render (remotion-render)."

Do NOT

  • Do NOT animate with CSS transitions/animations or setTimeout/setInterval. Remotion renders frames independently and in parallel; anything not derived from useCurrentFrame() is invisible or inconsistent in the final render even though it may look fine in the browser preview.
  • Do NOT use Math.random() for scattered/particle effects - every render worker gets different values and frames stop matching. Use Remotion's random(seed) for deterministic pseudo-randomness.
  • Do NOT fetch data or wait on async work without delayRender() / continueRender() - the renderer captures the frame before the data arrives.
  • Do NOT hardcode fps, width, or height inside scene components - read them from useVideoConfig() so switching 30↔60fps or landscape↔vertical doesn't break every timing and layout.
  • Do NOT omit extrapolateLeft/Right: "clamp" on enter/exit interpolations - opacity climbs past 1 and elements drift off-canvas after their range ends.
  • Do NOT invent headlines, feature claims, or CTAs - use the user's real copy, and ask for it if missing.

Quality bar

  • Every animated value is a pure function of useCurrentFrame() (plus props) - scrubbing backwards in Studio looks identical to playing forwards.
  • The frame budget in the plan sums exactly to durationInFrames in Root.tsx, and no text beat holds for less than its readable minimum.
  • All copy and colors arrive via typed props with defaultProps supplied - no literals buried in scene components.
  • Assets load via staticFile(); the file registers cleanly and previews in Studio without console errors.

Individual skills in this repo

This repo contains 11 individual skills — each has its own dedicated page.

Captions From Transcript

Produce an accurate, properly timed caption track (SRT or WebVTT) from a video

Kinetic Typography

Put text in motion the right way - title cards, animated captions, lower-thirds, callouts, and word-by-word reveals - with a reading-time-per-word budget so copy holds long enough to read, plus enter/exit timing, weight and size transitions, and type hierarchy in motion. Use when someone asks to

Motion Design Principles

The craft layer for motion: pick the right easing (ease-in / ease-out / ease-in-out / spring), get timing and spacing right, build the anticipation→action→follow-through arc, and apply Disney

Narration Script

Write the spoken voiceover for a tutorial or demo - the actual words, phrased for the ear and synced one-instruction-per-action to what is on screen, with a pacing budget and a confident, jargon-checked tone. Use when someone says

Product Demo Director

Direct the craft of putting a real software UI on screen - cursor choreography, zoom/pan/callout language, screen-recording vs recreated-UI, and making state changes legible with highlights, focus pulls, and slow-downs. Use when filming or recreating an app for a product demo, feature walkthrough, onboarding clip, or release reel and asking

Remotion Render

Renders a Remotion composition to MP4 and runs the edit-and-re-render loop - CLI render commands, 1080p/4K/9:16 presets, concurrency tuning, codec selection, batch variants from a JSON data file, and Lambda for cloud rendering. Use when someone says

Remotion Setup

Scaffolds a new Remotion video project wired for Claude Code Agent Skills - Node check, create-video scaffold, skills install, folder conventions, Google Fonts, and a smoke-test render. Use whenever someone wants to start making videos with Remotion and Claude, even just

Screencast Capture

Capture clean raw screen and camera footage for a tutorial or product demo - choosing the recorder (macOS Screenshot toolbar, QuickTime, OBS, Windows Game Bar), setting resolution / frame-rate / cursor / microphone, prepping a distraction-free stage, and recording in retakeable segments. Use when someone says

Social Video Formatter

Reframe and export a finished video for social platforms - 9:16 ↔ 16:9 cropping, burned-in captions, a platform-native first frame, loop design, and per-platform specs (aspect, length, safe areas) for TikTok, Reels, Shorts, X, and LinkedIn. Use when someone says

Sound and Music Sync

Score a video like an editor: beat-match cuts to the music, land SFX on transitions, pace the voiceover so it breathes, source royalty-free tracks safely, and duck the music so the VO sits clearly on top. Use when adding music, sound effects, or voiceover to a video, when asked to

Video Storyboard

Plan a product demo, feature announcement, or launch video as a beat sheet and shot list BEFORE animating - hook in the first 3s, problem, reveal, proof, CTA - with target duration and pacing per scene type, output as a JSON scene plan that remotion-compose consumes directly. Use when someone says

相关技能