Communitygithub.com

Remotion Compose

将自然语言视频简介转换为完整、可预览的 Remotion 合成,自动提取时长、场景、品牌色、宽高比和真实文案,规划帧预算,并编写数据驱动的 React/TypeScript 代码。

Remotion Compose 是什么?

Remotion Compose 是一个专门用于将自然语言需求转化为 Remotion 视频项目的智能技能。它能够从用户提供的简短描述中自动提取关键信息,包括视频时长、场景列表、品牌颜色、字体和宽高比,并基于帧驱动动画(`useCurrentFrame`、`interpolate`、`spring`、`AbsoluteFill`、`Sequence`)生成完整的 React/TypeScript 组件。该技能支持 16:9 横屏、9:16 竖屏和 1:1 正方形等常见平台适配,并内置了产品展示的标准结构(品牌介绍 → 功能亮点 → 号召行动),确保动画流畅且可预览。生成的代码通过 typed props 实现数据驱动,用户只需修改 props 即可调整文案、颜色或布局,无需重新编写代码。最终输出会保存为 `src/compositions/<VideoName>.tsx` 并注册到 `src/Root.tsx`,用户可直接在 Remotion Studio 中预览和调整。

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

在你喜欢的 AI 中提问

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

文档

Remotion Compose 是做什么的?

你将一个自然语言需求转化为完整的、可预览的 Remotion 合成——真实的 React/TypeScript 帧驱动动画。输出是一个 .tsx 文件,位于 src/compositions/ 中,并注册到 src/Root.tsx,用户可以在 Studio 中立即拖动预览,或者交给 remotion-render 渲染。

当收到任何创建、生成、动画或“为……编写视频代码”的请求时触发,例如产品演示、引导、功能展示或营销动画——包括“制作一个展示 X 的 20 秒视频”。

第一步 - 提取需求

在开始编码前,必须先获取以下信息。尽可能一次性询问,对于明显缺失的部分使用合理的默认值,不要卡住:

  1. 时长(秒)和 fps(默认 30——产品和营销视频的标准,渲染成本是 60fps 的一半。仅在动画精细光标运动或滚动 UI 且 30fps 明显卡顿时才使用 60fps)。
  2. 场景——按顺序发生了什么。优先获取节拍列表:“logo,然后三个功能,然后一个 CTA”优于“我的应用程序的演示”。
  3. 品牌——主色/强调色/背景色十六进制颜色,以及字体(一个 @remotion/google-fonts 字体家族名称)。
  4. 宽高比/平台——16:9 横屏(1920×1080)、9:16 竖屏(1080×1920)用于社交媒体,或 1:1 正方形(1080×1080)。
  5. 文案——实际的标题/功能名称/CTA 文字。永远不要发明产品声明;询问真正的文字。

将所有内容转换为帧:durationInFrames = 秒 * fps。典型总长度:社交媒体/产品演示 15-60 秒,广告片段 6-15 秒。

第二步 - 构建场景计划

每个视频一个 <Composition>,每个场景一个组件,在时间轴上用 <Sequence> 拼接。在编写代码之前先规划好帧预算:

总计:20 秒 @ 30fps = 600 帧
  Intro (logo)        帧 0-90    (Sequence from=0   durationInFrames=90)
  功能 1             帧 90-240   (Sequence from=90  durationInFrames=150)
  功能 2             帧 240-390  (Sequence from=240 durationInFrames=150)
  功能 3             帧 390-540  (Sequence from=390 durationInFrames=150)
  CTA outro          帧 540-600  (Sequence from=540 durationInFrames=60)

预算时的节奏阈值:

  • 任何包含文本的节拍至少需要 2 秒(30fps 下 60 帧)——入场动画加上停留。一个标题每个词大约需要 150-200ms 的停留时间才能被阅读;一个 6 个词的标题在动画落地后大约需要 1 秒停留。
  • 入场动画:10-20 帧。淡入淡出和退出:12-15 帧。更长会显得迟缓,更短则像故障。
  • 除非是有意的闪切,否则没有场景短于约 45 帧。

<Sequence from={F}> 将子元素的本地时钟偏移,因此在组件内部 useCurrentFrame() 从 0 开始。将每个场景当作从帧 0 开始进行动画。

第三步 - 核心 API 参考

  • useCurrentFrame()——当前帧(时钟)。所有动画都是它的函数。
  • useVideoConfig()——{ fps, width, height, durationInFrames }。
  • interpolate(frame, [inFrames], [outValues], opts)——线性映射。在入场/退出时始终传递 { extrapolateLeft: "clamp", extrapolateRight: "clamp" },这样值不会超出其范围。
  • spring({ frame, fps, config })——基于物理的 0→1(轻微过冲)。用于任何需要显得有生命的东西(弹入、滑动、缩放进入)。
  • AbsoluteFill——一个全屏绝对定位的 div;每个场景的基础层。
  • Sequence——时间偏移和时间边界子元素(场景调度器)。
  • Series / Series.Sequence——无需手动计算 from 偏移量的背靠背场景序列。
  • Img, staticFile——见第六步。

第四步 - spring() 与 interpolate() 对比

使用 spring() 的场景……使用 interpolate() 的场景……
运动需要有物理感觉——弹跳、缩放进入、滑动进入需要在精确帧之间进行精确的线性控制
希望自然的稳定/过冲效果淡入淡出(不透明度 0→1)、颜色变化、进度条、任何按帧计时的东西
卡片、logo、徽章等元素的入场淡入淡出和退出,过冲会导致视觉错误

模式——用 spring 驱动变换,用 interpolate 驱动不透明度:

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

damping: 200 是主力配置——快速稳定,几乎看不到过冲。较低的阻尼(约 10-20)会明显反弹;只有在反弹是目的时才使用它。

第五步 - 标准产品演示结构

除非另有说明,否则使用此结构:logo/品牌介绍 → N 个功能展示 → CTA 结尾。使其数据驱动(第六步),这样变体就免费了。

// 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>
  );
};

在 src/Root.tsx 中注册,基于相同的数字计算 durationInFrames 并提供 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 →",
  }}
/>

对于竖屏/社交,设置 width={1080} height={1920};对于正方形,1080×1080。保持组件相同——只有画布变化。

第六步 - 数据驱动的属性与静态资源

上述合成是完全数据驱动的:每个词和颜色都是属性。这就是关键——变体(新文案、新调色板、本地化文本)无需重新提示;只需传入不同的属性(remotion-render 支持从 JSON 文件批量处理)。

静态资源(logo、截图、音频)位于 public/assets/ 中,通过 staticFile() 引用——绝不使用 import 或原始路径:

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

第七步 - 输出

将完成的文件保存到 src/compositions/<VideoName>.tsx,在 src/Root.tsx 中注册,并告诉用户使用 npx remotion studio(http://localhost:3000)预览。然后交接:*“在 Studio 中拖动预览。告诉我需要修改什么——太快了、颜色不对、文案不同——我会编辑并重新渲染(remotion-render)。”*

禁止事项

  • 禁止使用 CSS 过渡/动画或 setTimeout/setInterval 进行动画。Remotion 会独立并行渲染每一帧;任何不基于 useCurrentFrame() 的内容在最终渲染中都是不可见或不一致的,尽管在浏览器预览中可能看起来正常。
  • 禁止使用 Math.random() 进行散射/粒子效果——每个渲染工作线程会得到不同的值,帧不再匹配。使用 Remotion 的 random(seed) 实现确定性的伪随机性。
  • 禁止在没有 delayRender() / continueRender() 的情况下获取数据或等待异步工作——渲染器会在数据到达之前捕获帧。
  • 禁止在场景组件内硬编码 fps、width 或 height——从 useVideoConfig() 读取它们,这样切换 30↔60fps 或横屏↔竖屏不会破坏每个时间和布局。
  • 禁止在入场/退出插值中省略 extrapolateLeft/Right: "clamp"——不透明度会超过 1,元素在其范围结束后会漂移到画布之外。
  • 禁止发明标题、功能声明或 CTA——使用用户的真实文案,如果缺失则询问。

质量标准

  • 每个动画值都是 useCurrentFrame()(加上属性)的纯函数——在 Studio 中向后拖拽看起来与向前播放相同。
  • 计划中的帧预算总和正好等于 Root.tsx 中的 durationInFrames,并且没有文本节拍停留时间低于其可读性最小值。
  • 所有文案和颜色都通过类型化的属性传入,并附带 defaultProps——场景组件中没有硬编码的字面量。
  • 资源通过 staticFile() 加载;文件正确注册并在 Studio 中预览,没有控制台错误。

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

SkillMedev/tutorial-video-studio

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

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

相关技能