通过 CLI 生成视频
快速参考
# 编写配置 → 生成 JSON → 渲染
node scripts/gen_canvas.mjs /tmp/video-<name>.mjs /tmp/video-<name>.json
npx hypr-video-cli /tmp/video-<name>.json -o ./output/<name>.mp4
工作流程
- [ ] 第一步:阅读参考文档并规划场景
- [ ] 第二步:构建配置并生成 JSON
- [ ] 第三步:渲染并验证
第一步 — 阅读参考文档并规划场景
1a. 阅读以下参考文档(始终必需):
- gen-canada.md — 配置规范:
theme()(24 个主题)、11 个角色辅助函数、autoTracks()、内联animIn/animOut/kf、SVG 辅助函数、buildCanvas。常见陷阱以 ⚠️ 标记标出。
1b. 规划场景:确定视频类型,列出场景名称/时长,为每个场景选择最佳的 SVG 辅助函数、元素和表情符号。
1c. 根据规划阅读额外内容:
| 何时阅读 | 参考文档 |
|---|---|
| 使用 SVG 辅助函数时(几乎总是) | svg-helpers.md — 所有 65 个辅助函数的参数 |
| 选择字体时 | font-assets.md — 18 个内置字体及搭配 |
| 添加表情符号/Unicode 装饰时 | icons.md |
第二步 — 构建配置并生成 JSON
2a. 编写一个配置 .mjs 文件。配置和 JSON 存放于 /tmp/ 目录下——绝不要写入 examples/。
export default function build(h) {
const {
makeShape, makeEffect, buildCanvas, theme, autoTracks,
svgVignette, svgDotGrid, svgGradientOrb, svgParticles,
svgCheckMark, svgNumberCounter, // ...按需引入 SVG 辅助函数
} = h;
const t = theme("cyberpunk"); // 24 个主题 — 颜色 + 角色辅助函数 + 字体
const MAX = 25000;
// ── 全局层 ──
const g_dot = svgDotGrid("g_dot", { start: 0, end: MAX, opacity: 0.04, color: t.ACCENT });
const g_vig = svgVignette("g_vig", { start: 0, end: MAX, opacity: 0.6 });
// ── 场景 1:片头 (0–7 秒) ──
const s1_orb = svgGradientOrb("s1_orb", {
x: 360, y: 60, w: 1200, h: 960, start: 0, end: 7500, opacity: 0.10, color: t.ACCENT,
});
const s1_title = t.hero("s1_title", "Product Name", {
x: 160, y: 340, start: 0, end: 7000,
animIn: ["blurIn", 1200], animOut: ["blurOut", 700],
kf: { scale: { dur: 7000, amp: 0.02 } },
});
const s1_div = makeShape("s1_div", "rect", t.ACCENT, {
x: 760, y: 510, w: 400, h: 3, start: 500, end: 6500,
animIn: ["expandIn", 500], animOut: ["fadeOut", 300],
});
const s1_sub = t.subtitle("s1_sub", "Tagline goes here", {
x: 260, y: 540, start: 700, end: 6500,
animIn: ["fadeIn", 800], animOut: ["fadeOut", 500],
});
// ── 场景 2:功能特性 (6.5–16 秒) ──
// ... 更多场景遵循相同的模式
const elements = [g_dot, g_vig, s1_orb, s1_title, s1_div, s1_sub /* ... */];
return buildCanvas({
bg: t.BG, maxTime: MAX,
// t.fonts 是一个对象 { Montserrat: {...}, "Fira Code": {...}, ... } — 不是数组
// 要添加额外字体(例如中日韩文字),请使用对象展开:
fontAssets: {
...t.fonts,
"Noto Sans SC": { url: "skill/assets/fonts/NotoSansSC-Variable.ttf", fileType: "ttf" },
},
elements, tracks: autoTracks(elements),
fps: 30, quality: "medium",
});
}
node scripts/gen_canvas.mjs /tmp/video-<name>.mjs /tmp/video-<name>.json
2b. 在渲染之前,请验证:
- 所有文本都使用了角色辅助函数(
t.hero…t.eyebrow)——仅在需要自定义字体/大小/颜色时(例如代码块、使用Noto Sans SC的中日韩文字)才使用原始的makeText - 每个可见元素都具有
animIn+animOut;元素之间的交错时间为 300–500 毫秒 - SVG 背景不透明度 ≤ 0.15;每个场景使用 2–4 个辅助函数;全局层跨越
0–MAX maxTime>= 最后一个元素的end
第三步 — 渲染并验证
npx hypr-video-cli /tmp/video-<name>.json -o ./output/<name>.mp4
CLI 标志:--fps 24|30|60,--quality low|medium|high|very_high,--format mp4|mov|mp3,--width N,--height N,-q(静默模式)。
如果渲染失败 → 请检查 gen-canada.md 中的 ⚠️ 常见陷阱
关键规则
maxTime>= 最大元素的end— 太小会导致元素被截断- 配置文件放在
/tmp/目录下 — 绝不要写入examples/ - 始终使用现代 API —
theme()+ 角色辅助函数 + 内联animIn/animOut/kf+autoTracks() - 场景结构 — 元素 ID 使用
s1_/s2_… 前缀,每个场景独占一组;使用注释块// ── 场景 N:标题 (Xs–Ys) ── - 过渡效果需要相邻元素位于同一轨道(推荐使用基于效果的闪光/故障切换)
- 使用
backgroundColor时通过bg: t.BG— 不要使用全屏背景形状 gen_canvas.mjs路径 — 从技能根目录运行:node scripts/gen_canvas.mjs(不是skill/scripts/)t.fonts是对象,不是数组 — 使用{ ...t.fonts, "额外字体": { url: "...", fileType: "ttf" } }添加字体。绝不要使用[...t.fonts](数组展开)