Communitygithub.com

ccreator-space/video-storytelling

设计和构建长视频中说话人画面的视觉层,将其打造为一个摄像机穿行其中的持续性世界,而非一系列独立的图形。当被要求编辑视频、添加动态图形、为脚本设计视觉效果、规划剪辑,或修复被判断为混乱、文字过多、难以理解或“看起来像AI制作的”剪辑时使用。涵盖持续性世界、摄像机语法、聚光法则、空间开放循环、装饰与令牌规范、字幕时间同步以及验证关卡。

video-storytelling 是什么?

该技能旨在解决长视频中常见的“场景思维”问题:每隔几秒切换新图形会导致观众频繁重启理解过程,最终以模糊的“混乱”或“信息过载”反馈告终。核心方案是将视频视觉层设计为一个“持续性世界”——所有元素一旦绘制便永不重置、移动或重命名,摄像机在其中平滑移动而非剪切。技能详细阐述了四大原则:持续性世界(空间语法统一且唯一一次有意识打破)、摄像机即剪辑(三种高度:世界、区域、细节,以及相邻高度间的移动规则和多项硬件约束)、注意力聚光灯(同一时刻只有一个元素全亮度,其余保持安静但可见,并给出具体的亮度/透明度数值和实现函数)、以及空间开放循环(通过视觉上未完成的事物制造悬念并逐步推进)。此外,技能还强调了严格的视觉学科:无文字的图形不绘制、一个跟随目标、全局令牌集(5种颜色、5种描边宽度、5种字号、3种圆角半径)、运动曲线规范,以及一份详细的构建合同(每节独立生成器、共享模块、SVG命名空间冲突回避、按词定时、气口间隙审计等),并提供了可复用的设计系统和模式参考。支持任何有脚本的说话人头像视频,如新闻、深度解析、对比、教程、列表清单等。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ccreator-space/edit-flow/tree/HEAD/.agents/skills/video-storytelling

在你喜欢的 AI 中提问

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

文档

视频叙事技巧

如何构建长视频的视觉层,使得观众在第九分钟依然保持方向感。适用于任何有脚本的说话人头像视频:新闻观点、单一主题深度解析、对比、教程、列表清单。

本技能旨在取代的失败模式是“场景思维”。每隔几秒出现新图形会迫使观众每隔几秒重新开始理解,而没有任何单个图形是罪魁祸首——这就是为什么反馈会以模糊的“混乱”或“东西太多”的形式出现,而不是具体的缺陷。

如需一份中立的练习节奏表,请阅读仓库根目录下的 docs/STORYTELLING-WORKBOOK.md。可复用的设计系统在本技能的 reference/design-system.md 中;已实现的开放循环几何结构在 reference/patterns/wall-of-slots/ 中。不需要私有的源视频。

这与 hyperframes-video-beats 不同。那个技能是在说话人头顶叠加卡片。本技能设计视频所关于的内容。

1 · 四大原则

一个持续性世界

视频存在于一个单一空间内,且永不重置。观众已经看到的所有内容仍留在他们离开的位置,新素材被添加进去,而非替换。一个元素一旦被绘制,就永不重绘、移动或重新标记。

本技能中的一切都依赖于此。如果空间不断变化,摄像机无处可去;如果屏幕上没有其他内容,聚光灯毫无意义;在一个会重置的世界里,开放循环无法保持开放。

这个世界还必须值得观众停留,因此在构建任何东西之前决定空间语法,并在整个运行时间内保持它。在参考构建中:从左到右是朝向结果,向上是朝向人类并且是屏幕上唯一温暖的东西,向下是进入一个记录系统。在前两分钟学会这一点的观众,可以在视频剩余部分免费解读。

刻意且仅一次打破语法,以求含义。参考构建中十分钟内唯一的从右到左移动,是在“再次开放率”这个词上,一个已解决的工单反转回队列。它落地时无需言语,因为方向在过去三分钟里一直意味着某种东西。

摄像机即剪辑

每次切换到新图形都会让观众失去方向感。在一个保持不变的空间中移动则不会损失任何东西。推近镜头于是被解读为“更仔细地观察你已经理解的那部分”,而拉远镜头则是工作得到回报的地方——因为之前构建的一切仍然在那里。

在三个高度上工作,并在相邻高度之间移动:

高度展示内容用途
世界整个空间定位、回报、“我们所在之处”
区域正在讨论的子图大部分运行时间
细节一个元素数字、状态变化、决策

从细节跳到世界会让人迷失方向,除非这是一个刻意的回报节拍,在这种情况下,这是最好的可用动作。

需要花费一次重建才能学会的规则:

  • 将取景精确命名为世界窗口,而不是缩放比例。 窗口边界必须落在标签之间。将取景指定为“缩放 0.6”会在框架边缘将单词切成两半。
  • 为相同目的重复使用相同窗口。 如果定位镜头是某个特定窗口,始终使用该确切窗口。几乎相同的取景会被解读为漂移。
  • 持续时间随移动距离变化,而不是使用一个全局预设。
  • 摄像机擦拭和全帧擦拭必须顺序执行,永不重叠。 同时进行会斩断内容。摄像机先动,然后擦拭。
  • 覆盖层在摄像机在其下方移动之前变为不透明。 反过来,部分移动会被暴露并解读为跳切。
  • 没有标签距离框架边缘 60px 以内。 元素可以出血并被视为“世界在继续”;被切断一半的字形会被解读为 bug。通过放置解决,而不是通过遮罩,因为羽化无法捕捉到以约 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:      # 从未绘制:无需照亮
            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 后缀折叠)。一个被照亮的元素下方有不可读的标签正是要修复的缺陷。
  • 一个已经完成的道具通过 MUTED 上限退休到不透明度 0,而不是 0.3。静音到 0.3 会在屏幕留下无法解释的碎屑。生成器规则:在任何稍后开始的 lit() 之前发出 mute(),否则当补间完成时,静音会被覆盖。
  • 不透明度事件必须按时间线顺序发出,否则追踪器会看到过时状态并计算错误目标。使用一个在乱序发出时报错的 seq() 守卫。
  • 每个窗口每个元素只有一个不透明度权威。 两个同时活动的补间驱动同一元素的不透明度到不同值,在独立章节中能平滑渲染,但在组装后的主视频中会以约 10Hz 的频率闪烁,因为获胜的补间每帧交替。参考构建在每个停靠点都存在此缺陷。当 lit() 这样的扫描与显式的变亮或静音重叠时,较晚开始的补间成为唯一驱动者,并且扫描跳过这些 ID(lit(..., skip=(...)))。通过检查来把关:在每一个过渡窗口中扫描组装后的渲染,寻找一帧的亮度跳变(参考构建中的 qa/v4/flicker/qa-flicker.mjs)。

开放循环是空间性的

绝不说“我们稍后再回到这一点”。在世界中留下一些视觉上不完整的东西,然后再回来处理它。一个观众能看到的承诺是一个他们能感到悬而未决的承诺。

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

  1. 在钩子中植入它,在空间中,在做出承诺的那句台词上。
  2. 在每个边界处重新展示它。 任何章节交接都是边界。重新展示大约花费两秒钟,是保持观看的机制;跳过它就是回报最终得不到任何回报的原因。
  3. 使其可视地推进。 观众必须看到不完整部分在缩小。
  4. 在你开始时的图像上关闭。

根据脚本选择形状:

脚本形状世界不完整的部分
N 个并列项目脊柱上的 N 个插槽空插槽(参见 reference/patterns/wall-of-slots/)
一个过程,深度完整的管线,已布置一个断裂或缺失的链接
层级或等级向上构建的堆栈堆栈顶部是一个幻影
对比共享轴上的两列一列为空,或未填写的记分卡
新闻或公告时间线或景观地图右侧,未来,是空白的
教程或跟着做完整的架构,幻影显示每个尚未构建的节点

将项目放入其插槽是一个实时的摄像机运动,约 1.4 秒,绝不剪切到预先制作的已填充状态图片。观众看着他们刚刚学到的内容变成卡片。如果视频有数字或计数器,在同一运动中滚动它,作为里程表,数字使用相同的开始、持续时间和缓动,否则它们会在滚动过程中合并成一个带。

计数器需要一个名称,而不仅仅是一个数字。 角落的数字告诉观众他们在序列中的位置,但未告诉他们当前项目是什么;九分钟时,“03”不传达任何信息。将数字与一个 1-2 个词的标签配对,命名当前项目(支持,语音 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 是手动维护的,因此取景更改在那里进行。
  • 共享模块保持共享。 任何定义共享几何的内容都被每个章节导入。如果章节由并行代理构建,禁止它们触及共享模块;分叉的几何会静默地破坏每一个交接。
  • 在组装前为 SVG 定义添加命名空间。 每个章节定义自己的 gEdge、shadow、edgeFade。在一个已组装的 DOM 中,url(#id) 解析为文档顺序中的第一个匹配,因此一旦较早的章节卸载,之后的每个图形都绘制空内容。在参考构建中的代价:35 秒的空屏,但每一项检查都是绿色。只有查看组装后的渲染才发现了它。
  • 根据单词级转录本,将所有时间对齐到单词开始,在锚定词之前 0.15-0.25 秒 进入。绝不将章节均匀划分成节拍。
  • 审计间隙。 任何超过约 1.5 秒且无变化发生的延伸都是死屏;让生成器打印它们。
  • 在剪辑中留下气口。 激进的暂停修剪会在句子边界产生接近零的间隙,客户听起来像“口吃”和跳切。根据说话者自己的标准进行校准:标记出句子边界间隙比其中位数紧约 10 倍的连接点,并通过插入 4-8 帧气口来修复,绝不触及单词。气口是取自轨道真实房间音调的捐赠切片,带有 10ms 淡入淡出,绝不使用 anullsrc:在 -50dBFS 底噪之上的数字静音是可闻的中断。视频保持静止;在句子之间,说话人的头几乎不动,保持 4-8 帧是不可见的。仅插入更改会确定性地移动转录本,因此无需重新转录。插入的边缘必须尊重语音包络:以 1ms 将捐赠音调邻接单词尾部……

……

[已截断以用于翻译]

相关技能