remotion 4.0.535 → 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.
Files changed (73) hide show
  1. package/dist/cjs/AbsoluteFill.d.ts +1 -1
  2. package/dist/cjs/CompositionManagerContext.d.ts +3 -0
  3. package/dist/cjs/CompositionManagerContext.js +5 -3
  4. package/dist/cjs/CompositionManagerProvider.js +3 -1
  5. package/dist/cjs/HtmlInCanvas.d.ts +4 -2
  6. package/dist/cjs/HtmlInCanvas.js +70 -19
  7. package/dist/cjs/Img.d.ts +4 -2
  8. package/dist/cjs/Img.js +2 -2
  9. package/dist/cjs/Interactive.d.ts +21 -7
  10. package/dist/cjs/Interactive.js +22 -1
  11. package/dist/cjs/Sequence.js +47 -3
  12. package/dist/cjs/SequenceActivityBoundary.js +14 -1
  13. package/dist/cjs/SequenceActivityBudget.js +26 -11
  14. package/dist/cjs/SequenceActivitySuspensionProvider.d.ts +4 -0
  15. package/dist/cjs/SequenceActivitySuspensionProvider.js +45 -0
  16. package/dist/cjs/SequenceManager.d.ts +5 -0
  17. package/dist/cjs/SequenceManager.js +22 -4
  18. package/dist/cjs/Track.js +1 -2
  19. package/dist/cjs/animated-image/AnimatedImage.d.ts +3 -2
  20. package/dist/cjs/animated-image/AnimatedImage.js +17 -10
  21. package/dist/cjs/animated-image/canvas.d.ts +2 -1
  22. package/dist/cjs/animated-image/canvas.js +2 -2
  23. package/dist/cjs/animated-image/props.d.ts +2 -1
  24. package/dist/cjs/asset-types.d.ts +4 -0
  25. package/dist/cjs/audio/shared-audio-tags.d.ts +1 -1
  26. package/dist/cjs/audio/shared-audio-tags.js +1 -1
  27. package/dist/cjs/canvas-image/CanvasImage.d.ts +3 -2
  28. package/dist/cjs/canvas-image/CanvasImage.js +4 -4
  29. package/dist/cjs/canvas-image/props.d.ts +2 -1
  30. package/dist/cjs/effects/Solid.d.ts +3 -2
  31. package/dist/cjs/effects/Solid.js +4 -4
  32. package/dist/cjs/effects/effect-types.d.ts +4 -0
  33. package/dist/cjs/effects/index.d.ts +1 -1
  34. package/dist/cjs/effects/run-effect-chain.d.ts +3 -1
  35. package/dist/cjs/effects/run-effect-chain.js +94 -56
  36. package/dist/cjs/effects/use-effect-chain-state.d.ts +2 -1
  37. package/dist/cjs/effects/use-effect-chain-state.js +11 -2
  38. package/dist/cjs/effects/use-memoized-effects.js +86 -44
  39. package/dist/cjs/index.d.ts +1 -1
  40. package/dist/cjs/interactivity-schema.d.ts +5 -5
  41. package/dist/cjs/interactivity-schema.js +2 -1
  42. package/dist/cjs/internals.d.ts +11 -10
  43. package/dist/cjs/internals.js +1 -1
  44. package/dist/cjs/interpolate.js +8 -1
  45. package/dist/cjs/no-react.d.ts +1 -1
  46. package/dist/cjs/sequence-activity-context.d.ts +1 -1
  47. package/dist/cjs/sequence-activity-context.js +4 -3
  48. package/dist/cjs/sequence-activity-defaults.d.ts +1 -1
  49. package/dist/cjs/sequence-activity-defaults.js +1 -1
  50. package/dist/cjs/timeline-position-state.d.ts +1 -0
  51. package/dist/cjs/timeline-position-state.js +21 -1
  52. package/dist/cjs/timeline-track-context.d.ts +0 -1
  53. package/dist/cjs/timeline-track-context.js +1 -2
  54. package/dist/cjs/use-current-frame.d.ts +1 -0
  55. package/dist/cjs/use-current-frame.js +14 -7
  56. package/dist/cjs/use-schema.js +3 -1
  57. package/dist/cjs/use-timeline-seek.d.ts +1 -0
  58. package/dist/cjs/use-timeline-seek.js +10 -0
  59. package/dist/cjs/validation/validate-duration-in-frames.js +3 -3
  60. package/dist/cjs/version.d.ts +1 -1
  61. package/dist/cjs/version.js +1 -1
  62. package/dist/cjs/video/seek-until-right.js +11 -7
  63. package/dist/cjs/with-interactivity-schema.js +18 -16
  64. package/dist/cjs/wrap-remotion-context.d.ts +0 -1
  65. package/dist/cjs/wrap-remotion-context.js +1 -4
  66. package/dist/esm/index.mjs +951 -720
  67. package/dist/esm/no-react.mjs +7 -6
  68. package/dist/esm/version.mjs +1 -1
  69. package/package.json +2 -2
  70. package/dist/cjs/nonce.d.ts +0 -11
  71. package/dist/cjs/nonce.js +0 -42
  72. package/dist/cjs/sequence-order-marker.d.ts +0 -58
  73. package/dist/cjs/sequence-order-marker.js +0 -44
@@ -6,6 +6,8 @@ const effect_internals_js_1 = require("./effect-internals.js");
6
6
  const gpu_device_js_1 = require("./gpu-device.js");
7
7
  const createEffectChainState = (width, height) => {
8
8
  const state = {
9
+ width,
10
+ height,
9
11
  pool: new canvas_pool_js_1.CanvasPool(width, height, (canvas) => {
10
12
  var _a;
11
13
  // The GL objects these setups hold died with the context and stay
@@ -62,9 +64,8 @@ const ensureSetup = (state, def, target) => {
62
64
  // Runs the effect pipeline imperatively. Returns `true` if the pipeline
63
65
  // completed and wrote to `output`, `false` if it was superseded by a newer
64
66
  // run (caller should not act on a stale result).
65
- const runEffectChain = async ({ state, source, effects, output, width, height, }) => {
67
+ const runEffectChainWithoutResize = async ({ state, source, effects, output, width, height }, initialFlipSourceY, runId) => {
66
68
  var _a;
67
- const runId = ++state.currentRunId;
68
69
  const isCancelled = () => state.currentRunId !== runId;
69
70
  // Bypass any effect with `disabled: true` before grouping by backend, so
70
71
  // disabled effects don't create empty runs or force unnecessary backend
@@ -102,66 +103,77 @@ const runEffectChain = async ({ state, source, effects, output, width, height, }
102
103
  // Canvas sources are DOM-oriented. Flip them when uploading into WebGL so
103
104
  // texture coordinates match clip-space output. `ImageBitmap` bridges below
104
105
  // opt out because they are already oriented for upload.
105
- let flipWebGLSourceY = true;
106
- for (let runIndex = 0; runIndex < runs.length; runIndex++) {
107
- const run = runs[runIndex];
108
- let canvasIndex = 0;
109
- for (const eff of run.effects) {
110
- const dst = state.pool.getCanvas(run.backend, canvasIndex);
111
- const def = eff.definition;
112
- if (run.backend === 'webgl2') {
113
- // Checked before `setup()`: a lost context cannot compile shaders,
114
- // and this surfaces the dedicated error instead of an effect's own.
115
- state.pool.assertContextNotLost(dst);
116
- }
117
- const setupState = ensureSetup(state, def, dst);
118
- def.apply({
119
- source: currentImage,
120
- target: dst,
121
- state: setupState,
122
- params: eff.params,
123
- width,
124
- height,
125
- gpuDevice,
126
- flipSourceY: run.backend === 'webgl2' ? flipWebGLSourceY : false,
127
- });
128
- if (run.backend === 'webgl2') {
129
- // Same-backend ping-pong passes feed the previous WebGL canvas back
130
- // through `texImage2D()`. That source is still a DOM canvas, so the
131
- // next upload also needs to be flipped.
132
- flipWebGLSourceY = true;
133
- }
134
- currentImage = dst;
135
- canvasIndex = canvasIndex === 0 ? 1 : 0;
136
- }
137
- lastTarget = (_a = currentImage) !== null && _a !== void 0 ? _a : lastTarget;
138
- const nextRun = runs[runIndex + 1];
139
- if (nextRun && nextRun.backend !== run.backend && lastTarget) {
140
- // 2D → WebGL: pass the 2D canvas directly so `texImage2D` + `UNPACK_FLIP_Y`
141
- // matches blur-only on a raw frame canvas. `createImageBitmap` here changes
142
- // upload orientation and produced upside-down stacks (wave + blur).
143
- if (run.backend === '2d' && nextRun.backend === 'webgl2') {
144
- currentImage = lastTarget;
145
- flipWebGLSourceY = true;
106
+ let flipWebGLSourceY = initialFlipSourceY;
107
+ // Only bridge bitmaps are owned here; the original source belongs to the caller.
108
+ let bridgeBitmap = null;
109
+ try {
110
+ for (let runIndex = 0; runIndex < runs.length; runIndex++) {
111
+ const run = runs[runIndex];
112
+ let canvasIndex = 0;
113
+ for (const eff of run.effects) {
114
+ const dst = state.pool.getCanvas(run.backend, canvasIndex);
115
+ const def = eff.definition;
116
+ if (run.backend === 'webgl2') {
117
+ // Checked before `setup()`: a lost context cannot compile shaders,
118
+ // and this surfaces the dedicated error instead of an effect's own.
119
+ state.pool.assertContextNotLost(dst);
120
+ }
121
+ const setupState = ensureSetup(state, def, dst);
122
+ def.apply({
123
+ source: currentImage,
124
+ target: dst,
125
+ state: setupState,
126
+ params: eff.params,
127
+ width: state.width,
128
+ height: state.height,
129
+ gpuDevice,
130
+ flipSourceY: run.backend === 'webgl2' ? flipWebGLSourceY : false,
131
+ });
132
+ // Effects consume their source synchronously. Release it before the
133
+ // next bridge so a run never retains multiple temporary bitmaps.
134
+ bridgeBitmap === null || bridgeBitmap === void 0 ? void 0 : bridgeBitmap.close();
135
+ bridgeBitmap = null;
136
+ if (run.backend === 'webgl2') {
137
+ // Same-backend ping-pong passes feed the previous WebGL canvas back
138
+ // through `texImage2D()`. That source is still a DOM canvas, so the
139
+ // next upload also needs to be flipped.
140
+ flipWebGLSourceY = true;
141
+ }
142
+ currentImage = dst;
143
+ canvasIndex = canvasIndex === 0 ? 1 : 0;
146
144
  }
147
- else {
148
- // Other bridges use `createImageBitmap` rather than passing the canvas
149
- // straight through. A direct `drawImage(webglCanvas)` in the next
150
- // backend's first effect forces an implicit GPU readback / finish on the
151
- // consuming context, which empirically blows the per-frame vsync budget and
152
- // halves the paint rate. `createImageBitmap` pipelines the GPU work.
153
- const bitmap = await createImageBitmap(lastTarget);
154
- if (isCancelled()) {
155
- bitmap.close();
156
- return false;
145
+ lastTarget = (_a = currentImage) !== null && _a !== void 0 ? _a : lastTarget;
146
+ const nextRun = runs[runIndex + 1];
147
+ if (nextRun && nextRun.backend !== run.backend && lastTarget) {
148
+ // 2D → WebGL: pass the 2D canvas directly so `texImage2D` + `UNPACK_FLIP_Y`
149
+ // matches blur-only on a raw frame canvas. `createImageBitmap` here changes
150
+ // upload orientation and produced upside-down stacks (wave + blur).
151
+ if (run.backend === '2d' && nextRun.backend === 'webgl2') {
152
+ currentImage = lastTarget;
153
+ flipWebGLSourceY = true;
157
154
  }
158
- currentImage = bitmap;
159
- if (nextRun.backend === 'webgl2') {
160
- flipWebGLSourceY = false;
155
+ else {
156
+ // Other bridges use `createImageBitmap` rather than passing the canvas
157
+ // straight through. A direct `drawImage(webglCanvas)` in the next
158
+ // backend's first effect forces an implicit GPU readback / finish on the
159
+ // consuming context, which empirically blows the per-frame vsync budget and
160
+ // halves the paint rate. `createImageBitmap` pipelines the GPU work.
161
+ bridgeBitmap = await createImageBitmap(lastTarget);
162
+ if (isCancelled()) {
163
+ return false;
164
+ }
165
+ currentImage = bridgeBitmap;
166
+ if (nextRun.backend === 'webgl2') {
167
+ flipWebGLSourceY = false;
168
+ }
161
169
  }
162
170
  }
163
171
  }
164
172
  }
173
+ finally {
174
+ // Also release a bridge if setup/apply throws or the run is cancelled.
175
+ bridgeBitmap === null || bridgeBitmap === void 0 ? void 0 : bridgeBitmap.close();
176
+ }
165
177
  if (!lastTarget) {
166
178
  return true;
167
179
  }
@@ -173,4 +185,30 @@ const runEffectChain = async ({ state, source, effects, output, width, height, }
173
185
  outCtx.drawImage(lastTarget, 0, 0, width, height);
174
186
  return true;
175
187
  };
188
+ // Keep ownership of the optional resized source until the existing chain settles.
189
+ const runEffectChain = async (options) => {
190
+ const { state, source, width, height, effects } = options;
191
+ // Keep one ID across resizing and effect passes so callers can cancel the run.
192
+ const runId = ++state.currentRunId;
193
+ if ((state.width === width && state.height === height) ||
194
+ !effects.some((effect) => !effect.params.disabled)) {
195
+ return runEffectChainWithoutResize(options, true, runId);
196
+ }
197
+ const firstEnabledEffect = effects.find((effect) => !effect.params.disabled);
198
+ const resized = await createImageBitmap(source, {
199
+ resizeWidth: state.width,
200
+ resizeHeight: state.height,
201
+ // WebGL ignores UNPACK_FLIP_Y_WEBGL for ImageBitmap uploads.
202
+ imageOrientation: firstEnabledEffect.definition.backend === 'webgl2' ? 'flipY' : 'none',
203
+ });
204
+ try {
205
+ if (state.currentRunId !== runId) {
206
+ return false;
207
+ }
208
+ return await runEffectChainWithoutResize({ ...options, source: resized }, false, runId);
209
+ }
210
+ finally {
211
+ resized.close();
212
+ }
213
+ };
176
214
  exports.runEffectChain = runEffectChain;
@@ -1,4 +1,5 @@
1
+ import type { EffectsOutputSize } from './effect-types.js';
1
2
  import type { EffectChainState } from './run-effect-chain.js';
2
- export declare const useEffectChainState: () => {
3
+ export declare const useEffectChainState: (effectsOutputSize?: EffectsOutputSize | null) => {
3
4
  get: (width: number, height: number) => EffectChainState | null;
4
5
  };
@@ -2,8 +2,15 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useEffectChainState = void 0;
4
4
  const react_1 = require("react");
5
+ const validate_dimensions_js_1 = require("../validation/validate-dimensions.js");
5
6
  const run_effect_chain_js_1 = require("./run-effect-chain.js");
6
- const useEffectChainState = () => {
7
+ const useEffectChainState = (effectsOutputSize = null) => {
8
+ const effectWidth = effectsOutputSize === null || effectsOutputSize === void 0 ? void 0 : effectsOutputSize.width;
9
+ const effectHeight = effectsOutputSize === null || effectsOutputSize === void 0 ? void 0 : effectsOutputSize.height;
10
+ if (effectsOutputSize) {
11
+ (0, validate_dimensions_js_1.validateDimension)(effectWidth, 'effectsOutputSize.width', 'on an effect-capable component');
12
+ (0, validate_dimensions_js_1.validateDimension)(effectHeight, 'effectsOutputSize.height', 'on an effect-capable component');
13
+ }
7
14
  const chainStateRef = (0, react_1.useRef)(null);
8
15
  const sizeRef = (0, react_1.useRef)(null);
9
16
  const unmountedRef = (0, react_1.useRef)(false);
@@ -22,6 +29,8 @@ const useEffectChainState = () => {
22
29
  }, []);
23
30
  return (0, react_1.useMemo)(() => ({
24
31
  get: (width, height) => {
32
+ width = effectWidth !== null && effectWidth !== void 0 ? effectWidth : width;
33
+ height = effectHeight !== null && effectHeight !== void 0 ? effectHeight : height;
25
34
  // Async work such as a late decoded video frame can still get here
26
35
  // after unmount. Nothing would release a pool created at this point.
27
36
  if (unmountedRef.current) {
@@ -38,6 +47,6 @@ const useEffectChainState = () => {
38
47
  }
39
48
  return chainStateRef.current;
40
49
  },
41
- }), []);
50
+ }), [effectWidth, effectHeight]);
42
51
  };
43
52
  exports.useEffectChainState = useEffectChainState;
@@ -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 === definitions.length &&
112
- previous.definitions.every((definition, i) => definition === definitions[i]);
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(definitions, {
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 !== null &&
143
- currentSnapshot !== null &&
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].setSnapshot(snapshot);
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 resolved = effects.map((descriptor, index) => {
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 effectStatus = (0, exports.getEffectPropStatusesCtx)({
230
+ const status = (0, exports.getEffectPropStatusesCtx)({
226
231
  propStatuses,
227
232
  nodePath: { ...nodePath, videoConfigValues },
228
- effectIndex: index,
233
+ effectIndex,
229
234
  });
230
- const propStatusOverrides = effectStatus.type === 'can-update-effect'
231
- ? resolvePropStatusOverrides(effectStatus.props, frame)
232
- : null;
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 { descriptor, params, effectKey };
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 === resolved.length &&
245
- previous.every((p, i) => p.definition === resolved[i].descriptor.definition &&
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
- : resolved.map(({ descriptor, params, effectKey }) => ({
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;
@@ -98,7 +98,7 @@ export type BundleEvaluationState = {
98
98
  export type BundleState = BundleIndexState | BundleEvaluationState | BundleCompositionState;
99
99
  export * from './AbsoluteFill.js';
100
100
  export * from './animated-image/index.js';
101
- export { createEffect, type Backend, type EffectApplyParams, type EffectDefinition, type EffectDefinitionAndStack, type EffectDescriptor, type EffectFactory, type EffectsProp, } from './effects/index.js';
101
+ export { createEffect, type Backend, type EffectApplyParams, type EffectDefinition, type EffectDefinitionAndStack, type EffectDescriptor, type EffectFactory, type EffectsProp, type EffectsOutputSize, } from './effects/index.js';
102
102
  /**
103
103
  * @description Renders a solid-color rectangle on a `<canvas>`.
104
104
  * @see [Documentation](https://www.remotion.dev/docs/solid)
@@ -450,7 +450,7 @@ export declare const textContentSchema: {
450
450
  export declare const premountSchema: {
451
451
  readonly premountFor: {
452
452
  readonly type: "number";
453
- readonly default: 0;
453
+ readonly default: undefined;
454
454
  readonly description: "Premount For";
455
455
  readonly min: 0;
456
456
  readonly step: 1;
@@ -469,7 +469,7 @@ export declare const premountSchema: {
469
469
  export declare const sequencePremountSchema: {
470
470
  readonly premountFor: {
471
471
  readonly type: "number";
472
- readonly default: 0;
472
+ readonly default: undefined;
473
473
  readonly description: "Premount For";
474
474
  readonly min: 0;
475
475
  readonly step: 1;
@@ -683,7 +683,7 @@ export declare const sequenceStyleSchema: {
683
683
  };
684
684
  readonly premountFor: {
685
685
  readonly type: "number";
686
- readonly default: 0;
686
+ readonly default: undefined;
687
687
  readonly description: "Premount For";
688
688
  readonly min: 0;
689
689
  readonly step: 1;
@@ -1040,7 +1040,7 @@ export declare const sequenceSchema: {
1040
1040
  };
1041
1041
  readonly premountFor: {
1042
1042
  readonly type: "number";
1043
- readonly default: 0;
1043
+ readonly default: undefined;
1044
1044
  readonly description: "Premount For";
1045
1045
  readonly min: 0;
1046
1046
  readonly step: 1;
@@ -1286,7 +1286,7 @@ export declare const sequenceSchemaWithoutFrom: {
1286
1286
  };
1287
1287
  readonly premountFor: {
1288
1288
  readonly type: "number";
1289
- readonly default: 0;
1289
+ readonly default: undefined;
1290
1290
  readonly description: "Premount For";
1291
1291
  readonly min: 0;
1292
1292
  readonly step: 1;
@@ -245,7 +245,8 @@ exports.textContentSchema = exports.childrenSchema;
245
245
  exports.premountSchema = {
246
246
  premountFor: {
247
247
  type: 'number',
248
- default: 0,
248
+ // Omission inherits the preview's default; zero explicitly disables it.
249
+ default: undefined,
249
250
  description: 'Premount For',
250
251
  min: 0,
251
252
  step: 1,
@@ -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>;
@@ -364,7 +367,7 @@ export declare const Internals: {
364
367
  };
365
368
  readonly premountFor: {
366
369
  readonly type: "number";
367
- readonly default: 0;
370
+ readonly default: undefined;
368
371
  readonly description: "Premount For";
369
372
  readonly min: 0;
370
373
  readonly step: 1;
@@ -455,9 +458,8 @@ export declare const Internals: {
455
458
  readonly SequenceContent: import("react").FC<{
456
459
  readonly children: import("react").ReactNode;
457
460
  }>;
458
- readonly DEFAULT_SEQUENCE_ACTIVITY_LIMIT: 20;
461
+ readonly DEFAULT_SEQUENCE_ACTIVITY_LIMIT: number;
459
462
  readonly SequenceActivitySettingsContext: import("react").Context<{
460
- readonly enabled: boolean;
461
463
  readonly limit: number;
462
464
  } | null>;
463
465
  readonly SequenceWithoutSchema: import("react").ForwardRefExoticComponent<import("./Sequence.js").SequenceProps & import("react").RefAttributes<HTMLDivElement>>;
@@ -575,7 +577,7 @@ export declare const Internals: {
575
577
  };
576
578
  readonly premountFor: {
577
579
  readonly type: "number";
578
- readonly default: 0;
580
+ readonly default: undefined;
579
581
  readonly description: "Premount For";
580
582
  readonly min: 0;
581
583
  readonly step: 1;
@@ -671,7 +673,7 @@ export declare const Internals: {
671
673
  readonly sequencePremountSchema: {
672
674
  readonly premountFor: {
673
675
  readonly type: "number";
674
- readonly default: 0;
676
+ readonly default: undefined;
675
677
  readonly description: "Premount For";
676
678
  readonly min: 0;
677
679
  readonly step: 1;
@@ -833,7 +835,7 @@ export declare const Internals: {
833
835
  readonly premountSchema: {
834
836
  readonly premountFor: {
835
837
  readonly type: "number";
836
- readonly default: 0;
838
+ readonly default: undefined;
837
839
  readonly description: "Premount For";
838
840
  readonly min: 0;
839
841
  readonly step: 1;
@@ -909,7 +911,6 @@ export declare const Internals: {
909
911
  readonly truthy: typeof truthy;
910
912
  readonly SequenceContext: import("react").Context<import("./SequenceContext.js").SequenceContextType | null>;
911
913
  readonly TimelineTrackContext: import("react").Context<import("./timeline-track-context.js").TimelineTrack | null>;
912
- readonly ExperimentalTracksEnabledContext: import("react").Context<boolean>;
913
914
  readonly TrackWithoutSchema: import("react").FC<import("./Track.js").TrackWithoutSchemaProps>;
914
915
  readonly PremountContext: import("react").Context<import("./PremountContext.js").PremountContextValue>;
915
916
  readonly usePremounting: ({ from, durationInFrames, premountFor, postmountFor, style, styleWhilePremounted, styleWhilePostmounted, hideWhilePremounted, }: {
@@ -956,7 +957,7 @@ export declare const Internals: {
956
957
  resumeAsAutoPlay: () => Promise<void>;
957
958
  suspend: () => Promise<void>;
958
959
  getIsResumingAudioContext: () => Promise<import("./audio/wait-until-actually-resumed.js").AudioContextResumeResult> | null;
959
- unscheduleAudioNode: (node: AudioBufferSourceNode) => void;
960
+ unscheduleAudioNode: (node: AudioBufferSourceNode) => boolean;
960
961
  _experimentalKeepAudioContextAlive: boolean;
961
962
  } | null>;
962
963
  readonly SharedAudioContextProvider: import("react").FC<{
@@ -1316,12 +1317,12 @@ export declare const Internals: {
1316
1317
  shouldResortToDefaultValueIfUndefined: boolean;
1317
1318
  }) => unknown;
1318
1319
  readonly CompositionRenderErrorContext: import("react").Context<import("./composition-render-error-context.js").CompositionRenderErrorContextType>;
1319
- readonly useEffectChainState: () => {
1320
+ readonly useEffectChainState: (effectsOutputSize?: import("./index.js").EffectsOutputSize | null) => {
1320
1321
  get: (width: number, height: number) => import("./internals.js").EffectChainState | null;
1321
1322
  };
1322
1323
  readonly createEffectChainState: (width: number, height: number) => import("./internals.js").EffectChainState;
1323
1324
  readonly cleanupEffectChainState: (state: import("./internals.js").EffectChainState) => void;
1324
- readonly runEffectChain: ({ state, source, effects, output, width, height, }: import("./effects/run-effect-chain.js").RunEffectChainOptions) => Promise<boolean>;
1325
+ readonly runEffectChain: (options: import("./effects/run-effect-chain.js").RunEffectChainOptions) => Promise<boolean>;
1325
1326
  readonly useMemoizedEffects: ({ effects, overrideId, videoConfigValues, }: {
1326
1327
  effects: readonly import("./index.js").EffectDescriptor<unknown>[];
1327
1328
  readonly overrideId: string | null;
@@ -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,
@@ -228,7 +229,6 @@ exports.Internals = {
228
229
  truthy: truthy_js_1.truthy,
229
230
  SequenceContext: SequenceContext_js_1.SequenceContext,
230
231
  TimelineTrackContext: timeline_track_context_js_1.TimelineTrackContext,
231
- ExperimentalTracksEnabledContext: timeline_track_context_js_1.ExperimentalTracksEnabledContext,
232
232
  TrackWithoutSchema: Track_js_1.TrackWithoutSchema,
233
233
  PremountContext: PremountContext_js_1.PremountContext,
234
234
  usePremounting: use_premounting_js_1.usePremounting,
@@ -288,7 +288,14 @@ const parseStringInterpolationValue = (output, outputType) => {
288
288
  }
289
289
  const parts = output.trim().split(/\s+/);
290
290
  if (parts.length < 1 || parts.length > 3 || parts[0] === '') {
291
- throw new TypeError(`String outputRange values must contain 1 to 3 components, but got "${output}"`);
291
+ // Long text values (for example custom cursor CSS) may use hold easing.
292
+ // Malformed numeric transforms must still fail instead of becoming text.
293
+ const ErrorType = outputType === undefined &&
294
+ parts.some((part) => !cssNumberRegex.test(part) &&
295
+ !transformOriginKeywords.has(part.toLowerCase()))
296
+ ? UnsupportedStringInterpolationValueError
297
+ : TypeError;
298
+ throw new ErrorType(`String outputRange values must contain 1 to 3 components, but got "${output}"`);
292
299
  }
293
300
  if (parts.some((part) => transformOriginKeywords.has(part.toLowerCase()))) {
294
301
  if (outputType !== undefined) {
@@ -226,7 +226,7 @@ export declare const NoReactInternals: {
226
226
  };
227
227
  readonly premountFor: {
228
228
  readonly type: "number";
229
- readonly default: 0;
229
+ readonly default: undefined;
230
230
  readonly description: "Premount For";
231
231
  readonly min: 0;
232
232
  readonly step: 1;