Tooscut — ブラウザで動くGPU加速映像エディタ
WebGPU + Rust/WASMでネイティブ級リアルタイム合成をブラウザで実現する仕組み
Tooscutはブラウザタブ1つで動くNLE(Non-Linear Editor)だ。DaVinci ResolveやPremiere Proをインストールせず、URLにアクセスするだけで映像編集を始められる。
ただ「ブラウザ映像エディタ」と聞くと普通はおもちゃレベルを想像する。Tooscutが違うのは、レンダリングエンジン全体がRust/WASM + WebGPUで動くという点だ。JavaScriptはUI担当のみ。実際のフレーム合成はGPUで処理される。
3層アーキテクチャ
React UI(TanStack Start)→ TypeScriptレンダーエンジン → Rust/WASMコンポジター。コードベースはTypeScript 80%、Rust 20%の比率。そのRust 20%が性能の核心を全て担う。
GPU加速が実際に何をするか
明るさ・コントラスト・彩度・ブラー・色相回転 — これらのエフェクトが全て1つのWGSLフラグメントシェーダー内で動く。スライダーを動かすとGPUユニフォーム値だけが変わり、シェーダーが即座に再実行される。CPUは触らない。
ブラーを例にすると、13×13ガウシアンカーネルがシェーダー内にハードコードされている。sigma値に応じてステップサイズをスケーリングする方式で、ブラー強度を変えてもテクスチャパスの追加は不要だ。
リアルタイムプレビューパイプライン
ここが一番巧妙な部分だ。
- メインスレッドで
requestAnimationFrameループを回す - 現在時刻に表示されるクリップだけをフィルタリング(ソート済み配列 + 二分探索)
HTMLVideoElementからcreateImageBitmap()でビデオフレームを抽出- ImageBitmapをWeb Workerにtransfer(コピーではない)
- Worker内のWASMコンポジターがWebGPUでOffscreenCanvasに直接合成
4番がポイントだ。ImageBitmap transferはゼロコピー — メインスレッドのメモリの所有権をWorkerに移すだけで複製コストがない。テクスチャアップロードもcopy_external_image_to_textureでGPUに直接転送する。
メモリ管理
WASM linear memoryはV8ヒープにカウントされない。GPUバッファはVRAMに、BitmapはネイティブアロケーションJavaScript。ビデオファイルは全体をメモリに載せずオンデマンドでデコードする。この構造のおかげで4K映像もブラウザタブのメモリ制限に引っかからない。
エクスポート
FrameRendererPoolで複数のWeb Workerを並列実行する。各Workerに独立したWASMコンポジターがあり、フレームを分割してレンダリングする。MediaBunnyライブラリがMP4マルチプレクシングを担当。
JSから直接WebGPUを使えばいいのでは?
使える。WebGPUはJavaScript APIなのでJSから直接呼ぶのが本来の正攻法だ。GPUで動くシェーダーコード(WGSL)はJSでもRustでも完全に同一で、ブラー・明るさ・コントラストなどのエフェクト性能に差はない。
差が出るのはGPU外でCPUが処理する部分だ。毎フレーム、キーフレーム補間(ベジエカーブ)、4×4行列演算、ユニフォームバッファパッキング(128バイト、16バイトアラインメント)を16.6ms以内に終わらせる必要がある。
| 処理 | JS | Rust/WASM |
|---|---|---|
| キーフレーム補間 | V8 JIT最適化に依存 | コンパイル時最適化、SIMD可能 |
| ユニフォームバッファ | ArrayBufferの手動オフセット計算 | Pod deriveで構造体→バイト自動変換 |
| オーディオミキシング(~128サンプル) | GCジッターリスク | GCなし — リアルタイムオーディオに致命的差 |
結論:トラック3〜4個、エフェクト1〜2個ならJSで十分だ。トラック10個以上+キーフレーム数十個+オーディオエフェクトチェーンになるとJSのGC(ガベージコレクション)がランダムにフレームを落とす。オーディオは~128サンプル(~2.9ms)単位のコールバックで、GCが挟まると音が途切れる。TooscutがRustを選んだ本当の理由は速度ではなくGCのない決定論的タイミングだ。
レンダリングパイプライン詳細
フレーム合成フロー
requestAnimationFrameループ → 現在時刻の可視クリップをフィルタリング(二分探索)→ buildRenderFrame()でキーフレーム評価 + Transform/Effects統合
HTMLVideoElement → createImageBitmap() → ImageBitmapをWorkerにtransfer(ゼロコピー)
Compositor.renderFrame() → WebGPUパイプライン実行 → OffscreenCanvasに直接出力
copy_external_image_to_texture) → バーテックスシェーダー(フルスクリーンクワッド)→ フラグメントシェーダー(エフェクトチェーン)→ アルファブレンディング合成
GPUエフェクトシェーダー実装
全エフェクトが単一WGSLフラグメントシェーダー内で順次適用される。ユニフォームバッファ1つ(128バイト)で全パラメータを伝達。
| エフェクト | シェーダー実装 | 性能特性 |
|---|---|---|
| ブラー | 13×13ガウシアンカーネル、sigmaベースステップスケーリング | シングルパス — 追加テクスチャ不要 |
| 明るさ | color.rgb * brightness |
乗算1回 |
| コントラスト | (rgb - 0.5) * contrast + 0.5 |
ベクトル演算1回 |
| 彩度 | luminance(dot積)ベース mix(grayscale, color, saturation) |
dot + mix演算 |
| 色相回転 | RGB → HSL変換 → H += radian → HSL → RGB | 色空間変換2回 |
| トランジション | UV座標ベース smoothstepマスキング(Wipe L/R/U/D) |
ピクセル単位条件分岐なし |
適用順序:ブラー → 明るさ → コントラスト → 彩度 → 色相回転 → トランジション → 不透明度 → clamp
Rust/WASMクレート構成
| クレート | 役割 | コア技術 |
|---|---|---|
| compositor | GPU合成エンジン — メディア/テキスト/図形/ライン描画 | wgpu, glyphon, cosmic-text |
| keyframe | キーフレーム補間 — Linear/Step/Bezier | 時間的一貫性キャッシュ(順次O(1)、シークO(log n)) |
| audio-engine | AudioWorkletマルチトラックミキサー — EQ/コンプ/リバーブ | ~128サンプル単位リアルタイムPCM出力 |
| types | 共有型定義 — tsify-nextでTS型自動生成 | serde + wasm-bindgen |
メモリ管理戦略
-
●
WASM linear memory — V8ヒープにカウントされない。DevToolsのJSヒープサイズとは別
-
●
GPUバッファ — VRAMに格納。TextureManagerが同サイズテクスチャはデータ更新のみで再生成しない
-
●
ビデオデコード — 全体ロードなし。オンデマンドバッファリングウィンドウ方式。プレビューはHTMLVideoElement(ブラウザ最適化)、エクスポートはMediaBunny(フレーム精度)
-
●
ImageBitmap transfer — メインスレッド→Worker移動時に所有権移転(ゼロコピー)。複製コストなし
開発者バックグラウンド
Mohamad Mohebifar — Codemod共同創業者 & CTO。Meta、Brex、Shopify出身。コード変換/トランスパイラー10年+のキャリア。WorldSkills 2015銅メダル(Web Design & Development)。目標は「映像編集版Photopea」— インストールなしで日常的な編集作業の80%をカバーすること。
実践ステップ
tooscut.appにアクセス → ブラウザで直接エディタ実行(インストール不要)
File System Access APIでローカルファイルを直接参照 — アップロード/ダウンロードなしで編集可能
タイムラインにビデオ・オーディオ・画像・テキスト・図形クリップを配置
キーフレームパネルで位置・サイズ・不透明度・エフェクトにベジエカーブアニメーション適用
エクスポート時にFrameRendererPoolが並列Workerでレンダリング → MP4出力
メリット
- ✓ インストールゼロ — URLアクセスだけでプロ編集機能利用
- ✓ GPU加速リアルタイムエフェクト — スライダー操作時レンダリング遅延なし
- ✓ Local-first — メディアファイルがサーバーに送信されない
- ✓ Rust/WASMエンジン — ネイティブの90〜95%性能
デメリット
- ✗ WebGPU必須 — Safari非対応、Firefox不安定(事実上Chrome専用)
- ✗ 8Kマルチトラックやカラーグレーディングのようなハイエンド作業はDaVinci Resolve領域
- ✗ Elastic License 2.0 — OSI定義のオープンソースではない(商用ホスティング制限)