MuJoCo bindings and high-level wrappers for the Rust programming language. Includes the viewer.
77
stars
266
commits
Rust
primary language
Sep 6, 2026
updated
[!IMPORTANT] Upgrading from 4.x to 5.0.0? This release updates MuJoCo to 3.9.0. Read the migration guide before upgrading.
MuJoCo bindings and high-level wrappers for the Rust programming language. Includes a Rust-native viewer and also bindings to a modified C++ one.
MuJoCo is a general purpose physics simulator.
More detailed documentation is available at the:
This library uses FFI bindings to MuJoCo 3.9.0.
Rust version 1.88 or newer is required.
For installation, see the guide book.
The guide book also contains information on how to configure MuJoCo. MuJoCo-rs cannot fully configure it itself due to MuJoCo being a shared C library. As a result you may encounter load-time errors about missing libraries.
Information on how to configure MuJoCo and resolve these issues is available here.
MuJoCo-rs tries to stay close to MuJoCo's C API, with a few additional features for ease of use. The main features on top of MuJoCo include:
Safe wrappers around structs:
Methods as function wrappers.
Easy manipulation of simulation data via attribute views.
High-level model editing.
Visualization:
Screenshot of the built-in Rust viewer. Showing a scene from MuJoCo's menagerie.
Requires the viewer feature or the viewer-ui feature for UI support.

Optional Cargo features can be enabled:
viewer: enables the Rust-native MuJoCo viewer.
viewer-ui: enables the (additional) user UI within the viewer.
This also allows users to add custom egui widgets to the viewer.cpp-viewer: enables the Rust wrapper around the C++ MuJoCo viewer.
This requires static linking to a modified fork of MuJoCo, as described in installation.
renderer: enables offscreen rendering for writing RGB and
depth data to memory or file.
renderer-winit-fallback: enables the invisible window fallback (based on winit) when offscreen
rendering fails to initialize. Note that true offscreen rendering is only available on Linux platforms
when the video driver supports it. On Windows and macOS, this feature must always be
enabled when the renderer feature is enabled.auto-download-mujoco: MuJoCo dependency will be automatically downloaded to the specified path.
MUJOCO_DOWNLOAD_DIR must be
set to the absolute path of the download location.cross tool
or manually set MUJOCO_DYNAMIC_LINK_DIR.By default, no optional features are enabled. Enable the features you need explicitly
(e.g. cargo add mujoco-rs --features "viewer-ui renderer-winit-fallback").
On macOS, the visualization features (viewer and renderer) do not work without
patching the glutin dependency. See
installation
for instructions.
This example requires the viewer or the viewer-ui feature
(cargo add mujoco-rs --features viewer).
It launches the viewer and prints the coordinates
of a moving ball to the terminal.
Other examples can be found under the examples/ directory.
//! Example of using views.
//! The example shows how to obtain a [`MjJointDataInfo`] struct that can be used
//! to create a (temporary) [`MjJointDataView`] to corresponding fields in [`MjData`].
use std::time::Duration;
use mujoco_rs::viewer::MjViewer;
use mujoco_rs::prelude::*;
const EXAMPLE_MODEL: &str = "
<mujoco>
<worldbody>
<light ambient=\"0.2 0.2 0.2\"/>
<body name=\"ball\">
<geom name=\"green_sphere\" size=\".1\" rgba=\"0 1 0 1\" solref=\"0.004 1.0\"/>
<joint name=\"ball_joint\" type=\"free\"/>
</body>
<geom name=\"floor1\" type=\"plane\" size=\"10 10 1\" euler=\"15 4 0\" solref=\"0.004 1.0\"/>
<geom name=\"floor2\" type=\"plane\" pos=\"15 -20 0\" size=\"10 10 1\" euler=\"-15 -4 0\" solref=\"0.004 1.0\"/>
</worldbody>
</mujoco>
";
fn main() {
/* Load the model and create data */
let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
let mut data = model.make_data(); // or MjData::new(&model);
/* Launch a passive Rust-native viewer */
let mut viewer = MjViewer::builder()
.max_user_geoms(0)
.vsync(false)
.warn_non_realtime(false)
.build_passive(&model)
.expect("could not launch the viewer");
/* Create the joint info */
let ball_info = data.joint("ball_joint").unwrap();
/* Obtain the timestep through the wrapped mjModel */
let timestep = model.opt().timestep;
while viewer.running() {
/* Step the simulation and sync the viewer */
data.step();
viewer.sync_data(&mut data); // see rust_viewer_threaded.rs for the multi-threaded variant using ViewerSharedState
viewer.render().unwrap();
/* Obtain the view and access first three variables of `qpos` (x, y, z) */
let xyz = &ball_info.view(&data).qpos[..3];
println!("The ball's position is: {xyz:.2?}");
std::thread::sleep(Duration::from_secs_f64(timestep));
}
}
265 commits
1 commits
Rust
99.6%
MuJoCo bindings and high-level wrappers for the Rust programming language. Includes the viewer.
77
stars
266
commits
Rust
primary language
Sep 6, 2026
updated
[!IMPORTANT] Upgrading from 4.x to 5.0.0? This release updates MuJoCo to 3.9.0. Read the migration guide before upgrading.
MuJoCo bindings and high-level wrappers for the Rust programming language. Includes a Rust-native viewer and also bindings to a modified C++ one.
MuJoCo is a general purpose physics simulator.
More detailed documentation is available at the:
This library uses FFI bindings to MuJoCo 3.9.0.
Rust version 1.88 or newer is required.
For installation, see the guide book.
The guide book also contains information on how to configure MuJoCo. MuJoCo-rs cannot fully configure it itself due to MuJoCo being a shared C library. As a result you may encounter load-time errors about missing libraries.
Information on how to configure MuJoCo and resolve these issues is available here.
MuJoCo-rs tries to stay close to MuJoCo's C API, with a few additional features for ease of use. The main features on top of MuJoCo include:
Safe wrappers around structs:
Methods as function wrappers.
Easy manipulation of simulation data via attribute views.
High-level model editing.
Visualization:
Screenshot of the built-in Rust viewer. Showing a scene from MuJoCo's menagerie.
Requires the viewer feature or the viewer-ui feature for UI support.

Optional Cargo features can be enabled:
viewer: enables the Rust-native MuJoCo viewer.
viewer-ui: enables the (additional) user UI within the viewer.
This also allows users to add custom egui widgets to the viewer.cpp-viewer: enables the Rust wrapper around the C++ MuJoCo viewer.
This requires static linking to a modified fork of MuJoCo, as described in installation.
renderer: enables offscreen rendering for writing RGB and
depth data to memory or file.
renderer-winit-fallback: enables the invisible window fallback (based on winit) when offscreen
rendering fails to initialize. Note that true offscreen rendering is only available on Linux platforms
when the video driver supports it. On Windows and macOS, this feature must always be
enabled when the renderer feature is enabled.auto-download-mujoco: MuJoCo dependency will be automatically downloaded to the specified path.
MUJOCO_DOWNLOAD_DIR must be
set to the absolute path of the download location.cross tool
or manually set MUJOCO_DYNAMIC_LINK_DIR.By default, no optional features are enabled. Enable the features you need explicitly
(e.g. cargo add mujoco-rs --features "viewer-ui renderer-winit-fallback").
On macOS, the visualization features (viewer and renderer) do not work without
patching the glutin dependency. See
installation
for instructions.
This example requires the viewer or the viewer-ui feature
(cargo add mujoco-rs --features viewer).
It launches the viewer and prints the coordinates
of a moving ball to the terminal.
Other examples can be found under the examples/ directory.
//! Example of using views.
//! The example shows how to obtain a [`MjJointDataInfo`] struct that can be used
//! to create a (temporary) [`MjJointDataView`] to corresponding fields in [`MjData`].
use std::time::Duration;
use mujoco_rs::viewer::MjViewer;
use mujoco_rs::prelude::*;
const EXAMPLE_MODEL: &str = "
<mujoco>
<worldbody>
<light ambient=\"0.2 0.2 0.2\"/>
<body name=\"ball\">
<geom name=\"green_sphere\" size=\".1\" rgba=\"0 1 0 1\" solref=\"0.004 1.0\"/>
<joint name=\"ball_joint\" type=\"free\"/>
</body>
<geom name=\"floor1\" type=\"plane\" size=\"10 10 1\" euler=\"15 4 0\" solref=\"0.004 1.0\"/>
<geom name=\"floor2\" type=\"plane\" pos=\"15 -20 0\" size=\"10 10 1\" euler=\"-15 -4 0\" solref=\"0.004 1.0\"/>
</worldbody>
</mujoco>
";
fn main() {
/* Load the model and create data */
let model = MjModel::from_xml_string(EXAMPLE_MODEL).expect("could not load the model");
let mut data = model.make_data(); // or MjData::new(&model);
/* Launch a passive Rust-native viewer */
let mut viewer = MjViewer::builder()
.max_user_geoms(0)
.vsync(false)
.warn_non_realtime(false)
.build_passive(&model)
.expect("could not launch the viewer");
/* Create the joint info */
let ball_info = data.joint("ball_joint").unwrap();
/* Obtain the timestep through the wrapped mjModel */
let timestep = model.opt().timestep;
while viewer.running() {
/* Step the simulation and sync the viewer */
data.step();
viewer.sync_data(&mut data); // see rust_viewer_threaded.rs for the multi-threaded variant using ViewerSharedState
viewer.render().unwrap();
/* Obtain the view and access first three variables of `qpos` (x, y, z) */
let xyz = &ball_info.view(&data).qpos[..3];
println!("The ball's position is: {xyz:.2?}");
std::thread::sleep(Duration::from_secs_f64(timestep));
}
}
265 commits
1 commits
Rust
99.6%