mcpField
V
video-storytelling

video-storytelling

github.com/nateherkai创意与媒体2.3k195 次安装2 周前更新
代码仓库

关于 video-storytelling

video-storytelling 是为长篇脚本视频设计视觉层的技能,尤其适用于真人讲述形式。它通过持续存在的视觉空间、镜头移动和空间化悬念,帮助观众保持理解方向。

主要功能

  1. 01维持单一且持续存在的视觉空间
  2. 02用镜头移动引导注意力
  3. 03构建空间化悬念和可见的兑现
  4. 04统一视觉令牌与运动规则
  5. 05让图形聚焦于有标签的信息

适用场景

  1. 01为长篇真人讲述视频设计画面
  2. 02用持续的图示解释一个流程
  3. 03以视觉方式组织教程、对比或清单视频

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/nateherkai/herk-edit-kit --skill video-storytelling

安装后在 Claude Code 中输入/video-storytelling确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

reference/
design-system.md
reference/patterns/wall-of-slots/
geom.py
README.md
wall.py

详细介绍

视频叙事

如何构建长视频的视觉层,让观众在第九分钟时仍能理清方向。适用于任何带脚本的真人出镜视频:新闻解读、单主题深度分析、对比、教程、清单类视频。

要替代的是按场景思考的做法。每隔几秒就换一张新图,会让观众每隔几秒就得重新理解内容;但问题并不出在任何一张具体的图上,所以反馈往往含糊地说“看不懂”或“信息太多”,而不是指出具体缺陷。

如需一份中性的练习节拍表,请阅读仓库根目录下的 docs/STORYTELLING-WORKBOOK.md。可复用的设计系统位于此技能的 reference/design-system.md;完整演示的开放循环几何结构位于 reference/patterns/wall-of-slots/。无需使用私有源视频。

这不是 hyperframes-video-beats。该技能是在真人出镜画面上叠加卡片;本技能设计的是视频所讲述的内容。

1 · 四项原则

一个持续存在的世界

视频存在于一个单一空间中,且这个空间永不重置。观众已经看过的所有内容都仍留在原处,而新内容是在其上添加,而不是取而代之。一个元素一旦绘制,就绝不重绘、移动或重新标注。

本技能的其他一切都以此为基础。如果空间不断变化,镜头就无处可去;如果屏幕上没有其他内容,聚光就毫无意义;如果世界不断重置,开放循环也无法保持开放。

这个世界还必须值得观众停留,因此要在开始构建前确定空间语法,并在整个视频时长内保持一致。在参考作品中:从左到右代表走向结果,向上代表走向人,且是屏幕上唯一的暖色;向下则进入记录系统。观众若在前两分钟学会了这套规则,之后的视频就能轻松看懂。

只为表达含义而有意打破语法一次。参考作品在十分钟内唯一一次从右向左移动,是在说到“重新打开率”时,一个已解决的工单反向回到队列。这一幕无需言语便能传达意思,因为此前三分钟里,方向一直有其含义。

摄像机就是剪辑

每次切换到新的图形,观众都会失去方向感。在一个保持不变的空间中移动,则不会让他们付出任何代价。因此,推近会让人觉得是在说“仔细看看你已经了解的事物中的这一部分”,而拉远才是作品见效的地方,因为迄今构建的一切都还在那里。

在三个景别层级间工作,并在相邻层级间移动:

景别层级展示内容用途
全景整个空间确定方向、呈现成果、“我们现在在这里”
区域正在讨论的子图大部分运行时间
细节单个元素一个数字、一次状态变化、一个决定

除非是刻意安排的成果呈现节拍,否则从细节直接跳到全景会让人迷失方向;若是刻意安排的成果呈现节拍,这就是最好的选择。

以下规则,每条都曾让我付出重做的代价才学会:

  • 将构图命名为精确的世界窗口,而不是缩放比例。 窗口边界必须落在标签之间。将构图指定为“scale 0.6”,会让画面边缘把文字切成两半。
  • 同一用途始终复用同一窗口。 如果定向镜头使用的是某个特定窗口,就始终使用这个精确窗口。近乎相同的构图会让人感觉画面在漂移。
  • 根据移动距离调整时长,不要使用一个全局预设。
  • 摄像机移动和全屏擦除应依次发生,绝不能重叠。 同时发生会把内容拦腰截断。先移动摄像机,再擦除。
  • 遮罩层应先变为不透明,再让摄像机在其下方移动。 顺序相反会暴露部分移动过程,看起来像跳切。
  • 标签距画面边缘至少 60px。 元素可以延伸出画面,让人读作“世界仍在延续”;但文字被切掉半个字形则会像程序错误。通过调整位置解决,而不是用遮罩,因为羽化边缘追不上以约 1800 px/s 移动的刀刃。
  • 同一主体上连续进行两次移动会让人觉得是故障。 先完成重新构图,然后再开始擦除,会呈现为缩放、突然停顿、再进行第二次移动——客户端称之为“故障和停顿”。将它们合并为一个动作:共享对称缓动(power2.inOut),并落在同一帧上,这样面板看起来才像是在把画面推开。另请注意:对可见画面的移动使用前置缓动(power3/4.out),会让约 90% 的移动距离集中在前段,随后缓慢爬行至停止;应将这类缓动留给元素入场,此时缓慢爬行会呈现出安定下来的感觉。(在示例简介中,这导致了一次由客户端指出的问题修改。)
注意力是一束聚光

任何时刻都只有一个元素处于全亮状态。其他所有已绘制的内容都保持柔和,但仍清晰可辨。 这不是可选项。这条规则让世界可以逐步累积到十几个元素,却始终不会显得杂乱;也正是它让拉远镜头的画面清晰易读,而非令人不知所措。

层级来自活跃元素与柔和元素之间的比值,绝不是把所有内容都调暗。参考构建的第一个原型中,最亮像素的亮度只有 101/255,在 960x540 下难以辨认;解决办法是让笔迹更亮,而不是进一步调暗。

状态目标亮度(Y,16-235)参考构建中的不透明度
活跃笔画 + 标签200-2351.0
上下文,已绘制且仍相关120-1500.56
已完成,已表达其内容85-1050.33
任何状态下的任何标签不低于 90

实现由一个函数完成,每个旁白节拍都会调用它,并传入正在讨论的 id(build_s01.py、lit()):

def lit(t, active, warm=(), dur=0.5, floor=FLOOR):
    active = list(active) + [g + "-l" for g in active if g + "-l" in order]
    for gid in order:
        if gid not in opac:      # never drawn: nothing to light
            continue
        tgt = 1.0 if gid in active else (WARM if gid in warm else floor)
        if gid not in active:
            tgt = min(tgt, MUTED.get(gid, 1.0))
        ...

其中有三个关键细节:

  • 标签始终继承其元素的状态(折叠处理 -l 后缀)。元素已点亮、但其下方的标签无法辨认,正是要修复的问题。
  • 完成的道具会以不透明度 0 退场,通过 MUTED 上限实现,而不是调到 0.3。调到 0.3 会让无法解释的零碎内容留在屏幕上,直到本节结束。生成器规则:在任何后续开始的 lit() 之前发出 mute(),否则其补间完成时会覆盖该设置。
  • 必须按时间线顺序发出不透明度事件,否则跟踪器会看到过时状态并计算出错误的目标。保留一个 seq() 检查,以便在事件顺序错误时抛出异常。
  • 每个时间窗口内,每个元素只能有一个不透明度控制源。 两个同时活跃的补间若将同一元素的不透明度驱动到不同值,在独立片段中渲染会很平滑,但在组装后的主成片中会以约 10 Hz 闪烁,因为每帧胜出的补间会交替。参考构建在每个停靠点都带有这个缺陷。当 lit() 这类扫掠动画与显式增亮或静音重叠时,较晚开始的补间是唯一的控制源,扫掠动画会跳过这些 id(lit(..., skip=(...)))。对此进行把关:扫描组装后的渲染,在每个转场窗口中检查亮度是否出现单帧内突增后又回落的跳变(参考构建中的 qa/v4/flicker/qa-flicker.mjs)。
留下的悬念要具象可见

永远不要说“我们之后再说这个”。在画面中留下一个明显未完成的东西,然后再回到它。观众看得见的承诺,才是他们感受到尚未兑现的承诺。

无论形状如何,机制都相同:

  1. 在钩子中种下它:放在空间里,放在许下承诺的那句旁边。
  2. 在每个转场处重新展示它。 任何章节交接都是一个转场。重新展示大约需要 2 秒,也是留存机制;省略这一步,就会让后续的兑现变得毫无意义。
  3. 让它 visibly 推进。 观众必须看见未完成的部分逐渐缩小。
  4. 以开场时的画面收尾。

根据脚本选择形状:

脚本形式世界未完成的部分
N 个并列项目主干上的 N 个插槽空槽(参见 reference/patterns/wall-of-slots/)
一个深入讲解的流程完整铺开的流程线断裂或缺失的连接
多个级别或层级向上搭建的堆叠顶层是虚影
比较共用同一轴线的两列一列为空,或评分卡尚未填完
新闻或公告时间线或景观地图右侧,也就是未来,一片空白
教程或跟做用虚影呈现的完整架构尚未构建的每个节点

将项目放入对应插槽时,要用实时镜头移动,约 1.4 秒,绝不能直接切到预先制作好的填充完成图。让观众看着刚学到的东西变成那个方块。如果视频中有数字或计数器,就在同一次移动中像里程表一样滚动更新;两个数字的起始时间、时长和缓动必须相同,否则滚动到一半时就会融合成一条色带。

计数器需要名称,不能只有数字。 角落里的数字能告诉观众他们看到序列中的第几项,却不能说明当前项目是什么;过了 9 分钟,“03”毫无意义。用 1–2 个词的标签标明当前项目(SUPPORT、VOICE AI),并让它与数字采用相同的底板视觉效果,作为一个固定整体移动,并在同一次里程表式滚动中切换。客户对参考版本的评审明确提出了这一点:视觉效果很好,但观众还是会搞不清屏幕上展示的是哪个使用场景。

2 · 规范

不给它配文字,就不要画出来

所有形状都必须是带标签的元素、连接带标签元素的连线、移动中的主体,或环境底色。除此之外,不要画任何东西。

这一原则来自一次静音测试评审:理解度得分为 7/10,评审指出了原因:图表很简洁,装饰却不是。十几个没有标签的形状,采用了与有意义的元素相同的线条粗细和配色,因此初次观看的观众无法分辨信息与纹理,并将宝贵的注意力花在解读那些本来就无需解读的图形上。这就是把“画面内容太多”从文字转移到图形上。

预算:每个章节的画面文字约 20 个词。 不写句子。标签为 1–2 个词,放在元素下方。参考版本第 1 节在 84 秒内共 21 个词。

推论:反模式图示绝不覆盖推荐方案。 先将画面暗至接近全黑,或把反例放在与优秀图示不同的位置。

让观众跟随一个对象

用一个状态会明显变化的移动主体来承载故事:带有数据行和分数条的芯片、文档或请求。数据行逐渐填满,进度条移动,边框改变颜色。观众必须能通过观察这个对象跟完整个章节;它绝不能瞬移,而要沿着画出的连线匀速移动。

一套全局令牌

完整说明见 reference/design-system.md。

令牌值
描边1.5 / 2.5 / 4 / 7,仅限这些值
字号22 / 30 / 42 / 60 / 84
圆角10 / 22 / 40,始终使用 superellipse(2)

五种颜色、五种固定含义,不做任何装饰。暖色表示有人参与,除此之外绝不使用暖色。文字绝不使用纯白色;纯白色在深色背景上会产生光晕。

首次构建的工艺审查指出,这套规则要防止的失败是:"每个决策都在局部做出,而且都正确;但没有一个决策是全局性的。" 18 种描边粗细和 9 种字号,其中大多数只差 0.2,单独看都难以察觉,合在一起却足以致命。眼睛接收到的不是层次,而是噪声。用令牌检查器拦截此类问题,并让构建失败。

动效

入场使用 cubic-bezier(0.16,1,0.3,1),退场比入场更快;时长随质量感变化,因此 290px 的节点和 40px 的标签不会以相同方式减速;每个章节中 back.out 恰好使用一次,放在最值得使用的节拍上。

绝不交叉淡化。 全屏图层通过裁切在已不透明的背景上入场和退场。在任意时刻,每个像素要么是图形,要么是视频画面。

3 · 构建规范

  • 每个章节使用一个生成器。 scripts/build_<id>.py 仅写入 compositions/<id>.html。编辑生成器,绝不编辑生成的 HTML。章节根目录中的 index-*.html 由人工维护,因此取景调整应在那里进行。
  • 共享模块必须保持共享。 定义共享几何形状的内容都必须由每个章节导入。如果由并行 Agent 构建各个章节,必须禁止它们修改共享模块;几何形状出现分歧会悄无声息地破坏每次交接。
  • 组装前为 SVG 定义添加命名空间。 每个章节都定义自己的 gEdge、shadow、edgeFade。在组装后的 DOM 中,url(#id) 会解析到文档顺序中的第一个匹配项,因此较早的合成卸载后,所有后续图形都会变成空白。参考构建中的代价:所有检查项都显示绿色,屏幕却空白了 35 秒。只有查看组装后的渲染结果才发现了这个问题。
  • 根据词级转录文本的每个词语起始时间安排所有内容,并在锚定词出现前 0.15-0.25s 入场。绝不要把一个章节平均划分成多个节拍。
  • 审查间隙。 任何超过约 1.5s 且没有内容变化的片段都是死屏;让生成器打印这些片段。
  • 剪辑时留出呼吸感。 激进地压缩停顿会使句子边界处的间隙接近于零,客户端会觉得像是在“结巴”和跳切。应根据说话者自身的常态进行校准:标记比其中位数紧约 10 倍的句子边界间隙(参考说话者的中位数为 470ms;被标记的连接处为 20-40ms),并通过插入 4-8 帧留白来修复,绝不移动词语。留白应取自轨道中真实的房间底噪片段,并添加 10ms 淡变,绝不使用 anullsrc:在 -50dBFS 的底噪上插入数字静音,会听起来像音频掉失。视频保持当前帧;句子之间的讲话人头部几乎静止,保持 4-8 帧不会被察觉。仅插入内容的更改会确定性地移动转录文本,因此无需重新转录。插入片段的边缘必须遵循语音包络:若在 1ms 内将供体底噪直接接到词尾,会截断自然需要 60-120ms 才消退的尾音,客户端会把这种断崖式变化听成结巴。应以 40ms 等功率交叉淡化接入尾音自身的衰减,绝不硬接。
  • 已烘焙的时间意味着必须通过脚本移位。 生成器会烘焙数百个原型时间字面值,章节偏移、接缝表和根级补间也都使用绝对时间。图形生成后的任何时间线更改(即使只是进行 2s 的留白处理),都必须通过经过审查的 AST/解析级转换来完成:每个编辑点之后的所有字面值都要移位,然后审查差异,绝不手动编辑。每次移位都必须从规范编辑列表本身推导;参考处理通过重新推导,发现自身审计中预先计算的偏移有 2 帧误差。
  • 渲染时使用 --workers 1。并行工作进程会使视频图层渲染为黑色。

4 · 检查关卡

全部运行一遍,然后仍要亲自查看。

node scripts/qa-tokens.mjs          # 0 off-system strokes / type sizes / radii
node scripts/qa-no-crossfade.mjs    # 0 full-bleed layers animating opacity
node scripts/qa-legibility.mjs <render>
node scripts/qa-seamjump.mjs <render> plan/cover-seams.json --control <cut>
node scripts/qa-deadframe.mjs <render> --control <cut>
node scripts/qa-presence.mjs <render> --every 1      # speaker on-screen share
node scripts/integrate.mjs --check                   # 0 gaps, 0 stale mounts
npx hyperframes lint

检查关卡不能替代亲自查看,而从未失败过的关卡也算不上关卡。

  • 运动流畅度必须通过连续帧验证,绝不能只看节拍帧。 每个节拍取一帧只能证明构图;所有运动缺陷——动作开始时的跳变、第二个动作前缓慢爬行后骤停、冻结、单帧弹跳——都存在于节拍帧之间,能通过其他所有关卡。交付前,必须为每个转场窗口(镜头移动、擦除、重新构图、停靠、章节衔接处)截取连续帧条带,并仔细检查:

    ffmpeg -i render.mp4 -vf "select='between(n,A,B)',scale=480:270,tile=layout=6x7" \
      -frames:v 1 tile-<window>.png
    

    需要检查的缺陷特征:相邻画面先出现大幅跳变,随后数帧几乎完全相同(缓动集中在前段/骤停);一段运动停止后,又开始另一段运动(本应是一个连贯动作,却被拆成两个动作);任何与前后两帧都不同的单帧画面(弹跳)。示例构建中的片头出现了缩放冻结故障,尽管它通过了令牌、交叉淡化、可读性、空白间隙和逐节拍帧检查,客户还是一眼就发现了。这类问题会反复出现——要把逐帧条带检查视为不可或缺的环节,而非可选项。

  • 可读性无法自动化。 绝对像素占比阈值衡量的是文本量,而非可读性;文字密集的构建得分会高于文字稀疏的构建。请逐一用肉眼检查每个主要节拍缩小到 960x540 的画面。

  • 每个关卡都要用已知会触发它的对照样本进行验证。 对于有缺陷的构建,如果衔接处检查关卡报告零问题,那还不如没有关卡。

  • 验证最终合成的成品,绝不要只验证章节原型。本次构建中,大多数逃过关卡的 Bug 只存在于合成成品里。

  • 从声学层面审查音频,而非只看转录文本。 根据编辑前素材生成的转录文本,在结构上无法发现剪辑产生的瑕疵;对它进行文本扫描会报告“干净”,但客户听到的却是卡顿。根据参考构建中的检出率排序,真正有效的方法是:扫描整条音轨中的静音区间(停顿中出现连续数字零采样,而实际底噪约为 -70dBFS,这会形成死寂空洞;应以室内底噪填充);在每个连接边缘处进行 1ms 分辨率的包络取证(基于采样导数的咔嗒声检查会漏过包络陡变,但耳朵能立刻听出);以及对交付音频重新运行 ASR,并与预期文本进行差异比对。音素重复自相关检查没有发现问题:客户所说的“卡顿”通常是截断陡变和死寂空洞,而非词语重复。

出镜占比:以图形为主的视频中,目标是让讲者约 40% 的时间出现在画面中。需要完整画面宽度的重点呈现段落可以长时间不出镜;应审查这些段落,而不是给它们设置上限。

5 · 工作顺序

  1. 锁定剪辑版本,并获取逐词转录文本。所有内容都以此为时间依据。
  2. 选择视觉世界、空间语法和贯穿全片的主体。开始构建前先将它们记录下来。
  3. 根据脚本结构选择开放式悬念,并先构建其共用模块。片头钩子、每个章节边界和重点呈现段落都会引用它的几何结构。
  4. 先完整构建一个章节并渲染。先在这个章节中验证系统,再着手其他章节。
  5. 静音后用肉眼审查该章节的装饰元素和可读性。修复系统,而不是章节。
  6. 以已验证的章节为基准构建其余部分。然后设置命名空间、合成、渲染、运行检查关卡,并检查合成后的渲染结果。

质量的关键在于第 4 和第 5 步。参考构建中的整个视觉系统,都是通过将第一个章节审查三次后形成的。

评论

支持 Markdown