clone

an endless marble-race generator in the browser; the url is the seed, so every track can be shared

main
marbles / tools / physics-spike
README.md

M9 physics spike — Box3D → WASM (2026-08-08)

Verdict: Box3D confirmed as the physics-era engine.

Box3D (Erin Catto, released 2026-06-30, MIT, C17) — the 3D successor to Box2D. Spiked at commit 3fc20f5b453ba9e14cdf54ecafa87a2a4bcdf53c.

Spike setup

  • git clone --depth 1 https://github.com/erincatto/box3d && cd box3d
  • emcmake cmake -B build-wasm -DCMAKE_BUILD_TYPE=Release -DBOX3D_SAMPLES=OFF -DBOX3D_UNIT_TESTS=OFF -DBOX3D_BENCHMARKS=OFF && cmake --build build-wasm — builds libbox3d.a for wasm32 with ZERO patches.
  • emcc spike.c libbox3d.a -I include -O2 -o spike.js && node spike.js

spike.c here: a slalom-like trough (floor + walls + end caps, tilted 5°) with a marble-sized (r=0.2) sphere rolling down 60 units, 1200 steps at 60 Hz × 4 substeps.

Gate results

  • Determinism: position-trace FNV hash bit-identical, both in-process (two worlds) and across separate runs. Box3D advertises cross-platform determinism + record/replay — matches what we measured.
  • Performance: ~228k steps/s single-worker under Node (≈3,800× realtime at 60 Hz; the gate was ≥4×). Effectively unlimited headroom.
  • Behavior: marble slalom maxAbsX settled at exactly the geometric wall-contact plane (0.75 − 0.05 wall − 0.2 radius = 0.500) — contact precision is excellent. Escaped-marble freefall behaves as expected (first run tumbled into the void forever — endless-mode-compatible).
  • API: portable C API in the Box2D v3 style (b3DefaultWorldDef / b3CreateBody / b3CreateHullShape / b3CreateSphereShape / b3CreateMeshShape / b3World_Step / b3Body_GetPosition). Double-precision positions by default (b3CreateWorld = b3CreateWorldDoublePrecision) — good for the endless line's unbounded coordinates.
  • Size: spike .wasm 369 KB (-O2, whole library linked).

M10 integration plan

  • Vendor box3d pinned at the commit above (or a submodule) + a build task producing static/dist/box3d.js/.wasm.
  • Hand-written C shim exporting exactly the calls the marble needs (world/step/static hulls+meshes per piece proxy, one dynamic sphere, transforms out) — keep the JS surface tiny.
  • Collision proxies per PieceDef measured from the GLBs (floor ribbon + wall strips as hulls; helix/curved floors as trimesh), authored in the registry like centerlines.