@cut-workbench/workbench

中文文档
0.5.0发布于 2026/11/05MITTypeScriptESM + CJS近 30 天下载 2636

Cut Workbench 的 UI 组件库:素材库、预览、时间轴、属性面板与导出对话框。

原始使用文档
文档目录16 节
  1. 安装
  2. 关于 react / react-dom / zustand
  3. 为什么 WebAV 是 dependencies 而不是 peer
  4. React 项目
  5. 布局
  6. 顶栏定制
  7. 非 React 项目
  8. script 标签 / 微前端
  9. 类型与依赖缺失
  10. 关掉能力实验室(可选)
  11. 宿主桥(Electron / 自定义文件来源)
  12. 主题定制
  13. 样式隔离
  14. 导出与 Worker
  15. 浏览器要求
  16. License

@cut-workbench/workbench

可嵌入的浏览器端剪辑台 UI:素材库、预览、时间轴、属性面板与导出对话框。 基于 React 19 + Tailwind CSS v4 + Radix,样式已作用域化,嵌进任何宿主都不污染。

安装

只需要装这一个包:

npm i @cut-workbench/workbench

@cut-workbench/core、@cut-workbench/react 以及引擎依赖 @webav/av-cliper、@webav/av-canvas、@webav/av-recorder 都是它的 dependencies,会一起装上 —— 不需要你再显式安装,也不需要知道有这些东西。

选装(按需):

想要什么装什么
只取纯逻辑,不渲染 UInpm i @cut-workbench/core
只要 React hooks,自己写 UInpm i @cut-workbench/core @cut-workbench/react
Electron 宿主桥(「下载」→「保存到指定路径」)npm i @cut-workbench/host-electron
需要控制 React 实例宿主自己提供 react / react-dom / zustand(见下)

关于 react / react-dom / zustand

这三个是 peer 依赖,由宿主提供,库不会替你装 —— 一旦出现两份 React, 宿主会碰到 Cannot read properties of null (reading 'useContext')。项目已有 React 时无需任何额外操作。

zustand 同理:@cut-workbench/react 直接 import 它,两份实例会让订阅错乱, 所以必须由宿主提供(React 项目通常已有)。

为什么 WebAV 是 dependencies 而不是 peer

@webav/* 是运行时必需的:没有 av-cliper / av-canvas 就没有预览和 导出,功能直接不可用。所以这个包选择把它们带上,让「装一个包就能用」成立。

@cut-workbench/core 则相反 —— 它的定位是「只取纯逻辑」,有人只要 timeline 模型和工程序列化,不该被迫装 WebAV,所以 core 那边是 optional peer。

⚠️ 0.1.0 的 WebAV 是 peer,只靠 npm 7+ 自动安装 peer 的隐式行为碰巧能跑; pnpm / yarn 不会自动装 peer,在它们下面构建会报 [MISSING_EXPORT] "Combinator" is not exported by "__vite-optional-peer-dep:…"。 0.2.0 起改为 dependencies,与包管理器无关。

React 项目

推荐:用 /auto 子入口,一行自带样式:

import { createEditor } from '@cut-workbench/core/engine'
import { CutEditorProvider } from '@cut-workbench/react'
import { CutWorkbench, CutWorkbenchProvider } from '@cut-workbench/workbench/auto'

const editor = createEditor()

createRoot(el).render(
  <CutEditorProvider editor={editor}>
    <CutWorkbenchProvider theme="dark">
      <CutWorkbench className="h-screen" onSaveProject={save} onOpenProject={open} />
    </CutWorkbenchProvider>
  </CutEditorProvider>,
)

根入口不自带样式 —— 给已经有自己的构建流程、需要控制 CSS 顺序 (例如要压过某条全局重置)的场景:

import { CutWorkbench, CutWorkbenchProvider } from '@cut-workbench/workbench'
import '@cut-workbench/workbench/style.css'   // ← 必须自己引,忘了就是无样式

两者的 API 完全一致,/auto 只是多了一行 import './cut-workbench.css'。 不要同时引两个入口 —— 样式会被引入两次(作用域化之后是幂等的,但没必要)。

布局

┌───────────────────────────────────────────┐
│ 顶栏                                      │
├──────────┬──────────────┬─────────────────┤
│ 素材库   │ 预览         │ 属性            │  ← 上半区,可纵向滚动
├──────────┴──────────────┴─────────────────┤
│ 时间轴(横跨整行)                        │  ← 下栏
└───────────────────────────────────────────┘

时间轴通栏占满底部一行,不随左右面板宽度变化。左上「素材」、中「预览」、 右「属性」三栏可拖拽调整,面板内的内容各自滚动。

0.2.0 之前时间轴被塞在中间列里,左右面板一拉宽就把它挤窄,工具条按钮会 溢出到属性面板上;窄列下播放控制条的时间码也会被裁掉。现在布局与控件都有 容器级自适应(按容器宽度分档收起次要控件,而不是按视口宽度), scripts/layout-test.mjs 守着这两条。

顶栏定制

内置顶栏分三层可定制,由浅到深:

1. 改文案 —— labels:

<CutWorkbench toolbar={{ labels: { export: '导出成片', untitledProject: '新建项目' } }} />

2. 改局部 —— brand / title / status / actions:

<CutWorkbench
  toolbar={{
    brand: <MyLogo />,                      // 默认**没有**品牌区,避免露出本库名字
    title: null,                            // 不要工程名区
    status: <AutoSaveBadge />,              // 默认「空工程 · 16:9」
    actions: <MyShareButton />,             // 追加在右侧按钮组末尾
    editableTitle: true,                    // 双击工程名重命名(走撤销栈)
    showCapabilityBadge: false,             // 隐藏引擎能力徽标
  }}
/>

3. 整条替换 —— slots.topBar(优先级最高):

<CutWorkbench slots={{ topBar: <MyHeader /> }} />   // 传 null 表示完全不要顶栏

slots.topBar 会替换整条顶栏,撤销/导出等内置动作一并由宿主负责; toolbar 只换其中一块,其余保留。可运行示例见 playground 的 /toolbar-demo.html。

非 React 项目

import { initCutWorkbench } from '@cut-workbench/workbench/auto'

const wb = initCutWorkbench('#app', { theme: 'dark', namespace: 'my-project' })
await wb.whenReady()
wb.on('export:done', ({ blob, filename }) => upload(blob, filename))

script 标签 / 微前端

UMD 单文件已把 React、WebAV、Worker 与样式全部内联,暴露 window.CutWorkbench:

<script src="https://unpkg.com/@cut-workbench/workbench/dist/umd/cut-workbench.umd.js"></script>
<script>
  const wb = CutWorkbench.initCutWorkbench('#app', { theme: 'dark' })
</script>

⚠️ React 19 不再发布 UMD 产物,因此 UMD 版本内置了一份 React。有任何构建工具时 都优先选 ESM。

类型与依赖缺失

如果引擎依赖没解析到(例如被 npm 的 hoisting 拔掉、或在 pnpm 下版本冲突), 工作台不会白屏:能力探测会把「缺依赖」和「浏览器不支持」分开报告, 阻断页直接给出可执行的安装命令:

缺少 @webav/av-cliper,请执行 npm i @webav/av-cliper @webav/av-canvas @webav/av-recorder

注意缺失依赖只在构建期解析 —— 装完必须重新跑一次构建,刷新浏览器没用。

关掉能力实验室(可选)

config.features.lab 是运行时开关,默认 false。lab 本体是独立子入口 @cut-workbench/workbench/lab,主包对它做动态 import —— 所以默认配置下 lab 的代码(含 @webav/av-recorder)不会加载,但打包器仍会产出一个约 33 KB 的 lab chunk。

要在产物里彻底删掉它,在宿主的构建配置里把子入口指到空实现:

// vite.config.ts
export default {
  resolve: {
    alias: [
      {
        find: /^@cut-workbench\/workbench\/lab$/,
        replacement: '@cut-workbench/workbench/lab-disabled',
      },
    ],
  },
}

验证方式:

grep -c "FrameCounterClip" dist/assets/*.js   # 应为 0

为什么不是 define: { __CUT_WORKBENCH_LAB__: 'false' }:实测(Vite 8 / Rolldown)动态 import 只要出现在模块图里,chunk 就会被写进 dist,即便所在 分支已被折成死代码。只有把模块解析本身换掉才真正生效。

宿主桥(Electron / 自定义文件来源)

宿主想接管「导出保存到哪」和「素材从哪来」时,用 @cut-workbench/host-electron:

const editor = createEditor({
  bridge: createElectronBridge(window.cutHost),   // ← 传给 createEditor 即可
})

<CutEditorProvider editor={editor}>
  <CutWorkbenchProvider theme="dark">
    <CutWorkbench className="h-full w-full" />
  </CutWorkbenchProvider>
</CutEditorProvider>

CutWorkbenchProvider 不传 bridge 时会回落到编辑器自己的 bridge, 所以不用传两遍。若想给 UI 层单独换一套桥,再显式传 bridge 覆盖。

⚠️ 只把桥传给 createEditor 却期待 UI 也生效,在 0.2.0 之前是不成立的: Provider 会另建一个浏览器内置桥,于是「导出走宿主、素材导入走内置 <input>」的半接管状态静默存在 —— 界面完全正常,宿主自己的素材库永远 弹不出来。0.2.0 起已改为回落。scripts/bridge-host-test.mjs 守着这条, 可运行验收页见 playground 的 /bridge-host.html。

主题定制

<CutWorkbenchProvider theme="inherit" />        // 跟随宿主 <html class="dark">
<CutWorkbenchProvider tokens={{ primary: '#4d6bfe', radius: '8px' }} />

token 通过根节点 inline style 应用,优先级高于样式表,不依赖引入顺序;变量都带 --cw- 前缀且挂在 .cw-root 上,不污染宿主 :root。

样式隔离

  • 不引 preflight,宿主 h1 / button 默认样式不变;
  • 每条 utility 前置 .cw-root,宿主的 .flex 与工作台的互不干扰;
  • 不使用 @layer,避免被宿主未分层样式压过。

导出与 Worker

导出默认在 Web Worker 中执行,产物里的 assets/export.worker-*.js 由 @cut-workbench/workbench 自身携带。若宿主有严格 CSP,可用 HostBridge.createExportWorker 完全接管 Worker 的创建。

含文字片段的工程会自动回退主线程渲染(文字依赖 DOM)。

浏览器要求

仅支持 Chromium 内核(Chrome / Edge):WebAV 依赖 WebCodecs 与 OPFS。

License

MIT

版本与发布记录

@cut-workbench/workbench 共发布 13 个版本,首次发布于 2026/11/01;过去 12 个月发布了 13 个版本。

版本发布日期距今
0.5.0latest2026/11/056 天前
0.4.62026/11/056 天前
0.4.52026/11/047 天前
0.4.42026/11/047 天前
0.4.32026/11/047 天前
0.4.22026/11/038 天前

关于 @cut-workbench/workbench 的常见问题

@cut-workbench/workbench 是什么?

Cut Workbench 的 UI 组件库:素材库、预览、时间轴、属性面板与导出对话框。

如何安装 @cut-workbench/workbench?

在项目目录运行 npm install @cut-workbench/workbench,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^19.0.0)、zustand(^5.0.0)、react-dom(^19.0.0)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@cut-workbench/workbench 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cut-workbench/workbench 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@cut-workbench/workbench 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@cut-workbench/workbench 可以商用吗?

@cut-workbench/workbench 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@cut-workbench/workbench 的下载量有多少?

根据 npm 官方下载统计,@cut-workbench/workbench 在 2026/10/11 – 2026/11/09 这 30 天内被下载 2,636 次,日均约 88 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cut-workbench/workbench 还在维护吗?

最新版本 0.5.0 发布于 2026/11/05(6 天前);至今共发布 13 个版本,其中过去 12 个月发布了 13 个;首次发布于 2026/11/01。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。