@remotion/studio
Version:
APIs for interacting with the Remotion Studio
341 lines (340 loc) • 17.5 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.setBundleModeAndUpdate = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
// This file is not compiled by Typescript, but by ESBuild
// to keep the dynamic import
const react_1 = require("react");
// In React 18, you should use createRoot() from "react-dom/client".
// In React 18, you should use render from "react-dom".
// We support both, but Webpack chooses both of them and normalizes them to "react-dom/client",
// hence why we import the right thing all the time but need to differentiate here
const client_1 = __importDefault(require("react-dom/client"));
const remotion_1 = require("remotion");
const no_react_1 = require("remotion/no-react");
let currentBundleMode = {
type: 'index',
};
const setBundleMode = (state) => {
currentBundleMode = state;
};
const getBundleMode = () => {
return currentBundleMode;
};
remotion_1.Internals.CSSUtils.injectCSS(remotion_1.Internals.CSSUtils.makeDefaultPreviewCSS(null, '#1f2428'));
const getCanSerializeDefaultProps = (object) => {
try {
const str = JSON.stringify(object);
// 256MB is the theoretical limit, making it throw if over 90% of that is reached.
return str.length < 256 * 1024 * 1024 * 0.9;
}
catch (err) {
if (err.message.includes('Invalid string length')) {
return false;
}
throw err;
}
};
const isInHeadlessBrowser = () => {
return typeof window.remotion_puppeteerTimeout !== 'undefined';
};
const DelayedSpinner = () => {
const [show, setShow] = (0, react_1.useState)(false);
(0, react_1.useEffect)(() => {
const timeout = setTimeout(() => {
setShow(true);
}, 2000);
return () => {
clearTimeout(timeout);
};
}, []);
if (!show) {
return null;
}
return ((0, jsx_runtime_1.jsx)(remotion_1.AbsoluteFill, { style: {
justifyContent: 'center',
alignItems: 'center',
fontSize: 13,
opacity: 0.6,
color: 'white',
fontFamily: 'Helvetica, Arial, sans-serif',
}, children: "Loading Studio" }));
};
const GetVideoComposition = ({ state }) => {
const { compositions, currentCompositionMetadata, canvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
const { setCanvasContent } = (0, react_1.useContext)(remotion_1.Internals.CompositionSetters);
const portalContainer = (0, react_1.useRef)(null);
const { delayRender, continueRender } = (0, remotion_1.useDelayRender)();
const [handle] = (0, react_1.useState)(() => delayRender(`Waiting for Composition "${state.compositionName}"`));
(0, react_1.useEffect)(() => {
return () => continueRender(handle);
}, [handle, continueRender]);
(0, react_1.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]);
(0, react_1.useEffect)(() => {
if (!canvasContent) {
return;
}
const { current } = portalContainer;
if (!current) {
throw new Error('portal did not render');
}
current.appendChild(remotion_1.Internals.portalNode());
continueRender(handle);
return () => {
current.removeChild(remotion_1.Internals.portalNode());
};
}, [canvasContent, handle, continueRender]);
if (!currentCompositionMetadata) {
return null;
}
return ((0, jsx_runtime_1.jsx)("div", { ref: portalContainer, id: "remotion-canvas", style: {
width: currentCompositionMetadata.width,
height: currentCompositionMetadata.height,
display: 'flex',
backgroundColor: 'transparent',
} }));
};
const DEFAULT_ROOT_COMPONENT_TIMEOUT = 10000;
const waitForRootHandle = (0, remotion_1.delayRender)('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
: ((_a = window.remotion_puppeteerTimeout) !== null && _a !== void 0 ? _a : DEFAULT_ROOT_COMPONENT_TIMEOUT),
});
const videoContainer = document.getElementById('video-container');
let root = null;
const getRootForElement = () => {
if (root) {
return root;
}
root = client_1.default.createRoot(videoContainer);
return root;
};
const renderToDOM = (content) => {
if (!client_1.default.createRoot) {
if (no_react_1.NoReactInternals.ENABLE_V5_BREAKING_CHANGES) {
throw new Error('Remotion 5.0 does only support React 18+. However, ReactDOM.createRoot() is undefined.');
}
client_1.default.render(content, videoContainer);
return;
}
getRootForElement().render(content);
};
const renderContent = (Root) => {
var _a, _b;
const bundleMode = getBundleMode();
if (bundleMode.type === 'composition') {
const markup = ((0, jsx_runtime_1.jsxs)(remotion_1.Internals.RemotionRoot, { audioEnabled: window.remotion_audioEnabled, videoEnabled: window.remotion_videoEnabled, logLevel: window.remotion_logLevel, numberOfAudioTags: 0, audioLatencyHint: (_a = window.remotion_audioLatencyHint) !== null && _a !== void 0 ? _a : 'interactive', onlyRenderComposition: bundleMode.compositionName, currentCompositionMetadata: {
props: no_react_1.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,
}, children: [(0, jsx_runtime_1.jsx)(Root, {}), (0, jsx_runtime_1.jsx)(GetVideoComposition, { state: bundleMode })] }));
renderToDOM(markup);
}
if (bundleMode.type === 'evaluation') {
const markup = ((0, jsx_runtime_1.jsx)(remotion_1.Internals.RemotionRoot, { audioEnabled: window.remotion_audioEnabled, videoEnabled: window.remotion_videoEnabled, logLevel: window.remotion_logLevel, numberOfAudioTags: 0, onlyRenderComposition: null, currentCompositionMetadata: null, audioLatencyHint: (_b = window.remotion_audioLatencyHint) !== null && _b !== void 0 ? _b : 'interactive', children: (0, jsx_runtime_1.jsx)(Root, {}) }));
renderToDOM(markup);
}
if (bundleMode.type === 'index') {
if (isInHeadlessBrowser()) {
return;
}
renderToDOM((0, jsx_runtime_1.jsx)("div", { children: (0, jsx_runtime_1.jsx)(DelayedSpinner, {}) }));
Promise.resolve().then(() => __importStar(require('./internals'))).then(({ StudioInternals }) => {
window.remotion_isStudio = true;
window.remotion_isReadOnlyStudio = true;
remotion_1.Internals.enableSequenceStackTraces();
renderToDOM((0, jsx_runtime_1.jsx)(StudioInternals.Studio, { readOnly: true, rootComponent: Root }));
})
.catch((err) => {
renderToDOM((0, jsx_runtime_1.jsxs)("div", { children: ["Failed to load Remotion Studio: ", err.message] }));
});
}
};
remotion_1.Internals.waitForRoot((Root) => {
renderContent(Root);
(0, remotion_1.continueRender)(waitForRootHandle);
});
const setBundleModeAndUpdate = (state) => {
setBundleMode(state);
const delay = (0, remotion_1.delayRender)('Waiting for root component to load - See https://remotion.dev/docs/troubleshooting/loading-root-component if you experience a timeout');
remotion_1.Internals.waitForRoot((Root) => {
renderContent(Root);
requestAnimationFrame(() => {
(0, remotion_1.continueRender)(delay);
});
});
};
exports.setBundleModeAndUpdate = setBundleModeAndUpdate;
if (typeof window !== 'undefined') {
const getUnevaluatedComps = () => {
if (!remotion_1.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 (!remotion_1.Internals.compositionsRef.current) {
throw new Error('Unexpectedly did not have a CompositionManager');
}
const compositions = remotion_1.Internals.compositionsRef.current.getCompositions();
const canSerializeDefaultProps = getCanSerializeDefaultProps(compositions);
if (!canSerializeDefaultProps) {
remotion_1.Internals.Log.warn({ logLevel: window.remotion_logLevel, tag: null }, 'defaultProps are too big to serialize - trying to find the problematic composition...');
remotion_1.Internals.Log.warn({ logLevel: window.remotion_logLevel, 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`);
}
}
remotion_1.Internals.Log.warn({ logLevel: window.remotion_logLevel, 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 = () => {
var _a;
const compositions = getUnevaluatedComps();
const inputProps = typeof window === 'undefined' || (0, remotion_1.getRemotionEnvironment)().isPlayer
? {}
: ((_a = (0, remotion_1.getInputProps)()) !== null && _a !== void 0 ? _a : {});
return Promise.all(compositions.map(async (c) => {
var _a, _b, _c, _d, _e, _f;
const handle = (0, remotion_1.delayRender)(`Running calculateMetadata() for composition ${c.id}. If you didn't want to evaluate this composition, use "selectComposition()" instead of "getCompositions()"`);
const originalProps = {
...((_a = c.defaultProps) !== null && _a !== void 0 ? _a : {}),
...(inputProps !== null && inputProps !== void 0 ? inputProps : {}),
};
const comp = remotion_1.Internals.resolveVideoConfig({
calculateMetadata: c.calculateMetadata,
compositionDurationInFrames: (_b = c.durationInFrames) !== null && _b !== void 0 ? _b : null,
compositionFps: (_c = c.fps) !== null && _c !== void 0 ? _c : null,
compositionHeight: (_d = c.height) !== null && _d !== void 0 ? _d : null,
compositionWidth: (_e = c.width) !== null && _e !== void 0 ? _e : null,
signal: new AbortController().signal,
originalProps,
defaultProps: (_f = c.defaultProps) !== null && _f !== void 0 ? _f : {},
compositionId: c.id,
});
const resolved = await Promise.resolve(comp);
(0, remotion_1.continueRender)(handle);
const { props, defaultProps, ...data } = resolved;
return {
...data,
serializedResolvedPropsWithCustomSchema: no_react_1.NoReactInternals.serializeJSONWithSpecialTypes({
data: props,
indent: undefined,
staticBase: null,
}).serializedString,
serializedDefaultPropsWithCustomSchema: no_react_1.NoReactInternals.serializeJSONWithSpecialTypes({
data: defaultProps,
indent: undefined,
staticBase: null,
}).serializedString,
};
}));
};
window.remotion_getCompositionNames = () => {
return getUnevaluatedComps().map((c) => c.id);
};
window.remotion_calculateComposition = async (compId) => {
var _a, _b, _c, _d, _e, _f, _g;
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 = (0, remotion_1.delayRender)(`Running the calculateMetadata() function for composition ${compId}`);
const inputProps = typeof window === 'undefined' || (0, remotion_1.getRemotionEnvironment)().isPlayer
? {}
: ((_a = (0, remotion_1.getInputProps)()) !== null && _a !== void 0 ? _a : {});
const originalProps = {
...((_b = selectedComp.defaultProps) !== null && _b !== void 0 ? _b : {}),
...(inputProps !== null && inputProps !== void 0 ? inputProps : {}),
};
const prom = await Promise.resolve(remotion_1.Internals.resolveVideoConfig({
calculateMetadata: selectedComp.calculateMetadata,
compositionDurationInFrames: (_c = selectedComp.durationInFrames) !== null && _c !== void 0 ? _c : null,
compositionFps: (_d = selectedComp.fps) !== null && _d !== void 0 ? _d : null,
compositionHeight: (_e = selectedComp.height) !== null && _e !== void 0 ? _e : null,
compositionWidth: (_f = selectedComp.width) !== null && _f !== void 0 ? _f : null,
originalProps,
signal: abortController.signal,
defaultProps: (_g = selectedComp.defaultProps) !== null && _g !== void 0 ? _g : {},
compositionId: selectedComp.id,
}));
(0, remotion_1.continueRender)(handle);
const { props, defaultProps, ...data } = prom;
return {
...data,
serializedResolvedPropsWithCustomSchema: no_react_1.NoReactInternals.serializeJSONWithSpecialTypes({
data: props,
indent: undefined,
staticBase: null,
}).serializedString,
serializedDefaultPropsWithCustomSchema: no_react_1.NoReactInternals.serializeJSONWithSpecialTypes({
data: defaultProps,
indent: undefined,
staticBase: null,
}).serializedString,
};
};
window.remotion_setBundleMode = exports.setBundleModeAndUpdate;
}