till download files, everything works
This commit is contained in:
1 parent
ce893a4185
commit
ed1a580b09
6050 files changed
+768543
-177
No files matched your search
+74
@@ -0,0 +1,74 @@
|
||||
import { MotionGlobalConfig } from '../utils/GlobalConfig.mjs';
|
||||
import { createRenderStep } from './render-step.mjs';
|
||||
|
||||
const stepsOrder = [
|
||||
"read", // Read
|
||||
"resolveKeyframes", // Write/Read/Write/Read
|
||||
"update", // Compute
|
||||
"preRender", // Compute
|
||||
"render", // Write
|
||||
"postRender", // Compute
|
||||
];
|
||||
const maxElapsed = 40;
|
||||
function createRenderBatcher(scheduleNextBatch, allowKeepAlive) {
|
||||
let runNextFrame = false;
|
||||
let useDefaultElapsed = true;
|
||||
const state = {
|
||||
delta: 0.0,
|
||||
timestamp: 0.0,
|
||||
isProcessing: false,
|
||||
};
|
||||
const flagRunNextFrame = () => (runNextFrame = true);
|
||||
const steps = stepsOrder.reduce((acc, key) => {
|
||||
acc[key] = createRenderStep(flagRunNextFrame);
|
||||
return acc;
|
||||
}, {});
|
||||
const { read, resolveKeyframes, update, preRender, render, postRender } = steps;
|
||||
const processBatch = () => {
|
||||
const timestamp = MotionGlobalConfig.useManualTiming
|
||||
? state.timestamp
|
||||
: performance.now();
|
||||
runNextFrame = false;
|
||||
state.delta = useDefaultElapsed
|
||||
? 1000 / 60
|
||||
: Math.max(Math.min(timestamp - state.timestamp, maxElapsed), 1);
|
||||
state.timestamp = timestamp;
|
||||
state.isProcessing = true;
|
||||
// Unrolled render loop for better per-frame performance
|
||||
read.process(state);
|
||||
resolveKeyframes.process(state);
|
||||
update.process(state);
|
||||
preRender.process(state);
|
||||
render.process(state);
|
||||
postRender.process(state);
|
||||
state.isProcessing = false;
|
||||
if (runNextFrame && allowKeepAlive) {
|
||||
useDefaultElapsed = false;
|
||||
scheduleNextBatch(processBatch);
|
||||
}
|
||||
};
|
||||
const wake = () => {
|
||||
runNextFrame = true;
|
||||
useDefaultElapsed = true;
|
||||
if (!state.isProcessing) {
|
||||
scheduleNextBatch(processBatch);
|
||||
}
|
||||
};
|
||||
const schedule = stepsOrder.reduce((acc, key) => {
|
||||
const step = steps[key];
|
||||
acc[key] = (process, keepAlive = false, immediate = false) => {
|
||||
if (!runNextFrame)
|
||||
wake();
|
||||
return step.schedule(process, keepAlive, immediate);
|
||||
};
|
||||
return acc;
|
||||
}, {});
|
||||
const cancel = (process) => {
|
||||
for (let i = 0; i < stepsOrder.length; i++) {
|
||||
steps[stepsOrder[i]].cancel(process);
|
||||
}
|
||||
};
|
||||
return { schedule, cancel, state, steps };
|
||||
}
|
||||
|
||||
export { createRenderBatcher, stepsOrder };
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import { noop } from '../utils/noop.mjs';
|
||||
import { createRenderBatcher } from './batcher.mjs';
|
||||
|
||||
const { schedule: frame, cancel: cancelFrame, state: frameData, steps: frameSteps, } = createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
|
||||
|
||||
export { cancelFrame, frame, frameData, frameSteps };
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import { stepsOrder } from './batcher.mjs';
|
||||
import { frame, cancelFrame } from './frame.mjs';
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* Import as `frame` instead.
|
||||
*/
|
||||
const sync = frame;
|
||||
/**
|
||||
* @deprecated
|
||||
*
|
||||
* Use cancelFrame(callback) instead.
|
||||
*/
|
||||
const cancelSync = stepsOrder.reduce((acc, key) => {
|
||||
acc[key] = (process) => cancelFrame(process);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
export { cancelSync, sync };
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import { createRenderBatcher } from './batcher.mjs';
|
||||
|
||||
const { schedule: microtask, cancel: cancelMicrotask } = createRenderBatcher(queueMicrotask, false);
|
||||
|
||||
export { cancelMicrotask, microtask };
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
function createRenderStep(runNextFrame) {
|
||||
/**
|
||||
* We create and reuse two queues, one to queue jobs for the current frame
|
||||
* and one for the next. We reuse to avoid triggering GC after x frames.
|
||||
*/
|
||||
let thisFrame = new Set();
|
||||
let nextFrame = new Set();
|
||||
/**
|
||||
* Track whether we're currently processing jobs in this step. This way
|
||||
* we can decide whether to schedule new jobs for this frame or next.
|
||||
*/
|
||||
let isProcessing = false;
|
||||
let flushNextFrame = false;
|
||||
/**
|
||||
* A set of processes which were marked keepAlive when scheduled.
|
||||
*/
|
||||
const toKeepAlive = new WeakSet();
|
||||
let latestFrameData = {
|
||||
delta: 0.0,
|
||||
timestamp: 0.0,
|
||||
isProcessing: false,
|
||||
};
|
||||
function triggerCallback(callback) {
|
||||
if (toKeepAlive.has(callback)) {
|
||||
step.schedule(callback);
|
||||
runNextFrame();
|
||||
}
|
||||
callback(latestFrameData);
|
||||
}
|
||||
const step = {
|
||||
/**
|
||||
* Schedule a process to run on the next frame.
|
||||
*/
|
||||
schedule: (callback, keepAlive = false, immediate = false) => {
|
||||
const addToCurrentFrame = immediate && isProcessing;
|
||||
const queue = addToCurrentFrame ? thisFrame : nextFrame;
|
||||
if (keepAlive)
|
||||
toKeepAlive.add(callback);
|
||||
if (!queue.has(callback))
|
||||
queue.add(callback);
|
||||
return callback;
|
||||
},
|
||||
/**
|
||||
* Cancel the provided callback from running on the next frame.
|
||||
*/
|
||||
cancel: (callback) => {
|
||||
nextFrame.delete(callback);
|
||||
toKeepAlive.delete(callback);
|
||||
},
|
||||
/**
|
||||
* Execute all schedule callbacks.
|
||||
*/
|
||||
process: (frameData) => {
|
||||
latestFrameData = frameData;
|
||||
/**
|
||||
* If we're already processing we've probably been triggered by a flushSync
|
||||
* inside an existing process. Instead of executing, mark flushNextFrame
|
||||
* as true and ensure we flush the following frame at the end of this one.
|
||||
*/
|
||||
if (isProcessing) {
|
||||
flushNextFrame = true;
|
||||
return;
|
||||
}
|
||||
isProcessing = true;
|
||||
[thisFrame, nextFrame] = [nextFrame, thisFrame];
|
||||
// Clear the next frame queue
|
||||
nextFrame.clear();
|
||||
// Execute this frame
|
||||
thisFrame.forEach(triggerCallback);
|
||||
isProcessing = false;
|
||||
if (flushNextFrame) {
|
||||
flushNextFrame = false;
|
||||
step.process(frameData);
|
||||
}
|
||||
},
|
||||
};
|
||||
return step;
|
||||
}
|
||||
|
||||
export { createRenderStep };
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
import { MotionGlobalConfig } from '../utils/GlobalConfig.mjs';
|
||||
import { frameData } from './frame.mjs';
|
||||
|
||||
let now;
|
||||
function clearTime() {
|
||||
now = undefined;
|
||||
}
|
||||
/**
|
||||
* An eventloop-synchronous alternative to performance.now().
|
||||
*
|
||||
* Ensures that time measurements remain consistent within a synchronous context.
|
||||
* Usually calling performance.now() twice within the same synchronous context
|
||||
* will return different values which isn't useful for animations when we're usually
|
||||
* trying to sync animations to the same frame.
|
||||
*/
|
||||
const time = {
|
||||
now: () => {
|
||||
if (now === undefined) {
|
||||
time.set(frameData.isProcessing || MotionGlobalConfig.useManualTiming
|
||||
? frameData.timestamp
|
||||
: performance.now());
|
||||
}
|
||||
return now;
|
||||
},
|
||||
set: (newTime) => {
|
||||
now = newTime;
|
||||
queueMicrotask(clearTime);
|
||||
},
|
||||
};
|
||||
|
||||
export { time };
|
||||
Reference in new issue
Block a user