remotion 4.0.526 → 4.0.528

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 (66) hide show
  1. package/dist/cjs/AbsoluteFill.d.ts +29 -3
  2. package/dist/cjs/AbsoluteFill.js +19 -2
  3. package/dist/cjs/CompositionManager.d.ts +2 -0
  4. package/dist/cjs/HtmlInCanvas.d.ts +28 -2
  5. package/dist/cjs/HtmlInCanvas.js +17 -3
  6. package/dist/cjs/Img.d.ts +2 -2
  7. package/dist/cjs/Img.js +1 -1
  8. package/dist/cjs/Interactive.d.ts +20 -2
  9. package/dist/cjs/Interactive.js +30 -8
  10. package/dist/cjs/Sequence.d.ts +1 -0
  11. package/dist/cjs/Sequence.js +49 -18
  12. package/dist/cjs/SequenceContext.d.ts +5 -0
  13. package/dist/cjs/TimelineContext.d.ts +2 -0
  14. package/dist/cjs/TimelineContext.js +8 -1
  15. package/dist/cjs/animated-image/AnimatedImage.d.ts +9 -10
  16. package/dist/cjs/animated-image/AnimatedImage.js +1 -12
  17. package/dist/cjs/audio/AudioForPreview.js +1 -0
  18. package/dist/cjs/audio/AudioForRendering.js +11 -7
  19. package/dist/cjs/audio/html5-audio.js +14 -7
  20. package/dist/cjs/audio/use-audio-frame.d.ts +1 -0
  21. package/dist/cjs/audio/use-audio-frame.js +14 -2
  22. package/dist/cjs/calculate-media-duration.js +1 -2
  23. package/dist/cjs/canvas-image/CanvasImage.d.ts +1 -1
  24. package/dist/cjs/canvas-image/CanvasImage.js +1 -1
  25. package/dist/cjs/canvas-image/props.d.ts +1 -1
  26. package/dist/cjs/effects/Solid.d.ts +28 -2
  27. package/dist/cjs/effects/Solid.js +16 -3
  28. package/dist/cjs/freeze.js +11 -3
  29. package/dist/cjs/get-asset-file-name.js +7 -1
  30. package/dist/cjs/get-sequence-boundary-tolerance.d.ts +7 -0
  31. package/dist/cjs/get-sequence-boundary-tolerance.js +10 -0
  32. package/dist/cjs/index.d.ts +3 -3
  33. package/dist/cjs/interactivity-schema.d.ts +75 -1
  34. package/dist/cjs/interactivity-schema.js +21 -1
  35. package/dist/cjs/internals.d.ts +23 -2
  36. package/dist/cjs/internals.js +2 -0
  37. package/dist/cjs/interpolate.d.ts +5 -0
  38. package/dist/cjs/interpolate.js +85 -5
  39. package/dist/cjs/loop/index.d.ts +7 -1
  40. package/dist/cjs/loop/index.js +35 -9
  41. package/dist/cjs/no-react.d.ts +10 -1
  42. package/dist/cjs/series/index.d.ts +1 -1
  43. package/dist/cjs/series/index.js +1 -0
  44. package/dist/cjs/spring/spring-utils.js +15 -12
  45. package/dist/cjs/timeline-position-state.d.ts +1 -0
  46. package/dist/cjs/timeline-position-state.js +8 -1
  47. package/dist/cjs/use-current-frame.js +2 -1
  48. package/dist/cjs/use-media-in-timeline.d.ts +5 -2
  49. package/dist/cjs/use-media-in-timeline.js +78 -13
  50. package/dist/cjs/use-media-playback.js +8 -3
  51. package/dist/cjs/use-premounting.js +19 -5
  52. package/dist/cjs/use-timeline-seek.d.ts +6 -0
  53. package/dist/cjs/use-timeline-seek.js +18 -0
  54. package/dist/cjs/version.d.ts +1 -1
  55. package/dist/cjs/version.js +1 -1
  56. package/dist/cjs/video/OffthreadVideo.js +7 -1
  57. package/dist/cjs/video/OffthreadVideoForRendering.js +11 -8
  58. package/dist/cjs/video/VideoForPreview.js +1 -0
  59. package/dist/cjs/video/VideoForRendering.js +12 -10
  60. package/dist/cjs/video/html5-video.js +12 -7
  61. package/dist/esm/index.mjs +927 -477
  62. package/dist/esm/no-react.mjs +103 -17
  63. package/dist/esm/version.mjs +1 -1
  64. package/package.json +2 -2
  65. package/dist/cjs/nonce.d.ts +0 -11
  66. package/dist/cjs/nonce.js +0 -42
@@ -1537,7 +1537,7 @@ var Composition = (props) => {
1537
1537
  };
1538
1538
 
1539
1539
  // src/version.ts
1540
- var VERSION = "4.0.526";
1540
+ var VERSION = "4.0.528";
1541
1541
 
1542
1542
  // src/multiple-versions-warning.ts
1543
1543
  var checkMultipleRemotionVersions = () => {
@@ -1578,18 +1578,19 @@ import {
1578
1578
  forwardRef as forwardRef3,
1579
1579
  useCallback as useCallback6,
1580
1580
  useContext as useContext20,
1581
- useMemo as useMemo13,
1582
- useRef as useRef6,
1581
+ useMemo as useMemo14,
1582
+ useRef as useRef7,
1583
1583
  useState as useState6
1584
1584
  } from "react";
1585
1585
 
1586
1586
  // src/freeze.tsx
1587
- import { useContext as useContext15, useMemo as useMemo9 } from "react";
1587
+ import { useContext as useContext15, useMemo as useMemo10 } from "react";
1588
1588
 
1589
1589
  // src/timeline-position-state.ts
1590
1590
  var exports_timeline_position_state = {};
1591
1591
  __export(exports_timeline_position_state, {
1592
1592
  useTimelineSetFrame: () => useTimelineSetFrame,
1593
+ useTimelineSeekFrame: () => useTimelineSeekFrame,
1593
1594
  useTimelinePosition: () => useTimelinePosition,
1594
1595
  useTimelineContext: () => useTimelineContext,
1595
1596
  usePlaying: () => usePlaying,
@@ -1609,8 +1610,8 @@ import {
1609
1610
  createContext as createContext13,
1610
1611
  useCallback as useCallback4,
1611
1612
  useLayoutEffect,
1612
- useMemo as useMemo8,
1613
- useRef as useRef2,
1613
+ useMemo as useMemo9,
1614
+ useRef as useRef3,
1614
1615
  useState as useState2
1615
1616
  } from "react";
1616
1617
 
@@ -1641,12 +1642,26 @@ var createRuntimeValueStore = (initialSnapshot) => {
1641
1642
  };
1642
1643
  };
1643
1644
 
1645
+ // src/use-timeline-seek.ts
1646
+ import { useMemo as useMemo8, useRef as useRef2 } from "react";
1647
+ var useTimelineSeek = (setFrame) => {
1648
+ const revision = useRef2(0);
1649
+ return useMemo8(() => ({
1650
+ revision,
1651
+ setFrame: (frame) => {
1652
+ revision.current++;
1653
+ setFrame(frame);
1654
+ }
1655
+ }), [setFrame]);
1656
+ };
1657
+
1644
1658
  // src/TimelineContext.tsx
1645
1659
  import { jsx as jsx8 } from "react/jsx-runtime";
1646
1660
  var missingSetTimelineContext = () => {
1647
1661
  throw new Error("SetTimelineContext is missing. This is likely caused by a Remotion version mismatch.");
1648
1662
  };
1649
1663
  var SetTimelineContext = createContext13({
1664
+ seek: null,
1650
1665
  setFrame: missingSetTimelineContext,
1651
1666
  setPlaying: missingSetTimelineContext,
1652
1667
  setBuffering: missingSetTimelineContext,
@@ -1665,13 +1680,16 @@ var TimelineContext = createContext13(null);
1665
1680
  var PlaybackRateContext = createContext13(null);
1666
1681
  var AbsoluteTimeContext = createContext13(null);
1667
1682
  var TimelineContextProvider = ({ children, frameState }) => {
1668
- const playingStore = useMemo8(() => createRuntimeValueStore({ playing: false }), []);
1669
- const bufferingStore = useMemo8(() => createRuntimeValueStore({ buffering: false }), []);
1683
+ const playingStore = useMemo9(() => createRuntimeValueStore({ playing: false }), []);
1684
+ const bufferingStore = useMemo9(() => createRuntimeValueStore({ buffering: false }), []);
1670
1685
  const [playbackRate, setPlaybackRate] = useState2(1);
1671
- const audioAndVideoTags = useRef2([]);
1686
+ const audioAndVideoTags = useRef3([]);
1672
1687
  const [_frame, setFrame] = useState2(() => getInitialFrameState());
1688
+ const timelineSeek = useTimelineSeek(setFrame);
1689
+ const { isStudio } = useRemotionEnvironment();
1690
+ const seek = isStudio ? timelineSeek : null;
1673
1691
  const frame = frameState ?? _frame;
1674
- const frameRef = useRef2(frame);
1692
+ const frameRef = useRef3(frame);
1675
1693
  frameRef.current = frame;
1676
1694
  const readIsPlaying = useCallback4(() => playingStore.store.getSnapshot().playing, [playingStore]);
1677
1695
  const readIsBuffering = useCallback4(() => bufferingStore.store.getSnapshot().buffering, [bufferingStore]);
@@ -1702,7 +1720,7 @@ var TimelineContextProvider = ({ children, frameState }) => {
1702
1720
  window.remotion_isPlayer = false;
1703
1721
  }, [continueRender2, delayRender2]);
1704
1722
  }
1705
- const timelineContextValue = useMemo8(() => {
1723
+ const timelineContextValue = useMemo9(() => {
1706
1724
  return {
1707
1725
  frame,
1708
1726
  isPlaying: readIsPlaying,
@@ -1710,15 +1728,16 @@ var TimelineContextProvider = ({ children, frameState }) => {
1710
1728
  audioAndVideoTags
1711
1729
  };
1712
1730
  }, [frame, readIsPlaying]);
1713
- const playbackRateContextValue = useMemo8(() => {
1731
+ const playbackRateContextValue = useMemo9(() => {
1714
1732
  return {
1715
1733
  playbackRate,
1716
1734
  setPlaybackRate
1717
1735
  };
1718
1736
  }, [playbackRate]);
1719
- const setTimelineContextValue = useMemo8(() => {
1737
+ const setTimelineContextValue = useMemo9(() => {
1720
1738
  return {
1721
1739
  setFrame,
1740
+ seek,
1722
1741
  setPlaying: (updater) => {
1723
1742
  const current = playingStore.store.getSnapshot().playing;
1724
1743
  const next = typeof updater === "function" ? updater(current) : updater;
@@ -1738,7 +1757,7 @@ var TimelineContextProvider = ({ children, frameState }) => {
1738
1757
  frameRef,
1739
1758
  audioAndVideoTags
1740
1759
  };
1741
- }, [bufferingStore, playingStore, readIsBuffering, readIsPlaying]);
1760
+ }, [bufferingStore, playingStore, readIsBuffering, readIsPlaying, seek]);
1742
1761
  return /* @__PURE__ */ jsx8(AbsoluteTimeContext.Provider, {
1743
1762
  value: timelineContextValue,
1744
1763
  children: /* @__PURE__ */ jsx8(PlaybackRateContext.Provider, {
@@ -1877,6 +1896,10 @@ var useTimelineSetFrame = () => {
1877
1896
  const { setFrame } = useContext12(SetTimelineContext);
1878
1897
  return setFrame;
1879
1898
  };
1899
+ var useTimelineSeekFrame = () => {
1900
+ const { seek, setFrame } = useContext12(SetTimelineContext);
1901
+ return seek?.setFrame ?? setFrame;
1902
+ };
1880
1903
 
1881
1904
  // src/use-current-frame.ts
1882
1905
  import { useContext as useContext13 } from "react";
@@ -1892,7 +1915,7 @@ var useCurrentFrame = () => {
1892
1915
  const frame = useTimelinePosition();
1893
1916
  const context = useContext13(SequenceContext);
1894
1917
  const contextOffset = context ? context.cumulatedFrom + context.relativeFrom : 0;
1895
- return frame - contextOffset;
1918
+ return (frame - contextOffset) * (context?.playbackRate ?? 1);
1896
1919
  };
1897
1920
 
1898
1921
  // src/use-video-config.ts
@@ -1938,7 +1961,7 @@ var Freeze = ({
1938
1961
  if (!Number.isFinite(frameToFreeze)) {
1939
1962
  throw new Error(`The 'frame' prop of <Freeze /> must be a finite number, but it is ${frameToFreeze}.`);
1940
1963
  }
1941
- const isActive = useMemo9(() => {
1964
+ const isActive = useMemo10(() => {
1942
1965
  if (typeof active === "boolean") {
1943
1966
  return active;
1944
1967
  }
@@ -1949,7 +1972,8 @@ var Freeze = ({
1949
1972
  const timelineContext = useTimelineContext();
1950
1973
  const sequenceContext = useContext15(SequenceContext);
1951
1974
  const relativeFrom = sequenceContext?.relativeFrom ?? 0;
1952
- const timelineValue = useMemo9(() => {
1975
+ const playbackRate = sequenceContext?.playbackRate ?? 1;
1976
+ const timelineValue = useMemo10(() => {
1953
1977
  if (!isActive) {
1954
1978
  return timelineContext;
1955
1979
  }
@@ -1958,11 +1982,18 @@ var Freeze = ({
1958
1982
  isPlaying: () => false,
1959
1983
  isInsideFreeze: true,
1960
1984
  frame: {
1961
- [videoConfig.id]: frameToFreeze + relativeFrom
1985
+ [videoConfig.id]: frameToFreeze / playbackRate + relativeFrom
1962
1986
  }
1963
1987
  };
1964
- }, [isActive, timelineContext, videoConfig.id, frameToFreeze, relativeFrom]);
1965
- const newSequenceContext = useMemo9(() => {
1988
+ }, [
1989
+ isActive,
1990
+ timelineContext,
1991
+ videoConfig.id,
1992
+ frameToFreeze,
1993
+ relativeFrom,
1994
+ playbackRate
1995
+ ]);
1996
+ const newSequenceContext = useMemo10(() => {
1966
1997
  if (!sequenceContext) {
1967
1998
  return null;
1968
1999
  }
@@ -1983,6 +2014,17 @@ var Freeze = ({
1983
2014
  });
1984
2015
  };
1985
2016
 
2017
+ // src/get-sequence-boundary-tolerance.ts
2018
+ var getSequenceBoundaryTolerance = ({
2019
+ absoluteFrame,
2020
+ cumulatedFrom,
2021
+ from,
2022
+ parentPlaybackRate,
2023
+ durationInFrames
2024
+ }) => {
2025
+ return Math.min(durationInFrames / 2, Number.EPSILON * Math.max(Math.abs(absoluteFrame * parentPlaybackRate), Math.abs(cumulatedFrom * parentPlaybackRate), Math.abs(from)) * 4);
2026
+ };
2027
+
1986
2028
  // src/interactivity-schema.ts
1987
2029
  var captionsSchema = {
1988
2030
  captions: {
@@ -2331,7 +2373,26 @@ var freezeField = {
2331
2373
  step: 1,
2332
2374
  hiddenFromList: true
2333
2375
  };
2376
+ var playbackRateField = {
2377
+ type: "number",
2378
+ default: 1,
2379
+ min: 0.01,
2380
+ step: 0.1,
2381
+ description: "Playback rate",
2382
+ hiddenFromList: false,
2383
+ keyframable: false
2384
+ };
2334
2385
  var baseSchema = {
2386
+ durationInFrames: durationInFramesField,
2387
+ from: fromField,
2388
+ trimBefore: trimBeforeField,
2389
+ playbackRate: playbackRateField,
2390
+ freeze: freezeField,
2391
+ hidden: hiddenField,
2392
+ name: sequenceNameField,
2393
+ showInTimeline: showInTimelineField
2394
+ };
2395
+ var baseSchemaWithoutPlaybackRate = {
2335
2396
  durationInFrames: durationInFramesField,
2336
2397
  from: fromField,
2337
2398
  trimBefore: trimBeforeField,
@@ -2355,6 +2416,7 @@ var sequenceSchema = {
2355
2416
  var baseSchemaWithoutFrom = {
2356
2417
  durationInFrames: durationInFramesField,
2357
2418
  trimBefore: trimBeforeField,
2419
+ playbackRate: playbackRateField,
2358
2420
  freeze: freezeField,
2359
2421
  hidden: hiddenField,
2360
2422
  name: sequenceNameField,
@@ -2431,7 +2493,7 @@ var validateSequenceCrop = (crop, componentName = "<Sequence />") => {
2431
2493
  };
2432
2494
 
2433
2495
  // src/SequenceManager.tsx
2434
- import React14, { useCallback as useCallback5, useMemo as useMemo10, useRef as useRef3, useState as useState4 } from "react";
2496
+ import React14, { useCallback as useCallback5, useMemo as useMemo11, useRef as useRef4, useState as useState4 } from "react";
2435
2497
  import { jsx as jsx10 } from "react/jsx-runtime";
2436
2498
  var useIsomorphicLayoutEffect = typeof window === "undefined" ? React14.useEffect : React14.useLayoutEffect;
2437
2499
  var SequenceManager = React14.createContext({
@@ -2489,17 +2551,17 @@ var effectDragOverridesKey = (nodePath, effectIndex) => `${makeSequencePropsSubs
2489
2551
  var SequenceManagerProvider = ({ children }) => {
2490
2552
  const { isStudio } = useRemotionEnvironment();
2491
2553
  const [sequenceManagerId] = useState4(() => String(Math.random()));
2492
- const committedOrderRef = useRef3(null);
2493
- const committedOrderIdsRef = useRef3(null);
2554
+ const committedOrderRef = useRef4(null);
2555
+ const committedOrderIdsRef = useRef4(null);
2494
2556
  const [sequences, setSequences] = useState4([]);
2495
- const sequencesRef = useRef3(sequences);
2557
+ const sequencesRef = useRef4(sequences);
2496
2558
  sequencesRef.current = sequences;
2497
2559
  const [dragOverrides, setControlOverrides] = useState4({});
2498
- const controlOverridesRef = useRef3(dragOverrides);
2560
+ const controlOverridesRef = useRef4(dragOverrides);
2499
2561
  controlOverridesRef.current = dragOverrides;
2500
2562
  const [effectDragOverridesState, setEffectDragOverridesState] = useState4({});
2501
2563
  const [propStatuses, setPropStatusesMapState] = useState4({});
2502
- const propStatusesRef = useRef3(propStatuses);
2564
+ const propStatusesRef = useRef4(propStatuses);
2503
2565
  propStatusesRef.current = propStatuses;
2504
2566
  const setDragOverrides = useCallback5((nodePath, key, value) => {
2505
2567
  setControlOverrides((prev) => ({
@@ -2642,7 +2704,7 @@ var SequenceManagerProvider = ({ children }) => {
2642
2704
  const unregisterSequence = useCallback5((seq) => {
2643
2705
  setSequences((seqs) => seqs.filter((s) => s.id !== seq));
2644
2706
  }, []);
2645
- const sequenceContext = useMemo10(() => {
2707
+ const sequenceContext = useMemo11(() => {
2646
2708
  return {
2647
2709
  registerSequence,
2648
2710
  sequences,
@@ -2656,18 +2718,18 @@ var SequenceManagerProvider = ({ children }) => {
2656
2718
  const getEffectDragOverrides = useCallback5((nodePath, effectIndex) => {
2657
2719
  return effectDragOverridesState[effectDragOverridesKey(nodePath, effectIndex)] ?? {};
2658
2720
  }, [effectDragOverridesState]);
2659
- const propStatusesContext = useMemo10(() => {
2721
+ const propStatusesContext = useMemo11(() => {
2660
2722
  return {
2661
2723
  propStatuses
2662
2724
  };
2663
2725
  }, [propStatuses]);
2664
- const dragOverridesContext = useMemo10(() => {
2726
+ const dragOverridesContext = useMemo11(() => {
2665
2727
  return {
2666
2728
  getDragOverrides,
2667
2729
  getEffectDragOverrides
2668
2730
  };
2669
2731
  }, [getDragOverrides, getEffectDragOverrides]);
2670
- const settersContext = useMemo10(() => {
2732
+ const settersContext = useMemo11(() => {
2671
2733
  return {
2672
2734
  setDragOverrides,
2673
2735
  clearDragOverrides,
@@ -2733,7 +2795,7 @@ var useRequireToBeInsideSeries = () => {
2733
2795
  };
2734
2796
 
2735
2797
  // src/use-premounting.ts
2736
- import { useContext as useContext16, useMemo as useMemo11 } from "react";
2798
+ import { useContext as useContext16, useMemo as useMemo12 } from "react";
2737
2799
 
2738
2800
  // src/PremountContext.tsx
2739
2801
  import { createContext as createContext15 } from "react";
@@ -2764,12 +2826,20 @@ var usePremounting = ({
2764
2826
  const { fps } = useVideoConfig();
2765
2827
  const effectivePremountFor = ENABLE_V5_BREAKING_CHANGES ? premountFor ?? fps : premountFor ?? 0;
2766
2828
  const effectivePostmountFor = postmountFor ?? 0;
2767
- const endThreshold = Math.ceil(from + durationInFrames - 1);
2768
- const premountingActive = !environment.isRendering && frame < from && frame >= from - effectivePremountFor;
2769
- const postmountingActive = !environment.isRendering && frame > endThreshold && frame <= endThreshold + effectivePostmountFor;
2829
+ const endExclusive = from + durationInFrames;
2830
+ const sequenceContext = useContext16(SequenceContext);
2831
+ const boundaryTolerance = getSequenceBoundaryTolerance({
2832
+ absoluteFrame: useTimelinePosition(),
2833
+ cumulatedFrom: sequenceContext ? sequenceContext.cumulatedFrom + sequenceContext.relativeFrom : 0,
2834
+ from,
2835
+ parentPlaybackRate: sequenceContext?.playbackRate ?? 1,
2836
+ durationInFrames
2837
+ });
2838
+ const premountingActive = !environment.isRendering && frame - from < -boundaryTolerance && frame - (from - effectivePremountFor) >= -boundaryTolerance;
2839
+ const postmountingActive = !environment.isRendering && frame - endExclusive >= -boundaryTolerance && frame - (endExclusive + effectivePostmountFor) < -boundaryTolerance;
2770
2840
  const isPremountingOrPostmounting = premountingActive || postmountingActive;
2771
2841
  const freezeFrame = premountingActive ? from : postmountingActive ? from + durationInFrames - 1 : 0;
2772
- const premountingStyle = useMemo11(() => {
2842
+ const premountingStyle = useMemo12(() => {
2773
2843
  if (!isPremountingOrPostmounting) {
2774
2844
  return style;
2775
2845
  }
@@ -2801,15 +2871,15 @@ var usePremounting = ({
2801
2871
  };
2802
2872
 
2803
2873
  // src/use-sequence-registration.ts
2804
- import { useContext as useContext17, useEffect as useEffect4, useRef as useRef4 } from "react";
2874
+ import { useContext as useContext17, useEffect as useEffect4, useRef as useRef5 } from "react";
2805
2875
  var useSequenceRegistration = ({
2806
2876
  getSequence,
2807
2877
  id
2808
2878
  }) => {
2809
2879
  const { registerSequence, unregisterSequence, updateSequence } = useContext17(SequenceManager);
2810
- const getSequenceRef = useRef4(getSequence);
2880
+ const getSequenceRef = useRef5(getSequence);
2811
2881
  getSequenceRef.current = getSequence;
2812
- const lastRegisteredGetterRef = useRef4(null);
2882
+ const lastRegisteredGetterRef = useRef5(null);
2813
2883
  const registrationEnabled = getSequence !== null;
2814
2884
  useEffect4(() => {
2815
2885
  if (!registrationEnabled) {
@@ -2841,7 +2911,7 @@ import React16, {
2841
2911
  forwardRef as forwardRef2,
2842
2912
  useContext as useContext19,
2843
2913
  useLayoutEffect as useLayoutEffect4,
2844
- useMemo as useMemo12,
2914
+ useMemo as useMemo13,
2845
2915
  useState as useState5
2846
2916
  } from "react";
2847
2917
 
@@ -2879,7 +2949,7 @@ var deleteNestedKey = (obj, keysToRemove) => {
2879
2949
  };
2880
2950
 
2881
2951
  // src/effects/use-memoized-effects.ts
2882
- import { useContext as useContext18, useLayoutEffect as useLayoutEffect3, useRef as useRef5 } from "react";
2952
+ import { useContext as useContext18, useLayoutEffect as useLayoutEffect3, useRef as useRef6 } from "react";
2883
2953
 
2884
2954
  // src/bezier.ts
2885
2955
  var NEWTON_ITERATIONS = 4;
@@ -3226,7 +3296,7 @@ var parseAxisRotationValue = (output) => {
3226
3296
  axisRotation: true
3227
3297
  };
3228
3298
  };
3229
- var parseStringInterpolationValue = (output) => {
3299
+ var parseStringInterpolationValue = (output, outputType) => {
3230
3300
  if (typeof output === "number") {
3231
3301
  if (!Number.isFinite(output)) {
3232
3302
  throw new Error(`outputRange must contain only finite numbers, but got [${output}]`);
@@ -3239,8 +3309,18 @@ var parseStringInterpolationValue = (output) => {
3239
3309
  axisRotation: false
3240
3310
  };
3241
3311
  }
3312
+ if (outputType === "transform-origin") {
3313
+ const transformOriginParts = output.trim().split(/\s+/);
3314
+ if (transformOriginParts.length < 1 || transformOriginParts.length > 3 || transformOriginParts[0] === "") {
3315
+ throw new TypeError(`String outputRange values must contain 1 to 3 components, but got "${output}"`);
3316
+ }
3317
+ return parseTransformOriginValue(output, transformOriginParts);
3318
+ }
3242
3319
  const axisRotation = parseAxisRotationValue(output);
3243
3320
  if (axisRotation !== null) {
3321
+ if (outputType !== undefined && outputType !== "rotate") {
3322
+ throw new TypeError(`Cannot interpolate "${output}" as ${outputType} because it is a rotate value`);
3323
+ }
3244
3324
  return axisRotation;
3245
3325
  }
3246
3326
  const parts = output.trim().split(/\s+/);
@@ -3248,6 +3328,9 @@ var parseStringInterpolationValue = (output) => {
3248
3328
  throw new TypeError(`String outputRange values must contain 1 to 3 components, but got "${output}"`);
3249
3329
  }
3250
3330
  if (parts.some((part) => transformOriginKeywords.has(part.toLowerCase()))) {
3331
+ if (outputType !== undefined) {
3332
+ throw new TypeError(`Cannot interpolate "${output}" as ${outputType} because it is a transform-origin value`);
3333
+ }
3251
3334
  return parseTransformOriginValue(output, parts);
3252
3335
  }
3253
3336
  const parsed = parts.map((part) => parseStringInterpolationComponent(part, output));
@@ -3257,6 +3340,9 @@ var parseStringInterpolationValue = (output) => {
3257
3340
  throw new TypeError(`Cannot interpolate "${output}" because it mixes ${kind} and ${part.kind} values`);
3258
3341
  }
3259
3342
  }
3343
+ if (outputType !== undefined && outputType !== kind) {
3344
+ throw new TypeError(`Cannot interpolate "${output}" as ${outputType} because it is a ${kind} value`);
3345
+ }
3260
3346
  if (kind === "scale") {
3261
3347
  const x = parsed[0].value;
3262
3348
  const y = parsed[1]?.value ?? x;
@@ -3457,9 +3543,10 @@ var interpolateString = ({
3457
3543
  input,
3458
3544
  inputRange,
3459
3545
  outputRange,
3460
- options
3546
+ options,
3547
+ outputType
3461
3548
  }) => {
3462
- const initiallyParsedOutputRange = outputRange.map(parseStringInterpolationValue);
3549
+ const initiallyParsedOutputRange = outputRange.map((output) => parseStringInterpolationValue(output, outputType));
3463
3550
  const hasAxisRotation = initiallyParsedOutputRange.some((parsed) => parsed.axisRotation);
3464
3551
  const posterizedInput = options?.posterize === undefined ? input : Math.floor(input / options.posterize) * options.posterize;
3465
3552
  const segmentIndex = inputRange.length === 1 ? 0 : findRange(posterizedInput, inputRange);
@@ -3539,6 +3626,36 @@ var interpolateString = ({
3539
3626
  axisRotation: hasAxisRotation
3540
3627
  });
3541
3628
  };
3629
+ var interpolateFontWeight = ({
3630
+ input,
3631
+ inputRange,
3632
+ outputRange,
3633
+ options
3634
+ }) => {
3635
+ const normalizedOutputRange = outputRange.map((output) => {
3636
+ if (typeof output === "string") {
3637
+ const lowerCaseOutput = output.toLowerCase();
3638
+ if (lowerCaseOutput === "normal") {
3639
+ return 400;
3640
+ }
3641
+ if (lowerCaseOutput === "bold") {
3642
+ return 700;
3643
+ }
3644
+ }
3645
+ const match = typeof output === "string" ? cssNumberRegex.exec(output) : null;
3646
+ const value = typeof output === "number" ? output : match !== null && match[2] === undefined ? Number(match[1]) : Number.NaN;
3647
+ if (!Number.isFinite(value) || value < 1 || value > 1000) {
3648
+ throw new TypeError(`Cannot interpolate font weight "${output}". Expected "normal", "bold", or a number between 1 and 1000`);
3649
+ }
3650
+ return value;
3651
+ });
3652
+ return interpolateNumber({
3653
+ input,
3654
+ inputRange,
3655
+ outputRange: normalizedOutputRange,
3656
+ options
3657
+ });
3658
+ };
3542
3659
  var interpolateDiscreteString = ({
3543
3660
  input,
3544
3661
  inputRange,
@@ -3670,6 +3787,12 @@ function assertValidInterpolateOutputOption(output) {
3670
3787
  }
3671
3788
  throw new Error(`output must be "linear" or "perceptual-scale", but got ${String(output)}`);
3672
3789
  }
3790
+ function assertValidInterpolateOutputType(outputType) {
3791
+ if (outputType === undefined || outputType === "font-weight" || outputType === "scale" || outputType === "translate" || outputType === "rotate" || outputType === "transform-origin") {
3792
+ return;
3793
+ }
3794
+ throw new Error(`outputType must be "font-weight", "scale", "translate", "rotate", or "transform-origin", but got ${String(outputType)}`);
3795
+ }
3673
3796
  function interpolate(input, inputRange, outputRange, options) {
3674
3797
  if (typeof input === "undefined") {
3675
3798
  throw new Error("input can not be undefined");
@@ -3688,26 +3811,48 @@ function interpolate(input, inputRange, outputRange, options) {
3688
3811
  assertValidInterpolateEasingOption(options?.easing, inputRange.length);
3689
3812
  assertValidInterpolatePosterizeOption(options?.posterize);
3690
3813
  assertValidInterpolateOutputOption(options?.output);
3814
+ assertValidInterpolateOutputType(options?.outputType);
3691
3815
  if (typeof input !== "number") {
3692
3816
  throw new TypeError("Cannot interpolate an input which is not a number");
3693
3817
  }
3694
3818
  if (!Array.isArray(outputRange)) {
3695
3819
  throw new Error("outputRange must contain only numbers");
3696
3820
  }
3821
+ const outputType = options?.outputType;
3822
+ if (outputType === "font-weight") {
3823
+ if (!outputRange.every((output) => typeof output === "number" || typeof output === "string")) {
3824
+ throw new TypeError("Font weight outputRange must contain only numbers or strings");
3825
+ }
3826
+ return interpolateFontWeight({
3827
+ input,
3828
+ inputRange,
3829
+ outputRange,
3830
+ options
3831
+ });
3832
+ }
3697
3833
  const hasStringOutput = outputRange.some((output) => typeof output === "string");
3834
+ if (outputType !== undefined && outputType !== "scale" && !hasStringOutput) {
3835
+ throw new TypeError(`${outputType} outputRange must contain strings with the appropriate CSS units`);
3836
+ }
3698
3837
  if (hasStringOutput) {
3699
3838
  if (!outputRange.every((output) => typeof output === "string" || typeof output === "number")) {
3700
3839
  throw new TypeError("outputRange must contain only numbers, or supported scale, translate, and rotate strings");
3701
3840
  }
3702
3841
  try {
3703
- return interpolateString({ input, inputRange, outputRange, options });
3842
+ return interpolateString({
3843
+ input,
3844
+ inputRange,
3845
+ outputRange,
3846
+ options,
3847
+ outputType
3848
+ });
3704
3849
  } catch (error2) {
3705
3850
  if (!outputRange.every((output) => typeof output === "string")) {
3706
3851
  throw error2;
3707
3852
  }
3708
3853
  const hasNonNumericString = outputRange.some((output) => {
3709
3854
  try {
3710
- parseStringInterpolationValue(output);
3855
+ parseStringInterpolationValue(output, outputType);
3711
3856
  return false;
3712
3857
  } catch (parseError) {
3713
3858
  return parseError instanceof UnsupportedStringInterpolationValueError;
@@ -3846,13 +3991,19 @@ function springCalculation({
3846
3991
  }) {
3847
3992
  const from = 0;
3848
3993
  const to = 1;
3994
+ const resolvedConfig = {
3995
+ damping: config.damping ?? defaultSpringConfig.damping,
3996
+ mass: config.mass ?? defaultSpringConfig.mass,
3997
+ stiffness: config.stiffness ?? defaultSpringConfig.stiffness,
3998
+ overshootClamping: config.overshootClamping ?? defaultSpringConfig.overshootClamping
3999
+ };
3849
4000
  const cacheKey = [
3850
4001
  frame,
3851
4002
  fps,
3852
- config.damping,
3853
- config.mass,
3854
- config.overshootClamping,
3855
- config.stiffness
4003
+ resolvedConfig.damping,
4004
+ resolvedConfig.mass,
4005
+ resolvedConfig.overshootClamping,
4006
+ resolvedConfig.stiffness
3856
4007
  ].join("-");
3857
4008
  if (calculationCache[cacheKey]) {
3858
4009
  return calculationCache[cacheKey];
@@ -3871,20 +4022,14 @@ function springCalculation({
3871
4022
  animation = advance({
3872
4023
  animation,
3873
4024
  now: time,
3874
- config: {
3875
- ...defaultSpringConfig,
3876
- ...config
3877
- }
4025
+ config: resolvedConfig
3878
4026
  });
3879
4027
  }
3880
4028
  if (unevenRest > 0) {
3881
4029
  animation = advance({
3882
4030
  animation,
3883
4031
  now: frameClamped / fps * 1000,
3884
- config: {
3885
- ...defaultSpringConfig,
3886
- ...config
3887
- }
4032
+ config: resolvedConfig
3888
4033
  });
3889
4034
  }
3890
4035
  calculationCache[cacheKey] = animation;
@@ -4823,7 +4968,7 @@ var resolvePropStatusOverrides = (propStatus, frame) => {
4823
4968
  return hasAny ? out : null;
4824
4969
  };
4825
4970
  var useMemoizedEffectDefinitions = (effects) => {
4826
- const previousRef = useRef5(null);
4971
+ const previousRef = useRef6(null);
4827
4972
  const definitions = effects.map((descriptor) => descriptor.definition);
4828
4973
  const previous = previousRef.current;
4829
4974
  const isSame = previous !== null && previous.definitions.length === definitions.length && previous.definitions.every((definition, i) => definition === definitions[i]);
@@ -4875,7 +5020,7 @@ var useMemoizedEffects = ({
4875
5020
  effects,
4876
5021
  overrideId
4877
5022
  }) => {
4878
- const previousRef = useRef5(null);
5023
+ const previousRef = useRef6(null);
4879
5024
  const { propStatuses } = useContext18(VisualModePropStatusesContext);
4880
5025
  const { getEffectDragOverrides } = useContext18(VisualModeDragOverridesContext);
4881
5026
  const frame = useCurrentFrame();
@@ -5252,7 +5397,7 @@ var withInteractivitySchema = ({
5252
5397
  const fps = videoConfig?.fps;
5253
5398
  const height = videoConfig?.height;
5254
5399
  const width = videoConfig?.width;
5255
- const videoConfigValues = useMemo12(() => durationInFrames === undefined || fps === undefined || height === undefined || width === undefined ? null : {
5400
+ const videoConfigValues = useMemo13(() => durationInFrames === undefined || fps === undefined || height === undefined || width === undefined ? null : {
5256
5401
  durationInFrames,
5257
5402
  fps,
5258
5403
  height,
@@ -5286,12 +5431,12 @@ var withInteractivitySchema = ({
5286
5431
  key,
5287
5432
  props: cleanProps
5288
5433
  }));
5289
- const currentRuntimeValueDotNotation = useMemo12(() => readValuesFromProps(cleanProps, flatKeys, flatSchema), runtimeValues);
5434
+ const currentRuntimeValueDotNotation = useMemo13(() => readValuesFromProps(cleanProps, flatKeys, flatSchema), runtimeValues);
5290
5435
  const [runtimeValueStore] = useState5(() => createRuntimeValueStore(currentRuntimeValueDotNotation));
5291
5436
  useLayoutEffect4(() => {
5292
5437
  runtimeValueStore.setSnapshot(currentRuntimeValueDotNotation);
5293
5438
  }, [currentRuntimeValueDotNotation, runtimeValueStore]);
5294
- const controls = useMemo12(() => {
5439
+ const controls = useMemo13(() => {
5295
5440
  return {
5296
5441
  schema: schemaWithSequenceName,
5297
5442
  currentRuntimeValueDotNotation,
@@ -5309,7 +5454,7 @@ var withInteractivitySchema = ({
5309
5454
  videoConfigValues
5310
5455
  ]);
5311
5456
  setStackForControls(controls, internalStack);
5312
- const { merged: valuesDotNotation, propsToDelete } = useMemo12(() => {
5457
+ const { merged: valuesDotNotation, propsToDelete } = useMemo13(() => {
5313
5458
  return computeEffectiveSchemaValuesDotNotation({
5314
5459
  schema: schemaWithSequenceName,
5315
5460
  currentValue: currentRuntimeValueDotNotation,
@@ -5348,6 +5493,7 @@ var EMPTY_EFFECTS = [];
5348
5493
  var RegularSequenceRefForwardingFunction = ({
5349
5494
  from = 0,
5350
5495
  trimBefore = 0,
5496
+ playbackRate = 1,
5351
5497
  freeze,
5352
5498
  durationInFrames = Infinity,
5353
5499
  children,
@@ -5375,6 +5521,8 @@ var RegularSequenceRefForwardingFunction = ({
5375
5521
  const { layout = "absolute-fill" } = other;
5376
5522
  const [id] = useState6(() => String(Math.random()));
5377
5523
  const parentSequence = useContext20(SequenceContext);
5524
+ const parentPlaybackRate = parentSequence?.playbackRate ?? 1;
5525
+ const cumulativePlaybackRate = parentPlaybackRate * playbackRate;
5378
5526
  const cumulatedFrom = parentSequence ? parentSequence.cumulatedFrom + parentSequence.relativeFrom : 0;
5379
5527
  if (layout !== "absolute-fill" && layout !== "none") {
5380
5528
  throw new TypeError(`The layout prop of <Sequence /> expects either "absolute-fill" or "none", but you passed: ${layout}`);
@@ -5430,32 +5578,42 @@ var RegularSequenceRefForwardingFunction = ({
5430
5578
  }
5431
5579
  }
5432
5580
  const absoluteFrame = useTimelinePosition();
5581
+ const lastPlaybackRate = useRef7({ playbackRate, frame: absoluteFrame });
5582
+ if (typeof playbackRate !== "number" || !Number.isFinite(playbackRate) || playbackRate <= 0) {
5583
+ throw new TypeError(`The "playbackRate" prop of <Sequence /> must be a positive finite number, but got ${playbackRate}.`);
5584
+ }
5585
+ if (lastPlaybackRate.current.frame !== absoluteFrame && lastPlaybackRate.current.playbackRate !== playbackRate) {
5586
+ throw new Error('The "playbackRate" prop of <Sequence /> must be constant. Animating playbackRate is not supported.');
5587
+ }
5588
+ lastPlaybackRate.current = { playbackRate, frame: absoluteFrame };
5433
5589
  const videoConfig = useVideoConfig();
5434
- const effectiveRelativeFrom = from - trimBefore;
5435
- const absoluteFrom = (parentSequence?.absoluteFrom ?? 0) + effectiveRelativeFrom;
5590
+ const effectiveRelativeFrom = from - trimBefore / playbackRate;
5591
+ const relativeFrom = effectiveRelativeFrom / parentPlaybackRate;
5592
+ const absoluteFrom = (parentSequence?.absoluteFrom ?? 0) + relativeFrom;
5436
5593
  const parentSequenceDuration = parentSequence ? Math.min(parentSequence.durationInFrames - effectiveRelativeFrom, durationInFrames) : durationInFrames;
5437
5594
  const actualDurationInFrames = Math.max(0, Math.min(videoConfig.durationInFrames - from, parentSequenceDuration));
5438
5595
  const sequenceRegistrationEnabled = useContext20(SequenceRegistrationContext);
5439
- const wrapperRefForOutline = useRef6(null);
5596
+ const wrapperRefForOutline = useRef7(null);
5440
5597
  const refForOutline = other.layout === "none" ? passedRefForOutline ?? null : passedRefForOutline ?? wrapperRefForOutline;
5441
- const premounting = useMemo13(() => {
5598
+ const premounting = useMemo14(() => {
5442
5599
  return parentSequence?.premounting || Boolean(other._remotionInternalIsPremounting);
5443
5600
  }, [other._remotionInternalIsPremounting, parentSequence?.premounting]);
5444
- const postmounting = useMemo13(() => {
5601
+ const postmounting = useMemo14(() => {
5445
5602
  return parentSequence?.postmounting || Boolean(other._remotionInternalIsPostmounting);
5446
5603
  }, [other._remotionInternalIsPostmounting, parentSequence?.postmounting]);
5447
- const currentSequenceStart = cumulatedFrom + effectiveRelativeFrom;
5604
+ const currentSequenceStart = cumulatedFrom + relativeFrom;
5448
5605
  const parentSequenceStart = parentSequence ? parentSequence.cumulatedFrom + parentSequence.relativeFrom : 0;
5449
- const parentFirstFrame = parentSequence ? parentSequenceStart - parentSequence.cumulatedNegativeFrom : 0;
5450
- const firstFrame = Math.max(0, parentFirstFrame, currentSequenceStart);
5451
- const cumulatedNegativeFrom = currentSequenceStart - firstFrame;
5452
- const contextValue = useMemo13(() => {
5606
+ const parentFirstFrame = parentSequence ? parentSequenceStart - parentSequence.cumulatedNegativeFrom / parentPlaybackRate : 0;
5607
+ const firstFrame = Math.max(0, parentFirstFrame, cumulatedFrom + from / parentPlaybackRate);
5608
+ const cumulatedNegativeFrom = (currentSequenceStart - firstFrame) * cumulativePlaybackRate;
5609
+ const contextValue = useMemo14(() => {
5453
5610
  return {
5611
+ playbackRate: cumulativePlaybackRate,
5454
5612
  absoluteFrom,
5455
5613
  cumulatedFrom,
5456
- relativeFrom: effectiveRelativeFrom,
5614
+ relativeFrom,
5457
5615
  cumulatedNegativeFrom,
5458
- durationInFrames: actualDurationInFrames,
5616
+ durationInFrames: actualDurationInFrames * playbackRate + trimBefore,
5459
5617
  parentFrom: parentSequence?.relativeFrom ?? 0,
5460
5618
  id,
5461
5619
  height: height ?? parentSequence?.height ?? null,
@@ -5468,7 +5626,10 @@ var RegularSequenceRefForwardingFunction = ({
5468
5626
  }, [
5469
5627
  cumulatedFrom,
5470
5628
  absoluteFrom,
5471
- effectiveRelativeFrom,
5629
+ relativeFrom,
5630
+ cumulativePlaybackRate,
5631
+ playbackRate,
5632
+ trimBefore,
5472
5633
  actualDurationInFrames,
5473
5634
  parentSequence,
5474
5635
  id,
@@ -5480,13 +5641,13 @@ var RegularSequenceRefForwardingFunction = ({
5480
5641
  postmountDisplay,
5481
5642
  cumulatedNegativeFrom
5482
5643
  ]);
5483
- const timelineClipName = useMemo13(() => {
5644
+ const timelineClipName = useMemo14(() => {
5484
5645
  return name ?? "";
5485
5646
  }, [name]);
5486
5647
  const resolvedDocumentationLink = documentationLink ?? "https://www.remotion.dev/docs/sequence";
5487
5648
  const env = useRemotionEnvironment();
5488
5649
  const isInsideSeries = useContext20(IsInsideSeriesContext);
5489
- const stackRef = useRef6(null);
5650
+ const stackRef = useRef7(null);
5490
5651
  stackRef.current = controls ? getStackForControls(controls) ?? stack ?? null : stack ?? null;
5491
5652
  const registeredFrozenFrame = typeof freeze === "number" ? freeze : null;
5492
5653
  const registeredTrimBefore = trimBefore === 0 ? null : trimBefore;
@@ -5501,8 +5662,8 @@ var RegularSequenceRefForwardingFunction = ({
5501
5662
  const controlsComponentIdentity = controls?.componentIdentity;
5502
5663
  const controlsComponentName = controls?.componentName;
5503
5664
  const controlsVideoConfigValues = controls?.videoConfigValues;
5504
- const effectRuntimeValues = useMemo13(() => _remotionInternalEffects?.runtimeValues ?? null, [_remotionInternalEffects]);
5505
- const registrationControls = useMemo13(() => {
5665
+ const effectRuntimeValues = useMemo14(() => _remotionInternalEffects?.runtimeValues ?? null, [_remotionInternalEffects]);
5666
+ const registrationControls = useMemo14(() => {
5506
5667
  if (controlsSchema === undefined || controlsRuntimeValues === undefined || controlsOverrideId === undefined || controlsSupportsEffects === undefined || controlsComponentIdentity === undefined || controlsComponentName === undefined || controlsVideoConfigValues === undefined) {
5507
5668
  return null;
5508
5669
  }
@@ -5528,6 +5689,7 @@ var RegularSequenceRefForwardingFunction = ({
5528
5689
  if (isMedia) {
5529
5690
  if (isMedia.type === "image") {
5530
5691
  return {
5692
+ sequencePlaybackRate: playbackRate,
5531
5693
  type: "image",
5532
5694
  controls: registrationControls,
5533
5695
  effects: _remotionInternalEffects ?? EMPTY_EFFECTS,
@@ -5554,6 +5716,7 @@ var RegularSequenceRefForwardingFunction = ({
5554
5716
  }
5555
5717
  return {
5556
5718
  type: isMedia.type,
5719
+ sequencePlaybackRate: playbackRate,
5557
5720
  controls: registrationControls,
5558
5721
  effects: _remotionInternalEffects ?? EMPTY_EFFECTS,
5559
5722
  effectRuntimeValues,
@@ -5586,6 +5749,7 @@ var RegularSequenceRefForwardingFunction = ({
5586
5749
  }
5587
5750
  return {
5588
5751
  from,
5752
+ sequencePlaybackRate: playbackRate,
5589
5753
  trimBefore: registeredTrimBefore,
5590
5754
  duration: actualDurationInFrames,
5591
5755
  id,
@@ -5610,6 +5774,7 @@ var RegularSequenceRefForwardingFunction = ({
5610
5774
  }, [
5611
5775
  id,
5612
5776
  timelineClipName,
5777
+ playbackRate,
5613
5778
  parentSequence?.id,
5614
5779
  actualDurationInFrames,
5615
5780
  from,
@@ -5635,8 +5800,16 @@ var RegularSequenceRefForwardingFunction = ({
5635
5800
  getSequence: env.isStudio || sequenceRegistrationEnabled ? getSequenceForRegistration : null,
5636
5801
  id
5637
5802
  });
5638
- const endThreshold = Math.ceil(cumulatedFrom + from + durationInFrames - 1);
5639
- const content2 = absoluteFrame < cumulatedFrom + from ? null : absoluteFrame > endThreshold ? null : children;
5803
+ const frameInParent = (absoluteFrame - cumulatedFrom) * parentPlaybackRate;
5804
+ const endThreshold = from + durationInFrames;
5805
+ const boundaryTolerance = getSequenceBoundaryTolerance({
5806
+ absoluteFrame,
5807
+ cumulatedFrom,
5808
+ from,
5809
+ parentPlaybackRate,
5810
+ durationInFrames
5811
+ });
5812
+ const content2 = frameInParent - from < -boundaryTolerance ? null : frameInParent - endThreshold >= -boundaryTolerance ? null : children;
5640
5813
  const frozenContent = content2 === null || typeof freeze === "undefined" || freeze === null ? content2 : /* @__PURE__ */ jsx12(Freeze, {
5641
5814
  frame: freeze,
5642
5815
  children: content2
@@ -5657,7 +5830,7 @@ var RegularSequenceRefForwardingFunction = ({
5657
5830
  ref.current = node;
5658
5831
  }
5659
5832
  }, [ref]);
5660
- const defaultStyle = useMemo13(() => {
5833
+ const defaultStyle = useMemo14(() => {
5661
5834
  return {
5662
5835
  flexDirection: undefined,
5663
5836
  ...width ? { width } : {},
@@ -5775,10 +5948,11 @@ var SequenceWithoutFrom = withInteractivitySchema({
5775
5948
  });
5776
5949
 
5777
5950
  // src/AbsoluteFill.tsx
5778
- import { useCallback as useCallback7, useRef as useRef7 } from "react";
5951
+ import { useCallback as useCallback7, useRef as useRef8 } from "react";
5779
5952
  import { jsx as jsx13 } from "react/jsx-runtime";
5780
5953
  var absoluteFillSchema = {
5781
5954
  ...baseSchema,
5955
+ ...premountSchema,
5782
5956
  ...transformSchema,
5783
5957
  ...backgroundSchema,
5784
5958
  ...borderSchema,
@@ -5793,10 +5967,83 @@ var setRef = (ref, value) => {
5793
5967
  ref.current = value;
5794
5968
  }
5795
5969
  };
5970
+ var AbsoluteFillWithTiming = ({
5971
+ ref: callbackRef,
5972
+ outlineRef: refForOutline,
5973
+ from,
5974
+ premountFor,
5975
+ postmountFor,
5976
+ styleWhilePremounted,
5977
+ styleWhilePostmounted,
5978
+ trimBefore,
5979
+ playbackRate,
5980
+ freeze,
5981
+ durationInFrames,
5982
+ hidden,
5983
+ name,
5984
+ showInTimeline,
5985
+ stack,
5986
+ controls,
5987
+ children,
5988
+ ...divProps
5989
+ }) => {
5990
+ const {
5991
+ effectivePremountFor,
5992
+ effectivePostmountFor,
5993
+ freezeFrame,
5994
+ isPremountingOrPostmounting,
5995
+ premountingActive,
5996
+ postmountingActive,
5997
+ premountingStyle
5998
+ } = usePremounting({
5999
+ from: from ?? 0,
6000
+ durationInFrames: durationInFrames ?? Infinity,
6001
+ premountFor: premountFor ?? null,
6002
+ postmountFor: postmountFor ?? null,
6003
+ style: divProps.style ?? null,
6004
+ styleWhilePremounted: styleWhilePremounted ?? null,
6005
+ styleWhilePostmounted: styleWhilePostmounted ?? null,
6006
+ hideWhilePremounted: "opacity"
6007
+ });
6008
+ return /* @__PURE__ */ jsx13(Freeze, {
6009
+ frame: freezeFrame,
6010
+ active: isPremountingOrPostmounting,
6011
+ children: /* @__PURE__ */ jsx13(Sequence, {
6012
+ layout: "none",
6013
+ from: from ?? 0,
6014
+ trimBefore,
6015
+ playbackRate,
6016
+ freeze,
6017
+ durationInFrames: durationInFrames ?? Infinity,
6018
+ hidden,
6019
+ name: name ?? "<AbsoluteFill>",
6020
+ showInTimeline: showInTimeline ?? true,
6021
+ controls,
6022
+ _remotionInternalStack: stack,
6023
+ _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/absolute-fill",
6024
+ outlineRef: refForOutline,
6025
+ _remotionInternalPremountDisplay: effectivePremountFor || null,
6026
+ _remotionInternalPostmountDisplay: effectivePostmountFor || null,
6027
+ _remotionInternalIsPremounting: premountingActive,
6028
+ _remotionInternalIsPostmounting: postmountingActive,
6029
+ children: /* @__PURE__ */ jsx13(AbsoluteFillElement, {
6030
+ ref: callbackRef,
6031
+ ...divProps,
6032
+ style: premountingStyle ?? undefined,
6033
+ children
6034
+ })
6035
+ })
6036
+ });
6037
+ };
5796
6038
  var AbsoluteFillInner = ({
5797
6039
  ref,
5798
6040
  from,
6041
+ premountFor,
6042
+ postmountFor,
6043
+ styleWhilePremounted,
6044
+ styleWhilePostmounted,
5799
6045
  trimBefore,
6046
+ playbackRate,
5800
6047
  freeze,
5801
6048
  durationInFrames,
5802
6049
  hidden,
@@ -5808,7 +6055,7 @@ var AbsoluteFillInner = ({
5808
6055
  ...divProps
5809
6056
  }) => {
5810
6057
  const videoConfig = useUnsafeVideoConfig();
5811
- const refForOutline = useRef7(null);
6058
+ const refForOutline = useRef8(null);
5812
6059
  const callbackRef = useCallback7((element) => {
5813
6060
  refForOutline.current = element;
5814
6061
  setRef(ref, element);
@@ -5820,24 +6067,25 @@ var AbsoluteFillInner = ({
5820
6067
  children
5821
6068
  });
5822
6069
  }
5823
- return /* @__PURE__ */ jsx13(Sequence, {
5824
- layout: "none",
5825
- from: from ?? 0,
6070
+ return /* @__PURE__ */ jsx13(AbsoluteFillWithTiming, {
6071
+ ...divProps,
6072
+ ref: callbackRef,
6073
+ outlineRef: refForOutline,
6074
+ from,
6075
+ premountFor,
6076
+ postmountFor,
6077
+ styleWhilePremounted,
6078
+ styleWhilePostmounted,
5826
6079
  trimBefore,
6080
+ playbackRate,
5827
6081
  freeze,
5828
- durationInFrames: durationInFrames ?? Infinity,
6082
+ durationInFrames,
5829
6083
  hidden,
5830
- name: name ?? "<AbsoluteFill>",
5831
- showInTimeline: showInTimeline ?? true,
6084
+ name,
6085
+ showInTimeline,
6086
+ stack,
5832
6087
  controls,
5833
- _remotionInternalStack: stack,
5834
- _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/absolute-fill",
5835
- outlineRef: refForOutline,
5836
- children: /* @__PURE__ */ jsx13(AbsoluteFillElement, {
5837
- ref: callbackRef,
5838
- ...divProps,
5839
- children
5840
- })
6088
+ children
5841
6089
  });
5842
6090
  };
5843
6091
  var AbsoluteFill = withInteractivitySchema({
@@ -5854,12 +6102,12 @@ import {
5854
6102
  useEffect as useEffect6,
5855
6103
  useImperativeHandle as useImperativeHandle2,
5856
6104
  useLayoutEffect as useLayoutEffect5,
5857
- useRef as useRef10,
6105
+ useRef as useRef11,
5858
6106
  useState as useState7
5859
6107
  } from "react";
5860
6108
 
5861
6109
  // src/use-crop-style.ts
5862
- import { useMemo as useMemo14 } from "react";
6110
+ import { useMemo as useMemo15 } from "react";
5863
6111
  var useCropStyle = ({
5864
6112
  cropLeft,
5865
6113
  cropRight,
@@ -5869,7 +6117,7 @@ var useCropStyle = ({
5869
6117
  componentName
5870
6118
  }) => {
5871
6119
  validateSequenceCrop({ cropLeft, cropRight, cropTop, cropBottom }, componentName);
5872
- return useMemo14(() => {
6120
+ return useMemo15(() => {
5873
6121
  const cropClipPath = getSequenceCropClipPath({
5874
6122
  ...resolveSequenceCrop({ cropLeft, cropRight, cropTop, cropBottom }),
5875
6123
  style
@@ -5882,7 +6130,7 @@ var useCropStyle = ({
5882
6130
  };
5883
6131
 
5884
6132
  // src/animated-image/canvas.tsx
5885
- import React19, { useCallback as useCallback8, useImperativeHandle, useMemo as useMemo16, useRef as useRef9 } from "react";
6133
+ import React19, { useCallback as useCallback8, useImperativeHandle, useMemo as useMemo17, useRef as useRef10 } from "react";
5886
6134
 
5887
6135
  // src/calculate-image-fit.ts
5888
6136
  var calculateImageFit = (fit, imageSize, canvasSize) => {
@@ -6178,10 +6426,10 @@ var runEffectChain = async ({
6178
6426
  };
6179
6427
 
6180
6428
  // src/effects/use-effect-chain-state.ts
6181
- import { useEffect as useEffect5, useMemo as useMemo15, useRef as useRef8 } from "react";
6429
+ import { useEffect as useEffect5, useMemo as useMemo16, useRef as useRef9 } from "react";
6182
6430
  var useEffectChainState = () => {
6183
- const chainStateRef = useRef8(null);
6184
- const sizeRef = useRef8(null);
6431
+ const chainStateRef = useRef9(null);
6432
+ const sizeRef = useRef9(null);
6185
6433
  useEffect5(() => {
6186
6434
  return () => {
6187
6435
  if (chainStateRef.current) {
@@ -6189,7 +6437,7 @@ var useEffectChainState = () => {
6189
6437
  }
6190
6438
  };
6191
6439
  }, []);
6192
- return useMemo15(() => ({
6440
+ return useMemo16(() => ({
6193
6441
  get: (width, height) => {
6194
6442
  if (!sizeRef.current || sizeRef.current.width !== width || sizeRef.current.height !== height) {
6195
6443
  if (chainStateRef.current) {
@@ -6206,9 +6454,9 @@ var useEffectChainState = () => {
6206
6454
  // src/animated-image/canvas.tsx
6207
6455
  import { jsx as jsx14 } from "react/jsx-runtime";
6208
6456
  var CanvasRefForwardingFunction = ({ width, height, fit, className, style, effects, ...props }, ref) => {
6209
- const canvasRef = useRef9(null);
6457
+ const canvasRef = useRef10(null);
6210
6458
  const chainState = useEffectChainState();
6211
- const sourceCanvas = useMemo16(() => {
6459
+ const sourceCanvas = useMemo17(() => {
6212
6460
  if (typeof document === "undefined") {
6213
6461
  return null;
6214
6462
  }
@@ -6486,16 +6734,6 @@ var animatedImageSchema = {
6486
6734
  ...baseSchema,
6487
6735
  ...cropSchema,
6488
6736
  ...premountSchema,
6489
- playbackRate: {
6490
- type: "number",
6491
- min: 0,
6492
- max: 10,
6493
- step: 0.1,
6494
- default: 1,
6495
- description: "Playback rate",
6496
- hiddenFromList: false,
6497
- keyframable: false
6498
- },
6499
6737
  ...transformSchema,
6500
6738
  ...backgroundSchema,
6501
6739
  ...borderSchema,
@@ -6531,12 +6769,12 @@ var AnimatedImageContent = forwardRef4(({
6531
6769
  const frame = useCurrentFrame();
6532
6770
  const { fps } = useVideoConfig();
6533
6771
  const currentTime = getCurrentTime({ frame, playbackRate, fps });
6534
- const currentTimeRef = useRef10(currentTime);
6772
+ const currentTimeRef = useRef11(currentTime);
6535
6773
  currentTimeRef.current = currentTime;
6536
6774
  const requestInitKey = serializeRequestInit(requestInit);
6537
- const requestInitRef = useRef10(requestInit);
6775
+ const requestInitRef = useRef11(requestInit);
6538
6776
  requestInitRef.current = requestInit;
6539
- const ref = useRef10(null);
6777
+ const ref = useRef11(null);
6540
6778
  const memoizedEffects = useMemoizedEffects({
6541
6779
  effects,
6542
6780
  overrideId: controls?.overrideId ?? null
@@ -6690,7 +6928,7 @@ var AnimatedImageInner = ({
6690
6928
  ref,
6691
6929
  ...sequenceProps
6692
6930
  }) => {
6693
- const actualRef = useRef10(null);
6931
+ const actualRef = useRef11(null);
6694
6932
  const memoizedEffectDefinitions = useMemoizedEffectDefinitions(effects);
6695
6933
  useImperativeHandle2(ref, () => {
6696
6934
  return actualRef.current;
@@ -6728,7 +6966,6 @@ var AnimatedImageInner = ({
6728
6966
  height,
6729
6967
  onError,
6730
6968
  fit,
6731
- playbackRate,
6732
6969
  loopBehavior,
6733
6970
  id,
6734
6971
  className,
@@ -6742,6 +6979,7 @@ var AnimatedImageInner = ({
6742
6979
  children: /* @__PURE__ */ jsx15(Sequence, {
6743
6980
  layout: "none",
6744
6981
  from: from ?? 0,
6982
+ playbackRate,
6745
6983
  durationInFrames: durationInFrames ?? Infinity,
6746
6984
  name: "<AnimatedImage>",
6747
6985
  _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/animatedimage",
@@ -6811,8 +7049,8 @@ import {
6811
7049
  useCallback as useCallback9,
6812
7050
  useImperativeHandle as useImperativeHandle3,
6813
7051
  useLayoutEffect as useLayoutEffect6,
6814
- useMemo as useMemo17,
6815
- useRef as useRef11,
7052
+ useMemo as useMemo18,
7053
+ useRef as useRef12,
6816
7054
  useState as useState8
6817
7055
  } from "react";
6818
7056
 
@@ -6860,7 +7098,7 @@ var RenderAssetManager = createContext18({
6860
7098
  });
6861
7099
  var RenderAssetManagerProvider = ({ children, collectAssets }) => {
6862
7100
  const [renderAssets, setRenderAssets] = useState8([]);
6863
- const renderAssetsRef = useRef11([]);
7101
+ const renderAssetsRef = useRef12([]);
6864
7102
  const registerRenderAsset = useCallback9((renderAsset) => {
6865
7103
  validateRenderAsset(renderAsset);
6866
7104
  renderAssetsRef.current = [...renderAssetsRef.current, renderAsset];
@@ -6892,7 +7130,7 @@ var RenderAssetManagerProvider = ({ children, collectAssets }) => {
6892
7130
  };
6893
7131
  }
6894
7132
  }, []);
6895
- const contextValue = useMemo17(() => {
7133
+ const contextValue = useMemo18(() => {
6896
7134
  return {
6897
7135
  registerRenderAsset,
6898
7136
  unregisterRenderAsset,
@@ -6965,7 +7203,7 @@ var Artifact = ({ filename, content: content2, downloadBehavior }) => {
6965
7203
  };
6966
7204
  Artifact.Thumbnail = ArtifactThumbnail;
6967
7205
  // src/audio/html5-audio.tsx
6968
- import { forwardRef as forwardRef7, useCallback as useCallback16, useContext as useContext34 } from "react";
7206
+ import { forwardRef as forwardRef7, useCallback as useCallback16, useContext as useContext36 } from "react";
6969
7207
 
6970
7208
  // src/absolute-src.ts
6971
7209
  var getAbsoluteSrc = (relativeSrc) => {
@@ -6992,14 +7230,14 @@ var calculateMediaDuration = ({
6992
7230
  if (typeof trimBefore !== "undefined") {
6993
7231
  duration -= trimBefore;
6994
7232
  }
6995
- const actualDuration = duration / playbackRate;
6996
- return Number(actualDuration.toFixed(10));
7233
+ return duration / playbackRate;
6997
7234
  };
6998
7235
 
6999
7236
  // src/loop/index.tsx
7000
- import React20, { createContext as createContext19, useMemo as useMemo18 } from "react";
7237
+ import React20, { createContext as createContext19, useContext as useContext22, useMemo as useMemo19 } from "react";
7001
7238
  import { jsx as jsx17 } from "react/jsx-runtime";
7002
7239
  var LoopContext = createContext19(null);
7240
+ var LoopTimelineContext = createContext19(null);
7003
7241
  var useLoop = () => {
7004
7242
  return React20.useContext(LoopContext);
7005
7243
  };
@@ -7009,10 +7247,16 @@ var Loop = ({
7009
7247
  children,
7010
7248
  name,
7011
7249
  showInTimeline,
7250
+ playbackRate,
7012
7251
  ...props
7013
7252
  }) => {
7014
7253
  const currentFrame = useCurrentFrame();
7015
7254
  const { durationInFrames: compDuration } = useVideoConfig();
7255
+ const parentSequence = useContext22(SequenceContext);
7256
+ const parentPlaybackRate = parentSequence?.playbackRate ?? 1;
7257
+ const loopStartFrame = parentSequence ? parentSequence.cumulatedFrom + parentSequence.relativeFrom : 0;
7258
+ const firstVisibleFrame = loopStartFrame - (parentSequence?.cumulatedNegativeFrom ?? 0) / parentPlaybackRate;
7259
+ const endFrame = loopStartFrame + Math.min(compDuration, durationInFrames * times) / parentPlaybackRate;
7016
7260
  validateDurationInFrames(durationInFrames, {
7017
7261
  component: "of the <Loop /> component",
7018
7262
  allowFloats: true
@@ -7028,43 +7272,57 @@ var Loop = ({
7028
7272
  }
7029
7273
  const maxTimes = Math.ceil(compDuration / durationInFrames);
7030
7274
  const actualTimes = Math.min(maxTimes, times);
7031
- const style = props.layout === "none" ? undefined : props.style;
7032
7275
  const maxFrame = durationInFrames * (actualTimes - 1);
7033
- const iteration = Math.floor(currentFrame / durationInFrames);
7034
- const start = iteration * durationInFrames;
7035
- const from = Math.min(start, maxFrame);
7036
- const loopDisplay = useMemo18(() => {
7276
+ const loopsElapsed = currentFrame / durationInFrames;
7277
+ const nearestIteration = Math.round(loopsElapsed);
7278
+ const isAtBoundary = Math.abs(loopsElapsed - nearestIteration) <= Number.EPSILON * Math.max(1, Math.abs(loopsElapsed)) * 4;
7279
+ const iteration = Math.max(0, Math.min(actualTimes - 1, isAtBoundary ? nearestIteration : Math.floor(loopsElapsed)));
7280
+ const start = isAtBoundary ? currentFrame : iteration * durationInFrames;
7281
+ const from = Math.max(0, Math.min(start, maxFrame));
7282
+ const loopDisplay = useMemo19(() => {
7037
7283
  return {
7038
7284
  numberOfTimes: Math.min(compDuration / durationInFrames, times),
7039
7285
  startOffset: -from,
7040
7286
  durationInFrames
7041
7287
  };
7042
7288
  }, [compDuration, durationInFrames, from, times]);
7043
- const loopContext = useMemo18(() => {
7289
+ const loopContext = useMemo19(() => {
7044
7290
  return {
7045
- iteration: Math.floor(currentFrame / durationInFrames),
7291
+ iteration,
7046
7292
  durationInFrames
7047
7293
  };
7048
- }, [currentFrame, durationInFrames]);
7049
- return /* @__PURE__ */ jsx17(LoopContext.Provider, {
7050
- value: loopContext,
7051
- children: /* @__PURE__ */ jsx17(Sequence, {
7052
- durationInFrames,
7053
- from,
7054
- name: name ?? "<Loop>",
7055
- _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/loop",
7056
- _remotionInternalLoopDisplay: loopDisplay,
7057
- layout: props.layout,
7058
- style,
7059
- showInTimeline,
7060
- children
7294
+ }, [iteration, durationInFrames]);
7295
+ const timelineContext = useMemo19(() => ({
7296
+ startFrame: loopStartFrame,
7297
+ firstVisibleFrame,
7298
+ endFrame,
7299
+ playbackRate: parentPlaybackRate
7300
+ }), [loopStartFrame, firstVisibleFrame, endFrame, parentPlaybackRate]);
7301
+ if (actualTimes === 0) {
7302
+ return null;
7303
+ }
7304
+ return /* @__PURE__ */ jsx17(LoopTimelineContext.Provider, {
7305
+ value: timelineContext,
7306
+ children: /* @__PURE__ */ jsx17(LoopContext.Provider, {
7307
+ value: loopContext,
7308
+ children: /* @__PURE__ */ jsx17(Sequence, {
7309
+ durationInFrames,
7310
+ from,
7311
+ name: name ?? "<Loop>",
7312
+ _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/loop",
7313
+ _remotionInternalLoopDisplay: loopDisplay,
7314
+ ...props,
7315
+ showInTimeline,
7316
+ playbackRate,
7317
+ children
7318
+ })
7061
7319
  })
7062
7320
  });
7063
7321
  };
7064
7322
  Loop.useLoop = useLoop;
7065
7323
 
7066
7324
  // src/prefetch.ts
7067
- import { useContext as useContext22 } from "react";
7325
+ import { useContext as useContext23 } from "react";
7068
7326
 
7069
7327
  // src/playback-logging.ts
7070
7328
  var playbackLogging = ({
@@ -7120,7 +7378,7 @@ var getSrcWithoutHash = (src) => {
7120
7378
  return src.slice(0, hashIndex);
7121
7379
  };
7122
7380
  var usePreload = (src) => {
7123
- const preloads2 = useContext22(PreloadContext);
7381
+ const preloads2 = useContext23(PreloadContext);
7124
7382
  const hashFragmentIndex = removeAndGetHashFragment(src);
7125
7383
  const withoutHashFragment = getSrcWithoutHash(src);
7126
7384
  if (!preloads2[withoutHashFragment]) {
@@ -7405,7 +7663,7 @@ var resolveTrimProps = ({
7405
7663
  };
7406
7664
 
7407
7665
  // src/video/duration-state.tsx
7408
- import { createContext as createContext21, useMemo as useMemo19, useReducer } from "react";
7666
+ import { createContext as createContext21, useMemo as useMemo20, useReducer } from "react";
7409
7667
  import { jsx as jsx19 } from "react/jsx-runtime";
7410
7668
  var durationReducer = (state, action) => {
7411
7669
  switch (action.type) {
@@ -7431,7 +7689,7 @@ var DurationsContext = createContext21({
7431
7689
  });
7432
7690
  var DurationsContextProvider = ({ children }) => {
7433
7691
  const [durations, setDurations] = useReducer(durationReducer, {});
7434
- const value = useMemo19(() => {
7692
+ const value = useMemo20(() => {
7435
7693
  return {
7436
7694
  durations,
7437
7695
  setDurations
@@ -7447,11 +7705,11 @@ var DurationsContextProvider = ({ children }) => {
7447
7705
  import { useCallback as useCallback15 } from "react";
7448
7706
  import React26, {
7449
7707
  forwardRef as forwardRef5,
7450
- useContext as useContext31,
7708
+ useContext as useContext33,
7451
7709
  useEffect as useEffect15,
7452
7710
  useImperativeHandle as useImperativeHandle4,
7453
- useMemo as useMemo27,
7454
- useRef as useRef20,
7711
+ useMemo as useMemo28,
7712
+ useRef as useRef21,
7455
7713
  useState as useState15
7456
7714
  } from "react";
7457
7715
 
@@ -7508,17 +7766,17 @@ var random = (seed, dummy) => {
7508
7766
  };
7509
7767
 
7510
7768
  // src/use-amplification.ts
7511
- import { useContext as useContext24, useLayoutEffect as useLayoutEffect8, useRef as useRef15 } from "react";
7769
+ import { useContext as useContext25, useLayoutEffect as useLayoutEffect8, useRef as useRef16 } from "react";
7512
7770
 
7513
7771
  // src/audio/shared-audio-tags.tsx
7514
7772
  import React23, {
7515
7773
  createContext as createContext22,
7516
7774
  createRef as createRef2,
7517
7775
  useCallback as useCallback10,
7518
- useContext as useContext23,
7776
+ useContext as useContext24,
7519
7777
  useEffect as useEffect8,
7520
- useMemo as useMemo21,
7521
- useRef as useRef13,
7778
+ useMemo as useMemo22,
7779
+ useRef as useRef14,
7522
7780
  useState as useState11
7523
7781
  } from "react";
7524
7782
 
@@ -7622,7 +7880,7 @@ var makeSharedElementSourceNode = ({
7622
7880
  };
7623
7881
 
7624
7882
  // src/audio/use-audio-context.ts
7625
- import { useMemo as useMemo20, useRef as useRef12 } from "react";
7883
+ import { useMemo as useMemo21, useRef as useRef13 } from "react";
7626
7884
  var warned = false;
7627
7885
  var warnOnce = (logLevel) => {
7628
7886
  if (warned) {
@@ -7640,11 +7898,11 @@ var useSingletonAudioContext = ({
7640
7898
  sampleRate
7641
7899
  }) => {
7642
7900
  const env = useRemotionEnvironment();
7643
- const initialSampleRate = useRef12(sampleRate);
7901
+ const initialSampleRate = useRef13(sampleRate);
7644
7902
  if (sampleRate !== initialSampleRate.current) {
7645
7903
  throw new Error(`Changing the AudioContext sample rate dynamically is not supported. The sample rate was initialized with ${initialSampleRate.current} Hz, but ${sampleRate} Hz was passed later.`);
7646
7904
  }
7647
- const context = useMemo20(() => {
7905
+ const context = useMemo21(() => {
7648
7906
  if (env.isRendering) {
7649
7907
  return null;
7650
7908
  }
@@ -7823,17 +8081,17 @@ var SharedAudioContextProvider = ({
7823
8081
  audioEnabled,
7824
8082
  sampleRate
7825
8083
  });
7826
- const audioContextIsPlayingEventually = useRef13(false);
7827
- const initialExperimentalKeepAudioContextAlive = useRef13(_experimentalKeepAudioContextAlive);
8084
+ const audioContextIsPlayingEventually = useRef14(false);
8085
+ const initialExperimentalKeepAudioContextAlive = useRef14(_experimentalKeepAudioContextAlive);
7828
8086
  if (initialExperimentalKeepAudioContextAlive.current !== _experimentalKeepAudioContextAlive) {
7829
8087
  throw new Error("`_experimentalKeepAudioContextAlive` cannot be changed dynamically.");
7830
8088
  }
7831
- const isResuming = useRef13(null);
7832
- const nextResumeAttemptId = useRef13(0);
7833
- const nextResumeIsAutoPlayAttempt = useRef13(false);
7834
- const audioSyncAnchor = useMemo21(() => ({ value: 0 }), []);
7835
- const audioSyncAnchorListeners = useRef13([]);
7836
- const audioSyncAnchorEmitter = useMemo21(() => {
8089
+ const isResuming = useRef14(null);
8090
+ const nextResumeAttemptId = useRef14(0);
8091
+ const nextResumeIsAutoPlayAttempt = useRef14(false);
8092
+ const audioSyncAnchor = useMemo22(() => ({ value: 0 }), []);
8093
+ const audioSyncAnchorListeners = useRef14([]);
8094
+ const audioSyncAnchorEmitter = useMemo22(() => {
7837
8095
  return {
7838
8096
  dispatch: (event) => {
7839
8097
  audioSyncAnchorListeners.current.forEach((l) => l(event));
@@ -7848,12 +8106,12 @@ var SharedAudioContextProvider = ({
7848
8106
  }
7849
8107
  };
7850
8108
  }, []);
7851
- const prevEndTimes = useRef13({ scheduledEndTime: null, mediaEndTime: null });
7852
- const nodesToResume = useRef13(new Map);
8109
+ const prevEndTimes = useRef14({ scheduledEndTime: null, mediaEndTime: null });
8110
+ const nodesToResume = useRef14(new Map);
7853
8111
  const unscheduleAudioNode = useCallback10((node) => {
7854
8112
  nodesToResume.current.delete(node);
7855
8113
  }, []);
7856
- const scheduleAudioNode = useMemo21(() => {
8114
+ const scheduleAudioNode = useMemo22(() => {
7857
8115
  return ({
7858
8116
  node,
7859
8117
  mediaTimestamp,
@@ -7998,7 +8256,7 @@ var SharedAudioContextProvider = ({
7998
8256
  ctxAndGain.suspend().catch(() => {});
7999
8257
  };
8000
8258
  }, [ctxAndGain, _experimentalKeepAudioContextAlive]);
8001
- const audioContextValue = useMemo21(() => {
8259
+ const audioContextValue = useMemo22(() => {
8002
8260
  return {
8003
8261
  sampleRate,
8004
8262
  audioContext: ctxAndGain?.audioContext ?? null,
@@ -8033,7 +8291,7 @@ var SharedAudioContextProvider = ({
8033
8291
  });
8034
8292
  };
8035
8293
  var SharedAudioTagsContextProvider = ({ children, numberOfAudioTags }) => {
8036
- const audios = useRef13([]);
8294
+ const audios = useRef14([]);
8037
8295
  const [initialNumberOfAudioTags] = useState11(numberOfAudioTags);
8038
8296
  if (numberOfAudioTags !== initialNumberOfAudioTags) {
8039
8297
  throw new Error("The number of shared audio tags has changed dynamically. Once you have set this property, you cannot change it afterwards.");
@@ -8041,7 +8299,7 @@ var SharedAudioTagsContextProvider = ({ children, numberOfAudioTags }) => {
8041
8299
  const logLevel = useLogLevel();
8042
8300
  const mountTime = useMountTime();
8043
8301
  const env = useRemotionEnvironment();
8044
- const audioCtx = useContext23(SharedAudioContext);
8302
+ const audioCtx = useContext24(SharedAudioContext);
8045
8303
  const audioContext = audioCtx?.audioContext ?? null;
8046
8304
  const resume = audioCtx?.resume;
8047
8305
  const [refs] = useState11(() => {
@@ -8070,7 +8328,7 @@ var SharedAudioTagsContextProvider = ({ children, numberOfAudioTags }) => {
8070
8328
  });
8071
8329
  };
8072
8330
  }, [refs]);
8073
- const takenAudios = useRef13(new Array(numberOfAudioTags).fill(false));
8331
+ const takenAudios = useRef14(new Array(numberOfAudioTags).fill(false));
8074
8332
  const rerenderAudios = useCallback10(() => {
8075
8333
  refs.forEach(({ ref, id }) => {
8076
8334
  const data = audios.current?.find((a2) => a2.id === id);
@@ -8186,7 +8444,7 @@ var SharedAudioTagsContextProvider = ({ children, numberOfAudioTags }) => {
8186
8444
  });
8187
8445
  resume?.();
8188
8446
  }, [logLevel, mountTime, refs, env.isPlayer, resume]);
8189
- const audioTagsValue = useMemo21(() => {
8447
+ const audioTagsValue = useMemo22(() => {
8190
8448
  return {
8191
8449
  registerAudio,
8192
8450
  unregisterAudio,
@@ -8201,7 +8459,7 @@ var SharedAudioTagsContextProvider = ({ children, numberOfAudioTags }) => {
8201
8459
  unregisterAudio,
8202
8460
  updateAudio
8203
8461
  ]);
8204
- const sharedAudioTagElements = useMemo21(() => {
8462
+ const sharedAudioTagElements = useMemo22(() => {
8205
8463
  return refs.map(({ id, ref }) => {
8206
8464
  return /* @__PURE__ */ jsx20("audio", {
8207
8465
  ref,
@@ -8224,8 +8482,8 @@ var useSharedAudio = ({
8224
8482
  premounting,
8225
8483
  postmounting
8226
8484
  }) => {
8227
- const audioCtx = useContext23(SharedAudioContext);
8228
- const tagsCtx = useContext23(SharedAudioTagsContext);
8485
+ const audioCtx = useContext24(SharedAudioContext);
8486
+ const tagsCtx = useContext24(SharedAudioTagsContext);
8229
8487
  const [elem] = useState11(() => {
8230
8488
  if (tagsCtx && tagsCtx.numberOfAudioTags > 0) {
8231
8489
  return tagsCtx.registerAudio({ aud, audioId, premounting, postmounting });
@@ -8281,7 +8539,7 @@ var isApproximatelyTheSame = (num1, num2) => {
8281
8539
  };
8282
8540
 
8283
8541
  // src/video/video-fragment.ts
8284
- import { useRef as useRef14 } from "react";
8542
+ import { useRef as useRef15 } from "react";
8285
8543
  var toSeconds = (time, fps) => {
8286
8544
  return Math.round(time / fps * 100) / 100;
8287
8545
  };
@@ -8370,9 +8628,9 @@ var useAppendVideoFragment = ({
8370
8628
  duration: initialDuration,
8371
8629
  fps
8372
8630
  }) => {
8373
- const actualFromRef = useRef14(initialActualFrom);
8374
- const actualDuration = useRef14(initialDuration);
8375
- const actualSrc = useRef14(initialActualSrc);
8631
+ const actualFromRef = useRef15(initialActualFrom);
8632
+ const actualDuration = useRef15(initialDuration);
8633
+ const actualSrc = useRef15(initialActualSrc);
8376
8634
  if (!isSubsetOfDuration({
8377
8635
  prevStartFrom: actualFromRef.current,
8378
8636
  newStartFrom: initialActualFrom,
@@ -8411,10 +8669,10 @@ var useVolume = ({
8411
8669
  source,
8412
8670
  shouldUseWebAudioApi
8413
8671
  }) => {
8414
- const audioStuffRef = useRef15(null);
8415
- const currentVolumeRef = useRef15(volume);
8672
+ const audioStuffRef = useRef16(null);
8673
+ const currentVolumeRef = useRef16(volume);
8416
8674
  currentVolumeRef.current = volume;
8417
- const sharedAudioContext = useContext24(SharedAudioContext);
8675
+ const sharedAudioContext = useContext25(SharedAudioContext);
8418
8676
  if (!sharedAudioContext) {
8419
8677
  throw new Error("useAmplification must be used within a SharedAudioContext");
8420
8678
  }
@@ -8480,22 +8738,25 @@ var useVolume = ({
8480
8738
  };
8481
8739
 
8482
8740
  // src/use-media-in-timeline.ts
8483
- import { useCallback as useCallback11, useContext as useContext26, useEffect as useEffect9, useMemo as useMemo22, useState as useState12 } from "react";
8741
+ import { useCallback as useCallback11, useContext as useContext27, useEffect as useEffect9, useMemo as useMemo23, useState as useState12 } from "react";
8484
8742
 
8485
8743
  // src/audio/use-audio-frame.ts
8486
- import { useContext as useContext25 } from "react";
8744
+ import { createContext as createContext23, useContext as useContext26 } from "react";
8745
+ var Html5MediaTrimContext = createContext23(0);
8487
8746
  var useMediaStartsAt = () => {
8488
- const parentSequence = useContext25(SequenceContext);
8747
+ const parentSequence = useContext26(SequenceContext);
8489
8748
  return parentSequence?.cumulatedNegativeFrom ?? 0;
8490
8749
  };
8491
8750
  var useFrameForVolumeProp = (behavior) => {
8492
8751
  const loop = Loop.useLoop();
8752
+ const loopTimeline = useContext26(LoopTimelineContext);
8753
+ const sequenceContext = useContext26(SequenceContext);
8493
8754
  const frame = useCurrentFrame();
8494
8755
  const startsAt = useMediaStartsAt();
8495
8756
  if (behavior === "repeat" || loop === null) {
8496
8757
  return frame + startsAt;
8497
8758
  }
8498
- return frame + startsAt + loop.durationInFrames * loop.iteration;
8759
+ return frame + startsAt + loop.durationInFrames * loop.iteration * (sequenceContext?.playbackRate ?? 1) / (loopTimeline?.playbackRate ?? 1);
8499
8760
  };
8500
8761
 
8501
8762
  // src/get-asset-file-name.ts
@@ -8508,7 +8769,12 @@ var getAssetDisplayName = (filename) => {
8508
8769
  return staticFile ? getAssetDisplayName(staticFile.name) : "Blob URL";
8509
8770
  }
8510
8771
  const splitted = filename.split("/").map((s) => s.split("\\")).flat(1);
8511
- return splitted[splitted.length - 1];
8772
+ const name = splitted[splitted.length - 1];
8773
+ try {
8774
+ return decodeURIComponent(name);
8775
+ } catch {
8776
+ return name;
8777
+ }
8512
8778
  };
8513
8779
 
8514
8780
  // src/get-timeline-duration.ts
@@ -8581,13 +8847,15 @@ var useBasicMediaInTimeline = ({
8581
8847
  playbackRate,
8582
8848
  sequenceDurationInFrames,
8583
8849
  mediaStartsAt,
8850
+ mediaFrom,
8584
8851
  loop,
8585
8852
  muted
8586
8853
  }) => {
8587
8854
  if (!src) {
8588
8855
  throw new Error("No src passed");
8589
8856
  }
8590
- const parentSequence = useContext26(SequenceContext);
8857
+ const parentSequence = useContext27(SequenceContext);
8858
+ const sequencePlaybackRate = parentSequence?.playbackRate ?? 1;
8591
8859
  const [initialVolume] = useState12(() => volume);
8592
8860
  const duration = getTimelineDuration({
8593
8861
  compositionDurationInFrames: sequenceDurationInFrames,
@@ -8597,7 +8865,7 @@ var useBasicMediaInTimeline = ({
8597
8865
  parentSequenceDurationInFrames: parentSequence?.durationInFrames ?? null,
8598
8866
  loop
8599
8867
  });
8600
- const volumes = useMemo22(() => {
8868
+ const volumes = useMemo23(() => {
8601
8869
  if (typeof volume === "number") {
8602
8870
  return volume;
8603
8871
  }
@@ -8608,14 +8876,21 @@ var useBasicMediaInTimeline = ({
8608
8876
  mediaVolume
8609
8877
  });
8610
8878
  }
8611
- return new Array(Math.floor(Math.max(0, duration + mediaStartsAt))).fill(true).map((_, i) => {
8879
+ return new Array(Math.ceil(Math.max(0, duration + Math.min(0, mediaStartsAt + mediaFrom)) / sequencePlaybackRate)).fill(true).map((_, i) => {
8612
8880
  return evaluateVolume({
8613
- frame: i + mediaStartsAt,
8881
+ frame: i * sequencePlaybackRate,
8614
8882
  volume,
8615
8883
  mediaVolume
8616
8884
  });
8617
8885
  }).join(",");
8618
- }, [duration, mediaStartsAt, volume, mediaVolume]);
8886
+ }, [
8887
+ duration,
8888
+ mediaStartsAt,
8889
+ mediaFrom,
8890
+ volume,
8891
+ mediaVolume,
8892
+ sequencePlaybackRate
8893
+ ]);
8619
8894
  useEffect9(() => {
8620
8895
  if (typeof volume === "number" && volume !== initialVolume) {
8621
8896
  warnOnce2(`Remotion: The ${mediaType} with src ${src} has changed it's volume. Prefer the callback syntax for setting volume to get better timeline display: https://www.remotion.dev/docs/audio/volume`);
@@ -8623,7 +8898,7 @@ var useBasicMediaInTimeline = ({
8623
8898
  }, [initialVolume, mediaType, src, volume]);
8624
8899
  const doesVolumeChange = typeof volume === "function";
8625
8900
  const startMediaFrom = 0 - mediaStartsAt + (trimBefore ?? 0);
8626
- const memoizedResult = useMemo22(() => {
8901
+ const memoizedResult = useMemo23(() => {
8627
8902
  return {
8628
8903
  volumes,
8629
8904
  duration,
@@ -8659,17 +8934,24 @@ var useMediaInTimeline = ({
8659
8934
  premountDisplay,
8660
8935
  postmountDisplay,
8661
8936
  loopDisplay,
8937
+ loopVolumeCurveBehavior,
8662
8938
  documentationLink,
8663
8939
  refForOutline,
8664
8940
  muted
8665
8941
  }) => {
8666
- const parentSequence = useContext26(SequenceContext);
8667
- const startsAt = useMediaStartsAt();
8668
- const sequenceRegistrationEnabled = useContext26(SequenceRegistrationContext);
8942
+ const parentSequence = useContext27(SequenceContext);
8943
+ const mediaTrimBefore = useContext27(Html5MediaTrimContext);
8944
+ const sequenceRegistrationEnabled = useContext27(SequenceRegistrationContext);
8669
8945
  const { durationInFrames } = useVideoConfig();
8670
8946
  const mediaStartsAt = useMediaStartsAt();
8671
- const { volumes, duration, doesVolumeChange, finalDisplayName } = useBasicMediaInTimeline({
8672
- volume,
8947
+ const loopContext = Loop.useLoop();
8948
+ const loopTimeline = useContext27(LoopTimelineContext);
8949
+ const {
8950
+ volumes: basicVolumes,
8951
+ duration,
8952
+ finalDisplayName
8953
+ } = useBasicMediaInTimeline({
8954
+ volume: loopContext && typeof volume === "function" ? undefined : volume,
8673
8955
  mediaVolume,
8674
8956
  mediaType,
8675
8957
  src,
@@ -8679,9 +8961,43 @@ var useMediaInTimeline = ({
8679
8961
  playbackRate,
8680
8962
  sequenceDurationInFrames: durationInFrames,
8681
8963
  mediaStartsAt,
8964
+ mediaFrom: 0,
8682
8965
  loop: false,
8683
8966
  muted
8684
8967
  });
8968
+ const doesVolumeChange = typeof volume === "function";
8969
+ const volumes = useMemo23(() => {
8970
+ if (!loopContext || !loopTimeline || typeof volume !== "function") {
8971
+ return basicVolumes;
8972
+ }
8973
+ const timeline = loopTimeline;
8974
+ const loopDuration = loopContext.durationInFrames;
8975
+ const sequenceRate = parentSequence?.playbackRate ?? 1;
8976
+ const mediaOrigin = parentSequence ? parentSequence.cumulatedFrom + parentSequence.relativeFrom : 0;
8977
+ const mediaOffset = mediaOrigin + mediaTrimBefore / sequenceRate - (timeline.startFrame + loopContext.iteration * loopDuration / timeline.playbackRate);
8978
+ const firstVisible = Math.max(0, timeline.firstVisibleFrame);
8979
+ const firstCompositionFrame = Math.ceil(firstVisible);
8980
+ return Array.from({
8981
+ length: Math.max(0, Math.ceil(timeline.endFrame) - firstCompositionFrame)
8982
+ }, (_, index) => {
8983
+ const compositionFrame = firstCompositionFrame + index;
8984
+ const loopsElapsed = (compositionFrame - timeline.startFrame) * timeline.playbackRate / loopDuration;
8985
+ const nearestIteration = Math.round(loopsElapsed);
8986
+ const iteration = Math.abs(loopsElapsed - nearestIteration) <= Number.EPSILON * Math.max(1, Math.abs(loopsElapsed)) * 4 ? nearestIteration : Math.floor(loopsElapsed);
8987
+ const iterationStart = timeline.startFrame + iteration * loopDuration / timeline.playbackRate + mediaOffset;
8988
+ const frame = Math.max(0, compositionFrame - Math.max(firstVisible, iterationStart)) * sequenceRate + (loopVolumeCurveBehavior === "extend" ? iteration * loopDuration * sequenceRate / timeline.playbackRate : 0);
8989
+ return evaluateVolume({ frame, volume, mediaVolume });
8990
+ }).join(",");
8991
+ }, [
8992
+ basicVolumes,
8993
+ loopContext,
8994
+ loopTimeline,
8995
+ mediaTrimBefore,
8996
+ mediaVolume,
8997
+ parentSequence,
8998
+ volume,
8999
+ loopVolumeCurveBehavior
9000
+ ]);
8685
9001
  const { isStudio } = useRemotionEnvironment();
8686
9002
  const getSequenceForRegistration = useCallback11(() => {
8687
9003
  if (!src) {
@@ -8702,11 +9018,12 @@ var useMediaInTimeline = ({
8702
9018
  muted,
8703
9019
  showInTimeline: true,
8704
9020
  timelineOrder: null,
8705
- startMediaFrom: 0 - startsAt,
8706
- mediaFrameAtSequenceZero: null,
9021
+ startMediaFrom: mediaTrimBefore,
9022
+ mediaFrameAtSequenceZero: mediaTrimBefore * (1 - playbackRate),
8707
9023
  doesVolumeChange,
8708
9024
  loopDisplay,
8709
9025
  playbackRate,
9026
+ sequencePlaybackRate: 1,
8710
9027
  getStack,
8711
9028
  premountDisplay,
8712
9029
  postmountDisplay,
@@ -8725,7 +9042,7 @@ var useMediaInTimeline = ({
8725
9042
  volumes,
8726
9043
  doesVolumeChange,
8727
9044
  mediaType,
8728
- startsAt,
9045
+ mediaTrimBefore,
8729
9046
  playbackRate,
8730
9047
  getStack,
8731
9048
  premountDisplay,
@@ -8744,21 +9061,27 @@ var useMediaInTimeline = ({
8744
9061
  };
8745
9062
 
8746
9063
  // src/use-media-playback.ts
8747
- import { useCallback as useCallback14, useEffect as useEffect13, useLayoutEffect as useLayoutEffect10, useRef as useRef18 } from "react";
9064
+ import {
9065
+ useCallback as useCallback14,
9066
+ useContext as useContext30,
9067
+ useEffect as useEffect13,
9068
+ useLayoutEffect as useLayoutEffect10,
9069
+ useRef as useRef19
9070
+ } from "react";
8748
9071
 
8749
9072
  // src/buffer-until-first-frame.ts
8750
- import { useCallback as useCallback13, useMemo as useMemo25, useRef as useRef16 } from "react";
9073
+ import { useCallback as useCallback13, useMemo as useMemo26, useRef as useRef17 } from "react";
8751
9074
 
8752
9075
  // src/use-buffer-state.ts
8753
- import { useContext as useContext28, useMemo as useMemo24 } from "react";
9076
+ import { useContext as useContext29, useMemo as useMemo25 } from "react";
8754
9077
 
8755
9078
  // src/buffering.tsx
8756
9079
  import React24, {
8757
9080
  useCallback as useCallback12,
8758
- useContext as useContext27,
9081
+ useContext as useContext28,
8759
9082
  useEffect as useEffect10,
8760
9083
  useLayoutEffect as useLayoutEffect9,
8761
- useMemo as useMemo23,
9084
+ useMemo as useMemo24,
8762
9085
  useState as useState13
8763
9086
  } from "react";
8764
9087
  import { jsx as jsx21 } from "react/jsx-runtime";
@@ -8816,12 +9139,12 @@ var useBufferManager = (logLevel, mountTime, setBuffering, isBuffering) => {
8816
9139
  }
8817
9140
  }, [blockCount]);
8818
9141
  }
8819
- return useMemo23(() => ({ addBlock }), [addBlock]);
9142
+ return useMemo24(() => ({ addBlock }), [addBlock]);
8820
9143
  };
8821
9144
  var BufferingContextReact = React24.createContext(null);
8822
9145
  var BufferingProvider = ({ children }) => {
8823
- const { logLevel, mountTime } = useContext27(LogLevelContext);
8824
- const { isBuffering, setBuffering } = useContext27(SetTimelineContext);
9146
+ const { logLevel, mountTime } = useContext28(LogLevelContext);
9147
+ const { isBuffering, setBuffering } = useContext28(SetTimelineContext);
8825
9148
  const bufferManager = useBufferManager(logLevel ?? "info", mountTime, setBuffering, isBuffering);
8826
9149
  return /* @__PURE__ */ jsx21(BufferingContextReact.Provider, {
8827
9150
  value: bufferManager,
@@ -8831,10 +9154,10 @@ var BufferingProvider = ({ children }) => {
8831
9154
 
8832
9155
  // src/use-buffer-state.ts
8833
9156
  var useBufferState = () => {
8834
- const buffer = useContext28(BufferingContextReact);
9157
+ const buffer = useContext29(BufferingContextReact);
8835
9158
  const logLevel = useLogLevel();
8836
9159
  const addBlock = buffer ? buffer.addBlock : null;
8837
- return useMemo24(() => ({
9160
+ return useMemo25(() => ({
8838
9161
  delayPlayback: () => {
8839
9162
  if (!addBlock) {
8840
9163
  throw new Error("Tried to enable the buffering state, but a Remotion context was not found. This API can only be called in a component that was passed to the Remotion Player or a <Composition>. Or you might have experienced a version mismatch - run `npx remotion versions` and ensure all packages have the same version. This error is thrown by the buffer state https://remotion.dev/docs/player/buffer-state");
@@ -8869,7 +9192,7 @@ var useBufferUntilFirstFrame = ({
8869
9192
  logLevel,
8870
9193
  mountTime
8871
9194
  }) => {
8872
- const bufferingRef = useRef16(false);
9195
+ const bufferingRef = useRef17(false);
8873
9196
  const { delayPlayback } = useBufferState();
8874
9197
  const bufferUntilFirstFrame = useCallback13((requestedTime) => {
8875
9198
  if (mediaType !== "video") {
@@ -8942,7 +9265,7 @@ var useBufferUntilFirstFrame = ({
8942
9265
  onVariableFpsVideoDetected,
8943
9266
  pauseWhenBuffering
8944
9267
  ]);
8945
- return useMemo25(() => {
9268
+ return useMemo26(() => {
8946
9269
  return {
8947
9270
  isBuffering: () => bufferingRef.current,
8948
9271
  bufferUntilFirstFrame
@@ -9195,14 +9518,14 @@ var useMediaBuffering = ({
9195
9518
  };
9196
9519
 
9197
9520
  // src/use-request-video-callback-time.ts
9198
- import { useEffect as useEffect12, useRef as useRef17 } from "react";
9521
+ import { useEffect as useEffect12, useRef as useRef18 } from "react";
9199
9522
  var useRequestVideoCallbackTime = ({
9200
9523
  mediaRef,
9201
9524
  mediaType,
9202
9525
  lastSeek,
9203
9526
  onVariableFpsVideoDetected
9204
9527
  }) => {
9205
- const currentTime = useRef17(null);
9528
+ const currentTime = useRef18(null);
9206
9529
  useEffect12(() => {
9207
9530
  const { current } = mediaRef;
9208
9531
  if (current) {
@@ -9354,12 +9677,12 @@ var useMediaPlayback = ({
9354
9677
  const playing = usePlaying();
9355
9678
  const playerBuffering = useBuffering();
9356
9679
  const { fps } = useVideoConfig();
9357
- const mediaStartsAt = useMediaStartsAt();
9358
- const lastSeekDueToShift = useRef18(null);
9359
- const lastSeek = useRef18(null);
9680
+ const mediaTrimBefore = useContext30(Html5MediaTrimContext);
9681
+ const lastSeekDueToShift = useRef19(null);
9682
+ const lastSeek = useRef19(null);
9360
9683
  const logLevel = useLogLevel();
9361
9684
  const mountTime = useMountTime();
9362
- const isVariableFpsVideoMap = useRef18({});
9685
+ const isVariableFpsVideoMap = useRef19({});
9363
9686
  const onVariableFpsVideoDetected = useCallback14(() => {
9364
9687
  if (!src) {
9365
9688
  return;
@@ -9380,7 +9703,7 @@ var useMediaPlayback = ({
9380
9703
  const desiredUnclampedTime = getMediaTime({
9381
9704
  frame,
9382
9705
  playbackRate: localPlaybackRate,
9383
- startFrom: -mediaStartsAt,
9706
+ startFrom: mediaTrimBefore,
9384
9707
  fps
9385
9708
  });
9386
9709
  const isMediaTagBuffering = useMediaBuffering({
@@ -9400,7 +9723,8 @@ var useMediaPlayback = ({
9400
9723
  logLevel,
9401
9724
  mountTime
9402
9725
  });
9403
- const playbackRate = localPlaybackRate * globalPlaybackRate;
9726
+ const sequenceContext = useContext30(SequenceContext);
9727
+ const playbackRate = localPlaybackRate * globalPlaybackRate * (sequenceContext?.playbackRate ?? 1);
9404
9728
  const acceptableTimeShiftButLessThanDuration = (() => {
9405
9729
  if (mediaRef.current?.duration) {
9406
9730
  return Math.min(mediaRef.current.duration, acceptableTimeshift ?? DEFAULT_ACCEPTABLE_TIMESHIFT_WITH_AMPLIFICATION);
@@ -9563,7 +9887,7 @@ var useMediaPlayback = ({
9563
9887
  };
9564
9888
 
9565
9889
  // src/use-media-tag.ts
9566
- import { useContext as useContext29, useEffect as useEffect14, useRef as useRef19 } from "react";
9890
+ import { useContext as useContext31, useEffect as useEffect14, useRef as useRef20 } from "react";
9567
9891
  var useMediaTag = ({
9568
9892
  mediaRef,
9569
9893
  id,
@@ -9573,8 +9897,8 @@ var useMediaTag = ({
9573
9897
  isPostmounting
9574
9898
  }) => {
9575
9899
  const { audioAndVideoTags, isPlaying } = useTimelineContext();
9576
- const { subscribePlaying } = useContext29(SetTimelineContext);
9577
- const isPlayingRef = useRef19(isPlaying);
9900
+ const { subscribePlaying } = useContext31(SetTimelineContext);
9901
+ const isPlayingRef = useRef20(isPlaying);
9578
9902
  isPlayingRef.current = isPlaying;
9579
9903
  const logLevel = useLogLevel();
9580
9904
  const mountTime = useMountTime();
@@ -9637,12 +9961,12 @@ var useMediaTag = ({
9637
9961
  };
9638
9962
 
9639
9963
  // src/volume-position-state.ts
9640
- import { createContext as createContext23, useContext as useContext30, useMemo as useMemo26 } from "react";
9641
- var MediaVolumeContext = createContext23({
9964
+ import { createContext as createContext24, useContext as useContext32, useMemo as useMemo27 } from "react";
9965
+ var MediaVolumeContext = createContext24({
9642
9966
  playerMuted: false,
9643
9967
  mediaVolume: 1
9644
9968
  });
9645
- var SetMediaVolumeContext = createContext23({
9969
+ var SetMediaVolumeContext = createContext24({
9646
9970
  setPlayerMuted: () => {
9647
9971
  throw new Error("default");
9648
9972
  },
@@ -9651,16 +9975,16 @@ var SetMediaVolumeContext = createContext23({
9651
9975
  }
9652
9976
  });
9653
9977
  var useMediaVolumeState = () => {
9654
- const { mediaVolume } = useContext30(MediaVolumeContext);
9655
- const { setMediaVolume } = useContext30(SetMediaVolumeContext);
9656
- return useMemo26(() => {
9978
+ const { mediaVolume } = useContext32(MediaVolumeContext);
9979
+ const { setMediaVolume } = useContext32(SetMediaVolumeContext);
9980
+ return useMemo27(() => {
9657
9981
  return [mediaVolume, setMediaVolume];
9658
9982
  }, [mediaVolume, setMediaVolume]);
9659
9983
  };
9660
9984
  var usePlayerMutedState = () => {
9661
- const { playerMuted } = useContext30(MediaVolumeContext);
9662
- const { setPlayerMuted } = useContext30(SetMediaVolumeContext);
9663
- return useMemo26(() => {
9985
+ const { playerMuted } = useContext32(MediaVolumeContext);
9986
+ const { setPlayerMuted } = useContext32(SetMediaVolumeContext);
9987
+ return useMemo27(() => {
9664
9988
  return [playerMuted, setPlayerMuted];
9665
9989
  }, [playerMuted, setPlayerMuted]);
9666
9990
  };
@@ -9749,7 +10073,7 @@ var AudioForDevelopmentForwardRefFunction = (props, ref) => {
9749
10073
  throw new TypeError("No 'src' was passed to <Html5Audio>.");
9750
10074
  }
9751
10075
  const preloadedSrc = usePreload(src);
9752
- const sequenceContext = useContext31(SequenceContext);
10076
+ const sequenceContext = useContext33(SequenceContext);
9753
10077
  const { isStudio } = useRemotionEnvironment();
9754
10078
  const [timelineId] = useState15(() => String(Math.random()));
9755
10079
  const userPreferredVolume = evaluateVolume({
@@ -9768,7 +10092,7 @@ var AudioForDevelopmentForwardRefFunction = (props, ref) => {
9768
10092
  requestsVideoFrame: false,
9769
10093
  isClientSideRendering: false
9770
10094
  });
9771
- const propsToPass = useMemo27(() => {
10095
+ const propsToPass = useMemo28(() => {
9772
10096
  return {
9773
10097
  muted: isMutedForPlayback,
9774
10098
  src: preloadedSrc,
@@ -9783,7 +10107,7 @@ var AudioForDevelopmentForwardRefFunction = (props, ref) => {
9783
10107
  preloadedSrc,
9784
10108
  crossOriginValue
9785
10109
  ]);
9786
- const id = useMemo27(() => `audio-${random(src ?? "")}-${sequenceContext?.relativeFrom}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.durationInFrames}-muted:${props.muted}-loop:${props.loop}`, [
10110
+ const id = useMemo28(() => `audio-${random(src ?? "")}-${sequenceContext?.relativeFrom}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.durationInFrames}-muted:${props.muted}-loop:${props.loop}`, [
9787
10111
  src,
9788
10112
  sequenceContext?.relativeFrom,
9789
10113
  sequenceContext?.cumulatedFrom,
@@ -9817,6 +10141,7 @@ var AudioForDevelopmentForwardRefFunction = (props, ref) => {
9817
10141
  premountDisplay: sequenceContext?.premountDisplay ?? null,
9818
10142
  postmountDisplay: sequenceContext?.postmountDisplay ?? null,
9819
10143
  loopDisplay: undefined,
10144
+ loopVolumeCurveBehavior: loopVolumeCurveBehavior ?? "repeat",
9820
10145
  documentationLink: "https://www.remotion.dev/docs/html5-audio",
9821
10146
  refForOutline: null,
9822
10147
  muted: isMutedForTimeline
@@ -9860,7 +10185,7 @@ var AudioForDevelopmentForwardRefFunction = (props, ref) => {
9860
10185
  useImperativeHandle4(ref, () => {
9861
10186
  return audioRef.current;
9862
10187
  }, [audioRef]);
9863
- const currentOnDurationCallback = useRef20(onDuration);
10188
+ const currentOnDurationCallback = useRef21(onDuration);
9864
10189
  currentOnDurationCallback.current = onDuration;
9865
10190
  useEffect15(() => {
9866
10191
  const { current } = audioRef;
@@ -9901,20 +10226,20 @@ var AudioForPreview = forwardRef5(AudioForDevelopmentForwardRefFunction);
9901
10226
  // src/audio/AudioForRendering.tsx
9902
10227
  import {
9903
10228
  forwardRef as forwardRef6,
9904
- useContext as useContext33,
10229
+ useContext as useContext35,
9905
10230
  useEffect as useEffect16,
9906
10231
  useImperativeHandle as useImperativeHandle5,
9907
10232
  useLayoutEffect as useLayoutEffect11,
9908
- useMemo as useMemo29,
9909
- useRef as useRef21
10233
+ useMemo as useMemo30,
10234
+ useRef as useRef22
9910
10235
  } from "react";
9911
10236
 
9912
10237
  // src/use-media-enabled.tsx
9913
- import { createContext as createContext24, useContext as useContext32, useMemo as useMemo28 } from "react";
10238
+ import { createContext as createContext25, useContext as useContext34, useMemo as useMemo29 } from "react";
9914
10239
  import { jsx as jsx23 } from "react/jsx-runtime";
9915
- var MediaEnabledContext = createContext24(null);
10240
+ var MediaEnabledContext = createContext25(null);
9916
10241
  var useVideoEnabled = () => {
9917
- const context = useContext32(MediaEnabledContext);
10242
+ const context = useContext34(MediaEnabledContext);
9918
10243
  if (!context) {
9919
10244
  return window.remotion_videoEnabled;
9920
10245
  }
@@ -9924,7 +10249,7 @@ var useVideoEnabled = () => {
9924
10249
  return context.videoEnabled;
9925
10250
  };
9926
10251
  var useAudioEnabled = () => {
9927
- const context = useContext32(MediaEnabledContext);
10252
+ const context = useContext34(MediaEnabledContext);
9928
10253
  if (!context) {
9929
10254
  return window.remotion_audioEnabled;
9930
10255
  }
@@ -9938,7 +10263,7 @@ var MediaEnabledProvider = ({
9938
10263
  videoEnabled,
9939
10264
  audioEnabled
9940
10265
  }) => {
9941
- const value = useMemo28(() => ({ videoEnabled, audioEnabled }), [videoEnabled, audioEnabled]);
10266
+ const value = useMemo29(() => ({ videoEnabled, audioEnabled }), [videoEnabled, audioEnabled]);
9942
10267
  return /* @__PURE__ */ jsx23(MediaEnabledContext.Provider, {
9943
10268
  value,
9944
10269
  children
@@ -9948,7 +10273,7 @@ var MediaEnabledProvider = ({
9948
10273
  // src/audio/AudioForRendering.tsx
9949
10274
  import { jsx as jsx24 } from "react/jsx-runtime";
9950
10275
  var AudioForRenderingRefForwardingFunction = (props, ref) => {
9951
- const audioRef = useRef21(null);
10276
+ const audioRef = useRef22(null);
9952
10277
  const {
9953
10278
  volume: volumeProp,
9954
10279
  playbackRate,
@@ -9971,10 +10296,12 @@ var AudioForRenderingRefForwardingFunction = (props, ref) => {
9971
10296
  const absoluteFrame = useTimelinePosition();
9972
10297
  const volumePropFrame = useFrameForVolumeProp(loopVolumeCurveBehavior ?? "repeat");
9973
10298
  const frame = useCurrentFrame();
9974
- const sequenceContext = useContext33(SequenceContext);
9975
- const { registerRenderAsset, unregisterRenderAsset } = useContext33(RenderAssetManager);
10299
+ const sequenceContext = useContext35(SequenceContext);
10300
+ const sequencePlaybackRate = sequenceContext?.playbackRate ?? 1;
10301
+ const audioStartFrame = useContext35(Html5MediaTrimContext);
10302
+ const { registerRenderAsset, unregisterRenderAsset } = useContext35(RenderAssetManager);
9976
10303
  const { delayRender: delayRender2, continueRender: continueRender2 } = useDelayRender();
9977
- const id = useMemo29(() => `audio-${random(props.src ?? "")}-${sequenceContext?.relativeFrom}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.durationInFrames}`, [
10304
+ const id = useMemo30(() => `audio-${random(props.src ?? "")}-${sequenceContext?.relativeFrom}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.durationInFrames}`, [
9978
10305
  props.src,
9979
10306
  sequenceContext?.relativeFrom,
9980
10307
  sequenceContext?.cumulatedFrom,
@@ -10008,10 +10335,10 @@ var AudioForRenderingRefForwardingFunction = (props, ref) => {
10008
10335
  id,
10009
10336
  frame: absoluteFrame,
10010
10337
  volume,
10011
- mediaFrame: frame,
10012
- playbackRate: props.playbackRate ?? 1,
10338
+ mediaFrame: audioStartFrame + (frame - audioStartFrame) / sequencePlaybackRate,
10339
+ playbackRate: (props.playbackRate ?? 1) * sequencePlaybackRate,
10013
10340
  toneFrequency: toneFrequency ?? 1,
10014
- audioStartFrame: Math.max(0, -(sequenceContext?.cumulatedNegativeFrom ?? 0)),
10341
+ audioStartFrame,
10015
10342
  audioStreamIndex: audioStreamIndex ?? 0
10016
10343
  });
10017
10344
  return () => unregisterRenderAsset(id);
@@ -10028,7 +10355,8 @@ var AudioForRenderingRefForwardingFunction = (props, ref) => {
10028
10355
  playbackRate,
10029
10356
  props.playbackRate,
10030
10357
  toneFrequency,
10031
- sequenceContext?.cumulatedNegativeFrom,
10358
+ audioStartFrame,
10359
+ sequencePlaybackRate,
10032
10360
  audioStreamIndex
10033
10361
  ]);
10034
10362
  const { src } = props;
@@ -10084,7 +10412,7 @@ var AudioForRendering = forwardRef6(AudioForRenderingRefForwardingFunction);
10084
10412
  // src/audio/html5-audio.tsx
10085
10413
  import { jsx as jsx25 } from "react/jsx-runtime";
10086
10414
  var AudioRefForwardingFunction = (props, ref) => {
10087
- const audioTagsContext = useContext34(SharedAudioTagsContext);
10415
+ const audioTagsContext = useContext36(SharedAudioTagsContext);
10088
10416
  const propsWithFreeze = props;
10089
10417
  const {
10090
10418
  startFrom,
@@ -10109,7 +10437,7 @@ var AudioRefForwardingFunction = (props, ref) => {
10109
10437
  if (typeof freeze !== "undefined") {
10110
10438
  throw new TypeError('The "freeze" prop is not supported on <Html5Audio />. Use <Sequence freeze={...}> to freeze media playback.');
10111
10439
  }
10112
- const { durations, setDurations } = useContext34(DurationsContext);
10440
+ const { durations, setDurations } = useContext36(DurationsContext);
10113
10441
  if (typeof props.src !== "string") {
10114
10442
  throw new TypeError(`The \`<Html5Audio>\` tag requires a string for \`src\`, but got ${JSON.stringify(props.src)} instead.`);
10115
10443
  }
@@ -10139,20 +10467,20 @@ var AudioRefForwardingFunction = (props, ref) => {
10139
10467
  trimBefore,
10140
10468
  trimAfter
10141
10469
  });
10142
- if (loop && durationFetched !== undefined) {
10143
- if (!Number.isFinite(durationFetched)) {
10470
+ const loopDuration = trimAfterValue ?? (durationFetched === undefined ? undefined : durationFetched * fps);
10471
+ if (loop && loopDuration !== undefined) {
10472
+ if (!Number.isFinite(loopDuration)) {
10144
10473
  return /* @__PURE__ */ jsx25(Html5Audio, {
10145
10474
  ...propsOtherThanLoop,
10146
10475
  ref,
10147
10476
  _remotionInternalNativeLoopPassed: true
10148
10477
  });
10149
10478
  }
10150
- const duration = durationFetched * fps;
10151
10479
  return /* @__PURE__ */ jsx25(Loop, {
10152
10480
  layout: "none",
10153
10481
  durationInFrames: calculateMediaDuration({
10154
10482
  trimAfter: trimAfterValue,
10155
- mediaDurationInFrames: duration,
10483
+ mediaDurationInFrames: loopDuration,
10156
10484
  playbackRate: props.playbackRate ?? 1,
10157
10485
  trimBefore: trimBeforeValue
10158
10486
  }),
@@ -10164,17 +10492,20 @@ var AudioRefForwardingFunction = (props, ref) => {
10164
10492
  });
10165
10493
  }
10166
10494
  if (typeof trimBeforeValue !== "undefined" || typeof trimAfterValue !== "undefined") {
10167
- return /* @__PURE__ */ jsx25(Sequence, {
10168
- layout: "none",
10169
- from: 0 - (trimBeforeValue ?? 0),
10170
- showInTimeline: false,
10171
- durationInFrames: trimAfterValue,
10172
- name,
10173
- children: /* @__PURE__ */ jsx25(Html5Audio, {
10174
- _remotionInternalNeedsDurationCalculation: Boolean(loop),
10175
- pauseWhenBuffering: shouldPauseWhenBuffering,
10176
- ...otherProps,
10177
- ref
10495
+ return /* @__PURE__ */ jsx25(Html5MediaTrimContext.Provider, {
10496
+ value: trimBeforeValue ?? 0,
10497
+ children: /* @__PURE__ */ jsx25(Sequence, {
10498
+ layout: "none",
10499
+ from: 0 - (trimBeforeValue ?? 0),
10500
+ showInTimeline: false,
10501
+ durationInFrames: trimAfterValue === undefined ? undefined : (trimBeforeValue ?? 0) + (trimAfterValue - (trimBeforeValue ?? 0)) / (props.playbackRate ?? 1),
10502
+ name,
10503
+ children: /* @__PURE__ */ jsx25(Html5Audio, {
10504
+ _remotionInternalNeedsDurationCalculation: Boolean(loop),
10505
+ pauseWhenBuffering: shouldPauseWhenBuffering,
10506
+ ...otherProps,
10507
+ ref
10508
+ })
10178
10509
  })
10179
10510
  });
10180
10511
  }
@@ -10214,8 +10545,8 @@ import {
10214
10545
  useCallback as useCallback17,
10215
10546
  useEffect as useEffect17,
10216
10547
  useImperativeHandle as useImperativeHandle6,
10217
- useMemo as useMemo30,
10218
- useRef as useRef22,
10548
+ useMemo as useMemo31,
10549
+ useRef as useRef23,
10219
10550
  useState as useState16
10220
10551
  } from "react";
10221
10552
  import { jsx as jsx26 } from "react/jsx-runtime";
@@ -10230,6 +10561,7 @@ var resolveSolidPixelDensity = (pixelDensity) => {
10230
10561
  };
10231
10562
  var solidSchema = {
10232
10563
  ...baseSchema,
10564
+ ...premountSchema,
10233
10565
  color: {
10234
10566
  type: "color",
10235
10567
  default: "transparent",
@@ -10286,7 +10618,7 @@ var SolidInner = ({
10286
10618
  effects,
10287
10619
  overrideId: overrideId ?? null
10288
10620
  });
10289
- const sourceCanvas = useMemo30(() => {
10621
+ const sourceCanvas = useMemo31(() => {
10290
10622
  if (typeof document === "undefined") {
10291
10623
  return null;
10292
10624
  }
@@ -10354,7 +10686,7 @@ var SolidInner = ({
10354
10686
  cancelRender2,
10355
10687
  memoizedEffects
10356
10688
  ]);
10357
- const canvasStyle = useMemo30(() => {
10689
+ const canvasStyle = useMemo31(() => {
10358
10690
  return {
10359
10691
  width,
10360
10692
  height,
@@ -10380,7 +10712,12 @@ var SolidOuter = forwardRef8(({
10380
10712
  style,
10381
10713
  name,
10382
10714
  from,
10715
+ premountFor,
10716
+ postmountFor,
10717
+ styleWhilePremounted,
10718
+ styleWhilePostmounted,
10383
10719
  trimBefore,
10720
+ playbackRate,
10384
10721
  freeze,
10385
10722
  hidden,
10386
10723
  showInTimeline,
@@ -10392,42 +10729,69 @@ var SolidOuter = forwardRef8(({
10392
10729
  ...props2
10393
10730
  }, ref) => {
10394
10731
  const memoizedEffectDefinitions = useMemoizedEffectDefinitions(effects);
10395
- const actualRef = useRef22(null);
10732
+ const actualRef = useRef23(null);
10396
10733
  useImperativeHandle6(ref, () => {
10397
10734
  return actualRef.current;
10398
10735
  }, []);
10736
+ const {
10737
+ effectivePremountFor,
10738
+ effectivePostmountFor,
10739
+ freezeFrame,
10740
+ isPremountingOrPostmounting,
10741
+ premountingActive,
10742
+ postmountingActive,
10743
+ premountingStyle
10744
+ } = usePremounting({
10745
+ from: from ?? 0,
10746
+ durationInFrames: durationInFrames ?? Infinity,
10747
+ premountFor: premountFor ?? null,
10748
+ postmountFor: postmountFor ?? null,
10749
+ style: style ?? null,
10750
+ styleWhilePremounted: styleWhilePremounted ?? null,
10751
+ styleWhilePostmounted: styleWhilePostmounted ?? null,
10752
+ hideWhilePremounted: "opacity"
10753
+ });
10399
10754
  const croppedStyle = useCropStyle({
10400
10755
  cropLeft,
10401
10756
  cropRight,
10402
10757
  cropTop,
10403
10758
  cropBottom,
10404
- style: style ?? null,
10759
+ style: premountingStyle,
10405
10760
  componentName: "<Solid />"
10406
10761
  });
10407
- return /* @__PURE__ */ jsx26(Sequence, {
10408
- layout: "none",
10409
- from,
10410
- trimBefore,
10411
- freeze,
10412
- hidden,
10413
- showInTimeline,
10414
- controls,
10415
- _remotionInternalEffects: memoizedEffectDefinitions,
10416
- durationInFrames,
10417
- name: name ?? "<Solid>",
10418
- outlineRef: actualRef,
10419
- _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/solid",
10420
- ...props2,
10421
- children: /* @__PURE__ */ jsx26(SolidInner, {
10422
- reference: actualRef,
10423
- overrideId: controls?.overrideId ?? null,
10424
- color,
10425
- height,
10426
- width,
10427
- className,
10428
- style: croppedStyle ?? undefined,
10429
- effects,
10430
- pixelDensity
10762
+ return /* @__PURE__ */ jsx26(Freeze, {
10763
+ frame: freezeFrame,
10764
+ active: isPremountingOrPostmounting,
10765
+ children: /* @__PURE__ */ jsx26(Sequence, {
10766
+ layout: "none",
10767
+ from,
10768
+ trimBefore,
10769
+ playbackRate,
10770
+ freeze,
10771
+ hidden,
10772
+ showInTimeline,
10773
+ controls,
10774
+ _remotionInternalEffects: memoizedEffectDefinitions,
10775
+ durationInFrames,
10776
+ name: name ?? "<Solid>",
10777
+ outlineRef: actualRef,
10778
+ _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/solid",
10779
+ ...props2,
10780
+ _remotionInternalPremountDisplay: effectivePremountFor || null,
10781
+ _remotionInternalPostmountDisplay: effectivePostmountFor || null,
10782
+ _remotionInternalIsPremounting: premountingActive,
10783
+ _remotionInternalIsPostmounting: postmountingActive,
10784
+ children: /* @__PURE__ */ jsx26(SolidInner, {
10785
+ reference: actualRef,
10786
+ overrideId: controls?.overrideId ?? null,
10787
+ color,
10788
+ height,
10789
+ width,
10790
+ className,
10791
+ style: croppedStyle ?? undefined,
10792
+ effects,
10793
+ pixelDensity
10794
+ })
10431
10795
  })
10432
10796
  });
10433
10797
  });
@@ -10442,13 +10806,13 @@ Solid.displayName = "Solid";
10442
10806
  addSequenceStackTraces(Solid);
10443
10807
  // src/HtmlInCanvas.tsx
10444
10808
  import {
10445
- createContext as createContext25,
10809
+ createContext as createContext26,
10446
10810
  forwardRef as forwardRef9,
10447
10811
  useCallback as useCallback18,
10448
- useContext as useContext35,
10812
+ useContext as useContext37,
10449
10813
  useLayoutEffect as useLayoutEffect12,
10450
- useMemo as useMemo31,
10451
- useRef as useRef23
10814
+ useMemo as useMemo32,
10815
+ useRef as useRef24
10452
10816
  } from "react";
10453
10817
  import { jsx as jsx27 } from "react/jsx-runtime";
10454
10818
  var transferredOffscreenCanvases = new WeakMap;
@@ -10524,7 +10888,7 @@ var defaultOnPaint = ({
10524
10888
  const transform = ctx.drawElementImage(elementImage, 0, 0);
10525
10889
  element.style.transform = transform.toString();
10526
10890
  };
10527
- var HtmlInCanvasAncestorContext = createContext25(false);
10891
+ var HtmlInCanvasAncestorContext = createContext26(false);
10528
10892
  var HtmlInCanvasContent = forwardRef9(({
10529
10893
  width,
10530
10894
  height,
@@ -10536,7 +10900,7 @@ var HtmlInCanvasContent = forwardRef9(({
10536
10900
  controls,
10537
10901
  style
10538
10902
  }, ref) => {
10539
- const isInsideAncestorHtmlInCanvas = useContext35(HtmlInCanvasAncestorContext);
10903
+ const isInsideAncestorHtmlInCanvas = useContext37(HtmlInCanvasAncestorContext);
10540
10904
  assertHtmlInCanvasDimensions(width, height);
10541
10905
  if (isInsideAncestorHtmlInCanvas) {
10542
10906
  throw new Error("<HtmlInCanvas> components cannot be nested. Chrome does not reliably render nested HTML-in-canvas subtrees. Consider merging the effects into one <HtmlInCanvas> if you can.");
@@ -10551,9 +10915,9 @@ var HtmlInCanvasContent = forwardRef9(({
10551
10915
  if (!isHtmlInCanvasSupported()) {
10552
10916
  cancelRender2(new Error(HTML_IN_CANVAS_UNSUPPORTED_MESSAGE));
10553
10917
  }
10554
- const canvas2dRef = useRef23(null);
10555
- const paintTargetRef = useRef23(null);
10556
- const divRef = useRef23(null);
10918
+ const canvas2dRef = useRef24(null);
10919
+ const paintTargetRef = useRef24(null);
10920
+ const divRef = useRef24(null);
10557
10921
  const canvasSizeKey = `${width}x${height}@${resolvedPixelDensity}-${usesDirectLayoutCanvas ? "direct" : "offscreen"}`;
10558
10922
  const setLayoutCanvasRef = useCallback18((node) => {
10559
10923
  canvas2dRef.current = node;
@@ -10568,15 +10932,15 @@ var HtmlInCanvasContent = forwardRef9(({
10568
10932
  effects,
10569
10933
  overrideId: controls?.overrideId ?? null
10570
10934
  });
10571
- const effectsRef = useRef23(memoizedEffects);
10935
+ const effectsRef = useRef24(memoizedEffects);
10572
10936
  effectsRef.current = memoizedEffects;
10573
- const onPaintRef = useRef23(onPaint);
10937
+ const onPaintRef = useRef24(onPaint);
10574
10938
  onPaintRef.current = onPaint;
10575
- const onInitRef = useRef23(onInit);
10939
+ const onInitRef = useRef24(onInit);
10576
10940
  onInitRef.current = onInit;
10577
- const initializedRef = useRef23(false);
10578
- const onInitCleanupRef = useRef23(null);
10579
- const unmountedRef = useRef23(false);
10941
+ const initializedRef = useRef24(false);
10942
+ const onInitCleanupRef = useRef24(null);
10943
+ const unmountedRef = useRef24(false);
10580
10944
  const onPaintCb = useCallback18(async () => {
10581
10945
  const element = divRef.current;
10582
10946
  if (!element) {
@@ -10731,7 +11095,7 @@ var HtmlInCanvasContent = forwardRef9(({
10731
11095
  canvasHeight,
10732
11096
  usesDirectLayoutCanvas
10733
11097
  ]);
10734
- const onPaintChangedRef = useRef23(false);
11098
+ const onPaintChangedRef = useRef24(false);
10735
11099
  useLayoutEffect12(() => {
10736
11100
  if (!onPaintChangedRef.current) {
10737
11101
  onPaintChangedRef.current = true;
@@ -10756,13 +11120,13 @@ var HtmlInCanvasContent = forwardRef9(({
10756
11120
  continueRender2(handle);
10757
11121
  };
10758
11122
  }, [width, height, continueRender2, delayRender2, canvasSizeKey]);
10759
- const innerStyle = useMemo31(() => {
11123
+ const innerStyle = useMemo32(() => {
10760
11124
  return {
10761
11125
  width,
10762
11126
  height
10763
11127
  };
10764
11128
  }, [width, height]);
10765
- const canvasStyle = useMemo31(() => {
11129
+ const canvasStyle = useMemo32(() => {
10766
11130
  return {
10767
11131
  width,
10768
11132
  height,
@@ -10800,11 +11164,15 @@ var HtmlInCanvasInner = forwardRef9(({
10800
11164
  cropTop,
10801
11165
  cropBottom,
10802
11166
  durationInFrames,
11167
+ premountFor,
11168
+ postmountFor,
11169
+ styleWhilePremounted,
11170
+ styleWhilePostmounted,
10803
11171
  name,
10804
11172
  ...sequenceProps
10805
11173
  }, ref) => {
10806
11174
  const memoizedEffectDefinitions = useMemoizedEffectDefinitions(effects);
10807
- const actualRef = useRef23(null);
11175
+ const actualRef = useRef24(null);
10808
11176
  const setCanvasRef = useCallback18((node) => {
10809
11177
  actualRef.current = node;
10810
11178
  if (typeof ref === "function") {
@@ -10813,40 +11181,67 @@ var HtmlInCanvasInner = forwardRef9(({
10813
11181
  ref.current = node;
10814
11182
  }
10815
11183
  }, [ref]);
11184
+ const {
11185
+ effectivePremountFor,
11186
+ effectivePostmountFor,
11187
+ freezeFrame,
11188
+ isPremountingOrPostmounting,
11189
+ premountingActive,
11190
+ postmountingActive,
11191
+ premountingStyle
11192
+ } = usePremounting({
11193
+ from: sequenceProps.from ?? 0,
11194
+ durationInFrames: durationInFrames ?? Infinity,
11195
+ premountFor: premountFor ?? null,
11196
+ postmountFor: postmountFor ?? null,
11197
+ style: style ?? null,
11198
+ styleWhilePremounted: styleWhilePremounted ?? null,
11199
+ styleWhilePostmounted: styleWhilePostmounted ?? null,
11200
+ hideWhilePremounted: "opacity"
11201
+ });
10816
11202
  const croppedStyle = useCropStyle({
10817
11203
  cropLeft,
10818
11204
  cropRight,
10819
11205
  cropTop,
10820
11206
  cropBottom,
10821
- style: style ?? null,
11207
+ style: premountingStyle,
10822
11208
  componentName: "<HtmlInCanvas />"
10823
11209
  });
10824
- return /* @__PURE__ */ jsx27(Sequence, {
10825
- durationInFrames,
10826
- name: name ?? "<HtmlInCanvas>",
10827
- _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/remotion/html-in-canvas",
10828
- controls,
10829
- _remotionInternalEffects: memoizedEffectDefinitions,
10830
- outlineRef: actualRef,
10831
- layout: "none",
10832
- ...sequenceProps,
10833
- children: /* @__PURE__ */ jsx27(HtmlInCanvasContent, {
10834
- ref: setCanvasRef,
10835
- width,
10836
- height,
10837
- effects,
10838
- onPaint,
10839
- onInit,
10840
- pixelDensity,
11210
+ return /* @__PURE__ */ jsx27(Freeze, {
11211
+ frame: freezeFrame,
11212
+ active: isPremountingOrPostmounting,
11213
+ children: /* @__PURE__ */ jsx27(Sequence, {
11214
+ layout: "none",
11215
+ durationInFrames,
11216
+ name: name ?? "<HtmlInCanvas>",
11217
+ _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/remotion/html-in-canvas",
10841
11218
  controls,
10842
- style: croppedStyle ?? undefined,
10843
- children
11219
+ _remotionInternalEffects: memoizedEffectDefinitions,
11220
+ outlineRef: actualRef,
11221
+ ...sequenceProps,
11222
+ _remotionInternalPremountDisplay: effectivePremountFor || null,
11223
+ _remotionInternalPostmountDisplay: effectivePostmountFor || null,
11224
+ _remotionInternalIsPremounting: premountingActive,
11225
+ _remotionInternalIsPostmounting: postmountingActive,
11226
+ children: /* @__PURE__ */ jsx27(HtmlInCanvasContent, {
11227
+ ref: setCanvasRef,
11228
+ width,
11229
+ height,
11230
+ effects,
11231
+ onPaint,
11232
+ onInit,
11233
+ pixelDensity,
11234
+ controls,
11235
+ style: croppedStyle ?? undefined,
11236
+ children
11237
+ })
10844
11238
  })
10845
11239
  });
10846
11240
  });
10847
11241
  HtmlInCanvasInner.displayName = "HtmlInCanvas";
10848
11242
  var htmlInCanvasSchema = {
10849
11243
  ...baseSchema,
11244
+ ...premountSchema,
10850
11245
  pixelDensity: {
10851
11246
  type: "number",
10852
11247
  min: 1,
@@ -10878,11 +11273,11 @@ addSequenceStackTraces(HtmlInCanvas);
10878
11273
  import {
10879
11274
  forwardRef as forwardRef10,
10880
11275
  useCallback as useCallback19,
10881
- useContext as useContext36,
11276
+ useContext as useContext38,
10882
11277
  useImperativeHandle as useImperativeHandle7,
10883
11278
  useLayoutEffect as useLayoutEffect13,
10884
- useMemo as useMemo32,
10885
- useRef as useRef24,
11279
+ useMemo as useMemo33,
11280
+ useRef as useRef25,
10886
11281
  useState as useState17
10887
11282
  } from "react";
10888
11283
 
@@ -10907,7 +11302,7 @@ var canvasImageSchema = {
10907
11302
  description: "Source",
10908
11303
  keyframable: false
10909
11304
  },
10910
- ...baseSchema,
11305
+ ...baseSchemaWithoutPlaybackRate,
10911
11306
  ...cropSchema,
10912
11307
  ...premountSchema,
10913
11308
  fit: {
@@ -11025,8 +11420,8 @@ var CanvasImageContent = forwardRef10(({
11025
11420
  effects,
11026
11421
  overrideId: controls?.overrideId ?? null
11027
11422
  });
11028
- const sequenceContext = useContext36(SequenceContext);
11029
- const pendingLoadDelayRef = useRef24(null);
11423
+ const sequenceContext = useContext38(SequenceContext);
11424
+ const pendingLoadDelayRef = useRef25(null);
11030
11425
  const [isLoadPending, setIsLoadPending] = useState17(false);
11031
11426
  const isPremounting = Boolean(sequenceContext?.premounting);
11032
11427
  const isPostmounting = Boolean(sequenceContext?.postmounting);
@@ -11042,7 +11437,7 @@ var CanvasImageContent = forwardRef10(({
11042
11437
  continueRender2(pending.handle);
11043
11438
  pendingLoadDelayRef.current = null;
11044
11439
  }, [continueRender2]);
11045
- const sourceCanvas = useMemo32(() => {
11440
+ const sourceCanvas = useMemo33(() => {
11046
11441
  if (typeof document === "undefined") {
11047
11442
  return null;
11048
11443
  }
@@ -11271,12 +11666,12 @@ var CanvasImageInner = forwardRef10(({
11271
11666
  if (!src) {
11272
11667
  throw new Error('No "src" prop was passed to <CanvasImage>.');
11273
11668
  }
11274
- const isMedia = useMemo32(() => ({
11669
+ const isMedia = useMemo33(() => ({
11275
11670
  type: "image",
11276
11671
  src
11277
11672
  }), [src]);
11278
11673
  const memoizedEffectDefinitions = useMemoizedEffectDefinitions(effects);
11279
- const actualRef = useRef24(null);
11674
+ const actualRef = useRef25(null);
11280
11675
  useImperativeHandle7(ref, () => {
11281
11676
  return actualRef.current;
11282
11677
  }, []);
@@ -11429,10 +11824,10 @@ var IFrame = forwardRef11(IFrameRefForwarding);
11429
11824
  // src/Img.tsx
11430
11825
  import {
11431
11826
  useCallback as useCallback21,
11432
- useContext as useContext37,
11827
+ useContext as useContext39,
11433
11828
  useLayoutEffect as useLayoutEffect14,
11434
- useMemo as useMemo33,
11435
- useRef as useRef25,
11829
+ useMemo as useMemo34,
11830
+ useRef as useRef26,
11436
11831
  useState as useState19
11437
11832
  } from "react";
11438
11833
  import { jsx as jsx30 } from "react/jsx-runtime";
@@ -11454,10 +11849,10 @@ var ImgContent = ({
11454
11849
  refForOutline,
11455
11850
  ...props2
11456
11851
  }) => {
11457
- const imageRef = useRef25(null);
11458
- const errors = useRef25({});
11852
+ const imageRef = useRef26(null);
11853
+ const errors = useRef26({});
11459
11854
  const { delayPlayback } = useBufferState();
11460
- const sequenceContext = useContext37(SequenceContext);
11855
+ const sequenceContext = useContext39(SequenceContext);
11461
11856
  const [isLoading, setIsLoading] = useState19(false);
11462
11857
  const _propsValid = true;
11463
11858
  if (!_propsValid) {
@@ -11624,7 +12019,7 @@ var NativeImgInner = ({
11624
12019
  if (!src) {
11625
12020
  throw new Error('No "src" prop was passed to <Img>.');
11626
12021
  }
11627
- const isMedia = useMemo33(() => ({
12022
+ const isMedia = useMemo34(() => ({
11628
12023
  type: "image",
11629
12024
  src
11630
12025
  }), [src]);
@@ -11692,7 +12087,7 @@ var imgSchema = {
11692
12087
  description: "Source",
11693
12088
  keyframable: false
11694
12089
  },
11695
- ...baseSchema,
12090
+ ...baseSchemaWithoutPlaybackRate,
11696
12091
  ...cropSchema,
11697
12092
  ...premountSchema,
11698
12093
  ...transformSchema,
@@ -11773,7 +12168,7 @@ var ImgInner = ({
11773
12168
  onImageError,
11774
12169
  ...props2
11775
12170
  }) => {
11776
- const refForOutline = useRef25(null);
12171
+ const refForOutline = useRef26(null);
11777
12172
  const shouldPauseWhenLoading = resolveV5Default(pauseWhenLoading);
11778
12173
  if (effects.length === 0) {
11779
12174
  return /* @__PURE__ */ jsx30(NativeImgInner, {
@@ -11867,7 +12262,7 @@ var Img = withInteractivitySchema({
11867
12262
  });
11868
12263
  addSequenceStackTraces(Img);
11869
12264
  // src/Interactive.tsx
11870
- import React33, { forwardRef as forwardRef12, useCallback as useCallback22, useRef as useRef26 } from "react";
12265
+ import React33, { forwardRef as forwardRef12, useCallback as useCallback22, useRef as useRef27 } from "react";
11871
12266
  import { jsx as jsx31 } from "react/jsx-runtime";
11872
12267
  var sourcePathToIdentityPrefix = (packageName) => {
11873
12268
  if (packageName === "remotion") {
@@ -11887,6 +12282,7 @@ var makeRemotionComponentIdentity = ({
11887
12282
  };
11888
12283
  var interactiveElementSchema = {
11889
12284
  ...baseSchema,
12285
+ ...premountSchema,
11890
12286
  ...transformSchema,
11891
12287
  ...cropSchema
11892
12288
  };
@@ -11914,6 +12310,15 @@ var interactiveSvgElementSchema = {
11914
12310
  ...interactiveElementSchema,
11915
12311
  ...svgPaintSchema
11916
12312
  };
12313
+ var interactiveSvgPathElementSchema = {
12314
+ ...interactiveSvgElementSchema,
12315
+ d: {
12316
+ type: "svg-path",
12317
+ default: undefined,
12318
+ description: "Path",
12319
+ keyframable: false
12320
+ }
12321
+ };
11917
12322
  var interactiveSvgStrokeElementSchema = {
11918
12323
  ...interactiveElementSchema,
11919
12324
  ...svgStrokeSchema
@@ -11939,7 +12344,12 @@ var makeInteractiveElement = (tag, displayName, schema) => {
11939
12344
  const {
11940
12345
  durationInFrames,
11941
12346
  from,
12347
+ premountFor,
12348
+ postmountFor,
12349
+ styleWhilePremounted,
12350
+ styleWhilePostmounted,
11942
12351
  trimBefore,
12352
+ playbackRate,
11943
12353
  freeze,
11944
12354
  hidden,
11945
12355
  name,
@@ -11952,35 +12362,62 @@ var makeInteractiveElement = (tag, displayName, schema) => {
11952
12362
  style,
11953
12363
  ...props2
11954
12364
  } = propsWithControls;
12365
+ const {
12366
+ effectivePremountFor,
12367
+ effectivePostmountFor,
12368
+ freezeFrame,
12369
+ isPremountingOrPostmounting,
12370
+ premountingActive,
12371
+ postmountingActive,
12372
+ premountingStyle
12373
+ } = usePremounting({
12374
+ from: from ?? 0,
12375
+ durationInFrames: durationInFrames ?? Infinity,
12376
+ premountFor: premountFor ?? null,
12377
+ postmountFor: postmountFor ?? null,
12378
+ style: style ?? null,
12379
+ styleWhilePremounted: styleWhilePremounted ?? null,
12380
+ styleWhilePostmounted: styleWhilePostmounted ?? null,
12381
+ hideWhilePremounted: "opacity"
12382
+ });
11955
12383
  const croppedStyle = useCropStyle({
11956
12384
  cropLeft,
11957
12385
  cropRight,
11958
12386
  cropTop,
11959
12387
  cropBottom,
11960
- style: style ?? null,
12388
+ style: premountingStyle,
11961
12389
  componentName: displayName
11962
12390
  });
11963
- const refForOutline = useRef26(null);
12391
+ const refForOutline = useRef27(null);
11964
12392
  const callbackRef = useCallback22((element) => {
11965
12393
  refForOutline.current = element;
11966
12394
  setRef2(ref, element);
11967
12395
  }, [ref]);
11968
- return /* @__PURE__ */ jsx31(Sequence, {
11969
- layout: "none",
11970
- from: from ?? 0,
11971
- trimBefore,
11972
- durationInFrames: durationInFrames ?? Infinity,
11973
- freeze,
11974
- hidden,
11975
- name: name ?? displayName,
11976
- showInTimeline: showInTimeline ?? true,
11977
- controls,
11978
- _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/interactive",
11979
- outlineRef: refForOutline,
11980
- children: React33.createElement(tag, {
11981
- ...props2,
11982
- style: croppedStyle ?? undefined,
11983
- ref: callbackRef
12396
+ return /* @__PURE__ */ jsx31(Freeze, {
12397
+ frame: freezeFrame,
12398
+ active: isPremountingOrPostmounting,
12399
+ children: /* @__PURE__ */ jsx31(Sequence, {
12400
+ layout: "none",
12401
+ from: from ?? 0,
12402
+ trimBefore,
12403
+ playbackRate,
12404
+ durationInFrames: durationInFrames ?? Infinity,
12405
+ freeze,
12406
+ hidden,
12407
+ name: name ?? displayName,
12408
+ showInTimeline: showInTimeline ?? true,
12409
+ controls,
12410
+ _remotionInternalDocumentationLink: "https://www.remotion.dev/docs/interactive",
12411
+ outlineRef: refForOutline,
12412
+ _remotionInternalPremountDisplay: effectivePremountFor || null,
12413
+ _remotionInternalPostmountDisplay: effectivePostmountFor || null,
12414
+ _remotionInternalIsPremounting: premountingActive,
12415
+ _remotionInternalIsPostmounting: postmountingActive,
12416
+ children: React33.createElement(tag, {
12417
+ ...props2,
12418
+ style: croppedStyle ?? undefined,
12419
+ ref: callbackRef
12420
+ })
11984
12421
  })
11985
12422
  });
11986
12423
  });
@@ -12047,7 +12484,7 @@ var Interactive = {
12047
12484
  Nav: makeInteractiveTextElement("nav", "<Interactive.Nav>"),
12048
12485
  Ol: makeInteractiveTextElement("ol", "<Interactive.Ol>"),
12049
12486
  P: makeInteractiveTextElement("p", "<Interactive.P>"),
12050
- Path: makeInteractiveSvgElement("path", "<Interactive.Path>"),
12487
+ Path: makeInteractiveElement("path", "<Interactive.Path>", interactiveSvgPathElementSchema),
12051
12488
  Pre: makeInteractiveTextElement("pre", "<Interactive.Pre>"),
12052
12489
  Rect: makeInteractiveSvgElement("rect", "<Interactive.Rect>"),
12053
12490
  Section: makeInteractiveTextElement("section", "<Interactive.Section>"),
@@ -12102,8 +12539,8 @@ import {
12102
12539
  useEffect as useEffect18,
12103
12540
  useImperativeHandle as useImperativeHandle8,
12104
12541
  useLayoutEffect as useLayoutEffect15,
12105
- useMemo as useMemo34,
12106
- useRef as useRef27,
12542
+ useMemo as useMemo35,
12543
+ useRef as useRef28,
12107
12544
  useState as useState20
12108
12545
  } from "react";
12109
12546
  import { jsx as jsx32 } from "react/jsx-runtime";
@@ -12117,21 +12554,21 @@ var CompositionManagerProvider = ({
12117
12554
  }) => {
12118
12555
  const { isStudio } = useRemotionEnvironment();
12119
12556
  const [compositionManagerId] = useState20(() => String(Math.random()));
12120
- const committedOrderRef = useRef27(null);
12121
- const committedOrderIdsRef = useRef27(null);
12122
- const internalOrderRef = useRef27(new Map(initialCompositions.map((composition, index) => [
12557
+ const committedOrderRef = useRef28(null);
12558
+ const committedOrderIdsRef = useRef28(null);
12559
+ const internalOrderRef = useRef28(new Map(initialCompositions.map((composition, index) => [
12123
12560
  getCompositionAndFolderOrderKey({
12124
12561
  type: "composition",
12125
12562
  id: composition.id
12126
12563
  }),
12127
12564
  index
12128
12565
  ])));
12129
- const nextInternalOrderRef = useRef27(initialCompositions.length);
12566
+ const nextInternalOrderRef = useRef28(initialCompositions.length);
12130
12567
  const [folders, setFolders] = useState20([]);
12131
12568
  const [canvasContent, setCanvasContent] = useState20(initialCanvasContent);
12132
12569
  const [currentAssetMetadata, setCurrentAssetMetadata] = useState20(null);
12133
12570
  const [compositions, setCompositions] = useState20(() => initialCompositions.map((composition, order) => ({ ...composition, order })));
12134
- const currentcompositionsRef = useRef27(compositions);
12571
+ const currentcompositionsRef = useRef28(compositions);
12135
12572
  const updateCompositions = useCallback23((updateComps) => {
12136
12573
  setCompositions((comps) => {
12137
12574
  const updated = updateComps(comps);
@@ -12265,7 +12702,7 @@ var CompositionManagerProvider = ({
12265
12702
  getCompositions: () => currentcompositionsRef.current
12266
12703
  };
12267
12704
  }, []);
12268
- const compositionManagerSetters = useMemo34(() => {
12705
+ const compositionManagerSetters = useMemo35(() => {
12269
12706
  return {
12270
12707
  registerComposition,
12271
12708
  unregisterComposition,
@@ -12282,7 +12719,7 @@ var CompositionManagerProvider = ({
12282
12719
  unregisterFolder,
12283
12720
  onlyRenderComposition
12284
12721
  ]);
12285
- const compositionManagerContextValue = useMemo34(() => {
12722
+ const compositionManagerContextValue = useMemo35(() => {
12286
12723
  return {
12287
12724
  compositions,
12288
12725
  folders,
@@ -12527,7 +12964,7 @@ var waitForRoot = (fn) => {
12527
12964
  };
12528
12965
 
12529
12966
  // src/RemotionRoot.tsx
12530
- import { useMemo as useMemo35 } from "react";
12967
+ import { useMemo as useMemo36 } from "react";
12531
12968
  import { jsx as jsx33 } from "react/jsx-runtime";
12532
12969
  var RemotionRootContexts = ({
12533
12970
  children,
@@ -12540,7 +12977,7 @@ var RemotionRootContexts = ({
12540
12977
  frameState,
12541
12978
  _experimentalKeepAudioContextAlive
12542
12979
  }) => {
12543
- const logging = useMemo35(() => {
12980
+ const logging = useMemo36(() => {
12544
12981
  return { logLevel, mountTime: Date.now() };
12545
12982
  }, [logLevel]);
12546
12983
  return /* @__PURE__ */ jsx33(LogLevelContext.Provider, {
@@ -12839,7 +13276,7 @@ var setupEnvVariables = () => {
12839
13276
  };
12840
13277
 
12841
13278
  // src/use-pixel-density.ts
12842
- import React39, { useContext as useContext38 } from "react";
13279
+ import React39, { useContext as useContext40 } from "react";
12843
13280
  var PixelDensityContext = React39.createContext(null);
12844
13281
  var getBrowserPixelDensity = () => {
12845
13282
  if (typeof window === "undefined") {
@@ -12848,8 +13285,8 @@ var getBrowserPixelDensity = () => {
12848
13285
  return window.devicePixelRatio || 1;
12849
13286
  };
12850
13287
  var usePixelDensity = (options) => {
12851
- const pixelDensity = useContext38(PixelDensityContext);
12852
- const canUseRemotionHooks = useContext38(CanUseRemotionHooks);
13288
+ const pixelDensity = useContext40(PixelDensityContext);
13289
+ const canUseRemotionHooks = useContext40(CanUseRemotionHooks);
12853
13290
  if (pixelDensity !== null) {
12854
13291
  return pixelDensity;
12855
13292
  }
@@ -12871,10 +13308,10 @@ import { useCallback as useCallback26 } from "react";
12871
13308
  // src/video/OffthreadVideoForRendering.tsx
12872
13309
  import {
12873
13310
  useCallback as useCallback24,
12874
- useContext as useContext39,
13311
+ useContext as useContext41,
12875
13312
  useEffect as useEffect19,
12876
13313
  useLayoutEffect as useLayoutEffect16,
12877
- useMemo as useMemo36,
13314
+ useMemo as useMemo37,
12878
13315
  useState as useState21
12879
13316
  } from "react";
12880
13317
 
@@ -12914,13 +13351,14 @@ var OffthreadVideoForRendering = ({
12914
13351
  const frame = useCurrentFrame();
12915
13352
  const volumePropsFrame = useFrameForVolumeProp(loopVolumeCurveBehavior);
12916
13353
  const videoConfig = useUnsafeVideoConfig();
12917
- const sequenceContext = useContext39(SequenceContext);
12918
- const mediaStartsAt = useMediaStartsAt();
12919
- const { registerRenderAsset, unregisterRenderAsset } = useContext39(RenderAssetManager);
13354
+ const sequenceContext = useContext41(SequenceContext);
13355
+ const sequencePlaybackRate = sequenceContext?.playbackRate ?? 1;
13356
+ const audioStartFrame = useContext41(Html5MediaTrimContext);
13357
+ const { registerRenderAsset, unregisterRenderAsset } = useContext41(RenderAssetManager);
12920
13358
  if (!src) {
12921
13359
  throw new TypeError("No `src` was passed to <OffthreadVideo>.");
12922
13360
  }
12923
- const id = useMemo36(() => `offthreadvideo-${random(src)}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.relativeFrom}-${sequenceContext?.durationInFrames}`, [
13361
+ const id = useMemo37(() => `offthreadvideo-${random(src)}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.relativeFrom}-${sequenceContext?.durationInFrames}`, [
12924
13362
  src,
12925
13363
  sequenceContext?.cumulatedFrom,
12926
13364
  sequenceContext?.relativeFrom,
@@ -12954,10 +13392,10 @@ var OffthreadVideoForRendering = ({
12954
13392
  id,
12955
13393
  frame: absoluteFrame,
12956
13394
  volume,
12957
- mediaFrame: frame,
12958
- playbackRate,
13395
+ mediaFrame: audioStartFrame + (frame - audioStartFrame) / sequencePlaybackRate,
13396
+ playbackRate: playbackRate * sequencePlaybackRate,
12959
13397
  toneFrequency,
12960
- audioStartFrame: Math.max(0, -(sequenceContext?.cumulatedNegativeFrom ?? 0)),
13398
+ audioStartFrame,
12961
13399
  audioStreamIndex
12962
13400
  });
12963
13401
  return () => unregisterRenderAsset(id);
@@ -12972,17 +13410,18 @@ var OffthreadVideoForRendering = ({
12972
13410
  absoluteFrame,
12973
13411
  playbackRate,
12974
13412
  toneFrequency,
12975
- sequenceContext?.cumulatedNegativeFrom,
13413
+ audioStartFrame,
13414
+ sequencePlaybackRate,
12976
13415
  audioStreamIndex
12977
13416
  ]);
12978
- const currentTime = useMemo36(() => {
13417
+ const currentTime = useMemo37(() => {
12979
13418
  return getExpectedMediaFrameUncorrected({
12980
13419
  frame,
12981
13420
  playbackRate: playbackRate || 1,
12982
- startFrom: -mediaStartsAt
13421
+ startFrom: audioStartFrame
12983
13422
  }) / videoConfig.fps;
12984
- }, [frame, mediaStartsAt, playbackRate, videoConfig.fps]);
12985
- const actualSrc = useMemo36(() => {
13423
+ }, [frame, audioStartFrame, playbackRate, videoConfig.fps]);
13424
+ const actualSrc = useMemo37(() => {
12986
13425
  return getOffthreadVideoSource({
12987
13426
  src,
12988
13427
  currentTime,
@@ -13070,7 +13509,7 @@ var OffthreadVideoForRendering = ({
13070
13509
  cancelRender("Failed to load image with src " + imageSrc);
13071
13510
  }
13072
13511
  }, [imageSrc, onError]);
13073
- const className = useMemo36(() => {
13512
+ const className = useMemo37(() => {
13074
13513
  return [OBJECTFIT_CONTAIN_CLASS_NAME, props2.className].filter(truthy).join(" ");
13075
13514
  }, [props2.className]);
13076
13515
  const onImageFrame = useCallback24((img) => {
@@ -13097,11 +13536,11 @@ var OffthreadVideoForRendering = ({
13097
13536
  import React41, {
13098
13537
  forwardRef as forwardRef13,
13099
13538
  useCallback as useCallback25,
13100
- useContext as useContext40,
13539
+ useContext as useContext42,
13101
13540
  useEffect as useEffect21,
13102
13541
  useImperativeHandle as useImperativeHandle9,
13103
- useMemo as useMemo37,
13104
- useRef as useRef28,
13542
+ useMemo as useMemo38,
13543
+ useRef as useRef29,
13105
13544
  useState as useState22
13106
13545
  } from "react";
13107
13546
 
@@ -13153,12 +13592,12 @@ class MediaPlaybackError extends Error {
13153
13592
  // src/video/VideoForPreview.tsx
13154
13593
  import { jsx as jsx35 } from "react/jsx-runtime";
13155
13594
  var VideoForDevelopmentRefForwardingFunction = (props2, ref) => {
13156
- const context = useContext40(SharedAudioContext);
13595
+ const context = useContext42(SharedAudioContext);
13157
13596
  if (!context) {
13158
13597
  throw new Error("SharedAudioContext not found");
13159
13598
  }
13160
- const videoRef = useRef28(null);
13161
- const sharedSource = useMemo37(() => {
13599
+ const videoRef = useRef29(null);
13600
+ const sharedSource = useMemo38(() => {
13162
13601
  if (!context.audioContext) {
13163
13602
  return null;
13164
13603
  }
@@ -13210,7 +13649,7 @@ var VideoForDevelopmentRefForwardingFunction = (props2, ref) => {
13210
13649
  }
13211
13650
  const volumePropFrame = useFrameForVolumeProp(loopVolumeCurveBehavior ?? "repeat");
13212
13651
  const { fps, durationInFrames } = useVideoConfig();
13213
- const parentSequence = useContext40(SequenceContext);
13652
+ const parentSequence = useContext42(SequenceContext);
13214
13653
  const { isStudio } = useRemotionEnvironment();
13215
13654
  const logLevel = useLogLevel();
13216
13655
  const mountTime = useMountTime();
@@ -13246,6 +13685,7 @@ var VideoForDevelopmentRefForwardingFunction = (props2, ref) => {
13246
13685
  premountDisplay: parentSequence?.premountDisplay ?? null,
13247
13686
  postmountDisplay: parentSequence?.postmountDisplay ?? null,
13248
13687
  loopDisplay: undefined,
13688
+ loopVolumeCurveBehavior: loopVolumeCurveBehavior ?? "repeat",
13249
13689
  documentationLink: onlyWarnForMediaSeekingError ? "https://www.remotion.dev/docs/offthreadvideo" : "https://www.remotion.dev/docs/html5-video",
13250
13690
  refForOutline: videoRef,
13251
13691
  muted: isMutedForTimeline
@@ -13336,7 +13776,7 @@ var VideoForDevelopmentRefForwardingFunction = (props2, ref) => {
13336
13776
  current.removeEventListener("error", errorHandler);
13337
13777
  };
13338
13778
  }, [onError, src]);
13339
- const currentOnDurationCallback = useRef28(onDuration);
13779
+ const currentOnDurationCallback = useRef29(onDuration);
13340
13780
  currentOnDurationCallback.current = onDuration;
13341
13781
  useEmitVideoFrame({ ref: videoRef, onVideoFrame });
13342
13782
  useEffect21(() => {
@@ -13367,7 +13807,7 @@ var VideoForDevelopmentRefForwardingFunction = (props2, ref) => {
13367
13807
  current.preload = "auto";
13368
13808
  }
13369
13809
  }, []);
13370
- const actualStyle = useMemo37(() => {
13810
+ const actualStyle = useMemo38(() => {
13371
13811
  return {
13372
13812
  ...style
13373
13813
  };
@@ -13429,22 +13869,25 @@ var InnerOffthreadVideo = (props2) => {
13429
13869
  trimAfter
13430
13870
  });
13431
13871
  if (typeof trimBeforeValue !== "undefined" || typeof trimAfterValue !== "undefined") {
13432
- return /* @__PURE__ */ jsx36(Sequence, {
13433
- layout: "none",
13434
- from: 0 - (trimBeforeValue ?? 0),
13435
- showInTimeline: false,
13436
- durationInFrames: trimAfterValue,
13437
- name,
13438
- children: /* @__PURE__ */ jsx36(InnerOffthreadVideo, {
13439
- pauseWhenBuffering: shouldPauseWhenBuffering,
13440
- ...otherProps,
13441
- trimAfter: undefined,
13442
- name: undefined,
13443
- showInTimeline,
13444
- trimBefore: undefined,
13445
- _remotionInternalStack: undefined,
13446
- startFrom: undefined,
13447
- endAt: undefined
13872
+ return /* @__PURE__ */ jsx36(Html5MediaTrimContext.Provider, {
13873
+ value: trimBeforeValue ?? 0,
13874
+ children: /* @__PURE__ */ jsx36(Sequence, {
13875
+ layout: "none",
13876
+ from: 0 - (trimBeforeValue ?? 0),
13877
+ showInTimeline: false,
13878
+ durationInFrames: trimAfterValue === undefined ? undefined : (trimBeforeValue ?? 0) + (trimAfterValue - (trimBeforeValue ?? 0)) / (props2.playbackRate ?? 1),
13879
+ name,
13880
+ children: /* @__PURE__ */ jsx36(InnerOffthreadVideo, {
13881
+ pauseWhenBuffering: shouldPauseWhenBuffering,
13882
+ ...otherProps,
13883
+ trimAfter: undefined,
13884
+ name: undefined,
13885
+ showInTimeline,
13886
+ trimBefore: undefined,
13887
+ _remotionInternalStack: undefined,
13888
+ startFrom: undefined,
13889
+ endAt: undefined
13890
+ })
13448
13891
  })
13449
13892
  });
13450
13893
  }
@@ -13594,7 +14037,7 @@ var watchStaticFile = (fileName, callback) => {
13594
14037
  };
13595
14038
 
13596
14039
  // src/wrap-remotion-context.tsx
13597
- import React43, { useMemo as useMemo38 } from "react";
14040
+ import React43, { useMemo as useMemo39 } from "react";
13598
14041
  import { jsx as jsx37 } from "react/jsx-runtime";
13599
14042
  function useRemotionContexts() {
13600
14043
  const compositionManagerCtx = React43.useContext(CompositionManager);
@@ -13610,7 +14053,7 @@ function useRemotionContexts() {
13610
14053
  const visualModePropStatusesRefContext = React43.useContext(VisualModePropStatusesRefContext);
13611
14054
  const bufferManagerContext = React43.useContext(BufferingContextReact);
13612
14055
  const logLevelContext = React43.useContext(LogLevelContext);
13613
- return useMemo38(() => ({
14056
+ return useMemo39(() => ({
13614
14057
  compositionManagerCtx,
13615
14058
  timelineContext,
13616
14059
  setTimelineContext,
@@ -13826,6 +14269,7 @@ var Internals = {
13826
14269
  useAudioEnabled,
13827
14270
  useBuffering,
13828
14271
  TimelinePosition: exports_timeline_position_state,
14272
+ useTimelineSeek,
13829
14273
  DelayRenderContextType,
13830
14274
  TimelineContext,
13831
14275
  usePlaying,
@@ -13868,7 +14312,7 @@ var fontDataByUrl = new Map;
13868
14312
  // src/series/index.tsx
13869
14313
  import React45, {
13870
14314
  forwardRef as forwardRef14,
13871
- useMemo as useMemo39
14315
+ useMemo as useMemo40
13872
14316
  } from "react";
13873
14317
 
13874
14318
  // src/series/flatten-children.tsx
@@ -13893,6 +14337,7 @@ var seriesSequenceSchema = {
13893
14337
  showInTimeline: Interactive.sequenceSchema.showInTimeline,
13894
14338
  freeze: Interactive.baseSchema.freeze,
13895
14339
  trimBefore: Interactive.sequenceSchema.trimBefore,
14340
+ playbackRate: Interactive.sequenceSchema.playbackRate,
13896
14341
  layout: Interactive.sequenceSchema.layout
13897
14342
  };
13898
14343
  var SeriesSequenceInner = forwardRef14(({ offset = 0, className = "", _remotionInternalRender = null, ...props2 }, ref) => {
@@ -13938,7 +14383,7 @@ var validateSeriesSequenceProps = ({
13938
14383
  return offset;
13939
14384
  };
13940
14385
  var SeriesInner = (props2) => {
13941
- const childrenValue = useMemo39(() => {
14386
+ const childrenValue = useMemo40(() => {
13942
14387
  const flattenedChildren = flattenChildren(props2.children);
13943
14388
  const renderChildren = (i, startFrame) => {
13944
14389
  if (i === flattenedChildren.length) {
@@ -14132,17 +14577,17 @@ var Still = (props2) => {
14132
14577
  };
14133
14578
  addSequenceStackTraces(Still);
14134
14579
  // src/video/html5-video.tsx
14135
- import { forwardRef as forwardRef16, useCallback as useCallback27, useContext as useContext42 } from "react";
14580
+ import { forwardRef as forwardRef16, useCallback as useCallback27, useContext as useContext44 } from "react";
14136
14581
 
14137
14582
  // src/video/VideoForRendering.tsx
14138
14583
  import {
14139
14584
  forwardRef as forwardRef15,
14140
- useContext as useContext41,
14585
+ useContext as useContext43,
14141
14586
  useEffect as useEffect22,
14142
14587
  useImperativeHandle as useImperativeHandle10,
14143
14588
  useLayoutEffect as useLayoutEffect17,
14144
- useMemo as useMemo40,
14145
- useRef as useRef29
14589
+ useMemo as useMemo41,
14590
+ useRef as useRef30
14146
14591
  } from "react";
14147
14592
 
14148
14593
  // src/video/seek-until-right.ts
@@ -14292,15 +14737,16 @@ var VideoForRenderingForwardFunction = ({
14292
14737
  const frame = useCurrentFrame();
14293
14738
  const volumePropsFrame = useFrameForVolumeProp(loopVolumeCurveBehavior ?? "repeat");
14294
14739
  const videoConfig = useUnsafeVideoConfig();
14295
- const videoRef = useRef29(null);
14296
- const sequenceContext = useContext41(SequenceContext);
14297
- const mediaStartsAt = useMediaStartsAt();
14740
+ const videoRef = useRef30(null);
14741
+ const sequenceContext = useContext43(SequenceContext);
14742
+ const sequencePlaybackRate = sequenceContext?.playbackRate ?? 1;
14743
+ const audioStartFrame = useContext43(Html5MediaTrimContext);
14298
14744
  const environment = useRemotionEnvironment();
14299
14745
  const logLevel = useLogLevel();
14300
14746
  const mountTime = useMountTime();
14301
14747
  const { delayRender: delayRender2, continueRender: continueRender2 } = useDelayRender();
14302
- const { registerRenderAsset, unregisterRenderAsset } = useContext41(RenderAssetManager);
14303
- const id = useMemo40(() => `video-${random(props2.src ?? "")}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.relativeFrom}-${sequenceContext?.durationInFrames}`, [
14748
+ const { registerRenderAsset, unregisterRenderAsset } = useContext43(RenderAssetManager);
14749
+ const id = useMemo41(() => `video-${random(props2.src ?? "")}-${sequenceContext?.cumulatedFrom}-${sequenceContext?.relativeFrom}-${sequenceContext?.durationInFrames}`, [
14304
14750
  props2.src,
14305
14751
  sequenceContext?.cumulatedFrom,
14306
14752
  sequenceContext?.relativeFrom,
@@ -14334,10 +14780,10 @@ var VideoForRenderingForwardFunction = ({
14334
14780
  id,
14335
14781
  frame: absoluteFrame,
14336
14782
  volume,
14337
- mediaFrame: frame,
14338
- playbackRate: playbackRate ?? 1,
14783
+ mediaFrame: audioStartFrame + (frame - audioStartFrame) / sequencePlaybackRate,
14784
+ playbackRate: (playbackRate ?? 1) * sequencePlaybackRate,
14339
14785
  toneFrequency: toneFrequency ?? 1,
14340
- audioStartFrame: Math.max(0, -(sequenceContext?.cumulatedNegativeFrom ?? 0)),
14786
+ audioStartFrame,
14341
14787
  audioStreamIndex: audioStreamIndex ?? 0
14342
14788
  });
14343
14789
  return () => unregisterRenderAsset(id);
@@ -14352,7 +14798,8 @@ var VideoForRenderingForwardFunction = ({
14352
14798
  absoluteFrame,
14353
14799
  playbackRate,
14354
14800
  toneFrequency,
14355
- sequenceContext?.cumulatedNegativeFrom,
14801
+ audioStartFrame,
14802
+ sequencePlaybackRate,
14356
14803
  audioStreamIndex
14357
14804
  ]);
14358
14805
  useImperativeHandle10(ref, () => {
@@ -14370,7 +14817,7 @@ var VideoForRenderingForwardFunction = ({
14370
14817
  const currentTime = getMediaTime({
14371
14818
  frame,
14372
14819
  playbackRate: playbackRate || 1,
14373
- startFrom: -mediaStartsAt,
14820
+ startFrom: audioStartFrame,
14374
14821
  fps: videoConfig.fps
14375
14822
  });
14376
14823
  const handle = delayRender2(`Rendering <Html5Video /> with src="${props2.src}" at time ${currentTime}`, {
@@ -14438,7 +14885,7 @@ var VideoForRenderingForwardFunction = ({
14438
14885
  playbackRate,
14439
14886
  videoConfig.fps,
14440
14887
  frame,
14441
- mediaStartsAt,
14888
+ audioStartFrame,
14442
14889
  onError,
14443
14890
  delayRenderRetries,
14444
14891
  delayRenderTimeoutInMilliseconds,
@@ -14515,7 +14962,7 @@ var VideoForwardingFunction = (props2, ref) => {
14515
14962
  if (environment.isClientSideRendering) {
14516
14963
  throw new Error("<Html5Video> is not supported in @remotion/web-renderer. Use <Video> from @remotion/media instead. See https://remotion.dev/docs/client-side-rendering/limitations");
14517
14964
  }
14518
- const { durations, setDurations } = useContext42(DurationsContext);
14965
+ const { durations, setDurations } = useContext44(DurationsContext);
14519
14966
  if (typeof ref === "string") {
14520
14967
  throw new Error("string refs are not supported");
14521
14968
  }
@@ -14534,8 +14981,9 @@ var VideoForwardingFunction = (props2, ref) => {
14534
14981
  trimBefore,
14535
14982
  trimAfter
14536
14983
  });
14537
- if (loop && durationFetched !== undefined) {
14538
- if (!Number.isFinite(durationFetched)) {
14984
+ const loopDuration = trimAfterValue ?? (durationFetched === undefined ? undefined : durationFetched * fps);
14985
+ if (loop && loopDuration !== undefined) {
14986
+ if (!Number.isFinite(loopDuration)) {
14539
14987
  return /* @__PURE__ */ jsx40(Html5Video, {
14540
14988
  ...propsOtherThanLoop,
14541
14989
  ref,
@@ -14543,11 +14991,10 @@ var VideoForwardingFunction = (props2, ref) => {
14543
14991
  _remotionInternalNativeLoopPassed: true
14544
14992
  });
14545
14993
  }
14546
- const mediaDuration = durationFetched * fps;
14547
14994
  return /* @__PURE__ */ jsx40(Loop, {
14548
14995
  durationInFrames: calculateMediaDuration({
14549
14996
  trimAfter: trimAfterValue,
14550
- mediaDurationInFrames: mediaDuration,
14997
+ mediaDurationInFrames: loopDuration,
14551
14998
  playbackRate: props2.playbackRate ?? 1,
14552
14999
  trimBefore: trimBeforeValue
14553
15000
  }),
@@ -14563,18 +15010,21 @@ var VideoForwardingFunction = (props2, ref) => {
14563
15010
  });
14564
15011
  }
14565
15012
  if (typeof trimBeforeValue !== "undefined" || typeof trimAfterValue !== "undefined") {
14566
- return /* @__PURE__ */ jsx40(Sequence, {
14567
- layout: "none",
14568
- from: 0 - (trimBeforeValue ?? 0),
14569
- showInTimeline: false,
14570
- durationInFrames: trimAfterValue === undefined ? undefined : trimAfterValue / (props2.playbackRate ?? 1),
14571
- name,
14572
- children: /* @__PURE__ */ jsx40(Html5Video, {
14573
- pauseWhenBuffering: shouldPauseWhenBuffering,
14574
- onVideoFrame,
14575
- ...otherProps,
14576
- ref,
14577
- _remotionInternalStack
15013
+ return /* @__PURE__ */ jsx40(Html5MediaTrimContext.Provider, {
15014
+ value: trimBeforeValue ?? 0,
15015
+ children: /* @__PURE__ */ jsx40(Sequence, {
15016
+ layout: "none",
15017
+ from: 0 - (trimBeforeValue ?? 0),
15018
+ showInTimeline: false,
15019
+ durationInFrames: trimAfterValue === undefined ? undefined : (trimBeforeValue ?? 0) + (trimAfterValue - (trimBeforeValue ?? 0)) / (props2.playbackRate ?? 1),
15020
+ name,
15021
+ children: /* @__PURE__ */ jsx40(Html5Video, {
15022
+ pauseWhenBuffering: shouldPauseWhenBuffering,
15023
+ onVideoFrame,
15024
+ ...otherProps,
15025
+ ref,
15026
+ _remotionInternalStack
15027
+ })
14578
15028
  })
14579
15029
  });
14580
15030
  }