Boids(群れ)シミュレーションを TypeScript + Canvas でブラウザに実装した。リーダーも全体計画も無く、各個体が 近傍だけを見て 3 つの局所ルール(分離・整列・結合)に従うと、協調した群れ(murmuration)が 創発 する。実装の勘所は 2 つ: (1) 3 ルールを Reynolds の「操舵力(steering force)=希望速度−現在速度」として表現し、重み付き合成する、(2) ベクトル演算と操舵ロジックを DOM 非依存の純粋モジュールに切り出して単体テストする(Canvas 無しで挙動を pin)。直近の CLI 続きから、クリックできるライブデモ付き Web アプリへ。
🌐 ライブデモ: https://sen.ltd/portfolio/boids-flocking/
📦 GitHub: https://github.com/sen-ltd/boids-flocking
創発: 3 つの局所ルール
Craig Reynolds が 1986 年に示した boids は、群れにリーダーも全体計画も要らないことの実演だ。各個体は近傍だけを見て 3 ルールを適用し、協調した群れはプログラムされた結果ではなく創発する:
- 分離 (Separation) — 近すぎる隣から離れる向きに操舵。
- 整列 (Alignment) — 近傍の平均進行方向へ操舵。
- 結合 (Cohesion) — 近傍の平均位置へ操舵。
各ルールは Reynolds 流の 操舵力——最大速度での希望速度から現在速度を引き、最大操舵力でクランプしたもの——を生む:
function steer(desired: Vec, vel: Vec, p: Params): Vec {
if (mag(desired) === 0) return { x: 0, y: 0 };
return limit(sub(setMag(desired, p.maxSpeed), vel), p.maxForce);
}
3 つの力を距離で見つけた近傍から計算し、スライダーで設定した重みで合成する。分離だけ「距離の逆数で重み付け」して、最も近い隣ほど強く押しのける。
エンジンは純粋で、テスト可能
ベクトルと操舵の数学はすべて src/boids.ts に置き、DOM を一切参照しない。だから Canvas 無しで直接単体テストできる(vitest 12 ケース)。テストは各ルールの向きを pin する——近接 2 体は互いに離れる、静止した個体は近傍の進行方向へ向き始める、散らばったリングは結合で収縮する——さらに step が全個体をトーラス世界の内側かつ速度上限以下に保つこと、入力配列を破壊しないことも確認する:
it('a diffuse cloud contracts under cohesion', () => {
// 結合のみで 60 tick 回す
expect(spread(world)).toBeLessThan(spread(boids));
});
「純粋な計算コア+薄い描画層」という分離のおかげで、群れの挙動をブラウザを立ち上げずに CI で担保できる。
描画層は薄く
Canvas フロントエンド (src/main.ts) が持つのはアニメーションループ、描画(各個体を進行方向で色付けした三角形+モーショントレイル)、コントロールパネル、そしてドラッグで群れを散らすポインタ操作だけ。シミュレーション本体は import した純粋関数に委ねる。
なお実装中、devicePixelRatio を使った Canvas スケーリングで「描画が左上 1/4 にしか出ない」不具合に当たった。canvas.width/height(バッキング解像度)と canvas.style.width/height(論理サイズ)を両方明示することで解消した——Retina で崩れる典型パターンなので、スクリーンショットで dsf=1/2 両方を撮って検証した。
src/boids.ts — 純粋モデル: ベクトル・3 ルール・トーラス step()
src/boids.test.ts — 操舵数学の vitest 12 ケース
src/main.ts — Canvas 描画ループ・操作・ポインタ操作
まとめ
Boids は「単純な局所ルールから大域の秩序が創発する」古典。鍵は 3 ルールを操舵力として表現すること、そして 純粋エンジンとして切り出してテスト可能にすること。CLI が続いていたが、ここでクリックできるライブデモ付き Web アプリに振り、TypeScript + Canvas で見て触れる成果物にした。ぜひデモをドラッグして群れを散らしてみてほしい。
🌐 ライブデモ: https://sen.ltd/portfolio/boids-flocking/
📦 GitHub: https://github.com/sen-ltd/boids-flocking
