{"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 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)\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\n | number = springDefaults.visualDuration,\n bounce = springDefaults.bounce\n): KeyframeGenerator {\n const options =\n typeof optionsOrVisualDuration !== \"object\"\n ? ({\n visualDuration: optionsOrVisualDuration,\n keyframes: [0, 1],\n bounce,\n } as ValueAnimationOptions)\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 = { 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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"}