关于 caption-animation
caption-animation 是一项将转录文本或旁白制作成逐词定时动画字幕的技能,适用于短视频等场景。它涵盖从时间戳令牌到 Remotion 或网页动画及字幕导出的流程。
主要功能
- 01逐词时间戳处理流程
- 02逐词弹入与当前词高亮
- 03字幕分页与布局指导
- 04画面内字幕及 SRT/VTT 导出
- 05基于帧的渲染验证
适用场景
- 01为竖屏视频制作卡拉 OK 字幕
- 02将转录字幕烧录到旁白视频
- 03用 Remotion 动画呈现 Whisper 或 SRT 文本
- 04为无障碍播放提供独立字幕文件
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ iart-ai/ tiktok-video-skills --skill caption-animation安装后在 Claude Code 中输入/caption-animation确认已加载。
附带文件README.mdreferences/word-timed-captions.md
详细介绍
字幕动画
将转录文本或旁白转化为按词定时、吸睛的字幕:每个词随音节弹出,高亮当前词,文本与旁白紧密同步。制作能提升 TikTok、Reels 和 Shorts 观看时长的字幕——清晰易读、紧跟节拍,并位于安全区域内。
适用场景
- 在竖屏短视频(9:16)中逐词显示字幕或卡拉 OK 字幕。
- 根据转录文本,将开放字幕烧录到旁白音轨上。
- 将 Whisper/SRT 转录文本转换为 Remotion 或网页中的动画文本。
- 将自动生成的字幕重新设计为品牌风格的 “Hormozi-style” 逐字呈现效果。
工作流程
| 阶段 | 任务 | 工具 |
|---|---|---|
| 转录 | 音频 → 词级时间戳 | Whisper(@remotion/install-whisper-cpp)、AssemblyAI |
| 规范化 | → { text, startMs, endMs }[] 令牌 | @remotion/captions Caption 类型 |
| 分页 | 将词分组为 1–4 词的“页” | createTikTokStyleCaptions() |
| 动画 | 逐词弹出 + 当前词高亮 | Remotion spring() / CSS |
| 放置 | 安全区域、清晰易读的字体 | 下方的布局规则 |
| 导出 | 烧录字幕(MP4)和/或旁挂 SRT/VTT 文件 | Remotion 渲染 / 文件输出 |
两条不可妥协的规则
- 使用词级时间,而非行级时间。 只有每个词都落在对应音节上,卡拉 OK 字幕才会显得神奇。始终转录出词级时间戳;绝不要把一行的持续时间平均分配给每个词来伪造时间——偏差会立刻显现。
- 可读性优先于风格。 字幕需要在阳光下、静音时也能在手机上看清。优先使用粗体无衬线字体、粗描边或阴影,并确保高对比度;装饰其次。看不清的字幕只是装饰,不是字幕。
从转录文本获取词级时间
Whisper 会直接输出词级时间戳。将所有来源规范化为统一的扁平令牌结构,这样渲染器就无需关心词语来自哪里:
// Caption token — the one shape everything downstream consumes
type Token = { text: string; startMs: number; endMs: number };
// Parse an SRT cue block "00:00:01,200 --> 00:00:01,640" into ms
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; // word's own entrance frame
const p = spring({ frame: frame - enter, fps, config: { damping: 12, mass: 0.6 } });
const scale = interpolate(p, [0, 1], [0.6, 1]); // pop from 60% → 100% (overshoots)
return (
<span style={{
display: "inline-block",
transform: `scale(${scale})`,
opacity: interpolate(p, [0, 1], [0, 1]),
color: active ? "#FFE45E" : "#FFFFFF", // active-word highlight
transition: "color 80ms linear",
}}>{token.text} </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 words per page
});
网页/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 行的边距。
同步到旁白/解说
转录文本已经带有精确音频的时间信息。将同一段音频置于合成内容下方,并保持时间戳与音频使用相同的时间基准——字幕和语音会始终同步,无需手动微调。如果重新录制旁白,请重新转录;切勿手动调整偏移量。
烧录字幕与外挂 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)。
验证流程——渲染静帧 → 检查 → 编码。 最容易出问题的是词语时间;在花时间编码之前,先检查精确帧。
# Stills at start / a sampled active-word frame / end — WITH SHIPPED PROPS (real tokens + audio)
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
# Inspect each PNG:
# - the word highlighted at frame 90 is the word whose [startMs,endMs] contains 90/fps (no drift)
# - burn-in legible: bold sans, stroke+shadow holds, no clipping
# - 9:16 safe area: caption sits in the center band, clear of top ~12% and bottom ~20-35% (captions/CTA/audio UI) and the right action rail
npx remotion render Captions out/captions.mp4 --props='{"captionsSrc":"vo.json"}' # encode once stills are right
npx remotion render Captions out/demo.gif --codec=gif # README proof clip
使用 npx remotion compositions 读取 durationInFrames/fps,并选取当前词帧和结束帧。
完成前:
- 帧 0、中间的当前词帧和最后一帧均能正常渲染——不能缺少字体/音频。
- 采样帧中高亮的是正确词语(帧数/fps 落在其词元时间范围内);不要伪造均分时间。
- 烧录字幕清晰可读(描边+阴影),且所有检查帧中的字幕都完全处于 9:16 安全区域内。
- 只能按帧驱动——不使用
Date.now()/Math.random()/ 定时器。 - 已交付的 props(真实词元,而不仅是
defaultProps)能正确渲染;输出 MP4 和外挂 SRT/VTT,GIF 可选。
参考文件
references/word-timed-captions.md— 端到端构建指南:Whisper 转录和Caption类型、完整的 SRT 解析器、带当前词高亮的 Remotion 词级计时组件、手动分页、SRT/VTT 生成器、各平台安全区域映射,以及易读字体规格表。