139a5b6494
PiperOrigin-RevId: 838701951 Change-Id: I339eafd35d919710cb47bb04e9a8e29f92739513
214 lines
9.3 KiB
Markdown
214 lines
9.3 KiB
Markdown
# MuJoCo JavaScript Bindings
|
||
|
||
These are the canonical JavaScript and TypeScript bindings for the MuJoCo
|
||
physics engine.
|
||
|
||
This package provides a high-level API that allows you to interact with the core
|
||
MuJoCo engine compiled into a high-performance WebAssembly (WASM) module. These
|
||
bindings are developed and maintained by Google DeepMind and are always up to
|
||
date with the latest developments in MuJoCo. For brevity, the documentation
|
||
below will often refer to “JavaScript” but the concepts apply equally to
|
||
TypeScript.
|
||
|
||
> [!IMPORTANT]
|
||
> _These bindings are still a WIP. For details, see the [Future Work](#future-work)
|
||
> section. Also note that development has primarily taken place on Linux using
|
||
> Google Chrome. If you're working on a different OS or browser, you may
|
||
> encounter some rough edges. We have successfully tested the bindings on MacOS
|
||
> in CI but as of November 13th 2025 Windows in untested (the instructions here
|
||
> have worked on one Windows 11 machine but have failed on other machines)._
|
||
|
||
## Prerequisites
|
||
|
||
> [!NOTE]
|
||
> Run all the commands in this README from the top-level directory.
|
||
|
||
- To compile the [`bindings.cc`](codegen/generated/bindings.cc) file, which
|
||
generates the `.wasm` WebAssembly file, `.js` JavaScript import, and `.d.ts`
|
||
TypeScript declaration file, you will need Emscripten SDK version `4.0.10`.
|
||
Later versions may work but are untested. To set up the SDK, do the
|
||
following, you can run this anywhere but the rest of the commands in this
|
||
README only work in the shell where you source the `emsdk_env.sh` script.
|
||
|
||
```sh
|
||
git clone https://github.com/emscripten-core/emsdk.git
|
||
./emsdk/emsdk install 4.0.10
|
||
./emsdk/emsdk activate 4.0.10
|
||
source ./emsdk/emsdk_env.sh
|
||
```
|
||
|
||
- To easily run the JavaScript tests and the demo application, `node` and `npm`
|
||
are required. We recommend managing these using
|
||
[nvm](https://github.com/nvm-sh/nvm). There are also various JavaScript
|
||
dependencies needed for the tests, demo, and bindings build process. These
|
||
dependencies are expected to be located in the `wasm` folder. To install
|
||
them and ensure they can be found by later commands, run the following:
|
||
|
||
```sh
|
||
npm install --prefix ./wasm
|
||
export PATH="$(pwd)/wasm/node_modules/.bin:$PATH"
|
||
```
|
||
|
||
- To modify the bindings `python3` is required because the [`bindings.cc`](codegen/generated/bindings.cc)
|
||
file is generated by a Python script. To run the bindings generator tests,
|
||
`absl` is required and `pytest` will be helpful. Set up a Python environment
|
||
with these dependencies as follows:
|
||
|
||
```sh
|
||
python3 -m venv .venv
|
||
source .venv/bin/activate
|
||
pip install -r python/build_requirements.txt
|
||
```
|
||
|
||
> [!TIP]
|
||
> _Emscripten is well-documented. We recommend reading the sections covering the
|
||
> [Emscripten Compiler Settings](https://emscripten.org/docs/tools_reference/settings_reference.html),
|
||
> the [Emscripten SDK](https://emscripten.org/docs/tools_reference/emsdk.html),
|
||
> and the [Embind](https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html)
|
||
> library. To understand the limitations and caveats related to using the
|
||
> browser as a platform, see the
|
||
> [Porting](https://emscripten.org/docs/porting/index.html#porting) section._
|
||
|
||
## User Guide
|
||
|
||
### Bindings Generation
|
||
|
||
The [`bindings.cc`](codegen/generated/bindings.cc) file is compiled to generate
|
||
to `.wasm` WebAssembly file, `.js` JavaScript import, and `.d.ts` TypeScript
|
||
declaration file. These are the files you'll use to call MuJoCo from JavaScript.
|
||
To generate them ensure the npm and Emscripten SDK prerequisites are set up and
|
||
then run the following:
|
||
|
||
```sh
|
||
emcmake cmake -B build && cmake --build build
|
||
```
|
||
|
||
This command will generate the following folders under the project root:
|
||
|
||
- `build`: contains MuJoCo compiled using Emscripten.
|
||
- `wasm/dist`: contains the WebAssembly module, `.js` and `.d.ts` files.
|
||
|
||
### Example Application
|
||
|
||
After generating the bindings you will be ready to write web applications using
|
||
MuJoCo. We have provided a basic web application that uses Three.js to render a
|
||
simple simulation, to try it run this command:
|
||
|
||
```sh
|
||
npm run dev:demo --prefix ./wasm
|
||
```
|
||
|
||
You may prefer to write your entire app in C++ and compile it using Emscripten.
|
||
If you do this, you won’t need to use these bindings, since you’ll be writing
|
||
minimal JavaScript, and the granularity of these bindings may be inappropriate
|
||
(e.g., you might want to call multiple MuJoCo functions in the C++ callback
|
||
invoked by `requestAnimationFrame`).
|
||
|
||
We have also found that a hybrid approach can be helpful, as it is often more
|
||
convenient to work with browser APIs directly in JavaScript. If you choose to
|
||
write your application in C++ and compile it using Emscripten, you may want to
|
||
copy a subset of the `EMSCRIPTEN_BINDINGS` from `bindings.cc` into your
|
||
application’s source file.
|
||
|
||
## Development
|
||
|
||
In order to change the bindings you will need to change the [`bindings.cc`](codegen/generated/bindings.cc)
|
||
file but this should not be done manually. The file is generated using the
|
||
Python scripts and template files in the [`codegen`](codegen) folder, to edit
|
||
the bindings you will need to change those files and re-generate [`bindings.cc`](codegen/generated/bindings.cc)
|
||
using this command:
|
||
|
||
```sh
|
||
PYTHONPATH=python/mujoco python3 -m wasm.codegen.update
|
||
```
|
||
|
||
The codegen scripts use MuJoCo’s Python introspect library to generate the
|
||
Embind `EMSCRIPTEN_BINDINGS` block that binds C++ functions and classes to
|
||
JavaScript. The functions and classes that are bound are wrappers around
|
||
MuJoCo's C API. These wrappers provide a convenient place to add features like
|
||
bounds checking and nice error reporting.
|
||
|
||
### Testing
|
||
|
||
1. **JavaScript API tests.**
|
||
These verify that a wide variety of MuJoCo functions and classes work
|
||
correctly when called from JavaScript. Run the tests as follows:
|
||
|
||
```sh
|
||
npm run test --prefix ./wasm
|
||
```
|
||
|
||
2. **JavaScript API benchmark tests.**
|
||
The current benchmark tests check JavaScript/C++ shared memory buffers
|
||
performance. We will increase the coverage of the benchmarks overtime. Run
|
||
the benchmarks using this command:
|
||
|
||
```sh
|
||
npm run benchmark --prefix ./wasm
|
||
```
|
||
|
||
3. **Bindings generator tests.**
|
||
These are relevant when developing or extending the bindings. The following
|
||
command finds and runs all `test_*.py` or `*_test.py` files in the `wasm`
|
||
folder:
|
||
|
||
```sh
|
||
PYTHONPATH=python/mujoco python3 -m pytest ./wasm
|
||
```
|
||
|
||
### Debugging
|
||
|
||
We provide a “sandbox” app where you can quickly write code to run in your
|
||
browser. Write your code in the [`main.ts`](tests/sandbox/main.ts) file and use
|
||
the following command to execute it in your browser:
|
||
|
||
```sh
|
||
npm run dev:sandbox --prefix ./wasm
|
||
```
|
||
|
||
The page will be blank since the script only logs to the console output. You
|
||
can add your code at the indicated placeholder and use Chrome DevTools for
|
||
debugging. It is possible to set up a debug workflow where stack traces and
|
||
stepping through code across language boundaries work correctly. Our current
|
||
method to do this only works internally at Google, but it should be possible to
|
||
replicate the experience with open-source tooling — community suggestions are
|
||
welcome!
|
||
|
||
## Future Work
|
||
|
||
1. **Bind all useful APIs.**
|
||
These bindings are not yet complete. While the main MuJoCo APIs (`mj_step`,
|
||
`mj_loadXML`, etc.) are well tested, other APIs (e.g., functions from
|
||
`mjspec.h`) remain untested in real web applications (though test code for
|
||
the `mjspec` bindings does exist). One notable feature not yet supported in
|
||
the WASM bindings, which has proved very useful in the Python bindings, is
|
||
named access methods — where data distributed across multiple arrays in C can
|
||
be conveniently accessed by name, e.g., `model.geom('mygeom')` or
|
||
`data.joint('myjoint')`. Currently, this data must be accessed via the
|
||
`mj_name2id` function. Adding support for these features is a high priority,
|
||
as it affects user code written in JavaScript.
|
||
|
||
2. **Improve the developer experience.**
|
||
There is still work to be done to improve the developer experience when
|
||
developing the WASM bindings. The most obvious issue is that bindings
|
||
generation is not yet fully automated. As a result, it is currently less
|
||
convenient than we'd like to identify and apply the changes needed to update
|
||
the bindings. The goal is to eventually automate all binding code generation
|
||
and clearly communicate what changes are required in the WASM bindings as a
|
||
result of C++ updates. This problem should only affect developers working on
|
||
the MuJoCo engine in C++, not end users writing JavaScript.
|
||
|
||
3. **Improve the documentation.**
|
||
The documentation in this README will eventually be merged into the main
|
||
MuJoCo documentation once the bindings are complete and named access is
|
||
implemented. We also intend to review the bindings APIs and make adjustments
|
||
to minimize differences with the Python bindings (while respecting language
|
||
idioms) to reduce the amount of additional documentation required.
|
||
|
||
4. **Improve the [example](#example-application).**
|
||
We aim to provide an example application that can be easily modified and
|
||
embedded into a paper project page (see [this example](https://kzakka.com/robopianist/)).
|
||
This could be achieved by extending the Three.js example or by compiling the
|
||
MuJoCo platform C++ code using the Emscripten toolchain. Community
|
||
suggestions and contributions are welcome!
|