mujoco-mojo 2.2.0__tar.gz → 2.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (252) hide show
  1. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/PKG-INFO +1 -1
  2. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/pyproject.toml +8 -8
  3. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/mesh.py +186 -2
  4. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/geom.py +27 -4
  5. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/filters/filters.py +42 -46
  6. mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/routers/mosaic.py +488 -0
  7. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/base.html +201 -10
  8. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/monitor.html +8 -8
  9. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/mosaic.html +3 -3
  10. mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_chart.html +1085 -0
  11. mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_header.html +322 -0
  12. mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_json_editor.html +60 -0
  13. mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_overlays.html +83 -0
  14. mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_series_panel.html +1009 -0
  15. mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/js/__init__.py +0 -0
  16. mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/js/main.js +277 -0
  17. mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/js/monitor.js +212 -0
  18. mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/js/mosaic.js +42 -0
  19. mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/js/toast.js +4 -0
  20. mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/js/trial-viewer.js +1388 -0
  21. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/main.css +22 -0
  22. mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored/__init__.py +0 -0
  23. mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/trial_viewer.html +55 -0
  24. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/proximity_mixin.py +12 -22
  25. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo.egg-info/PKG-INFO +1 -1
  26. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo.egg-info/SOURCES.txt +18 -6
  27. mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/routers/mosaic.py +0 -208
  28. mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/templates/trial_viewer.html +0 -2241
  29. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/LICENSE +0 -0
  30. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/README.md +0 -0
  31. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/setup.cfg +0 -0
  32. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/__about__.py +0 -0
  33. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/__init__.py +0 -0
  34. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/base.py +0 -0
  35. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/meta.py +0 -0
  36. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/__init__.py +0 -0
  37. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/defaults.py +0 -0
  38. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/dependency_path.py +0 -0
  39. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/extension.py +0 -0
  40. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/meta/__init__.py +0 -0
  41. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/meta/frame.py +0 -0
  42. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/meta/include.py +0 -0
  43. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/meta/replicate.py +0 -0
  44. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco.py +0 -0
  45. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/__init__.py +0 -0
  46. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator.py +0 -0
  47. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/__init__.py +0 -0
  48. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/adhesion.py +0 -0
  49. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/base.py +0 -0
  50. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/cylinder.py +0 -0
  51. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/damper.py +0 -0
  52. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/dcmotor.py +0 -0
  53. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/general.py +0 -0
  54. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/intvelocity.py +0 -0
  55. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/motor.py +0 -0
  56. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/muscle.py +0 -0
  57. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/plugin.py +0 -0
  58. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/position.py +0 -0
  59. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/velocity.py +0 -0
  60. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset.py +0 -0
  61. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/__init__.py +0 -0
  62. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/hfield.py +0 -0
  63. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/material.py +0 -0
  64. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/material_attr/__init__.py +0 -0
  65. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/material_attr/layer.py +0 -0
  66. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/model.py +0 -0
  67. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/texture.py +0 -0
  68. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body.py +0 -0
  69. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/__init__.py +0 -0
  70. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/attach.py +0 -0
  71. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/camera.py +0 -0
  72. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite.py +0 -0
  73. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/__init__.py +0 -0
  74. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/geom.py +0 -0
  75. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/joint.py +0 -0
  76. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/site.py +0 -0
  77. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/skin.py +0 -0
  78. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp.py +0 -0
  79. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/__init__.py +0 -0
  80. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/contact.py +0 -0
  81. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/edge.py +0 -0
  82. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/elasticity.py +0 -0
  83. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/pin.py +0 -0
  84. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/free_joint.py +0 -0
  85. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/inertial.py +0 -0
  86. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/joint.py +0 -0
  87. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/light.py +0 -0
  88. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/plugin.py +0 -0
  89. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/site.py +0 -0
  90. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/compiler.py +0 -0
  91. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/compiler_attr/__init__.py +0 -0
  92. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/compiler_attr/lengthrange.py +0 -0
  93. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/contact.py +0 -0
  94. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/contact_attr/__init__.py +0 -0
  95. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/contact_attr/exclude.py +0 -0
  96. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/contact_attr/pair.py +0 -0
  97. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable.py +0 -0
  98. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/__init__.py +0 -0
  99. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex.py +0 -0
  100. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex_attr/__init__.py +0 -0
  101. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex_attr/contact.py +0 -0
  102. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex_attr/edge.py +0 -0
  103. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex_attr/elasticity.py +0 -0
  104. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/skin.py +0 -0
  105. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/skin_attr/__init__.py +0 -0
  106. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/skin_attr/bone.py +0 -0
  107. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality.py +0 -0
  108. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/__init__.py +0 -0
  109. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/connect.py +0 -0
  110. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/equality_base.py +0 -0
  111. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/flex.py +0 -0
  112. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/flexstrain.py +0 -0
  113. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/flexvert.py +0 -0
  114. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/joint.py +0 -0
  115. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/tendon.py +0 -0
  116. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/weld.py +0 -0
  117. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/keyframe.py +0 -0
  118. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/keyframe_attr/__init__.py +0 -0
  119. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/keyframe_attr/key.py +0 -0
  120. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/option.py +0 -0
  121. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/option_attr/__init__.py +0 -0
  122. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/option_attr/flag.py +0 -0
  123. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor.py +0 -0
  124. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/__init__.py +0 -0
  125. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/accelerometer.py +0 -0
  126. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/actuatorfrc.py +0 -0
  127. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/actuatorpos.py +0 -0
  128. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/actuatorvel.py +0 -0
  129. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/ballangvel.py +0 -0
  130. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/ballquat.py +0 -0
  131. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/base.py +0 -0
  132. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/base_collision.py +0 -0
  133. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/camprojection.py +0 -0
  134. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/clock.py +0 -0
  135. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/contact.py +0 -0
  136. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/distance.py +0 -0
  137. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/e_kinetic.py +0 -0
  138. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/e_potential.py +0 -0
  139. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/force.py +0 -0
  140. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/frameangacc.py +0 -0
  141. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/frameangvel.py +0 -0
  142. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framelinacc.py +0 -0
  143. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framelinvel.py +0 -0
  144. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framepos.py +0 -0
  145. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framequat.py +0 -0
  146. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framexaxis.py +0 -0
  147. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/frameyaxis.py +0 -0
  148. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framezaxis.py +0 -0
  149. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/fromto.py +0 -0
  150. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/gyro.py +0 -0
  151. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/insidesite.py +0 -0
  152. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointactuatorfrc.py +0 -0
  153. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointlimitfrc.py +0 -0
  154. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointlimitpos.py +0 -0
  155. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointlimitvel.py +0 -0
  156. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointpos.py +0 -0
  157. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointvel.py +0 -0
  158. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/magnetometer.py +0 -0
  159. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/normal.py +0 -0
  160. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/plugin.py +0 -0
  161. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/rangefinder.py +0 -0
  162. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/subtreeangmom.py +0 -0
  163. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/subtreecom.py +0 -0
  164. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/subtreelinvel.py +0 -0
  165. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tactile.py +0 -0
  166. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonactuatorfrc.py +0 -0
  167. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonlimitfrc.py +0 -0
  168. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonlimitpos.py +0 -0
  169. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonlimitvel.py +0 -0
  170. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonpos.py +0 -0
  171. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonvel.py +0 -0
  172. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/torque.py +0 -0
  173. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/touch.py +0 -0
  174. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/user.py +0 -0
  175. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/velocimeter.py +0 -0
  176. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/size.py +0 -0
  177. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/statistic.py +0 -0
  178. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon.py +0 -0
  179. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/__init__.py +0 -0
  180. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/fixed.py +0 -0
  181. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/fixed_attr/__init__.py +0 -0
  182. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/fixed_attr/joint.py +0 -0
  183. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial.py +0 -0
  184. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial_attr/__init__.py +0 -0
  185. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial_attr/geom.py +0 -0
  186. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial_attr/pulley.py +0 -0
  187. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial_attr/site.py +0 -0
  188. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/tendon_base.py +0 -0
  189. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual.py +0 -0
  190. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/__init__.py +0 -0
  191. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/global_.py +0 -0
  192. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/headlight.py +0 -0
  193. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/map.py +0 -0
  194. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/quality.py +0 -0
  195. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/rgba.py +0 -0
  196. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/scale.py +0 -0
  197. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/orientation.py +0 -0
  198. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/plugin.py +0 -0
  199. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/pose.py +0 -0
  200. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/position.py +0 -0
  201. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/xml_model.py +0 -0
  202. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mojo_model.py +0 -0
  203. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/runtime/__init__.py +0 -0
  204. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/runtime/load.py +0 -0
  205. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/runtime/runtime_manager.py +0 -0
  206. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/runtime/signal_manager.py +0 -0
  207. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/runtime/video_recorder.py +0 -0
  208. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/stochas/__init__.py +0 -0
  209. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/typing.py +0 -0
  210. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/__init__.py +0 -0
  211. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/color.py +0 -0
  212. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/dataframe.py +0 -0
  213. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/defaults.py +0 -0
  214. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/filters/__init__.py +0 -0
  215. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/interp.py +0 -0
  216. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/__init__.py +0 -0
  217. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/cli.py +0 -0
  218. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/__init__.py +0 -0
  219. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/main.py +0 -0
  220. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/routers/__init__.py +0 -0
  221. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/routers/monitor.py +0 -0
  222. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/routers/morph.py +0 -0
  223. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/shared.py +0 -0
  224. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/__init__.py +0 -0
  225. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/error.html +0 -0
  226. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/morph.html +0 -0
  227. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/__init__.py +0 -0
  228. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/chime.mp3 +0 -0
  229. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/dark-logo.svg +0 -0
  230. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/light-logo.svg +0 -0
  231. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/main.js +0 -0
  232. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/monitor.js +0 -0
  233. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/mosaic.js +0 -0
  234. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/trial-viewer.js +0 -0
  235. {mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/templates/static → mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored}/alpine.min.js +0 -0
  236. {mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/templates/static → mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored}/confetti.browser.min.js +0 -0
  237. {mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/templates/static → mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored}/iro.min.js +0 -0
  238. {mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/templates/static → mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored}/lz-string.min.js +0 -0
  239. {mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/templates/static → mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored}/plotly-3.4.0.min.js +0 -0
  240. {mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/templates/static → mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored}/tailwind.min.js +0 -0
  241. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/reloaded.py +0 -0
  242. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/log.py +0 -0
  243. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/proximity.py +0 -0
  244. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/runner.py +0 -0
  245. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/statusing.py +0 -0
  246. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/utils.py +0 -0
  247. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/visualization.py +0 -0
  248. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo.egg-info/dependency_links.txt +0 -0
  249. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo.egg-info/entry_points.txt +0 -0
  250. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo.egg-info/requires.txt +0 -0
  251. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo.egg-info/top_level.txt +0 -0
  252. {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/tests/test_writer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mujoco-mojo
3
- Version: 2.2.0
3
+ Version: 2.2.2
4
4
  Summary: A complete MJCF lifecycle and trial orchestration suite for MuJoCo, powered by Pydantic v2.
5
5
  Author-email: David Gable <dave.a.gable@gmail.com>
6
6
  Maintainer-email: David Gable <dave.a.gable@gmail.com>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "mujoco-mojo"
7
- version = "2.2.0"
7
+ version = "2.2.2"
8
8
  description = "A complete MJCF lifecycle and trial orchestration suite for MuJoCo, powered by Pydantic v2."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -68,11 +68,8 @@ keywords = [
68
68
  "mjcf",
69
69
  ]
70
70
 
71
- [project.scripts]
72
- mujoco-mojo = "mujoco_mojo.utils.layers.cli:cli_app"
73
-
74
- [tool.setuptools.package-data]
75
- "*" = ["*.html", "*.js", "*.mp3", "*.svg", "*.css"]
71
+ [project.optional-dependencies]
72
+ reloaded = ["mjviser>=0.0.11", "viser>=1.0.26"]
76
73
 
77
74
  [dependency-groups]
78
75
  dev = [
@@ -94,8 +91,11 @@ dev = [
94
91
  "zensical>=0.0.31",
95
92
  ]
96
93
 
97
- [project.optional-dependencies]
98
- reloaded = ["mjviser>=0.0.11", "viser>=1.0.26"]
94
+ [project.scripts]
95
+ mujoco-mojo = "mujoco_mojo.utils.layers.cli:cli_app"
96
+
97
+ [tool.setuptools.package-data]
98
+ "*" = ["*.html", "*.js", "*.mp3", "*.svg", "*.css"]
99
99
 
100
100
  [tool.ruff]
101
101
  exclude = ["typings", "scripts/templating/sensor_template.py"]
@@ -1,10 +1,23 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from pathlib import Path
4
- from typing import Annotated, Any, ClassVar, Literal, Self, overload
4
+ from typing import (
5
+ TYPE_CHECKING,
6
+ Annotated,
7
+ Any,
8
+ ClassVar,
9
+ Literal,
10
+ NotRequired,
11
+ Self,
12
+ TypedDict,
13
+ Unpack,
14
+ overload,
15
+ )
5
16
 
6
17
  import mujoco
7
18
  import numpy as np
19
+ import trimesh
20
+ import trimesh.visual
8
21
  from pydantic import Field, field_validator, model_validator
9
22
 
10
23
  from mujoco_mojo.mjcf.dependency_path import DepPath
@@ -12,6 +25,8 @@ from mujoco_mojo.mjcf.xml_model import XMLModel
12
25
  from mujoco_mojo.typing import Inertia, MaterialName, MeshName, Vec3, Vec4
13
26
  from mujoco_mojo.utils.log import get_logger
14
27
 
28
+ if TYPE_CHECKING:
29
+ from trimesh.typed import BooleanEngineType
15
30
  logger = get_logger(__name__)
16
31
 
17
32
  __all__ = [
@@ -29,6 +44,7 @@ _mesh_attr = (
29
44
  "name",
30
45
  "class_",
31
46
  "content_type",
47
+ "scale",
32
48
  "file",
33
49
  "vertex",
34
50
  "normal",
@@ -36,7 +52,6 @@ _mesh_attr = (
36
52
  "face",
37
53
  "refpos",
38
54
  "refquat",
39
- "scale",
40
55
  "smoothnormal",
41
56
  "maxhullvert",
42
57
  "inertia",
@@ -44,6 +59,24 @@ _mesh_attr = (
44
59
  )
45
60
 
46
61
 
62
+ class MeshAttributes(TypedDict):
63
+ name: NotRequired[MeshName | None]
64
+ class_: NotRequired[str | None]
65
+ content_type: NotRequired[str | None]
66
+ file: NotRequired[DepPath | None]
67
+ scale: NotRequired[Vec3]
68
+ inertia: NotRequired[Inertia]
69
+ smoothnormal: NotRequired[bool]
70
+ maxhullvert: NotRequired[int]
71
+ vertex: NotRequired[tuple[tuple[float, float, float], ...] | None]
72
+ normal: NotRequired[tuple[tuple[float, float, float], ...] | None]
73
+ texcoord: NotRequired[tuple[tuple[float, float], ...] | None]
74
+ face: NotRequired[tuple[tuple[int, int, int], ...] | None]
75
+ refpos: NotRequired[Vec3]
76
+ refquat: NotRequired[Vec4]
77
+ material: NotRequired[MaterialName | None]
78
+
79
+
47
80
  class MeshBase(XMLModel):
48
81
  """Base class from which other mesh classes are built from."""
49
82
 
@@ -314,6 +347,157 @@ class Mesh(MeshBase):
314
347
 
315
348
  builtin: Literal["none"] = "none"
316
349
 
350
+ @classmethod
351
+ def new_from_trimesh(
352
+ cls,
353
+ mesh: trimesh.Trimesh | trimesh.Scene,
354
+ **kwargs: Unpack[MeshAttributes],
355
+ ) -> Self:
356
+ """
357
+ Creates a Mesh instance from a trimesh object.
358
+
359
+ Automatically extracts vertices, faces, and (if present) normals/texcoords.
360
+ """
361
+ if isinstance(mesh, trimesh.Scene):
362
+ mesh = mesh.to_mesh()
363
+
364
+ assert isinstance(mesh, trimesh.Trimesh)
365
+ mesh.process(validate=True)
366
+ mesh.fill_holes()
367
+
368
+ # mandatory geometry data
369
+ extracted_data: dict[str, Any] = {
370
+ "vertex": tuple(map(tuple, mesh.vertices.tolist())),
371
+ "face": tuple(map(tuple, mesh.faces.tolist())),
372
+ }
373
+
374
+ # extract normals (if they exist and weren't provided)
375
+ if "normal" not in kwargs:
376
+ # only pull if the count matches
377
+ v_normals = getattr(mesh, "vertex_normals", None)
378
+ if v_normals is not None and len(v_normals) == len(mesh.vertices):
379
+ extracted_data["normal"] = tuple(map(tuple, v_normals.tolist()))
380
+
381
+ # extract texture coordinates (if they exist and weren't provided)
382
+ if "texcoord" not in kwargs:
383
+ if isinstance(mesh.visual, trimesh.visual.TextureVisuals):
384
+ uvs = mesh.visual.uv
385
+ if uvs is not None and len(uvs) == len(mesh.vertices):
386
+ extracted_data["texcoord"] = tuple(map(tuple, uvs.tolist()))
387
+
388
+ # merge kwargs
389
+ final_attrs = {**extracted_data, **kwargs}
390
+
391
+ return cls(**final_attrs)
392
+
393
+ @classmethod
394
+ def new_frustum(
395
+ cls,
396
+ radius_bottom: float,
397
+ radius_top: float,
398
+ height: float,
399
+ sections: int = 32,
400
+ wall_thickness: float = 0.0,
401
+ engine: BooleanEngineType = None,
402
+ base_at_zero: bool = True,
403
+ **kwargs: Unpack[MeshAttributes],
404
+ ) -> Self:
405
+ """
406
+ Generates a conical frustum (tapered cylinder).
407
+
408
+ Args:
409
+ radius_bottom (float): Radius at z = -height/2.
410
+ radius_top (float): Radius at z = +height/2.
411
+ height (float): Total height of the frustum.
412
+ sections (int): Number of radial segments.
413
+ wall_thickness (float): Thickness of the walls (makes a hollow frustum if not equal to zero).
414
+ engine (BooleanEngineType): Which engine to use for boolean subtraction (only used for hollow volumes, reccomended to use "manifold" but requires `manifold3d`).
415
+ base_at_zero (bool): Whether or not to shift the volume so it sits on z=0 instead of underground.
416
+ **kwargs (MeshAttributes): Standard MuJoCo mesh attributes (name, inertia, etc.)
417
+
418
+ Example:
419
+ <img src="https://raw.githubusercontent.com/Hydrowelder/mujoco-mojo/refs/heads/master/docs/assets/mesh/frustums.jpg" width="300" />
420
+
421
+ Two frustums generated using this method. The red frustum has its wall thickness set to 0 and its bottom radius is greater than the top. The cyan frustum has a non-zero wall thickness and a larger top radius than the bottom resulting in a hollow volume. The cyan frustum has more sections than the red.
422
+
423
+ """
424
+ # create the outer mesh
425
+ mesh = trimesh.creation.cylinder(radius=1.0, height=height, sections=sections)
426
+
427
+ def taper_mesh(m: trimesh.Trimesh, r_b: float, r_t: float) -> None:
428
+ verts = m.vertices.copy()
429
+ # Dynamically find the midpoint of the specific mesh's height extent
430
+ z_ext = m.bounds[:, 2]
431
+ z_mid = (z_ext[1] - z_ext[0]) / 4
432
+
433
+ mask_top = verts[:, 2] > z_mid
434
+ mask_bottom = verts[:, 2] < -z_mid
435
+
436
+ verts[mask_top, :2] *= r_t
437
+ verts[mask_bottom, :2] *= r_b
438
+ m.vertices = verts
439
+
440
+ taper_mesh(mesh, radius_bottom, radius_top)
441
+
442
+ if wall_thickness != 0:
443
+ inner = trimesh.creation.cylinder(
444
+ radius=1.0, height=height + 0.02, sections=sections
445
+ )
446
+ taper_mesh(
447
+ inner, radius_bottom - wall_thickness, radius_top - wall_thickness
448
+ )
449
+
450
+ # perform boolean subtraction to make it hollow
451
+ # Note: This requires the 'manifold' or 'blender' engine installed for trimesh,
452
+ # otherwise it falls back to a simpler but less robust internal boolean.
453
+ mesh = mesh.difference(inner, engine=engine)
454
+
455
+ if base_at_zero:
456
+ mesh.apply_translation([0, 0, height / 2])
457
+ return cls.new_from_trimesh(mesh, **kwargs)
458
+
459
+ @classmethod
460
+ def new_hollow_box(
461
+ cls,
462
+ width: float,
463
+ depth: float,
464
+ height: float,
465
+ wall_thickness: float = 0.02,
466
+ engine: BooleanEngineType = None,
467
+ base_at_zero: bool = True,
468
+ **kwargs: Unpack[MeshAttributes],
469
+ ) -> Self:
470
+ """
471
+ Generates an open-top box with physical wall thickness (concave bin).
472
+
473
+ Args:
474
+ width (float): Total outer dimension along X.
475
+ depth (float): Total outer dimension along Y.
476
+ height (float): Total outer dimension along Z.
477
+ wall_thickness (float): Thickness of the walls and bottom floor.
478
+ engine (BooleanEngineType): Engine to use for boolean subtraction.
479
+ base_at_zero (bool): Shift volume so it sits on z=0 instead of underground.
480
+ **kwargs (MeshAttributes): Standard MuJoCo mesh attributes (name, inertia, etc.)
481
+
482
+ """
483
+ # outer box centered at (0, 0, 0)
484
+ outer = trimesh.creation.box(extents=(width, depth, height))
485
+
486
+ # inner cutout box
487
+ inner = trimesh.creation.box(
488
+ extents=(width - (2 * wall_thickness), depth - (2 * wall_thickness), height)
489
+ )
490
+
491
+ # shift the inner tool up by the floor thickness
492
+ inner.apply_translation([0, 0, wall_thickness])
493
+
494
+ mesh = outer.difference(inner, engine=engine)
495
+
496
+ if base_at_zero:
497
+ mesh.apply_translation([0, 0, height / 2])
498
+
499
+ return cls.new_from_trimesh(mesh, **kwargs)
500
+
317
501
 
318
502
  class MeshSphere(MeshBase):
319
503
  """
@@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Annotated, ClassVar, Literal
4
4
 
5
5
  import mujoco
6
6
  import numpy as np
7
+ import trimesh
7
8
  from pydantic import ConfigDict, Field
8
9
 
9
10
  from mujoco_mojo.mjcf.defaults import SOLIMP_DEFAULT, SOLREF_DEFAULT
@@ -262,10 +263,7 @@ class GeomBase(XMLModel):
262
263
  signal_manager: SignalManager,
263
264
  attrs: list[
264
265
  Literal["xpos", "xmat", "xvelp", "xvelr", "xaccp", "xaccr", "quat"]
265
- ] = [
266
- "xpos",
267
- "quat",
268
- ],
266
+ ] = ["xpos", "quat"],
269
267
  ):
270
268
  """
271
269
  Registers specific geom attributes for logging.
@@ -476,6 +474,31 @@ class GeomMesh(GeomBase, ProximityMixin):
476
474
  mesh: MeshName
477
475
  """If the geom type is "mesh", this attribute is required. It references the mesh asset to be instantiated. This attribute can also be specified if the geom type corresponds to a geometric primitive, namely one of "sphere", "capsule", "cylinder", "ellipsoid", "box". In that case the primitive is automatically fitted to the mesh asset referenced here. The fitting procedure uses either the equivalent inertia box or the axis-aligned bounding box of the mesh, as determined by the attribute fitaabb of compiler. The resulting size of the fitted geom is usually what one would expect, but if not, it can be further adjusted with the fitscale attribute below. In the compiled mjModel the geom is represented as a regular geom of the specified primitive type, and there is no reference to the mesh used for fitting."""
478
476
 
477
+ def trimesh(self, mj_model: mujoco.MjModel) -> trimesh.Trimesh:
478
+ # get mesh id and data from mujoco
479
+ mesh_id = mj_model.geom_dataid[self.get_id(mj_model)]
480
+
481
+ if mesh_id == -1:
482
+ msg = "Exact proximity mesh tool is not currently supported for geoms of this type. Please use the `SPHERE_TO_SPHERE`/`CONVEX_HULL` algorithm, or convert the Geom to a GeomMesh."
483
+ logger.error(msg)
484
+ raise TypeError(msg)
485
+
486
+ # extract vertices and faces
487
+ if self._local_verts is None:
488
+ adr = mj_model.mesh_vertadr[mesh_id]
489
+ num = mj_model.mesh_vertnum[mesh_id]
490
+ self._local_verts = mj_model.mesh_vert[adr : adr + num].copy()
491
+
492
+ f_adr = mj_model.mesh_faceadr[mesh_id]
493
+ f_num = mj_model.mesh_facenum[mesh_id]
494
+ self._local_faces = mj_model.mesh_face[f_adr : f_adr + f_num].copy()
495
+
496
+ # create a trimesh and its proximity query
497
+ self._baked_mesh = trimesh.Trimesh(
498
+ vertices=self._local_verts, faces=self._local_faces
499
+ )
500
+ return self._baked_mesh
501
+
479
502
 
480
503
  class GeomSDF(GeomBase):
481
504
  attributes = (*_geom_attr, "type")
@@ -11,6 +11,7 @@ from pydantic import BaseModel, ConfigDict, Field, TypeAdapter, model_validator
11
11
  from scipy.signal import savgol_filter
12
12
 
13
13
  __all__ = [
14
+ "UNIT_GROUPS",
14
15
  "AbsoluteValueFilter",
15
16
  "AnyFilter",
16
17
  "ClipFilter",
@@ -302,56 +303,50 @@ class SavitzkyGolayFilter(BaseFilter):
302
303
 
303
304
 
304
305
  ureg = pint.UnitRegistry()
305
- # --- Kinematics ---
306
- AngleUnit = Literal["rad", "deg", "rad/s", "deg/s", "rad/s^2", "deg/s^2", "rev", "rpm"]
307
- LenUnit = Literal["m", "mm", "cm", "km", "in", "ft", "thou"]
308
- VelUnit = Literal["m/s", "ft/s", "in/s", "km/h", "mph"]
309
- AccUnit = Literal["m/s^2", "g", "ft/s^2", "in/s^2"]
310
-
311
- # --- Dynamics & Statics ---
312
- MassUnit = Literal["kg", "lbm", "slug", "g", "mg"]
313
- ForceUnit = Literal["N", "lbf", "kN", "mN"]
314
- TorqueUnit = Literal["N*m", "N*mm", "mN*m", "lbf*ft", "lbf*in", "ozf*in"]
315
- InertiaUnit = Literal["kg*m^2", "lbm*in^2", "lbm*ft^2", "slug*ft^2"]
316
-
317
- # --- Work & Thermodynamics ---
318
- EnergyUnit = Literal["J", "kJ", "mJ", "W*s", "ft*lbf", "BTU"]
319
- PowerUnit = Literal["W", "kW", "hp", "ft*lbf/s"]
320
- PressureUnit = Literal["Pa", "kPa", "psi", "bar", "atm", "torr"]
321
-
322
- # --- Temporal & Electronics ---
323
- TimeUnit = Literal["s", "ms", "us", "ns", "min", "hr"]
324
- FreqUnit = Literal["Hz", "kHz", "MHz", "rad/s"]
325
-
326
- # --- Dimensionless & Ratios ---
327
- MiscUnit = Literal["dimensionless", "pct", "count", "bit", "V", "A"]
328
-
329
- SignalUnit = (
330
- AngleUnit
331
- | LenUnit
332
- | VelUnit
333
- | AccUnit
334
- | MassUnit
335
- | ForceUnit
336
- | TorqueUnit
337
- | InertiaUnit
338
- | EnergyUnit
339
- | PowerUnit
340
- | PressureUnit
341
- | TimeUnit
342
- | FreqUnit
343
- | MiscUnit
344
- | str
345
- )
346
-
347
306
  try:
348
- # explicitly map lbm and lbf to avoid ambiguity
349
307
  ureg.define("lbm = pound")
350
308
  ureg.define("lbf = force_pound")
309
+ ureg.define("ozf = force_ounce")
351
310
  except pint.errors.RedefinitionError:
352
- # already defined in some Pint versions
353
311
  pass
354
312
 
313
+ # ---------------------------------------------------------------------------
314
+ # Unit groups — single source of truth for both the frontend smart dropdown
315
+ # and the SignalUnit type annotation on UnitFilter. To add a new unit,
316
+ # add it here; SignalUnit is derived automatically. Verify that pint can
317
+ # parse any new string via `ureg.parse_units(...)` before committing.
318
+ # ---------------------------------------------------------------------------
319
+ UNIT_GROUPS: list[tuple[str, list[str]]] = [
320
+ # --- Kinematics ---
321
+ ("Angle", ["rad", "deg", "mrad", "rev", "rpm"]),
322
+ ("Angular Velocity", ["rad/s", "deg/s"]),
323
+ ("Angular Accel.", ["rad/s^2", "deg/s^2"]),
324
+ ("Length", ["m", "mm", "cm", "um", "km", "in", "ft", "thou"]),
325
+ ("Velocity", ["m/s", "mm/s", "cm/s", "ft/s", "in/s", "km/h", "mph"]),
326
+ ("Acceleration", ["m/s^2", "mm/s^2", "ft/s^2", "in/s^2"]),
327
+ # --- Dynamics & Statics ---
328
+ ("Mass", ["kg", "g", "mg", "lbm", "slug"]),
329
+ ("Force", ["N", "mN", "uN", "kN", "lbf"]),
330
+ ("Torque", ["N*m", "N*mm", "mN*m", "kN*m", "lbf*ft", "lbf*in", "ozf*in"]),
331
+ ("Inertia", ["kg*m^2", "kg*mm^2", "lbm*in^2", "lbm*ft^2", "slug*ft^2"]),
332
+ # --- Work & Thermodynamics ---
333
+ ("Energy", ["J", "mJ", "kJ", "W*s", "W*h", "kW*h", "ft*lbf", "BTU"]),
334
+ ("Power", ["W", "mW", "kW", "MW", "hp", "ft*lbf/s"]),
335
+ ("Pressure", ["Pa", "kPa", "MPa", "psi", "bar", "atm", "torr"]),
336
+ # --- Temporal & Electronics ---
337
+ ("Time", ["s", "ms", "us", "ns", "min", "hr"]),
338
+ ("Frequency", ["Hz", "kHz", "MHz"]),
339
+ ("Voltage", ["V", "mV", "kV"]),
340
+ ("Current", ["A", "mA"]),
341
+ # --- Dimensionless & Ratios ---
342
+ ("Misc.", ["dimensionless", "pct", "count", "bit"]),
343
+ ]
344
+
345
+ # Derived automatically — Literal[tuple_of_strings] is equivalent to Literal["a", "b", ...]
346
+ # in Python 3.9+ because x[a, b] and x[(a, b)] make the same __getitem__ call.
347
+ _ALL_UNITS: tuple[str, ...] = tuple(u for _, us in UNIT_GROUPS for u in us)
348
+ SignalUnit = Literal[_ALL_UNITS] | str
349
+
355
350
 
356
351
  class UnitFilter(BaseFilter):
357
352
  """
@@ -362,9 +357,10 @@ class UnitFilter(BaseFilter):
362
357
  type: Literal[FilterType.UNIT] = FilterType.UNIT
363
358
  """The discriminator type for Pydantic."""
364
359
 
365
- from_unit: SignalUnit
360
+ from_unit: SignalUnit # pyright: ignore[reportInvalidTypeForm]
366
361
  """The original unit of the telemetry data (e.g., 'rad')."""
367
- to_unit: SignalUnit
362
+
363
+ to_unit: SignalUnit # pyright: ignore[reportInvalidTypeForm]
368
364
  """The target unit for analysis/display (e.g., 'deg')."""
369
365
 
370
366
  @model_validator(mode="after")