box3d-rust 0.2.1

Pure Rust port of the Box3D 3D physics engine
Documentation

box3d-rust

A pure Rust port of Box3D, Erin Catto's 3D physics engine for games — exact behavioral match, including cross-platform deterministic math.

crates.io docs.rs License Live Demo

Demo Site

Follow the port live in your browser

box3d-rust demo

The demo site mirrors the upstream samples app via WebAssembly — same light SPA shell as our finished box2d-rust demos. Collision-layer demos and rigid-body simulation samples (including the falling-ragdoll determinism scene) are live in the browser.

Part of the rust-apps suite — a collection of Rust graphics and geometry libraries by Lars Brubaker.

Status: Determinism gate passed — bit-exact with the C reference

Box3D was released by Erin Catto in June 2026. The pinned reference source lives in the box3d-cpp-reference/ submodule (v0.1.0+, 540ea38), and this port follows the same playbook that took box2d-rust to completion: whole modules in dependency order, each landing with its portion of the upstream C test suite.

Area Ported Tests
Foundation: math_functions (Vec3/Quat/Matrix3), core/constants ✅ (test_math.c)
Foundation: id, bitset, id_pool, table (container → Vec) ✅ (test_id/bitset/table.c)
Collision: aabb, distance (GJK/TOI) ✅ (test_collision AABB + test_distance.c)
Collision: hull, geometry, manifolds, mesh, height_field, compound, dynamic_tree ✅ (test_hull/shape/compound/height_field + authored)
Broad phase: proxy ops, move buffer (pair update deferred to world) ✅ (authored proxy tests)
Dynamics: body/shape lifecycle, contact lifecycle, constraint graph, solver sets ✅ (test_body + authored world tests)
Dynamics: islands — link, merge, split, sleep/wake ✅ (authored sleep/split tests)
Joints: distance, motor, parallel, prismatic, revolute, spherical, weld, wheel ✅ (test_joint.c)
Solver: serial contact solve, sub-step pipeline, sleeping, CCD/bullets, sensors, hit events ✅ (test_world.c)
Narrow phase: mesh/height-field contacts (mesh_contact.c) ✅ (TestMeshDrop + authored)
World API: queries, casts, explode, character mover ✅ (test_body_query.c, test_mover.c)
Shape/Body public API (filters, materials, geometry set, per-shape queries) ✅ (test_shape.c, test_body.c)
Determinism: bit-exact vs the C scalar build (both precision modes) ✅ (test_determinism.c)
Large world mode (double-precision feature = BOX3D_DOUBLE_PRECISION) ✅ (test_large_world.c)
API completeness: introspection accessors, kinematic targets, wind ✅ (WorldTest/BodyTest remainders)
Debug draw (b3DebugDraw / b3World_Draw) ✅ (authored)
Snapshots and recording/replay ✅ (test_recording.c)

Not ported (by design): the task scheduler/worker threads (the port is serial), SIMD codepaths (the scalar BOX3D_DISABLE_SIMD path is the behavioral reference), and the C arena/block allocators (Rust Vecs).

Quick start

[dependencies]

box3d-rust = "0.2"

# Optional: large-world positions (mirrors BOX3D_DOUBLE_PRECISION)

# box3d-rust = { version = "0.2", features = ["double-precision"] }

use box3d_rust::body::create_body;
use box3d_rust::geometry::Sphere;
use box3d_rust::hull::make_box_hull;
use box3d_rust::shape::{create_hull_shape, create_sphere_shape};
use box3d_rust::types::{default_body_def, default_shape_def, default_world_def, BodyType};
use box3d_rust::world::World;
use box3d_rust::{Pos, VEC3_ZERO};

fn main() {
    let mut world = World::new(&default_world_def());

    let mut ground_def = default_body_def();
    ground_def.type_ = BodyType::Static;
    let ground = create_body(&mut world, &ground_def);

    let mut ball_def = default_body_def();
    ball_def.type_ = BodyType::Dynamic;
    ball_def.position = Pos {
        x: 0.0 as _,
        y: 0.5 as _,
        z: 0.0 as _,
    };
    let ball = create_body(&mut world, &ball_def);

    let shape_def = default_shape_def();
    let ground_hull = make_box_hull(5.0, 0.5, 5.0);
    create_hull_shape(&mut world, ground, &shape_def, &ground_hull.base);

    let mut ball_shape = default_shape_def();
    ball_shape.density = 1.0;
    create_sphere_shape(
        &mut world,
        ball,
        &ball_shape,
        &Sphere {
            center: VEC3_ZERO,
            radius: 0.5,
        },
    );

    // 60 Hz, 1 sub-step
    world.step(1.0 / 60.0, 1);
}

Porting principles

  • Exact behavioral match — same algorithms, same f32 arithmetic, same edge cases as the C source. Floating-point operations are never reordered or "improved".
  • Determinism preserved — Box3D's hand-rolled b3Atan2 and b3ComputeCosSin (built for cross-platform determinism) are ported bit-for-bit, never replaced with std functions.
  • Tests ported too — every module lands together with its portion of the C test suite.
  • No stubs — no todo!(), no placeholders; modules are ported whole, in dependency order.
  • Large world mode — the double-precision cargo feature mirrors BOX3D_DOUBLE_PRECISION.

The approach follows HOW_WE_PORTED_CLIPPER2.md and the completed box2d-rust port.

API style

The public API is a direct C-mirror (same shapes, defs, and call patterns as Box3D / box2d-rust), not a Rust-ergonomic wrapper. A thin ergonomic layer may be considered later if downstream users ask for one.

Development

# Clone with the C reference submodule

git clone --recurse-submodules https://github.com/larsbrubaker/box3d-rust.git


# Run tests (both precision modes)

cargo test

cargo test --features double-precision


# Full pre-commit gauntlet: file lengths, tests, fmt, clippy, build

./scripts/pre-commit-check.ps1   # or .sh

Demo site

The demo site (demo/) runs the port in the browser via WebAssembly.

The quickest way to see it — builds the wasm and serves the demo at http://localhost:3001, opening your browser:

run_demo.cmd      # Windows (double-click or run from a terminal)
./run_demo.sh     # Linux / macOS

Or drive the steps yourself:

cd demo

bun install

bun run build:wasm   # wasm-pack build (once, and after Rust changes)

bun run dev          # dev server at http://localhost:3001, rebuilds wasm on Rust edits

Deployed automatically to GitHub Pages on push to main.

Acknowledgments