demo_canvas の設計
設計目標
demo_canvas は、できるだけ少ないブラウザ用コード(キャンバス 1 つ、セレクタ 1 つ、アニメーションループ 1 つ)で、実際のページ上に Canvas バックエンドを示します。ターミナルデモのシーンを再利用しているので、2 つの出力を直接比べられます。
制約
- プログラムは自分で作ったのではないブラウザのページで動きます。必要な要素は
index.htmlに含まれていなければなりません。 - 使えるのはライブラリパッケージと
rabbitaの公開 API だけです。
数学的背景
アニメーションフレームからの時刻
requestAnimationFrame はページ開始からのミリ秒単位のタイムスタンプ を渡します。トーラスのシーンは角度 だけ回るので、 まわりの 1 回転には 秒かかり、ディスプレイのリフレッシュレートには依存しません。ドリーのシーンはターミナルデモのフレーム単位で定義されているので、ページは 30 fps で時刻をフレーム番号に変換し、
フレーム を描画します。60 Hz のディスプレイではドリーの各フレームが 2 回表示され、動きの速さはターミナルと同じです。
構図
キャンバスは 640 × 480(4:3)、センサーはフルサイズ(3:2)です。投影スケール では、view の設計で導いたとおり、垂直方向の画角がキャンバスの高さを満たし、水平方向の視野はレンズの水平画角より狭くなります。キャンバスのピクセルは正方形なので、ターミナルと違ってアスペクト補正はしません。
設計上の判断
毎フレーム最初から描画する
コールバックのたびにシーン、描画リスト、キャンバス全体を作り直します。何もキャッシュしないので、プログラムはタイムスタンプと選択の純粋関数のままで、640 × 480 では問題になるコストもありません。
Ref による選択
change ハンドラは選ばれたシーンを Ref に書くだけで、アニメーションループが次のフレームでそれを読みます。描画は 1 か所で行われ、シーンの切り替えにループとの調整は要りません。
正しさと不変条件
- キャンバスのビットマップは 640 × 480 で、投影のビューポートと一致します。
- 時刻 の画は と現在の選択だけで決まります。
採用しなかった案
- シーンごとに別のページにすると、初期化のコードが重複します。
- タイムスタンプの代わりに固定のフレームカウンタを使うと、速度がリフレッシュレートに依存してしまいます。
境界
demo_canvas は API を公開せず、ブラウザの外では動かず、再生の制御も提供せず(demo_gsap を参照)、ウィンドウのサイズにも合わせません。