import type { PhysicsBounds, PhysicsWorld } from "./physicsWorld.js"; export type ForceMode = "impulse" | "velocity" | "accelerate"; /** World-space force position, axis or acceleration vector. */ export type ForceVector = readonly [number, number, number]; /** Renderer-free localized acceleration shared by physical actors and cosmetic particles. */ export interface ForceFieldConfig { center: ForceVector; shape: { kind: "sphere"; radius: number; } | { kind: "box"; halfExtents: ForceVector; }; /** Positive attracts toward the center; negative repels. Units/s². */ strength: number; /** Edge-to-center falloff exponent; zero is uniform. Default 1. */ attenuation?: number; /** Blend radial attraction with `direction`, from 0 to 1. */ directionality?: number; /** World-space direction; default [0, 0, -1]. */ direction?: ForceVector; /** Signed tangential acceleration around a world-space axis. */ vortex?: { axis: ForceVector; strength: number; /** Independent signed acceleration along the normalized axis, in units/s². */ lift?: number; }; /** Affected target bits; omission affects every target. */ mask?: number; /** Cap the combined acceleration magnitude. */ maxAcceleration?: number; } /** Validate force authoring once before sampling in a hot loop. * Coordinates stay within the safe integer range; acceleration magnitudes stay within 1e12 units/s². * @capability force-field-validation reject invalid localized force authoring before simulation */ export declare function validateForceField(config: ForceFieldConfig): void; /** Sample localized acceleration; `out` permits allocation-free integration. * @capability localized-forces sample signed attraction, directional force, vortex spin and axial lift with target masks and caps */ export declare function sampleForceField(config: ForceFieldConfig, position: ForceVector, targetMask?: number, out?: [number, number, number]): [number, number, number]; export interface ForceVolumeConfig { /** Region a body's center must be inside to be affected. */ bounds: PhysicsBounds; /** `impulse` adds to velocity, `velocity` sets it, `accelerate` adds force·dt each tick. */ force: readonly [number, number, number]; /** Default `impulse`. */ mode?: ForceMode; /** Fire only when a body first enters (boost pad) rather than every tick inside (fan/wind). Default false. */ once?: boolean; } /** * A trigger region that pushes bodies passing through it — boost pads (`impulse` + `once`), * conveyors (`velocity`), fans/wind (`accelerate`). Call `apply` each tick; `once` mode fires only * on entry by tracking membership between ticks. */ export declare class ForceVolume { readonly bounds: PhysicsBounds; readonly mode: ForceMode; readonly once: boolean; private readonly fx; private readonly fy; private readonly fz; private members; private nextMembers; constructor(config: ForceVolumeConfig); apply(world: PhysicsWorld, dt: number): void; } /** One tick's force math for a body outside `PhysicsWorld` — apply the returned velocity in any custom integrator. */ export declare function applyVolumeForce(velocity: readonly [number, number, number], force: readonly [number, number, number], mode: ForceMode, dt: number): readonly [number, number, number]; export interface VolumeTriggerConfig { bounds: PhysicsBounds; } export interface VolumeTriggerStep { /** Ids inside this tick that were outside last tick — the boost-pad edge. */ entered: readonly TId[]; /** Every id inside this tick. */ inside: readonly TId[]; /** Ids inside last tick that left. */ exited: readonly TId[]; } /** * The enter-once membership tracking from `ForceVolume`, freed from `PhysicsWorld`'s body indices * (#286.8): feed any integrator's `{ id, position }` list each tick and act on the edges — apply * `applyVolumeForce` on `entered` for a boost pad, on `inside` for a fan. */ export interface VolumeTrigger { readonly bounds: PhysicsBounds; step(bodies: Iterable<{ id: TId; position: readonly [number, number, number]; }>): VolumeTriggerStep; reset(): void; } export declare function createVolumeTrigger(config: VolumeTriggerConfig): VolumeTrigger; export interface PlatformCarryConfig { /** Vertical gap between a rider's base and the platform top counted as "standing on". Default 0.12. */ contactTolerance?: number; } /** * Carries bodies standing on a moving platform by composing their transform with the platform's * per-`step` delta — moving/rotating lifts and conveyor floors (Fall Guys, Gang Beasts). The * platform is a body the game repositions each frame; riders are detected by overlap on its top face. */ export declare class PlatformCarry { private readonly world; private readonly platform; private readonly tolerance; private prevX; private prevY; private prevZ; constructor(world: PhysicsWorld, platform: number, config?: PlatformCarryConfig); step(): void; }