---
title: "Reference: Physics Contract"
description: "The v1 physics contract surface over Rapier 3D and the shared character controller - body types, colliders, contact defaults, force commands, layers, queries, joints, and the named proof tests - pinned to symbols and linking down to the generated component reference."
engineVersion: v1.0.234
date: 2026-09-28
license: "(c) Gessa, proprietary. Cite with attribution to https://gessa.ai/docs/. Terms: https://gessa.ai/terms/."
canonical: https://gessa.ai/docs/reference/physics-contract/
---

# Reference: Physics Contract

Last verified: 2026-09-02 against engine v1.0.232.

{% version engineVersion="v1.0.232" coordinate="docs-public.v0" /%}

Gessa physics is an integration contract over [Rapier 3D](https://rapier.rs) for the rigid-body world plus a shared deterministic character controller for player movement. This page is the **contract surface**: what the physics components accept, what the runtime enforces, and which named tests prove each guarantee. It is a thin pointer over the generated component reference; the exact field shapes are generated facts and live there, not here. For the model behind the contract (the timestep derivation, the mass model, the transaction and epoch, and the controller equations), read [Physics Simulation](../explanation/physics-simulation.md).

{% proof class="docs.physics_contract" registry="docs/cycles/v1-engine-readiness-loop/PROOF_REGISTRY.json" status="pending" %}
Every field shape below is verified against the generated component-type reference. Behavioral guarantees are tied to the named conformance tests listed under Proof surfaces; prose alone is not the proof.
{% /proof %}

## Canonical source

The physics component fields are a **Tier-2 generated artifact**. Read them directly; do not hand-edit them.

- [`docs/spec/generated/component-types.md`](../../../spec/generated/component-types.md) - the generated inventory and per-component field contracts.

{% generated-reference file="docs/spec/generated/component-types.md" label="ECS component inventory (physics components)" /%}

The Tier-1 source of truth is code: `COMPONENT_TYPE_DEFINITIONS` and `ComponentSchema` in `packages/ecs/src/index.ts`, the runtime physics modules under `server/src/modules/runtime/physics/`, and the shared controller under `packages/runtime-shared/src/`. The Rapier version is pinned as `@dimforge/rapier3d-compat` in `server/package.json`.

## Body types

A body's type is the `bodyType` field of {% component name="RigidBodyComponent" /%} `RigidBodyComponent`, which also carries `mass`, `linearDamping`, `angularDamping`, `gravityScale`, `lockTranslations`, `lockRotations`, and `ccdEnabled`. The runtime lowers each type to a Rapier descriptor in `componentSync.ts`:

- `static` becomes a fixed descriptor.
- `kinematic` becomes a position-based kinematic descriptor driven by `setNextKinematicTranslation`; Rapier derives its velocity from the per-tick delta.
- `dynamic` becomes a dynamic descriptor.

Continuous collision detection defaults on for dynamic bodies and is opt-in for kinematic and static, resolved by `ccdEnabledForBody`; an authored `ccdEnabled: false` is honored. Changing `bodyType` re-fingerprints the body (`bodyFingerprint`), so the sync recreates it with the new authority, which is how a grab hands a body between dynamic and kinematic while it is held.

## Colliders and contact defaults

Collider geometry is the `shape` field of {% component name="ColliderComponent" /%} `ColliderComponent`, one of `box`, `sphere`, `disc`, `capsule`, or `mesh` (a string form or an object form), with `size`, `collision` (`solid`, `trigger`, or `none`), `layers`, `friction`, and `restitution`. A string `disc` lowers to a flat Rapier cylinder. Contact material defaults come from the schema: `friction` defaults to `0.5` and `restitution` to `0`, both clamped to `[0, 1]` by `ColliderComponentSchema`. No friction or restitution combine rule is configured, so Rapier's own default combine rule applies (the default value is a property of the pinned Rapier build, not this contract).

Mass is scalar: mass is explicit (default 1), angular inertia is isotropic and equal to the mass scalar via `angularInertiaForMass`, and collider density is forced to 0 by `setDensity(0)`, so geometry never contributes mass.

Aggregate colliders for an {% component name="InstanceSetComponent" /%} `InstanceSetComponent` lower through `instanceSetCollider.ts` to a single static Rapier collider: a grid becomes voxels, a free set becomes a trimesh.

## Force commands and preflight

Runtime forces are the per-tick `pending` queue of {% component name="ForceComponent" /%} `ForceComponent`. Its authored entry schema, `ForceEntrySchema`, defines `force`, `impulse`, `torque`, `torqueImpulse`, `applyAtPoint`, `teleport`, and `reset`. Persistent user forces are cleared each tick before this tick's commands are applied, so a one-shot force does not integrate forever.

The whole command batch is preflighted for count and magnitude before any native mutation, and is rejected **atomically** on violation (`physicsCommandMagnitudeViolation` plus the batch count check in `componentSync.ts`): nothing partial is applied. The magnitude ceilings are safety bounds in `RUNTIME_PHYSICS_POLICY`: `maxForceMagnitude` 1e6, `maxImpulseMagnitude` 1e5, `maxTorqueMagnitude` 1e6, and `maxLaunchVelocityMagnitude` 1e3 m/s. The per-room budgets `maxRigidBodies`, `maxColliders`, and `maxActiveForces` are 1000 each.

A `launch` command (a velocity set) is **not** an authored `ForceEntrySchema` field: it is injected by runtime command translation (`physicsPendingEntryFromBodyCommand` in `runtimeSystems.ts`). For a character that carries the movement velocity lane ({% component name="VelocityComponent" /%} `VelocityComponent`), a launch is redirected to a `VelocityComponent` patch (preflighted against `maxLaunchVelocityMagnitude`, emitting a `RuntimeCharacterLaunched` effect); a body without that lane falls through to the `ForceComponent` queue, where `componentSync.ts` applies it as a Rapier `setLinvel`.

## Collision layers

Interaction layers are the `layers` field of `ColliderComponent`. The runtime caps interaction layers at `MAX_RAPIER_INTERACTION_LAYERS` (16) in `layers.ts`; layers beyond the cap are sliced off the Rapier interaction groups and a `physics.collision_layer_budget_exceeded` correction is pushed from `componentSync.ts`.

## Queries

Physics queries are `raycast`, `shapecast`, and `overlap`, exposed to scripts through the runtime physics query host and resolved in `queries.ts` and `rapierQueries.ts`. Two limits are part of the contract: `shapecast` and `overlap` shapes are limited to box, sphere, and capsule (mesh query shapes are unsupported), and historical (lag-compensated) rewind is supported only for `raycast`; historical `shapecast` and `overlap` are not offered.

## Joints

Joints are {% component name="JointComponent" /%} `JointComponent`, lowered to Rapier impulse joints in `componentSync.ts`. The supported types are `fixed`, `revolute`, `prismatic`, `spherical`, `spring`, and `rope`. Motors and limits are honored only on `revolute` and `prismatic` joints and fail closed elsewhere; a generic six-degree joint is deferred.

## Character controller surface

Player movement is the KCC. Its authored inputs are {% component name="CharacterMovementComponent" /%} `CharacterMovementComponent` (`maxSpeed`, `gravity`, `jumpSpeed`, and the `enableKcc` governance flag) and the live velocity on `VelocityComponent`. `deriveMovementParams` (`movementParams.ts`) turns those components into controller parameters over the named defaults in `RUNTIME_KCC_DEFAULTS`, and both the server tick and the client predictor derive from the same components with the same function.

Two governance facts are part of the contract:

- The KCC steps only a character whose `CharacterMovementComponent.enableKcc` is `true`; the schema default is `false`, resolved by the shared `ownsKccGovernance` predicate (`kccGovernance.ts`). For which character motor the runtime calls on each path, see the traced conclusion in [Physics Simulation](../explanation/physics-simulation.md).
- `deriveMovementParams` reads `gravity` as a non-negative field defaulting to 0, so an unauthored character does not fall under the KCC (vertical motion is opt-in).

The static-collision snapshot the KCC sweeps is derived by `deriveCollisionSnapshot` and is bounded at `RUNTIME_COLLISION_SNAPSHOT_MAX_TRIANGLES` (50000) triangles. It ignores collider rotation for **box solids only** (a world axis-aligned box cannot represent an oriented box); mesh-collider triangles carry the full authored rotation. It excludes movers (a `VelocityComponent`, a `CharacterMovementComponent`, or a dynamic `RigidBodyComponent`), so a kinematic or rigidbody-less solid is swept as static world geometry and character-versus-character stays server-authoritative.

## Proof surfaces

Each guarantee is bound to a named conformance test or check:

- **Golden corpus** (`check:physics-golden-corpus`, in the root check chain): per-tick observable output stays byte-identical across refactors at 6-decimal canon precision.
- **Native isolation** (`physicsKernelArchitecture.test.ts`): every native Rapier dependency stays inside the adapter family, with exactly one `world.step()` owner.
- **Tick transaction** (`physicsTransaction.test.ts`): a prepared step does not advance the coordinate, commit is monotonic, abort cold-rebuilds, and a config change is an observable epoch restart.
- **Character parity** (`runtimeNetcodeKccParity.test.ts`): server authority and client predictor produce bit-identical `{position, velocity, onFloor}` over randomized tapes.
- **Body-type authority** (`physicsBodyTypeAuthority.test.ts`): flipping `bodyType` changes the fingerprint and recreates the body with the new authority.
- **Governance** (`kccGovernance.test.ts`): KCC governance is owned only by the explicit `enableKcc` flag.
- **Backend registry** (`physicsBackendRegistry.test.ts`): the registry fails closed on an uninstalled backend and validates adapter output at the boundary.
- **Command atomicity** (`physicsFoundationFuzz.test.ts`, `physicsFoundationDefects.test.ts`): an over-budget or over-magnitude command batch applies nothing.

## Limits

- No first-party integrator or solver; the engine drives Rapier `world.step()` (`rapierAdapter.ts`).
- Angular inertia is isotropic and equal to the mass scalar, not shape-derived (`angularInertiaForMass`).
- Mesh colliders require a static body; on a dynamic body they emit `physics.mesh_collider_requires_static_body` and are skipped.
- Interaction layers are capped at `MAX_RAPIER_INTERACTION_LAYERS`; overflow is dropped with a correction.
- `shapecast` and `overlap` shapes are limited to box, sphere, and capsule; historical rewind is `raycast`-only.
- The backend selection object accepts only `backendId`; per-room tuning (gravity, solver and friction iterations, substep bound, CCD substeps) is the runtime-budget profile, hashed into `physicsEpochKey`.
- Motors and limits apply only to revolute and prismatic joints; a generic joint is deferred.
- No friction or restitution combine rule is configured; Rapier's default applies.
- Sleep state is kept internal and never patched onto the authored component.

## Related

- [Physics Simulation](../explanation/physics-simulation.md) - the model, the equations, and the traced two-motor conclusion.
- [ECS Components](ecs-components.md) - how to read the generated component catalog this page points into.
- [Runtime Playability](runtime-playability.md) - the runtime modules and readiness registries.
