Physics Overview

Web Engine integrates Rapier3D, a high-performance physics engine written in Rust and compiled to WebAssembly, providing deterministic rigid body dynamics, advanced collision detection, and character controllers.

Physics in Web Engine is powered by Rapier3D, a fast and deterministic physics engine written in Rust and compiled to WebAssembly. The engine provides rigid body dynamics, advanced collision detection, character controllers, joints, raycasting, and more. Physics can run on the main thread or offloaded to a Web Worker for improved performance.

Physics Architecture

Web Engine supports multiple physics backends through the PhysicsBridge abstraction: Server (main thread Rapier), Client (Web Worker), Simple (lightweight fallback), and Wasm (optimized WebAssembly). The system automatically selects the best available backend with graceful fallbacks.

Physics Components#

Quick Start#

To make an object fall with gravity:

  1. Select an entity with a MeshRenderer.
  2. Add a RigidBody component.
  3. Set the body type to Dynamic.
  4. Add a Collider component.
  5. Choose a shape (Box, Sphere, Capsule, etc.).
  6. Press Play to see it fall!

Rigid Body Types#

Dynamic#

Fully simulated bodies affected by gravity, forces, and collisions. Use for anything that should move realistically.

  • Affected by gravity
  • Responds to forces and impulses
  • Collides with other bodies
  • Examples: boxes, balls, debris, ragdolls

Kinematic#

Bodies moved by code (not physics). They affect dynamic bodies but aren't affected by them.

  • Not affected by gravity or forces
  • Move by directly setting position/rotation
  • Push dynamic bodies out of the way
  • Examples: moving platforms, elevators, doors

Static#

Immovable bodies. Perfect for level geometry that never moves.

  • Never move (fastest)
  • Other bodies collide with them
  • Examples: walls, floors, terrain

Collider Shapes#

Choose the collider shape that best approximates your mesh:

  • Box — Best for rectangular objects (crates, walls).
  • Sphere — Best for round objects (balls, planets). Cheapest.
  • Capsule — Cylinder with rounded ends. Great for characters.
  • Cylinder — Barrels, pillars.
  • Convex Hull — Wraps around complex shapes. More expensive.
  • Trimesh — Exact mesh collision. Only for static bodies.

Performance Tip

Simple shapes (Box, Sphere, Capsule) are much faster than complex shapes (Convex, Trimesh). Use compound colliders with simple shapes when possible.

Physics World Configuration#

The physics world can be configured with custom gravity, simulation timestep, and collision event buffer sizes. Configuration is managed through the PhysicsConfig system.

PropertyDefaultDescription
gravity{ x: 0, y: -9.81, z: 0 }World gravity vector in m/s²
eventsBufferSize16384Collision event ring buffer capacity
raycastQueueCapacity1024Max concurrent raycast requests
protocolVersion2Physics bridge protocol version
import { setPhysicsConfig } from '@web-engine/core';
// Configure custom gravity (e.g., moon gravity)
setPhysicsConfig({
gravity: { x: 0, y: -1.62, z: 0 },
});
// Configure larger event buffer for many collisions
setPhysicsConfig({
eventsBufferSize: 32768,
raycastQueueCapacity: 2048,
});

Collision Groups#

Collision groups use 16-bit bitmasks to control which colliders interact. Each collider has a membership (which groups it belongs to) and a filter (which groups it can collide with).

import { CollisionGroups } from '@web-engine/core';
// Player collides with enemies and environment
const playerGroup = CollisionGroups.create(
CollisionGroups.PLAYER,
CollisionGroups.ENEMY | CollisionGroups.ENVIRONMENT
);
// Projectile only hits enemies (not player who fired it)
const projectileGroup = CollisionGroups.create(
CollisionGroups.PROJECTILE,
CollisionGroups.ENEMY | CollisionGroups.ENVIRONMENT
);

Pre-configured collision presets are available for common scenarios:

PresetMembershipFilter
PLAYERPLAYERENVIRONMENT | ENEMY | INTERACTIVE | TRIGGER
ENEMYENEMYENVIRONMENT | PLAYER | ENEMY | PROJECTILE
ENVIRONMENTENVIRONMENTALL (except TRIGGER)
TRIGGERTRIGGERPLAYER | ENEMY | VEHICLE
GHOSTNONENONE (no collision)

Scripting Physics#

Access physics in scripts through the api object:

export default (api) => {
return (dt) => {
// Read/write velocity
const vel = api.velocity;
vel.y -= 9.8 * dt; // Custom gravity
api.velocity = vel;
// Apply impulse (instant force)
if (api.input.jumpDown) {
api.applyImpulse({ x: 0, y: 10, z: 0 });
}
// Apply impulse at specific point (torque)
api.applyImpulseAtPoint(
{ x: 10, y: 0, z: 0 },
{ x: 0, y: 1, z: 0 } // Point offset
);
// Raycast for ground detection
const hit = await api.raycast(
api.position,
{ x: 0, y: -1, z: 0 },
2.0 // Max distance
);
if (hit && hit.distance < 1.0) {
api.log(`Hit: ${hit.eid} at distance ${hit.distance}`);
}
};
};

Performance Optimization#

  • Use simple shapes (Box, Sphere, Capsule) over complex shapes (ConvexHull, Trimesh) whenever possible.
  • Keep static bodies for immovable geometry (walls, floors) - they're optimized for zero movement.
  • Use compound colliders (multiple simple shapes) instead of a single complex mesh.
  • Enable sleeping for bodies that rarely move to skip simulation.
  • Use collision groups to avoid unnecessary collision checks between unrelated objects.
  • Enable CCD (Continuous Collision Detection) only for fast-moving objects.
  • Consider using the Client physics backend (Web Worker) to offload physics from the main thread.

Trimesh Limitation

Trimesh colliders (exact mesh collision) can only be used with static bodies. For dynamic bodies, use convex hull or compound colliders with simple shapes.

Physics Overview | Web Engine Docs