What it does
await game.box2d.create(options) loads the core and makes a world, and game.box2d.bind(object, options) gives an
object a body, sized from its width and height. Each fixed step Box2D simulates and the pack writes the poses back
onto the objects, interpolated for display. A killed object takes its body with it, removed before the step so a pose
is never written onto a recycled slot.
The wrapper's real work is the bridge. A game works in world units with y down; Box2D works in metres with y up and
counter-clockwise rotation. Missing any part of that conversion gives a simulation that runs perfectly while everything
falls upwards, drifts at the wrong rate or spins the wrong way. The pack handles the scale (pixelsPerMeter, 32 by
default, since Box2D's tolerances expect a human-sized object to be about a metre), the flip and the angle negation,
down to joint limits that must be negated and swapped on the way in. Joints take world points, converted into each
body's own frame for you.
It also takes away Box2D's sharp edges. Polygons are hulled and simplified to Box2D's convex eight-vertex limit rather
than silently becoming empty shapes, or split into convex pieces on one body when the notch matters. force and
torque are accelerations scaled by the body's mass and inertia, so a number means the same on a pebble as on a
chassis. Collision filters are names, given bits on first use, and a family makes a ragdoll's own limbs ignore each
other.
Features
- Bodies on your objects — dynamic, static or kinematic, with
auto,box,circle,capsule,polygonanddecomposeshapes, and rounded box corners. - Body options — density or mass, friction, bounce, damping, gravity scale, fixed rotation, sensors, a
centre-of-mass offset (
balance) andbulletcontinuous collision. - Steering —
velocity,spin,impulse(optionally at a point, which spins), mass-scaledforceandtorque, andteleportas the one hard move. - Joints —
pin(a hinge with limits and a motor),rope(rod, slack or spring),weld,sliderandwheel(sprung suspension), with motors you can drive every frame. - Grabbing — a mouse-joint spring to a point you keep moving, so a dragged crate is stopped by walls and a fast release throws it.
- Chain ground —
world.chain(points)turns a polyline into static terrain with no inner corners for a fast body to snag on. - Queries and blasts —
raycastwith the point, normal and distance, andexplosionon every dynamic body in range. - Contact handlers —
onHitwith the approach speed,onTouch,onRelease,onEnterandonExit, which can ride the spawn spec before the world exists. - Debug drawing —
world.debugDrawstrokes every collision shape in its live pose, coloured by whether it is awake, asleep or static.
Good for
- Toppling and stacking games — domino runs, tower builders and demolition, where stacks must stay up until hit.
- Vehicle games — a chassis on sprung wheels with motors, driven over chain terrain.
- Ragdoll games — limbs on hinges that share a family.
- Contraptions — rope bridges, pendulum cradles, launchers and bowling, from ropes, hinges and welds.
- Drag-and-throw toys — a grabbed object that walls still stop and a fast release throws.
- Fast projectiles —
bulletbodies that hit thin walls instead of passing through them.
Make it yours
The options are gravity (900 units per second squared, y down, or a vector), pixelsPerMeter (32), substeps (4)
and module, to load the core from elsewhere during development; they go in the manifest or in create. Every body takes its own shape,
material and filtering, and gravity can change at any time.
Two different uses: a domino run of thin boxes standing on chain ground, set going by a pendulum on a rope, with a
sensor at the end whose onEnter wins the level; and a buggy game where the chassis carries its weight low with
balance, two motor-driven wheel joints carry it over hills made from a polyline, and the speeds onHit reports
decide the damage.
A quick look
A world, the ground, a crate kicked upwards and a hinge driven by its motor:
await game.box2d.create({ gravity: 900 }); // units/s², +y down
game.box2d.bind(ground, { type: 'static' });
const crate = game.box2d.bind(crateObject, { bounce: 0.2, friction: 0.6 });
crate.impulse({ x: 0, y: -400 }); // a kick up the screen
const hinge = game.box2d.pin(post, arm, { at: { x: 100, y: 60 }, limits: [-0.5, 0.5] });
hinge.motor(4, 900); // drive it
Works with
physics-2d— the engine's own solver, instant and deterministic and right for most games; compose one or the other, never both, since they do not share bodies.physics-workshop— physics levels as JSON, loaded into Box2D worlds of their own.physics-rope— ropes with weight whose ends can be tied to these bodies.
Good to know
- One world at a time: calling
create()again destroys the old one. - A body's shape is built from the object's size at bind time; resizing the object later does not resize the body.
- Never write
xoryon a dynamic body, since the step overwrites them;teleportis the hard move. - The core is WebAssembly, loaded on the first
create(), and standalone builds carry it inside the game. It runs fully headless, so the whole simulation can be tested in Node.
Changes
3.0.0-5 (2026-10-26)
- Changed: the
moduleoption only loads the core from the game's own origin; a URL on another origin, or adata:URL, is refused. Standalone builds embed the core and are unaffected.






