Releases: mujocolab/mjlab
mjlab v1.3.0
TLDR: A packed release with a viewer rebuilt on mjviser, a preset-based terrain system, simplified actuator configuration, and new MDP primitives like RecorderManager and termination_curriculum.
Physics engine bump
mjlab 1.3.0 uses mujoco-warp 3.7.0.1 and mujoco 3.7.0.
Viewer: Rebuilt on mjviser
The Viser viewer internals have been replaced with the standalone mjviser package. Scene creation, mesh conversion, and overlay rendering (contacts, forces, inertia, tendons, joints, frames) now live in mjviser, while mjlab keeps debug visualization and warp tensor conversion in its MjlabViserScene subclass. The viewer exposes a new Visualization tab for overlay controls and a Groups tab for geom and site visibility.
mjviser_teaser.mp4
New panels and tabs:
- Reward bar panel showing horizontal bars for each reward term with a running mean over ~1 second
- W&B run tab for browsing recent runs and pulling checkpoints
- Checkpoints tab in play for hot-swapping checkpoints without restarting, with support for local directories and W&B runs
- Motion reference scrubber for tracking tasks
- Per-pixel segmentation camera data type for geom ID output alongside RGB and depth, with a new
Mjlab-Multi-Cube-Seg-Yamtask that uses it
Terrain System, Revamped
Terrain configuration moves to a preset-based system with a new @terrain_preset decorator for composing reusable configurations. Curriculum mode now assigns exactly one column per terrain type, with proportion controlling robot spawning distribution rather than column counts. A new STAIRS_TERRAINS_CFG preset provides a progressive stair curriculum out of the box.
mjlab_go1_stair_terrain.mp4
A Go1 velocity policy trained on the new stair terrain
TerrainHeightSensor, a RayCastSensor subclass, computes per-frame vertical clearance above terrain. The velocity task configs now use it for feet_clearance, feet_swing_height, and foot_height, replacing the previous world-Z proxy that was incorrect on rough terrain. A new terrain-aware upright reward penalizes body pitch and roll relative to the local terrain normal.
RayCastSensor itself was generalized: pass a tuple of ObjRef to frame for multi-frame, per-site raycasting, and use the new RingPatternCfg for concentric ring sampling around each frame.
Actuator Configuration, Simplified
Actuator delay is now configured inline on any ActuatorCfg subclass:
# Before
DelayedActuatorCfg(BuiltinPositionActuatorCfg(...), delay_min_lag=2, delay_max_lag=5)
# After
BuiltinPositionActuatorCfg(..., delay_min_lag=2, delay_max_lag=5)DelayedActuator, DelayedActuatorCfg, and DelayedBuiltinActuatorGroup are removed. Delay always applies to the actuator's command_field automatically, so delay_target is no longer needed.
The four XML actuator config classes (XmlPositionActuatorCfg, XmlVelocityActuatorCfg, XmlMotorActuatorCfg, XmlMuscleActuatorCfg) collapse into a single XmlActuatorCfg that auto detects the actuator type from XML. Pass command_field=... to override.
Two new behaviors on ActuatorCfg:
viscous_dampingfor passive velocity proportional damping (f = -b·v), distinct from the PD derivative gaindampingused by position and velocity actuators. Maps to<joint damping>for JOINT transmission and<tendon damping>for TENDON transmission.armatureandfrictionlossnow default toNoneinstead of0.0, preserving the XML values instead of silently overwriting them. Passarmature=0.0orfrictionloss=0.0explicitly to restore the old behavior.
New MDP Primitives
Several additions to the manager and MDP APIs:
RecorderManagerfor logging observations, actions, or arbitrary environment data during rollouts. Implement aRecorderTermsubclass and register it in therecordersdict onManagerBasedRlEnvCfg. The manager providesrecord_pre_reset,record_post_reset, andrecord_post_steplifecycle hooks with no opinion on how data is stored.termination_curriculumfor scheduling changes to termination term parameters during training, matching the existingreward_curriculumpattern. Both now share a single internal engine with init-time validation of stage ordering, field existence, and param keys.MetricsTermCfg.reducefield with a"last"option that reports the final step of the episode rather than the episode mean. Useful for binary success metrics.RelativeJointPositionActionfor joint position control relative to the current configuration. The target iscurrent_pos + action * scale, so a zero action holds the current configuration rather than commanding the default pose.dr.pair_frictionfor randomizing geom-pair friction overrides, with anisotropic=Trueoption that mirrors the symmetric tangent and roll axes so single-axis randomization does not leave the paired axis stale.ActionTermCfg.clipfor clamping processed actions after scale and offset.qfrc_actuatorandqfrc_externalgeneralized force accessors onEntityData.qfrc_actuatorgives actuator forces in joint space (projected through the transmission);qfrc_externalrecovers the generalized force from body external wrenches (xfrc_applied).
Cartpole Tutorial
A new cartpole tutorial walks through building an environment from scratch, using the Mjlab-Cartpole-Balance and Mjlab-Cartpole-Swingup tasks as running examples. It covers scene setup, action and observation terms, rewards, terminations, and training.
Also In This Release
- Mujoco 3.7.0 and mujoco-warp 3.7.0.1 are now the minimum supported versions
- Motion imitation documentation with preprocessing instructions, replacing the BeyondMimic link that produced incompatible NPZ files
margin,gap,solmixfields onCollisionCfgfor per geom contact parameter configurationManagerBasedRlEnvCfg.auto_resetflag for custom training loops that need access to the true terminal state- Top-level
--helpfortrainandplaythat points users atlist-envsand<TASK> --help list_envsrenamed tolist-envsfor consistency with other hyphenated entry points- RNN model support in
RslRlModelCfg - NaN guard now captures mocap body poses, enabling full state reconstruction in the dump viewer for fixed-base entities
- Per-substep metric evaluation via
MetricsTermCfg.per_substepfor metrics evaluated inside the decimation loop dr.pseudo_inertiano longer loads cuSOLVER, eliminating ~4 GB of persistent GPU memory overhead- CUDA graph capture no longer triggers GC, avoiding capture failures on long runs
- Onnxruntime roundtrip tests for ONNX policy export
Breaking Changes
DelayedActuator,DelayedActuatorCfg,DelayedBuiltinActuatorGroupare removed. Configure delay inline on anyActuatorCfgsubclass.delay_targetis removed. Delay always applies to the actuator'scommand_field.XmlPositionActuatorCfg,XmlVelocityActuatorCfg,XmlMotorActuatorCfg,XmlMuscleActuatorCfgare replaced by a singleXmlActuatorCfg.TerrainImporterandTerrainImporterCfgaliases are removed. UseTerrainEntityandTerrainEntityCfg.EntityData.generalized_forceis removed. Useqfrc_actuatororqfrc_external.ActuatorCfg.armatureand.frictionlossdefault toNoneinstead of0.0.Entity.clear_state()is deprecated. UseEntity.reset().out_of_terrain_boundsis replaced withterrain_edge_reached.
Bug Fixes
SceneEntityCfgnames and IDs ordering mismatch withpreserve_order=False(#876)- ONNX export path resolution when a parent directory name contains
"model"(#867) export-scenewriting assets to the wrong location and allowing path traversal in asset keys (#858)electrical_power_costnow uses joint space forces, correct for actuators with non-unit gear ratios (#776)create_velocity_actuatorno longer setsctrllimited=Truewithinheritrange=1.0, which crashed on continuous joints such as wheels (#787)write_root_com_velocity_to_simwith tensorenv_idson floating base entities (#793)dr.pseudo_inertia4 GB GPU memory overhead (#753)- Contact force visualization for non-builtin actuators (#786)
BoxSteppingStonesTerrainCfglarge gap around the platform (#785)TerrainHeightSensorreporting box thickness during penetration andmax_distanceduring ground contact (#835, #841)- Sensor name prefix duplicated on deepcopy (#851)
get_wandb_checkpoint_pathstale cache on repeated calls (#869)- Ghost geom filtering now uses visual alpha instead of collision flags (#888)
- Native viewer syncs
qpos0when domain randomized, fixing incorrect body positions afterdr.joint_default_pos(#760) command_manager.compute()is now called duringreset()so derived command state is populated before the first observation (#761)RayCastSensorframe offset alignment for sites and geoms with a local offset from their parent body (#775)
New Contributors
Thank you to @cjyyx, @omarrayyann, @gokulp01, @cmjang, @jsw7460, and @lzyang2000 for their first contributions to mjlab!
Full Changelog: v1.2.0...v1.3.0
mjlab v1.2.0
Our biggest release yet. 60+ pull requests from 12 contributors. A ground up redesign of domain randomization, major viewer improvements, cloud training support, and many bug fixes.
pip install mjlabdr_hero.mp4
Domain randomization on the yam lift cube task: cube color, cube size, cube mass, link orientations, link inertias, camera FOV, and lighting all randomized per environment on every reset.
Domain Randomization, Redesigned
Domain randomization is a key technique for sim-to-real transfer. The new dr module replaces the previous randomize_field interface with typed, per-field randomization functions. These functions automatically recompute dependent physical quantities when a parameter is modified. For example, if body mass is randomized, the corresponding inertia values are updated to remain physically consistent. Similarly, when geom size parameters change, the broadphase collision bounds are recomputed. This design removes the need for manual set_const calls and reduces the risk of introducing inconsistent physics states.
import mjlab.envs.mdp.dr as dr
dr.geom_friction(env, cfg, operation=dr.scale, distribution=dr.uniform, ranges=(0.8, 1.2))
dr.pseudo_inertia(env, cfg, alpha_range=(-0.3, 0.3), d_range=(-0.3, 0.3))
dr.mat_rgba(env, cfg, operation=dr.add, distribution=dr.gaussian, ranges=(-0.1, 0.1))The full lineup covers geometry, bodies, visuals, cameras, and lights. Custom operations and distributions are first class: define your own and pass them anywhere a string is accepted. The native viewer syncs all randomized fields from the GPU model on every reset, so DR changes are immediately visible.
Viewer Overhaul
viewer.mp4
The viewer timing model was rewritten. A single sim budget accumulator with a wall time deadline keeps physics and rendering in sync at any speed multiplier (1/32x to 8x). When physics cannot keep up, the deadline caps the burst so the renderer always gets a turn.
New in both viewers:
- Single step mode to advance exactly one physics step while paused
- Error recovery that pauses and logs the traceback instead of crashing
- Force arrows that visualize
apply_body_impulseevents in real time - Realtime factor displayed alongside FPS
New in Viser:
- Velocity joystick for manual command override
- Revamped term plotter with per term filtering
- Reorganized controls with a cleaner folder hierarchy
Step Events and Body Impulses
The new "step" event mode fires every environment step, not just on reset. Combine it with apply_body_impulse to throw external forces at your robot during training, with configurable duration, magnitude, and application point.
impulse.mp4
Cloud Training
Train on cloud GPUs with a single command. We added SkyPilot integration for Lambda Cloud with docs covering setup, monitoring, and cost management. W&B sweep scripts distribute one agent per GPU across multi GPU instances.
Documentation
The docs have been completely rewritten with improved guides, API reference, and multi versioned support. Check them out at mujocolab.github.io/mjlab.
Also In This Release
export-sceneCLI to dump any task scene or asset zoo entity to a directory or zip for inspection and debuggingrsl-rl-libupgraded to 5.0.1 with automatic checkpoint migration for the new distribution config format- Contact sensor history across decimation substeps for more reliable self collision and illegal contact detection
- Docker images published on every push to main
joint_torques_l2now acceptsactuator_idsfor penalizing a subset of actuators
Breaking Changes
randomize_fieldis removed. Use typed functions from thedrmodule (e.g.dr.geom_friction,dr.body_mass).EventTermCfgno longer acceptsdomain_randomization.RslRlModelCfgusesdistribution_cfgdict instead ofstochastic/init_noise_std/noise_std_type. Existing checkpoints are migrated automatically on load.
Bug Fixes
- Viewer FPS drops from physics starving the renderer (#694, #705)
height_scanreturning ~0 for missed rays (#646)- Ghost mesh rendering for fixed base entities (#645)
- Actuator target resolution for entities with internal attach prefixes (#714)
- Offscreen rendering artifacts in large vectorized scenes (#682)
- Viser viewer crashing on scenes with no mocap bodies (#662)
- Bundled
ffmpegviaimageio-ffmpeg, no more system install required (#650)
New Contributors
Thank you to @Msornerrrr, @rdeits-bd, @jonzamora, @jgueldenstein, @saikishor, @ax-anoop, @chengruiz, @ManuelActisCassa, and @etaoxing!
Full Changelog: v1.1.1...v1.2.0
mjlab v1.1.1
Minor patch release with bug fixes and small improvements. Highlights include a new differential IK action space, reward visualization in the native viewer, and a switch from moviepy to mediapy for video recording.
What's Changed
- Enable reward plots in the native viewer. by @kevinzakka in #629
- Extend Viser plotting to plot metrics by @saikishor in #625
- Fix viser depth image display for vision example tasks by @pthangeda in #627
- Add differential IK action space. by @kevinzakka in #632
- fix(play): use MjlabOnPolicyRunner as default runner by @griffinaddison in #626
- Remove unsafe body fields from domain randomization by @kevinzakka in #631
- Replace moviepy with mediapy for video recording by @kevinzakka in #637
- Use bleeding edge mujoco and mujoco_warp for dev. by @kevinzakka in #638
New Contributors
- @pthangeda made their first contribution in #627
- @griffinaddison made their first contribution in #626
Full Changelog: v1.1.0...v1.1.1
mjlab v1.1.0
mjlab and all its dependencies (including mujoco-warp) are now available directly from PyPI. Installation no longer requires pinning a specific mujoco-warp revision or custom indices and is now just:
pip install mjlabor try it instantly with:
uvx --from mjlab demoWhat's new
- RGB and depth camera sensors with BVH-accelerated raycasting
- MetricsManager for logging custom metrics during training
- Terrain visualizer and many new terrain types
- Site group visualization in the Viser viewer
- Upgraded rsl-rl-lib to 4.0.0 with native ONNX export
- Various bug fixes
See the full changelog for details.
mjlab v1.0.0
mjlab is now stable. Thank you to everyone who contributed code, reported issues, and provided feedback along the way. This release wouldn't have happened without you.
Some highlights:
- RayCastSensor: Terrain and obstacle detection for navigation tasks
- ContactSensor improvements: History tracking for better contact dynamics
- Muscle actuator support: Biomechanical simulation capabilities
- Sensor caching: Performance optimizations for large-scale training
- Better NaN handling: Easier debugging with detection in observations and sensor data
v1.1 will follow shortly after mjwarp exits beta (imminent), adding RGB-D camera support (experimental #511).
Cheers!
v0.1.0 - Beta Release
mjlab is public and on PyPI! 🎉
We're excited to announce the release of mjlab. It is available here on GitHub and on PyPI.
Quick Demo
See mjlab in action with a pre-trained motion imitation policy on the Unitree G1 humanoid:
uvx --from mjlab --with "mujoco-warp @ git+https://github.com/google-deepmind/mujoco_warp" demoBeta Release
This is an early beta release - we're actively implementing missing features and would love your feedback on what to prioritize! The API may evolve as we incorporate community input, add new features and squash bugs.
Thanks!