短影音自動上字幕:用 Whisper 幫你逐字跳動字幕
從音訊轉錄、解析 SRT、到做出 TikTok 風格逐字高亮字幕——完整的短影音字幕工作流,全程 Claude Code 指令驅動。
成品預覽
這支 15 秒的 demo 是用接下來的步驟做出來的: Gemini 2.5 Pro TTS(Charon 聲音)生成旁白 → Whisper 轉錄出 word-level 時間戳 → Remotion 排版 → 渲染 MP4。 整個流程沒有任何手動上字幕、沒有剪輯軟體。
🔊 記得打開聲音,字幕會跟著旁白逐字跳動。
這篇會做出什麼
一支 9:16 直式短影音,主角是一段旁白音訊,畫面上會出現逐字跳動、當前字高亮的字幕——就是你在 TikTok、IG Reels 看到的那種字幕。
整個流程全部用 Claude Code 指令完成,你不需要:
- 手動對時間軸
- 用 CapCut / Premiere 上字幕
- 寫任何一行
interpolate()
你只需要準備一段 .mp3 或 .wav 旁白檔案。
前置知識
建議先完成這兩篇:
- Remotion Skills 安裝指南 — 把 Skills 裝進 Claude Code
- 第一支影片:從開啟 Remotion 到 AI 生成動畫 — 熟悉「跟 AI 描述影片」的節奏
專案設定建議:9:16 短影音尺寸 1080×1920,30 fps。下面 Step 1 的 prompt 會幫你設好。
Step 1:建立短影音專屬的 Composition
打開你的 Remotion 專案,在 Claude Code 裡輸入:
在現有的 Remotion 專案裡新增一個 Composition:
- id: "ShortsCaptions"
- 尺寸 1080x1920(9:16 直式)
- fps: 30
- durationInFrames 先設 450(15 秒)
- 新建 src/compositions/ShortsCaptions.tsx 作為主元件
- 背景色 #0f172a
- 中央放一個暫時的 placeholder 文字「短影音字幕 Demo」
- 記得在 src/Root.tsx 註冊這個 Composition
Claude 會建立 ShortsCaptions.tsx、在 Root.tsx 加上 <Composition>。打開 Remotion Studio 確認左側列表能看到它,中央預覽是深藍背景加上標題。
💡 短影音尺寸相關的細節可以進一步閱讀 /docs/composition。
Step 2:準備旁白並用 Whisper 轉錄
把你準備好的旁白音訊放進專案的 public/ 資料夾:
public/
└── audio/
└── voiceover.mp3
接著在 Claude Code 裡輸入:
幫我用 @remotion/install-whisper-cpp 安裝 Whisper.cpp,然後寫一個 Node.js 腳本
scripts/transcribe.mjs,做這些事:
1. 讀取 public/audio/voiceover.mp3
2. 如果需要,先用 ffmpeg 轉成 16kHz wav
3. 用本地 Whisper 轉錄成 SRT 檔
4. 把 SRT 存到 public/captions/voiceover.srt
安裝完成後直接執行一次腳本,讓我看看 SRT 檔的內容。
Claude 會:
npm install @remotion/install-whisper-cpp並下載模型- 建立
scripts/transcribe.mjs,用 Whisper.cpp 產生 SRT - 執行腳本,把 SRT 存到
public/captions/voiceover.srt
你會看到類似這樣的 SRT 檔:
1
00:00:00,000 --> 00:00:02,400
大家好,我是 Claude
2
00:00:02,400 --> 00:00:05,100
今天要示範 Remotion 的字幕功能
...💡 Whisper 不是唯一選擇。OpenAI 雲端、ElevenLabs、其他本地模型的比較可以看 /docs/captions-transcribing。
Step 3:在影片裡播放旁白
有了音訊檔,先讓 Composition 把聲音放進去:
在 ShortsCaptions.tsx 中:
- 用 <Audio> 元件載入 staticFile("audio/voiceover.mp3")
- 把 placeholder 文字拿掉
- 改成上方 1/3 空白,中央到下方預留字幕區
Claude 會用 staticFile() 和 <Audio>。在 Studio 按下播放,你應該可以聽到旁白。
💡
staticFile()如何把public/的檔案轉成可載入的 URL,細節在 /docs/staticfile。音訊元件完整 API 則看 /docs/audio 和 /docs/audio-importing。
Step 4:解析 SRT 並做出基本字幕顯示
現在把 SRT 轉成 Remotion 看得懂的 Caption 陣列,並逐句顯示:
在 ShortsCaptions.tsx 裡加上字幕邏輯:
1. 使用 @remotion/captions 的 parseSrt() 解析
staticFile("captions/voiceover.srt") 的內容(用 fetch 讀取)
2. 把每一條 caption 包成一個 <Sequence>,用 startMs / endMs 對應
to frame 的換算(記得用 fps = 30)
3. 字幕放在畫面下方 1/4 的位置
4. 字體大小 72px,Noto Sans TC 粗體,白色
5. 加一層黑色半透明外框提高可讀性
6. 整個 captions 區塊用 <AbsoluteFill> 疊在 Audio 上層
不要做任何花俏的動畫,先讓基本字幕能對到時間軸就好。
這一步會用到四個核心 API:
parseSrt()— 把 SRT 變成Caption[](/docs/captions-importing)<Sequence from durationInFrames>— 控制每條字幕的顯示區間(/docs/sequence)<AbsoluteFill>— 全螢幕疊層容器(/docs/absolute-fill)staticFile()— 載入 SRT 檔
回到 Studio 按播放,你應該看到字幕準確地跟著旁白一句一句出現。
Step 5:升級成「當前字高亮」的 TikTok 風格
整句顯示太陽春了。現在加上逐字跳動效果:
把 ShortsCaptions.tsx 改成「當前字高亮」的 TikTok 風格:
1. 把 parseSrt() 的每一條 caption 再切成 word-level 的片段
(如果 Whisper SRT 沒有 word timestamps,就用句子長度平均分配)
2. 每個 word 一個 <Sequence>,只在它的時間區間顯示
3. 當前字用亮黃色 #facc15、比其他字大 15%、並加一個 spring() 彈跳
scale 從 0.8 → 1.0,damping 12
4. 前後三個字顯示為白色 + 60% opacity,用來給觀眾上下文
5. 文字置中對齊,最多顯示 7 個字
6. 超過 7 個字就以當前字為中心做 window scroll
動畫用 spring(),不要用 CSS transition。
這一步做完你就有 TikTok/IG Reels 風格的逐字字幕了。核心概念:
- 用
spring()做彈跳縮放(/docs/spring) - 每個字都是獨立的
<Sequence>,可以精準控制顯示/隱藏 useCurrentFrame()+ 時間區間換算決定「哪個字是當前字」
💡 TikTok 風格分頁字幕、逐字高亮的完整範例與變體在 /docs/captions-displaying 和 /docs/animated-captions 都有。
Step 6:加背景影片(可選)
純色背景配字幕已經可用,但短影音通常會放一段 B-roll 背景:
在字幕下面加一層背景影片:
1. 在 public/video/ 放一個 background.mp4
2. 用 <OffthreadVideo> 而不是 <Video> 載入
(渲染時比較穩定)
3. 影片要覆蓋整個 1080x1920,用 objectFit: "cover"
4. 影片要靜音(muted)因為我們只要旁白聲音
5. 上面疊一層半透明黑色 rgba(0,0,0,0.4) 讓字幕更清楚
為什麼用 <OffthreadVideo> 而不是 <Video>?
渲染時 Remotion 會用 FFmpeg 精準提取每一幀,不會遇到瀏覽器影片元件的時間碼飄移問題,短影音這種要求幀準確的場景尤其重要。詳細說明在 /docs/offthreadvideo。
Step 7:匯出 SRT 燒進影片 + 輸出 MP4
想讓上傳到 YouTube Shorts 時附 SRT 檔(平台會讓觀眾開關字幕):
1. 渲染整支影片成 MP4:
npx remotion render src/index.ts ShortsCaptions out/shorts.mp4
2. 同時把 captions 匯出成獨立的 SRT 檔到 out/shorts.srt
用 @remotion/captions 的 serializeSrt() 即可
3. 在 render 時用 --codec h264,crf 設 20
💡 匯出 SRT/VTT 的完整流程在 /docs/captions-exporting。
完成!回顧學到的概念
一支 15 秒的短影音做完,你實際上已經摸過了 Remotion 字幕生態系的幾乎所有核心 API:
| 概念 | 用在哪 |
|---|---|
<Composition> 9:16 尺寸 | Step 1 |
| Whisper 轉錄 + SRT | Step 2 |
<Audio> + staticFile() | Step 3 |
parseSrt() 解析字幕 | Step 4 |
<Sequence> 控制字幕顯示區間 | Step 4、5 |
<AbsoluteFill> 疊層 | Step 4 |
spring() + useCurrentFrame() | Step 5 |
| 逐字 word-level 時間軸 | Step 5 |
<OffthreadVideo> 渲染安全的背景影片 | Step 6 |
serializeSrt() 匯出獨立字幕檔 | Step 7 |
本篇涵蓋的官方文件
核心字幕 API:
- /docs/captions —
@remotion/captions套件總覽 - /docs/captions-transcribing — 音訊轉錄為字幕(Whisper、OpenAI、ElevenLabs 比較)
- /docs/captions-importing — 匯入 SRT 字幕檔
- /docs/captions-displaying — 在影片中顯示字幕(含 TikTok 風格)
- /docs/captions-exporting — 匯出 SRT/VTT 獨立字幕檔
- /docs/animated-captions — 進階動畫字幕範例
相關媒體 API:
- /docs/audio —
<Audio>元件 - /docs/audio-importing — 匯入音訊資源
- /docs/offthreadvideo —
<OffthreadVideo>渲染安全的影片元件 - /docs/staticfile —
staticFile()載入public/資產
動畫基礎:
- /docs/sequence — 用
<Sequence>控制時序 - /docs/absolute-fill —
<AbsoluteFill>疊層容器 - /docs/spring —
spring()物理動畫 - /docs/composition —
<Composition>定義影片尺寸與時長
常見問題
Q:Whisper 轉出來的時間戳不準怎麼辦?
A:用 large-v3 模型會比 base 精準很多,代價是下載時間與運算時間。或者改用雲端 API,品質更穩定——可以看 /docs/captions-transcribing 的方案比較。
Q:字幕跟音訊對不上?
A:確認 <Audio> 沒有被 <Sequence> 包在奇怪的 from 裡面造成偏移。也要確認你的 fps 跟 SRT 時間戳的換算正確:frame = Math.round(seconds * fps)。
Q:為什麼要 <OffthreadVideo> 而不是 <Video>?
A:<Video> 在瀏覽器端(Studio 預覽)比較流暢,但渲染時會靠 HTMLVideoElement,時間碼容易飄。<OffthreadVideo> 直接用 FFmpeg 抓幀,渲染精度高。完整差異看 /docs/offthreadvideo。
Q:字幕在 Studio 看得到,渲染出來卻沒有?
A:檢查字型是否用了 @remotion/fonts 正確載入,特別是 Noto Sans TC 這類非預設字型。也確認 SRT 檔放在 public/ 而不是 src/(src/ 裡的東西不會被當成靜態資產)。
下一步
接下來可以挑戰:
- T09:影片剪輯——裁切、拼接、配樂 — 更深入處理影片/音訊
- T04:Instagram Reels 產品展示卡 — 同樣是 9:16 但主打產品展示
有問題歡迎到 FB 社群 討論!