Joints
Connecting bodies with the Joint constraint - ball-sockets, hinges, sliders, welds, and world anchors.
A Joint connects two bodies - or a body and the world - and removes degrees of freedom between them. One configurable constraint expresses the whole joint taxonomy: it has six independent degrees of freedom (3 linear, 3 angular), each of which can be locked, free, limited, sprung, or motorised. The named helpers below pick the right combination for you.
Anatomy
A joint holds an anchor frame on each body coincident according to its per-DOF rules:
entityA/entityB- the two bodies. SetentityB = JOINT_WORLDto anchor body A to a fixed point in the world instead of a second body.localAnchorA/localAnchorB- the anchor point on each body, in that body’s local frame. WhenentityB === JOINT_WORLD,localAnchorBis a world coordinate.localBasisA/localBasisB- the orientation of the joint’s reference frame on each body (unit quaternions, identity by default). The locked/free/limited axes are this frame’s axes - so for a hinge you orient the frame so its free axis is the hinge axis.
Register a joint with the PhysicsSystem once both bodies exist; remove it with unlink_joint:
import { Joint, JOINT_WORLD } from "@woosh/meep-engine/src/engine/physics/ecs/Joint.js";
import { v3_set } from "@woosh/meep-engine/src/core/geom/vec3/v3_set.js";
const joint = new Joint(); // default: ball-socket
joint.entityA = linkA;
joint.entityB = linkB;
v3_set(joint.localAnchorA, 0, 0, -0.3, 0); // bottom of A
v3_set(joint.localAnchorB, 0, 0, 0.3, 0); // top of B
physics.link_joint(joint);
Joint types
Each helper configures the six DOFs and returns the joint, so you can chain. They’re the standard joints expressed as DOF patterns:
| Helper | DOFs | Use for |
|---|---|---|
asBallSocket() (default) | 3 linear locked, 3 angular free | chains, ropes, pendulums |
asHinge(axis) | 3 linear + 2 angular locked, 1 angular free | doors, wheels, elbows |
asPrismatic(axis) | 2 linear + 3 angular locked, 1 linear free | sliders, pistons, lifts |
asWeld() | all 6 locked | rigidly fuse two bodies |
asConeTwist(twistLo, twistHi, swingY, swingZ?) | 3 linear locked, 3 angular limited | ragdoll shoulders / hips |
For hinges and sliders, orient localBasisA / localBasisB so the free frame axis is the one you want. Anchors are three-element Float64Arrays; basis quaternions are four-element arrays in [x, y, z, w] order. Use v3_set for anchors and v4_set (from src/core/geom/vec4/v4_set.js) for bases, or copy an existing indexed vector with .set(vector).
Anchoring to the world
entityB = JOINT_WORLD pins body A to a fixed world point. A pendulum is one ball-socket to the world:
const pivot = new Joint();
pivot.entityA = bob;
pivot.entityB = JOINT_WORLD;
v3_set(pivot.localAnchorA, 0, 0, 1, 0); // top of the bob, in its frame
v3_set(pivot.localAnchorB, 0, 0, 5, 0); // fixed world point to hang from
physics.link_joint(pivot);
Chains
Wire a column of bodies anchor-to-anchor - bottom of each link to the top of the next - and pin the first to the world, and you have a rope or chain. The solver runs extra iterations on joints (physics.jointIterations) so impulses propagate the length of the chain in a single tick. See the Jointed chains example, which hangs four of them and sweeps a kinematic log through.
Beyond locked DOFs
Locking and freeing DOFs covers the rigid joints above. The same Joint also gives each DOF a limit, spring, or motor - end-stops, suspension, powered hinges. Those live on the Constraints page.
Where to go next
- Constraints - per-DOF limits, springs, and motors on a joint.
- Rigid bodies - the bodies a joint connects.
- Jointed chains - a live demo built on ball-socket joints.