アーキテクチャ概要
両側の所有権
TSX / hooks → Mutation Stream → Scene / Layout / Paint
(TypeScript Shell) バイナリ・バッチ (Rust Core, wasm)
↓
Canvas2D リプレイヤー ← DisplayList ← PictureShell はコンポーネントツリーを、Core は Scene を所有します。両者は可変オブジェクトを共有しません。 境界を越える通信はすべてバージョン管理されたバイナリストリームです。リトルエンディアン、4 バイト境界、 命令化されており、受信側はメモリに触れる前に opcode、長さ、アラインメント、ID、算術を検証します。 不正な入力は部分適用されずアトミックに拒否されます。
この境界は性能最適化ではなく正しさの境界です。バイトが通常このプロジェクト自身のエンコーダから来る としても、デコーダは信頼できない入力として扱い、ファジングで守られています。
デュアルクロック
UI クロック(メインスレッド)とレンダリングクロック(Worker)は独立しています。
- メインスレッドは入力を集め、コンポーネントツリーを実行し、Mutation フレームをコミットします。
- Worker はスクロール物理、アニメーション、レイアウト、合成を駆動します。
スクロール中に Shell を呼び出すことはありません。 欠けているデータはプレースホルダーで描き、 後続フレームで補完します。そのためアプリケーションコードがメインスレッドを 200ms ブロックしても、 スクロールとアニメーションは途切れません。この状況は自動的な障害注入テストで守られています。
フォールバックチェーン
能力検出が順に転送経路を選びます。3 段階はいずれも機能的に等価です。
- SharedArrayBuffer —— クロスオリジン分離(COOP/COEP)が必要
- postMessage —— SAB が使えない場合
- メインスレッド Canvas2D —— Worker / OffscreenCanvas が使えない場合
const root = await createHostedCanvasRoot(canvas, {
transport: { preference: "sab" }, // 希望であり、満たせなければフォールバックします
});
console.log(root.mode); // "sab" | "post-message" | "main-thread"このサイトの Playground が実例です。GitHub Pages は COOP/COEP ヘッダを送出できないため 公開版は postMessage 経路で動作し、ページ上部の transport バッジがそれを正直に表示します。
無効化モデル
prop の意味論が無効化ドメインを決めます。 呼び出し側が手動でダーティを立てることはなく、 forceUpdate のような抜け道もありません。
各プロパティは単一のスキーマで、レイアウト・描画・ヒット・セマンティクスのどれに影響するかを宣言します。 opacity の変更は再レイアウトを起こしませんが、width の変更は起こします。ダーティビットマップは ドメインごとに保持され、onFrame が各ドメインのダーティノード数を公開します。
この選択は「積極的に最小の無効化 + プロパティテストの安全網」です。差分描画の結果は全体描画と ピクセル単位で一致しなければならず、差分テストは反例を最小の失敗ケースまで縮小します。
Scene の表現
Core 内の Scene は SoA(構造体の配列ではなく配列の構造体)です。
- ノード ID は世代を含み、スロットを再利用しても古い ID が再び有効になることはありません。
- コミット後はトポロジ順を保ちます。親は常に子より前に並びます。
- 構造変更の詰め直しは mutation ごとではなくコミットごとに一度だけ行います。
- レイアウト結果はダブルバッファの SoA でまとめて比較し、ホットパスでノードごとのクロージャや リスナーを確保しません。
差し替え可能なバックエンド
Core はフラットなバイナリ DisplayList を出力し、バックエンドは単なるリプレイヤーです。Canvas2D バックエンドは確保を切り詰めた typed-array のループです。描画ごとに wasm→JS を呼ぶ設計は 許容できるレンダリング経路ではありません。
同じ DisplayList を隔離された wgpu プロトタイプにも与え、両者の出力をピクセル差分します。 WebGPU を採用するかどうかはデータで決める事項です。ADR-0006 を参照してください。
決定性
時間、乱数源、入力ストリームはすべて注入または再生でき、Core の出力はスレッドのスケジューリング順に 依存しません。DOPR アーカイブは Mutation と Input のストリームを元の順序で記録し、ブラウザなしの ヘッドレス環境で決定的に再生できます。本番の問題を手元で再現できる一方、機微な編集ストリームは 明示的に記録から除外されます。
さらに詳しく
アルゴリズム、データ構造、受け入れ基準の全体は技術設計文書にあります。