Getting Started

The project enable3d offers 4 different ways. As a Standalone 3D Framework, a Physics Plugin for three.js, as a 3D Objects and Physics extension for Phaser or as a library to run Ammo.js on Node.js

In this guide, you will learn how to use the Standalone 3D Framework. Most of what you learn, will be applicable to all packages. Just take a look at the examples to see what Enable3d can do and how to use the different packages.

Note: Not everything is documented yet, the examples page helps a lot!

Basic Setup

// import the UMD bundle enable3d.framework.min.js
// or from npm enable3d
import { Project, Scene3D, PhysicsLoader } from 'enable3d'

class MainScene extends Scene3D {
  constructor() {

  async init() {
    this.renderer.setSize(window.innerWidth, window.innerHeight)

  async preload() {
    // preload your assets here

  async create() {
    // set up scene (light, ground, grid, sky, orbitControls)

    // enable physics debug

    // position camera, 10, 20)

    // blue box (without physics){ y: 2 }, { lambert: { color: 'deepskyblue' } })

    // pink box (with physics){ y: 10 }, { lambert: { color: 'hotpink' } })

  update() { += 0.01 += 0.01

// set your project configs
const config = { scenes: [MainScene] }

// load the ammo.js file from the /lib folder and start the project
PhysicsLoader('/lib', () => new Project(config))

Native Three.js Objects

You can use native Three.js objects if you include THREE

import { THREE } from 'enable3d'

// green sphere
const geometry = new THREE.SphereGeometry(0.8, 16, 16)
const material = new THREE.MeshLambertMaterial({ color: 0x00ff00 })
const cube = new THREE.Mesh(geometry, material)
cube.position.set(0.2, 3, 0)
// add physics to an existing object

Extended Three.js Objects

To have more functionalities and a better compatibility, use new ExtendedMesh() and new ExtendedObject3D() instead of new THREE.Mesh() and new THREE.Object3D()

import { THREE, ExtendedMesh, ExtendedObject3D } from 'enable3d'

const cube = new THREE.Mesh(geometry, material)
// instead of
const cube = new ExtendedMesh(geometry, material)

const object = new ExtendedObject3D()
// instead of
const object = new THREE.Object3D()

Warp Speed

Not documented yet.


Enable3d provides a simple factory for creating physical objects.

// will add a 5x3x1 red box
const box =
  { x: 1, y: 2, z: 10, width: 5, height: 3, depth: 1, mass: 2, collisionFlags: 0 },
  { lambert: { color: 'red', transparent: true, opacity: 0.5 } }

If you want to use the factory without adding physics to the object, extract the factory from physics.

// get the objects factory
const { factory } = physics

// add the same box as above, but without physics
const box ={ x: 1, y: 2, z: 10, width: 5, height: 3, depth: 1 }, { lambert: { color: 'red', transparent: true, opacity: 0.5 } })

// you can later add physics to it
physics.add.existing(box, { mass: 2, collisionFlags: 0 })

You can also add custom materials like so:{}, { custom: THREE.MeshLambertMaterial({ color: 0x2194ce }) })

Basic Shapes

Enable3d supports these shapes:

  • Plane
  • Box
  • Sphere
  • Cylinder
  • Cone
  • Capsule
  • Compound
  • Hull
  • HACD (Hierarchical Approximate Convex Decomposition)
  • ConvexMesh
  • ConcaveMesh
  • Heightfield (not yet)

Enable3d does automatically recognize the shape of simple three.js object when adding it via physics.add.existing(object). But you can also change the shape like so physics.add.existing(object, { shape: 'hacd' })

Take a look at the compare-physics-body-shapes and the play-with-physics-bodies examples to see creating & adding shapes in action.

Compound shapes

There are 3 ways to use compound shapes. Automatically generated (child or group) and manually generated. The automatically generated follow three.js objects structure. To manually generate a compound shape, simply add multiple shapes to the second parameter of physics.add.existing()


// example:

// compound shape (child based)
// (the center of mass is the center of the box)
let box1 ={ x: 0, y: 2 })
let sphere3 = this.add.sphere({ radius: 0.5, x: 0.25, y: 0.5 }) // relative position to box1

// compound shape (group based)
// (the center of mass is 0,0,0)
let group = new THREE.Group()
const body ={ height: 0.8, y: 1, width: 0.4, depth: 0.4 }, { lambert: { color: 0xffff00 } })
const head = this.add.sphere({ radius: 0.25, y: 1.7, z: 0.05 }, { lambert: { color: 0xffff00 } })
group.add(body, head)


// example:

// custom compound shape
const box ={ x: 9 })
const compound = [
  { shape: 'box', width: 0.5, height: 1, depth: 0.4, y: -0.5, z: 0.5 },
  { shape: 'box', width: 2.4, height: 0.6, depth: 0.4, z: -0.4, y: 0.2 },
  { shape: 'sphere', radius: 0.65, z: -0.25, y: 0.35 },
  { shape: 'box', width: 1.5, height: 0.8, depth: 1, y: 0.2, z: 0.2 }
this.physics.add.existing(box, { compound })

Physics Body

Body Types

There are 4 different body types you can choose from by setting object.body.setCollisionFlags(number) accordingly.

  • 0 - Dynamic
  • 1 - Static
  • 2 - Kinematic
  • 4 - Ghost (aka Sensor or NO_CONTACT_RESPONSE).


The dynamic bodies react to force and gravity and you can apply velocity and torque to them.

// example:

jump() {


These object are just there but do not move at all.


These bodies do NOT react to force or gravity. You can only move them by adjusting its position or rotation.

// example:

update() {
  kinematicObject.rotation.x =+ 0.01
  // set needUpdate to true, every time you want
  // to adjust the position or rotation of a kinematic body
  kinematicObject.body.needUpdate = true


These bodies do never interact with other bodies. But they fire collision events. Use them as sensory in your game. Ghost can be dynamic (4), static (5) or kinematic (6), by settings the collisionFlags accordingly.

Body Methods

You can use a lot of method on the body (object.body.something()). It does not make send listing them all here.

Just take a look the the physicsBody.ts source code.

Physics Configuration

When we add Enable3d to the scene, there are a few choices we can make.

new Project({ gravity: { x: 0, y: -9.81, z: 0 }, maxSubSteps: 4, fixedTimeStep: 1 / 60 })
  • gravity default { x: 0, y: -9.81, z: 0 } Sets the amount and direction of gravitational forces

  • maxSubSteps default 2 Set the max sub steps allowed.

  • fixedTimeStep default 1 / 60 This number determines how much time one simulation step is to simulate. The smaller the number, the more accurate (and slower) the simulation.

You must always satisfy the equation timeStep(fps) < maxSubSteps * fixedTimeStep

Position, Rotation and Scale


You can only set the position (and rotation) at any moment if it the body is of type kinematic. See Body Types. For all other types, you have to set the position and the rotation before you add a physics body to it.

Example of a non kinematic box:

const { factory } = physics

// add a box without physics
const box =
// set position and rotation
box.position.set(10, 10, 0)
box.rotation.set(0, Math.PI / 2, 0)
// add physics to the box

But if you really need to set a new position or rotation to any other type than kinematic, see the Teleport Example.


Same as Position.


You can't scale a physics body after added to the world. But you can scale your object before adding physics to it or remove the physics body and add a new one.

Example of a Torus:

const { factory } = physics

// add torus (without physics)
let torus = factory.add.torus()
// scale the torus
torus.scale.set(2, 2, 2)
// add a rigid body to it
physics.add.existing(torus, { shape: 'hacd' })

// add torus (with physics)
let torus = physics.add.torus()
// remove the rigid body
// scale the torus
torus.scale.set(2, 2, 2)
// add a new rigid body to it
physics.add.existing(torus, { shape: 'hacd' })


You can check all collisions on a single body or check for collision between 2 specific bodies. The event will be start, colliding or end.

// all collision for blueBox
blueBox.body.on.collision((otherObject, event) => {
  if ( !== 'ground') {
    console.log('blueBox collided with another object than the ground')
// collision between blueBox and redBox
physics.add.collider(blueBox, redBox, event => {
  console.log(`blueBox and redBox: ${event}`)

See the collisions example for details on implementing and using this event.

Motion Clamping

When an object has a high velocity, collisions can be missed if it moves through and past other objects between simulation steps. To fix this, enable CCD motion clamping. For a cube of size 1 try:

// Enable CCD if the object moves more than 1 meter in one simulation frame

// Set the radius of the embedded sphere such that it is smaller than the object


The following constraints are available, but I have not yet written the documentation.

  • Lock
  • Fixed
  • Spring
  • Slider
  • Hinge
  • Cone Twist
  • Point To Point

You will find an example of all constraints here.


Not documented yet.


Not documented yet.


Want to use Tweens? Checkout


Not documented yet.







Not documented yet.

Objects Raycasting

Physics Raycasting


Not documented yet.

Virtual Reality

Augmented Reality


Not documented yet.