motion 12.3.1 → 12.4.1
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 +48 -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/animation-state.mjs +12 -0
- 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;
|
|
@@ -253,6 +253,18 @@ function createAnimationState(visualElement) {
|
|
|
253
253
|
*/
|
|
254
254
|
if (removedKeys.size) {
|
|
255
255
|
const fallbackAnimation = {};
|
|
256
|
+
/**
|
|
257
|
+
* If the initial prop contains a transition we can use that, otherwise
|
|
258
|
+
* allow the animation function to use the visual element's default.
|
|
259
|
+
*/
|
|
260
|
+
if (typeof props.initial !== "boolean") {
|
|
261
|
+
const initialTransition = resolveVariant(visualElement, Array.isArray(props.initial)
|
|
262
|
+
? props.initial[0]
|
|
263
|
+
: props.initial);
|
|
264
|
+
if (initialTransition && initialTransition.transition) {
|
|
265
|
+
fallbackAnimation.transition = initialTransition.transition;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
256
268
|
removedKeys.forEach((key) => {
|
|
257
269
|
const fallbackTarget = visualElement.getBaseTarget(key);
|
|
258
270
|
const motionValue = visualElement.getValue(key);
|
|
@@ -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.1", `Attempting to mix Motion versions ${nextValue.version} with 12.4.1 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.1";
|
|
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';
|