mjviser
A web-based MuJoCo viewer built on Viser.
Quick start
Run it directly with uvx (nothing to install):
uvx mjviser path/to/model.xml
Or pip install mjviser and run mjviser path/to/model.xml.
mjviser also does fuzzy path matching against the current directory:
mjviser humanoid # finds **/humanoid*.xml mjviser shadow_hand # finds **/shadow_hand*.xml
Use --port to bind to a specific port (default: 8080):
mjviser model.xml --port 7070
If robot_descriptions is available, you can load any of its 57 MuJoCo models by name:
uvx --with robot_descriptions mjviser go1
[!NOTE]
uvxdefaults to the system Python and may not respectrequires-pythonconstraints (astral-sh/uv#8206). If your system Python is 3.14+, where MuJoCo can't build yet, pass-p 3.13explicitly:uvx -p 3.13 mjviser path/to/model.xml.
Python API
import mujoco from mjviser import Viewer model = mujoco.MjModel.from_xml_path("robot.xml") data = mujoco.MjData(model) Viewer(model, data).run()
Open the printed URL in your browser. You get most of what the native MuJoCo viewer offers: simulation controls, joint and actuator sliders, contact and force visualization, camera tracking, keyframes, and more.
Extension points
Viewer accepts three optional callbacks:
step_fn(model, data): called each simulation step. Defaults tomujoco.mj_step.render_fn(scene): called each render frame. Defaults toscene.update_from_mjdata(data).reset_fn(model, data): called on reset.
For full control, use ViserMujocoScene directly. The server is a standard Viser server, so you can add GUI elements, scene overlays, or anything else Viser supports.
server = viser.ViserServer() scene = ViserMujocoScene(server, model, num_envs=1) scene.create_visualization_gui() with server.gui.add_folder("My Controls"): slider = server.gui.add_slider("Force", min=0, max=100, initial_value=0) while True: mujoco.mj_step(model, data) scene.update_from_mjdata(data)
Examples
active_viewer.py: simplest usage with playback controlsactive_viewer_with_controller.py: customstep_fnwith random torquespassive_viewer.py: manual simulation loop withViserMujocoScenemulti_env.py: 4 humanoids in parallel via mujoco-warpghost_overlay.py: customrender_fnthat overlays a time-delayed ghostmotion_playback.py: recorded trajectory with timeline scrubber, speed control, and contact replay
Acknowledgments
Thanks to Matija Kecman for early feedback and suggestions.
Limitations
- No mouse interaction: clicking/dragging bodies and keyboard callbacks require upstream Viser support.