Rigid-body dynamics, collisions, spatial queries. The engine owns one
physics.World at engine.physics and steps it
each tick before syncing transforms back into the scene graph.
update sleep timers
cache previous contacts (for warmstart)
apply gravity
integrate velocities (forces, damping)
CCD pass (swept tests, clamp dt for tunneling-prone bodies)
rebuild dynamic + static BVH if kill-count > threshold
substep loop × NUM_SUBSTEPS:
bvh_refit
broadphase (BVH traversal → contact candidates)
narrow-phase (test_box_box / sphere_cyl / …)
prepare_contact (mass matrix, Baumgarte bias)
warmstart from previous frame (first substep only)
constraint solver × CONSTRAINT_SOLVER_ITERS
stabilization × STABILIZATION_ITERS (bias-free)
integrate positions + rotations
update cached AABB
trigger overlap detection
mark bodies below KILL_Y dead (deferred removal next rebuild)
KILL_Y is
marked dead and only removed at the next BVH rebuild — keeps handle
generations stable inside a single step.Collider is a union of SphereCollider,
BoxCollider, CylinderCollider,
FanCollider (a cylinder wedge — useful for
cone-of-influence triggers). Each collider has a matching inertia helper
that spawn_dynamic calls automatically.
Triggers don’t generate contact responses. They overlap-test only.
engine.physics.trigger_overlaps and
trigger_static_overlaps are populated each step for
continuous-overlap events; on-demand snapshots are available via
query_trigger*.