Communitygithub.com

Remotion 影片組合

將自然語言影片需求轉換為完整、可預覽的 Remotion 組合 - 提取片長、場景、品牌顏色、長寬比和實際文案;規劃幀數預算;並使用 useCurrentFrame、interpolate、spring、AbsoluteFill 和 Sequence 編寫資料驅動的 React/TypeScript 程式碼,並在 Root.tsx 中註冊。

Remotion 影片組合 是什麼?

此技能可將自然語言簡報轉換為完整、可立即預覽的 Remotion 影片組合。它自動提取影片的基本參數,如片長、幀率、場景順序、品牌色彩和文案,並生成基於幀數驅動動畫的 React/TypeScript 原始碼。技能會建立詳細的場景規劃,包括每個場景的幀數預算,並使用 Remotion 核心 API,如 `useCurrentFrame()`、`interpolate()`、`spring()`、`AbsoluteFill` 和 `Sequence`,以確保動畫精準且一致。組合檔案會保存至 `src/compositions/` 並在 `src/Root.tsx` 中註冊,使用者可立即在 Remotion Studio 中預覽或使用 `remotion-render` 渲染。此技能支援 16:9、9:16 和 1:1 等多種長寬比,並強調資料驅動的 props,以便輕鬆進行變體和批次渲染。

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

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

Remotion 影片組合 是做什麼的?

你將一個自然語言簡報轉換成 完整、可立即預覽的 Remotion 影片組合 —— 使用真實的 React/TypeScript 搭配幀驅動動畫。輸出為一個位於 src/compositions/ 的 .tsx 檔案,並在 src/Root.tsx 中註冊,讓使用者能立即在 Studio 中拖曳預覽,或交給 remotion-render 進行渲染。

當使用者要求建立、生成、動畫化,或「為某個產品展示、導覽、功能介紹或行銷動畫撰寫影片程式碼」時觸發此技能——包括「建立一個顯示 X 的 20 秒影片」。

步驟 1 - 提取簡報

在開始撰寫程式碼之前,你必須取得以下資訊。以一次性的方式詢問;對於明顯的空白,使用合理的預設值而非停滯不前:

  1. 片長(以秒為單位),以及 fps(預設 30 - 這是產品與行銷影片的標準,且渲染成本僅為 60fps 的一半。只有在動畫精細的游標移動或捲動 UI 且 30fps 明顯卡頓時,才使用 60fps)。
  2. 場景 - 發生什麼事,依序進行。引導使用者給出節拍列表:「標誌,然後三個功能,最後一個行動呼籲」比「我的應用程式的展示」更好。
  3. 品牌 - 主要/強調/背景十六進位顏色,以及字型(一個 @remotion/google-fonts 系列名稱)。
  4. 長寬比 / 平台 - 16:9 橫向(1920×1080)、9:16 直向(1080×1920)用於社交媒體,或 1:1 方形(1080×1080)。
  5. 文案 - 實際的標題/功能名稱/行動呼籲文字。切勿虛構產品宣稱;要求使用者提供真實的文字。

將秒數轉換為幀數:durationInFrames = seconds * fps。典型的總長度:社交/產品展示為 15-60 秒,廣告為 6-15 秒。

步驟 2 - 建立場景規劃

每部影片一個 <Composition>,每個場景一個元件,透過 <Sequence> 在時間軸上拼接。在撰寫程式碼之前規劃好幀數預算:

總計:20s @ 30fps = 600 幀
  片頭(標誌)       幀數   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)
  行動呼籲結尾      幀數 540-600   (Sequence from=540 durationInFrames=60)

規劃時的節奏門檻:

  • 任何包含文字的節拍至少需要 2 秒(30fps 下為 60 幀)—— 進場動畫加上停留。一個標題的每個單字大約需要 150-200 毫秒的停留時間才能閱讀;一個 6 字的標題在動畫完成後需要約 1 秒的停留。
  • 進場動畫:10-20 幀。交叉淡入淡出和出場:12-15 幀。更長會顯得遲緩,更短則像故障。
  • 除非是刻意的閃現剪輯,否則場景不應短於約 45 幀。

<Sequence from={F}> 會將子元件的本地時鐘偏移,因此在該元件內 useCurrentFrame() 從 0 開始。每個場景都當作從第 0 幀開始來進行動畫。

步驟 3 - 核心 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 - 請參閱步驟 6。

步驟 4 - spring() 與 interpolate() 的比較

使用 spring() 的時機…使用 interpolate() 的時機…
需要物理感的運動 - 彈出、反彈、縮放進入、滑入需要在精確幀之間進行精確、線性控制
想要自然的穩定/超調效果淡入淡出(透明度 0→1)、顏色轉變、進度條、任何需要精確計時的動畫
卡片、標誌、徽章的進場效果交叉淡入淡出和出場效果,超調會看起來很奇怪的地方

模式 - 用 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)會明顯反彈;只有在反彈是重點時才使用。

步驟 5 - 標準產品展示結構

除非簡報另有說明,否則採用以下結構:標誌/品牌介紹 → N 個功能展示 → 行動呼籲結尾。使其資料驅動(步驟 6),以便各種變體可以自由調整。

// 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。保持元件相同 - 只有畫布尺寸會改變。

步驟 6 - 資料驅動的 Props 與靜態資源

上述組合是完全資料驅動的:每個文字和顏色都是一個 prop。這就是重點 - 變體(新文案、新調色板、在地化文字)無需重新提示;只需傳遞不同的 props(remotion-render 可以從一個 JSON 檔案批次執行此操作)。

靜態資源(標誌、螢幕截圖、音訊)放置在 public/assets/ 中,並使用 staticFile() 引用 - 永遠不要使用 import 或原始路徑:

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

步驟 7 - 輸出

將完成的檔案儲存到 src/compositions/<VideoName>.tsx,在 src/Root.tsx 中註冊,並告訴使用者使用 npx remotion studio(http://localhost:3000)進行預覽。然後交接:*「在 Studio 中拖曳預覽。告訴我需要修改什麼 - 太快、顏色錯誤、文案不同 - 我會編輯並重新渲染(remotion-render)。」*

請勿

  • 請勿使用 CSS 過渡/動畫或 setTimeout/setInterval 來製作動畫。Remotion 會獨立且並行地渲染每個影格;任何不是從 useCurrentFrame() 派生的內容在最終渲染中都是不可見或不一致的,即使在瀏覽器預覽中看起來可能正常。
  • 請勿使用 Math.random() 來進行散佈/粒子效果 - 每個渲染 worker 會得到不同的值,導致影格不匹配。請使用 Remotion 的 random(seed) 來獲得確定性的偽隨機性。
  • 如果沒有使用 delayRender() / continueRender(),請勿擷取資料或等待非同步工作 - 渲染器會在資料到達之前捕捉影格。
  • 請勿在場景元件內硬編碼 fps、width 或 height - 應從 useVideoConfig() 讀取它們,這樣在切換 30↔60fps 或橫向↔直向時就不會破壞所有的時間和佈局。
  • 請勿在進場/出場的 interpolate 中省略 extrapolateLeft/Right: "clamp" - 透明度的值會超過 1,元素會在其範圍結束後偏移到畫布之外。
  • 請勿虛構標題、功能宣稱或行動呼籲 - 使用使用者的真實文案,若缺少則詢問。

品質標準

  • 每個動畫值都是 useCurrentFrame()(加上 props)的純函數 - 在 Studio 中向後拖曳預覽看起來與向前播放相同。
  • 規劃中的幀數預算總和必須與 Root.tsx 中的 durationInFrames 完全一致,且任何文字節拍的停留時間都不低於其可讀的最小值。
  • 所有文案和顏色都透過型別化的 props 傳遞,並提供 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

相關技能