# Agent guide - 2D physics and geometry

## Choose a supported entry

Use `@pibbl/core/physics/2d` for scheduled bodies/worlds and `/physics/2d/geometry` for pure shape operations. There is no root physics barrel, Pibbl-owned 3D physics API, renderer-coupled 3D world, or official Three physics binding. Rapier is privately bundled by Pibbl; applications do not initialize or drive it directly.

Read [the 2D physics guide](/guides/physics-2d/) for a complete public-browser test fixture and supported manual test harness. Use [Stirred Ink](/examples/stirred-ink/) for complete application source, or [the existing drag-and-throw editor](/playground/#/examples/composition/physics-2d). These sources use public package entries. Do not depend on repository test helpers.

## Ownership and coordinate systems

`PhysicsWorld2D` owns one world for its mounted identity. `space="root"` is the compatibility default; `space="local"` makes poses, geometry, gravity, and queries relative to the world. Space is creation-only, so changing it requires a new key/lifetime. Parent transforms for a local world must be finite and invertible. Body transforms within the world remain rigid.

Pointer events are root-logical. Convert using `toPhysicsPoint2D` before a local query or target; use `fromPhysicsPoint2D` to return. Do not divide by CSS density or assume a Group's transform has already localized the event.

Dynamic bodies own their pose after mounting. Initial drawing transforms and velocities seed the body; subsequent movement uses commands. Static bodies follow authored geometry. Kinematic bodies follow target signals. Dragging or animation needs an explicit handoff between these owners. Retain body handles and observe `enabled`/`generation`; stale handles cannot command a new generation.

## Timing and limits

Distances use logical Canvas units, velocities use units per second, angles use degrees, and fixed-step duration uses milliseconds. Gravity defaults to zero. The default world runs 60 fixed ticks per second with at most four catch-up ticks per frame. Sleeping/stationary worlds stop requesting frames; commands wake them through Pibbl scheduling.

The engine uses single-precision values and an internal 100-logical-units-per-meter scale. Use tolerances, not exact floating-point trajectories. CCD helps fast dynamic solids but is bounded: a required substep count above 64 rejects and rolls back. Sensors observe discrete overlaps; use casts for fast triggers. Do not promise arbitrary-speed exact collision detection.

Rounded/elliptical collision shapes use bounded approximations while pure geometry queries retain mathematical shapes. Inspect actual collider bounds when changing visual scale. A physics body with a filter still uses unfiltered logical geometry.

## Data flow into textures

Read committed position in `useReaction`, normalize it into the texture rectangle, and send displacement messages. Reset previous position on first sample, generation change, or teleport. The body and texture own separate simulation memories. A reaction-diffusion field does not feed forces back into Rapier unless an application explicitly implements and validates that coupling.

## Verification

Use `inspectPhysics2D` outside render to capture JSON-safe body poses, velocities, bounds, contacts, sleep, and failure diagnostics. Inspection does not step or restore the world. `PhysicsDebug2D` shows authoritative geometry; interpolated presentation can differ between fixed ticks.

Use `createPhysicsTestHarness2D` from the public testing subpath in an isolated browser fixture. Assert contact/pose/velocity changes with tolerances, then compare presentation. Cover pause, zero gravity, a collision, reset, stale-handle commands, local transforms, and disposal. Report fixed-step configuration and simulated duration with results. A screenshot of a moving ball is not collision evidence.

## Documentation version

Documentation built with @pibbl/core 0.0.2, revision 272a94a. ALPHA — NOT FOR PRODUCTION USE.
