/** * Procedural animation for part-composed (rig-less) models — characters kit-bashed from * primitives/`ModelPart`s with no skeleton or clips. Pure, deterministic curve sampling: * the same (time, speed, phase, flinch, death) input always yields the same pose, so * replays and multi-client renders stay in lockstep and the hot path allocates nothing * when an `out` pose is reused. */ /** Semantic motion role of one `ModelPart` in a part-composed character. */ export type PartRole = "head" | "arm.l" | "arm.r" | "leg.l" | "leg.r" | "tail" | "wing.l" | "wing.r"; /** Tuning for {@link samplePartPose}/{@link sampleBodyPose}; every field has a sensible default. */ export interface PartMotionParams { /** Full stride cycles per second at walking speed. Default 1.6. */ strideHz?: number; /** Limb swing amplitude in radians at full walk. Default 0.7. */ swingRad?: number; /** Body bob height in model units at full walk. Default 0.04. */ bobAmp?: number; /** Idle sway/breathe amplitude in radians. Default 0.05. */ swayRad?: number; /** Speed (world units/sec) treated as a full walk; swing/bob scale linearly below it. Default 2. */ walkSpeed?: number; /** Backward flinch pitch in radians at flinch = 1. Default 0.35. */ flinchRad?: number; /** Sideways topple roll in radians at death = 1. Default PI / 2. */ toppleRad?: number; /** * Squash-and-stretch amplitude for soft characters (blobs, slimes): footfall squash while * walking, jelly breathe while idle, a squash pulse on flinch. Volume-conserving — the body * bulges horizontally as it compresses. Default 0 (rigid; scale stays exactly 1). */ squashAmp?: number; /** How death reads: `"topple"` rolls sideways (default, hard characters); `"splat"` flattens the body out — right for blobs. */ deathStyle?: "topple" | "splat"; } /** Sampled offsets to add onto a part's authored transform (or the character root). `scale` is multiplicative (1 = unchanged). */ export interface PartPose { position: [number, number, number]; rotation: [number, number, number]; scale: [number, number, number]; } /** Live signals a driver feeds the samplers each frame. All values are render-side only. */ export interface PartMotionInput { /** Seconds since the driver started (any monotonic clock). */ timeSec: number; /** Horizontal speed in world units/sec (smoothed by the driver). */ speed: number; /** Per-character phase offset in [0, 1) so crowds don't stride in sync — see {@link partMotionPhase}. */ phase: number; /** Hit-flinch envelope in [0, 1]; the driver sets 1 on a hit and decays it. */ flinch: number; /** Death ramp in [0, 1]; the driver eases it to 1 after the entity dies. */ death: number; } /** A reusable identity pose (zero offsets, unit scale). */ export declare function createPartPose(): PartPose; /** * Deterministic per-character stride phase in [0, 1) from an id (e.g. the entity instance id), * so a crowd of identical part-composed characters doesn't animate in lockstep. */ export declare function partMotionPhase(id: string): number; /** * Sample the character-root pose: walk bob, idle breathe/sway, backward hit flinch, and death — * a sideways topple by default, or a flatten-out splat with `deathStyle: "splat"`. With * `squashAmp > 0` the body also squashes and stretches (footfall squash, jelly idle breathe, * flinch squash pulse), volume-conserving. A driver applies this to the group wrapping the * whole composition (base model plus parts) — limbs ride along, as they would on a real torso. * * @capability part-motion sample the root bob/sway/squash/flinch/death pose for a rig-less part-composed character */ export declare function sampleBodyPose(input: PartMotionInput, params?: PartMotionParams, out?: PartPose): PartPose; /** * Sample one part's pose offset by role: counter-phase leg/arm swing driven by speed, a head * counter-sway, tail wag, and wing flap. Offsets are added onto the part's authored * position/rotation. Motion fades to zero as `death` ramps so the topple reads as one piece. * * @capability part-motion sample a limb/head/tail/wing pose offset for a role-tagged ModelPart */ export declare function samplePartPose(role: PartRole, input: PartMotionInput, params?: PartMotionParams, out?: PartPose): PartPose;