Skip to main content

mujoco-gui

Dear ImGui and ImPlot user interfaces across C++ and Python, immediate-mode widget design, layout and multi-row widget/column alignment (Tables API), naming conventions (build_gui vs render), ID stack rules (## label disambiguation vs ### seed reset override), list virtualization (ImGuiListClipper), theming, input capture (WantCaptureKeyboard). Use for building, aligning, styling, and debugging Dear ImGui widgets and ImPlot charts. Do NOT use for Studio app architecture/plugins (mujoco-studio) or physics (mujoco-python).

Informações da origem

Repositório
google-deepmind/mujoco
Última atividade na origem
31 de outubro de 2026 às 13:21
Idioma detectado do SKILL.md
inglês
Estrelas
16.031
Forks
1.912

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
mujoco-gui
description
Dear ImGui and ImPlot user interfaces across C++ and Python, immediate-mode widget design, layout and multi-row widget/column alignment (Tables API), naming conventions (build_gui vs render), ID stack rules (## label disambiguation vs ### seed reset override), list virtualization (ImGuiListClipper), theming, input capture (WantCaptureKeyboard). Use for building, aligning, styling, and debugging Dear ImGui widgets and ImPlot charts. Do NOT use for Studio app architecture/plugins (mujoco-studio) or physics (mujoco-python).
# Dear ImGui Development & Architecture Guide > [!TIP] > > **Official MuJoCo documentation (`doc/*.rst`) & related skills:** > > - [`../../studio/python_plugins.rst`](../../studio/python_plugins.rst) > (`.. _StudioUiPlugins:`, `.. _StudioImGuiTips:`) and > [`../../studio/architecture.rst`](../../studio/architecture.rst) > (`.. _StudioCppComponents:`) — How Dear ImGui and ImPlot integrate into > MuJoCo Studio, `UpdateEvent` vs `BuildGuiEvent`, and C++ (`ux/`) vs Python > widget trade-offs. Read these short `.rst` chapters directly when in a > MuJoCo checkout, or fetch > `https://mujoco.readthedocs.io/en/latest/<path>.html` (or `/en/stable/` > once released; Sphinx anchors lowercase the label, e.g. > `#studioimguitips`). > - [`../../programming/ui.rst`](../../programming/ui.rst) (`.. _UI:`) — > Legacy `mjui` C framework used only in classic `simulate.cc` (distinct > from Studio's Dear ImGui stack). > - [mujoco-studio](../studio/SKILL.md) — Studio viewer launchers, decoupled > sim/viewer threads, plugins, hot reload, and `WebViewer` streaming. > [!NOTE] > > Dear ImGui is an immediate-mode GUI framework designed for fast iterations, > minimal state overhead, and high responsiveness. This guide documents best > practices and conventions for writing maintainable, performant, and > testable UI code across MuJoCo, its Python bindings, and dependent targets > in C++, Python, and WebViewer. > > **Applies to both C++ and Python**: All architectural guidelines, widget > patterns, Tables API usage, ID stack rules (`##` vs `###`), and performance > principles apply equally whether authoring native C++ (`ImGui::`) or Python > (`imgui.`) code. While snippets frequently illustrate patterns in Python for > concise readability, the corresponding immediate-mode concepts, widget APIs, > ID stack mechanics, clipper usage, and styling rules translate directly 1-to-1 > to C++. Guidelines apply both to core Dear ImGui and extension libraries, most > importantly ImPlot. ## 1. Naming Conventions: `build_gui` vs `render` / `draw` ImGui code does not render pixels to the screen directly. Instead, calling ImGui functions builds and records **draw command lists** (vertex buffers, index buffers, clip rects, and texture references) that are processed, rasterized, and rendered later in the frame pipeline (via OpenGL, Vulkan, or WebGL/NetImgui). - **Use `build_gui()` or `build_xxx_gui()`** (in Python) or `BuildGui()` / `BuildXxxGui()` (in C++) for all functions and methods that submit ImGui widgets (e.g., `build_control_panel_gui()`, `BuildControlPanelGui()`). - **Avoid `render()` or `draw()`** for UI layout functions. Reserve `render` / `draw` strictly for low-level graphics backend operations (such as `ImGui_ImplOpenGL3_RenderDrawData`). ```python # Good: Accurately describes building the frame's UI hierarchy def build_gui(self) -> None: self.build_header_gui() self.build_table_gui() # Avoid: Suggests immediate rasterization/rendering def draw_ui(self): ... ``` ## 2. Decoupling GUI from Application Logic GUI code must strictly handle user layout, presentation, and input forwarding. The GUI is intended solely to glue the underlying logic together, and that glue layer should be as small and thin as possible. Never mix business logic, network/RPC queries, file operations, or simulation steps directly into frame build functions. - **Minimal Glue Layer**: The GUI component should do little more than bind user inputs to underlying library calls and render current state. - **Separate Libraries**: Core business logic belongs in a standalone library or module (e.g., `inspector_lib.py` vs `inspector_gui.py`). - **Asynchronous Execution**: Expensive operations (RPCs, subprocesses, large searches) must run on worker threads/tasks, with GUI code reading cached state or progress flags. - **Testability**: Decoupled libraries can be thoroughly tested via standard unit tests without requiring an active ImGui context or window. ## 3. Custom Widgets: Immediate Mode Pure Functions Custom widgets should remain lightweight, immediate-mode pure functions: - **Pure Immediate Mode**: Pass inputs as arguments, return output or mutation tuples (e.g., `changed, new_val = dial_widget(...)`). Avoid heavy stateful framework abstractions. - **Avoid Per-Widget Persistent State**: Storing state across frames inside a widget incurs a maintenance burden and limits reusability across arbitrary contexts. Keep widgets stateless whenever possible; if state is essential, store it in the parent application state rather than inside the widget. - **UX Customizations & Libraries**: Tailored visual controls (e.g., dial knobs, meters) are encouraged when they enhance UX. Instead of importing large external dependencies, copy and refactor small, focused snippets (must be MIT-licensed) into clean immediate-mode functions. In MuJoCo, shared custom ImGui widget functionality lives in the `imgui_widgets.h`/`cc` files in the Studio UX module. - **Test Engine Readiness**: Expose interaction endpoints and bounding boxes using Dear ImGui Test Engine hooks/macros so automated test drivers can interact with custom controls. - **Check Upstream & Changelog Before Implementing**: Before writing a new custom widget, layout behavior, or feature from scratch: - Check the latest upstream changelog for the `docking` branch at https://github.com/ocornut/imgui/blob/docking/docs/CHANGELOG.txt and inspect what has changed relative to the vendored version in MuJoCo. - Search Dear ImGui GitHub issues (https://github.com/ocornut/imgui/issues) and the Wiki (https://github.com/ocornut/imgui/wiki) for existing solutions, standard snippets, or discussions on the topic. - **Check Local vs Upstream (Update Dependency)**: In general, check both the local checked-out code and the latest code on GitHub. If the feature, widget, or bugfix already exists in a newer upstream release, the cleaner solution is often to update the vendored dependency rather than maintaining custom workarounds in application code. ## 4. Disallowing Obsolete Functions & Internal Headers ImGui maintains a stable public API and clearly documents deprecations: - **Ban Obsolete Functions**: Always define `IMGUI_DISABLE_OBSOLETE_FUNCTIONS` (and `IMGUI_DISABLE_OBSOLETE_KEYIO`) during builds and framework updates to prevent deprecated patterns from lingering in the codebase. - **Public API Stability**: Rely on the official public API (`imgui.h`). Avoid including internal headers (`imgui_internal.h`) in application and tool code unless implementing foundational backend extensions. ## 5. Performance & Virtualization: `ImGuiListClipper` When rendering lists, tables, or log views that may contain many items (e.g., 100+ bodies, simulation trajectories, log buffers): - **Always Virtualize with `ImGuiListClipper` / `imgui.ListClipper`**: Without clipping, ImGui generates vertices and text layouts for every item in the list even when offscreen. In remote streaming backends (NetImgui / WebViewer), unclipped tables saturate the WebSocket stream. In C++, use `ImGuiListClipper clipper; clipper.Begin(...)`; in Python, use `clipper = imgui.ListClipper(); clipper.Begin(...)`. - **Clipper Usage**: The clipper calculates the visible range and only submits the items currently in view. ```python if imgui.BeginTable('ItemsTable', 1): clipper = imgui.ListClipper() clipper.Begin(len(items)) while clipper.Step(): for i in range(clipper.DisplayStart, clipper.DisplayEnd): imgui.TableNextRow() imgui.TableNextColumn() imgui.TextUnformatted(items[i].name) imgui.EndTable() ``` - **Memory & Lifetime (`imgui.TextUnformatted`)**: Use `imgui.TextUnformatted` when displaying large or read-only text strings to avoid string copy and formatting overhead in Python bindings. ## 6. Runtime IDs, the ID Stack, and Test Automation (`##` vs `###`) Dear ImGui identifies widgets by hashing their label text against the current ID stack seed (`ImGuiWindow::GetID` calling `ImHashStr` in `imgui.cpp`). Understanding the string operators `##` and `###` is critical for avoiding ID collisions, maintaining state across dynamic label changes, and writing automatable UIs. ### Technical Mechanics: `##` vs `###` Both operators rely on Dear ImGui's internal text-rendering and hashing routines: - **Display Boundary (`FindRenderedTextEnd`)**: Text rendering stops at the first occurrence of `##`. Because `###` also begins with `##`, **any characters following either `##` or `###` are hidden from the user**. - **Hidden Disambiguator (`##`)**: - `ImHashStr` hashes the **entire string** (`"Label##Suffix"`), including both the visible label and the hidden suffix. - **Purpose**: Disambiguating widgets that share the same visible label within the same ID scope (e.g., multiple "Delete" buttons or repeating row entries). - **Why `Selectable(f'{body_name}##body_row_{i}')` uses `##`**: The visible label is `body_name`, but lists may contain duplicate body names or repeating entries. Appending `##body_row_{i}` hashes the full string `"{body_name}##body_row_{i}"`, producing a unique ID while keeping only `body_name` visible on screen. (Alternatively, wrap row rendering in `imgui.PushID(i)` / `imgui.PopID()`). If `###` were used here instead, `body_name` would be discarded completely from the hash. - **ID Override / Seed Reset (`###`)**: - `ImHashStr` specifically detects three `#` characters (`###`). When encountered, it **resets the hash seed** back to the initial seed (`crc = seed`) and hashes **only** the substring following `###`. Any preceding visible text is completely discarded from the hash. - **Dynamic Labels**: When visible text changes across frames (e.g., `f'Items ({count})###ItemCounterBtn'` or animated frame titles), `###` guarantees that the widget's internal ID remains constant. This preserves active focus, hover state, window docking positions, and collapse states. - **Semantically Meaningful Names for Automation**: For icon-only buttons (e.g., `f'{ICON_FA_PLAY}###PlayButton'`, where `ICON_FA_PLAY = '\uf04b'`), the icon glyph itself is constant across frames and would technically produce a stable hash even without `###`. However, without `###PlayButton`, the resulting ID is derived from an opaque unicode codepoint. Using `###PlayButton` assigns a human-readable, semantically meaningful identifier that facilitates agent-driven Dear ImGui Test Engine UI automation and computer control to reliably locate, inspect, and click the control by name (`"PlayButton"`). > [!NOTE] > Dear ImGui Test Engine is not currently bundled with MuJoCo, but support is > planned, along with recorded UI interaction testing. ```python # Icon glyph constant (e.g. FontAwesome play button unicode "\uf04b") ICON_FA_PLAY = '\uf04b' # Semantic ID override: The glyph is displayed, but the ID hashes only # 'PlayButton'. Provides a meaningful identifier for test automation agents and # tooling. imgui.Button(f'{ICON_FA_PLAY}###PlayButton') # Dynamic label with stable ID: Visible text changes with 'count', but the ID # remains hashed from 'ItemCounterBtn', preserving focus, click, and hover # state. imgui.Button(f'Items ({count})###ItemCounterBtn') # Disambiguated duplicate label: Visible text is 'body_name', but the ID hashes # the full string '{body_name}##body_row_{i}' to prevent ID collisions across # rows. imgui.Selectable(f'{body_name}##body_row_{i}', is_selected) # ID Scoping alternative: Using PushID / PopID for row loops instead of ## # suffixes imgui.PushID(i) imgui.Selectable(body_name, is_selected) imgui.PopID() ``` ### Further ImGui & ImPlot References Consult the upstream Dear ImGui and ImPlot sources and guides for authoritative details and patterns: - **Dear ImGui ID Stack & API Guide**: `imgui.h` (around line 600) covers ID stack operations (`PushID`, `PopID`, `GetID`) and widget disambiguation rules. - **Dear ImGui Programmer Guide & String Hashing**: The top of `imgui.cpp` contains the comprehensive Programmer Guide; lines ~2470–2515 contain `ImHashStr` documenting `###` seed resetting. - **Dear ImGui FAQ**: The Dear ImGui [FAQ](https://github.com/ocornut/imgui/blob/master/docs/FAQ.md) includes dedicated sections on *"How can I have multiple widgets with the same label?"* and *"Why is my widget not reacting when I click on it?"*. - **Interactive ImGui Demo Window**: `imgui_demo.cpp` provides complete, working examples of every widget, table feature, and clipper pattern. Call `imgui.ShowDemoWindow()` in your application to explore features interactively. - **ImPlot Header & API Guide**: `implot.h` documents all plotting APIs, flags, styling properties, and context management. - **Interactive ImPlot Demo Window**: `implot_demo.cpp` contains extensive interactive demos for lines, scatter, bars, shaded plots, and realtime scrolling subplots. Call `implot.ShowDemoWindow()` to inspect implementations. ## 7. UI Design & Aesthetics: Grid Alignment (Tables API) & Theming Costs High-quality ImGui tools balance immediate-mode simplicity with clean visual structure and consistent styling: - **Grid-Aligned Widgets & Form Rows (Prefer the Tables API)**: - When arranging widgets into grids, key-value inspector panels, parameter sheets, or multi-row control bars where labels, dropdowns, or sliders must line up vertically and share equal widths, **prefer the modern Tables API** (`imgui.BeginTable`, `TableNextRow`, `TableNextColumn`). - Avoid legacy or brittle alignment techniques such as `imgui.Columns()` (obsolete), chaining `SameLine()` after variable-length text labels (different label widths shift every subsequent control horizontally), hardcoding pixel widths with `SetNextItemWidth(px)`, or inserting dummy spacing. - **Form & Multi-Control Alignment Recipe**: - Pass `int(imgui.TableFlags.SizingStretchProp) | int(imgui.TableFlags.NoPadOuterX)` for borderless layout tables so the outer left and right edges stay flush with surrounding non-table widgets. - Place text labels in `imgui.TableColumnFlags.WidthFixed` columns (omitting an explicit width so ImGui auto-fits to the widest label across all rows) and call `imgui.AlignTextToFramePadding()` before `TextUnformatted(...)` so label baselines center vertically against framed controls (`Combo`, `Slider`, `Input`). - Place controls (`Combo`, `SliderInt`, `SliderFloat`, `InputFloat`) in `imgui.TableColumnFlags.WidthStretch` columns using hidden `##` labels and `imgui.SetNextItemWidth(-1)` so every control in the column starts at the exact same X coordinate and stretches to the exact same length. If sliders also have trailing right-hand labels of different lengths (e.g., `'Quality'` vs `'Overlay'`), place those trailing labels in their own `WidthFixed` column—calling `SetNextItemWidth(-1)` directly on a widget with a visible label sizes the frame box to the full column width and clips the label. - **Costs of Overriding Colors & Styles (Theming Impact)**: - Dear ImGui manages color palettes and visual metrics globally (supporting dark mode, light mode, or custom studio themes). Semantic colors are queried via `ImGui::GetStyleColorVec4(...)` in C++ or `imgui.GetStyleColorVec4(...)` in Python. - When custom widgets hardcode local color or style overrides (via `imgui.PushStyleColor` or `imgui.PushStyleVar`), **those values become decoupled from the global theme defaults**. - If an application or viewer switches themes (such as toggling between dark and light modes) or updates global styling metrics, hardcoded local overrides will not adapt and cannot be edited or updated via global defaults, often causing unreadable contrast or visual inconsistencies.
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub