# WebEditorSketch 项目框架结构图 本文用 Mermaid 描述整个学习型 Web 视频编辑器 Demo 的架构。核心边界是:`Project Document` 保持纯 JSON,媒体运行对象和二进制资源留在 Runtime、Worker、OPFS、WebCodecs 和 PixiJS 所在层。 ## 1. 总体架构 ```mermaid flowchart LR USER["用户操作
导入 / 编辑 / 预览 / 导出"] subgraph Main["主线程:Editor App"] UI["React UI
Media / Timeline / Inspector / Preview / Export / Logs"] CMD["Command Bus
事务 / Undo / Redo / revision"] STORE["Redux Toolkit
Project Document + Editor Session"] RX["RxJS Scheduler
取消 / 背压 / 并发 / 进度"] ECS["Miniplex ECS
timeline -> animation -> transform -> video -> effect -> render"] PIXI["PixiJS v8
Scene Graph / Text / Filter / Canvas"] LOGUI["Log Panel
结构化日志展示"] end subgraph MediaWorker["Media Worker:导入与代理"] PROBE["Mediabunny Probe
BlobSource / UrlSource / CustomSource"] TRACK["主轨选择
排除封面轨 / 元数据归一化"] PROXY["Proxy Pipeline
低分辨率 MP4 / 缩略图 / 关键帧"] WASM["Rust WASM
时间换算 / PCM 波形 / 摘要"] OPFS_CACHE["OPFS Cache
proxy / thumbnail / waveform manifest"] end subgraph PreviewWorker["Preview Worker:低分辨率预览解码"] PDEMUX["Mediabunny Demux
按 sourceTime 取样"] PDEC["WebCodecs Decode
VideoFrame / AudioData"] PQUEUE["Decode Queue Metrics
in-flight / HWM / stale"] end subgraph ExportWorker["Export Worker:高质量导出"] ESOURCE["Original Source
File / Blob / URL"] EECS["Export Runtime Adapter
复用 ECS 语义"] COMPOSE["OffscreenCanvas 2D
原素材帧 + 标题 + 变换 + 滤镜"] ENCODE["WebCodecs Encode
H.264 / AAC"] MUX["Mediabunny MP4 Mux
fragmented MP4"] OPFS_OUT["OPFS Output
tmp -> final mp4"] end subgraph Persist["持久化与可观察性"] IDB["IndexedDB
Project JSON"] OBS["packages/observability
日志 schema / marker / sinks"] DOCS["VitePress Docs
架构 / 管线 / 测试说明"] end USER --> UI UI --> CMD CMD --> STORE STORE --> IDB UI --> RX RX --> PROBE PROBE --> TRACK TRACK --> PROXY PROXY --> WASM PROXY --> OPFS_CACHE WASM --> OPFS_CACHE STORE --> ECS ECS --> PIXI OPFS_CACHE --> PDEMUX RX --> PDEMUX PDEMUX --> PDEC PDEC --> PQUEUE PDEC -->|"Transfer VideoFrame"| PIXI PIXI -->|"present()"| UI STORE --> EECS ESOURCE --> EECS EECS --> COMPOSE COMPOSE --> ENCODE ENCODE --> MUX MUX --> OPFS_OUT OBS --> LOGUI UI --> OBS CMD --> OBS PROXY --> OBS PDEC --> OBS ENCODE --> OBS OBS --> DOCS ``` ## 2. Monorepo 模块依赖 ```mermaid flowchart TD ROOT["WebEditorSketch
pnpm workspace"] subgraph Apps["apps"] EDITOR["apps/editor
React 编辑器"] DOCAPP["apps/docs
VitePress 文档站"] end subgraph Packages["packages"] DOMAIN["packages/domain
Project schema / commands / migration"] MEDIA["packages/media-runtime
Mediabunny / RxJS / Worker 协议 / OPFS"] WASMPKG["packages/media-wasm
Rust crate + wasm-bindgen 包装"] PREVIEW["packages/preview-runtime
ECS / Runtime Adapter / Pixi renderer"] OBSERV["packages/observability
日志 schema / marker / sinks"] CONFIG["packages/config
共享 TypeScript / lint / test 配置"] end subgraph Other["辅助目录"] SCRIPTS["scripts
verify / docs source generation / probe"] ASSETS["test_assets
固定测试素材"] SPEC[".trae/specs
spec / tasks / checklist"] AGENT["Agent.md
技术方案与验证手册"] end ROOT --> EDITOR ROOT --> DOCAPP ROOT --> DOMAIN ROOT --> MEDIA ROOT --> WASMPKG ROOT --> PREVIEW ROOT --> OBSERV ROOT --> CONFIG ROOT --> SCRIPTS ROOT --> ASSETS ROOT --> SPEC ROOT --> AGENT EDITOR --> DOMAIN EDITOR --> MEDIA EDITOR --> WASMPKG EDITOR --> PREVIEW EDITOR --> OBSERV DOCAPP --> OBSERV MEDIA --> WASMPKG MEDIA --> OBSERV PREVIEW --> DOMAIN PREVIEW --> MEDIA PREVIEW --> OBSERV SCRIPTS --> MEDIA ``` ## 3. 导入、代理与预览管线 ```mermaid sequenceDiagram autonumber participant U as User participant UI as React UI participant CB as Command Bus participant S as Redux Store participant Q as RxJS / BoundedTaskQueue participant MW as Media Worker participant OPFS as OPFS Cache participant PW as Preview Worker participant PIXI as PixiJS Renderer U->>UI: 选择 test_assets 或本地 File UI->>Q: submitImport(fileOrUrl) Q->>MW: probe(source) MW->>MW: Mediabunny 读取元数据并选择主轨 MW-->>UI: asset metadata + capability + probe logs UI->>CB: addAsset / addClip CB->>S: 写入纯 JSON Project Document Q->>MW: generateProxy(assetId) MW->>MW: 低分辨率转码 / 缩略图 / 关键帧 MW->>MW: Rust WASM 计算 PCM 波形 MW->>OPFS: commit proxy manifest MW-->>UI: proxyReady(cacheKey) U->>UI: 播放或 Seek UI->>S: 读取 playhead + revision UI->>PW: requestFrame(assetId, sourceTimeUs, generation) PW->>OPFS: 读取 proxy 或按需 source PW->>PW: Mediabunny Demux + WebCodecs Decode PW-->>PIXI: Transfer VideoFrame PIXI->>PIXI: draw frame / text / filter / transform PIXI-->>UI: presentedFrames + render metrics ``` ## 4. 编辑与状态所有权 ```mermaid flowchart LR subgraph PureState["可序列化状态"] PROJECT["Project Document
asset / track / clip / title / effect / exportSettings"] SESSION["Editor Session
selection / zoom / playhead / panel state"] HISTORY["Command History
undoStack / redoStack / transaction"] SNAPSHOT["IndexedDB Snapshot
Project JSON"] end subgraph RuntimeState["运行时对象"] FILES["File / Blob / URL Handle"] BUFFERS["ArrayBuffer / TypedArray / PCM"] CODECS["VideoDecoder / AudioDecoder / VideoEncoder / AudioEncoder"] FRAMES["VideoFrame / AudioData"] PIXIOBJ["Pixi Sprite / Text / Texture"] WORKERS["Media / Preview / Export Workers"] OPFSFILES["OPFS proxy / tmp / output"] end UIEDIT["UI 编辑动作"] --> COMMAND["Command"] COMMAND --> INVARIANT["Zod schema
引用完整性 / 非重叠约束"] INVARIANT --> PROJECT COMMAND --> HISTORY PROJECT --> SNAPSHOT SESSION --> SNAPSHOT PROJECT -->|"revision 编译"| WORKERS PROJECT -->|"revision 编译"| PIXIOBJ WORKERS -->|"metrics / logs only"| SESSION FRAMES -->|"metrics / logs only"| SESSION OPFSFILES -->|"metrics / logs only"| SESSION FILES -. "禁止写入 Redux" .-> PROJECT BUFFERS -. "禁止转普通 Number 数组长期保存" .-> PROJECT CODECS -. "取消或结束后释放" .-> PROJECT FRAMES -. "消费后 close()" .-> PROJECT PIXIOBJ -. "不反向写入 Project" .-> PROJECT WORKERS -. "只通过协议通信" .-> PROJECT ``` ## 5. 高质量导出管线 ```mermaid flowchart LR PROJECT["Project revision
JSON timeline"] ORIGINAL["Original Source
File / Blob / URL"] CAP["Capability Check
VideoEncoder.isConfigSupported
AudioEncoder.isConfigSupported"] RUNTIME["ProjectRuntimeAdapter
export profile"] VIDEO_SAMPLE["Mediabunny VideoSample
source time"] AUDIO_SAMPLE["Mediabunny AudioSample
trim / resample"] CANVAS["OffscreenCanvas
1920x1080 或工程设置"] FRAME["VideoFrame
close after encode"] ADATA["AudioData
close after encode"] VENC["VideoEncoder
H.264"] AENC["AudioEncoder
AAC"] PACKETS["EncodedPacket"] MP4["Mediabunny Output
MP4 Mux"] FINAL["OPFS final file
export-requestId.mp4"] PROJECT --> CAP ORIGINAL --> CAP CAP --> RUNTIME PROJECT --> RUNTIME ORIGINAL --> VIDEO_SAMPLE ORIGINAL --> AUDIO_SAMPLE RUNTIME --> CANVAS VIDEO_SAMPLE --> CANVAS CANVAS --> FRAME FRAME --> VENC AUDIO_SAMPLE --> ADATA ADATA --> AENC VENC --> PACKETS AENC --> PACKETS PACKETS --> MP4 MP4 --> FINAL PROXY_NOTE["proxy 只服务预览
禁止作为导出源"] -. "must not use" .-> ORIGINAL ``` ## 6. 日志、验证与文档反馈闭环 ```mermaid flowchart TD CODE["源码变更"] LOGS["结构化日志
[CAPABILITY] [COMMAND] [IMPORT] [PROXY] [SEEK] [DEMUX] [DECODE] [WASM] [ECS] [RENDER] [EXPORT]"] UNIT["Vitest
domain / runtime / preview"] WASMTEST["Rust fmt / clippy / test
wasm browser test"] E2E["Playwright
导入 / 代理 / 预览 / 编辑 / 导出"] BUILD["pnpm build
editor + docs"] VERIFY["pnpm verify
统一验证入口"] DOCS["apps/docs
架构和管线说明"] AGENTMD["Agent.md
长期维护指南"] ARCHMD["arch.md
当前架构图"] CODE --> LOGS CODE --> UNIT CODE --> WASMTEST CODE --> E2E CODE --> BUILD UNIT --> VERIFY WASMTEST --> VERIFY E2E --> VERIFY BUILD --> VERIFY LOGS --> DOCS VERIFY --> DOCS DOCS --> AGENTMD DOCS --> ARCHMD ```