Repository navigation
4.0.0
Version 4.0.0 (November 6, 2026)
Important
Read the MuJoCo 4.0 announcement for an overview of everything new since 3.0, the interactive showcase at mujoco.org, MuJoCo Live browser demos, visual showcases, and maintainer Q&A.
Significant new features
89daf8d19Added the speculative enable flag for speculative contacts to prevent fast-moving convex geoms from tunneling through thin obstacles within a single
timestep. On the right, one step of conservative advancement between two rotating boxes. See
model/speculative/ for examples.
-
Added elasto-plasticity, with stateful plastic deformation stored in
mjData.plastic(mjSTATE_PLASTIC):-
e140c026fIdeal elasto-plasticity for joint (springyield) and tendon
(spatial, fixed) springs (left). -
0c0f63b3f,c39fe6f02,e3bd72742,7cb32488bContinuum elasto-plasticity
(yield) for 2D and 3D flexes, with separate stretching and
bending yield strains for 2D shells, volumetric-deviatoric (von Mises$J_2$ ) stretching and 2D shell bending
return mapping (right). -
See model/plastic/ for examples.
-
abaf8d518Split the Python distribution intomujoco-core(minimal bindings and C library depending only
onnumpy),mujoco-studio(Studio and Filament renderer bindings), andmujoco(default package installing
both). When upgrading from a pre-splitmujocoinstallation withpip, uninstall first
(pip uninstall -y mujoco && pip install mujoco) or run
pip install --force-reinstall --no-deps mujoco mujoco-core mujoco-studioafter upgrading sopipdoes not
remove files moved tomujoco-core. To switch an existingmujocoinstallation to core-only, run
pip uninstall -y mujoco mujoco-studio && pip install --force-reinstall --no-deps mujoco-core.
Note
Updated documentation for the split Python packages (mujoco, mujoco-core, mujoco-studio) and prebuilt OpenUSD wheels (mujoco-usd / mujoco[usd]) landed shortly after the 4.0.0 release (39ddbb61a). Please refer to the latest docs for Python bindings and OpenUSD rather than stable or 4.0.0.
Engine
Warning
Breaking changes
a65050166Changed the semantics of sidesite: the tendon now goes around
the geom the same way as the path from the first endpoint, through the side site, to the second endpoint (thin
grey line below). Formally, the tendon is the shortest path homotopic to this polyline in the wrapping plane with
the geom removed.
Previously, a half-plane test was used, which could make the tendon jump onto the geom, a discontinuity in tendon
length, when the segment between the endpoints moved away from the side site while clear of the geom. It could
also select the wrong side for wraps longer than 180 degrees. Top row: old rule; bottom row: new rule.
The new rule has a single discontinuity: when an endpoint crosses the ray opposite the side site, the path
through the side site changes its winding around the geom and the tendon snaps off. This can change the behavior
of existing models.
Migration: Place side sites so that the endpoints do not cross this ray over the range of motion, typically
near the middle of the wrapped arc. For example, the side sites of the
two-link arm were moved from
directly below the joints to 45 degrees below the arm, which reproduces the previous tendon lengths exactly.
-
9a7f240f0TheRK4integrator is now fourth-order accurate for the
orientations of ball and free joints. Previously, the angular velocities of the Runge-Kutta stages were combined
without the Runge-Kutta-Munthe-Kaas correction, so orientations converged only at second order. This changes the
simulation of models with ball or free joints that useRK4. -
9916cc5f7Addedsurfacevel[3]tomjContact, storing the relative
surface velocity (geom[1]minusgeom[0]) in the contact frame
(tangent1, tangent2, spin). Collision detection populates it fromgeom_surfacevelwhen
mjModel.flg_surfacevelis set, and external contact generators can write it directly (setting
flg_surfacevel = 1if no geom specifiessurfacevel). Contact-point visualization now draws a single relative
tangential velocity arrow per active frictional contact. -
629feb74bAddedxiquat,geom_xquat, andsite_xquattomjData, storing the Cartesian
quaternion orientations of body inertias, geoms, and sites alongsideximat,geom_xmat, andsite_xmat. -
64af6504fAddedmjModel.tendon_typewith values from the newmjtTendonenum, distinguishing
fixed and spatial tendons. Previously, the type was implied by whether the first path element was a joint.
Deformables
Warning
Breaking changes
-
1d6cc8ff5Removed thecableplugin (plugin/elasticity) and thecompositeelement, which are
superseded by 1D flexcomp with elasticity.Migration:
-
countandcurve/size/vertex: use flexcompdim="1"with
type="grid",count, andspacing(ortype="circle"for closed loops), ortype="direct"with
point. Add<edge equality="true"/>to keep edges inextensible. -
Geom
size(capsule radius): set flexcompradius. For geomtype="box", set
<elasticity section="box" sectionsize="..."/>. -
Plugin
bendandtwist: set<elasticity young="..." shear="..."/>. -
Root attachment
initial:initial="none"maps to<pin id="0 1"/>(clamps the first edge's material
frame to the parent body and omits<name>_twist_0);initial="ball"maps to<pin id="0"/>(spherical
anchor at the first vertex, keeping<name>_twist_0free);initial="free"maps to no<pin/>. -
Plugin
flat="true": define the rod straight inqpos0(e.g.,type="grid") and set the curved initial
pose viaqposor a keyframe (curves defined directly inpointare at rest inqpos0,
corresponding toflat="false"). -
Plugin
vmaxstress coloring: not supported. -
Integrator: use
integrator="discrete"for implicit integration (orEuler/RK4;implicitand
implicitfastare not supported for 1D rod elasticity). -
Body names
B_first/B_<i>/B_last: unpinned vertices create bodies<name>_<i>(pinned
vertices attach directly to the parent body), plus per-edge twist bodies and joints (see the next entry).
-
-
95cf15e58Open elastic 1D flexcomps with at least two elements now create
per-edge twist bodies with hinge joints<name>_twist_0, ...,<name>_twistunder the world body (omitting
the joint of an edge clamped by pinning both of its points:<name>_twist_0for<pin id="0 1"/>, and
<name>_twistfor the last two points of a rod with at least three elements), and store their time-parallel
reference frames and reference twists inmjData.plastic. This changesnq,nv,nbody,nplastic
and theqposlayout of such models, shifts the indices of bodies and joints declared after the flexcomp, and
changes the simulation: rods now roll on surfaces and twist in grippers. Box sections (sectionbox)
require these joints, so raw flexes with box sections now need them too, and their
collisionradiusis set to the minor half-size of the section (an explicitradiusthat differs from
it is now a compile error).Migration: Update keyframes and any code that indexes
qpos,qvelor bodies by number, preferably
addressing vertex bodies (<name>_<i>) and twist joints by name. Save and restore rod state with
mjSTATE_PLASTIC. Raw box-section flexes need hinge joints named as above (see
elasticity). -
7ba52b533Fixed the elastic constants of non-interpolated flexes (full and
radial dofs), which now match young,
poisson and thickness as documented, and the
interpolated flexes:-
3D Saint Venant-Kirchhoff stretching used twice the first Lamé parameter
$\lambda$ . -
2D stretching used a quarter of the shear modulus
$\mu$ and half of the 3D$\lambda$ , instead of
$\mu$ and the plane-stress$\lambda^* = E \nu / (1 - \nu^2)$ . -
2D bending used
$\tfrac{3}{4}(1-\nu) D$ instead of the plate bending rigidity
$D = E t^3 / (12 (1 - \nu^2))$ .
Models with these flexes become stiffer, except 3D models with zero Poisson's ratio, which are unchanged.
Migration: To keep the previous behavior, use these parameters:
-
3D:
$\nu' = 2\nu / (1 + 2\nu)$ and$E' = E (1 + \nu') / (1 + \nu)$ . -
2D bending only (
elastic2d="bend"):$E' = \tfrac{3}{4}(1 - \nu) E$ . -
2D stretching (
elastic2d="stretch"or"both"):$\nu' = 2\nu$ , which is exact for
$\nu < 1/4$ (so that$\nu' < 1/2$ ). Then:-
"stretch":$E' = E (1 + 2\nu) / (4 (1 + \nu))$ . -
"both":$t' = t \sqrt{3 (1 - 2\nu)}$ and$E' = E t (1 + 2\nu) / (4 (1 + \nu) t')$ .
-
The flex models in
model/flexwere remapped in this way, so their behavior is unchanged. -
-
c0e6b15fd1D rod bending elasticity (dim="1"with positiveyoung) is no
longer supported underimplicitandimplicitfast, matching 2D and 3D flex elasticity.Migration: Use
integrator="discrete"for implicit integration, orintegrator="Euler"with a small
timestep for explicit integration. -
c0e6b15fdFlex edge stiffness and damping are no
longer supported underintegrator="discrete"(where they were integrated explicitly rather than in the
effective metric).Migration: Use elasticity (or edge equality), or use
Euler/RK4/implicitfast. -
b2577a630Unpinned flexcomp models (with full, trilinear, or
quadratic dofs) now fail to compile if their parent or ancestor body has joints
when no active vertices or nodes are pinned to it.Migration: Remove joints from the parent/ancestor body of an unpinned flex, or pin at least one vertex/node to
the parent body with pin. -
145cdc2beRemovedflexvertequality constraints (<equality><flexvert>and
<edge equality="vert"/>in flexcomp), along with the associatedmjModelfields
(nJfv,flex_vertedgeadr,flex_vertedgenum,flex_vertedge,flex_vertmetric,
flexvert_J_rownnz,flexvert_J_rowadr,flexvert_J_colind) andmjDatafields
(flexvert_length,flexvert_J).mjEQ_FLEXVERTis retained as an unsupported placeholder in
mjtEqand causes an error if used.Migration: Use continuum elasticity with
integrator="discrete"or
edge equality for 2D cloth models. -
6f28d4adfFlexes now support per-element visual materials:mjModel.flex_matidis now
(nflexelem x 1)instead of(nflex x 1), and thematerialattribute on flex
and flexcomp (mjsFlex.material) is nowmjStringVecrather thanmjString
(accepting either a single material name broadcast to all elements or one material name per element).Migration: Index
mjModel.flex_matidby elementm->flex_elemadr[f] + erather than by flexf. In C,
setmjsFlex.materialwithmjs_setStringVec(ormjs_appendString) instead ofmjs_setString; in
Python, assign a list of material names (e.g.flex.material = ['mat']). -
7ba5d6732Records of 1D flexes inmjModel.flex_bendinggrow from 4 to 10 values, to store curved
reference configurations and pairs of adjacent bent vertices. Previously, each record was
[v_prev, v, v_next, k].Migration: Read 1D records with stride 10. A record whose fourth value is negative is a single hinge
[v0, v1, v2, -1, k1, k2 - k1, |kb0|, jnt, kt, b]: principal bending stiffnessesk1 <= k2, the twist hinge
jointjntof the edge(v1, v2)(-1 if none; the joint of the first edge, when present, is that of the
first record minus one), torsional stiffnesskt, and the signed minor half-sizebof a box section (0
for circular sections). Otherwise it is a hinge pair[v0, v1, v2, v3, w0, w1, om0[4]].
-
8892bf44b,0d8a109de,f9a589361SparseNewton(solver) is
1.4-3x faster on flex models, using fill-reducing DOF ordering, incremental active-set
Hessian updates, direct elliptic cone folding, and pre-ordered sparse Cholesky for the 2D
discreteintegrator smooth solve. Most flex models inmodel/flexnow use
solver="Newton", and the experimental ipc flag now supportssolver="Newton"in
addition tosolver="CG". -
57d9b960fsolver="Newton"with thediscreteintegrator now supports
flex vertices and nodes (both standard and interpolated) attached to articulated bodies.
Previously, such models requiredsolver="CG". Themodel/flex/gripper_trilinear.xmlgripper now uses
solver="Newton". MuJoCo Warp still requiressolver="CG"for such models. -
7ba5d67321D rod bending elasticity now supports curved reference configurations
and torsional stiffness: vertices bent by more than$10^{-4}$ rad inqpos0keep their reference curvature
and dihedral twist angle, so that rods such as rings, arcs, and coil springs are at rest in their compiled shape.
Previously, such models failed to compile. The new shear attribute optionally
overrides the shear modulus used for torsion. Open rods carry per-edge twist joints (see the breaking change above)
with per-edge polar inertia, frame-indifferent relative Rayleigh torsional damping, time-parallel reference frames,
and frictional contact lever-arm coupling. Box sections additionally use anisotropic principal stiffnesses with
equalized damping ratio ($\sqrt{k_1 k_2}$ on the weak axis) and an oriented box in the DER material frame for
rendering and collision detection. See the documentation. -
9ca6b7171Volumetric interpolated flexes (trilinear or quadratic dofs
withelastic2d="none") now integrate cell stiffness and lump nodal masses over the mesh volume using Finite Cell
Method (FCM) subcell quadrature instead of treating every non-empty grid cell as a full cube. This changes the
stiffness and nodal mass distribution of volumetric interpolated flexes whose mesh does not fill its bounding box,
as well as the nodal mass distribution of multi-cell trilinear flexes. -
f9f3ee653Contacts with flex elements now distribute the contact to the element vertices with the
barycentric coordinates of the point on the element closest to the contact. Previously the vertex weights were
inversely proportional to the distances from the contact, which do not interpolate the contact point: the contact
Jacobian measured the velocity of a different material point, and the contact force exerted a spurious torque on the
element. This changes the simulation of models with flex contacts. -
115907e6dInterpolated flexes (trilinear or quadratic dofs) now support
passive contact. -
51572eab0Flex edge damping is now integrated explicitly underimplicitand
implicitfast(previously it also damped rigid translation). -
9fb4eca48Fixed contact Jacobians of quadratic flexes, which dropped nodes with negative basis weights. -
b16e09838Sphere and capsule contacts with 3D flex elements are now computed analytically instead of the
general convex pipeline. -
3bbf510d4Improved numerical stability of nativeccd convex collision
detection and multiccd contact generation. This can slightly change contacts for models
with convex or mesh collisions.
Compiler
Warning
Breaking changes
-
00057bcefModels that include the same file through different paths, which previously
loaded, are now rejected withalready included.Migration: Remove redundant
<include>elements referencing the same file. -
The compiler now rejects the following invalid models, which previously loaded:
-
b6192732bHeight fields with nrow or
ncol less than 2. -
a4c699040Fixed tendons referencingball/freeor duplicate joints, or
with negative armature. -
a4c699040Spatial tendon pulleys with non-positive
divisor. -
a4c699040camprojection or camera-attached
rangefinder sensors referencing an invalid camera or a camera with non-positive
resolution. -
881e53e2emjs_makeMeshmjMESH_BUILTIN_CONEcalls with fewer than 3 edges orradius
outside[0, 1].
Migration: Ensure height fields have
nrow >= 2andncol >= 2, fixed tendons wrap distinctslide
orhingejoints with non-negative armature, pulley divisors are positive, cameras referenced by
camprojectionorrangefindersensors have positive resolution, skin face indices are in[0, nvert),
and cone meshes have at least 3 edges and a radius in[0, 1]. -
-
432376a59fullinertia and inertias inferred from geoms which are not
positive definite are now bounded by boundinertia when it is positive. Previously they
gave a compile error. -
a4c699040mj_encodenow supports binary MJB output formjSpecvia the
model/vnd.mujoco.mjbcontent type.
Rendering
-
1edd2c67dAdded a castshadow attribute to geom
(mjsGeom.castshadow,mjModel.geom_castshadow,mjvGeom.castshadow; defaulttrue) to disable shadow
casting per geom in both the classic OpenGL and Filament renderers, andmjrf_setRenderableCastShadow
(mjrf.Renderable.set_cast_shadowin Python) to toggle shadow casting of Filament renderables dynamically. -
c831b97d6Added horizon haze and skybox visibility support to Filament rendering: infinite planes are
centered beneath the camera and blend smoothly into the skybox horizon according to
visual/map/haze and visual/rgba/haze, toggled per view viahaze
andskyboxonmjrfRenderRequest(mjRND_HAZE and mjRND_SKYBOX). -
939bc882eWhen no light specifies an intensity, the fallback intensity given
to each light in Filament rendering is now scaled by the brightness of its diffuse color, which is factored out of
the light's color. Lights look the same, but the brightest directional light now casts the shadows, rather than an
arbitrary one that could differ between runs. -
0fc0b44d6Added filament.material.base_color_type flag for configuring how the base color
material parameter is interpreted. -
e19117325Addedmjrf_flush(mjrf.Context.flushin Python) to flush pending operations to the
rendering backend and invoke any completed callbacks. -
93033f5baAdded mjRND_POST_PROCESSING rendering flag. -
e66b53380Allow headlight.active to be set to "false", "true", or "auto"
while continuing to support integer values (0=false, 1=true, 2=auto). Change the default to "auto" instead of
"true".
Python bindings
-
68390c316Removed support for Python 3.10, now that it's
deprecated upstream. -
a1b9fce44Bundled the MuJoCo Sphinx manual (doc/**/*.rst) and agent skills (doc/skills/**/*.md)
inside themujocopackage undermujoco/doc/.
Samples
Warning
Breaking changes
-
006586d30Removedsample/record.cc; multi-frame raw RGB24 video recording is now supported by
sample/render.cc across both the Filament and classic OpenGL backends via--durationand
--fps.Migration: Replace
record model.xml T F out.rgb 0with
render model.xml out.rgb --duration=T --fps=F(or pass-as the output path to pipe top-down RGB24 frames
directly toffmpeg;vflipis no longer needed).
Models
-
9647e0290Added six
elasto-plasticity example models, each
placing an elastic reference next to a plastic counterpart: joint and tendon springs, 2D shells and 3D continua. -
89daf8d19Added
speculative contacts example models: a
Newton's cradle of thin plates, an interlocking chain, and a ball struck by a hinged flipper.
Documentation
-
74ad32d20Added documentation for MuJoCo Studio, covering web
and native viewers, architecture, and
Python and C++ development. -
0f1092ebbAdded a Model tuning guide to the Modeling chapter---covering the
fidelity--speed trade-off, tuning defaults, priority-ordered global
and model-level parameters, deformables, and
system identification---along with module documentation for mujoco.sysid.
Bug fixes
-
fdf141238accelerometer and framelinacc sensors
andmj_objectAccelerationon static and mocap bodies now report the gravitational proper acceleration, like a
dynamic body at rest. Previously they returned zero, a regression introduced in 3.3.7. -
c4137ef7c,aeb871ba1Actuators saturated by joint or tendon actuator force limits
(joint and tendon
actuatorfrcrange) no longer contribute implicit actuator derivatives, changing integration underimplicit,
implicitfast, anddiscrete. Because saturated actuators no longer contribute implicit damping, models with
light links and no armature may need joint armature or a smaller timestep. -
aaf2abaa7,1b46a496eFixed sleep filtering bugs in history sensors
(nsample,delay,interval),mj_energyPos, flex passive forces, tendon limit and
frictionloss constraints, two-tree tendon armature and bias,mj_subtreeVel, and
caller-suppliedmj_rnebuffers. -
13fb7844emj_setConstnow wakes all sleeping trees, since it recomputes their
kinematics atqpos0andqpos_spring. Previously their cached poses could be left atqpos_spring. It also
no longer overwritescam_xpos,cam_xmat,light_xposandlight_xdirinmjData, which left
static cameras and lights with tracking or targeting at their fixed-mode poses. -
432376a59Contact pairs created with an undefinedmjsPair.solrefnow mix thesolrefof their geoms
usingsolmixwhen both are positive, like contacts not defined by pairs. Previously they always took the
element-wise minimum. -
18d65f4e0,ea6aa8214Filament depth and segmentation renders no longer apply post-processing
(tone mapping, dithering), which corrupted depth values and segment ID colors; perspective depth renders now project
with the finite zfar plane instead of Filament's infinite far plane, matching orthographic
depth and the classic renderer; and themjr_compatibility API now respectsreadDepthMap
(mjtDepthMap) onmjrContextinmjr_readPixelsand colors geoms bysegid + 1like
mjRND_IDCOLOR so a geom withsegid0 no longer renders as background. -
9b19fd07c,ef34acbeeFile paths on Windows are now interpreted as UTF-8 rather than the active
ANSI code page, fixing loading and saving files, plugin library discovery and loading (mj_loadPluginLibrary,
mj_loadAllPluginLibraries), and simulate executable directory lookup when paths contain
non-ASCII UTF-8 characters (#3139). Contribution by @mar-yan24. -
a5ff8f6c7Fixed dcmotor parameter handling: allow zero
motorconst forinput="none", reject negative constants (e.g.
motorconst="-a b"is now rejected instead of silently usingK = b), replace capacitance when an inconsistent
thermal triple is given, clear inherited
forcerange when saturation is authored, let
zerosaturationorinductanceclear class defaults, and validate actdim at
compile time. -
8694cc9ceImproved numerical stability of sphere and cylinder spatial tendon
geom wrapping at wrap onset. Thanks to @M-Colley for reporting and analyzing the
issue in MJWarp issue 1772. -
b6192732bmj_raynow scales SDF hit distances by1 / ||vec||for non-unit ray vectors, and
mju_rayTrianglerejects triangle intersections behind the ray origin. -
00c19f04bmj_resetData,mj_copyData, andmj_recompilenow preserve the destination
mjDatathread pool instead of dropping and leaking it. -
a206daa42mju_mat2Rotnow normalizes the input quaternion and escapes 180-degree stationary points
(saddles and minima) that do not maximize$\operatorname{tr}(R^\top M)$ . -
afa16414cFixed the cotangent weight and length scale of the curved reference term of 2D
flex bending (elastic2d bend or both), so
out-of-plane bending forces vanish at curved rest configurations and scale consistently with model size. -
a4c699040Fixed several bugs when editing or copying anmjSpec:-
mjs_delete(MjSpec.deletein Python) now removes deleted default classes from the class lookup map
instead of leaving dangling pointers. -
mj_copyBack(MjSpec.copy_backin Python) preserves materialmetallic,roughness, and
texuniformattributes. -
mjs_findChildno longer matches a non-world body against itself. -
mjs_setToMuscleacceptsNULLtimeconstandrangepointers.
-
-
00057bcefFixed several MJCF XML loading and saving bugs:-
include no longer double-prefixes the model directory on nested or relative paths.
-
Loading MJCF now applies enclosing frame transforms to flexcomp, and allows
explicitrangeor inheritrange attributes on actuator shortcuts to
override conflicting defaults. -
default/tendon now accepts armature,
actuatorfrclimited, and
actuatorfrcrange, which were previously emitted when saving XML and then
failed schema validation on reload. -
Saving MJCF (
mj_saveLastXML,mj_saveXML,mj_saveXMLString) now preserves
texture nchannel and clamps emitted
gridlayout togridsize(while loading resetsgridlayoutwhen an authored
gridsizediffers from the inherited default), compares material layer textures, camera
sensorsize, and light texture against default classes, and
writes all attributes on plugin-backed meshes andreftype/refnameon plugin sensors.
-
-
881e53e2eLegacy.mshmeshes with mirrored scale no longer double-flip face
winding (which inverted faces), and.mshfiles without vertex normals no longer populate empty face normals or
reject custom normals on recompilation.
Update (November 7, 2026, 01:00 PST): The four standalone release archives (mujoco-4.0.0-linux-x86_64.tar.gz, mujoco-4.0.0-linux-aarch64.tar.gz, mujoco-4.0.0-windows-x86_64.zip, and mujoco-4.0.0-macos-universal2.dmg) and their .sha256 checksum files were rebuilt and replaced to remove usd_decoder_plugin from the simulate auto-load plugin directory, fixing a startup crash when Python/OpenUSD runtime libraries are not installed. The 4.0.0 Git tag, PyPI wheels, and npm WASM package are unchanged.

