mujoco-mojo 2.3.0__tar.gz → 2.3.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 (395) hide show
  1. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/.gitignore +1 -0
  2. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/PKG-INFO +4 -1
  3. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/pyproject.toml +5 -2
  4. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/requirements.txt +60 -61
  5. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/scripts/gen_ts_models.py +12 -1
  6. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/__about__.py +3 -0
  7. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/__init__.py +1 -1
  8. mujoco_mojo-2.3.2/src/mujoco_mojo/meta.py +11 -0
  9. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mojo_model.py +18 -1
  10. mujoco_mojo-2.3.2/src/mujoco_mojo/runtime/video_recorder.py +221 -0
  11. mujoco_mojo-2.3.2/src/mujoco_mojo/settings.py +70 -0
  12. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/typing.py +1 -0
  13. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/dataframe.py +7 -0
  14. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/filters/filters.py +10 -1
  15. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/cli.py +187 -0
  16. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/lab_executor.py +71 -5
  17. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/main.py +44 -0
  18. mujoco_mojo-2.3.2/src/mujoco_mojo/utils/layers/dojo/plot_config.py +379 -0
  19. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/routers/monitor.py +28 -4
  20. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/routers/mosaic.py +158 -8
  21. mujoco_mojo-2.3.2/src/mujoco_mojo/utils/layers/dojo/routers/sensai.py +343 -0
  22. mujoco_mojo-2.3.2/src/mujoco_mojo/utils/layers/dojo/sensai/__init__.py +17 -0
  23. mujoco_mojo-2.3.2/src/mujoco_mojo/utils/layers/dojo/sensai/agent.py +475 -0
  24. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/base.html +239 -124
  25. mujoco_mojo-2.3.2/src/mujoco_mojo/utils/layers/dojo/templates/partials/_sensai.html +256 -0
  26. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_chart.html +47 -6
  27. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_json_editor.html +4 -2
  28. mujoco_mojo-2.3.2/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_media_player.html +246 -0
  29. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_signal_lab.html +985 -205
  30. mujoco_mojo-2.3.2/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_trial_status.html +103 -0
  31. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/js/main.js +33 -1
  32. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/js/monitor.js +1 -1
  33. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/js/mosaic.js +1 -1
  34. mujoco_mojo-2.3.2/src/mujoco_mojo/utils/layers/dojo/templates/static/js/sensai.js +1566 -0
  35. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/js/trial-viewer.js +952 -110
  36. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/build.mjs +1 -0
  37. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/package-lock.json +14 -1
  38. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/package.json +2 -1
  39. mujoco_mojo-2.3.2/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/src/lib/plot-config.generated.ts +232 -0
  40. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/src/models.ts +40 -0
  41. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/src/monitor.ts +1 -1
  42. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/src/mosaic.ts +1 -1
  43. mujoco_mojo-2.3.2/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/src/sensai.ts +393 -0
  44. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/src/store.ts +50 -1
  45. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/src/trial-viewer.ts +1208 -136
  46. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/src/types/global.d.ts +24 -0
  47. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/trial_viewer.html +6 -3
  48. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/reloaded.py +195 -28
  49. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/runner.py +16 -0
  50. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/statusing.py +4 -0
  51. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/runtime/monte_carlo_bumper.py +5 -4
  52. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/uv.lock +86 -64
  53. mujoco_mojo-2.3.0/src/mujoco_mojo/meta.py +0 -4
  54. mujoco_mojo-2.3.0/src/mujoco_mojo/runtime/video_recorder.py +0 -109
  55. mujoco_mojo-2.3.0/src/mujoco_mojo/utils/layers/dojo/plot_config.py +0 -163
  56. mujoco_mojo-2.3.0/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/src/lib/plot-config.generated.ts +0 -90
  57. mujoco_mojo-2.3.0/typings/mujoco/__init__.pyi +0 -1273
  58. mujoco_mojo-2.3.0/typings/mujoco/_callbacks.pyi +0 -50
  59. mujoco_mojo-2.3.0/typings/mujoco/_constants.pyi +0 -183
  60. mujoco_mojo-2.3.0/typings/mujoco/_enums.pyi +0 -6973
  61. mujoco_mojo-2.3.0/typings/mujoco/_errors.pyi +0 -5
  62. mujoco_mojo-2.3.0/typings/mujoco/_functions.pyi +0 -2950
  63. mujoco_mojo-2.3.0/typings/mujoco/_render.pyi +0 -503
  64. mujoco_mojo-2.3.0/typings/mujoco/_specs.pyi +0 -2988
  65. mujoco_mojo-2.3.0/typings/mujoco/_structs.pyi +0 -6587
  66. mujoco_mojo-2.3.0/typings/mujoco/cgl/__init__.pyi +0 -23
  67. mujoco_mojo-2.3.0/typings/mujoco/cgl/cgl.pyi +0 -89
  68. mujoco_mojo-2.3.0/typings/mujoco/gl_context.pyi +0 -14
  69. mujoco_mojo-2.3.0/typings/mujoco/glfw/__init__.pyi +0 -17
  70. mujoco_mojo-2.3.0/typings/mujoco/renderer.pyi +0 -113
  71. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/.gitattributes +0 -0
  72. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/.github/workflows/docs.yml +0 -0
  73. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/.github/workflows/release.yml +0 -0
  74. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/.pre-commit-config.yaml +0 -0
  75. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/.python-version +0 -0
  76. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/.vscode/settings.json +0 -0
  77. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/LICENSE +0 -0
  78. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/README.md +0 -0
  79. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/TODO.md +0 -0
  80. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/about.md +0 -0
  81. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/dark-hero-logo.png +0 -0
  82. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/dark-hero-logo.svg +0 -0
  83. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/dark-logo.svg +0 -0
  84. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/light-hero-logo.svg +0 -0
  85. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/light-logo.svg +0 -0
  86. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/logo.svg +0 -0
  87. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/mesh/bunny_original.jpg +0 -0
  88. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/mesh/bunny_with_coacd.jpg +0 -0
  89. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/mesh/bunny_without_coacd.jpg +0 -0
  90. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/mesh/frustums.jpg +0 -0
  91. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/mesh/proximity/convex_hull_wireframe.jpg +0 -0
  92. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/mesh/proximity/real_wireframe.jpg +0 -0
  93. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/mesh/with_coacd.jpg +0 -0
  94. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/mesh/without_coacd.jpg +0 -0
  95. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/dark-export-options.jpg +0 -0
  96. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/dark-monitor-view.jpg +0 -0
  97. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/dark-mosaic-view.jpg +0 -0
  98. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/dark-notes-editor.jpg +0 -0
  99. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/dark-plot-editor.jpg +0 -0
  100. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/dark-selector-bar.jpg +0 -0
  101. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/dark-shapes-editor.jpg +0 -0
  102. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/generate-result.jpg +0 -0
  103. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/light-export-options.jpg +0 -0
  104. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/light-monitor-view.jpg +0 -0
  105. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/light-mosaic-view.jpg +0 -0
  106. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/light-notes-editor.jpg +0 -0
  107. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/light-plot-editor.jpg +0 -0
  108. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/light-selector-bar.jpg +0 -0
  109. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/light-shapes-editor.jpg +0 -0
  110. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/assets/user-guides/runtime-anim.gif +0 -0
  111. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/index.md +0 -0
  112. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/javascripts/favicon-switcher.js +0 -0
  113. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/javascripts/mojo-highlighter.js +0 -0
  114. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/javascripts/tablesort.js +0 -0
  115. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/stylesheets/extra.css +0 -0
  116. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/user-guides/MOJO_RUNTIME_REPORT.md +0 -0
  117. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/user-guides/dojo.md +0 -0
  118. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/user-guides/generate-script.md +0 -0
  119. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/user-guides/getting-started.md +0 -0
  120. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/user-guides/init.md +0 -0
  121. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/user-guides/monitor.md +0 -0
  122. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/user-guides/monte_carlo_example.py +0 -0
  123. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/user-guides/mosaic.md +0 -0
  124. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/user-guides/optimization.md +0 -0
  125. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/user-guides/optimization_example.py +0 -0
  126. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/user-guides/reloaded.md +0 -0
  127. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/user-guides/running-jobs.md +0 -0
  128. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/docs/user-guides/runtime-script.md +0 -0
  129. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/examples/boxes_and_springs_monte_carlo.py +0 -0
  130. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/examples/boxes_and_springs_optimization.py +0 -0
  131. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/examples/tennis_racket_theorem.py +0 -0
  132. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/mkdocs.yml +0 -0
  133. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/scripts/copy_docs_examples_to_examples.py +0 -0
  134. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/scripts/fix_smart_quotes.py +0 -0
  135. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/scripts/gen_ref_pages.py +0 -0
  136. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/scripts/templating/filestomake.txt +0 -0
  137. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/scripts/templating/make_sensors.py +0 -0
  138. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/scripts/templating/sensor_template.py +0 -0
  139. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/base.py +0 -0
  140. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/__init__.py +0 -0
  141. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/defaults.py +0 -0
  142. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/dependency_path.py +0 -0
  143. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/extension.py +0 -0
  144. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/meta/__init__.py +0 -0
  145. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/meta/frame.py +0 -0
  146. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/meta/include.py +0 -0
  147. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/meta/replicate.py +0 -0
  148. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco.py +0 -0
  149. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/__init__.py +0 -0
  150. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator.py +0 -0
  151. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/__init__.py +0 -0
  152. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/adhesion.py +0 -0
  153. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/base.py +0 -0
  154. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/cylinder.py +0 -0
  155. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/damper.py +0 -0
  156. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/dcmotor.py +0 -0
  157. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/general.py +0 -0
  158. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/intvelocity.py +0 -0
  159. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/motor.py +0 -0
  160. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/muscle.py +0 -0
  161. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/plugin.py +0 -0
  162. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/position.py +0 -0
  163. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/velocity.py +0 -0
  164. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset.py +0 -0
  165. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/__init__.py +0 -0
  166. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/hfield.py +0 -0
  167. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/material.py +0 -0
  168. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/material_attr/__init__.py +0 -0
  169. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/material_attr/layer.py +0 -0
  170. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/mesh.py +0 -0
  171. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/model.py +0 -0
  172. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/texture.py +0 -0
  173. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body.py +0 -0
  174. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/__init__.py +0 -0
  175. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/attach.py +0 -0
  176. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/camera.py +0 -0
  177. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite.py +0 -0
  178. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/__init__.py +0 -0
  179. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/geom.py +0 -0
  180. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/joint.py +0 -0
  181. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/site.py +0 -0
  182. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/skin.py +0 -0
  183. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp.py +0 -0
  184. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/__init__.py +0 -0
  185. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/contact.py +0 -0
  186. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/edge.py +0 -0
  187. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/elasticity.py +0 -0
  188. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/pin.py +0 -0
  189. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/free_joint.py +0 -0
  190. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/geom.py +0 -0
  191. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/inertial.py +0 -0
  192. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/joint.py +0 -0
  193. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/light.py +0 -0
  194. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/plugin.py +0 -0
  195. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/site.py +0 -0
  196. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/compiler.py +0 -0
  197. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/compiler_attr/__init__.py +0 -0
  198. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/compiler_attr/lengthrange.py +0 -0
  199. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/contact.py +0 -0
  200. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/contact_attr/__init__.py +0 -0
  201. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/contact_attr/exclude.py +0 -0
  202. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/contact_attr/pair.py +0 -0
  203. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable.py +0 -0
  204. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/__init__.py +0 -0
  205. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex.py +0 -0
  206. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex_attr/__init__.py +0 -0
  207. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex_attr/contact.py +0 -0
  208. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex_attr/edge.py +0 -0
  209. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex_attr/elasticity.py +0 -0
  210. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/skin.py +0 -0
  211. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/skin_attr/__init__.py +0 -0
  212. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/skin_attr/bone.py +0 -0
  213. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality.py +0 -0
  214. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/__init__.py +0 -0
  215. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/connect.py +0 -0
  216. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/equality_base.py +0 -0
  217. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/flex.py +0 -0
  218. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/flexstrain.py +0 -0
  219. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/flexvert.py +0 -0
  220. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/joint.py +0 -0
  221. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/tendon.py +0 -0
  222. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/weld.py +0 -0
  223. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/keyframe.py +0 -0
  224. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/keyframe_attr/__init__.py +0 -0
  225. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/keyframe_attr/key.py +0 -0
  226. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/option.py +0 -0
  227. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/option_attr/__init__.py +0 -0
  228. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/option_attr/flag.py +0 -0
  229. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor.py +0 -0
  230. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/__init__.py +0 -0
  231. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/accelerometer.py +0 -0
  232. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/actuatorfrc.py +0 -0
  233. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/actuatorpos.py +0 -0
  234. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/actuatorvel.py +0 -0
  235. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/ballangvel.py +0 -0
  236. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/ballquat.py +0 -0
  237. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/base.py +0 -0
  238. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/base_collision.py +0 -0
  239. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/camprojection.py +0 -0
  240. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/clock.py +0 -0
  241. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/contact.py +0 -0
  242. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/distance.py +0 -0
  243. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/e_kinetic.py +0 -0
  244. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/e_potential.py +0 -0
  245. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/force.py +0 -0
  246. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/frameangacc.py +0 -0
  247. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/frameangvel.py +0 -0
  248. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framelinacc.py +0 -0
  249. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framelinvel.py +0 -0
  250. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framepos.py +0 -0
  251. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framequat.py +0 -0
  252. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framexaxis.py +0 -0
  253. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/frameyaxis.py +0 -0
  254. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framezaxis.py +0 -0
  255. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/fromto.py +0 -0
  256. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/gyro.py +0 -0
  257. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/insidesite.py +0 -0
  258. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointactuatorfrc.py +0 -0
  259. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointlimitfrc.py +0 -0
  260. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointlimitpos.py +0 -0
  261. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointlimitvel.py +0 -0
  262. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointpos.py +0 -0
  263. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointvel.py +0 -0
  264. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/magnetometer.py +0 -0
  265. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/normal.py +0 -0
  266. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/plugin.py +0 -0
  267. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/rangefinder.py +0 -0
  268. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/subtreeangmom.py +0 -0
  269. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/subtreecom.py +0 -0
  270. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/subtreelinvel.py +0 -0
  271. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tactile.py +0 -0
  272. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonactuatorfrc.py +0 -0
  273. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonlimitfrc.py +0 -0
  274. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonlimitpos.py +0 -0
  275. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonlimitvel.py +0 -0
  276. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonpos.py +0 -0
  277. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonvel.py +0 -0
  278. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/torque.py +0 -0
  279. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/touch.py +0 -0
  280. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/user.py +0 -0
  281. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/velocimeter.py +0 -0
  282. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/size.py +0 -0
  283. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/statistic.py +0 -0
  284. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon.py +0 -0
  285. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/__init__.py +0 -0
  286. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/fixed.py +0 -0
  287. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/fixed_attr/__init__.py +0 -0
  288. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/fixed_attr/joint.py +0 -0
  289. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial.py +0 -0
  290. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial_attr/__init__.py +0 -0
  291. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial_attr/geom.py +0 -0
  292. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial_attr/pulley.py +0 -0
  293. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial_attr/site.py +0 -0
  294. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/tendon_base.py +0 -0
  295. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual.py +0 -0
  296. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/__init__.py +0 -0
  297. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/global_.py +0 -0
  298. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/headlight.py +0 -0
  299. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/map.py +0 -0
  300. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/quality.py +0 -0
  301. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/rgba.py +0 -0
  302. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/scale.py +0 -0
  303. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/orientation.py +0 -0
  304. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/plugin.py +0 -0
  305. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/pose.py +0 -0
  306. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/position.py +0 -0
  307. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/mjcf/xml_model.py +0 -0
  308. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/runtime/__init__.py +0 -0
  309. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/runtime/load.py +0 -0
  310. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/runtime/runtime_manager.py +0 -0
  311. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/runtime/signal_manager.py +0 -0
  312. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/stochas/__init__.py +0 -0
  313. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/templates/__init__.py +0 -0
  314. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/templates/monte_carlo.py +0 -0
  315. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/templates/optimization.py +0 -0
  316. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/templates/reloaded.sh +0 -0
  317. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/templates/run_mc.sh +0 -0
  318. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/templates/run_opt.sh +0 -0
  319. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/__init__.py +0 -0
  320. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/color.py +0 -0
  321. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/defaults.py +0 -0
  322. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/filters/__init__.py +0 -0
  323. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/interp.py +0 -0
  324. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/__init__.py +0 -0
  325. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/__init__.py +0 -0
  326. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/routers/__init__.py +0 -0
  327. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/routers/morph.py +0 -0
  328. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/shared.py +0 -0
  329. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/__init__.py +0 -0
  330. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/error.html +0 -0
  331. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/monitor.html +0 -0
  332. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/morph.html +0 -0
  333. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/mosaic.html +0 -0
  334. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_header.html +0 -0
  335. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_lab_trigger.html +0 -0
  336. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_macros.html +0 -0
  337. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_overlays.html +0 -0
  338. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_series_panel.html +0 -0
  339. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/__init__.py +0 -0
  340. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/chime.mp3 +0 -0
  341. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/dark-logo.svg +0 -0
  342. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/js/__init__.py +0 -0
  343. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/js/toast.d.ts +0 -0
  344. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/js/toast.d.ts.map +0 -0
  345. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/js/toast.js +0 -0
  346. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/light-logo.svg +0 -0
  347. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/main.css +0 -0
  348. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/src/cm-bundle.ts +0 -0
  349. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/src/lib/format.ts +0 -0
  350. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/src/lib/options.ts +0 -0
  351. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/src/lib/toast.ts +0 -0
  352. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/ts/tsconfig.json +0 -0
  353. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored/__init__.py +0 -0
  354. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored/alpine.min.js +0 -0
  355. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored/codemirror.bundle.js +0 -0
  356. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored/confetti.browser.min.js +0 -0
  357. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored/iro.min.js +0 -0
  358. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored/litegraph.min.css +0 -0
  359. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored/litegraph.min.js +0 -0
  360. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored/lz-string.min.js +0 -0
  361. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored/plotly-3.4.0.min.js +0 -0
  362. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored/tailwind.min.js +0 -0
  363. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/log.py +0 -0
  364. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/proximity.py +0 -0
  365. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/proximity_mixin.py +0 -0
  366. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/utils/utils.py +0 -0
  367. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/src/mujoco_mojo/visualization.py +0 -0
  368. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/.gitignore +0 -0
  369. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/make_skybox.py +0 -0
  370. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/meshes/ball.stl +0 -0
  371. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/meshes/bunny2.stl +0 -0
  372. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/meshes/cup.stl +0 -0
  373. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/mjcf/inertial_test.py +0 -0
  374. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/mjcf/mesh.py +0 -0
  375. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/mjcf/orientation_test.py +0 -0
  376. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/mjcf/pos_test.py +0 -0
  377. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/mjcf/pose_test.py +0 -0
  378. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/mjcf/xml_model_test.py +0 -0
  379. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/model_with_skybox.xml +0 -0
  380. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/monte_carlo_test/asset_image.png +0 -0
  381. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/monte_carlo_test/monte_carlo.py +0 -0
  382. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/monte_carlo_test/overrides.json +0 -0
  383. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/monte_carlo_test/running_with_slurm.sh +0 -0
  384. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/runtime/conftest.py +0 -0
  385. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/runtime/loads_test.py +0 -0
  386. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/runtime/optimizer_bumper.py +0 -0
  387. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/runtime/runtime_manager_test.py +0 -0
  388. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/runtime/signal_manager_test.py +0 -0
  389. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/smoke_test.py +0 -0
  390. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/test_writer.py +0 -0
  391. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/utils/color_test.py +0 -0
  392. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/utils/dataframe_test.py +0 -0
  393. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/utils/filter_test.py +0 -0
  394. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/utils/interp_test.py +0 -0
  395. {mujoco_mojo-2.3.0 → mujoco_mojo-2.3.2}/tests/utils/proximity_test.py +0 -0
@@ -17,6 +17,7 @@ docs/reference/
17
17
  mojo-models
18
18
  textures
19
19
 
20
+ typings
20
21
  MUJOCO_LOG.TXT
21
22
 
22
23
  /*.mp4
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mujoco-mojo
3
- Version: 2.3.0
3
+ Version: 2.3.2
4
4
  Summary: A complete MJCF lifecycle and trial orchestration suite for MuJoCo, powered by Pydantic v2.
5
5
  Project-URL: Homepage, https://github.com/Hydrowelder/mujoco-mojo
6
6
  Project-URL: Documentation, https://hydrowelder.github.io/mujoco-mojo/
@@ -42,6 +42,7 @@ Requires-Dist: pip>=26.0.1
42
42
  Requires-Dist: polars>=1.39.0
43
43
  Requires-Dist: pyarrow>=23.0.1
44
44
  Requires-Dist: pybind11-stubgen>=2.5.5
45
+ Requires-Dist: pydantic-settings>=2.14.1
45
46
  Requires-Dist: pydantic>=2.12.5
46
47
  Requires-Dist: python-fcl>=0.7.0.11
47
48
  Requires-Dist: rich>=14.3.3
@@ -51,12 +52,14 @@ Requires-Dist: scipy>=1.17.0
51
52
  Requires-Dist: sse-starlette>=3.3.4
52
53
  Requires-Dist: stochas>=2.0.0
53
54
  Requires-Dist: tabulate>=0.9.0
55
+ Requires-Dist: tomli-w>=1.2.0
54
56
  Requires-Dist: trimesh>=4.11.2
55
57
  Requires-Dist: typer>=0.24.1
56
58
  Requires-Dist: uvicorn>=0.41.0
57
59
  Provides-Extra: reloaded
58
60
  Requires-Dist: mjviser>=0.0.11; extra == 'reloaded'
59
61
  Requires-Dist: viser>=1.0.26; extra == 'reloaded'
62
+ Requires-Dist: watchfiles>=1.1.1; extra == 'reloaded'
60
63
  Description-Content-Type: text/markdown
61
64
 
62
65
  <p align="center">
@@ -42,6 +42,8 @@ dependencies = [
42
42
  "python-fcl>=0.7.0.11",
43
43
  "rtree>=1.4.1",
44
44
  "filelock>=3.29.0",
45
+ "pydantic-settings>=2.14.1",
46
+ "tomli-w>=1.2.0",
45
47
  ]
46
48
  classifiers = [
47
49
  "Development Status :: 4 - Beta",
@@ -69,7 +71,8 @@ keywords = [
69
71
  ]
70
72
 
71
73
  [project.optional-dependencies]
72
- reloaded = ["mjviser>=0.0.11", "viser>=1.0.26"]
74
+ reloaded = ["mjviser>=0.0.11", "viser>=1.0.26", "watchfiles>=1.1.1"]
75
+ # sensai = ["pydantic-ai>=1.102.0", "requests>=2.32.5"]
73
76
 
74
77
  [dependency-groups]
75
78
  dev = [
@@ -143,7 +146,7 @@ ignore = [
143
146
  ]
144
147
 
145
148
  [tool.pyright]
146
- stubPath = "typings"
149
+ stubPath = "./typings"
147
150
  venvPath = ".."
148
151
  venv = ".venv"
149
152
  ignore = ["typings", "scripts/templating/sensor_template.py"]
@@ -1033,9 +1033,9 @@ optype==0.15.0 \
1033
1033
  --hash=sha256:457d6ca9e7da19967ec16d42bdf94e240b33b5d70a56fbbf5b427e5ea39cf41e \
1034
1034
  --hash=sha256:caba40ece9ea39b499fa76c036a82e0d452a432dd4dd3e8e0d30892be2e8c76c
1035
1035
  # via scipy-stubs
1036
- packaging==26.0 \
1037
- --hash=sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4 \
1038
- --hash=sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529
1036
+ packaging==25.0 \
1037
+ --hash=sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484 \
1038
+ --hash=sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f
1039
1039
  # via
1040
1040
  # fastparquet
1041
1041
  # ipykernel
@@ -1293,6 +1293,7 @@ pydantic==2.12.5 \
1293
1293
  # fastapi
1294
1294
  # mujoco-mojo
1295
1295
  # numpydantic
1296
+ # pydantic-settings
1296
1297
  # stochas
1297
1298
  pydantic-core==2.41.5 \
1298
1299
  --hash=sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90 \
@@ -1357,6 +1358,10 @@ pydantic-core==2.41.5 \
1357
1358
  --hash=sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75 \
1358
1359
  --hash=sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7
1359
1360
  # via pydantic
1361
+ pydantic-settings==2.14.1 \
1362
+ --hash=sha256:6e3c7edfd8277687cdc598f56e5cff0e9bfff0910a3749deaa8d4401c3a2b9de \
1363
+ --hash=sha256:e874d3bec7e787b0c9958277956ed9b4dd5de6a80e162188fdaff7c5e26fd5fa
1364
+ # via mujoco-mojo
1360
1365
  pygments==2.19.2 \
1361
1366
  --hash=sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887 \
1362
1367
  --hash=sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b
@@ -1420,6 +1425,10 @@ python-dateutil==2.9.0.post0 \
1420
1425
  # jupyter-client
1421
1426
  # matplotlib
1422
1427
  # pandas
1428
+ python-dotenv==1.2.2 \
1429
+ --hash=sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a \
1430
+ --hash=sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3
1431
+ # via pydantic-settings
1423
1432
  python-fcl==0.7.0.11 \
1424
1433
  --hash=sha256:0a48312a0dcd8466e79be4b5025f52168d0e5b866b809f727923b313246989bc \
1425
1434
  --hash=sha256:136585069f547c303d9b7d7a3e9a63e0b03937279532cd3144c0f12c5ce853d2 \
@@ -1735,6 +1744,10 @@ tabulate==0.9.0 \
1735
1744
  --hash=sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c \
1736
1745
  --hash=sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f
1737
1746
  # via mujoco-mojo
1747
+ tomli-w==1.2.0 \
1748
+ --hash=sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90 \
1749
+ --hash=sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021
1750
+ # via mujoco-mojo
1738
1751
  tornado==6.5.5 \
1739
1752
  --hash=sha256:192b8f3ea91bd7f1f50c06955416ed76c6b72f96779b962f07f911b91e8d30e9 \
1740
1753
  --hash=sha256:2c9a876e094109333f888539ddb2de4361743e5d21eece20688e3e351e4990a6 \
@@ -1794,6 +1807,7 @@ typing-inspection==0.4.2 \
1794
1807
  # via
1795
1808
  # fastapi
1796
1809
  # pydantic
1810
+ # pydantic-settings
1797
1811
  tzdata==2025.3 ; sys_platform == 'emscripten' or sys_platform == 'win32' \
1798
1812
  --hash=sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1 \
1799
1813
  --hash=sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7
@@ -1890,64 +1904,49 @@ wcwidth==0.6.0 \
1890
1904
  --hash=sha256:1a3a1e510b553315f8e146c54764f4fb6264ffad731b3d78088cdb1478ffbdad \
1891
1905
  --hash=sha256:cdc4e4262d6ef9a1a57e018384cbeb1208d8abbc64176027e2c2455c81313159
1892
1906
  # via prompt-toolkit
1893
- wrapt==2.1.2 \
1894
- --hash=sha256:08ffa54146a7559f5b8df4b289b46d963a8e74ed16ba3687f99896101a3990c5 \
1895
- --hash=sha256:0fc04bc8664a8bc4c8e00b37b5355cffca2535209fba1abb09ae2b7c76ddf82b \
1896
- --hash=sha256:1370e516598854e5b4366e09ce81e08bfe94d42b0fd569b88ec46cc56d9164a9 \
1897
- --hash=sha256:162e4e2ba7542da9027821cb6e7c5e068d64f9a10b5f15512ea28e954893a267 \
1898
- --hash=sha256:16997dfb9d67addc2e3f41b62a104341e80cac52f91110dece393923c0ebd5ca \
1899
- --hash=sha256:1c51c738d7d9faa0b3601708e7e2eda9bf779e1b601dce6c77411f2a1b324a63 \
1900
- --hash=sha256:2d3ff4f0024dd224290c0eabf0240f1bfc1f26363431505fb1b0283d3b08f11d \
1901
- --hash=sha256:3144b027ff30cbd2fca07c0a87e67011adb717eb5f5bd8496325c17e454257a3 \
1902
- --hash=sha256:3278c471f4468ad544a691b31bb856374fbdefb7fee1a152153e64019379f015 \
1903
- --hash=sha256:3769a77df8e756d65fbc050333f423c01ae012b4f6731aaf70cf2bef61b34596 \
1904
- --hash=sha256:3969c56e4563c375861c8df14fa55146e81ac11c8db49ea6fb7f2ba58bc1ff9a \
1905
- --hash=sha256:3996a67eecc2c68fd47b4e3c564405a5777367adfd9b8abb58387b63ee83b21e \
1906
- --hash=sha256:3b8d15e52e195813efe5db8cec156eebe339aaf84222f4f4f051a6c01f237ed7 \
1907
- --hash=sha256:3beb22f674550d5634642c645aba4c72a2c66fb185ae1aebe1e955fae5a13baf \
1908
- --hash=sha256:4006c351de6d5007aa33a551f600404ba44228a89e833d2fadc5caa5de8edfbf \
1909
- --hash=sha256:467e7c76315390331c67073073d00662015bb730c566820c9ca9b54e4d67fd04 \
1910
- --hash=sha256:4bdf26e03e6d0da3f0e9422fd36bcebf7bc0eeb55fdf9c727a09abc6b9fe472e \
1911
- --hash=sha256:57d7c0c980abdc5f1d98b11a2aa3bb159790add80258c717fa49a99921456d90 \
1912
- --hash=sha256:5c35b5d82b16a3bc6e0a04349b606a0582bc29f573786aebe98e0c159bc48db6 \
1913
- --hash=sha256:62503ffbc2d3a69891cf29beeaccdb4d5e0a126e2b6a851688d4777e01428dbb \
1914
- --hash=sha256:6433ea84e1cfacf32021d2a4ee909554ade7fd392caa6f7c13f1f4bf7b8e8748 \
1915
- --hash=sha256:6de1a3851c27e0bd6a04ca993ea6f80fc53e6c742ee1601f486c08e9f9b900a9 \
1916
- --hash=sha256:6f2c5390460de57fa9582bc8a1b7a6c86e1a41dfad74c5225fc07044c15cc8d1 \
1917
- --hash=sha256:6f8dbdd3719e534860d6a78526aafc220e0241f981367018c2875178cf83a413 \
1918
- --hash=sha256:6f97edc9842cf215312b75fe737ee7c8adda75a89979f8e11558dfff6343cc4b \
1919
- --hash=sha256:72aaa9d0d8e4ed0e2e98019cea47a21f823c9dd4b43c7b77bba6679ffcca6a00 \
1920
- --hash=sha256:76405518ca4e1b76fbb1b9f686cff93aebae03920cc55ceeec48ff9f719c5f67 \
1921
- --hash=sha256:776867878e83130c7a04237010463372e877c1c994d449ca6aaafeab6aab2586 \
1922
- --hash=sha256:787fd6f4d67befa6fe2abdffcbd3de2d82dfc6fb8a6d850407c53332709d030b \
1923
- --hash=sha256:79847b83eb38e70d93dc392c7c5b587efe65b3e7afcc167aa8abd5d60e8761c8 \
1924
- --hash=sha256:7dfa9f2cf65d027b951d05c662cc99ee3bd01f6e4691ed39848a7a5fffc902b2 \
1925
- --hash=sha256:84ce8f1c2104d2f6daa912b1b5b039f331febfeee74f8042ad4e04992bd95c8f \
1926
- --hash=sha256:970d57ed83fa040d8b20c52fe74a6ae7e3775ae8cff5efd6a81e06b19078484c \
1927
- --hash=sha256:a76d61a2e851996150ba0f80582dd92a870643fa481f3b3846f229de88caf044 \
1928
- --hash=sha256:a8914c754d3134a3032601c6984db1c576e6abaf3fc68094bb8ab1379d75ff92 \
1929
- --hash=sha256:a9372fc3639a878c8e7d87e1556fa209091b0a66e912c611e3f833e2c4202be2 \
1930
- --hash=sha256:a93cd767e37faeddbe07d8fc4212d5cba660af59bdb0f6372c93faaa13e6e679 \
1931
- --hash=sha256:a9b9d50c9af998875a1482a038eb05755dfd6fe303a313f6a940bb53a83c3f18 \
1932
- --hash=sha256:a9dd9813825f7ecb018c17fd147a01845eb330254dff86d3b5816f20f4d6aaf8 \
1933
- --hash=sha256:b8fd6fa2b2c4e7621808f8c62e8317f4aae56e59721ad933bac5239d913cf0e8 \
1934
- --hash=sha256:bbac24d879aa22998e87f6b3f481a5216311e7d53c7db87f189a7a0266dafffb \
1935
- --hash=sha256:c0be8b5a74c5824e9359b53e7e58bef71a729bacc82e16587db1c4ebc91f7c5a \
1936
- --hash=sha256:c20b757c268d30d6215916a5fa8461048d023865d888e437fab451139cad6c8e \
1937
- --hash=sha256:c7e6cd120ef837d5b6f860a6ea3745f8763805c418bb2f12eeb1fa6e25f22d22 \
1938
- --hash=sha256:c8e46ae8e4032792eb2f677dbd0d557170a8e5524d22acc55199f43efedd39bf \
1939
- --hash=sha256:da1f00a557c66225d53b095a97eace0fc5349e3bfda28fa34ffae238978ee575 \
1940
- --hash=sha256:de9f1a2bbc5ac7f6012ec24525bdd444765a2ff64b5985ac6e0692144838542e \
1941
- --hash=sha256:e3d3b35eedcf5f7d022291ecd7533321c4775f7b9cd0050a31a68499ba45757c \
1942
- --hash=sha256:e6ed62c82ddf58d001096ae84ce7f833db97ae2263bff31c9b336ba8cfe3f508 \
1943
- --hash=sha256:eba8155747eb2cae4a0b913d9ebd12a1db4d860fc4c829d7578c7b989bd3f2f0 \
1944
- --hash=sha256:f01277d9a5fc1862f26f7626da9cf443bebc0abd2f303f41c5e995b15887dabd \
1945
- --hash=sha256:f29c827a8d9936ac320746747a016c4bc66ef639f5cd0d32df24f5eacbf9c69f \
1946
- --hash=sha256:f8bc1c264d8d1cf5b3560a87bbdd31131573eb25f9f9447bb6252b8d4c44a3a1 \
1947
- --hash=sha256:f8fba1bae256186a83d1875b2b1f4e2d1242e8fac0f58ec0d7e41b26967b965c \
1948
- --hash=sha256:fab036efe5464ec3291411fabb80a7a39e2dd80bae9bcbeeca5087fdfa891e19 \
1949
- --hash=sha256:ff2aad9c4cda28a8f0653fc2d487596458c2a3f475e56ba02909e950a9efa6a9 \
1950
- --hash=sha256:ff95d4264e55839be37bafe1536db2ab2de19da6b65f9244f01f332b5286cfbf
1907
+ wrapt==1.17.3 \
1908
+ --hash=sha256:042ec3bb8f319c147b1301f2393bc19dba6e176b7da446853406d041c36c7828 \
1909
+ --hash=sha256:0b02e424deef65c9f7326d8c19220a2c9040c51dc165cddb732f16198c168396 \
1910
+ --hash=sha256:0ed61b7c2d49cee3c027372df5809a59d60cf1b6c2f81ee980a091f3afed6a2d \
1911
+ --hash=sha256:16ecf15d6af39246fe33e507105d67e4b81d8f8d2c6598ff7e3ca1b8a37213f7 \
1912
+ --hash=sha256:1f0b2f40cf341ee8cc1a97d51ff50dddb9fcc73241b9143ec74b30fc4f44f6cb \
1913
+ --hash=sha256:223db574bb38637e8230eb14b185565023ab624474df94d2af18f1cdb625216f \
1914
+ --hash=sha256:249f88ed15503f6492a71f01442abddd73856a0032ae860de6d75ca62eed8067 \
1915
+ --hash=sha256:281262213373b6d5e4bb4353bc36d1ba4084e6d6b5d242863721ef2bf2c2930b \
1916
+ --hash=sha256:373342dd05b1d07d752cecbec0c41817231f29f3a89aa8b8843f7b95992ed0c7 \
1917
+ --hash=sha256:3af60380ba0b7b5aeb329bc4e402acd25bd877e98b3727b0135cb5c2efdaefe9 \
1918
+ --hash=sha256:41b1d2bc74c2cac6f9074df52b2efbef2b30bdfe5f40cb78f8ca22963bc62977 \
1919
+ --hash=sha256:423ed5420ad5f5529db9ce89eac09c8a2f97da18eb1c870237e84c5a5c2d60aa \
1920
+ --hash=sha256:4da9f45279fff3543c371d5ababc57a0384f70be244de7759c85a7f989cb4ebe \
1921
+ --hash=sha256:507553480670cab08a800b9463bdb881b2edeed77dc677b0a5915e6106e91a58 \
1922
+ --hash=sha256:53e5e39ff71b3fc484df8a522c933ea2b7cdd0d5d15ae82e5b23fde87d44cbd8 \
1923
+ --hash=sha256:54a30837587c6ee3cd1a4d1c2ec5d24e77984d44e2f34547e2323ddb4e22eb77 \
1924
+ --hash=sha256:5a03a38adec8066d5a37bea22f2ba6bbf39fcdefbe2d91419ab864c3fb515454 \
1925
+ --hash=sha256:5d4478d72eb61c36e5b446e375bbc49ed002430d17cdec3cecb36993398e1a9e \
1926
+ --hash=sha256:5ea5eb3c0c071862997d6f3e02af1d055f381b1d25b286b9d6644b79db77657c \
1927
+ --hash=sha256:604d076c55e2fdd4c1c03d06dc1a31b95130010517b5019db15365ec4a405fc6 \
1928
+ --hash=sha256:6b538e31eca1a7ea4605e44f81a48aa24c4632a277431a6ed3f328835901f4fd \
1929
+ --hash=sha256:6fd1ad24dc235e4ab88cda009e19bf347aabb975e44fd5c2fb22a3f6e4141277 \
1930
+ --hash=sha256:7171ae35d2c33d326ac19dd8facb1e82e5fd04ef8c6c0e394d7af55a55051c22 \
1931
+ --hash=sha256:73d496de46cd2cdbdbcce4ae4bcdb4afb6a11234a1df9c085249d55166b95116 \
1932
+ --hash=sha256:7425ac3c54430f5fc5e7b6f41d41e704db073309acfc09305816bc6a0b26bb16 \
1933
+ --hash=sha256:74afa28374a3c3a11b3b5e5fca0ae03bef8450d6aa3ab3a1e2c30e3a75d023dc \
1934
+ --hash=sha256:88547535b787a6c9ce4086917b6e1d291aa8ed914fdd3a838b3539dc95c12804 \
1935
+ --hash=sha256:9baa544e6acc91130e926e8c802a17f3b16fbea0fd441b5a60f5cf2cc5c3deba \
1936
+ --hash=sha256:a47681378a0439215912ef542c45a783484d4dd82bac412b71e59cf9c0e1cea0 \
1937
+ --hash=sha256:ab232e7fdb44cdfbf55fc3afa31bcdb0d8980b9b95c38b6405df2acb672af0e0 \
1938
+ --hash=sha256:cf30f6e3c077c8e6a9a7809c94551203c8843e74ba0c960f4a98cd80d4665d39 \
1939
+ --hash=sha256:d40770d7c0fd5cbed9d84b2c3f2e156431a12c9a37dc6284060fb4bec0b7ffd4 \
1940
+ --hash=sha256:dc4a8d2b25efb6681ecacad42fca8859f88092d8732b170de6a5dddd80a1c8fa \
1941
+ --hash=sha256:e01375f275f010fcbf7f643b4279896d04e571889b8a5b3f848423d91bf07050 \
1942
+ --hash=sha256:e1a4120ae5705f673727d3253de3ed0e016f7cd78dc463db1b31e2463e1f3cf6 \
1943
+ --hash=sha256:e228514a06843cae89621384cfe3a80418f3c04aadf8a3b14e46a7be704e4235 \
1944
+ --hash=sha256:e405adefb53a435f01efa7ccdec012c016b5a1d3f35459990afc39b6be4d5056 \
1945
+ --hash=sha256:e71d5c6ebac14875668a1e90baf2ea0ef5b7ac7918355850c0908ae82bcb297c \
1946
+ --hash=sha256:ed7c635ae45cfbc1a7371f708727bf74690daedc49b4dba310590ca0bd28aa8a \
1947
+ --hash=sha256:f38e60678850c42461d4202739f9bf1e3a737c7ad283638251e79cc49effb6b6 \
1948
+ --hash=sha256:f66eb08feaa410fe4eebd17f2a2c8e2e46d3476e9f8c783daa8e09e0faa666d0 \
1949
+ --hash=sha256:fbd3c8319de8e1dc79d346929cd71d523622da527cca14e0c1d257e31c2b8b10
1951
1950
  # via deprecated
1952
1951
  zensical==0.0.31 \
1953
1952
  --hash=sha256:03fa11e629a308507693489541f43e751697784e94365e7435b02104aefd1c2c \
@@ -60,7 +60,11 @@ def _schema_to_ts(node: dict, defs: dict) -> str:
60
60
  items = [_schema_to_ts(s, defs) for s in node["prefixItems"]]
61
61
  return f"[{', '.join(items)}]"
62
62
  if "items" in node:
63
- return f"{_schema_to_ts(node['items'], defs)}[]"
63
+ items_node = node["items"]
64
+ # discriminated union (oneOf + discriminator) → use the FilterEntry alias
65
+ if "oneOf" in items_node and "discriminator" in items_node:
66
+ return "FilterEntry[]"
67
+ return f"{_schema_to_ts(items_node, defs)}[]"
64
68
  return "unknown[]"
65
69
 
66
70
  if t == "object":
@@ -150,6 +154,13 @@ def main() -> None:
150
154
 
151
155
  blocks: list[str] = []
152
156
 
157
+ # FilterEntry is the structural base for every discriminated filter object;
158
+ # emitted first so XAxisConfig/YAxisConfig can reference it.
159
+ blocks.append(
160
+ "/** a single filter in a filter stack — type-discriminated, open-ended properties. */\n"
161
+ "export type FilterEntry = { type: string; enabled?: boolean; [key: string]: unknown };\n"
162
+ )
163
+
153
164
  # Emit each $def in definition order
154
165
  for def_name, def_schema in defs.items():
155
166
  blocks.append(_def_to_ts(def_name, def_schema, defs))
@@ -1,3 +1,4 @@
1
+ from datetime import date
1
2
  from importlib.metadata import PackageNotFoundError, version
2
3
 
3
4
  try:
@@ -9,3 +10,5 @@ __author__ = "David Gable"
9
10
  __email__ = "dave.a.gable@gmail.com"
10
11
  __license__ = "Apache-2.0"
11
12
  __summary__ = "A complete MJCF lifecycle and trial orchestration suite for MuJoCo, powered by Pydantic v2."
13
+ __copyright__ = f"© {date.today().year} David Gable"
14
+ __url__ = "https://github.com/Hydrowelder/mujoco-mojo"
@@ -12,7 +12,7 @@ MuJoCo does not ship Python type stubs. Generate them once with pybind11-stubgen
12
12
  pip install pybind11-stubgen
13
13
  pybind11-stubgen mujoco -o typings/ --numpy-array-wrap-with-annotated
14
14
 
15
- Run this from the project root. The ``typings/`` directory is gitignored.
15
+ Run this from the project root. The `typings/` directory is gitignored.
16
16
  Then add to pyproject.toml:
17
17
 
18
18
  .. code-block:: toml
@@ -0,0 +1,11 @@
1
+ from pathlib import Path
2
+
3
+ from pydantic import HttpUrl
4
+
5
+ from mujoco_mojo.__about__ import __url__
6
+
7
+ REPO_URL = HttpUrl(url=__url__)
8
+ """Link to the remote repo for use with reporting elements."""
9
+
10
+ MUJOCO_MOJO_DIR: Path = Path.home() / ".mujoco-mojo"
11
+ """Canonical user-level directory for all mujoco-mojo data (settings, profiles, lab graphs, etc.)."""
@@ -1,8 +1,9 @@
1
1
  from __future__ import annotations
2
2
 
3
+ from pathlib import Path
3
4
  from typing import TypeVar
4
5
 
5
- from pydantic import BaseModel, ConfigDict, Field, SerializeAsAny
6
+ from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, SerializeAsAny
6
7
  from stochas import StochasBase
7
8
 
8
9
  from mujoco_mojo.base import MojoBaseModel
@@ -32,6 +33,22 @@ class MojoModel(MojoBaseModel, StochasBase):
32
33
  user_data: SerializeAsAny[UserData] | None = None
33
34
  """User defined data for the model. This is used for transferring information from one function to another (generator to runtime or objective function)."""
34
35
 
36
+ _trial_dir: Path | None = PrivateAttr(default=None)
37
+
38
+ @property
39
+ def trial_dir(self) -> Path:
40
+ """
41
+ Absolute path to this trial's workspace directory.
42
+
43
+ Set automatically after the generator runs. Available in runtime and objective functions. Raises `RuntimeError` if accessed inside the generator, where the directory has not yet been created.
44
+ """
45
+ if self._trial_dir is None:
46
+ raise RuntimeError(
47
+ "trial_dir is not available inside the generator. "
48
+ "It is set after generation completes and the workspace is created."
49
+ )
50
+ return self._trial_dir
51
+
35
52
  def get_user_data(self, cls: type[T]) -> T:
36
53
  """Returns the user_data re-validated into the requested class."""
37
54
  if self.user_data is None:
@@ -0,0 +1,221 @@
1
+ from dataclasses import dataclass, field
2
+ from pathlib import Path
3
+ from typing import TYPE_CHECKING, Self
4
+
5
+ import mujoco
6
+
7
+ from mujoco_mojo.typing import CameraName
8
+ from mujoco_mojo.utils.log import get_logger
9
+ from mujoco_mojo.visualization import ArrowConfig, LineConfig
10
+
11
+ if TYPE_CHECKING:
12
+ from mujoco_mojo.runtime.runtime_manager import RuntimeManager
13
+
14
+ logger = get_logger(__name__)
15
+
16
+
17
+ @dataclass
18
+ class VideoRecorder:
19
+ """
20
+ Records a MuJoCo simulation to a video file.
21
+
22
+ Frames are captured at a fixed rate (`fps`) relative to simulation time, not wall-clock time, so the output plays back at the exact rate specified regardless of how fast the simulation runs. The recorder skips `capture_frame` calls that fall between the interval boundaries, which prevents duplicate frames when the physics step is finer than 1/fps.
23
+
24
+ Typical usage inside a runtime function::
25
+
26
+ recorder = VideoRecorder(
27
+ path=model.trial_dir / "camera.mp4",
28
+ camera_name="top_view",
29
+ fps=30,
30
+ width=1280,
31
+ height=720,
32
+ ).setup(mj_model).register_to_rm(runtime_manager)
33
+
34
+ `register_to_rm` wires the recorder into the `RuntimeManager` so that `capture_frame` is called automatically on every physics step and `save` is called when the simulation finishes.
35
+
36
+ Supported output formats (determined by the `path` extension):
37
+
38
+ - `.mp4`: H.264 via mediapy/ffmpeg; widest browser and player compatibility.
39
+ - `.webm`: VP9 via ffmpeg; smaller files, fully seekable in the Dojo viewer. Requires ffmpeg with libvpx-vp9 support.
40
+ - `.gif`: via PIL; no audio, loops automatically; large file size, not seekable.
41
+
42
+ Visual overlays (contact forces, net forces, custom arrows/lines) are controlled by the `show_*` flags and the `show_loads` flag passed to `capture_frame`.
43
+ """
44
+
45
+ path: Path
46
+ """Output file path. The extension determines the container and codec."""
47
+
48
+ camera_name: CameraName
49
+ """Name of the MuJoCo camera to render from (must exist in the model)."""
50
+
51
+ show_loads: bool = False
52
+ """Whether to render custom arrow overlays (passed via `custom_arrows` in `capture_frame`)."""
53
+
54
+ show_net_force: bool = False
55
+ """Whether to render net force visualizations (`mjVIS_PERTFORCE`)."""
56
+
57
+ show_contacts: bool = False
58
+ """Whether to render contact force visualizations (`mjVIS_CONTACTFORCE`)."""
59
+
60
+ show_proximities: bool = False
61
+ """Whether to render custom line overlays (passed via `custom_lines` in `capture_frame`)."""
62
+
63
+ fps: int = 30
64
+ """Target frame rate of the output video. Frames are sampled every `1/fps` seconds of simulation time."""
65
+
66
+ width: int = 640
67
+ """Render width in pixels."""
68
+
69
+ height: int = 480
70
+ """Render height in pixels."""
71
+
72
+ _frames: list = field(default_factory=list)
73
+ _renderer: mujoco.Renderer = field(init=False)
74
+ _vopt: mujoco.MjvOption = field(default_factory=mujoco.MjvOption, init=False)
75
+ _next_record_time: float = field(default=0.0, init=False)
76
+
77
+ def setup(self, mj_model: mujoco.MjModel) -> Self:
78
+ """Initializes the MuJoCo renderer for this model. Must be called before the simulation loop."""
79
+ try:
80
+ self._renderer = mujoco.Renderer(
81
+ model=mj_model, height=self.height, width=self.width
82
+ )
83
+ except Exception as e:
84
+ msg = "Failed to initialize the MuJoCo Renderer. If on a server, try setting 'export MUJOCO_GL=egl' in your terminal."
85
+ logger.error(msg)
86
+ raise RuntimeError(msg) from e
87
+
88
+ # initialize the vopt with defaults
89
+ mujoco.mjv_defaultOption(self._vopt)
90
+
91
+ # whether or not to show debug graphics
92
+ self._vopt.flags[mujoco.mjtVisFlag.mjVIS_PERTFORCE] = int(self.show_net_force)
93
+ self._vopt.flags[mujoco.mjtVisFlag.mjVIS_CONTACTFORCE] = int(self.show_contacts)
94
+ return self
95
+
96
+ def capture_frame(
97
+ self,
98
+ mj_model: mujoco.MjModel,
99
+ mj_data: mujoco.MjData,
100
+ custom_arrows: list[ArrowConfig],
101
+ custom_lines: list[LineConfig],
102
+ ):
103
+ """Captures the current state as a video frame."""
104
+ if mj_data.time < self._next_record_time:
105
+ return
106
+
107
+ # update standard mujoco objects in scene
108
+ self._renderer.update_scene(
109
+ data=mj_data,
110
+ camera=self.camera_name,
111
+ scene_option=self._vopt,
112
+ )
113
+
114
+ if custom_arrows and self.show_loads:
115
+ for arrow in custom_arrows:
116
+ arrow.draw_in_scene(mj_model, self._renderer.scene)
117
+
118
+ if custom_lines and self.show_proximities:
119
+ for line in custom_lines:
120
+ line.draw_in_scene(self._renderer.scene)
121
+
122
+ # capture and increment the clock for the next frame
123
+ self._frames.append(self._renderer.render())
124
+ self._next_record_time += 1 / self.fps
125
+
126
+ def save(self):
127
+ """
128
+ Writes the captured frames to a video file.
129
+
130
+ Supported formats:
131
+ - `.mp4` — H.264 via mediapy/ffmpeg; universally compatible.
132
+ - `.webm` — VP9 via mediapy/ffmpeg; smaller files and fully seekable.
133
+ - `.gif` — via PIL; no audio, loops automatically, large file size, not seekable.
134
+
135
+ The output format is determined by the extension of `path`.
136
+ """
137
+ if not self._frames:
138
+ return
139
+ import mediapy as media
140
+
141
+ if self.path.suffix.lower() == ".gif":
142
+ from PIL import Image
143
+
144
+ # convert arrays to PIL images
145
+ pil_images = [Image.fromarray(frame) for frame in self._frames]
146
+
147
+ # save gif
148
+ pil_images[0].save(
149
+ self.path,
150
+ save_all=True,
151
+ append_images=pil_images[1:],
152
+ duration=int(1000 / self.fps), # ms per frame
153
+ loop=0, # loop forever
154
+ )
155
+ elif self.path.suffix.lower() == ".webm":
156
+ self._save_webm()
157
+ else:
158
+ media.write_video(path=self.path, images=self._frames, fps=self.fps)
159
+ logger.info(f"Video saved to {self.path}")
160
+
161
+ def _save_webm(self) -> None:
162
+ """Encodes frames to VP9 WebM by piping raw RGB directly to ffmpeg (no intermediate file)."""
163
+ import subprocess
164
+
165
+ h_raw, w_raw = self._frames[0].shape[:2]
166
+ # yuv420p requires even dimensions
167
+ w = w_raw - (w_raw % 2)
168
+ h = h_raw - (h_raw % 2)
169
+
170
+ proc = subprocess.Popen(
171
+ [
172
+ "ffmpeg",
173
+ "-y",
174
+ "-f",
175
+ "rawvideo",
176
+ "-vcodec",
177
+ "rawvideo",
178
+ "-s",
179
+ f"{w}x{h}",
180
+ "-pix_fmt",
181
+ "rgb24",
182
+ "-r",
183
+ str(self.fps),
184
+ "-i",
185
+ "pipe:0",
186
+ "-c:v",
187
+ "libvpx-vp9",
188
+ "-b:v",
189
+ "0",
190
+ "-crf",
191
+ "33",
192
+ "-cpu-used",
193
+ "2", # 0=slowest/best ... 8=fastest/worst; 4 is a good balance
194
+ "-row-mt",
195
+ "1", # row-based multithreading
196
+ "-threads",
197
+ "0", # use all available cores
198
+ "-an",
199
+ "-pix_fmt",
200
+ "yuv420p",
201
+ str(self.path),
202
+ ],
203
+ stdin=subprocess.PIPE,
204
+ stderr=subprocess.DEVNULL,
205
+ )
206
+ try:
207
+ assert proc.stdin is not None
208
+ for frame in self._frames:
209
+ proc.stdin.write(frame[:h, :w].tobytes())
210
+ proc.stdin.close()
211
+ if proc.wait() != 0:
212
+ raise RuntimeError(
213
+ f"ffmpeg exited with a non-zero status while encoding {self.path}"
214
+ )
215
+ except Exception:
216
+ proc.kill()
217
+ raise
218
+
219
+ def register_to_rm(self, runtime_manager: "RuntimeManager") -> Self:
220
+ runtime_manager.add_video_recorder(self)
221
+ return self
@@ -0,0 +1,70 @@
1
+ """Global user settings for mujoco_mojo, persisted to ~/.mujoco-mojo/settings.toml."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import tomli_w
6
+ from pydantic import BaseModel, Field, SecretStr, field_serializer
7
+ from pydantic_settings import (
8
+ BaseSettings,
9
+ PydanticBaseSettingsSource,
10
+ SettingsConfigDict,
11
+ TomlConfigSettingsSource,
12
+ )
13
+
14
+ from mujoco_mojo.meta import MUJOCO_MOJO_DIR
15
+
16
+ SETTINGS_DIR = MUJOCO_MOJO_DIR
17
+ SETTINGS_FILE = SETTINGS_DIR / "settings.toml"
18
+
19
+
20
+ class SensAISettings(BaseModel):
21
+ """Settings for the SensAI assistant embedded in the Dojo dashboard."""
22
+
23
+ model_name: str = Field(default="qwen2.5:0.5b")
24
+ """Ollama model identifier (e.g. `qwen2.5:0.5b`, `llama3.2:3b`)."""
25
+
26
+ base_url: str = Field(default="http://localhost:11434/v1")
27
+ """Base URL for the OpenAI-compatible endpoint. Defaults to local Ollama."""
28
+
29
+ api_key: SecretStr = Field(default=SecretStr("ollama"))
30
+ """API key sent with each request. For real keys prefer the `MUJOCO_MOJO_SENSAI__API_KEY` env var over storing here. Ollama ignores the value but the client requires a non-empty string."""
31
+
32
+ enabled: bool = Field(default=False)
33
+ """Whether SensAI is active. Opt-in; toggled from the dashboard."""
34
+
35
+ @field_serializer("api_key")
36
+ def _serialize_api_key(self, v: SecretStr) -> str:
37
+ return v.get_secret_value()
38
+
39
+
40
+ class MujocoMojoSettings(BaseSettings):
41
+ """
42
+ Global user-level settings persisted to ~/.mujoco-mojo/settings.toml.
43
+
44
+ Instantiate to load. Sources are checked in priority order: constructor kwargs > environment variables > TOML file > defaults. Environment variables use the prefix `MUJOCO_MOJO_` with `__` as the nested delimiter, e.g. `MUJOCO_MOJO_SENSAI__MODEL_NAME=llama3.2:3b`.
45
+ """
46
+
47
+ model_config = SettingsConfigDict(
48
+ toml_file=SETTINGS_FILE,
49
+ env_prefix="MUJOCO_MOJO_",
50
+ env_nested_delimiter="__",
51
+ )
52
+
53
+ sensai: SensAISettings = Field(default_factory=SensAISettings)
54
+ """Settings for the SensAI assistant."""
55
+
56
+ @classmethod
57
+ def settings_customise_sources(
58
+ cls,
59
+ settings_cls: type[BaseSettings],
60
+ init_settings: PydanticBaseSettingsSource,
61
+ env_settings: PydanticBaseSettingsSource,
62
+ dotenv_settings: PydanticBaseSettingsSource,
63
+ file_secret_settings: PydanticBaseSettingsSource,
64
+ ) -> tuple[PydanticBaseSettingsSource, ...]:
65
+ return (init_settings, env_settings, TomlConfigSettingsSource(settings_cls))
66
+
67
+ def save(self) -> None:
68
+ """Persist current settings to ~/.mujoco-mojo/settings.toml."""
69
+ SETTINGS_DIR.mkdir(parents=True, exist_ok=True)
70
+ SETTINGS_FILE.write_bytes(tomli_w.dumps(self.model_dump()).encode())
@@ -309,6 +309,7 @@ class SignalCategory(StrEnum):
309
309
  DEFORMABLES = "Deformables"
310
310
  PROXIMITIES = "Proximities"
311
311
  CUSTOM = "Custom"
312
+ LAB = "Lab"
312
313
 
313
314
 
314
315
  class EulerSeq(StrEnum):
@@ -104,9 +104,16 @@ else:
104
104
 
105
105
 
106
106
  class ColumnManifest(TypedDict):
107
+ """Manifest of all columns available for plotting."""
108
+
107
109
  all: list[str]
110
+ """Manifest of all columns available for plotting."""
111
+
108
112
  rotatable_vectors: list[str]
113
+ """All columns in self.all which are available be rotated using self.available_quats."""
114
+
109
115
  available_quats: list[str]
116
+ """All quaternion names which have enough information to rotate self.rotateable_vectors."""
110
117
 
111
118
 
112
119
  class MojoNamespace: