How to Expose C++ Bullet Classes to Ammo.js

This article explains how to expose missing C++ Bullet Physics classes to ammo.js, the direct port of the Bullet engine to JavaScript using Emscripten. You will learn how to locate the WebIDL definition file, define missing C++ classes and methods, and rebuild the library to generate the updated JavaScript bindings.

Ammo.js relies on Emscripten’s WebIDL Binder to bridge the gap between C++ and JavaScript. To expose a missing Bullet class, you must modify the interface definition and recompile the project.

Step 1: Locate and Modify the IDL File

The WebIDL definitions are stored in a file named ammo.idl in the root of the ammo.js repository. Open this file in a text editor.

To expose a missing C++ class, you must define its interface inside ammo.idl. For example, if you want to expose a Bullet class named btCustomConstraint, you would add its definition using WebIDL syntax:

interface btCustomConstraint {
  void btCustomConstraint(btRigidBody rbA, btRigidBody rbB);
  void setParam(long num, float value);
  float getParam(long num);
};

Ensure that any types used in the constructor or method arguments (such as btRigidBody) are also defined elsewhere in the IDL file.

Step 2: Handle Inheritance

If the class inherits from another Bullet class, you must declare the inheritance in the IDL file so that JavaScript respects the prototype chain:

interface btCustomConstraint : btTypedConstraint {
  // Class members here
};

Specifying the parent class (like btTypedConstraint) allows JavaScript to call inherited methods on your new class.

Step 3: Run the Build Script

Once the ammo.idl file is updated, you need to regenerate the glue code and compile the WebAssembly and JavaScript files.

  1. Ensure you have the Emscripten SDK (emsdk) installed and activated in your terminal environment.
  2. Navigate to the root directory of your cloned ammo.js repository.
  3. Run the build script using Python:
python make.py

This script automatically runs Emscripten’s WebIDL binder to generate the C++ and JavaScript wrapper files, and then compiles the source code into the final output builds.

Step 4: Verify the New Class in JavaScript

After a successful build, the output files (typically located in the builds/ folder) will contain your new bindings. You can now instantiate and use the class in JavaScript:

Ammo().then(function(Ammo) {
  const rbA = new Ammo.btRigidBody(...);
  const rbB = new Ammo.btRigidBody(...);
  
  // Instantiating the newly exposed class
  const constraint = new Ammo.btCustomConstraint(rbA, rbB);
  constraint.setParam(0, 1.5);
});