Communitygithub.com

字幕动画

将转录稿或旁白转换为逐字精准、引人注目的字幕:每个字在音节处弹出,当前词高亮,文字与旁白紧密同步。打造适合抖音、Reels 和 Shorts 的吸睛字幕——清晰、合拍、位于安全区域内。

字幕动画 是什么?

“字幕动画”技能专为 AI 代理设计,用于在短视频或任何项目中创建逐字逐句的动态字幕。它支持 Remotion、CSS/Web 以及浏览器环境,可生成类似卡拉 OK 效果的字幕,其中每个字通过弹簧动画弹出,当前词高亮,文字保持在画面安全区域内。该技能详细描述了完整的工作流程:从使用 Whisper 进行音频转录、将时间戳标准化为统一格式、将文字分组为 1-4 词的“页面”、到通过 Remotion 的 `useCurrentFrame()` 或 CSS 的 `animation-delay` 实现逐字动画。它强调两个核心原则:必须使用逐字时间戳(而非行级),且可读性优先于样式。技能还涵盖了排版规范(粗体无衬线字体、字号 56-80px、描边和阴影)、在 9:16 竖屏视频中的安全区域布局(居中于 62-70% 处,避开底部 UI 区域),以及同时输出内嵌字幕(用于社交媒体)和独立 SRT/VTT 文件(用于无障碍访问)的最佳实践。最后提供详细的输出核对清单和验证步骤,以确保无时间偏移、字幕清晰且帧驱动。

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

在你喜欢的 AI 中提问

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

文档

字幕动画 是做什么的?

将转录稿或旁白转换为逐字精准、引人注目的字幕:每个字在音节处弹出,当前词高亮,文字与旁白紧密同步。打造适合抖音、Reels 和 Shorts 的吸睛字幕——清晰、合拍、位于安全区域内。

使用场景

  • 在 9:16 竖版短视频中创建逐字或卡拉 OK 字幕。
  • 将旁白/解说音轨根据转录稿烧录为开放字幕。
  • 将 Whisper/SRT 转录稿转换为 Remotion 或 Web 上的动画文本。
  • 将自动生成的字幕重制为带有品牌风格的“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 快约 2 倍且精度足够。

逐字弹出动画 (Remotion)

每个字的缩放和透明度由一个以其自身 startMs 为锚点的弹簧驱动。微小的过冲正是让效果感觉“生动”的关键。

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 状态。保持高亮为一个单色或当前词后方的填充“方框”——绝不要同时改变所有词的颜色。

分页,而非文字墙

一次显示 1-4 个词。使用 Remotion 的 createTikTokStyleCaptions()(或手动分组)并调整 combineTokensWithinMilliseconds 参数:约 200-500ms 实现真正的逐字效果,约 1000-1500ms 形成短小可读的短语。

import { createTikTokStyleCaptions } from "@remotion/captions";
const { pages } = createTikTokStyleCaptions({
  captions, combineTokensWithinMilliseconds: 1200,       // 每页约 2-3 个词
});

Web/CSS 弹出动画(无需 Remotion)

对于 DOM/实时播放器,为每个字设置其 animation-delay 等于 startMs:

.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 行。

与旁白/解说同步

转录稿已包含对应音频的精确时间。将该音频放置在合成层下方,并确保时间戳基于音频的时间基准——字幕和语音将完美同步,无需手动调整。如果重新录制了旁白,请重新转录;切勿手动偏移时间。

内嵌字幕 vs 独立 SRT/VTT

内嵌(开放字幕)独立 SRT/VTT(闭合字幕)
位置嵌入 MP4 像素中单独的 .srt/.vtt 文件
社交媒体(抖音/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)。

验证循环——渲染静帧 → 检查 → 编码。 逐字时间戳是容易出问题的地方;在花费时间编码之前,先在精确帧上检查它。

# 起始帧 / 某个采样当前词帧 / 结束帧——使用实际数据参数(真实令牌 + 音频)
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:
#  - 在 frame 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. 在采样帧处正确的字被高亮(帧/帧率对应的时间落在其令牌区间内);无平均分割的伪造。
  3. 内嵌字幕清晰可读(描边+阴影),且在检查的每一帧都完全位于 9:16 安全区域内。
  4. 仅帧驱动——无 Date.now() / Math.random() / 定时器。
  5. 实际数据参数(真实令牌,不仅仅是 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.

相关技能