diff --git a/examples/cloudxr_mujoco_teleop/README.md b/examples/cloudxr_mujoco_teleop/README.md index f384b2362b..abb7bf77aa 100644 --- a/examples/cloudxr_mujoco_teleop/README.md +++ b/examples/cloudxr_mujoco_teleop/README.md @@ -13,8 +13,8 @@ works with any CloudXR / OpenXR-compatible HMD. | Example | What it shows | |---------|---------------| -| `visualize_poses_mujoco_example.py` | HMD + left/right controller as textured mocap bodies. | -| `visualize_hands_mujoco_example.py` | Both hands as 26-joint skeletons (spheres + capsule bones), with the HMD as optional context. | +| `visualize_poses_mujoco_example` | HMD + left/right controller as textured mocap bodies. | +| `visualize_hands_mujoco_example` | Both hands as 26-joint skeletons (spheres + capsule bones), with the HMD as optional context. | ## Prerequisites @@ -24,9 +24,11 @@ Assumes IsaacTeleop is already built and installed in this tree. ```bash curl -LsSf https://astral.sh/uv/install.sh | sh ``` - On first launch, `uv run` fetches this example's Python dependencies - (`mujoco`, `numpy`, `scipy` — see `pyproject.toml`) into an isolated - environment. + Install the example once; this pulls its Python dependencies + (`mujoco`, `numpy`, `scipy` — see `pyproject.toml`): + ```bash + uv pip install -e ./examples/cloudxr_mujoco_teleop + ``` 2. **CloudXR environment loaded**, so OpenXR resolves to the CloudXR runtime. Source the setup script that ships with your CloudXR install: @@ -41,12 +43,12 @@ limit, no recording. ## Examples -### `visualize_poses_mujoco_example.py` +### `visualize_poses_mujoco_example` HMD + left + right controller, each rendered as a textured mesh mocap body. ```bash -uv run visualize_poses_mujoco_example.py +python -m isaacteleop_examples.cloudxr_mujoco_teleop.visualize_poses_mujoco_example ``` | Flag | Default | Description | @@ -55,7 +57,7 @@ uv run visualize_poses_mujoco_example.py | `--pose {grip,aim}` | `grip` | Which controller pose drives the mesh — natural "hold" pose or the aim ray. | | `--debug` | off | Print `mocap_pos` for all three devices once per second. | -### `visualize_hands_mujoco_example.py` +### `visualize_hands_mujoco_example` Both hands as 26-joint skeletons drawn directly into `viewer.user_scn` each frame (left = cyan, right = warm orange) — avoids paying for 52 mocap bodies @@ -63,7 +65,7 @@ in the model. The HMD is shown as context using the same mesh + texture as the poses example. ```bash -uv run visualize_hands_mujoco_example.py +python -m isaacteleop_examples.cloudxr_mujoco_teleop.visualize_hands_mujoco_example ``` | Flag | Default | Description | @@ -92,16 +94,17 @@ HMD will be visible. ``` cloudxr_mujoco_teleop/ ├── README.md -├── pyproject.toml # uv dependency declaration -├── visualize_poses_mujoco_example.py -├── visualize_hands_mujoco_example.py -└── vive_assets/ - ├── generic_hmd.obj # HMD mesh (~500 KB) - ├── generic_hmd_color.png # HMD texture - ├── vive_focus3_controller_left.obj - ├── vive_focus3_controller_left_color.png - ├── vive_focus3_controller_right.obj - └── vive_focus3_controller_right_color.png +├── pyproject.toml # the distribution +└── python/isaacteleop_examples/cloudxr_mujoco_teleop/ + ├── visualize_poses_mujoco_example.py + ├── visualize_hands_mujoco_example.py + └── vive_assets/ + ├── generic_hmd.obj # HMD mesh (~500 KB) + ├── generic_hmd_color.png # HMD texture + ├── vive_focus3_controller_left.obj + ├── vive_focus3_controller_left_color.png + ├── vive_focus3_controller_right.obj + └── vive_focus3_controller_right_color.png ``` The bundled meshes are a generic HMD and the Vive Focus 3 controllers. diff --git a/examples/cloudxr_mujoco_teleop/pyproject.toml b/examples/cloudxr_mujoco_teleop/pyproject.toml index 0333857cca..63ec3e7772 100644 --- a/examples/cloudxr_mujoco_teleop/pyproject.toml +++ b/examples/cloudxr_mujoco_teleop/pyproject.toml @@ -1,8 +1,14 @@ # SPDX-FileCopyrightText: Copyright (c) 2026 HTC CORPORATION & AFFILIATES. All rights reserved. # SPDX-License-Identifier: Apache-2.0 +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + [project] -name = "cloudxr-mujoco-teleop-example" +# The dist name mirrors the import path, so an installed example claims no bare +# top-level name in site-packages. +name = "isaacteleop-examples-cloudxr-mujoco-teleop" version = "0.1.0" description = "Visualize OpenXR / CloudXR headset + controller poses in MuJoCo." requires-python = ">=3.11,<3.14" @@ -12,3 +18,14 @@ dependencies = [ "numpy>=1.22.2", "scipy>=1.10", ] + +# `isaacteleop_examples` is a PEP 420 namespace shared by every example dist and +# must stay without an __init__.py. `only-include` + `sources`, not `packages`: +# the latter keeps only the last path component and would root the wheel at a +# bare top-level `cloudxr_mujoco_teleop/`. +# +# vive_assets/ lives inside the package because both scripts resolve it from +# __file__, so the meshes must travel with the modules. +[tool.hatch.build.targets.wheel] +only-include = ["python/isaacteleop_examples/cloudxr_mujoco_teleop"] +sources = ["python"] diff --git a/examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/__init__.py b/examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/__init__.py new file mode 100644 index 0000000000..f3e5d4b141 --- /dev/null +++ b/examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/__init__.py @@ -0,0 +1,2 @@ +# SPDX-FileCopyrightText: Copyright (c) 2026 HTC CORPORATION & AFFILIATES. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 diff --git a/examples/cloudxr_mujoco_teleop/visualize_hands_mujoco_example.py b/examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/visualize_hands_mujoco_example.py similarity index 100% rename from examples/cloudxr_mujoco_teleop/visualize_hands_mujoco_example.py rename to examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/visualize_hands_mujoco_example.py diff --git a/examples/cloudxr_mujoco_teleop/visualize_poses_mujoco_example.py b/examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/visualize_poses_mujoco_example.py similarity index 100% rename from examples/cloudxr_mujoco_teleop/visualize_poses_mujoco_example.py rename to examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/visualize_poses_mujoco_example.py diff --git a/examples/cloudxr_mujoco_teleop/vive_assets/generic_hmd.obj b/examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/vive_assets/generic_hmd.obj similarity index 100% rename from examples/cloudxr_mujoco_teleop/vive_assets/generic_hmd.obj rename to examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/vive_assets/generic_hmd.obj diff --git a/examples/cloudxr_mujoco_teleop/vive_assets/generic_hmd_color.png b/examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/vive_assets/generic_hmd_color.png similarity index 100% rename from examples/cloudxr_mujoco_teleop/vive_assets/generic_hmd_color.png rename to examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/vive_assets/generic_hmd_color.png diff --git a/examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_left.obj b/examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_left.obj similarity index 100% rename from examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_left.obj rename to examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_left.obj diff --git a/examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_left_color.png b/examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_left_color.png similarity index 100% rename from examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_left_color.png rename to examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_left_color.png diff --git a/examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_right.obj b/examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_right.obj similarity index 100% rename from examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_right.obj rename to examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_right.obj diff --git a/examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_right_color.png b/examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_right_color.png similarity index 100% rename from examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_right_color.png rename to examples/cloudxr_mujoco_teleop/python/isaacteleop_examples/cloudxr_mujoco_teleop/vive_assets/vive_focus3_controller_right_color.png