Communitygithub.com

字幕動畫

將逐字稿或旁白轉換為逐字計時、引人注目的字幕;每個字詞會隨著音節彈出,現正播放的字詞會高亮,文字會緊貼旁白。

字幕動畫 是什麼?

這個「字幕動畫」技能用於建立逐字(或卡拉OK風格)字幕,非常適合 TikTok、Reels 和 Shorts 等短影音平台。其核心原理是先透過 Whisper 或 AssemblyAI 等服務,將音訊精確轉錄為包含每個字詞開始與結束時間戳記(以毫秒為單位)的資料。接著,系統會將這些字詞分組,形成 1 到 4 個字詞為一組的「頁面」,避免顯示一大段文字。最後,利用 Remotion 框架(或純 CSS)驅動每個字詞的縮放與透明度動畫,並以特定顏色高亮顯示「現正播放」的字詞,營造出生動的卡拉OK效果。此技能支援在 Remotion 組成中直接嵌入字幕(Burn-in),並同時匯出標準的 SRT 或 VTT 字幕檔,以滿足社交平台與無障礙存取(如 ADA/WCAG 法規)的需求。它還強調了兩個關鍵規則:必須使用真實的逐字時間戳記,而非平均分割時間;以及在任何情況下,可讀性都優先於花俏的裝飾。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/iart-ai/tiktok-video-skills/tree/main/skills/caption-animation

在你喜歡的 AI 中提問

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

說明文件

字幕動畫 是做什麼的?

將逐字稿或旁白轉換為逐字計時、引人注目的字幕:每個字詞會隨著音節彈出,現正播放的字詞會高亮,文字會緊貼旁白。建立那種能帶動 TikTok、Reels 和 Shorts 觀看時長的字幕——易於閱讀、與節奏同步,並且完全位於安全區域內。

使用時機

  • 在短格式垂直影片(9:16)上建立逐字或卡拉OK風格的字幕。
  • 將旁白/敘述音軌根據逐字稿燒錄成開放式字幕(open captions)。
  • 將 Whisper/SRT 逐字稿轉換為 Remotion 或網頁上的動畫文字。
  • 將自動產生的字幕重新調整為具品牌風格的「Hormozi 風格」揭示效果。

處理管線

階段工作工具
轉錄音訊 → 逐字時間戳記Whisper (@remotion/install-whisper-cpp), AssemblyAI
正規化→ { text, startMs, endMs }[] 令牌@remotion/captions Caption 類型
分頁將字詞分組為 1–4 個字詞的「頁面」createTikTokStyleCaptions()
動畫逐字彈出 + 現正播放字詞高亮Remotion spring() / CSS
放置安全區域、易於閱讀的排版下方佈局規則
匯出燒錄嵌入(MP4)與/或側載 SRT/VTTRemotion 渲染 / 檔案輸出

兩個不容妥協的規則

  1. 逐字時間,而非逐行時間。 只有當每個字詞都精準地落在音節上時,卡拉OK 效果才顯得出神入化。務必轉錄出逐字時間戳記;絕對不要透過將一個行均分給其持續時間來偽造——時間偏移會立刻被察覺。
  2. 可讀性勝於風格。 字幕是在手機上、陽光下、靜音狀態下閱讀的。粗體無襯線字型、厚重的描邊或陰影、高對比度是首要考量;裝飾則是次要。一個沒人能讀懂的字幕,那只是裝飾,不是字幕。

從逐字稿獲得逐字時間

Whisper 可以直接輸出逐字時間戳記。將所有來源正規化為一個統一的扁平令牌形狀,這樣渲染器永遠不需要關心這些字詞來自何處:

// 字幕令牌 — 下游所有環節都使用的統一形狀
type Token = { text: string; startMs: number; endMs: number };

// 解析 SRT 提示區塊 "00:00:01,200 --> 00:00:01,640" 為毫秒
const toMs = (t: string) => {
  const [h, m, rest] = t.split(":");
  const [s, ms] = rest.split(",");
  return ((+h * 60 + +m) * 60 + +s) * 1000 + +ms;
};

如果只有句子級別的提示存在,請重新轉錄以獲得逐字時間——不要進行內插。Whisper 的 medium.en 模型速度約為 large 模型的兩倍,且對於乾淨的語音音訊來說準確度足夠。

逐字彈入效果(Remotion)

每個字詞的縮放與透明度均由一個錨定在其自身 startMs 上的彈簧(spring)動畫驅動。微小的過衝正是讓它感覺「活靈活現」的關鍵。

import { useCurrentFrame, useVideoConfig, spring, interpolate } from "remotion";

const Word: React.FC<{ token: Token; active: boolean }> = ({ token, active }) => {
  const frame = useCurrentFrame();
  const { fps } = useVideoConfig();
  const enter = (token.startMs / 1000) * fps;            // 字詞自身的入場影格
  const p = spring({ frame: frame - enter, fps, config: { damping: 12, mass: 0.6 } });
  const scale = interpolate(p, [0, 1], [0.6, 1]);        // 從 60% 彈入至 100%(會產生過衝)
  return (
    <span style={{
      display: "inline-block",
      transform: `scale(${scale})`,
      opacity: interpolate(p, [0, 1], [0, 1]),
      color: active ? "#FFE45E" : "#FFFFFF",             // 現正播放字詞高亮
      transition: "color 80ms linear",
    }}>{token.text}&nbsp;</span>
  );
};

透過測試 frame 是否落在每個令牌的 [startMs, endMs] 區間內來計算 active 狀態。將高亮效果保持為單一的強調色,或是在當前字詞後面加上一個填滿的「方塊」——切勿同時讓每個字詞的顏色都發生變化。

頁面(Pages),而非文字牆

一次顯示 1 到 4 個字詞。使用 Remotion 的 createTikTokStyleCaptions()(或手動分組),並調整 combineTokensWithinMilliseconds 參數:設定約 200–500ms 可實現真正的逐字顯示,設定約 1000–1500ms 則可顯示簡短的易讀詞組。

import { createTikTokStyleCaptions } from "@remotion/captions";
const { pages } = createTikTokStyleCaptions({
  captions, combineTokensWithinMilliseconds: 1200,       // 每個頁面約 2–3 個字
});

網頁/CSS 彈入效果(無須 Remotion)

對於 DOM/即時播放器,給予每個字詞一個等於其 startMs 的 animation-delay 屬性:

.word { display:inline-block; opacity:0; animation: pop .26s cubic-bezier(.34,1.56,.64,1) forwards; }
@keyframes pop { from { opacity:0; transform:translateY(.18em) scale(.7) } to { opacity:1; transform:none } }
.word.active { color:#FFE45E; }
words.forEach(w => { const el = mk(w.text); el.style.animationDelay = `${w.startMs}ms`; track.append(el); });

可讀性排版與安全區域放置(9:16,1080×1920)

屬性數值原因
字型粗體/特粗體無襯線字型(Montserrat, Inter, Helvetica)在小型、繁忙的螢幕上易於閱讀
大小56–80px(約畫面高度的 8%),最小 45px在手機上靜音觀看時仍然清晰可辨
描邊2–6px 實心黑色外框在任何背景上都清晰可見
陰影柔和的投影作為描邊的備援方案在明亮畫面上增加區隔度
大小寫全大寫或句子形式;高對比度填色具衝擊力且易於掃讀
垂直位置中間區域,約在畫面 62–70% 處位於 UI 之上,動作之下
底部安全保持與底部約 280px / 15% 的距離避開字幕/CTA/音訊 UI
側邊安全保持在中間 80% 寬度內避開右側導航欄圖示

將字幕放置在中間區域——不要固定在最底部,那裡是平台 UI(使用者名稱、音訊、按鈕)所在的位置。文字最多限制在約 2 行。

與旁白/敘述同步

逐字稿已經包含了確切音訊的時間資訊。將相同的音訊放在合成影片下方,並保持時間戳記處於音訊的時間基準中——字幕和語音將完美鎖定,無需手動調整偏移量。如果重新錄製 VO,請重新進行轉錄;切勿手動移動偏移量。

燒錄嵌入 vs. 側載 SRT/VTT

燒錄嵌入(開放式)側載 SRT/VTT(封閉式)
位置MP4 檔案內的像素獨立的 .srt/.vtt 檔案
社群媒體(TikTok/Reels)必要——保證顯示,可設計樣式通常被平台忽略
無障礙性(ADA/WCAG)無法單獨滿足要求必要(可開關)
最佳實踐為社群媒體燒錄動畫字幕同時為網頁和 SEO 提供側載字幕

兩者都輸出:為社群媒體燒錄動畫字幕,並從相同的令牌資料庫中輸出一個純文字 SRT/VTT 檔案,以供無障礙播放和 SEO 使用。

輸出檢查清單

  • 逐字時間戳記(真實的,來自信箱)——無均分時間的造假行為。
  • 逐字彈入效果,帶有微過衝;使用一個強調色標記現正播放的字詞。
  • 每頁 1–4 個字詞;絕不顯示一大段文字。
  • 粗體無襯線字型,56–80px,2–6px 描邊加陰影,高對比度。
  • 中間區域,距離底部約 280px 和側邊欄。
  • 音訊已置於合成影片下方;時間戳記與音訊時間基準一致。
  • 為社群媒體輸出燒錄嵌入的字幕,並為無障礙性輸出側載 SRT/VTT。

交付與驗證(渲染靜止畫面 → MP4)

打包好的輔助工具(在 scripts/ 目錄下):使用 scripts/contact-sheet.sh sheet.png f-hook.png f-mid.png f-end.png 將你的靜止畫面拼貼成一張圖,然後使用 scripts/probe-mp4.sh out.mp4 [WxH] [fps] 驗證編碼。詳見 scripts/README.md。

字幕以 Remotion 組成(<Composition> + zod schema + defaultProps)的形式交付——所有文字動畫均由 useCurrentFrame() 驅動影格,絕不使用 Date.now() / Math.random() / 計時器。交付物 = out/*.mp4(燒錄嵌入) + 專案 + 側載 SRT/VTT。9:16 垂直(1080×1920)為預設值。

驗證循環——渲染靜止畫面 → 檢查 → 編碼。 字詞時間是最容易出問題的地方;在花費時間進行完整編碼之前,先在精確的影格上檢查它。

# 在起始影格 / 一個取樣的現正播放字詞影格 / 結束影格 渲染靜止畫面 — 使用已交付的 props(真實令牌 + 音訊)
npx remotion still Captions out/f-start.png --frame=0   --props='{"captionsSrc":"vo.json"}'
npx remotion still Captions out/f-mid.png   --frame=90  --props='{"captionsSrc":"vo.json"}'
npx remotion still Captions out/f-end.png   --frame=N   --props='{"captionsSrc":"vo.json"}'  # N = durationInFrames-1

# 檢查每個 PNG:
#  - 在第 90 影格高亮的字詞,其 [startMs,endMs] 區間應包含 90/fps(無時間偏移)
#  - 燒錄嵌入的字幕清晰可讀:粗體無襯線字型,描邊+陰影效果正常,無裁切
#  - 9:16 安全區域:字幕位於中間區域,距離頂部約 12% 和底部約 20-35%(字幕/CTA/音訊 UI)以及右側操作欄都有足夠空間

npx remotion render Captions out/captions.mp4 --props='{"captionsSrc":"vo.json"}'   # 靜止畫面確認無誤後再進行編碼
npx remotion render Captions out/demo.gif --codec=gif                                # README 示範片段

使用 npx remotion compositions 讀取 durationInFrames/fps,並選取現正播放字詞的影格與結束影格。

完成之前:

  1. 靜止畫面在第 0 影格、一個中間的現正播放字詞影格、以及最後一個影格都能乾淨渲染——沒有缺少字型或音訊。
  2. 在取樣的影格中,正確的字詞被高亮(影格/fps 落在其令牌的時間區間內);沒有均分時間的造假行為。
  3. 燒錄嵌入的字幕清晰可讀(描邊+陰影),且在每個檢查的影格中,字幕都完全位於 9:16 的安全區域內。
  4. 僅由影格驅動——沒有 Date.now() / Math.random() / 計時器。
  5. 已交付的 props(真實令牌,不僅是 defaultProps)能正確渲染;已輸出 MP4 + 側載 SRT/VTT,GIF 為選項。

參考檔案

  • references/word-timed-captions.md — 端到端建構指南:包含 Whisper 轉錄和 Caption 類型、完整的 SRT 解析器、附帶現正播放字詞高亮的 Remotion 逐字計時元件、手動分頁功能、SRT/VTT 輸出器、各平台的安全區域對照表,以及一份可讀性排版的規格說明頁。

Individual skills in this repo

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

相關技能