Quick answer: Insert the collider with the rigid body handle as its parent: collider_set.insert_with_parent(collider, body_handle, &mut bodies). A collider inserted without a parent is a static, free collider.

Using the Rapier physics engine, a rigid body falls under gravity but its collider stays at the origin — collisions happen in the wrong place.

Two Insert Paths

The free-collider path is the bug if you wanted a moving body.

Correct Setup

let body = RigidBodyBuilder::dynamic()
    .translation(vector![0.0, 10.0])
    .build();
let body_handle = bodies.insert(body);

let collider = ColliderBuilder::cuboid(0.5, 0.5).build();
colliders.insert_with_parent(collider, body_handle, &mut bodies);

Read the Body, Not the Collider

For rendering, read the rigid body’s position each step (bodies[handle].position()). The collider’s world transform is derived from the body plus its local offset — the body is the source of truth.

Local Offset, If Any

A collider can sit offset from its body’s center via its local position. Set that deliberately; an unintended offset looks like “collider not following” when it’s actually following with a shift.

Verifying

The body falls; the collider moves with it; collisions register at the body’s actual position. The rendered mesh, read from the body, lines up with the physics.

“insert vs insert_with_parent. The parent handle is what attaches a collider to a moving body.”

If you use bevy_rapier or another wrapper, the equivalent is making the Collider a child entity of the RigidBody entity — same concept.