camera-3d-captions
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinese3D camera captions
3D 摄像机字幕
The After Effects move (3D camera, depth of field, text on a path, Posterize Time 15, motion blur) rebuilt as a
deterministic per-frame painter for HyperFrames. One clock paints plate, matte and every glyph. Nothing is a CSS
animation.
将 After Effects 运镜(3D 摄像机、景深、路径上的文字、Posterize Time 15、运动模糊)重建为 HyperFrames 的确定性逐帧绘制器。由同一个时钟驱动 plate、matte 和每个字形的绘制。没有任何内容使用 CSS animation。
When to use / when not
何时使用 / 何时不使用
- Use on a static-camera talking-head take (avatar or real), landscape, medium shot or wider, 5–20 s per piece. The words must perform in depth around the speaker.
- Do not use for plain subtitles, a moving or handheld camera (the matte and the plate transform assume a locked shot), extreme close-ups (no room behind or around the head), or a subject a person-matting model can't separate.
- 使用场景:固定机位的 talking-head 素材(虚拟形象或真人)、横屏、中景或更宽的景别,每段 5–20 秒。文字需要在说话者周围呈现纵深运动。
- 不要用于:普通字幕、移动或手持摄像机画面(matte 和 plate 的变换假定镜头固定)、极近特写(头部后方或周围没有足够空间),以及人物分割模型无法分离的主体。
Requirements and side effects (complete list)
要求与副作用(完整清单)
- Tools:
- Node 22+ and the HyperFrames CLI pinned to the tested version, (downloads from
npx hyperframes@0.8.62). Use that exact version for every command below.registry.npmjs.org - on PATH.
ffmpeg - Python 3 with ,
fonttools,brotli,numpy.pillow
- Node 22+ and the HyperFrames CLI pinned to the tested version,
- Matte: runs locally. On first run it downloads its person-segmentation model (~170 MB) to
npx hyperframes@0.8.62 remove-background.~/.cache/hyperframes/ - Render time: compositions load GSAP 3.14.2 from at preview/render time.
cdn.jsdelivr.net - Word clock: any word-level transcriber the user already runs locally. Onset accuracy matters; plain Whisper starts run late.
- Fonts: user-supplied files. Confirm the licence allows embedding.
- Hand-drawn style (optional): needs the skill installed and set up (its setup downloads pinned puppeteer, Chrome for Testing, p5 and p5.brush).
p5-paint-animationruns it headlessly; frames are written to that skill'sbuild-sprites.pyand removed afterwards.out/ - Nothing else: no credentials, no paid calls, nothing uploaded. Files are written only into the project
(,
assets/).renders/
- 工具:
- Node 22+,以及固定到已测试版本的 HyperFrames CLI:(从
npx hyperframes@0.8.62下载)。以下所有命令都必须使用这个精确版本。registry.npmjs.org - PATH 中可用的 。
ffmpeg - Python 3,并安装 、
fonttools、brotli、numpy。pillow
- Node 22+,以及固定到已测试版本的 HyperFrames CLI:
- Matte:在本地运行。首次运行会下载人物分割模型(约 170 MB)到
npx hyperframes@0.8.62 remove-background。~/.cache/hyperframes/ - 渲染时:合成会在预览或渲染时从 加载 GSAP 3.14.2。
cdn.jsdelivr.net - Word clock:使用用户已在本地运行的任意逐词转录工具。起始时间准确度很重要;普通 Whisper 的启动时间偏晚。
- 字体:由用户提供文件。需确认许可证允许嵌入。
- 手绘风格(可选):需要安装并配置 skill。其安装过程会下载固定版本的 puppeteer、Chrome for Testing、p5 和 p5.brush。
p5-paint-animation以 headless 模式运行;帧会写入该 skill 的build-sprites.py,并在完成后删除。out/ - 除此之外:不需要凭据、付费调用,也不会上传任何内容。文件只会写入项目目录(、
assets/)。renders/
Prep (once per take)
准备工作(每段素材执行一次)
- Portion and plate. produces:
bash scripts/prep-take.sh <take.mp4> <start_s> <dur_s> <project>/assets- : the audio source.
portion.mp4 - : reflect-padded 240 px each side, 480 px top, 240 px bottom, so whips, trucks and pull-backs never show an edge.
plate-tall.mp4 - : the alpha matte, same frames.
person.webm - The script then checks the plate and matte against the portion (size, frame rate, frame count) and fails on any mismatch.
- Word clock. Word timings for the portion, in seconds from its start.
- Fonts. Pick 2–3 roles (caption / hero / ring), then
.
python3 scripts/font-metrics.py assets/metrics.js key=font.woff2[@wght=…,opsz=…] …- A variable font must get its axes passed here AND pinned in CSS (,
font-variation-settings). Otherwise the browser's opsz follows the size and words overlap.font-optical-sizing: none
- A variable font must get its axes passed here AND pinned in CSS (
- Silhouette. Read the head box and shoulder line off the alpha before placing anything.
person.webm
- 片段与画布。 会生成:
bash scripts/prep-take.sh <take.mp4> <start_s> <dur_s> <project>/assets- :音频源。
portion.mp4 - :左右各反射填充 240 px、顶部填充 480 px、底部填充 240 px,确保 whip、truck 和 pull-back 过程中不会露出边缘。
plate-tall.mp4 - :alpha matte,帧范围与前两者相同。
person.webm - 随后脚本会对照 portion 检查 plate 和 matte 的大小、帧率及帧数,任何不匹配都会导致失败。
- Word clock。 portion 的逐词时间,以片段起点后的秒数表示。
- 字体。 选择 2–3 种用途(caption / hero / ring),然后执行 。
python3 scripts/font-metrics.py assets/metrics.js key=font.woff2[@wght=…,opsz=…] …- 可变字体的字体轴必须同时在此处传入,并在 CSS 中固定(、
font-variation-settings)。否则浏览器的font-optical-sizing: none会随字号变化,导致文字重叠。opsz
- 可变字体的字体轴必须同时在此处传入,并在 CSS 中固定(
- 轮廓。 在放置任何元素之前,从 的 alpha 中读取头部边界框和肩线。
person.webm
Build
构建
- Copy and
assets/kit/{cam3d.js,tables.js,finish.js}into the project'smetrics.js.assets/ - is the complete reference film. It has two shots, a body wipe, both ring types, a fly-through, a finale and the grade; its media is not included.
references/worked-film.html - holds the depth-first groups, the wrapped ring, the staircase and hand-drawn words.
references/recipes.md - :
C3.init(metrics, {W, H})- The lens keeps the tutorial's vertical field of view (F = 1326.1·H/1080), so applies unscaled at any width.
tables.js - On a frame wider than 1440, add to
(W − 1440) / 2.wipe.x
- The lens keeps the tutorial's vertical field of view (F = 1326.1·H/1080), so
- 将 和
assets/kit/{cam3d.js,tables.js,finish.js}复制到项目的metrics.js。assets/ - 是完整的参考成片,包含两个镜头、人物擦除转场、两种词环、穿行镜头、收尾和调色;其中不包含媒体文件。
references/worked-film.html - 包含深度优先字幕组、环绕词环、阶梯式排布和手绘文字的配方。
references/recipes.md - :
C3.init(metrics, {W, H})- 镜头保持教程中的垂直视场角(F = 1326.1·H/1080),因此 可按未缩放比例应用于任意宽度。
tables.js - 当画面宽度超过 1440 时,向 中添加
wipe.x。(W − 1440) / 2
- 镜头保持教程中的垂直视场角(F = 1326.1·H/1080),因此
Shot grammar
镜头语法
Pick 4–6 beats. Split each spoken clause into its own group.
| Beat | Build | Rule |
|---|---|---|
| Whip-in punch-in | | plate |
| Depth groups | 2–3 caption groups per clause at D 1250 / 1500 / 2200 | near = bigger with a bigger shadow; the creep and truck reveal the parallax |
| Hero behind | hero word in the behind layer at the plate depth, masthead-style across the head | the head hides the middle letters; ≥ 60 % stays legible; the ascender is inside the frame |
| Parallax truck | | the old layout fades over 3 steps; the next layout arrives by parallax |
| Body wipe | the speaker's own matte, | shot A clips left of the band, shot B right; pull-out on both sides |
| Wrapped ring | horizontal circle IN FRONT of the speaker (centre Z 2000), 11–16° from above, turning | words enter small at the side as spoken, swing round the front, settle; lower arc flips to read upright |
| Fly-through | phrases at D 1500 / 2000 / 2500, camera swings between them | focus follows the phrase |
| Staircase finale | push segment; caption words each deeper and smaller down a diagonal | the push drives the near words apart |
选择 4–6 个节拍。将每段口语分句拆成独立字幕组。
| 节拍 | 构建方式 | 规则 |
|---|---|---|
| Whip-in punch-in | | |
| 深度字幕组 | 每个分句设置 2–3 组字幕,D 为 1250 / 1500 / 2200 | 近处文字更大、阴影更重; |
| Hero behind | 主视觉词放在 behind layer,深度与 plate 相同,以 masthead 风格横跨头部 | 头部遮住中间字母;至少 60% 保持可读;字母上伸部位于画面内 |
| Parallax truck | | 旧布局在 3 个 step 内淡出;新布局通过视差运动进入 |
| 人物擦除转场 | 使用说话者自身的 matte、 | 镜头 A 在带状区域左侧被裁切,镜头 B 在右侧被裁切;两侧均做 pull-out |
| 环绕词环 | 位于说话者前方的水平圆环(中心 Z 2000),从上方观察有 11–16° 倾角,并持续旋转 | 文字在对应语音开始时从侧面以小尺寸进入,绕到前景后停稳;下半弧翻转至正向可读 |
| 穿行镜头 | 短语分别位于 D 1500 / 2000 / 2500,摄像机在它们之间摆动 | 焦点跟随目标短语 |
| 阶梯式收尾 | push 片段;字幕词沿对角线逐级加深并缩小 | push 将近处文字相互拉开 |
Rules
规则
- Motion:
- Text is posterized to 15 fps (its own animation and the camera it sees). Plate and matte move every frame.
- Motion blur is 7 ghosts over half a 15-fps step. Use on turning rings.
shutter: 0.5 - Captions lead the voice by 0.2 s, snapped to the 15-fps grid: .
fr(t) = 2·round((t − 0.2)·15) - Entries rise by : captions 30 px, heroes 110–260 px. Ring words ease their last 30–44 px along the path. Use
ENTRY's overshoot only when no neighbour is seated yet.RING_ENTRY
- Depth:
- Every group gets its own D. Plate 3000, captions 1250–2400, wrapped ring ≈ 1100–2700.
- Depth shadow scales as 1500/(D − cz).
[6, 16, 0.5, 1500] - DOF σ = 6.7·|D − focus|/D px at 1080 tall. Flat captions cap at 1.2 px; ring glyphs take the full blur.
- Sizes: /
sizeare on-screen px at the landing camera (rise). Sprites are rendered at their on-screen size.tland - Spacing:
- Ring text always goes through (on-screen advance; type: track 1.10, gap 26–30; hand-drawn: track 1.0, gap 28).
ringLine - A turning ring is re-laid every pose.
- Ring text always goes through
- Occlusion:
- Rings draw in front of the speaker.
- Split a word into behind/front instances (,
side) only when it is MEANT to pass behind the head.zSplit
- Legibility:
- Captions go over the dark side of the frame.
- Text crossing skin or light clothing gets a dark halo.
- No trailing periods on screen.
- Grade (optional): supplies curves, saturation 1.12 for skin, and grain re-rolled per frame. Put the opaque scene (plate + behind text + matte) in a filtered wrapper. Give front text the same grade with grain composited atop, so a word split behind/front stays one colour (see
finish.js).references/worked-film.html
- 运动:
- 文字以 15 fps 做帧率量化(文字自身的动画及其所看到的摄像机运动均如此)。plate 和 matte 则每帧运动。
- 运动模糊由 7 个残影覆盖 15 fps 步长的一半构成。旋转词环使用 。
shutter: 0.5 - 字幕比语音提前 0.2 s,并吸附到 15 fps 网格:。
fr(t) = 2·round((t − 0.2)·15) - 入场位移由 控制:字幕为 30 px,主视觉词为 110–260 px。词环文字在路径最后 30–44 px 的范围内缓动。仅当相邻词尚未就位时,才使用
ENTRY的 overshoot。RING_ENTRY
- 深度:
- 每组使用独立的 D。plate 为 3000,字幕为 1250–2400,环绕词环约为 1100–2700。
- 深度阴影 按 1500/(D − cz) 缩放。
[6, 16, 0.5, 1500] - 在高度为 1080 时,DOF σ = 6.7·|D − focus|/D px。平面字幕的模糊上限为 1.2 px;词环字形使用完整模糊量。
- 尺寸:/
size表示落地摄像机(rise)下的屏幕像素。sprite 按其屏幕尺寸进行渲染。tland - 间距:
- 词环文字始终通过 排版(屏幕前进宽度;印刷体:track 1.10、gap 26–30;手绘:track 1.0、gap 28)。
ringLine - 旋转词环在每个姿态下重新排版。
- 词环文字始终通过
- 遮挡:
- 词环绘制在说话者前方。
- 仅当某个词确实需要从头部后方穿过时,才使用 、
side将其拆分为 behind/front 实例。zSplit
- 可读性:
- 字幕放在画面较暗的一侧。
- 文字穿过皮肤或浅色服装时添加深色 halo。
- 屏幕字幕末尾不显示句号。
- 调色(可选):提供曲线、1.12 的肤色饱和度,以及逐帧重新生成的 grain。将不透明场景(plate + behind text + matte)放入应用滤镜的 wrapper。前景文字使用相同的调色,并将 grain 叠加在上层,使拆分为 behind/front 的词保持同一种颜色(参见
finish.js)。references/worked-film.html
Styles
风格
- Editorial: a condensed display serif, italic for heroes; a text serif for captions; cream plus one accent.
- Bold: heavy grotesk heroes, light captions, one saturated accent (the worked film).
- Hand-drawn: p5.brush write-on sprites from :
scripts/hand/build-sprites.py- Each word writes itself on from its onset.
- Rings place words whole, rotated to the tangent and scaled by depth, on a bigger, flatter ring.
- Recipe in .
references/recipes.md
- 编辑排版:紧凑型标题衬线字体,主视觉词使用斜体;字幕使用正文字体衬线;奶油色搭配一种强调色。
- 粗体风格:主视觉词使用粗重 grotesk 字体,字幕使用轻字重,并搭配一种高饱和度强调色(参考成片采用此风格)。
- 手绘:使用 生成 p5.brush 书写显现 sprite:
scripts/hand/build-sprites.py- 每个词从其起始时刻开始逐笔写出。
- 词环以完整单词进行放置,按切线方向旋转,并根据深度缩放;词环更大、更扁。
- 配方见 。
references/recipes.md
Verify
验证
- . The ghost layers trip the WCAG contrast check; the whip and wipe seams are overlapping by design.
npx hyperframes@0.8.62 check . --no-contrast - In the preview page, paste and run
scripts/frame-bounds.js.__frameBounds(0, dur)- It must return : no group outside the frame for 5+ steps while visible.
[]
- It must return
- Paste and run
scripts/glyph-gaps.jsat rest.__glyphGaps(t)- No cross-word touches.
- Flat words measure as one box (descenders flag false positives). An italic f's overhang reads negative. Words on opposite sides of the wipe band both show.
- Word gaps: the rendered gap between words ≈ one space advance.
- Snapshot every beat, render with , and check full-resolution frames per beat.
npx hyperframes@0.8.62 render . --crf 12
- 。残影图层会导致 WCAG 对比度检查失败;whip 和 wipe 的接缝重叠属于预期设计。
npx hyperframes@0.8.62 check . --no-contrast - 在预览页面中粘贴 并运行
scripts/frame-bounds.js。__frameBounds(0, dur)- 必须返回 :可见期间连续 5 个以上 step 都不能有字幕组超出画面。
[]
- 必须返回
- 粘贴 ,并在静止状态下运行
scripts/glyph-gaps.js。__glyphGaps(t)- 不得出现跨词接触。
- 平面词应测量为一个 box(descender 可能产生误报)。斜体 f 的悬伸会显示为负值。位于 wipe 带两侧的词都应显示。
- 词间距:渲染后的词间空隙约等于一个空格的前进宽度。
- 为每个节拍创建快照,执行 ,并逐个检查节拍的全分辨率画面。
npx hyperframes@0.8.62 render . --crf 12
Limits
限制
- Matte edges flicker on fine hair. The mirrored pad shows briefly during a whip.
- A speaker who fills the frame leaves little room behind: go masthead-high, or tuck behind a shoulder.
- shares one page, so grain does not re-roll between captures. Judge grain on a render.
snapshot --at - Rendering with the grade and many ghost layers costs about 2× a plain render.
- 细发丝处的 matte 边缘可能闪烁。whip 过程中会短暂露出镜像填充区域。
- 如果说话者占满画面,头部后方几乎没有空间:可将文字提高到 masthead 高度,或藏到肩膀后方。
- 共用同一个页面,因此多次截图之间 grain 不会重新随机生成。应以实际 render 的结果判断 grain。
snapshot --at - 同时应用调色和大量残影图层时,渲染耗时约为普通渲染的 2 倍。