motion 12.3.1 → 12.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/debug.js +291 -0
- package/dist/cjs/index.js +34 -16
- package/dist/cjs/mini.js +2 -1
- package/dist/cjs/react-client.js +36 -54
- package/dist/cjs/react-m.js +30 -13
- package/dist/cjs/react-mini.js +2 -1
- package/dist/debug.d.ts +1 -0
- package/dist/es/framer-motion/dist/es/animation/animators/MainThreadAnimation.mjs +3 -0
- package/dist/es/framer-motion/dist/es/animation/animators/waapi/index.mjs +12 -1
- package/dist/es/framer-motion/dist/es/frameloop/batcher.mjs +8 -13
- package/dist/es/framer-motion/dist/es/frameloop/index-legacy.mjs +1 -1
- package/dist/es/framer-motion/dist/es/frameloop/order.mjs +10 -0
- package/dist/es/framer-motion/dist/es/frameloop/render-step.mjs +12 -1
- package/dist/es/framer-motion/dist/es/projection/node/create-projection-node.mjs +22 -17
- package/dist/es/framer-motion/dist/es/render/utils/motion-values.mjs +1 -1
- package/dist/es/framer-motion/dist/es/stats/animation-count.mjs +7 -0
- package/dist/es/framer-motion/dist/es/stats/buffer.mjs +6 -0
- package/dist/es/framer-motion/dist/es/stats/index.mjs +113 -0
- package/dist/es/framer-motion/dist/es/utils/use-in-view.mjs +2 -2
- package/dist/es/framer-motion/dist/es/value/index.mjs +1 -1
- package/dist/es/motion/lib/debug.mjs +1 -0
- package/dist/motion.dev.js +34 -16
- package/dist/motion.js +1 -1
- package/package.json +9 -3
package/dist/cjs/react-m.js
CHANGED
|
@@ -187,7 +187,21 @@ const camelToDash = (str) => str.replace(/([a-z])([A-Z])/gu, "$1-$2").toLowerCas
|
|
|
187
187
|
const optimizedAppearDataId = "framerAppearId";
|
|
188
188
|
const optimizedAppearDataAttribute = "data-" + camelToDash(optimizedAppearDataId);
|
|
189
189
|
|
|
190
|
-
|
|
190
|
+
const stepsOrder = [
|
|
191
|
+
"read", // Read
|
|
192
|
+
"resolveKeyframes", // Write/Read/Write/Read
|
|
193
|
+
"update", // Compute
|
|
194
|
+
"preRender", // Compute
|
|
195
|
+
"render", // Write
|
|
196
|
+
"postRender", // Compute
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
const statsBuffer = {
|
|
200
|
+
value: null,
|
|
201
|
+
addProjectionMetrics: null,
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
function createRenderStep(runNextFrame, stepName) {
|
|
191
205
|
/**
|
|
192
206
|
* We create and reuse two queues, one to queue jobs for the current frame
|
|
193
207
|
* and one for the next. We reuse to avoid triggering GC after x frames.
|
|
@@ -209,11 +223,13 @@ function createRenderStep(runNextFrame) {
|
|
|
209
223
|
timestamp: 0.0,
|
|
210
224
|
isProcessing: false,
|
|
211
225
|
};
|
|
226
|
+
let numCalls = 0;
|
|
212
227
|
function triggerCallback(callback) {
|
|
213
228
|
if (toKeepAlive.has(callback)) {
|
|
214
229
|
step.schedule(callback);
|
|
215
230
|
runNextFrame();
|
|
216
231
|
}
|
|
232
|
+
numCalls++;
|
|
217
233
|
callback(latestFrameData);
|
|
218
234
|
}
|
|
219
235
|
const step = {
|
|
@@ -254,6 +270,13 @@ function createRenderStep(runNextFrame) {
|
|
|
254
270
|
[thisFrame, nextFrame] = [nextFrame, thisFrame];
|
|
255
271
|
// Execute this frame
|
|
256
272
|
thisFrame.forEach(triggerCallback);
|
|
273
|
+
/**
|
|
274
|
+
* If we're recording stats then
|
|
275
|
+
*/
|
|
276
|
+
if (stepName && statsBuffer.value) {
|
|
277
|
+
statsBuffer.value.frameloop[stepName].push(numCalls);
|
|
278
|
+
}
|
|
279
|
+
numCalls = 0;
|
|
257
280
|
// Clear the frame so no callbacks remain. This is to avoid
|
|
258
281
|
// memory leaks should this render step not run for a while.
|
|
259
282
|
thisFrame.clear();
|
|
@@ -267,14 +290,6 @@ function createRenderStep(runNextFrame) {
|
|
|
267
290
|
return step;
|
|
268
291
|
}
|
|
269
292
|
|
|
270
|
-
const stepsOrder = [
|
|
271
|
-
"read", // Read
|
|
272
|
-
"resolveKeyframes", // Write/Read/Write/Read
|
|
273
|
-
"update", // Compute
|
|
274
|
-
"preRender", // Compute
|
|
275
|
-
"render", // Write
|
|
276
|
-
"postRender", // Compute
|
|
277
|
-
];
|
|
278
293
|
const maxElapsed = 40;
|
|
279
294
|
function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
280
295
|
let runNextFrame = false;
|
|
@@ -286,16 +301,18 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
|
286
301
|
};
|
|
287
302
|
const flagRunNextFrame = () => (runNextFrame = true);
|
|
288
303
|
const steps = stepsOrder.reduce((acc, key) => {
|
|
289
|
-
acc[key] = createRenderStep(flagRunNextFrame);
|
|
304
|
+
acc[key] = createRenderStep(flagRunNextFrame, allowKeepAlive ? key : undefined);
|
|
290
305
|
return acc;
|
|
291
306
|
}, {});
|
|
292
307
|
const { read, resolveKeyframes, update, preRender, render, postRender } = steps;
|
|
293
308
|
const processBatch = () => {
|
|
294
309
|
const timestamp = performance.now();
|
|
295
310
|
runNextFrame = false;
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
311
|
+
{
|
|
312
|
+
state.delta = useDefaultElapsed
|
|
313
|
+
? 1000 / 60
|
|
314
|
+
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed), 1);
|
|
315
|
+
}
|
|
299
316
|
state.timestamp = timestamp;
|
|
300
317
|
state.isProcessing = true;
|
|
301
318
|
// Unrolled render loop for better per-frame performance
|
package/dist/cjs/react-mini.js
CHANGED
|
@@ -392,7 +392,7 @@ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duratio
|
|
|
392
392
|
*/
|
|
393
393
|
if (Array.isArray(easing))
|
|
394
394
|
keyframeOptions.easing = easing;
|
|
395
|
-
|
|
395
|
+
const animation = element.animate(keyframeOptions, {
|
|
396
396
|
delay,
|
|
397
397
|
duration,
|
|
398
398
|
easing: !Array.isArray(easing) ? easing : "linear",
|
|
@@ -400,6 +400,7 @@ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duratio
|
|
|
400
400
|
iterations: repeat + 1,
|
|
401
401
|
direction: repeatType === "reverse" ? "alternate" : "normal",
|
|
402
402
|
});
|
|
403
|
+
return animation;
|
|
403
404
|
}
|
|
404
405
|
|
|
405
406
|
const createUnitType = (unit) => ({
|
package/dist/debug.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from 'framer-motion/debug';
|
|
@@ -3,6 +3,7 @@ import { millisecondsToSeconds, secondsToMilliseconds } from '../../../../../mot
|
|
|
3
3
|
import { calcGeneratorDuration } from '../../../../../motion-dom/dist/es/animation/generators/utils/calc-duration.mjs';
|
|
4
4
|
import { isGenerator } from '../../../../../motion-dom/dist/es/animation/generators/utils/is-generator.mjs';
|
|
5
5
|
import { KeyframeResolver } from '../../render/utils/KeyframesResolver.mjs';
|
|
6
|
+
import { activeAnimations } from '../../stats/animation-count.mjs';
|
|
6
7
|
import { clamp } from '../../utils/clamp.mjs';
|
|
7
8
|
import { mix } from '../../utils/mix/index.mjs';
|
|
8
9
|
import { pipe } from '../../utils/pipe.mjs';
|
|
@@ -140,6 +141,7 @@ class MainThreadAnimation extends BaseAnimation {
|
|
|
140
141
|
}
|
|
141
142
|
onPostResolved() {
|
|
142
143
|
const { autoplay = true } = this.options;
|
|
144
|
+
activeAnimations.mainThread++;
|
|
143
145
|
this.play();
|
|
144
146
|
if (this.pendingPlayState === "paused" || !autoplay) {
|
|
145
147
|
this.pause();
|
|
@@ -371,6 +373,7 @@ class MainThreadAnimation extends BaseAnimation {
|
|
|
371
373
|
this.updateFinishedPromise();
|
|
372
374
|
this.startTime = this.cancelTime = null;
|
|
373
375
|
this.resolver.cancel();
|
|
376
|
+
activeAnimations.mainThread--;
|
|
374
377
|
}
|
|
375
378
|
stopDriver() {
|
|
376
379
|
if (!this.driver)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import '../../../../../../motion-utils/dist/es/errors.mjs';
|
|
2
2
|
import { mapEasingToNativeEasing } from '../../../../../../motion-dom/dist/es/animation/waapi/utils/easing.mjs';
|
|
3
|
+
import { activeAnimations } from '../../../stats/animation-count.mjs';
|
|
4
|
+
import { statsBuffer } from '../../../stats/buffer.mjs';
|
|
3
5
|
|
|
4
6
|
function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duration = 300, repeat = 0, repeatType = "loop", ease = "easeInOut", times, } = {}) {
|
|
5
7
|
const keyframeOptions = { [valueName]: keyframes };
|
|
@@ -11,7 +13,10 @@ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duratio
|
|
|
11
13
|
*/
|
|
12
14
|
if (Array.isArray(easing))
|
|
13
15
|
keyframeOptions.easing = easing;
|
|
14
|
-
|
|
16
|
+
if (statsBuffer.value) {
|
|
17
|
+
activeAnimations.waapi++;
|
|
18
|
+
}
|
|
19
|
+
const animation = element.animate(keyframeOptions, {
|
|
15
20
|
delay,
|
|
16
21
|
duration,
|
|
17
22
|
easing: !Array.isArray(easing) ? easing : "linear",
|
|
@@ -19,6 +24,12 @@ function startWaapiAnimation(element, valueName, keyframes, { delay = 0, duratio
|
|
|
19
24
|
iterations: repeat + 1,
|
|
20
25
|
direction: repeatType === "reverse" ? "alternate" : "normal",
|
|
21
26
|
});
|
|
27
|
+
if (statsBuffer.value) {
|
|
28
|
+
animation.finished.finally(() => {
|
|
29
|
+
activeAnimations.waapi--;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return animation;
|
|
22
33
|
}
|
|
23
34
|
|
|
24
35
|
export { startWaapiAnimation };
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import { MotionGlobalConfig } from '../utils/GlobalConfig.mjs';
|
|
2
|
+
import { stepsOrder } from './order.mjs';
|
|
2
3
|
import { createRenderStep } from './render-step.mjs';
|
|
3
4
|
|
|
4
|
-
const stepsOrder = [
|
|
5
|
-
"read", // Read
|
|
6
|
-
"resolveKeyframes", // Write/Read/Write/Read
|
|
7
|
-
"update", // Compute
|
|
8
|
-
"preRender", // Compute
|
|
9
|
-
"render", // Write
|
|
10
|
-
"postRender", // Compute
|
|
11
|
-
];
|
|
12
5
|
const maxElapsed = 40;
|
|
13
6
|
function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
14
7
|
let runNextFrame = false;
|
|
@@ -20,7 +13,7 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
|
20
13
|
};
|
|
21
14
|
const flagRunNextFrame = () => (runNextFrame = true);
|
|
22
15
|
const steps = stepsOrder.reduce((acc, key) => {
|
|
23
|
-
acc[key] = createRenderStep(flagRunNextFrame);
|
|
16
|
+
acc[key] = createRenderStep(flagRunNextFrame, allowKeepAlive ? key : undefined);
|
|
24
17
|
return acc;
|
|
25
18
|
}, {});
|
|
26
19
|
const { read, resolveKeyframes, update, preRender, render, postRender } = steps;
|
|
@@ -29,9 +22,11 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
|
29
22
|
? state.timestamp
|
|
30
23
|
: performance.now();
|
|
31
24
|
runNextFrame = false;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
25
|
+
if (!MotionGlobalConfig.useManualTiming) {
|
|
26
|
+
state.delta = useDefaultElapsed
|
|
27
|
+
? 1000 / 60
|
|
28
|
+
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed), 1);
|
|
29
|
+
}
|
|
35
30
|
state.timestamp = timestamp;
|
|
36
31
|
state.isProcessing = true;
|
|
37
32
|
// Unrolled render loop for better per-frame performance
|
|
@@ -71,4 +66,4 @@ function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
|
71
66
|
return { schedule, cancel, state, steps };
|
|
72
67
|
}
|
|
73
68
|
|
|
74
|
-
export { createRenderBatcher
|
|
69
|
+
export { createRenderBatcher };
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { statsBuffer } from '../stats/buffer.mjs';
|
|
2
|
+
|
|
3
|
+
function createRenderStep(runNextFrame, stepName) {
|
|
2
4
|
/**
|
|
3
5
|
* We create and reuse two queues, one to queue jobs for the current frame
|
|
4
6
|
* and one for the next. We reuse to avoid triggering GC after x frames.
|
|
@@ -20,11 +22,13 @@ function createRenderStep(runNextFrame) {
|
|
|
20
22
|
timestamp: 0.0,
|
|
21
23
|
isProcessing: false,
|
|
22
24
|
};
|
|
25
|
+
let numCalls = 0;
|
|
23
26
|
function triggerCallback(callback) {
|
|
24
27
|
if (toKeepAlive.has(callback)) {
|
|
25
28
|
step.schedule(callback);
|
|
26
29
|
runNextFrame();
|
|
27
30
|
}
|
|
31
|
+
numCalls++;
|
|
28
32
|
callback(latestFrameData);
|
|
29
33
|
}
|
|
30
34
|
const step = {
|
|
@@ -65,6 +69,13 @@ function createRenderStep(runNextFrame) {
|
|
|
65
69
|
[thisFrame, nextFrame] = [nextFrame, thisFrame];
|
|
66
70
|
// Execute this frame
|
|
67
71
|
thisFrame.forEach(triggerCallback);
|
|
72
|
+
/**
|
|
73
|
+
* If we're recording stats then
|
|
74
|
+
*/
|
|
75
|
+
if (stepName && statsBuffer.value) {
|
|
76
|
+
statsBuffer.value.frameloop[stepName].push(numCalls);
|
|
77
|
+
}
|
|
78
|
+
numCalls = 0;
|
|
68
79
|
// Clear the frame so no callbacks remain. This is to avoid
|
|
69
80
|
// memory leaks should this render step not run for a while.
|
|
70
81
|
thisFrame.clear();
|
|
@@ -8,6 +8,8 @@ import { microtask } from '../../frameloop/microtask.mjs';
|
|
|
8
8
|
import { time } from '../../frameloop/sync-time.mjs';
|
|
9
9
|
import { isSVGElement } from '../../render/dom/utils/is-svg-element.mjs';
|
|
10
10
|
import { FlatTree } from '../../render/utils/flat-tree.mjs';
|
|
11
|
+
import { activeAnimations } from '../../stats/animation-count.mjs';
|
|
12
|
+
import { statsBuffer } from '../../stats/buffer.mjs';
|
|
11
13
|
import { clamp } from '../../utils/clamp.mjs';
|
|
12
14
|
import { delay } from '../../utils/delay.mjs';
|
|
13
15
|
import { mixNumber } from '../../utils/mix/number.mjs';
|
|
@@ -28,12 +30,10 @@ import { hasTransform, hasScale, has2DTranslate } from '../utils/has-transform.m
|
|
|
28
30
|
import { globalProjectionState } from './state.mjs';
|
|
29
31
|
|
|
30
32
|
const metrics = {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
recalculatedProjection: 0,
|
|
33
|
+
nodes: 0,
|
|
34
|
+
calculatedTargetDeltas: 0,
|
|
35
|
+
calculatedProjections: 0,
|
|
35
36
|
};
|
|
36
|
-
const isDebug = typeof window !== "undefined" && window.MotionDebug !== undefined;
|
|
37
37
|
const transformAxes = ["", "X", "Y", "Z"];
|
|
38
38
|
const hiddenVisibility = { visibility: "hidden" };
|
|
39
39
|
/**
|
|
@@ -187,18 +187,18 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
187
187
|
* Reset debug counts. Manually resetting rather than creating a new
|
|
188
188
|
* object each frame.
|
|
189
189
|
*/
|
|
190
|
-
if (
|
|
191
|
-
metrics.
|
|
192
|
-
metrics.
|
|
193
|
-
metrics.
|
|
190
|
+
if (statsBuffer.value) {
|
|
191
|
+
metrics.nodes =
|
|
192
|
+
metrics.calculatedTargetDeltas =
|
|
193
|
+
metrics.calculatedProjections =
|
|
194
194
|
0;
|
|
195
195
|
}
|
|
196
196
|
this.nodes.forEach(propagateDirtyNodes);
|
|
197
197
|
this.nodes.forEach(resolveTargetDelta);
|
|
198
198
|
this.nodes.forEach(calcProjection);
|
|
199
199
|
this.nodes.forEach(cleanDirtyNodes);
|
|
200
|
-
if (
|
|
201
|
-
|
|
200
|
+
if (statsBuffer.addProjectionMetrics) {
|
|
201
|
+
statsBuffer.addProjectionMetrics(metrics);
|
|
202
202
|
}
|
|
203
203
|
};
|
|
204
204
|
/**
|
|
@@ -845,8 +845,8 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
845
845
|
/**
|
|
846
846
|
* Increase debug counter for resolved target deltas
|
|
847
847
|
*/
|
|
848
|
-
if (
|
|
849
|
-
metrics.
|
|
848
|
+
if (statsBuffer.value) {
|
|
849
|
+
metrics.calculatedTargetDeltas++;
|
|
850
850
|
}
|
|
851
851
|
}
|
|
852
852
|
getClosestProjectingParent() {
|
|
@@ -976,8 +976,8 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
976
976
|
/**
|
|
977
977
|
* Increase debug counter for recalculated projections
|
|
978
978
|
*/
|
|
979
|
-
if (
|
|
980
|
-
metrics.
|
|
979
|
+
if (statsBuffer.value) {
|
|
980
|
+
metrics.calculatedProjections++;
|
|
981
981
|
}
|
|
982
982
|
}
|
|
983
983
|
hide() {
|
|
@@ -1079,13 +1079,18 @@ function createProjectionNode({ attachResizeListener, defaultParent, measureScro
|
|
|
1079
1079
|
*/
|
|
1080
1080
|
this.pendingAnimation = frame.update(() => {
|
|
1081
1081
|
globalProjectionState.hasAnimatedSinceResize = true;
|
|
1082
|
+
activeAnimations.layout++;
|
|
1082
1083
|
this.currentAnimation = animateSingleValue(0, animationTarget, {
|
|
1083
1084
|
...options,
|
|
1084
1085
|
onUpdate: (latest) => {
|
|
1085
1086
|
this.mixTargetDelta(latest);
|
|
1086
1087
|
options.onUpdate && options.onUpdate(latest);
|
|
1087
1088
|
},
|
|
1089
|
+
onStop: () => {
|
|
1090
|
+
activeAnimations.layout--;
|
|
1091
|
+
},
|
|
1088
1092
|
onComplete: () => {
|
|
1093
|
+
activeAnimations.layout--;
|
|
1089
1094
|
options.onComplete && options.onComplete();
|
|
1090
1095
|
this.completeAnimation();
|
|
1091
1096
|
},
|
|
@@ -1485,8 +1490,8 @@ function propagateDirtyNodes(node) {
|
|
|
1485
1490
|
/**
|
|
1486
1491
|
* Increase debug counter for nodes encountered this frame
|
|
1487
1492
|
*/
|
|
1488
|
-
if (
|
|
1489
|
-
metrics.
|
|
1493
|
+
if (statsBuffer.value) {
|
|
1494
|
+
metrics.nodes++;
|
|
1490
1495
|
}
|
|
1491
1496
|
if (!node.parent)
|
|
1492
1497
|
return;
|
|
@@ -17,7 +17,7 @@ function updateMotionValuesFromProps(element, next, prev) {
|
|
|
17
17
|
* and warn against mismatches.
|
|
18
18
|
*/
|
|
19
19
|
if (process.env.NODE_ENV === "development") {
|
|
20
|
-
warnOnce(nextValue.version === "12.
|
|
20
|
+
warnOnce(nextValue.version === "12.4.0", `Attempting to mix Motion versions ${nextValue.version} with 12.4.0 may not work as expected.`);
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
else if (isMotionValue(prevValue)) {
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { activeAnimations } from './animation-count.mjs';
|
|
2
|
+
import { statsBuffer } from './buffer.mjs';
|
|
3
|
+
import { frame, cancelFrame, frameData } from '../frameloop/frame.mjs';
|
|
4
|
+
|
|
5
|
+
function record() {
|
|
6
|
+
const { value } = statsBuffer;
|
|
7
|
+
if (value === null) {
|
|
8
|
+
cancelFrame(record);
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
value.frameloop.rate.push(frameData.delta);
|
|
12
|
+
value.animations.mainThread.push(activeAnimations.mainThread);
|
|
13
|
+
value.animations.waapi.push(activeAnimations.waapi);
|
|
14
|
+
value.animations.layout.push(activeAnimations.layout);
|
|
15
|
+
}
|
|
16
|
+
function mean(values) {
|
|
17
|
+
return values.reduce((acc, value) => acc + value, 0) / values.length;
|
|
18
|
+
}
|
|
19
|
+
function summarise(values, calcAverage = mean) {
|
|
20
|
+
if (values.length === 0) {
|
|
21
|
+
return {
|
|
22
|
+
min: 0,
|
|
23
|
+
max: 0,
|
|
24
|
+
avg: 0,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
min: Math.min(...values),
|
|
29
|
+
max: Math.max(...values),
|
|
30
|
+
avg: calcAverage(values),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const msToFps = (ms) => Math.round(1000 / ms);
|
|
34
|
+
function clearStatsBuffer() {
|
|
35
|
+
statsBuffer.value = null;
|
|
36
|
+
statsBuffer.addProjectionMetrics = null;
|
|
37
|
+
}
|
|
38
|
+
function reportStats() {
|
|
39
|
+
const { value } = statsBuffer;
|
|
40
|
+
if (!value) {
|
|
41
|
+
throw new Error("Stats are not being measured");
|
|
42
|
+
}
|
|
43
|
+
clearStatsBuffer();
|
|
44
|
+
cancelFrame(record);
|
|
45
|
+
const summary = {
|
|
46
|
+
frameloop: {
|
|
47
|
+
rate: summarise(value.frameloop.rate),
|
|
48
|
+
read: summarise(value.frameloop.read),
|
|
49
|
+
resolveKeyframes: summarise(value.frameloop.resolveKeyframes),
|
|
50
|
+
update: summarise(value.frameloop.update),
|
|
51
|
+
preRender: summarise(value.frameloop.preRender),
|
|
52
|
+
render: summarise(value.frameloop.render),
|
|
53
|
+
postRender: summarise(value.frameloop.postRender),
|
|
54
|
+
},
|
|
55
|
+
animations: {
|
|
56
|
+
mainThread: summarise(value.animations.mainThread),
|
|
57
|
+
waapi: summarise(value.animations.waapi),
|
|
58
|
+
layout: summarise(value.animations.layout),
|
|
59
|
+
},
|
|
60
|
+
layoutProjection: {
|
|
61
|
+
nodes: summarise(value.layoutProjection.nodes),
|
|
62
|
+
calculatedTargetDeltas: summarise(value.layoutProjection.calculatedTargetDeltas),
|
|
63
|
+
calculatedProjections: summarise(value.layoutProjection.calculatedProjections),
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Convert the rate to FPS
|
|
68
|
+
*/
|
|
69
|
+
const { rate } = summary.frameloop;
|
|
70
|
+
rate.min = msToFps(rate.min);
|
|
71
|
+
rate.max = msToFps(rate.max);
|
|
72
|
+
rate.avg = msToFps(rate.avg);
|
|
73
|
+
[rate.min, rate.max] = [rate.max, rate.min];
|
|
74
|
+
return summary;
|
|
75
|
+
}
|
|
76
|
+
function recordStats() {
|
|
77
|
+
if (statsBuffer.value) {
|
|
78
|
+
clearStatsBuffer();
|
|
79
|
+
throw new Error("Stats are already being measured");
|
|
80
|
+
}
|
|
81
|
+
const newStatsBuffer = statsBuffer;
|
|
82
|
+
newStatsBuffer.value = {
|
|
83
|
+
frameloop: {
|
|
84
|
+
rate: [],
|
|
85
|
+
read: [],
|
|
86
|
+
resolveKeyframes: [],
|
|
87
|
+
update: [],
|
|
88
|
+
preRender: [],
|
|
89
|
+
render: [],
|
|
90
|
+
postRender: [],
|
|
91
|
+
},
|
|
92
|
+
animations: {
|
|
93
|
+
mainThread: [],
|
|
94
|
+
waapi: [],
|
|
95
|
+
layout: [],
|
|
96
|
+
},
|
|
97
|
+
layoutProjection: {
|
|
98
|
+
nodes: [],
|
|
99
|
+
calculatedTargetDeltas: [],
|
|
100
|
+
calculatedProjections: [],
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
newStatsBuffer.addProjectionMetrics = (metrics) => {
|
|
104
|
+
const { layoutProjection } = newStatsBuffer.value;
|
|
105
|
+
layoutProjection.nodes.push(metrics.nodes);
|
|
106
|
+
layoutProjection.calculatedTargetDeltas.push(metrics.calculatedTargetDeltas);
|
|
107
|
+
layoutProjection.calculatedProjections.push(metrics.calculatedProjections);
|
|
108
|
+
};
|
|
109
|
+
frame.postRender(record, true);
|
|
110
|
+
return reportStats;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export { recordStats };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react';
|
|
2
2
|
import { inView } from '../render/dom/viewport/index.mjs';
|
|
3
3
|
|
|
4
|
-
function useInView(ref, { root, margin, amount, once = false } = {}) {
|
|
5
|
-
const [isInView, setInView] = useState(
|
|
4
|
+
function useInView(ref, { root, margin, amount, once = false, initial = false, } = {}) {
|
|
5
|
+
const [isInView, setInView] = useState(initial);
|
|
6
6
|
useEffect(() => {
|
|
7
7
|
if (!ref.current || (once && isInView))
|
|
8
8
|
return;
|
|
@@ -34,7 +34,7 @@ class MotionValue {
|
|
|
34
34
|
* This will be replaced by the build step with the latest version number.
|
|
35
35
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
36
36
|
*/
|
|
37
|
-
this.version = "12.
|
|
37
|
+
this.version = "12.4.0";
|
|
38
38
|
/**
|
|
39
39
|
* Tracks whether this value can output a velocity. Currently this is only true
|
|
40
40
|
* if the value is numerical, but we might be able to widen the scope here and support
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { recordStats } from '../../framer-motion/dist/es/stats/index.mjs';
|
package/dist/motion.dev.js
CHANGED
|
@@ -1320,7 +1320,21 @@
|
|
|
1320
1320
|
useManualTiming: false,
|
|
1321
1321
|
};
|
|
1322
1322
|
|
|
1323
|
-
|
|
1323
|
+
const stepsOrder = [
|
|
1324
|
+
"read", // Read
|
|
1325
|
+
"resolveKeyframes", // Write/Read/Write/Read
|
|
1326
|
+
"update", // Compute
|
|
1327
|
+
"preRender", // Compute
|
|
1328
|
+
"render", // Write
|
|
1329
|
+
"postRender", // Compute
|
|
1330
|
+
];
|
|
1331
|
+
|
|
1332
|
+
const statsBuffer = {
|
|
1333
|
+
value: null,
|
|
1334
|
+
addProjectionMetrics: null,
|
|
1335
|
+
};
|
|
1336
|
+
|
|
1337
|
+
function createRenderStep(runNextFrame, stepName) {
|
|
1324
1338
|
/**
|
|
1325
1339
|
* We create and reuse two queues, one to queue jobs for the current frame
|
|
1326
1340
|
* and one for the next. We reuse to avoid triggering GC after x frames.
|
|
@@ -1342,11 +1356,13 @@
|
|
|
1342
1356
|
timestamp: 0.0,
|
|
1343
1357
|
isProcessing: false,
|
|
1344
1358
|
};
|
|
1359
|
+
let numCalls = 0;
|
|
1345
1360
|
function triggerCallback(callback) {
|
|
1346
1361
|
if (toKeepAlive.has(callback)) {
|
|
1347
1362
|
step.schedule(callback);
|
|
1348
1363
|
runNextFrame();
|
|
1349
1364
|
}
|
|
1365
|
+
numCalls++;
|
|
1350
1366
|
callback(latestFrameData);
|
|
1351
1367
|
}
|
|
1352
1368
|
const step = {
|
|
@@ -1387,6 +1403,13 @@
|
|
|
1387
1403
|
[thisFrame, nextFrame] = [nextFrame, thisFrame];
|
|
1388
1404
|
// Execute this frame
|
|
1389
1405
|
thisFrame.forEach(triggerCallback);
|
|
1406
|
+
/**
|
|
1407
|
+
* If we're recording stats then
|
|
1408
|
+
*/
|
|
1409
|
+
if (stepName && statsBuffer.value) {
|
|
1410
|
+
statsBuffer.value.frameloop[stepName].push(numCalls);
|
|
1411
|
+
}
|
|
1412
|
+
numCalls = 0;
|
|
1390
1413
|
// Clear the frame so no callbacks remain. This is to avoid
|
|
1391
1414
|
// memory leaks should this render step not run for a while.
|
|
1392
1415
|
thisFrame.clear();
|
|
@@ -1400,14 +1423,6 @@
|
|
|
1400
1423
|
return step;
|
|
1401
1424
|
}
|
|
1402
1425
|
|
|
1403
|
-
const stepsOrder = [
|
|
1404
|
-
"read", // Read
|
|
1405
|
-
"resolveKeyframes", // Write/Read/Write/Read
|
|
1406
|
-
"update", // Compute
|
|
1407
|
-
"preRender", // Compute
|
|
1408
|
-
"render", // Write
|
|
1409
|
-
"postRender", // Compute
|
|
1410
|
-
];
|
|
1411
1426
|
const maxElapsed$1 = 40;
|
|
1412
1427
|
function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
|
1413
1428
|
let runNextFrame = false;
|
|
@@ -1419,16 +1434,18 @@
|
|
|
1419
1434
|
};
|
|
1420
1435
|
const flagRunNextFrame = () => (runNextFrame = true);
|
|
1421
1436
|
const steps = stepsOrder.reduce((acc, key) => {
|
|
1422
|
-
acc[key] = createRenderStep(flagRunNextFrame);
|
|
1437
|
+
acc[key] = createRenderStep(flagRunNextFrame, allowKeepAlive ? key : undefined);
|
|
1423
1438
|
return acc;
|
|
1424
1439
|
}, {});
|
|
1425
1440
|
const { read, resolveKeyframes, update, preRender, render, postRender } = steps;
|
|
1426
1441
|
const processBatch = () => {
|
|
1427
1442
|
const timestamp = performance.now();
|
|
1428
1443
|
runNextFrame = false;
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1444
|
+
{
|
|
1445
|
+
state.delta = useDefaultElapsed
|
|
1446
|
+
? 1000 / 60
|
|
1447
|
+
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed$1), 1);
|
|
1448
|
+
}
|
|
1432
1449
|
state.timestamp = timestamp;
|
|
1433
1450
|
state.isProcessing = true;
|
|
1434
1451
|
// Unrolled render loop for better per-frame performance
|
|
@@ -1571,7 +1588,7 @@
|
|
|
1571
1588
|
* This will be replaced by the build step with the latest version number.
|
|
1572
1589
|
* When MotionValues are provided to motion components, warn if versions are mixed.
|
|
1573
1590
|
*/
|
|
1574
|
-
this.version = "12.
|
|
1591
|
+
this.version = "12.4.0";
|
|
1575
1592
|
/**
|
|
1576
1593
|
* Tracks whether this value can output a velocity. Currently this is only true
|
|
1577
1594
|
* if the value is numerical, but we might be able to widen the scope here and support
|
|
@@ -3870,7 +3887,7 @@
|
|
|
3870
3887
|
*/
|
|
3871
3888
|
if (Array.isArray(easing))
|
|
3872
3889
|
keyframeOptions.easing = easing;
|
|
3873
|
-
|
|
3890
|
+
const animation = element.animate(keyframeOptions, {
|
|
3874
3891
|
delay,
|
|
3875
3892
|
duration,
|
|
3876
3893
|
easing: !Array.isArray(easing) ? easing : "linear",
|
|
@@ -3878,6 +3895,7 @@
|
|
|
3878
3895
|
iterations: repeat + 1,
|
|
3879
3896
|
direction: repeatType === "reverse" ? "alternate" : "normal",
|
|
3880
3897
|
});
|
|
3898
|
+
return animation;
|
|
3881
3899
|
}
|
|
3882
3900
|
|
|
3883
3901
|
const supportsWaapi = /*@__PURE__*/ memo(() => Object.hasOwnProperty.call(Element.prototype, "animate"));
|
|
@@ -4505,7 +4523,7 @@
|
|
|
4505
4523
|
* and warn against mismatches.
|
|
4506
4524
|
*/
|
|
4507
4525
|
{
|
|
4508
|
-
warnOnce(nextValue.version === "12.
|
|
4526
|
+
warnOnce(nextValue.version === "12.4.0", `Attempting to mix Motion versions ${nextValue.version} with 12.4.0 may not work as expected.`);
|
|
4509
4527
|
}
|
|
4510
4528
|
}
|
|
4511
4529
|
else if (isMotionValue(prevValue)) {
|