npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

openhypercore

v0.6.3

Published

Lightweight, GPU-free video composition + rendering engine: a JSON scene-graph IR, CanvasKit/Skia (wasm) or native (Rust + skia-safe) renderer, and an FFmpeg encoder — with a CLI for scripted/agent use.

Readme

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 中。

界面与效果预览

openHyperEditor —— 配套的浏览器端工作台(apps/editor):CanvasKit 所见即所得预览(与引擎渲染同一棵 draw 树)、图层/关键帧时间线、schema 自动生成的属性面板、一键调用 HTTP 服务渲染 MP4:

openHyperEditor

内置插件库页 —— 每个动效插件都有实时循环预览、自动参数表单和对应的 Scene Graph IR:

插件库

以下动效帧由引擎自身渲染(openhyper still),每个效果在 IR 中只是一个非破坏性的 { type: "plugin" } 节点:

| | | | --- | --- | | neon-trace-title neon-trace-title 霓虹描迹标题 | hyperspace-warp hyperspace-warp 超空间跃迁 | | rgb-glitch-shake rgb-glitch-shake RGB 故障抖动 | sticker-pop sticker-pop 贴纸弹出 | | kinetic-bars kinetic-bars 动能字条 | radar-sweep radar-sweep 雷达扫描 | | aperture-reveal aperture-reveal 光圈开启 | particle-assemble particle-assemble 粒子汇聚 |

开源

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/plugins(动效插件)、openhypercore/renderer-skia(CanvasKit 栅格)、openhypercore/renderer-skia/draw(浏览器安全 draw 树,用于实时预览)、openhypercore/renderer-svgopenhypercore/encoder-ffmpegopenhypercore/assetsopenhypercore/jsx-runtimeopenhypercore/server(HTTP 渲染服务)、openhypercore/cli

默认使用可搬的 CanvasKit/wasm 后端(无需原生二进制)。原生(Rust + skia-safe)后端——快 ~8–14×——为可选项:用 pnpm build:native 从源码构建并以 --renderer native(或 OPENHYPERCORE_RENDERER=native)选用;跨平台 prebuilt 二进制在规划中。

动效插件

只填几个参数就能得到丰富的成品动画——在 layers 里放一个 { type: "plugin" } 节点,渲染前它会展开成普通 IR 图层。CLI、渲染服务、编辑器都会自动展开;插件节点原样保留在 JSON 里,参数随时可改(非破坏性)。

// 三个插件节点拼出完整冷开场(见 examples/plugin-cold-open.ts):
const composition = defineComposition({
  fps: 30, width: 1280, height: 720, durationMs: 13000,
  layers: [
    { type: "plugin", plugin: "countdown", params: { from: 3 }, endMs: 3000 },
    { type: "plugin", plugin: "globe-route",
      params: { src: "assets/earth.jpg", from: [39.9, 116.4], to: [48.85, 2.35], fromLabel: "北京", toLabel: "Paris" },
      startMs: 3000, endMs: 10000 },
    { type: "plugin", plugin: "light-sweep-title", params: { text: "巴黎 72 小時", y: 0.82 }, startMs: 9200 }
  ]
});

内置插件(openhypercore/plugins):

| 插件 | 效果 | 关键参数 | | --- | --- | --- | | globe-intro | 卫星地球仪自转到目标点并俯冲放大(星空、大气辉光、雷达 ping) | src(2:1 等距圆柱贴图)、target [lat,lng]、spinzoombackground | | globe-route | 大圆航线在旋转的地球表面上自己画出来(转到背面会藏进地平线) | srcfrom/to [lat,lng]、fromLabel/toLabelrouteColorzoom | | map-route | 2D 路线在内置 Natural Earth 世界地图上划出弧线,线头带光点、起终点弹出 | from/to [lat,lng]、标签、landColor/routeColorlineStylezoom | | countdown | 经典胶片倒计时:时钟楔形扫掠、圆环、十字线、大数字 | from(3..1)、配色 | | curtain-open | 舞台幕布先合拢再向两侧拉开,露出下方场景 | colorholdMsopenMsfoldCount | | ken-burns | 满屏照片居中缓慢缩放+漂移,淡入淡出 | srczoomFrom/TodriftX/Y | | glitch-title | 居中 RGB 分离故障标题,带闪烁与故障条 | textsize、两个强调色 | | light-sweep-title | 标题上浮入场、下划线从中心生长、光条扫过 | textsizesweepColor | | neon-trace-title | 字母沿霓虹光迹逐个点亮,下划线带光点画出,最后整词灌满霓虹填充 | textsizecolorglowtraceMsbackground | | aperture-reveal | 相机光圈叶片先合拢,再旋转张开露出后方场景,最后一片让开时标题居中落下 | bladescolorholdMsopenMstitlebackground | | radar-sweep | 荧光雷达网格上扫描线旋转并拖出衰减尾迹;光标被扫过的瞬间闪亮并荡出圆环 | colorringssweepMsblipsbackground | | kinetic-bars | 色块从左右两侧交替撞入,各自遮罩一行文字,文字随交错缓动依次归位 | lines(以 / 分隔)、barColorstaggerMsslideMsbackground | | particle-assemble | 散落的粒子从随机位置汇聚成环形标记 logo,字标随后在下方淡入 | countcolorassembleMsshapetitlebackground | | hyperspace-warp | 星光拖尾从中心径向加速,到达光速时白闪一下,标题随后从超大尺寸砸入 | streaksaccelflashMstitle | | velocity-zoom | CapCut 风格变速开场:画面随节拍猛推变焦并带运动模糊抖动,最后定格到标题 | textbeatszoomshakebluraccent | | beat-bounce | 粗体大字砸入并随每个节拍压扁回弹,带投影——经典卡点歌词字幕风格 | textbouncebeatMsboxColor/textColoraccent | | rgb-glitch-shake | 色差故障:RGB 通道分离抖动、故障条撕过标题、数字噪点闪烁——"黑客感"开场 | textsplitsliceRatenoisecolor/colorB | | sticker-pop | Emoji/贴纸五彩纸屑带弹性过冲爆开,围绕弹跳的气泡字幕——反应视频式俏皮开场 | captionstickerspopspinbubbleColoraccent |

最新的十个里,前六个(neon-trace-titlehyperspace-warp)是 opener 开场效果,后四个(velocity-zoombeat-bouncergb-glitch-shakesticker-pop,category 为 tiktok)组成 TikTok/CapCut 风格套装——节奏感强的短视频卡点开场。它们的完整参数 schema:

neon-trace-title(默认时长 3400 ms)

| 参数 | 标签 | 类型 | 默认值 | 范围 | | --- | --- | --- | --- | --- | | text | 标题文字 | string | "HYPERCORE" | — | | size | 字号(0 = 自动) | number | 0 | ≥ 0 | | color | 霓虹颜色 | color | #4f8cff | — | | glow | 光晕半径(px) | number | 18 | 0–60 | | traceMs | 描迹时长(ms) | number | 2400 | ≥ 200 | | background | 背景色 | color | #0d1526 | — |

aperture-reveal(默认时长 3600 ms)

| 参数 | 标签 | 类型 | 默认值 | 范围 | | --- | --- | --- | --- | --- | | blades | 叶片数 | number | 8 | 3–16 | | color | 强调色 | color | #4f8cff | — | | holdMs | 合拢停留(ms) | number | 300 | ≥ 0 | | openMs | 张开时长(ms) | number | 1600 | ≥ 200 | | title | 标题文字 | string | "APERTURE" | — | | background | 背景色 | color | #2a3b66 | — |

radar-sweep(默认时长 4000 ms)

| 参数 | 标签 | 类型 | 默认值 | 范围 | | --- | --- | --- | --- | --- | | color | 荧光颜色 | color | #7dffcf | — | | rings | 圆环数 | number | 4 | 1–8 | | sweepMs | 扫描周期(ms) | number | 4000 | ≥ 500 | | blips | 光标数 | number | 4 | 0–8 | | background | 背景色 | color | #060d0a | — |

kinetic-bars(默认时长 3600 ms)

| 参数 | 标签 | 类型 | 默认值 | 范围 | | --- | --- | --- | --- | --- | | lines | 行文本(以 / 分隔) | string | "MOTION / IN / FRAMES" | — | | barColor | 色块颜色 | color | #4f8cff | — | | staggerMs | 交错间隔(ms) | number | 120 | 0–600 | | slideMs | 滑入时长(ms) | number | 400 | 100–2000 | | background | 背景色 | color | #0b0f16 | — |

particle-assemble(默认时长 4000 ms)

| 参数 | 标签 | 类型 | 默认值 | 范围 | | --- | --- | --- | --- | --- | | count | 粒子数 | number | 90 | 8–240 | | color | 粒子颜色 | color | #4f8cff | — | | assembleMs | 汇聚时长(ms) | number | 2800 | ≥ 300 | | shape | 目标形状 | select | ring | ring / burst | | title | 标题文字 | string | "ASSEMBLE" | — | | background | 背景色 | color | #070a12 | — |

hyperspace-warp(默认时长 3800 ms)

| 参数 | 标签 | 类型 | 默认值 | 范围 | | --- | --- | --- | --- | --- | | streaks | 拖尾数量 | number | 120 | 20–240 | | accel | 加速指数 | number | 2.0 | 1–4 | | flashMs | 白闪时长(ms) | number | 300 | 0–1000 | | title | 标题文字 | string | "HYPERSPACE" | — |

velocity-zoom(默认时长 2600 ms)

| 参数 | 标签 | 类型 | 默认值 | 范围 | | --- | --- | --- | --- | --- | | text | 标题文字 | string | "GO VIRAL" | — | | beats | 节拍数 | number | 3 | 1–8 | | zoom | 推近倍率 | number | 1.9 | 1.1–3 | | shake | 抖动(px) | number | 14 | 0–40 | | blur | 运动模糊 | number | 0.6 | 0–1 | | accent | 强调色 | color | #4f8cff | — |

beat-bounce(默认时长 2400 ms)

| 参数 | 标签 | 类型 | 默认值 | 范围 | | --- | --- | --- | --- | --- | | text | 字幕文字 | string | "LET’S GO" | — | | bounce | 回弹幅度 | number | 0.7 | 0–1 | | beatMs | 节拍周期(ms) | number | 400 | 120–1200 | | boxColor | 底框颜色 | color | #000000 | — | | textColor | 文字颜色 | color | #ffffff | — | | accent | 强调色 | color | #4f8cff | — |

rgb-glitch-shake(默认时长 2600 ms)

| 参数 | 标签 | 类型 | 默认值 | 范围 | | --- | --- | --- | --- | --- | | text | 标题文字 | string | "GLITCH" | — | | split | 通道分离(px) | number | 16 | 0–48 | | sliceRate | 撕裂条频率 | number | 0.4 | 0–1 | | noise | 噪点强度 | number | 0.3 | 0–1 | | color | 通道 A 颜色 | color | #ff2e63 | — | | colorB | 通道 B 颜色 | color | #2effe6 | — |

sticker-pop(默认时长 3000 ms)

| 参数 | 标签 | 类型 | 默认值 | 范围 | | --- | --- | --- | --- | --- | | caption | 字幕 | string | "OMG 😱" | — | | stickers | 贴纸(空格分隔) | string | "✨ 🔥 💖 😂 ⭐" | — | | pop | 过冲幅度 | number | 0.8 | 0–1 | | spin | 环绕漂移 | number | 0.3 | 0–1 | | bubbleColor | 气泡颜色 | color | #ffffff | — | | accent | 贴纸强调色 | color | #ffd166 | — |

插件内容运行在本地时间轴上:节点的 startMs/endMs 决定整段效果的位置,基础属性(transformclipblendMode…)作用于展开后的 group——插件效果和普通图层一样可以搬移、淡入淡出、加遮罩。手动展开(例如调试)只需一行:

import { expandComposition, definePlugin, registerPlugin, listPlugins } from "openhypercore/plugins";

const expanded = expandComposition(composition); // 插件节点 -> 普通图层

// 自定义插件:params 是可序列化 schema(编辑器据此自动生成表单),
// expand() 是纯函数,返回本地时间轴上的图层。
registerPlugin(definePlugin({
  name: "badge",
  params: { text: { type: "string", required: true }, color: { type: "color", default: "#ffb703" } },
  expand: (p, ctx) => [
    { type: "text", text: p.text, color: p.color, align: "center",
      transform: { x: ctx.width / 2, y: ctx.height / 2 } }
  ]
}));

功能特点

  • 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() 可把物理弹簧运动烘焙为关键帧轨道;interpolateColors()(多档 RGB 颜色映射)、确定性 random(seed)stagger() 级联错峰入场。
  • 颜色关键帧:shape 的 fill/stroke、text 的 color 均可用颜色关键帧轨道(RGB 空间插值、逐段缓动),shape strokeWidth 也可动画——在解析阶段化为普通值,所有渲染后端零改动即获得支持。
  • 路径描画动画:shape path 携带可动画的 trimStart/trimEnd(占总长度的分数)——trimEnd 0→1 关键帧即可随时间"画出"路线或签名,可与虚线描边叠加。
  • 地球仪图层:2:1 等距圆柱贴图渲染为正交投影地球(UV 三角网格 + 逐顶点 Lambert/晨昏光照),radius/yaw/pitch 可关键帧;routes 大圆航线贴地绘制、progress 可动画、转到背面自动藏进地平线。wasm 与原生后端生成同一份顶点数据(parity 测试保证)。
  • 场景级转场:createTransitionSeries(...).scene(...).transition({ type, durationMs, direction, easing }) 串联整屏场景并产生真正重叠的转场——wipeclockWipe(遮罩揭示)、slide(整屏推移)、flip(绕中心轴翻面);相邻场景按转场时长重叠(对标 Remotion TransitionSeries 语义),见 examples/scene-transitions.ts
  • IR 新增逐轴缩放与揭示遮罩:transform.scaleX/scaleY(与统一 scale 相乘);GroupLayer.revealwipe/clock,动画化 0→1 progress)把 group 裁剪到扫掠矩形或时钟楔形区域。
  • 静态图层栅格缓存:内容跨帧不变(只有 transform/透明度/reveal 在动)的 group 只栅格化一次、之后直接贴图。缓存由成本模型驱动且自调优——实测每次直绘耗时,只缓存“直绘比预估贴图更慢”的子树,平价场景零回归,辉光/密集文字卡片自动加速。可用 cache: false(单个 group)或 --no-layer-cache(全局)关闭;图片图层另有跨帧解码缓存。
  • 电影感特效 helper:cinematicBarsflashTransitionLayerspeedLineBurstglitchTitle 可生成片头/转场常用 layer stack,减少手写大量图层。
  • 动效插件:{ type: "plugin" } IR 节点经 openhypercore/plugins 展开为普通图层(expandComposition,CLI/服务/编辑器自动执行),参数带可序列化 schema(编辑器自动生成表单)——从舞台幕布到旋转卫星地球仪共 18 个内置插件(见上文章节),并可用 definePlugin/registerPlugin 自定义。
  • 场景时间线 builder:createTimeline(...).scene(...).transition(...).build() 可顺序编排命名场景和转场,并返回 Composition 与 timing markers。
  • 图层 fit 模式:ImageLayer.fitVideoLayer.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。文本/字幕支持 letterSpacing 字距(两个后端逐字符一致应用)。
  • 任意形状裁剪:任意图层(或整个 group)可设置 clip 为本地坐标系下的 rect(可带圆角 radius)、circle 或 SVG path 区域。
  • 文本排版: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 每帧图片解码。视频自带的音轨会自动混入导出的 MP4(遵循 startMs、trim、playbackRate(经 atempo)与 volumevolume: 0 静音;自动探测源文件,无音轨的自动跳过;loop 循环段暂不重复音频)。
  • 资产 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 渲染服务(openhyper serve)、解耦的 Web 编辑器(apps/editor——素材库拖拽/点击导入图片视频音频、字幕/形状/SVG 图案一键添加、画布点选拖拽缩放旋转、渐变与 rgba 颜色可视化编辑、播放器走带、轨道式时间轴(片段拖动/两端裁剪/关键帧编辑)、撤销重做、工程保存/打开、深浅色主题、一键渲染下载 MP4)和 npm 发布均已就绪;跨平台原生 prebuilt 二进制仍在规划中(当前可从源码构建)。

环境要求

  • 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.mp4

CLI 使用

probe

打印 Composition 的基础信息,包括 fps、尺寸、时长、帧数和 layer 数量。

pnpm cli probe examples/simple-video.ts

still

导出指定时间点的单帧。默认输出 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 png

render

渲染 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-cache

bench

渲染视频并输出 JSON 指标,适合比较单线程、worker 和窗口大小配置。

pnpm cli bench examples/simple-video.ts \
  --out /tmp/openhyper-bench.json \
  --video-out /tmp/openhyper-bench.mp4 \
  --workers auto

典型指标包括:

  • renderModeworkerSelectionworkerCountworkerWindow
  • framesrenderedFramesreusedFramesmaxBufferedFrames
  • durationMsframeDurationMsencodedVideoDurationMs
  • audioInputsaudioTimelineStartMsaudioTimelineEndMs
  • renderWallMsrenderCpuMsencodeMstotalMspeakRssBytes

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:fixtures

Benchmark

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 服务、模板系统和可视化编辑器提供稳定的底层渲染能力。