@hyperframes/studio
studio 包提供了一个基于浏览器的可视化编辑器,用于创建和预览 Hyperframes 合成。它为你提供视频的实时预览、所有 clip 的可视化时间轴,以及用于跳转和播放的播放器控件 — 所有这些在你编辑 HTML 时都会实时更新。
npm install @hyperframes/studio
何时使用
在以下场景使用 @hyperframes/studio:
- 构建自定义合成编辑器 UI(例如嵌入到你自己的 Web 应用中)
- 将 Hyperframes 预览播放器集成到更大的产品中
- 使用自定义面板、工具栏或集成扩展编辑器
如果需要以下功能,请使用其他包:
- 开发期间预览合成 — 使用 CLI(
npx hyperframes preview),它会为你启动 studio - 将合渲染为 MP4 — 使用 CLI 或 producer
- 以编程方式捕获帧 — 使用 engine
💡 Tip
对于大多数开发工作流,你不需要直接安装 studio。 运行
npx hyperframes preview会自动启动带有热重载的 studio。只有在将编辑器嵌入到你自己的应用中时才需要安装@hyperframes/studio。
运行 Studio
通过 CLI(推荐)
npx hyperframes preview
这会启动 studio 开发服务器,在浏览器中打开你的合成,并监视文件更改。这是获取实时预览的最简单方式。
从 monorepo
# 从根目录
bun run dev
# 或直接指定 studio 包
bun run --filter @hyperframes/studio dev
包导出
studio 有两个入口点:
| 导入路径 | 描述 |
|---|---|
@hyperframes/studio | React 组件、hooks 和类型 |
@hyperframes/studio/tailwind-preset | Studio 样式的 Tailwind CSS 预设 |
对等依赖:react (18 或 19)、react-dom (18 或 19)、zustand (4 或 5)。
组件
布局
import { NLELayout, NLEPreview, CompositionBreadcrumb } from '@hyperframes/studio';
import type { CompositionLevel } from '@hyperframes/studio';
// 主 NLE(非线性编辑器)布局容器
<NLELayout>
{/* 预览、时间轴和编辑器面板 */}
</NLELayout>
// 预览面板
<NLEPreview />
// 嵌套合成的面包屑导航
<CompositionBreadcrumb levels={levels} />
播放器与时间轴
import {
Player,
PlayerControls,
Timeline,
PreviewPanel,
AgentActivityTrack,
} from '@hyperframes/studio';
import type { AgentActivity, TimelineElement, ActiveEdits } from '@hyperframes/studio';
// 嵌入预览播放器
<Player />
// 播放控制(播放、暂停、跳转、逐帧前进)
<PlayerControls />
// 带拖动条的时间轴编辑器
<Timeline />
// 预览显示区域
<PreviewPanel />
// 活动可视化轨道(用于 Agent 工作流)
<AgentActivityTrack activities={activities} />
编辑器组件
import { SourceEditor, PropertyPanel, FileTree } from '@hyperframes/studio';
// 代码编辑器(基于 CodeMirror),用于 HTML、CSS 和 JavaScript
<SourceEditor />
// 选中元素的属性检查器
<PropertyPanel />
// 项目文件浏览器
<FileTree />
完整应用
import { StudioApp } from '@hyperframes/studio';
// 完整的 studio 应用(封装所有组件)
<StudioApp />
Hooks
useTimelinePlayer
管理播放器状态和播放控制:
import { useTimelinePlayer } from '@hyperframes/studio';
const player = useTimelinePlayer();
// player.play(), player.pause(), player.seek(time), player.stepForward(), player.stepBackward()
usePlayerStore
用于播放器状态的 Zustand store:
import { usePlayerStore, liveTime, formatTime } from '@hyperframes/studio';
const store = usePlayerStore();
// 访问当前时间、时长、播放状态等
// 格式化时间用于显示
const display = formatTime(liveTime.current);
useCodeEditor
代码编辑器状态和编辑功能:
import { useCodeEditor } from '@hyperframes/studio';
const editor = useCodeEditor();
// editor.code, editor.setCode(), editor.diff, editor.onChange()
useElementPicker
从预览中选择元素:
import { useElementPicker } from '@hyperframes/studio';
const picker = useElementPicker();
// picker.selectedElement, picker.selectElement(id), picker.clearSelection()
功能
实时预览
studio 在 iframe 中使用 Hyperframes 运行时渲染你的合成。你在预览中看到的内容与渲染期间捕获的内容完全一致 — 相同的运行时代码、相同的跳转逻辑、相同的 clip 生命周期。
对 HTML 的更改会通过热重载自动捕获,因此你可以在编辑器中编辑 index.html 并在毫秒内看到浏览器中的结果。
ℹ️ Note
预览的视觉输出与渲染完全匹配。实时播放流畅度则取决于你的硬件,因为预览实际上在你的浏览器中以 30/60fps 播放合成。渲染没有这个限制 — 它通过跳转驱动的管道逐帧捕获,因此耗时较长的帧会使渲染变慢但永远不会丢帧。如果你在预览中看到卡顿但渲染的 mp4 是流畅的,这是预期行为。参见性能了解最常导致此问题的模式。
时间轴视图
时间轴面板提供了合成结构的可视化表示:
- 每个 clip 显示为轨道上的彩色条
- 条的位置和宽度反映
data-start和data-duration - 视觉上更高的行渲染在前面;更低的行渲染在下面
- 相对时序引用(例如
data-start="intro")会被解析并显示为绝对位置
这使得理解具有多个重叠 clip 的复杂合成的时间结构变得容易。
时间轴编辑
时间轴支持移动和修剪操作,这些操作会直接持久化回你的 HTML 源文件。
有关以下内容的完整说明:
- 时间轴编辑目前能做什么
- 每个操作如何映射到
data-start、data-duration、data-track-index和z-index - 哪些 clip 类型支持起始修剪
- 当前限制和心智模型
请参阅时间轴编辑。
播放器控件
studio 包含一套完整的播放控制:
- 播放 / 暂停 — 开始和停止播放
- 跳转 — 点击时间轴上的任意位置跳转到该点
- 拖动 — 拖动播放头逐帧浏览合成
- 逐帧前进 — 一次前进或后退一帧以精确定位
热重载
文件更改会被检测并应用,无需重启服务器。预览会尽可能保持当前播放位置,因此你可以在 5 秒处调整动画而无需在每次保存后重新跳转回去。
架构
studio 是一个 React 应用,具有以下结构:
- Iframe 预览 — 你的合成 HTML 在一个隔离的 iframe 中加载,并注入 Hyperframes 运行时。这确保预览使用与生产相同的渲染路径。
- 运行时桥接 — studio 通过
postMessage与 iframe 通信,控制播放(播放、暂停、跳转)并接收状态更新(当前时间、时长、就绪状态)。 - 时间轴组件 — 使用
@hyperframes/core解析合成以提取 clip 时序数据,并渲染可视化时间轴面板。 - 文件监视器 — 开发服务器(基于 Vite)监视你的项目文件,并在检测到更改时触发热模块替换。
Tailwind CSS 预设
studio 导出了一个 Tailwind CSS 预设以保持一致的样式:
// tailwind.config.ts
import studioPreset from '@hyperframes/studio/tailwind-preset';
export default {
presets: [studioPreset],
// ... 你的配置
};