Mission Control Dashboard - Initial implementation
This commit is contained in:
73
node_modules/motion-dom/dist/es/frameloop/batcher.mjs
generated
vendored
Normal file
73
node_modules/motion-dom/dist/es/frameloop/batcher.mjs
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
import { MotionGlobalConfig } from 'motion-utils';
|
||||
import { stepsOrder } from './order.mjs';
|
||||
import { createRenderStep } from './render-step.mjs';
|
||||
|
||||
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, allowKeepAlive ? key : undefined);
|
||||
return acc;
|
||||
}, {});
|
||||
const { setup, read, resolveKeyframes, preUpdate, update, preRender, render, postRender, } = steps;
|
||||
const processBatch = () => {
|
||||
const useManualTiming = MotionGlobalConfig.useManualTiming;
|
||||
const timestamp = useManualTiming
|
||||
? state.timestamp
|
||||
: performance.now();
|
||||
runNextFrame = false;
|
||||
if (!useManualTiming) {
|
||||
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
|
||||
setup.process(state);
|
||||
read.process(state);
|
||||
resolveKeyframes.process(state);
|
||||
preUpdate.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 };
|
||||
//# sourceMappingURL=batcher.mjs.map
|
||||
1
node_modules/motion-dom/dist/es/frameloop/batcher.mjs.map
generated
vendored
Normal file
1
node_modules/motion-dom/dist/es/frameloop/batcher.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
7
node_modules/motion-dom/dist/es/frameloop/frame.mjs
generated
vendored
Normal file
7
node_modules/motion-dom/dist/es/frameloop/frame.mjs
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import { noop } from 'motion-utils';
|
||||
import { createRenderBatcher } from './batcher.mjs';
|
||||
|
||||
const { schedule: frame, cancel: cancelFrame, state: frameData, steps: frameSteps, } = /* @__PURE__ */ createRenderBatcher(typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : noop, true);
|
||||
|
||||
export { cancelFrame, frame, frameData, frameSteps };
|
||||
//# sourceMappingURL=frame.mjs.map
|
||||
1
node_modules/motion-dom/dist/es/frameloop/frame.mjs.map
generated
vendored
Normal file
1
node_modules/motion-dom/dist/es/frameloop/frame.mjs.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"frame.mjs","sources":["../../../src/frameloop/frame.ts"],"sourcesContent":["import { noop } from \"motion-utils\"\nimport { createRenderBatcher } from \"./batcher\"\n\nexport const {\n schedule: frame,\n cancel: cancelFrame,\n state: frameData,\n steps: frameSteps,\n} = /* @__PURE__ */ createRenderBatcher(\n typeof requestAnimationFrame !== \"undefined\" ? requestAnimationFrame : noop,\n true\n)\n"],"names":[],"mappings":";;;AAGO,MAAM,EACT,QAAQ,EAAE,KAAK,EACf,MAAM,EAAE,WAAW,EACnB,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,UAAU,GACpB,mBAAmB,mBAAmB,CACnC,OAAO,qBAAqB,KAAK,WAAW,GAAG,qBAAqB,GAAG,IAAI,EAC3E,IAAI;;;;"}
|
||||
21
node_modules/motion-dom/dist/es/frameloop/index-legacy.mjs
generated
vendored
Normal file
21
node_modules/motion-dom/dist/es/frameloop/index-legacy.mjs
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
import { stepsOrder } from './order.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 };
|
||||
//# sourceMappingURL=index-legacy.mjs.map
|
||||
1
node_modules/motion-dom/dist/es/frameloop/index-legacy.mjs.map
generated
vendored
Normal file
1
node_modules/motion-dom/dist/es/frameloop/index-legacy.mjs.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index-legacy.mjs","sources":["../../../src/frameloop/index-legacy.ts"],"sourcesContent":["import { cancelFrame, frame } from \".\"\nimport { stepsOrder } from \"./order\"\nimport { Process } from \"./types\"\n\n/**\n * @deprecated\n *\n * Import as `frame` instead.\n */\nexport const sync = frame\n\n/**\n * @deprecated\n *\n * Use cancelFrame(callback) instead.\n */\nexport const cancelSync = stepsOrder.reduce((acc, key) => {\n acc[key] = (process: Process) => cancelFrame(process)\n return acc\n}, {} as Record<string, (process: Process) => void>)\n"],"names":[],"mappings":";;;AAIA;;;;AAIG;AACI,MAAM,IAAI,GAAG;AAEpB;;;;AAIG;AACI,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,KAAI;AACrD,IAAA,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,OAAgB,KAAK,WAAW,CAAC,OAAO,CAAC;AACrD,IAAA,OAAO,GAAG;AACd,CAAC,EAAE,EAAgD;;;;"}
|
||||
7
node_modules/motion-dom/dist/es/frameloop/microtask.mjs
generated
vendored
Normal file
7
node_modules/motion-dom/dist/es/frameloop/microtask.mjs
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import { createRenderBatcher } from './batcher.mjs';
|
||||
|
||||
const { schedule: microtask, cancel: cancelMicrotask } =
|
||||
/* @__PURE__ */ createRenderBatcher(queueMicrotask, false);
|
||||
|
||||
export { cancelMicrotask, microtask };
|
||||
//# sourceMappingURL=microtask.mjs.map
|
||||
1
node_modules/motion-dom/dist/es/frameloop/microtask.mjs.map
generated
vendored
Normal file
1
node_modules/motion-dom/dist/es/frameloop/microtask.mjs.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"microtask.mjs","sources":["../../../src/frameloop/microtask.ts"],"sourcesContent":["import { createRenderBatcher } from \"./batcher\"\n\nexport const { schedule: microtask, cancel: cancelMicrotask } =\n /* @__PURE__ */ createRenderBatcher(queueMicrotask, false)\n"],"names":[],"mappings":";;AAEO,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,EAAE;AACzD,gBAAgB,mBAAmB,CAAC,cAAc,EAAE,KAAK;;;;"}
|
||||
13
node_modules/motion-dom/dist/es/frameloop/order.mjs
generated
vendored
Normal file
13
node_modules/motion-dom/dist/es/frameloop/order.mjs
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
const stepsOrder = [
|
||||
"setup", // Compute
|
||||
"read", // Read
|
||||
"resolveKeyframes", // Write/Read/Write/Read
|
||||
"preUpdate", // Compute
|
||||
"update", // Compute
|
||||
"preRender", // Compute
|
||||
"render", // Write
|
||||
"postRender", // Compute
|
||||
];
|
||||
|
||||
export { stepsOrder };
|
||||
//# sourceMappingURL=order.mjs.map
|
||||
1
node_modules/motion-dom/dist/es/frameloop/order.mjs.map
generated
vendored
Normal file
1
node_modules/motion-dom/dist/es/frameloop/order.mjs.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"order.mjs","sources":["../../../src/frameloop/order.ts"],"sourcesContent":["import { StepId } from \"./types\"\n\nexport const stepsOrder: StepId[] = [\n \"setup\", // Compute\n \"read\", // Read\n \"resolveKeyframes\", // Write/Read/Write/Read\n \"preUpdate\", // Compute\n \"update\", // Compute\n \"preRender\", // Compute\n \"render\", // Write\n \"postRender\", // Compute\n] as const\n\nexport type StepNames = (typeof stepsOrder)[number]\n"],"names":[],"mappings":"AAEO,MAAM,UAAU,GAAa;AAChC,IAAA,OAAO;AACP,IAAA,MAAM;AACN,IAAA,kBAAkB;AAClB,IAAA,WAAW;AACX,IAAA,QAAQ;AACR,IAAA,WAAW;AACX,IAAA,QAAQ;AACR,IAAA,YAAY;;;;;"}
|
||||
95
node_modules/motion-dom/dist/es/frameloop/render-step.mjs
generated
vendored
Normal file
95
node_modules/motion-dom/dist/es/frameloop/render-step.mjs
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
import { statsBuffer } from '../stats/buffer.mjs';
|
||||
|
||||
function createRenderStep(runNextFrame, stepName) {
|
||||
/**
|
||||
* 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,
|
||||
};
|
||||
let numCalls = 0;
|
||||
function triggerCallback(callback) {
|
||||
if (toKeepAlive.has(callback)) {
|
||||
step.schedule(callback);
|
||||
runNextFrame();
|
||||
}
|
||||
numCalls++;
|
||||
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);
|
||||
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;
|
||||
// Swap this frame and the next to avoid GC
|
||||
const prevFrame = thisFrame;
|
||||
thisFrame = nextFrame;
|
||||
nextFrame = prevFrame;
|
||||
// Execute this frame
|
||||
thisFrame.forEach(triggerCallback);
|
||||
/**
|
||||
* If we're recording stats then
|
||||
*/
|
||||
if (stepName && statsBuffer.value) {
|
||||
statsBuffer.value.frameloop[stepName].push(numCalls);
|
||||
}
|
||||
numCalls = 0;
|
||||
// Clear the frame so no callbacks remain. This is to avoid
|
||||
// memory leaks should this render step not run for a while.
|
||||
thisFrame.clear();
|
||||
isProcessing = false;
|
||||
if (flushNextFrame) {
|
||||
flushNextFrame = false;
|
||||
step.process(frameData);
|
||||
}
|
||||
},
|
||||
};
|
||||
return step;
|
||||
}
|
||||
|
||||
export { createRenderStep };
|
||||
//# sourceMappingURL=render-step.mjs.map
|
||||
1
node_modules/motion-dom/dist/es/frameloop/render-step.mjs.map
generated
vendored
Normal file
1
node_modules/motion-dom/dist/es/frameloop/render-step.mjs.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
32
node_modules/motion-dom/dist/es/frameloop/sync-time.mjs
generated
vendored
Normal file
32
node_modules/motion-dom/dist/es/frameloop/sync-time.mjs
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import { MotionGlobalConfig } from 'motion-utils';
|
||||
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 };
|
||||
//# sourceMappingURL=sync-time.mjs.map
|
||||
1
node_modules/motion-dom/dist/es/frameloop/sync-time.mjs.map
generated
vendored
Normal file
1
node_modules/motion-dom/dist/es/frameloop/sync-time.mjs.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"sync-time.mjs","sources":["../../../src/frameloop/sync-time.ts"],"sourcesContent":["import { MotionGlobalConfig } from \"motion-utils\"\nimport { frameData } from \"./frame\"\n\nlet now: number | undefined\n\nfunction clearTime() {\n now = undefined\n}\n\n/**\n * An eventloop-synchronous alternative to performance.now().\n *\n * Ensures that time measurements remain consistent within a synchronous context.\n * Usually calling performance.now() twice within the same synchronous context\n * will return different values which isn't useful for animations when we're usually\n * trying to sync animations to the same frame.\n */\nexport const time = {\n now: (): number => {\n if (now === undefined) {\n time.set(\n frameData.isProcessing || MotionGlobalConfig.useManualTiming\n ? frameData.timestamp\n : performance.now()\n )\n }\n\n return now!\n },\n set: (newTime: number) => {\n now = newTime\n queueMicrotask(clearTime)\n },\n}\n"],"names":[],"mappings":";;;AAGA,IAAI,GAAuB;AAE3B,SAAS,SAAS,GAAA;IACd,GAAG,GAAG,SAAS;AACnB;AAEA;;;;;;;AAOG;AACI,MAAM,IAAI,GAAG;IAChB,GAAG,EAAE,MAAa;AACd,QAAA,IAAI,GAAG,KAAK,SAAS,EAAE;YACnB,IAAI,CAAC,GAAG,CACJ,SAAS,CAAC,YAAY,IAAI,kBAAkB,CAAC;kBACvC,SAAS,CAAC;AACZ,kBAAE,WAAW,CAAC,GAAG,EAAE,CAC1B;QACL;AAEA,QAAA,OAAO,GAAI;IACf,CAAC;AACD,IAAA,GAAG,EAAE,CAAC,OAAe,KAAI;QACrB,GAAG,GAAG,OAAO;QACb,cAAc,CAAC,SAAS,CAAC;IAC7B,CAAC;;;;;"}
|
||||
Reference in New Issue
Block a user