SkillAgentSearch skills...

html-to-video

把 HTML/Canvas 动画逐帧渲染成 MP4(可配乐、可出 GIF、可出透明层)。当用户说「用代码做视频」「HTML 转视频」「导出 MP4/GIF」「做个动态图解/宣传片/数据动画」「逐帧渲染」时使用。自带渲染器与 11 个开箱即用模板(含多镜头讲解片、竖屏 9:16、前后对比、流程图、字幕卡)、图标/人物/运镜素材库,支持透明输出、外部字幕时间轴与 JSON 镜头表,装好依赖后一条命令出片。

Install / Use

npx skills add wx4766/html-to-video

Installs into whichever agent you are using.

About this skill
📄

SKILL.md

Installable skill definition

Quality Score

70/100

Category

Design

Supported Platforms

Universal

Tags

Our assessment of html-to-video

html-to-video scores 70/100 on our quality scale, 245th of 264 Design skills we index.

Its SKILL.md is 24 KB long, well organised into 50 sections with 35 code examples: a thorough specification that gives an agent plenty to work with.

It has no GitHub stars yet, so there is no community track record; judge it on its content.

Substance
30/30
Structure
20/20
Description
15/15
Adoption
0/20
Freshness
5/15

Maintenance, license and trust

  • We could not determine when the repository was last updated.
  • No license is declared. By default that means all rights are reserved: you can read it, but reusing or redistributing it is not clearly permitted. Ask the author before building on it commercially.
  • Its trust signals score 68/100, with 3 cautions from licensing, adoption, age or documentation. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

html-to-video compared with similar skills

All 4 of these similar skills score higher than html-to-video; compare them before choosing.

SkillScoreStarsUpdatedFormat
html-to-video (this skill)by wx4766700—SKILL.md
algorithmic-artby anthropics100177.9k41d agoSKILL.md
pptxby anthropics100177.9k41d agoSKILL.md
designby nextlevelbuilder100143.4k2d agoSKILL.md
ui-ux-pro-maxby nextlevelbuilder100143.4k2d agoSKILL.md

Frequently asked questions

How do I install html-to-video?
Run npx skills add wx4766/html-to-video. The install tabs above show the steps for each supported agent.
Which AI agents does html-to-video work with?
It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
Is html-to-video safe to use?
It declares no license and scores 68/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is html-to-video still maintained?
We could not determine when the repository was last updated.

name: html-to-video description: 把 HTML/Canvas 动画逐帧渲染成 MP4(可配乐、可出 GIF、可出透明层)。当用户说「用代码做视频」「HTML 转视频」「导出 MP4/GIF」「做个动态图解/宣传片/数据动画」「逐帧渲染」时使用。自带渲染器与 11 个开箱即用模板(含多镜头讲解片、竖屏 9:16、前后对比、流程图、字幕卡)、图标/人物/运镜素材库,支持透明输出、外部字幕时间轴与 JSON 镜头表,装好依赖后一条命令出片。 agent_created: true

html-to-video · 代码逐帧做视频

这套东西是什么

不是 AI 生成视频,是用代码逐帧画视频:

写 HTML/Canvas,把画面写成 frame(t) 纯函数
   → 无头浏览器逐帧 seek 到 t,截图
   → ffmpeg 编成 H.264 MP4
字幕 / 运镜 / 转场全在代码里,改代码重渲即可

优点:确定性(同输入同输出)、可控到帧、中文文字完美、零费用。 最适合做:讲解动画、动态图解、产品演示、数据可视化动画、宣传片片头。 不适合:实拍感/氛围镜头(那种走 VideoGen)。

能拿它做什么(assets/templates/ 里 11 个模板直接改字就能出片):

| 模板 | 用途 | 出片 | |---|---|---| | explainer.html | 多镜头讲解片:片头 / 人物+气泡 / 要点 / 条形对比 / 片尾,镜头带转场,可喂 JSON 镜头表;横屏恰好三条要点时自动并排成三栏,竖屏(1080×1920)另有上下版式 | --duration=17.6 | | title-card.html | 视频片头:主标题逐字弹入 + 副标题 | --duration=6 | | bar-chart.html | 条形图/排名:条形依次生长,数值同步滚动 | --duration=6 | | line-chart.html | 折线趋势:折线生长 + 数据点亮起 + 末点浮标 | --duration=8 | | number-counter.html | 大数字/KPI:从 0 滚到目标值 + 涨跌标签 | --duration=7 | | timeline.html | 时间线/流程:中轴生长,节点逐个点亮 | --duration=7 | | vertical-card.html | 竖屏 9:16 卡片:大字标题 + 大数字,抖音/视频号/Reels 用 | --duration=6 --width=1080 --height=1920 | | compare.html | 前后对比:左右两栏对照,结论条收口 | --duration=7 | | flow-steps.html | 流程图动画:步骤依次点亮,当前步高亮 | --duration=7 | | subtitle-card.html | 逐句解说卡:一句话一句地出,底部带进度条 | --duration=8 + --srt | | vertical-subtitle.html | 竖屏字幕卡:关键词高亮,9:16 原生版式 | --duration=8 --width=1080 --height=1920 + --srt |

每个模板单文件自包含,顶部有一个显眼的 CFG 配置块,改文案/数据即可 —— 不用懂 canvas 也能出片。11 个模板全部支持换主题(见「换配色」一节)。 想做别的,再看 assets/animation-skeleton.html 从零写。

做「一支片子」而不是「一段动画」:用 assets/lib/scenes.js 写多镜头 + 转场, 镜头表还能用 --story=shots.json 外置 —— LLM 写 JSON 比写几百行 canvas 代码可靠得多。 详见下面「多镜头与转场」一节。

尺寸:模板跟视口走,不用手改

11 个模板都按 window.innerWidth/innerHeight 设画布,所以换任何尺寸都不裁切:

# 横屏 1080p(默认)
bash assets/render.sh title-card.html --duration=6 --fps=60
# 竖屏 9:16
bash assets/render.sh title-card.html --duration=6 --fps=60 --width=1080 --height=1920
# 720p / 4K 同理
bash assets/render.sh title-card.html --duration=6 --fps=60 --width=1280 --height=720

模板内部用三档缩放把设计稿落到实际画布:

| 变量 | 含义 | 1920×1080 | 1080×1920 | |---|---|---|---| | SX = W/1920 | 横向尺寸、左右边距 | 1 | 0.5625 | | SY = H/1080 | 纵向尺寸、行距 | 1 | 1.7778 | | SF = √(SX·SY) | 字号、线宽、圆角、模糊 | 1 | 1 |

字号用面积等比(SF)而不是跟宽度走 —— 换成竖屏时字不会变小,只是版式铺开。 1920×1080 下三者都等于 1,所以默认输出与旧版逐像素一致(实测 PSNR = inf)。

自己写的动画也照这个来,否则改 --width/--height 会静默裁掉右下角:

const cv = document.getElementById('stage');
cv.width  = window.innerWidth;      // ← 不要写死 1920
cv.height = window.innerHeight;     // ← 不要写死 1080

渲染器现在会主动量一次画布尺寸,比视口小就明确告警(不再静默出半张图)。

先装依赖(只需一次)

渲染器需要 Node 工作区(内含 playwright + 完整版 ffmpeg)。一条命令搞定:

bash scripts/install-deps.sh                       # 工作区默认 ~/.workbuddy/binaries/node/workspace
bash scripts/install-deps.sh /path/to/workspace    # 或自己指定

它会自动探测本机浏览器缓存、挑匹配的 playwright 版本、装完整版 ffmpeg, 并把工作区路径写进 ~/.workbuddy/.html2video-env,之后 render.sh / smoke.sh / qa.sh 开箱即用。

手动装也行(工作区需含 playwright + @ffmpeg-installer/ffmpeg),然后自己写配置:

# ~/.workbuddy/.html2video-env
WB_NODE_WORKSPACE="<你的 node 工作区绝对路径>"

也可以用环境变量临时指定:export WB_NODE_WORKSPACE="<路径>"。 不要把路径写进 ${VAR:-默认值}——用户名若含撇号(如 O'Brien), bash 会把撇号当引号开始,报 bad substitution。

四条硬约束(踩过,别重犯)

  1. Playwright 版本必须和浏览器缓存匹配。 playwright-core@X 只认自己在 browsers.json 里声明的 chromium build 号, 不匹配就报 "Executable doesn't exist"。

    → 别猜版本,用 scripts/install-deps.sh,它会跑 scripts/detect-env.js 探测缓存后自动挑版本。 单独探测:node scripts/detect-env.js(输出 RECOMMEND_PW=...)。 已知映射:build 1148→1.49.1、1155→1.50.1、1169→1.52.0、1187→1.55.0、1208→1.58.0。

    注意:某些网络环境下 chromium 下载会反复中断(表现为缓存目录里躺着半截的残缺目录)。 此时优先复用已有缓存而非升级——这正是探测脚本存在的理由。

  2. Playwright 自带的那个 ffmpeg 没用。 ms-playwright/ffmpeg-*/ffmpeg-win64.exe 是 --disable-everything 编译的, 只有 VP8 编码 + webm 封装,没有 H.264、没有 GIF、连 PNG 解码都没开。 必须用 @ffmpeg-installer/ffmpeg 的完整版。

  3. ESM 不认 NODE_PATH。 .mjs 里 import 'playwright' 必然 ERR_MODULE_NOT_FOUND。 → 辅助脚本一律写 CJS(.cjs / require)。

  4. PATH 不可靠。 尤其在 Git Bash / Windows 上,塞进 PATH 的 Windows 风格路径会被转换搞坏。 → 别靠 PATH 传 ffmpeg,用 FFMPEG 环境变量(渲染器已支持)。

出片流程

第 0 步(最省事的路):挑一个模板改字

cp assets/templates/bar-chart.html my-video.html
# 打开 my-video.html,只改顶部 CFG 里的 title / data / note
bash assets/render.sh my-video.html --duration=6 --fps=60

模板有字幕安全区意识:文字不会落在画面底部 15%(烧录字幕后会被盖住)。 自己做版式时也照这个来。

第 1 步:写动画 HTML(模板不够用时)

用 assets/animation-skeleton.html 当骨架。核心契约(渲染器靠它工作):

// 必须暴露这两个
window.__seek = (t) => { /* 把 t 时刻的画面完整重绘一帧 */ };
window.__ready = true;                 // 就绪信号

// 渲染器会注入 window.__seekRender = true,
// 此时必须【冻结自驱时钟】,完全由外部 __seek 推帧(保证确定性)
if (window.__seekRender) { renderAt(0); window.__ready = true; }
else { /* 浏览器预览:requestAnimationFrame 自驱循环 */ }

铁律:每一帧画面 = 时间 t 的纯函数。 不要依赖「上一帧」的状态, 不要用 Math.random() / Date.now() / performance.now()——那会让同输入不同输出, QA 里的「确定性」会亮红灯,而且多 worker 并行渲染会各渲各的。

画布就是唯一输出:<canvas width=1920 height=1080>,CSS 定位在 left:0; top:0, body margin:0。渲染器用 clip:{x:0,y:0,width:W,height:H} 截左上角,所以画布必须正好铺满视口、不能居中。

(渲染器也支持 DOM/CSS/SVG 动画,同样只需暴露 __seek——但注意:DOM 动画每帧重排较慢, 纯 canvas 通常更稳更快。)

禁止使用的 class 名(渲染器注入的 CSS 会无条件隐藏它们,元素会凭空消失): .no-record .progress .progress-bar .counter .tCur .phases .phase-label .phase .replay .masthead .kicker .title .footer 另外别给 position:fixed/sticky 的元素加 <button>,会被启发式规则当成播放控件隐藏。 (想让某块出现在成片里,给它加 data-record-keep="true" 就能豁免启发式隐藏。)

中文字体:'"Microsoft YaHei", "PingFang SC", system-ui, sans-serif';等宽用 'ui-monospace, Consolas, monospace'。

第 2 步:冒烟测试(别跳)

先只截几帧,确认契约就绪、没控制台报错、画面没糊,再跑全量:

bash assets/smoke.sh animation.html
# SMOKE_T="0,1,2" SMOKE_W=1280 SMOKE_H=720 bash assets/smoke.sh animation.html

更快的迭代方式:只渲一小段,几秒就能看到动态效果。

bash assets/render.sh animation.html --from=3 --to=5 --fps=30   # 只渲 3s–5s
bash assets/render.sh animation.html --stills=1,3,5            # 只导出三张静帧

第 3 步:全量渲染

bash assets/render.sh animation.html --duration=12 --fps=60 --width=1920 --height=1080 --concurrency=4

常用参数:

| 参数 | 作用 | |---|---| | --duration / --from / --to | 时长 / 只渲某段(秒)。给了范围时输出名变成 名.起-止s.mp4,不会覆盖成品 | | --stills=0.5,2.0 | 只导出这些时刻的 PNG,不编码 | | --fps / --width / --height | 帧率与分辨率 | | --preset=<名> | 按平台预设定尺寸:douyin / tiktok / vertical(1080×1920)、xiaohongshu(1080×1440)、instagram(1080×1350)、square(1080×1080)、bilibili / youtube / landscape(1920×1080) | | --presets=a,b,c | 一条命令出全套比例,每个比例一个成片(文件名自动加 -比例名 后缀)。跨平台发布用这个 | | --theme=<名> | 换主题(midnight / paper / neon),覆盖模板里的 CFG.theme,不用改文件。名字打错会明确告警并回退 midnight | | --out=<文件> | 指定成片路径(默认同目录同名)。一份 HTML 出多套配色时用它,否则后渲的会盖掉前一个;上级目录不存在会自动建 | | --json | stdout 只输出一行结果 JSON(output / duration / frames / warnings 等),人读日志全部走 stderr。给 Agent 解析用 | | --concurrency | 并行 worker 数(每个 worker 一个 Chromium 页面,注意内存)。给 auto 按 CPU 与内存自己挑 | | --audio=<file> | 编码后自动混音(视频流直接 copy,不重编码)。没给 --duration 时自动按音频长度出片(向上取整到整帧,尾音不被削) | | --audio-fit=trim\|pad | 音画长度不一致时怎么办:trim 按音轨收尾(默认)/pad 给音频补静音、保住视频长度 | | --gop=<秒> | 关键帧间隔,如 --gop=1 每秒一个关键帧,方便后期按秒 seek | | --keep-frames | 成功也保留逐帧 PNG(换 CRF 重编码时不必重截) | | --tmpdir=<目录> | 逐帧 PNG 放哪块盘(默认挨着 HTML)。1080p 一分钟约 2.4 GB,系统盘没余量时指到别的盘 | | --resume | 上次渲到一半被打断?接着渲,已渲好的帧直接复用(参数和上次不一致会拒绝,见下) | | --alpha | 透明背景输出(ProRes 4444 .mov),叠到实拍 / AI 生成画面上用,见下 | | --srt=<file> | 外部字幕时间轴(SRT / VTT / JSON),注入 window.__cues,见下。同义参数 --cues | | --cue-log=<file> | 导出 frame,t,cue_index,cue_start,cue_end CSV,用来核对字幕到底对不对轴 | | --story=<file> | 镜头表 JSON,注入 window.__story,整份换掉剧本(见「多镜头与转场」) | | --scene-log=<file> | 导出镜头时间轴 CSV;镜头表总时长与 --duration 不一致会告警 | | --gif[=fps,宽] | 出片后顺手产 GIF(默认 15fps / 宽 960),两阶段 palette 优化,不重渲 | | --poster=<秒> | 出片后顺手抽一张封面静帧 .jpg,发站 / 社媒用 | | --batch=<file.json> | 一串任务按顺序渲,最后打汇总表;单个失败不连坐已渲好的,但整体非零退出 | | --headed | 开着浏览器窗口渲(调试用;并发自动降到 1,免得弹一排窗口) | | --allow-errors | 页面报错不判失败(默认:有报错 → 非零退出) | | --keep-chrome | 不隐藏播放控件(调试用) | | --readytimeout=8 | 等 __seek 就绪的秒数(启动慢的大字体/大数据可调大) | | --no-serve | 用 file:// 加载页面(默认走本地 http server,见下) |

ESM / fetch 项目直接能渲。渲染器默认起一个只绑 127.0.0.1 的本地 http server 来加载页面 —— file:// 下 <script type="module"> 和 fetch() 会被 CORS 拦死,用 Vite/esbuild 组织的动画、 读本地 JSON 的项目根本起不来;走 http 就没这些事。渲染开头会打印这个地址,排障时直接粘到浏览器里看控制台最方便。 服务器起不来会自动退回 file:// 并提示(只警告,不判失败)。

  • 输出与 HTML 同名的 .mp4
  • 帧数 = fps × duration。12s@60fps = 720 帧,实测约 6~7 分钟(concurrency=4)
  • 编码约 1 分钟(crf 18 / preset medium)

渲染结束有页面报错会非零退出(但成片照样产出,方便你核对)。

渲到一半断了,别从零开始

长片子(60fps × 30s = 1800 帧)跑到 80% 崩了,从零重来最伤。加 --resume 就接着渲:

bash assets/render.sh animation.html --fps=60 --duration=30 --resume
# ▸ resume: 已复用 1432 帧,还需渲 368 帧

规则三条,都是为了「续出来的片子和一次渲完的片子一模一样」:

  • 帧先写 .part 再改名。被 kill 的那一帧不会留下半个 PNG 冒充「已完成」,所以复用的帧都是真画完的。
  • 参数变了直接拒绝。上次 30fps、这次 60fps 会把两批帧混着编码,片子前后节奏不一致还不报错 —— 所以 fps / 尺寸 / 范围 / 渲染模式 任一不同就退出并打印「上次 vs 这次」,让你自己决定删不删。
  • 帧号必须连续。缺一张 ffmpeg 会静默提前收尾、成片莫名变短,所以编码前按 [起,止) 逐个核号, 有洞就报出来并提示加 --resume 补。

临时目录固定在 HTML 旁边的 .seek-tmp-resume/(不加 --resume 时仍是一次性目录,并发渲互不干扰)。 渲完自动清掉;中途想留着就配 --keep-frames。 这是故意的:页面报错常常意味着「整片黑屏 / 缺了半屏内容」,以前的版本会一路说成功, 直到你回抽帧才发现——现在它会在编码前就把报错打出来,并在最后判失败。

透明输出:把文字层叠到别人拍的画面上

AI 生成的背景 + 代码生成的文字层,是现在最省钱的组合(模型画文字必糊,代码画文字精确到像素)。 --alpha 就是为这条路准备的:

bash assets/render.sh animation.html --duration=6 --fps=30 --alpha
# → animation.mov(ProRes 4444 / yuva444p10le,背景透明)

模板侧要配合一件事:读到 window.__transparent 为真时跳过背景层绘制。 目前 title-card、compare、flow-steps、subtitle-card、vertical-subtitle、 explainer 这 6 个已经这样写,直接加 --alpha 就有透明效果; 其余 5 个是满版图表(条形 / 折线 / 大数字 / 时间线 / 竖屏卡),本来就要底色,加了也只会得到不透明的片子。 自己写的动画照这个来:

const TRANSPARENT = !!window.__transparent;
function drawFrame(t) {
  g.clearRect(0, 0, W, H);
  if (!TRANSPARENT) {
    // 底色 / 全屏渐变 / 光斑 —— 这些都要跳过
    g.fillStyle = '#080A10';
    g.fillRect(0, 0, W, H);
  }
  // 文字、图形照常画
}

全屏的半透明光晕也要一起跳过。哪怕它只有 5% 不透明度,叠到实拍上会让整片区域泛白, 剪辑师第一反应是「这素材脏」。实测:只跳底色、留着光斑时,四角 alpha=12(不是 0); 全跳之后四角 alpha=0、只有 3.7% 的像素不透明(全是文字)。

体积代价(960×540 / 2s / 20 帧实测):

| 输出 | 体积 | 用途 | |---|---|---| | H.264 .mp4 | 118 KB | 成片直接发 | | ProRes 4444 .mov | 760 KB(6.5×) | 拖进剪辑软件叠层 |

只有 ProRes,没有 VP9。试过 --pix_fmt yuva420p + -auto-alt-ref 0,文件确实从 7.8KB 涨到 16.8KB(alpha 数据写进去了),但 Chromium 播出来整帧 alpha 全 0 —— 连文字都透明; 换 lossless、固定码率、-lag-in-frames 0 都一样。既然没法自证正确,就不把它作为选项发布。 要小体积透明素材,用 ProRes 导入剪辑软件后再导 webm,那是那边的活。

配音对齐:先有声音,再定画面长度

真实工作流是「写文案 → 配音 → 配画面」,而不是先定 6 秒再想办法把配音塞进去。 所以给了 --audio 又没给 --duration 时,视频按音频长度出片:

bash assets/render.sh title-card.html --audio=voice.m4a --story=shots.json
# ▸ audio: 音频 12.48s,未指定 --duration → 视频按音频定长(12.5s,向上取整到整帧)
  • 向上取整到整帧,不是四舍五入:少半帧就会把最后一个字的尾音削掉。
  • 显式给了 --duration 且与音频差超过 0.35s 会明确告警,说清差多少、伤在哪边。 旧版本这里会静默出一支短片 —— 画面后半段整段消失,日志却只有一句 ✓ Done。
  • --audio-fit=pad:音频比视频短时补静音,保住整段画面(默认 trim 按音轨收尾)。

注意:trim 下成片不会精确等于音频秒数。视频流是 -c:v copy 直接复制的, ffmpeg 只能按帧包边界收尾,实测会多留 0.3–0.5s。想要毫秒级对齐得重编码, 那是拿画质换精度,不值得 —— 片尾多留几帧通常看不出来。

一稿多发:一条命令出全套平台比例

同一条片子要发抖音、小红书、B 站,剪辑软件里得一个比例一个序列、导一次盯一次。 这里版式本来就是参数化的,多渲一遍只是多一次循环:

bash assets/render.sh bar-chart.html --duration=8 \
  --presets=douyin,xiaohongshu,square --out=dist/chart.mp4
# → dist/chart-douyin.mp4       1080×1920
#   dist/chart-xiaohongshu.mp4  1080×1440
#   dist/chart-square.mp4       1080×1080

| 预设 | 尺寸 | 给谁用 | |---|---|---| | douyin / tiktok / vertical | 1080×1920 | 抖音、快手、视频号、Reels、Shorts | | xiaohongshu / xhs | 1080×1440 | 小红书 3:4 | | instagram / ig | 1080×1350 | IG 信息流 4:5 | | square | 1080×1080 | 方版 1:1 | | bilibili / youtube / landscape | 1920×1080 | 横屏 16:9 |

  • 单个比例用 --preset=xiaohongshu;多个用 --presets=a,b(至少两个,只想要一个就用 --preset)。
  • 预设名拼错会直接失败并列出可用名字 —— 不会悄悄按 1920×1080 渲一版比例

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars0
CategoryDesign
UpdatedNaNy ago
Forks0

Trust signals

68/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

2 medium1 low
html-to-video — Universal Skill: Install & Safety Check | SkillAgent