UNPKG

@remotion/studio

Version:

APIs for interacting with the Remotion Studio

353 lines (351 loc) 13.8 kB
import { __require, __toESM } from "./chunk-6jf1natv.js"; // src/renderEntry.tsx import { useContext, useEffect, useRef, useState } from "react"; import ReactDOM from "react-dom/client"; import { AbsoluteFill, getInputProps, getRemotionEnvironment, continueRender as globalContinueRender, delayRender as globalDelayRender, Internals, useDelayRender } from "remotion"; import { NoReactInternals } from "remotion/no-react"; import { jsx, jsxs } from "react/jsx-runtime"; var currentBundleMode = { type: "index" }; var setBundleMode = (state) => { currentBundleMode = state; }; var getBundleMode = () => { return currentBundleMode; }; Internals.CSSUtils.injectCSS(Internals.CSSUtils.makeDefaultPreviewCSS(null, "#1f2428")); var getCanSerializeDefaultProps = (object) => { try { const str = JSON.stringify(object); return str.length < 256 * 1024 * 1024 * 0.9; } catch (err) { if (err.message.includes("Invalid string length")) { return false; } throw err; } }; var isInHeadlessBrowser = () => { return typeof window.remotion_puppeteerTimeout !== "undefined"; }; var DelayedSpinner = () => { const [show, setShow] = useState(false); useEffect(() => { const timeout = setTimeout(() => { setShow(true); }, 2000); return () => { clearTimeout(timeout); }; }, []); if (!show) { return null; } return /* @__PURE__ */ jsx(AbsoluteFill, { style: { justifyContent: "center", alignItems: "center", fontSize: 13, opacity: 0.6, color: "white", fontFamily: "Helvetica, Arial, sans-serif" }, children: "Loading Studio" }); }; var GetVideoComposition = ({ state }) => { const { compositions, currentCompositionMetadata, canvasContent } = useContext(Internals.CompositionManager); const { setCanvasContent } = useContext(Internals.CompositionSetters); const portalContainer = useRef(null); const { delayRender, continueRender } = useDelayRender(); const [handle] = useState(() => delayRender(`Waiting for Composition "${state.compositionName}"`)); useEffect(() => { return () => continueRender(handle); }, [handle, continueRender]); useEffect(() => { if (compositions.length === 0) { return; } const foundComposition = compositions.find((c) => c.id === state.compositionName); if (!foundComposition) { throw new Error(`Found no composition with the name ${state.compositionName}. The following compositions were found instead: ${compositions.map((c) => c.id).join(", ")}. All compositions must have their ID calculated deterministically and must be mounted at the same time.`); } setCanvasContent({ type: "composition", compositionId: foundComposition.id }); }, [compositions, state, currentCompositionMetadata, setCanvasContent]); useEffect(() => { if (!canvasContent) { return; } const { current } = portalContainer; if (!current) { throw new Error("portal did not render"); } current.appendChild(Internals.portalNode()); continueRender(handle); return () => { current.removeChild(Internals.portalNode()); }; }, [canvasContent, handle, continueRender]); if (!currentCompositionMetadata) { return null; } return /* @__PURE__ */ jsx("div", { ref: portalContainer, id: "remotion-canvas", style: { width: currentCompositionMetadata.width, height: currentCompositionMetadata.height, display: "flex", backgroundColor: "transparent" } }); }; var DEFAULT_ROOT_COMPONENT_TIMEOUT = 1e4; var waitForRootHandle = globalDelayRender("Loading root component - See https://remotion.dev/docs/troubleshooting/loading-root-component if you experience a timeout", { timeoutInMilliseconds: typeof window === "undefined" ? DEFAULT_ROOT_COMPONENT_TIMEOUT : window.remotion_puppeteerTimeout ?? DEFAULT_ROOT_COMPONENT_TIMEOUT }); var videoContainer = document.getElementById("video-container"); var root = null; var getRootForElement = () => { if (root) { return root; } root = ReactDOM.createRoot(videoContainer); return root; }; var renderToDOM = (content) => { if (!ReactDOM.createRoot) { if (NoReactInternals.ENABLE_V5_BREAKING_CHANGES) { throw new Error("Remotion 5.0 does only support React 18+. However, ReactDOM.createRoot() is undefined."); } ReactDOM.render(content, videoContainer); return; } getRootForElement().render(content); }; var renderContent = (Root) => { const bundleMode = getBundleMode(); if (bundleMode.type === "composition") { const markup = /* @__PURE__ */ jsx(Internals.CompositionManagerProvider, { initialCanvasContent: null, onlyRenderComposition: bundleMode.compositionName, currentCompositionMetadata: { props: NoReactInternals.deserializeJSONWithSpecialTypes(bundleMode.serializedResolvedPropsWithSchema), durationInFrames: bundleMode.compositionDurationInFrames, fps: bundleMode.compositionFps, height: bundleMode.compositionHeight, width: bundleMode.compositionWidth, defaultCodec: bundleMode.compositionDefaultCodec, defaultOutName: bundleMode.compositionDefaultOutName, defaultVideoImageFormat: bundleMode.compositionDefaultVideoImageFormat, defaultPixelFormat: bundleMode.compositionDefaultPixelFormat, defaultProResProfile: bundleMode.compositionDefaultProResProfile }, initialCompositions: [], children: /* @__PURE__ */ jsx(Internals.RemotionRootContexts, { frameState: null, audioEnabled: window.remotion_audioEnabled, videoEnabled: window.remotion_videoEnabled, logLevel: window.remotion_logLevel ?? "info", numberOfAudioTags: 0, audioLatencyHint: window.remotion_audioLatencyHint ?? "interactive", visualModeEnabled: false, children: /* @__PURE__ */ jsxs(Internals.RenderAssetManagerProvider, { collectAssets: null, children: [ /* @__PURE__ */ jsx(Root, {}), /* @__PURE__ */ jsx(GetVideoComposition, { state: bundleMode }) ] }) }) }); renderToDOM(markup); } if (bundleMode.type === "evaluation") { const markup = /* @__PURE__ */ jsx(Internals.CompositionManagerProvider, { initialCanvasContent: null, onlyRenderComposition: null, currentCompositionMetadata: null, initialCompositions: [], children: /* @__PURE__ */ jsx(Internals.RemotionRootContexts, { frameState: null, audioEnabled: window.remotion_audioEnabled, videoEnabled: window.remotion_videoEnabled, logLevel: window.remotion_logLevel ?? "info", numberOfAudioTags: 0, audioLatencyHint: window.remotion_audioLatencyHint ?? "interactive", visualModeEnabled: false, children: /* @__PURE__ */ jsx(Internals.RenderAssetManagerProvider, { collectAssets: null, children: /* @__PURE__ */ jsx(Root, {}) }) }) }); renderToDOM(markup); } if (bundleMode.type === "index") { if (isInHeadlessBrowser()) { return; } renderToDOM(/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(DelayedSpinner, {}) })); import("./chunk-bqd9dhnk.js").then(({ StudioInternals }) => { window.remotion_isStudio = true; window.remotion_isReadOnlyStudio = true; window.remotion_inputProps = "{}"; renderToDOM(/* @__PURE__ */ jsx(StudioInternals.Studio, { readOnly: true, rootComponent: Root, visualModeEnabled: false })); }).catch((err) => { renderToDOM(/* @__PURE__ */ jsxs("div", { children: [ "Failed to load Remotion Studio: ", err.message ] })); }); } }; Internals.waitForRoot((Root) => { renderContent(Root); globalContinueRender(waitForRootHandle); }); var setBundleModeAndUpdate = (state) => { setBundleMode(state); const delay = globalDelayRender("Waiting for root component to load - See https://remotion.dev/docs/troubleshooting/loading-root-component if you experience a timeout"); Internals.waitForRoot((Root) => { renderContent(Root); requestAnimationFrame(() => { globalContinueRender(delay); }); }); }; if (typeof window !== "undefined") { const getUnevaluatedComps = () => { if (!Internals.getRoot()) { throw new Error("registerRoot() was never called. 1. Make sure you specified the correct entrypoint for your bundle. 2. If your registerRoot() call is deferred, use the delayRender/continueRender pattern to tell Remotion to wait."); } if (!Internals.compositionsRef.current) { throw new Error("Unexpectedly did not have a CompositionManager"); } const compositions = Internals.compositionsRef.current.getCompositions(); const canSerializeDefaultProps = getCanSerializeDefaultProps(compositions); if (!canSerializeDefaultProps) { Internals.Log.warn({ logLevel: window.remotion_logLevel ?? "info", tag: null }, "defaultProps are too big to serialize - trying to find the problematic composition..."); Internals.Log.warn({ logLevel: window.remotion_logLevel ?? "info", tag: null }, "Serialization:", compositions); for (const comp of compositions) { if (!getCanSerializeDefaultProps(comp)) { throw new Error(`defaultProps too big - could not serialize - the defaultProps of composition with ID ${comp.id} - the object that was passed to defaultProps was too big. Learn how to mitigate this error by visiting https://remotion.dev/docs/troubleshooting/serialize-defaultprops`); } } Internals.Log.warn({ logLevel: window.remotion_logLevel ?? "info", tag: null }, "Could not single out a problematic composition - The composition list as a whole is too big to serialize."); throw new Error("defaultProps too big - Could not serialize - an object that was passed to defaultProps was too big. Learn how to mitigate this error by visiting https://remotion.dev/docs/troubleshooting/serialize-defaultprops"); } return compositions; }; window.getStaticCompositions = () => { const compositions = getUnevaluatedComps(); const inputProps = typeof window === "undefined" || getRemotionEnvironment().isPlayer ? {} : getInputProps() ?? {}; return Promise.all(compositions.map(async (c) => { const handle = globalDelayRender(`Running calculateMetadata() for composition ${c.id}. If you didn't want to evaluate this composition, use "selectComposition()" instead of "getCompositions()"`); const originalProps = { ...c.defaultProps ?? {}, ...inputProps ?? {} }; const comp = Internals.resolveVideoConfig({ calculateMetadata: c.calculateMetadata, compositionDurationInFrames: c.durationInFrames ?? null, compositionFps: c.fps ?? null, compositionHeight: c.height ?? null, compositionWidth: c.width ?? null, signal: new AbortController().signal, inputProps: originalProps, defaultProps: c.defaultProps ?? {}, compositionId: c.id }); const resolved = await Promise.resolve(comp); globalContinueRender(handle); const { props, defaultProps, ...data } = resolved; return { ...data, serializedResolvedPropsWithCustomSchema: NoReactInternals.serializeJSONWithSpecialTypes({ data: props, indent: undefined, staticBase: null }).serializedString, serializedDefaultPropsWithCustomSchema: NoReactInternals.serializeJSONWithSpecialTypes({ data: defaultProps, indent: undefined, staticBase: null }).serializedString }; })); }; window.remotion_getCompositionNames = () => { return getUnevaluatedComps().map((c) => c.id); }; window.remotion_calculateComposition = async (compId) => { const compositions = getUnevaluatedComps(); const selectedComp = compositions.find((c) => c.id === compId); if (!selectedComp) { throw new Error(`Could not find composition with ID ${compId}. Available compositions: ${compositions.map((c) => c.id).join(", ")}`); } const abortController = new AbortController; const handle = globalDelayRender(`Running the calculateMetadata() function for composition ${compId}`); const inputProps = typeof window === "undefined" || getRemotionEnvironment().isPlayer ? {} : getInputProps() ?? {}; const originalProps = { ...selectedComp.defaultProps ?? {}, ...inputProps ?? {} }; const prom = await Promise.resolve(Internals.resolveVideoConfig({ calculateMetadata: selectedComp.calculateMetadata, compositionDurationInFrames: selectedComp.durationInFrames ?? null, compositionFps: selectedComp.fps ?? null, compositionHeight: selectedComp.height ?? null, compositionWidth: selectedComp.width ?? null, inputProps: originalProps, signal: abortController.signal, defaultProps: selectedComp.defaultProps ?? {}, compositionId: selectedComp.id })); globalContinueRender(handle); const { props, defaultProps, ...data } = prom; return { ...data, serializedResolvedPropsWithCustomSchema: NoReactInternals.serializeJSONWithSpecialTypes({ data: props, indent: undefined, staticBase: null }).serializedString, serializedDefaultPropsWithCustomSchema: NoReactInternals.serializeJSONWithSpecialTypes({ data: defaultProps, indent: undefined, staticBase: null }).serializedString }; }; window.remotion_setBundleMode = setBundleModeAndUpdate; } export { setBundleModeAndUpdate };