Repository navigation
Version 3.17.0 (October 22, 2026)
Significant new features
c00ed8153Added a batch API inmujoco/mjbatch.h(in Python as
mujoco.batch): many simulations of one model stepped on a thread pool of its own, each held as its
integration state and loaded into anmjDatafor each call, so memory scales with threads and results are
bit-identical to a plain loop at any thread count. It supports per-simulation model and option fields or models of
the caller's, observations of the state after a step, recorded trajectories, persistent simulations (required for
sleep), and arbitrary per-simulation functions. Follows the design of
mjbatch by @kevinzakka.
Engine
-
Flex improvements:
-
94483e166Added bending elasticity for 1D flexes, using a twist-free isotropic
discrete elastic rod model. The cross-section is selected with the new section
attribute: a circle of the flex radius, or a box with half-sizes sectionsize
that uses the stiffness of its weak axis. It is enabled by a positive young modulus,
requires a straight reference configuration (curved initial poses can be set withqposor keyframes), is
compatible with edge equality constraints, and is integrated implicitly by the discrete
integrator. Previouslyyoungwas ignored for 1D flexes: existing models that set it now bend, and fail to
compile if the cross-section is degenerate (zero radius with the default circle section), if a vertex joins a
zero-length edge, or if the rod is not straight. -
36d0df9a5,897e3fcb1Interpolated flexes (trilinear or quadratic
dofs) now support self-collision, excluding elements in
the same or neighboring cells. -
39dd10f2dThe default arena memory for flex models is now much smaller, sized from
the flex mesh topology instead ofnv^2. If the Newton solver runs out of arena memory it falls back to CG with
a warning.
-
-
mj_setConstnow computes only quantities derived from other fields ofmjModel, while the compiler alone
resolves spec-level conventions:-
55c1b585a,d6d41f324The damping of position actuators from
dampratio, the spring length of tendons from(-1, -1), and model statistics
are now resolved only at compile time, not bymj_setConst. Set the model fields directly when editing a
compiled model (mj_copyBacknow copies tendon spring lengths back to the spec). -
c8362756dConstraint solvers now scale their termination criteria by the trace of the current inertia
matrix (of the model or island) instead ofmjModel.stat.meaninertia. Models solved with PGS, noslip or islands
disabled can stop at slightly different iterations. The meaninertia attribute is
deprecated and now emits a compile warning; remove it to migrate. -
abddec5b9For body-based weld constraints without a specified
relpose, the relative pose inqpos0is now recomputed bymj_setConstwhen
the model is modified after compilation (matching the second body's anchor in
body-basedconnectconstraints). The compiler marks such welds with a nonzeroeq_data[11], and
mjNEQDATA increased from 11 to 12.
-
Warning
Breaking ABI changes
body-based welds that had no relpose at compile time. Zero eq_data[11] before calling mj_setConst
to set the relative pose of such a weld directly.
865316f19AddedMJSETCONST_ARRAYSandMJSETCONST_SCALARSinmjxmacro.h, listing the
mjModelarrays and scalars read and written by each phase ofmj_setConst.
-
e15ecd842Added single-shot multicontact for geoms with positive contact
margins. -
7394a8672mju_boxQPnow updates its Cholesky factor incrementally withmju_cholUpdate, making
cold-started solves 1.4-1.6x faster and warm-started solves 1.9-2.9x faster. -
aa0f88e77Trees marked sleep="init" which cannot be put to sleep now cause a warning
rather than an error, and start awake. See Sleeping for details.
Compiler
Warning
Breaking API changes
-
aad2e2982mjs_fuseStaticandmjs_discardVisualnow return the number of bodies fused or
elements discarded, and -1 on error. Previously they returned 0 on success, so a caller could not tell whether the
spec changed. In Python,MjSpec.fuse_staticandMjSpec.discard_visualreturn the same number instead of
None.Migration: Test for an error with
< 0rather than!= 0. -
084828896mjs_addTexturenow takes a default class, likemjs_addMeshand
mjs_addMaterial.Migration:
mjs_addTexture(spec)→mjs_addTexture(spec, NULL).MjSpec.add_textureis unchanged.
-
3576818f5,b0f206d04Textures can be left by reference instead of being
decoded intomjModel. With compiler/passthrough set to "textures", or
texture/embed set to "false", a single-file texture is not read at compile time; the
model holds its path instead of its pixels, so a scene that attaches many textured sub-models loads in a fraction of
the memory and time. In addition, a compiledmjSpecno longer keeps the decoded pixels of its textures between
compilations.-
3576818f5What the model holds:tex_adris -1,tex_widthandtex_heightare 0,ntexdata
excludes the texture, the resolved path is attex_pathadr, and any authored
content_type is at the newtex_contenttypeadr. Flipped, composite, six-file,
procedural, buffer and in-memory textures stay embedded, as does any texture withembed"true". -
1be762d0cGetting the pixels:mj_loadTexturedecodes a texture of either kind, and
mj_embedAssetsreturns a copy of the model with every by-reference texture loaded (which followed by
mj_saveModelgives a hermetic MJB). Both are in Python asmujoco.mj_loadTextureand
mujoco.mj_embedAssets. -
fd92ba1dbRendering: the built-in and Filament renderers load by-reference textures on demand, and
Filament uploads each file once for all textures that share it. A file that fails to resolve produces a warning and
an untextured material.
-
-
084828896Textures can have default classes:mjsDefaulthas atexture
member and texture takes a class. -
4e9a2de2dAddedmjs_dedupAssets(MjSpec.dedup_assets), which merges the textures and meshes of
anmjSpecthat would compile to the same asset, as those of a sub-model attached several times do: the first
of each group is kept and every reference to the others is rewritten to it. Likemjs_fuseStatic, it returns
the number of assets merged. -
027cb3dd8The asset paths inmjModel(pathsatmesh_pathadr,hfield_pathadr,
skin_pathadrandtex_pathadr) now store the resolved path or URI from which the compiler read the asset
(combining the model file's directory andmeshdirortexturedirwithfile, unlessfileis an
absolute path or URI), somju_openResourcecan open them directly even after attaching
models with different asset directories. Code that prefixed these paths with its own directory should pass them to
mju_openResourceas is. -
9f035384dMesh polygon normals (mjModel.mesh_polynormal) are now computed from the whole polygon
outline using Newell's method rather than the first three vertices (#3691).
Python bindings
-
08330629bAdded a mujoco.batch module over the batch API:Batch(model, nsim)with live
(nsim, ...)arrays frombind()and named views such asjoint(name), per-simulation model fields from
expand(),step,forward,reset,set_constandrolloutwith the GIL released, andjacand
rayqueries. -
1313ef78eAdded support for building the Python bindings with Bazel (initially
covers the core bindings, without rendering or the viewer). -
39b7193e8Fixed several bugs in named access (data.actuator('a'),
model.joint('j'),data.bind(...)), and the corresponding generated accessors in the JavaScript bindings:-
Multi-control or multi-output actuators (such as orientation) now follow
actuator_ctrladrandactuator_outadrwith leading dimensionctrlnumoroutnum, instead of reading
a single row at the actuator index. -
data.actuator('a').momentis now a read-only dense copy of the actuator's moment arm of shape(nv,)or
(outnum, nv), instead of reading the sparseactuator_momentarray as if it were dense. -
Views of multi-column per-dof fields (
cdof,cdof_dot,dof_dampingpoly) on joints after the first now
index the right rows.
-
-
7cdc8857eUnallocated arena arrays ofMjData(such asefm_*when thediscreteintegrator is
not used, or island arrays when no islands are formed) are now filled with zeros, or -1 for index fields, instead of
returning uninitialized memory.
Bug fixes
-
Fixed several bugs in interpolated flexcomp elasticity:
-
4bbc96957Volume (solid) interpolated flexes whose first cell is empty (e.g. a trilinear
flexcomp from a mesh that does not fill the corner of its bounding box) now retain their
elasticity; previously elasticity was gated on the first cell's stiffness. -
b0b20166dEditing a flex to remove a strain equality (e.g. from
body.make_flex) and recompiling now recomputes stiffness instead of keeping the strain constraint eigenmodes. -
08bf94b18Shell-mode interpolated flexes with elastic2d set to
"stretch"or"both"now apply membrane stretch forces and implicit stiffness, and"bend"shells
without strain constraints no longer allocateflex_stiffness.
-
-
Fixed several bugs in the Filament renderer:
-
5c7c1e3aeTextures now allocate mipmap levels (including sRGB textures), fixing minification aliasing. -
e81c8aed4Skins that share vertices across faces no longer fail with an index count mismatch
(#3719). -
001aa3203Material colors now apply only when an object has the default color, instead of overwriting
custom object colors. -
6cfc76e32Textures with an unsupported number of channels are now skipped with a warning, matching the
classic renderer, instead of callingmju_error.
-
-
Fixed several bugs on error paths which called
mju_errorwhile C++ objects or locks were held (an error
handler that does not return, as in the Python bindings and the model compiler, skips C++ destructors):-
4cc38db84,8c1e45559,526583e5bInvalid configurations of the touch grid, cable and
SDF plugins leaked more than 10 MB per failed compilation (they now fail plugin initialization with a warning);
mju_getXMLDependenciesand unknown material layer roles also leaked memory on
invalid XML, and unsupported equality types in the XML writer are now reported as write errors instead of calling
mju_error. -
4cc38db84An error while compiling meshes or textures on the compiler's worker threads crashed the
process, and a failed library load inmj_loadAllPluginLibrariesleft its mutex locked. -
ae15ab978mj_recompilefreed the givenmjDataand calledmju_errorif a plugin
failed to initialize, and did not delete the model and data on some other failures, contrary to its documentation.
-
Models
94483e166The
elastic mechanism example models
now use 1D flex rods: the cantilever comparison of quadratic flexes adds a rod, and the elastic slider-crank and the
tendon-loaded dipper arm are built from rods.