API reference
Every public class, method, and event in @codexo/exojs. Generated from source.
classPhysicsWorld
The collision/query world: owns bodies, colliders, the detection backend, bindings, the query engine and the fixed-step accumulator. Stepped by the caller (commonly from a `Scene.update`), each fixed sub-step it integrates body velocities, runs broad- and narrow-phase detection, solves contacts and integrates positions, then fires immutable contact/sensor events and writes bound node transforms. It holds **no module-level state**, so any number of worlds run in isolation (gate I-1). The dynamics are a native, warm-started **TGS-Soft** solver (Box2D-v3 "soft step"): each fixed step runs detection once, then several sub-steps, each integrating gravity over the sub-step and solving contacts with a soft position bias plus a bias-free relax pass; a 2-point block normal solve propagates stack loads, and restitution is a separate final pass. Decoupling stiffness from the iteration count keeps tall towers stable. The detection backend sits behind an internal seam, so the solver is swappable without touching this public surface. **Operating envelope.** The soft solver trades a little accuracy for robustness, so it has a few documented limits — each stays finite/stable and each is pinned by a gate in `dynamics.test.ts`: - **Mass ratio** — resting stacks are slop-accurate up to ~100:1. Beyond that the velocity-capped soft push-out (`maxBiasVelocity`) lets the lighter body settle progressively deeper (≈6px at 500:1, fully through a thin floor by ~5000:1) — always finite, never exploding (SG-MR3). - **No CCD** — detection runs once per fixed step with no swept test, so a body that travels farther than an obstacle's thickness in one step tunnels straight through it (it stays finite). Reliably stopping fast projectiles is a future bullet-mode feature (SG-X5). - **PhysicsWorldOptions.subStepCount** — the default `4` is load-bearing for tall-stack stability; lowering it below `2` visibly degrades stacking, so do not reduce it for performance.
import { PhysicsWorld } from '@codexo/exojs-physics' The collision/query world: owns bodies, colliders, the detection backend, bindings, the query engine and the fixed-step accumulator. Stepped by the caller (commonly from a `Scene.update`), each fixed sub-step it integrates body velocities, runs broad- and narrow-phase detection, solves contacts and integrates positions, then fires immutable contact/sensor events and writes bound node transforms. It holds **no module-level state**, so any number of worlds run in isolation (gate I-1).
The dynamics are a native, warm-started **TGS-Soft** solver (Box2D-v3 "soft step"): each fixed step runs detection once, then several sub-steps, each integrating gravity over the sub-step and solving contacts with a soft position bias plus a bias-free relax pass; a 2-point block normal solve propagates stack loads, and restitution is a separate final pass. Decoupling stiffness from the iteration count keeps tall towers stable. The detection backend sits behind an internal seam, so the solver is swappable without touching this public surface.
**Operating envelope.** The soft solver trades a little accuracy for robustness, so it has a few documented limits — each stays finite/stable and each is pinned by a gate in `dynamics.test.ts`: - **Mass ratio** — resting stacks are slop-accurate up to ~100:1. Beyond that the velocity-capped soft push-out (`maxBiasVelocity`) lets the lighter body settle progressively deeper (≈6px at 500:1, fully through a thin floor by ~5000:1) — always finite, never exploding (SG-MR3). - **No CCD** — detection runs once per fixed step with no swept test, so a body that travels farther than an obstacle's thickness in one step tunnels straight through it (it stays finite). Reliably stopping fast projectiles is a future bullet-mode feature (SG-X5). - **PhysicsWorldOptions.subStepCount** — the default `4` is load-bearing for tall-stack stability; lowering it below `2` visibly degrades stacking, so do not reduce it for performance.
new(options: PhysicsWorldOptions): PhysicsWorld _allocateColliderId(): number _registerCollider(collider: Collider): void add(body: PhysicsBody): PhysicsBody addJoint(joint: T): T attach(node: SceneNode, options: AttachOptions): PhysicsBody bind(body: PhysicsBody, node: SceneNode): PhysicsBinding destroy(): void destroyBody(body: PhysicsBody): void destroyCollider(collider: Collider): void forEachAabbHit(bounds: Aabb, filter: Partial<object> | undefined, callback: object): void overlapShape(shape: AnyShape, position: VectorLike, filter?: Partial<object>, angle?: number): Collider[] queryAabb(bounds: Aabb, filter?: Partial<object>, out?: Collider[]): Collider[] queryPoint(point: VectorLike, filter?: Partial<object>): Collider[] rayCast(origin: VectorLike, direction: VectorLike, filter?: Partial<object>, maxDistance?: number): RayHit | null rayCastAll(origin: VectorLike, direction: VectorLike, filter?: Partial<object>, out?: RayHit[], maxDistance?: number): RayHit[] removeJoint(joint: Joint): void step(frameDeltaSeconds: number): void unbind(body: PhysicsBody): void contactHertz: number dampingRatio: number enableSleeping: boolean gravity: Vector sleepAngularVelocity: number sleepLinearVelocity: number subStepCount: number timeStepper: TimeStepper timeToSleep: number backend: PhysicsBackend bodies: readonly PhysicsBody[] colliders: readonly Collider[] joints: readonly Joint[] onCollisionEnd: Signal<[CollisionEvent]> onCollisionStart: Signal<[CollisionEvent]> onSensorEnter: Signal<[SensorEvent]> onSensorExit: Signal<[SensorEvent]>