Files
Mujoco_WASM/python/mujoco/experimental/studio/viewer_protocol.py
T
Matija Kecman f594778813 Refactor viewer initialization and protocol.
Introduced a ViewerConfig dataclass to encapsulate common viewer window parameters. The NativeViewer now accepts a ViewerConfig and no longer requires a model at initialization. The Viewer protocol has been updated to include a close method (renamed from stop) and an upload_image method. Added checks for None models/data in studio event handling.

PiperOrigin-RevId: 939631378
Change-Id: Ibc07d0e775efa0d79ce5552ee52102e943a9b290
2026-06-28 23:07:02 -07:00

113 lines
2.9 KiB
Python

# Copyright 2026 DeepMind Technologies Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Structural protocol defining the common viewer interface.
ViewerApp uses the protocol for convenience methods that accept any viewer.
"""
import dataclasses
import enum
from typing import Any, Protocol
import mujoco
from mujoco.experimental.studio import ux
import numpy as np
GFX_MODES = (
'classic',
'classic_headless',
'opengl',
'opengl_headless',
'opengl_software',
'vulkan',
'vulkan_software',
'webgl',
)
class ViewerMode(enum.StrEnum):
"""Determines where the viewer is rendered."""
NATIVE = 'native'
WEB = 'web'
# -----------------------------------------------------------------------------
# Viewer configuration.
# -----------------------------------------------------------------------------
@dataclasses.dataclass
class ViewerConfig:
"""Common configuration for creating a viewer window."""
title: str = ''
width: int = 1200
height: int = 800
gfx: str = ''
viewer_mode: ViewerMode = ViewerMode.NATIVE
# Legacy message types kept for backward compatibility.
# Will be removed when callers are migrated.
@dataclasses.dataclass
class SimToView:
"""A message sent from the simulation to the viewer."""
model: mujoco.MjModel | None = None
state: np.ndarray | None = None
state_sig: int = 0
user_data: dict[str, Any] = dataclasses.field(default_factory=dict)
@dataclasses.dataclass
class ViewToSim:
"""A message sent from the viewer to the simulation."""
state: np.ndarray | None = None
state_sig: int = 0
reset: bool = False
send_rate: float = 60.0
user_data: dict[str, Any] = dataclasses.field(default_factory=dict)
# -----------------------------------------------------------------------------
# Structural interface for any viewer.
# -----------------------------------------------------------------------------
class Viewer(Protocol):
"""Structural interface for any viewer."""
camera: mujoco.MjvCamera
perturb: mujoco.MjvPerturb
vis_options: mujoco.MjvOption
render_flags: ux.RenderFlags
def is_running(self) -> bool:
...
def sync(self, model: mujoco.MjModel, data: mujoco.MjData) -> None:
...
def close(self) -> None:
...
def get_drop_file(self) -> str:
...
def upload_image(
self, tex_id: int, img: str | bytes, width: int, height: int, bpp: int
) -> int:
...