remotion 4.0.490 → 4.0.491

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.
@@ -33,6 +33,7 @@ type EnhancedTSequenceData = {
33
33
  volume: string | number;
34
34
  doesVolumeChange: boolean;
35
35
  startMediaFrom: number;
36
+ mediaFrameAtSequenceZero: number | null;
36
37
  playbackRate: number;
37
38
  frozenMediaFrame: number | null;
38
39
  } | {
@@ -41,6 +42,7 @@ type EnhancedTSequenceData = {
41
42
  volume: string | number;
42
43
  doesVolumeChange: boolean;
43
44
  startMediaFrom: number;
45
+ mediaFrameAtSequenceZero: number | null;
44
46
  playbackRate: number;
45
47
  frozenMediaFrame: number | null;
46
48
  } | {
@@ -63,12 +63,12 @@ const isMissingPaintRecordError = (error) => {
63
63
  return error instanceof DOMException && error.name === 'InvalidStateError';
64
64
  };
65
65
  const missingPaintRecordMessage = 'HtmlInCanvas: Expected the element to be inside the viewport during rendering, but Chrome had no cached paint record for it.';
66
- const resizeOffscreenCanvas = ({ offscreen, width, height, }) => {
67
- if (offscreen.width !== width) {
68
- offscreen.width = width;
66
+ const resizePaintTarget = ({ target, width, height, }) => {
67
+ if (target.width !== width) {
68
+ target.width = width;
69
69
  }
70
- if (offscreen.height !== height) {
71
- offscreen.height = height;
70
+ if (target.height !== height) {
71
+ target.height = height;
72
72
  }
73
73
  };
74
74
  const defaultOnPaint = ({ canvas, element, elementImage, }) => {
@@ -80,24 +80,25 @@ const defaultOnPaint = ({ canvas, element, elementImage, }) => {
80
80
  const transform = ctx.drawElementImage(elementImage, 0, 0);
81
81
  element.style.transform = transform.toString();
82
82
  };
83
- /* eslint-enable react/require-default-props */
84
- const HtmlInCanvasAncestorContext = (0, react_1.createContext)(false);
83
+ const HtmlInCanvasAncestorContext = (0, react_1.createContext)(null);
85
84
  const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, children, onPaint, onInit, pixelDensity, controls, style, }, ref) => {
86
85
  var _a;
87
- const isInsideAncestorHtmlInCanvas = (0, react_1.useContext)(HtmlInCanvasAncestorContext);
86
+ const ancestor = (0, react_1.useContext)(HtmlInCanvasAncestorContext);
88
87
  assertHtmlInCanvasDimensions(width, height);
89
88
  const resolvedPixelDensity = resolveHtmlInCanvasPixelDensity(pixelDensity);
90
89
  const canvasWidth = Math.ceil(width * resolvedPixelDensity);
91
90
  const canvasHeight = Math.ceil(height * resolvedPixelDensity);
92
91
  const { continueRender, cancelRender } = (0, use_delay_render_js_1.useDelayRender)();
93
- const { isRendering } = (0, use_remotion_environment_js_1.useRemotionEnvironment)();
92
+ const { isClientSideRendering, isRendering } = (0, use_remotion_environment_js_1.useRemotionEnvironment)();
93
+ const canRetryMissingPaintRecord = !isRendering || isClientSideRendering;
94
+ const usesDirectLayoutCanvas = onPaint === undefined && onInit === undefined;
94
95
  if (!(0, exports.isHtmlInCanvasSupported)()) {
95
96
  cancelRender(new Error(exports.HTML_IN_CANVAS_UNSUPPORTED_MESSAGE));
96
97
  }
97
98
  const canvas2dRef = (0, react_1.useRef)(null);
98
- const offscreenRef = (0, react_1.useRef)(null);
99
+ const paintTargetRef = (0, react_1.useRef)(null);
99
100
  const divRef = (0, react_1.useRef)(null);
100
- const canvasSizeKey = `${width}x${height}@${resolvedPixelDensity}`;
101
+ const canvasSizeKey = `${width}x${height}@${resolvedPixelDensity}-${usesDirectLayoutCanvas ? 'direct' : 'offscreen'}`;
101
102
  const setLayoutCanvasRef = (0, react_1.useCallback)((node) => {
102
103
  canvas2dRef.current = node;
103
104
  if (typeof ref === 'function') {
@@ -122,18 +123,20 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, c
122
123
  const initializedRef = (0, react_1.useRef)(false);
123
124
  const onInitCleanupRef = (0, react_1.useRef)(null);
124
125
  const unmountedRef = (0, react_1.useRef)(false);
126
+ const ancestorRef = (0, react_1.useRef)(ancestor);
127
+ ancestorRef.current = ancestor;
125
128
  const onPaintCb = (0, react_1.useCallback)(async () => {
126
129
  var _a;
127
130
  const element = divRef.current;
128
131
  if (!element) {
129
132
  throw new Error('Canvas or scene element not found');
130
133
  }
131
- const offscreen = offscreenRef.current;
132
- if (!offscreen) {
133
- throw new Error('HtmlInCanvas: offscreen canvas not ready (transferControlToOffscreen failed or canvas is remounting)');
134
+ const paintTarget = paintTargetRef.current;
135
+ if (!paintTarget) {
136
+ throw new Error('HtmlInCanvas: paint target is not ready because the canvas is remounting');
134
137
  }
135
- resizeOffscreenCanvas({
136
- offscreen,
138
+ resizePaintTarget({
139
+ target: paintTarget,
137
140
  width: canvasWidth,
138
141
  height: canvasHeight,
139
142
  });
@@ -144,34 +147,38 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, c
144
147
  }
145
148
  const handle = (0, delay_render_js_1.delayRender)('onPaint');
146
149
  if (!initializedRef.current) {
147
- // `onInit` may be async (e.g. WebGPU `requestAdapter`/`requestDevice`).
148
- // Capture an `ElementImage` here only for `onInit` consumers — do NOT
149
- // reuse it for the paint handler below, because awaiting `onInit`
150
- // can invalidate the capture's paint context, leaving subsequent
151
- // uploads (e.g. `copyElementImageToTexture`) failing with
152
- // "No context found for ElementImage" on the very first paint.
153
- let initImage = null;
154
- try {
155
- initImage = placeholderCanvas.captureElementImage(element);
150
+ const currentOnInit = onInitRef.current;
151
+ if (!currentOnInit) {
152
+ initializedRef.current = true;
156
153
  }
157
- catch (error) {
158
- if (isMissingPaintRecordError(error) && !isRendering) {
159
- // Element may be outside viewport (no cached paint record).
160
- // Skip init will retry on the next paint cycle.
161
- }
162
- else if (isMissingPaintRecordError(error)) {
163
- throw new Error(missingPaintRecordMessage);
154
+ else {
155
+ // `onInit` may be async (e.g. WebGPU
156
+ // `requestAdapter`/`requestDevice`). Do not reuse this capture for
157
+ // `onPaint`: awaiting initialization can invalidate its paint context.
158
+ let initImage;
159
+ try {
160
+ initImage = placeholderCanvas.captureElementImage(element);
164
161
  }
165
- else {
162
+ catch (error) {
163
+ if (isMissingPaintRecordError(error) &&
164
+ canRetryMissingPaintRecord) {
165
+ // The web renderer explicitly drives additional paint cycles, so a
166
+ // transient missing record can be retried without failing the render.
167
+ continueRender(handle);
168
+ return;
169
+ }
170
+ if (isMissingPaintRecordError(error)) {
171
+ throw new Error(missingPaintRecordMessage);
172
+ }
166
173
  throw error;
167
174
  }
168
- }
169
- if (initImage) {
170
175
  initializedRef.current = true;
171
- const currentOnInit = onInitRef.current;
172
- if (currentOnInit) {
176
+ try {
177
+ if (paintTarget instanceof HTMLCanvasElement) {
178
+ throw new Error('HtmlInCanvas: onInit requires an OffscreenCanvas paint target');
179
+ }
173
180
  const cleanup = await currentOnInit({
174
- canvas: offscreen,
181
+ canvas: paintTarget,
175
182
  element,
176
183
  elementImage: initImage,
177
184
  pixelDensity: resolvedPixelDensity,
@@ -186,9 +193,11 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, c
186
193
  onInitCleanupRef.current = cleanup;
187
194
  }
188
195
  }
196
+ finally {
197
+ initImage.close();
198
+ }
189
199
  }
190
200
  }
191
- const handler = (_a = onPaintRef.current) !== null && _a !== void 0 ? _a : defaultOnPaint;
192
201
  let elImage;
193
202
  try {
194
203
  elImage = placeholderCanvas.captureElementImage(element);
@@ -197,7 +206,7 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, c
197
206
  // `captureElementImage` throws `InvalidStateError` when the
198
207
  // element is outside the viewport (no cached paint record).
199
208
  // Skip this paint cycle — the canvas retains its last state.
200
- if (isMissingPaintRecordError(error) && !isRendering) {
209
+ if (isMissingPaintRecordError(error) && canRetryMissingPaintRecord) {
201
210
  continueRender(handle);
202
211
  return;
203
212
  }
@@ -206,20 +215,46 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, c
206
215
  }
207
216
  throw error;
208
217
  }
209
- await handler({
210
- canvas: offscreen,
211
- element,
212
- elementImage: elImage,
213
- pixelDensity: resolvedPixelDensity,
214
- });
215
- await (0, run_effect_chain_js_1.runEffectChain)({
216
- state: chainState.get(canvasWidth, canvasHeight),
217
- source: offscreen,
218
- effects: effectsRef.current,
219
- output: offscreen,
220
- width: canvasWidth,
221
- height: canvasHeight,
222
- });
218
+ try {
219
+ const currentOnPaint = onPaintRef.current;
220
+ if (currentOnPaint) {
221
+ if (paintTarget instanceof HTMLCanvasElement) {
222
+ throw new Error('HtmlInCanvas: onPaint requires an OffscreenCanvas paint target');
223
+ }
224
+ const paintResult = currentOnPaint({
225
+ canvas: paintTarget,
226
+ element,
227
+ elementImage: elImage,
228
+ pixelDensity: resolvedPixelDensity,
229
+ });
230
+ if (paintResult) {
231
+ await paintResult;
232
+ }
233
+ }
234
+ else {
235
+ defaultOnPaint({
236
+ canvas: paintTarget,
237
+ element,
238
+ elementImage: elImage,
239
+ pixelDensity: resolvedPixelDensity,
240
+ });
241
+ }
242
+ await (0, run_effect_chain_js_1.runEffectChain)({
243
+ state: chainState.get(canvasWidth, canvasHeight),
244
+ source: paintTarget,
245
+ effects: effectsRef.current,
246
+ output: paintTarget,
247
+ width: canvasWidth,
248
+ height: canvasHeight,
249
+ });
250
+ }
251
+ finally {
252
+ elImage.close();
253
+ }
254
+ // Effects may complete after Chromium has dispatched the parent's
255
+ // paint event. Repaint the direct parent so deeply nested canvases
256
+ // propagate their final pixels through every ancestor.
257
+ (_a = ancestorRef.current) === null || _a === void 0 ? void 0 : _a.requestParentPaint();
223
258
  continueRender(handle);
224
259
  }
225
260
  catch (error) {
@@ -232,20 +267,23 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, c
232
267
  continueRender,
233
268
  cancelRender,
234
269
  resolvedPixelDensity,
235
- isRendering,
270
+ canRetryMissingPaintRecord,
236
271
  ]);
237
- // Transfer control once per layout canvas instance, then listen for paint on
238
- // the placeholder (capture) while drawing on the linked offscreen surface.
272
+ // Default paint handlers draw synchronously on the layout canvas itself so
273
+ // Chromium can include their final pixels during its deepest-first nested
274
+ // paint traversal. Custom handlers retain the transferred OffscreenCanvas API.
239
275
  (0, react_1.useLayoutEffect)(() => {
240
276
  const placeholder = canvas2dRef.current;
241
277
  if (!placeholder) {
242
278
  throw new Error('Canvas not found');
243
279
  }
244
280
  placeholder.layoutSubtree = true;
245
- const offscreen = placeholder.transferControlToOffscreen();
246
- offscreenRef.current = offscreen;
247
- resizeOffscreenCanvas({
248
- offscreen,
281
+ const paintTarget = usesDirectLayoutCanvas
282
+ ? placeholder
283
+ : placeholder.transferControlToOffscreen();
284
+ paintTargetRef.current = paintTarget;
285
+ resizePaintTarget({
286
+ target: paintTarget,
249
287
  width: canvasWidth,
250
288
  height: canvasHeight,
251
289
  });
@@ -255,13 +293,19 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, c
255
293
  return () => {
256
294
  var _a;
257
295
  placeholder.removeEventListener('paint', onPaintCb);
258
- offscreenRef.current = null;
296
+ paintTargetRef.current = null;
259
297
  initializedRef.current = false;
260
298
  unmountedRef.current = true;
261
299
  (_a = onInitCleanupRef.current) === null || _a === void 0 ? void 0 : _a.call(onInitCleanupRef);
262
300
  onInitCleanupRef.current = null;
263
301
  };
264
- }, [onPaintCb, cancelRender, canvasWidth, canvasHeight]);
302
+ }, [
303
+ onPaintCb,
304
+ cancelRender,
305
+ canvasWidth,
306
+ canvasHeight,
307
+ usesDirectLayoutCanvas,
308
+ ]);
265
309
  const onPaintChangedRef = (0, react_1.useRef)(false);
266
310
  (0, react_1.useLayoutEffect)(() => {
267
311
  var _a;
@@ -301,10 +345,15 @@ const HtmlInCanvasContent = (0, react_1.forwardRef)(({ width, height, effects, c
301
345
  ...(style !== null && style !== void 0 ? style : {}),
302
346
  };
303
347
  }, [height, style, width]);
304
- if (isInsideAncestorHtmlInCanvas) {
305
- throw new Error('<HtmlInCanvas> effects cannot be nested together. Chrome will only display the outer effect. Consider merging the effects into one if you can.');
306
- }
307
- return (jsx_runtime_1.jsx(HtmlInCanvasAncestorContext.Provider, { value: true, children: jsx_runtime_1.jsx("canvas", { ref: setLayoutCanvasRef, width: canvasWidth, height: canvasHeight, style: canvasStyle, children: jsx_runtime_1.jsx("div", { ref: divRef, style: innerStyle, children: children }) }, canvasSizeKey) }));
348
+ const ancestorValue = (0, react_1.useMemo)(() => {
349
+ return {
350
+ requestParentPaint: () => {
351
+ var _a, _b;
352
+ (_b = (_a = canvas2dRef.current) === null || _a === void 0 ? void 0 : _a.requestPaint) === null || _b === void 0 ? void 0 : _b.call(_a);
353
+ },
354
+ };
355
+ }, []);
356
+ return (jsx_runtime_1.jsx(HtmlInCanvasAncestorContext.Provider, { value: ancestorValue, children: jsx_runtime_1.jsx("canvas", { ref: setLayoutCanvasRef, width: canvasWidth, height: canvasHeight, style: canvasStyle, children: jsx_runtime_1.jsx("div", { ref: divRef, style: innerStyle, children: children }) }, canvasSizeKey) }));
308
357
  });
309
358
  HtmlInCanvasContent.displayName = 'HtmlInCanvasContent';
310
359
  const HtmlInCanvasInner = (0, react_1.forwardRef)(({ width, height, effects = [], children, onPaint, onInit, pixelDensity, controls, style, durationInFrames, name, ...sequenceProps }, ref) => {
@@ -235,6 +235,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, freeze
235
235
  src: isMedia.data.src,
236
236
  getStack: () => stackRef.current,
237
237
  startMediaFrom: startMediaFrom !== null && startMediaFrom !== void 0 ? startMediaFrom : isMedia.data.startMediaFrom,
238
+ mediaFrameAtSequenceZero,
238
239
  volume: isMedia.data.volumes,
239
240
  refForOutline: refForOutline !== null && refForOutline !== void 0 ? refForOutline : null,
240
241
  isInsideSeries,
@@ -298,6 +299,7 @@ const RegularSequenceRefForwardingFunction = ({ from = 0, trimBefore = 0, freeze
298
299
  isInsideSeries,
299
300
  registeredFrozenFrame,
300
301
  startMediaFrom,
302
+ mediaFrameAtSequenceZero,
301
303
  frozenMediaFrame,
302
304
  ]);
303
305
  // Ceil to support floats
@@ -64,6 +64,13 @@ export type SequencePropsSubscriptionKey = {
64
64
  nodePath: SequenceNodePath;
65
65
  sequenceKeys: string[];
66
66
  effectKeys: string[][];
67
+ videoConfigValues: VideoConfigValues | null;
68
+ };
69
+ export type VideoConfigValues = {
70
+ durationInFrames: number;
71
+ fps: number;
72
+ height: number;
73
+ width: number;
67
74
  };
68
75
  export declare const SequenceManagerProvider: React.FC<{
69
76
  readonly children: React.ReactNode;
@@ -49,7 +49,7 @@ exports.SequenceManagerRefContext = react_1.default.createContext({
49
49
  current: [],
50
50
  });
51
51
  const makeSequencePropsSubscriptionKey = (key) => {
52
- return `${key.nodePath.join('.')}.${key.sequenceKeys.join('.')}.${key.effectKeys.map((keys) => keys.join('.')).join('.')}`;
52
+ return `${key.absolutePath}\0${key.nodePath.join('.')}\0${key.sequenceKeys.join('.')}\0${key.effectKeys.map((keys) => keys.join('.')).join('.')}`;
53
53
  };
54
54
  exports.makeSequencePropsSubscriptionKey = makeSequencePropsSubscriptionKey;
55
55
  exports.VisualModePropStatusesContext = react_1.default.createContext({
@@ -321,7 +321,9 @@ const SharedAudioTagsContextProvider = ({ children, numberOfAudioTags }) => {
321
321
  return;
322
322
  }
323
323
  if (data === undefined) {
324
- current.src = EMPTY_AUDIO;
324
+ if (current.src !== EMPTY_AUDIO) {
325
+ current.src = EMPTY_AUDIO;
326
+ }
325
327
  return;
326
328
  }
327
329
  if (!data) {
@@ -393,7 +395,9 @@ const SharedAudioTagsContextProvider = ({ children, numberOfAudioTags }) => {
393
395
  prevA.premounting === premounting &&
394
396
  prevA.postmounting === postmounting;
395
397
  if (isTheSame) {
396
- return prevA;
398
+ return prevA.audioMounted === audioMounted
399
+ ? prevA
400
+ : { ...prevA, audioMounted };
397
401
  }
398
402
  changed = true;
399
403
  return {
@@ -405,7 +409,9 @@ const SharedAudioTagsContextProvider = ({ children, numberOfAudioTags }) => {
405
409
  audioMounted,
406
410
  };
407
411
  }
408
- return prevA;
412
+ return prevA.audioMounted === audioMounted
413
+ ? prevA
414
+ : { ...prevA, audioMounted };
409
415
  });
410
416
  if (changed) {
411
417
  rerenderAudios();
@@ -444,13 +450,16 @@ const SharedAudioTagsContextProvider = ({ children, numberOfAudioTags }) => {
444
450
  unregisterAudio,
445
451
  updateAudio,
446
452
  ]);
447
- return (jsx_runtime_1.jsxs(exports.SharedAudioTagsContext.Provider, { value: audioTagsValue, children: [refs.map(({ id, ref }) => {
448
- return (
449
- // Without preload="metadata", iOS will seek the time internally
450
- // but not actually with sound. Adding `preload="metadata"` helps here.
451
- // https://discord.com/channels/809501355504959528/817306414069710848/1130519583367888906
452
- jsx_runtime_1.jsx("audio", { ref: ref, preload: "metadata", src: EMPTY_AUDIO }, id));
453
- }), children] }));
453
+ const sharedAudioTagElements = (0, react_1.useMemo)(() => {
454
+ return refs.map(({ id, ref }) => {
455
+ return (
456
+ // Without preload="metadata", iOS will seek the time internally
457
+ // but not actually with sound. Adding `preload="metadata"` helps here.
458
+ // https://discord.com/channels/809501355504959528/817306414069710848/1130519583367888906
459
+ jsx_runtime_1.jsx("audio", { ref: ref, preload: "metadata", src: EMPTY_AUDIO }, id));
460
+ });
461
+ }, [refs]);
462
+ return (jsx_runtime_1.jsxs(exports.SharedAudioTagsContext.Provider, { value: audioTagsValue, children: [sharedAudioTagElements, children] }));
454
463
  };
455
464
  exports.SharedAudioTagsContextProvider = SharedAudioTagsContextProvider;
456
465
  const useSharedAudio = ({ aud, audioId, premounting, postmounting, }) => {
@@ -14,11 +14,11 @@ import type { OverrideIdToNodePaths, OverrideToNodePathGetters, OverrideToNodeSe
14
14
  import { OverrideIdsToNodePathsGettersContext, OverrideIdsToNodePathsSettersContext } from './sequence-node-path.js';
15
15
  import type { ResolvedStackLocation } from './sequence-stack-traces.js';
16
16
  import type { CannotUpdateSequenceReason } from './SequenceManager.js';
17
- import { type CanUpdateEffectPropsResponse, type CanUpdateEffectPropsResponseFalse, type CanUpdateEffectPropsResponseTrue, type CanUpdateSequencePropsResponse, type CanUpdateSequencePropsResponseFalse, type CanUpdateSequencePropsResponseTrue, type SequenceNodePath, type SequencePropsSubscriptionKey } from './SequenceManager.js';
17
+ import { type CanUpdateEffectPropsResponse, type CanUpdateEffectPropsResponseFalse, type CanUpdateEffectPropsResponseTrue, type CanUpdateSequencePropsResponse, type CanUpdateSequencePropsResponseFalse, type CanUpdateSequencePropsResponseTrue, type SequenceNodePath, type SequencePropsSubscriptionKey, type VideoConfigValues } from './SequenceManager.js';
18
18
  import * as TimelinePosition from './timeline-position-state.js';
19
19
  import { type PlaybackRateContextValue, type SetTimelineContextValue, type TimelineContextValue } from './TimelineContext.js';
20
20
  import { truthy } from './truthy.js';
21
- import type { CanUpdateSequencePropStatusFalse, CanUpdateSequencePropStatusEasing, CanUpdateSequencePropStatusKeyframed, CanUpdateSequencePropStatusStatic, DragOverrideValue, GetDragOverrides, GetEffectDragOverrides, GetEffectPropStatuses, GetPropStatuses } from './use-schema.js';
21
+ import type { CanUpdateSequencePropStatusFalse, CanUpdateSequencePropStatusEasing, CanUpdateSequencePropStatusKeyframed, CanUpdateSequencePropStatusStatic, DragOverrideValue, GetDragOverrides, GetEffectDragOverrides, GetEffectPropStatuses, GetPropStatuses, VideoConfigNumericExpression } from './use-schema.js';
22
22
  import { type CanUpdateSequencePropStatus, type DragOverrides, type EffectDragOverrides, type PropStatuses } from './use-schema.js';
23
23
  import type { MediaVolumeContextValue, SetMediaVolumeContextValue } from './volume-position-state.js';
24
24
  import type { WatchRemotionStaticFilesPayload } from './watch-static-file.js';
@@ -930,4 +930,4 @@ export declare const Internals: {
930
930
  readonly hiddenFromList: true;
931
931
  };
932
932
  };
933
- export type { ArrayFieldSchema, ArrayItemFieldSchema, CannotUpdateSequenceReason, CanUpdateEffectPropsResponse, CanUpdateEffectPropsResponseFalse, CanUpdateEffectPropsResponseTrue, CanUpdateSequencePropsResponse, CanUpdateSequencePropsResponseFalse, CanUpdateSequencePropsResponseTrue, CanUpdateSequencePropStatus, CanUpdateSequencePropStatusEasing, CanUpdateSequencePropStatusFalse, CanUpdateSequencePropStatusKeyframed, CanUpdateSequencePropStatusStatic, CompositionManagerContext, CompProps, DragOverrides, DragOverrideValue, EffectDragOverrides, GetDragOverrides, GetEffectDragOverrides, GetEffectPropStatuses, GetPropStatuses, JsxComponentIdentity, LoggingContextValue, MediaVolumeContextValue, NonceHistory, OverrideIdsToNodePathsGettersContext, OverrideIdsToNodePathsSettersContext, OverrideIdToNodePaths, OverrideToNodePathGetters, OverrideToNodeSetters, PlaybackRateContextValue, PropStatuses, RemotionAudioContextState, RemotionEnvironment, ResolvedStackLocation, ScheduleAudioNodeOptions, ScheduleAudioNodeResult, InteractivitySchemaField, SequenceNodePath, SequencePropsSubscriptionKey, InteractivitySchema, SerializedJSONWithCustomFields, SetMediaVolumeContextValue, SetTimelineContextValue, TCompMetadata, TComposition, TimelineContextValue, TRenderAsset, TSequence, VisibleFieldSchema, WatchRemotionStaticFilesPayload, };
933
+ export type { ArrayFieldSchema, ArrayItemFieldSchema, CannotUpdateSequenceReason, CanUpdateEffectPropsResponse, CanUpdateEffectPropsResponseFalse, CanUpdateEffectPropsResponseTrue, CanUpdateSequencePropsResponse, CanUpdateSequencePropsResponseFalse, CanUpdateSequencePropsResponseTrue, CanUpdateSequencePropStatus, CanUpdateSequencePropStatusEasing, CanUpdateSequencePropStatusFalse, CanUpdateSequencePropStatusKeyframed, CanUpdateSequencePropStatusStatic, VideoConfigNumericExpression, CompositionManagerContext, CompProps, DragOverrides, DragOverrideValue, EffectDragOverrides, GetDragOverrides, GetEffectDragOverrides, GetEffectPropStatuses, GetPropStatuses, JsxComponentIdentity, LoggingContextValue, MediaVolumeContextValue, NonceHistory, OverrideIdsToNodePathsGettersContext, OverrideIdsToNodePathsSettersContext, OverrideIdToNodePaths, OverrideToNodePathGetters, OverrideToNodeSetters, PlaybackRateContextValue, PropStatuses, RemotionAudioContextState, RemotionEnvironment, ResolvedStackLocation, ScheduleAudioNodeOptions, ScheduleAudioNodeResult, InteractivitySchemaField, SequenceNodePath, SequencePropsSubscriptionKey, VideoConfigValues, InteractivitySchema, SerializedJSONWithCustomFields, SetMediaVolumeContextValue, SetTimelineContextValue, TCompMetadata, TComposition, TimelineContextValue, TRenderAsset, TSequence, VisibleFieldSchema, WatchRemotionStaticFilesPayload, };
@@ -0,0 +1,8 @@
1
+ import { type InterpolateOptions } from './interpolate.js';
2
+ export type InterpolateTranslateOptions = InterpolateOptions;
3
+ export declare const interpolateTranslate: (input: number, inputRange: readonly number[], outputRange: readonly string[], options?: Partial<{
4
+ easing: import("./interpolate.js").EasingFunction | readonly import("./interpolate.js").EasingFunction[];
5
+ extrapolateLeft: import("./interpolate.js").ExtrapolateType;
6
+ extrapolateRight: import("./interpolate.js").ExtrapolateType;
7
+ posterize: number;
8
+ }> | undefined) => string;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.interpolateTranslate = void 0;
4
+ const interpolate_js_1 = require("./interpolate.js");
5
+ const pixelValueRegex = /^([+-]?(?:\d+\.?\d*|\.\d+))px$/;
6
+ const parseTranslate = (value) => {
7
+ if (typeof value !== 'string') {
8
+ throw new TypeError(`outputRange must contain only strings, but got ${typeof value}`);
9
+ }
10
+ const parts = value.trim().split(/\s+/);
11
+ if (parts.length < 1 || parts.length > 3 || parts[0] === '') {
12
+ throw new TypeError(`translate values must contain 1 to 3 pixel values, but got "${value}"`);
13
+ }
14
+ return parts.map((part) => {
15
+ const match = pixelValueRegex.exec(part);
16
+ if (match === null) {
17
+ throw new TypeError(`interpolateTranslate() only supports px values, but got "${part}" in "${value}"`);
18
+ }
19
+ return Number(match[1]);
20
+ });
21
+ };
22
+ /*
23
+ * @description Allows you to map a range of values to CSS translate values using pixel units.
24
+ * @see [Documentation](https://remotion.dev/docs/interpolate-translate)
25
+ */
26
+ const interpolateTranslate = (input, inputRange, outputRange, options) => {
27
+ var _a;
28
+ if (typeof input === 'undefined') {
29
+ throw new TypeError('input can not be undefined');
30
+ }
31
+ if (typeof inputRange === 'undefined') {
32
+ throw new TypeError('inputRange can not be undefined');
33
+ }
34
+ if (typeof outputRange === 'undefined') {
35
+ throw new TypeError('outputRange can not be undefined');
36
+ }
37
+ if (inputRange.length !== outputRange.length) {
38
+ throw new TypeError('inputRange (' +
39
+ inputRange.length +
40
+ ' values provided) and outputRange (' +
41
+ outputRange.length +
42
+ ' values provided) must have the same length');
43
+ }
44
+ const parsedOutputRange = outputRange.map((translateValue) => parseTranslate(translateValue));
45
+ const firstValueLength = (_a = parsedOutputRange[0]) === null || _a === void 0 ? void 0 : _a.length;
46
+ if (firstValueLength === undefined) {
47
+ throw new TypeError('outputRange must have at least 1 element');
48
+ }
49
+ for (const parsedTranslate of parsedOutputRange) {
50
+ if (parsedTranslate.length !== firstValueLength) {
51
+ throw new TypeError(`All translate values must have the same number of pixel values, but got ${firstValueLength} and ${parsedTranslate.length}`);
52
+ }
53
+ }
54
+ return new Array(firstValueLength)
55
+ .fill(true)
56
+ .map((_, index) => {
57
+ const outputValues = [];
58
+ for (const translateValue of parsedOutputRange) {
59
+ const value = translateValue[index];
60
+ if (value === undefined) {
61
+ throw new TypeError(`All translate values must have the same number of pixel values, but got ${firstValueLength} and ${translateValue.length}`);
62
+ }
63
+ outputValues.push(value);
64
+ }
65
+ const interpolatedValue = (0, interpolate_js_1.interpolate)(input, inputRange, outputValues, options);
66
+ return `${interpolatedValue}px`;
67
+ })
68
+ .join(' ');
69
+ };
70
+ exports.interpolateTranslate = interpolateTranslate;