@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
layers?
ts
optional layers?: LayerOptions;Object-layer slot tuning. See LayerOptions.
Inherited from
maxBodies?
ts
optional maxBodies?: number;Hard ceiling on simultaneous bodies. Defaults to 4096.
Inherited from
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
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
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
Methods
addBody()
ts
addBody(args): void;Create a body. See BodyArgs.
Parameters
| Parameter | Type |
|---|---|
args | BodyArgs |
Returns
void
Inherited from
applyImpulse()
ts
applyImpulse(
id,
impulse,
point?
): void;Apply an impulse, at the centre of mass unless point says otherwise.
Parameters
| Parameter | Type |
|---|---|
id | number |
impulse | Vec3 |
point? | Vec3 |
Returns
void
Inherited from
bodyIds()
ts
bodyIds(): readonly number[];Snapshot of the live body ids, cheap and non-allocating to iterate.
Returns
readonly number[]
Inherited from
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
| Parameter | Type | Description |
|---|---|---|
scene | Scene<Object3DEventMap> | null | The 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
drainContacts()
ts
drainContacts(out): number;Move queued contacts into out.
Parameters
| Parameter | Type |
|---|---|
out | ContactRecord[] |
Returns
number
Inherited from
groundState()
ts
groundState(id): GroundState;What a character body is standing on, as of the last step.
Parameters
| Parameter | Type |
|---|---|
id | number |
Returns
Inherited from
moveCharacter()
ts
moveCharacter(id, desiredVelocity): void;Set the desired world-space velocity of a character body for the next step.
Parameters
| Parameter | Type |
|---|---|
id | number |
desiredVelocity | Vec3 |
Returns
void
Inherited from
overlapSphere()
ts
overlapSphere(
center,
radius,
mask
): number[];Guest body ids overlapping a sphere, nearest first.
Parameters
| Parameter | Type |
|---|---|
center | Vec3 |
radius | number |
mask | number |
Returns
number[]
Inherited from
overlapSphereInto()
ts
overlapSphereInto(
center,
radius,
mask,
out
): number;Zero-allocation form of PhysicsWorld.overlapSphere.
Parameters
| Parameter | Type |
|---|---|
center | Vec3 |
radius | number |
mask | number |
out | Uint32Array |
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
| Parameter | Type |
|---|---|
origin | Vec3 |
direction | Vec3 |
maxDistance | number |
mask | number |
Returns
RayHit | null
Inherited from
raycastBatch()
ts
raycastBatch(
rays,
mask,
out
): number;Many rays, one call.
Parameters
| Parameter | Type |
|---|---|
rays | Float32Array |
mask | number |
out | Float32Array |
Returns
number
Inherited from
readBodies()
ts
readBodies(out): number;Write stride-14 body rows into out. See PhysicsWorld.readBodies.
Parameters
| Parameter | Type |
|---|---|
out | Float32Array |
Returns
number
Inherited from
readBodyBounds()
ts
readBodyBounds(
id,
out,
offset
): boolean;Local-space bounds and world transform of a body, for debug drawing.
Parameters
| Parameter | Type |
|---|---|
id | number |
out | Float32Array |
offset | number |
Returns
boolean
Inherited from
removeBody()
ts
removeBody(id): void;Destroy a body and release its shape reference. Unknown ids are ignored.
Parameters
| Parameter | Type |
|---|---|
id | number |
Returns
void
Inherited from
setEnabled()
ts
setEnabled(id, enabled): void;Take a body out of the simulation without destroying it, or put it back.
Parameters
| Parameter | Type |
|---|---|
id | number |
enabled | boolean |
Returns
void
Inherited from
setTransform()
ts
setTransform(
id,
position,
rotation
): void;Teleport a body. Velocities are left alone; clear them yourself if you meant a hard cut.
Parameters
| Parameter | Type |
|---|---|
id | number |
position | Vec3 |
rotation | Quat |
Returns
void
Inherited from
setVelocity()
ts
setVelocity(
id,
linear,
angular
): void;Set linear and angular velocity.
Parameters
| Parameter | Type |
|---|---|
id | number |
linear | Vec3 |
angular | Vec3 |
Returns
void
Inherited from
step()
ts
step(dt, substeps?): number;Advance the simulation.
Parameters
| Parameter | Type |
|---|---|
dt | number |
substeps? | number |
Returns
number
Inherited from
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
| Parameter | Type |
|---|---|
args | BodyArgs |
Returns
void
applyImpulse()
ts
applyImpulse(
id,
impulse,
point?
): void;Apply an impulse, at the centre of mass unless point says otherwise.
Parameters
| Parameter | Type |
|---|---|
id | number |
impulse | Vec3 |
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
| Parameter | Type |
|---|---|
out | ContactRecord[] |
Returns
number
groundState()
ts
groundState(id): GroundState;What a character body is standing on, as of the last step.
Parameters
| Parameter | Type |
|---|---|
id | number |
Returns
moveCharacter()
ts
moveCharacter(id, desiredVelocity): void;Set the desired world-space velocity of a character body for the next step.
Parameters
| Parameter | Type |
|---|---|
id | number |
desiredVelocity | Vec3 |
Returns
void
overlapSphere()
ts
overlapSphere(
center,
radius,
mask
): number[];Guest body ids overlapping a sphere, nearest first.
Parameters
| Parameter | Type |
|---|---|
center | Vec3 |
radius | number |
mask | number |
Returns
number[]
overlapSphereInto()
ts
overlapSphereInto(
center,
radius,
mask,
out
): number;Zero-allocation form of PhysicsWorld.overlapSphere.
Parameters
| Parameter | Type |
|---|---|
center | Vec3 |
radius | number |
mask | number |
out | Uint32Array |
Returns
number
raycast()
ts
raycast(
origin,
direction,
maxDistance,
mask
): RayHit | null;Closest hit along a ray, or null. The returned object is reused.
Parameters
| Parameter | Type |
|---|---|
origin | Vec3 |
direction | Vec3 |
maxDistance | number |
mask | number |
Returns
RayHit | null
raycastBatch()
ts
raycastBatch(
rays,
mask,
out
): number;Many rays, one call.
Parameters
| Parameter | Type |
|---|---|
rays | Float32Array |
mask | number |
out | Float32Array |
Returns
number
readBodies()
ts
readBodies(out): number;Write stride-14 body rows into out. See PhysicsWorld.readBodies.
Parameters
| Parameter | Type |
|---|---|
out | Float32Array |
Returns
number
readBodyBounds()
ts
readBodyBounds(
id,
out,
offset
): boolean;Local-space bounds and world transform of a body, for debug drawing.
Parameters
| Parameter | Type |
|---|---|
id | number |
out | Float32Array |
offset | number |
Returns
boolean
removeBody()
ts
removeBody(id): void;Destroy a body and release its shape reference. Unknown ids are ignored.
Parameters
| Parameter | Type |
|---|---|
id | number |
Returns
void
setEnabled()
ts
setEnabled(id, enabled): void;Take a body out of the simulation without destroying it, or put it back.
Parameters
| Parameter | Type |
|---|---|
id | number |
enabled | boolean |
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
| Parameter | Type |
|---|---|
id | number |
position | Vec3 |
rotation | Quat |
Returns
void
setVelocity()
ts
setVelocity(
id,
linear,
angular
): void;Set linear and angular velocity.
Parameters
| Parameter | Type |
|---|---|
id | number |
linear | Vec3 |
angular | Vec3 |
Returns
void
step()
ts
step(dt, substeps?): number;Advance the simulation.
Parameters
| Parameter | Type |
|---|---|
dt | number |
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
| Parameter | Type | Description |
|---|---|---|
jolt | typeof Jolt | The initialised Jolt module. |
points | Float32Array | Point positions, stride 3 (x, y, z), in metres. |
options | ConvexHullOptions | Hull 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
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
| Parameter | Type | Description |
|---|---|---|
jolt | typeof Jolt | The module from loadJolt. |
options | PhysicsWorldOptions | Gravity, capacity and layer tuning. |
Returns
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
| Parameter | Type | Description |
|---|---|---|
options | LoadJoltOptions | Where 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
| Parameter | Type | Description |
|---|---|---|
jolt | typeof Jolt | The initialised Jolt module. |
positions | Float32Array | Vertex positions, stride 3 (x, y, z), in metres. |
indices | Uint32Array | Triangle indices, three per triangle, into positions. |
options | MeshShapeOptions | Build 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
| Parameter | Type | Description |
|---|---|---|
options | PhysicsOptions | Gravity, capacity, layer tuning and the wasm location. |
Returns
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);