Communitygithub.com

carissadarmafissaleha/remotion

React 程式化影片製作完整大師指南,涵蓋設計、動畫、配音同步與硬體加速渲染。

remotion 是什麼?

此技能提供一份全面的指南,教您如何使用 React 和 Remotion 4.x 以程式化方式建立專業級動態圖形影片(例如 16:9 解說影片、9:16 直式 Shorts/TikTok/Reels)。它詳細說明了核心架構,包括使用「Composition」設定根目錄、利用「Sequence」和「Series」管理時間軸、以及使用基於物理的「spring()」函數和「interpolate()」進行流暢動畫。該技能還涵蓋了鍵擊式文字動畫、旁白音訊同步以及使用「delayRender」預載非同步資源。此外,它還提供了硬體加速 CLI 渲染命令(包含「--gl=angle」和「--concurrency」等標誌)和一個 8 階段的電影式腳本模板,幫助用戶告別簡報風格的靜態影片。

相容平台~Claude Code~Codex CLI~Cursor✓Antigravity
npx skills add https://github.com/carissadarmafissaleha/office-nara/tree/main/skills/remotion

在你喜歡的 AI 中提問

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

說明文件

Remotion 大師指南 — React 程式化影片製作

Remotion 讓你能用純 React 程式碼創作出電影般的影片。每個影片畫面都被視為一個確定性的狀態 (frame) => UI,從而產生完美無瑕的 60 FPS 視覺效果,不會有任何卡頓或掉幀。


1. 組合架構與根目錄配置

A. 根入口點 (Root.tsx)

import { Composition } from 'remotion';
import { MainExplainer } from './compositions/MainExplainer';
import { VerticalShort } from './compositions/VerticalShort';

export const RemotionRoot: React.FC = () => {
  return (
    <>
      {/* 16:9 橫向電影解說 */}
      <Composition
        id="MainExplainer-1080p"
        component={MainExplainer}
        durationInFrames={30 * 32} // 32 秒 @ 30 FPS = 960 幀
        fps={30}
        width={1920}
        height={1080}
        defaultProps={{
          title: 'Misteri Mencairnya Puncak Es Dunia',
          author: 'NARA Studio',
          themeColor: '#f97316',
        }}
      />

      {/* 9:16 直式 TikTok / Reels / Shorts */}
      <Composition
        id="VerticalShort-60fps"
        component={VerticalShort}
        durationInFrames={60 * 15} // 15 秒 @ 60 FPS = 900 幀
        fps={60}
        width={1080}
        height={1920}
      />
    </>
  );
};

B. 持續時間與 FPS 規則

  • 16:9 YouTube / 解說影片:建議使用 30 fps(在渲染速度與運動平滑度之間取得平衡),或為超清晰的鍵擊式文字使用 60 fps。
  • 幀數計算:一律使用 durationInFrames = Math.round(seconds * fps) 計算。
  • 零抖動:請勿使用 setInterval 或 setTimeout。務必使用 useCurrentFrame() 和 useVideoConfig()。

2. 佈局與時間軸基礎元件

AbsoluteFill

所有場景圖層的基礎。自動設定為 position: absolute; inset: 0; width: 100%; height: 100%;:

import { AbsoluteFill } from 'remotion';

export const SceneBackground: React.FC = () => {
  return (
    <AbsoluteFill style={{ backgroundColor: '#090812', overflow: 'hidden' }}>
      {/* 視覺內容 */}
    </AbsoluteFill>
  );
};

Sequence vs Series

  • Sequence:將元素放置在絕對時間點(使用 from 和 durationInFrames)。適合背景音樂、浮水印、HUD 疊加層或相互重疊的元素。
  • Series:自動依序排列場景,無需手動計算幀偏移量。
import { Series, Sequence, Audio, staticFile } from 'remotion';

export const VideoStory: React.FC = () => {
  return (
    <AbsoluteFill>
      {/* 整個影片的背景音樂 */}
      <Audio src={staticFile('audio/ambient_score.mp3')} volume={0.35} />

      {/* 自動場景順序 */}
      <Series>
        <Series.Sequence durationInFrames={120}>
          <HookScene />
        </Series.Sequence>
        <Series.Sequence durationInFrames={180}>
          <ProblemScene />
        </Series.Sequence>
        <Series.Sequence durationInFrames={240}>
          <SolutionScene />
        </Series.Sequence>
        <Series.Sequence durationInFrames={150}>
          <CallToActionScene />
        </Series.Sequence>
      </Series>
    </AbsoluteFill>
  );
};

3. 動畫物理:spring() 與 interpolate()

A. 自然彈簧公式 (spring())

使用 spring() 來產生真實的物理運動(消除「PowerPoint」式的僵硬感):

import { spring, useCurrentFrame, useVideoConfig } from 'remotion';

const frame = useCurrentFrame();
const { fps } = useVideoConfig();

// 1. 活潑彈出(文字/徽章突然出現)
const popScale = spring({
  frame,
  fps,
  config: { damping: 10, mass: 0.4, stiffness: 180 },
});

// 2. 平滑漂移(鏡頭平滑滑動)
const smoothSlide = spring({
  frame,
  fps,
  config: { damping: 20, mass: 1.2, stiffness: 60 },
});

// 3. 彈力掉落(圖示/粒子掉落並反彈)
const bounce = spring({
  frame: frame - 10, // 延遲 10 幀
  fps,
  config: { damping: 8, mass: 0.6, stiffness: 140 },
});

B. 數值平滑映射 (interpolate())

import { interpolate, Easing } from 'remotion';

// 使用貝茲曲線進行透明度與旋轉過渡
const opacity = interpolate(frame, [0, 20], [0, 1], {
  extrapolateRight: 'clamp',
});

const rotateY = interpolate(frame, [0, 60], [-45, 0], {
  easing: Easing.bezier(0.16, 1, 0.3, 1),
  extrapolateRight: 'clamp',
});

4. 鍵擊式文字與配音同步

A. 逐詞顯示文字

import React from 'react';
import { useCurrentFrame, useVideoConfig, spring, interpolate } from 'remotion';

interface KineticTextProps {
  sentence: string;
  startFrame?: number;
  wordDelay?: number;
}

export const KineticText: React.FC<KineticTextProps> = ({
  sentence,
  startFrame = 0,
  wordDelay = 4, // 每個單詞間隔 4 幀
}) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const words = sentence.split(' ');

  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: '12px', justifyContent: 'center' }}>
      {words.map((word, idx) => {
        const wordStart = startFrame + idx * wordDelay;
        const progress = spring({
          frame: frame - wordStart,
          fps,
          config: { damping: 12, mass: 0.4, stiffness: 160 },
        });

        const translateY = interpolate(progress, [0, 1], [40, 0]);
        const opacity = interpolate(progress, [0, 1], [0, 1]);

        return (
          <span
            key={idx}
            style={{
              display: 'inline-block',
              transform: `translateY(${translateY}px)`,
              opacity,
              fontSize: '48px',
              fontWeight: 800,
              color: idx === 0 ? '#f97316' : '#ffffff',
              letterSpacing: '-1px',
              fontFamily: "'JetBrains Mono', sans-serif",
            }}
          >
            {word}
          </span>
        );
      })}
    </div>
  );
};

B. 旁白與音效同步

  • 將音訊檔案放置在 public/audio/ 資料夾中。
  • 使用 staticFile('audio/file.mp3') 引用。
  • 使用 volume 屬性來建立音訊的淡入/淡出效果:
<Audio
  src={staticFile('audio/naskah_vo.mp3')}
  volume={(f) =>
    interpolate(f, [0, 15, 880, 900], [0, 1, 1, 0], {
      extrapolateLeft: 'clamp',
      extrapolateRight: 'clamp',
    })
  }
/>

5. 非同步資源與預載入 (delayRender)

當影片載入自訂字型、外部圖片或 API 資料時,必須告知 Remotion 以防止渲染出空白幀:

import { delayRender, continueRender } from 'remotion';
import { useEffect, useState } from 'react';

export const DynamicScene: React.FC = () => {
  const [handle] = useState(() => delayRender('載入字型與資源'));

  useEffect(() => {
    document.fonts.ready.then(() => {
      continueRender(handle);
    });
  }, [handle]);

  return <AbsoluteFill>...</AbsoluteFill>;
};

6. NARA 動態圖形模板與配方

8 階段電影式公式(告別簡報風)

  1. 場景 1:開場鉤子 (00-03s) $ ightarrow$ 神秘視覺 + 大型鍵擊式文字。
  2. 場景 2:問題陳述 (04-07s) $ ightarrow$ 冰層崩塌視覺 / 熾熱的紅色圖表。
  3. 場景 3:深入數據 (08-12s) $ ightarrow$ 統計數字動態計數上升 (Math.floor)。
  4. 場景 4:動態縮放轉換 (13-16s) $ ightarrow$ 從宏觀到微觀的尺度變化。
  5. 場景 5:人類影響 (17-20s) $ ightarrow$ 卡通角色在畫布上反應。
  6. 場景 6:解決方案揭示 (21-25s) $ ightarrow$ 視覺轉向明亮的綠色/橙色。
  7. 場景 7:行動步驟 (26-29s) $ ightarrow$ 3 張 3D 浮動卡片。
  8. 場景 8:高潮與行動呼籲 (30-32s) $ ightarrow$ 工作室標誌脈衝 + 音效 whoosh 重擊。

7. CLI 渲染執行與硬體加速

A. 渲染單一影片 (1080p 60fps)

npx remotion render src/remotion/index.ts MainExplainer-1080p out/output.mp4 --gl=angle

B. 高並發快速渲染

npx remotion render src/remotion/index.ts MainExplainer-1080p out/output.mp4 --concurrency=8 --gl=angle --jpeg-quality=90

C. 重要渲染標誌

  • --gl=angle:在 Windows 上使用 DirectX GPU 加速(遠比軟體光柵化快)。
  • --gl=swiftshader:如果在容器/CI 環境中沒有 GPU,則作為軟體備用方案。
  • --concurrency=N:用於平行渲染的 CPU 核心數量。
  • --muted:如果只需要視覺,則不渲染音訊串流。
  • --props='{"title":"新標題"}':透過命令列 JSON 傳遞動態參數。

8. 疑難排解指南

  1. 黑畫面 / 圖片未顯示:確保資源位於 public/ 資料夾中,並使用 staticFile('檔案名稱') 呼叫。
  2. 渲染時影片卡住:檢查 useMemo 中是否有無限迴圈,或 React 元件未正確關閉 delayRender。
  3. 音訊不同步:確保組合的 fps 值與旁白秒數的計算完全一致 (seconds = frames / fps)。

相關技能