Expand description
Safe, owner-scoped Rust bindings for the pinned Box2D v3 C API.
boxdd deliberately presents one ownership model and one fallible API:
Worldowns the native simulation and all Rust-side identity and callback state.BodyId,ShapeId,JointId, andChainIdare copyable, world-bound identifiers intended for application storage.Body,Shape,Joint, andChainare capabilities tied to a mutable borrow of the world. Dropping one releases the borrow; destruction is always explicit.Queryis a read-only capability tied to its owner borrow. Reusable query buffers avoid repeated allocation on hot paths.- Public operations that can fail return
Result. Stale IDs, invalid definitions, callback reentry, and terminal native state are reported rather than routed through a parallel panic-style API.
Live IDs cannot be detached, rebound, reconstructed from raw Box2D IDs, or used as persistence
keys through Safe Rust. Use application-owned stable keys for saved state. Use boxdd_sys
directly only when the caller accepts the raw FFI contract.
§Quick start
use boxdd::{BodyType, Foundation, ShapeDef, Vec2, shapes};
let foundation = Foundation::initialize_default().unwrap();
let mut world = foundation.create_world(
foundation
.world_builder()
.gravity(Vec2::new(0.0, -9.8))
.build()?,
)?;
let body_id = world.create_body(
world
.body_builder()
.body_type(BodyType::Dynamic)
.position([0.0, 2.0])
.build()?,
)?;
{
let mut body = world.body(body_id)?;
body.create_polygon(
&ShapeDef::builder().density(1.0).build()?,
&shapes::box_polygon(0.5, 0.5)?,
)?;
}
let completed = world.step(1.0 / 60.0, 4)?;
let contacts = completed.contact_events()?.to_owned()?;§Ownership and identity
Creation returns a world-bound ID. Acquire a capability when an operation needs access to the corresponding object:
let body_id = world.create_body(world.body_builder().build()?)?;
world.body(body_id)?.set_awake(true)?;
world.body(body_id)?.destroy()?;Capability acquisition validates the ID once and prevents overlapping mutable world access for
the lifetime of the capability. A body, shape, joint, or chain is destroyed only by its
explicit destroy method or by destruction of an owning native object/world.
ContactId values are additionally tied to a contact epoch. Inspect them through
World::contact_is_valid and World::contact_data.
§Coordinates
Position and WorldTransform represent absolute world coordinates using WorldScalar,
which is f32 by default and f64 with double-precision. Vec2 and Transform represent
local offsets, directions, extents, and relative transforms and always remain f32.
Queries therefore take an explicit absolute origin plus local geometry:
use boxdd::{Aabb, Foundation, Position, QueryFilter, ShapeQueryBuffer};
let foundation = Foundation::initialize_default().unwrap();
let world = foundation.create_world(foundation.world_def())?;
let query = world.query()?;
let mut hits = ShapeQueryBuffer::new();
query.overlap_aabb_into(
Position::ZERO,
Aabb::from_center_half_extents([0.0, 0.0], [5.0, 5.0])?,
QueryFilter::default(),
&mut hits,
)?;§Threading and callbacks
World and its borrow-scoped capabilities are !Send and !Sync. Keep a world on one
owner thread; a dedicated physics thread plus channels is the portable integration model for
multi-threaded or async applications.
On native targets, custom-filter, pre-solve, friction-mix, and restitution-mix callbacks may run
on Box2D workers. Their closures are Send + Sync + 'static and receive only copyable values and
branded IDs, never a world context. Query, dynamic-tree, event-view, and debug-draw callbacks
are closure-scoped. Every Rust callback catches unwind-capable panics before returning through C.
WorkerCount selects the qualified built-in Box2D scheduler. Safe Rust does not expose raw
task-system function pointers.
§Snapshots, recording, and replay
Snapshot is an opaque capability that can restore only its originating world.
RecordingSession exclusively borrows a world and produces an opaque process-local
Recording. ReplayPlayer accepts only such a recording and exposes epoch-bound views while
holding exclusive process-global foundation access.
Safe Rust exposes no native snapshot or recording bytes, fresh-world snapshot loading, or replay from external bytes. Durable persistence requires an application-owned versioned schema that rebuilds a world.
§Features
double-precisionchanges absolute world coordinates and the native ABI together.serdecovers safe value and configuration types, not live worlds or object IDs.mint,nalgebra, andglamprovide scalar-correct math interop.bytemuckcovers layout-qualified value types.
See the repository’s migration guide and FFI lifetime audit for the complete ownership, provider, callback, and platform contracts.
Re-exports§
pub use body::Body;pub use body::BodyBuilder;pub use body::BodyDef;pub use body::BodyType;pub use body::MAX_BODY_NAME_BYTES;pub use collision::CastOutput;pub use collision::DistanceInput;pub use collision::DistanceOutput;pub use collision::LocalManifold;pub use collision::LocalManifoldPoint;pub use collision::MAX_LOCAL_MANIFOLD_POINTS;pub use collision::MAX_SHAPE_PROXY_POINTS;pub use collision::SegmentDistanceResult;pub use collision::ShapeCastInput;pub use collision::ShapeCastPairInput;pub use collision::ShapeProxy;pub use collision::SimplexCache;pub use collision::Sweep;pub use collision::ToiInput;pub use collision::ToiOutput;pub use collision::ToiState;pub use collision::collide_capsule_and_circle;pub use collision::collide_capsules;pub use collision::collide_chain_segment_and_capsule;pub use collision::collide_chain_segment_and_circle;pub use collision::collide_chain_segment_and_polygon;pub use collision::collide_circles;pub use collision::collide_polygon_and_capsule;pub use collision::collide_polygon_and_circle;pub use collision::collide_polygons;pub use collision::collide_segment_and_capsule;pub use collision::collide_segment_and_circle;pub use collision::collide_segment_and_polygon;pub use collision::segment_distance;pub use collision::shape_cast;pub use collision::shape_distance;pub use collision::time_of_impact;pub use core::foundation::Foundation;pub use core::foundation::FoundationActivity;pub use core::foundation::FoundationActivityError;pub use core::foundation::FoundationAdapterIdentityField;pub use core::foundation::FoundationConfig;pub use core::foundation::FoundationDiagnostics;pub use core::foundation::FoundationInitError;pub use core::foundation::FoundationAssertHook;pub use core::foundation::FoundationLogHook;pub use core::math::HASH_INIT;pub use core::math::Rot;pub use core::math::Transform;pub use core::math::Version;pub use core::math::allocated_byte_count;pub use core::math::atan2;pub use core::math::compute_cos_sin;pub use core::math::hash_bytes;pub use core::math::is_valid_float;pub use core::math::milliseconds_and_reset;pub use core::math::milliseconds_since;pub use core::math::rotation_between_unit_vectors;pub use core::math::ticks;pub use core::math::version;pub use core::math::yield_now;pub use debug_draw::DebugDraw;pub use debug_draw::DebugDrawCmd;pub use debug_draw::DebugDrawOptions;pub use debug_draw::HexColor;pub use dynamic_tree::DynamicTree;pub use dynamic_tree::TreeBoxCastInput;pub use dynamic_tree::TreeCastControl;pub use dynamic_tree::TreeProxyId;pub use dynamic_tree::TreeRayCastInput;pub use dynamic_tree::TreeStats;pub use error::Error;pub use error::Result;pub use events::BodyEvents;pub use events::BodyMoveEvent;pub use events::CompletedStep;pub use events::ContactBeginTouchEvent;pub use events::ContactEndTouchEvent;pub use events::ContactEvents;pub use events::ContactEventsView;pub use events::ContactHitEvent;pub use events::JointEvent;pub use events::JointEvents;pub use events::SensorBeginTouchEvent;pub use events::SensorEndTouchEvent;pub use events::SensorEvents;pub use events::SensorEventsView;pub use events::StepEventsSnapshot;pub use filter::Filter;pub use joints::ConstraintTuning;pub use joints::DistanceJoint;pub use joints::DistanceJointBuilder;pub use joints::DistanceJointDef;pub use joints::FilterJoint;pub use joints::FilterJointBuilder;pub use joints::FilterJointDef;pub use joints::Joint;pub use joints::JointBase;pub use joints::JointType;pub use joints::MotorJoint;pub use joints::MotorJointBuilder;pub use joints::MotorJointDef;pub use joints::PrismaticJoint;pub use joints::PrismaticJointBuilder;pub use joints::PrismaticJointDef;pub use joints::RevoluteJoint;pub use joints::RevoluteJointBuilder;pub use joints::RevoluteJointDef;pub use joints::WeldJoint;pub use joints::WeldJointBuilder;pub use joints::WeldJointDef;pub use joints::WheelJoint;pub use joints::WheelJointBuilder;pub use joints::WheelJointDef;pub use query::Aabb;pub use query::ClosestRayCastResult;pub use query::CollisionPlane;pub use query::MoverPlaneResult;pub use query::Plane;pub use query::PlaneSolverResult;pub use query::Query;pub use query::QueryFilter;pub use query::RayResult;pub use query::clip_vector;pub use query::solve_planes;pub use query::MoverQueryBuffer;pub use query::RayQueryBuffer;pub use query::ShapeQueryBuffer;pub use recording::MixerId;pub use recording::MixerIdentities;pub use recording::Recording;pub use recording::RecordingLimits;pub use recording::RecordingSession;pub use replay::ReplayBodyView;pub use replay::ReplayConfig;pub use replay::ReplayEpoch;pub use replay::ReplayInfo;pub use replay::ReplayKeyframePolicy;pub use replay::ReplayKeyframeState;pub use replay::ReplayPlayer;pub use replay::ReplayQueryHitView;pub use replay::ReplayQueryKind;pub use replay::ReplayQueryView;pub use replay::ReplayStatus;pub use replay::ReplayView;pub use shapes::chain::Chain;pub use shapes::chain::ChainDef;pub use shapes::chain::ChainDefBuilder;pub use shapes::chain::ChainDefMaterialLayout;pub use shapes::Capsule;pub use shapes::ChainSegment;pub use shapes::Circle;pub use shapes::MAX_POLYGON_VERTICES;pub use shapes::Polygon;pub use shapes::Segment;pub use shapes::Shape;pub use shapes::ShapeDef;pub use shapes::ShapeDefBuilder;pub use shapes::ShapeType;pub use shapes::SurfaceMaterial;pub use snapshot::PreparedSnapshotRestore;pub use snapshot::Snapshot;pub use snapshot::SnapshotRestore;pub use types::BodyId;pub use types::ChainId;pub use types::ContactData;pub use types::ContactId;pub use types::JointId;pub use types::MAX_MANIFOLD_POINTS;pub use types::Manifold;pub use types::ManifoldPoint;pub use types::MassData;pub use types::MotionLocks;pub use types::Position;pub use types::PositionToLocalError;pub use types::ShapeId;pub use types::Vec2;pub use types::WorldCastOutput;pub use types::WorldScalar;pub use types::WorldTransform;pub use types::WorldTransformFromInteropError;pub use world::B2_MAX_WORKERS;pub use world::Counters;pub use world::MaterialMixInput;pub use world::Profile;pub use world::WorkerCount;pub use world::World;pub use world::WorldBuilder;pub use world::WorldCapacity;pub use world::WorldDef;pub use world_extras::ExplosionDef;
Modules§
- body
- collision
- Standalone low-level collision geometry helpers.
- contact
- core
- debug_
draw - Debug Draw bridge to Box2D v3 callbacks.
- dynamic_
tree - Safe wrapper for Box2D’s standalone dynamic AABB tree.
- error
- Common errors for the safe API.
- events
- Lazy, borrow-scoped event access for one completed simulation step.
- filter
- id
- Opaque world-bound Box2D object identifiers.
- joints
- Joint definitions, creation helpers, and borrow-scoped runtime capabilities.
- prelude
- query
- Borrow-scoped broad-phase queries, casts, and character-mover helpers.
- recording
- Owned Box2D recording sessions and opaque process-local recordings.
- replay
- Owned, preflighted Box2D recording playback.
- shapes
- Shapes API
- snapshot
- Transactional Box2D world snapshots.
- tuning
- Tuning Notes and Upstream Constants
- types
- world
- world_
extras - Additional world runtime helpers and value types that sit beside the core world API.