Web Engine Docs
Preparing documentation
Use the search bar to quickly find any topic
Preparing documentation
Use the search bar to quickly find any topic
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.
Makes an entity participate in physics simulation. Supports dynamic, kinematic (position/velocity-based), and static bodies with mass, friction, restitution, and CCD.
Defines collision shapes. Supports primitives (box, sphere, capsule), complex shapes (convex hull, trimesh, heightfield), sensors, and collision filtering.
Kinematic character controller with ground detection, slope handling, step climbing, and smooth collision response.
Connect rigid bodies with constraints: fixed, spherical (ball), revolute (hinge), prismatic (slider) joints with limits and motors.
Perform ray casts, shape casts, and overlap queries for line-of-sight, ground detection, and hit detection.
Configure gravity, simulation stepping, collision groups, and performance optimizations.
To make an object fall with gravity:
MeshRenderer.RigidBody component.Collider component.Fully simulated bodies affected by gravity, forces, and collisions. Use for anything that should move realistically.
Bodies moved by code (not physics). They affect dynamic bodies but aren't affected by them.
Immovable bodies. Perfect for level geometry that never moves.
Choose the collider shape that best approximates your mesh:
Performance Tip
Simple shapes (Box, Sphere, Capsule) are much faster than complex shapes (Convex, Trimesh). Use compound colliders with simple shapes when possible.
The physics world can be configured with custom gravity, simulation timestep, and collision event buffer sizes. Configuration is managed through the PhysicsConfig system.
| Property | Default | Description |
|---|---|---|
| gravity | { x: 0, y: -9.81, z: 0 } | World gravity vector in m/s² |
| eventsBufferSize | 16384 | Collision event ring buffer capacity |
| raycastQueueCapacity | 1024 | Max concurrent raycast requests |
| protocolVersion | 2 | Physics bridge protocol version |
import { Physics } from '@web-engine-dev/core';// Configure custom gravity (e.g., moon gravity)Physics.setPhysicsConfig({gravity: { x: 0, y: -1.62, z: 0 },});// Configure larger event buffer for many collisionsPhysics.setPhysicsConfig({eventsBufferSize: 32768,raycastQueueCapacity: 2048,});
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-dev/core';// Player collides with enemies and environmentconst 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:
| Preset | Membership | Filter |
|---|---|---|
| PLAYER | PLAYER | ENVIRONMENT | ENEMY | INTERACTIVE | TRIGGER |
| ENEMY | ENEMY | ENVIRONMENT | PLAYER | ENEMY | PROJECTILE |
| ENVIRONMENT | ENVIRONMENT | ALL (except TRIGGER) |
| TRIGGER | TRIGGER | PLAYER | ENEMY | VEHICLE |
| GHOST | NONE | NONE (no collision) |
Access physics in scripts through the api object:
export default (api) => {return (dt) => {// Read/write velocityconst vel = api.velocity;vel.y -= 9.8 * dt; // Custom gravityapi.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 detectionconst 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}`);}};};
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.