<div align="center">
# boxdd - Rust bindings for Box2D v3 (C API)
[](https://crates.io/crates/boxdd)
[](https://docs.rs/boxdd)
[](#license)

</div>
## Crates
- `boxdd-sys`: low-level FFI for the official Box2D v3 C API (vendored)
- `boxdd`: safe layer (world, bodies, shapes, joints, queries, events, debug draw)
## 0.4.0 Highlights
- `0.4.0` realigns `boxdd-sys` with the official upstream Box2D submodule again, so repository checkouts and CI no longer depend on a local-only Box2D patch commit.
- Hot-path APIs are first-class: keep the simple `Vec`-returning calls for one-off use, or move per-frame code to `*_into` and `visit_*`.
- `boxdd::collision` now exposes standalone distance, shape-cast, TOI, manifold, and `Aabb::ray_cast` helpers without dropping to raw `ffi`.
- Character-mover support is complete on the safe surface: `cast_mover`, `collide_mover`, `solve_planes`, and `clip_vector`.
- `WorldHandle` is now a practical read-only follow-up surface for body, shape, joint, query, and owned-event inspection.
- Raw FFI boundaries are explicit and easier to reason about: use crate-owned ids/value types plus named `from_raw(...)`, `into_raw()`, and `*_raw` escape hatches.
- Open-chain runtime material access still uses visible live-segment indexing on the safe API, but that normalization now lives in Rust instead of a custom Box2D patch.
- The examples and testbed were reorganized around the intended current workflows instead of a loose grab bag of demos.
## Detailed Highlights
- Safe, ergonomic Rust wrapper over the official Box2D v3 C API.
- Math interop (features: `mint`/`cgmath`/`nalgebra`/`glam`): any `Into<Vec2>` accepts the corresponding 2D vector/point types, plus arrays/tuples.
- Two error-handling styles: panic-on-misuse by default, plus `try_*` APIs returning `ApiResult<T>` for recoverable errors.
- Explicit threading model: `worker_count` remains part of `WorldDef`, while `World` and owned handles stay pinned to one thread/task; actual Box2D worker-thread stepping still requires an explicit raw task-system configuration path.
- Hot-path query, debug-draw collection, and state-extraction APIs expose `*_into` buffer-reuse variants, and overlap queries also expose `visit_*` forms for zero result-container allocation.
- Character mover helpers cover the full safe workflow: `cast_mover`, `collide_mover`, `solve_planes`, and `clip_vector`.
- World runtime helpers cover counters, per-stage `Profile` timings, speculative-collision toggles, and safe explosion control.
- Core math types (`Vec2`, `Rot`, `Transform`) now cross the Box2D raw boundary explicitly through `from_raw(...)` / `into_raw()` instead of implicit conversions.
- Global foundation helpers now cover allocated-byte inspection, timing ticks/millisecond helpers, thread yielding, and deterministic hashing without dropping to raw `ffi`.
- Standalone collision geometry helpers cover shape proxies, GJK distance, segment distance, contact manifolds, chain-segment manifolds, shape cast, TOI, and `Aabb::is_valid` / `Aabb::ray_cast` without raw `ffi`, with matching recoverable `try_*` entrypoints for malformed input.
- Shape creation and editing now use crate-owned geometry values, and chain segments can be inspected through the crate-owned `ChainSegment` type.
- Chain runtime material access now uses visible segment indexing on open chains instead of leaking Box2D's ghost-placeholder storage layout.
- Safe shape/joint mutators now front-load obvious Box2D assert preconditions such as non-negative material scalars and ordered joint limits.
- Safe world/body/joint creation now validates obvious Box2D definition preconditions before entering native code, and definition value objects expose `validate()` helpers for preflight checks.
- Pointer-bearing config wrappers now keep their raw re-entry explicit: `BodyDef::from_raw(...)` and `WorldDef::from_raw(...)` are `unsafe` because raw names/task callbacks can otherwise punch through later safe creation paths.
- Live shape runtime helpers now cover `aabb`, `test_point`, direct `ray_cast`, computed `mass_data`, and runtime event toggles without raw `ffi`.
- Body runtime helpers now cover `rotation`, sleep/awake/enabled/bullet/name controls, attached `shapes/joints` enumeration, and body-level contact/hit event toggles.
- Joint runtime helpers now cover both common metadata/control and type-specific distance/prismatic/revolute/weld/wheel/motor state across owned/scoped/id-style APIs.
- Opaque ids (`BodyId`, `ShapeId`, `JointId`, `ChainId`, `ContactId`) are now crate-owned value types; raw interop is explicit through `from_raw(...)` / `into_raw()`.
- `ContactId` now exposes direct `is_valid` / `data` / `data_raw` and `try_*` helpers as inherent methods; no extension-trait import is required to inspect contact ids from events or snapshots.
- Shape classification, mass properties, and contact extraction now use crate-owned value types such as `ShapeType`, `MassData`, `ContactData`, and `Manifold`.
- Body motion constraints use the crate-owned `MotionLocks` type instead of raw Box2D flags.
- Crate-owned `MassData` and `MotionLocks` cross the FFI boundary explicitly via `from_raw(...)` / `into_raw()` when raw interop is still needed.
- Debug draw callbacks and collected commands use the crate-owned `HexColor` type instead of raw `ffi` colors.
- Typed world-level friction and restitution mixing callbacks expose `user_material_id` without dropping to raw `ffi`.
## Quickstart
```rust
use boxdd::{World, WorldDef, BodyBuilder, ShapeDef, shapes, Vec2};
let def = WorldDef::builder().gravity(Vec2::new(0.0, -9.8)).build();
let mut world = World::new(def).unwrap();
let mut body = world.create_body_owned(BodyBuilder::new().position([0.0, 2.0]).build());
let poly = shapes::box_polygon(0.5, 0.5);
let _shape = body.create_polygon_shape(&ShapeDef::default(), &poly);
world.step(1.0/60.0, 4);
```
## Features (optional)
- `serde`: serialization for core value/config types (`Vec2`, `Rot`, `Transform`, `Aabb`, `QueryFilter`, etc.).
- `serialize`: snapshot helpers (save/apply world config; take/rebuild minimal full-scene snapshot).
- `mint`: lightweight math interop types (`mint::Vector2`, `mint::Point2`, bidirectional `mint::RowMatrix2` / `mint::ColumnMatrix2` for `Rot`, and row/column-major 2D affine matrices for `Transform`).
- `cgmath`, `nalgebra`, `glam`: conversions with their 2D types (e.g. `Vector2/Point2`, `UnitComplex/Isometry2`, `glam::Vec2`).
- `bytemuck`: enable `Pod`/`Zeroable` for core math types (`Vec2`, `Rot`, `Transform`, `Aabb`) for zero-copy interop.
- `unchecked`: exposes extra `unsafe` unchecked APIs for hot paths (skips id validity checks; you must guarantee ids are valid).
## Math Interop
- `Vec2` always accepts `[f32; 2]` and `(f32, f32)` anywhere `Into<Vec2>` is used.
- `mint` now covers `Vec2`, `Aabb`, `Rot`, and `Transform`, including row- and column-major 2D matrix forms and recoverable `TryFrom` validation for `Rot` / `Transform`.
- `cgmath`, `nalgebra`, and `glam` remain first-class interop options for projects that already standardize on those math crates.
## Threading and Async
- `WorldDef::builder().worker_count(n)` stores the desired upstream worker count, but Box2D only uses worker threads when task callbacks are also installed through `unsafe WorldBuilder::task_system_raw(...)`, `WorldDef::set_task_system_raw(...)`, or a fully raw `WorldDef` path. It does not make `World`, `WorldHandle`, or owned handles `Send`/`Sync`.
- Keep physics ownership on one thread/task. In async runtimes prefer `spawn_local` / `LocalSet`; in multi-threaded engines prefer a dedicated physics thread and communicate with channels.
- `set_custom_filter*`, `set_pre_solve*`, `set_friction_callback`, and `set_restitution_callback` may run on Box2D worker threads, so those closures must stay `Send + Sync` and should be treated as pure callbacks.
- See `examples/physics_thread.rs` for a minimal dedicated-thread pattern.
## Error Handling
- The default safe APIs panic on misuse such as stale ids or calling Box2D while the world is locked in a callback. This keeps the common path terse and avoids Rust-level UB.
- At engine/runtime boundaries, prefer `try_*` APIs and handle `ApiError` explicitly.
- `ApiError` covers stale ids, callback-locked access, invalid arguments, out-of-range runtime indices, invalid typed-joint family use, invalid chain defs, interior NUL strings, typed user-data mismatches, and material-callback slot exhaustion.
- `WorldDef`, `BodyDef`, `ShapeDef`, `SurfaceMaterial`, `JointBase`, and concrete `*JointDef` values expose `validate()` so tooling and editor flows can reject invalid config before calling `create_*`.
- World-level runtime tuning and explosion helpers now also expose `try_*` variants when callback locking should be handled recoverably.
## World Runtime Extras
- `world.counters()` and `world.profile()` expose simulation size counters and last-step timing breakdowns without dropping to raw `ffi`.
- `ExplosionDef` and `world.explode(...)` / `world.try_explode(...)` now expose Box2D's explosion API directly on the main safe surface.
- Runtime tuning controls such as sleeping, continuous collision, warm starting, speculative collision, restitution threshold, hit threshold, contact tuning, and maximum linear speed now have matching `try_*` coverage.
- `BodyBuilder::allow_fast_rotation(...)`, computed body AABB helpers (`Body::aabb()`, `OwnedBody::aabb()`, `World::body_aabb(...)`), and read-only `WorldHandle` runtime getters for world diagnostics plus body-by-id, shape-by-id, and joint-by-id queries keep more of the upstream runtime surface on the main safe API.
## Snapshots
- Enable `serialize` and see example `examples/scene_serialize.rs` for a minimal scene round-trip.
- Note: chain shapes are captured when created via this wrapper (`World::create_chain_for_id` / `Body::create_chain`).
- Note: `ShapeDef` flags that have no runtime getters are captured for shapes created via this wrapper.
## Build Modes
- From source: builds vendored Box2D C sources via `cc` and uses pregenerated bindings by default.
- Example: `cargo build -p boxdd`.
- System library (optional): link an existing `box2d` installed on the system.
- Via env: set `BOX2D_LIB_DIR=/path/to/lib` and optionally `BOXDD_SYS_LINK_KIND=static|dylib`.
- Via feature: enable `pkg-config` and provide `box2d` through your system's package manager.
- Note: crate features that affect C build (e.g. `simd-avx2`, `disable-simd`, `validate`) are ignored in system mode. Set `BOXDD_SYS_STRICT_FEATURES=1` to fail the build if such features are enabled.
## Getting Started
```bash
git submodule update --init --recursive
cargo build
# run a few representative examples
cargo r --example world_basics
cargo r --example queries
cargo r --example character_mover
cargo r --example mint_interop --features mint
cargo r --example physics_thread
cargo r --example scene_serialize --features serialize
cargo r --example testbed_imgui_glow --features imgui-glow-testbed
```
## Examples
- The example catalog is now grouped by topic in [`boxdd/examples/README.md`](boxdd/examples/README.md), so users can start from the workflows they care about instead of scanning file names.
- Recommended starting points:
- `world_basics`: minimal world/body/shape setup
- `buffer_reuse`, `queries`, `query_casts`, `character_mover`: the main `0.4.0` hot-path, overlap, cast, and mover workflows
- `mint_interop`: optional `mint` vector/point/matrix interop sample behind the `mint` feature
- `collision_basics`: standalone collision geometry helpers without constructing a `World`
- `events_summary`, `events_view`: owned-with-reuse vs borrowed zero-copy event access
- `world_handle_reads`: stored read-only `WorldHandle` follow-up queries after id-producing world queries, including reusable-buffer overlap reads
- `scene_serialize`: snapshot/restore flows behind the `serialize` feature
- `physics_thread`: the recommended dedicated physics-thread ownership model
- `testbed_imgui_glow`: optional interactive testbed on the current `dear-imgui-*` stack
## Hot Path APIs
- Convenience methods like `world.overlap_aabb(...)` and `world.cast_ray_all(...)` still return owned `Vec`s for one-off use.
- For per-frame hot paths, prefer reusable-buffer variants such as `world.overlap_aabb_into(...)`, `world.cast_ray_all_into(...)`, `world.debug_draw_collect_into(...)`, `shape.sensor_overlaps_into(...)`, `body.contact_data_into(...)`, `body.shapes_into(...)`, `body.joints_into(...)`, and `chain.segments_into(...)`.
- For overlap-heavy paths that only need streaming inspection or early exit, prefer `world.visit_overlap_aabb(...)`, `visit_overlap_polygon_points(...)`, and `visit_overlap_polygon_points_with_offset(...)` so no result container needs to be built at all.
- `body.contact_data_into(...)` and `shape.contact_data_into(...)` now fill `Vec<ContactData>`; explicit raw escape hatches are available as `contact_data_raw_into(...)` if you truly need the upstream FFI layout.
## Character Mover APIs
- The safe wrapper now covers Box2D's geometric character mover pipeline.
- Use `world.cast_mover(...)` to test motion, `world.collide_mover(...)` or `world.collide_mover_into(...)` to collect planes, `boxdd::solve_planes(...)` / `boxdd::try_solve_planes(...)` to solve them, and `boxdd::clip_vector(...)` / `boxdd::try_clip_vector(...)` to clip velocity against solved planes.
- See `examples/character_mover.rs` for a minimal end-to-end usage example.
## Collision Geometry APIs
- `boxdd::collision` exposes Box2D's standalone low-level geometry algorithms as safe Rust value types.
- Use `ShapeProxy`, `SimplexCache`, `DistanceInput`, `ShapeCastPairInput`, `Sweep`, and `ToiInput` with `segment_distance(...)`, `shape_distance(...)`, `shape_cast(...)`, and `time_of_impact(...)`, or the matching recoverable `try_*` variants when malformed input should return `ApiError::InvalidArgument`.
- Standalone manifold helpers such as `collide_polygons(...)`, `collide_polygon_and_circle(...)`, `collide_segment_and_capsule(...)`, and `collide_chain_segment_and_polygon(...)` return the safe `Manifold` type and now also expose matching recoverable `try_collide_*` variants.
- `Aabb::is_valid()` and `Aabb::ray_cast(origin, translation)` now cover common AABB validation and ray-cast needs without reaching for `boxdd_sys::ffi`.
- These advanced APIs are intentionally not in the prelude, so collision-heavy code can import them explicitly.
## Shape Geometry APIs
- `boxdd::shapes::circle`, `segment`, `capsule`, `box_polygon`, `rounded_box_polygon`, and `polygon_from_points` return safe geometry value types instead of raw Box2D structs.
- `Shape::circle()` / `segment()` / `capsule()` / `polygon()` and the corresponding setters now use the same geometry types as world/body creation APIs.
- `Circle`, `Segment`, `Capsule`, and `Polygon` expose standalone helpers such as `mass_data(...)`, `aabb(...)`, `contains_point(...)`, `ray_cast(...)`, and `transformed(...)` for world-free geometry work.
- `Circle`, `Segment`, `Capsule`, `ChainSegment`, and `Polygon` now expose `is_valid()` / `validate()` so engines can preflight geometry before crossing the FFI boundary.
- Those world-free helper methods also expose recoverable `try_*` variants (`try_mass_data`, `try_aabb`, `try_contains_point`, `try_ray_cast`, `try_transformed`) so malformed helper inputs can return `ApiError::InvalidArgument` instead of panicking.
- Polygon construction helpers also expose recoverable `try_*` variants (`try_square_polygon`, `try_box_polygon`, `try_rounded_box_polygon`, `try_offset_*`, `try_polygon_from_points`) so finite extents, transforms, and hull construction can be validated without collapsing everything to `Option`.
- Live `Shape` / `OwnedShape` / `World::shape_*` APIs now also cover runtime `aabb`, `test_point`, `ray_cast`, `mass_data`, and event-toggle state.
- Raw geometry conversion is explicit on the crate-owned geometry types: use `from_raw(...)` / `into_raw()` when you intentionally cross the FFI boundary.
- `ShapeDefBuilder::filter(...)` and `ChainDef::builder().filter(...)` now take the safe `Filter` type; explicit raw escape hatches are named `filter_raw(...)`.
- `Filter` also uses explicit raw conversion via `from_raw(...)` / `into_raw()` instead of implicit `From<ffi::b2Filter>` conversions.
- `SurfaceMaterial` now behaves like a normal crate-owned value type: builder-style mutation uses `with_*` methods, read access uses getters such as `friction()`, `restitution()`, and `custom_color()`, `custom_color` uses crate-owned `HexColor`, and raw interop stays explicit through `from_raw(...)` / `into_raw()`.
## Joint Runtime APIs
- `Joint`, `OwnedJoint`, `World::joint_*`, and read-only `WorldHandle::joint_*` now stay aligned for common runtime metadata and control: joint type, connected body ids, `collide_connected`, constraint tuning, local frames, thresholds, and wake helpers.
- Type-specific runtime getters/setters for distance, prismatic, revolute, weld, wheel, and motor joints are aligned across `World`, `OwnedJoint`, and scoped `Joint<'_>` handles, while `WorldHandle` mirrors the read-only getter half so stored `JointId` values can stay on the handle path.
- `JointType` and `ConstraintTuning` are crate-owned value types; raw access stays explicit through `joint_type_raw` and `JointType::from_raw(...)` / `into_raw()`.
- `try_*` typed joint APIs now return `ApiError::InvalidJointType` when a valid joint is used through the wrong family surface.
- World-space joint builders now preserve previously configured base flags such as `collide_connected` while populating runtime-computed body ids and local frames.
## Material Mixing Callbacks
- `world.set_friction_callback(...)` and `world.set_restitution_callback(...)` expose Box2D's material mixing hooks as safe typed closures.
- Each callback receives two `MaterialMixInput` values containing the incoming coefficient and `user_material_id`.
- These callbacks may run on Box2D worker threads, so they must stay thread-safe and should be treated as pure mixing functions.
## Events
- Four access styles:
- By value: `world.contact_events()`/`sensor_events()`/`body_events()`/`joint_events()` return owned data for storage or cross-frame use.
- Reusable buffers: `*_events_into(...)` reuse caller-owned owned-event storage across frames.
- Zero‑copy views: `with_*_events_view(...)` iterate without allocations (borrows internal buffers).
- Raw slices: `unsafe { with_*_events_raw(...) }` expose FFI slices (borrows internal buffers).
- Callback-sensitive event entrypoints also have matching `try_*` variants so callback-lock failures can return `ApiError::InCallback` instead of forcing panic-only control flow.
- Owned event snapshots (`*_events`, `*_events_into`, `try_*`) are available on both `World` and `WorldHandle`.
- Borrowed zero-copy event views and raw event-buffer access intentionally stay on `World`, because they are tied to the completed step's world-local event buffers plus deferred-destroy flushing.
- Example (reusable buffers + zero-copy views):
```rust
use boxdd::{ContactEvents, World, WorldDef};
let mut world = World::new(WorldDef::default()).unwrap();
let mut contact_events = ContactEvents::default();
world.contact_events_into(&mut contact_events);
world.with_contact_events_view(|begin, end, hit| {
let _ = (begin.count(), end.count(), hit.count());
});
world.with_sensor_events_view(|beg, end| {
let _ = (beg.count(), end.count());
});
world.with_body_events_view(|moves| {
for m in moves { let _ = (m.body_id(), m.fell_asleep()); }
});
world.with_joint_events_view(|j| { let _ = j.count(); });
```
## Notes
- Vendored C sources + pregenerated bindings by default (no LLVM needed on CI).
- To force bindgen: enable the `boxdd-sys/bindgen` feature, set `BOXDD_SYS_FORCE_BINDGEN=1`, and ensure `libclang` is available. On Windows/MSVC, set `LIBCLANG_PATH` if needed.
- On docs.rs, the native C build is skipped.
- Safe handle methods validate ids and panic on invalid ids (prevents UB if an id becomes stale). For recoverable failures (invalid ids / calling during Box2D callbacks), use `try_*` APIs.
- Threading: `World` and owned handles are `!Send`/`!Sync`. `worker_count` only controls Box2D's internal stepping workers. Run physics on one thread; in async runtimes prefer `spawn_local`/`LocalSet`, or create the world inside a dedicated physics thread and communicate via channels.
## Documentation
- Local: `cargo doc --open`
- Online: https://docs.rs/boxdd
## Changelog
- See `CHANGELOG.md`.
## Acknowledgments
- Thanks to the Rust Box2D bindings project for prior art and inspiration: https://github.com/Bastacyclop/rust_box2d
- Huge thanks to the upstream Box2D project by Erin Catto: https://github.com/erincatto/box2d
## Related Projects
If you're working with graphics applications in Rust, you might also be interested in:
- **[asset-importer](https://github.com/Latias94/asset-importer)** - A comprehensive Rust binding for the latest [Assimp](https://github.com/assimp/assimp) 3D asset import library, providing robust 3D model loading capabilities for graphics applications
- **[dear-imgui](https://github.com/Latias94/dear-imgui)** - Comprehensive Dear ImGui bindings for Rust using C++ bindgen, providing immediate mode GUI capabilities for graphics applications
## License
- `boxdd`: MIT OR Apache-2.0
- `boxdd-sys`: MIT OR Apache-2.0