Colliders

Complete guide to collision shapes in Web Engine. Learn about primitive shapes, complex meshes, sensors, collision groups, and compound colliders.

The Collider component defines the collision shape for physics bodies. Web Engine supports primitive shapes (box, sphere, capsule), complex shapes (convex hull, trimesh, heightfield), and compound colliders. Colliders can be solid (blocking) or sensors (trigger volumes).

Collider Shapes#

Box (Cuboid)

Rectangular box defined by half-extents (X, Y, Z). Fast and stable. Best for crates, walls, buildings.

Sphere (Ball)

Perfect sphere defined by radius. Fastest shape for collision detection. Best for balls, planets.

Capsule

Cylinder with rounded ends (radius + height). Excellent for characters - smooth sliding and no getting stuck.

Heightfield (Terrain)

Grid of height values for terrain. Efficient for large outdoor environments.

Trimesh

Exact mesh collision using triangle mesh. Static bodies only. Best for complex level geometry.

Convex Hull

Convex approximation of a mesh. More expensive but allows dynamic bodies.

Component Properties#

PropertyTypeDefaultDescription
typeenum0 (Box)Shape: 0=Box, 1=Sphere, 2=Capsule, 3=Heightfield, 4=Trimesh, 5=ConvexHull
sizevec3[1,1,1]Box: half-extents (X,Y,Z). Sphere: radius (X). Capsule: radius (X), height (Y)
offsetvec3[0,0,0]Local position offset from body center
isSensorbooleanfalseTrue = trigger volume (no collision response)
collisionGroupint1Membership bitmask (which groups this belongs to)
solverGroupint1Solver bitmask (which groups to solve with)

Primitive Shapes#

Box (Cuboid) - Type 0#

Rectangular box defined by half-extents. The size property specifies half the width, height, and depth.

// 2x2x2 cube (size = half-extents)
{
type: 0, // Box
size: [1, 1, 1], // Half-extents: 1m in each direction
offset: [0, 0, 0],
}
// Wall: 10m wide, 5m tall, 0.5m thick
{
type: 0, // Box
size: [5, 2.5, 0.25], // Half-extents
offset: [0, 2.5, 0], // Offset up by half-height
}
  • Fast collision detection
  • Stable for stacking
  • Good for: crates, walls, buildings, platforms

Sphere (Ball) - Type 1#

Perfect sphere defined by radius. The size.x property specifies the radius.

// Sphere with 1m radius
{
type: 1, // Sphere
size: [1, 0, 0], // Only X component used (radius)
offset: [0, 0, 0],
}
// Basketball (radius ~0.12m)
{
type: 1, // Sphere
size: [0.12, 0, 0],
offset: [0, 0.12, 0], // Offset to sit on ground
}
  • Fastest collision detection
  • Rolls smoothly
  • Good for: balls, planets, orbs, spherical projectiles

Capsule - Type 2#

Cylinder with rounded ends. Perfect for characters - won't get stuck on edges. size.x = radius, size.y = half-height.

// Character capsule: 0.5m radius, 2m tall
{
type: 2, // Capsule
size: [0.5, 1.0, 0], // Radius (X), Half-height (Y)
offset: [0, 1.0, 0], // Center at character center
}
// Barrel
{
type: 2, // Capsule
size: [0.3, 0.5, 0], // Radius 0.3m, height 1m
offset: [0, 0.5, 0],
}
  • Smooth collision (no edge catching)
  • Best for characters
  • Good for: humanoid characters, cylindrical objects

Character Colliders

Always use a Capsule for character colliders. The rounded ends prevent getting stuck on stairs and edges. Avoid box colliders for characters.

Complex Shapes#

Convex Hull - Type 5#

Wraps a convex hull around a set of vertices. More expensive than primitives but can approximate complex shapes. Works with dynamic bodies.

// Convex hull from mesh vertices
// (Typically created automatically from mesh)
{
type: 5, // ConvexHull
vertices: meshVertices, // Float32Array of vertices
offset: [0, 0, 0],
}
  • Approximates complex shapes
  • Works with dynamic bodies
  • More expensive than primitives
  • Good for: rocks, irregular objects, simplified meshes

Convex Limitation

Convex hulls can only represent convex shapes (no concave indentations). For concave objects, use multiple convex hulls (compound collider) or a trimesh (static only).

Trimesh (Triangle Mesh) - Type 4#

Exact mesh collision using triangles. Most accurate but also most expensive. Only works with static (fixed) bodies.

// Trimesh collider for level geometry
{
type: 4, // Trimesh
vertices: meshVertices, // Float32Array
indices: meshIndices, // Uint32Array
offset: [0, 0, 0],
}
// Note: Parent body MUST be type 1 (Fixed/Static)
  • Exact mesh collision
  • Static bodies only
  • Most expensive collision detection
  • Good for: level geometry, terrain, buildings

Static Only

Trimesh colliders cannot be used with dynamic bodies. Attempting to create a dynamic trimesh will result in undefined behavior. Use convex hull or compound colliders instead.

Heightfield (Terrain) - Type 3#

Efficient terrain representation using a grid of height values. Perfect for large outdoor environments.

// Heightfield terrain
{
type: 3, // Heightfield
heights: heightData, // Float32Array of height values
nrows: 128, // Number of rows
ncols: 128, // Number of columns
scale: { x: 1, y: 1, z: 1 }, // Scale factors
}
  • Efficient for large terrains
  • Grid-based height data
  • Static bodies only
  • Good for: outdoor terrain, landscapes

Compound Colliders#

Combine multiple simple shapes to approximate complex objects. More efficient than a single complex mesh. Attach multiple collider entities as children.

// Chair made from boxes
// Parent entity: RigidBody (dynamic)
// Child 1: Collider (seat - box)
// Child 2: Collider (back - box)
// Child 3: Collider (leg1 - box)
// Child 4: Collider (leg2 - box)
// Child 5: Collider (leg3 - box)
// Child 6: Collider (leg4 - box)
// Each child has position offset
// Seat:
{
type: 0, // Box
size: [0.4, 0.05, 0.4],
offset: [0, 0.5, 0],
}
// Leg:
{
type: 0, // Box
size: [0.05, 0.25, 0.05],
offset: [0.35, 0.25, 0.35],
}

Compound vs Mesh

Compound colliders (multiple simple shapes) are often faster than a single complex mesh. They also work with dynamic bodies, unlike trimesh.

Sensors (Trigger Volumes)#

Sensors detect overlap but don't generate collision response. Perfect for trigger zones, checkpoints, and area detection.

// Trigger zone that detects player entry
{
type: 0, // Box
size: [5, 2, 5], // 10x4x10 zone
offset: [0, 2, 0],
isSensor: true, // No collision response!
}
// Script to detect sensor events
export default (api) => {
return (dt) => {
// Handle collision events
const events = api.getCollisionEvents();
for (const event of events) {
if (event.isSensor) {
if (event.type === 'START') {
api.log(`Entity ${event.eid2} entered trigger!`);
} else if (event.type === 'END') {
api.log(`Entity ${event.eid2} exited trigger!`);
}
}
}
};
};
  • Detects overlap (no blocking)
  • Generates collision events
  • Zero performance cost for physics response
  • Good for: triggers, checkpoints, detection zones

Collision Groups and Masks#

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

GroupValueUse Case
DEFAULT0x0001Default group for all objects
PLAYER0x0002Player character
ENEMY0x0004Enemies and NPCs
PROJECTILE0x0008Bullets, arrows, projectiles
TRIGGER0x0010Trigger volumes
ENVIRONMENT0x0020Static level geometry
INTERACTIVE0x0040Pickups, doors, interactive objects
VEHICLE0x0080Vehicles
import { CollisionGroups } from '@web-engine/core';
// Player collides with enemies and environment
const playerGroup = CollisionGroups.create(
CollisionGroups.PLAYER,
CollisionGroups.ENEMY | CollisionGroups.ENVIRONMENT
);
// Projectile hits enemies but not player (friendly fire off)
const projectileGroup = CollisionGroups.create(
CollisionGroups.PROJECTILE,
CollisionGroups.ENEMY | CollisionGroups.ENVIRONMENT
);
// Ghost object (no collision)
const ghostGroup = CollisionGroups.create(
CollisionGroups.NONE,
CollisionGroups.NONE
);

Collision Logic

Two colliders A and B collide if both conditions are true:
- A's membership overlaps with B's filter: (A.membership & B.filter) !== 0
- B's membership overlaps with A's filter: (B.membership & A.filter) !== 0

Collider Offset#

The offset property positions the collider relative to the body's center. Useful for non-centered shapes.

// Character: capsule offset up so bottom is at feet
{
type: 2, // Capsule
size: [0.5, 1.0, 0], // Radius 0.5m, half-height 1m
offset: [0, 1.0, 0], // Offset up by half-height
}
// Vehicle: box offset down to ground
{
type: 0, // Box
size: [1, 0.5, 2], // Car shape
offset: [0, -0.5, 0], // Bottom at ground level
}

Performance Comparison#

ShapePerformanceAccuracyDynamic Support
SphereFastestPerfect for spheresYes
BoxVery FastPerfect for boxesYes
CapsuleVery FastPerfect for capsulesYes
Convex HullMediumApproximateYes
TrimeshSlowExactNo (static only)
HeightfieldMediumGood for terrainNo (static only)

Shape Selection

Always prefer simple shapes (sphere, box, capsule) over complex shapes. Use compound colliders (multiple simple shapes) to approximate complex objects. Reserve trimesh for static level geometry only.

Common Patterns#

Character Collider#

{
type: 2, // Capsule
size: [0.5, 1.0, 0], // Radius 0.5m, height 2m
offset: [0, 1.0, 0], // Centered at character
isSensor: false,
collisionGroup: CollisionGroups.PLAYER,
}

Level Geometry#

{
type: 4, // Trimesh (exact mesh)
vertices: meshVertices,
indices: meshIndices,
offset: [0, 0, 0],
isSensor: false,
collisionGroup: CollisionGroups.ENVIRONMENT,
}
// Body MUST be type 1 (Fixed/Static)

Trigger Zone#

{
type: 0, // Box
size: [5, 2, 5], // 10x4x10 zone
offset: [0, 2, 0],
isSensor: true, // Trigger!
collisionGroup: CollisionGroups.TRIGGER,
}
Physics | Web Engine Docs | Web Engine Docs