short-form-video

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Short-Form Vertical Video (Hyperframes)

短视频竖屏视频(Hyperframes)

Short-form = 1080x1920 vertical, 10–30s, talking-head face + motion-graphic scene overlays + karaoke captions. Everything in this skill is distilled from the May Shorts 19 iteration autopsy (v1 → v4) and is preserved for maintenance of those examples. Use
short-form-edit
for new recordings.
Always invoke
/hyperframes
first.
This skill sits on top of it — it does not replace the framework rules (
data-*
attributes,
window.__timelines
, composition structure). Those are non-negotiable regardless of the format.
短视频 = 1080x1920 竖屏,时长 10–30 秒,包含 talking-head face + motion-graphic scene overlays + karaoke captions。本 skill 的所有内容均提炼自 May Shorts 19 iteration autopsy(v1 → v4),并为维护这些示例而保留。新录制内容请使用
short-form-edit
。
始终先调用
/hyperframes
。
本 skill 叠加于它之上,不会取代 framework rules(
data-*
attributes、
window.__timelines
、composition structure)。无论 format 如何,这些规则都不可更改。

When this skill fires

本 skill 的触发场景

  • Maintaining the existing May Shorts examples.
  • Explicitly requesting their legacy four-layer scaffold.
  • 维护现有的 May Shorts 示例。
  • 明确要求使用其 legacy four-layer scaffold。

The playbook (high-level)

Playbook(执行手册)

  1. Audio is source of truth. Edit audio FIRST (cut retakes, pauses). Save as
    <name>-edit.mp4
    . Measure exact duration with
    ffprobe
    — this is the composition's
    data-duration
    .
  2. Transcribe the edited audio with the root
    scripts/transcribe-elevenlabs.mjs
    helper (ElevenLabs Scribe), a student-selected alternative normalized per
    docs/TOOLS-AND-API-KEYS.md
    , or if retiming an existing build with a
    shift()
    function in captions, keep the existing captions and just shift scene starts.
  3. Author scene boundaries in edited-time — NEVER mix original-time and edited-time anchors in the same file. See "Audio-sync protocol" below.
  4. Build the composition scaffold (4 layers: ambient-bg, seam-treatment, captions, face) — see "Composition scaffold" below.
  5. Author scenes with LOCAL offsets relative to each scene's
    data-start
    . Each scene is its own sub-composition under
    compositions/scene<N>-<label>.html
    .
  6. Lint → draft render → word-exact frame verification → final render. This is the verification gate. Never skip step 3 (frame verification).
  1. Audio 是唯一事实来源。 先编辑 audio(剪掉重拍和停顿)。保存为
    <name>-edit.mp4
    。用
    ffprobe
    测量准确时长——这就是 composition 的
    data-duration
    。
  2. 使用根目录的
    scripts/transcribe-elevenlabs.mjs
    helper(ElevenLabs Scribe)转录编辑后的 audio,或使用学生选择并按
    docs/TOOLS-AND-API-KEYS.md
    规范化的替代方案;如果是在重定时现有 build,且 captions 中包含
    shift()
    function,则保留现有 captions,只平移 scene starts。
  3. 按 edited-time 编写 scene boundaries——同一文件中绝不混用 original-time 和 edited-time anchors。参见下方“Audio-sync protocol”。
  4. 构建 composition scaffold(4 层:ambient-bg、seam-treatment、captions、face)——参见下方“Composition scaffold”。
  5. 使用 LOCAL offsets 编写 scenes,相对于每个 scene 的
    data-start
    。每个 scene 都是位于
    compositions/scene<N>-<label>.html
    的独立 sub-composition。
  6. Lint → draft render → word-exact frame verification → final render。 这是 verification gate。绝不跳过 step 3(frame verification)。

Composition scaffold (the 4 always-on layers)

Composition scaffold(4 个始终启用的图层)

Every short-form vertical has these four sub-compositions under
compositions/
, loaded on shared tracks:
index.html (root, 1080x1920, data-composition-id="main")
├── ambient-bg.html        track-index="3" — radial gradient + drift grid + particles + vignette
├── face-wrapper + <video> track-index="0" — talking head (see face-mode choreography)
├── seam-treatment.html    track-index="5" — feathers y=960 edge (bottom-half scenes only)
├── scene1-<label>.html    track-index="1" — scene overlays (back-to-back, no gaps)
├── scene2-<label>.html    track-index="1"
├── …
└── captions.html          track-index="2" — karaoke captions, word-synced
  • data-duration
    is identical across root, ambient-bg, seam-treatment, face-video, face-audio, captions. Only scene overlays change over time.
  • <audio>
    for the face is a SEPARATE element (mixer needs it), never use the video's own audio track.
  • class="clip"
    goes on timed divs — NEVER on
    <video>
    or
    <audio>
    .
每个短视频竖屏 composition 都有以下四个 sub-compositions,位于
compositions/
下,并加载到共享 tracks 上:
index.html (root, 1080x1920, data-composition-id="main")
├── ambient-bg.html        track-index="3" — radial gradient + drift grid + particles + vignette
├── face-wrapper + <video> track-index="0" — talking head (see face-mode choreography)
├── seam-treatment.html    track-index="5" — feathers y=960 edge (bottom-half scenes only)
├── scene1-<label>.html    track-index="1" — scene overlays (back-to-back, no gaps)
├── scene2-<label>.html    track-index="1"
├── …
└── captions.html          track-index="2" — karaoke captions, word-synced
  • root、ambient-bg、seam-treatment、face-video、face-audio 和 captions 的
    data-duration
    完全一致。只有 scene overlays 会随时间变化。
  • face 的
    <audio>
    是独立元素(mixer 需要它),绝不要使用 video 自带的 audio track。
  • class="clip"
    应放在 timed div 上——绝不能放在
    <video>
    或
    <audio>
    上。

Face-mode choreography (the signature move of short-form)

Face-mode choreography(short-form 的标志性动作)

The face lives in a wrapper div sized at the source's native landscape (1920x1080). GSAP animates the WRAPPER (never the video element — animating
<video>
dimensions freezes frames).
Two modes:
js
const BOTTOM     = { x: 0,       y: 1136, scale: 0.5625 }; // bottom-half, full landscape visible
const FULLSCREEN = { x: -1166.5, y: 0,    scale: 1.7778 }; // cropped-cover, fills 1080x1920
const MODE_DUR = 0.32;
BOTTOM
renders the 1920x1080 source at 1080x607.5 centered in the bottom 960px.
FULLSCREEN
crops horizontally to fill the portrait frame.
Transition 0.15s BEFORE the new scene's content lands, using
ease: "expo.inOut"
:
js
[
  { t: <scene-4-start>, mode: FULLSCREEN },
  { t: <scene-5-start>, mode: BOTTOM },
  …
].forEach(({ t, mode }) => {
  mainTl.to("#face-wrapper", { ...mode, duration: MODE_DUR, ease: "expo.inOut" }, t - 0.15);
});
A face that snaps modes instantly is the single most jarring frame in a vertical video. Always interpolate.
face 位于一个 wrapper div 中,其尺寸采用 source 的原生 landscape 比例(1920x1080)。GSAP 负责动画化 WRAPPER(绝不能动画化 video element——改变
<video>
尺寸会冻结帧)。
两种 mode:
js
const BOTTOM     = { x: 0,       y: 1136, scale: 0.5625 }; // bottom-half, full landscape visible
const FULLSCREEN = { x: -1166.5, y: 0,    scale: 1.7778 }; // cropped-cover, fills 1080x1920
const MODE_DUR = 0.32;
BOTTOM
会将 1920x1080 source 渲染为 1080x607.5,居中放置在底部 960px 区域。
FULLSCREEN
会裁剪水平方向,以填满 1080x1920 竖屏画面。
在新 scene 的内容落地前 0.15 秒执行过渡,使用
ease: "expo.inOut"
:
js
[
  { t: <scene-4-start>, mode: FULLSCREEN },
  { t: <scene-5-start>, mode: BOTTOM },
  …
].forEach(({ t, mode }) => {
  mainTl.to("#face-wrapper", { ...mode, duration: MODE_DUR, ease: "expo.inOut" }, t - 0.15);
});
瞬间切换 mode 的 face 是竖屏视频中最突兀的一帧。始终使用插值。

Face grading (every short, no exceptions)

Face grading(每个短视频,无例外)

css
#face-video {
  filter: contrast(1.08) saturate(1.08) brightness(0.97);
}
Plus a subtle 1.00 → 1.025 Ken Burns zoom over the full duration (
ease: "none"
) and a side-vignette
::after
pseudo-element so the face sinks into the surrounding navy instead of butting against a razor edge.
css
#face-video {
  filter: contrast(1.08) saturate(1.08) brightness(0.97);
}
此外,在完整时长内加入轻微的 1.00 → 1.025 Ken Burns zoom(
ease: "none"
),并使用 side-vignette
::after
pseudo-element,让 face 融入周围的 navy,而不是紧贴锐利边缘。

Seam treatment (required for bottom-half scenes)

Seam treatment(bottom-half scenes 必需)

A navy→transparent gradient band (60–100px) at y=960 plus a 2px accent scan line with soft glow. Draw it AFTER the face so it sits on top; full-screen scenes will cover it when they take over. Razor-sharp y=960 cuts are the #2 tell for AI-edited content (after background flatness).
在 y=960 处设置 navy→transparent gradient band(60–100px),再加上一条 2px accent scan line 和柔和 glow。将其绘制在 face 之后,使其位于上层;full-screen scenes 接管时自然会将其覆盖。锋利的 y=960 切边是 AI 编辑内容最明显的第二特征(仅次于背景过于扁平)。

Audio-sync protocol (DO NOT skip)

Audio-sync protocol(绝不能跳过)

Problem: if audio is edited (retakes/pauses removed), timestamps in the source transcript no longer match the edited video. Scene starts authored in original-time will fire late.
The rule: ALL timing lives in edited-time. Never mix.
Verification procedure for any short-form retime:
  1. Measure both audio files:
    bash
    ffprobe -v error -show_entries format=duration -of csv=p=0 assets/original.mp4
    ffprobe -v error -show_entries format=duration -of csv=p=0 assets/<name>-edit.mp4
    Difference = total cut time.
  2. If using a
    shift()
    function in
    captions.html
    to map transcript words, treat that as the source of truth. The map
    shift(originalTime) = editedTime
    applies to EVERY scene
    data-start
    too.
  3. Scene internal offsets (inside
    compositions/sceneN.html
    ) are LOCAL relative to the scene's
    data-start
    . If a scene's parent
    data-start
    is correct in edited-time, internal offsets stay correct WITHOUT modification — UNLESS a scene straddles a cut, in which case both the parent duration AND internal offsets shift.
  4. Face-mode transition array times MUST use edited-time. They are NOT automatically shifted.
Plan format for retimes (use this table structure every time):
SceneCurrent startCurrent durNew startNew durRationale
..................
Then the face-mode array, then any internal-offset changes, then frame-verification list.
问题: 如果 audio 已被编辑(重拍或停顿被删除),source transcript 中的时间戳就不再与 edited video 匹配。使用 original-time 编写的 scene starts 会延迟触发。
规则: 所有 timing 都必须使用 edited-time。绝不混用。
任何 short-form retime 的验证流程:
  1. 测量两个 audio 文件:
    bash
    ffprobe -v error -show_entries format=duration -of csv=p=0 assets/original.mp4
    ffprobe -v error -show_entries format=duration -of csv=p=0 assets/<name>-edit.mp4
    差值 = total cut time。
  2. 如果在
    captions.html
    中使用
    shift()
    function 映射 transcript words,应将其视为唯一事实来源。该映射
    shift(originalTime) = editedTime
    也适用于每个 scene 的
    data-start
    。
  3. Scene internal offsets(位于
    compositions/sceneN.html
    内部)相对于 scene 的
    data-start
    。如果 scene 的 parent
    data-start
    已正确使用 edited-time,internal offsets 无需修改——除非该 scene 横跨剪切点,此时 parent duration 和 internal offsets 都必须平移。
  4. Face-mode transition array 的时间必须使用 edited-time。它们不会自动平移。
Retimes 的计划格式(每次都使用以下表格结构):
SceneCurrent startCurrent durNew startNew durRationale
..................
然后列出 face-mode array,再列出所有 internal-offset changes,最后列出 frame-verification 清单。

Scene authoring

Scene authoring

One scene = one sub-composition file. Scenes sit on the same
data-track-index
back-to-back (no gaps). Inside each scene:
  • data-duration
    matches the parent's slot exactly
  • All GSAP anchors are LOCAL (0-based from scene start)
  • Use
    tl.set({}, {}, <data-duration>)
    to pad the timeline so GSAP
    tl.duration()
    matches
    data-duration
一个 scene 对应一个 sub-composition 文件。Scenes 使用相同的
data-track-index
,彼此首尾相接(不留空隙)。每个 scene 内部:
  • data-duration
    与 parent slot 完全一致
  • 所有 GSAP anchors 都是 LOCAL(从 scene start 的 0 开始计算)
  • 使用
    tl.set({}, {}, <data-duration>)
    填充 timeline,确保 GSAP
    tl.duration()
    与
    data-duration
    一致

Scene pacing rules (from the 10 principles)

Scene pacing rules(来自 10 principles)

  • No dead frames. Every 100ms has ≥1 animating element. Offset first entrance 0.1–0.3s, not t=0.
  • Payoff ≥ 1s hold. The "big reveal" of the scene (stamp, number lock, punchline) must have ≥1s on screen, ideally 1.5s. Budget scenes by reveal time, not total time.
  • Motion through full duration. If entrance anims all land by local 2s on a 4s scene, add secondary motion: underline sweeps, checkmark pops, ambient drift on cards, small oscillating glows on pills. Dead pacing = swipe-away.
  • Vary eases. At least 3 different eases per scene across entrances.
  • One jaw-dropper per 5s of runtime. Typography slam, glitch/chromatic reveal, whip-pan, audio-sync slam. Without these, the video reads as "labeled talking head" — correct but forgettable.
  • 无静止帧。 每 100ms 至少有一个元素在执行动画。将首次入场偏移 0.1–0.3 秒,而不是放在 t=0。
  • Payoff 至少停留 1 秒。 Scene 的“big reveal”(stamp、number lock、punchline)必须在画面上停留至少 1 秒,最好达到 1.5 秒。依据 reveal time 分配 scene 预算,而不是依据总时长。
  • 整个时长都保持运动。 如果 4 秒 scene 的入场动画都在 local 2 秒前结束,就要添加次级运动:underline sweeps、checkmark pops、cards 的 ambient drift、pills 上轻微摆动的 glows。节奏停滞会使用户划走。
  • 变换 easing 要有变化。 每个 scene 的入场动画至少使用 3 种不同的 eases。
  • 每 5 秒运行时至少安排一个 jaw-dropper。 可以使用 typography slam、glitch/chromatic reveal、whip-pan 或 audio-sync slam。缺少这些元素,视频会显得像“加了标签的 talking head”——虽然正确,却缺乏记忆点。

Captions (karaoke style)

Captions(karaoke style)

  • Montserrat 900, 46–58px (for 1080 width), 100% white base
  • Active word: scale-1.08 pop + color change to accent (
    #37bdf8
    for AIS, adapt to brand)
  • Stroke via layered
    text-shadow
    , NEVER
    -webkit-text-stroke
    (renders inconsistently in Chromium render)
  • Drop the rgba background pill — let the stroke hold readability. Captions should feel like graffiti on the frame, not a subtitle track.
  • For retimes, use a
    shift()
    function inside
    captions.html
    to map transcript word timestamps → edited-time. This keeps the transcript JSON untouched and makes retimes mechanical.
See
references/captions.md
under
/hyperframes
for the full karaoke implementation. TL;DR: per-word
<span>
elements with
data-word-start
, GSAP tweens scoped to each span, tight 0.08–0.12s pop durations.
  • 使用 Montserrat 900、46–58px(适配 1080 宽度),以 100% white 为基础色
  • 当前词:scale-1.08 pop + 颜色变为 accent(AIS 使用
    #37bdf8
    ,也可按品牌调整)
  • 使用分层
    text-shadow
    实现 stroke,绝不能使用
    -webkit-text-stroke
    (在 Chromium render 中表现不一致)
  • 去掉 rgba background pill——依靠 stroke 保持可读性。Captions 应该像画面上的 graffiti,而不是普通的 subtitle track
  • Retimes 时,在
    captions.html
    中使用
    shift()
    function 将 transcript word timestamps 映射到 edited-time。这样无需修改 transcript JSON,即可机械地完成 retime
完整 karaoke 实现请参阅
/hyperframes
下的
references/captions.md
。简而言之:每个词使用一个
<span>
元素并设置
data-word-start
,GSAP tweens 作用于各个 span,pop duration 控制在紧凑的 0.08–0.12 秒。

Ambient background (never ship flat navy)

Ambient background(绝不能只使用平坦的 navy)

Minimum viable background stack:
  1. Radial gradient base (center lighter than edges by 15–20%)
  2. Animated noise/grain overlay at 8–12% opacity
  3. 4–8 drifting particle dots or grid traces
  4. Subtle vignette
background: #07121c
alone is a placeholder, not a design. For techy/control-room aesthetic, use the 6-layer stack from
feedback_techy_background_layers.md
(HUD grid masked to vignette + circuit traces + pulse nodes + scan beam + telemetry ticker + corner mono labels).
最低可用 background stack:
  1. Radial gradient base(中心比边缘亮 15–20%)
  2. Animated noise/grain overlay,opacity 为 8–12%
  3. 4–8 个 drifting particle dots 或 grid traces
  4. Subtle vignette
单独使用
background: #07121c
只是 placeholder,不是设计。对于 techy/control-room aesthetic,请使用
feedback_techy_background_layers.md
中的 6-layer stack(HUD grid masked to vignette + circuit traces + pulse nodes + scan beam + telemetry ticker + corner mono labels)。

Audio reactivity

Audio reactivity

  • Headlines pulse 3–6% on beat. Backgrounds can go 10–30% on bass.
  • Text reactivity kept subtle (3–6%) so captions stay readable; backgrounds can push harder.
  • Use a SEEDED offline analyser (pre-compute the audio feature track) so renders are deterministic. Do NOT use
    AnalyserNode
    in the render path —
    Math.random()
    and real-time audio nodes break determinism.
  • Headlines 根据 beat 产生 3–6% 的 pulse。Backgrounds 可根据 bass 产生 10–30% 的变化。
  • Text reactivity 保持轻微(3–6%),确保 captions 仍然清晰;backgrounds 可以有更强烈的变化。
  • 使用 SEEDED offline analyser(预先计算 audio feature track),确保 renders 具有确定性。绝不要在 render path 中使用
    AnalyserNode
    ——
    Math.random()
    和 real-time audio nodes 会破坏确定性。

Transitions

Transitions

  • Rotate flavors. No two consecutive transitions the same type. Six hard cuts in a row is the #1 tell for AI editing.
  • Face-mode transitions (
    BOTTOM ↔ FULLSCREEN
    ) double as scene transitions when the mode changes between scenes.
  • For pure overlay scene-to-scene, install from registry:
    push-up
    ,
    flash-through-white
    ,
    sdf-iris
    , or the full shader-transitions pack.
    npx hyperframes catalog --type block
    to browse.
  • 轮换 transition flavors。 不要连续使用同一种 transition。连续六次 hard cut 是 AI editing 最明显的首要特征。
  • Face-mode transitions(
    BOTTOM ↔ FULLSCREEN
    )在 mode 随 scene 变化时,也可作为 scene transitions。
  • 对于纯 overlay 的 scene-to-scene transition,从 registry 安装:
    push-up
    、
    flash-through-white
    、
    sdf-iris
    ,或使用完整 shader-transitions pack。可通过
    npx hyperframes catalog --type block
    浏览。

The verification gate (mandatory — DO NOT ship without)

The verification gate(强制执行——未通过绝不能发布)

Lint passing ≠ design working. Never report a short-form render done until you have extracted frames at word-exact timestamps and READ every PNG.
Lint 通过 ≠ 设计正常。在按 word-exact timestamps 提取 frames 并 READ 每一张 PNG 之前,绝不能报告 short-form render 已完成。

Step 1 — draft render

Step 1 — draft render

bash
cd video-projects/<slug>
npx hyperframes lint
npx hyperframes render --quality draft --output renders/<slug>-vN-draft.mp4
bash
cd video-projects/<slug>
npx hyperframes lint
npx hyperframes render --quality draft --output renders/<slug>-vN-draft.mp4

Step 2 — word-exact frame extraction

Step 2 — word-exact frame extraction

Pick 8–15 timestamps that each correspond to a SPOKEN WORD where a specific visual should be on-screen. Not round numbers. Not mid-scene. The exact word.
bash
mkdir -p renders/frames-vN
for pair in "<t>:<label>" "<t>:<label>" ...; do
  t="${pair%%:*}"; label="${pair##*:}"
  ffmpeg -y -ss "$t" -i renders/<slug>-vN-draft.mp4 \
    -frames:v 1 -q:v 2 "renders/frames-vN/t${t}-${label}.png"
done
选择 8–15 个 timestamps,每个 timestamp 都应对应一个 spoken word,并且该词应触发特定 visual。不要使用整数时间,也不要选择 scene 中间位置,必须精确对应到具体单词。
bash
mkdir -p renders/frames-vN
for pair in "<t>:<label>" "<t>:<label>" ...; do
  t="${pair%%:*}"; label="${pair##*:}"
  ffmpeg -y -ss "$t" -i renders/<slug>-vN-draft.mp4 \
    -frames:v 1 -q:v 2 "renders/frames-vN/t${t}-${label}.png"
done

Step 3 — Read every PNG

Step 3 — Read every PNG

Call
Read
on every PNG so the image loads into context. Do NOT just list filenames. For each frame confirm:
  • The expected visual is on-screen at the expected moment (not 1s late, not early)
  • Speaker's face is not cropped in any bottom-half scene
  • Full-screen vs bottom-half face mode is correct for that scene
  • Captions are on-brand, readable, not overflowing
  • No blank frames, no unintentional overlap, no text-off-canvas
对每一张 PNG 调用
Read
,使图片加载到 context 中。绝不能只列出 filenames。对每一帧确认:
  • 预期 visual 出现在预期时刻(没有延迟 1 秒,也没有提前出现)
  • 在任何 bottom-half scene 中,speaker 的 face 都没有被裁切
  • 每个 scene 的 full-screen 与 bottom-half face mode 均正确
  • Captions 符合品牌规范、清晰可读且没有溢出
  • 没有空白帧、意外重叠或超出画布的文本

Step 4 — if anything fails, fix + re-verify. Never ship broken.

Step 4 — 如有任何失败,修复并重新验证。绝不能发布有问题的版本。

Step 5 — final render

Step 5 — final render

bash
npx hyperframes render --quality standard --output renders/<slug>-vN.mp4
Spot-check 3–4 frames from the final render (same timestamps, different folder
frames-vN-final/
) to confirm the standard-quality encode didn't change anything.
bash
npx hyperframes render --quality standard --output renders/<slug>-vN.mp4
从 final render 中抽查 3–4 帧(使用相同 timestamps,但放在不同的
frames-vN-final/
文件夹中),确认 standard-quality encode 没有改变任何效果。

The 10 rules (quality checklist — run BEFORE first draft)

The 10 rules(quality checklist——首次 draft 前运行)

Every short-form build. Run this list during authoring, not after.
  1. No dead frames. Every 100ms has an animating element.
  2. Scene payoff ≥ 1s hold. Budget by reveal time, not total time.
  3. Face is a character. Grade + Ken Burns + side vignette.
  4. No hard seams. Feather y=960 with gradient + scan line.
  5. One jaw-dropper per 5s. Typography slam, glitch, whip-pan, audio slam.
  6. Audio reactivity non-negotiable. 3–6% text, 10–30% background.
  7. Rotate transition flavors. No two consecutive the same.
  8. Captions pop, don't politely label. Stroke not pill. Scale + color on active word.
  9. Motion through full scene duration. Secondary motion if entrances land early.
  10. Background is a layer, not a color. Radial + noise + particles + vignette minimum.
  11. Slam/stamp overlays land AFTER target text is fully visible. Reveal logic > word-sync. Stamp
    t
    ≥ target-visible
    t
    + 0.10–0.25s. Otherwise the punchline lands before the setup.
每个 short-form build 都应遵循此清单。执行时间应放在 authoring 阶段,而不是完成之后。
  1. 无静止帧。 每 100ms 至少有一个元素在执行动画。
  2. Scene payoff 至少停留 1 秒。 依据 reveal time 分配预算,而不是依据总时长。
  3. **Face 是一个角色。**始终应用 Grade + Ken Burns + side vignette。
  4. 无硬切缝。 使用 gradient + scan line 羽化 y=960。
  5. 每 5 秒一个 jaw-dropper。 可以使用 typography slam、glitch、whip-pan 或 audio slam。
  6. Audio reactivity 不可妥协。 Text 使用 3–6%,background 使用 10–30%。
  7. 轮换 transition flavors。 不要连续使用同一种 transition。
  8. Captions 要 pop,而不是礼貌式标注。 使用 stroke,不使用 pill。当前词应用 scale + color。
  9. 整个 scene 时长都保持运动。 如果入场动画提前结束,就添加次级运动。
  10. Background 是一层,而不是一种颜色。 最低要求是 radial + noise + particles + vignette。
  11. Slam/stamp overlays 必须在 target text 完全可见后落地。 Reveal logic > word-sync。Stamp 的
    t
    ≥ target-visible 的
    t
    + 0.10–0.25 秒。否则 punchline 会在 setup 之前出现。

Project structure (every short-form project)

Project structure(每个 short-form project)

video-projects/<slug>/
├── hyperframes.json
├── meta.json                    (id, name, dimensions 1080x1920, fps 30)
├── index.html                   (root composition, the 4-layer scaffold)
├── compositions/
│   ├── ambient-bg.html
│   ├── seam-treatment.html
│   ├── captions.html            (with shift() function if retiming)
│   ├── scene1-<label>.html
│   ├── scene2-<label>.html
│   └── ...
├── assets/
│   ├── <name>.mp4               (original recording)
│   ├── <name>-edit.mp4          (edited — cuts removed — this is what the comp uses)
│   ├── transcript.json          (whisper output)
│   └── brand assets (logo, brand-tokens.css, background music)
└── renders/
    ├── <slug>-v1-draft.mp4
    ├── frames-v1/
    ├── <slug>-v1.mp4
    └── ...
video-projects/<slug>/
├── hyperframes.json
├── meta.json                    (id, name, dimensions 1080x1920, fps 30)
├── index.html                   (root composition, the 4-layer scaffold)
├── compositions/
│   ├── ambient-bg.html
│   ├── seam-treatment.html
│   ├── captions.html            (with shift() function if retiming)
│   ├── scene1-<label>.html
│   ├── scene2-<label>.html
│   └── ...
├── assets/
│   ├── <name>.mp4               (original recording)
│   ├── <name>-edit.mp4          (edited — cuts removed — this is what the comp uses)
│   ├── transcript.json          (whisper output)
│   └── brand assets (logo, brand-tokens.css, background music)
└── renders/
    ├── <slug>-v1-draft.mp4
    ├── frames-v1/
    ├── <slug>-v1.mp4
    └── ...

Retime protocol (when audio is re-edited or timestamps drift)

Retime protocol(当 audio 被重新编辑或 timestamps 发生漂移)

  1. Measure old and new edited audio durations with
    ffprobe
    . Delta = total cut time.
  2. Identify cut window(s): which seconds were removed, from where.
  3. Write the Plan table: every scene
    data-start
    ,
    data-duration
    , every face-mode transition
    t
    , any scene whose internal offsets straddle a cut.
  4. For each scene that straddles a cut, both its parent duration AND its internal offsets change. Scenes entirely on one side of the cut just need parent
    data-start
    shifted.
  5. Lint → draft render → word-exact frame verify → final render. No shortcuts.
  1. 使用
    ffprobe
    测量旧、新 edited audio 的时长。Delta = total cut time。
  2. 确定剪切窗口:删除了哪些秒数,以及从哪里删除。
  3. 编写 Plan table:记录每个 scene 的
    data-start
    、
    data-duration
    、每个 face-mode transition 的
    t
    ,以及任何横跨剪切点的 scene。
  4. 对于每个横跨剪切点的 scene,parent duration 和 internal offsets 都必须改变。完全位于剪切点某一侧的 scenes 只需平移 parent
    data-start
    。
  5. Lint → draft render → word-exact frame verify → final render。不能跳过任何步骤。

What NOT to do in short-form

Short-form 中禁止的做法

  • Don't animate
    <video>
    element dimensions — freezes frames. Animate wrapper div.
  • Don't use
    repeat: -1
    on any timeline — breaks the capture engine. Finite counts only.
  • Don't use
    Math.random()
    or
    Date.now()
    — breaks determinism. Seeded PRNG if pseudo-random needed.
  • Don't use
    <br>
    inside captions — natural wrapping +
    <br>
    produces extra unwanted breaks.
  • Don't skip the frame verification gate. Lint exit code is not visual truth.
  • Don't author in original-time if the audio is edited. Edited-time or nothing.
  • Don't leave
    background: #07121c
    flat. Layer it.
  • Don't hard-cut between scenes. Rotate transition flavors.
  • Don't polite-caption. Pop them.
  • Don't let the face sit still. Grade + Ken Burns always.
  • 不要动画化
    <video>
    元素的 dimensions——会冻结帧。应动画化 wrapper div。
  • 不要在任何 timeline 上使用
    repeat: -1
    ——会破坏 capture engine。只能使用有限次数。
  • 不要使用
    Math.random()
    或
    Date.now()
    ——会破坏确定性。如需 pseudo-random,请使用 Seeded PRNG。
  • 不要在 captions 中使用
    <br>
    ——自然换行与
    <br>
    组合会产生额外的非预期断行。
  • 不要跳过 frame verification gate。Lint exit code 并不代表视觉结果正确。
  • 如果 audio 已被编辑,不要使用 original-time authoring。只能使用 edited-time。
  • 不要留下平坦的
    background: #07121c
    。必须构建多层背景。
  • 不要在 scenes 之间使用 hard cut。轮换 transition flavors。
  • 不要使用礼貌式 captions。让它们 pop 起来。
  • 不要让 face 静止不动。始终应用 Grade + Ken Burns。

Lessons from may-shorts-18 (v1 → v2)

Lessons from may-shorts-18(v1 → v2)

Distilled from the 4 concrete problems the v1 render had and what fixed them in v2. Apply these on every new short.
以下内容提炼自 v1 render 中的 4 个具体问题及其在 v2 中采用的修复方式。应用到每个新的 short。

1. Slam/stamp timing — reveal logic beats word-sync

1. Slam/stamp timing——reveal logic 优先于 word-sync

A SLAM/STAMP overlay (KILLED, DEAD, STOP, etc.) lands AFTER its target text is fully visible, not during the spoken word. In may-shorts-18 v1 scene 1, CLAUDE and CHATGPT were pitched as opponents — KILLED fired at local 0.46s while CHATGPT didn't appear until 0.66s, so viewers saw "Claude … KILLED" with no visible target. The joke collapsed.
Rule:
stamp_t ≥ target-text-visible_t + 0.10–0.25s
. The "visible" timestamp is the END of the target's entrance animation, not its start. Word-sync is a guideline; visual reveal order is the constraint.
SLAM/STAMP overlay(KILLED、DEAD、STOP 等)必须在 target text 完全可见之后落地,而不是在 spoken word 播放期间出现。在 may-shorts-18 v1 的 scene 1 中,CLAUDE 和 CHATGPT 被设定成对手——KILLED 在 local 0.46 秒触发,而 CHATGPT 到 0.66 秒才出现,因此观众只看到“Claude … KILLED”,却看不到目标。笑点因此失效。
规则:
stamp_t ≥ target-text-visible_t + 0.10–0.25 秒
。“Visible” timestamp 指目标入场动画的结束时间,而不是开始时间。Word-sync 只是参考,visual reveal order 才是硬性约束。

2. BOTTOM face-mode scale — don't ship the default

2. BOTTOM face-mode scale——不要使用默认值

Default
BOTTOM = { x: 0, y: 1136, scale: 0.5625 }
(exact horizontal fit for a 1920×1080 source) leaves empty studio background flanking the speaker if they occupy <70% of the source frame. This is the default in may-shorts-19 and was copied into may-shorts-18 v1 — both videos had visible dead space left and right of the speaker in every BOTTOM scene.
Rule: prefer
BOTTOM = { x: -180, y: 1110, scale: 0.75 }
— crops 180px each side, bottom-anchors to y=1920. Preview ONE frame of BOTTOM mode against the actual source video before committing the constant. If the source speaker is tight-framed already, scale 0.65 may be enough; if the source is wide studio framing, push to scale 0.80 and re-tune x.
Always keep HIDDEN's
x
,
y
,
scale
identical to BOTTOM — they only differ in
opacity
— so the opacity-fade scenes don't drift geometrically mid-fade.
默认的
BOTTOM = { x: 0, y: 1136, scale: 0.5625 }
(针对 1920×1080 source 精确横向适配)会在 speaker 占据 source frame 不到 70% 时,于左右两侧留下空白 studio background。这是 may-shorts-19 中的默认值,并被复制到了 may-shorts-18 v1——两个视频的每个 BOTTOM scene 中,speaker 两侧都存在明显的 dead space。
规则: 优先使用
BOTTOM = { x: -180, y: 1110, scale: 0.75 }
——裁剪左右各 180px,并将底部锚定到 y=1920。在确定常量之前,使用实际 source video 预览一帧 BOTTOM mode。如果 source 中的 speaker 已经采用紧凑构图,scale 0.65 可能已经足够;如果采用宽幅 studio framing,则将 scale 提高到 0.80,并重新调整 x。
始终确保 HIDDEN 的
x
、
y
、
scale
与 BOTTOM 完全一致——它们只在
opacity
上存在差异,避免 opacity-fade scenes 在淡出过程中发生几何漂移。

3. Face-mode transitions — three things at once, not one

3. Face-mode transitions——需要同时完成三件事

When the face changes mode between adjacent scenes, a bare 0.15s pre-roll + 0.32s duration
expo.inOut
on just the face wrapper reads as rigid — the outgoing scene's panels are still fully opaque behind the morphing face, so the eye sees two things fighting instead of a crossfade.
Rule: for any "hero" scene-to-scene face-mode change (especially BOTTOM ↔ FULLSCREEN), do all three:
  1. Extend that specific transition's duration to 0.45–0.55s (not the default 0.32s)
  2. Start it 0.25–0.30s before the new scene's
    data-start
    (not the default 0.15s)
  3. Fade + blur the outgoing scene's panel wrapper to
    opacity: 0, filter: blur(6px)
    over 0.20–0.25s, starting 0.25s before scene end
Implementation-wise, promote the face-mode transition array to per-entry
dur
so one transition can be longer than the others:
js
[ { t: 2.06, mode: FULLSCREEN, dur: 0.50 }, { t: 3.71, mode: HIDDEN, dur: 0.32 }, ... ]
  .forEach(({ t, mode, dur }) => mainTl.to("#face-wrapper", { ...mode, duration: dur, ease: "expo.inOut" }, t));
Three simultaneous changes = "a real editor edited this." Any one alone = rigid.
当 face 在相邻 scenes 之间切换 mode 时,如果只在 face wrapper 上使用 0.15 秒 pre-roll + 0.32 秒 duration 的
expo.inOut
,效果会显得生硬——outgoing scene 的 panels 在 face 变形时仍然完全不透明,因此观众看到的不是 crossfade,而是两个元素在相互争夺注意力。
规则: 对于任何“hero” scene-to-scene face-mode change(尤其是 BOTTOM ↔ FULLSCREEN),必须同时完成以下三项:
  1. 将该次 transition 的 duration 延长到 0.45–0.55 秒(而不是默认的 0.32 秒)
  2. 在新 scene 的
    data-start
    前 0.25–0.30 秒开始 transition(而不是默认的 0.15 秒)
  3. 从 scene 结束前 0.25 秒开始,用 0.20–0.25 秒将 outgoing scene 的 panel wrapper 淡出并模糊至
    opacity: 0, filter: blur(6px)
在实现层面,将 face-mode transition array 改为允许每个 entry 使用独立的
dur
,从而让某一次 transition 比其他 transition 更长:
js
[ { t: 2.06, mode: FULLSCREEN, dur: 0.50 }, { t: 3.71, mode: HIDDEN, dur: 0.32 }, ... ]
  .forEach(({ t, mode, dur }) => mainTl.to("#face-wrapper", { ...mode, duration: dur, ease: "expo.inOut" }, t));
同时完成三项变化,才能产生“真正由人工剪辑师完成”的效果。只完成其中任何一项都会显得生硬。

4. Data-feel scenes beat decoration scenes mid-video

4. Data-feel scenes 优于中段的装饰性 scenes

For scenes 3–5 of a 15–20s short (the "middle grind" where attention drops the hardest), lean on visuals that read as information — bar races, stat grids with counting numbers, heatmaps, sparklines, flowcharts, dashboard chrome with telemetry ticking, pain-point grids that flash red in sequence. may-shorts-18 v1 scene 4 was a radar-rings + terminal-chip + sparks combo — functional but decorative, and Nate called it "bland." v2 replaced it with a 3×3 pain-point grid lighting up red-orange in sequence + a sparkline stroke-drawing with a YOU-ARE-HERE marker + the payoff slam — same time budget, much higher engagement.
Rule: pure typography-plus-icon scenes feel like slides. Data-feel scenes feel like evidence. When a middle scene feels bland, replace the decoration with something that reads as information: a small number ticking up, a bar filling, a chart stroking in, a grid flashing in sequence.
对于 15–20 秒 short 中的 scenes 3–5(注意力最容易下降的“middle grind”),优先使用看起来像 information 呈现的 visuals:bar races、带计数数字的 stat grids、heatmaps、sparklines、flowcharts、带有动态 telemetry 的 dashboard chrome,以及依次闪红的 pain-point grids。may-shorts-18 v1 的 scene 4 使用 radar-rings + terminal-chip + sparks 组合——功能完整,但偏装饰性,Nate 称其“bland”。v2 在相同时间预算下,将其替换为依次点亮红橙色的 3×3 pain-point grid + 带 YOU-ARE-HERE marker 的 sparkline stroke-drawing + payoff slam,参与度显著提高。
规则: 纯 typography + icon scenes 看起来像 slides,data-feel scenes 则像 evidence。当中间某个 scene 显得平淡时,应使用看起来像“信息”的内容替换装饰:小型计数器递增、bar 被填满、chart 被描边绘制、grid 依次闪烁。

Reference compositions

Reference compositions

  • video-projects/may-shorts-19/
    — the canonical short-form example (18.84s, 1080x1920, 7 scenes, face-mode choreography, karaoke captions with shift(), ambient bg + seam treatment). Read
    index.html
    and any
    compositions/scene*.html
    before authoring a new short.
  • video-projects/may-shorts-18/
    — secondary reference with the 4 lessons above baked in: BOTTOM scale=0.75, KILLED stamp timed after CHATGPT reveal, scene-1→2 fluid fade, scene 4 data-dashboard "THE PATTERN" grid.
  • video-projects/may-shorts-19/
    ——标准 short-form 示例(18.84 秒、1080x1920、7 个 scenes、face-mode choreography、带
    shift()
    的 karaoke captions、ambient bg + seam treatment)。编写新 short 之前,请阅读
    index.html
    和任意
    compositions/scene*.html
    。
  • video-projects/may-shorts-18/
    ——次要参考示例,已应用上述 4 项经验:BOTTOM scale=0.75、KILLED stamp 在 CHATGPT reveal 后触发、scene-1→2 fluid fade、scene 4 data-dashboard “THE PATTERN” grid。

Related skills (invoke in addition)

Related skills(需要额外调用)

  • /hyperframes
    — framework rules (always first)
  • /hyperframes-cli
    — CLI commands (init, lint, preview, render)
  • /gsap
    — animation library reference
  • /hyperframes-registry
    — installing transition blocks
  • /seedance-loop-prompt
    — if the short needs an AI-generated looping background video
  • /hyperframes
    ——framework rules(始终先调用)
  • /hyperframes-cli
    ——CLI commands(init、lint、preview、render)
  • /gsap
    ——animation library reference
  • /hyperframes-registry
    ——安装 transition blocks
  • /seedance-loop-prompt
    ——如果 short 需要 AI-generated looping background video

Memory pointers (relevant feedback entries)

Memory pointers(相关 feedback entries)

  • feedback_short_form_principles.md
    — the 10 rules, full rationale
  • feedback_contrast_technique.md
    — glow localization + text-shadow halos + brightening dim text
  • feedback_techy_background_layers.md
    — 6-layer control-room background stack
  • feedback_visual_verification.md
    — the verification gate
  • project_ais_brand_specs.md
    — if the short is AIS-branded (hex codes, fonts, logo glow)
  • feedback_short_form_principles.md
    ——10 条规则及完整理由
  • feedback_contrast_technique.md
    ——glow localization + text-shadow halos + 提亮暗色文本
  • feedback_techy_background_layers.md
    ——6 层 control-room background stack
  • feedback_visual_verification.md
    ——verification gate
  • project_ais_brand_specs.md
    ——如果 short 使用 AIS 品牌规范(hex codes、fonts、logo glow)