Physics · interface
ConvexShape
Convex collision shapes: the volume an element actually occupies, rather than a world-axis box around it.
Explained in Your first game, Rigid bodies.
interface ConvexShapeimport type { ConvexShape } from '@driftengine/physics';In depth
One representation covers every convex solid — a point cloud plus two kinds of
rounding. A box is its eight corners; a sphere is one point and a radius; a
stretch of banked track is its own drawn cross-sections, so the geometry a
player sees is the geometry that stops them. Face normals and edge directions
are enumerated once, at build time, because they are the separating-axis
candidates the sweep in collide.ts tests — a fixed, data-driven axis list
per shape pair is what lets two machines replay the same run bit for bit,
where an iterate-to-tolerance method would not.
Two kinds of rounding rather than one, as of 2026-08-27. radius grows a
shape by a ball and is what makes a sphere and a capsule; sideRadius grows
it by a disc perpendicular to the segment through its first two points, and is
what makes a cylinder. The second exists because the first cannot express a
cylinder at all: a uniform radius rounds the rim along with the side, and the
rim is what a wheel rolls on. Everything that consumes a shape reads both, and
a shape carrying neither is a plain polytope, which is most of them.
Build-time only: nothing here may be called per frame or per tick. The hull builder is O(n^4) in the point count — trivial for the intended n (a slab is 8–16 points, a body part 8), wrong for a render mesh, hence the cap. Shapes come from the few points that define an element, not from its triangles.
Properties
| Name | Type | Description |
|---|---|---|
verticesreadonly | Float32Array | xyz-packed points whose convex hull is the shape. Local space for a body's shape, world space for a static collider's — the sweep never needs to know which, because bodies carry a frame and colliders are baked. |
faceNormalsreadonly | Float32Array | xyz-packed unit face normals, one per direction (a line: n and −n once). |
edgeDirsreadonly | Float32Array | xyz-packed unit edge directions, one per direction. |
radiusreadonly | number | Rounding grown around the points — a sphere is one point and this. |
sideRadiusreadonly | number | Rounding grown around the points only perpendicular to the segment through them, in
metres. Zero for everything but a cylinder, which is what it exists for.More
The axis is the shape's own first two points, not a stored vector, so a cylinder baked into world space by a collider carries its orientation the same way its position is carried. |
boundRadiusreadonly | number | Distance from the local origin enclosing the whole shape, for broad bounds. |
facePlanesreadonly | Float32Array | xyzw-packed outward face planes, four floats per face: normal then offset, so a point p lies
on the face when dot(n, p) === d.MoreOne entry per face, where |
faceVertexStartreadonly | Uint16Array | CSR offsets into faceVertexIndices, length faceCount + 1. Empty when there are no faces. |
faceVertexIndicesreadonly | Uint16Array | Vertex indices, each face's loop wound counter-clockwise seen from outside. |
trianglesreadonlyoptional | TriangleMesh | A static triangle mesh, where this shape is one, or absent where it is a convex solid.MoreThe one thing in this file that is not convex, and it is a field rather than a second type
on purpose. A union would put a narrowing at every call site that takes a shape — the broad
phase, the bounds, the collider set, the sweep, the mass, the queries, the cloth — for a shape
only the narrow phase and the raycast can act on, and every one of those narrowings would be a
place to forget one. A discriminating field is what A mesh's |