boxddd 0.1.0

Safe, ergonomic Rust bindings for Box3D
Documentation

boxddd

CI Crates.io Docs.rs License

boxddd is a Rust binding workspace for Box3D, Erin Catto's 3D physics engine announced in Announcing Box3D.

It is the 3D sibling of boxdd, not a feature flag on the 2D crate.

What Is boxddd?

boxddd gives Rust projects a safe, engine-agnostic layer over Box3D's C API:

  • worlds, bodies, shapes, joints, queries, events, debug draw, and recording/replay
  • owned Rust value types for vectors, transforms, ids, filters, and debug data
  • recoverable try_* APIs for tools and engines that cannot panic on invalid input
  • optional conversions for mint, glam, nalgebra, and cgmath
  • a first-party bevy_boxddd plugin for Bevy 0.19 apps and teaching examples

Status

boxddd is an experimental 0.1.0 binding while Box3D itself is new. The native desktop path is the main supported runtime surface today. The safe API covers the primary simulation path and tracks the remaining public Box3D surface in a tested coverage inventory; see docs/api-coverage.md.

Surface Status
Core boxddd on Windows, Linux, macOS Supported and tested
bevy_boxddd on Windows, Linux, macOS Supported for native Bevy apps and examples
WASM Experimental core support; browser apps are not ready yet
Mobile Not a supported runtime target yet

The core crate MSRV is Rust 1.92. bevy_boxddd currently requires Rust 1.95 because it tracks Bevy 0.19.

Version Compatibility

boxddd release Box3D API target Vendored Box3D source
0.1.0 box3d v0.1.0 erincatto/box3d@29bf523

The 0.1.0 vendored source includes a local single-thread WASM timer portability patch. Native desktop is the supported runtime path for the first release.

Crates

Crate Purpose
boxddd-sys Low-level FFI for the vendored Box3D C API.
boxddd Safe Rust wrapper for engine-independent physics code.
bevy_boxddd Bevy 0.19 plugin with ECS components, fixed-step systems, messages, queries, debug drawing, and windowed 3D examples.

Getting Started

Add the core crate when you want to own the physics loop yourself.

cargo add boxddd
use boxddd::prelude::*;

fn main() -> boxddd::Result<()> {
    let mut world = World::new(
        WorldDef::builder()
            .gravity(Vec3::new(0.0, -10.0, 0.0))
            .build(),
    )?;

    let ground = world.create_body(BodyDef::builder().position([0.0, -10.0, 0.0]).build());
    world.create_hull_shape(ground, &ShapeDef::default(), &BoxHull::new(50.0, 10.0, 50.0));

    let body = world.create_body(
        BodyDef::builder()
            .body_type(BodyType::Dynamic)
            .position([0.0, 4.0, 0.0])
            .build(),
    );
    world.create_hull_shape(
        body,
        &ShapeDef::builder().density(1.0).friction(0.3).build(),
        &BoxHull::cube(1.0),
    );

    world.step(1.0 / 60.0, 4);
    Ok(())
}

Run the smallest core example:

cargo run -p boxddd --example hello_world

Bevy

Use bevy_boxddd when you want Bevy entities and transforms to author the physics scene:

cargo add bevy_boxddd
cargo add bevy@0.19
use bevy::prelude::*;
use bevy_boxddd::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(BoxdddPhysicsPlugin::default())
        .add_systems(Startup, setup)
        .run();
}

fn setup(mut commands: Commands) {
    commands.spawn((
        RigidBody::Static,
        Collider::cuboid(8.0, 0.25, 8.0),
        Transform::from_xyz(0.0, -0.25, 0.0),
    ));

    commands.spawn((
        RigidBody::Dynamic,
        Collider::cube(0.5),
        Transform::from_xyz(0.0, 4.0, 0.0),
    ));
}

Good first Bevy examples:

cargo run -p bevy_boxddd --example falling_stack_3d
cargo run -p bevy_boxddd --example advanced_colliders_3d
cargo run -p bevy_boxddd --example joint_gallery_3d
cargo run -p bevy_boxddd --features "debug-gizmos physics-picking" --example testbed_3d

See bevy_boxddd/README.md for components, messages, fixed-step behavior, debug draw, picking, platform notes, and the full example catalog.

Examples

Start here:

Example Command Teaches
Core hello world cargo run -p boxddd --example hello_world World creation, ground, dynamic body, stepping
Error handling cargo run -p boxddd --example error_handling Recoverable try_* APIs
Events cargo run -p boxddd --example events Sensor, contact, hit, and body-move event snapshots
Body controls cargo run -p boxddd --example body_controls Body type changes, enable/disable, forces, impulses, and locks
Shape queries cargo run -p boxddd --example shape_queries World, body, and shape-scoped query APIs
Advanced collision cargo run -p boxddd --example advanced_collision Standalone distance, shape-cast, manifold, and plane helpers
Continuous collision cargo run -p boxddd --example continuous_collision Shape-cast, time-of-impact, and bullet body diagnostics
Character mover cargo run -p boxddd --example character_mover Capsule mover casts, contact planes, correction, and velocity clipping
Dynamic tree cargo run -p boxddd --example dynamic_tree Standalone broad-phase tree lifecycle, filters, and visitor callbacks
Joints cargo run -p boxddd --example joints Joint creation and runtime reads
Recording cargo run -p boxddd --example recording_replay Recording and replay validation
Native debug viewer cargo run -p boxddd --example egui_debug_draw --features egui-example Consuming debug draw data in an app-owned renderer
Bevy testbed cargo run -p bevy_boxddd --features "debug-gizmos physics-picking" --example testbed_3d Switchable stacks, advanced colliders, body controls, continuous collision, character mover, materials, joints, contacts, picking, and debug draw scenes

The full catalog lives in boxddd/examples/README.md and bevy_boxddd/README.md. The mapping from official Box3D samples to Rust examples and deliberate deferrals lives in docs/upstream-parity/box3d-sample-matrix.md.

Design Goals

  • Keep boxddd engine-agnostic. Bevy support lives in bevy_boxddd.
  • Prefer safe, typed Rust APIs over exposing raw Box3D handles directly.
  • Make invalid ids, stale resources, callback reentry, and unsupported platforms explicit.
  • Keep the default build simple: vendored Box3D C sources plus pregenerated bindings, with no normal-user dependency on LLVM or libclang.
  • Treat examples as teaching material, not just compile smoke tests.

Platform Notes

Native Windows, Linux, and macOS are the primary runtime targets. WASM support is early and core-only: it is useful for compatibility work today, but not yet a recommended browser app path. Bevy Web, browser rendering, web workers, pthreads, and cross-module callbacks are deferred.

Normal builds compile the vendored Box3D C sources locally through the Rust cc crate and link them into boxddd-sys. Users need a working platform C compiler, but they do not need CMake, LLVM, libclang, or bindgen unless they explicitly refresh bindings with boxddd-sys/bindgen and BOXDDD_SYS_FORCE_BINDGEN=1.

Read more:

Features

Core feature flags:

  • double-precision: build and bind Box3D in double-precision position mode.
  • disable-simd, validate: forward the matching Box3D C build options.
  • serde: serialize crate-owned value/id/query/debug/replay metadata types.
  • mint, glam, nalgebra, cgmath: enable conversions for common math crates.
  • egui-example, tokio-example: opt into heavier example-only dependencies.

Math interop is feature-gated and covered by runnable examples: mint_interop, glam_interop, and nalgebra_interop.

bevy_boxddd feature flags:

  • debug-gizmos: render collected Box3D debug draw commands through Bevy Gizmos.
  • physics-picking: enable the physics picking example surface.

Threading, Async, And Errors

World, native resources, and replay players are intentionally !Send/!Sync. Keep physics ownership on one thread or in Bevy's NonSend<BoxdddPhysicsContext>, then move plain snapshots across thread or async boundaries.

For async apps, use spawn_blocking, channels, and snapshots. See physics_thread.rs and tokio_async_bridge.rs.

The terse APIs panic on programming misuse such as invalid stale ids. Use try_* APIs at engine, editor, scripting, and tooling boundaries where invalid input should become boxddd::Error. Unsafe native interop such as raw void* user data and process-global scalar tuning lives under boxddd::raw, outside the prelude.

Development

Common local checks:

cargo fmt --all --check
cargo nextest run --workspace
cargo check --workspace --all-features
RUSTDOCFLAGS="-D warnings" cargo doc --workspace --no-deps

More maintainer commands are documented in docs/development/ci.md.

License

boxddd, boxddd-sys, and bevy_boxddd are licensed as MIT OR Apache-2.0. Vendored Box3D is MIT-licensed.