diff --git a/packages/motion-dom/src/animation/generators/__tests__/inertia.test.ts b/packages/motion-dom/src/animation/generators/__tests__/inertia.test.ts index 774b8f0e99..4ff9619b3e 100644 --- a/packages/motion-dom/src/animation/generators/__tests__/inertia.test.ts +++ b/packages/motion-dom/src/animation/generators/__tests__/inertia.test.ts @@ -360,56 +360,56 @@ const expectedAnimationKeyframesWithMin = [ 23.75667836122817, 21.30613194252669, 18.904109594038857, 16.54965047479793, 14.241812769762973, 11.979673313080411, 9.762327218805297, 7.5888875189348965, 5.458484808609711, 3.3702668983398354, - 1.323398473117905, -0.6829392417180884, -2.5504366392219304, - -4.119369806458783, -5.343809500682082, -6.198520496050522, - -6.678188018315215, -6.795773895279445, -6.580163132703302, - -6.073279953832154, -5.3268604416091545, -4.399067385327798, - -3.3511227480280765, -2.2441156429408005, -1.136120366010626, - -0.07973153617477233, 0.8799065562226499, 1.7065300468331976, - 2.37362871817985, 2.864773961641232, 3.1734378288347873, 3.302360175606138, - 3.2625368901677088, 3.0719132051868026, 2.753872074110266, - 2.335608739809387, 1.846479344239635, 1.3164042979261712, - 0.7743968519689656, 0.24727467923178975, -0.24140190124916064, - -0.6721363140548124, -1.0300328250543445, -1.30506452397808, - -1.4920851036546723, -1.5906082587432058, -1.6043872707269085, - -1.5408337146515911, -1.4103181408493322, -1.2253970992892542, - -1.0000101421945307, -0.7486877106164858, -0.48580640224657123, - -0.22492239948750456, 0.021792795705084606, 0.2439973191859265, - 0.4334948642340047, 0.5844188736374692, 0.6932888121343098, - 0.7589480259929683, 0.7823974026306241, 0.7665426279792613, - 0.7158752396658898, 0.6361088889525295, 0.5337923090315198, - 0.4159195452371194, 0.2895561763537697, 0.16149771617176029, - 0.037973319030147924, -0.07559548245909954, -0.17477481268355835, - -0.2562345571360686, -0.3178011178014577, -0.3584503485224228, - -0.3782466977185835, -0.37823656113066495, -0.36030525539150166, - -0.32700785143820765, -0.28138437101840846, -0.22676959095649116, - -0.1666069804396438, -0.10427519429859669, -0.042934148760251846, - 0.014603890392405254, 0.06597447921726202, 0.10933041512042661, - 0.14338004157100342, 0.16739558397970875, 0.1811939736709082, - 0.1850936866775042, 0.17985192497466335, 0.16658698738329775, - 0.14669091786299812, 0.12173749544390697, 0.0933903688489364, - 0.06331567493104524, 0.03310285466958556, 0.004196638632041875, - -0.02215763825401838, -0.04495406989839077, -0.06345105763119208, - -0.07718129749175254, -0.0859478200857468, -0.08980759792920584, - -0.08904468012921841, -0.08413512397713321, -0.07570616574155123, - -0.06449211350032416, -0.05128936389831648, -0.03691275765931889, - -0.0221552144769921, -0.007752247846719602, 0.005647423141537939, - 0.017504352738798582, 0.027403530576788012, 0.03506220467756449, - 0.040330693153308554, 0.04318681334953267, 0.0437247997784003, - 0.04213976040910249, 0.03870883241054338, 0.033770244339933406, - 0.027701476109967472, 0.02089763744729107, 0.013751068552181367, - 0.006633013241694939, -0.00012196425782889296, -0.0062283415763344264, - -0.011458500270676337, -0.01564800087287013, -0.018697362316561276, - -0.020570594078835346, -0.02129085960947034, -0.020933749523185694, - -0.019618710755027215, -0.017499213277943633, -0.014752240453738455, - -0.011567665365081987, -0.00813802736441628, -0.004649155175939006, - -0.0012720002997873648, 0.0018440474959955946, 0.0045761869003028, - 0.006831493576234213, 0.008548480061993557, 0.009697017641601163, - 0.010276779766636322, 0.010314421477998086, 0.009859748761770204, - 0.008981155468606688, 0.007760613711452574, 0.006288497605736688, - 0.004658501480378907, 0.0029628843619596023, 0.0012882350155569177, - -0.0002880913285060006, -0.0017007596413722969, -0.002898407017964739, - -0.0038447468026205616, -0.00451885327934322, -0.0049146914166663174, 0, + 1.323398473117905, -0.6829392417180884, -2.5410326014563864, + -4.101902238713091, -5.319873422015533, -6.169865639422336, + -6.646621199315949, -6.7630679669369265, -6.547976213645946, + -6.0430877794146145, -5.299903794618887, -4.376315662172488, + -3.3332538512677767, -2.2315115992678196, -1.1288773808379744, + -0.0776826345876386, 0.8771585727084213, 1.6995718709876848, + 2.363190704796105, 2.8516818495939003, 3.1585645377703133, + 3.286579954199072, 3.246683764773457, 3.0567452884980573, 2.740042867341184, + 2.323646122685416, 1.8367725167272368, 1.3091985357395746, + 0.7697955807766584, 0.24524807281343838, -0.24100282714122964, + -0.6695613029300629, -1.0256109574762429, -1.2991810746896508, + -1.4851579383685267, -1.583064932803068, -1.5966438479919849, + -1.53327614653619, -1.4032868442111268, -1.2191751595075755, + -0.9948153554344805, -0.7446684769966139, -0.48304129804386037, + -0.22342309854335646, 0.022075708522620596, 0.24316619314082147, + 0.4316950957175925, 0.5818279203174821, 0.6901047333736142, + 0.7553781376133086, 0.7786475727158589, 0.7628076599163445, + 0.7123306946434456, 0.6329045984123333, 0.5310477236547004, + 0.41372096607653586, 0.28795582020103355, 0.16051448489448542, + 0.03759507427140651, -0.07540839025625874, -0.1740850475085182, + -0.2551226380650384, -0.3163599045938195, -0.3567794672384564, + -0.37644717619946855, -0.3764059085589138, -0.35853317681913227, + -0.32537273991770715, -0.27995066955255526, -0.22558606649261018, + -0.1657059048998106, -0.10367238513547945, -0.04262978532223912, + 0.014623787196960595, 0.06573603718945949, 0.10886951664424274, + 0.1427396951126933, 0.16662320806411346, 0.1803387303580254, + 0.18420398617769154, 0.17897320335629344, 0.16575983668444602, + 0.1459496236731492, 0.12110901247412983, 0.0928937413513812, + 0.06296188709724626, 0.03289507717831337, 0.0041308219658158975, + -0.022091884836511068, -0.044772382566424414, -0.06317307791869127, + -0.0768293604538175, -0.0855456396654032, -0.08937901209165267, + -0.08861250953574876, -0.08372018747390819, -0.07532648438980863, + -0.06416232292168611, -0.05102034295646993, -0.03671147048526515, + -0.022024753020921207, -0.007692053857625504, 0.0056411843014568435, + 0.017438298606540704, 0.027286483199281716, 0.03490456280624432, + 0.040143789472658335, 0.04298228862049804, 0.043514021942220205, + 0.0419333118978449, 0.03851608346658833, 0.033599024377143065, + 0.027557849358667716, 0.02078578358985113, 0.013673264013907142, + 0.006589704444917432, -0.00013200789895279107, -0.006207809758054476, + -0.011411275499985534, -0.01557886099017781, -0.01861166890313651, + -0.020473982856576655, -0.02118894731331795, -0.020831869567978487, + -0.019521687481653435, -0.017411181804464698, -0.014676516327664965, + -0.011506665453913895, -0.008093240856956715, -0.004621161299767523, + -0.0012605274697481256, 0.0018400278436294317, 0.004558339534948625, + 0.006801980047590764, 0.00850980900357551, 0.009651892873765064, + 0.0102279536058988, 0.010264559707905225, 0.009811312553713853, + 0.008936304234580061, 0.0077211314999743414, 0.006255744288126154, + 0.00463338868122861, 0.0029458749195796813, 0.0012793637587843068, + -0.00028917850012965954, -0.001694751967601518, -0.0028862643266073717, + -0.0038276282797762946, -0.004498043571776675, -0.004891527821716417, 0, ] const expectedAnimationKeyframesNegative = [ @@ -524,51 +524,52 @@ const expectedAnimationKeyframesWithMax = [ 178.6938680574733, 181.09589040596114, 183.45034952520206, 185.758187230237, 188.0203266869196, 190.2376727811947, 192.41111248106512, 194.5415151913903, 196.62973310166018, 198.6766015268821, 200.6829392417181, - 202.55043663922197, 204.11936980645882, 205.34380950068214, - 206.1985204960506, 206.6781880183153, 206.79577389527952, 206.5801631327034, - 206.07327995383224, 205.32686044160923, 204.39906738532787, - 203.35112274802813, 202.24411564294084, 201.13612036601066, - 200.0797315361748, 199.12009344377734, 198.29346995316678, - 197.62637128182013, 197.13522603835872, 196.82656217116516, - 196.6976398243938, 196.73746310983225, 196.92808679481317, - 197.24612792588968, 197.66439126019057, 198.15352065576033, - 198.6835957020738, 199.225603148031, 199.7527253207682, 200.24140190124916, - 200.67213631405482, 201.03003282505435, 201.3050645239781, - 201.4920851036547, 201.59060825874323, 201.60438727072693, - 201.54083371465163, 201.41031814084934, 201.22539709928927, - 201.00001014219455, 200.7486877106165, 200.48580640224657, - 200.2249223994875, 199.9782072042949, 199.75600268081408, 199.566505135766, - 199.41558112636253, 199.3067111878657, 199.24105197400704, - 199.21760259736936, 199.23345737202072, 199.2841247603341, - 199.36389111104745, 199.46620769096847, 199.58408045476287, - 199.71044382364622, 199.83850228382823, 199.96202668096984, - 200.0755954824591, 200.17477481268355, 200.25623455713608, - 200.31780111780145, 200.35845034852244, 200.3782466977186, - 200.37823656113068, 200.3603052553915, 200.32700785143822, - 200.28138437101842, 200.2267695909565, 200.16660698043964, - 200.1042751942986, 200.04293414876025, 199.9853961096076, - 199.93402552078274, 199.89066958487956, 199.856619958429, 199.8326044160203, - 199.8188060263291, 199.8149063133225, 199.82014807502534, 199.8334130126167, - 199.853309082137, 199.8782625045561, 199.90660963115107, 199.93668432506897, - 199.96689714533042, 199.99580336136796, 200.02215763825401, - 200.04495406989838, 200.0634510576312, 200.07718129749176, - 200.08594782008575, 200.0898075979292, 200.0890446801292, - 200.08413512397715, 200.07570616574156, 200.06449211350034, - 200.05128936389832, 200.0369127576593, 200.02215521447698, - 200.00775224784672, 199.99435257685846, 199.9824956472612, - 199.97259646942322, 199.96493779532244, 199.95966930684668, - 199.95681318665046, 199.9562752002216, 199.9578602395909, - 199.96129116758945, 199.96622975566007, 199.97229852389003, - 199.9791023625527, 199.98624893144782, 199.9933669867583, - 200.00012196425783, 200.00622834157633, 200.01145850027066, - 200.01564800087286, 200.01869736231657, 200.02057059407883, - 200.02129085960948, 200.02093374952318, 200.01961871075503, - 200.01749921327794, 200.01475224045373, 200.01156766536508, - 200.00813802736442, 200.00464915517594, 200.0012720002998, - 199.998155952504, 199.9954238130997, 199.99316850642376, 199.991451519938, - 199.9903029823584, 199.98972322023337, 199.989685578522, 199.99014025123822, - 199.9910188445314, 199.99223938628856, 199.99371150239426, - 199.99534149851962, 199.99703711563805, 199.99871176498445, - 200.0002880913285, 200.00170075964138, 200.00289840701797, - 200.00384474680263, 200.00451885327934, 200.00491469141667, 200, + 202.54103260145638, 204.10190223871308, 205.31987342201552, + 206.16986563942234, 206.64662119931594, 206.76306796693692, + 206.54797621364594, 206.0430877794146, 205.2999037946189, 204.3763156621725, + 203.33325385126778, 202.23151159926783, 201.12887738083796, + 200.07768263458763, 199.12284142729158, 198.30042812901232, + 197.6368092952039, 197.1483181504061, 196.8414354622297, 196.71342004580092, + 196.75331623522655, 196.94325471150194, 197.25995713265883, + 197.6763538773146, 198.16322748327275, 198.69080146426043, + 199.23020441922336, 199.75475192718656, 200.24100282714122, + 200.66956130293005, 201.02561095747623, 201.29918107468964, + 201.48515793836853, 201.58306493280307, 201.596643847992, 201.5332761465362, + 201.40328684421112, 201.21917515950759, 200.99481535543447, + 200.74466847699662, 200.48304129804387, 200.22342309854335, + 199.9779242914774, 199.7568338068592, 199.5683049042824, 199.4181720796825, + 199.3098952666264, 199.24462186238668, 199.22135242728413, + 199.23719234008365, 199.28766930535656, 199.36709540158768, + 199.4689522763453, 199.58627903392346, 199.71204417979897, + 199.8394855151055, 199.9624049257286, 200.07540839025626, + 200.17408504750853, 200.25512263806505, 200.3163599045938, + 200.35677946723845, 200.37644717619946, 200.37640590855892, + 200.35853317681912, 200.3253727399177, 200.27995066955256, + 200.2255860664926, 200.16570590489982, 200.10367238513547, + 200.04262978532225, 199.98537621280303, 199.93426396281055, + 199.89113048335577, 199.85726030488732, 199.83337679193588, + 199.81966126964198, 199.8157960138223, 199.8210267966437, + 199.83424016331554, 199.85405037632685, 199.87889098752586, + 199.9071062586486, 199.93703811290274, 199.96710492282168, + 199.99586917803418, 200.0220918848365, 200.04477238256644, + 200.0631730779187, 200.07682936045381, 200.0855456396654, + 200.08937901209165, 200.08861250953575, 200.08372018747392, + 200.07532648438982, 200.06416232292167, 200.05102034295646, + 200.03671147048527, 200.02202475302093, 200.00769205385762, + 199.99435881569855, 199.98256170139345, 199.97271351680072, + 199.96509543719375, 199.95985621052733, 199.9570177113795, + 199.95648597805777, 199.95806668810215, 199.9614839165334, + 199.96640097562286, 199.97244215064134, 199.97921421641016, + 199.9863267359861, 199.9934102955551, 200.00013200789894, + 200.00620780975805, 200.0114112755, 200.0155788609902, 200.01861166890313, + 200.02047398285657, 200.0211889473133, 200.02083186956798, + 200.01952168748164, 200.01741118180448, 200.01467651632765, + 200.0115066654539, 200.00809324085697, 200.00462116129978, + 200.00126052746975, 199.99815997215637, 199.99544166046505, + 199.99319801995242, 199.99149019099642, 199.99034810712624, + 199.9897720463941, 199.9897354402921, 199.99018868744628, + 199.99106369576543, 199.99227886850002, 199.99374425571187, + 199.99536661131876, 199.9970541250804, 199.99872063624122, + 200.00028917850014, 200.0016947519676, 200.0028862643266, + 200.00382762827977, 200.00449804357177, 200.0048915278217, 200, ] diff --git a/packages/motion-dom/src/animation/generators/inertia.ts b/packages/motion-dom/src/animation/generators/inertia.ts index bbb40d3493..a433a3a6f3 100644 --- a/packages/motion-dom/src/animation/generators/inertia.ts +++ b/packages/motion-dom/src/animation/generators/inertia.ts @@ -4,7 +4,6 @@ import { ValueAnimationOptions, } from "../types" import { spring as createSpring } from "./spring" -import { getGeneratorVelocity } from "./utils/velocity" export function inertia({ keyframes, @@ -26,8 +25,7 @@ export function inertia({ value: origin, } - const isOutOfBounds = (v: number) => - (min !== undefined && v < min) || (max !== undefined && v > max) + const isOutOfBounds = (v: number) => v < min! || v > max! const nearestBoundary = (v: number) => { if (min === undefined) return max @@ -48,13 +46,10 @@ export function inertia({ const calcDelta = (t: number) => -amplitude * Math.exp(-t / timeConstant) - const calcLatest = (t: number) => target + calcDelta(t) - const applyFriction = (t: number) => { const delta = calcDelta(t) - const latest = calcLatest(t) state.done = Math.abs(delta) <= restDelta - state.value = state.done ? target : latest + state.value = state.done ? target : target + delta } /** @@ -73,7 +68,12 @@ export function inertia({ spring = createSpring({ keyframes: [state.value, nearestBoundary(state.value)!], - velocity: getGeneratorVelocity(calcLatest, t, state.value), // TODO: This should be passing * 1000 + /** + * The friction curve is target + calcDelta(t), so its exact + * derivative is -calcDelta(t) / timeConstant in units/ms, + * converted here to the units/second expected by spring. + */ + velocity: (-calcDelta(t) / timeConstant) * 1000, damping: bounceDamping, stiffness: bounceStiffness, restDelta, diff --git a/packages/motion-dom/src/animation/generators/spring.ts b/packages/motion-dom/src/animation/generators/spring.ts index 92647be5fa..97525443df 100644 --- a/packages/motion-dom/src/animation/generators/spring.ts +++ b/packages/motion-dom/src/animation/generators/spring.ts @@ -118,9 +118,13 @@ function findSpring({ const delta = exponentialDecay * duration const d = delta * velocity + velocity const e = - Math.pow(dampingRatio, 2) * Math.pow(undampedFreq, 2) * duration + dampingRatio * + dampingRatio * + undampedFreq * + undampedFreq * + duration const f = Math.exp(-delta) - const g = calcAngularFreq(Math.pow(undampedFreq, 2), dampingRatio) + const g = calcAngularFreq(undampedFreq * undampedFreq, dampingRatio) const factor = -envelope(undampedFreq) + safeMin > 0 ? -1 : 1 return (factor * ((d - e) * f)) / g } @@ -152,7 +156,7 @@ function findSpring({ duration, } } else { - const stiffness = Math.pow(undampedFreq, 2) * mass + const stiffness = undampedFreq * undampedFreq * mass return { stiffness, damping: dampingRatio * 2 * Math.sqrt(mass * stiffness), @@ -263,6 +267,7 @@ function spring( const undampedAngularFreq = millisecondsToSeconds( Math.sqrt(stiffness / mass) ) + const decay = dampingRatio * undampedAngularFreq /** * If we're working on a granular scale, use smaller defaults for determining @@ -282,42 +287,43 @@ function spring( let resolveSpring: (v: number) => number let resolveVelocity: (t: number) => number - // Underdamped coefficients, hoisted for use in the inlined next() hot path - let angularFreq: number - let A: number - let sinCoeff: number - let cosCoeff: number - if (dampingRatio < 1) { - angularFreq = calcAngularFreq(undampedAngularFreq, dampingRatio) + const angularFreq = calcAngularFreq(undampedAngularFreq, dampingRatio) + + const A = (initialVelocity + decay * initialDelta) / angularFreq - A = - (initialVelocity + - dampingRatio * undampedAngularFreq * initialDelta) / - angularFreq + // Coefficients for the analytical derivative (px/ms) + const sinCoeff = decay * A + initialDelta * angularFreq + const cosCoeff = decay * initialDelta - A * angularFreq + + /** + * The underdamped hot path needs both position and velocity every + * frame and they share the same exp/sin/cos terms, so sample both + * at once, memoized by t, to only calculate them once per frame. + */ + let sampledT = -1 + let position = 0 + let velocityAtT = 0 + const sample = (t: number) => { + if (t !== sampledT) { + sampledT = t + const envelope = Math.exp(-decay * t) + const sin = Math.sin(angularFreq * t) + const cos = Math.cos(angularFreq * t) + position = target - envelope * (A * sin + initialDelta * cos) + velocityAtT = envelope * (sinCoeff * sin + cosCoeff * cos) + } + } // Underdamped spring resolveSpring = (t: number) => { - const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t) - - return ( - target - - envelope * - (A * Math.sin(angularFreq * t) + - initialDelta * Math.cos(angularFreq * t)) - ) + sample(t) + return position } - // Analytical derivative of underdamped spring (px/ms) - sinCoeff = - dampingRatio * undampedAngularFreq * A + initialDelta * angularFreq - cosCoeff = - dampingRatio * undampedAngularFreq * initialDelta - A * angularFreq resolveVelocity = (t: number) => { - const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t) - return envelope * - (sinCoeff * Math.sin(angularFreq * t) + - cosCoeff * Math.cos(angularFreq * t)) + sample(t) + return velocityAtT } } else if (dampingRatio === 1) { // Critically damped spring @@ -338,7 +344,7 @@ function spring( undampedAngularFreq * Math.sqrt(dampingRatio * dampingRatio - 1) resolveSpring = (t: number) => { - const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t) + const envelope = Math.exp(-decay * t) // When performing sinh or cosh values can hit Infinity so we cap them here const freqForT = Math.min(dampedAngularFreq * t, 300) @@ -346,8 +352,7 @@ function spring( return ( target - (envelope * - ((initialVelocity + - dampingRatio * undampedAngularFreq * initialDelta) * + ((initialVelocity + decay * initialDelta) * Math.sinh(freqForT) + dampedAngularFreq * initialDelta * @@ -357,20 +362,17 @@ function spring( } // Analytical derivative of overdamped spring (px/ms) - const P = - (initialVelocity + - dampingRatio * undampedAngularFreq * initialDelta) / - dampedAngularFreq - const sinhCoeff = - dampingRatio * undampedAngularFreq * P - initialDelta * dampedAngularFreq - const coshCoeff = - dampingRatio * undampedAngularFreq * initialDelta - P * dampedAngularFreq + const P = (initialVelocity + decay * initialDelta) / dampedAngularFreq + const sinhCoeff = decay * P - initialDelta * dampedAngularFreq + const coshCoeff = decay * initialDelta - P * dampedAngularFreq resolveVelocity = (t: number) => { - const envelope = Math.exp(-dampingRatio * undampedAngularFreq * t) + const envelope = Math.exp(-decay * t) const freqForT = Math.min(dampedAngularFreq * t, 300) - return envelope * + return ( + envelope * (sinhCoeff * Math.sinh(freqForT) + coshCoeff * Math.cosh(freqForT)) + ) } } @@ -378,35 +380,6 @@ function spring( calculatedDuration: isResolvedFromDuration ? duration || null : null, velocity: (t: number) => secondsToMilliseconds(resolveVelocity(t)), next: (t: number) => { - /** - * For underdamped physics springs we need both position and - * velocity each tick. Compute shared trig values once to avoid - * duplicate Math.exp/sin/cos calls on the hot path. - */ - if (!isResolvedFromDuration && dampingRatio < 1) { - const envelope = Math.exp( - -dampingRatio * undampedAngularFreq * t - ) - const sin = Math.sin(angularFreq * t) - const cos = Math.cos(angularFreq * t) - - const current = - target - - envelope * - (A * sin + initialDelta * cos) - const currentVelocity = secondsToMilliseconds( - envelope * - (sinCoeff * sin + cosCoeff * cos) - ) - - state.done = - Math.abs(currentVelocity) <= restSpeed! && - Math.abs(target - current) <= restDelta! - state.value = state.done ? target : current - - return state - } - const current = resolveSpring(t) if (!isResolvedFromDuration) { diff --git a/packages/motion-dom/src/animation/generators/utils/calc-duration.ts b/packages/motion-dom/src/animation/generators/utils/calc-duration.ts index 77805604aa..b8e9a94dfc 100644 --- a/packages/motion-dom/src/animation/generators/utils/calc-duration.ts +++ b/packages/motion-dom/src/animation/generators/utils/calc-duration.ts @@ -5,16 +5,22 @@ import { KeyframeGenerator } from "../../types" * to prevent infinite loops */ export const maxGeneratorDuration = 20_000 -export function calcGeneratorDuration( - generator: KeyframeGenerator + +export function calcGeneratorDuration( + generator: KeyframeGenerator, + timeStep = 50, + maxDuration = maxGeneratorDuration, + keyframes?: T[] ): number { let duration = 0 - const timeStep = 50 let state = generator.next(duration) - while (!state.done && duration < maxGeneratorDuration) { + keyframes?.push(state.value) + + while (!state.done && duration < maxDuration) { duration += timeStep state = generator.next(duration) + keyframes?.push(state.value) } - return duration >= maxGeneratorDuration ? Infinity : duration + return duration >= maxDuration ? Infinity : duration } diff --git a/packages/motion-dom/src/animation/generators/utils/pregenerate.ts b/packages/motion-dom/src/animation/generators/utils/pregenerate.ts index 7695b7f0be..6fda719f06 100644 --- a/packages/motion-dom/src/animation/generators/utils/pregenerate.ts +++ b/packages/motion-dom/src/animation/generators/utils/pregenerate.ts @@ -1,5 +1,6 @@ import { millisecondsToSeconds } from "motion-utils" import { AnyResolvedKeyframe, KeyframeGenerator } from "../../types" +import { calcGeneratorDuration } from "./calc-duration" export interface KeyframesMetadata { keyframes: Array @@ -7,27 +8,22 @@ export interface KeyframesMetadata { } const timeStep = 10 -const maxDuration = 10000 +const maxDuration = 10_000 + export function pregenerateKeyframes( generator: KeyframeGenerator ): KeyframesMetadata { - let timestamp = timeStep - let state = generator.next(0) - const keyframes: Array = [state.value] - - while (!state.done && timestamp < maxDuration) { - state = generator.next(timestamp) - keyframes.push(state.value) - timestamp += timeStep - } - - const duration = timestamp - timeStep + const keyframes: number[] = [] + const duration = Math.min( + calcGeneratorDuration(generator, timeStep, maxDuration, keyframes), + maxDuration + ) /** * If generating an animation that didn't actually move, * generate a second keyframe so we have an origin and target. */ - if (keyframes.length === 1) keyframes.push(state.value) + if (keyframes.length === 1) keyframes.push(keyframes[0]) return { keyframes,