remotion 4.0.536 → 4.0.537
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/CompositionManagerContext.d.ts +3 -0
- package/dist/cjs/CompositionManagerContext.js +5 -3
- package/dist/cjs/CompositionManagerProvider.js +3 -1
- package/dist/cjs/HtmlInCanvas.js +66 -15
- package/dist/cjs/animated-image/AnimatedImage.js +11 -6
- package/dist/cjs/effects/use-memoized-effects.js +86 -44
- package/dist/cjs/internals.d.ts +3 -0
- package/dist/cjs/internals.js +1 -0
- package/dist/cjs/timeline-position-state.d.ts +1 -0
- package/dist/cjs/timeline-position-state.js +21 -1
- package/dist/cjs/use-current-frame.d.ts +1 -0
- package/dist/cjs/use-current-frame.js +14 -7
- package/dist/cjs/validation/validate-duration-in-frames.js +3 -3
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/with-interactivity-schema.js +18 -16
- package/dist/esm/index.mjs +327 -243
- package/dist/esm/no-react.mjs +3 -3
- package/dist/esm/version.mjs +1 -1
- package/package.json +2 -2
|
@@ -38,4 +38,7 @@ export type CompositionManagerContext = {
|
|
|
38
38
|
canvasContent: CanvasContent | null;
|
|
39
39
|
};
|
|
40
40
|
export declare const CompositionManager: React.Context<CompositionManagerContext>;
|
|
41
|
+
export declare const CompositionManagerRefContext: React.Context<{
|
|
42
|
+
readonly current: CompositionManagerContext;
|
|
43
|
+
}>;
|
|
41
44
|
export declare const CompositionSetters: React.Context<CompositionManagerSetters>;
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CompositionSetters = exports.CompositionManager = exports.getAssetPreviewCompositionId = void 0;
|
|
3
|
+
exports.CompositionSetters = exports.CompositionManagerRefContext = exports.CompositionManager = exports.getAssetPreviewCompositionId = void 0;
|
|
4
4
|
const react_1 = require("react");
|
|
5
5
|
const getAssetPreviewCompositionId = (asset) => `asset:${asset}`;
|
|
6
6
|
exports.getAssetPreviewCompositionId = getAssetPreviewCompositionId;
|
|
7
|
-
|
|
7
|
+
const defaultCompositionManagerContext = {
|
|
8
8
|
compositions: [],
|
|
9
9
|
folders: [],
|
|
10
10
|
currentCompositionMetadata: null,
|
|
11
11
|
currentAssetMetadata: null,
|
|
12
12
|
canvasContent: null,
|
|
13
|
-
}
|
|
13
|
+
};
|
|
14
|
+
exports.CompositionManager = (0, react_1.createContext)(defaultCompositionManagerContext);
|
|
15
|
+
exports.CompositionManagerRefContext = (0, react_1.createContext)({ current: defaultCompositionManagerContext });
|
|
14
16
|
exports.CompositionSetters = (0, react_1.createContext)({
|
|
15
17
|
setCanvasContent: () => undefined,
|
|
16
18
|
setCurrentAssetMetadata: () => undefined,
|
|
@@ -103,9 +103,11 @@ const CompositionManagerProvider = ({ children, onlyRenderComposition, currentCo
|
|
|
103
103
|
currentAssetMetadata,
|
|
104
104
|
canvasContent,
|
|
105
105
|
]);
|
|
106
|
+
const compositionManagerRef = (0, react_1.useRef)(compositionManagerContextValue);
|
|
107
|
+
compositionManagerRef.current = compositionManagerContextValue;
|
|
106
108
|
if (registrationError !== null) {
|
|
107
109
|
throw registrationError;
|
|
108
110
|
}
|
|
109
|
-
return (jsx_runtime_1.jsx(CompositionRegistryProvider_js_1.CompositionRegistryProvider, { ref: flushSnapshotRef, onSnapshot: onCommitRegistrations, children: jsx_runtime_1.jsx(CompositionManagerContext_1.CompositionManager.Provider, { value: compositionManagerContextValue, children: jsx_runtime_1.jsx(CompositionManagerContext_1.CompositionSetters.Provider, { value: compositionManagerSetters, children: children }) }) }));
|
|
111
|
+
return (jsx_runtime_1.jsx(CompositionRegistryProvider_js_1.CompositionRegistryProvider, { ref: flushSnapshotRef, onSnapshot: onCommitRegistrations, children: jsx_runtime_1.jsx(CompositionManagerContext_1.CompositionManager.Provider, { value: compositionManagerContextValue, children: jsx_runtime_1.jsx(CompositionManagerContext_1.CompositionManagerRefContext.Provider, { value: compositionManagerRef, children: jsx_runtime_1.jsx(CompositionManagerContext_1.CompositionSetters.Provider, { value: compositionManagerSetters, children: children }) }) }) }));
|
|
110
112
|
};
|
|
111
113
|
exports.CompositionManagerProvider = CompositionManagerProvider;
|
package/dist/cjs/HtmlInCanvas.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.HtmlInCanvas = exports.htmlInCanvasSchema = exports.getHtmlInCanvasUnsupportedMessage = exports.HTML_IN_CANVAS_UNSUPPORTED_MESSAGE = exports.isHtmlInCanvasNestingSupported = exports.isHtmlInCanvasSupported = void 0;
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const react_1 = require("react");
|
|
6
|
+
const DefaultPremountContext_js_1 = require("./DefaultPremountContext.js");
|
|
6
7
|
const run_effect_chain_js_1 = require("./effects/run-effect-chain.js");
|
|
7
8
|
const use_effect_chain_state_js_1 = require("./effects/use-effect-chain-state.js");
|
|
8
9
|
const use_memoized_effects_js_1 = require("./effects/use-memoized-effects.js");
|
|
@@ -160,11 +161,15 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, e
|
|
|
160
161
|
const { isClientSideRendering, isRendering } = (0, use_remotion_environment_js_1.useRemotionEnvironment)();
|
|
161
162
|
const canRetryMissingPaintRecord = !isRendering || isClientSideRendering;
|
|
162
163
|
const usesDirectLayoutCanvas = onPaint === undefined && onInit === undefined;
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
// Keep a nested drawable canvas separate from the bitmap captured by its
|
|
165
|
+
// parent. Reusing it for both can crash Chromium during raster invalidation.
|
|
166
|
+
const paintTargetMode = ancestorPaintState
|
|
167
|
+
? 'copied'
|
|
168
|
+
: usesDirectLayoutCanvas
|
|
169
|
+
? 'direct'
|
|
170
|
+
: isRendering
|
|
171
|
+
? 'copied'
|
|
172
|
+
: 'transferred';
|
|
168
173
|
if (!(0, exports.isHtmlInCanvasSupported)()) {
|
|
169
174
|
cancelRender(new Error((0, exports.getHtmlInCanvasUnsupportedMessage)()));
|
|
170
175
|
}
|
|
@@ -237,9 +242,11 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, e
|
|
|
237
242
|
const initializedRef = (0, react_1.useRef)(false);
|
|
238
243
|
const onInitCleanupRef = (0, react_1.useRef)(null);
|
|
239
244
|
const unmountedRef = (0, react_1.useRef)(false);
|
|
245
|
+
const effectScratchCanvasesRef = (0, react_1.useRef)(null);
|
|
240
246
|
const paintingTargets = (0, react_1.useRef)(new WeakMap());
|
|
241
247
|
const onPaintCb = (0, react_1.useCallback)(async () => {
|
|
242
248
|
var _a, _b;
|
|
249
|
+
var _c;
|
|
243
250
|
if (isRendering && paintState.pendingChildren > 0) {
|
|
244
251
|
return;
|
|
245
252
|
}
|
|
@@ -351,6 +358,7 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, e
|
|
|
351
358
|
}
|
|
352
359
|
throw error;
|
|
353
360
|
}
|
|
361
|
+
let effectSourceCanvas = null;
|
|
354
362
|
try {
|
|
355
363
|
const currentOnPaint = onPaintRef.current;
|
|
356
364
|
if (currentOnPaint) {
|
|
@@ -367,6 +375,48 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, e
|
|
|
367
375
|
await paintResult;
|
|
368
376
|
}
|
|
369
377
|
}
|
|
378
|
+
else if (paintTarget instanceof HTMLCanvasElement &&
|
|
379
|
+
effectsRef.current.some((effect) => !effect.params.disabled)) {
|
|
380
|
+
// The element image can only be drawn into the visible layout
|
|
381
|
+
// canvas, but effects finish asynchronously (e.g. while the
|
|
382
|
+
// WebGPU device initializes). Move the unprocessed pixels to a
|
|
383
|
+
// scratch canvas and restore the previous output within this task,
|
|
384
|
+
// so the browser never presents the HTML without its effects.
|
|
385
|
+
(_c = effectScratchCanvasesRef.current) !== null && _c !== void 0 ? _c : (effectScratchCanvasesRef.current = {
|
|
386
|
+
source: document.createElement('canvas'),
|
|
387
|
+
previousOutput: document.createElement('canvas'),
|
|
388
|
+
});
|
|
389
|
+
const { source: effectSource, previousOutput } = effectScratchCanvasesRef.current;
|
|
390
|
+
resizePaintTarget({
|
|
391
|
+
target: effectSource,
|
|
392
|
+
width: canvasWidth,
|
|
393
|
+
height: canvasHeight,
|
|
394
|
+
});
|
|
395
|
+
resizePaintTarget({
|
|
396
|
+
target: previousOutput,
|
|
397
|
+
width: canvasWidth,
|
|
398
|
+
height: canvasHeight,
|
|
399
|
+
});
|
|
400
|
+
const effectSourceCtx = effectSource.getContext('2d');
|
|
401
|
+
const previousOutputCtx = previousOutput.getContext('2d');
|
|
402
|
+
const paintTargetCtx = paintTarget.getContext('2d');
|
|
403
|
+
if (!effectSourceCtx || !previousOutputCtx || !paintTargetCtx) {
|
|
404
|
+
throw new Error('Failed to acquire 2D context for <HtmlInCanvas> canvas');
|
|
405
|
+
}
|
|
406
|
+
previousOutputCtx.reset();
|
|
407
|
+
previousOutputCtx.drawImage(paintTarget, 0, 0);
|
|
408
|
+
defaultOnPaint({
|
|
409
|
+
canvas: paintTarget,
|
|
410
|
+
element,
|
|
411
|
+
elementImage: elImage,
|
|
412
|
+
pixelDensity: resolvedPixelDensity,
|
|
413
|
+
});
|
|
414
|
+
effectSourceCtx.reset();
|
|
415
|
+
effectSourceCtx.drawImage(paintTarget, 0, 0);
|
|
416
|
+
paintTargetCtx.reset();
|
|
417
|
+
paintTargetCtx.drawImage(previousOutput, 0, 0);
|
|
418
|
+
effectSourceCanvas = effectSource;
|
|
419
|
+
}
|
|
370
420
|
else {
|
|
371
421
|
defaultOnPaint({
|
|
372
422
|
canvas: paintTarget,
|
|
@@ -380,7 +430,7 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, e
|
|
|
380
430
|
if (state) {
|
|
381
431
|
await (0, run_effect_chain_js_1.runEffectChain)({
|
|
382
432
|
state,
|
|
383
|
-
source: paintTarget,
|
|
433
|
+
source: effectSourceCanvas !== null && effectSourceCanvas !== void 0 ? effectSourceCanvas : paintTarget,
|
|
384
434
|
effects: effectsRef.current,
|
|
385
435
|
output: paintTarget,
|
|
386
436
|
width: canvasWidth,
|
|
@@ -445,10 +495,11 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, e
|
|
|
445
495
|
paintState.release = null;
|
|
446
496
|
};
|
|
447
497
|
}, [paintState]);
|
|
448
|
-
//
|
|
449
|
-
//
|
|
450
|
-
//
|
|
451
|
-
//
|
|
498
|
+
// Non-nested default handlers paint directly on the layout canvas. Nested
|
|
499
|
+
// canvases and custom handlers retain a transferred target because an
|
|
500
|
+
// ElementImage can only be drawn into its associated canvas. Nested canvases
|
|
501
|
+
// and rendering copy it to a separate visible canvas without waiting for
|
|
502
|
+
// the transferred canvas to present.
|
|
452
503
|
(0, react_1.useLayoutEffect)(() => {
|
|
453
504
|
var _a;
|
|
454
505
|
const placeholder = canvas2dRef.current;
|
|
@@ -539,7 +590,7 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, e
|
|
|
539
590
|
};
|
|
540
591
|
}, [height, style, width]);
|
|
541
592
|
return (jsx_runtime_1.jsxs(HtmlInCanvasAncestorContext.Provider, { value: paintState, children: [
|
|
542
|
-
jsx_runtime_1.
|
|
593
|
+
jsx_runtime_1.jsx("canvas", { ref: paintTargetMode === 'copied' ? canvas2dRef : setVisibleCanvasRef, width: canvasWidth, height: canvasHeight, style: paintTargetMode === 'copied'
|
|
543
594
|
? {
|
|
544
595
|
...canvasStyle,
|
|
545
596
|
position: 'absolute',
|
|
@@ -548,10 +599,10 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, e
|
|
|
548
599
|
visibility: 'hidden',
|
|
549
600
|
pointerEvents: 'none',
|
|
550
601
|
}
|
|
551
|
-
: canvasStyle, children: [
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
602
|
+
: canvasStyle, children: jsx_runtime_1.jsxs(DefaultPremountContext_js_1.DefaultPremountContext.Provider, { value: 0, children: [
|
|
603
|
+
jsx_runtime_1.jsx("div", { ref: divRef, style: paintTargetMode === 'copied'
|
|
604
|
+
? { ...innerStyle, visibility: 'visible' }
|
|
605
|
+
: innerStyle, children: children }), canvasSiblings] }) }, canvasSizeKey), paintTargetMode === 'copied' ? (jsx_runtime_1.jsx("canvas", { ref: setVisibleCanvasRef, width: canvasWidth, height: canvasHeight, style: canvasStyle }, `output-${canvasSizeKey}`)) : null] }));
|
|
555
606
|
});
|
|
556
607
|
HtmlInCanvasContent.displayName = 'HtmlInCanvasContent';
|
|
557
608
|
// Subscribe to frame changes only while rendering. Preview keeps relying on
|
|
@@ -56,6 +56,7 @@ const AnimatedImageContent = (0, react_2.forwardRef)(({ src, width, height, onEr
|
|
|
56
56
|
const resolvedSrc = (0, resolve_image_source_1.resolveAnimatedImageSource)(src);
|
|
57
57
|
const [decodedImage, setDecodedImage] = (0, react_2.useState)(null);
|
|
58
58
|
const imageDecoder = (_a = decodedImage === null || decodedImage === void 0 ? void 0 : decodedImage.decoder) !== null && _a !== void 0 ? _a : null;
|
|
59
|
+
const activeDecoderRef = (0, react_2.useRef)(null);
|
|
59
60
|
const { delayRender, continueRender, cancelRender } = (0, use_delay_render_js_1.useDelayRender)();
|
|
60
61
|
const frame = (0, use_current_frame_js_1.useCurrentFrame)();
|
|
61
62
|
const { fps } = (0, use_video_config_js_1.useVideoConfig)();
|
|
@@ -85,6 +86,7 @@ const AnimatedImageContent = (0, react_2.forwardRef)(({ src, width, height, onEr
|
|
|
85
86
|
const controller = new AbortController();
|
|
86
87
|
let cancelled = false;
|
|
87
88
|
let continued = false;
|
|
89
|
+
let decoder = null;
|
|
88
90
|
const continueRenderOnce = () => {
|
|
89
91
|
if (continued) {
|
|
90
92
|
return;
|
|
@@ -104,6 +106,8 @@ const AnimatedImageContent = (0, react_2.forwardRef)(({ src, width, height, onEr
|
|
|
104
106
|
d.close();
|
|
105
107
|
return;
|
|
106
108
|
}
|
|
109
|
+
decoder = d;
|
|
110
|
+
activeDecoderRef.current = d;
|
|
107
111
|
setDecodedImage({ decoder: d, handle: decodeHandle });
|
|
108
112
|
})
|
|
109
113
|
.catch((err) => {
|
|
@@ -124,6 +128,8 @@ const AnimatedImageContent = (0, react_2.forwardRef)(({ src, width, height, onEr
|
|
|
124
128
|
});
|
|
125
129
|
return () => {
|
|
126
130
|
cancelled = true;
|
|
131
|
+
activeDecoderRef.current = null;
|
|
132
|
+
decoder === null || decoder === void 0 ? void 0 : decoder.close();
|
|
127
133
|
controller.abort();
|
|
128
134
|
continueRenderOnce();
|
|
129
135
|
};
|
|
@@ -136,13 +142,12 @@ const AnimatedImageContent = (0, react_2.forwardRef)(({ src, width, height, onEr
|
|
|
136
142
|
delayRender,
|
|
137
143
|
cancelRender,
|
|
138
144
|
]);
|
|
139
|
-
(0, react_2.useEffect)(() => {
|
|
140
|
-
return () => {
|
|
141
|
-
imageDecoder === null || imageDecoder === void 0 ? void 0 : imageDecoder.close();
|
|
142
|
-
};
|
|
143
|
-
}, [imageDecoder]);
|
|
144
145
|
(0, react_2.useLayoutEffect)(() => {
|
|
145
|
-
|
|
146
|
+
// Activity and Suspense can retain state after cleaning up effects.
|
|
147
|
+
// Wait for the current loading effect to publish a live decoder.
|
|
148
|
+
if (!imageDecoder ||
|
|
149
|
+
!decodedImage ||
|
|
150
|
+
activeDecoderRef.current !== imageDecoder) {
|
|
146
151
|
return;
|
|
147
152
|
}
|
|
148
153
|
const delay = delayRender(`Rendering frame at ${currentTime} of <AnimatedImage src="${src}"/>`);
|
|
@@ -39,6 +39,7 @@ const react_1 = __importStar(require("react"));
|
|
|
39
39
|
const evaluate_source_expressions_js_1 = require("../evaluate-source-expressions.js");
|
|
40
40
|
const get_effective_visual_mode_value_js_1 = require("../get-effective-visual-mode-value.js");
|
|
41
41
|
const interpolate_keyframed_status_js_1 = require("../interpolate-keyframed-status.js");
|
|
42
|
+
const registry_store_js_1 = require("../registry-store.js");
|
|
42
43
|
const runtime_value_store_js_1 = require("../runtime-value-store.js");
|
|
43
44
|
const sequence_activity_context_js_1 = require("../sequence-activity-context.js");
|
|
44
45
|
const sequence_node_path_js_1 = require("../sequence-node-path.js");
|
|
@@ -46,6 +47,20 @@ const SequenceManager_js_1 = require("../SequenceManager.js");
|
|
|
46
47
|
const use_current_frame_js_1 = require("../use-current-frame.js");
|
|
47
48
|
const emptyDragOverrides = {};
|
|
48
49
|
const useCacheCommitEffect = (_a = react_1.default.useInsertionEffect) !== null && _a !== void 0 ? _a : react_1.useLayoutEffect;
|
|
50
|
+
const areEffectParamsEqual = (previous, next) => {
|
|
51
|
+
if (Object.is(previous, next)) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
if (previous === null ||
|
|
55
|
+
next === null ||
|
|
56
|
+
typeof previous !== 'object' ||
|
|
57
|
+
typeof next !== 'object' ||
|
|
58
|
+
Object.getPrototypeOf(previous) !== Object.prototype ||
|
|
59
|
+
Object.getPrototypeOf(next) !== Object.prototype) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return (0, registry_store_js_1.areRegistryEntriesEqual)(previous, next);
|
|
63
|
+
};
|
|
49
64
|
const mergeOverrides = ({ descriptor, propStatusOverrides, dragOverrides, frame, }) => {
|
|
50
65
|
if (!propStatusOverrides && !dragOverrides) {
|
|
51
66
|
return { params: descriptor.params, effectKey: descriptor.effectKey };
|
|
@@ -105,17 +120,16 @@ const resolvePropStatusOverrides = (propStatus, frame) => {
|
|
|
105
120
|
const useMemoizedEffectDefinitions = (effects) => {
|
|
106
121
|
const activityDormant = (0, react_1.useContext)(sequence_activity_context_js_1.SequenceActivityDormantContext);
|
|
107
122
|
const previousRef = (0, react_1.useRef)(null);
|
|
108
|
-
const definitions = effects.map((descriptor) => descriptor.definition);
|
|
109
123
|
const previous = previousRef.current;
|
|
110
124
|
const isSame = previous !== null &&
|
|
111
|
-
previous.definitions.length ===
|
|
112
|
-
previous.definitions.every((definition, i) => definition ===
|
|
125
|
+
previous.definitions.length === effects.length &&
|
|
126
|
+
previous.definitions.every((definition, i) => definition === effects[i].definition);
|
|
113
127
|
const controllers = isSame
|
|
114
128
|
? previous.controllers
|
|
115
129
|
: effects.map((effect) => (0, runtime_value_store_js_1.createRuntimeValueStore)(effect.params));
|
|
116
130
|
const stableDefinitions = isSame
|
|
117
131
|
? previous.definitions
|
|
118
|
-
: Object.assign(
|
|
132
|
+
: Object.assign(effects.map((descriptor) => descriptor.definition), {
|
|
119
133
|
runtimeValues: controllers.map((controller) => controller.store),
|
|
120
134
|
});
|
|
121
135
|
useCacheCommitEffect(() => {
|
|
@@ -125,6 +139,12 @@ const useMemoizedEffectDefinitions = (effects) => {
|
|
|
125
139
|
if (!activityDormant || controllers.length === 0) {
|
|
126
140
|
return;
|
|
127
141
|
}
|
|
142
|
+
if (controllers.every((controller, index) => {
|
|
143
|
+
var _a;
|
|
144
|
+
return areEffectParamsEqual(controller.store.getSnapshot(), (_a = effects[index]) === null || _a === void 0 ? void 0 : _a.params);
|
|
145
|
+
})) {
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
128
148
|
let cancelled = false;
|
|
129
149
|
queueMicrotask(() => {
|
|
130
150
|
if (cancelled) {
|
|
@@ -134,21 +154,10 @@ const useMemoizedEffectDefinitions = (effects) => {
|
|
|
134
154
|
var _a;
|
|
135
155
|
const snapshot = (_a = effects[index]) === null || _a === void 0 ? void 0 : _a.params;
|
|
136
156
|
const currentSnapshot = controller.store.getSnapshot();
|
|
137
|
-
if (Object.is(snapshot, currentSnapshot)) {
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
157
|
// Equivalent inline params should not notify inspector subscribers on
|
|
141
158
|
// every dormant render. Preserve changes to keys and leaf references.
|
|
142
|
-
if (snapshot
|
|
143
|
-
|
|
144
|
-
typeof snapshot === 'object' &&
|
|
145
|
-
typeof currentSnapshot === 'object') {
|
|
146
|
-
const keys = Object.keys(snapshot);
|
|
147
|
-
if (keys.length === Object.keys(currentSnapshot).length &&
|
|
148
|
-
keys.every((key) => Object.prototype.hasOwnProperty.call(currentSnapshot, key) &&
|
|
149
|
-
Object.is(snapshot[key], currentSnapshot[key]))) {
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
159
|
+
if (areEffectParamsEqual(snapshot, currentSnapshot)) {
|
|
160
|
+
return;
|
|
152
161
|
}
|
|
153
162
|
controller.setSnapshot(snapshot);
|
|
154
163
|
});
|
|
@@ -164,7 +173,9 @@ const useMemoizedEffectDefinitions = (effects) => {
|
|
|
164
173
|
stableDefinitions.forEach((_definition, index) => {
|
|
165
174
|
var _a;
|
|
166
175
|
const snapshot = (_a = effects[index]) === null || _a === void 0 ? void 0 : _a.params;
|
|
167
|
-
controllers[index].
|
|
176
|
+
if (!areEffectParamsEqual(controllers[index].store.getSnapshot(), snapshot)) {
|
|
177
|
+
controllers[index].setSnapshot(snapshot);
|
|
178
|
+
}
|
|
168
179
|
});
|
|
169
180
|
}, [controllers, effects, stableDefinitions]);
|
|
170
181
|
return stableDefinitions;
|
|
@@ -206,55 +217,86 @@ const useMemoizedEffects = ({ effects, overrideId, videoConfigValues, }) => {
|
|
|
206
217
|
var _a;
|
|
207
218
|
const previousRef = (0, react_1.useRef)(null);
|
|
208
219
|
const { propStatuses } = (0, react_1.useContext)(SequenceManager_js_1.VisualModePropStatusesContext);
|
|
209
|
-
const frame = (0, use_current_frame_js_1.useCurrentFrame)();
|
|
210
220
|
const { overrideIdToNodePathMappings } = (0, react_1.useContext)(sequence_node_path_js_1.OverrideIdsToNodePathsGettersContext);
|
|
211
221
|
const previous = previousRef.current;
|
|
212
222
|
const nodePath = overrideId
|
|
213
223
|
? ((_a = overrideIdToNodePathMappings[overrideId]) !== null && _a !== void 0 ? _a : null)
|
|
214
224
|
: null;
|
|
215
225
|
const effectDragOverrides = (0, SequenceManager_js_1.useEffectDragOverridesForNodePath)(nodePath);
|
|
216
|
-
const
|
|
217
|
-
var _a;
|
|
226
|
+
const effectPropStatuses = (0, react_1.useMemo)(() => Array.from({ length: effects.length }, (_, effectIndex) => {
|
|
218
227
|
if (nodePath === null) {
|
|
219
|
-
return
|
|
220
|
-
descriptor,
|
|
221
|
-
params: descriptor.params,
|
|
222
|
-
effectKey: descriptor.effectKey,
|
|
223
|
-
};
|
|
228
|
+
return null;
|
|
224
229
|
}
|
|
225
|
-
const
|
|
230
|
+
const status = (0, exports.getEffectPropStatusesCtx)({
|
|
226
231
|
propStatuses,
|
|
227
232
|
nodePath: { ...nodePath, videoConfigValues },
|
|
228
|
-
effectIndex
|
|
233
|
+
effectIndex,
|
|
229
234
|
});
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
235
|
+
return status.type === 'can-update-effect' ? status.props : null;
|
|
236
|
+
}), [effects.length, nodePath, propStatuses, videoConfigValues]);
|
|
237
|
+
const animatedEffects = (0, react_1.useMemo)(() => effectPropStatuses.map((status, index) => {
|
|
238
|
+
var _a;
|
|
239
|
+
return Object.values(status !== null && status !== void 0 ? status : {}).some((prop) => prop.status === 'keyframed') ||
|
|
240
|
+
Object.values((_a = effectDragOverrides[index]) !== null && _a !== void 0 ? _a : emptyDragOverrides).some((override) => override.type === 'keyframed');
|
|
241
|
+
}), [effectDragOverrides, effectPropStatuses]);
|
|
242
|
+
// Runtime animations arrive through props. Only source/drag keyframes need
|
|
243
|
+
// their own clock, and an animated effect must not invalidate static siblings.
|
|
244
|
+
const frame = (0, use_current_frame_js_1.useCurrentFrameWithOptionalSubscription)(animatedEffects.some(Boolean));
|
|
245
|
+
const prepared = effects.map((descriptor, index) => {
|
|
246
|
+
var _a;
|
|
247
|
+
const propStatus = effectPropStatuses[index];
|
|
233
248
|
const dragOverridesMap = (_a = effectDragOverrides[index]) !== null && _a !== void 0 ? _a : emptyDragOverrides;
|
|
234
249
|
const dragOverrides = Object.keys(dragOverridesMap).length === 0 ? null : dragOverridesMap;
|
|
250
|
+
const effectFrame = animatedEffects[index] ? frame : null;
|
|
251
|
+
const cached = previous === null || previous === void 0 ? void 0 : previous.prepared[index];
|
|
252
|
+
if (cached &&
|
|
253
|
+
cached.definition === descriptor.definition &&
|
|
254
|
+
cached.sourceKey === descriptor.effectKey &&
|
|
255
|
+
areEffectParamsEqual(cached.params, descriptor.params) &&
|
|
256
|
+
cached.propStatus === propStatus &&
|
|
257
|
+
cached.dragOverrides === dragOverrides &&
|
|
258
|
+
cached.frame === effectFrame) {
|
|
259
|
+
return cached;
|
|
260
|
+
}
|
|
261
|
+
const propStatusOverrides = resolvePropStatusOverrides(propStatus !== null && propStatus !== void 0 ? propStatus : undefined, frame);
|
|
235
262
|
const { params, effectKey } = mergeOverrides({
|
|
236
263
|
descriptor,
|
|
237
264
|
propStatusOverrides,
|
|
238
265
|
dragOverrides,
|
|
239
266
|
frame,
|
|
240
267
|
});
|
|
241
|
-
return {
|
|
268
|
+
return {
|
|
269
|
+
definition: descriptor.definition,
|
|
270
|
+
sourceKey: descriptor.effectKey,
|
|
271
|
+
// Snapshot plain params so shallow comparisons see in-place field edits.
|
|
272
|
+
params: descriptor.params !== null &&
|
|
273
|
+
typeof descriptor.params === 'object' &&
|
|
274
|
+
Object.getPrototypeOf(descriptor.params) === Object.prototype
|
|
275
|
+
? { ...descriptor.params }
|
|
276
|
+
: descriptor.params,
|
|
277
|
+
propStatus,
|
|
278
|
+
dragOverrides,
|
|
279
|
+
frame: effectFrame,
|
|
280
|
+
value: (cached === null || cached === void 0 ? void 0 : cached.value.definition) === descriptor.definition &&
|
|
281
|
+
cached.value.effectKey === effectKey
|
|
282
|
+
? cached.value
|
|
283
|
+
: {
|
|
284
|
+
definition: descriptor.definition,
|
|
285
|
+
effectKey,
|
|
286
|
+
params,
|
|
287
|
+
memoized: true,
|
|
288
|
+
},
|
|
289
|
+
};
|
|
242
290
|
});
|
|
243
291
|
const isSame = previous !== null &&
|
|
244
|
-
previous.length ===
|
|
245
|
-
previous.every((
|
|
246
|
-
p.effectKey === resolved[i].effectKey);
|
|
292
|
+
previous.effects.length === prepared.length &&
|
|
293
|
+
previous.effects.every((effect, i) => effect === prepared[i].value);
|
|
247
294
|
const next = isSame
|
|
248
|
-
? previous
|
|
249
|
-
:
|
|
250
|
-
definition: descriptor.definition,
|
|
251
|
-
effectKey,
|
|
252
|
-
params,
|
|
253
|
-
memoized: true,
|
|
254
|
-
}));
|
|
295
|
+
? previous.effects
|
|
296
|
+
: prepared.map((effect) => effect.value);
|
|
255
297
|
useCacheCommitEffect(() => {
|
|
256
|
-
previousRef.current = next;
|
|
257
|
-
}, [next]);
|
|
298
|
+
previousRef.current = { prepared, effects: next };
|
|
299
|
+
}, [next, prepared]);
|
|
258
300
|
return next;
|
|
259
301
|
};
|
|
260
302
|
exports.useMemoizedEffects = useMemoizedEffects;
|
package/dist/cjs/internals.d.ts
CHANGED
|
@@ -133,6 +133,9 @@ export declare const Internals: {
|
|
|
133
133
|
readonly crossOrigin?: "" | "anonymous" | "use-credentials" | undefined;
|
|
134
134
|
}, "ref"> & import("react").RefAttributes<HTMLVideoElement>>;
|
|
135
135
|
readonly CompositionManager: import("react").Context<CompositionManagerContext>;
|
|
136
|
+
readonly CompositionManagerRefContext: import("react").Context<{
|
|
137
|
+
readonly current: CompositionManagerContext;
|
|
138
|
+
}>;
|
|
136
139
|
readonly CompositionSetters: import("react").Context<import("./CompositionManagerContext.js").CompositionManagerSetters>;
|
|
137
140
|
readonly VisualModePropStatusesContext: import("react").Context<import("./SequenceManager.js").VisualModePropStatuses>;
|
|
138
141
|
readonly VisualModePropStatusesRefContext: import("react").Context<import("./SequenceManager.js").VisualModePropStatusesRef>;
|
package/dist/cjs/internals.js
CHANGED
|
@@ -180,6 +180,7 @@ exports.Internals = {
|
|
|
180
180
|
resolveTrimProps: validate_start_from_props_js_1.resolveTrimProps,
|
|
181
181
|
VideoForPreview: VideoForPreview_js_1.VideoForPreview,
|
|
182
182
|
CompositionManager: CompositionManagerContext_js_1.CompositionManager,
|
|
183
|
+
CompositionManagerRefContext: CompositionManagerContext_js_1.CompositionManagerRefContext,
|
|
183
184
|
CompositionSetters: CompositionManagerContext_js_1.CompositionSetters,
|
|
184
185
|
VisualModePropStatusesContext: SequenceManager_js_1.VisualModePropStatusesContext,
|
|
185
186
|
VisualModePropStatusesRefContext: SequenceManager_js_1.VisualModePropStatusesRefContext,
|
|
@@ -11,6 +11,7 @@ export declare const clampFrameToCompositionRange: (frame: number, durationInFra
|
|
|
11
11
|
export declare const useTimelineContext: () => TimelineContextValue;
|
|
12
12
|
export declare const usePlaybackRate: () => PlaybackRateContextValue;
|
|
13
13
|
export declare const useTimelinePosition: () => number;
|
|
14
|
+
export declare const useTimelinePositionWithOptionalSubscription: (subscribe: boolean) => number;
|
|
14
15
|
export declare const useIsInsideFreeze: () => boolean;
|
|
15
16
|
export declare const useAbsoluteTimelinePosition: () => number;
|
|
16
17
|
export declare const useTimelineSetFrameWithoutSeek: () => (u: import("react").SetStateAction<Record<string, number>>) => void;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useBuffering = exports.usePlaying = exports.useTimelineSeekFrame = exports.useTimelineSetFrameWithoutSeek = exports.useAbsoluteTimelinePosition = exports.useIsInsideFreeze = exports.useTimelinePosition = exports.usePlaybackRate = exports.useTimelineContext = exports.clampFrameToCompositionRange = exports.getFrameForComposition = exports.getInitialFrameState = exports.persistCurrentFrame = void 0;
|
|
3
|
+
exports.useBuffering = exports.usePlaying = exports.useTimelineSeekFrame = exports.useTimelineSetFrameWithoutSeek = exports.useAbsoluteTimelinePosition = exports.useIsInsideFreeze = exports.useTimelinePositionWithOptionalSubscription = exports.useTimelinePosition = exports.usePlaybackRate = exports.useTimelineContext = exports.clampFrameToCompositionRange = exports.getFrameForComposition = exports.getInitialFrameState = exports.persistCurrentFrame = void 0;
|
|
4
4
|
const react_1 = require("react");
|
|
5
5
|
const sequence_activity_context_js_1 = require("./sequence-activity-context.js");
|
|
6
6
|
const TimelineContext_js_1 = require("./TimelineContext.js");
|
|
7
7
|
const use_remotion_environment_js_1 = require("./use-remotion-environment.js");
|
|
8
8
|
const use_video_js_1 = require("./use-video.js");
|
|
9
|
+
// Reading TimelineContext and ignoring its value would still schedule frame
|
|
10
|
+
// updates. Inactive subscribers must read a separate, never-changing context.
|
|
11
|
+
const UnsubscribedTimelineContext = (0, react_1.createContext)(null);
|
|
9
12
|
const makeKey = () => {
|
|
10
13
|
return `remotion.time-all`;
|
|
11
14
|
};
|
|
@@ -42,6 +45,9 @@ const useTimelinePositionFromContext = (state) => {
|
|
|
42
45
|
const videoConfig = (0, use_video_js_1.useVideo)();
|
|
43
46
|
const env = (0, use_remotion_environment_js_1.useRemotionEnvironment)();
|
|
44
47
|
const dormant = (0, react_1.useContext)(sequence_activity_context_js_1.SequenceActivityDormantContext);
|
|
48
|
+
if (state === null) {
|
|
49
|
+
return 0;
|
|
50
|
+
}
|
|
45
51
|
if (!videoConfig) {
|
|
46
52
|
return typeof window === 'undefined'
|
|
47
53
|
? 0
|
|
@@ -76,6 +82,20 @@ const useTimelinePosition = () => {
|
|
|
76
82
|
return useTimelinePositionFromContext(state);
|
|
77
83
|
};
|
|
78
84
|
exports.useTimelinePosition = useTimelinePosition;
|
|
85
|
+
const useTimelinePositionWithOptionalSubscription = (subscribe) => {
|
|
86
|
+
const dormant = (0, react_1.useContext)(sequence_activity_context_js_1.SequenceActivityDormantContext);
|
|
87
|
+
const state = (0, react_1.useContext)(subscribe
|
|
88
|
+
? dormant
|
|
89
|
+
? sequence_activity_context_js_1.SequenceActivityTimelineContext
|
|
90
|
+
: TimelineContext_js_1.TimelineContext
|
|
91
|
+
: UnsubscribedTimelineContext);
|
|
92
|
+
const frame = useTimelinePositionFromContext(state);
|
|
93
|
+
if (subscribe && state === null) {
|
|
94
|
+
throw new Error('TimelineContext is not available. This hook must be used inside a <Player> or the Remotion Studio.');
|
|
95
|
+
}
|
|
96
|
+
return frame;
|
|
97
|
+
};
|
|
98
|
+
exports.useTimelinePositionWithOptionalSubscription = useTimelinePositionWithOptionalSubscription;
|
|
79
99
|
const useIsInsideFreeze = () => {
|
|
80
100
|
return (0, exports.useTimelineContext)().isInsideFreeze;
|
|
81
101
|
};
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.useCurrentFrame = void 0;
|
|
3
|
+
exports.useCurrentFrame = exports.useCurrentFrameWithOptionalSubscription = void 0;
|
|
4
4
|
const react_1 = require("react");
|
|
5
5
|
const CanUseRemotionHooks_js_1 = require("./CanUseRemotionHooks.js");
|
|
6
6
|
const SequenceContext_js_1 = require("./SequenceContext.js");
|
|
7
7
|
const timeline_position_state_js_1 = require("./timeline-position-state.js");
|
|
8
8
|
const use_remotion_environment_js_1 = require("./use-remotion-environment.js");
|
|
9
|
-
|
|
10
|
-
* @description Retrieves the current frame of the video within a component. Frames are 0-indexed, and if the component is wrapped in a `<Sequence>`, it returns the frame relative to when the Sequence starts.
|
|
11
|
-
* @see [Documentation](https://www.remotion.dev/docs/use-current-frame)
|
|
12
|
-
*/
|
|
13
|
-
const useCurrentFrame = () => {
|
|
9
|
+
const useCurrentFrameWithOptionalSubscription = (subscribe) => {
|
|
14
10
|
var _a;
|
|
15
11
|
const canUseRemotionHooks = (0, react_1.useContext)(CanUseRemotionHooks_js_1.CanUseRemotionHooks);
|
|
16
12
|
const env = (0, use_remotion_environment_js_1.useRemotionEnvironment)();
|
|
@@ -20,11 +16,22 @@ const useCurrentFrame = () => {
|
|
|
20
16
|
}
|
|
21
17
|
throw new Error(`useCurrentFrame() can only be called inside a component that was registered as a composition. See https://www.remotion.dev/docs/the-fundamentals#defining-compositions`);
|
|
22
18
|
}
|
|
23
|
-
const frame = (0, timeline_position_state_js_1.
|
|
19
|
+
const frame = (0, timeline_position_state_js_1.useTimelinePositionWithOptionalSubscription)(subscribe);
|
|
24
20
|
const context = (0, react_1.useContext)(SequenceContext_js_1.SequenceContext);
|
|
21
|
+
if (!subscribe) {
|
|
22
|
+
return 0;
|
|
23
|
+
}
|
|
25
24
|
const contextOffset = context
|
|
26
25
|
? context.cumulatedFrom + context.relativeFrom
|
|
27
26
|
: 0;
|
|
28
27
|
return (frame - contextOffset) * ((_a = context === null || context === void 0 ? void 0 : context.playbackRate) !== null && _a !== void 0 ? _a : 1);
|
|
29
28
|
};
|
|
29
|
+
exports.useCurrentFrameWithOptionalSubscription = useCurrentFrameWithOptionalSubscription;
|
|
30
|
+
/*
|
|
31
|
+
* @description Retrieves the current frame of the video within a component. Frames are 0-indexed, and if the component is wrapped in a `<Sequence>`, it returns the frame relative to when the Sequence starts.
|
|
32
|
+
* @see [Documentation](https://www.remotion.dev/docs/use-current-frame)
|
|
33
|
+
*/
|
|
34
|
+
const useCurrentFrame = () => {
|
|
35
|
+
return (0, exports.useCurrentFrameWithOptionalSubscription)(true);
|
|
36
|
+
};
|
|
30
37
|
exports.useCurrentFrame = useCurrentFrame;
|
|
@@ -12,10 +12,10 @@ function validateDurationInFrames(durationInFrames, options) {
|
|
|
12
12
|
if (durationInFrames <= 0) {
|
|
13
13
|
throw new TypeError(`The "durationInFrames" prop ${component} must be positive, but got ${durationInFrames}.`);
|
|
14
14
|
}
|
|
15
|
-
if (!allowFloats && durationInFrames % 1 !== 0) {
|
|
16
|
-
throw new TypeError(`The "durationInFrames" prop ${component} must be an integer, but got ${durationInFrames}.`);
|
|
17
|
-
}
|
|
18
15
|
if (!Number.isFinite(durationInFrames)) {
|
|
19
16
|
throw new TypeError(`The "durationInFrames" prop ${component} must be finite, but got ${durationInFrames}.`);
|
|
20
17
|
}
|
|
18
|
+
if (!allowFloats && durationInFrames % 1 !== 0) {
|
|
19
|
+
throw new TypeError(`The "durationInFrames" prop ${component} must be an integer, but got ${durationInFrames}.`);
|
|
20
|
+
}
|
|
21
21
|
}
|
package/dist/cjs/version.d.ts
CHANGED
package/dist/cjs/version.js
CHANGED