/** A per-frame camera shake offset: three positional axes plus three rotational axes (radians). */ export interface CameraShakeOffset { /** Positional kick along camera-space X. */ x: number; /** Positional kick along camera-space Y. */ y: number; /** Positional kick along camera-space Z. */ z: number; /** Rotational kick about the pitch axis (radians). */ pitch: number; /** Rotational kick about the yaw axis (radians). */ yaw: number; /** Rotational kick about the roll axis (radians). */ roll: number; } /** Configuration for {@link createCameraShake}. Every field has a game-feel default. */ export interface CameraShakeConfig { /** Trauma bled off per second while `update` runs. Default `1.6`. */ decayPerSecond?: number; /** * Exponent applied to trauma before it drives the offset (`shake = trauma^exp`), * so small hits stay subtle and big hits dominate. Default `2` (the classic * "trauma squared" curve). */ traumaExponent?: number; /** Peak positional offset at full shake, per `[x, y, z]` axis (world units). Default `[0.6, 0.6, 0.4]`. */ maxTranslation?: readonly [number, number, number]; /** Peak rotational offset at full shake, per `[pitch, yaw, roll]` axis (radians). Default `[0.06, 0.06, 0.12]`. */ maxRotation?: readonly [number, number, number]; /** Base noise frequency (oscillations per second) sampled along the time cursor. Default `18`. */ frequency?: number; /** Deterministic seed for the value noise; same seed + dt sequence reproduces the same offsets. Default `"camera-shake"`. */ seed?: string | number; /** Injected clock (ms) used when `update` is called with no explicit dt. Default `Date.now`. */ now?: () => number; } /** Serializable state for save/restore and deterministic replay. */ export interface CameraShakeSnapshot { /** Current trauma in `[0, 1]`. */ trauma: number; /** Advancing time cursor (seconds) the noise is sampled along. */ time: number; /** The base value-noise seed as a plain integer. */ seed: number; /** The last free-string `kind` label handed to `add`, or `null`. */ kind: string | null; } /** A live, dt-driven, trauma-based camera shake controller. */ export interface CameraShakeController { /** * Add trauma (clamped into `[0, 1]`). `kind` is a free string the model never * interprets — it only carries it through so a game can style/label impacts * ("hit", "explosion", "landing", …). Larger hits raise the ceiling toward 1. */ add(amount: number, kind?: string): void; /** * Advance the shake: bleed trauma by `decayPerSecond` and move the noise time * cursor forward. Pass explicit `dt` seconds to drive deterministically, else * the injected clock supplies the delta since the last call. */ update(dt?: number): void; /** * The shake to apply this frame — a POOLED object reused across calls (read it, * don't retain it). Each axis is `trauma^traumaExponent * max[axis] * noise`, * where the noise is deterministic seeded value-noise sampled at the time cursor. */ offset(): CameraShakeOffset; /** Current trauma in `[0, 1]`. */ trauma(): number; /** The last free-string `kind` handed to `add`, or `undefined` if none yet. */ kind(): string | undefined; /** Patch the config in place (e.g. retune decay or amplitudes at runtime). */ configure(patch: Partial): void; /** Reset trauma to 0 (keeps the seed and time cursor). */ clear(): void; /** Observe changes (add, update, configure, clear, restore). Returns an unsubscribe fn. */ subscribe(listener: () => void): () => void; /** Serializable state for a save. */ snapshot(): CameraShakeSnapshot; /** Restore from a {@link CameraShakeSnapshot}. */ restore(snapshot: CameraShakeSnapshot): void; } /** * A seeded, serializable, trauma-based camera shake / impulse controller. A game * calls `add(amount, kind?)` on impacts (a hit, an explosion, a landing) to raise * trauma in `[0, 1]`; `update(dt)` bleeds it off over time; and `offset()` returns * a pooled `{ x, y, z, pitch, yaw, roll }` kick equal to `trauma^exponent` times * per-axis maxima times deterministic seeded value-noise sampled along an internal * time cursor. A shell consumer applies that offset to the active camera each frame * so the view visibly shakes. Nothing here is genre-specific: `kind` is a free * label the game styles, all amplitudes/decay are parameters, and `snapshot`/ * `restore` round-trips the shake through a save. Deterministic from `seed`: the * same seed and dt sequence reproduce the same offsets. * * @capability camera-shake seeded serializable trauma-based camera shake/impulse controller (hit/explosion/landing juice) with pooled per-frame translation+rotation offset and snapshot/restore */ export declare function createCameraShake(config?: CameraShakeConfig): CameraShakeController;