High-performance physics engine bound to a Scene, backed by a caller-injected Rapier 3D world.

Mirrors the cached-singleton pattern of SceneCollisionIndex — get one via getScenePhysics and the engine self-maintains: it watches onSceneObjectCreated / onSceneObjectDestroyed / onSceneModelDestroyed and keeps Rapier rigid bodies in step with the Scene.

import RAPIER from "@dimforge/rapier3d-compat";
await RAPIER.init();

const physics = getScenePhysics(scene, { rapier: RAPIER });

// The default body for every SceneObject is fixed + cuboid (city stays put).
// Upgrade specific objects to dynamic to drop them under gravity:
physics.setBody("ball-1", { type: "dynamic", shape: "ball", restitution: 0.6 });

function frame() {
physics.step(); // advances Rapier and writes mesh transforms
requestAnimationFrame(frame);
}
frame();
  • Body per SceneObject — multi-mesh objects move rigidly together. Each mesh's world matrix at body-creation time is recorded relative to the body's starting transform, and reproduced post-step by one matrix multiply.
  • Cuboid AABB colliders by default — cheap, fits BIM blocks, swap to "ball" per-object when needed. Trimesh / convex hull is doable but not enabled here; AABB is enough for the demo cases this is built for.
  • Lazy + event-driven — bodies created on first call to step (so a freshly-loaded city doesn't pay the body-creation cost until the simulation actually starts), then refreshed incrementally as the scene mutates.
  • No allocations per step — temp matrices and the body-iteration loop reuse pre-allocated scratch.

Setting mesh.matrix per step fires onSceneMeshMatrixChanged (which triggers a re-render) but not onSceneMeshMoved, so the SceneCollisionIndex BVH is not invalidated by physics motion — BVH ray picks remain cheap during simulation.

Constructors

Properties

scene: Scene

The Scene this engine drives.

world: any

The Rapier World instance. Exposed for advanced users who want to reach in and use Rapier directly (e.g. add joints, queries, sensors).

Accessors

Methods

  • Returns the underlying Rapier RigidBody, or null if there's none. Use it to call Rapier APIs not surfaced here (joints, sleeping, additional colliders, ...).

    Parameters

    • objectId: string

    Returns any

  • Creates or replaces the body for one SceneObject. Returns the new Rapier RigidBody, or null when the object isn't in the scene or has no usable geometry.

    Use this to upgrade a default-fixed body to dynamic, swap a cuboid for a ball, or attach friction/restitution to specific objects.

    Parameters

    Returns any

  • Advances the simulation one step and writes the new world transforms back to every dynamic / kinematic SceneMesh.

    Lazy-creates default bodies for any SceneObject queued by event since the previous step. Fixed bodies are never written back — they don't move.

    Optional dt overrides Rapier's integration timestep for this call; use it when you want to drive the simulation at a fixed rate independent of frame rate. Otherwise Rapier uses its default 1/60 s.

    Parameters

    • Optionaldt: number

    Returns void