Skip to content

@aosengine/physics-jolt

Interfaces

BodyArgs

Everything needed to create one body. Mirrors the WIT add-body command, minus the entity handle, which the host module owns.

Properties

angularDamping?
ts
optional angularDamping?: number;

Angular velocity damping per second. Defaults to 0.05.

dims
ts
dims: readonly number[];

Shape dimensions, in metres: box half-extents [hx, hy, hz]; sphere [radius]; capsule and cylinder [radius, halfHeight]. Ignored for mesh and convex.

flags?
ts
optional flags?: BodyFlags;

Optional switches.

friction
ts
friction: number;

Coulomb friction, 0..1.

geometry?
ts
optional geometry?: Shape;

Prebuilt shape for mesh and convex bodies, from meshShapeFromGeometry or convexHullFromPoints. The world takes its own reference, so one shape can back many bodies.

id
ts
id: number;

Guest-minted handle. Must not already exist in this world.

kind
ts
kind: BodyKind;

Body class.

layer
ts
layer: number;

What this body is, as a bitset.

linearDamping?
ts
optional linearDamping?: number;

Linear velocity damping per second. Defaults to 0.05, Jolt's own default.

mask
ts
mask: number;

What this body collides with, as a bitset of other bodies' layers.

mass
ts
mass: number;

Kilograms. Ignored for static, kinematic and character bodies.

position
ts
position: Vec3;

World-space position of the body origin.

restitution
ts
restitution: number;

Bounciness, 0..1.

rotation
ts
rotation: Quat;

World-space orientation, xyzw.

shape
ts
shape: ShapeKind;

Shape family. mesh and convex additionally need BodyArgs.geometry.


BodyFlags

Per-body switches. Mirrors WIT body-flags.

Properties

ccd?
ts
optional ccd?: boolean;

Use continuous collision detection (linear cast).

lockRotation?
ts
optional lockRotation?: boolean;

Lock all rotation. The usual choice for a capsule.

noSleep?
ts
optional noSleep?: boolean;

Never let the solver put this body to sleep.

reportContacts?
ts
optional reportContacts?: boolean;

Emit this body's contacts from PhysicsWorld.drainContacts.

sensor?
ts
optional sensor?: boolean;

Trigger volume: generates contacts but no collision response.


ContactRecord

One contact event. Instances are pooled by the world and by the caller's out array; copy anything you want to keep past the next drainContacts.

Properties

a
ts
a: number;

Guest body id of the first body.

b
ts
b: number;

Guest body id of the second body.

impulse
ts
impulse: number;

Estimated normal impulse, newton-seconds. Jolt does not hand the solved impulse to a contact listener, so this is reduced mass * closing speed measured before the solve: right in order of magnitude, good enough to scale an impact sound, not a physical measurement.

nx
ts
nx: number;

Contact normal pointing from a towards b, x. Zero for end.

ny
ts
ny: number;

Contact normal, y.

nz
ts
nz: number;

Contact normal, z.

phase
ts
phase: ContactPhase;

Whether the contact started, continued or ended.

px
ts
px: number;

World-space contact point, x. Zero for end.

py
ts
py: number;

World-space contact point, y. Zero for end.

pz
ts
pz: number;

World-space contact point, z. Zero for end.


ConvexHullOptions

Options for convexHullFromPoints.

Properties

hullTolerance?
ts
optional hullTolerance?: number;

Distance, in metres, below which the hull builder merges coplanar faces.

maxConvexRadius?
ts
optional maxConvexRadius?: number;

Maximum convex radius used to round the hull off.


LayerOptions

Tuning for the object-layer slot table.

Properties

maxObjectLayers?
ts
optional maxObjectLayers?: number;

How many distinct Jolt object layers the world may hand out. Half of them back static bodies and half back moving bodies, so the default of 64 allows 32 distinct (layer, mask) pairs on each side.


LoadJoltOptions

Options for loadJolt.

Extended by

Properties

wasmUrl?
ts
optional wasmUrl?: string;

Where jolt-physics.wasm.wasm is served from.

Omit it and the loader asks the host for jolt-physics/jolt-physics.wasm.wasm via import.meta.resolve, which is correct under node and under any bundler that keeps an import map. In a plain browser build, pass the URL your bundler minted for the asset:

ts
import wasmUrl from 'jolt-physics/jolt-physics.wasm.wasm?url';

MeshShapeOptions

Options shared by the geometry shape builders.

Properties

maxTrianglesPerLeaf?
ts
optional maxTrianglesPerLeaf?: number;

Triangles per BVH leaf. Higher builds faster and uses less memory, lower queries faster. Jolt's own default is 8.


PhysicsOptions

Options for physics.

Extends

Properties

gravity?
ts
optional gravity?: Vec3;

Gravity in metres per second squared. Defaults to [0, -9.81, 0].

Inherited from

PhysicsWorldOptions.gravity

layers?
ts
optional layers?: LayerOptions;

Object-layer slot tuning. See LayerOptions.

Inherited from

PhysicsWorldOptions.layers

maxBodies?
ts
optional maxBodies?: number;

Hard ceiling on simultaneous bodies. Defaults to 4096.

Inherited from

PhysicsWorldOptions.maxBodies

maxBodyPairs?
ts
optional maxBodyPairs?: number;

Maximum body pairs the broad phase tracks. Defaults to maxBodies * 2.

Inherited from

PhysicsWorldOptions.maxBodyPairs

maxContactConstraints?
ts
optional maxContactConstraints?: number;

Maximum contact constraints per step. Defaults to maxBodies.

Inherited from

PhysicsWorldOptions.maxContactConstraints

substeps?
ts
optional substeps?: number;

Collision steps per fixed step. One is right for a 60 Hz simulation; raise it only if fast bodies tunnel and flags.ccd was not enough.

wasmUrl?
ts
optional wasmUrl?: string;

Where jolt-physics.wasm.wasm is served from.

Omit it and the loader asks the host for jolt-physics/jolt-physics.wasm.wasm via import.meta.resolve, which is correct under node and under any bundler that keeps an import map. In a plain browser build, pass the URL your bundler minted for the asset:

ts
import wasmUrl from 'jolt-physics/jolt-physics.wasm.wasm?url';
Inherited from

LoadJoltOptions.wasmUrl


PhysicsService

The physics service, published by the engine under the id physics.

It is the PhysicsWorld plus the debug view, so engine.get('physics').raycast(...) works directly.

Extends

Properties

bodyCount
ts
readonly bodyCount: number;

Number of bodies currently in the world.

Inherited from

PhysicsWorld.bodyCount

revision
ts
readonly revision: number;

Bumped whenever the set of bodies changes: add, remove or enable/disable. Debug views rebuild their geometry when this moves and not otherwise.

Inherited from

PhysicsWorld.revision

Methods

addBody()
ts
addBody(args): void;

Create a body. See BodyArgs.

Parameters
ParameterType
argsBodyArgs
Returns

void

Inherited from

PhysicsWorld.addBody

applyImpulse()
ts
applyImpulse(
   id, 
   impulse, 
   point?
): void;

Apply an impulse, at the centre of mass unless point says otherwise.

Parameters
ParameterType
idnumber
impulseVec3
point?Vec3
Returns

void

Inherited from

PhysicsWorld.applyImpulse

bodyIds()
ts
bodyIds(): readonly number[];

Snapshot of the live body ids, cheap and non-allocating to iterate.

Returns

readonly number[]

Inherited from

PhysicsWorld.bodyIds

debugWireframe()
ts
debugWireframe(scene): void;

Attach or detach a wireframe debug view.

Pass a scene to attach, null to detach and free the geometry. The line buffer is rebuilt only when the set of bodies changes; the per-frame cost is a transform of the cached corners in update, with no allocation.

Parameters
ParameterTypeDescription
sceneScene<Object3DEventMap> | nullThe scene to draw into, or null to remove the view.
Returns

void

dispose()
ts
dispose(): void;

Free every Jolt object this world owns.

Returns

void

Inherited from

PhysicsWorld.dispose

drainContacts()
ts
drainContacts(out): number;

Move queued contacts into out.

Parameters
ParameterType
outContactRecord[]
Returns

number

Inherited from

PhysicsWorld.drainContacts

groundState()
ts
groundState(id): GroundState;

What a character body is standing on, as of the last step.

Parameters
ParameterType
idnumber
Returns

GroundState

Inherited from

PhysicsWorld.groundState

moveCharacter()
ts
moveCharacter(id, desiredVelocity): void;

Set the desired world-space velocity of a character body for the next step.

Parameters
ParameterType
idnumber
desiredVelocityVec3
Returns

void

Inherited from

PhysicsWorld.moveCharacter

overlapSphere()
ts
overlapSphere(
   center, 
   radius, 
   mask
): number[];

Guest body ids overlapping a sphere, nearest first.

Parameters
ParameterType
centerVec3
radiusnumber
masknumber
Returns

number[]

Inherited from

PhysicsWorld.overlapSphere

overlapSphereInto()
ts
overlapSphereInto(
   center, 
   radius, 
   mask, 
   out
): number;

Zero-allocation form of PhysicsWorld.overlapSphere.

Parameters
ParameterType
centerVec3
radiusnumber
masknumber
outUint32Array
Returns

number

Inherited from

PhysicsWorld.overlapSphereInto

raycast()
ts
raycast(
   origin, 
   direction, 
   maxDistance, 
   mask
): RayHit | null;

Closest hit along a ray, or null. The returned object is reused.

Parameters
ParameterType
originVec3
directionVec3
maxDistancenumber
masknumber
Returns

RayHit | null

Inherited from

PhysicsWorld.raycast

raycastBatch()
ts
raycastBatch(
   rays, 
   mask, 
   out
): number;

Many rays, one call.

Parameters
ParameterType
raysFloat32Array
masknumber
outFloat32Array
Returns

number

Inherited from

PhysicsWorld.raycastBatch

readBodies()
ts
readBodies(out): number;

Write stride-14 body rows into out. See PhysicsWorld.readBodies.

Parameters
ParameterType
outFloat32Array
Returns

number

Inherited from

PhysicsWorld.readBodies

readBodyBounds()
ts
readBodyBounds(
   id, 
   out, 
   offset
): boolean;

Local-space bounds and world transform of a body, for debug drawing.

Parameters
ParameterType
idnumber
outFloat32Array
offsetnumber
Returns

boolean

Inherited from

PhysicsWorld.readBodyBounds

removeBody()
ts
removeBody(id): void;

Destroy a body and release its shape reference. Unknown ids are ignored.

Parameters
ParameterType
idnumber
Returns

void

Inherited from

PhysicsWorld.removeBody

setEnabled()
ts
setEnabled(id, enabled): void;

Take a body out of the simulation without destroying it, or put it back.

Parameters
ParameterType
idnumber
enabledboolean
Returns

void

Inherited from

PhysicsWorld.setEnabled

setTransform()
ts
setTransform(
   id, 
   position, 
   rotation
): void;

Teleport a body. Velocities are left alone; clear them yourself if you meant a hard cut.

Parameters
ParameterType
idnumber
positionVec3
rotationQuat
Returns

void

Inherited from

PhysicsWorld.setTransform

setVelocity()
ts
setVelocity(
   id, 
   linear, 
   angular
): void;

Set linear and angular velocity.

Parameters
ParameterType
idnumber
linearVec3
angularVec3
Returns

void

Inherited from

PhysicsWorld.setVelocity

step()
ts
step(dt, substeps?): number;

Advance the simulation.

Parameters
ParameterType
dtnumber
substeps?number
Returns

number

Inherited from

PhysicsWorld.step


PhysicsWorld

A live Jolt simulation. Everything the engine's physics command stream and synchronous query imports need, and nothing else.

Extended by

Properties

bodyCount
ts
readonly bodyCount: number;

Number of bodies currently in the world.

revision
ts
readonly revision: number;

Bumped whenever the set of bodies changes: add, remove or enable/disable. Debug views rebuild their geometry when this moves and not otherwise.

Methods

addBody()
ts
addBody(args): void;

Create a body. See BodyArgs.

Parameters
ParameterType
argsBodyArgs
Returns

void

applyImpulse()
ts
applyImpulse(
   id, 
   impulse, 
   point?
): void;

Apply an impulse, at the centre of mass unless point says otherwise.

Parameters
ParameterType
idnumber
impulseVec3
point?Vec3
Returns

void

bodyIds()
ts
bodyIds(): readonly number[];

Snapshot of the live body ids, cheap and non-allocating to iterate.

Returns

readonly number[]

dispose()
ts
dispose(): void;

Free every Jolt object this world owns.

Returns

void

drainContacts()
ts
drainContacts(out): number;

Move queued contacts into out.

Parameters
ParameterType
outContactRecord[]
Returns

number

groundState()
ts
groundState(id): GroundState;

What a character body is standing on, as of the last step.

Parameters
ParameterType
idnumber
Returns

GroundState

moveCharacter()
ts
moveCharacter(id, desiredVelocity): void;

Set the desired world-space velocity of a character body for the next step.

Parameters
ParameterType
idnumber
desiredVelocityVec3
Returns

void

overlapSphere()
ts
overlapSphere(
   center, 
   radius, 
   mask
): number[];

Guest body ids overlapping a sphere, nearest first.

Parameters
ParameterType
centerVec3
radiusnumber
masknumber
Returns

number[]

overlapSphereInto()
ts
overlapSphereInto(
   center, 
   radius, 
   mask, 
   out
): number;

Zero-allocation form of PhysicsWorld.overlapSphere.

Parameters
ParameterType
centerVec3
radiusnumber
masknumber
outUint32Array
Returns

number

raycast()
ts
raycast(
   origin, 
   direction, 
   maxDistance, 
   mask
): RayHit | null;

Closest hit along a ray, or null. The returned object is reused.

Parameters
ParameterType
originVec3
directionVec3
maxDistancenumber
masknumber
Returns

RayHit | null

raycastBatch()
ts
raycastBatch(
   rays, 
   mask, 
   out
): number;

Many rays, one call.

Parameters
ParameterType
raysFloat32Array
masknumber
outFloat32Array
Returns

number

readBodies()
ts
readBodies(out): number;

Write stride-14 body rows into out. See PhysicsWorld.readBodies.

Parameters
ParameterType
outFloat32Array
Returns

number

readBodyBounds()
ts
readBodyBounds(
   id, 
   out, 
   offset
): boolean;

Local-space bounds and world transform of a body, for debug drawing.

Parameters
ParameterType
idnumber
outFloat32Array
offsetnumber
Returns

boolean

removeBody()
ts
removeBody(id): void;

Destroy a body and release its shape reference. Unknown ids are ignored.

Parameters
ParameterType
idnumber
Returns

void

setEnabled()
ts
setEnabled(id, enabled): void;

Take a body out of the simulation without destroying it, or put it back.

Parameters
ParameterType
idnumber
enabledboolean
Returns

void

setTransform()
ts
setTransform(
   id, 
   position, 
   rotation
): void;

Teleport a body. Velocities are left alone; clear them yourself if you meant a hard cut.

Parameters
ParameterType
idnumber
positionVec3
rotationQuat
Returns

void

setVelocity()
ts
setVelocity(
   id, 
   linear, 
   angular
): void;

Set linear and angular velocity.

Parameters
ParameterType
idnumber
linearVec3
angularVec3
Returns

void

step()
ts
step(dt, substeps?): number;

Advance the simulation.

Parameters
ParameterType
dtnumber
substeps?number
Returns

number


PhysicsWorldOptions

Options for createPhysicsWorld.

Extended by

Properties

gravity?
ts
optional gravity?: Vec3;

Gravity in metres per second squared. Defaults to [0, -9.81, 0].

layers?
ts
optional layers?: LayerOptions;

Object-layer slot tuning. See LayerOptions.

maxBodies?
ts
optional maxBodies?: number;

Hard ceiling on simultaneous bodies. Defaults to 4096.

maxBodyPairs?
ts
optional maxBodyPairs?: number;

Maximum body pairs the broad phase tracks. Defaults to maxBodies * 2.

maxContactConstraints?
ts
optional maxContactConstraints?: number;

Maximum contact constraints per step. Defaults to maxBodies.


RayHit

One raycast result. The instance returned by raycast is reused.

Properties

body
ts
body: number;

Guest body id that was hit.

distance
ts
distance: number;

Distance from the ray origin, metres.

nx
ts
nx: number;

Surface normal at the hit, x.

ny
ts
ny: number;

Surface normal, y.

nz
ts
nz: number;

Surface normal, z.

px
ts
px: number;

Hit point, x.

py
ts
py: number;

Hit point, y.

pz
ts
pz: number;

Hit point, z.

Type Aliases

BodyKind

ts
type BodyKind = "static" | "dynamic" | "kinematic" | "character";

Body class. Mirrors WIT body-kind, except that WIT spells static as fixed because static is a WIT keyword.


ContactPhase

ts
type ContactPhase = "begin" | "stay" | "end";

Which side of a contact this record describes. Mirrors WIT contact-phase.


GroundState

ts
type GroundState = "on-ground" | "on-steep-ground" | "not-supported" | "in-air";

What a character controller is standing on.


JoltInstance

ts
type JoltInstance<K> = JoltModule[K] extends (...args) => infer R ? R : never;

Instance type of a Jolt class, e.g. JoltInstance<'Vec3'>.

Type Parameters

Type Parameter
K extends keyof JoltModule

JoltModule

ts
type JoltModule = Awaited<ReturnType<typeof initJolt>>;

The initialised Jolt wasm module: every Jolt class, enum constant and helper (destroy, wrapPointer, ...) hangs off this object.

It mirrors the Jolt C++ API one to one, so the C++ reference is the documentation.


JoltShape

ts
type JoltShape = JoltInstance<"Shape">;

A reference-counted Jolt collision shape.


Quat

ts
type Quat = readonly [number, number, number, number];

A unit quaternion in xyzw order, matching three.js and Jolt.


ShapeKind

ts
type ShapeKind = "box" | "sphere" | "capsule" | "cylinder" | "mesh" | "convex";

Collision shape family. Mirrors WIT shape-kind.


Vec3

ts
type Vec3 = readonly [number, number, number];

A position or direction, in metres.

Variables

BODY_STRIDE

ts
const BODY_STRIDE: 14 = 14;

Floats per row in the buffer PhysicsWorld.readBodies fills.


PACKAGE

ts
const PACKAGE: "@aosengine/physics-jolt";

Package identity marker for @aosengine/physics-jolt.

Example

ts
import { PACKAGE } from '@aosengine/physics-jolt';

console.log(PACKAGE); // '@aosengine/physics-jolt'

RAY_HIT_STRIDE

ts
const RAY_HIT_STRIDE: 9 = 9;

Floats per row of the output buffer PhysicsWorld.raycastBatch fills.


RAY_STRIDE

ts
const RAY_STRIDE: 7 = 7;

Floats per row of the input buffer PhysicsWorld.raycastBatch reads.

Functions

convexHullFromPoints()

ts
function convexHullFromPoints(
   jolt, 
   points, 
   options?
): Shape;

Wrap a point cloud in its convex hull.

Unlike a mesh shape a convex hull can back a dynamic body, so this is the right shape for props lifted out of a splat scene: feed it the point cloud of the region you want solid and Jolt builds the tightest convex volume around it.

The returned shape carries one reference owned by you; see meshShapeFromGeometry.

Parameters

ParameterTypeDescription
jolttypeof JoltThe initialised Jolt module.
pointsFloat32ArrayPoint positions, stride 3 (x, y, z), in metres.
optionsConvexHullOptionsHull build tuning.

Returns

Shape

A shape with a reference count of one.

Throws

When there are fewer than four points or Jolt cannot build a hull.

Example

ts
import { convexHullFromPoints, loadJolt } from '@aosengine/physics-jolt';

const jolt = await loadJolt();
const cube = new Float32Array([
  -1, -1, -1, 1, -1, -1, -1, 1, -1, 1, 1, -1,
  -1, -1, 1, 1, -1, 1, -1, 1, 1, 1, 1, 1,
]);
const hull = convexHullFromPoints(jolt, cube);
hull.Release();

createContactRecord()

ts
function createContactRecord(): ContactRecord;

Allocate one pooled ContactRecord.

Returns

ContactRecord

A zeroed record.

Example

ts
import { createContactRecord, type ContactRecord } from '@aosengine/physics-jolt';

const pool: ContactRecord[] = [createContactRecord(), createContactRecord()];

createPhysicsWorld()

ts
function createPhysicsWorld(jolt, options?): PhysicsWorld;

Create a Jolt simulation.

Parameters

ParameterTypeDescription
jolttypeof JoltThe module from loadJolt.
optionsPhysicsWorldOptionsGravity, capacity and layer tuning.

Returns

PhysicsWorld

A live world. Call PhysicsWorld.dispose when done.

Example

ts
import { createPhysicsWorld, loadJolt } from '@aosengine/physics-jolt';

const world = createPhysicsWorld(await loadJolt(), { gravity: [0, -9.81, 0] });
world.addBody({
  id: 1,
  shape: 'box',
  dims: [10, 0.5, 10],
  position: [0, -0.5, 0],
  rotation: [0, 0, 0, 1],
  mass: 0,
  kind: 'static',
  layer: 0b10,
  mask: 0xffff,
  friction: 0.6,
  restitution: 0,
});
world.step(1 / 60);
world.dispose();

isJoltLoaded()

ts
function isJoltLoaded(): boolean;

Whether loadJolt has been called in this process.

Returns

boolean

True once the singleton exists, in flight or resolved.

Example

ts
import { isJoltLoaded, loadJolt } from '@aosengine/physics-jolt';

if (!isJoltLoaded()) await loadJolt();

loadJolt()

ts
function loadJolt(options?): Promise<typeof Jolt>;

Instantiate the Jolt wasm module, once per page.

The module is a process-wide singleton: every call returns the same promise, so registering two physics worlds costs one wasm instantiation. Passing a different wasmUrl after the singleton exists is a bug and throws rather than silently loading a second copy of the engine.

Parameters

ParameterTypeDescription
optionsLoadJoltOptionsWhere to fetch the wasm binary from.

Returns

Promise<typeof Jolt>

The initialised Jolt module.

Throws

When called again with a different wasmUrl.

Example

ts
import { loadJolt } from '@aosengine/physics-jolt';

const jolt = await loadJolt();
const up = new jolt.Vec3(0, 1, 0);
jolt.destroy(up); // Jolt never frees anything for you.

meshShapeFromGeometry()

ts
function meshShapeFromGeometry(
   jolt, 
   positions, 
   indices, 
   options?
): Shape;

Turn indexed triangle geometry into a Jolt MeshShape.

A MeshShape is a triangle soup with a BVH over it: it can only back a static body, which is exactly what splat-environment colliders and baked level geometry are. Building one is expensive (it constructs a tree), so build it once at load time and share it across every body that needs it.

The returned shape carries one reference owned by you. addBody takes its own reference, so the shape survives bodies being removed; call shape.Release() when the geometry itself is gone.

Parameters

ParameterTypeDescription
jolttypeof JoltThe initialised Jolt module.
positionsFloat32ArrayVertex positions, stride 3 (x, y, z), in metres.
indicesUint32ArrayTriangle indices, three per triangle, into positions.
optionsMeshShapeOptionsBuild tuning.

Returns

Shape

A shape with a reference count of one.

Throws

When the arrays are malformed or Jolt rejects the mesh.

Example

ts
import { loadJolt, meshShapeFromGeometry } from '@aosengine/physics-jolt';

const jolt = await loadJolt();
const positions = new Float32Array([0, 0, 0, 1, 0, 0, 0, 0, 1]);
const indices = new Uint32Array([0, 1, 2]);
const shape = meshShapeFromGeometry(jolt, positions, indices);
shape.Release();

physics()

ts
function physics(options?): EngineModule;

The Jolt physics EngineModule.

Registered in the engine's module list, it loads the Jolt wasm module in init, publishes the world as the physics service, and steps the simulation once per fixed step — never in update, because reading body state there gives you an interpolated pose, not a simulated one.

Parameters

ParameterTypeDescription
optionsPhysicsOptionsGravity, capacity, layer tuning and the wasm location.

Returns

EngineModule

A module to hand to createEngine({ modules: [...] }).

Example

ts
import { createEngine } from '@aosengine/core';
import { physics } from '@aosengine/physics-jolt';

const engine = await createEngine({
  canvas,
  manifest,
  modules: [physics({ gravity: [0, -9.81, 0] })],
});
const hit = engine.get('physics').raycast([0, 2, 0], [0, -1, 0], 10, 0xffff);