Wjs Overlaying Video

AI生成封面、HTML/CSS字幕同步SRT,支持动画与CTA叠加的视频后期处理。

已扫描
适合谁
视频创作者、内容运营人员
不适合谁
无视频剪辑基础的新手、需直接剪辑视频的用户
国内可用性
需网络配置。可能需要网络配置或第三方服务可访问。
安装难度
新手友好(★☆☆)。基于终端操作、依赖、API Key 和本地环境要求的初步判断。

安装与下载

openclaw skills install @jianshuo/wjs-overlaying-video

Skill 说明

命令、参数、文件名以原文为准

wjs-overlaying-video

视频剪辑后期处理:封面、字幕、插图、行动号召(CTA)、自定义动态图形——所有内容均在一个 HyperFrames 项目中完成合成,并通过一次最终编码输出。无需多次解码/重新编码(每次解码/重编码都会降低画质并消耗时间)。

适用场景

  • **在 /wjs-segmenting-video 之后使用** —— 分段技能会提供裁剪后的视频片段和每段对应的 SRT 字幕文件;此技能将它们转换为可直接上传的 MP4 格式,包含封面、字幕、插图和 CTA。
  • 用户已有一段完成的视频,希望添加动态图形元素:开场钩子、关键语句强调、结尾标语、章节卡片、以及由 AI 生成的首帧封面。
  • 用户希望在视频中实现高质量的 HTML/CSS 字幕效果(如逐字高亮、自定义字体、大号描边文字、支持按字幕条目跳转)。
  • 用户希望在特定关键节点添加插图叠加层:示意图、大字号强调、流程图等。

不建议使用的情况:

  • 将一段长视频拆分为多个片段 → 请使用 /wjs-segmenting-video
  • 生成原始 SRT 字幕文件 → 请使用 /wjs-transcribing-audio(如需其他语言,请再配合 /wjs-translating-subtitles)。
  • 完整的 HyperFrames 制作流程,且源素材并非固定视频 → 请直接使用 hyperframes 工具。
  • 微信视频号 / 抖音 上传(这些平台无公开 API 支持)→ 本技能仅生成 MP4 文件,上传操作需手动完成。

本技能的功能范围 —— 与非功能范围

所有叠加在视频片段之上的内容:封面、字幕、章节卡、插图、CTA视频切割或裁剪(这是 /wjs-segmenting-video + /wjs-reframing-video 的职责)
每个片段对应一个 HyperFrames 项目 = 一次最终编码多次解码/重编码的级联过程
cover 是输出视频的实际首帧(平台自动提取为缩略图)用户单独上传一张独立的缩略图文件
字幕为 HTML/CSS 实现 —— 使用 -webkit-text-stroke 确保白字在任意背景上清晰可读旧式的 libass 内嵌字幕(已弃用)
插图支持可复用的 stack / hammer 模板 + 自定义扩展接口每个插图都需独立编写一套 HTML/CSS,无法复用
AI 生成的封面根据目标输出比例自动调整尺寸(竖屏为 1024×1792,横屏为 1536×1024)默认单一 1024×1536 尺寸,上传至平台后可能被拉伸、裁切或出现黑边

处理流程

clip.mp4 + clip.zh-CN.burn.srt   (来自 /wjs-segmenting-video 的输出)
   ↓
1. (可选)通过 gpt-image-2 生成 AI 封面
   make_cover.py --segments S.json --out output/ --size 1024x1792
   cover_NN_slug.png

2. 为每个片段搭建 HyperFrames 项目
   hf_clip_NN/1080/{index.html, clip.mp4, cover.png, captions.json}

3. 合成:封面场景 + 主视频 + 字幕轨道 + 章节卡片
            + 在关键节点插入 1-2 个插图 + CTA 场景

4. npm run check (代码检查 + 验证 + 可视化预览)
   npm run render → 输出可上传的 MP4

一个 2 分钟的竖屏 1080×1920 视频合成,可在 M 系列 Mac 上约 2-3 分钟内完成渲染。

标准叠加类型(六大构建模块)

每个视频片段的最终合成均由这些元素的组合构成。智能体将根据片段特性自动选择合适的组合,通常用于播客精华片段时启用全部 6 种,而单个注释叠加则可能仅使用 1-2 种。

1. cover —— 全幅 AI 生成图像作为首帧

封面即为输出视频的第一帧(无动画、无缩放),因此平台若自动提取首帧作为缩略图,将默认显示设计好的封面。**务必通过 ffmpeg -ss 0 -vframes 1 验证**:第 0 帧不能是纯黑,否则平台缩略图会显示为黑色。

HTML:

<div id="cover" class="clip" data-start="0" data-duration="1.6"
     data-track-index="1" data-layout-allow-overflow>
  <img src="cover.png" alt="" data-layout-allow-overflow />
</div>

CSS:

#cover { position: absolute; inset: 0; background: #0c0d10; overflow: hidden; }
#cover img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

生成方式: 使用 /wjs-segmenting-video/scripts/make_cover.py

(封装了 gpt-image-2 images edit,以中间帧作为参考图像):

# 生成竖屏 1080×1920 输出(适用于视频号 / 抖音):
make_cover.py --segments S.json --out output/ --size 1024x1792 [--single N]

# 生成横屏 1920×1080 输出(适用于 YouTube / B站):
make_cover.py --segments S.json --out output/ --size 1536x1024

输出尺寸必须与目标视频帧率一致。 若使用 --size 1024x1536(2:3,默认值),在 9:16 输出中会出现黑边或裁切。**竖屏输出务必指定 1024x1792**。封面图像的宽高比决定了观众看到的完整画面比例,不匹配会导致视觉异常。如遇失败,可使用 --single N 单独重试;Codex 提供商可能出现临时失败。

Codex 认证要求:脚本通过 gpt-image-2-skill 调用 codex CLI。若缺少 ~/.codex/auth.json 文件,脚本将报错。请参考 gpt-image-2-skill 文档进行配置。

2. caption —— 与 SRT 同步的描边式 HTML/CSS 字幕

采用白色文字搭配粗黑描边,无气泡背景,垂直居中于固定区域(确保单行与双行字幕不会导致视觉中心上下跳动)。

HTML:

<div id="caption" class="clip" data-start="{body_start}"
     data-duration="{body_dur}" data-track-index="4"></div>

CSS(竖屏 1080×1920):

#caption {
  position: absolute; left: 0; right: 0; bottom: 240px;
  height: 240px; z-index: 10; overflow: visible;
}
#caption .bubble {
  position: absolute; top: 50%; left: 50%;
  display: inline-block;
  padding: 0 24px;
  font-size: 56px; line-height: 1.18; font-weight: 900;
  color: #ffffff; max-width: 1020px; text-align: center;
  -webkit-text-stroke: 5px #000;
  paint-order: stroke fill;
  text-shadow: 0 6px 12px rgba(0,0,0,0.55), 0 0 4px rgba(0,0,0,0.6);
  letter-spacing: 0.01em;
}

Skill: Wjs Overlaying Video

Version: 0.1.0

Chunk: 2/4

JS(每条字幕一个气泡,使用 GSAP 实现淡入淡出,所有气泡居中于容器中心点):

// 字幕数据以内联 JSON 形式加载。每条字幕的开始/结束时间均加上片头时长(例如 1.5 秒),使时间轴与合成时间线对齐(而非以内容自身 t=0 为基准)。
const captionEl = document.getElementById("caption");
const groups = JSON.parse(document.getElementById("captions-data").textContent);
const bubbles = groups.map((g, i) => {
  const b = document.createElement("span");
  b.className = "bubble"; b.id = "cap-" + i;
  b.textContent = g.text; b.style.opacity = "0";
  captionEl.appendChild(b);
  return b;
});
// 使用 GSAP 的 xPercent/yPercent 实现居中(若使用 CSS transform,动画过程中会被覆盖)。
gsap.set(bubbles, { xPercent: -50, yPercent: -50 });
groups.forEach((g, i) => {
  const el = bubbles[i];
  tl.fromTo(el, { opacity: 0, y: 12 }, { opacity: 1, y: 0, duration: 0.18, ease: "power2.out" }, g.start);
  const exitStart = Math.max(g.start + 0.18, g.end - 0.12);
  tl.to(el, { opacity: 0, duration: 0.12, ease: "power2.in" }, exitStart);
  tl.set(el, { opacity: 0 }, g.end);
});

源 SRT — 切片并偏移后内联:

从分段结果中获取 clip_NN.zh-CN.burn.srt,解析每条字幕,将片头时长加到每个 start/end 时间上,然后以 JSON 格式内联至 <script id="captions-data" type="application/json"> 块中。

边距 / 位置说明:

  • 纵向(1080×1920):设置 bottom: 240px 可避免遮挡 视频号/抖音 底部 UI 层(如点赞、评论、分享按钮)。
  • 横向(1920×1080):建议设置 bottom: 100pxfont-size: 48px,并使用 -webkit-text-stroke: 4px 作为合理默认值。

字幕长度限制:

当单条字幕在 1080 宽度下超过约 18 个中文字符,且字号为 56px 时,会自动换行至两行,造成排版不美观。此问题需上游控制——/wjs-translating-subtitles 应通过词间距拆分 + 标点拆分的方式,将字幕长度控制在约 18 字以内。若收到更长的字幕,请降低 font-size 至 48px,或接受换行效果。

3. chapter — 左上角章节标签(4 秒渐显后淡出)

用于标识当前片段的微小徽章。在视频开始时出现,几秒后逐渐淡出,避免干扰整体视觉表达。

HTML:

<div id="chapter" class="clip" data-start="{body_start}"
     data-duration="{body_dur}" data-track-index="3">
  <span class="dot"></span>
  <span class="text">第一段 · 自然语言才是新代码</span>
</div>

CSS:

#chapter {
  position: absolute; top: 80px; left: 60px; z-index: 9;
  display: inline-flex; align-items: center; gap: 12px;
  padding: 12px 20px;
  background: rgba(12,13,16,0.78);
  border: 1px solid rgba(199,150,85,0.4);
  border-radius: 999px;
}
#chapter .dot { width: 10px; height: 10px; border-radius: 999px; background: #e8b063; }
#chapter .text {
  font-size: 24px; color: #f4f4f5; letter-spacing: 0.04em; font-weight: 600;
}

GSAP 动画:

tl.from("#chapter", { x: -40, opacity: 0, duration: 0.5, ease: "expo.out" }, body_start + 0.4);
tl.to("#chapter", { opacity: 0, duration: 0.4, ease: "power2.in" }, body_start + 4.0);

4. stack 插图 — 右上角垂直列表卡片

位于右上角的深色卡片,展示一组项目(如语言层级、工作流程步骤、等级划分)。其中一项可设为琥珀色高亮,突出当前讲解的重点。

适用场景: 在演讲者解释层级结构或列表内容时使用。卡片持续显示 8–50 秒。

HTML:

<div id="ill-stack" class="clip" data-start="{start}" data-duration="{dur}" data-track-index="5">
  <div class="ill-card">
    <div class="ill-card-label">我们写的层级</div>
    <div class="ill-row"><span class="ill-tag accent">自然语言</span></div>
    <div class="ill-row"><span class="ill-tag">Python</span></div>
    <div class="ill-row"><span class="ill-tag">C</span></div>
    <div class="ill-row"><span class="ill-tag">Assembly</span></div>
  </div>
</div>

CSS:(详见 references/illustration_patterns.md,请完整复制)

GSAP 动画 — 从右侧滑入 + 行间错落入场:

tl.fromTo("#ill-stack", { x: 360, opacity: 0 }, { x: 0, opacity: 1, duration: 0.6, ease: "expo.out" }, start + 0.2);
tl.from("#ill-stack .ill-row", { y: 20, opacity: 0, duration: 0.4, stagger: 0.12, ease: "power2.out" }, start + 0.4);
tl.to("#ill-stack", { x: 360, opacity: 0, duration: 0.5, ease: "power2.in" }, end - 0.5);

5. hammer 插图 — 中心大标题/公式叠加层

一个占据中心的大尺寸文本或公式,用于“强调”核心观点。适用于视频中最值得引用的瞬间(如:“LLM = 编译器”,“Token = 新 GDP”,“AI ≠ 更快的轿子”)。显示时长为 4–8 秒。

HTML:

<div id="ill-hammer" class="clip" data-start="{start}" data-duration="{dur}" data-track-index="6">
  <div class="ill-h-content">
    <div class="ill-h-eq">
      <span class="ill-h-left">LLM</span>
      <span class="ill-h-equals">=</span>
      <span class="ill-h-right">新编译器</span>
    </div>
    <div class="ill-h-foot">自然语言 → Python → 汇编</div>
  </div>
</div>

GSAP 动画 — 缩放弹入 + 分块错落入场 + 缩放淡出:

tl.fromTo("#ill-hammer", { scale: 0.85, opacity: 0 },
  { scale: 1.0, opacity: 1, duration: 0.45, ease: "back.out(1.6)" }, start);
tl.from("#ill-hammer .ill-h-left", { x: -40, opacity: 0, duration: 0.4, ease: "expo.out" }, start + 0.2);
tl.from("#ill-hammer .ill-h-equals", { scale: 0, opacity: 0, duration: 0.4, ease: "back.out(2)" }, start + 0.4);
tl.from("#ill-hammer .ill-h-right", { x: 40, opacity: 0, duration: 0.4, ease: "expo.out" }, start + 0.6);
tl.from("#ill-hammer .ill-h-foot", { y: 20, opacity: 0, duration: 0.4, ease: "power2.out" }, start + 0.8);
tl.to("#ill-hammer", { scale: 1.05, opacity: 0, duration: 0.45, ease: "power2.in" }, end - 0.45);

(详见 references/illustration_patterns.md 获取完整标准 CSS)

6. cta — 结尾卡片,包含频道引导信息

技能:Wjs 叠加视频

版本:0.1.0

分块:3/4

用于最后 3 秒的品牌化片尾。请使用 王建硕 作为频道名称(根据全局指令)——切勿在 CTA 区域放入嘉宾姓名。

HTML:

<div id="cta" class="clip" data-start="{cta_start}" data-duration="3.24" data-track-index="1">
  <div class="cta-line-1">关注王建硕</div>
  <div class="arrow">↓</div>
  <div class="cta-line-2">微信公众号 · 视频号</div>
  <div class="cta-foot">AI 炼金术 · 持续更新</div>
</div>

CSS / GSAP: 参见 references/illustration_patterns.md

旧版类型(适用于单个视频的临时叠加)

spec.json + scaffold.py 工作流也支持这些较老的叠加类型——当你只想为单个已有视频添加装饰性元素,而无需走完整的后期制作流程时非常有用:

  • **quote** —— 全宽动态文字,顶部或底部渐变。适合开场钩子和关键语句强调。
  • **slogan** —— quote 的别名,position: bottom,字体更大。适合结尾标语。
  • **callout** —— 角落中的小注释面板。适合章节标签、下三分之一信息、“如在视频中所示”类备注。
  • **custom** —— 逃生通道。Claude 将在 overlays/<name>.html 片段文件中编写叠加的 HTML/CSS/GSAP 内容。参见 references/custom_overlay_recipes.md

工作流 A —— 分段后预设(最常见)

当你直接从 /wjs-segmenting-video 出发,并希望对每个片段应用标准的“封面 + 字幕 + 章节 + 插图 + CTA”处理时使用。

步骤 1 —— 生成合适比例的 AI 封面

# 生成竖屏 9:16 输出(视频号 / 抖音):
python3 ~/.claude/skills/wjs-segmenting-video/scripts/make_cover.py \
    --segments segments.json --out output/ --size 1024x1792 --single 1
# 验证第 1 个片段的封面;然后批量处理:
python3 ~/.claude/skills/wjs-segmenting-video/scripts/make_cover.py \
    --segments segments.json --out output/ --size 1024x1792

步骤 2 —— 为每个片段搭建 HyperFrames 项目

创建 hf_clip_NN/1080/ 目录,包含以下文件:

  • index.html —— 组合页面(来自模板;参见 references/post_segmentation_template.html
  • clip.mp4 —— 从 output/clip_NN_slug.mp4 复制而来
  • cover.png —— 从 output/cover_NN_slug.png 复制而来
  • captions.json —— 由 output/clip_NN_slug.zh-CN.burn.srt 生成,且**所有字幕条目的起止时间均向后偏移 +cover_duration**(使字幕与组合时间线对齐,而非原始视频的时间戳)

references/build_hf_clips.py 脚本可一次性完成所有片段的构建。它读取 segments.json + ILLUSTRATIONS 字典(参见步骤 3)+ 模板,输出 5 个可直接渲染的项目。

步骤 3 —— 定义每个片段的插图

为每个片段识别 1–2 个关键钩子时刻,并选择 stackhammer 类型:

ILLUSTRATIONS = {
    1: [
        # 开场时展示语言层级的堆叠卡片
        {"key": "stack", "pattern": "stack", "body_start": 0.3, "body_end": 9.0,
         "label": "我们写的层级",
         "rows": [
             {"text": "自然语言", "accent": True},
             {"text": "Python",   "accent": False},
             {"text": "C",        "accent": False},
             {"text": "Assembly", "accent": False},
         ]},
        # 最具引用价值的时刻使用锤子动画
        {"key": "hammer", "pattern": "hammer", "body_start": 10.8, "body_end": 14.6,
         "left": "LLM", "equals": "=", "right": "新编译器",
         "foot": "自然语言 → Python → 汇编"},
    ],
    # ... 其他片段 2–5
}

时间戳为视频内容相对时间(覆盖场景持续时间之后);构建脚本会在生成 GSAP 位置时自动加上覆盖偏移量。

步骤 4 —— 构建并渲染

python3 references/build_hf_clips.py    # 批量搭建所有项目
for n in 01 02 03 04 05; do
  cd "hf_clip_$n/1080"
  npx hyperframes lint
  npx hyperframes validate
  npx hyperframes render
  cd ../..
done

一个 2 分 30 秒的片段约需 3 分钟渲染完成。输出路径:hf_clip_NN/1080/renders/*.mp4

工作流 B —— 单个视频的自定义叠加(旧版 spec.json)

当你拥有一个已有视频,并希望为其添加少量临时叠加元素(标题卡、注释、下三分之一信息)时使用。

spec.json 格式

{
  "source_video": "../path/to/source.mp4",
  "duration": 135.4,
  "size": "1920x1080",
  "name": "clip_01_animated",
  "overlays": [
    {"id": "o1", "type": "quote", "start": 8.0, "duration": 6.0,
     "position": "top", "lines": ["代码不存在错误", "只存在意图错配"],
     "accent": [false, true]},
    {"id": "o2", "type": "callout", "start": 30.0, "duration": 5.0,
     "anchor": "top-right", "text": "FRP 概念"},
    {"id": "o3", "type": "slogan", "start": 122.0, "duration": 13.4,
     "lines": ["改 prompt", "不改 AI 生成的代码"], "accent": [false, true]}
  ]
}
字段必填说明
source_video源视频 MP4 的路径。将在项目中以 source.mp4 的形式链接。
duration总时长(秒),需与源视频一致。
sizeWIDTHxHEIGHT(默认 1920x1080)。
overlays[].type类型:quoteslogancalloutcustom
overlays[].start开始时间(秒)。
overlays[].duration在屏幕上显示的持续时间(秒)。

搭建并渲染

python3 ~/.claude/skills/wjs-overlaying-video/scripts/scaffold.py spec.json
cd <name> && npm run check && npm run render

输出检查清单

在认为一个片段已完成前,请确认以下事项:

  • [ ] 第 0 帧为封面(非黑色)—— 使用 ffmpeg -ss 0 -vframes 1 out.mp4 检查
  • [ ] 字幕与音频同步(用播放器随机检查几秒)
  • [ ] 所有插图的进入和退出时机与语音内容相匹配
  • [ ] CTA 渲染正确(显示“关注王建硕”,而非嘉宾姓名)
  • [ ] npx hyperframes lintnpx hyperframes validate 均通过
  • [ ] npx hyperframes inspect 显示无布局溢出
  • [ ] 总时长等于源片段时长 + 覆盖时长 + CTA 时长

常见错误

  • 封面比例 ≠ 输出比例。 1024x1536(默认 make_cover.py 尺寸)为 2:3 比例,在 9:16 输出中会出现黑边或被裁切。竖屏输出时,请始终使用 --size 1024x1792
  • 字幕对齐随行数变化。 使用固定高度容器,通过 CENTERtranslate(-50%, -50%))锚定,确保单行与双行字幕共享相同的视觉中线。避免从底部锚定(会导致内容向上增长)。
  • GSAP 会覆盖 CSS 的 transform 居中设置。 若在 CSS 中设置 transform: translate(-50%, -50%),后续使用 GSAP 动画 y 时会重置 transform,导致居中失效。应改用 gsap.set(el, { xPercent: -50, yPercent: -50 }),以保证 xPercent/yPercent 与后续的 x/y 动画正确组合。
  • 在 HTML/CSS 字幕之上烧录 libass 字幕。 每个输出视频只能选择一种字幕系统。若使用本技能的 HTML/CSS 字幕,请勿在 /wjs-segmenting-video 中同时烧录字幕——应通过交接包请求原始片段。
  • 第 0 帧为黑色。 若封面场景包含从透明度 0 开始的淡入动画,实际第一帧为黑色,平台缩略图也会是黑色。请将封面静态放置(不使用透明度动画),并通过 ffmpeg -ss 0 -vframes 1 验证。
  • CTA 中的频道名称 = 客座嘉宾姓名。 始终使用 王建硕。嘉宾信息应放在元数据中的描述文本里,而非屏幕上的 CTA 显示。
  • 封面图像因比例不匹配被裁切。 object-fit: cover 在宽高比不一致时会导致裁切。解决方案:重新生成符合目标比例的封面(参见步骤 1),或使用 object-fit: contain + 深色背景实现留白。

与其他技能的集成

  • **/wjs-segmenting-video** — 典型上游流程。该技能完成剪辑、裁切及 SRT 分段后,本技能接续处理。交接包包含:clip_NN.mp4 + clip_NN.zh-CN.burn.srt + segments.json
  • **/wjs-transcribing-audio + /wjs-translating-subtitles** — 若无 SRT 文件,需先运行这两个技能。推荐使用词级 Whisper 或 Volcano/豆包 ASR 输出,以获得更精确的字幕时间戳。
  • **hyperframes** — 底层合成框架。本技能仅为封装成熟后期制作模式的轻量层;所有 hyperframes 技能的功能(预览、渲染、转场、音频响应等)均适用。编写 custom 叠加效果时,务必阅读其文档。
  • **hyperframes-cli** — 项目使用的 CLI 命令(init, lint, validate, inspect, render)。
  • **gpt-image-2-skill** — 封面生成器。make_cover.py 通过 codex CLI 调用它;需在 ~/.codex/auth.json 中配置 codex 认证信息。
  • **/wjs-uploading-video** — 本技能生成 MP4 后的下游流程。根据元数据文件中的标题、描述、标签,将渲染结果上传至 YouTube。

文件与参考

  • scripts/scaffold.py — Workflow B 的脚手架工具(遗留的 spec.json 格式,用于临时叠加效果)
  • references/post_segmentation_template.html — Workflow A 的模板:标准的 封面 + 字幕 + 章节 + 插图 + CTA 组合结构,支持占位符替换
  • references/build_hf_clips.py — Workflow A 多片段构建器。读取 segments.json 和每段插图字典,为每个片段生成独立项目
  • references/illustration_patterns.mdstackhammer 插图模式的标准 CSS / GSAP 实现
  • references/custom_overlay_recipes.md — 可复用的 custom 叠加效果配方(终端演示、层叠图示、带箭头标注等)
  • references/example_spec.json — Workflow B 示例配置
J
@jianshuo

已收录 1 个 Skill

相关推荐