{"version":3,"file":"index.mjs","sources":["../../../../../src/animation/generators/spring/index.ts"],"sourcesContent":["import {\n    clamp,\n    millisecondsToSeconds,\n    secondsToMilliseconds,\n} from \"motion-utils\"\nimport {\n    AnimationState,\n    KeyframeGenerator,\n    SpringOptions,\n    Transition,\n    ValueAnimationOptions,\n} from \"../../types\"\nimport { generateLinearEasing } from \"../../waapi/utils/linear\"\nimport {\n    calcGeneratorDuration,\n    maxGeneratorDuration,\n} from \"../utils/calc-duration\"\nimport { createGeneratorEasing } from \"../utils/create-generator-easing\"\nimport { calcGeneratorVelocity } from \"../utils/velocity\"\nimport { springDefaults } from \"./defaults\"\nimport { calcAngularFreq, findSpring } from \"./find\"\n\nconst durationKeys = [\"duration\", \"bounce\"]\nconst physicsKeys = [\"stiffness\", \"damping\", \"mass\"]\n\nfunction isSpringType(options: SpringOptions, keys: string[]) {\n    return keys.some((key) => (options as any)[key] !== undefined)\n}\n\nfunction getSpringOptions(options: SpringOptions) {\n    let springOptions = {\n        velocity: springDefaults.velocity,\n        stiffness: springDefaults.stiffness,\n        damping: springDefaults.damping,\n        mass: springDefaults.mass,\n        isResolvedFromDuration: false,\n        ...options,\n    }\n    // stiffness/damping/mass overrides duration/bounce\n    if (\n        !isSpringType(options, physicsKeys) &&\n        isSpringType(options, durationKeys)\n    ) {\n        // Time-defined springs should ignore inherited velocity.\n        // Velocity from interrupted animations can cause findSpring()\n        // to compute wildly different spring parameters, leading to\n        // massive oscillation on small-range animations.\n        springOptions.velocity = 0\n\n        if (options.visualDuration) {\n            const visualDuration = options.visualDuration\n            const root = (2 * Math.PI) / (visualDuration * 1.2)\n            const stiffness = root * root\n            const damping =\n                2 *\n                clamp(0.05, 1, 1 - (options.bounce || 0)) *\n                Math.sqrt(stiffness)\n\n            springOptions = {\n                ...springOptions,\n                mass: springDefaults.mass,\n                stiffness,\n                damping,\n            }\n        } else {\n            const derived = findSpring({ ...options, velocity: 0 })\n\n            springOptions = {\n                ...springOptions,\n                ...derived,\n                mass: springDefaults.mass,\n            }\n            springOptions.isResolvedFromDuration = true\n        }\n    }\n\n    return springOptions\n}\n\nfunction spring(\n    optionsOrVisualDuration:\n        | ValueAnimationOptions<number>\n        | number = springDefaults.visualDuration,\n    bounce = springDefaults.bounce\n): KeyframeGenerator<number> {\n    const options =\n        typeof optionsOrVisualDuration !== \"object\"\n            ? ({\n                  visualDuration: optionsOrVisualDuration,\n                  keyframes: [0, 1],\n                  bounce,\n              } as ValueAnimationOptions<number>)\n            : optionsOrVisualDuration\n\n    let { restSpeed, restDelta } = options\n\n    const origin = options.keyframes[0]\n    const target = options.keyframes[options.keyframes.length - 1]\n\n    /**\n     * This is the Iterator-spec return value. We ensure it's mutable rather than using a generator\n     * to reduce GC during animation.\n     */\n    const state: AnimationState<number> = { done: false, value: origin }\n\n    const {\n        stiffness,\n        damping,\n        mass,\n        duration,\n        velocity,\n        isResolvedFromDuration,\n    } = getSpringOptions({\n        ...options,\n        velocity: -millisecondsToSeconds(options.velocity || 0),\n    })\n\n    const initialVelocity = velocity || 0.0\n    const dampingRatio = damping / (2 * Math.sqrt(stiffness * mass))\n\n    const initialDelta = target - origin\n    const undampedAngularFreq = millisecondsToSeconds(\n        Math.sqrt(stiffness / mass)\n    )\n\n    /**\n     * If we're working on a granular scale, use smaller defaults for determining\n     * when the spring is finished.\n     *\n     * These defaults have been selected emprically based on what strikes a good\n     * ratio between feeling good and finishing as soon as changes are imperceptible.\n     */\n    const isGranularScale = Math.abs(initialDelta) < 5\n    restSpeed ||= isGranularScale\n        ? springDefaults.restSpeed.granular\n        : springDefaults.restSpeed.default\n    restDelta ||= isGranularScale\n        ? springDefaults.restDelta.granular\n        : springDefaults.restDelta.default\n\n    let resolveSpring: (v: number) => number\n    if (dampingRatio < 1) {\n        const angularFreq = calcAngularFreq(undampedAngularFreq, dampingRatio)\n\n        // Underdamped spring\n        resolveSpring = (t: number) => {\n            const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t)\n\n            return (\n                target -\n                envelope *\n                    (((initialVelocity +\n                        dampingRatio * undampedAngularFreq * initialDelta) /\n                        angularFreq) *\n                        Math.sin(angularFreq * t) +\n                        initialDelta * Math.cos(angularFreq * t))\n            )\n        }\n    } else if (dampingRatio === 1) {\n        // Critically damped spring\n        resolveSpring = (t: number) =>\n            target -\n            Math.exp(-undampedAngularFreq * t) *\n                (initialDelta +\n                    (initialVelocity + undampedAngularFreq * initialDelta) * t)\n    } else {\n        // Overdamped spring\n        const dampedAngularFreq =\n            undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1)\n\n        resolveSpring = (t: number) => {\n            const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t)\n\n            // When performing sinh or cosh values can hit Infinity so we cap them here\n            const freqForT = Math.min(dampedAngularFreq * t, 300)\n\n            return (\n                target -\n                (envelope *\n                    ((initialVelocity +\n                        dampingRatio * undampedAngularFreq * initialDelta) *\n                        Math.sinh(freqForT) +\n                        dampedAngularFreq *\n                            initialDelta *\n                            Math.cosh(freqForT))) /\n                    dampedAngularFreq\n            )\n        }\n    }\n\n    const generator = {\n        calculatedDuration: isResolvedFromDuration ? duration || null : null,\n        next: (t: number) => {\n            const current = resolveSpring(t)\n\n            if (!isResolvedFromDuration) {\n                let currentVelocity = t === 0 ? initialVelocity : 0.0\n\n                /**\n                 * We only need to calculate velocity for under-damped springs\n                 * as over- and critically-damped springs can't overshoot, so\n                 * checking only for displacement is enough.\n                 */\n                if (dampingRatio < 1) {\n                    currentVelocity =\n                        t === 0\n                            ? secondsToMilliseconds(initialVelocity)\n                            : calcGeneratorVelocity(resolveSpring, t, current)\n                }\n\n                const isBelowVelocityThreshold =\n                    Math.abs(currentVelocity) <= restSpeed!\n                const isBelowDisplacementThreshold =\n                    Math.abs(target - current) <= restDelta!\n\n                state.done =\n                    isBelowVelocityThreshold && isBelowDisplacementThreshold\n            } else {\n                state.done = t >= duration!\n            }\n\n            state.value = state.done ? target : current\n\n            return state\n        },\n        toString: () => {\n            const calculatedDuration = Math.min(\n                calcGeneratorDuration(generator),\n                maxGeneratorDuration\n            )\n\n            const easing = generateLinearEasing(\n                (progress: number) =>\n                    generator.next(calculatedDuration * progress).value,\n                calculatedDuration,\n                30\n            )\n\n            return calculatedDuration + \"ms \" + easing\n        },\n        toTransition: () => {},\n    }\n\n    return generator\n}\n\nspring.applyToOptions = (options: Transition) => {\n    const generatorOptions = createGeneratorEasing(options as any, 100, spring)\n\n    options.ease = generatorOptions.ease\n    options.duration = secondsToMilliseconds(generatorOptions.duration)\n    options.type = \"keyframes\"\n    return options\n}\n\nexport { spring }\n"],"names":[],"mappings":"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"}