Skip to main content

mujoco-accelerated

MuJoCo GPU and TPU batch simulation with MJX (mujoco.mjx in JAX) and MJWarp (mujoco_warp in CUDA): parallel rollouts (jax.vmap), trajectory scan (jax.lax.scan), differentiability, device memory (put_model, put_data), static contact sizing (max_contact_points, max_geom_pairs, nconmax, njmax), float32 precision, XLA compilation caching. Use only for MuJoCo MJX or MJWarp GPU/TPU batch rollouts, RL environments, and differentiable MuJoCo physics. Don't use for custom non-MuJoCo JAX or CUDA Warp simulations (e.g. custom 2D games, molecular dynamics, orbital mechanics, DEM granular solvers, or shallow-water PDEs that do not import `mujoco.mjx` or `mujoco_warp`), CPU simulation (mujoco-python), cross-engine parity debugging (mujoco-parity), rendering (mujoco-rendering), or GUI (mujoco-gui).

Source facts

Repository
google-deepmind/mujoco
Last source activity
November 7, 2026 at 17:05
Detected SKILL.md language
English
Stars
16,557
Forks
1,959

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
mujoco-accelerated
description
MuJoCo GPU and TPU batch simulation with MJX (mujoco.mjx in JAX) and MJWarp (mujoco_warp in CUDA): parallel rollouts (jax.vmap), trajectory scan (jax.lax.scan), differentiability, device memory (put_model, put_data), static contact sizing (max_contact_points, max_geom_pairs, nconmax, njmax), float32 precision, XLA compilation caching. Use only for MuJoCo MJX or MJWarp GPU/TPU batch rollouts, RL environments, and differentiable MuJoCo physics. Don't use for custom non-MuJoCo JAX or CUDA Warp simulations (e.g. custom 2D games, molecular dynamics, orbital mechanics, DEM granular solvers, or shallow-water PDEs that do not import `mujoco.mjx` or `mujoco_warp`), CPU simulation (mujoco-python), cross-engine parity debugging (mujoco-parity), rendering (mujoco-rendering), or GUI (mujoco-gui).
# MuJoCo Accelerated: MJX & MJWarp GPU Backends > [!TIP] > > **Official MuJoCo documentation (`doc/*.rst`):** Read > [`../../mjx.rst`](../../mjx.rst) (`.. _Mjx:`, `.. _MjxWarp:`, `.. _MjxJAX:`), > [`../../mjx_api.rst`](../../mjx_api.rst), > [`../../mjwarp/index.rst`](../../mjwarp/index.rst) (`.. _MJW:`), and > [`../../mjwarp/api.rst`](../../mjwarp/api.rst) directly when in a MuJoCo > checkout (reserve `.. _Label:` grep for large files like `python.rst`). > Outside a checkout, the same `doc/*.rst` tree ships offline in > `pip install mujoco` at `pathlib.Path(mujoco.__file__).parent / 'doc'`; > otherwise fetch `https://mujoco.readthedocs.io/en/latest/<path>.html` (or > `/en/stable/` for released pages; Sphinx anchors lowercase the label, e.g. > `.. _PyBatch:` → `#pybatch`) and browse repo paths (`../../../`) under > `https://github.com/google-deepmind/mujoco/tree/main/`. > > **Related skills:** > > - [mujoco-python](../python/SKILL.md) — CPU physics simulation, kinematics, > and full solver suite. > - [mujoco-parity](../parity/SKILL.md) — Cross-engine physics parity checks > between CPU MuJoCo and MJWarp/MJX (`forward` isolation, contact matching, > and `float32` baseline rollouts). > - [mujoco-studio](../studio/SKILL.md) — Interactive simulation and Studio > viewer plugins. > [!IMPORTANT] > > MJX and MJWarp are **Python-only** accelerated backends. Standard CPU > simulation runs in full `float64` via `import mujoco`. ## 1. Backend Comparison: C++ vs MJX-JAX vs MJX-Warp vs MJWarp | Feature | C++ Engine (Default) | MJX-JAX (`impl='jax'`) | MJX-Warp (`impl='warp'`) | MJWarp (CUDA) | | :--- | :--- | :--- | :--- | :--- | | **Import** | `import mujoco` (`mujoco.batch`, `mujoco.rollout`) | `from mujoco import mjx` | `from mujoco import mjx` | `import mujoco_warp as mjw` | | **Hardware** | CPU | CPU / GPU / TPU | NVIDIA GPU | NVIDIA GPU | | **Precision** | float64 | float32 | float32 | float32 | | **Differentiable** | ❌ No | ✅ Yes (JAX gradients) | ❌ No | ❌ No | | **Batch Stepping** | ✅ `mujoco.batch.Batch` & `mujoco.rollout` (CPU threads) | ✅ `jax.vmap` | ✅ `jax.vmap` (CUDA kernels) | ✅ Native CUDA batches | | **Solvers** | Newton, CG, PGS, **noslip** | Newton, CG | Newton, CG | Newton, CG | | **Constraint Islands**| ✅ Yes | ❌ No | ✅ Yes | ✅ Yes | | **Plugins** | All engine plugins | ❌ No | SDF plugins only | SDF plugins only | See [mjx.rst](../../mjx.rst) (`.. _MjxWarp:`, `.. _MjxJAX:`, `.. _MjxFeatureParity:`) and [mjwarp/index.rst](../../mjwarp/index.rst) (`.. _mjwDiff:`) for full feature parity and solver/collision details. For multi-threaded CPU batch simulation supporting `float64`, `noslip`/`PGS`, and all engine plugins without JAX or CUDA, use stateful `mujoco.batch.Batch` (for interactive RL stepping, subset resets, and per-sim domain randomization — see [python.rst](../../python.rst), `.. _PyBatch:`) or stateless `mujoco.rollout` (`.. _PyRollout:`, and [programming/simulation.rst](../../programming/simulation.rst), `.. _siBatch:`). ## 2. MJX Workflow (JAX) MJX translates MuJoCo data structures into immutable JAX pytrees that execute natively on GPUs and TPUs. ```python import mujoco from mujoco import mjx # 1. Load CPU model and data model = mujoco.MjModel.from_xml_path('scene.xml') data = mujoco.MjData(model) # 2. Transfer to device (GPU/TPU) mjx_model = mjx.put_model(model) mjx_data = mjx.put_data(model, data) # 3. Step on device (functional paradigm returns new data) mjx_data = mjx.step(mjx_model, mjx_data) # 4. Copy data back to host CPU mjx.get_data_into(data, model, mjx_data) print(data.body('torso').xpos) ``` On NVIDIA GPUs when JAX autodiff is not required, pass `impl='warp'` to `mjx.put_model(model, impl='warp')` and `mjx.make_data(model, impl='warp', naconmax=..., njmax=...)` (`pip install mujoco-mjx[warp]`) to run MJWarp's CUDA contact/constraint kernels inside JAX (`jax.jit` / `jax.vmap`); use `Data.where(...)` for conditional per-world resets and read [mjx.rst](../../mjx.rst) (`.. _MjxWarp:`, `.. _MjxWarpGraphModes:`, `.. _MjxPerformanceWarp:`) for CUDA graph modes and batch rendering. ## 3. High-Throughput Rollouts: jax.vmap and jax.lax.scan ### Parallel Batches (`jax.vmap`) ```python import jax from mujoco import mjx # Vectorize step over batch dimension (model unbatched, data batched) batched_step = jax.vmap(mjx.step, in_axes=(None, 0)) # JIT-compile for maximum device throughput batched_step_jit = jax.jit(batched_step) batch_data = batched_step_jit(mjx_model, batch_data) ``` ### Multi-Step Trajectory Rollouts (`jax.lax.scan`) For RL environment steps, avoid Python loops by scanning across steps: ```python def rollout(model: mjx.Model, init_data: mjx.Data, ctrl_sequence: jax.Array): def step_fn(d, ctrl): d = d.replace(ctrl=ctrl) d = mjx.step(model, d) return d, (d.qpos, d.sensordata) final_data, trajectory = jax.lax.scan(step_fn, init_data, ctrl_sequence) return final_data, trajectory ``` ## 4. Static Contact and Constraint Sizing JAX requires static array shapes, so contact and constraint buffers are sized when the device data is created, not per step. ### MJX (default JAX implementation) The contact buffer is sized **from the model**, not from `data.ncon`: every geom pair that can collide (after `contype`/`conaffinity`, `exclude` and `pair` filtering) gets a fixed number of contact slots, which is why large scenes produce large `efc_*` arrays and slow compilation. `put_data` raises a `ValueError` if the CPU `MjData` already holds more contacts than this capacity. The `njmax` argument of `mjx.put_data` is ignored here. To shrink the buffer, cap it with custom numerics in the MJCF: ```xml <custom> <!-- keep only the N closest geom pairs (bounding spheres) per geom-type pair --> <numeric name="max_geom_pairs" data="16"/> <!-- keep only the N deepest contacts per condim group --> <numeric name="max_contact_points" data="32"/> </custom> ``` Also reduce the number of candidate pairs with `contype`/`conaffinity` and `<exclude>`, and prefer primitive geoms over meshes. ### MJWarp (and `mjx.put_data(..., impl='warp')`) Buffers are sized by explicit arguments; omitted values fall back to defaults derived from the model: - `nconmax`: contacts per world (MJWarp `put_data`/`make_data`). - `naconmax`: contacts across all worlds. - `njmax`: constraint rows (`efc`) **per world**, a hard cap per world. `put_data` raises if the input `MjData` exceeds a capacity. During stepping, excess contacts/constraints are dropped, a warning is printed, and the per-world `d.overflow` bitmask (`mjw.OverflowType`) is set, so size for the peak. ## 5. MJX Named Access & `bind()` MJX provides declarative named access over JAX arrays via `bind()`: ```python spec = mujoco.MjSpec.from_file('model.xml') model = spec.compile() data = mujoco.MjData(model) mx = mjx.put_model(model) dx = mjx.put_data(model, data) # Read body positions from JAX device arrays torso_pos = dx.bind(mx, spec.body('torso')).xpos # Functional update of control inputs dx = dx.bind(mx, spec.actuators).set('ctrl', [1.0, 0.5]) ``` ## 6. MJWarp Guide (NVIDIA CUDA) MJWarp (`mujoco_warp`) provides a CUDA-native simulator optimized for maximum batch throughput on NVIDIA hardware without JAX: ```python import mujoco import mujoco_warp as mjw model = mujoco.MjModel.from_xml_path('scene.xml') data = mujoco.MjData(model) # Transfer to CUDA: one model, nworld copies of the data mjw_model = mjw.put_model(model) mjw_data = mjw.put_data(model, data, nworld=4096, nconmax=64, njmax=256) # or allocate fresh: mjw.make_data(model, nworld=4096, nconmax=64, njmax=256) # Advance all 4096 environments in parallel (in place) mjw.step(mjw_model, mjw_data) # Fields are Warp arrays with a leading world dimension qpos = mjw_data.qpos.numpy() # (4096, nq) # Copy one world back to CPU MjData mjw.get_data_into(data, model, mjw_data, world_id=0) ``` ## 7. Feature Parity, Tuning & Gotchas Instead of relying on static feature snapshots, check the authoritative parity and performance sections in the RST manual when choosing colliders, solvers, or tuning throughput: - **Supported geometries, solvers & differences from CPU MuJoCo**: [mjx.rst](../../mjx.rst) (`.. _MjxFeatureParity:`, `.. _MjxSharpBits:`) and [mjwarp/index.rst](../../mjwarp/index.rst) (`.. _mjwDiff:`, `.. _mjwPairwise:`, `.. _mjwBoxBox:`). Notably, `noslip` and `PGS` solvers are CPU-only, and MJX-JAX solves constraints monolithically without constraint islands. - **Performance tuning, CUDA graphs & domain randomization**: [mjx.rst](../../mjx.rst) (`.. _MjxPerformance:`, `.. _MjxPerformanceJAX:`, `.. _MjxPerformanceWarp:`), [mjwarp/index.rst](../../mjwarp/index.rst) (`.. _mjwPerf:`, `.. _mjwGC:`, `.. _mjwOverflow:`, `.. _mjwBatch:`), and [modeling.rst](../../modeling.rst) (`.. _CTuning:`, `.. _CTuningGlobal:`, `.. _CTuningModel:`) for general timestep, solver/iteration, friction-cone, and primitive-vs-mesh collision trade-offs. ### High-Frequency Gotchas 1. **Float32 precision**: GPU backends run in single precision (`float32`). Stiff systems may experience numerical drift or NaN errors. Counteract this by increasing `model.opt.iterations` or decreasing `model.opt.timestep`. For comparing `float32` GPU physics against CPU MuJoCo, refer to [`mujoco-parity`](../parity/SKILL.md). 2. **Immutability in MJX**: `mjx.Data` is a JAX pytree. In-place assignments fail; use `.replace()`: ```python mjx_data = mjx_data.replace(qpos=new_qpos) ``` 3. **Compilation caching**: Avoid long recompilations on startup by enabling persistent XLA caching: ```python import jax jax.config.update('jax_compilation_cache_dir', '/tmp/jax_cache') ``` ## 8. Key References ### Documentation - [MJX Guide (`MJX-JAX` & `MJX-Warp`)](../../mjx.rst) (`.. _Mjx:`, `.. _MjxWarp:`, `.. _MjxJAX:`, `.. _MjxFeatureParity:`, `.. _MjxPerformance:`, `.. _MjxSharpBits:`) and [MJX API Reference](../../mjx_api.rst) - [MuJoCo Warp (MJWarp) Guide](../../mjwarp/index.rst) (`.. _MJW:`,
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub