Skip to content

PhysicsSyncSystem ​

Initializes and manages the Rapier physics world, creates rigid bodies and colliders from PhysicsComponent authoring state, steps the simulation each frame, and writes the results back to entity transforms.

Overview ​

PhysicsSyncSystem runs every frame and is responsible for:

  • Lazy-initializing the Rapier physics engine (loaded asynchronously via @dimforge/rapier3d-compat) the first time the system updates.
  • Creating a Rapier RigidBody and Collider for each entity that has a PhysicsComponent and Object3DRef.
  • Recreating bodies and colliders when their type, shape, or size changes (detected by per-entity signatures).
  • Stepping the Rapier world each frame with the clamped delta time.
  • Writing the simulation's output (body translation + rotation) back into the entity's TransformComponent and THREE.js Object3D for dynamic and kinematic bodies.
  • Applying per-axis translation/rotation locks from PhysicsComponent.values.rigidbody.
  • Handling isSensor colliders that fire collision events without generating a physical response.

Queried components ​

ComponentAccess
PhysicsComponentRead + mutate (rigidBody, collider live refs; values for authoring state)
Object3DRefRead (initial world position for body placement)
TransformComponentMutate (position, rotation written from simulation output)
EnvironmentRead (global gravity vector)

Supported rigid body types ​

TypeDescription
dynamicFully simulated; affected by gravity and forces.
fixedImmovable; acts as a static collider.
kinematicPositionMoved by setting position directly; not affected by physics.
kinematicVelocityMoved by setting velocity; interacts with dynamics.

Supported collider shapes ​

ShapeParameters
cuboidwidth, height, depth
ballradius
capsuleradius, height
cylinderradius, height
trimeshAuto-extracted from the entity's THREE.js geometry

Behavior notes ​

  • Async init — the Rapier WASM module is loaded once on the first update() call. Physics simulation does not start until the module is ready; entities created before init are processed on the first frame after init completes.
  • Trimesh — trimesh colliders merge the vertex/index data of every mesh under the entity (multi-primitive GLBs are fully covered) with the entity's world scale baked into the vertices — Rapier bodies carry no scale, so scaling the entity is how you resize a trimesh; the collider rebuilds automatically when the scale or geometry changes. The extracted data is cached per entity by a geometry+scale signature, and the heavy vertex merge runs only when that signature changes.
  • Sensor colliders — setting values.collider.isSensor = true creates a Rapier sensor collider. Sensor contacts do not generate forces but can be used for overlap/trigger queries.
  • Gravity — the global gravity vector is read from the Environment component (gravity field, default { x: 0, y: -9.81, z: 0 }) and applied to the Rapier world gravity setting each frame.
  • Preview only — the system is typically constructed with { isEditor: false } for preview. In the editor the physics world step is skipped so objects don't fall during authoring.

API reference ​