Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | 5x 5x 5x 5x 5x 9753x 9753x 9753x 9753x 9753x 9753x 9753x 9753x 9753x 9753x 214566x 214566x 214566x 214566x 214566x 214566x 9753x 107283x 107283x 107283x 107283x 107283x 107283x 107283x 107283x 9753x 9753x 9753x 9753x 9753x 5x 9753x 9753x 107283x 9753x 321870x | import { warning } from "hey-listen"
import { clamp } from "../../utils/clamp"
import { SpringOptions } from "../types"
/**
* This is ported from the Framer implementation of duration-based spring resolution.
*/
type Resolver = (num: number) => number
const safeMin = 0.001
export const minDuration = 0.01
export const maxDuration = 10.0
export const minDamping = 0.05
export const maxDamping = 1
export function findSpring({
duration = 800,
bounce = 0.25,
velocity = 0,
mass = 1,
}: SpringOptions) {
let envelope: Resolver
let derivative: Resolver
warning(
duration <= maxDuration * 1000,
"Spring duration must be 10 seconds or less"
)
let dampingRatio = 1 - bounce
/**
* Restrict dampingRatio and duration to within acceptable ranges.
*/
dampingRatio = clamp(minDamping, maxDamping, dampingRatio)
duration = clamp(minDuration, maxDuration, duration / 1000)
Eif (dampingRatio < 1) {
/**
* Underdamped spring
*/
envelope = (undampedFreq) => {
const exponentialDecay = undampedFreq * dampingRatio
const delta = exponentialDecay * duration
const a = exponentialDecay - velocity
const b = calcAngularFreq(undampedFreq, dampingRatio)
const c = Math.exp(-delta)
return safeMin - (a / b) * c
}
derivative = (undampedFreq) => {
const exponentialDecay = undampedFreq * dampingRatio
const delta = exponentialDecay * duration
const d = delta * velocity + velocity
const e =
Math.pow(dampingRatio, 2) * Math.pow(undampedFreq, 2) * duration
const f = Math.exp(-delta)
const g = calcAngularFreq(Math.pow(undampedFreq, 2), dampingRatio)
const factor = -envelope(undampedFreq) + safeMin > 0 ? -1 : 1
return (factor * ((d - e) * f)) / g
}
} else {
/**
* Critically-damped spring
*/
envelope = (undampedFreq) => {
const a = Math.exp(-undampedFreq * duration)
const b = (undampedFreq - velocity) * duration + 1
return -safeMin + a * b
}
derivative = (undampedFreq) => {
const a = Math.exp(-undampedFreq * duration)
const b = (velocity - undampedFreq) * (duration * duration)
return a * b
}
}
const initialGuess = 5 / duration
const undampedFreq = approximateRoot(envelope, derivative, initialGuess)
Iif (isNaN(undampedFreq)) {
return {
stiffness: 100,
damping: 10,
}
} else {
const stiffness = Math.pow(undampedFreq, 2) * mass
return {
stiffness,
damping: dampingRatio * 2 * Math.sqrt(mass * stiffness),
}
}
}
const rootIterations = 12
function approximateRoot(
envelope: Resolver,
derivative: Resolver,
initialGuess: number
): number {
let result = initialGuess
for (let i = 1; i < rootIterations; i++) {
result = result - envelope(result) / derivative(result)
}
return result
}
export function calcAngularFreq(undampedFreq: number, dampingRatio: number) {
return undampedFreq * Math.sqrt(1 - dampingRatio * dampingRatio)
}
|