OpenHyperCore
OpenHyperCore 是一个面向低成本 CPU 服务器的视频剪辑渲染引擎原型。它用 TypeScript 描述 Scene Graph,使用 CanvasKit/Skia 做帧渲染,并通过 FFmpeg 输出 H.264/AAC MP4,目标是在不依赖 Chromium、无 GPU 的环境中提供比浏览器渲染链路更轻量、更可控的视频生成能力。
当前项目处于 alpha 阶段,核心 CLI 与渲染管线已经可用,但还不是完整的 HyperFrames 替代品。已实现的能力覆盖图文合成、字幕层、可复用电影感特效 helper、场景时间线编排、PNG still、无音频 MP4、音频合流、多音频混音、VideoLayer、本地素材 probe/cache、raw RGBA 视频帧批量解码、增量帧复用、worker_threads 帧级并行和 AWS 2CPU/2G benchmark 验证;服务化接口和发布打包流程仍在 Roadmap 中。
开源
OpenHyperCore 为开源 TypeScript 视频渲染内核,适合被集成到模板视频生成、批量剪辑、服务端渲染和自动化内容生产链路中。项目采用 MIT License,详见仓库根目录 LICENSE 文件。
作为包使用
npm install openhypercore合成 IR 是纯 JSON 可序列化数据,因此「编排」与「渲染」解耦——可在任意环境(含浏览器)编排,在 Node 服务端渲染。
// 编排(浏览器安全,无 Node/ffmpeg 依赖):主入口即 core。
import { defineComposition, interpolate, cubicBezier } from "openhypercore";
const composition = defineComposition({
fps: 30, width: 1280, height: 720, durationMs: 2000,
layers: [
{ type: "shape", shape: "rect", width: 1280, height: 720, fill: { type: "linear", from: [0, 0], to: [0, 720], stops: [{ offset: 0, color: "#1b2a4a" }, { offset: 1, color: "#070b14" }] } },
{ type: "text", text: "Hello", size: 96, color: "#fff", align: "center",
transform: { x: 640, y: 380, opacity: [{ timeMs: 0, value: 0 }, { timeMs: 600, value: 1, easing: [0.2, 0, 0, 1] }] } }
]
});// 渲染(Node):解析某帧并栅格化,或编码为 MP4。
import { resolveFrame } from "openhypercore";
import { renderPngFrame } from "openhypercore/renderer-skia";
const png = await renderPngFrame(resolveFrame(composition, 600));CLI(便于脚本与 Agent 调用——probe/still/render/bench):
npx openhyper render my-composition.ts --out out.mp4
npx openhyper render my-composition.ts --out out.mp4 --renderer native --workers auto子路径入口:openhypercore(≡ openhypercore/core,编排 IR + 动画)、openhypercore/renderer-skia(CanvasKit 栅格)、openhypercore/renderer-svg、openhypercore/encoder-ffmpeg、openhypercore/assets、openhypercore/jsx-runtime、openhypercore/cli。
默认使用可搬的 CanvasKit/wasm 后端(无需原生二进制)。原生(Rust + skia-safe)后端——快 ~8–14×——为可选项:用 pnpm build:native 从源码构建并以 --renderer native(或 OPENHYPERCORE_RENDERER=native)选用;跨平台 prebuilt 二进制在规划中。
功能特点
- Scene Graph IR:用纯数据描述 Composition、Layer、Transform、Keyframe,便于缓存、测试和后续服务化。
- TypeScript API 与轻量 JSX runtime:不引入 React,JSX/命令式写法最终都落到 Composition IR。
- CanvasKit/Skia 渲染后端:支持文本、矩形/圆形/path、图片和第一版本地 VideoLayer。
- 原生渲染后端(Rust + skia-safe,可选):在同一
FrameRenderer接缝下整帧原生绘制,与 wasm 渲染器功能对齐(golden 测试验证),吞吐大幅提升——特效密集 1080p 场景实测渲染快 ~8x、端到端快 ~6x。用pnpm build:native构建(需 Rust 工具链),再以--renderer native(或OPENHYPERCORE_RENDERER=native)选用;wasm 后端仍为默认与可搬 fallback。原生后端逐帧直绘(无需静态层栅格缓存——直绘已快过 wasm 的缓存贴图)。基准:node --experimental-strip-types packages/renderer-native/scripts/bench-vs-wasm.mjs。 - SVG debug still 与 PNG still:可快速检查单帧布局,也可生成真实 CanvasKit PNG。
- CaptionLayer:支持时间段字幕、字体大小、颜色、背景色、padding、对齐和 transform 位置。
- 全属性 transform:每个图层都可用关键帧驱动
x/y/scale/scaleX/scaleY/rotate/opacity。关键帧可附带 easing(预设名、自定义函数,或 CSS 风格cubicBezier(x1,y1,x2,y2)/[x1,y1,x2,y2]元组),作用于“终止于该关键帧”的区间——任意轨道无需烘焙即可获得逐帧精确曲线,见examples/full-transform-easing.ts。 - 转场 helper:提供 fade、slide、scale preset,并输出可复用 Scene Graph transform keyframes;支持 easing preset(
easeIn/easeOut/easeInOut/sine/quart/expo/back/elastic/bounce/...、自定义缓动函数或贝塞尔元组),通过采样烘焙为关键帧。 - 时间线 DSL:
composeTimeline可将同一属性的多段动画按时间串联(如同一图层的入场淡入 + 出场淡出),delayTransition可整体平移 transform 时间用于错峰编排。 - GroupLayer 预合成:
group图层在共享 transform 与组透明度下嵌套子图层(经 saveLayer 作为整体合成,无重叠双重混合)。子图层与 group 自身的关键帧都使用 group 本地时间轴,只改startMs即可整体搬移一段带动画的内容(对标 Remotion<Sequence>语义),见examples/group-spring.ts。 - Remotion 风格动画 API:
interpolate(t, inputRange, outputRange, { easing, extrapolateLeft/Right })支持多段映射;闭式解阻尼弹簧spring()与springKeyframes()可把物理弹簧运动烘焙为关键帧轨道。 - 场景级转场:
createTransitionSeries(...).scene(...).transition({ type, durationMs, direction, easing })串联整屏场景并产生真正重叠的转场——wipe、clockWipe(遮罩揭示)、slide(整屏推移)、flip(绕中心轴翻面);相邻场景按转场时长重叠(对标 Remotion TransitionSeries 语义),见examples/scene-transitions.ts。 - IR 新增逐轴缩放与揭示遮罩:
transform.scaleX/scaleY(与统一scale相乘);GroupLayer.reveal(wipe/clock,动画化 0→1progress)把 group 裁剪到扫掠矩形或时钟楔形区域。 - 静态图层栅格缓存:内容跨帧不变(只有 transform/透明度/reveal 在动)的 group 只栅格化一次、之后直接贴图。缓存由成本模型驱动且自调优——实测每次直绘耗时,只缓存“直绘比预估贴图更慢”的子树,平价场景零回归,辉光/密集文字卡片自动加速。可用
cache: false(单个 group)或--no-layer-cache(全局)关闭;图片图层另有跨帧解码缓存。 - 电影感特效 helper:
cinematicBars、flashTransitionLayer、speedLineBurst、glitchTitle可生成片头/转场常用 layer stack,减少手写大量图层。 - 场景时间线 builder:
createTimeline(...).scene(...).transition(...).build()可顺序编排命名场景和转场,并返回 Composition 与 timing markers。 - 图层 fit 模式:
ImageLayer.fit与VideoLayer.fit支持fill(拉伸)、cover(居中裁切)、contain(letterbox 留边);圆形裁切默认cover。 - 视觉效果:渐变填充(
fill/color/backgroundColor接受{ type: "linear"|"radial", stops })、逐图层blendMode(multiply/screen/overlay/add/...)、整层blur(高斯模糊)与方向性motionBlur({ angle, distance, samples }),见examples/effects-showcase.ts。 - 任意形状裁剪:任意图层(或整个 group)可设置
clip为本地坐标系下的rect(可带圆角radius)、circle或 SVGpath区域。 - 文本排版:text/caption 支持显式
\n与按maxWidth自动换行(Latin 按词、CJK 按字),并支持逐行align(left/center/right)。 - 字体:提供命名字体注册表(
registerFont(name, path))与逐字符 fallback 字体栈,支持彩色 emoji fallback(registerEmojiFont)。 - 字幕:
parseSubtitles解析 SRT/WebVTT 为带时间的 cue,subtitlesToCaptions生成带样式、按时间显示的 CaptionLayer。 - FFmpeg 编码后端:通过 raw RGBA stdin pipe 输出 H.264/yuv420p MP4;有音频时输出 AAC。
- AudioLayer:支持单音频、多音频 amix、start/end、fadeIn/fadeOut;
volume既可为常量也可为关键帧包络(压低/渐强),编译为 FFmpeg 逐帧 volume 表达式。 - VideoLayer:支持从本地视频按时间点抽帧并贴入 Skia 画布,支持
playbackRate(变速)与loop(在 trim 窗口内循环);有width/height的视频层会按源视频尺寸批量解码 raw RGBA,绕过 PNG 中间格式与 CanvasKit 每帧图片解码。 - 资产 probe/cache:提供图片、视频、音频 metadata probe,以及任务级缓存 API。
- 帧级优化:连续视觉内容相同则复用 RGBA buffer,保持编码帧序和 PTS 不变。
- worker_threads 并行渲染池:支持
--workers N、--workers auto、--worker-window N控制并行度与内存窗口。 - 持久帧缓存:
--cache-dir <dir>将解码后的 RGBA 帧按 源路径 + mtime/size + 时间 + 尺寸 落盘缓存,可跨渲染任务复用,并在指向同一目录的 worker 进程间共享。 - Benchmark:输出帧数、复用帧、worker 配置、音频 timeline、渲染耗时、编码耗时、峰值 RSS 等指标。
当前限制
- 仍是 alpha 工程原型,API 可能继续调整。
- VideoLayer 已具备源尺寸探测、任务级 raw RGBA 帧缓存、窗口化批量预取,并通过
--cache-dir支持跨任务持久磁盘缓存(同时在 worker 间共享)。解码已按连续顺序批量 pass 进行(无逐帧 seek);显式的 GOP/关键帧对齐调度仍是后续优化。 - 文本排版已支持多行换行、对齐、字体注册和 emoji fallback,但尚未支持行内富文本(单行内混合样式)或双向/复杂文种 shaping。
- 彩色 emoji fallback 依赖宿主机存在 emoji 字体(自动探测,或通过
registerEmojiFont指定);若没有,则 emoji 回退到默认字体。 - 转场 helper 已支持 easing preset、组合属性时间线 DSL(
composeTimeline/delayTransition)与轻量场景时间线 builder;更完整的 track-based 编辑时间线仍是后续工作。 - 尚未实现 HTTP 服务、可视化编辑器和发布打包流程。
环境要求
- Node.js 24+,当前测试命令使用
node --experimental-strip-types直接运行 TypeScript。 - pnpm。
- FFmpeg。项目依赖
@ffmpeg-installer/ffmpeg,多数本地场景无需额外安装;也可以通过 CLI 的--ffmpeg-path指定系统 FFmpeg。
安装与验证
pnpm install
pnpm check
pnpm build
pnpm test常用开发命令:
pnpm cli probe examples/simple-video.ts
pnpm cli still examples/simple-video.ts --t 1 --out /tmp/openhyper-frame.svg
pnpm cli still examples/simple-video.ts --t 1 --out /tmp/openhyper-frame.png --format png
pnpm cli render examples/simple-video.ts --out /tmp/openhyper.mp4
pnpm cli render examples/effects-opener.ts --out /tmp/openhyper-effects.mp4
pnpm cli bench examples/simple-video.ts --out /tmp/openhyper-bench.json --video-out /tmp/openhyper-bench.mp4
pnpm cli bench-suite examples/bench/animated-workload.ts --static examples/bench/static-reuse.ts --out /tmp/openhyper-bench-suite.json --video-dir /tmp/openhyper-bench-suite构建后也可以直接运行编译产物:
node dist/packages/cli/src/index.js probe examples/simple-video.ts
node dist/packages/cli/src/index.js render examples/simple-video.ts --out /tmp/openhyper.mp4CLI 使用
probe
打印 Composition 的基础信息,包括 fps、尺寸、时长、帧数和 layer 数量。
pnpm cli probe examples/simple-video.tsstill
导出指定时间点的单帧。默认输出 SVG debug still;加 --format png 后使用 CanvasKit 输出 PNG。
pnpm cli still examples/simple-video.ts --t 1 --out /tmp/frame.svg
pnpm cli still examples/simple-video.ts --t 1 --out /tmp/frame.png --format pngrender
渲染 MP4。默认走 raw RGBA pipe 到 FFmpeg;无音频时输出 H.264 MP4,有 AudioLayer 时输出 H.264 + AAC MP4。
pnpm cli render examples/simple-video.ts --out /tmp/openhyper.mp4
pnpm cli render examples/simple-video.ts --out /tmp/openhyper-720p.mp4 --fps 24 --size 1280x720
pnpm cli render examples/simple-video.ts --out /tmp/openhyper-worker.mp4 --workers auto --worker-window 4可指定 FFmpeg 路径或额外前置参数:
pnpm cli render examples/simple-video.ts --out /tmp/openhyper.mp4 --ffmpeg-path /usr/local/bin/ffmpeg
pnpm cli render examples/simple-video.ts --out /tmp/openhyper.mp4 --ffmpeg-arg-prefix -hide_banner--cache-dir <dir> 开启持久磁盘 RGBA 帧缓存:解码帧按 源路径 + mtime/size + 时间 + 尺寸 作为 key,可跨渲染复用,并在指向同一目录的 worker 进程间共享:
pnpm cli render examples/simple-video.ts --out /tmp/openhyper.mp4 --workers auto --cache-dir /tmp/openhyper-cachebench
渲染视频并输出 JSON 指标,适合比较单线程、worker 和窗口大小配置。
pnpm cli bench examples/simple-video.ts \
--out /tmp/openhyper-bench.json \
--video-out /tmp/openhyper-bench.mp4 \
--workers auto典型指标包括:
renderMode、workerSelection、workerCount、workerWindowframes、renderedFrames、reusedFrames、maxBufferedFramesdurationMs、frameDurationMs、encodedVideoDurationMsaudioInputs、audioTimelineStartMs、audioTimelineEndMsrenderWallMs、renderCpuMs、encodeMs、totalMs、peakRssBytes
bench-suite
运行 M4.1 benchmark 对比套件,自动生成四组 case:
single-thread:动态 workload,单线程渲染worker:动态 workload,worker_threads 渲染worker-window:动态 workload,worker_threads + 缓冲窗口static-reuse:静态 fixture,验证帧复用路径
pnpm cli bench-suite examples/bench/animated-workload.ts \
--static examples/bench/static-reuse.ts \
--out /tmp/openhyper-bench-suite.json \
--video-dir /tmp/openhyper-bench-suite \
--workers 2 \
--worker-window 4也可以直接运行内置 fixture 脚本:
pnpm bench:fixturesBenchmark
M4.2/M4.3 前置优化在 AWS 服务器上完成 1080p30 / 5s benchmark。测试机器为 2 vCPU、约 2GiB RAM、2GiB swap,无 GPU;输出均为 H.264、1920x1080、30fps、5.000s。
测试命令:
pnpm cli bench-suite examples/bench/animated-workload.ts \
--static examples/bench/static-reuse.ts \
--out bench-results/m4.3-pre/suite-1080p30-2cpu2g-final.json \
--video-dir bench-results/m4.3-pre/videos-final \
--fps 30 \
--size 1920x1080 \
--workers 2 \
--worker-window 2| case | total | render wall | encode | peak RSS | frame result |
|---|---|---|---|---|---|
single-thread |
4.99s | 3.30s | 1.69s | 236MB | 150 rendered / 0 reused |
worker |
6.42s | 4.28s | 2.15s | 600MB | 150 rendered / 0 reused |
worker-window |
6.59s | 4.76s | 1.83s | 561MB | 150 rendered / 0 reused |
static-reuse |
2.85s | 0.02s | 2.83s | 291MB | 1 rendered / 149 reused |
结论:
- 在 2CPU/2G 机器上,
single-thread是动态图文 workload 的推荐路径,5 秒 1080p30 视频约 4.99 秒完成,达到 5s 设计目标。 - 静态复用路径有效,150 帧只渲染 1 帧,其余 149 帧复用,总耗时约 2.85 秒。
- 所有 case 峰值 RSS 均低于 800MB 内存目标。
worker_threads现在复用持久渲染池,但在 2CPU/2G 低核数机器上仍慢于单线程,主要受并行 CanvasKit surface、线程通信和内存压力影响;2CPU 部署默认不建议启用 worker。
真实视频 demo 对照
以下数据来自同一台 AWS 2CPU/2G 服务器。测试素材为服务器本地 ignored fixture examples/demo.mp4,用于模拟“快速下扶梯进入地铁”的真实视频剪辑;素材文件和生成视频不提交到 GitHub。
| renderer | scenario | total | render wall | encode | peak RSS | note |
|---|---|---|---|---|---|---|
| OpenHyperCore | PNG batch VideoLayer | 64.07s | 62.86s | 1.21s | 249MB | 已批量抽帧,但仍有 PNG 编码/解码 |
| OpenHyperCore | raw RGBA source-sized VideoLayer | 52.63s | 51.60s | 1.03s | 235MB | 绕过 PNG,中间帧按源视频 480x272 缓存 |
| OpenHyperCore | raw RGBA + 2 workers | 63.12s | 62.10s | 1.02s | 487MB | 2CPU 上 worker 路径仍慢于单线程 |
| HyperFrames | Chromium screenshot fallback | 162.63s | n/a | n/a | 212MB | 当前服务器 Chromium 缺少 beginFrame,走 screenshot fallback |
结论:真实视频剪辑下,raw RGBA VideoLayer 相比 PNG batch 路径约快 18%,相比该服务器上的 HyperFrames fallback 约快 3.1 倍。下一步性能瓶颈主要在 CanvasKit 逐帧合成和 worker 间视频帧缓存无法共享,2CPU 机器默认仍建议 single-thread。
Composition 示例
最小命令式 Scene Graph:
import { defineComposition } from "../packages/core/src/index.ts";
export default defineComposition({
fps: 30,
width: 1280,
height: 720,
durationMs: 3000,
layers: [
{
type: "shape",
shape: "rect",
width: 1280,
height: 720,
fill: "#101820"
},
{
type: "text",
text: "OpenHyperCore",
size: 84,
color: "#f6f7f9",
transform: {
x: 120,
y: 220,
opacity: [
{ timeMs: 0, value: 0 },
{ timeMs: 600, value: 1 }
]
}
}
]
});音频示例:
{
type: "audio",
src: "./assets/music.wav",
startMs: 0,
endMs: 3000,
volume: 0.7,
fadeInMs: 300,
fadeOutMs: 500
}视频贴图示例:
{
type: "video",
src: "./assets/clip.mp4",
startMs: 500,
endMs: 2500,
trimStartMs: 1000,
width: 640,
height: 360
}字幕示例:
{
type: "caption",
text: "这一段会显示在画面底部",
startMs: 500,
endMs: 2500,
size: 42,
color: "#ffffff",
backgroundColor: "#000000",
padding: 12,
align: "center",
transform: { x: 640, y: 660 }
}转场 helper 示例:
import {
fadeTransition,
mergeTransforms,
scaleTransition,
slideTransition
} from "openhypercore/core";
{
type: "text",
text: "Animated title",
transform: mergeTransforms(
fadeTransition({ startMs: 0, durationMs: 600 }),
slideTransition({
startMs: 0,
durationMs: 600,
from: { y: 40 },
to: { y: 0 }
}),
scaleTransition({ startMs: 0, durationMs: 600, from: 0.92, to: 1 })
)
}特效 / 时间线片头示例:
import {
cinematicBars,
createTimeline,
flashTransitionLayer,
glitchTitle,
speedLineBurst
} from "openhypercore/core";
const timeline = createTimeline({ width: 1280, height: 720, fps: 30 })
.scene("intro", 1600, ({ startMs, endMs, width, height }) => [
...speedLineBurst({ width, height, startMs, endMs, count: 18, seed: 9 }),
...cinematicBars({ width, height, startMs, endMs }),
...glitchTitle({ text: "METRO RUN", startMs, endMs, x: 120, y: 340, size: 96 })
])
.transition("flash", 240, ({ startMs, width, height }) => [
flashTransitionLayer({ width, height, startMs, durationMs: 240 })
])
.build();
export default timeline.composition;资产 probe/cache 示例:
import { createAssetProbeCache } from "openhypercore/assets";
const cache = createAssetProbeCache();
const clip = await cache.probe("./assets/clip.mp4");
console.log(clip.width, clip.height, clip.durationMs);视频帧缓存示例:
import { createVideoFrameCache, renderRgbaFrame } from "openhypercore/renderer-skia";
const videoFrameCache = createVideoFrameCache();
const rgba = await renderRgbaFrame(frame, { videoFrameCache });仓库结构
packages/
core/ Scene Graph IR、Composition 校验、调度器、关键帧、特效/时间线 helper
jsx-runtime/ 自定义 JSX runtime,输出 IR
renderer-svg/ SVG debug still 后端
renderer-skia/ CanvasKit PNG/RGBA 渲染后端
encoder-ffmpeg/ FFmpeg rawvideo/image pipe、H.264/AAC 编码、音频 filter graph
assets/ 图片/视频/音频 probe 与任务级缓存
cli/ openhyper CLI、render/bench、worker_threads 调度
examples/ 示例 Composition
examples/bench/ M4.1 benchmark fixtures
Roadmap
- M3.5:已完成
packages/assets,提供图片/视频/音频 probe、尺寸/时长元信息和任务级缓存。 - M3.6:已完成任务级视频帧缓存、窗口化批量预取和 raw RGBA VideoLayer 解码,避免同一视频/同一时间点重复 FFmpeg 抽帧,并绕过 PNG 中间格式。
- M3.7:已完成基础 CaptionLayer,支持时间段文本、样式和位置。
- M3.8:已完成转场 preset、easing、组合 transform 时间线、电影感特效 helper 与轻量场景时间线 builder。
- M4.1:已完成 benchmark fixtures 与
bench-suite,对比 single-thread、worker、worker+window、静态复用路径。 - M4.2:已在 AWS 2CPU/2G 服务器上运行 benchmark,验证 1080p30/5s 与 <800MB 内存目标。
- M4.3:输出 benchmark 对比摘要 JSON,便于 CI 和服务器验收。
- M4.4:完成持久磁盘视频帧缓存加固,并修复部分缓存命中时 batch miss 顺序保持问题。
- M5:补齐项目模板、用户文档、错误提示、更完整 track-based 时间线和发布打包流程。
目标
OpenHyperCore 的长期目标是成为一个轻量、可编程、易部署的视频剪辑渲染内核:在低规格服务器上完成图文、图片、视频片段和音频的批量合成,并为后续 HTTP 服务、模板系统和可视化编辑器提供稳定的底层渲染能力。