Flit Physics について
Flit Physicsは、three.jsのゲームやデモを作る開発者向けの小規模な球体物理エンジンです。フラットなFloat32Arrayに状態を保持し、衝突、地形、レイキャストとthree.js連携を備えています。
主な機能
- 01重力と衝突を伴う球体シミュレーション
- 02剛体のスリープと接触ソルバー
- 03ハイトフィールド地形との衝突
- 04空間ハッシュの広域判定とレイキャスト
- 05InstancedMesh向け位置出力
活用シーン
- 01three.jsゲームへの球体物理の追加
- 02ハイトフィールド地形上の粒子シミュレーション
- 03シミュレーション位置のInstancedMeshへの同期
MCP 対応
任意のMCPサーバーが、ワールドの設定とリセット、粒子の生成・追加、シミュレーションの進行、状態確認、レイキャスト用のツールを公開します。位置出力はInstancedMeshとの同期に対応します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
Flit
Flit は 3js 向けの小さな物理エンジンです。まだできることは多くありませんが、きっとこれからです!
球体、衝突、レイキャスト、重力、空間ハッシュによるブロードフェーズのみを、意図的に実装しています。
シミュレーション状態はすべてフラットな Float32Array(構造体配列)に格納されるため、
CPU の処理経路が将来の WebGPU 計算バックエンドのリファレンス実装も兼ねます。同じバッファー、同じカーネルを使い、
アーキテクチャーを再設計する必要はありません。
内容
World— 点状の球体パーティクル、半陰的オイラー積分、 インパルスと位置補正による接触ソルバー、無限の地面平面。 静止状態を保つボディーは静止状態に落ち着きます(ボディーごとのスリープは固着しきい値で制御されます)。 そのため、静止した積み重なりの計算コストはほぼゼロです。十分に速い衝突でスリープが解除され、 ゆっくり押した場合は静止摩擦で動きを抑えます。Heightfield— メッシュ化せず、高さポストのグリッドで表現する 2.5D 地形です。 衝突判定では双線形補間による高さと中央差分法による法線を直接サンプリングし、 レイキャストでは 2D Amanatides-Woo DDA を使用します(index: -1)。- Raycast — ブロードフェーズグリッド上で Amanatides-Woo のボクセルウォークを行います。 経路を通るセルの周囲 3x3x3 ブロックから候補を取得するため、角をかすめるケースも見逃しません。 総当たりのオラクルと比較する差分テストを実施しています。
SpatialHash— Morton(Z オーダー)セルコードをキーにする一様グリッドのブロードフェーズです。 LSH ファミリーにおけるユークリッド距離版です。MinHash は Jaccard 類似度に基づいてドキュメントをバケットに分類しますが、 こちらは位置を分類するため、近くにある点は同じバケット内で衝突します。Morton キーは全単射で (ハッシュ衝突によるペアの肥大化がなく)、逆変換可能で(サイドテーブルが不要)、将来のソート済み配列 GPU バックエンドに向けて 局所性順に並びます。- 距離とビット演算ユーティリティ — 二乗ユークリッド距離、L1 距離、Minkowski 距離、L∞ 距離、Hellinger 距離、
カイ二乗距離、KL 距離(FLANN から移植)、Morton(Z オーダー)キー、
基数ソート用の浮動小数点ビット反転、八角形近似距離を提供します。
出典とライセンスについては
THIRD_PARTY_NOTICES.mdを参照してください。
エージェント向け
小さな three.js のゲームやデモを作っていますか?利用方法は 2 つあります。
- スキル:
skills/flit/SKILL.md—skills/flit/ディレクトリをエージェントのスキルパス(例:.claude/skills/、~/.code_puppy/skills/)にコピーします。 30 秒でできる統合手順、MCP の利用方法、計測済みのパフォーマンス範囲、コントリビューター向けルールが含まれています。 - MCP サーバー(コード不要):
npm run mcpを実行するか、クライアントの接続先に指定します。
{
"mcpServers": {
"flit": {
"command": "npx",
"args": ["vite-node", "mcp/server.ts"],
"cwd": "<path-to-this-repo>"
}
}
}
ツール:flit_info、flit_reset(gravity/restitution/ground/bounds/
settleSpeed/heightfield)、flit_spawn(rain/explosion/grid/fountain
プリセット)、flit_add_particles、flit_step、flit_state、flit_raycast
— step/state は、InstancedMesh との同期に適したフラットな xyz 位置と
settledCount を返すため、積み重なりが静止する様子を確認できます。
使い方
npm i flit-physics
import { World } from 'flit-physics';
const world = new World({ restitution: 0.4 }); // gravity and a floor at y=0 included
const ball = world.addParticle({ position: [0, 10, 0], radius: 0.5, mass: 1 });
// fixed timestep, e.g. from your rAF loop
world.step(1 / 60);
// sync to three.js: positions is a live Float32Array, 3 floats per particle
mesh.position.set(
world.positions[ball * 3],
world.positions[ball * 3 + 1],
world.positions[ball * 3 + 2],
);
地形とスリープは、それぞれ 1 つのオプションで有効にできます。
import { Heightfield, World } from 'flit-physics';
const terrain = new Heightfield({ rows: 64, cols: 64, cellSize: 1, heights });
const world = new World({ groundY: null, heightfield: terrain });
// bodies collide with the terrain and settle on it;
// world.raycast(...) reports terrain hits as index -1
// sleep is on by default (settleSpeed 0.01 m/s); opt out per world:
const wideAwake = new World({ settleSpeed: 0 });
開発
npm install
npm test # vitest
npm run build # tsc -> dist/
npm run bench # broadphase + full-step micro-benchmarks
npm run demo # three.js demo scene (vite dev server)
ベンチマーク
シードは固定しています。数値はローカルの開発マシンで、コミット時に記録したものです(却下した設計を含む一連の変更については、コミットメッセージを参照してください)。
bench/broadphase.bench.ts— ブロードフェーズのみ、N=4096: xor-hash は 3.4~3.7 ms(444 ペア、衝突による膨張は約 90%)→ Morton キーと順序付きプロービングで 3.5~3.7 ms(234 ペア、正確)。bench/world.bench.ts—World.step全体、N=1024: xor-hash は 0.85 ms/step → Morton の順序付きプロービングは 0.83 ms/step → 逐次インパルス速度ソルバー(4 回の反復+LUT 摩擦)では 0.93 ms/step。正確なキー、実際の接触、+11%。bench/scaling.bench.ts— 2 つの条件。固定サイズのボックス(密度上昇): 群集化による物理現象で、ペア数はおよそ N² に比例します。スケールするボックス(一定のスポーン密度):ボディが散在している間は、N=8000 まで 1000 個あたり約 1.2 ms で O(N) の一定値です。重力を有効にすると、約 2~4 秒で全体が密集した床の山に落下します(再現するにはWARMUP=240を指定してください)。そして 0.3.0 以降、この山は静止します。ボディが下から順にスリープするため、N=8000 で 34.2 → 9.2 ms/step(3.7 倍、60fps の予算内)になります。静止したボディは、1 m/s を超える衝撃で起こされるまで、積分、平面、相互接触の処理から除外されます。分析と残るアイデア(ウォームスタート、適応的反復回数)のために、docs/issues/001の概要は保持しています(解決済み)。bench/raycast.bench.ts— N=4096 でシードを固定した 2000 本のレイ: 63~68 µs/レイ(同じ密度で全探索する O(N) のオラクルは約 160 µs。N が増えるほどグリッド走査がさらに高速になります)。bench/morton-libs.bench.ts— npm ライブラリとのコーデック比較(npm run bench:libs):独自実装は 3.8 ns/encode、fast-morton MB は 26.1、fast-morton LUT は 43.8、@thi.ng/morton は 539.9。独自実装が最速です。比較をいつでも実行できるように、ライブラリは開発時の依存関係として残しています。bench/threaded.bench.ts— 実際のワーカースレッド上での WorkerWorld(SAB のピンポン方式):メインスレッドでのkick()のコストは 0.014 ms です。4 ms のレンダリング処理を行う場合、N=8192 でフレームあたりの時間は、パイプライン処理で 8.84 ms、逐次処理で 14.96 ms(113 fps 対 67 fps)です。N=1024 では、0.8 ms のステップ処理がレンダリングの背後に完全に隠れます(4.03 対 4.80 ms)。- 計測の結果、以下は却下しました(コミットを参照):63 ビット BigInt キー(割り当てが 13 倍に増加)、ソート済み配列+二分探索によるブロードフェーズ(JavaScript では Map プロービングより 1.4 倍遅い — 否定的な結果も記録済み)。
ロードマップ
Morton 順に並べたブロードフェーズセル— 完了、計測済み、リリース済みthree.js デモシーン—npm run demo、ボックス内に 220 個のボール(高さフィールドの丘には?terrain、負荷テストには?n=8000)ワーカースレッドによるステップ処理—WorkerWorld:kick/waitForUpdate、SAB によるゼロコピーのピンポンレンダリング静止した山におけるソルバーのコスト— ボディごとのスリープ機能をリリース済み(N=8000 で 34.2 → 9.2 ms)。残るアイデア(ウォームスタート、適応的反復回数)については課題の概要を保持しています高さフィールドの地形— メッシュ生成なしでリリース済み。ほかのコライダー形状を追加するためのフックを残しています- レイを多用するワークロードが現れた場合は、レイキャストの粗い占有フィルターを追加して空き領域をより高速にスキップ — 分析についてはコミット
3173a6fを参照 - CPU 版リファレンスが安定したら WebGPU コンピュートバックエンドを追加
ライセンス
MIT — LICENSE を参照してください。サードパーティのコードとそのライセンスは THIRD_PARTY_NOTICES.md に記載しています。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。