Understanding Newton Joint Types: D6, Ball, Prismatic, Revolute, Fixed, and Cable

Newton physics engine represents mechanical connections through a dual-layer system where JointType provides the public API catalog (D6, Ball, Prismatic, Revolute, Fixed, Cable) while JointDoFType handles internal solver representation with specific degrees-of-freedom constraints.

The newton-physics/newton repository implements a sophisticated rigid-body simulation framework that categorizes mechanical connections through distinct Newton joint types. Understanding the relationship between the user-facing enumeration and the internal solver representation is essential for correctly configuring robotic mechanisms, character joints, and physics-based animations.

The Two-Layer Architecture: JointType vs. JointDoFType

Newton’s joint system separates public interface from internal implementation through two complementary enumerations defined in separate modules.

JointType: The Public API Surface

The JointType enumeration in newton/_src/sim/enums.py (lines 46-69) serves as the primary contract for users, importers, and external tools such as USD Physics and MuJoCo. It defines the categorical joint types that appear in scene descriptions and configuration files.


# From newton/_src/sim/enums.py

class JointType(enum.IntEnum):
    PRISMATIC = 0   # 1 translational DoF

    REVOLUTE  = 1   # 1 rotational DoF

    BALL      = 2   # 3 rotational DoF (quaternion)

    FIXED     = 3   # 0 DoF – fully locked

    FREE      = 4   # 6 DoF (7 coordinates – 3 pos + 4 quat)

    DISTANCE  = 5   # 6 DoF, distance constraint

    D6        = 6   # Generic 6-DoF joint (any combination)

    CABLE     = 7   # 1 linear stretch + 1 isotropic bend/twist DoF

JointDoFType: The Internal Solver Representation

The JointDoFType enumeration in newton/_src/solvers/kamino/_src/core/joints.py (lines 87-124) encodes the internal representation that couples degrees-of-freedom (DoF), coordinate count, and constraint sets. This abstraction allows the Kamino solver to allocate state vectors and constraint rows efficiently.

Each variant stores:

  • num_coords: Scalar values needed for configuration (e.g., quaternion = 4)
  • num_dofs: Independent velocity components
  • num_cts: Bilateral kinematic constraints imposed

Complete Guide to Newton Joint Types

The following sections detail each joint type’s behavior, coordinate requirements, and constraint structure as implemented in the Newton physics engine.

D6 (Generic 6-DoF)

The D6 joint provides generic 6-DoF configurability, supporting any combination of translational and rotational axes. Internally, the solver maps specific D6 configurations to specialized JointDoFType variants including CARTESIAN, CYLINDRICAL, UNIVERSAL, and GIMBAL based on the enabled axes.

  • Coordinates: Up to 7 (depends on enabled axes)
  • DoFs: Up to 6 (3 translational + 3 rotational)
  • Constraints: 6 - num_enabled_axes (or 0 for free)

Ball (Spherical)

The Ball joint permits three rotational degrees of freedom while locking all translation. It uses a quaternion representation internally to avoid gimbal lock, mapping to the SPHERICAL JointDoFType.

  • Coordinates: 4 (quaternion)
  • DoFs: 3 (rotational)
  • Constraints: 3 (translational constraints)

Prismatic

The Prismatic joint allows motion along a single translational axis, functioning like a piston or linear guide. It constrains all rotation and two translation axes, corresponding to the PRISMATIC JointDoFType.

  • Coordinates: 1 (linear distance)
  • DoFs: 1 (translational)
  • Constraints: 5 (T_y, T_z, R_x, R_y, R_z)

Revolute

The Revolute joint permits rotation around a single axis, acting as a hinge. It constrains all three translations and two rotations, mapping to the REVOLUTE JointDoFType.

  • Coordinates: 1 (angle)
  • DoFs: 1 (rotational)
  • Constraints: 5 (T_x, T_y, T_z, R_y, R_z)

Fixed

The Fixed joint rigidly attaches two bodies, allowing zero relative motion. It applies six bilateral constraints to lock all degrees of freedom, corresponding to the FIXED JointDoFType.

  • Coordinates: 0
  • DoFs: 0
  • Constraints: 6 (fully locked)

Cable

The Cable joint is currently a specialized JointType entry representing flexible connections with 1 linear stretch degree of freedom and 1 isotropic bend/twist degree of freedom. Unlike other joints, it does not yet have a dedicated JointDoFType variant; the engine treats it as a special case in the solver.

  • Coordinates: 2
  • DoFs: 2 (1 translational + 1 rotational)
  • Constraints: 4

Mapping Between Representations

The conversion between public JointType and internal JointDoFType occurs through explicit mapping tables in newton/_src/solvers/kamino/_src/core/joints.py (lines 66-80).

The static method JointDoFType.to_newton() implements this mapping:


# Mapping table from JointDoFType.to_newton (lines 66-80)

_MAP_TO_NEWTON = {
    JointDoFType.FREE:        JointType.FREE,
    JointDoFType.REVOLUTE:    JointType.REVOLUTE,
    JointDoFType.PRISMATIC:   JointType.PRISMATIC,
    JointDoFType.SPHERICAL:   JointType.BALL,
    JointDoFType.FIXED:       JointType.FIXED,
    # D6-family joints map to the generic D6 type

    JointDoFType.CARTESIAN:   JointType.D6,
    JointDoFType.CYLINDRICAL: JointType.D6,
    JointDoFType.UNIVERSAL:   JointType.D6,
    JointDoFType.GIMBAL:      JointType.D6,
}

This explicit dictionary approach makes the system extensible—adding a new joint type requires only adding entries to the enum and updating the mapping table.

Practical Implementation Examples

Creating a Revolute Joint Descriptor

To instantiate a revolute joint in Newton, use the JointDescriptor class from newton.geometry with JointDoFType.REVOLUTE:

from newton.geometry import JointDescriptor, JointActuationType, JointDoFType

# A simple revolute joint that is position-controlled

rev_joint = JointDescriptor(
    name="elbow",
    act_type=JointActuationType.POSITION,
    dof_type=JointDoFType.REVOLUTE,
    bid_B=0,               # base body index

    bid_F=1,               # follower body index

    B_r_Bj=[0.0, 0.0, 0.0],  # joint origin in base frame

    F_r_Fj=[0.0, 0.0, 0.0],  # joint origin in follower frame

    k_p_j=1.0,             # PD proportional gain

    k_d_j=0.1,             # PD derivative gain

)

print(rev_joint)          # human-readable summary

print("Newton JointType →", rev_joint.dof_type.to_newton())

Source: JointDescriptor definition in newton/_src/solvers/kamino/_src/core/joints.py (lines 81-95).

Converting JointType to JointDoFType

When importing scenes from external formats like USD, you may need to convert the generic JointType back to a specific JointDoFType:

from newton._src.sim.enums import JointType
from newton._src.solvers.kamino._src.core.joints import JointDoFType
import numpy as np

# Suppose we read a joint from a USD file – it says type is D6

joint_type = JointType.D6

# Infer the most specific DoF type (requires extra info such as axis count)

# Here we assume a cylindrical joint (1 translational + 1 rotational)

dof_type = JointDoFType.from_newton(
    type=joint_type,
    q_count=2, qd_count=2,
    dof_dim=(1, 1),               # 1 translational, 1 rotational axis

    limit_lower=np.array([-1e3, -np.pi]),
    limit_upper=np.array([1e3, np.pi]),
)

print(dof_type)  # JointDoFType.CYLINDRICAL

Source: JointDoFType.from_newton logic in newton/_src/solvers/kamino/_src/core/joints.py (lines 86-112).

Running the Basic Joints Demo

Newton includes a ready-to-run demonstration that visualizes all supported joint types:

uv run -m newton.examples basic_joints

This command executes the example script at newton/examples/basic/example_basic_joints.py, which constructs a miniature world, adds bodies with each joint type (D6, Ball, Prismatic, Revolute, Fixed, and Cable), and renders a snapshot to docs/images/examples/example_basic_joints.jpg.

Summary

  • Newton joint types are defined by two complementary enumerations: the public JointType in newton/_src/sim/enums.py and the internal JointDoFType in newton/_src/solvers/kamino/_src/core/joints.py.
  • D6 joints provide generic 6-DoF configurability, mapping internally to specialized JointDoFType variants (CARTESIAN, CYLINDRICAL, UNIVERSAL, GIMBAL) based on enabled axes.
  • Ball, Prismatic, Revolute, and Fixed joints correspond directly to SPHERICAL, PRISMATIC, REVOLUTE, and FIXED internal types with specific coordinate counts and constraint structures.
  • Cable joints are currently represented as a specialized JointType with 2 DoFs (stretch and twist) without a dedicated JointDoFType variant.
  • Conversion between representations uses explicit mapping tables in JointDoFType.to_newton() and JointDoFType.from_newton(), making the system extensible through pure Python IntEnum modifications.

Frequently Asked Questions

What is the difference between JointType and JointDoFType in Newton?

JointType is the public-facing enumeration defined in newton/_src/sim/enums.py that serves as the primary contract for users and external tools like USD Physics or MuJoCo importers. JointDoFType is the internal solver representation in newton/_src/solvers/kamino/_src/core/joints.py that encodes mathematical properties including coordinate count, degrees of freedom, and bilateral constraint requirements for the physics solver.

How do I choose between a Ball joint and a D6 joint in Newton?

Choose a Ball joint when you need three rotational degrees of freedom with locked translation, such as for shoulder or hip joints in character animation, as it uses a quaternion representation that avoids gimbal lock. Choose a D6 joint when you need a configurable combination of specific translational and rotational axes, such as for robotic joints requiring prismatic motion along one axis combined with rotation around another, which the solver internally maps to specialized types like CYLINDRICAL or UNIVERSAL.

Where are Newton joint types defined in the source code?

The public JointType enumeration is defined in newton/_src/sim/enums.py (lines 46-69), while the internal JointDoFType enumeration and conversion logic reside in newton/_src/solvers/kamino/_src/core/joints.py (lines 87-124 for DoF definitions, lines 66-80 for the mapping table). The high-level JointDescriptor class used to instantiate joints is also located in the joints.py file (lines 81-95).

Can I create custom joint types in Newton?

Yes, the explicit mapping architecture between JointDoFType and JointType makes the system extensible without hidden magic. To create a custom joint, add a new member to JointDoFType with appropriate num_coords, num_dofs, and num_cts values in newton/_src/solvers/kamino/_src/core/joints.py, add a corresponding entry in the _MAP_TO_NEWTON dictionary (lines 66-80), and optionally expose a new JointType value in newton/_src/sim/enums.py for external API compatibility.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →