joeseesun/qiaomu-cut

GitHub: joeseesun/qiaomu-cut

一款纯前端的在线视频编辑器,在浏览器本地即可完成多轨剪辑与MP4导出,确保素材数据绝不上传。

Stars: 0 | Forks: 0

# 乔木剪辑 Qiaomu Cut **中文** | [English](#english) ![乔木剪辑编辑器:多轨时间轴、素材库与实时预览](https://static.pigsec.cn/wp-content/uploads/repos/cas/a7/a73ce9b3af7e9b8f83a67b4debb74350faed28c6e5f34222d0d63ae6e86939e0.png) ![License](https://img.shields.io/badge/license-MIT-blue) ![Stack](https://img.shields.io/badge/stack-Vite%20%2B%20React%2019%20%2B%20TS-646cff) ![Render](https://img.shields.io/badge/render-ffmpeg.wasm-009688) **在线体验:** [cut.qiaomu.ai](https://cut.qiaomu.ai)(已上线) **已验证:** `npm run build` ✅ · `npm run test` 36/36 ✅ · E2E 全流程(导入→剪辑→导出)+ ffprobe 校验 ✅(见「实测验证」) ## 这是什么 一个纯前端、可自部署的在线视频编辑器(类似剪映网页版的核心剪辑链路)。 全部剪辑、预览、渲染都在浏览器本地完成:没有账号体系、没有云存储、没有任何素材上传。 ## 为什么值得用 | 痛点 | 乔木剪辑的做法 | |---|---| | 剪个短片要装几百 MB 的客户端 | 打开网页即用,零安装 | | 网页版剪辑工具要登录、要上传素材 | 零登录;素材全程不离开浏览器(可在 DevTools Network 面板自证) | | 公司电脑装软件要审批、内部录屏不敢上云 | 纯本地处理,IT 无可指摘 | | SaaS 剪辑器不可控 | MIT 开源,静态文件可部署到任意服务器 | ## 核心能力 | 能力 | 用户得到什么 | |---|---| | 素材导入(视频/音频/图片) | 拖入即解析:时长、宽高、首帧缩略图,自动保存到 IndexedDB,刷新不丢 | | 多轨时间轴 | 1 文字轨 + 2 视频轨 + 1 音频轨;拖拽移动、裁剪出入点、分割、删除、波纹删除、吸附对齐、缩放、右键菜单 | | 剪辑操作 | 撤销/重做(50 步)、快捷键(Space 播放、S 分割、⌫ 删除、⌘Z 撤销、←/→ 逐帧) | | 实时预览 | 主时钟驱动多元素同步(漂移 >80ms 自动重同步),Canvas 合成画面与文字层 | | 文字叠加 | 样式预设、字号/颜色/描边/透明度/对齐、画布上直接拖动位置、双击改内容 | | 本地导出 MP4 | ffmpeg.wasm 浏览器端重编码(H.264 + AAC,1080P/720P),进度与取消;文字经 canvas 预渲染 PNG 烧录,与预览逐像素一致 | | 隐私与离线 | 无上传请求;引擎与素材缓存后第二次访问可离线使用 | ## 快速开始 ### 最快路径 git clone https://github.com/joeseesun/qiaomu-cut.git cd qiaomu-cut npm install # postinstall 会把 ffmpeg 引擎文件(约 31MB)复制到 public/ffmpeg* npm run dev # 打开 http://localhost:5173 打开编辑器后点「载入示例素材」,10 秒体验完整流程:入轨 → 分割 → 加文字 → 播放 → 导出 MP4。
手动配置与常用命令 npm run build # 类型检查 + 产物构建(dist/) npm run preview # 本地预览构建产物 npm run test # vitest 单元测试(时间轴/导入/预览/导出纯函数) node scripts/e2e.mjs # 端到端验收(需要本机装有 Chrome) node scripts/debug-export.mts # 用本机 ffmpeg 复现导出命令,排查 filter 图
## 产品巡游 | 界面 | 说明 | |---|---| | ![时间轴剪辑](https://static.pigsec.cn/wp-content/uploads/repos/cas/a7/a73ce9b3af7e9b8f83a67b4debb74350faed28c6e5f34222d0d63ae6e86939e0.png) | 多轨时间轴:视频胶片缩略图、音频轨、胶片级裁剪手柄 | | ![文字预览](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad332daef373b0a5ce755fcac8a2b8f0ec65d9e2ea869a7882aa3669c997aac4.png) | 文字叠加:画布选中框可拖动,双击直接改内容 | | ![导出完成](https://static.pigsec.cn/wp-content/uploads/repos/cas/fa/fabb27e6dd1442734cb9ba788f0d1b114ab496c0c5786cb611b91415ce5bbf40.png) | 浏览器端导出 MP4:进度、取消、本机完成不上传 | ## 工作流与架构 UI 层(React 19) 页面与组件,不含业务规则 状态层(zustand + immer) 单一 project JSON,编辑操作全为纯函数 action 媒体层 主时钟(performance.now) 驱动 video/audio seek,Canvas 合成 导出层(ffmpeg.wasm) tracks JSON → filter_complex 生成器(纯函数可单测)→ 重编码 持久层(IndexedDB) 工程 JSON + 素材 blob 自动保存 设计决策与产品规格全部公开:[`PRD.md`](PRD.md)(11 章产品需求)、[`DESIGN.md`](DESIGN.md)(设计系统)。 ### 关键技术点 - **文字烧录**:ffmpeg.wasm 官方 core 不含 drawtext(依赖 freetype)。改用浏览器 canvas 预渲染全尺寸透明 PNG(与预览同一绘制函数),再 `overlay + enable` 窗口贴合——中文用系统字体, 无字体文件依赖,烧录与预览逐像素一致。 - **多线程挂死兜底**:core-mt 在部分环境(无头/旧 Safari)会静默挂死。内置看门狗: 45s 无进度自动终止并降级单线程 core 重试;也可用 `localStorage.qmcut:coreFlavor = 'st'` 强制单线程。 - **主时钟规则**:预览不允许多个媒体元素自由播放后漂移,全部跟随唯一主时钟,偏差 >80ms 立即重同步。 ## 项目结构 src/ types/project.ts # 工程数据模型(version 化) store/projectStore.ts # zustand + immer:全部编辑 action + 撤销/重做 lib/ timeline.ts # 吸附/插入推开/波纹删除等纯函数 importMedia.ts # 导入管线(校验/解析/缩略图) persistence.ts # IndexedDB 工程与素材 blob preview/engine.ts # 主时钟、媒体池、Canvas 文字绘制 export/filterBuilder.ts # tracks JSON → filter_complex(纯函数) export/exporter.ts # wasm FS 管理、进度、挂死看门狗、ST 降级 components/editor/ # 顶栏/素材面板/预览/属性/时间轴/导出弹窗 scripts/e2e.mjs # puppeteer 端到端验收 ## 部署 静态站点,可部署到任意静态服务器。**必须配置两条跨域隔离响应头**(SharedArrayBuffer 前提): add_header Cross-Origin-Opener-Policy same-origin always; add_header Cross-Origin-Embedder-Policy require-corp always; npm run build # 产物在 dist/,含 ffmpeg 引擎文件(public/ffmpeg* 已并入) 缺头时编辑器会整页提示「服务器未配置跨域隔离头」,导出按钮禁用,其余功能可用。 ## 实测验证 - `npm run test`:36/36 通过(时间轴吸附/插入/波纹、导入校验、预览分层、filter 图生成) - E2E(`scripts/e2e.mjs`,本机 Chrome):载入示例 → 入轨 → 5s 分割删除 → 加文字 → 播放预览 → 导出 720P,产物经 ffprobe 验证 `h264 1280x720 + aac, duration 15.000s`, 抽帧目检中文文字烧录位置正确 - 导出速度参考:10s 720P 单片段,单线程 core 约 17.5s(Apple Silicon 实测) ## 限制与边界 - 单项目成片 ≤ 5 分钟、单素材建议 ≤ 500MB(浏览器 wasm 内存约束,超出会明确提示) - 仅桌面端 Chrome / Edge / Safari 最新版本;移动端为只读引导屏 - 无账号、无云同步:工程保存在当前浏览器 IndexedDB,换设备不会带走(工程文件导出在路线图中) - 不做:关键帧动画、转场、滤镜、抠像、多人协作(见 PRD 第九章优先级) ## Troubleshooting - **导出长时间 0% 或失败**:看门狗会自动降级单线程 core 重试;仍失败可在 Console 执行 `localStorage.setItem('qmcut:coreFlavor','st')` 后刷新重试 - **导出按钮禁用**:当前环境未开启跨域隔离(检查 COOP/COEP 响应头或更换浏览器) - **mov 文件导入失败**:浏览器无法解码该编码,请先转码为 H.264 的 mp4 ## 关于 由 [向阳乔木](https://qiaomu.ai/) 开发与维护。 - Blog: [blog.qiaomu.ai](https://blog.qiaomu.ai) - 推荐: [tuijian.qiaomu.ai](https://tuijian.qiaomu.ai) - X: [@vista8](https://x.com/vista8) - GitHub: [@joeseesun](https://github.com/joeseesun) - 微信公众号:向阳乔木推荐看 问题与建议欢迎开 Issue。当前为 v0.1 首发版本,暂无正式贡献流程。 ## License [MIT](LICENSE) © 向阳乔木 # Qiaomu Cut Edit videos right in your browser — a CapCut-web-style core editing flow, fully client-side. ![Editor](https://static.pigsec.cn/wp-content/uploads/repos/cas/a7/a73ce9b3af7e9b8f83a67b4debb74350faed28c6e5f34222d0d63ae6e86939e0.png) **What you get** - Import video/audio/image locally; metadata + thumbnails; autosaved to IndexedDB - Multi-track timeline (1 text + 2 video + 1 audio): drag, trim, split, ripple delete, snap, zoom, undo/redo (50 steps) - Real-time preview driven by a single master clock (media elements re-synced when drift > 80ms), canvas-composited text layer - Text overlays: presets, size/color/stroke/opacity/align, drag on canvas, double-click to edit - In-browser MP4 export (H.264 + AAC, 1080P/720P) via ffmpeg.wasm, with progress and cancel; text is burned in via canvas-pre-rendered transparent PNGs (pixel-identical to preview, no font files needed) - Privacy-first: no accounts, no uploads — media never leaves the browser **Quick start** git clone https://github.com/joeseesun/qiaomu-cut.git cd qiaomu-cut npm install npm run dev # http://localhost:5173 **Verified**: `npm run build` ✅ · `npm run test` 36/36 ✅ · Puppeteer E2E (import → edit → export) with ffprobe validation (`h264 1280x720 + aac, 15.000s`) ✅ **Requirements**: latest desktop Chrome / Edge / Safari. Export requires SharedArrayBuffer — your static host must send `Cross-Origin-Opener-Policy: same-origin` and `Cross-Origin-Embedder-Policy: require-corp` (see 部署/Deploy section above). **Limits**: project ≤ 5 min, asset ≤ 500MB recommended; no cloud sync (projects stay in local IndexedDB); no keyframes/transitions/filters yet (roadmap in `PRD.md`). Docs: product spec [`PRD.md`](PRD.md) · design system [`DESIGN.md`](DESIGN.md). Maintained by [向阳乔木 (Qiaomu)](https://qiaomu.ai/) · [MIT License](LICENSE).
标签:ffmpeg.wasm, React, Syscalls, WebAssembly, 本地渲染, 自动化攻击, 视频编辑器