Joints & Motors
Joints constrain two bodies together - a hinge, a slider, a weld, a ball socket - optionally driven by a motor or a spring.
Status - backend only, not yet authorable
Joints are fully implemented in the physics backend and the Rapier layer (the interface below is real and exercised), but they are not yet wired to any authoring surface. There is no Joint ECS component, no Inspector control, and no script API for creating joints today. This page documents the capability that exists in packages/runtime/src/physics so you know what the abstraction supports; expect a Joint component and/or a scripting hook in a later release. Nothing on this page is reachable from the editor UI yet.
What a joint is
A joint is a constraint between two physics bodies that removes some of their relative freedom. Where a plain collision only stops bodies inter-penetrating, a joint actively holds them in a defined relationship - a door hinged to a frame, a wheel spinning on an axle, a slider on a rail. Anchors are specified local to each body.
Joint types
The backend's JointDesc covers four kinds:
| Kind | Constraint | Typical use |
|---|---|---|
| fixed | Weld - no relative motion at all. | Bolting two parts into one rigid assembly. |
| spherical | Ball-and-socket - free rotation, optional swing/twist limits. | Ragdoll limbs, chains, pendulums. |
| revolute | Hinge - one rotation axis, optional angle limits. | Doors, wheels, levers. |
| prismatic | Slider - one translation axis, optional travel limits. | Suspension, pistons, elevators. |
Each is described with the two body handles, an anchor on each body, and (for revolute/prismatic) an axis. Spherical, revolute, and prismatic joints can carry limits.
📸 Screenshot - save as img/physics-joints.png
A joint in action in Play mode - e.g. a chain of spherical-jointed bodies swinging, or a revolute-hinged door/lever mid-swing. A mid-motion frame shows the constraint doing work.
Motors and springs
Revolute and prismatic joints can be driven:
JointMotor-{ targetVel?, targetPos?, maxForce? }. Drive the joint's free axis toward a target velocity or a target position within a force budget. A velocity motor spins a wheel; a position motor swings a door to an angle.JointSpring-{ restLength?, stiffness, damping }. A spring pulls the joint back toward a rest length/angle with the given stiffness and damping.
Together these are exactly what vehicles (suspension travel via a prismatic spring, wheel drive via a revolute motor) and doors (a hinge motor) need. The Rapier backend maps them onto configureMotorPosition(target, stiffness, damping) and configureMotorVelocity(target, factor), and exposes a setJointMotor call to retune a live joint.
The backend interface
For reference, joints live on the PhysicsWorld abstraction (see Runtime API):
| Method | Purpose |
|---|---|
addJoint(desc): JointHandle | Create a joint from a JointDesc; a revolute/prismatic motor is applied on creation. |
removeJoint(handle) | Destroy a joint. |
setJointMotor(handle, motor) | Retune the motor of an existing revolute/prismatic joint. |
These are backend-agnostic: the same calls would drive a future Jolt backend unchanged. What's missing is the layer above - a component the runner reads and turns into addJoint calls at Play start. Until that ships, joints can't be authored in a scene.
See also
- Physics Overview - the backend abstraction joints are part of.
- RigidBody - the bodies a joint would connect.
- Runtime API - the
PhysicsWorld/JointDesctypes. - Character Controller - the movement system that is wired today.