Game Physics for the Web
In This Guide
- What Physics Engines Do for Games
- Rigid Body Fundamentals
- The Web Physics Engine Landscape
- Choosing Between 2D and 3D Physics
- Collision Detection at a Glance
- Constraints, Joints and Ragdolls
- Integrating Physics with Your Renderer
- The Physics Step Loop
- Performance Considerations
- Common Physics Patterns in Web Games
- Explore This Topic
What Physics Engines Do for Games
A physics engine is a library that simulates the laws of motion, gravity, and collision inside a virtual world. In a game context, the engine maintains a list of bodies, each defined by a shape, a mass, and a position. Every frame, the engine advances time by a fixed step, applies forces like gravity, detects which bodies overlap or are about to overlap, computes the correct collision response, and updates each body's position and velocity. Your rendering code then reads those new positions and draws the scene.
Without a physics engine, you would write collision checks by hand for every pair of objects, manage velocity and acceleration yourself, and handle edge cases like tunneling, stacking, and resting contacts manually. For a simple single-object game this is feasible, but the moment you add a second moving body the complexity grows rapidly. Physics engines exist to handle that complexity behind a clean API.
On the web, physics engines come in two forms. Pure JavaScript engines like Cannon-es run directly in the main thread or a Web Worker, offering easy integration and readable source code. WebAssembly engines like Rapier and Havok compile high-performance native code (Rust or C++) to WASM, delivering near-native speed while still running in the browser. Both approaches produce identical results from a gameplay perspective, but WASM engines handle larger simulations with less frame budget spent on physics.
The job of a physics engine stops at computing positions and rotations. It does not draw anything. That separation is important because it means you can pair any physics engine with any renderer. Rapier works with Three.js, Babylon.js, PixiJS, or a raw WebGL context. Cannon-es plugs into the same renderers. Havok ships as a first-party integration inside Babylon.js but can technically be used standalone. The physics world and the visual scene are two parallel data structures, and your code bridges them every frame.
Rigid Body Fundamentals
Rigid body dynamics is the branch of physics that deals with solid objects that do not deform. Every object in a rigid body simulation is either dynamic (affected by forces and collisions), kinematic (moved by code, pushes other objects but ignores forces), or static (immovable scenery like floors and walls). Understanding these three categories is essential because choosing the wrong body type is one of the most common mistakes in game physics setup.
Each body carries a set of properties. Mass determines how much force is needed to accelerate it. The moment of inertia, derived from the body's shape and mass distribution, determines how it resists angular acceleration. Linear velocity is the body's speed and direction. Angular velocity is its spin. Restitution controls how bouncy a collision is, with 0 meaning no bounce and 1 meaning a perfectly elastic collision. Friction controls how much surfaces grip when sliding against each other.
Forces and impulses are the two ways to affect a body during simulation. A force is applied continuously over time, like gravity pulling every frame. An impulse is an instantaneous change in velocity, like the kick you apply when the player jumps. Both are vectors with a direction and magnitude. Torque is the rotational equivalent of force, spinning an object around its center of mass.
The engine integrates these forces over time using a numerical method, typically semi-implicit Euler or Verlet integration. Each step computes the new velocity from accumulated forces, then computes the new position from that velocity. The step size is usually fixed at 1/60th of a second regardless of the actual frame rate, which keeps the simulation deterministic. If the rendering frame rate drops, the engine runs multiple fixed steps per frame to keep physics time synchronized with real time. If the frame rate is higher than the physics rate, the renderer interpolates between the last two physics states for smooth visuals.
Collision shapes are geometric approximations of your visual models. A character mesh with 10,000 polygons would be far too expensive to use directly for collision detection, so you approximate it with a capsule, a box, or a convex hull. Common collision shapes include spheres, boxes, capsules, cylinders, convex hulls, and triangle meshes. Simpler shapes are faster to test. A sphere-sphere collision check is just a distance comparison, while a convex hull pair requires the GJK algorithm. Triangle meshes are the slowest and should only be used for static geometry like terrain.
The Web Physics Engine Landscape
The web has several mature physics engines, each with distinct strengths. Choosing the right one depends on your renderer, your performance needs, and whether you prefer JavaScript simplicity or WASM speed.
Rapier
Rapier is a physics engine written in Rust by Dimforge, compiled to WebAssembly for browser use. It supports both 2D and 3D simulation with separate npm packages (rapier2d, rapier3d). As of 2026, Rapier's SIMD-accelerated npm packages deliver between two and five times the performance of its 2024 releases, thanks to a new dynamic BVH implementation with SIMD-accelerated tree traversals. Rapier handles rigid bodies, colliders, joints, character controllers, and ray casting. Its API is well documented and actively maintained, with a growing community around the React Three Fiber ecosystem via react-three-rapier.
Cannon-es
Cannon-es is a pure JavaScript 3D physics engine maintained by the pmndrs community. It is a modernized fork of the original cannon.js, repackaged as an ES module with TypeScript type definitions and tree-shaking support. Cannon-es provides rigid bodies, collision shapes (sphere, box, plane, cylinder, convex polyhedron, trimesh, heightfield), constraints (point-to-point, hinge, lock, distance, spring), and a broadphase system. Performance tops out around 500 to 1,000 active bodies at 60 fps depending on complexity. It integrates naturally with Three.js and has a companion React wrapper in use-cannon.
Havok
Havok is an industry-standard physics engine used in hundreds of AAA console and PC games. In 2023, Microsoft released a free WebAssembly build of Havok under the MIT license, integrated as the default physics plugin for Babylon.js 6 and later. Havok for the web offers rigid body simulation, collision detection, character controllers, and constraints with performance up to 20 times faster than the older Ammo.js integration. It requires WebAssembly SIMD support, which is available in all modern desktop browsers and iOS 16.4 and later.
Ammo.js
Ammo.js is an Emscripten port of the Bullet physics engine to JavaScript and WebAssembly. It was the default physics backend for Babylon.js before Havok and remains available as a fallback. Ammo.js supports a wide feature set inherited from Bullet, including soft bodies, compound shapes, and vehicle dynamics. However, its API is low-level and closely mirrors the C++ Bullet interface, making it harder to use than purpose-built web engines. Performance is solid but not competitive with Rapier or Havok for large simulations.
Matter.js and Planck.js (2D)
For 2D games, Matter.js is a popular JavaScript physics engine with a friendly API, built-in rendering for prototyping, and support for rigid bodies, constraints, composites, and collision filtering. Planck.js is a JavaScript rewrite of Box2D, the legendary 2D physics engine behind Angry Birds, offering more precise simulation at the cost of a more technical API. Both are good choices for 2D platformers, puzzle games, and top-down action games where you do not need a third dimension.
Choosing Between 2D and 3D Physics
The choice between 2D and 3D physics depends on your game's visual perspective and gameplay mechanics, not just whether your renderer draws in three dimensions. A side-scrolling platformer rendered with Three.js still benefits from a 2D physics engine because all meaningful motion happens on two axes. Using a 3D engine for a 2D game wastes computation on a z-axis that never matters and introduces edge cases where bodies drift out of the intended plane.
2D engines are faster per body because every calculation involves two components instead of three, and rotation is a single scalar instead of a quaternion. A 2D engine can handle thousands of bodies at 60 fps, while a 3D engine might struggle with the same count. If your game is genuinely 2D in its mechanics, choose a 2D engine.
3D engines are necessary when objects move freely in all three dimensions, when you need vertical stacking, slopes, or orbiting cameras that reveal depth. Racing games, flight games, first-person shooters, and any game where the player can look up and down need 3D physics. Many 3D web engines support 2D-style constraints (locking one axis, for example) if you need a hybrid approach.
Collision Detection at a Glance
Collision detection is the most computationally expensive part of physics simulation. It runs in two phases. The broad phase quickly eliminates pairs of objects that are too far apart to possibly collide, using spatial data structures like axis-aligned bounding box (AABB) trees, sweep-and-prune lists, or spatial hash grids. The broad phase reduces thousands of potential pairs down to a few dozen candidates.
The narrow phase tests those candidates for actual geometric overlap. For convex shapes, the GJK (Gilbert-Johnson-Keerthi) algorithm determines whether two shapes intersect, and the EPA (Expanding Polytope Algorithm) computes the penetration depth and contact normal. For concave or mesh-based shapes, the engine decomposes them into convex parts or tests individual triangles. The narrow phase produces contact points, which the constraint solver then uses to push overlapping bodies apart and apply friction.
Continuous collision detection (CCD) is a technique that prevents fast-moving objects from passing through thin walls between frames, a problem called tunneling. CCD sweeps the body's shape along its velocity vector and checks for the first time of impact. It is more expensive than discrete detection and should only be enabled on objects that actually move fast enough to tunnel, like bullets or high-speed projectiles.
Collision filtering lets you control which objects can collide with which. Most engines support collision groups and masks, where each body belongs to one or more groups and defines a mask of groups it interacts with. This is how you prevent a player's own projectiles from hitting the player, or allow ghosts to pass through walls while still colliding with other ghosts.
Constraints, Joints and Ragdolls
Constraints restrict the relative motion of two bodies. A point-to-point constraint pins two bodies together at a shared point, like a ball-and-socket joint. A hinge constraint allows rotation around a single axis, like a door on its hinges. A slider constraint allows translation along a single axis, like a piston. A lock constraint removes all relative motion, effectively welding two bodies together. A spring constraint applies a restorative force proportional to how far the bodies drift from their resting distance.
Ragdolls are chains of rigid bodies connected by constrained joints that simulate a limp character. A typical ragdoll has 10 to 15 bodies representing the head, torso, upper arms, lower arms, hands, upper legs, lower legs, and feet. Each joint has angular limits that prevent unnatural poses, like an elbow bending backward. Building a ragdoll involves defining each body's shape and mass, connecting them with hinge or cone-twist joints, and setting the angular limits for each joint. When the character dies or goes limp, you disable the animation system and let the physics engine take over.
Constraints are also used for gameplay mechanics beyond ragdolls. A grappling hook is a distance constraint between the player and an anchor point. A swinging platform is a hinge constraint with a motor applying periodic torque. A destructible bridge is a series of bodies connected by breakable constraints that snap when the applied force exceeds a threshold.
Integrating Physics with Your Renderer
The physics world and the rendering scene are separate systems with separate object lists. Integration means synchronizing their positions and rotations every frame. The typical pattern involves three steps: create a visual mesh and a physics body for each game object, step the physics world once per frame, then copy each body's position and rotation quaternion onto its corresponding mesh.
With Three.js and Rapier, you create a RigidBodyDesc and ColliderDesc for the physics side, and a Mesh with geometry and material for the visual side. After calling world.step(), you loop through your objects, read body.translation() and body.rotation(), and set mesh.position and mesh.quaternion accordingly. The react-three-rapier library automates this by wrapping Three.js objects in physics-aware components.
With Babylon.js and Havok, integration is built in. You create a mesh, then call new PhysicsBody(mesh, PhysicsMotionType.DYNAMIC, false, scene) and add a PhysicsShape. The engine synchronizes positions automatically each frame because the Havok plugin is part of the scene's physics pipeline. You still need to understand the underlying model to debug issues, but the boilerplate is handled for you.
With Cannon-es and Three.js, the pattern is the same as Rapier but with different API calls. You create a CANNON.Body with a shape and add it to the CANNON.World. Each frame you call world.step(fixedTimeStep), then copy body.position and body.quaternion onto the Three.js mesh. The use-cannon React library provides declarative hooks that hide this loop.
Regardless of which engine you choose, the key principle is the same: physics bodies are the source of truth for position and rotation. Never manually set a dynamic body's position after creation unless you are teleporting it. Instead, apply forces or impulses and let the engine compute the resulting motion.
The Physics Step Loop
Physics engines use a fixed timestep to maintain deterministic behavior. The standard step is 1/60th of a second (roughly 16.67 milliseconds). Your game's render loop, driven by requestAnimationFrame, may run at a different rate depending on the device. The physics loop must account for this discrepancy.
The accumulator pattern is the standard approach. You track how much real time has elapsed since the last frame. Each frame, you add the elapsed time to an accumulator. While the accumulator holds at least one physics step worth of time, you call world.step() and subtract the step duration. This means you may call step zero, one, or multiple times per render frame. If the frame took 33 ms, you step twice. If it took 10 ms, you step zero times and carry the remainder.
Interpolation smooths the visual result between physics steps. After stepping, the accumulator holds a fractional remainder, the time between the last physics state and the current render moment. You interpolate each body's visual position between its previous and current physics position using that fraction as a blend factor. Without interpolation, objects appear to stutter at low physics rates because their visual positions update in discrete jumps.
Running physics in a Web Worker is a common optimization for complex simulations. The physics world lives entirely in the worker thread, receiving input commands via postMessage and sending back position and rotation arrays via a SharedArrayBuffer or structured cloning. This frees the main thread for rendering and input handling. Rapier's architecture makes this straightforward because its WASM module can be instantiated in a worker. Cannon-es also works in workers since it is pure JavaScript with no DOM dependencies.
Performance Considerations
Physics performance on the web depends on the engine choice, the number of active bodies, the complexity of collision shapes, and whether you use WASM or pure JavaScript. Rapier with SIMD enabled is the fastest general-purpose option as of 2026. Havok inside Babylon.js is similarly fast for 3D scenarios. Cannon-es is adequate for simulations under 500 bodies but falls behind WASM engines for larger scenes.
Reducing the number of active bodies is the single most effective optimization. Put distant or offscreen objects to sleep by setting their velocity to zero and marking them as sleeping. Most engines do this automatically when a body's velocity drops below a threshold for several consecutive frames. Sleeping bodies consume almost no CPU time until another body collides with them and wakes them up.
Shape complexity matters. Replace concave meshes with convex decompositions or primitive approximations. Use compound shapes (a box plus a sphere, for example) instead of detailed convex hulls. Avoid triangle mesh colliders for dynamic objects, and reserve them for static terrain where the cost is paid once during broad phase setup.
Collision filtering reduces the number of pairs the narrow phase must evaluate. Group your objects logically, perhaps separating environment, players, projectiles, and pickups into different collision groups, and configure masks so that groups that never interact are never tested.
The broad phase algorithm also affects performance at scale. Rapier's BVH (bounding volume hierarchy) scales well to thousands of bodies. Cannon-es offers SAPBroadphase (sweep-and-prune) and NaiveBroadphase. SAP is faster for scenes where most objects are roughly aligned along one axis. For uniformly distributed objects, a grid-based broadphase or BVH is better.
Common Physics Patterns in Web Games
Certain physics setups appear repeatedly across different game genres. A platformer needs a kinematic or dynamic character body with a capsule collider, a ground check ray cast to determine if the player is grounded, and manually controlled horizontal velocity with physics-driven vertical velocity for jumping and gravity. The character controller pattern, where the engine provides a dedicated API for moving a body while respecting collisions, is available in Rapier and Havok and simplifies this setup.
A top-down shooter uses 2D physics with circle or box colliders for characters and thin box or ray colliders for bullets. Collision callbacks trigger damage and visual effects. Bullet bodies are often set to CCD mode to prevent tunneling through thin enemies.
A stacking puzzle game (think Angry Birds or Tetris with physics) relies on accurate resting contact simulation and stable stacking behavior. Restitution should be low to prevent bouncing, and friction should be moderate to high to prevent sliding. The solver iteration count may need to be increased from the default for stable tall stacks.
Vehicle physics typically uses a raycast vehicle model where the chassis is a single rigid body and each wheel is a ray cast downward from a suspension point. The ray length determines suspension compression, and lateral and longitudinal forces simulate tire grip. Cannon-es includes a RaycastVehicle class. Rapier and Havok require building this from joints and forces manually, though community examples exist.
Destructible environments use compound bodies where each piece is a separate rigid body held together by breakable constraints. When the applied force on a constraint exceeds a threshold, the constraint is removed, and the pieces scatter as independent dynamic bodies. This technique works well for walls, bridges, and structures that shatter on impact.