/**
 * Tunable parameters for {@link FirstPersonPlayerController}. The full
 * config is the only serialized portion of the component — everything else
 * (intent, state, pose, signals) is transient and rebuilt on link.
 *
 * Defaults aim for a baseline "human soldier" feel — see DESIGN.md §4.1.
 * Every value is exposed so designers can mod it to taste.
 */
export class FirstPersonPlayerControllerConfig {
    body: {
        /** Standing eye height, meters above body origin. */
        height: number;
        /** Crouched eye height. */
        crouchHeight: number;
        /** Prone eye height (used by slide). Body is horizontal — eye
         *  just above ground level, head turned toward the direction
         *  of travel. */
        proneHeight: number;
        /** Capsule radius, for downstream physics. */
        radius: number;
        /** Kilograms — affects bob, jump, landing, accel, and exertion via massRatio. */
        mass: number;
        /** Reference mass against which `mass` is normalized (massRatio = mass/refMass). */
        referenceMass: number;
        /**
         * How strongly `mass` couples into derived effects. 0 = mass is
         * cosmetic; 1.0 = full coupling (heavier ⇒ lower jump, lower accel,
         * harder landing, faster exhaustion). At 1.0 a 25% mass increase
         * yields:
         *   jump peak       ≈ 0.83×   (∝ 1/√massRatio — kinematically motivated)
         *   ground accel    ≈ 0.80×   (∝ 1/massRatio — F = ma at fixed force)
         *   landing dip     ≈ 1.25×   (∝ massRatio — higher momentum to absorb)
         *   exertion rise   ≈ 1.25×   (∝ massRatio — more body to move)
         */
        massCouplingStrength: number;
    };
    motion: {
        walkSpeed: number;
        sprintSpeed: number;
        crouchSpeed: number;
        /** [0..1] how much intent influences velocity while airborne. */
        airControl: number;
        /**
         * Half-life (seconds) for the mono-exponential approach to top
         * sprint speed on the ground. The controller's ground-accel
         * model is Hill-based:
         *     v(t) = v_max · (1 − e^(−t / τ))
         * with τ = halfLife / ln 2. At each tick the velocity halves
         * the remaining gap to `targetSpeed` every `halfLife` seconds.
         *
         * Default `0.116 s` gives ~95 % of `sprintSpeed` reached in
         * 500 ms — the Apex Legends / Titanfall / modern CoD ramp
         * window. The curve is naturally non-uniform: roughly 45 %
         * of top speed in the first 100 ms, then the last 5 % takes
         * 300 ms — so a quick tap-and-go still feels snappy while
         * follow-up moves (slide, sprint-jump) require committed
         * sprint time to be at top speed.
         *
         * Literature: Hill 1927 / Furusawa-Hill 1928 (force-velocity
         * curve, original analytical formulation); Morin & Samozino
         * 2016 (modern sprint profiling using the same mono-exp fit).
         */
        groundAccelHalfLife: number;
        /** m/s^2 horizontal deceleration toward 0 when intent is zero. */
        groundDecel: number;
        /** m/s^2 horizontal acceleration while airborne. */
        airAccel: number;
        /**
         * Top-speed multiplier applied while the move intent has a backward
         * component (intent.move.y < 0). Backpedaling is mechanically slower
         * than running forward — this also enforces a hard cap rather than
         * letting "backward sprint" reach the same speed as forward sprint.
         */
        backwardSpeedFactor: number;
        /**
         * Acceleration multiplier while moving backward. Body has worse
         * mechanical advantage when reversing — slower to start, slower to
         * stop, sells the "fighting the gait" feel.
         */
        backwardAccelFactor: number;
    };
    jump: {
        /** Apex height of a clean jump, meters. */
        peakHeight: number;
        /** Seconds to reach apex from launch. Together these two derive g. */
        timeToApex: number;
        coyoteTime: number;
        bufferTime: number;
        /** Gravity multiplier while falling (vy <= 0). */
        fallGravityMult: number;
        /** Gravity multiplier when jump released early during ascent. */
        cutGravityMult: number;
        anticipation: {
            duration: number;
            dipAmount: number;
        };
    };
    landing: {
        /** m/s impact threshold; below = soft landing signal. */
        softThreshold: number;
        /** m/s impact threshold; above = hard landing signal. */
        hardThreshold: number;
        recovery: {
            /** Meters of eye dip per m/s of impact velocity. */
            dipPerVy: number;
            /** Clamp on total dip. */
            dipMax: number;
            spring: {
                halfLife: number;
                /** zeta < 1 → rings once before settling, reads as compression. */
                zeta: number;
            };
        };
    };
    crouch: {
        /** Seconds to lerp eye height between standing and crouched. */
        transitionTime: number;
        /** "hold" or "toggle" */
        mode: string;
    };
    /**
     * Wall-run ability — airborne + lateral wall + speed → run along the
     * wall with reduced gravity. Camera tilts into the wall via the
     * shared lean spring (consistent with the rest of the camera).
     * Fields here are consumed by the {@link WallRun} ability when
     * registered.
     */
    wallRun: {
        /**
         * Minimum horizontal speed (m/s) to engage wall-run. Set ABOVE
         * walkSpeed (4.5) so a wall-run is earned by a committed RUN — a walk
         * into the wall, or falling alongside it with leftover momentum,
         * shouldn't grab on. Below the ~7 m/s a sprint-into-wall carries.
         */
        minSpeed: number;
        /** Player must be airborne at least this long before wall-run can
         *  engage — prevents wall-run triggering off a jump's first frames. */
        minAirborneTime: number;
        /** Maximum wall-run duration (s). Auto-exits at the end. */
        maxDuration: number;
        /** Multiplier on base gravity while wall-running. Lower = longer hang. */
        gravityFactor: number;
        /** Camera tilt magnitude (deg) into the wall. Disabled by the
         *  motion-sickness toggle alongside the standard lean. */
        cameraRollDeg: number;
    };
    /**
     * Wall-jump ability — instantaneous off-wall impulse. Fires from
     * either an active wall-run state or from near-wall airborne (a
     * short window where the player is close enough to push off).
     */
    wallJump: {
        /** Impulse magnitude away from the wall (m/s, applied along wall normal). */
        outwardImpulse: number;
        /** Upward component multiplier on jumpInitialVy. */
        upFactor: number;
        /** Max distance to wall (m) at which a near-wall-airborne wall-jump
         *  is allowed (when not already wall-running). */
        nearWallMaxDistance: number;
    };
    /**
     * Ledge-grab ability — snap to a forward ledge while descending and
     * hang from it until the player releases. Climbing fatigue is
     * modelled via the shared exertion channel: hang too long and you
     * slip. Fields here are consumed by the {@link LedgeGrab} ability
     * if registered; ignored otherwise.
     */
    ledgeGrab: {
        /** Body Y offset from ledge top while hanging (negative — feet
         *  below the ledge so the body looks like it's gripping the
         *  edge). */
        hangOffsetY: number;
        /** Gap (m) the hanging body's front sits OUT from the wall face —
         *  added to the capsule radius to form the standoff along the wall's
         *  outward normal. Small positive = front just clears the face so the
         *  body grips the lip without clipping the wall. */
        hangOffsetForward: number;
        /** Exertion rise per second while hanging — drives slip-by-
         *  fatigue. The base exertion rise scale (massRatios) applies. */
        exertionRiseRate: number;
        /** Player must be airborne at least this long before a ledge-
         *  grab can engage — prevents auto-catching mid-jump. */
        minAirborneTime: number;
        /** Vertical kick (multiplier on jumpInitialVy) given on a
         *  mantle-up release. Just enough to put the body above the
         *  ledge so mantle's ledgeAhead probe still resolves correctly
         *  on the next tick. */
        mantleUpUpFactor: number;
    };
    /**
     * Mantle ability — auto-triggers when the player approaches a
     * reachable obstacle with forward intent. The body follows a scripted
     * path (horizontal + vertical eases) onto the surface; player input
     * is suspended for the path's duration. Fields here are consumed by
     * the {@link Mantle} ability if registered; ignored otherwise.
     */
    mantle: {
        /** Below this height (m above feet), the obstacle is just a step
         *  the player can walk over — no mantle. */
        minHeight: number;
        /** Above this, the surface is out of reach — no mantle. ~1.4m
         *  is chest height for a 1.8m body, which is the canonical
         *  "obstacle you can climb on but not over without help". */
        maxHeight: number;
        /** Total scripted-path duration (seconds). Short enough that the
         *  brief loss of player control isn't frustrating. */
        duration: number;
        /** How far past the obstacle edge the player lands (m). Slight
         *  forward bias so the player ends on top of the surface, not
         *  on the edge. */
        forwardOffsetOnLand: number;
    };
    /**
     * Slide ability — activates from sprint+crouch when grounded. The
     * fields here are read by the {@link Slide} ability if it's registered
     * on the controller; unused if Slide is not in use.
     */
    slide: {
        /**
         * Required horizontal speed to start a slide. Below this,
         * crouch + sprint just transitions to a normal crouched walk.
         *
         * The default — `7.5 m/s` — sits between walkSpeed (4.5) and
         * sprintSpeed (9), at ~83 % of sprint. Earning the slide is
         * enforced by the ground-accel model: with
         * `groundAccelHalfLife = 0.116 s`, reaching this threshold
         * from standstill takes ~300 ms of sustained sprint — well
         * past a normal reaction window. Walking off a ledge or
         * accelerating down a slope into a slide is explicitly
         * supported: anything that brings the player's horizontal
         * speed above this threshold lets crouch engage a slide.
         * (Following Apex Legends' velocity-only gate at 200 hu/s.)
         */
        minEntrySpeed: number;
        /** Auto-exit threshold — slide ends when speed drops below this. */
        endSpeed: number;
        /** Horizontal deceleration (m/s²) while sliding. Lower than the
         *  normal groundDecel so slides preserve momentum longer. */
        friction: number;
        /** Non-interruptible window (seconds) after slide start — higher-
         *  priority abilities can't preempt during this window so the
         *  player isn't yanked out the instant they commit to a slide. */
        startupWindow: number;
        /** Multiplier on the jump initial Vy for slide-jump. 1.0 = same
         *  height as a standing jump; >1 gives slide-jump some extra
         *  reward for chaining the input. */
        slideJumpUpFactor: number;
        /** Vertical-impact-spring kick (m/s) at slide entry — the
         *  satisfying "thud" of dropping into the slide. */
        entryImpactVelocity: number;
    };
    bob: {
        stepFreqAtWalk: number;
        stepFreqExp: number;
        verticalAmpAtWalk: number;
        lateralAmpAtWalk: number;
        /** Extra amplitude per kg above 80kg (reference mass). */
        ampMassScale: number;
        rollAtWalkDeg: number;
        /** Speeds below this don't tick the stride at all. */
        minStepSpeed: number;
        /**
         * Half-life of the bob-amplitude envelope (seconds). When the player
         * starts/stops moving, the bob amplitude springs toward its natural
         * value rather than cutting on/off — so releasing a movement key
         * doesn't whiplash the head from full sway back to neutral. The
         * stride phase itself still freezes when stationary; only the
         * AMPLITUDE is temporally smoothed.
         */
        intensityHalfLife: number;
        /**
         * Vertical impact spring — kicked downward at each footfall. The
         * spring's response shapes the actual vertical motion of the head:
         * a sharp dip (foot arresting the head's fall), recovery through
         * neutral, and a slight overshoot above neutral as the standing
         * leg injects energy into the body (the "push" phase). Models the
         * gait COM trajectory more accurately than a smooth sinusoid.
         */
        impactSpringHalfLife: number;
        /** zeta < 1 → spring overshoots after impact, sells the leg-push. */
        impactSpringZeta: number;
        /**
         * Multiplier converting "desired peak dip" (verticalAmpAtWalk + mass
         * boost, scaled by intensity and back-pedal factor) into the actual
         * velocity impulse delivered at footfall. Empirical — tuned so the
         * default verticalAmpAtWalk produces the expected peak dip with the
         * spring params above.
         */
        impactKickMultiplier: number;
        /**
         * Multipliers applied to bob amplitude when the player is moving
         * backward (interpolated by "backwardness" — the negative dot of
         * velocity onto screen-forward, normalized to sprint speed). At
         * full back-pedal these are fully applied; at rest they have no
         * effect.
         *
         * Lateral is intentionally larger than vertical: real back-gait
         * has worse side-to-side balance than vertical compression, so
         * the visual wobble should track that. Roll boosts each footfall's
         * head-tilt for the same reason — sells "unstable footing".
         */
        backwardVerticalAmpFactor: number;
        backwardLateralAmpFactor: number;
        backwardRollFactor: number;
        /**
         * Bob roll × lean coupling: when the body is leaning into a turn
         * (lean spring displaced), the per-stride head roll is biased
         * toward the lean direction. At 0 the bob roll is symmetric
         * regardless of lean. At 1.0 the bob roll excursions in the lean
         * direction are doubled and the opposite-direction excursions go to
         * zero. Typical 0.3–0.6 reads as a cohesive "leaning while running"
         * gait. Normalized against cfg.lean.maxRollDeg so the coupling
         * stays proportional regardless of how aggressive lean is tuned.
         */
        leanCouplingFactor: number;
    };
    breath: {
        rateRestHz: number;
        rateMaxHz: number;
        amplitudeRestM: number;
        amplitudeMaxM: number;
        pitchAmpRestDeg: number;
        pitchAmpMaxDeg: number;
        /** ±20% amplitude noise rides on the sine. */
        noiseAmount: number;
        /**
         * Locomotor-respiratory coupling strength at full exertion. The
         * breath-rate target is blended between purely metabolic (driven by
         * exertion) and stride-aligned (an integer N strides per breath
         * cycle). At 0 no coupling; at 1 breath rate is fully pulled toward
         * the stride-aligned target.
         *
         * Coupling is SCALED by exertion — low exertion means the breath is
         * dictated by metabolic demand alone, high sustained effort lets
         * the diaphragm couple to gait impacts (mechanistically: heavier
         * breathing means deeper chest excursions, which the gait's
         * vertical accelerations bias toward integer ratios). Matches
         * empirical findings in dynamic activity (Bernasconi & Kohl 1993,
         * Bramble & Carrier 1983) — much weaker than steady-state running.
         *
         * Frequency-coupled only, NOT phase-locked: breath rate matches a
         * sub-multiple of stride rate, but phase drifts. Holds the "loose"
         * character the user asked for.
         */
        locomotorCouplingMax: number;
        /** Coupling does not engage below this stride frequency (Hz). At
         *  walking pace your gait is too slow to mechanically influence
         *  breath; coupling really shows up at jog+ pace. */
        couplingMinStrideFreqHz: number;
    };
    exertion: {
        /** Per-second accumulation while sprinting (mass-scaled internally). */
        sprintRiseRate: number;
        /** Per-second decay toward 0 when not under sustained load. */
        idleDecayRate: number;
        /** Bump on jump fire — the muscular impulse of pushing off. */
        jumpRise: number;
        /** Bump on crouch-enter — the knee-grip on absorbing into a crouch.
         *  Small; we don't want crouch-spamming to instantly exhaust. */
        crouchEnterRise: number;
        /**
         * Per-(m/s) impulse on landing — proportional to vertical impact
         * speed. A clean low-jump landing barely registers; a hard fall
         * delivers a noticeable bump. Clamped internally so an impossible
         * fall doesn't max out exertion in one tick.
         */
        landImpulsePerVy: number;
        /** Max impulse magnitude added by any single landing. */
        landImpulseMax: number;
        /** How long after exertion subsides before breath rate normalizes. */
        rateDecayHalfLife: number;
        /** How long after exertion subsides before breath amplitude normalizes. */
        ampDecayHalfLife: number;
        /** At full exertion, bob lateral amp is multiplied by 1 + this.
         *  Sells "tired wobble" — modest effect (10–20% recommended). */
        bobLateralBoostAtMax: number;
        /** At full exertion, the head droops forward by this many degrees.
         *  Sells visual fatigue without compromising aim. Subtle. */
        headDroopAtMaxDeg: number;
        /** Spring half-life for the head-droop transition. */
        headDroopHalfLife: number;
    };
    lean: {
        enabled: boolean;
        /** Degrees of roll per (lateral m/s^2 / 9.81). */
        maxRollDeg: number;
        spring: {
            halfLife: number;
            zeta: number;
        };
        /**
         * Yaw-rate "look-lean": camera banks into mouse-driven turns even
         * without strafe input. Disable for motion-sickness sensitivity.
         */
        lookLeanEnabled: boolean;
        /**
         * Degrees of roll per rad/s of yaw rate. ~3 means a 180°/s turn
         * (slow camera pan) gives ~16.5° of bank; a fast mouse flick at
         * 5 rad/s (≈286°/s) would saturate against the clamp below.
         */
        lookLeanDegPerRadPerSec: number;
        /** Yaw rate is clamped to ±this (rad/s) before scaling — prevents
         *  single-frame flicks from spiking the lean target. */
        lookLeanYawRateClamp: number;
        /**
         * Multiplier applied to look-lean (yaw-rate banking) when crouched.
         * Crouched stance is low and stable; banking from a mouse turn
         * reads as unmotivated. Default 0 fully disables; dial up to add
         * a subtle tilt without it feeling like you're running. The lateral-
         * acceleration lean is NOT affected by this — it scales naturally
         * with crouch speeds since accel magnitudes drop.
         */
        crouchLookLeanFactor: number;
    };
    fov: {
        base: number;
        sprintAdd: number;
        crouchAdd: number;
        smoothHalfLife: number;
    };
    look: {
        pitchMinDeg: number;
        pitchMaxDeg: number;
        invertY: boolean;
    };
    /**
     * Postural shifts driven by intent — distinct from look (which is
     * player-driven) and from bob (which is procedural). Models
     * Mirror's Edge-style "commitment to motion": sprinting tilts the head
     * forward as the body leans into the run. Slow spring so it builds up
     * over a second or so rather than snapping — it's a *posture* change,
     * not a flick.
     */
    posture: {
        /** Forward pitch (deg) applied to the eye at full sprint. Positive = look-down. */
        sprintForwardPitchDeg: number;
        /** Spring half-life for the sprint pitch transition. */
        sprintForwardPitchHalfLife: number;
        /** Small forward eye-position shift (m) at full sprint — head leads the hips. */
        sprintForwardShiftM: number;
    };
    gravity: {
        /** Default gravity magnitude (m/s^2). Overridden by computeJumpFromApex once
         *  the jump tunables are resolved; kept here so non-jumping entities (NPCs,
         *  paused players) still have a sensible fall behavior. */
        magnitude: number;
    };
    toJSON(): {
        body: {
            /** Standing eye height, meters above body origin. */
            height: number;
            /** Crouched eye height. */
            crouchHeight: number;
            /** Prone eye height (used by slide). Body is horizontal — eye
             *  just above ground level, head turned toward the direction
             *  of travel. */
            proneHeight: number;
            /** Capsule radius, for downstream physics. */
            radius: number;
            /** Kilograms — affects bob, jump, landing, accel, and exertion via massRatio. */
            mass: number;
            /** Reference mass against which `mass` is normalized (massRatio = mass/refMass). */
            referenceMass: number;
            /**
             * How strongly `mass` couples into derived effects. 0 = mass is
             * cosmetic; 1.0 = full coupling (heavier ⇒ lower jump, lower accel,
             * harder landing, faster exhaustion). At 1.0 a 25% mass increase
             * yields:
             *   jump peak       ≈ 0.83×   (∝ 1/√massRatio — kinematically motivated)
             *   ground accel    ≈ 0.80×   (∝ 1/massRatio — F = ma at fixed force)
             *   landing dip     ≈ 1.25×   (∝ massRatio — higher momentum to absorb)
             *   exertion rise   ≈ 1.25×   (∝ massRatio — more body to move)
             */
            massCouplingStrength: number;
        };
        motion: {
            walkSpeed: number;
            sprintSpeed: number;
            crouchSpeed: number;
            /** [0..1] how much intent influences velocity while airborne. */
            airControl: number;
            /**
             * Half-life (seconds) for the mono-exponential approach to top
             * sprint speed on the ground. The controller's ground-accel
             * model is Hill-based:
             *     v(t) = v_max · (1 − e^(−t / τ))
             * with τ = halfLife / ln 2. At each tick the velocity halves
             * the remaining gap to `targetSpeed` every `halfLife` seconds.
             *
             * Default `0.116 s` gives ~95 % of `sprintSpeed` reached in
             * 500 ms — the Apex Legends / Titanfall / modern CoD ramp
             * window. The curve is naturally non-uniform: roughly 45 %
             * of top speed in the first 100 ms, then the last 5 % takes
             * 300 ms — so a quick tap-and-go still feels snappy while
             * follow-up moves (slide, sprint-jump) require committed
             * sprint time to be at top speed.
             *
             * Literature: Hill 1927 / Furusawa-Hill 1928 (force-velocity
             * curve, original analytical formulation); Morin & Samozino
             * 2016 (modern sprint profiling using the same mono-exp fit).
             */
            groundAccelHalfLife: number;
            /** m/s^2 horizontal deceleration toward 0 when intent is zero. */
            groundDecel: number;
            /** m/s^2 horizontal acceleration while airborne. */
            airAccel: number;
            /**
             * Top-speed multiplier applied while the move intent has a backward
             * component (intent.move.y < 0). Backpedaling is mechanically slower
             * than running forward — this also enforces a hard cap rather than
             * letting "backward sprint" reach the same speed as forward sprint.
             */
            backwardSpeedFactor: number;
            /**
             * Acceleration multiplier while moving backward. Body has worse
             * mechanical advantage when reversing — slower to start, slower to
             * stop, sells the "fighting the gait" feel.
             */
            backwardAccelFactor: number;
        };
        jump: {
            anticipation: {
                duration: number;
                dipAmount: number;
            };
            /** Apex height of a clean jump, meters. */
            peakHeight: number;
            /** Seconds to reach apex from launch. Together these two derive g. */
            timeToApex: number;
            coyoteTime: number;
            bufferTime: number;
            /** Gravity multiplier while falling (vy <= 0). */
            fallGravityMult: number;
            /** Gravity multiplier when jump released early during ascent. */
            cutGravityMult: number;
        };
        landing: {
            recovery: {
                spring: {
                    halfLife: number;
                    /** zeta < 1 → rings once before settling, reads as compression. */
                    zeta: number;
                };
                /** Meters of eye dip per m/s of impact velocity. */
                dipPerVy: number;
                /** Clamp on total dip. */
                dipMax: number;
            };
            /** m/s impact threshold; below = soft landing signal. */
            softThreshold: number;
            /** m/s impact threshold; above = hard landing signal. */
            hardThreshold: number;
        };
        crouch: {
            /** Seconds to lerp eye height between standing and crouched. */
            transitionTime: number;
            /** "hold" or "toggle" */
            mode: string;
        };
        ledgeGrab: {
            /** Body Y offset from ledge top while hanging (negative — feet
             *  below the ledge so the body looks like it's gripping the
             *  edge). */
            hangOffsetY: number;
            /** Gap (m) the hanging body's front sits OUT from the wall face —
             *  added to the capsule radius to form the standoff along the wall's
             *  outward normal. Small positive = front just clears the face so the
             *  body grips the lip without clipping the wall. */
            hangOffsetForward: number;
            /** Exertion rise per second while hanging — drives slip-by-
             *  fatigue. The base exertion rise scale (massRatios) applies. */
            exertionRiseRate: number;
            /** Player must be airborne at least this long before a ledge-
             *  grab can engage — prevents auto-catching mid-jump. */
            minAirborneTime: number;
            /** Vertical kick (multiplier on jumpInitialVy) given on a
             *  mantle-up release. Just enough to put the body above the
             *  ledge so mantle's ledgeAhead probe still resolves correctly
             *  on the next tick. */
            mantleUpUpFactor: number;
        };
        mantle: {
            /** Below this height (m above feet), the obstacle is just a step
             *  the player can walk over — no mantle. */
            minHeight: number;
            /** Above this, the surface is out of reach — no mantle. ~1.4m
             *  is chest height for a 1.8m body, which is the canonical
             *  "obstacle you can climb on but not over without help". */
            maxHeight: number;
            /** Total scripted-path duration (seconds). Short enough that the
             *  brief loss of player control isn't frustrating. */
            duration: number;
            /** How far past the obstacle edge the player lands (m). Slight
             *  forward bias so the player ends on top of the surface, not
             *  on the edge. */
            forwardOffsetOnLand: number;
        };
        wallRun: {
            /**
             * Minimum horizontal speed (m/s) to engage wall-run. Set ABOVE
             * walkSpeed (4.5) so a wall-run is earned by a committed RUN — a walk
             * into the wall, or falling alongside it with leftover momentum,
             * shouldn't grab on. Below the ~7 m/s a sprint-into-wall carries.
             */
            minSpeed: number;
            /** Player must be airborne at least this long before wall-run can
             *  engage — prevents wall-run triggering off a jump's first frames. */
            minAirborneTime: number;
            /** Maximum wall-run duration (s). Auto-exits at the end. */
            maxDuration: number;
            /** Multiplier on base gravity while wall-running. Lower = longer hang. */
            gravityFactor: number;
            /** Camera tilt magnitude (deg) into the wall. Disabled by the
             *  motion-sickness toggle alongside the standard lean. */
            cameraRollDeg: number;
        };
        wallJump: {
            /** Impulse magnitude away from the wall (m/s, applied along wall normal). */
            outwardImpulse: number;
            /** Upward component multiplier on jumpInitialVy. */
            upFactor: number;
            /** Max distance to wall (m) at which a near-wall-airborne wall-jump
             *  is allowed (when not already wall-running). */
            nearWallMaxDistance: number;
        };
        slide: {
            /**
             * Required horizontal speed to start a slide. Below this,
             * crouch + sprint just transitions to a normal crouched walk.
             *
             * The default — `7.5 m/s` — sits between walkSpeed (4.5) and
             * sprintSpeed (9), at ~83 % of sprint. Earning the slide is
             * enforced by the ground-accel model: with
             * `groundAccelHalfLife = 0.116 s`, reaching this threshold
             * from standstill takes ~300 ms of sustained sprint — well
             * past a normal reaction window. Walking off a ledge or
             * accelerating down a slope into a slide is explicitly
             * supported: anything that brings the player's horizontal
             * speed above this threshold lets crouch engage a slide.
             * (Following Apex Legends' velocity-only gate at 200 hu/s.)
             */
            minEntrySpeed: number;
            /** Auto-exit threshold — slide ends when speed drops below this. */
            endSpeed: number;
            /** Horizontal deceleration (m/s²) while sliding. Lower than the
             *  normal groundDecel so slides preserve momentum longer. */
            friction: number;
            /** Non-interruptible window (seconds) after slide start — higher-
             *  priority abilities can't preempt during this window so the
             *  player isn't yanked out the instant they commit to a slide. */
            startupWindow: number;
            /** Multiplier on the jump initial Vy for slide-jump. 1.0 = same
             *  height as a standing jump; >1 gives slide-jump some extra
             *  reward for chaining the input. */
            slideJumpUpFactor: number;
            /** Vertical-impact-spring kick (m/s) at slide entry — the
             *  satisfying "thud" of dropping into the slide. */
            entryImpactVelocity: number;
        };
        bob: {
            stepFreqAtWalk: number;
            stepFreqExp: number;
            verticalAmpAtWalk: number;
            lateralAmpAtWalk: number;
            /** Extra amplitude per kg above 80kg (reference mass). */
            ampMassScale: number;
            rollAtWalkDeg: number;
            /** Speeds below this don't tick the stride at all. */
            minStepSpeed: number;
            /**
             * Half-life of the bob-amplitude envelope (seconds). When the player
             * starts/stops moving, the bob amplitude springs toward its natural
             * value rather than cutting on/off — so releasing a movement key
             * doesn't whiplash the head from full sway back to neutral. The
             * stride phase itself still freezes when stationary; only the
             * AMPLITUDE is temporally smoothed.
             */
            intensityHalfLife: number;
            /**
             * Vertical impact spring — kicked downward at each footfall. The
             * spring's response shapes the actual vertical motion of the head:
             * a sharp dip (foot arresting the head's fall), recovery through
             * neutral, and a slight overshoot above neutral as the standing
             * leg injects energy into the body (the "push" phase). Models the
             * gait COM trajectory more accurately than a smooth sinusoid.
             */
            impactSpringHalfLife: number;
            /** zeta < 1 → spring overshoots after impact, sells the leg-push. */
            impactSpringZeta: number;
            /**
             * Multiplier converting "desired peak dip" (verticalAmpAtWalk + mass
             * boost, scaled by intensity and back-pedal factor) into the actual
             * velocity impulse delivered at footfall. Empirical — tuned so the
             * default verticalAmpAtWalk produces the expected peak dip with the
             * spring params above.
             */
            impactKickMultiplier: number;
            /**
             * Multipliers applied to bob amplitude when the player is moving
             * backward (interpolated by "backwardness" — the negative dot of
             * velocity onto screen-forward, normalized to sprint speed). At
             * full back-pedal these are fully applied; at rest they have no
             * effect.
             *
             * Lateral is intentionally larger than vertical: real back-gait
             * has worse side-to-side balance than vertical compression, so
             * the visual wobble should track that. Roll boosts each footfall's
             * head-tilt for the same reason — sells "unstable footing".
             */
            backwardVerticalAmpFactor: number;
            backwardLateralAmpFactor: number;
            backwardRollFactor: number;
            /**
             * Bob roll × lean coupling: when the body is leaning into a turn
             * (lean spring displaced), the per-stride head roll is biased
             * toward the lean direction. At 0 the bob roll is symmetric
             * regardless of lean. At 1.0 the bob roll excursions in the lean
             * direction are doubled and the opposite-direction excursions go to
             * zero. Typical 0.3–0.6 reads as a cohesive "leaning while running"
             * gait. Normalized against cfg.lean.maxRollDeg so the coupling
             * stays proportional regardless of how aggressive lean is tuned.
             */
            leanCouplingFactor: number;
        };
        breath: {
            rateRestHz: number;
            rateMaxHz: number;
            amplitudeRestM: number;
            amplitudeMaxM: number;
            pitchAmpRestDeg: number;
            pitchAmpMaxDeg: number;
            /** ±20% amplitude noise rides on the sine. */
            noiseAmount: number;
            /**
             * Locomotor-respiratory coupling strength at full exertion. The
             * breath-rate target is blended between purely metabolic (driven by
             * exertion) and stride-aligned (an integer N strides per breath
             * cycle). At 0 no coupling; at 1 breath rate is fully pulled toward
             * the stride-aligned target.
             *
             * Coupling is SCALED by exertion — low exertion means the breath is
             * dictated by metabolic demand alone, high sustained effort lets
             * the diaphragm couple to gait impacts (mechanistically: heavier
             * breathing means deeper chest excursions, which the gait's
             * vertical accelerations bias toward integer ratios). Matches
             * empirical findings in dynamic activity (Bernasconi & Kohl 1993,
             * Bramble & Carrier 1983) — much weaker than steady-state running.
             *
             * Frequency-coupled only, NOT phase-locked: breath rate matches a
             * sub-multiple of stride rate, but phase drifts. Holds the "loose"
             * character the user asked for.
             */
            locomotorCouplingMax: number;
            /** Coupling does not engage below this stride frequency (Hz). At
             *  walking pace your gait is too slow to mechanically influence
             *  breath; coupling really shows up at jog+ pace. */
            couplingMinStrideFreqHz: number;
        };
        exertion: {
            /** Per-second accumulation while sprinting (mass-scaled internally). */
            sprintRiseRate: number;
            /** Per-second decay toward 0 when not under sustained load. */
            idleDecayRate: number;
            /** Bump on jump fire — the muscular impulse of pushing off. */
            jumpRise: number;
            /** Bump on crouch-enter — the knee-grip on absorbing into a crouch.
             *  Small; we don't want crouch-spamming to instantly exhaust. */
            crouchEnterRise: number;
            /**
             * Per-(m/s) impulse on landing — proportional to vertical impact
             * speed. A clean low-jump landing barely registers; a hard fall
             * delivers a noticeable bump. Clamped internally so an impossible
             * fall doesn't max out exertion in one tick.
             */
            landImpulsePerVy: number;
            /** Max impulse magnitude added by any single landing. */
            landImpulseMax: number;
            /** How long after exertion subsides before breath rate normalizes. */
            rateDecayHalfLife: number;
            /** How long after exertion subsides before breath amplitude normalizes. */
            ampDecayHalfLife: number;
            /** At full exertion, bob lateral amp is multiplied by 1 + this.
             *  Sells "tired wobble" — modest effect (10–20% recommended). */
            bobLateralBoostAtMax: number;
            /** At full exertion, the head droops forward by this many degrees.
             *  Sells visual fatigue without compromising aim. Subtle. */
            headDroopAtMaxDeg: number;
            /** Spring half-life for the head-droop transition. */
            headDroopHalfLife: number;
        };
        lean: {
            spring: {
                halfLife: number;
                zeta: number;
            };
            enabled: boolean;
            /** Degrees of roll per (lateral m/s^2 / 9.81). */
            maxRollDeg: number;
            /**
             * Yaw-rate "look-lean": camera banks into mouse-driven turns even
             * without strafe input. Disable for motion-sickness sensitivity.
             */
            lookLeanEnabled: boolean;
            /**
             * Degrees of roll per rad/s of yaw rate. ~3 means a 180°/s turn
             * (slow camera pan) gives ~16.5° of bank; a fast mouse flick at
             * 5 rad/s (≈286°/s) would saturate against the clamp below.
             */
            lookLeanDegPerRadPerSec: number;
            /** Yaw rate is clamped to ±this (rad/s) before scaling — prevents
             *  single-frame flicks from spiking the lean target. */
            lookLeanYawRateClamp: number;
            /**
             * Multiplier applied to look-lean (yaw-rate banking) when crouched.
             * Crouched stance is low and stable; banking from a mouse turn
             * reads as unmotivated. Default 0 fully disables; dial up to add
             * a subtle tilt without it feeling like you're running. The lateral-
             * acceleration lean is NOT affected by this — it scales naturally
             * with crouch speeds since accel magnitudes drop.
             */
            crouchLookLeanFactor: number;
        };
        fov: {
            base: number;
            sprintAdd: number;
            crouchAdd: number;
            smoothHalfLife: number;
        };
        look: {
            pitchMinDeg: number;
            pitchMaxDeg: number;
            invertY: boolean;
        };
        posture: {
            /** Forward pitch (deg) applied to the eye at full sprint. Positive = look-down. */
            sprintForwardPitchDeg: number;
            /** Spring half-life for the sprint pitch transition. */
            sprintForwardPitchHalfLife: number;
            /** Small forward eye-position shift (m) at full sprint — head leads the hips. */
            sprintForwardShiftM: number;
        };
        gravity: {
            /** Default gravity magnitude (m/s^2). Overridden by computeJumpFromApex once
             *  the jump tunables are resolved; kept here so non-jumping entities (NPCs,
             *  paused players) still have a sensible fall behavior. */
            magnitude: number;
        };
    };
    fromJSON(json: any): void;
    /**
     * @param {FirstPersonPlayerControllerConfig} other
     */
    copy(other: FirstPersonPlayerControllerConfig): void;
    clone(): FirstPersonPlayerControllerConfig;
}
//# sourceMappingURL=FirstPersonPlayerControllerConfig.d.ts.map