Skip to content

Bodies & motion

A Body is a rigid body in the world. This guide covers creating them and everything you can do with one.

  • static — never moves. Floors, walls, terrain. Cheapest; doesn’t wake for collisions.
  • kinematic — moved by you, unaffected by forces, but pushes dynamic bodies. Drive it with moveKinematic.
  • dynamic — fully simulated under gravity, forces, and collisions.

Two equivalent styles. Object literals are easy to serialize and generate:

const box = world.createBody({
type: "dynamic",
shape: Shape.box({ halfExtents: [0.5, 0.5, 0.5] }),
position: [0, 4, 0],
layer: "moving",
restitution: 0.3,
friction: 0.6,
});

The fluent Body builder is nice for handwritten code:

import { Body, Shape } from "jolt-ts";
const ball = world.createBody(
Body.dynamic()
.shape(Shape.sphere(0.5))
.translation(0, 8, 0)
.layer("moving")
.restitution(0.4)
.linearVelocity(2, 0, 0),
);

Body.dynamic(), Body.kinematic(), Body.fixed() (alias Body.static()) start a builder.

OptionMeaning
type"static" | "kinematic" | "dynamic" (default dynamic).
shapeThe collider (required).
position, rotationInitial transform. Rotation is { x, y, z, w } or [x, y, z, w].
layerCollision layer name or index.
friction, restitutionSurface material (0…1-ish).
linearVelocity, angularVelocityInitial velocities.
linearDamping, angularDampingVelocity decay per second.
gravityFactorScale gravity for this body (0 = weightless).
density / mass / massPropertiesOverride mass — see below.
motionQuality"discrete" (default) or "linearCast" for CCD.
sensortrue makes it a sensor.
allowSleepingLet the body sleep when it comes to rest (default true).
allowedDofsRestrict degrees of freedom — see below.
activateWhether the body starts awake (default true).
userDataAny JS value; stored on body.userData.

All getters return plain objects; every vector getter has a zero-allocation …Into() twin.

body.translation(); // { x, y, z }
body.rotation(); // { x, y, z, w }
body.linearVelocity(); // { x, y, z }
body.angularVelocity(); // { x, y, z }
body.centerOfMassPosition(); // { x, y, z }
body.pointVelocity([1, 0, 0]); // velocity of a world-space point on the body
body.mass(); // number (Infinity for static/kinematic)
body.motionType(); // "static" | "kinematic" | "dynamic"
body.isActive(); // awake?
body.isSensor();
body.friction();
body.gravityFactor();
body.allowSleeping();
const p = new Float32Array(3);
body.translationInto(p); // no allocation
body.setTranslation([1, 2, 3]); // teleport position
body.setRotation([0, 0, 0, 1]); // teleport rotation
body.setTransform([1, 2, 3], [0, 0, 0, 1]);
// Kinematic move: derives velocity so the body arrives next step and pushes others.
body.moveKinematic([x, 0.5, 0], [0, 0, 0, 1], 1 / 60);

Teleporting with setTransform does not carry other bodies along; moveKinematic does. Optional { activate } on the setters controls whether the body wakes.

// Instant kick (change in momentum). Optional world-space application point adds spin.
body.applyImpulse([0, 10, 0]);
body.applyImpulse([0, 10, 0], [0.2, 0, 0]);
body.applyAngularImpulse([0, 1, 0]);
// Continuous push, applied until the next step. Call it every frame for sustained force.
body.addForce([0, 20, 0]);
body.addTorque([0, 0.5, 0]);
// Set velocity directly.
body.setLinearVelocity(1, 0, 0);
body.setAngularVelocity(0, 2, 0);

See the interactive Forces example.

A dynamic body’s mass comes from its shape and a default density (1000 kg/m³). Override per body:

world.createBody({ type: "dynamic", shape, density: 200 }); // scale the computed mass
world.createBody({ type: "dynamic", shape, mass: 42 }); // exact mass, inertia from shape
world.createBody({
type: "dynamic",
shape,
massProperties: { mass: 24, inertia: [10, 0, 0, 0, 12, 0, 0, 0, 14] }, // full control
});

density and mass/massProperties are mutually exclusive.

Restrict which axes a body may translate or rotate along. The classic use is an upright character capsule — see Locked rotations.

// Shorthand: translation on all axes, no rotation.
Body.dynamic().shape(capsule).lockRotations();
// Explicit — any subset of the six DOFs.
world.createBody({
type: "dynamic",
shape: capsule,
allowedDofs: ["translation-x", "translation-y", "translation-z"],
});

The six values are translation-x/y/z and rotation-x/y/z.

Resting dynamic bodies go to sleep to save CPU and wake on contact. Control it:

body.allowSleeping(); // is sleeping allowed?
body.setAllowSleeping(false); // keep it always awake (also wakes it now)
body.isActive(); // awake right now?
body.wakeUp();
body.sleep();
body.remove(); // or: world.removeBody(body)

This destroys the native body and invalidates the wrapper; calling methods on it afterward throws. Everything is also cleaned up automatically by world.dispose().