remotion 4.0.142 → 4.0.144

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 (54) hide show
  1. package/LICENSE.md +4 -0
  2. package/bunfig.toml +2 -0
  3. package/dist/cjs/CanUseRemotionHooks.d.ts +1 -1
  4. package/dist/cjs/Img.js +3 -2
  5. package/dist/cjs/Sequence.d.ts +14 -13
  6. package/dist/cjs/audio/Audio.d.ts +2 -1
  7. package/dist/cjs/audio/AudioForPreview.d.ts +7 -6
  8. package/dist/cjs/audio/AudioForPreview.js +2 -2
  9. package/dist/cjs/audio/AudioForRendering.d.ts +1 -0
  10. package/dist/cjs/audio/AudioForRendering.js +2 -2
  11. package/dist/cjs/audio/props.d.ts +2 -0
  12. package/dist/cjs/audio/use-audio-frame.d.ts +2 -1
  13. package/dist/cjs/audio/use-audio-frame.js +7 -2
  14. package/dist/cjs/default-css.d.ts +1 -1
  15. package/dist/cjs/default-css.js +3 -3
  16. package/dist/cjs/get-static-files.js +4 -0
  17. package/dist/cjs/index.d.ts +3 -3
  18. package/dist/cjs/internals.d.ts +1 -6
  19. package/dist/cjs/internals.js +0 -5
  20. package/dist/cjs/interpolate.d.ts +1 -1
  21. package/dist/cjs/loop/index.d.ts +13 -5
  22. package/dist/cjs/loop/index.js +38 -3
  23. package/dist/cjs/no-react.d.ts +5 -0
  24. package/dist/cjs/no-react.js +4 -0
  25. package/dist/cjs/series/index.js +4 -3
  26. package/dist/cjs/series/is-inside-series.d.ts +9 -0
  27. package/dist/cjs/series/is-inside-series.js +44 -0
  28. package/dist/cjs/spring/index.d.ts +2 -2
  29. package/dist/cjs/spring/index.js +8 -9
  30. package/dist/cjs/spring/measure-spring.d.ts +1 -1
  31. package/dist/cjs/spring/measure-spring.js +0 -2
  32. package/dist/cjs/spring/spring-utils.d.ts +1 -3
  33. package/dist/cjs/spring/spring-utils.js +3 -3
  34. package/dist/cjs/use-video-config.d.ts +1 -2
  35. package/dist/cjs/use-video-config.js +1 -2
  36. package/dist/cjs/version.d.ts +6 -1
  37. package/dist/cjs/version.js +7 -2
  38. package/dist/cjs/video/OffthreadVideoForRendering.js +2 -2
  39. package/dist/cjs/video/Video.d.ts +3 -2
  40. package/dist/cjs/video/VideoForPreview.d.ts +7 -7
  41. package/dist/cjs/video/VideoForPreview.js +5 -7
  42. package/dist/cjs/video/VideoForRendering.d.ts +1 -0
  43. package/dist/cjs/video/VideoForRendering.js +2 -2
  44. package/dist/cjs/video/index.d.ts +1 -1
  45. package/dist/cjs/video/props.d.ts +3 -0
  46. package/dist/cjs/video/video-fragment.js +9 -5
  47. package/dist/cjs/watch-static-file.js +4 -0
  48. package/dist/esm/index.mjs +576 -546
  49. package/dist/esm/no-react.mjs +3 -0
  50. package/dist/esm/version.mjs +6 -1
  51. package/ensure-correct-version.ts +47 -0
  52. package/happydom.ts +6 -0
  53. package/package.json +3 -1
  54. package/test.ts +1 -0
@@ -1,5 +1,5 @@
1
1
  import React, { createContext, useState, useMemo, useLayoutEffect, useContext, useEffect, forwardRef, useCallback, useRef, createRef, useImperativeHandle, useReducer, Suspense, Children } from 'react';
2
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { jsx, jsxs } from 'react/jsx-runtime';
3
3
  import { createPortal } from 'react-dom';
4
4
 
5
5
  const NativeLayersContext = createContext({
@@ -105,7 +105,12 @@ function truthy(value) {
105
105
  }
106
106
 
107
107
  // Automatically generated on publish
108
- const VERSION = '4.0.142';
108
+ /**
109
+ * @description Provides the current version number of the Remotion library.
110
+ * @see [Documentation](https://remotion.dev/docs/version)
111
+ * @returns {string} The current version of the remotion package
112
+ */
113
+ const VERSION = '4.0.144';
109
114
 
110
115
  const checkMultipleRemotionVersions = () => {
111
116
  if (typeof globalThis === 'undefined') {
@@ -926,10 +931,9 @@ const useUnsafeVideoConfig = () => {
926
931
  };
927
932
 
928
933
  /**
929
- * /**
930
934
  * @description Get some info about the context of the video that you are making.
931
935
  * @see [Documentation](https://www.remotion.dev/docs/use-video-config)
932
- * @returns Returns an object containing `fps`, `width`, `height` and `durationInFrames`, all of type `number`.
936
+ * @returns Returns an object containing `fps`, `width`, `height`, `durationInFrames`, `id` and `defaultProps`.
933
937
  */
934
938
  const useVideoConfig = () => {
935
939
  const videoConfig = useUnsafeVideoConfig();
@@ -1252,6 +1256,10 @@ function cancelRender(err) {
1252
1256
  throw error;
1253
1257
  }
1254
1258
 
1259
+ const LoopContext = createContext(null);
1260
+ const useLoop = () => {
1261
+ return React.useContext(LoopContext);
1262
+ };
1255
1263
  /**
1256
1264
  * @description This component allows you to quickly lay out an animation so it repeats itself.
1257
1265
  * @see [Documentation](https://www.remotion.dev/docs/loop)
@@ -1276,7 +1284,8 @@ const Loop = ({ durationInFrames, times = Infinity, children, name, ...props })
1276
1284
  const actualTimes = Math.min(maxTimes, times);
1277
1285
  const style = props.layout === 'none' ? undefined : props.style;
1278
1286
  const maxFrame = durationInFrames * (actualTimes - 1);
1279
- const start = Math.floor(currentFrame / durationInFrames) * durationInFrames;
1287
+ const iteration = Math.floor(currentFrame / durationInFrames);
1288
+ const start = iteration * durationInFrames;
1280
1289
  const from = Math.min(start, maxFrame);
1281
1290
  const loopDisplay = useMemo(() => {
1282
1291
  return {
@@ -1285,8 +1294,15 @@ const Loop = ({ durationInFrames, times = Infinity, children, name, ...props })
1285
1294
  durationInFrames,
1286
1295
  };
1287
1296
  }, [actualTimes, durationInFrames, from]);
1288
- return (jsx(Sequence, { durationInFrames: durationInFrames, from: from, name: name !== null && name !== void 0 ? name : '<Loop>', _remotionInternalLoopDisplay: loopDisplay, layout: props.layout, style: style, children: children }));
1297
+ const loopContext = useMemo(() => {
1298
+ return {
1299
+ iteration: Math.floor(currentFrame / durationInFrames),
1300
+ durationInFrames,
1301
+ };
1302
+ }, [currentFrame, durationInFrames]);
1303
+ return (jsx(LoopContext.Provider, { value: loopContext, children: jsx(Sequence, { durationInFrames: durationInFrames, from: from, name: name !== null && name !== void 0 ? name : '<Loop>', _remotionInternalLoopDisplay: loopDisplay, layout: props.layout, style: style, children: children }) }));
1289
1304
  };
1305
+ Loop.useLoop = useLoop;
1290
1306
 
1291
1307
  const PreloadContext = createContext({});
1292
1308
  let preloads = {};
@@ -1698,10 +1714,14 @@ const useMediaStartsAt = () => {
1698
1714
  * When passing a function as the prop for `volume`,
1699
1715
  * we calculate the way more intuitive value for currentFrame
1700
1716
  */
1701
- const useFrameForVolumeProp = () => {
1717
+ const useFrameForVolumeProp = (behavior) => {
1718
+ const loop = Loop.useLoop();
1702
1719
  const frame = useCurrentFrame();
1703
1720
  const startsAt = useMediaStartsAt();
1704
- return frame + startsAt;
1721
+ if (behavior === 'repeat' || loop === null) {
1722
+ return frame + startsAt;
1723
+ }
1724
+ return frame + startsAt + loop.durationInFrames * loop.iteration;
1705
1725
  };
1706
1726
 
1707
1727
  const getAssetDisplayName = (filename) => {
@@ -2076,15 +2096,19 @@ const appendVideoFragment = ({ actualSrc, actualFrom, duration, fps, }) => {
2076
2096
  actualSrc += `,${toSeconds(duration, fps)}`;
2077
2097
  return actualSrc;
2078
2098
  };
2079
- const isSubsetOfDuration = (prevStartFrom, newStartFrom, prevDuration, newDuration) => {
2080
- return (prevStartFrom <= newStartFrom &&
2081
- prevStartFrom + prevDuration >= newStartFrom + newDuration);
2082
- };
2099
+ const isSubsetOfDuration = ({ prevStartFrom, newStartFrom, prevDuration, newDuration, }) => prevStartFrom <= newStartFrom &&
2100
+ prevStartFrom + prevDuration >= newStartFrom + newDuration;
2083
2101
  const useAppendVideoFragment = ({ actualSrc: initialActualSrc, actualFrom: initialActualFrom, duration: initialDuration, fps, }) => {
2084
2102
  const actualFromRef = useRef(initialActualFrom);
2085
2103
  const actualDuration = useRef(initialDuration);
2086
2104
  const actualSrc = useRef(initialActualSrc);
2087
- if (!isSubsetOfDuration || initialActualSrc !== actualSrc.current) {
2105
+ if (!isSubsetOfDuration({
2106
+ prevStartFrom: actualFromRef.current,
2107
+ newStartFrom: initialActualFrom,
2108
+ prevDuration: actualDuration.current,
2109
+ newDuration: initialDuration,
2110
+ }) ||
2111
+ initialActualSrc !== actualSrc.current) {
2088
2112
  actualFromRef.current = initialActualFrom;
2089
2113
  actualDuration.current = initialDuration;
2090
2114
  actualSrc.current = initialActualSrc;
@@ -2537,10 +2561,10 @@ const AudioForDevelopmentForwardRefFunction = (props, ref) => {
2537
2561
  if (props.shouldPreMountAudioTags !== initialShouldPreMountAudioElements) {
2538
2562
  throw new Error('Cannot change the behavior for pre-mounting audio tags dynamically.');
2539
2563
  }
2564
+ const { volume, muted, playbackRate, shouldPreMountAudioTags, src, onDuration, acceptableTimeShiftInSeconds, _remotionInternalNeedsDurationCalculation, _remotionInternalNativeLoopPassed, _remotionInternalStack, allowAmplificationDuringRender, name, pauseWhenBuffering, showInTimeline, loopVolumeCurveBehavior, stack, ...nativeProps } = props;
2540
2565
  const [mediaVolume] = useMediaVolumeState();
2541
2566
  const [mediaMuted] = useMediaMutedState();
2542
- const volumePropFrame = useFrameForVolumeProp();
2543
- const { volume, muted, playbackRate, shouldPreMountAudioTags, src, onDuration, acceptableTimeShiftInSeconds, _remotionInternalNeedsDurationCalculation, _remotionInternalNativeLoopPassed, _remotionInternalStack, allowAmplificationDuringRender, name, pauseWhenBuffering, showInTimeline, ...nativeProps } = props;
2567
+ const volumePropFrame = useFrameForVolumeProp(loopVolumeCurveBehavior !== null && loopVolumeCurveBehavior !== void 0 ? loopVolumeCurveBehavior : 'repeat');
2544
2568
  const { hidden } = useContext(SequenceVisibilityToggleContext);
2545
2569
  if (!src) {
2546
2570
  throw new TypeError("No 'src' was passed to <Audio>.");
@@ -2762,8 +2786,9 @@ const continueRender = (handle) => {
2762
2786
 
2763
2787
  const AudioForRenderingRefForwardingFunction = (props, ref) => {
2764
2788
  const audioRef = useRef(null);
2789
+ const { volume: volumeProp, playbackRate, allowAmplificationDuringRender, onDuration, toneFrequency, _remotionInternalNeedsDurationCalculation, _remotionInternalNativeLoopPassed, acceptableTimeShiftInSeconds, name, onError, delayRenderRetries, delayRenderTimeoutInMilliseconds, loopVolumeCurveBehavior, ...nativeProps } = props;
2765
2790
  const absoluteFrame = useTimelinePosition();
2766
- const volumePropFrame = useFrameForVolumeProp();
2791
+ const volumePropFrame = useFrameForVolumeProp(loopVolumeCurveBehavior !== null && loopVolumeCurveBehavior !== void 0 ? loopVolumeCurveBehavior : 'repeat');
2767
2792
  const frame = useCurrentFrame();
2768
2793
  const sequenceContext = useContext(SequenceContext);
2769
2794
  const { registerRenderAsset, unregisterRenderAsset } = useContext(RenderAssetManager);
@@ -2778,7 +2803,6 @@ const AudioForRenderingRefForwardingFunction = (props, ref) => {
2778
2803
  sequenceContext === null || sequenceContext === void 0 ? void 0 : sequenceContext.cumulatedFrom,
2779
2804
  sequenceContext === null || sequenceContext === void 0 ? void 0 : sequenceContext.durationInFrames,
2780
2805
  ]);
2781
- const { volume: volumeProp, playbackRate, allowAmplificationDuringRender, onDuration, toneFrequency, _remotionInternalNeedsDurationCalculation, _remotionInternalNativeLoopPassed, acceptableTimeShiftInSeconds, name, onError, delayRenderRetries, delayRenderTimeoutInMilliseconds, ...nativeProps } = props;
2782
2806
  const volume = evaluateVolume({
2783
2807
  volume: volumeProp,
2784
2808
  frame: volumePropFrame,
@@ -3487,6 +3511,7 @@ const ImgRefForwarding = ({ onError, maxRetries = 2, src, pauseWhenLoading, dela
3487
3511
  cancelRender('Error loading image with src: ' + ((_l = imageRef.current) === null || _l === void 0 ? void 0 : _l.src));
3488
3512
  }, [maxRetries, onError, retryIn]);
3489
3513
  if (typeof window !== 'undefined') {
3514
+ const isPremounting = Boolean(sequenceContext === null || sequenceContext === void 0 ? void 0 : sequenceContext.premounting);
3490
3515
  // eslint-disable-next-line react-hooks/rules-of-hooks
3491
3516
  useLayoutEffect(() => {
3492
3517
  if (process.env.NODE_ENV === 'test') {
@@ -3496,7 +3521,7 @@ const ImgRefForwarding = ({ onError, maxRetries = 2, src, pauseWhenLoading, dela
3496
3521
  retries: delayRenderRetries !== null && delayRenderRetries !== void 0 ? delayRenderRetries : undefined,
3497
3522
  timeoutInMilliseconds: delayRenderTimeoutInMilliseconds !== null && delayRenderTimeoutInMilliseconds !== void 0 ? delayRenderTimeoutInMilliseconds : undefined,
3498
3523
  });
3499
- const unblock = pauseWhenLoading && !(sequenceContext === null || sequenceContext === void 0 ? void 0 : sequenceContext.premounting)
3524
+ const unblock = pauseWhenLoading && !isPremounting
3500
3525
  ? delayPlayback().unblock
3501
3526
  : () => undefined;
3502
3527
  const { current } = imageRef;
@@ -3531,7 +3556,7 @@ const ImgRefForwarding = ({ onError, maxRetries = 2, src, pauseWhenLoading, dela
3531
3556
  delayRenderRetries,
3532
3557
  delayRenderTimeoutInMilliseconds,
3533
3558
  pauseWhenLoading,
3534
- sequenceContext === null || sequenceContext === void 0 ? void 0 : sequenceContext.premounting,
3559
+ isPremounting,
3535
3560
  ]);
3536
3561
  }
3537
3562
  return (jsx("img", { ...props, ref: imageRef, src: actualSrc, onError: didGetError }));
@@ -3645,7 +3670,7 @@ const injectCSS = (css) => {
3645
3670
  injected[css] = true;
3646
3671
  };
3647
3672
  const OFFTHREAD_VIDEO_CLASS_NAME = '__remotion_offthreadvideo';
3648
- const makeDefaultCSS = (scope, backgroundColor) => {
3673
+ const makeDefaultPreviewCSS = (scope, backgroundColor) => {
3649
3674
  if (!scope) {
3650
3675
  return `
3651
3676
  * {
@@ -3678,7 +3703,7 @@ var CSSUtils = /*#__PURE__*/Object.freeze({
3678
3703
  __proto__: null,
3679
3704
  injectCSS: injectCSS,
3680
3705
  OFFTHREAD_VIDEO_CLASS_NAME: OFFTHREAD_VIDEO_CLASS_NAME,
3681
- makeDefaultCSS: makeDefaultCSS
3706
+ makeDefaultPreviewCSS: makeDefaultPreviewCSS
3682
3707
  });
3683
3708
 
3684
3709
  const REMOTION_STUDIO_CONTAINER_ELEMENT = '__remotion-studio-container';
@@ -3686,115 +3711,445 @@ const getPreviewDomElement = () => {
3686
3711
  return document.getElementById(REMOTION_STUDIO_CONTAINER_ELEMENT);
3687
3712
  };
3688
3713
 
3714
+ let Root = null;
3715
+ let listeners = [];
3689
3716
  /**
3690
- * Copied from:
3691
- * https://github.com/software-mansion/react-native-reanimated/blob/master/src/reanimated2/Colors.ts
3717
+ * @description This function registers the root component of the Remotion project
3718
+ * @see [Documentation](https://www.remotion.dev/docs/register-root)
3692
3719
  */
3693
- // var INTEGER = '[-+]?\\d+';
3694
- const NUMBER = '[-+]?\\d*\\.?\\d+';
3695
- const PERCENTAGE = NUMBER + '%';
3696
- function call(...args) {
3697
- return '\\(\\s*(' + args.join(')\\s*,\\s*(') + ')\\s*\\)';
3698
- }
3699
- function getMatchers() {
3700
- const cachedMatchers = {
3701
- rgb: undefined,
3702
- rgba: undefined,
3703
- hsl: undefined,
3704
- hsla: undefined,
3705
- hex3: undefined,
3706
- hex4: undefined,
3707
- hex5: undefined,
3708
- hex6: undefined,
3709
- hex8: undefined,
3710
- };
3711
- if (cachedMatchers.rgb === undefined) {
3712
- cachedMatchers.rgb = new RegExp('rgb' + call(NUMBER, NUMBER, NUMBER));
3713
- cachedMatchers.rgba = new RegExp('rgba' + call(NUMBER, NUMBER, NUMBER, NUMBER));
3714
- cachedMatchers.hsl = new RegExp('hsl' + call(NUMBER, PERCENTAGE, PERCENTAGE));
3715
- cachedMatchers.hsla = new RegExp('hsla' + call(NUMBER, PERCENTAGE, PERCENTAGE, NUMBER));
3716
- cachedMatchers.hex3 = /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/;
3717
- cachedMatchers.hex4 =
3718
- /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/;
3719
- cachedMatchers.hex6 = /^#([0-9a-fA-F]{6})$/;
3720
- cachedMatchers.hex8 = /^#([0-9a-fA-F]{8})$/;
3721
- }
3722
- return cachedMatchers;
3723
- }
3724
- function hue2rgb(p, q, t) {
3725
- if (t < 0) {
3726
- t += 1;
3727
- }
3728
- if (t > 1) {
3729
- t -= 1;
3720
+ const registerRoot = (comp) => {
3721
+ if (!comp) {
3722
+ throw new Error(`You must pass a React component to registerRoot(), but ${JSON.stringify(comp)} was passed.`);
3730
3723
  }
3731
- if (t < 1 / 6) {
3732
- return p + (q - p) * 6 * t;
3724
+ if (Root) {
3725
+ throw new Error('registerRoot() was called more than once.');
3733
3726
  }
3734
- if (t < 1 / 2) {
3735
- return q;
3727
+ Root = comp;
3728
+ listeners.forEach((l) => {
3729
+ l(comp);
3730
+ });
3731
+ };
3732
+ const getRoot = () => {
3733
+ return Root;
3734
+ };
3735
+ const waitForRoot = (fn) => {
3736
+ if (Root) {
3737
+ fn(Root);
3738
+ return () => undefined;
3736
3739
  }
3737
- if (t < 2 / 3) {
3738
- return p + (q - p) * (2 / 3 - t) * 6;
3740
+ listeners.push(fn);
3741
+ return () => {
3742
+ listeners = listeners.filter((l) => l !== fn);
3743
+ };
3744
+ };
3745
+
3746
+ const RemotionRoot = ({ children, numberOfAudioTags }) => {
3747
+ const [remotionRootId] = useState(() => String(random(null)));
3748
+ const [frame, setFrame] = useState(() => getInitialFrameState());
3749
+ const [playing, setPlaying] = useState(false);
3750
+ const imperativePlaying = useRef(false);
3751
+ const [fastRefreshes, setFastRefreshes] = useState(0);
3752
+ const [playbackRate, setPlaybackRate] = useState(1);
3753
+ const audioAndVideoTags = useRef([]);
3754
+ if (typeof window !== 'undefined') {
3755
+ // eslint-disable-next-line react-hooks/rules-of-hooks
3756
+ useLayoutEffect(() => {
3757
+ window.remotion_setFrame = (f, composition, attempt) => {
3758
+ window.remotion_attempt = attempt;
3759
+ const id = delayRender(`Setting the current frame to ${f}`);
3760
+ setFrame((s) => ({
3761
+ ...s,
3762
+ [composition]: f,
3763
+ }));
3764
+ requestAnimationFrame(() => continueRender(id));
3765
+ };
3766
+ window.remotion_isPlayer = false;
3767
+ }, []);
3739
3768
  }
3740
- return p;
3741
- }
3742
- function hslToRgb(h, s, l) {
3743
- const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
3744
- const p = 2 * l - q;
3745
- const r = hue2rgb(p, q, h + 1 / 3);
3746
- const g = hue2rgb(p, q, h);
3747
- const b = hue2rgb(p, q, h - 1 / 3);
3748
- return ((Math.round(r * 255) << 24) |
3749
- (Math.round(g * 255) << 16) |
3750
- (Math.round(b * 255) << 8));
3769
+ const timelineContextValue = useMemo(() => {
3770
+ return {
3771
+ frame,
3772
+ playing,
3773
+ imperativePlaying,
3774
+ rootId: remotionRootId,
3775
+ playbackRate,
3776
+ setPlaybackRate,
3777
+ audioAndVideoTags,
3778
+ };
3779
+ }, [frame, playbackRate, playing, remotionRootId]);
3780
+ const setTimelineContextValue = useMemo(() => {
3781
+ return {
3782
+ setFrame,
3783
+ setPlaying,
3784
+ };
3785
+ }, []);
3786
+ const nonceContext = useMemo(() => {
3787
+ let counter = 0;
3788
+ return {
3789
+ getNonce: () => counter++,
3790
+ fastRefreshes,
3791
+ };
3792
+ }, [fastRefreshes]);
3793
+ useEffect(() => {
3794
+ if (typeof __webpack_module__ !== 'undefined') {
3795
+ if (__webpack_module__.hot) {
3796
+ __webpack_module__.hot.addStatusHandler((status) => {
3797
+ if (status === 'idle') {
3798
+ setFastRefreshes((i) => i + 1);
3799
+ }
3800
+ });
3801
+ }
3802
+ }
3803
+ }, []);
3804
+ return (jsx(NonceContext.Provider, { value: nonceContext, children: jsx(TimelineContext.Provider, { value: timelineContextValue, children: jsx(SetTimelineContext.Provider, { value: setTimelineContextValue, children: jsx(EditorPropsProvider, { children: jsx(PrefetchProvider, { children: jsx(NativeLayersProvider, { children: jsx(CompositionManagerProvider, { numberOfAudioTags: numberOfAudioTags, children: jsx(DurationsContextProvider, { children: jsx(BufferingProvider, { children: children }) }) }) }) }) }) }) }) }));
3805
+ };
3806
+
3807
+ // https://github.com/remotion-dev/remotion/issues/3412#issuecomment-1910120552
3808
+ // eslint-disable-next-line no-useless-concat
3809
+ function getEnvVar() {
3810
+ const parts = ['proc', 'ess', '.', 'en', 'v', '.', 'NOD', 'E_EN', 'V'];
3811
+ return parts.join('');
3751
3812
  }
3752
- function parse255(str) {
3753
- const int = Number.parseInt(str, 10);
3754
- if (int < 0) {
3755
- return 0;
3813
+ const getEnvVariables = () => {
3814
+ if (getRemotionEnvironment().isRendering) {
3815
+ const param = window.remotion_envVariables;
3816
+ if (!param) {
3817
+ return {};
3818
+ }
3819
+ return { ...JSON.parse(param), NODE_ENV: process.env.NODE_ENV };
3756
3820
  }
3757
- if (int > 255) {
3758
- return 255;
3821
+ // For the Studio, we already set the environment variables in index-html.ts.
3822
+ // We just add NODE_ENV here.
3823
+ if (!process.env.NODE_ENV) {
3824
+ throw new Error(`${getEnvVar()} is not set`);
3759
3825
  }
3760
- return int;
3761
- }
3762
- function parse360(str) {
3763
- const int = Number.parseFloat(str);
3764
- return (((int % 360) + 360) % 360) / 360;
3765
- }
3766
- function parse1(str) {
3767
- const num = Number.parseFloat(str);
3768
- if (num < 0) {
3769
- return 0;
3826
+ return {
3827
+ NODE_ENV: process.env.NODE_ENV,
3828
+ };
3829
+ };
3830
+ const setupEnvVariables = () => {
3831
+ const env = getEnvVariables();
3832
+ if (!window.process) {
3833
+ window.process = {};
3770
3834
  }
3771
- if (num > 1) {
3772
- return 255;
3835
+ if (!window.process.env) {
3836
+ window.process.env = {};
3773
3837
  }
3774
- return Math.round(num * 255);
3775
- }
3776
- function parsePercentage(str) {
3777
- // parseFloat conveniently ignores the final %
3778
- const int = Number.parseFloat(str);
3779
- if (int < 0) {
3780
- return 0;
3838
+ Object.keys(env).forEach((key) => {
3839
+ window.process.env[key] = env[key];
3840
+ });
3841
+ };
3842
+
3843
+ const CurrentScaleContext = React.createContext(null);
3844
+ const PreviewSizeContext = createContext({
3845
+ setSize: () => undefined,
3846
+ size: { size: 'auto', translation: { x: 0, y: 0 } },
3847
+ });
3848
+ const calculateScale = ({ canvasSize, compositionHeight, compositionWidth, previewSize, }) => {
3849
+ const heightRatio = canvasSize.height / compositionHeight;
3850
+ const widthRatio = canvasSize.width / compositionWidth;
3851
+ const ratio = Math.min(heightRatio, widthRatio);
3852
+ return previewSize === 'auto' ? ratio : Number(previewSize);
3853
+ };
3854
+ /**
3855
+ * Gets the current scale of the container in which the component is being rendered.
3856
+ * Only works in the Remotion Studio and in the Remotion Player.
3857
+ */
3858
+ const useCurrentScale = (options) => {
3859
+ const hasContext = React.useContext(CurrentScaleContext);
3860
+ const zoomContext = React.useContext(PreviewSizeContext);
3861
+ const config = useUnsafeVideoConfig();
3862
+ if (hasContext === null || config === null || zoomContext === null) {
3863
+ if (options === null || options === void 0 ? void 0 : options.dontThrowIfOutsideOfRemotion) {
3864
+ return 1;
3865
+ }
3866
+ if (getRemotionEnvironment().isRendering) {
3867
+ return 1;
3868
+ }
3869
+ throw new Error([
3870
+ 'useCurrentScale() was called outside of a Remotion context.',
3871
+ 'This hook can only be called in a component that is being rendered by Remotion.',
3872
+ 'If you want to this hook to return 1 outside of Remotion, pass {dontThrowIfOutsideOfRemotion: true} as an option.',
3873
+ 'If you think you called this hook in a Remotion component, make sure all versions of Remotion are aligned.',
3874
+ ].join('\n'));
3781
3875
  }
3782
- if (int > 100) {
3783
- return 1;
3876
+ if (hasContext.type === 'scale') {
3877
+ return hasContext.scale;
3784
3878
  }
3785
- return int / 100;
3786
- }
3787
- const colorNames = {
3788
- transparent: 0x00000000,
3789
- // http://www.w3.org/TR/css3-color/#svg-color
3790
- aliceblue: 0xf0f8ffff,
3791
- antiquewhite: 0xfaebd7ff,
3792
- aqua: 0x00ffffff,
3793
- aquamarine: 0x7fffd4ff,
3794
- azure: 0xf0ffffff,
3795
- beige: 0xf5f5dcff,
3796
- bisque: 0xffe4c4ff,
3797
- black: 0x000000ff,
3879
+ return calculateScale({
3880
+ canvasSize: hasContext.canvasSize,
3881
+ compositionHeight: config.height,
3882
+ compositionWidth: config.width,
3883
+ previewSize: zoomContext.size.size,
3884
+ });
3885
+ };
3886
+
3887
+ const WATCH_REMOTION_STATIC_FILES = 'remotion_staticFilesChanged';
3888
+ /**
3889
+ * @description Watch for changes in a specific static file.
3890
+ * @param {string} fileName - The name of the static file to watch for changes.
3891
+ * @param {WatcherCallback} callback - A callback function to be called when the file changes.
3892
+ * @returns {{cancel: () => void}} A function that can be used to cancel the event listener.
3893
+ * @see [Documentation](https://www.remotion.dev/docs/watchstaticfile)
3894
+ */
3895
+ const watchStaticFile = (fileName, callback) => {
3896
+ // Check if function is called in Remotion Studio
3897
+ if (!getRemotionEnvironment().isStudio) {
3898
+ // eslint-disable-next-line no-console
3899
+ console.warn('The API is only available while using the Remotion Studio.');
3900
+ return { cancel: () => undefined };
3901
+ }
3902
+ const withoutStaticBase = fileName.startsWith(window.remotion_staticBase)
3903
+ ? fileName.replace(window.remotion_staticBase, '')
3904
+ : fileName;
3905
+ const withoutLeadingSlash = withoutStaticBase.startsWith('/')
3906
+ ? withoutStaticBase.slice(1)
3907
+ : withoutStaticBase;
3908
+ let prevFileData = window.remotion_staticFiles.find((file) => file.name === withoutLeadingSlash);
3909
+ // Check if the specified static file has updated or deleted
3910
+ const checkFile = (event) => {
3911
+ const staticFiles = event.detail.files;
3912
+ // Check for user specified file
3913
+ const newFileData = staticFiles.find((file) => file.name === withoutLeadingSlash);
3914
+ if (!newFileData) {
3915
+ // File is deleted
3916
+ if (prevFileData !== undefined) {
3917
+ callback(null);
3918
+ }
3919
+ prevFileData = undefined;
3920
+ return;
3921
+ }
3922
+ if (prevFileData === undefined ||
3923
+ prevFileData.lastModified !== newFileData.lastModified) {
3924
+ callback(newFileData); // File is added or modified
3925
+ prevFileData = newFileData;
3926
+ }
3927
+ };
3928
+ window.addEventListener(WATCH_REMOTION_STATIC_FILES, checkFile);
3929
+ const cancel = () => {
3930
+ return window.removeEventListener(WATCH_REMOTION_STATIC_FILES, checkFile);
3931
+ };
3932
+ return { cancel };
3933
+ };
3934
+
3935
+ function useRemotionContexts() {
3936
+ const compositionManagerCtx = React.useContext(CompositionManager);
3937
+ const timelineContext = React.useContext(TimelineContext);
3938
+ const setTimelineContext = React.useContext(SetTimelineContext);
3939
+ const sequenceContext = React.useContext(SequenceContext);
3940
+ const nonceContext = React.useContext(NonceContext);
3941
+ const canUseRemotionHooksContext = React.useContext(CanUseRemotionHooks);
3942
+ const nativeLayersContext = React.useContext(NativeLayersContext);
3943
+ const preloadContext = React.useContext(PreloadContext);
3944
+ const resolveCompositionContext = React.useContext(ResolveCompositionContext);
3945
+ const renderAssetManagerContext = React.useContext(RenderAssetManager);
3946
+ const sequenceManagerContext = React.useContext(SequenceManager);
3947
+ const bufferManagerContext = React.useContext(BufferingContextReact);
3948
+ return useMemo(() => ({
3949
+ compositionManagerCtx,
3950
+ timelineContext,
3951
+ setTimelineContext,
3952
+ sequenceContext,
3953
+ nonceContext,
3954
+ canUseRemotionHooksContext,
3955
+ nativeLayersContext,
3956
+ preloadContext,
3957
+ resolveCompositionContext,
3958
+ renderAssetManagerContext,
3959
+ sequenceManagerContext,
3960
+ bufferManagerContext,
3961
+ }), [
3962
+ compositionManagerCtx,
3963
+ nonceContext,
3964
+ sequenceContext,
3965
+ setTimelineContext,
3966
+ timelineContext,
3967
+ canUseRemotionHooksContext,
3968
+ nativeLayersContext,
3969
+ preloadContext,
3970
+ resolveCompositionContext,
3971
+ renderAssetManagerContext,
3972
+ sequenceManagerContext,
3973
+ bufferManagerContext,
3974
+ ]);
3975
+ }
3976
+ const RemotionContextProvider = (props) => {
3977
+ const { children, contexts } = props;
3978
+ return (jsx(CanUseRemotionHooks.Provider, { value: contexts.canUseRemotionHooksContext, children: jsx(NonceContext.Provider, { value: contexts.nonceContext, children: jsx(NativeLayersContext.Provider, { value: contexts.nativeLayersContext, children: jsx(PreloadContext.Provider, { value: contexts.preloadContext, children: jsx(CompositionManager.Provider, { value: contexts.compositionManagerCtx, children: jsx(SequenceManager.Provider, { value: contexts.sequenceManagerContext, children: jsx(RenderAssetManager.Provider, { value: contexts.renderAssetManagerContext, children: jsx(ResolveCompositionContext.Provider, { value: contexts.resolveCompositionContext, children: jsx(TimelineContext.Provider, { value: contexts.timelineContext, children: jsx(SetTimelineContext.Provider, { value: contexts.setTimelineContext, children: jsx(SequenceContext.Provider, { value: contexts.sequenceContext, children: jsx(BufferingContextReact.Provider, { value: contexts.bufferManagerContext, children: children }) }) }) }) }) }) }) }) }) }) }) }));
3979
+ };
3980
+
3981
+ // Mark them as Internals so use don't assume this is public
3982
+ // API and are less likely to use it
3983
+ const Internals = {
3984
+ useUnsafeVideoConfig,
3985
+ Timeline: TimelinePosition,
3986
+ CompositionManager,
3987
+ SequenceManager,
3988
+ SequenceVisibilityToggleContext,
3989
+ RemotionRoot,
3990
+ useVideo,
3991
+ getRoot,
3992
+ useMediaVolumeState,
3993
+ useMediaMutedState,
3994
+ useLazyComponent,
3995
+ truthy,
3996
+ SequenceContext,
3997
+ useRemotionContexts,
3998
+ RemotionContextProvider,
3999
+ CSSUtils,
4000
+ setupEnvVariables,
4001
+ MediaVolumeContext,
4002
+ SetMediaVolumeContext,
4003
+ getRemotionEnvironment,
4004
+ SharedAudioContext,
4005
+ SharedAudioContextProvider,
4006
+ invalidCompositionErrorMessage,
4007
+ isCompositionIdValid,
4008
+ getPreviewDomElement,
4009
+ compositionsRef,
4010
+ portalNode,
4011
+ waitForRoot,
4012
+ CanUseRemotionHooksProvider,
4013
+ CanUseRemotionHooks,
4014
+ PrefetchProvider,
4015
+ DurationsContextProvider,
4016
+ IsPlayerContextProvider,
4017
+ useIsPlayer,
4018
+ EditorPropsProvider,
4019
+ EditorPropsContext,
4020
+ usePreload,
4021
+ NonceContext,
4022
+ resolveVideoConfig,
4023
+ useResolvedVideoConfig,
4024
+ resolveCompositionsRef,
4025
+ ResolveCompositionConfig,
4026
+ REMOTION_STUDIO_CONTAINER_ELEMENT,
4027
+ RenderAssetManager,
4028
+ persistCurrentFrame,
4029
+ useTimelineSetFrame,
4030
+ NativeLayersProvider,
4031
+ ClipComposition,
4032
+ isIosSafari,
4033
+ WATCH_REMOTION_STATIC_FILES,
4034
+ addSequenceStackTraces,
4035
+ useMediaStartsAt,
4036
+ BufferingProvider,
4037
+ BufferingContextReact,
4038
+ enableSequenceStackTraces,
4039
+ CurrentScaleContext,
4040
+ PreviewSizeContext,
4041
+ calculateScale,
4042
+ };
4043
+
4044
+ /**
4045
+ * Copied from:
4046
+ * https://github.com/software-mansion/react-native-reanimated/blob/master/src/reanimated2/Colors.ts
4047
+ */
4048
+ // var INTEGER = '[-+]?\\d+';
4049
+ const NUMBER = '[-+]?\\d*\\.?\\d+';
4050
+ const PERCENTAGE = NUMBER + '%';
4051
+ function call(...args) {
4052
+ return '\\(\\s*(' + args.join(')\\s*,\\s*(') + ')\\s*\\)';
4053
+ }
4054
+ function getMatchers() {
4055
+ const cachedMatchers = {
4056
+ rgb: undefined,
4057
+ rgba: undefined,
4058
+ hsl: undefined,
4059
+ hsla: undefined,
4060
+ hex3: undefined,
4061
+ hex4: undefined,
4062
+ hex5: undefined,
4063
+ hex6: undefined,
4064
+ hex8: undefined,
4065
+ };
4066
+ if (cachedMatchers.rgb === undefined) {
4067
+ cachedMatchers.rgb = new RegExp('rgb' + call(NUMBER, NUMBER, NUMBER));
4068
+ cachedMatchers.rgba = new RegExp('rgba' + call(NUMBER, NUMBER, NUMBER, NUMBER));
4069
+ cachedMatchers.hsl = new RegExp('hsl' + call(NUMBER, PERCENTAGE, PERCENTAGE));
4070
+ cachedMatchers.hsla = new RegExp('hsla' + call(NUMBER, PERCENTAGE, PERCENTAGE, NUMBER));
4071
+ cachedMatchers.hex3 = /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/;
4072
+ cachedMatchers.hex4 =
4073
+ /^#([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/;
4074
+ cachedMatchers.hex6 = /^#([0-9a-fA-F]{6})$/;
4075
+ cachedMatchers.hex8 = /^#([0-9a-fA-F]{8})$/;
4076
+ }
4077
+ return cachedMatchers;
4078
+ }
4079
+ function hue2rgb(p, q, t) {
4080
+ if (t < 0) {
4081
+ t += 1;
4082
+ }
4083
+ if (t > 1) {
4084
+ t -= 1;
4085
+ }
4086
+ if (t < 1 / 6) {
4087
+ return p + (q - p) * 6 * t;
4088
+ }
4089
+ if (t < 1 / 2) {
4090
+ return q;
4091
+ }
4092
+ if (t < 2 / 3) {
4093
+ return p + (q - p) * (2 / 3 - t) * 6;
4094
+ }
4095
+ return p;
4096
+ }
4097
+ function hslToRgb(h, s, l) {
4098
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
4099
+ const p = 2 * l - q;
4100
+ const r = hue2rgb(p, q, h + 1 / 3);
4101
+ const g = hue2rgb(p, q, h);
4102
+ const b = hue2rgb(p, q, h - 1 / 3);
4103
+ return ((Math.round(r * 255) << 24) |
4104
+ (Math.round(g * 255) << 16) |
4105
+ (Math.round(b * 255) << 8));
4106
+ }
4107
+ function parse255(str) {
4108
+ const int = Number.parseInt(str, 10);
4109
+ if (int < 0) {
4110
+ return 0;
4111
+ }
4112
+ if (int > 255) {
4113
+ return 255;
4114
+ }
4115
+ return int;
4116
+ }
4117
+ function parse360(str) {
4118
+ const int = Number.parseFloat(str);
4119
+ return (((int % 360) + 360) % 360) / 360;
4120
+ }
4121
+ function parse1(str) {
4122
+ const num = Number.parseFloat(str);
4123
+ if (num < 0) {
4124
+ return 0;
4125
+ }
4126
+ if (num > 1) {
4127
+ return 255;
4128
+ }
4129
+ return Math.round(num * 255);
4130
+ }
4131
+ function parsePercentage(str) {
4132
+ // parseFloat conveniently ignores the final %
4133
+ const int = Number.parseFloat(str);
4134
+ if (int < 0) {
4135
+ return 0;
4136
+ }
4137
+ if (int > 100) {
4138
+ return 1;
4139
+ }
4140
+ return int / 100;
4141
+ }
4142
+ const colorNames = {
4143
+ transparent: 0x00000000,
4144
+ // http://www.w3.org/TR/css3-color/#svg-color
4145
+ aliceblue: 0xf0f8ffff,
4146
+ antiquewhite: 0xfaebd7ff,
4147
+ aqua: 0x00ffffff,
4148
+ aquamarine: 0x7fffd4ff,
4149
+ azure: 0xf0ffffff,
4150
+ beige: 0xf5f5dcff,
4151
+ bisque: 0xffe4c4ff,
4152
+ black: 0x000000ff,
3798
4153
  blanchedalmond: 0xffebcdff,
3799
4154
  blue: 0x0000ffff,
3800
4155
  blueviolet: 0x8a2be2ff,
@@ -4001,415 +4356,82 @@ function normalizeColor(color) {
4001
4356
  match[4], // a
4002
4357
  16) >>> 0);
4003
4358
  }
4004
- }
4005
- if (matchers.hsl) {
4006
- if ((match = matchers.hsl.exec(color))) {
4007
- return ((hslToRgb(parse360(match[1]), // h
4008
- parsePercentage(match[2]), // s
4009
- parsePercentage(match[3])) |
4010
- 0x000000ff) >>> // a
4011
- 0);
4012
- }
4013
- }
4014
- if (matchers.hsla) {
4015
- if ((match = matchers.hsla.exec(color))) {
4016
- return ((hslToRgb(parse360(match[1]), // h
4017
- parsePercentage(match[2]), // s
4018
- parsePercentage(match[3])) |
4019
- parse1(match[4])) >>> // a
4020
- 0);
4021
- }
4022
- }
4023
- throw new Error(`invalid color string ${color} provided`);
4024
- }
4025
- const opacity = (c) => {
4026
- return ((c >> 24) & 255) / 255;
4027
- };
4028
- const red = (c) => {
4029
- return (c >> 16) & 255;
4030
- };
4031
- const green = (c) => {
4032
- return (c >> 8) & 255;
4033
- };
4034
- const blue = (c) => {
4035
- return c & 255;
4036
- };
4037
- const rgbaColor = (r, g, b, alpha) => {
4038
- return `rgba(${r}, ${g}, ${b}, ${alpha})`;
4039
- };
4040
- function processColor(color) {
4041
- const normalizedColor = normalizeColor(color);
4042
- return ((normalizedColor << 24) | (normalizedColor >>> 8)) >>> 0; // argb
4043
- }
4044
- const interpolateColorsRGB = (value, inputRange, colors) => {
4045
- const [r, g, b, a] = [red, green, blue, opacity].map((f) => {
4046
- const unrounded = interpolate(value, inputRange, colors.map((c) => f(c)), {
4047
- extrapolateLeft: 'clamp',
4048
- extrapolateRight: 'clamp',
4049
- });
4050
- if (f === opacity) {
4051
- return Number(unrounded.toFixed(3));
4052
- }
4053
- return Math.round(unrounded);
4054
- });
4055
- return rgbaColor(r, g, b, a);
4056
- };
4057
- /**
4058
- * @description This function allows you to map a range of values to colors using a concise syntax.
4059
- * @see [Documentation](https://www.remotion.dev/docs/interpolate-colors)
4060
- */
4061
- const interpolateColors = (input, inputRange, outputRange) => {
4062
- if (typeof input === 'undefined') {
4063
- throw new TypeError('input can not be undefined');
4064
- }
4065
- if (typeof inputRange === 'undefined') {
4066
- throw new TypeError('inputRange can not be undefined');
4067
- }
4068
- if (typeof outputRange === 'undefined') {
4069
- throw new TypeError('outputRange can not be undefined');
4070
- }
4071
- if (inputRange.length !== outputRange.length) {
4072
- throw new TypeError('inputRange (' +
4073
- inputRange.length +
4074
- ' values provided) and outputRange (' +
4075
- outputRange.length +
4076
- ' values provided) must have the same length');
4077
- }
4078
- const processedOutputRange = outputRange.map((c) => processColor(c));
4079
- return interpolateColorsRGB(input, inputRange, processedOutputRange);
4080
- };
4081
-
4082
- let Root = null;
4083
- let listeners = [];
4084
- /**
4085
- * @description This function registers the root component of the Remotion project
4086
- * @see [Documentation](https://www.remotion.dev/docs/register-root)
4087
- */
4088
- const registerRoot = (comp) => {
4089
- if (!comp) {
4090
- throw new Error(`You must pass a React component to registerRoot(), but ${JSON.stringify(comp)} was passed.`);
4091
- }
4092
- if (Root) {
4093
- throw new Error('registerRoot() was called more than once.');
4094
- }
4095
- Root = comp;
4096
- listeners.forEach((l) => {
4097
- l(comp);
4098
- });
4099
- };
4100
- const getRoot = () => {
4101
- return Root;
4102
- };
4103
- const waitForRoot = (fn) => {
4104
- if (Root) {
4105
- fn(Root);
4106
- return () => undefined;
4107
- }
4108
- listeners.push(fn);
4109
- return () => {
4110
- listeners = listeners.filter((l) => l !== fn);
4111
- };
4112
- };
4113
-
4114
- const RemotionRoot = ({ children, numberOfAudioTags }) => {
4115
- const [remotionRootId] = useState(() => String(random(null)));
4116
- const [frame, setFrame] = useState(() => getInitialFrameState());
4117
- const [playing, setPlaying] = useState(false);
4118
- const imperativePlaying = useRef(false);
4119
- const [fastRefreshes, setFastRefreshes] = useState(0);
4120
- const [playbackRate, setPlaybackRate] = useState(1);
4121
- const audioAndVideoTags = useRef([]);
4122
- if (typeof window !== 'undefined') {
4123
- // eslint-disable-next-line react-hooks/rules-of-hooks
4124
- useLayoutEffect(() => {
4125
- window.remotion_setFrame = (f, composition, attempt) => {
4126
- window.remotion_attempt = attempt;
4127
- const id = delayRender(`Setting the current frame to ${f}`);
4128
- setFrame((s) => ({
4129
- ...s,
4130
- [composition]: f,
4131
- }));
4132
- requestAnimationFrame(() => continueRender(id));
4133
- };
4134
- window.remotion_isPlayer = false;
4135
- }, []);
4136
- }
4137
- const timelineContextValue = useMemo(() => {
4138
- return {
4139
- frame,
4140
- playing,
4141
- imperativePlaying,
4142
- rootId: remotionRootId,
4143
- playbackRate,
4144
- setPlaybackRate,
4145
- audioAndVideoTags,
4146
- };
4147
- }, [frame, playbackRate, playing, remotionRootId]);
4148
- const setTimelineContextValue = useMemo(() => {
4149
- return {
4150
- setFrame,
4151
- setPlaying,
4152
- };
4153
- }, []);
4154
- const nonceContext = useMemo(() => {
4155
- let counter = 0;
4156
- return {
4157
- getNonce: () => counter++,
4158
- fastRefreshes,
4159
- };
4160
- }, [fastRefreshes]);
4161
- useEffect(() => {
4162
- if (typeof __webpack_module__ !== 'undefined') {
4163
- if (__webpack_module__.hot) {
4164
- __webpack_module__.hot.addStatusHandler((status) => {
4165
- if (status === 'idle') {
4166
- setFastRefreshes((i) => i + 1);
4167
- }
4168
- });
4169
- }
4170
- }
4171
- }, []);
4172
- return (jsx(NonceContext.Provider, { value: nonceContext, children: jsx(TimelineContext.Provider, { value: timelineContextValue, children: jsx(SetTimelineContext.Provider, { value: setTimelineContextValue, children: jsx(EditorPropsProvider, { children: jsx(PrefetchProvider, { children: jsx(NativeLayersProvider, { children: jsx(CompositionManagerProvider, { numberOfAudioTags: numberOfAudioTags, children: jsx(DurationsContextProvider, { children: jsx(BufferingProvider, { children: children }) }) }) }) }) }) }) }) }));
4173
- };
4174
-
4175
- // https://github.com/remotion-dev/remotion/issues/3412#issuecomment-1910120552
4176
- // eslint-disable-next-line no-useless-concat
4177
- function getEnvVar() {
4178
- const parts = ['proc', 'ess', '.', 'en', 'v', '.', 'NOD', 'E_EN', 'V'];
4179
- return parts.join('');
4180
- }
4181
- const getEnvVariables = () => {
4182
- if (getRemotionEnvironment().isRendering) {
4183
- const param = window.remotion_envVariables;
4184
- if (!param) {
4185
- return {};
4186
- }
4187
- return { ...JSON.parse(param), NODE_ENV: process.env.NODE_ENV };
4188
- }
4189
- // For the Studio, we already set the environment variables in index-html.ts.
4190
- // We just add NODE_ENV here.
4191
- if (!process.env.NODE_ENV) {
4192
- throw new Error(`${getEnvVar()} is not set`);
4193
- }
4194
- return {
4195
- NODE_ENV: process.env.NODE_ENV,
4196
- };
4197
- };
4198
- const setupEnvVariables = () => {
4199
- const env = getEnvVariables();
4200
- if (!window.process) {
4201
- window.process = {};
4202
- }
4203
- if (!window.process.env) {
4204
- window.process.env = {};
4205
- }
4206
- Object.keys(env).forEach((key) => {
4207
- window.process.env[key] = env[key];
4208
- });
4209
- };
4210
-
4211
- const CurrentScaleContext = React.createContext(null);
4212
- const PreviewSizeContext = createContext({
4213
- setSize: () => undefined,
4214
- size: { size: 'auto', translation: { x: 0, y: 0 } },
4215
- });
4216
- const calculateScale = ({ canvasSize, compositionHeight, compositionWidth, previewSize, }) => {
4217
- const heightRatio = canvasSize.height / compositionHeight;
4218
- const widthRatio = canvasSize.width / compositionWidth;
4219
- const ratio = Math.min(heightRatio, widthRatio);
4220
- return previewSize === 'auto' ? ratio : Number(previewSize);
4221
- };
4222
- /**
4223
- * Gets the current scale of the container in which the component is being rendered.
4224
- * Only works in the Remotion Studio and in the Remotion Player.
4225
- */
4226
- const useCurrentScale = (options) => {
4227
- const hasContext = React.useContext(CurrentScaleContext);
4228
- const zoomContext = React.useContext(PreviewSizeContext);
4229
- const config = useUnsafeVideoConfig();
4230
- if (hasContext === null || config === null || zoomContext === null) {
4231
- if (options === null || options === void 0 ? void 0 : options.dontThrowIfOutsideOfRemotion) {
4232
- return 1;
4233
- }
4234
- if (getRemotionEnvironment().isRendering) {
4235
- return 1;
4359
+ }
4360
+ if (matchers.hsl) {
4361
+ if ((match = matchers.hsl.exec(color))) {
4362
+ return ((hslToRgb(parse360(match[1]), // h
4363
+ parsePercentage(match[2]), // s
4364
+ parsePercentage(match[3])) |
4365
+ 0x000000ff) >>> // a
4366
+ 0);
4236
4367
  }
4237
- throw new Error([
4238
- 'useCurrentScale() was called outside of a Remotion context.',
4239
- 'This hook can only be called in a component that is being rendered by Remotion.',
4240
- 'If you want to this hook to return 1 outside of Remotion, pass {dontThrowIfOutsideOfRemotion: true} as an option.',
4241
- 'If you think you called this hook in a Remotion component, make sure all versions of Remotion are aligned.',
4242
- ].join('\n'));
4243
4368
  }
4244
- if (hasContext.type === 'scale') {
4245
- return hasContext.scale;
4369
+ if (matchers.hsla) {
4370
+ if ((match = matchers.hsla.exec(color))) {
4371
+ return ((hslToRgb(parse360(match[1]), // h
4372
+ parsePercentage(match[2]), // s
4373
+ parsePercentage(match[3])) |
4374
+ parse1(match[4])) >>> // a
4375
+ 0);
4376
+ }
4246
4377
  }
4247
- return calculateScale({
4248
- canvasSize: hasContext.canvasSize,
4249
- compositionHeight: config.height,
4250
- compositionWidth: config.width,
4251
- previewSize: zoomContext.size.size,
4378
+ throw new Error(`invalid color string ${color} provided`);
4379
+ }
4380
+ const opacity = (c) => {
4381
+ return ((c >> 24) & 255) / 255;
4382
+ };
4383
+ const red = (c) => {
4384
+ return (c >> 16) & 255;
4385
+ };
4386
+ const green = (c) => {
4387
+ return (c >> 8) & 255;
4388
+ };
4389
+ const blue = (c) => {
4390
+ return c & 255;
4391
+ };
4392
+ const rgbaColor = (r, g, b, alpha) => {
4393
+ return `rgba(${r}, ${g}, ${b}, ${alpha})`;
4394
+ };
4395
+ function processColor(color) {
4396
+ const normalizedColor = normalizeColor(color);
4397
+ return ((normalizedColor << 24) | (normalizedColor >>> 8)) >>> 0; // argb
4398
+ }
4399
+ const interpolateColorsRGB = (value, inputRange, colors) => {
4400
+ const [r, g, b, a] = [red, green, blue, opacity].map((f) => {
4401
+ const unrounded = interpolate(value, inputRange, colors.map((c) => f(c)), {
4402
+ extrapolateLeft: 'clamp',
4403
+ extrapolateRight: 'clamp',
4404
+ });
4405
+ if (f === opacity) {
4406
+ return Number(unrounded.toFixed(3));
4407
+ }
4408
+ return Math.round(unrounded);
4252
4409
  });
4410
+ return rgbaColor(r, g, b, a);
4253
4411
  };
4254
-
4255
- const WATCH_REMOTION_STATIC_FILES = 'remotion_staticFilesChanged';
4256
4412
  /**
4257
- * @description Watch for changes in a specific static file.
4258
- * @param {string} fileName - The name of the static file to watch for changes.
4259
- * @param {WatcherCallback} callback - A callback function to be called when the file changes.
4260
- * @returns {{cancel: () => void}} A function that can be used to cancel the event listener.
4261
- * @see [Documentation](https://www.remotion.dev/docs/watchstaticfile)
4413
+ * @description This function allows you to map a range of values to colors using a concise syntax.
4414
+ * @see [Documentation](https://www.remotion.dev/docs/interpolate-colors)
4262
4415
  */
4263
- const watchStaticFile = (fileName, callback) => {
4264
- // Check if function is called in Remotion Studio
4265
- if (!getRemotionEnvironment().isStudio) {
4266
- // eslint-disable-next-line no-console
4267
- console.warn('The API is only available while using the Remotion Studio.');
4268
- return { cancel: () => undefined };
4416
+ const interpolateColors = (input, inputRange, outputRange) => {
4417
+ if (typeof input === 'undefined') {
4418
+ throw new TypeError('input can not be undefined');
4269
4419
  }
4270
- const withoutStaticBase = fileName.startsWith(window.remotion_staticBase)
4271
- ? fileName.replace(window.remotion_staticBase, '')
4272
- : fileName;
4273
- const withoutLeadingSlash = withoutStaticBase.startsWith('/')
4274
- ? withoutStaticBase.slice(1)
4275
- : withoutStaticBase;
4276
- let prevFileData = window.remotion_staticFiles.find((file) => file.name === withoutLeadingSlash);
4277
- // Check if the specified static file has updated or deleted
4278
- const checkFile = (event) => {
4279
- const staticFiles = event.detail.files;
4280
- // Check for user specified file
4281
- const newFileData = staticFiles.find((file) => file.name === withoutLeadingSlash);
4282
- if (!newFileData) {
4283
- // File is deleted
4284
- if (prevFileData !== undefined) {
4285
- callback(null);
4286
- }
4287
- prevFileData = undefined;
4288
- return;
4289
- }
4290
- if (prevFileData === undefined ||
4291
- prevFileData.lastModified !== newFileData.lastModified) {
4292
- callback(newFileData); // File is added or modified
4293
- prevFileData = newFileData;
4294
- }
4295
- };
4296
- window.addEventListener(WATCH_REMOTION_STATIC_FILES, checkFile);
4297
- const cancel = () => {
4298
- return window.removeEventListener(WATCH_REMOTION_STATIC_FILES, checkFile);
4299
- };
4300
- return { cancel };
4301
- };
4302
-
4303
- function useRemotionContexts() {
4304
- const compositionManagerCtx = React.useContext(CompositionManager);
4305
- const timelineContext = React.useContext(TimelineContext);
4306
- const setTimelineContext = React.useContext(SetTimelineContext);
4307
- const sequenceContext = React.useContext(SequenceContext);
4308
- const nonceContext = React.useContext(NonceContext);
4309
- const canUseRemotionHooksContext = React.useContext(CanUseRemotionHooks);
4310
- const nativeLayersContext = React.useContext(NativeLayersContext);
4311
- const preloadContext = React.useContext(PreloadContext);
4312
- const resolveCompositionContext = React.useContext(ResolveCompositionContext);
4313
- const renderAssetManagerContext = React.useContext(RenderAssetManager);
4314
- const sequenceManagerContext = React.useContext(SequenceManager);
4315
- const bufferManagerContext = React.useContext(BufferingContextReact);
4316
- return useMemo(() => ({
4317
- compositionManagerCtx,
4318
- timelineContext,
4319
- setTimelineContext,
4320
- sequenceContext,
4321
- nonceContext,
4322
- canUseRemotionHooksContext,
4323
- nativeLayersContext,
4324
- preloadContext,
4325
- resolveCompositionContext,
4326
- renderAssetManagerContext,
4327
- sequenceManagerContext,
4328
- bufferManagerContext,
4329
- }), [
4330
- compositionManagerCtx,
4331
- nonceContext,
4332
- sequenceContext,
4333
- setTimelineContext,
4334
- timelineContext,
4335
- canUseRemotionHooksContext,
4336
- nativeLayersContext,
4337
- preloadContext,
4338
- resolveCompositionContext,
4339
- renderAssetManagerContext,
4340
- sequenceManagerContext,
4341
- bufferManagerContext,
4342
- ]);
4343
- }
4344
- const RemotionContextProvider = (props) => {
4345
- const { children, contexts } = props;
4346
- return (jsx(CanUseRemotionHooks.Provider, { value: contexts.canUseRemotionHooksContext, children: jsx(NonceContext.Provider, { value: contexts.nonceContext, children: jsx(NativeLayersContext.Provider, { value: contexts.nativeLayersContext, children: jsx(PreloadContext.Provider, { value: contexts.preloadContext, children: jsx(CompositionManager.Provider, { value: contexts.compositionManagerCtx, children: jsx(SequenceManager.Provider, { value: contexts.sequenceManagerContext, children: jsx(RenderAssetManager.Provider, { value: contexts.renderAssetManagerContext, children: jsx(ResolveCompositionContext.Provider, { value: contexts.resolveCompositionContext, children: jsx(TimelineContext.Provider, { value: contexts.timelineContext, children: jsx(SetTimelineContext.Provider, { value: contexts.setTimelineContext, children: jsx(SequenceContext.Provider, { value: contexts.sequenceContext, children: jsx(BufferingContextReact.Provider, { value: contexts.bufferManagerContext, children: children }) }) }) }) }) }) }) }) }) }) }) }));
4347
- };
4348
-
4349
- // Mark them as Internals so use don't assume this is public
4350
- // API and are less likely to use it
4351
- const Internals = {
4352
- useUnsafeVideoConfig,
4353
- Timeline: TimelinePosition,
4354
- CompositionManager,
4355
- SequenceManager,
4356
- SequenceVisibilityToggleContext,
4357
- RemotionRoot,
4358
- useVideo,
4359
- getRoot,
4360
- useMediaVolumeState,
4361
- useMediaMutedState,
4362
- useLazyComponent,
4363
- truthy,
4364
- SequenceContext,
4365
- useRemotionContexts,
4366
- RemotionContextProvider,
4367
- CSSUtils,
4368
- setupEnvVariables,
4369
- MediaVolumeContext,
4370
- SetMediaVolumeContext,
4371
- getRemotionEnvironment,
4372
- SharedAudioContext,
4373
- SharedAudioContextProvider,
4374
- invalidCompositionErrorMessage,
4375
- isCompositionIdValid,
4376
- getPreviewDomElement,
4377
- compositionsRef,
4378
- portalNode,
4379
- waitForRoot,
4380
- CanUseRemotionHooksProvider,
4381
- CanUseRemotionHooks,
4382
- PrefetchProvider,
4383
- DurationsContextProvider,
4384
- IsPlayerContextProvider,
4385
- useIsPlayer,
4386
- EditorPropsProvider,
4387
- EditorPropsContext,
4388
- usePreload,
4389
- NonceContext,
4390
- resolveVideoConfig,
4391
- useResolvedVideoConfig,
4392
- resolveCompositionsRef,
4393
- ResolveCompositionConfig,
4394
- REMOTION_STUDIO_CONTAINER_ELEMENT,
4395
- RenderAssetManager,
4396
- persistCurrentFrame,
4397
- useTimelineSetFrame,
4398
- FILE_TOKEN,
4399
- DATE_TOKEN,
4400
- NativeLayersProvider,
4401
- ClipComposition,
4402
- isIosSafari,
4403
- WATCH_REMOTION_STATIC_FILES,
4404
- addSequenceStackTraces,
4405
- useMediaStartsAt,
4406
- BufferingProvider,
4407
- BufferingContextReact,
4408
- enableSequenceStackTraces,
4409
- colorNames,
4410
- CurrentScaleContext,
4411
- PreviewSizeContext,
4412
- calculateScale,
4420
+ if (typeof inputRange === 'undefined') {
4421
+ throw new TypeError('inputRange can not be undefined');
4422
+ }
4423
+ if (typeof outputRange === 'undefined') {
4424
+ throw new TypeError('outputRange can not be undefined');
4425
+ }
4426
+ if (inputRange.length !== outputRange.length) {
4427
+ throw new TypeError('inputRange (' +
4428
+ inputRange.length +
4429
+ ' values provided) and outputRange (' +
4430
+ outputRange.length +
4431
+ ' values provided) must have the same length');
4432
+ }
4433
+ const processedOutputRange = outputRange.map((c) => processColor(c));
4434
+ return interpolateColorsRGB(input, inputRange, processedOutputRange);
4413
4435
  };
4414
4436
 
4415
4437
  const validateFrame = ({ allowFloats, durationInFrames, frame, }) => {
@@ -4449,10 +4471,25 @@ const flattenChildren = (children) => {
4449
4471
  }, []);
4450
4472
  };
4451
4473
 
4474
+ const IsInsideSeriesContext = createContext(false);
4475
+ const IsInsideSeriesContainer = ({ children }) => {
4476
+ return (jsx(IsInsideSeriesContext.Provider, { value: true, children: children }));
4477
+ };
4478
+ const IsNotInsideSeriesProvider = ({ children }) => {
4479
+ return (jsx(IsInsideSeriesContext.Provider, { value: false, children: children }));
4480
+ };
4481
+ const useRequireToBeInsideSeries = () => {
4482
+ const isInsideSeries = React.useContext(IsInsideSeriesContext);
4483
+ if (!isInsideSeries) {
4484
+ throw new Error('This component must be inside a <Series /> component.');
4485
+ }
4486
+ };
4487
+
4452
4488
  const SeriesSequenceRefForwardingFunction = ({ children }, _ref) => {
4489
+ useRequireToBeInsideSeries();
4453
4490
  // Discard ref
4454
4491
  // eslint-disable-next-line react/jsx-no-useless-fragment
4455
- return jsx(Fragment, { children: children });
4492
+ return jsx(IsNotInsideSeriesProvider, { children: children });
4456
4493
  };
4457
4494
  const SeriesSequence = forwardRef(SeriesSequenceRefForwardingFunction);
4458
4495
  /**
@@ -4504,8 +4541,7 @@ const Series = ({ children }) => {
4504
4541
  return (jsx(Sequence, { name: name || '<Series.Sequence>', from: currentStartFrame, durationInFrames: durationInFramesProp, ...passedProps, ref: castedChild.ref, children: child }));
4505
4542
  });
4506
4543
  }, [children]);
4507
- /* eslint-disable react/jsx-no-useless-fragment */
4508
- return jsx(Fragment, { children: childrenValue });
4544
+ return jsx(IsInsideSeriesContainer, { children: childrenValue });
4509
4545
  };
4510
4546
  Series.Sequence = SeriesSequence;
4511
4547
  addSequenceStackTraces(SeriesSequence);
@@ -4587,10 +4623,10 @@ function advance({ animation, now, config, }) {
4587
4623
  return animationNode;
4588
4624
  }
4589
4625
  const calculationCache = {};
4590
- function springCalculation({ from = 0, to = 1, frame, fps, config = {}, }) {
4626
+ function springCalculation({ frame, fps, config = {}, }) {
4627
+ const from = 0;
4628
+ const to = 1;
4591
4629
  const cacheKey = [
4592
- from,
4593
- to,
4594
4630
  frame,
4595
4631
  fps,
4596
4632
  config.damping,
@@ -4674,8 +4710,6 @@ function measureSpring({ fps, config = {}, threshold = 0.005, from = 0, to = 1,
4674
4710
  fps,
4675
4711
  frame,
4676
4712
  config,
4677
- from,
4678
- to,
4679
4713
  });
4680
4714
  };
4681
4715
  let animation = calc();
@@ -4764,16 +4798,14 @@ function spring({ frame: passedFrame, fps, config = {}, from = 0, to = 1, durati
4764
4798
  fps,
4765
4799
  frame: durationProcessed,
4766
4800
  config,
4767
- from,
4768
- to,
4769
4801
  });
4770
- if (!config.overshootClamping) {
4771
- return spr.current;
4772
- }
4773
- if (to >= from) {
4774
- return Math.min(spr.current, to);
4775
- }
4776
- return Math.max(spr.current, to);
4802
+ const inner = config.overshootClamping
4803
+ ? to >= from
4804
+ ? Math.min(spr.current, to)
4805
+ : Math.max(spr.current, to)
4806
+ : spr.current;
4807
+ const interpolated = from === 0 && to === 1 ? inner : interpolate(inner, [0, 1], [from, to]);
4808
+ return interpolated;
4777
4809
  }
4778
4810
 
4779
4811
  /**
@@ -4790,10 +4822,10 @@ const Still = (props) => {
4790
4822
  return React.createElement((Composition), newProps);
4791
4823
  };
4792
4824
 
4793
- const OffthreadVideoForRendering = ({ onError, volume: volumeProp, playbackRate, src, muted, allowAmplificationDuringRender, transparent = false, toneMapped = true, toneFrequency, name, ...props }) => {
4825
+ const OffthreadVideoForRendering = ({ onError, volume: volumeProp, playbackRate, src, muted, allowAmplificationDuringRender, transparent = false, toneMapped = true, toneFrequency, name, loopVolumeCurveBehavior, ...props }) => {
4794
4826
  const absoluteFrame = useTimelinePosition();
4795
4827
  const frame = useCurrentFrame();
4796
- const volumePropsFrame = useFrameForVolumeProp();
4828
+ const volumePropsFrame = useFrameForVolumeProp(loopVolumeCurveBehavior !== null && loopVolumeCurveBehavior !== void 0 ? loopVolumeCurveBehavior : 'repeat');
4797
4829
  const videoConfig = useUnsafeVideoConfig();
4798
4830
  const sequenceContext = useContext(SequenceContext);
4799
4831
  const mediaStartsAt = useMediaStartsAt();
@@ -4893,15 +4925,15 @@ const OffthreadVideoForRendering = ({ onError, volume: volumeProp, playbackRate,
4893
4925
  const VideoForDevelopmentRefForwardingFunction = (props, ref) => {
4894
4926
  var _a, _b, _c;
4895
4927
  const videoRef = useRef(null);
4896
- const volumePropFrame = useFrameForVolumeProp();
4928
+ const { volume, muted, playbackRate, onlyWarnForMediaSeekingError, src, onDuration,
4929
+ // @ts-expect-error
4930
+ acceptableTimeShift, acceptableTimeShiftInSeconds, toneFrequency, name, _remotionInternalNativeLoopPassed, _remotionInternalStack, style, pauseWhenBuffering, showInTimeline, loopVolumeCurveBehavior, ...nativeProps } = props;
4931
+ const volumePropFrame = useFrameForVolumeProp(loopVolumeCurveBehavior !== null && loopVolumeCurveBehavior !== void 0 ? loopVolumeCurveBehavior : 'repeat');
4897
4932
  const { fps, durationInFrames } = useVideoConfig();
4898
4933
  const parentSequence = useContext(SequenceContext);
4899
4934
  const { hidden } = useContext(SequenceVisibilityToggleContext);
4900
4935
  const [timelineId] = useState(() => String(Math.random()));
4901
4936
  const isSequenceHidden = (_a = hidden[timelineId]) !== null && _a !== void 0 ? _a : false;
4902
- const { volume, muted, playbackRate, onlyWarnForMediaSeekingError, src, onDuration,
4903
- // @ts-expect-error
4904
- acceptableTimeShift, acceptableTimeShiftInSeconds, toneFrequency, name, _remotionInternalNativeLoopPassed, _remotionInternalStack, style, pauseWhenBuffering, showInTimeline, ...nativeProps } = props;
4905
4937
  if (typeof acceptableTimeShift !== 'undefined') {
4906
4938
  throw new Error('acceptableTimeShift has been removed. Use acceptableTimeShiftInSeconds instead.');
4907
4939
  }
@@ -4941,9 +4973,7 @@ const VideoForDevelopmentRefForwardingFunction = (props, ref) => {
4941
4973
  shouldBuffer: pauseWhenBuffering,
4942
4974
  isPremounting: Boolean(parentSequence === null || parentSequence === void 0 ? void 0 : parentSequence.premounting),
4943
4975
  });
4944
- const actualFrom = parentSequence
4945
- ? parentSequence.relativeFrom + parentSequence.cumulatedFrom
4946
- : 0;
4976
+ const actualFrom = parentSequence ? parentSequence.relativeFrom : 0;
4947
4977
  const duration = parentSequence
4948
4978
  ? Math.min(parentSequence.durationInFrames, durationInFrames)
4949
4979
  : durationInFrames;
@@ -5149,10 +5179,10 @@ const seekToTimeMultipleUntilRight = (element, desiredTime, fps) => {
5149
5179
  };
5150
5180
  };
5151
5181
 
5152
- const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAmplificationDuringRender, playbackRate, onDuration, toneFrequency, name, acceptableTimeShiftInSeconds, delayRenderRetries, delayRenderTimeoutInMilliseconds, ...props }, ref) => {
5182
+ const VideoForRenderingForwardFunction = ({ onError, volume: volumeProp, allowAmplificationDuringRender, playbackRate, onDuration, toneFrequency, name, acceptableTimeShiftInSeconds, delayRenderRetries, delayRenderTimeoutInMilliseconds, loopVolumeCurveBehavior, ...props }, ref) => {
5153
5183
  const absoluteFrame = useTimelinePosition();
5154
5184
  const frame = useCurrentFrame();
5155
- const volumePropsFrame = useFrameForVolumeProp();
5185
+ const volumePropsFrame = useFrameForVolumeProp(loopVolumeCurveBehavior !== null && loopVolumeCurveBehavior !== void 0 ? loopVolumeCurveBehavior : 'repeat');
5156
5186
  const videoConfig = useUnsafeVideoConfig();
5157
5187
  const videoRef = useRef(null);
5158
5188
  const sequenceContext = useContext(SequenceContext);