{
  "markdown": "# Flit\n\nFlit is a tiny little physics engine for 3js. It doesn't do much yet! but I believe!\n\nSpheres, gravity, and a spatial-hash broadphase — nothing more, on purpose.\nAll simulation state lives in flat `Float32Array`s (structure-of-arrays), so\nthe CPU path doubles as the reference implementation for a future WebGPU\ncompute backend: same buffers, same kernels, no re-architecting.\n\n## What's in the box\n\n- **`World`** — point-sphere particles, semi-implicit Euler integration,\n  impulse + positional-correction contact solver, infinite ground plane.\n- **`SpatialHash`** — uniform grid broadphase keyed by Morton (Z-order)\n  cell codes. This is the Euclidean cousin in the LSH family: MinHash\n  buckets documents by Jaccard similarity; this buckets positions so\n  *nearby points collide in the same bucket*. Morton keys are bijective\n  (no hash-collision pair bloat), invertible (no side table), and\n  locality-ordered for a future sorted-array GPU backend.\n- **Distance & bit utilities** — squared Euclidean/L1/Minkowski/L∞/Hellinger/\n  chi-square/KL distances (ported from FLANN), Morton (Z-order) keys,\n  float bit-flips for radix sorting, octagonal approximate distance.\n  See `THIRD_PARTY_NOTICES.md` for provenance and licenses.\n\n## For agents\n\nBuilding a little three.js game or demo? Two ways in:\n\n- **Skill**: `skills/flit/SKILL.md` — copy the `skills/flit/` directory into\n  your agent's skills path (e.g. `.claude/skills/`, `~/.code_puppy/skills/`).\n  It carries the 30-second integration recipe, the MCP option, measured\n  performance envelope, and contributor rules.\n- **MCP server** (no code needed): `npm run mcp`, or point your client at it:\n\n```json\n{\n  \"mcpServers\": {\n    \"flit\": {\n      \"command\": \"npx\",\n      \"args\": [\"vite-node\", \"mcp/server.ts\"],\n      \"cwd\": \"<path-to-this-repo>\"\n    }\n  }\n}\n```\n\nTools: `flit_info`, `flit_reset`, `flit_spawn` (rain/explosion/grid/fountain\npresets), `flit_add_particles`, `flit_step`, `flit_state` — the last two\nreturn flat xyz positions shaped for `InstancedMesh` syncing.\n\n## Usage\n\n```bash\nnpm i flit-physics\n```\n\n```ts\nimport { World } from 'flit-physics';\n\nconst world = new World({ restitution: 0.4 }); // gravity and a floor at y=0 included\n\nconst ball = world.addParticle({ position: [0, 10, 0], radius: 0.5, mass: 1 });\n\n// fixed timestep, e.g. from your rAF loop\nworld.step(1 / 60);\n\n// sync to three.js: positions is a live Float32Array, 3 floats per particle\nmesh.position.set(\n  world.positions[ball * 3],\n  world.positions[ball * 3 + 1],\n  world.positions[ball * 3 + 2],\n);\n```\n\n## Develop\n\n```bash\nnpm install\nnpm test        # vitest\nnpm run build   # tsc -> dist/\nnpm run bench   # broadphase + full-step micro-benchmarks\nnpm run demo    # three.js demo scene (vite dev server)\n```\n\n## Benchmarks\n\nDeterministic seeds; numbers from a local dev machine, recorded at commit\ntime (see commit messages for the full series, including rejected designs).\n\n- `bench/broadphase.bench.ts` — broadphase only, N=4096:\n  xor-hash 3.4–3.7 ms (444 pairs, ~90% collision bloat) → Morton keys\n  with ordered probing **3.5–3.7 ms (234 pairs, exact)**.\n- `bench/world.bench.ts` — full `World.step`, N=1024:\n  xor-hash 0.85 ms/step → Morton ordered-probing 0.83 ms/step →\n  **0.93 ms/step** with the sequential-impulse velocity solver\n  (4 iterations + LUT friction). Exact keys, real contacts, +11%.\n- `bench/scaling.bench.ts` — two regimes, and one important caveat.\n  Fixed box (density rises): pairs scale ~N² from crowding physics.\n  Scaled box (constant *spawn* density): flat O(N) ≈ 1.2 ms per 1000\n  through N=8000 — **but only while bodies are scattered**. The\n  caveat: with gravity on, everything rains into a dense floor pile\n  over ~2-4s (`WARMUP=240` to reproduce), and steady-state piles are\n  contact-solver dominated: ~4.3 ms per 1000 at N=8000 (87k contacts\n  x 4 iterations), putting the 60fps pile budget near 3k bodies.\n  The known fix for piles is island sleeping / agglomeration — parked.\n- `bench/morton-libs.bench.ts` — codec bake-off vs npm libs\n  (`npm run bench:libs`): ours 3.8 ns/encode, fast-morton MB 26.1,\n  fast-morton LUT 43.8, @thi.ng/morton 539.9. In-house wins; the libs\n  stay as devDependencies purely so the bake-off stays runnable.\n- Rejected on measurement (see commits): 63-bit BigInt keys (13× alloc\n  regression); sorted-array + binary-search broadphase (1.4× slower\n  than Map probing in JS — negative result recorded).\n\n## Roadmap\n\n- ~~Morton-ordered broadphase cells~~ — done, measured, shipped\n- ~~three.js demo scene~~ — `npm run demo`, 220 balls in a box\n- **Open issue:** settled-pile solver cost — see\n  [`docs/issues/001-settled-pile-performance.md`](docs/issues/001-settled-pile-performance.md)\n  (self-contained brief with repro, evidence, and definition of done;\n  suitable for an agent or human to pick up)\n- WebGPU compute backend once the CPU reference settles\n\n## License\n\nMIT — see `LICENSE`. Third-party portions and their licenses are listed in\n`THIRD_PARTY_NOTICES.md`.\n",
  "bytes": 4997,
  "sha": "30781d3776f6a4f45807111a0a7cd321afd6380ede5f2939ea738ff0218d3013",
  "repo_slug": "brashler/flit",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_brashler_flit_7d4ce9f1/readme"
}