"use client"; // src/icons.tsx import { jsx, jsxs } from "react/jsx-runtime"; var ICON_SIZE = 25; var fullscreenIconSize = 16; var PlayIcon = () => { return /* @__PURE__ */ jsx("svg", { width: ICON_SIZE, height: ICON_SIZE, viewBox: "0 0 25 25", fill: "none", children: /* @__PURE__ */ jsx("path", { d: "M8 6.375C7.40904 8.17576 7.06921 10.2486 7.01438 12.3871C6.95955 14.5255 7.19163 16.6547 7.6875 18.5625C9.95364 18.2995 12.116 17.6164 14.009 16.5655C15.902 15.5147 17.4755 14.124 18.6088 12.5C17.5158 10.8949 15.9949 9.51103 14.1585 8.45082C12.3222 7.3906 10.2174 6.68116 8 6.375Z", fill: "white", stroke: "white", strokeWidth: "6.25", strokeLinejoin: "round" }) }); }; var PauseIcon = () => { return /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 100 100", width: ICON_SIZE, height: ICON_SIZE, children: [ /* @__PURE__ */ jsx("rect", { x: "25", y: "20", width: "20", height: "60", fill: "#fff", ry: "5", rx: "5" }), /* @__PURE__ */ jsx("rect", { x: "55", y: "20", width: "20", height: "60", fill: "#fff", ry: "5", rx: "5" }) ] }); }; var FullscreenIcon = ({ isFullscreen }) => { const strokeWidth = 6; const viewSize = 32; const out = isFullscreen ? 0 : strokeWidth / 2; const middleInset = isFullscreen ? strokeWidth * 1.6 : strokeWidth / 2; const inset = isFullscreen ? strokeWidth * 1.6 : strokeWidth * 2; return /* @__PURE__ */ jsxs("svg", { viewBox: `0 0 ${viewSize} ${viewSize}`, height: fullscreenIconSize, width: fullscreenIconSize, children: [ /* @__PURE__ */ jsx("path", { d: ` M ${out} ${inset} L ${middleInset} ${middleInset} L ${inset} ${out} `, stroke: "#fff", strokeWidth, fill: "none" }), /* @__PURE__ */ jsx("path", { d: ` M ${viewSize - out} ${inset} L ${viewSize - middleInset} ${middleInset} L ${viewSize - inset} ${out} `, stroke: "#fff", strokeWidth, fill: "none" }), /* @__PURE__ */ jsx("path", { d: ` M ${out} ${viewSize - inset} L ${middleInset} ${viewSize - middleInset} L ${inset} ${viewSize - out} `, stroke: "#fff", strokeWidth, fill: "none" }), /* @__PURE__ */ jsx("path", { d: ` M ${viewSize - out} ${viewSize - inset} L ${viewSize - middleInset} ${viewSize - middleInset} L ${viewSize - inset} ${viewSize - out} `, stroke: "#fff", strokeWidth, fill: "none" }) ] }); }; var VolumeOffIcon = () => { return /* @__PURE__ */ jsx("svg", { width: ICON_SIZE, height: ICON_SIZE, viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { d: "M3.63 3.63a.996.996 0 000 1.41L7.29 8.7 7 9H4c-.55 0-1 .45-1 1v4c0 .55.45 1 1 1h3l3.29 3.29c.63.63 1.71.18 1.71-.71v-4.17l4.18 4.18c-.49.37-1.02.68-1.6.91-.36.15-.58.53-.58.92 0 .72.73 1.18 1.39.91.8-.33 1.55-.77 2.22-1.31l1.34 1.34a.996.996 0 101.41-1.41L5.05 3.63c-.39-.39-1.02-.39-1.42 0zM19 12c0 .82-.15 1.61-.41 2.34l1.53 1.53c.56-1.17.88-2.48.88-3.87 0-3.83-2.4-7.11-5.78-8.4-.59-.23-1.22.23-1.22.86v.19c0 .38.25.71.61.85C17.18 6.54 19 9.06 19 12zm-8.71-6.29l-.17.17L12 7.76V6.41c0-.89-1.08-1.33-1.71-.7zM16.5 12A4.5 4.5 0 0014 7.97v1.79l2.48 2.48c.01-.08.02-.16.02-.24z", fill: "#fff" }) }); }; var VolumeOnIcon = () => { return /* @__PURE__ */ jsx("svg", { width: ICON_SIZE, height: ICON_SIZE, viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx("path", { d: "M3 10v4c0 .55.45 1 1 1h3l3.29 3.29c.63.63 1.71.18 1.71-.71V6.41c0-.89-1.08-1.34-1.71-.71L7 9H4c-.55 0-1 .45-1 1zm13.5 2A4.5 4.5 0 0014 7.97v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 4.45v.2c0 .38.25.71.6.85C17.18 6.53 19 9.06 19 12s-1.82 5.47-4.4 6.5c-.36.14-.6.47-.6.85v.2c0 .63.63 1.07 1.21.85C18.6 19.11 21 15.84 21 12s-2.4-7.11-5.79-8.4c-.58-.23-1.21.22-1.21.85z", fill: "#fff" }) }); }; // src/BufferingIndicator.tsx import { jsx as jsx2, jsxs as jsxs2, Fragment } from "react/jsx-runtime"; var className = "__remotion_buffering_indicator"; var remotionBufferingAnimation = "__remotion_buffering_animation"; var playerStyle = { width: ICON_SIZE, height: ICON_SIZE, overflow: "hidden", lineHeight: "normal", fontSize: "inherit" }; var studioStyle = { width: 14, height: 14, overflow: "hidden", lineHeight: "normal", fontSize: "inherit" }; var BufferingIndicator = ({ type }) => { const style = type === "player" ? playerStyle : studioStyle; return /* @__PURE__ */ jsxs2(Fragment, { children: [ /* @__PURE__ */ jsx2("style", { type: "text/css", children: ` @keyframes ${remotionBufferingAnimation} { 0% { rotate: 0deg; } 100% { rotate: 360deg; } } .${className} { animation: ${remotionBufferingAnimation} 1s linear infinite; } ` }), /* @__PURE__ */ jsx2("div", { style, children: /* @__PURE__ */ jsx2("svg", { viewBox: type === "player" ? "0 0 22 22" : "0 0 18 18", style, className, children: /* @__PURE__ */ jsx2("path", { d: type === "player" ? "M 11 4 A 7 7 0 0 1 15.1145 16.66312" : "M 9 2 A 7 7 0 0 1 13.1145 14.66312", stroke: "white", strokeLinecap: "round", fill: "none", strokeWidth: 3 }) }) }) ] }); }; // src/calculate-scale.ts import { Internals } from "remotion"; // src/utils/calculate-player-size.ts var calculatePlayerSize = ({ currentSize, width, height, compositionWidth, compositionHeight }) => { if (width !== undefined && height === undefined) { return { aspectRatio: [compositionWidth, compositionHeight].join("/") }; } if (height !== undefined && width === undefined) { return { aspectRatio: [compositionWidth, compositionHeight].join("/") }; } if (!currentSize) { return { width: compositionWidth, height: compositionHeight }; } return { width: compositionWidth, height: compositionHeight }; }; // src/calculate-scale.ts var calculateCanvasTransformation = ({ previewSize, compositionWidth, compositionHeight, canvasSize }) => { const scale = Internals.calculateScale({ canvasSize, compositionHeight, compositionWidth, previewSize }); const correction = 0 - (1 - scale) / 2; const xCorrection = correction * compositionWidth; const yCorrection = correction * compositionHeight; const width = compositionWidth * scale; const height = compositionHeight * scale; const centerX = canvasSize.width / 2 - width / 2; const centerY = canvasSize.height / 2 - height / 2; return { centerX, centerY, xCorrection, yCorrection, scale }; }; var calculateOuterStyle = ({ config, style, canvasSize, overflowVisible, layout }) => { if (!config) { return {}; } return { position: "relative", overflow: overflowVisible ? "visible" : "hidden", ...calculatePlayerSize({ compositionHeight: config.height, compositionWidth: config.width, currentSize: canvasSize, height: style?.height, width: style?.width }), opacity: layout ? 1 : 0, ...style }; }; var calculateContainerStyle = ({ config, layout, scale, overflowVisible }) => { if (!config) { return {}; } if (!layout) { return { position: "absolute", width: config.width, height: config.height, display: "flex", transform: `scale(${scale})`, overflow: overflowVisible ? "visible" : "hidden" }; } return { position: "absolute", width: config.width, height: config.height, display: "flex", transform: `scale(${scale})`, marginLeft: layout.xCorrection, marginTop: layout.yCorrection, overflow: overflowVisible ? "visible" : "hidden" }; }; var calculateOuter = ({ layout, scale, config, overflowVisible }) => { if (!config) { return {}; } if (!layout) { return { width: config.width * scale, height: config.height * scale, display: "flex", flexDirection: "column", position: "absolute", overflow: overflowVisible ? "visible" : "hidden" }; } const { centerX, centerY } = layout; return { width: config.width * scale, height: config.height * scale, display: "flex", flexDirection: "column", position: "absolute", left: centerX, top: centerY, overflow: overflowVisible ? "visible" : "hidden" }; }; // src/emitter-context.ts import React from "react"; var PlayerEventEmitterContext = React.createContext(undefined); var ThumbnailEmitterContext = React.createContext(undefined); // src/EmitterProvider.tsx import { useContext as useContext2, useEffect, useState } from "react"; import { Internals as Internals3 } from "remotion"; // src/event-emitter.ts class PlayerEmitter { listeners = { ended: [], error: [], pause: [], play: [], ratechange: [], scalechange: [], seeked: [], timeupdate: [], frameupdate: [], fullscreenchange: [], volumechange: [], mutechange: [], waiting: [], resume: [] }; addEventListener(name, callback) { this.listeners[name].push(callback); } removeEventListener(name, callback) { this.listeners[name] = this.listeners[name].filter((l) => l !== callback); } dispatchEvent(dispatchName, context) { this.listeners[dispatchName].forEach((callback) => { callback({ detail: context }); }); } dispatchSeek = (frame) => { this.dispatchEvent("seeked", { frame }); }; dispatchVolumeChange = (volume) => { this.dispatchEvent("volumechange", { volume }); }; dispatchPause = () => { this.dispatchEvent("pause", undefined); }; dispatchPlay = () => { this.dispatchEvent("play", undefined); }; dispatchEnded = () => { this.dispatchEvent("ended", undefined); }; dispatchRateChange = (playbackRate) => { this.dispatchEvent("ratechange", { playbackRate }); }; dispatchScaleChange = (scale) => { this.dispatchEvent("scalechange", { scale }); }; dispatchError = (error) => { this.dispatchEvent("error", { error }); }; dispatchTimeUpdate = (event) => { this.dispatchEvent("timeupdate", event); }; dispatchFrameUpdate = (event) => { this.dispatchEvent("frameupdate", event); }; dispatchFullscreenChange = (event) => { this.dispatchEvent("fullscreenchange", event); }; dispatchMuteChange = (event) => { this.dispatchEvent("mutechange", event); }; dispatchWaiting = (event) => { this.dispatchEvent("waiting", event); }; dispatchResume = (event) => { this.dispatchEvent("resume", event); }; } class ThumbnailEmitter { listeners = { error: [], waiting: [], resume: [] }; addEventListener(name, callback) { this.listeners[name].push(callback); } removeEventListener(name, callback) { this.listeners[name] = this.listeners[name].filter((l) => l !== callback); } dispatchEvent(dispatchName, context) { this.listeners[dispatchName].forEach((callback) => { callback({ detail: context }); }); } dispatchError = (error) => { this.dispatchEvent("error", { error }); }; dispatchWaiting = (event) => { this.dispatchEvent("waiting", event); }; dispatchResume = (event) => { this.dispatchEvent("resume", event); }; } // src/use-buffer-state-emitter.ts import { useContext, useLayoutEffect } from "react"; import { Internals as Internals2 } from "remotion"; var useBufferStateEmitter = (emitter) => { const bufferManager = useContext(Internals2.BufferingContextReact); if (!bufferManager) { throw new Error("BufferingContextReact not found"); } useLayoutEffect(() => { const clear1 = bufferManager.listenForBuffering(() => { bufferManager.buffering.current = true; emitter.dispatchWaiting({}); }); const clear2 = bufferManager.listenForResume(() => { bufferManager.buffering.current = false; emitter.dispatchResume({}); }); return () => { clear1.remove(); clear2.remove(); }; }, [bufferManager, emitter]); }; // src/EmitterProvider.tsx import { jsx as jsx3 } from "react/jsx-runtime"; var PlayerEmitterProvider = ({ children, currentPlaybackRate }) => { const [emitter] = useState(() => new PlayerEmitter); const bufferManager = useContext2(Internals3.BufferingContextReact); if (!bufferManager) { throw new Error("BufferingContextReact not found"); } useEffect(() => { if (currentPlaybackRate) { emitter.dispatchRateChange(currentPlaybackRate); } }, [emitter, currentPlaybackRate]); useBufferStateEmitter(emitter); return /* @__PURE__ */ jsx3(PlayerEventEmitterContext.Provider, { value: emitter, children }); }; // src/use-frame-imperative.ts import { useCallback, useRef } from "react"; import { Internals as Internals4 } from "remotion"; var useFrameImperative = () => { const frame = Internals4.Timeline.useTimelinePosition(); const frameRef = useRef(frame); frameRef.current = frame; const getCurrentFrame = useCallback(() => { return frameRef.current; }, []); return getCurrentFrame; }; // src/use-hover-state.ts import { useEffect as useEffect2, useState as useState2 } from "react"; var useHoverState = (ref, hideControlsWhenPointerDoesntMove) => { const [hovered, setHovered] = useState2(false); useEffect2(() => { const { current } = ref; if (!current) { return; } let hoverTimeout; const addHoverTimeout = () => { if (hideControlsWhenPointerDoesntMove) { clearTimeout(hoverTimeout); hoverTimeout = setTimeout(() => { setHovered(false); }, hideControlsWhenPointerDoesntMove === true ? 3000 : hideControlsWhenPointerDoesntMove); } }; const onHover = () => { setHovered(true); addHoverTimeout(); }; const onLeave = () => { setHovered(false); clearTimeout(hoverTimeout); }; const onMove = () => { setHovered(true); addHoverTimeout(); }; current.addEventListener("mouseenter", onHover); current.addEventListener("mouseleave", onLeave); current.addEventListener("mousemove", onMove); return () => { current.removeEventListener("mouseenter", onHover); current.removeEventListener("mouseleave", onLeave); current.removeEventListener("mousemove", onMove); clearTimeout(hoverTimeout); }; }, [hideControlsWhenPointerDoesntMove, ref]); return hovered; }; // src/use-playback.ts import { useContext as useContext4, useEffect as useEffect5, useRef as useRef4 } from "react"; import { Internals as Internals6 } from "remotion"; // src/browser-mediasession.ts import { useEffect as useEffect3 } from "react"; // src/use-player.ts import { useCallback as useCallback2, useContext as useContext3, useMemo, useRef as useRef2, useState as useState3 } from "react"; import { Internals as Internals5 } from "remotion"; var usePlayer = () => { const [playing, setPlaying, imperativePlaying] = Internals5.Timeline.usePlayingState(); const [hasPlayed, setHasPlayed] = useState3(false); const frame = Internals5.Timeline.useTimelinePosition(); const playStart = useRef2(frame); const setFrame = Internals5.Timeline.useTimelineSetFrame(); const setTimelinePosition = Internals5.Timeline.useTimelineSetFrame(); const audioContext = useContext3(Internals5.SharedAudioContext); const { audioAndVideoTags } = useContext3(Internals5.TimelineContext); const frameRef = useRef2(frame); frameRef.current = frame; const video = Internals5.useVideo(); const config = Internals5.useUnsafeVideoConfig(); const emitter = useContext3(PlayerEventEmitterContext); const lastFrame = (config?.durationInFrames ?? 1) - 1; const isLastFrame = frame === lastFrame; const isFirstFrame = frame === 0; if (!emitter) { throw new TypeError("Expected Player event emitter context"); } const bufferingContext = useContext3(Internals5.BufferingContextReact); if (!bufferingContext) { throw new Error("Missing the buffering context. Most likely you have a Remotion version mismatch."); } const { buffering } = bufferingContext; const seek = useCallback2((newFrame) => { if (video?.id) { setTimelinePosition((c) => ({ ...c, [video.id]: newFrame })); } frameRef.current = newFrame; emitter.dispatchSeek(newFrame); }, [emitter, setTimelinePosition, video?.id]); const play = useCallback2((e) => { if (imperativePlaying.current) { return; } setHasPlayed(true); if (isLastFrame) { seek(0); } audioContext?.audioContext?.resume(); if (audioContext && audioContext.numberOfAudioTags > 0 && e) { audioContext.playAllAudios(); } audioAndVideoTags.current.forEach((a) => a.play("player play() was called and playing audio from a click")); imperativePlaying.current = true; setPlaying(true); playStart.current = frameRef.current; emitter.dispatchPlay(); }, [ imperativePlaying, isLastFrame, audioContext, setPlaying, emitter, seek, audioAndVideoTags ]); const pause = useCallback2(() => { if (imperativePlaying.current) { imperativePlaying.current = false; setPlaying(false); emitter.dispatchPause(); audioContext?.audioContext?.suspend(); } }, [emitter, imperativePlaying, setPlaying, audioContext]); const pauseAndReturnToPlayStart = useCallback2(() => { if (imperativePlaying.current) { imperativePlaying.current = false; frameRef.current = playStart.current; if (config) { setTimelinePosition((c) => ({ ...c, [config.id]: playStart.current })); setPlaying(false); emitter.dispatchPause(); } } }, [config, emitter, imperativePlaying, setPlaying, setTimelinePosition]); const videoId = video?.id; const frameBack = useCallback2((frames) => { if (!videoId) { return null; } if (imperativePlaying.current) { return; } setFrame((c) => { const prevFrame = c[videoId] ?? window.remotion_initialFrame ?? 0; const newFrame = Math.max(0, prevFrame - frames); if (prevFrame === newFrame) { return c; } return { ...c, [videoId]: newFrame }; }); }, [imperativePlaying, setFrame, videoId]); const frameForward = useCallback2((frames) => { if (!videoId) { return null; } if (imperativePlaying.current) { return; } setFrame((c) => { const prevFrame = c[videoId] ?? window.remotion_initialFrame ?? 0; const newFrame = Math.min(lastFrame, prevFrame + frames); if (prevFrame === newFrame) { return c; } return { ...c, [videoId]: newFrame }; }); }, [videoId, imperativePlaying, lastFrame, setFrame]); const toggle = useCallback2((e) => { if (imperativePlaying.current) { pause(); } else { play(e); } }, [imperativePlaying, pause, play]); const isPlaying = useCallback2(() => { return imperativePlaying.current; }, [imperativePlaying]); const getCurrentFrame = useCallback2(() => { return frameRef.current; }, [frameRef]); const isBuffering = useCallback2(() => { return buffering.current; }, [buffering]); const returnValue = useMemo(() => { return { frameBack, frameForward, isLastFrame, emitter, playing, play, pause, seek, isFirstFrame, getCurrentFrame, isPlaying, isBuffering, pauseAndReturnToPlayStart, hasPlayed, toggle }; }, [ emitter, frameBack, frameForward, hasPlayed, isFirstFrame, isLastFrame, getCurrentFrame, pause, pauseAndReturnToPlayStart, play, playing, seek, toggle, isPlaying, isBuffering ]); return returnValue; }; // src/browser-mediasession.ts var useBrowserMediaSession = ({ browserMediaControlsBehavior, videoConfig, playbackRate }) => { const { playing, pause, play, emitter, getCurrentFrame, seek } = usePlayer(); useEffect3(() => { if (!navigator.mediaSession) { return; } if (browserMediaControlsBehavior.mode === "do-nothing") { return; } if (playing) { navigator.mediaSession.playbackState = "playing"; } else { navigator.mediaSession.playbackState = "paused"; } }, [browserMediaControlsBehavior.mode, playing]); useEffect3(() => { if (!navigator.mediaSession) { return; } if (browserMediaControlsBehavior.mode === "do-nothing") { return; } const onTimeUpdate = () => { if (!videoConfig) { return; } if (navigator.mediaSession) { navigator.mediaSession.setPositionState({ duration: videoConfig.durationInFrames / videoConfig.fps, playbackRate, position: getCurrentFrame() / videoConfig.fps }); } }; emitter.addEventListener("timeupdate", onTimeUpdate); return () => { emitter.removeEventListener("timeupdate", onTimeUpdate); }; }, [ browserMediaControlsBehavior.mode, emitter, getCurrentFrame, playbackRate, videoConfig ]); useEffect3(() => { if (!navigator.mediaSession) { return; } if (browserMediaControlsBehavior.mode === "do-nothing") { return; } navigator.mediaSession.setActionHandler("play", () => { if (browserMediaControlsBehavior.mode === "register-media-session") { play(); } }); navigator.mediaSession.setActionHandler("pause", () => { if (browserMediaControlsBehavior.mode === "register-media-session") { pause(); } }); navigator.mediaSession.setActionHandler("seekto", (event) => { if (browserMediaControlsBehavior.mode === "register-media-session" && event.seekTime !== undefined && videoConfig) { seek(Math.round(event.seekTime * videoConfig.fps)); } }); navigator.mediaSession.setActionHandler("seekbackward", () => { if (browserMediaControlsBehavior.mode === "register-media-session" && videoConfig) { seek(Math.max(0, Math.round((getCurrentFrame() - 10) * videoConfig.fps))); } }); navigator.mediaSession.setActionHandler("seekforward", () => { if (browserMediaControlsBehavior.mode === "register-media-session" && videoConfig) { seek(Math.max(videoConfig.durationInFrames - 1, Math.round((getCurrentFrame() + 10) * videoConfig.fps))); } }); navigator.mediaSession.setActionHandler("previoustrack", () => { if (browserMediaControlsBehavior.mode === "register-media-session") { seek(0); } }); return () => { navigator.mediaSession.metadata = null; navigator.mediaSession.setActionHandler("play", null); navigator.mediaSession.setActionHandler("pause", null); navigator.mediaSession.setActionHandler("seekto", null); navigator.mediaSession.setActionHandler("seekbackward", null); navigator.mediaSession.setActionHandler("seekforward", null); navigator.mediaSession.setActionHandler("previoustrack", null); }; }, [ browserMediaControlsBehavior.mode, getCurrentFrame, pause, play, seek, videoConfig ]); }; // src/calculate-next-frame.ts var calculateNextFrame = ({ time, currentFrame: startFrame, playbackSpeed, fps, actualLastFrame, actualFirstFrame, framesAdvanced, shouldLoop }) => { const op = playbackSpeed < 0 ? Math.ceil : Math.floor; const framesToAdvance = op(time * playbackSpeed / (1000 / fps)) - framesAdvanced; const nextFrame = framesToAdvance + startFrame; const isCurrentFrameOutside = startFrame > actualLastFrame || startFrame < actualFirstFrame; const isNextFrameOutside = nextFrame > actualLastFrame || nextFrame < actualFirstFrame; const hasEnded = !shouldLoop && isNextFrameOutside && !isCurrentFrameOutside; if (playbackSpeed > 0) { if (isNextFrameOutside) { return { nextFrame: actualFirstFrame, framesToAdvance, hasEnded }; } return { nextFrame, framesToAdvance, hasEnded }; } if (isNextFrameOutside) { return { nextFrame: actualLastFrame, framesToAdvance, hasEnded }; } return { nextFrame, framesToAdvance, hasEnded }; }; // src/is-backgrounded.ts import { useEffect as useEffect4, useRef as useRef3 } from "react"; var getIsBackgrounded = () => { if (typeof document === "undefined") { return false; } return document.visibilityState === "hidden"; }; var useIsBackgrounded = () => { const isBackgrounded = useRef3(getIsBackgrounded()); useEffect4(() => { const onVisibilityChange = () => { isBackgrounded.current = getIsBackgrounded(); }; document.addEventListener("visibilitychange", onVisibilityChange); return () => { document.removeEventListener("visibilitychange", onVisibilityChange); }; }, []); return isBackgrounded; }; // src/use-playback.ts var usePlayback = ({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, outFrame, browserMediaControlsBehavior, getCurrentFrame }) => { const config = Internals6.useUnsafeVideoConfig(); const frame = Internals6.Timeline.useTimelinePosition(); const { playing, pause, emitter, isPlaying } = usePlayer(); const setFrame = Internals6.Timeline.useTimelineSetFrame(); const isBackgroundedRef = useIsBackgrounded(); const lastTimeUpdateEvent = useRef4(null); const context = useContext4(Internals6.BufferingContextReact); if (!context) { throw new Error("Missing the buffering context. Most likely you have a Remotion version mismatch."); } useBrowserMediaSession({ browserMediaControlsBehavior, playbackRate, videoConfig: config }); useEffect5(() => { if (!config) { return; } if (!playing) { return; } let hasBeenStopped = false; let reqAnimFrameCall = null; let startedTime = performance.now(); let framesAdvanced = 0; const cancelQueuedFrame = () => { if (reqAnimFrameCall !== null) { if (reqAnimFrameCall.type === "raf") { cancelAnimationFrame(reqAnimFrameCall.id); } else { clearTimeout(reqAnimFrameCall.id); } } }; const stop = () => { hasBeenStopped = true; cancelQueuedFrame(); }; const callback = () => { if (hasBeenStopped) { return; } if (!isPlaying()) { return; } const time = performance.now() - startedTime; const actualLastFrame = outFrame ?? config.durationInFrames - 1; const actualFirstFrame = inFrame ?? 0; const currentFrame = getCurrentFrame(); const { nextFrame, framesToAdvance, hasEnded } = calculateNextFrame({ time, currentFrame, playbackSpeed: playbackRate, fps: config.fps, actualFirstFrame, actualLastFrame, framesAdvanced, shouldLoop: loop }); framesAdvanced += framesToAdvance; if (nextFrame !== getCurrentFrame() && (!hasEnded || moveToBeginningWhenEnded)) { setFrame((c) => ({ ...c, [config.id]: nextFrame })); } if (hasEnded) { stop(); pause(); emitter.dispatchEnded(); return; } queueNextFrame(); }; const queueNextFrame = () => { if (context.buffering.current) { const stopListening = context.listenForResume(() => { stopListening.remove(); startedTime = performance.now(); framesAdvanced = 0; queueNextFrame(); }); return; } if (isBackgroundedRef.current) { reqAnimFrameCall = { type: "timeout", id: setTimeout(callback, 1000 / config.fps) }; return; } reqAnimFrameCall = { type: "raf", id: requestAnimationFrame(callback) }; }; queueNextFrame(); const onVisibilityChange = () => { if (document.visibilityState === "visible") { return; } cancelQueuedFrame(); callback(); }; window.addEventListener("visibilitychange", onVisibilityChange); return () => { window.removeEventListener("visibilitychange", onVisibilityChange); stop(); }; }, [ config, loop, pause, playing, setFrame, emitter, playbackRate, inFrame, outFrame, moveToBeginningWhenEnded, isBackgroundedRef, getCurrentFrame, context, isPlaying ]); useEffect5(() => { const interval = setInterval(() => { if (lastTimeUpdateEvent.current === getCurrentFrame()) { return; } emitter.dispatchTimeUpdate({ frame: getCurrentFrame() }); lastTimeUpdateEvent.current = getCurrentFrame(); }, 250); return () => clearInterval(interval); }, [emitter, getCurrentFrame]); useEffect5(() => { emitter.dispatchFrameUpdate({ frame }); }, [emitter, frame]); }; // src/utils/use-element-size.ts import { useCallback as useCallback3, useEffect as useEffect6, useMemo as useMemo2, useState as useState4 } from "react"; var elementSizeHooks = []; var updateAllElementsSizes = () => { for (const listener of elementSizeHooks) { listener(); } }; var useElementSize = (ref, options) => { const [size, setSize] = useState4(() => { if (!ref.current) { return null; } const rect = ref.current.getClientRects(); if (!rect[0]) { return null; } return { width: rect[0].width, height: rect[0].height, left: rect[0].x, top: rect[0].y, windowSize: { height: window.innerHeight, width: window.innerWidth } }; }); const observer = useMemo2(() => { if (typeof ResizeObserver === "undefined") { return null; } return new ResizeObserver((entries) => { const { contentRect, target } = entries[0]; const newSize = target.getClientRects(); if (!newSize?.[0]) { setSize(null); return; } const probableCssParentScale = contentRect.width === 0 ? 1 : newSize[0].width / contentRect.width; const width = options.shouldApplyCssTransforms || probableCssParentScale === 0 ? newSize[0].width : newSize[0].width * (1 / probableCssParentScale); const height = options.shouldApplyCssTransforms || probableCssParentScale === 0 ? newSize[0].height : newSize[0].height * (1 / probableCssParentScale); setSize((prevState) => { const isSame = prevState && prevState.width === width && prevState.height === height && prevState.left === newSize[0].x && prevState.top === newSize[0].y && prevState.windowSize.height === window.innerHeight && prevState.windowSize.width === window.innerWidth; if (isSame) { return prevState; } return { width, height, left: newSize[0].x, top: newSize[0].y, windowSize: { height: window.innerHeight, width: window.innerWidth } }; }); }); }, [options.shouldApplyCssTransforms]); const updateSize = useCallback3(() => { if (!ref.current) { return; } const rect = ref.current.getClientRects(); if (!rect[0]) { setSize(null); return; } setSize((prevState) => { const isSame = prevState && prevState.width === rect[0].width && prevState.height === rect[0].height && prevState.left === rect[0].x && prevState.top === rect[0].y && prevState.windowSize.height === window.innerHeight && prevState.windowSize.width === window.innerWidth; if (isSame) { return prevState; } return { width: rect[0].width, height: rect[0].height, left: rect[0].x, top: rect[0].y, windowSize: { height: window.innerHeight, width: window.innerWidth } }; }); }, [ref]); useEffect6(() => { if (!observer) { return; } const { current } = ref; if (current) { observer.observe(current); } return () => { if (current) { observer.unobserve(current); } }; }, [observer, ref, updateSize]); useEffect6(() => { if (!options.triggerOnWindowResize) { return; } window.addEventListener("resize", updateSize); return () => { window.removeEventListener("resize", updateSize); }; }, [options.triggerOnWindowResize, updateSize]); useEffect6(() => { elementSizeHooks.push(updateSize); return () => { elementSizeHooks = elementSizeHooks.filter((e) => e !== updateSize); }; }, [updateSize]); return useMemo2(() => { if (!size) { return null; } return { ...size, refresh: updateSize }; }, [size, updateSize]); }; // src/Player.tsx import { forwardRef as forwardRef2, useEffect as useEffect13, useImperativeHandle as useImperativeHandle2, useLayoutEffect as useLayoutEffect2, useMemo as useMemo14, useRef as useRef11, useState as useState13 } from "react"; import { Composition, Internals as Internals15 } from "remotion"; // src/PlayerUI.tsx import React10, { Suspense, forwardRef, useCallback as useCallback11, useContext as useContext6, useEffect as useEffect12, useImperativeHandle, useMemo as useMemo12, useRef as useRef10, useState as useState11 } from "react"; import { Internals as Internals11 } from "remotion"; // src/PlayerControls.tsx import { useCallback as useCallback8, useEffect as useEffect10, useMemo as useMemo9, useRef as useRef8, useState as useState10 } from "react"; // src/DefaultPlayPauseButton.tsx import { jsx as jsx4 } from "react/jsx-runtime"; var DefaultPlayPauseButton = ({ playing, buffering }) => { if (playing && buffering) { return /* @__PURE__ */ jsx4(BufferingIndicator, { type: "player" }); } if (playing) { return /* @__PURE__ */ jsx4(PauseIcon, {}); } return /* @__PURE__ */ jsx4(PlayIcon, {}); }; // src/MediaVolumeSlider.tsx import { useCallback as useCallback5, useMemo as useMemo4, useRef as useRef5, useState as useState6 } from "react"; import { Internals as Internals7 } from "remotion"; // src/render-volume-slider.tsx import React3, { useCallback as useCallback4, useMemo as useMemo3, useState as useState5 } from "react"; import { random } from "remotion"; import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime"; var KNOB_SIZE = 12; var BAR_HEIGHT = 5; var DefaultVolumeSlider = ({ volume, isVertical, onBlur, inputRef, setVolume }) => { const sliderContainer = useMemo3(() => { const paddingLeft = 5; const common = { paddingLeft, height: ICON_SIZE, width: VOLUME_SLIDER_WIDTH, display: "inline-flex", alignItems: "center" }; if (isVertical) { return { ...common, position: "absolute", transform: `rotate(-90deg) translateX(${VOLUME_SLIDER_WIDTH / 2 + ICON_SIZE / 2}px)` }; } return { ...common }; }, [isVertical]); const randomId = typeof React3.useId === "undefined" ? "volume-slider" : React3.useId(); const [randomClass] = useState5(() => `__remotion-volume-slider-${random(randomId)}`.replace(".", "")); const onVolumeChange = useCallback4((e) => { setVolume(parseFloat(e.target.value)); }, [setVolume]); const inputStyle = useMemo3(() => { const commonStyle = { WebkitAppearance: "none", backgroundColor: "rgba(255, 255, 255, 0.5)", borderRadius: BAR_HEIGHT / 2, cursor: "pointer", height: BAR_HEIGHT, width: VOLUME_SLIDER_WIDTH, backgroundImage: `linear-gradient( to right, white ${volume * 100}%, rgba(255, 255, 255, 0) ${volume * 100}% )` }; if (isVertical) { return { ...commonStyle, bottom: ICON_SIZE + VOLUME_SLIDER_WIDTH / 2 }; } return commonStyle; }, [isVertical, volume]); const sliderStyle = ` .${randomClass}::-webkit-slider-thumb { -webkit-appearance: none; background-color: white; border-radius: ${KNOB_SIZE / 2}px; box-shadow: 0 0 2px black; height: ${KNOB_SIZE}px; width: ${KNOB_SIZE}px; } .${randomClass}::-moz-range-thumb { -webkit-appearance: none; background-color: white; border-radius: ${KNOB_SIZE / 2}px; box-shadow: 0 0 2px black; height: ${KNOB_SIZE}px; width: ${KNOB_SIZE}px; } `; return /* @__PURE__ */ jsxs3("div", { style: sliderContainer, children: [ /* @__PURE__ */ jsx5("style", { dangerouslySetInnerHTML: { __html: sliderStyle } }), /* @__PURE__ */ jsx5("input", { ref: inputRef, "aria-label": "Change volume", className: randomClass, max: 1, min: 0, onBlur, onChange: onVolumeChange, step: 0.01, type: "range", value: volume, style: inputStyle }) ] }); }; var renderDefaultVolumeSlider = (props) => { return /* @__PURE__ */ jsx5(DefaultVolumeSlider, { ...props }); }; // src/MediaVolumeSlider.tsx import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime"; var VOLUME_SLIDER_WIDTH = 100; var MediaVolumeSlider = ({ displayVerticalVolumeSlider, renderMuteButton, renderVolumeSlider }) => { const [mediaMuted, setMediaMuted] = Internals7.useMediaMutedState(); const [mediaVolume, setMediaVolume] = Internals7.useMediaVolumeState(); const [focused, setFocused] = useState6(false); const parentDivRef = useRef5(null); const inputRef = useRef5(null); const hover = useHoverState(parentDivRef, false); const onBlur = useCallback5(() => { setTimeout(() => { if (inputRef.current && document.activeElement !== inputRef.current) { setFocused(false); } }, 10); }, []); const isVolume0 = mediaVolume === 0; const onClick = useCallback5(() => { if (isVolume0) { setMediaVolume(1); setMediaMuted(false); return; } setMediaMuted((mute) => !mute); }, [isVolume0, setMediaMuted, setMediaVolume]); const parentDivStyle = useMemo4(() => { return { display: "inline-flex", background: "none", border: "none", justifyContent: "center", alignItems: "center", touchAction: "none", ...displayVerticalVolumeSlider && { position: "relative" } }; }, [displayVerticalVolumeSlider]); const volumeContainer = useMemo4(() => { return { display: "inline", width: ICON_SIZE, height: ICON_SIZE, cursor: "pointer", appearance: "none", background: "none", border: "none", padding: 0 }; }, []); const renderDefaultMuteButton = useCallback5(({ muted, volume }) => { const isMutedOrZero = muted || volume === 0; return /* @__PURE__ */ jsx6("button", { "aria-label": isMutedOrZero ? "Unmute sound" : "Mute sound", title: isMutedOrZero ? "Unmute sound" : "Mute sound", onClick, onBlur, onFocus: () => setFocused(true), style: volumeContainer, type: "button", children: isMutedOrZero ? /* @__PURE__ */ jsx6(VolumeOffIcon, {}) : /* @__PURE__ */ jsx6(VolumeOnIcon, {}) }); }, [onBlur, onClick, volumeContainer]); const muteButton = useMemo4(() => { return renderMuteButton ? renderMuteButton({ muted: mediaMuted, volume: mediaVolume }) : renderDefaultMuteButton({ muted: mediaMuted, volume: mediaVolume }); }, [mediaMuted, mediaVolume, renderDefaultMuteButton, renderMuteButton]); const volumeSlider = useMemo4(() => { return (focused || hover) && !mediaMuted && !Internals7.isIosSafari() ? (renderVolumeSlider ?? renderDefaultVolumeSlider)({ isVertical: displayVerticalVolumeSlider, volume: mediaVolume, onBlur: () => setFocused(false), inputRef, setVolume: setMediaVolume }) : null; }, [ displayVerticalVolumeSlider, focused, hover, mediaMuted, mediaVolume, renderVolumeSlider, setMediaVolume ]); return /* @__PURE__ */ jsxs4("div", { ref: parentDivRef, style: parentDivStyle, children: [ muteButton, volumeSlider ] }); }; // src/PlaybackrateControl.tsx import { useCallback as useCallback6, useContext as useContext5, useEffect as useEffect8, useMemo as useMemo5, useState as useState8 } from "react"; import { Internals as Internals8 } from "remotion"; // src/utils/use-component-visible.ts import { useEffect as useEffect7, useRef as useRef6, useState as useState7 } from "react"; function useComponentVisible(initialIsVisible) { const [isComponentVisible, setIsComponentVisible] = useState7(initialIsVisible); const ref = useRef6(null); useEffect7(() => { const handleClickOutside = (event) => { if (ref.current && !ref.current.contains(event.target)) { setIsComponentVisible(false); } }; document.addEventListener("pointerup", handleClickOutside, true); return () => { document.removeEventListener("pointerup", handleClickOutside, true); }; }, []); return { ref, isComponentVisible, setIsComponentVisible }; } // src/PlaybackrateControl.tsx import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime"; var BOTTOM = 35; var THRESHOLD = 70; var rateDiv = { height: 30, paddingRight: 15, paddingLeft: 12, display: "flex", flexDirection: "row", alignItems: "center" }; var checkmarkContainer = { width: 22, display: "flex", alignItems: "center" }; var checkmarkStyle = { width: 14, height: 14, color: "black" }; var Checkmark = () => /* @__PURE__ */ jsx7("svg", { viewBox: "0 0 512 512", style: checkmarkStyle, children: /* @__PURE__ */ jsx7("path", { fill: "currentColor", d: "M435.848 83.466L172.804 346.51l-96.652-96.652c-4.686-4.686-12.284-4.686-16.971 0l-28.284 28.284c-4.686 4.686-4.686 12.284 0 16.971l133.421 133.421c4.686 4.686 12.284 4.686 16.971 0l299.813-299.813c4.686-4.686 4.686-12.284 0-16.971l-28.284-28.284c-4.686-4.686-12.284-4.686-16.97 0z" }) }); var formatPlaybackRate = (rate) => { const str = rate.toString(); return str.includes(".") ? str : str + ".0"; }; var PlaybackrateOption = ({ rate, onSelect, selectedRate, keyboardSelectedRate }) => { const onClick = useCallback6((e) => { e.stopPropagation(); e.preventDefault(); onSelect(rate); }, [onSelect, rate]); const [hovered, setHovered] = useState8(false); const onMouseEnter = useCallback6(() => { setHovered(true); }, []); const onMouseLeave = useCallback6(() => { setHovered(false); }, []); const isFocused = keyboardSelectedRate === rate; const actualStyle = useMemo5(() => { return { ...rateDiv, backgroundColor: hovered || isFocused ? "#eee" : "transparent" }; }, [hovered, isFocused]); return /* @__PURE__ */ jsxs5("div", { onPointerEnter: onMouseEnter, onPointerLeave: onMouseLeave, tabIndex: 0, style: actualStyle, onClick, children: [ /* @__PURE__ */ jsx7("div", { style: checkmarkContainer, children: rate === selectedRate ? /* @__PURE__ */ jsx7(Checkmark, {}) : null }), formatPlaybackRate(rate), "x" ] }, rate); }; var PlaybackPopup = ({ setIsComponentVisible, playbackRates, canvasSize }) => { const { setPlaybackRate, playbackRate } = useContext5(Internals8.TimelineContext); const [keyboardSelectedRate, setKeyboardSelectedRate] = useState8(playbackRate); useEffect8(() => { const listener = (e) => { e.preventDefault(); if (e.key === "ArrowUp") { const currentIndex = playbackRates.findIndex((rate) => rate === keyboardSelectedRate); if (currentIndex === 0) { return; } if (currentIndex === -1) { setKeyboardSelectedRate(playbackRates[0]); } else { setKeyboardSelectedRate(playbackRates[currentIndex - 1]); } } else if (e.key === "ArrowDown") { const currentIndex = playbackRates.findIndex((rate) => rate === keyboardSelectedRate); if (currentIndex === playbackRates.length - 1) { return; } if (currentIndex === -1) { setKeyboardSelectedRate(playbackRates[playbackRates.length - 1]); } else { setKeyboardSelectedRate(playbackRates[currentIndex + 1]); } } else if (e.key === "Enter") { setPlaybackRate(keyboardSelectedRate); setIsComponentVisible(false); } }; window.addEventListener("keydown", listener); return () => { window.removeEventListener("keydown", listener); }; }, [ playbackRates, keyboardSelectedRate, setPlaybackRate, setIsComponentVisible ]); const onSelect = useCallback6((rate) => { setPlaybackRate(rate); setIsComponentVisible(false); }, [setIsComponentVisible, setPlaybackRate]); const playbackPopup = useMemo5(() => { return { position: "absolute", right: 0, width: 125, maxHeight: canvasSize.height - THRESHOLD - BOTTOM, bottom: 35, background: "#fff", borderRadius: 4, overflow: "auto", color: "black", textAlign: "left" }; }, [canvasSize.height]); return /* @__PURE__ */ jsx7("div", { style: playbackPopup, children: playbackRates.map((rate) => { return /* @__PURE__ */ jsx7(PlaybackrateOption, { selectedRate: playbackRate, onSelect, rate, keyboardSelectedRate }, rate); }) }); }; var label = { fontSize: 13, fontWeight: "bold", color: "white", border: "2px solid white", borderRadius: 20, paddingLeft: 8, paddingRight: 8, paddingTop: 2, paddingBottom: 2 }; var playerButtonStyle = { appearance: "none", backgroundColor: "transparent", border: "none", cursor: "pointer", paddingLeft: 0, paddingRight: 0, paddingTop: 6, paddingBottom: 6, height: 37, display: "inline-flex", marginBottom: 0, marginTop: 0, alignItems: "center" }; var button = { ...playerButtonStyle, position: "relative" }; var PlaybackrateControl = ({ playbackRates, canvasSize }) => { const { ref, isComponentVisible, setIsComponentVisible } = useComponentVisible(false); const { playbackRate } = useContext5(Internals8.TimelineContext); const onClick = useCallback6((e) => { e.stopPropagation(); e.preventDefault(); setIsComponentVisible((prevIsComponentVisible) => !prevIsComponentVisible); }, [setIsComponentVisible]); return /* @__PURE__ */ jsx7("div", { ref, children: /* @__PURE__ */ jsxs5("button", { type: "button", "aria-label": "Change playback rate", style: button, onClick, children: [ /* @__PURE__ */ jsxs5("div", { style: label, children: [ playbackRate, "x" ] }), isComponentVisible && /* @__PURE__ */ jsx7(PlaybackPopup, { canvasSize, playbackRates, setIsComponentVisible }) ] }) }); }; // src/PlayerSeekBar.tsx import { useCallback as useCallback7, useEffect as useEffect9, useMemo as useMemo6, useRef as useRef7, useState as useState9 } from "react"; import { Internals as Internals9, interpolate } from "remotion"; import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime"; var getFrameFromX = (clientX, durationInFrames, width) => { const pos = clientX; const frame = Math.round(interpolate(pos, [0, width], [0, durationInFrames - 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" })); return frame; }; var BAR_HEIGHT2 = 5; var KNOB_SIZE2 = 12; var VERTICAL_PADDING = 4; var containerStyle = { userSelect: "none", WebkitUserSelect: "none", paddingTop: VERTICAL_PADDING, paddingBottom: VERTICAL_PADDING, boxSizing: "border-box", cursor: "pointer", position: "relative", touchAction: "none" }; var barBackground = { height: BAR_HEIGHT2, backgroundColor: "rgba(255, 255, 255, 0.25)", width: "100%", borderRadius: BAR_HEIGHT2 / 2 }; var findBodyInWhichDivIsLocated = (div) => { let current = div; while (current.parentElement) { current = current.parentElement; } return current; }; var PlayerSeekBar = ({ durationInFrames, onSeekEnd, onSeekStart, inFrame, outFrame }) => { const containerRef = useRef7(null); const barHovered = useHoverState(containerRef, false); const size = useElementSize(containerRef, { triggerOnWindowResize: true, shouldApplyCssTransforms: true }); const { seek, play, pause, playing } = usePlayer(); const frame = Internals9.Timeline.useTimelinePosition(); const [dragging, setDragging] = useState9({ dragging: false }); const width = size?.width ?? 0; const onPointerDown = useCallback7((e) => { if (e.button !== 0) { return; } const posLeft = containerRef.current?.getBoundingClientRect().left; const _frame = getFrameFromX(e.clientX - posLeft, durationInFrames, width); pause(); seek(_frame); setDragging({ dragging: true, wasPlaying: playing }); onSeekStart(); }, [durationInFrames, width, pause, seek, playing, onSeekStart]); const onPointerMove = useCallback7((e) => { if (!size) { throw new Error("Player has no size"); } if (!dragging.dragging) { return; } const posLeft = containerRef.current?.getBoundingClientRect().left; const _frame = getFrameFromX(e.clientX - posLeft, durationInFrames, size.width); seek(_frame); }, [dragging.dragging, durationInFrames, seek, size]); const onPointerUp = useCallback7(() => { setDragging({ dragging: false }); if (!dragging.dragging) { return; } if (dragging.wasPlaying) { play(); } else { pause(); } onSeekEnd(); }, [dragging, onSeekEnd, pause, play]); useEffect9(() => { if (!dragging.dragging) { return; } const body = findBodyInWhichDivIsLocated(containerRef.current); body.addEventListener("pointermove", onPointerMove); body.addEventListener("pointerup", onPointerUp); return () => { body.removeEventListener("pointermove", onPointerMove); body.removeEventListener("pointerup", onPointerUp); }; }, [dragging.dragging, onPointerMove, onPointerUp]); const knobStyle = useMemo6(() => { return { height: KNOB_SIZE2, width: KNOB_SIZE2, borderRadius: KNOB_SIZE2 / 2, position: "absolute", top: VERTICAL_PADDING - KNOB_SIZE2 / 2 + 5 / 2, backgroundColor: "white", left: Math.max(0, frame / Math.max(1, durationInFrames - 1) * width - KNOB_SIZE2 / 2), boxShadow: "0 0 2px black", opacity: Number(barHovered || dragging.dragging) }; }, [barHovered, dragging.dragging, durationInFrames, frame, width]); const fillStyle = useMemo6(() => { return { height: BAR_HEIGHT2, backgroundColor: "rgba(255, 255, 255, 1)", width: (frame - (inFrame ?? 0)) / (durationInFrames - 1) * width, marginLeft: (inFrame ?? 0) / (durationInFrames - 1) * width, borderRadius: BAR_HEIGHT2 / 2 }; }, [durationInFrames, frame, inFrame, width]); const active = useMemo6(() => { return { height: BAR_HEIGHT2, backgroundColor: "rgba(255, 255, 255, 0.25)", width: ((outFrame ?? durationInFrames - 1) - (inFrame ?? 0)) / (durationInFrames - 1) * 100 + "%", marginLeft: (inFrame ?? 0) / (durationInFrames - 1) * 100 + "%", borderRadius: BAR_HEIGHT2 / 2, position: "absolute" }; }, [durationInFrames, inFrame, outFrame]); return /* @__PURE__ */ jsxs6("div", { ref: containerRef, onPointerDown, style: containerStyle, children: [ /* @__PURE__ */ jsxs6("div", { style: barBackground, children: [ /* @__PURE__ */ jsx8("div", { style: active }), /* @__PURE__ */ jsx8("div", { style: fillStyle }) ] }), /* @__PURE__ */ jsx8("div", { style: knobStyle }) ] }); }; // src/PlayerTimeLabel.tsx import { useMemo as useMemo7 } from "react"; import { Internals as Internals10 } from "remotion"; // src/format-time.ts var formatTime = (timeInSeconds) => { const minutes = Math.floor(timeInSeconds / 60); const seconds = Math.floor(timeInSeconds - minutes * 60); return `${String(minutes)}:${String(seconds).padStart(2, "0")}`; }; // src/PlayerTimeLabel.tsx import { jsxs as jsxs7 } from "react/jsx-runtime"; var PlayerTimeLabel = ({ durationInFrames, maxTimeLabelWidth, fps }) => { const frame = Internals10.Timeline.useTimelinePosition(); const timeLabel = useMemo7(() => { return { color: "white", fontFamily: "sans-serif", fontSize: 14, maxWidth: maxTimeLabelWidth === null ? undefined : maxTimeLabelWidth, overflow: "hidden", textOverflow: "ellipsis" }; }, [maxTimeLabelWidth]); const isLastFrame = frame === durationInFrames - 1; const frameToDisplay = isLastFrame ? frame + 1 : frame; return /* @__PURE__ */ jsxs7("div", { style: timeLabel, children: [ formatTime(frameToDisplay / fps), " / ", formatTime(durationInFrames / fps) ] }); }; // src/use-video-controls-resize.ts import { useMemo as useMemo8 } from "react"; var X_SPACER = 10; var X_PADDING = 12; var useVideoControlsResize = ({ allowFullscreen: allowFullScreen, playerWidth }) => { const resizeInfo = useMemo8(() => { const playPauseIconSize = ICON_SIZE; const volumeIconSize = ICON_SIZE; const _fullscreenIconSize = allowFullScreen ? fullscreenIconSize : 0; const elementsSize = volumeIconSize + playPauseIconSize + _fullscreenIconSize + X_PADDING * 2 + X_SPACER * 2; const maxTimeLabelWidth = playerWidth - elementsSize; const maxTimeLabelWidthWithoutNegativeValue = Math.max(maxTimeLabelWidth, 0); const availableTimeLabelWidthIfVolumeOpen = maxTimeLabelWidthWithoutNegativeValue - VOLUME_SLIDER_WIDTH; const computedLabelWidth = availableTimeLabelWidthIfVolumeOpen < VOLUME_SLIDER_WIDTH ? maxTimeLabelWidthWithoutNegativeValue : availableTimeLabelWidthIfVolumeOpen; const minWidthForHorizontalDisplay = computedLabelWidth + elementsSize + VOLUME_SLIDER_WIDTH; const displayVerticalVolumeSlider = playerWidth < minWidthForHorizontalDisplay; return { maxTimeLabelWidth: maxTimeLabelWidthWithoutNegativeValue === 0 ? null : maxTimeLabelWidthWithoutNegativeValue, displayVerticalVolumeSlider }; }, [allowFullScreen, playerWidth]); return resizeInfo; }; // src/PlayerControls.tsx import { jsx as jsx9, jsxs as jsxs8, Fragment as Fragment2 } from "react/jsx-runtime"; var gradientSteps = [ 0, 0.013, 0.049, 0.104, 0.175, 0.259, 0.352, 0.45, 0.55, 0.648, 0.741, 0.825, 0.896, 0.951, 0.987 ]; var gradientOpacities = [ 0, 8.1, 15.5, 22.5, 29, 35.3, 41.2, 47.1, 52.9, 58.8, 64.7, 71, 77.5, 84.5, 91.9 ]; var globalGradientOpacity = 1 / 0.7; var containerStyle2 = { boxSizing: "border-box", position: "absolute", bottom: 0, width: "100%", paddingTop: 40, paddingBottom: 10, backgroundImage: `linear-gradient(to bottom,${gradientSteps.map((g, i) => { return `hsla(0, 0%, 0%, ${g}) ${gradientOpacities[i] * globalGradientOpacity}%`; }).join(", ")}, hsl(0, 0%, 0%) 100%)`, backgroundSize: "auto 145px", display: "flex", paddingRight: X_PADDING, paddingLeft: X_PADDING, flexDirection: "column", transition: "opacity 0.3s" }; var controlsRow = { display: "flex", flexDirection: "row", width: "100%", alignItems: "center", justifyContent: "center", userSelect: "none", WebkitUserSelect: "none" }; var leftPartStyle = { display: "flex", flexDirection: "row", userSelect: "none", WebkitUserSelect: "none", alignItems: "center" }; var xSpacer = { width: 12 }; var ySpacer = { height: 8 }; var flex1 = { flex: 1 }; var fullscreen = {}; var Controls = ({ durationInFrames, isFullscreen, fps, showVolumeControls, onFullscreenButtonClick, allowFullscreen, onExitFullscreenButtonClick, spaceKeyToPlayOrPause, onSeekEnd, onSeekStart, inFrame, outFrame, initiallyShowControls, canvasSize, renderPlayPauseButton, renderFullscreenButton, alwaysShowControls, showPlaybackRateControl, containerRef, buffering, hideControlsWhenPointerDoesntMove, onPointerDown, onDoubleClick, renderMuteButton, renderVolumeSlider, playing, toggle, renderCustomControls }) => { const playButtonRef = useRef8(null); const [supportsFullscreen, setSupportsFullscreen] = useState10(false); const hovered = useHoverState(containerRef, hideControlsWhenPointerDoesntMove); const { maxTimeLabelWidth, displayVerticalVolumeSlider } = useVideoControlsResize({ allowFullscreen, playerWidth: canvasSize?.width ?? 0 }); const [shouldShowInitially, setInitiallyShowControls] = useState10(() => { if (typeof initiallyShowControls === "boolean") { return initiallyShowControls; } if (typeof initiallyShowControls === "number") { if (initiallyShowControls % 1 !== 0) { throw new Error("initiallyShowControls must be an integer or a boolean"); } if (Number.isNaN(initiallyShowControls)) { throw new Error("initiallyShowControls must not be NaN"); } if (!Number.isFinite(initiallyShowControls)) { throw new Error("initiallyShowControls must be finite"); } if (initiallyShowControls <= 0) { throw new Error("initiallyShowControls must be a positive integer"); } return initiallyShowControls; } throw new TypeError("initiallyShowControls must be a number or a boolean"); }); const containerCss = useMemo9(() => { const shouldShow = hovered || !playing || shouldShowInitially || alwaysShowControls; return { ...containerStyle2, opacity: Number(shouldShow) }; }, [hovered, shouldShowInitially, playing, alwaysShowControls]); useEffect10(() => { if (playButtonRef.current && spaceKeyToPlayOrPause) { playButtonRef.current.focus({ preventScroll: true }); } }, [playing, spaceKeyToPlayOrPause]); useEffect10(() => { setSupportsFullscreen((typeof document !== "undefined" && (document.fullscreenEnabled || document.webkitFullscreenEnabled)) ?? false); }, []); useEffect10(() => { if (shouldShowInitially === false) { return; } const time = shouldShowInitially === true ? 2000 : shouldShowInitially; const timeout = setTimeout(() => { setInitiallyShowControls(false); }, time); return () => { clearInterval(timeout); }; }, [shouldShowInitially]); const playbackRates = useMemo9(() => { if (showPlaybackRateControl === true) { return [0.5, 0.8, 1, 1.2, 1.5, 1.8, 2, 2.5, 3]; } if (Array.isArray(showPlaybackRateControl)) { for (const rate of showPlaybackRateControl) { if (typeof rate !== "number") { throw new Error("Every item in showPlaybackRateControl must be a number"); } if (rate <= 0) { throw new Error("Every item in showPlaybackRateControl must be positive"); } } return showPlaybackRateControl; } return null; }, [showPlaybackRateControl]); const customControlsElement = renderCustomControls ? renderCustomControls() : null; const ref = useRef8(null); const flexRef = useRef8(null); const onPointerDownIfContainer = useCallback8((e) => { if (e.target === ref.current || e.target === flexRef.current) { onPointerDown?.(e); } }, [onPointerDown]); const onDoubleClickIfContainer = useCallback8((e) => { if (e.target === ref.current || e.target === flexRef.current) { onDoubleClick?.(e); } }, [onDoubleClick]); return /* @__PURE__ */ jsxs8("div", { ref, style: containerCss, onPointerDown: onPointerDownIfContainer, onDoubleClick: onDoubleClickIfContainer, children: [ /* @__PURE__ */ jsxs8("div", { ref: flexRef, style: controlsRow, children: [ /* @__PURE__ */ jsxs8("div", { style: leftPartStyle, children: [ /* @__PURE__ */ jsx9("button", { ref: playButtonRef, type: "button", style: playerButtonStyle, onClick: toggle, "aria-label": playing ? "Pause video" : "Play video", title: playing ? "Pause video" : "Play video", children: renderPlayPauseButton === null ? /* @__PURE__ */ jsx9(DefaultPlayPauseButton, { buffering, playing }) : renderPlayPauseButton({ playing, isBuffering: buffering }) ?? /* @__PURE__ */ jsx9(DefaultPlayPauseButton, { buffering, playing }) }), showVolumeControls ? /* @__PURE__ */ jsxs8(Fragment2, { children: [ /* @__PURE__ */ jsx9("div", { style: xSpacer }), /* @__PURE__ */ jsx9(MediaVolumeSlider, { renderMuteButton, renderVolumeSlider, displayVerticalVolumeSlider }) ] }) : null, /* @__PURE__ */ jsx9("div", { style: xSpacer }), /* @__PURE__ */ jsx9(PlayerTimeLabel, { durationInFrames, fps, maxTimeLabelWidth }), /* @__PURE__ */ jsx9("div", { style: xSpacer }) ] }), /* @__PURE__ */ jsx9("div", { style: flex1 }), customControlsElement, customControlsElement && playbackRates && canvasSize ? /* @__PURE__ */ jsx9("div", { style: xSpacer }) : null, playbackRates && canvasSize && /* @__PURE__ */ jsx9(PlaybackrateControl, { canvasSize, playbackRates }), playbackRates && supportsFullscreen && allowFullscreen ? /* @__PURE__ */ jsx9("div", { style: xSpacer }) : null, /* @__PURE__ */ jsx9("div", { style: fullscreen, children: supportsFullscreen && allowFullscreen ? /* @__PURE__ */ jsx9("button", { type: "button", "aria-label": isFullscreen ? "Exit fullscreen" : "Enter Fullscreen", title: isFullscreen ? "Exit fullscreen" : "Enter Fullscreen", style: playerButtonStyle, onClick: isFullscreen ? onExitFullscreenButtonClick : onFullscreenButtonClick, children: renderFullscreenButton === null ? /* @__PURE__ */ jsx9(FullscreenIcon, { isFullscreen }) : renderFullscreenButton({ isFullscreen }) }) : null }) ] }), /* @__PURE__ */ jsx9("div", { style: ySpacer }), /* @__PURE__ */ jsx9(PlayerSeekBar, { onSeekEnd, onSeekStart, durationInFrames, inFrame, outFrame }) ] }); }; // src/error-boundary.tsx import React8 from "react"; import { jsx as jsx10 } from "react/jsx-runtime"; var errorStyle = { display: "flex", justifyContent: "center", alignItems: "center", flex: 1, height: "100%", width: "100%" }; class ErrorBoundary extends React8.Component { state = { hasError: null }; static getDerivedStateFromError(error) { return { hasError: error }; } componentDidCatch(error) { this.props.onError(error); } render() { if (this.state.hasError) { return /* @__PURE__ */ jsx10("div", { style: errorStyle, children: this.props.errorFallback({ error: this.state.hasError }) }); } return this.props.children; } } // src/license-blacklist.tsx import React9, { useEffect as useEffect11 } from "react"; import { jsx as jsx11 } from "react/jsx-runtime"; var getHashOfDomain = async () => { if (typeof window === "undefined") { return null; } if (typeof window.crypto === "undefined") { return null; } if (typeof window.crypto.subtle === "undefined") { return null; } try { const hashBuffer = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(window.location.hostname)); return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join(""); } catch { return null; } }; var style = { backgroundColor: "red", position: "absolute", padding: 12, fontFamily: "Arial" }; var DOMAIN_BLACKLIST = [ "28d262b44cc61fa750f1686b16ad0604dabfe193fbc263eec05c89b7ad4c2cd6", "4db1b0a94be33165dfefcb3ba03d04c7a2666dd27c496d3dc9fa41858e94925e", "fbc48530bbf245da790f63675e84e06bab38c3b114fab07eb350025119922bdc", "7baf10a8932757b1b3a22b3fce10a048747ac2f8eaf638603487e3705b07eb83", "8a6c21a598d8c667272b5207c051b85997bf5b45d5fb712378be3f27cd72c6a6", "a2f7aaac9c50a9255e7fc376110c4e0bfe153722dc66ed3c5d3bf2a135f65518" ]; var ran = false; var RenderWarningIfBlacklist = () => { const [unlicensed, setUnlicensed] = React9.useState(false); useEffect11(() => { if (ran) { return; } ran = true; getHashOfDomain().then((hash) => { if (hash && DOMAIN_BLACKLIST.includes(hash)) { setUnlicensed(true); } }).catch(() => {}); }, []); useEffect11(() => { if (!unlicensed) { return; } const ensureBanner = () => { const banner = document.querySelector(".warning-banner"); if (!banner) { const div = document.createElement("div"); div.className = "warning-banner"; Object.assign(div.style, style, { zIndex: "9999", cssText: `${style.cssText} !important;` }); div.innerHTML = ` Remotion Unlicensed – Contact hi@remotion.dev `; document.body.appendChild(div); } }; const observer = new MutationObserver(() => ensureBanner()); observer.observe(document.body, { childList: true, subtree: true }); return () => { observer.disconnect(); }; }, [unlicensed]); if (!unlicensed) { return null; } return /* @__PURE__ */ jsx11("div", { style, className: "warning-banner", children: /* @__PURE__ */ jsx11("a", { style: { color: "white" }, href: "https://github.com/remotion-dev/remotion/pull/4589", children: "Remotion Unlicensed – Contact hi@remotion.dev" }) }); }; // src/player-css-classname.ts var playerCssClassname = (override) => { return override ?? "__remotion-player"; }; // src/utils/is-node.ts var IS_NODE = typeof document === "undefined"; // src/utils/use-click-prevention-on-double-click.ts import { useCallback as useCallback10, useMemo as useMemo11 } from "react"; // src/utils/cancellable-promise.ts var cancellablePromise = (promise) => { let isCanceled = false; const wrappedPromise = new Promise((resolve, reject) => { promise.then((value) => { if (isCanceled) { reject({ isCanceled, value }); return; } resolve(value); }).catch((error) => { reject({ isCanceled, error }); }); }); return { promise: wrappedPromise, cancel: () => { isCanceled = true; } }; }; // src/utils/delay.ts var delay = (n) => new Promise((resolve) => setTimeout(resolve, n)); // src/utils/use-cancellable-promises.ts import { useCallback as useCallback9, useMemo as useMemo10, useRef as useRef9 } from "react"; var useCancellablePromises = () => { const pendingPromises = useRef9([]); const appendPendingPromise = useCallback9((promise) => { pendingPromises.current = [...pendingPromises.current, promise]; }, []); const removePendingPromise = useCallback9((promise) => { pendingPromises.current = pendingPromises.current.filter((p) => p !== promise); }, []); const clearPendingPromises = useCallback9(() => pendingPromises.current.map((p) => p.cancel()), []); const api = useMemo10(() => ({ appendPendingPromise, removePendingPromise, clearPendingPromises }), [appendPendingPromise, clearPendingPromises, removePendingPromise]); return api; }; // src/utils/use-click-prevention-on-double-click.ts var useClickPreventionOnDoubleClick = (onClick, onDoubleClick, doubleClickToFullscreen) => { const api = useCancellablePromises(); const handleClick = useCallback10(async (e) => { if (e instanceof PointerEvent ? e.pointerType === "touch" : e.nativeEvent.pointerType === "touch") { onClick(e); return; } api.clearPendingPromises(); const waitForClick = cancellablePromise(delay(200)); api.appendPendingPromise(waitForClick); try { await waitForClick.promise; api.removePendingPromise(waitForClick); onClick(e); } catch (errorInfo) { const info = errorInfo; api.removePendingPromise(waitForClick); if (!info.isCanceled) { throw info.error; } } }, [api, onClick]); const handlePointerDown = useCallback10(() => { document.addEventListener("pointerup", (newEvt) => { handleClick(newEvt); }, { once: true }); }, [handleClick]); const handleDoubleClick = useCallback10(() => { api.clearPendingPromises(); onDoubleClick(); }, [api, onDoubleClick]); const returnValue = useMemo11(() => { if (!doubleClickToFullscreen) { return { handlePointerDown: onClick, handleDoubleClick: () => { return; } }; } return { handlePointerDown, handleDoubleClick }; }, [doubleClickToFullscreen, handleDoubleClick, handlePointerDown, onClick]); return returnValue; }; // src/PlayerUI.tsx import { jsx as jsx12, jsxs as jsxs9, Fragment as Fragment3 } from "react/jsx-runtime"; var reactVersion = React10.version.split(".")[0]; if (reactVersion === "0") { throw new Error(`Version ${reactVersion} of "react" is not supported by Remotion`); } var doesReactVersionSupportSuspense = parseInt(reactVersion, 10) >= 18; var PlayerUI = ({ controls, style: style2, loop, autoPlay, allowFullscreen, inputProps, clickToPlay, showVolumeControls, doubleClickToFullscreen, spaceKeyToPlayOrPause, errorFallback, playbackRate, renderLoading, renderPoster, className: className2, moveToBeginningWhenEnded, showPosterWhenUnplayed, showPosterWhenEnded, showPosterWhenPaused, showPosterWhenBuffering, showPosterWhenBufferingAndPaused, inFrame, outFrame, initiallyShowControls, renderFullscreen: renderFullscreenButton, renderPlayPauseButton, renderMuteButton, renderVolumeSlider, renderCustomControls, alwaysShowControls, showPlaybackRateControl, posterFillMode, bufferStateDelayInMilliseconds, hideControlsWhenPointerDoesntMove, overflowVisible, browserMediaControlsBehavior, overrideInternalClassName, noSuspense }, ref) => { const config = Internals11.useUnsafeVideoConfig(); const video = Internals11.useVideo(); const container = useRef10(null); const canvasSize = useElementSize(container, { triggerOnWindowResize: false, shouldApplyCssTransforms: false }); const [hasPausedToResume, setHasPausedToResume] = useState11(false); const [shouldAutoplay, setShouldAutoPlay] = useState11(autoPlay); const [isFullscreen, setIsFullscreen] = useState11(() => false); const [seeking, setSeeking] = useState11(false); const supportsFullScreen = useMemo12(() => { if (typeof document === "undefined") { return false; } return Boolean(document.fullscreenEnabled || document.webkitFullscreenEnabled); }, []); const player = usePlayer(); const playerToggle = player.toggle; usePlayback({ loop, playbackRate, moveToBeginningWhenEnded, inFrame, outFrame, getCurrentFrame: player.getCurrentFrame, browserMediaControlsBehavior }); useEffect12(() => { if (hasPausedToResume && !player.playing) { setHasPausedToResume(false); player.play(); } }, [hasPausedToResume, player]); useEffect12(() => { const { current } = container; if (!current) { return; } const onFullscreenChange = () => { const newValue = document.fullscreenElement === current || document.webkitFullscreenElement === current; setIsFullscreen(newValue); }; document.addEventListener("fullscreenchange", onFullscreenChange); document.addEventListener("webkitfullscreenchange", onFullscreenChange); return () => { document.removeEventListener("fullscreenchange", onFullscreenChange); document.removeEventListener("webkitfullscreenchange", onFullscreenChange); }; }, []); const toggle = useCallback11((e) => { playerToggle(e); }, [playerToggle]); const requestFullscreen = useCallback11(() => { if (!allowFullscreen) { throw new Error("allowFullscreen is false"); } if (!supportsFullScreen) { throw new Error("Browser doesnt support fullscreen"); } if (!container.current) { throw new Error("No player ref found"); } if (container.current.webkitRequestFullScreen) { container.current.webkitRequestFullScreen(); } else { container.current.requestFullscreen(); } }, [allowFullscreen, supportsFullScreen]); const exitFullscreen = useCallback11(() => { if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); } else { document.exitFullscreen(); } }, []); useEffect12(() => { const { current } = container; if (!current) { return; } const fullscreenChange = () => { const element = document.webkitFullscreenElement ?? document.fullscreenElement; if (element && element === container.current) { player.emitter.dispatchFullscreenChange({ isFullscreen: true }); } else { player.emitter.dispatchFullscreenChange({ isFullscreen: false }); } }; current.addEventListener("webkitfullscreenchange", fullscreenChange); current.addEventListener("fullscreenchange", fullscreenChange); return () => { current.removeEventListener("webkitfullscreenchange", fullscreenChange); current.removeEventListener("fullscreenchange", fullscreenChange); }; }, [player.emitter]); const durationInFrames = config?.durationInFrames ?? 1; const layout = useMemo12(() => { if (!config || !canvasSize) { return null; } return calculateCanvasTransformation({ canvasSize, compositionHeight: config.height, compositionWidth: config.width, previewSize: "auto" }); }, [canvasSize, config]); const scale = layout?.scale ?? 1; const initialScaleIgnored = useRef10(false); useEffect12(() => { if (!initialScaleIgnored.current) { initialScaleIgnored.current = true; return; } player.emitter.dispatchScaleChange(scale); }, [player.emitter, scale]); const { setMediaVolume, setMediaMuted } = useContext6(Internals11.SetMediaVolumeContext); const { mediaMuted, mediaVolume } = useContext6(Internals11.MediaVolumeContext); useEffect12(() => { player.emitter.dispatchVolumeChange(mediaVolume); }, [player.emitter, mediaVolume]); const isMuted = mediaMuted || mediaVolume === 0; useEffect12(() => { player.emitter.dispatchMuteChange({ isMuted }); }, [player.emitter, isMuted]); const [showBufferIndicator, setShowBufferState] = useState11(false); useEffect12(() => { let timeout = null; let stopped = false; const onBuffer = () => { stopped = false; requestAnimationFrame(() => { if (bufferStateDelayInMilliseconds === 0) { setShowBufferState(true); } else { timeout = setTimeout(() => { if (!stopped) { setShowBufferState(true); } }, bufferStateDelayInMilliseconds); } }); }; const onResume = () => { requestAnimationFrame(() => { stopped = true; setShowBufferState(false); if (timeout) { clearTimeout(timeout); } }); }; player.emitter.addEventListener("waiting", onBuffer); player.emitter.addEventListener("resume", onResume); return () => { player.emitter.removeEventListener("waiting", onBuffer); player.emitter.removeEventListener("resume", onResume); setShowBufferState(false); if (timeout) { clearTimeout(timeout); } stopped = true; }; }, [bufferStateDelayInMilliseconds, player.emitter]); useImperativeHandle(ref, () => { const methods = { play: player.play, pause: () => { setHasPausedToResume(false); player.pause(); }, toggle, getContainerNode: () => container.current, getCurrentFrame: player.getCurrentFrame, isPlaying: player.isPlaying, seekTo: (f) => { const lastFrame = durationInFrames - 1; const frameToSeekTo = Math.max(0, Math.min(lastFrame, f)); if (player.isPlaying()) { const pauseToResume = frameToSeekTo !== lastFrame || loop; setHasPausedToResume(pauseToResume); player.pause(); } if (frameToSeekTo === lastFrame && !loop) { player.emitter.dispatchEnded(); } player.seek(frameToSeekTo); }, isFullscreen: () => { const { current } = container; if (!current) { return false; } return document.fullscreenElement === current || document.webkitFullscreenElement === current; }, requestFullscreen, exitFullscreen, getVolume: () => { if (mediaMuted) { return 0; } return mediaVolume; }, setVolume: (vol) => { if (typeof vol !== "number") { throw new TypeError(`setVolume() takes a number, got value of type ${typeof vol}`); } if (isNaN(vol)) { throw new TypeError(`setVolume() got a number that is NaN. Volume must be between 0 and 1.`); } if (vol < 0 || vol > 1) { throw new TypeError(`setVolume() got a number that is out of range. Must be between 0 and 1, got ${typeof vol}`); } setMediaVolume(vol); }, isMuted: () => isMuted, mute: () => { setMediaMuted(true); }, unmute: () => { setMediaMuted(false); }, getScale: () => scale, pauseAndReturnToPlayStart: () => { player.pauseAndReturnToPlayStart(); } }; return Object.assign(player.emitter, methods); }, [ durationInFrames, exitFullscreen, loop, mediaMuted, isMuted, mediaVolume, player, requestFullscreen, setMediaMuted, setMediaVolume, toggle, scale ]); const VideoComponent = video ? video.component : null; const outerStyle = useMemo12(() => { return calculateOuterStyle({ canvasSize, config, style: style2, overflowVisible, layout }); }, [canvasSize, config, layout, overflowVisible, style2]); const outer = useMemo12(() => { return calculateOuter({ config, layout, scale, overflowVisible }); }, [config, layout, overflowVisible, scale]); const containerStyle3 = useMemo12(() => { return calculateContainerStyle({ config, layout, scale, overflowVisible }); }, [config, layout, overflowVisible, scale]); const playerPause = player.pause; const playerDispatchError = player.emitter.dispatchError; const onError = useCallback11((error) => { playerPause(); playerDispatchError(error); }, [playerDispatchError, playerPause]); const onFullscreenButtonClick = useCallback11((e) => { e.stopPropagation(); requestFullscreen(); }, [requestFullscreen]); const onExitFullscreenButtonClick = useCallback11((e) => { e.stopPropagation(); exitFullscreen(); }, [exitFullscreen]); const onSingleClick = useCallback11((e) => { const rightClick = e instanceof MouseEvent ? e.button === 2 : e.nativeEvent.button; if (rightClick) { return; } toggle(e); }, [toggle]); const onSeekStart = useCallback11(() => { setSeeking(true); }, []); const onSeekEnd = useCallback11(() => { setSeeking(false); }, []); const onDoubleClick = useCallback11(() => { if (isFullscreen) { exitFullscreen(); } else { requestFullscreen(); } }, [exitFullscreen, isFullscreen, requestFullscreen]); const { handlePointerDown, handleDoubleClick } = useClickPreventionOnDoubleClick(onSingleClick, onDoubleClick, doubleClickToFullscreen && allowFullscreen && supportsFullScreen); useEffect12(() => { if (shouldAutoplay) { player.play(); setShouldAutoPlay(false); } }, [shouldAutoplay, player]); const loadingMarkup = useMemo12(() => { return renderLoading ? renderLoading({ height: outerStyle.height, width: outerStyle.width, isBuffering: showBufferIndicator }) : null; }, [outerStyle.height, outerStyle.width, renderLoading, showBufferIndicator]); const currentScale = useMemo12(() => { return { type: "scale", scale }; }, [scale]); if (!config) { return null; } const poster = renderPoster ? renderPoster({ height: posterFillMode === "player-size" ? outerStyle.height : config.height, width: posterFillMode === "player-size" ? outerStyle.width : config.width, isBuffering: showBufferIndicator }) : null; if (poster === undefined) { throw new TypeError("renderPoster() must return a React element, but undefined was returned"); } const shouldShowPoster = poster && [ showPosterWhenPaused && !player.isPlaying() && !seeking, showPosterWhenEnded && player.isLastFrame && !player.isPlaying(), showPosterWhenUnplayed && !player.hasPlayed && !player.isPlaying(), showPosterWhenBuffering && showBufferIndicator && player.isPlaying(), showPosterWhenBufferingAndPaused && showBufferIndicator && !player.isPlaying() ].some(Boolean); const { left, top, width, height, ...outerWithoutScale } = outer; const content = /* @__PURE__ */ jsxs9(Fragment3, { children: [ /* @__PURE__ */ jsxs9("div", { style: outer, onPointerDown: clickToPlay ? handlePointerDown : undefined, onDoubleClick: doubleClickToFullscreen ? handleDoubleClick : undefined, children: [ /* @__PURE__ */ jsxs9("div", { style: containerStyle3, className: playerCssClassname(overrideInternalClassName), children: [ VideoComponent ? /* @__PURE__ */ jsx12(ErrorBoundary, { onError, errorFallback, children: /* @__PURE__ */ jsx12(Internals11.CurrentScaleContext.Provider, { value: currentScale, children: /* @__PURE__ */ jsx12(VideoComponent, { ...video?.props ?? {}, ...inputProps ?? {} }) }) }) : null, shouldShowPoster && posterFillMode === "composition-size" ? /* @__PURE__ */ jsx12("div", { style: { ...outerWithoutScale, width: config.width, height: config.height }, onPointerDown: clickToPlay ? handlePointerDown : undefined, onDoubleClick: doubleClickToFullscreen ? handleDoubleClick : undefined, children: poster }) : null ] }), /* @__PURE__ */ jsx12(RenderWarningIfBlacklist, {}) ] }), shouldShowPoster && posterFillMode === "player-size" ? /* @__PURE__ */ jsx12("div", { style: outer, onPointerDown: clickToPlay ? handlePointerDown : undefined, onDoubleClick: doubleClickToFullscreen ? handleDoubleClick : undefined, children: poster }) : null, controls ? /* @__PURE__ */ jsx12(Controls, { fps: config.fps, playing: player.playing, toggle: player.toggle, durationInFrames: config.durationInFrames, containerRef: container, onFullscreenButtonClick, isFullscreen, allowFullscreen, showVolumeControls, onExitFullscreenButtonClick, spaceKeyToPlayOrPause, onSeekEnd, onSeekStart, inFrame, outFrame, initiallyShowControls, canvasSize, renderFullscreenButton, renderPlayPauseButton, alwaysShowControls, showPlaybackRateControl, buffering: showBufferIndicator, hideControlsWhenPointerDoesntMove, onDoubleClick: doubleClickToFullscreen ? handleDoubleClick : undefined, onPointerDown: clickToPlay ? handlePointerDown : undefined, renderMuteButton, renderVolumeSlider, renderCustomControls }) : null ] }); if (noSuspense || IS_NODE && !doesReactVersionSupportSuspense) { return /* @__PURE__ */ jsx12("div", { ref: container, style: outerStyle, className: className2, children: content }); } return /* @__PURE__ */ jsx12("div", { ref: container, style: outerStyle, className: className2, children: /* @__PURE__ */ jsx12(Suspense, { fallback: loadingMarkup, children: content }) }); }; var PlayerUI_default = forwardRef(PlayerUI); // src/SharedPlayerContext.tsx import { useCallback as useCallback12, useMemo as useMemo13, useState as useState12 } from "react"; import { Internals as Internals13 } from "remotion"; // src/volume-persistance.ts import { Internals as Internals12 } from "remotion"; var DEFAULT_VOLUME_PERSISTANCE_KEY = "remotion.volumePreference"; var persistVolume = (volume, logLevel, volumePersistenceKey) => { if (typeof window === "undefined") { return; } try { window.localStorage.setItem(volumePersistenceKey ?? DEFAULT_VOLUME_PERSISTANCE_KEY, String(volume)); } catch (e) { Internals12.Log.error({ logLevel, tag: null }, "Could not persist volume", e); } }; var getPreferredVolume = (volumePersistenceKey) => { if (typeof window === "undefined") { return 1; } try { const val = window.localStorage.getItem(volumePersistenceKey ?? DEFAULT_VOLUME_PERSISTANCE_KEY); return val ? Number(val) : 1; } catch { return 1; } }; // src/SharedPlayerContext.tsx import { jsx as jsx13 } from "react/jsx-runtime"; var PLAYER_COMP_ID = "player-comp"; var SharedPlayerContexts = ({ children, timelineContext, fps, compositionHeight, compositionWidth, durationInFrames, component, numberOfSharedAudioTags, initiallyMuted, logLevel, audioLatencyHint, volumePersistenceKey, inputProps, audioEnabled }) => { const compositionManagerContext = useMemo13(() => { const context = { compositions: [ { component, durationInFrames, height: compositionHeight, width: compositionWidth, fps, id: PLAYER_COMP_ID, nonce: 777, folderName: null, parentFolderName: null, schema: null, calculateMetadata: null } ], folders: [], currentCompositionMetadata: { defaultCodec: null, defaultOutName: null, defaultPixelFormat: null, defaultProResProfile: null, defaultVideoImageFormat: null, durationInFrames, fps, height: compositionHeight, width: compositionWidth, props: inputProps }, canvasContent: { type: "composition", compositionId: "player-comp" } }; return context; }, [ component, durationInFrames, compositionHeight, compositionWidth, fps, inputProps ]); const [mediaMuted, setMediaMuted] = useState12(() => initiallyMuted); const [mediaVolume, setMediaVolume] = useState12(() => getPreferredVolume(volumePersistenceKey ?? null)); const mediaVolumeContextValue = useMemo13(() => { return { mediaMuted, mediaVolume }; }, [mediaMuted, mediaVolume]); const setMediaVolumeAndPersist = useCallback12((vol) => { setMediaVolume(vol); persistVolume(vol, logLevel, volumePersistenceKey ?? null); }, [logLevel, volumePersistenceKey]); const setMediaVolumeContextValue = useMemo13(() => { return { setMediaMuted, setMediaVolume: setMediaVolumeAndPersist }; }, [setMediaVolumeAndPersist]); const logLevelContext = useMemo13(() => { return { logLevel, mountTime: Date.now() }; }, [logLevel]); const env = useMemo13(() => { return { isPlayer: true, isRendering: false, isStudio: false, isClientSideRendering: false, isReadOnlyStudio: false }; }, []); return /* @__PURE__ */ jsx13(Internals13.RemotionEnvironmentContext.Provider, { value: env, children: /* @__PURE__ */ jsx13(Internals13.LogLevelContext.Provider, { value: logLevelContext, children: /* @__PURE__ */ jsx13(Internals13.CanUseRemotionHooksProvider, { children: /* @__PURE__ */ jsx13(Internals13.TimelineContext.Provider, { value: timelineContext, children: /* @__PURE__ */ jsx13(Internals13.CompositionManager.Provider, { value: compositionManagerContext, children: /* @__PURE__ */ jsx13(Internals13.PrefetchProvider, { children: /* @__PURE__ */ jsx13(Internals13.DurationsContextProvider, { children: /* @__PURE__ */ jsx13(Internals13.MediaVolumeContext.Provider, { value: mediaVolumeContextValue, children: /* @__PURE__ */ jsx13(Internals13.SetMediaVolumeContext.Provider, { value: setMediaVolumeContextValue, children: /* @__PURE__ */ jsx13(Internals13.SharedAudioContextProvider, { numberOfAudioTags: numberOfSharedAudioTags, audioLatencyHint, audioEnabled, children: /* @__PURE__ */ jsx13(Internals13.BufferingProvider, { children }) }) }) }) }) }) }) }) }) }) }); }; // src/use-remotion-license-acknowledge.ts import { Internals as Internals14 } from "remotion"; var warningShown = false; var acknowledgeRemotionLicenseMessage = (acknowledge, logLevel) => { if (acknowledge) { return; } if (warningShown) { return; } warningShown = true; Internals14.Log.warn({ logLevel, tag: null }, "Note: Some companies are required to obtain a license to use Remotion. See: https://remotion.dev/license\nPass the `acknowledgeRemotionLicense` prop to `` function to make this message disappear."); }; // src/utils/validate-in-out-frame.ts var validateSingleFrame = (frame, variableName) => { if (typeof frame === "undefined" || frame === null) { return frame ?? null; } if (typeof frame !== "number") { throw new TypeError(`"${variableName}" must be a number, but is ${JSON.stringify(frame)}`); } if (Number.isNaN(frame)) { throw new TypeError(`"${variableName}" must not be NaN, but is ${JSON.stringify(frame)}`); } if (!Number.isFinite(frame)) { throw new TypeError(`"${variableName}" must be finite, but is ${JSON.stringify(frame)}`); } if (frame % 1 !== 0) { throw new TypeError(`"${variableName}" must be an integer, but is ${JSON.stringify(frame)}`); } return frame; }; var validateInOutFrames = ({ inFrame, durationInFrames, outFrame }) => { const validatedInFrame = validateSingleFrame(inFrame, "inFrame"); const validatedOutFrame = validateSingleFrame(outFrame, "outFrame"); if (validatedInFrame === null && validatedOutFrame === null) { return; } if (validatedInFrame !== null && validatedInFrame > durationInFrames - 1) { throw new Error("inFrame must be less than (durationInFrames - 1), but is " + validatedInFrame); } if (validatedOutFrame !== null && validatedOutFrame > durationInFrames - 1) { throw new Error("outFrame must be less than (durationInFrames - 1), but is " + validatedOutFrame); } if (validatedInFrame !== null && validatedInFrame < 0) { throw new Error("inFrame must be greater than 0, but is " + validatedInFrame); } if (validatedOutFrame !== null && validatedOutFrame <= 0) { throw new Error(`outFrame must be greater than 0, but is ${validatedOutFrame}. If you want to render a single frame, use instead.`); } if (validatedOutFrame !== null && validatedInFrame !== null && validatedOutFrame <= validatedInFrame) { throw new Error("outFrame must be greater than inFrame, but is " + validatedOutFrame + " <= " + validatedInFrame); } }; // src/utils/validate-initial-frame.ts var validateInitialFrame = ({ initialFrame, durationInFrames }) => { if (typeof durationInFrames !== "number") { throw new Error(`\`durationInFrames\` must be a number, but is ${JSON.stringify(durationInFrames)}`); } if (typeof initialFrame === "undefined") { return; } if (typeof initialFrame !== "number") { throw new Error(`\`initialFrame\` must be a number, but is ${JSON.stringify(initialFrame)}`); } if (Number.isNaN(initialFrame)) { throw new Error(`\`initialFrame\` must be a number, but is NaN`); } if (!Number.isFinite(initialFrame)) { throw new Error(`\`initialFrame\` must be a number, but is Infinity`); } if (initialFrame % 1 !== 0) { throw new Error(`\`initialFrame\` must be an integer, but is ${JSON.stringify(initialFrame)}`); } if (initialFrame > durationInFrames - 1) { throw new Error(`\`initialFrame\` must be less or equal than \`durationInFrames - 1\`, but is ${JSON.stringify(initialFrame)}`); } }; // src/utils/validate-playbackrate.ts var validatePlaybackRate = (playbackRate) => { if (playbackRate === undefined) { return; } if (playbackRate > 4) { throw new Error(`The highest possible playback rate is 4. You passed: ${playbackRate}`); } if (playbackRate < -4) { throw new Error(`The lowest possible playback rate is -4. You passed: ${playbackRate}`); } if (playbackRate === 0) { throw new Error(`A playback rate of 0 is not supported.`); } }; // src/validate.ts import { NoReactInternals } from "remotion/no-react"; var validateFps = NoReactInternals.validateFps; var validateDimension = NoReactInternals.validateDimension; var validateDurationInFrames = NoReactInternals.validateDurationInFrames; var validateDefaultAndInputProps = NoReactInternals.validateDefaultAndInputProps; // src/Player.tsx import { jsx as jsx14 } from "react/jsx-runtime"; var componentOrNullIfLazy = (props) => { if ("component" in props) { return props.component; } return null; }; var PlayerFn = ({ durationInFrames, compositionHeight, compositionWidth, fps, inputProps, style: style2, controls = false, loop = false, autoPlay = false, showVolumeControls = true, allowFullscreen = true, clickToPlay, doubleClickToFullscreen = false, spaceKeyToPlayOrPause = true, moveToBeginningWhenEnded = true, numberOfSharedAudioTags = 5, errorFallback = () => "⚠️", playbackRate = 1, renderLoading, className: className2, showPosterWhenUnplayed, showPosterWhenEnded, showPosterWhenPaused, showPosterWhenBuffering, showPosterWhenBufferingAndPaused, initialFrame, renderPoster, inFrame, outFrame, initiallyShowControls, renderFullscreenButton, renderPlayPauseButton, renderVolumeSlider, renderCustomControls, alwaysShowControls = false, initiallyMuted = false, showPlaybackRateControl = false, posterFillMode = "player-size", bufferStateDelayInMilliseconds, hideControlsWhenPointerDoesntMove = true, overflowVisible = false, renderMuteButton, browserMediaControlsBehavior: passedBrowserMediaControlsBehavior, overrideInternalClassName, logLevel = "info", noSuspense, acknowledgeRemotionLicense, audioLatencyHint = "interactive", volumePersistenceKey, ...componentProps }, ref) => { if (typeof window !== "undefined") { window.remotion_isPlayer = true; } if (componentProps.defaultProps !== undefined) { throw new Error("The component does not accept `defaultProps`, but some were passed. Use `inputProps` instead."); } const componentForValidation = componentOrNullIfLazy(componentProps); if (componentForValidation?.type === Composition) { throw new TypeError(`'component' should not be an instance of . Pass the React component directly, and set the duration, fps and dimensions as separate props. See https://www.remotion.dev/docs/player/examples for an example.`); } if (componentForValidation === Composition) { throw new TypeError(`'component' must not be the 'Composition' component. Pass your own React component directly, and set the duration, fps and dimensions as separate props. See https://www.remotion.dev/docs/player/examples for an example.`); } useState13(() => acknowledgeRemotionLicenseMessage(Boolean(acknowledgeRemotionLicense), logLevel)); const component = Internals15.useLazyComponent({ compProps: componentProps, componentName: "Player", noSuspense: Boolean(noSuspense) }); validateInitialFrame({ initialFrame, durationInFrames }); const [frame, setFrame] = useState13(() => ({ [PLAYER_COMP_ID]: initialFrame ?? 0 })); const [playing, setPlaying] = useState13(false); const [rootId] = useState13("player-comp"); const rootRef = useRef11(null); const audioAndVideoTags = useRef11([]); const imperativePlaying = useRef11(false); const [currentPlaybackRate, setCurrentPlaybackRate] = useState13(playbackRate); if (typeof compositionHeight !== "number") { throw new TypeError(`'compositionHeight' must be a number but got '${typeof compositionHeight}' instead`); } if (typeof compositionWidth !== "number") { throw new TypeError(`'compositionWidth' must be a number but got '${typeof compositionWidth}' instead`); } validateDimension(compositionHeight, "compositionHeight", "of the component"); validateDimension(compositionWidth, "compositionWidth", "of the component"); validateDurationInFrames(durationInFrames, { component: "of the component", allowFloats: false }); validateFps(fps, "as a prop of the component", false); validateDefaultAndInputProps(inputProps, "inputProps", null); validateInOutFrames({ durationInFrames, inFrame, outFrame }); if (typeof controls !== "boolean" && typeof controls !== "undefined") { throw new TypeError(`'controls' must be a boolean or undefined but got '${typeof controls}' instead`); } if (typeof autoPlay !== "boolean" && typeof autoPlay !== "undefined") { throw new TypeError(`'autoPlay' must be a boolean or undefined but got '${typeof autoPlay}' instead`); } if (typeof loop !== "boolean" && typeof loop !== "undefined") { throw new TypeError(`'loop' must be a boolean or undefined but got '${typeof loop}' instead`); } if (typeof doubleClickToFullscreen !== "boolean" && typeof doubleClickToFullscreen !== "undefined") { throw new TypeError(`'doubleClickToFullscreen' must be a boolean or undefined but got '${typeof doubleClickToFullscreen}' instead`); } if (typeof showVolumeControls !== "boolean" && typeof showVolumeControls !== "undefined") { throw new TypeError(`'showVolumeControls' must be a boolean or undefined but got '${typeof showVolumeControls}' instead`); } if (typeof allowFullscreen !== "boolean" && typeof allowFullscreen !== "undefined") { throw new TypeError(`'allowFullscreen' must be a boolean or undefined but got '${typeof allowFullscreen}' instead`); } if (typeof clickToPlay !== "boolean" && typeof clickToPlay !== "undefined") { throw new TypeError(`'clickToPlay' must be a boolean or undefined but got '${typeof clickToPlay}' instead`); } if (typeof spaceKeyToPlayOrPause !== "boolean" && typeof spaceKeyToPlayOrPause !== "undefined") { throw new TypeError(`'spaceKeyToPlayOrPause' must be a boolean or undefined but got '${typeof spaceKeyToPlayOrPause}' instead`); } if (typeof numberOfSharedAudioTags !== "number" || numberOfSharedAudioTags % 1 !== 0 || !Number.isFinite(numberOfSharedAudioTags) || Number.isNaN(numberOfSharedAudioTags) || numberOfSharedAudioTags < 0) { throw new TypeError(`'numberOfSharedAudioTags' must be an integer but got '${numberOfSharedAudioTags}' instead`); } validatePlaybackRate(currentPlaybackRate); useEffect13(() => { setCurrentPlaybackRate(playbackRate); }, [playbackRate]); useImperativeHandle2(ref, () => rootRef.current, []); useState13(() => { Internals15.playbackLogging({ logLevel, message: `[player] Mounting . User agent = ${typeof navigator === "undefined" ? "server" : navigator.userAgent}`, tag: "player", mountTime: Date.now() }); }); const timelineContextValue = useMemo14(() => { return { frame, playing, rootId, playbackRate: currentPlaybackRate, imperativePlaying, setPlaybackRate: (rate) => { setCurrentPlaybackRate(rate); }, audioAndVideoTags }; }, [frame, currentPlaybackRate, playing, rootId]); const setTimelineContextValue = useMemo14(() => { return { setFrame, setPlaying }; }, [setFrame]); if (typeof window !== "undefined") { useLayoutEffect2(() => { Internals15.CSSUtils.injectCSS(Internals15.CSSUtils.makeDefaultPreviewCSS(`.${playerCssClassname(overrideInternalClassName)}`, "#fff")); }, [overrideInternalClassName]); } const actualInputProps = useMemo14(() => inputProps ?? {}, [inputProps]); const browserMediaControlsBehavior = useMemo14(() => { return passedBrowserMediaControlsBehavior ?? { mode: "prevent-media-session" }; }, [passedBrowserMediaControlsBehavior]); return /* @__PURE__ */ jsx14(Internals15.IsPlayerContextProvider, { children: /* @__PURE__ */ jsx14(SharedPlayerContexts, { timelineContext: timelineContextValue, component, compositionHeight, compositionWidth, durationInFrames, fps, numberOfSharedAudioTags, initiallyMuted, logLevel, audioLatencyHint, volumePersistenceKey, inputProps: actualInputProps, audioEnabled: true, children: /* @__PURE__ */ jsx14(Internals15.SetTimelineContext.Provider, { value: setTimelineContextValue, children: /* @__PURE__ */ jsx14(PlayerEmitterProvider, { currentPlaybackRate, children: /* @__PURE__ */ jsx14(PlayerUI_default, { ref: rootRef, posterFillMode, renderLoading, autoPlay: Boolean(autoPlay), loop: Boolean(loop), controls: Boolean(controls), errorFallback, style: style2, inputProps: actualInputProps, allowFullscreen: Boolean(allowFullscreen), moveToBeginningWhenEnded: Boolean(moveToBeginningWhenEnded), clickToPlay: typeof clickToPlay === "boolean" ? clickToPlay : Boolean(controls), showVolumeControls: Boolean(showVolumeControls), doubleClickToFullscreen: Boolean(doubleClickToFullscreen), spaceKeyToPlayOrPause: Boolean(spaceKeyToPlayOrPause), playbackRate: currentPlaybackRate, className: className2 ?? undefined, showPosterWhenUnplayed: Boolean(showPosterWhenUnplayed), showPosterWhenEnded: Boolean(showPosterWhenEnded), showPosterWhenPaused: Boolean(showPosterWhenPaused), showPosterWhenBuffering: Boolean(showPosterWhenBuffering), showPosterWhenBufferingAndPaused: Boolean(showPosterWhenBufferingAndPaused), renderPoster, inFrame: inFrame ?? null, outFrame: outFrame ?? null, initiallyShowControls: initiallyShowControls ?? true, renderFullscreen: renderFullscreenButton ?? null, renderPlayPauseButton: renderPlayPauseButton ?? null, renderMuteButton: renderMuteButton ?? null, renderVolumeSlider: renderVolumeSlider ?? null, renderCustomControls: renderCustomControls ?? null, alwaysShowControls, showPlaybackRateControl, bufferStateDelayInMilliseconds: bufferStateDelayInMilliseconds ?? 300, hideControlsWhenPointerDoesntMove, overflowVisible, browserMediaControlsBehavior, overrideInternalClassName: overrideInternalClassName ?? undefined, noSuspense: Boolean(noSuspense) }) }) }) }) }); }; var forward = forwardRef2; var Player = forward(PlayerFn); // src/Thumbnail.tsx import { forwardRef as forwardRef4, useImperativeHandle as useImperativeHandle4, useLayoutEffect as useLayoutEffect3, useMemo as useMemo17, useRef as useRef13, useState as useState14 } from "react"; import { Internals as Internals17, random as random2 } from "remotion"; // src/ThumbnailUI.tsx import React13, { forwardRef as forwardRef3, Suspense as Suspense2, useCallback as useCallback13, useImperativeHandle as useImperativeHandle3, useMemo as useMemo16, useRef as useRef12 } from "react"; import { Internals as Internals16 } from "remotion"; // src/use-thumbnail.ts import { useContext as useContext7, useMemo as useMemo15 } from "react"; var useThumbnail = () => { const emitter = useContext7(ThumbnailEmitterContext); if (!emitter) { throw new TypeError("Expected Player event emitter context"); } const returnValue = useMemo15(() => { return { emitter }; }, [emitter]); return returnValue; }; // src/ThumbnailUI.tsx import { jsx as jsx15 } from "react/jsx-runtime"; var reactVersion2 = React13.version.split(".")[0]; if (reactVersion2 === "0") { throw new Error(`Version ${reactVersion2} of "react" is not supported by Remotion`); } var doesReactVersionSupportSuspense2 = parseInt(reactVersion2, 10) >= 18; var ThumbnailUI = ({ style: style2, inputProps, errorFallback, renderLoading, className: className2, overflowVisible, noSuspense, overrideInternalClassName }, ref) => { const config = Internals16.useUnsafeVideoConfig(); const video = Internals16.useVideo(); const container = useRef12(null); const canvasSize = useElementSize(container, { triggerOnWindowResize: false, shouldApplyCssTransforms: false }); const layout = useMemo16(() => { if (!config || !canvasSize) { return null; } return calculateCanvasTransformation({ canvasSize, compositionHeight: config.height, compositionWidth: config.width, previewSize: "auto" }); }, [canvasSize, config]); const scale = layout?.scale ?? 1; const thumbnail = useThumbnail(); useBufferStateEmitter(thumbnail.emitter); useImperativeHandle3(ref, () => { const methods = { getContainerNode: () => container.current, getScale: () => scale }; return Object.assign(thumbnail.emitter, methods); }, [scale, thumbnail.emitter]); const VideoComponent = video ? video.component : null; const outerStyle = useMemo16(() => { return calculateOuterStyle({ config, style: style2, canvasSize, overflowVisible, layout }); }, [canvasSize, config, layout, overflowVisible, style2]); const outer = useMemo16(() => { return calculateOuter({ config, layout, scale, overflowVisible }); }, [config, layout, overflowVisible, scale]); const containerStyle3 = useMemo16(() => { return calculateContainerStyle({ config, layout, scale, overflowVisible }); }, [config, layout, overflowVisible, scale]); const onError = useCallback13((error) => { thumbnail.emitter.dispatchError(error); }, [thumbnail.emitter]); const loadingMarkup = useMemo16(() => { return renderLoading ? renderLoading({ height: outerStyle.height, width: outerStyle.width, isBuffering: false }) : null; }, [outerStyle.height, outerStyle.width, renderLoading]); const currentScaleContext = useMemo16(() => { return { type: "scale", scale }; }, [scale]); if (!config) { return null; } const content = /* @__PURE__ */ jsx15("div", { style: outer, children: /* @__PURE__ */ jsx15("div", { style: containerStyle3, className: playerCssClassname(overrideInternalClassName), children: VideoComponent ? /* @__PURE__ */ jsx15(ErrorBoundary, { onError, errorFallback, children: /* @__PURE__ */ jsx15(Internals16.CurrentScaleContext.Provider, { value: currentScaleContext, children: /* @__PURE__ */ jsx15(VideoComponent, { ...video?.props ?? {}, ...inputProps ?? {} }) }) }) : null }) }); if (noSuspense || IS_NODE && !doesReactVersionSupportSuspense2) { return /* @__PURE__ */ jsx15("div", { ref: container, style: outerStyle, className: className2, children: content }); } return /* @__PURE__ */ jsx15("div", { ref: container, style: outerStyle, className: className2, children: /* @__PURE__ */ jsx15(Suspense2, { fallback: loadingMarkup, children: content }) }); }; var ThumbnailUI_default = forwardRef3(ThumbnailUI); // src/Thumbnail.tsx import { jsx as jsx16 } from "react/jsx-runtime"; var ThumbnailFn = ({ frameToDisplay, style: style2, inputProps, compositionHeight, compositionWidth, durationInFrames, fps, className: className2, errorFallback = () => "⚠️", renderLoading, overflowVisible = false, overrideInternalClassName, logLevel = "info", noSuspense, ...componentProps }, ref) => { if (typeof window !== "undefined") { useLayoutEffect3(() => { window.remotion_isPlayer = true; }, []); } const [thumbnailId] = useState14(() => String(random2(null))); const rootRef = useRef13(null); const timelineState = useMemo17(() => { const value = { playing: false, frame: { [PLAYER_COMP_ID]: frameToDisplay }, rootId: thumbnailId, imperativePlaying: { current: false }, playbackRate: 1, setPlaybackRate: () => { throw new Error("thumbnail"); }, audioAndVideoTags: { current: [] } }; return value; }, [frameToDisplay, thumbnailId]); useImperativeHandle4(ref, () => rootRef.current, []); const Component = Internals17.useLazyComponent({ compProps: componentProps, componentName: "Thumbnail", noSuspense: Boolean(noSuspense) }); const [emitter] = useState14(() => new ThumbnailEmitter); const passedInputProps = useMemo17(() => { return inputProps ?? {}; }, [inputProps]); return /* @__PURE__ */ jsx16(Internals17.IsPlayerContextProvider, { children: /* @__PURE__ */ jsx16(SharedPlayerContexts, { timelineContext: timelineState, component: Component, compositionHeight, compositionWidth, durationInFrames, fps, numberOfSharedAudioTags: 0, initiallyMuted: true, logLevel, audioLatencyHint: "playback", inputProps: passedInputProps, audioEnabled: false, children: /* @__PURE__ */ jsx16(ThumbnailEmitterContext.Provider, { value: emitter, children: /* @__PURE__ */ jsx16(ThumbnailUI_default, { ref: rootRef, className: className2, errorFallback, inputProps: passedInputProps, renderLoading, style: style2, overflowVisible, overrideInternalClassName, noSuspense: Boolean(noSuspense) }) }) }) }); }; var forward2 = forwardRef4; var Thumbnail = forward2(ThumbnailFn); // src/index.ts var PlayerInternals = { PlayerEventEmitterContext, PlayerEmitter, usePlayer, usePlayback, useElementSize, calculateCanvasTransformation, useHoverState, updateAllElementsSizes, PlayerEmitterProvider, BufferingIndicator, useFrameImperative }; export { Thumbnail, PlayerInternals, Player };