Communitygithub.com

daoge96/dsh-skills

通过代码生成视频成品——一个纯时间→帧渲染器加上经过验证的渲染/编码/复用管线(动态图形、数据动画、解说视频、展示片、生成式循环、音频响应作品)。当交付物是视频文件、循环动画、需要与音频复用的帧序列,或者需要验证时长/帧率/容器规格、循环接缝、“永不冻结”底线、接触页审查、响度/真峰值目标或渲染吞吐量时使用。在编写第一行绘图代码前加载。

dsh-skills 是什么?

该技能定义了一种以代码为核心的视频生产工作流,将视频视为纯函数 `render(t)` 加上可分阶段、可断言的管线。它强调确定性(使用种子PRNG、数据URI嵌入资源)和可观测性,通过一系列早期探测(捕获完整性、成本、运动序列)来暴露错误。该技能支持多种平台(如Claude Code、Cursor等),并提供 `av_audit.mjs` 和 `mux_normalize.mjs` 两个零依赖脚本,用于容器/运动/循环/响度检查以及音频复用和归一化。其核心哲学是:冻结接口并哈希化、通过断言编写规范而非描述、确保审查路径与交付路径完全一致,并严格区分精确与近似声明。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/daoge96/dsh-skills/tree/HEAD/video-production

在你喜欢的 AI 中提问

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

文档

用代码生产视频

将视频视为 一个纯函数 render(t) 加上一个可分阶段、可断言的管线。此类任务中几乎所有的失败模式都是无声地传播的单位/符号/通道/度量错误——因此下面的工作流旨在让每一种错误都变得可观测。

0. 在绘制任何内容之前冻结契约

  1. 单一时间源。 一切都在 render(t) 内部;帧与时间的映射(t = frame/fps)是整个公共 API。没有 CSS 动画、没有定时器、没有帧到帧的状态。结果是:帧可并行化、可恢复、可比对,并且错误可定位到一个时间范围。
  2. 确定性。 使用种子 PRNG(hash(i)/mulberry32),绝不使用 Math.random;绝不使用 Date.now;将字体和纹理作为数据 URI 嵌入,这样没有网络/字体回退能在运行中改变像素。
  3. 将规范编写为断言,而不是散文。 时长、帧率、分辨率、编解码器、像素格式、响度、真峰值、安全区域/边距、禁用技术、文件路径、CLI 标志、退出码、JSON 输出结构。如果简报中有一个数字,它必须最终出现在一项检查中。
  4. 提前决定接缝策略——一次性 / 循环 / 拼接片段。对于循环:每个振荡器是 sin(2π·k·t/D),其中 k 为整数;画面收敛回自己的第一个状态(而不是“看起来相似”);事件表以及屏幕上的计数器/标签在最终过渡中重置;验证 render(0) 与 render(D) 的渲染结果。
  5. 每帧预算。 在构建内容之前测量 render(t)(一个 1080p 画布绘制需要 2–30 毫秒;3 个子帧 × 5400 帧会成倍增加)。记录预算并保持它。
  6. 冻结接口,然后哈希化它。 画布大小、页面/API 表面、工作线程 CLI、输出路径。所有质量控制都绑定到该修订版本的哈希——针对过期哈希进行的质量控制渲染是无用的。
  7. 记录有意偏差。 现实与简报不符的每一处(干净线条上的网格抖动、小于声明最小值的微字体、超出声明范围的弹簧率)都进入一个带有理由的简短列表,以便审阅者可以判断而非发现。

1. 第一天的三个探测

探测断言原因
捕获完整性精确像素,alpha == 255,颜色范围,首/末帧存在半透明累积、范围/色彩空间错误会无声地毁掉整个视频
成本render(t) 每场景毫秒分布,内存架构变更现在便宜,以后昂贵
运动整个时长内每帧差异序列 + 最长冻结段能立即显示死时间段

来自真实失败的经验法则:

  • 白色合成陷阱。 通过将 alpha 合成到白色上的查看器来审阅帧会隐藏半透明度;编码器则合成到黑色上。让审阅路径的合成方式与交付路径完全相同,并比较两个路径间的像素差异。
  • 了解度量能看见什么。 经过 12 倍下采样后,细线的亚像素运动会改变平均绝对差异约 0.03/255,而整帧亮度变化会使其移动约 1.5/255。如果接受度量是下采样后的均值,那么最便宜且真正有效的杠杆是全局值通道(例如,在节拍率上叠加一个 2 Hz ±3% 的亮度脉冲),而不是更大的抖动。
  • 在验证资产之前先验证度量。 当检查失败时,首先转储原始信号(1 毫秒的包络、像素行轮廓、帧序列)。一半的“资产错误”情况实际上是检测器的问题。
  • 让检测器自我描述。 建模并补偿系统性偏差(滤波器群延迟、因果分析窗口延迟);优先选择最接近事件的候选者而不是最响亮的一个;永远不要调整阈值直到它通过。
  • 精确声明与近似声明。 “render(0) ≡ render(D),PSNR ∞”是一个证明;“第一个与最后一个编码帧相差 2/255(一帧的运动)”是一个观察结果。绝不要在报告中模糊两者。

捆绑:scripts/av_audit.mjs 实现了这部分中容器/运动/循环/响度/接触页的一半功能(仅依赖 ffmpeg,无 npm 依赖)。

2. 审阅循环是一项特性,而不是开销

  • 网格化:数百张静止帧→十几张接触页,一次审查通过。
  • 嵌入引导:安全区域框、中心十字准线、时间码、事件 ID。审阅者不应在脑中记住布局。
  • 按事件采样,而非固定间隔:每个预期事件上取一帧,每个移动过程中间取一帧。
  • 最仔细地查看接缝:场景过渡、循环包裹、片段边界、首帧和末帧。
  • 隔离并放大可疑元素到空白画布上,放大 4–6 倍;大多数错误在全帧中不可见。
  • 工件是可丢弃的:一条命令即可重新生成;永远不要手动修补审阅帧。
  • 保留问题列表(杂乱/不协调/重叠/超出安全区域/不可读/冻结),并在每次修复循环后重新审查。

3. 运动与循环工艺

  • 环境 ≠ 动作。 每个场景都需要一个与动作频率不同的连续通道(漂移、波浪、空闲旋转、值脉冲),其零交叉点与节拍对齐,以便动作仍然干净地落地。这满足了“从未冻结”的要求。
  • 一种缓动系列。 临界阻尼弹簧 1-(1+x)e^-x(永不超调)用于移动;指数缓出/入用于擦除、按压、退出。确保着陆与事件同时发生:开始 = 事件 − 持续时间,并归一化使得在事件发生时进度恰好为 1。
  • 两处运动模糊:在帧函数内部(2–4 个快门样本,使用运行平均——alpha = 1/(k+1)——最终完全不透明度),以及编码器侧的时间混合。用一个索引编码的定标(输入帧的像素编码帧号并回读哪些索引被平均)证明滤镜窗口语义,绝不依赖文档。
  • 通过构造保持连续性。 跨场景携带一个几何/状态模型并进行变换(变形、材质替换、硬边擦除冲刷、扫描线),而不是剪切或溶解。
  • 保持长度的变形:通过角度/弧长参数化形状,使混合时生长而非缩放。
  • 默认禁用列表(除非要求,否则删除):粒子、发光、镜头眩光、摄像机抖动、RGB 分裂、交叉淡化、通用渐变、弹跳超调。

4. 渲染与编码

  • 格式 vs 目标:首先测量吞吐量。无损 PNG 帧为多 MB,会压垮管道;高质量 JPEG 速度大约快 1.5 倍。一次决定,然后保持。
  • 使用管道,而不是假脱机:将帧输入 ffmpeg 的标准输入(-f image2pipe -framerate <fps*sub> -vcodec png -i -)。使用 tmix 混合,选择组的最后一帧,重新计时,使用 -frames:v <n> 进行裁剪。
  • 按成本并行化,而非帧数。测量每场景毫秒数,然后划分为大致相等的时间块;统一的帧计数会使最慢的工作线程决定挂钟时间。
  • 片段必须可拼接安全:每端重复 2 个边界帧,相同的编码器参数和时间基,使用 ffprobe 验证帧数/时长,然后使用 -c copy 拼接。
  • 将管线分阶段,使得一次失败仅损失一个阶段:渲染 → 混合 → 编码 → 音频 → 复用 → 测量;每个阶段写入一个文件。
  • 在阶段之间保留无损视频母版(所有地方使用 -c copy),并且最后进行响度处理。
  • 在依赖未知工具链之前先探测它:滤镜/编码器列表、浏览器可执行文件、版本;允许 $FFMPEG/$FFPROBE 覆盖;优先使用固定的本地二进制文件而非 PATH 猜测。浏览器附带的精简版“媒体” ffmpeg 通常缺少 x264/tmix/loudnorm。
  • 通过文件描述符捕获子进程输出,而不是管道。 在受限沙箱内,spawn/execSync 配合 stdio: 'pipe' 可能会因 EPERM 失败,而相同的二进制文件从 shell 运行则正常。改为传递打开的文件句柄:spawnSync(cmd, a, { stdio: ['ignore', fdOut, fdErr] }),然后读取文件——对于纯存在性/版本探测,使用 stdio: 'ignore'。将标准输出和标准错误路由到单独的文件,以便二进制帧数据不会与日志文本交织。
  • 完成后从源代码进行端到端重建,以确保交付的文件不是幸运缓存。

5. 音频与复用

  • 与画面相同的时间基和相同的确定性(离线渲染、种子、无实时依赖)。
  • 一个提示表({t, name})作为每个可听/可见事件的唯一真相来源;音效位于自己的总线上,声音比音乐轻。
  • 使用两遍 loudnorm 进行归一化(print_format=json → measured_* → 第二遍使用 linear=true),然后使用独立的第三测量验证;断言综合响度在 ±0.5 LU 以内,真峰值 ≤ 目标。
  • 循环:将尾部(约 40 毫秒)淡出到精确零值,第一个样本不发出咔嗒声;测量打击乐命中对齐到网格的程度并报告。
  • 使用 -c:v copy -c:a aac -b:a <spec> 复用,然后使用 ffprobe 检查容器作为断言,而非查看。
  • -b:a Nk 对于 ffmpeg 的原生 AAC 编码器来说是目标,而非下限(在安静素材上,针对 320k 请求测得约 180–250 kbps;-aac_coder twoloop 有帮助)。读取声明的 bit_rate 并报告实测平均值,而不是重复请求的数字,并在规范要求比特率时明确说明。

捆绑:scripts/mux_normalize.mjs。

6. 保持绘制层廉价且确定

  • 缓存所有时间不变的内容:预烘的背景、文本遮罩、图案、Path2D。缓存键包含每一个可能改变像素的参数。
  • 画布池必须根据源画布尺寸进行大小设置,而非逻辑内容尺寸——否则 drawImage 会无声地拉伸或裁剪(这导致了裁剪/损坏的文本)。
  • 避免在帧循环中使用 shadowBlur/filter;优先使用几何。
  • 内存:一个 1080p 画布约 8 MB;限制池的大小。
  • 记住子帧计数会线性增加帧预算。

7. 协作

  • 分开作者与验证者。 验证者拥有质量控制脚本和判定交付物不合格的权力,并独立检查作者未检查的维度(alpha、与页面的保真度、响度、循环闭合)。这能捕获作者视而不见的错误类型。
  • 不重叠的写入范围 + 冻结的接口,以便并行工作不会冲突;哈希化修订版本并在任何更改后重新运行质量控制。
  • 失败要响亮:非零退出、每个声明一行 PASS/FAIL、机器读取的部分使用 JSON、无静默回退。

8. 反模式

  1. 通过白色合成的审阅图像判断颜色。
  2. 编辑资产以满足一个从未表征过的度量。
  3. 调整检测器的阈值而不是修复其模型。
  4. 为了回答一个 20 秒的页面侧探测就能回答的问题而重新运行完整渲染。
  5. 在成本差异很大的场景上使用均匀的帧计数分块。
  6. 审阅路径与交付路径不同(比例、颜色范围、合成)。
  7. “看起来还行”而不是一个断言;失败但退出码为 0。
  8. 使用会损坏非 ASCII 的工具进行文本/资产手术(编辑后验证编码)。
  9. 手动修复审阅帧而不是修复源。
  10. 用交叉淡化掩盖状态不连续性。

9. 检查清单

预飞行——规范 → 断言;render(t) 签名冻结;接缝策略 + 循环代数;资产嵌入;三个探测存在;每帧预算已设定;FFMPEG/FFPROBE 已解析并探测能力。

飞行中——每个场景后:成本探测、运动序列、事件采样审阅网格;问题列表已关闭;语法/类型检查以及对编辑过的源进行非 ASCII 检查;哈希化修订版本。

交付前——从源代码重建;完整渲染(按成本加权、边界帧、拼接已验证);响度两遍 + 第三遍验证;独立测量脚本 → PASS/FAIL;明确报告精确与近似声明;删除临时脚本/截图,并记录每个内容的一条命令重新生成方式。

完成定义——容器元数据精确;接缝行为已验证;冻结段限制已满足;响度/真峰值已满足;屏幕上的文本与简报逐字匹配;一条命令从源代码重建;针对冻结哈希的所有质量控制通过。

10. 捆绑脚本

两者都是单文件、零依赖(仅需要 ffmpeg/ffprobe),从 $FFMPEG/$FFPROBE → PATH → 公共位置解析工具,每个声明打印一行 PASS/FAIL,使用 --json 输出 JSON,并在失败时以非零退出码退出。它们从该技能自身的路径解析其目录。

# QC 一个完成的文件:容器与期望对比、冻结段限制、循环接缝、
# 响度/真峰值、可选的用于人工审查的接触页
node av_audit.mjs film.mp4 --expect-duration 30 --expect-fps 60 --expect-size 1920x1080 \
     --static-limit 0.5 --sheets ./sheets        # exit 0 = 所有检查通过

# 将 WAV 归一化到目标值并复用到一个已编码的视频上(视频流复制),
# 然后通过第三独立的测量验证
node mux_normalize.mjs silent.mp4 score.wav film.mp4 --lufs -14 --tp -1 --abr 320k

av_audit.mjs 有意使用低分辨率(160×90)的 MAD 序列:它能检测整帧值变化和块移动,而不是细线的亚像素运动——将其与 §1 中的度量敏感性规则配对使用。对于循环,将 first_vs_last_psnr_db 视为关于一帧运动的观察结果,并通过比较渲染器自身的两次渲染来单独证明精确性。

一行总结——成功取决于三件事,没有一件是绘图技巧:时间函数是纯且可验证的,度量在被优化之前就被理解,以及审阅路径与交付路径是相同的路径。

相关技能