Skip to main content

mujoco-studio

Builds and launches interactive MuJoCo Studio viewers and plugins in Python and C++, covering decoupled sim/viewer threads, Snapshot and Event messaging, lifecycle events, WebViewer browser streaming, and Python hot reload. Use when launching Studio viewers (launch_web, launch_native, launch_passive, LaunchStudio), authoring Python ViewerPlugin/SimPlugin or C++ RegisterPlugin (mjPLUGIN_LIB_INIT) extensions, synchronizing sim and viewer state (ViewerHandle.sync, @messages.handler), hot-reloading Python plugins or models (HotReloadEvent), iterating on a live hot-reload Studio session, configuring graphics modes or WebViewer NetImgui/WASM streaming, or debugging Studio and browser console logs. Don't use for Dear ImGui/ImPlot widget layout or styling (use mujoco-gui), core physics stepping (use mujoco-python), or headless offscreen rendering (use mujoco-rendering).

来源信息

仓库
google-deepmind/mujoco
最近来源活动
2026年11月5日 12:37
检测到的 SKILL.md 语言
英语
星标
16,072
Forks
1,925

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
mujoco-studio
description
Builds and launches interactive MuJoCo Studio viewers and plugins in Python and C++, covering decoupled sim/viewer threads, Snapshot and Event messaging, lifecycle events, WebViewer browser streaming, and Python hot reload. Use when launching Studio viewers (launch_web, launch_native, launch_passive, LaunchStudio), authoring Python ViewerPlugin/SimPlugin or C++ RegisterPlugin (mjPLUGIN_LIB_INIT) extensions, synchronizing sim and viewer state (ViewerHandle.sync, @messages.handler), hot-reloading Python plugins or models (HotReloadEvent), iterating on a live hot-reload Studio session, configuring graphics modes or WebViewer NetImgui/WASM streaming, or debugging Studio and browser console logs. Don't use for Dear ImGui/ImPlot widget layout or styling (use mujoco-gui), core physics stepping (use mujoco-python), or headless offscreen rendering (use mujoco-rendering).
# MuJoCo Studio: Interactive Simulation, UI & Plugin Architecture Studio replaces the legacy `simulate` tools with a modular interactive visualization stack built on [Dear ImGui](https://github.com/ocornut/imgui) and ImPlot for UI, Google Filament (PBR with Vulkan, OpenGL, Metal, and WebGL backends) for rendering, and out-of-the-box browser streaming via `WebViewer` (NetImgui WASM). Its default interface, the **Studio Viewer App**, is designed around composable **Studio Plugins** that teams can share across environment authoring (e.g., Gymnasium or robotics suites), asset inspection/loading tools, and agent monitoring/control workflows. > [!TIP] > > **Official MuJoCo documentation (`doc/*.rst`):** Detailed Studio architecture, > lifecycle tables, and C++/web docs live in > [`../../studio/`](../../studio/index.rst)—read these short `.rst` chapters > directly when present locally or in `pip install mujoco` under > `pathlib.Path(mujoco.__file__).parent / 'doc'` (reserve `.. _Label:` grep for > large files like `XMLreference.rst`), or fetch > `https://mujoco.readthedocs.io/en/latest/studio/<page>.html` (or `/en/stable/` > once released; Sphinx anchors lowercase the label, e.g. `#studiodiffsync`). > > **Related skills:** > > - [mujoco-gui](../gui/SKILL.md) — Dear ImGui and ImPlot widget layout, > Tables API alignment, `##` vs `###` IDs, and `ImGuiListClipper`. > - [mujoco-python](../python/SKILL.md) — Core simulation lifecycle > (`MjSpec` -> `MjModel` -> `MjData`), named access, and spatial math. > - [mujoco-spec-editing](../spec_editing/SKILL.md) — Procedural `MjSpec` > modeling, attachments, and runtime recompilation. > - [mujoco-rendering](../rendering/SKILL.md) — Headless offscreen RGB, depth, > and segmentation rendering. ## Official Studio Docs (Load on Demand) Instead of duplicating reference tables here, read the matching `.rst` chapter when your task touches these areas: - **[studio/index.rst](../../studio/index.rst)** (`.. _Studio:`, `.. _StudioQuickStart:`, `.. _StudioComparison:`) — Overview, CLI quick start, and feature comparison across `NativeViewer`, `WebViewer`, C++ Studio, MuJoCo Live, and legacy `simulate` / `mujoco.viewer`. - **[studio/architecture.rst](../../studio/architecture.rst)** (`.. _StudioThreads:`, `.. _StudioCppComponents:`, `.. _StudioMessaging:`, `.. _StudioSnapshotsVsEvents:`) — Sim/viewer thread split in Python & C++, when to implement heavy or WASM-portable widgets in C++ (`ux/`) vs Python (GIL release, MuJoCo Live vs `WebViewer`), and `Snapshot` vs `Event` channel semantics. - **[studio/native_viewers.rst](../../studio/native_viewers.rst)** (`.. _StudioApp:`, `.. _StudioPythonNative:`, `.. _StudioLaunchers:`, `.. _StudioExecutionModes:`, `.. _StudioBackends:`) — Prebuilt standalone desktop application (`MuJoCoStudio.app` on macOS, `bin\mujoco_studio.exe` on Windows, `bin/mujoco_studio` on Linux) vs Python `NativeViewer` (and when shared custom components belong in C++ bound to Python), `launch_native` / `launch_web` / `launch_passive`, blocking `.run(...)` vs non-blocking `.launch(...)`, and `ViewerConfig.gfx` modes (`opengl`, `vulkan`, `opengl_headless`, `opengl_software`, `vulkan_software`, `web`). - **[studio/web_viewers.rst](../../studio/web_viewers.rst)** (`.. _StudioLive:`, `.. _StudioWebViewer:`, `.. _StudioBrowserSandboxing:`) — MuJoCo Live (`?model=github:...`), `WebViewer` `/ui` + `/model` + `/state` + `/drop` streams, Controller vs Spectator roles, COOP/COEP + `localhost`/HTTPS `SharedArrayBuffer` rules (`ssh -L 8080:localhost:8080`), and persistent C++ global/static state across WASM and sequential Python sessions. - **[studio/python_plugins.rst](../../studio/python_plugins.rst)** (`.. _StudioViewerPlugins:`, `.. _StudioSceneOverlays:`, `.. _StudioImGuiTips:`, `.. _StudioSplitPlugins:`, `.. _StudioLifecycle:`, `.. _StudioDiffSync:`, `.. _StudioPriorities:`, `.. _StudioHotReload:`) — Authoring `ViewerPlugin` & `SimPlugin` extensions, `viewer.extra_geoms` (`MjvGeom`) vs `mujoco.mjrf`, full Viewer & Sim lifecycle event tables (including `HotReloadEvent`), `send_if_changes` diff sync, handler priorities, and `--hot_reload`. - **[studio/cpp.rst](../../studio/cpp.rst)** (`.. _StudioCppLauncher:`, `.. _StudioCppPlugins:`, `.. _StudioLiveCpp:`) — C++ `LaunchStudio`, `LauncherConfig`, `GuiPlugin` / `ScenePlugin` / `ModelPlugin` / `KeyHandlerPlugin` / `SpecEditorPlugin` callbacks, `mjPLUGIN_LIB_INIT` vs explicit `RegisterPlugin`, and the Emscripten WASM build. ## 1. Architecture & Threading Model ### Studio vs Legacy `simulate` | Feature | Legacy `simulate` / `mujoco.viewer` | Studio (`mujoco.studio`) | | :--- | :--- | :--- | | **GUI & Plotting** | Fixed `mjui` panels & `mjr_figure` | **Dear ImGui** & **ImPlot** | | **Render Backend** | Classic OpenGL (`mjrContext`) | **Filament** PBR (Vulkan, OpenGL, Metal, WebGL) | | **Web & Remote** | None | **WebViewer** (NetImgui UI + state over HTTP/WS) & **MuJoCo Live** (WASM) | | **Extensibility** | Hardcoded panels and keybinds | **Plugin Architecture** in Python and C++ | | **Threading & Sync** | Shared `model`/`data` with locking | Python & desktop C++: decoupled sim/viewer threads; WASM (`MuJoCo Live`): single-threaded | ### Decoupled Sim & Viewer Threads (Python) `viewer_protocol.py` and `viewer_handle.py` decouple simulation execution from rendering and UI through non-blocking message endpoints: ```text ┌────────────────────────────────────────────────────────┐ │ Simulation Thread (Caller) │ │ - Owns MjModel and MjData │ │ - Runs physics loop, RL policies, or MPC planners │ │ - Executes SimPlugin instances (e.g. StepControl) │ │ - Drives simulation via handle.sync() │ └────────────────────────────────────────────────────────┘ ▲ │ Queued Events & Snapshots │ (SimEndpoint <-> ViewerEndpoint) ▼ ┌────────────────────────────────────────────────────────┐ │ Viewer Thread (or Web Client) │ │ - Owns Window, Renderer, Camera, VisOptions, Perturb │ │ - Owns local copy of MjModel and MjData for rendering │ │ - Executes ViewerPlugin instances (studio_app, UI) │ │ - Dispatches lifecycle events (UpdateEvent, BuildGuiEvent) │ └────────────────────────────────────────────────────────┘ ``` - **Priority-based Plugin System (`plugin.py`, `plugin_registry.py`)**: `plugin_registry.PluginRegistry` discovers `@messages.handler` methods and dispatches messages in priority order. Launchers accept a single `plugins=[...]` list and partition instances by base class: - **`plugin.SimPlugin`**: Runs on the simulation thread, automatically caches `self.handle` on `SimInitEvent`, and handles physics stepping, resets, perturbations, model reloads, and policy updates. - **`plugin.ViewerPlugin`**: Runs on the viewer thread, automatically caches `self.viewer` on `ViewerInitEvent`, and handles visual updates, rendering overlays, and Dear ImGui construction. - **Canonical Samples (`python/mujoco/sample/studio/`)**: - `python/mujoco/studio/viewer.py` — Standard Studio viewer (`studio_app.App`); run with `viewer.py --model=<file> --plugins=a.py,b.py` (instantiates every `ViewerPlugin`/`SimPlugin` defined in those files). - `python/mujoco/sample/studio/ghost.py` — `GhostRenderer` injecting transient `extra_geoms` on `UpdateEvent` and ImGui controls on `BuildGuiEvent` (`viewer.py --model=... --plugins=python/mujoco/sample/studio/ghost.py`). - `python/mujoco/sample/studio/implot.py` — `BodyInspector` demonstrating real-time ImGui + ImPlot charting (`viewer.py --model=... --plugins=python/mujoco/sample/studio/implot.py`). - `python/mujoco/sample/studio/custom_sim_loop.py` — External script owning its stepping and pacing loop via `handle.sync(model, data)`. ## 2. Launching Python Viewers Studio provides three runner modules sharing the same `.run(...)` and `.launch(...)` interfaces: 1. **`launch_web.run`** (`python/mujoco/studio/launch_web.py`) — **Recommended default.** Spawns `WebViewer` in a background daemon thread with **zero host graphics dependencies** (no X11/Wayland display server or host Filament libraries required): physics and headless Dear ImGui layout run on the host while draw commands (NetImgui) and state stream over WebSockets to a browser WASM client. Ideal for remote workstations, containers, and headless servers. 2. **`launch_native.run`** (`python/mujoco/studio/launch_native.py`) — Opens a local desktop window with native Filament graphics (Vulkan or OpenGL). 3. **`launch_passive.run`** (`python/mujoco/studio/launch_passive.py`) — Inspects `config.gfx` and delegates to `launch_web` (`config.gfx in ('web', 'webgl')`) or `launch_native`. Use `launch_web` or `launch_native` directly unless you need runtime switching via `config.gfx`. ### Blocking Runner (`.run`) Accepts either `model_path=...` (loaded on the sim thread by `ViewerHandle` via `LoadModelEvent`, setting `handle.model_path` so **Reload** works) or an in-memory `model=...` (with optional `data=...`, published via `handle.set_model`). `studio_app.SIM_PLUGINS` bundles `step_control.StepControl()` and `sim_history.SimHistory()`: ```python from mujoco.studio import app as studio_app from mujoco.studio import launch_web # Or launch_native / launch_passive from mujoco.studio import viewer_protocol config = viewer_protocol.ViewerConfig(title='Studio') launch_web.run( config, model_path=model_path, # Or model=model, data=data for an in-memory model. plugins=[ studio_app.App(), *studio_app.SIM_PLUGINS, ], ) ``` > [!WARNING] > > **Stepping and pacing are plugin responsibilities.** `studio_app.SIM_PLUGINS` > includes `step_control.StepControl()` (real-time-paced CPU stepping) and > `sim_history.SimHistory()` (history scrubbing). Without `StepControl()` (or > your own `StepEvent` plugin), `handle.sync()` does **not** advance physics or > sleep—a tight `while handle.is_running(): handle.sync(...)` loop will spin at > 100% CPU. When replacing `StepControl()` (e.g., for GPU rollouts, custom RL > loops, or a pure non-physics mesh/asset viewer via a `NullSimulation` plugin > that throttles each iteration without calling `mj_step`), pass individual > plugins and manage pacing explicitly. ### Non-Blocking Launchers (`launch_web.launch`, `launch_native.launch`, `launch_passive.launch`) Use `.launch(...)` only when attaching a viewer to an external loop that you do not want to invert into a `StepEvent` plugin (e.g., an existing RL training loop, trajectory replay script, or test): ```python with launch_web.launch( config, plugins=[ studio_app.App(), *studio_app.SIM_PLUGINS, ], ) as handle: while handle.is_running(): # Mutate model.opt or data in step-event handlers, NOT here (see §5.2). model, data = handle.sync(model, data) ``` To step and pace physics directly in the caller loop instead, omit `StepControl()` and step after `model, data = handle.sync(model, data)` (see `python/mujoco/sample/studio/custom_sim_loop.py`). ## 3. Plugin & Messaging Essentials All cross-thread communication in `messages.py` uses two channel base classes (custom classes end in `*Snapshot` or `*Event` by convention): - **`Snapshot` (Lossy, Latest-Wins)**: Replaces any unread previous value of the same type; use for continuous state or complete control configs where only the latest value matters (e.g., `StateSnapshot`, `StepControlSnapshot`, `MjOptionSnapshot`). - **`Event` (Lossless FIFO Queue)**: Guaranteed in-order, exactly-once delivery; use for discrete actions, reloads, and distinct edits that must not clobber one another (e.g., `ModelEvent`, `StateEvent`, `ResetEvent`,
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看