Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ryanhcode/sable/llms.txt

Use this file to discover all available pages before exploring further.

Sable’s constraint system lets you connect two sub-levels (or a sub-level to the world) with a joint. Constraints are created via PhysicsPipeline.addConstraint() using a typed configuration record and return a handle for later management or removal. Both bodies in a constraint can be independently null, which pins the non-null body to the static world.
PhysicsPipeline pipeline = physicsSystem.getPipeline();
FixedConstraintConfiguration config = new FixedConstraintConfiguration(pos1, pos2, orientation);
FixedConstraintHandle handle = pipeline.addConstraint(sublevelA, sublevelB, config);

PhysicsConstraintConfiguration

public interface PhysicsConstraintConfiguration<T extends PhysicsConstraintHandle> {}
A marker interface for constraint configurations. Each configuration record implements this interface and declares the handle type T it produces. Pass a configuration to PhysicsPipeline.addConstraint() to create the corresponding joint.

PhysicsConstraintHandle

public interface PhysicsConstraintHandle
The base interface returned by addConstraint(). All constraint handle types extend this interface.

getJointImpulses

void getJointImpulses(Vector3d linearImpulseDest, Vector3d angularImpulseDest)
Reads the latest global linear and angular impulses resolved by the constraint solver in the last physics step. Useful for monitoring joint load.
linearImpulseDest
Vector3d
required
Destination for the linear impulse vector.
angularImpulseDest
Vector3d
required
Destination for the angular impulse vector.

setContactsEnabled

void setContactsEnabled(boolean enabled)
Enables or disables collision detection between the two constrained bodies. Disabling contacts lets two sub-levels overlap, which is often desirable for tightly coupled joints.

setMotor

void setMotor(
    ConstraintJointAxis axis,
    double target,
    double stiffness,
    double damping,
    boolean hasMaxForce,
    double maxForce
)
Adds or replaces a PD-controller motor on a specific degree of freedom. The motor drives the joint toward target along axis.
axis
ConstraintJointAxis
required
The degree of freedom on which the motor acts. See ConstraintJointAxis.
target
double
required
Target position along the axis. Units are [m] for linear axes and [rad] for angular axes.
stiffness
double
required
Proportional gain (P) of the PD controller.
damping
double
required
Derivative gain (D) of the PD controller.
hasMaxForce
boolean
required
If true, the motor force is clamped to maxForce.
maxForce
double
required
Maximum force the motor can apply. Ignored when hasMaxForce is false.

remove

void remove()
Removes this constraint from the active physics engine. The handle is invalid after this call — check isValid() before further use.

isValid

boolean isValid()
Returns true if the constraint is still registered with the physics engine and has not been removed.

FixedConstraint

A fixed joint locks all six degrees of freedom, rigidly connecting two bodies. Use this to weld sub-levels together.

FixedConstraintConfiguration

public record FixedConstraintConfiguration(
    Vector3dc pos1,
    Vector3dc pos2,
    Quaterniondc orientation
) implements PhysicsConstraintConfiguration<FixedConstraintHandle>
pos1
Vector3dc
required
A world-space position inside the first sub-level’s plot (e.g. a block center). Used to anchor the joint frame on body A.
pos2
Vector3dc
required
A world-space position inside the second sub-level’s plot. Used to anchor the joint frame on body B.
orientation
Quaterniondc
required
The local orientation of body B’s joint frame relative to body A. Motor axes are expressed in this frame.

FixedConstraintHandle

public interface FixedConstraintHandle extends PhysicsConstraintHandle
Extends PhysicsConstraintHandle with no additional methods. All interaction is through the base handle interface. Example — weld two sub-levels:
FixedConstraintConfiguration config = new FixedConstraintConfiguration(
    new Vector3d(10.5, 64.5, 10.5),   // block center in sublevel A
    new Vector3d(10.5, 66.5, 10.5),   // block center in sublevel B
    new Quaterniond()                  // identity — no relative rotation
);

FixedConstraintHandle weld = pipeline.addConstraint(sublevelA, sublevelB, config);
weld.setContactsEnabled(false); // let the bodies overlap

RotaryConstraint

A rotary joint allows a single angular degree of freedom (rotation around one axis), locking all other motion. Use this for axles, hinges, and motors.

RotaryConstraintConfiguration

public record RotaryConstraintConfiguration(
    Vector3dc pos1,
    Vector3dc pos2,
    Vector3dc normal1,
    Vector3dc normal2
) implements PhysicsConstraintConfiguration<RotaryConstraintHandle>
pos1
Vector3dc
required
World-space anchor position on the first sub-level.
pos2
Vector3dc
required
World-space anchor position on the second sub-level.
normal1
Vector3dc
required
Local rotation axis on the first sub-level.
normal2
Vector3dc
required
Local rotation axis on the second sub-level.

RotaryConstraintHandle

public interface RotaryConstraintHandle extends PhysicsConstraintHandle
Extends PhysicsConstraintHandle with a convenience for servo control.
ConstraintJointAxis DEFAULT_AXIS = ConstraintJointAxis.ANGULAR_X;
The default motor axis for this constraint type.
setServoCoefficients(double angle, double stiffness, double damping) is deprecated and will be removed. Use setMotor(RotaryConstraintHandle.DEFAULT_AXIS, angle, stiffness, damping, false, 0.0) instead.
Example — spinning axle with a motor:
RotaryConstraintConfiguration config = new RotaryConstraintConfiguration(
    new Vector3d(5.5, 64.5, 5.5),
    new Vector3d(5.5, 64.5, 6.5),
    new Vector3d(0, 0, 1),   // Z axis on body A
    new Vector3d(0, 0, 1)    // Z axis on body B
);

RotaryConstraintHandle axle = pipeline.addConstraint(sublevelA, sublevelB, config);

// Spin at a target angle with a stiff spring
axle.setMotor(RotaryConstraintHandle.DEFAULT_AXIS, Math.PI, 200.0, 10.0, true, 500.0);

FreeConstraint

A free joint imposes no hard locks on any degree of freedom. It tracks the relationship between two bodies and lets you attach motors on individual axes without any hard constraints.

FreeConstraintConfiguration

public record FreeConstraintConfiguration(
    Vector3dc pos1,
    Vector3dc pos2,
    Quaterniondc orientation
) implements PhysicsConstraintConfiguration<FreeConstraintHandle>
pos1
Vector3dc
required
World-space anchor position on the first body.
pos2
Vector3dc
required
World-space anchor position on the second body.
orientation
Quaterniondc
required
Local orientation of the second body’s joint frame relative to the first. Motor axes are expressed in this frame.

FreeConstraintHandle

public interface FreeConstraintHandle extends PhysicsConstraintHandle
Extends PhysicsConstraintHandle with no additional methods. Useful for attaching motors to otherwise unconstrained body pairs.

GenericConstraint

Available since Sable 1.1.0.
A generic joint with per-axis hard locks and re-anchorable local frames. It is the most flexible constraint type and can emulate fixed, rotary, prismatic, or free joints by choosing which axes to lock.

GenericConstraintConfiguration

public record GenericConstraintConfiguration(
    Vector3dc pos1,
    Vector3dc pos2,
    Quaterniondc orientation1,
    Quaterniondc orientation2,
    Set<ConstraintJointAxis> lockedAxes
) implements PhysicsConstraintConfiguration<GenericConstraintHandle>
A secondary constructor is also provided for convenience when no axes should be locked (equivalent to a free constraint):
public GenericConstraintConfiguration(
    Vector3dc pos1,
    Vector3dc pos2,
    Quaterniondc orientation1,
    Quaterniondc orientation2
)
pos1
Vector3dc
required
World-space anchor position on the first body.
pos2
Vector3dc
required
World-space anchor position on the second body.
orientation1
Quaterniondc
required
Local orientation of the joint frame on the first body.
orientation2
Quaterniondc
required
Local orientation of the joint frame on the second body.
lockedAxes
Set<ConstraintJointAxis>
The set of degrees of freedom hard-locked by the solver. An empty set is equivalent to a FreeConstraint. Use EnumSet.of(...) for efficient construction.

GenericConstraintHandle

public interface GenericConstraintHandle extends PhysicsConstraintHandle
Extends PhysicsConstraintHandle with methods to re-anchor the joint frames at runtime.

setFrame1

void setFrame1(Vector3dc localPosition, Quaterniondc localRotation)
Updates the joint’s local anchor frame on the first body.
localPosition
Vector3dc
required
New local anchor position on body 1.
localRotation
Quaterniondc
required
New local frame orientation on body 1.

setFrame2

void setFrame2(Vector3dc localPosition, Quaterniondc localRotation)
Updates the joint’s local anchor frame on the second body.
localPosition
Vector3dc
required
New local anchor position on body 2.
localRotation
Quaterniondc
required
New local frame orientation on body 2.
Example — planar constraint (lock Y translation and all rotations):
Set<ConstraintJointAxis> locked = EnumSet.of(
    ConstraintJointAxis.LINEAR_Y,
    ConstraintJointAxis.ANGULAR_X,
    ConstraintJointAxis.ANGULAR_Y,
    ConstraintJointAxis.ANGULAR_Z
);

GenericConstraintConfiguration config = new GenericConstraintConfiguration(
    pos1, pos2, new Quaterniond(), new Quaterniond(), locked
);

GenericConstraintHandle handle = pipeline.addConstraint(sublevelA, sublevelB, config);

ConstraintJointAxis

public enum ConstraintJointAxis {
    LINEAR_X, LINEAR_Y, LINEAR_Z,
    ANGULAR_X, ANGULAR_Y, ANGULAR_Z;

    public static final ConstraintJointAxis[] ALL     = values();
    public static final ConstraintJointAxis[] LINEAR  = { LINEAR_X,  LINEAR_Y,  LINEAR_Z  };
    public static final ConstraintJointAxis[] ANGULAR = { ANGULAR_X, ANGULAR_Y, ANGULAR_Z };
}
Represents one of the six degrees of freedom available for hard locks and motors.
ValueDescription
LINEAR_XTranslation along the X axis
LINEAR_YTranslation along the Y axis
LINEAR_ZTranslation along the Z axis
ANGULAR_XRotation around the X axis (default axis for RotaryConstraint)
ANGULAR_YRotation around the Y axis
ANGULAR_ZRotation around the Z axis
The convenience arrays ALL, LINEAR, and ANGULAR let you lock entire groups at once:
// Lock all translational DOFs (prismatic-like)
for (ConstraintJointAxis axis : ConstraintJointAxis.LINEAR) {
    handle.setMotor(axis, 0.0, 1000.0, 50.0, false, 0.0);
}

Build docs developers (and LLMs) love