本文へ移動
cccskills
無料GitHub で公開

html-explainer

把任意主题做成「讲解/科普视频」并渲染成 MP4:调研→审查→解说词→字幕→配音(edge-tts,或火山引擎语音合成 2.0)→**主题驱动风格编排**→并行构建 HTML 场景→确定性逐帧渲染→成片后出多画幅封面。**画面语言内置 23 个模板风格 / 8 个类别**(大胆信号卡、奢华极简、NYT 数据图表、瑞士网格、故障艺术、胶片漏光、流体 Hero、Logo 收尾、东方柔和有机、VFX 文字光标…共 23 种风格,含每种的画布/配色/字体/时间轴规范,见 references/style-catalog.md)。**v2.0 新增**:①**动效库**(`assets/motion.js`,5 组共 40+ 动作词汇:弹簧/进出场/承接/接触/运镜/环境光);②**4K60 + 快门运动模糊**(`--quality / --fps / --profile`,线性光积分 + 三级快门闸门 `--shutter-only` / `--motion-hold`);③**渲染提速**(多浏览器进程级并行 / `--png-fast` / `--jpeg` / `--resume` 断点续渲),且**渲染前必须先问用户选哪条中间帧通道**(`png-fast` / `jpeg q95` / `png` / `jpeg q82`,**默认推荐 `png-fast`**,四条都要列全并附速度对比与描述;未拍板由 `gate_check.py --phase render` 挡下);④**主题驱动模板编排**(`scripts/style_director.py`,按内容类型/情绪/节奏/受众挑风格、混用与局部替换、动态开头与转场,不再一片一模板)。流程规范与音画同步体系承自 anything2explainer(词边界字幕、两级时钟、语速标定、多 agent 分工与 QC 判据),渲染层为自研 seek 式渲染器。**封面默认 16:9 + 3:4 两张**:抖音主封面 1920×1080 + 兼容主页栅格 3:4 的 1440×1080(独立重排,防切字);**竖版投放再加 9:16 的 1080×1920**(左右并置必须改上下堆叠、上下边距让开平台 UI 层)。独立可移植:GSAP 内置、playwright-core 随包、ffmpeg 走 imageio-ffmpeg 回退、浏览器自动探测 Chrome/Edge;**不依赖 html-video / anything2explainer 任何代码或目录**。触发场景:要做科普/讲解/教学/知识/产品类视频、"讲一下 X 做成视频"、要用 html-video 那种模板化画面但更稳的音画同步、要挑某种视觉风格(极简/数据/赛博/电影感/品牌)出片、要出抖音封面/竖版封面/9:16 封面、anything2explainer 换 HTML 渲染、或提到 html-explainer / HTML 讲解视频 / explainer video / MG 视频。

インストール方法を見る

含まれるファイル(68)

  • SKILL.md54.7 KB
  • .gitattributes741 B
  • .github/ISSUE_TEMPLATE/bug_report.yml3.2 KB
  • .github/ISSUE_TEMPLATE/config.yml658 B
  • .github/ISSUE_TEMPLATE/feature_request.yml1.3 KB
  • .github/PULL_REQUEST_TEMPLATE.md1.1 KB
  • .github/workflows/ci.yml3.3 KB
  • .gitignore1.1 KB
  • assets/cover-template.html8.3 KB
  • assets/frame-template.html8.1 KB
  • assets/gsap-README.md6.0 KB
  • assets/gsap.min.js70.7 KB
  • assets/motion.js34.4 KB
  • CHANGELOG.md64.0 KB
  • CONTRIBUTING.md6.1 KB
  • LICENSE1.0 KB
  • licenses/Apache-2.0.txt11.1 KB
  • node/package-lock.json705 B
  • node/package.json205 B
  • package_skill.py4.8 KB
  • README.en.md34.3 KB
  • README.md31.6 KB
  • references/cover-guide.md11.3 KB
  • references/frame-contract.md10.8 KB
  • references/lessons.md149.7 KB
  • references/library-showcase.md5.2 KB
  • references/motion-library.md11.4 KB
  • references/render-profiles.md28.8 KB
  • references/showcase-mode.md6.4 KB
  • references/style-catalog.json30.2 KB
  • references/style-catalog.md28.9 KB
  • references/style-director.md7.6 KB
  • references/template-guide.md4.2 KB
  • references/v2-capabilities.md9.7 KB
  • references/volcano-tts.md10.9 KB
  • references/workflow-guide.md14.0 KB
  • scripts/bench_render.py14.2 KB
  • scripts/blur_integrate.py13.7 KB
  • scripts/check_beats_refs.py4.5 KB
  • scripts/check_cover.mjs24.7 KB
  • scripts/check_integrity.py10.8 KB
  • scripts/check_layout.mjs26.5 KB
  • scripts/cover_build.mjs13.8 KB
  • scripts/frame_at.py12.8 KB
  • scripts/gate_check.py7.5 KB
  • scripts/import_styles.py15.6 KB
  • scripts/lint_frames.py6.9 KB
  • scripts/make_theme.py13.0 KB
  • scripts/new_project.py9.3 KB
  • scripts/peek_frame.mjs11.7 KB
  • scripts/qc_check.py14.5 KB
  • scripts/render_video.mjs63.9 KB
  • scripts/style_director.py34.6 KB
  • scripts/subs.py16.7 KB
  • scripts/timeline_build.py5.2 KB
  • scripts/tts_build.py18.1 KB
  • scripts/tts_setup.py14.7 KB
  • scripts/tts_volcano.py27.1 KB
  • setup_env.sh5.9 KB
  • tests/geometry-fixture/frames/broken.html2.8 KB
  • tests/geometry-fixture/project.json132 B
  • tests/geometry-fixture/README.md1.6 KB
  • tests/test_beats_norm.mjs3.7 KB
  • tests/test_motion.mjs16.6 KB
  • tests/test_style_director.py15.2 KB
  • tests/test_subs_text.py4.3 KB
  • THIRD_PARTY_NOTICES.md9.6 KB
  • tts.env.example1.1 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

html-explainer

定位:anything2explainer 的流程与音画同步 + html-video 的 23 个模板风格库, 渲染层独立实现。作者 Moh,MIT 许可(第三方声明见 THIRD_PARTY_NOTICES.md)。

零外部依赖:不需要 Remotion/npm 工程,不需要 html-video 仓库/Studio/pnpm/agent 后端。 技能自带:GSAP(离线)、playwright-core、渲染器、TTS/字幕/时间轴/主题/QC/封面全套脚本。 对两个来源项目的引用只存在于注释署名里,运行时不读它们的任何文件。 风格库是抄下来的设计规范文本(references/style-catalog.md),来源 html-video(Apache-2.0), 类比:把菜谱抄回家,之后做菜不需要原餐厅营业。

v2.0 新增能力(全部可选、向下兼容;不用就是 v1.4 行为)

能力入口文档
动效库(40+ 动作词汇)assets/motion.js → window.HXMreferences/motion-library.md
主题驱动模板编排(挑风格 / 混用 / 动态开头)scripts/style_director.pyreferences/style-director.md
画质帧率档位 + 快门运动模糊 + 提速scripts/render_video.mjs --profile/--quality/--fps/--shutter-only/--motion-holdreferences/render-profiles.md
渲染基准测试(优化前后对比)scripts/bench_render.pyreferences/render-profiles.md
宣传片范式(去模板化:模板只吸纳配色/字体/时序三层)设计方法references/showcase-mode.md
库全量演示编排(统一舞台 + 节拍网格 + 标签常驻)设计方法references/library-showcase.md
确认闸门(六个确认点由用户拍板才放行)scripts/gate_check.pySKILL.md 流程第 3 步
★ 渲染通道确认(渲染前必问:png-fast / jpeg q95 / png / jpeg q82,默认推荐 png-fast,附速度与描述)consent.json 的 render_channel + gate_check.py --phase renderSKILL.md 确认点 5 · references/render-profiles.md §0

把一个主题做成原创讲解视频:任意风格的 MG 画面(HTML/CSS/GSAP,1920×1080 或竖版)、 配音(edge-tts)、词级对齐硬字幕、全局进度条。一句话一个场景,画面节拍直接锚在 吐字时刻上(B('块文本') 节拍器)。

★ 画面风格库(23 个模板 / 8 个类别)

不要自己从零想画面 —— 先从风格库里挑;多个风格要混用时用编排器自动挑(见下)。 挑出候选后交用户拍板(见确认点 0),不许静默自选。 完整目录(含每种的画布/字体/时间轴/配色纪律) 见 references/style-catalog.md;怎么改编成合规帧见 references/template-guide.md。

两种用法的深度不同,先分清在做哪一种:

你在做怎么用风格库读这篇
讲解片(默认)从 23 个模板里挑一个,按 template-guide.md 改编成帧references/template-guide.md
宣传片 / 发布片(去模板化)只从模板吸纳配色 / 字体 / 时序骨架三层,画面语言用 assets/motion.js 重写 —— 不搬模板画面references/showcase-mode.md
要全量展示某个库(40+ 动效 / 23 个模板)统一舞台 + 节拍网格 + 标签常驻,把「N 个动作」演成「一个动作语言的 N 拍」references/library-showcase.md

判据:成片能被认出「这是 bold-signal 模板」= 吸纳过头;只能说「颜色像 xx、节奏像 yy」= 深度对了。

★ v2.0:不要一片只用一个模板。 用 scripts/style_director.py 读解说词, 自动给每场挑主风格(按角色/时长/关键词打分)、按需搭次风格做局部替换、 决定动态开头变体与场间转场、并算出每场的动效强度。 详见 references/style-director.md。核心价值:让模板服务于主题,而不是让主题被模板限制。

类别可用风格
演示 / 标题卡大胆海报帧、大胆信号卡帧、奢华极简留白帧、创意电压分屏帧、电光工作室分屏帧、故障艺术标题帧、Kinetic Type、Swiss Grid、Warm Grain
数据可视化NYT 风数据图表帧、数据滚动帧、NYT Graph、瑞士网格数据帧
图解 / 流程东方柔和有机帧、Decision Tree
氛围 / 空镜胶片漏光电影帧
营销 / Hero流体背景 Hero 帧
片头片尾品牌 Logo 收尾帧
社媒竖版Play Mode、Vignelli(9:16)
产品演示Product Promo、Product Promo · 30s
特效VFX 文字光标

两类模板、两种改编成本(速查表「类型」列):

类型数量处理
★ rich12单文件 + 纯 CSS @keyframes。零改动可渲染 —— 只需①换系统字体栈(删 Google Fonts)②让出底部字幕带③填真实内容
gsap11多 composition + CDN GSAP(或 Remotion)。不要搬代码,只取视觉 DNA 用 CSS keyframes 重写(搬进来会得到静止首帧且零报错,见 lessons.md #9)

时长档要匹配内容:frame-bold-signal 是 3–6s 的短片花,拉长到 20s 会空。 长段(>10s)优先选 3–30s 档的(Swiss Grid / Kinetic Type / NYT Graph / Warm Grain)。

何时用 / 不用

  • 用:给主题/文章/文档做讲解视频;要挑某种视觉风格出片;要 html-video 那种模板化画面但要求音画稳;要 anything2explainer 流程但不想装 Remotion。
  • 不用:复刻现有视频、真人口播、实拍为主;要 Remotion/React 代码动画本体(那是 anything2explainer 的领域)。

环境(首台机器跑一次)

bash <skill>/setup_env.sh            # 自检;--install 联网补装

依赖:Python≥3.9(edge-tts==7.2.8 钉死 / numpy / pillow / imageio-ffmpeg)、Node≥18、 火山引擎零额外依赖(tts_volcano.py 只用标准库 urllib,不需要装任何 SDK)。 Chrome 或 Edge(几乎必有;都没有才下载 playwright chromium ~115MB)、ffmpeg(PATH 或 imageio-ffmpeg 静态二进制自动回退)。Windows 注意:项目路径全 ASCII;给 Node/Python 传 C:/... 正斜杠路径;别用 heredoc 给 Python 传正则。

命令流水线(项目目录内,顺序不能乱)

PY=<venv python 绝对路径>          # 派子 agent 时必须展开成绝对路径写进 prompt
"$PY" <skill>/scripts/new_project.py <dir> <slug> --topic "主题"   # 阶段 0 建项目
"$PY" <skill>/scripts/tts_setup.py      --project .   # ★ 先定配音方案 + 音色(问用户:edge / 火山)
"$PY" <skill>/scripts/tts_build.py      --project .   # 配音:audio/*.mp3 + manifest
"$PY" <skill>/scripts/timeline_build.py --project .   # 全局时间轴:layout.json + narration-full.mp3
"$PY" <skill>/scripts/subs.py           --project .   # 字幕:subs.json + beats.js + srt/vtt
"$PY" <skill>/scripts/check_beats_refs.py --project . # ★ 节拍引用校验:B()/Be() 是否都能解析(前缀匹配,失配秒级报出可用块)
"$PY" <skill>/scripts/style_director.py --project .   # ★ v2.0 风格编排:读解说词给每场挑主/次风格 + 开场变体 + 转场 + 动效强度 → style-plan.json
"$PY" <skill>/scripts/gate_check.py     --project .   # ★★ 确认闸门:六个确认点未由用户拍板 → 拒绝放行(缺 consent.json 用 --init 生成)
"$PY" <skill>/scripts/gate_check.py     --project . --phase render   # ★★ 渲染前必过:render_channel(渲染通道)未拍板 → 拒绝渲染
"$PY" <skill>/scripts/lint_frames.py    --project .   # 静态体检:八条契约违规(渲染前一秒出结果,比渲完再发现便宜得多)
node <skill>/scripts/check_layout.mjs   .             # ★ 几何体检:越界 / 侵入字幕带 / 元素互相遮挡(lint 看不见几何)
node <skill>/scripts/render_video.mjs   . [--audio audio/narration-full.mp3] [--profile draft|balanced|final|master] [--quality 1080p|2k|4k] [--fps 30|60] [--shutter 180] [--shutter-flush 4] [--shutter-only <场景id,场景id>] [--motion-hold 1] [--preview 30] [--keep-frames] [--only <场景id>] [--mux-only] [--png-fast|--jpeg --jpeg-quality 95] [--workers N] [--concurrency N] [--resume]   # 渲染:out/<slug>.mp4(★ 通道/档位先按确认点 5 问过用户;★ 通道与档位必须一起报——`--jpeg` 与默认快门同时用,中间帧扩展名要一路贯穿到积分器;★ 快门覆盖面也要问:全片开还是 `--shutter-only` 点名几场)
"$PY" <skill>/scripts/qc_check.py       --project .   # 体检 + 抽帧速览图
node <skill>/scripts/cover_build.mjs    .             # 封面:out/cover_169.png + cover_34.png(竖版再加 cover_916.png)
node <skill>/scripts/check_cover.mjs    .             # 封面终态几何实测:边距/钩子字号/行宽/孤字/文字重叠/9:16 禁两栏(FAIL 清零再交)

配音引擎(跑之前必须先问用户,见确认点 3):edge(默认,免费免密钥)或 volcano(火山引擎语音合成 2.0,音质更好,需 API Key)。两者产出的 manifest 结构一致, 下游零改动。切换:--provider edge|volcano 或 TTS_PROVIDER 环境变量。 火山密钥只存 tts.env(已 gitignore)—— agent 只调 tts_volcano.py,不读该文件。 详见 references/volcano-tts.md。

★ 确认点 5 —— 渲染通道:动手渲染前必须问用户选哪条,不许默认开工

硬规则:任何一次真正的渲染(打样 / 全片 / 局部补渲)之前,先把下表摆给用户让他挑通道。 不许凭「上次用的 png-fast」或「PNG 是默认」就静默开工。 用户在打样阶段选定后, 同一轮的重复渲染可沿用;换通道或换档位要重新确认一次。

通道参数相对速度(纯 CSS 图形帧并行 / 满幅照片帧)画质(客观口径)中间帧体积(1080p · 纯图形帧实测)定位
PNG-fast ★默认推荐--png-fast×1.02 / ×4.4逐像素无损(PSNR 99 dB、最大差 0)0.10 MB/帧(8525 帧 ≈ 0.85 GB)纯 CSS/MG 图形帧上与 JPEG q95 同速、体积更小、还是无损 → 默认就用它
JPEG q95--jpeg --jpeg-quality 95×1.00 / ×13PSNR 41.65 dB,低于 x264 crf18 成片自身失真0.12 MB/帧含满幅照片 / 重合成帧、或 4K 终稿时的首选(照片帧上 PNG 是 582ms/帧的黑洞)
PNG(1.4.x 默认)不带开关×1.16 / ×1.0(基准)逐像素无损0.08 MB/帧仅 --profile legacy 逐位复现旧成片、或 master 极限档
JPEG q82--jpeg --jpeg-quality 82最快略低于 q95,仍高于多数成片编码失真~0.08 MB/帧只做打样/迭代预览,不用于交付

体积口径提醒:上表体积是纯 CSS/MG 图形帧(大面积平色 + 文字)实测。同一批通道在 满幅照片 / 重合成帧上会整体抬高一到两个数量级(精细 PNG 单帧可达 1.6–2.0 MB), 表格里的相对关系不变,但绝对量级不可直接套用。

为什么默认改成 PNG-fast(2026-10-05 口径修订):原表把 JPEG q95 列为默认推荐, 依据是「×13 编码速度」—— 但那组倍率测的是满幅照片帧。本技能绝大多数片子是 纯 CSS/MG 图形帧,PNG 的 deflate 对平色块极其高效,本机 6 进程并行实测:

通道吞吐相对体积
JPEG q9527.14 帧/秒×1.000.12 MB/帧
PNG-fast26.65 帧/秒×1.020.10 MB/帧
PNG 精细23.41 帧/秒×1.160.08 MB/帧

→ 纯图形帧上 PNG-fast 与 JPEG q95 基本同速、体积更小、且逐像素无损,默认场景下全面占优。 而「JPEG q95 不是降质」这句依然成立:中间帧还要再被 x264 压一次,q95 的 PSNR 41.65 dB 低于 crf18 成片自身失真,所以它在照片帧 / 4K 终稿里依旧是对的默认。

怎么问(照抄这句,四条都要列全 —— 这是硬要求):

渲染通道你要哪条? ① PNG-fast(推荐 —— 纯 CSS/MG 图形帧上实测与 JPEG q95 同速、体积更小,且逐像素无损) ② JPEG q95(含满幅照片/重合成帧、或 4K 终稿时首选;照片帧上 PNG 是 582ms/帧的黑洞。不失质:失真低于成片自身编码失真) ③ PNG(最慢,只有要逐位复现 1.4.x 老成片时才选) ④ JPEG q82(最快,只适合打样)

自动推荐口径(给建议时按这个判,但仍要用户点头):

  • 默认(绝大多数片子,纯 CSS/MG 图形帧) → --png-fast(同速 + 体积更小 + 逐像素无损)。
  • 帧里有满幅照片 / 重合成、或 4K 终稿 → --jpeg --jpeg-quality 95 (照片帧上 PNG 是 582ms/帧,是最大的时间与磁盘黑洞;4K 精细 PNG 单帧 2–6 MB)。
  • 中间帧必须逐像素无损(合规 / 归档 / 要拿去二次调色)→ --png-fast。
  • 只是看节奏的打样 → --profile draft(档位内已含 png-fast)+ --preview。
  • 精细 PNG → 只在 --profile legacy 逐位复现旧成片时才用。

档位表里的 shot 字段(draft/balanced/final = png-fast)保持原样不动 —— 它现在与推荐口径是同一个值:不传通道参数时就走 PNG-fast,两者已不再冲突。 只有照片 / 4K 场景才显式加 --jpeg --jpeg-quality 95。

关键事实:中间帧编码在浏览器进程内是串行的,--concurrency 对 PNG 完全无效 (实测并发 1/3/6 路的总吞吐 1.80 / 1.86 / 1.87 帧/秒)。想加速只有两条路:换通道或 加 --workers(真·多进程)。照片类片子的历史教训见 lessons.md 第 69 条。

选定的通道写进 consent.json 的 render_channel 字段,由 gate_check.py 挡在渲染之前。

快门(运动模糊)开 / 关,到底影响什么

用户几乎一定会问这句,照下表答(不是"开了更好看"这么含糊):

开(balanced 默认,180°)关(--shutter 0;draft 档即无快门)
观感运动中的元素带真实拖影,快速横移 / 推镜不闪、不跳帧,更像摄影机拍的运动元素是清晰硬边;快速横移在 30fps 下会有轻微顿挫感(judder)
画质线性光 8 样本积分,比"后处理 blur 滤镜"干净得多(不会糊成一坨)无损失(就是清晰帧)
速度慢 ≈6.4×(每个动帧 = 8 次完整页面渲染 + 一次 numpy 积分)快 —— 本机实测 18.4 帧/秒(8525 帧 9 分钟)
磁盘高:样本会堆积,必须靠 --shutter-flush 护栏压峰值(见 render-profiles.md §6)低(只剩最终帧)
值得开有真实位移运镜(推拉摇移)、大片幅元素横穿、要电影感画面以静态排版 + 出场动画为主(绝大多数 MG 科普 / 数据讲解片)

判据:画面里有没有「大幅位移的连续运动」。 只有淡入淡出、逐行出现、数字跳动的话, 快门基本是白付 8× 的账;有横移 / 推镜时它才换来肉眼可辨的顺滑。

★ 只在需要的那几场开 —— 别让全片为几处运镜买单(v2.0.3)

上面那张表是「全片开 / 全片关」的二选一。但真实片子里需要拖影的往往只有几场。 三级闸门(粗 → 细)把成本只花在该花的帧上:

# ① 场景级白名单:只有这两场开快门,其余场走零成本单张(不采样 / 不落盘 / 不积分)
node <skill>/scripts/render_video.mjs . --shutter-only hook,cta --jpeg --jpeg-quality 95

# ② 帧级(可靠):帧里导出 window.__motion(t0,t1),位移 < 1 设备像素的帧自动单张落盘
node <skill>/scripts/render_video.mjs . --motion-hold 1
级别开关粒度判据8525 帧实测
①--shutter-only <id,id>场景白名单快门钉在点名的那几场,其余零成本
②--motion-hold <px>(默认 1)帧页面导出的 __motion可靠:位移不到 1px 直接单张,不截图
③自动,无开关帧first.equals(last)只判掉 ~20%,剩下 80% 全额付费

为什么 ③ 不可靠:阈值等于 0 —— 快门窗口只有 16.7 ms,任何亚像素抗锯齿差异都让两张 PNG 不等。实测 8525 帧里只有 ~20% 被 ③ 判成 hold,截图吞吐 18.4 → 2.9 帧/秒(≈6.4×)。

想省快门成本,就让帧诚实导出 window.__motion(t0,t1)(写法见 motion-library.md; assets/motion.js 的 screenTravel(c0,c1) 直接给这段运镜走了多少 px)。

⚠ 反直觉坑:给整场加的全时长缓慢推镜每帧只走不到 1px(肉眼无拖影),却让 __motion 全非零 → ②变成无操作、③必然不等 → 整场全额付费。要么导出 __motion 让 ②摘掉它, 要么别加这种「防静止」的整场推镜。

截图结束会打印 快门覆盖面:X/Y 帧走快门采样;日志里 位移闸门 0 就是 「② 完全没起作用」的告警信号。

v2.0 画质×帧率档位(--profile,显式开关永远覆盖档位默认值):

node <skill>/scripts/render_video.mjs . --list-profiles   # 看全部档位与实测量级
node <skill>/scripts/render_video.mjs . --profile draft      # 打样:1080p30,无运动模糊,最快
node <skill>/scripts/render_video.mjs . --profile balanced   # ★ 默认推荐:1080p30 + 快门运动模糊
node <skill>/scripts/render_video.mjs . --profile final      # 终稿:4K60 + 运动模糊
node <skill>/scripts/render_video.mjs . --quality 2k --fps 60 --shutter 180   # 自由组合
档位画质帧率快门说明
draft1080p30关打样/迭代,最快
balanced1080p30180°默认推荐(质量/速度平衡)
final4K60180°终稿(原始工作量约 1080p30 的 8–12×;并行后墙钟差距远小于此,见 render-profiles.md)
master4K60180°极限画质(PNG 精细 + 最慢编码)
legacy1080p—关逐位复现 v1.4.x 旧成片
  • 快门运动模糊是线性光下多样本积分(不是 blur 滤镜);hold 静帧直接沿用单张, 不落样本、不进积分。判 hold 有三级闸门(见上)—— 只有导出 window.__motion 的那级才可靠。 快动作 > 80px/帧 不开快门会重影成串。
  • 多浏览器进程级并行(--workers)+ --resume 断点续渲 + --recycle 定期重启浏览器(4K 长片防 OOM)。
  • 画质只改 deviceScaleFactor(1× / 1.333× / 2×),布局逐像素不变,只是采样更密。
  • 完整权衡(速度/质量/体积)、基准数据与硬件要求见 references/render-profiles.md。

辅助工具(随时可用,不进主流水线):

"$PY" <skill>/scripts/make_theme.py --topic "医疗" --use   # 主题换色(只重写 theme.css,帧零改动)
node <skill>/scripts/peek_frame.mjs . <帧id> --at 40,80    # 单帧速览:秒级出图,先看设计对不对
node <skill>/scripts/peek_frame.mjs . <帧id> --at-sec 3.5,12,16.2   # ★ 更推荐:按「绝对秒」定位
# ★ --at 是**百分比**(相对 GSAP 时间轴全长);轴长常被尾段防冻层拉长 10–60s,
#   所以「帧尾终态」对应的百分比因帧而异、极易算错 —— 优先用 --at-sec。
#   看终态取 speech_end−1.5s,看中段取 speech_end/2(值都在 frames/<id>.beats.js 的 __SEG__ 里)。
#   没有 --at-sec 时才退回 --at(查冷开场空屏传 1,3,6 这种小百分数)。
node <skill>/scripts/peek_frame.mjs . <帧id> --at 100 --guides  # 叠十字中线 + 字幕禁区线(判对齐必开)
"$PY" <skill>/scripts/frame_at.py --project . --at 1:23    # 时间点 → 场景/帧号/源文件/终态帧图
"$PY" <skill>/scripts/frame_at.py --project . --list       # 全片场景时间表

画面排障(用户报「几分几秒」→ 定位到帧 → 视觉模型看图 → 改 → 局部重渲)的完整四步见 上文「★ 画面出错怎么定位」。

顺序不能乱:tts → timeline → subs(beats 依赖前两者)→ lint → 渲染 → QC → 封面。改解说词 → 重跑前三条, frames/<id>.beats.js 自动刷新,场景 HTML 一行不用改(这是对 anything2explainer 「帧号硬编码、改一个字全片重对位」的结构性改进)。

--preview 会删掉渲出来的帧(设计上是「预览模式顺手清草稿」)。凡是要拿 PNG 做 拼接 / 复核 / 只重渲单场,一律加 --keep-frames,否则帧目录会在合成后被清空(lessons #32)。 只改了一两个场景的画面时,不要全片重渲:用「临时项目法」按全局帧号补渲再贴回, 本片 3802 帧全重渲 924s,补渲 hook+outro 两段只花 220s(lessons #33)。

★ 封面(成片后必做,不是可选项)

封面决定点击率,成片决定完播率 —— 一张被切掉半个钩子的封面会让整片白做。

默认出两张(16:9 + 3:4),竖版投放再加第三张 9:16。 用户点名某画幅就按用户说的出。

规格画布输出用途
A. 抖音主封面1920×1080out/cover_169.png信息流 / 播放页
B. 兼容 3:41440×1080out/cover_34.png主页栅格(防切字)
C. 竖版 9:161080×1920out/cover_916.png竖版全屏信息流 / 小红书 / 视频号

核心纪律:每张都是独立排版,不是裁切关系。 从 16:9 居中裁 3:4 只剩 810px 宽,丢掉 57.8% 画面;裁 9:16 只剩 608px 高,丢掉 43.7%。 大字钩子必被切。所以各张共享同一套视觉基因(配色/幕底/主视觉/钩子文案),各自重排一次版:

元素16:9 版3:4 版9:16 版
悖论视觉右侧,左右并置上方,竖排堆叠上段(10–45%),竖排堆叠
钩子左下,两行 132px下方,三行 118px中下段(50–88%),三行 150px
角标左上顶部居中顶部居中(留 ≥180px 上边距)
每行字数≤8 字(防孤字断行)≤8 字≤6 字
分裂线右栏内横线横贯(留边距)横贯(留边距),不要竖线

9:16 专属纪律:上边距 ≥180px、下边距 ≥160px(让开平台顶/底 UI 层,这是不可裁区); 禁止左右两栏(1080 宽里两栏必然放不下字)。

封面三要素(缺一返工):① 大字钩子(≥96px / ≥120px / ≥130px,含反差悬念) ② 核心悖论视觉(两数对照 / 一升一降 / 分裂线 / 一明一暗,不是装饰图形) ③ 信息余量(四边 ≥96px / ≥110px / 左右 ≥90px,无贴边文字)。

做法:复制 assets/cover-template.html 为 frames/cover_169.html、frames/cover_34.html、 frames/cover_916.html(竖版才要第三份),各自排版 → node scripts/cover_build.mjs . (默认 seek 到时间轴末尾取完整态,--at 0.8 可取入场中间态;缺哪张就跳哪张)。

出图后必跑几何实测 —— 肉眼只能看出明显问题,差 20px 的贴边、多出一字的孤行全靠它抓:

node <skill>/scripts/check_cover.mjs .              # 量三张:边距 / 钩子字号 / 行宽 / 孤字 / 文字重叠 / 9:16 禁两栏
node <skill>/scripts/check_cover.mjs . --only 916   # 只量一张
node <skill>/scripts/check_cover.mjs . --shot       # 顺手把 1x 预览图丢到 out/

它按 tl.pause(tl.duration(), false) 把页内时间轴 seek 到轴末再量(必须量终态,lessons #30), FAIL 清零才算封面过。退出码 0/1,可直接挂流水线。

详规见 references/cover-guide.md。

核心机制(为什么音画稳)

机制口径
帧时长MP3 容器时长(tts_build 裁首尾静音后回填)。词边界时长每段少 ~0.86s,用它必错位
末块字幕收尾语音真实结束(speech_end_sec)—— 两级时钟,混用则「字幕过了语音还没过」
字幕节拍词级时间戳首字对帧号,绝不按字数插值(中文同字数时长差 3 倍)。edge 取 WordBoundary,火山取 sentence.words[](需显式开 audio_params.enable_subtitle,本包默认开;不开会静默退回插值)
画面节拍场景 HTML 里 B('块文本') 取该词起播秒排 GSAP —— 画面与吐字同源
渲染确定性 seek:tl.pause(t, false) + CSS 动画 currentTime=t×1000 → 截图 → ffmpeg 合成。无实时录制,html-video 的引导期/起播/字体坑整类不存在。第二参必须传 false,少了它 onUpdate 类回调被静默抑制(数字滚动恒为初值,见 lessons #27)
字幕层/进度条渲染器注入并逐帧驱动(#mg-subs 44px 白字黑边 bottom 96px;#mg-progress accent 填充),帧作者零负担

流程(六个确认点必须停下等用户回话)

完整版见 references/workflow-guide.md(含研究员/构建/QC agent 的 prompt 模板与时长档位表)。

  1. 建项目(5 分钟):new_project.py + 定主题(make_theme.py --topic/--preset … --use,颜色全在 theme.css 的 CSS 变量里,画面代码禁止色值字面量)

    ★ 确认点 0 —— 配色 / 风格一律先问,禁止凭记忆替用户拍板

    这是硬规则,每一期都要走一遍,不得沿用上一期的选择。

    • 开工(乃至挑风格)之前,先给用户 2–4 个候选,每条写清三件事: ① 色号(hex)② 一句气质描述 ③ 适合什么内容。让用户挑,而不是替他挑。
    • 风格模板同样要问:从 references/style-catalog.md 选出 2–4 个候选列出来, 不要静默从「上次挺好用」的记忆里定 2–4 种。
    • 用户自带色号时:照他的色号落地,但仍要回报 「我打算用哪个色做哪个语义(重点 / 指标 / 警示)」,请他确认。
    • 用户明确说「你决定」「按你上一次的来」时才可以自行选择 —— 且要说明选了什么、为什么。
    • ⚠️ 反面教材:看到暖色题就默认 --preset amber、看到数据题就默认瑞士网格。 记忆里"好用"的东西不构成用户的选择。
    • 设计思维要一次问全(宣传片 / 发布片尤其)—— 除配色外,还要问清三件事: ① 影片形态(纯视觉宣言 / 主视觉+章节讲解 / 双版本); ② 库演示方式(全量逐条罗列 / 分组深挖 / 精选高光); ③ 时长与画幅(多少秒;是否出竖版成片与 9:16 封面)。 这四问的答复全部写进 consent.json,然后由 gate_check.py 挡在场景构建之前。
  2. 调研(20 分钟,1 agent):research/调研.md,每个数字带 URL;确认点 1(时长/语言 + 投放画幅与封面张数)并行问

    确认点 1 顺带问一件事:封面要哪几张。 默认 16:9 + 3:4 两张(横版投抖音/视频号)。 若用户会投竖版(竖版成片、全屏竖版信息流、小红书、朋友圈),要再加 9:16 那张 —— 9:16 不是把 3:4 拉长,是另一种构图(左右并置必须改上下堆叠、上下边距让开平台 UI 层)。 现在问清,后面就不用返工;用户说「按默认」就只做两张。

  3. 解说词(30 分钟):narration.json(| 切字幕块,中文 ≤16 字/块)→ 填 order → 确认点 2(文案定稿)→ 确认点 3(配音方案 + 音色)→ tts/timeline/subs 三连 → 核对时长区间(差 >15% 改句子,别改语速硬凑)→ 定稿后不改词

    确认点 3 必须问两件事(用 tts_setup.py 落实): ① 方案 —— 「配音用 edge-tts(免费、免密钥、开箱可用)还是火山引擎语音合成 2.0 (音质更好,需要 API Key,约 1 分钟配置)」; ② 音色 —— 选定方案后列候选让用户挑,也可自定义 ID。 选火山时:缺 tts.env → tts_setup.py 生成空模板并停下来,让用户手工填密钥 (agent 不读该文件、不参与填值);用户说填好了 → --check 测连接 → 再选音色。 ★ 提醒用户用 cp tts.env.example tts.env 复制,别把 tts.env.example 改名成 tts.env —— 那是要留在仓库里的模板(改名会让 check_integrity.py 报错)。 详见 references/volcano-tts.md。

  4. 分镜(含选风格,20 分钟):script/storyboard.md,每场景一行 —— 先从风格库挑出 2–4 个候选交用户选(受确认点 0 约束,不可静默自选), 再照 references/style-catalog.md 的「挑风格的实用建议」表核对内容类型与时长档, 最后写画面/主角·尺寸/光/B() 锚点;末尾全局约束 (贯穿示例、事实清单、每章 1–2 高光时刻、每章 ≥3 运镜)。 全片建议 2–4 种风格轮换,避免 8 个场景全用同一个模板。

    ★ 确认闸门 —— 进阶段 4 之前必须过(把纸面规则变成硬闸门)

    "$PY" <skill>/scripts/gate_check.py --project .                # 缺一项确认就拒绝放行
    "$PY" <skill>/scripts/gate_check.py --project . --phase render # ★ 渲染前再跑:只查渲染通道拍板没有
    

    为什么要有这一步:纸面规则会被静默跳过 —— 确认点写得再清楚, agent 也可能直接跑 style_director.py 把风格自选了,用户事后才发现「你没问过我」; 渲染同理:默认 PNG 一路渲完,用户才发现「你没问过我用哪条通道」。 本闸门要求 consent.json 里七项(配色 / 风格 / 形态 / 配音 / 时长 / 封面 / 渲染通道) 全部由用户拍板(decided_by == "user"),任一缺失即退出码 1。 缺文件时用 --init 生成模板,脚本不替用户选任何一项。 其中 render_channel 由 --phase render 在每次渲染前单独复检(确认点 5)。

  5. 场景构建(并行):每组 4–8 场景一个 agent(一波 ≤3–4 个)。

    • 挑中的 rich 模板:从它的 source/index.html 改写 —— ①删 Google Fonts 换系统栈 ②底部元素抬到 ≥176px ③填真实内容(照 example.md 的字段)
    • 挑中的 gsap 模板:别搬代码,只照风格规范用 CSS keyframes 重写
    • 全新画面:从 frames/_template.html 复制,契约见 references/frame-contract.md
    • 改编细则见 references/template-guide.md;边做边写盘
    • 想「照镜子」不必渲全片:node scripts/peek_frame.mjs <项目> <id> --at 40,80 秒级出图
  6. 静态体检:三条命令,全是秒级,都在渲染之前:

    "$PY" scripts/check_beats_refs.py --project .   # ① B()/Be() 是否都能解析(前缀匹配)
    "$PY" scripts/lint_frames.py --project .        # ② 八条契约违规
    node scripts/check_layout.mjs .                 # ③ 几何(遮挡/越界/侵入字幕带)
    

    ① 管节拍引用:B() 抛错只在渲到那一帧时才发生,前面几百帧白渲 —— 必须提前抓; ② 管文本规则(外链字体、色值字面量、墙钟逻辑、B()||N 兜底、字幕带压内容、缺中文字体族…); ③ 管几何 —— lint 看不见几何,元素互相遮挡 / 侵入字幕带 / 出画只有它管。 三条全绿再进渲染(比渲完几千帧再回来看便宜得多)。

  7. 打样:render_video.mjs . --preview 30 → 确认点 4(风格/字号/语速/节奏一次定稿) → ★ 确认点 5 —— 渲染通道:把 png / png-fast / jpeg q95 / jpeg q82 四条摆给用户挑 (每条带一句描述、逐帧耗时、相对速度与推荐口径,见上文「确认点 5」与 references/render-profiles.md §0), 拍板后写进 consent.json 的 render_channel,跑 gate_check.py --phase render 放行 → 顺带问一句快门覆盖面:全片开,还是只点名那几场(--shutter-only)? (全片开 = 慢 ≈6.4×;片子只有几处运镜要拖影时必须主动问,别默认全片开) → 全片渲染 + qc_check

  8. QC:qc_report.md 的 FAIL 清零 + qc_sheet.jpg 肉眼过(字幕带 80–170px 无内容、一焦点、光跟主角)→ 按组修复 → 重渲

  9. 封面:做 frames/cover_169.html + cover_34.html(独立排版;竖版投放再加 cover_916.html) → node scripts/cover_build.mjs . → node scripts/check_cover.mjs .(量终态几何,FAIL 清零) → 核对 out/cover_report.md + references/cover-guide.md 的自检清单

  10. 交付:mp4 + 封面(默认两张,竖版三张)+ srt/vtt(上传平台=可检索文本)+ 发布说明(硬字幕→关平台自动字幕; AI 配音→勾 AIGC;封面文字须与视频首帧钩子同义;受监管题材过合规)

★ 画面出错怎么定位(用户报「几分几秒」,agent 直接落到那一帧)

成片里发现画面问题(元素错位、被压住、少了东西、动效没走完)时,不要重新描述场景内容、 不要从头翻 5000 帧。流程固定成四步:

  1. 用户只需要给「几分几秒」+ 一句现象。 例:1:23 右下角示意图里小黑点没在射线汇聚点上,偏左上。 .github/ISSUE_TEMPLATE/bug_report.yml 里有一栏专门收这个时间点。

  2. frame_at.py 把时间点翻译成定位信息(一条命令,秒级):

    "$PY" <skill>/scripts/frame_at.py --project . --at 1:23
    "$PY" <skill>/scripts/frame_at.py --project . --at 1:23 --box 1400,200,1920,900   # 再裁一块可疑区
    "$PY" <skill>/scripts/frame_at.py --project . --list                              # 全片场景时间表
    

    产出 out/probe/:场景 id / 帧号 / 场景源文件 frames/<id>.html / 节拍文件 / 当刻字幕块 (反查代码里的哪一句 B('…')),以及三张给视觉模型看的图 —— 整帧(1280 宽)、 底部 260px 禁区带(1:1)、场景终态帧。

  3. 带视觉的模型看那几张图(这是关键:只用文本描述「蓝点没在中间」定位不到,看图能直接 读出偏了多少、偏哪个方向、被谁压住)。先看终态帧,再看当刻帧。

  4. 改 frames/<id>.html → 重跑 check_layout.mjs(几何)→ lint_frames.py(契约)→ render_video.mjs . --only <场景id> 局部重渲 → 回到第 2 步复核同一时间点。

两条判据(省掉大量返工)

  • 先看终态,再看中途。 中途帧的入场动画可能还没走完,元素位置本来就该和终态不同 —— 单看它分不清「代码错」还是「动画错」。终态也错 = 布局本身错了;只有中途错 = 动画时序问题。
  • --only <id> 只对末场安全(见 lessons.md #15):改短了必须删尾部过期帧, 且渲染日志的 ✓ 不算证据 —— 用 frame_at.py 回到那个时间点看图确认。

场景契约速查(完整版 references/frame-contract.md)

八条:1920×1080 系统字体(禁外部字体)→ 颜色只取 theme.css 变量 → 动画只用 GSAP (window.__tl 注册,禁 CSS transition 入场;@keyframes 循环装饰可用,渲染器会 seek)→ 节拍用 B() → 字幕带(80–170px)与进度条带(0–12px)不放内容 → 一场景一焦点 (主角 ≥170px 或大字 ≥96px 带 accent 柔光,配角不发光,文字 ≥22px)→ GSAP 用 ../assets/gsap.min.js(本地内置)→ 主体动画压在 speech_end 前。

质量标尺

  • 画面:每帧一个焦点,主角带光;accent 只给当前重点;背景只有幕底+网格,无碎屑
  • 几何:check_layout.mjs ERROR 清零 —— 遮挡/越界是唯一一类「lint 全绿但仍然错」的问题 (lint 只看文本规则)。一个几何体只准有一个坐标系:SVG 图元与 HTML 部件不得混用两套基准 (issue #1「蓝点没落在射线汇聚点上」的根因,见 references/frame-contract.md)
  • 节拍:元素出现落在对应字幕块起始 ±0.2s 内(B() 天然保证);每句至少一处可察觉变化。 check_beats_refs.py 必须全绿 —— B() 是前缀匹配(text 必须是块文本的开头), 且抛错只在渲到那一帧时才发生(见 references/lessons.md #90)
  • 字幕:中文 ≤16 字/块、无标点、单帧硬切、每块 ≥0.6s;末块跟着语音消失。 小数点不算标点(2.4% 上屏幕必须是 2.4%,削成 24% 是差一个数量级的假数字); , / : 照删。这条规则有五个出口,改动要一起动(见 references/lessons.md #88)
  • 底色:用了亮底(浅色背景)就必须先给字幕层换肤 —— 渲染器注入的字幕/进度条默认是 「白字 + 黑描边」,白字落在米白纸面上等于看不见。主题文件里给亮底作用域补 --mg-sub-fg / --mg-sub-stroke / --mg-track / --mg-tick 即可(见 references/lessons.md #75)。 它是渲染期产物 —— 改它 = 整片重渲,所以第一次全片渲染前先用 --preview 拿到 跨明暗切换的那几十秒。 ★ 亮底帧的 HTML 必须带 <body class="paper">(body.paper 才会切字幕/进度条皮肤)。 派子 agent 写亮底帧时要把这条写进硬规矩并点名"同组的暗底帧不能加",交付后 grep -n '<body' frames/*.html 自查 (见 references/lessons.md #94)
  • 事实:画面数字/术语/年份逐个对调研 URL;示例数据标「示意」。 ★ 画面文字写的「口径名」必须与来源报告的口径名逐字一致 —— 二手转述会偷换统计主体 (「网络视听 201 分钟」被写成「短视频 201 分钟」是造数)。拿不到一手口径的数字,宁缺勿用 (见 references/lessons.md #95)
  • 时长:落在确认点 1 区间内;成片与音轨差 <0.5s(qc_check 把关)。 ★ 解说词一次定稿:数据/文案一改就要重跑 tts→timeline→subs,全部 beats 的秒数一起位移 ——「时效刷新」是流水线的正式步骤,位置在 tts_build 之前(见 references/lessons.md #96)

关键文件

流水线脚本(按执行顺序)

路径作用
scripts/new_project.py阶段 0 脚手架:建目录树 + project.json + narration.json 占位 + theme.css + 两份封面 HTML(16:9 + 3:4;9:16 按投放需要自己加,注释里给了做法)
scripts/tts_setup.py配音方案向导:选 edge/火山 → 缺密钥则生成 tts.env 模板并停下 → 测连接 → 选音色 → 写回 project.json。输出 NEXT_ACTION=… 供 agent 判断下一步
scripts/tts_volcano.py火山引擎语音合成 2.0 接口包:唯一读 tts.env 的地方;--check / --voices / --synth。密钥不回显、异常脱敏(_redact)
scripts/tts_build.py配音合成:edge-tts 或 火山引擎(--provider);缓存/硬超时/退避重试/裁静音,manifest 写两级时长。两引擎 manifest 结构一致
scripts/timeline_build.pylayout.json 全局轴 + narration-full.mp3(gap 显式插入)
scripts/subs.py字幕三出口(subs.json / srt+vtt / 画面内层由渲染器注入)+ beats.js 节拍器
scripts/check_beats_refs.py节拍引用构建期校验:把每帧的 B()/Be() 全抓出来和自己的 beats 表对一遍。B() 是前缀匹配(bt===t ‖ bt.startsWith(t) ‖ t.startsWith(bt),归一化不去 《》「」),取中间一段会抛错 —— 而那个错只在渲到那一帧时才炸(前面几百帧白渲)。本脚本把它提前到构建期:失配打印该帧可用块列表,退出码 1,秒级
scripts/style_director.py★ v2.0 主题驱动风格编排:读 narration.json 推断每场角色(开场/陈述/数据/原理/例证/反差/收束/落版),按角色×子类别×时长×内容词打分挑主风格,按能量预算给部分场搭次风格(局部替换),决定开场变体、场间转场、动效强度,并施加多样性约束(风格数上限/连续同风格上限/开场≠第二场)。产物 style-plan.json 的 why 字段逐条可解释
scripts/lint_frames.py渲染前静态体检:八条契约违规逐条报(外链字体/色值字面量/墙钟/B()||N/字幕带压内容/缺中文字体族…)—— 只看文本规则,看不见几何
scripts/check_layout.mjs渲染前几何体检(终态):侵入字幕禁区 / 出画 / 文字被遮挡 / 文字重叠 = ERROR;越安全边 / 文字压色块 / 色块重叠 = WARN;疑似未对齐 = INFO。量的是字墨范围(Range 逐行)而非元素框。--only / --json / --safe-bottom;有 ERROR 退出码 1
scripts/render_video.mjs渲染器:浏览器探测 → 逐场景 seek 截图 →(可选快门运动模糊积分)→ ffmpeg 合成;--preview N 快样片,--only <场景id> 只重渲指定场景(仅末场安全,变短后须清尾部过期帧,见 lessons 45),--mux-only 用现有帧重新合成;帧里有满幅照片就必须换截图模式(默认 PNG 编码占 96% 帧时间且与并发无关):--png-fast 无损 4.4×,--jpeg --jpeg-quality 95 13×;--crf N / --preset <名> 单独控制成片码率。v2.0 新增:--profile 成套档位、--quality×--fps 自由组合、--shutter 快门运动模糊、--workers 多浏览器进程级并行、--resume 断点续渲、--recycle 定期重启浏览器。v2.0.2/.3 新增:--shutter-flush 快门样本磁盘护栏(防峰值堆到数十 GB)、--shutter-only <id,id> 场景级快门白名单、--motion-hold <px> 位移闸门(配合帧导出的 window.__motion)。v2.0.6 修复:路径 A(精细 PNG 单浏览器)的看门狗改为逐帧打点(此前量的是「单场耗时」,>105s 的场必被误杀);--resume 在路径 A 真正生效(此前加了不报错也不跳帧 = 静默 no-op,而看门狗挂死提示恰恰叫人用它)
scripts/blur_integrate.py快门运动模糊积分器(渲染管线第 2 段):把 Node 侧抓到的 K 张快门样本在线性光下逐像素平均 —— 真的积分,不是 blur 滤镜。多进程并行、天然支持断点续渲
scripts/bench_render.py渲染管线基准工装:合成复杂度可控的项目 → 同机多档位各渲一遍 → 拉出「截图耗时/fps/体积」对比表(优化前后同表对比)
scripts/qc_check.py流/时长/音量/抽帧体检 + contact sheet
scripts/cover_build.mjs封面渲染器:169(1920×1080) / 34(1440×1080) / 916(1080×1920) 各一份独立排版 → 2 倍图;--at / --only / --jpg;缺哪张就跳哪张
scripts/check_cover.mjs封面终态几何实测器:边距 / 钩子字号 / 钩子是否最大文字 / 行宽 / 孤字断行 / 文字重叠(量字墨,不量行框) / 9:16 禁左右两栏 / 越界;--only / --json / --shot;退出码 0/1

辅助工具

路径作用
scripts/peek_frame.mjs单帧速览:不渲全片,秒级截某场景的几个时点看图。--at-sec 3.5,12 按绝对秒定位(推荐,自动读轴长换算);--at 是相对整条时间轴的百分比(轴长会被尾段防冻层拉长,容易算错);--guides 叠十字中线 + 字幕禁区线(判「元素有没有对齐」必须开,没有基准线肉眼判不了)
scripts/frame_at.py时间点 → 定位:报「几分几秒」就能拿到场景 id / 帧号 / 源文件 / 当刻字幕块 / 整帧图 / 底部禁区带裁图 / 场景终态帧(--at 1:23 / --list / --box x0,y0,x1,y1 / --final)。画面排障的入口工具
scripts/check_integrity.py仓库自洽性:版本号/风格目录/计数一致性 + 模板外链扫描(CI 与本地都跑)
scripts/make_theme.py4 预设 + 主题词推色 → theme.css(CSS 变量单源)
scripts/import_styles.py(移植期一次性工具)把已装 html-video 的设计规范抄成纯文本风格目录;跑视频永不需要它
tests/geometry-fixture/几何体检的证伪样本:故意坏掉的帧(越界 + 遮挡 + 错位),期望 ERROR 2 / WARN 0 / INFO 1。改 check_layout.mjs 后先拿它验「还抓得到错」,再拿真实项目验「误报没变多」
setup_env.sh环境自检 / --install 联网装缺项
package_skill.py打成可移植 zip(--with-deps 含 node_modules)

参考文档与资源

路径作用
references/style-catalog.md23 个画面风格目录(画布/字体/时间轴/配色纪律 + rich/gsap 分类)——纯知识,非代码依赖
references/style-catalog.json同上的机器可读版(kf/multi/engine 字段用于自动判类型)
references/template-guide.md模板改编指南(rich 三步法 / gsap 重写法 / 挑风格建议)
references/frame-contract.md契约细则 + 版式基因 + 反例
references/cover-guide.md封面详规:一张还是几张 / 各画幅排版纪律 / 重排对照表 / 三要素 / 尺寸倍率 / 上传策略 / 自检清单
references/workflow-guide.md阶段详解 + agent prompt 模板 + 时长档位表
references/motion-library.md★ v2.0 动效库文档:40+ 动作词汇(enter/carry/contact/camera/ambience 五组)、曲线表、场景契约、完整示例、六条纪律
references/style-director.md★ v2.0 模板编排文档:八种角色、打分维度、混用与局部替换、多样性约束、style-plan.json 结构、命令行
references/render-profiles.md★ v2.0 画质/帧率档位与性能文档:档位表、质量-速度-体积权衡、快门与并行原理、基准数据、4K60 硬件要求
references/lessons.md踩坑台账(继承 14 条 + 本技能记录,持续追加)
assets/frame-template.html场景模板(契约注释在文件头,B() 用法示例)
assets/cover-template.html封面模板(封面三要素注释在文件头,可改尺寸复用为 16:9 / 3:4 / 9:16 各一份)
assets/gsap.min.jsGSAP 3.13 本地内置(离线渲染;License 见同目录 gsap-README.md)
assets/motion.js★ v2.0 动效库(40+ 动作词汇)。浏览器挂 window.HXM,Node 可 require 跑自测。无依赖、无构建、纯函数(可逐帧 seek)
README.md / README.en.md对外项目说明(README.md 中文为默认,README.en.md 英文;含跨 Agent 安装指引)
CONTRIBUTING.md贡献指南:硬性规则、端到端自检、PR 清单
CHANGELOG.md版本变更史
THIRD_PARTY_NOTICES.md第三方组件与衍生内容的授权声明(发布前必读)

跨 Agent 安装

本技能遵循 Agent Skills 约定(SKILL.md + scripts/ + references/ + assets/),不绑定任何单一智能体平台。仓库根目录就是 技能目录,所以 clone 到下表任一路径即可直接生效,不需要再拷子目录。

智能体个人级(全局)项目级(仓库内)
WorkBuddy~/.workbuddy/skills/<工作区>/.workbuddy/skills/
Claude Code~/.claude/skills/.claude/skills/
OpenAI Codex~/.codex/skills/.codex/skills/ 或 .agents/skills/
Gemini CLI~/.gemini/skills/.gemini/skills/ 或 .agents/skills/
Cursor~/.cursor/skills/.cursor/skills/
GitHub Copilot / VS Code~/.copilot/skills/.github/skills/
OpenCode~/.config/opencode/skills/.opencode/skills/
Windsurf~/.windsurf/skills/.windsurf/skills/
通用约定~/.agents/skills/.agents/skills/

手动安装(把 ~/.claude 换成你所用智能体的目录):

git clone https://github.com/OneMoh/html-explainer.git ~/.claude/skills/html-explainer
bash ~/.claude/skills/html-explainer/setup_env.sh --install

也可以直接把这句话交给智能体,让它自己装:

给当前本地环境安装该 Skill:https://github.com/OneMoh/html-explainer.git 安装到你的技能目录,并检测安装必要的运行环境(Python 3.9+ / Node 18+ / Chrome 或 Edge / ffmpeg)

装完新开一个会话,让智能体重新扫描技能目录。同理,调用本技能时应把 <SKILL_ROOT> 替换成实际安装路径 —— 派子 agent 时要展开成绝对路径写进 prompt。

打包移植

技能目录自包含,不引用本机任何绝对路径(脚本按自身位置定位 SKILL_ROOT)。 仅有两处兜底探测会去探 WorkBuddy 托管的运行时目录(setup_env.sh 的 Python/Node 候选、peek_frame.mjs 的技能根候选)—— 探不到就自动跳过,不影响其它平台。

零依赖声明(重要):本技能不需要 html-video 或 anything2explainer 存在。 两个来源项目的名字只出现在:① 代码注释的出处署名 ② scripts/import_styles.py 这个移植期一次性工具的用法说明里。跑一条视频(tts → timeline → subs → render → qc → cover)完全不碰这两个项目。风格库是抄成纯文本的设计规范 (references/style-catalog.md),已随技能打包。

# ① 打包(默认不含 node_modules,只有 ~110KB)
python package_skill.py                # → dist/html-explainer-v<版本>.zip
python package_skill.py --with-deps    # 含 playwright-core,~14MB(目标机全程离线)

# ② 新机器:解压到任意目录(放进上表任一「个人级」技能目录即可被该智能体识别)
bash setup_env.sh --install            # 自检 + 装缺项(先装后判定,装成功即算就绪)

# ③ 跑一遍端到端(可选,验证链路)
python scripts/new_project.py demo --topic "人工智能"
# …填 narration.json / 写 frames/*.html / 填 project.json.order…
python scripts/tts_build.py --project . && python scripts/timeline_build.py --project .
python scripts/subs.py --project . && python scripts/style_director.py --project .
node scripts/render_video.mjs . --profile balanced --audio audio/narration-full.mp3
python scripts/qc_check.py --project . && node scripts/cover_build.mjs .

v2.0 提速自检:跑一次基准,确认本机各档位速度符合预期(不需要素材):

python scripts/bench_render.py --out .scratch/bench --scenes 6 --sec 2.0 --fps 30 \
    --configs legacy,draft,balanced --preview 6

依赖探测顺序(都尽量用系统已有的,避免下载):

  • Python:先找 WorkBuddy 托管 venv,再 python3 / python
  • Node:node -v ≥18;没有则扫 ~/.workbuddy/binaries/node/versions/*(WorkBuddy 托管路径)
  • 浏览器:Chrome → Edge → playwright chromium → BROWSER_PATH 环境变量
  • ffmpeg:PATH → imageio_ffmpeg.get_ffmpeg_exe()(pip 装依赖时自带静态二进制)
  • GSAP:包内 assets/gsap.min.js(离线,不外链)

已验证:把 zip 解压到干净目录、只跑 setup_env.sh --install,全链路输出与原目录逐帧一致 (同 346 帧、同抽帧体积、同音画差 0.05s)。

许可与致谢

  • 本技能原创代码与文档:MIT © 2026 Moh(见 LICENSE)。
  • 画面风格目录(references/style-catalog.md / .json)由 nexu-io/html-video (Apache-2.0)的模板设计规范转写而来,已保留署名;转写文本按 Apache-2.0 分发。
  • 方法论思路来源:Vincentwei1021/anything2explainer (词边界字幕 / 两级时钟 / 语速标定 / QC 判据)。两者均为他人独立项目,与本技能不是同一作者。 确定性 seek 渲染器、B() 节拍锚定、多画幅独立排版封面(16:9 / 3:4 / 9:16)为本项目原创。
  • 打包内置:GSAP 3.13(GreenSock 标准「no charge」许可,见 assets/gsap-README.md)、 playwright-core(Apache-2.0)。
  • 完整清单与逐条授权见 THIRD_PARTY_NOTICES.md。发布/再分发前请连同该文件一起带上。

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

このスキルの問題を報告する