UNPKG

@remotion/studio

Version:

APIs for interacting with the Remotion Studio

624 lines (611 loc) 19.3 kB
var __create = Object.create; var __getProtoOf = Object.getPrototypeOf; var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __toESM = (mod, isNodeMode, target) => { target = mod != null ? __create(__getProtoOf(mod)) : {}; const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target; for (let key of __getOwnPropNames(mod)) if (!__hasOwnProp.call(to, key)) __defProp(to, key, { get: () => mod[key], enumerable: true }); return to; }; var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { get: (a, b) => (typeof require !== "undefined" ? require : a)[b] }) : x)(function(x) { if (typeof require !== "undefined") return require.apply(this, arguments); throw Error('Dynamic require of "' + x + '" is not supported'); }); // src/api/create-composition.tsx import { Composition, Still } from "remotion"; import { jsx } from "react/jsx-runtime"; var createComposition = ({ ...other }) => () => { return /* @__PURE__ */ jsx(Composition, { ...other }); }; var createStill = ({ ...other }) => () => { return /* @__PURE__ */ jsx(Still, { ...other }); }; // src/api/delete-static-file.ts import { getRemotionEnvironment } from "remotion"; // src/components/call-api.ts var callApi = (endpoint, body, signal) => { return new Promise((resolve, reject) => { fetch(endpoint, { method: "post", headers: { "content-type": "application/json" }, signal, body: JSON.stringify(body) }).then((res) => res.json()).then((data) => { if (data.success) { resolve(data.data); } else { reject(new Error(data.error)); } }).catch((err) => { reject(err); }); }); }; // src/api/delete-static-file.ts var deleteStaticFile = async (relativePath) => { if (!getRemotionEnvironment().isStudio) { throw new Error("deleteStaticFile() is only available in the Studio"); } if (window.remotion_isReadOnlyStudio) { throw new Error("deleteStaticFile() is not available in Read-Only Studio"); } if (relativePath.startsWith(window.remotion_staticBase)) { relativePath = relativePath.substring(window.remotion_staticBase.length + 1); } const res = await callApi("/api/delete-static-file", { relativePath }); return res; }; // src/components/RenderModal/SchemaEditor/scroll-to-default-props-path.ts import React from "react"; var DEFAULT_PROPS_PATH_CLASSNAME = "__remotion-default-props-editor-label"; var DEFAULT_PROPS_PATH_ACTIVE_CLASSNAME = "__remotion-default-props-editor-label-active"; var defaultPropsEditorScrollableAreaRef = React.createRef(); // src/api/focus-default-props-path.ts var focusDefaultPropsPath = ({ path, scrollBehavior }) => { const currentlyActive = document.querySelector(`.${DEFAULT_PROPS_PATH_ACTIVE_CLASSNAME}`); if (currentlyActive !== null) { currentlyActive.classList.remove(DEFAULT_PROPS_PATH_ACTIVE_CLASSNAME); } const query = document.querySelector(`.${DEFAULT_PROPS_PATH_CLASSNAME}[data-json-path="${path.join(".")}"]`); if (query === null) { return { success: false }; } query.scrollIntoView({ behavior: scrollBehavior }); query.classList.add(DEFAULT_PROPS_PATH_ACTIVE_CLASSNAME); return { success: true }; }; // src/api/get-static-files.ts var warnedServer = false; var warnedPlayer = false; var warnServerOnce = () => { if (warnedServer) { return; } warnedServer = true; console.warn("Called getStaticFiles() on the server. The API is only available in the browser. An empty array was returned."); }; var warnPlayerOnce = () => { if (warnedPlayer) { return; } warnedPlayer = true; console.warn("Called getStaticFiles() while using the Remotion Player. The API is only available while using the Remotion Studio. An empty array was returned."); }; var getStaticFiles = () => { if (typeof document === "undefined") { warnServerOnce(); return []; } if (window.remotion_isPlayer) { warnPlayerOnce(); return []; } return window.remotion_staticFiles; }; // src/api/go-to-composition.ts import { Internals } from "remotion"; var goToComposition = (compositionId) => { Internals.compositionSelectorRef.current?.selectComposition(compositionId); }; // src/api/helpers/calc-new-props.ts import { Internals as Internals2, getRemotionEnvironment as getRemotionEnvironment2 } from "remotion"; var calcNewProps = (compositionId, defaultProps) => { if (!getRemotionEnvironment2().isStudio) { throw new Error("saveDefaultProps can only be called in the Remotion Studio."); } const { compositionsRef, editorPropsProviderRef } = Internals2; const compositionsStore = compositionsRef.current; if (!compositionsStore) { throw new Error("No compositions ref found. Are you in the Remotion Studio and are the Remotion versions aligned?"); } const compositions = compositionsStore.getCompositions(); const composition = compositions.find((c) => c.id === compositionId); if (!composition) { throw new Error(`No composition with the ID ${compositionId} found. Available compositions: ${compositions.map((c) => c.id).join(", ")}`); } const propsStore = editorPropsProviderRef.current; if (!propsStore) { throw new Error("No props store found. Are you in the Remotion Studio and are the Remotion versions aligned?"); } const savedDefaultProps = composition.defaultProps ?? {}; const unsavedDefaultProps = propsStore.getProps()[compositionId] ?? savedDefaultProps; const generatedDefaultProps = defaultProps({ schema: composition.schema, savedDefaultProps, unsavedDefaultProps }); return { composition, generatedDefaultProps }; }; // src/api/pause.ts import { Internals as Internals3 } from "remotion"; var pause = () => { Internals3.timeValueRef.current?.pause(); }; // src/api/play.ts import { Internals as Internals4 } from "remotion"; var play = (e) => { Internals4.timeValueRef.current?.play(e); }; // src/api/reevaluate-composition.ts import { Internals as Internals5 } from "remotion"; var reevaluateComposition = () => { Internals5.resolveCompositionsRef.current?.reloadCurrentlySelectedComposition(); }; // src/api/restart-studio.ts import { getRemotionEnvironment as getRemotionEnvironment3 } from "remotion"; var restartStudio = () => { if (!getRemotionEnvironment3().isStudio) { throw new Error("restartStudio() is only available in the Studio"); } if (window.remotion_isReadOnlyStudio) { throw new Error("restartStudio() is not available in read-only Studio"); } return callApi("/api/restart-studio", {}); }; // src/api/save-default-props.ts import { getRemotionEnvironment as getRemotionEnvironment4 } from "remotion"; // src/components/RenderModal/SchemaEditor/extract-enum-json-paths.ts var extractEnumJsonPaths = ({ schema, zodRuntime, currentPath, zodTypes }) => { const def = schema._def; const typeName = def.typeName; switch (typeName) { case zodRuntime.ZodFirstPartyTypeKind.ZodObject: { const shape = def.shape(); const keys = Object.keys(shape); return keys.map((key) => { return extractEnumJsonPaths({ schema: shape[key], zodRuntime, currentPath: [...currentPath, key], zodTypes }); }).flat(1); } case zodRuntime.ZodFirstPartyTypeKind.ZodArray: { return extractEnumJsonPaths({ schema: def.type, zodRuntime, currentPath: [...currentPath, "[]"], zodTypes }); } case zodRuntime.ZodFirstPartyTypeKind.ZodUnion: { return def.options.map((option) => { return extractEnumJsonPaths({ schema: option, zodRuntime, currentPath, zodTypes }); }).flat(1); } case zodRuntime.ZodFirstPartyTypeKind.ZodDiscriminatedUnion: { return def.options.map((op) => { return extractEnumJsonPaths({ schema: op, zodRuntime, currentPath, zodTypes }); }).flat(1); } case zodRuntime.ZodFirstPartyTypeKind.ZodLiteral: { return [currentPath]; } case zodRuntime.ZodFirstPartyTypeKind.ZodEffects: { if (zodTypes && schema._def.description === zodTypes.ZodZypesInternals.REMOTION_MATRIX_BRAND) { return [currentPath]; } return extractEnumJsonPaths({ schema: def.schema, zodRuntime, currentPath, zodTypes }); } case zodRuntime.ZodFirstPartyTypeKind.ZodIntersection: { const { left, right } = def; const leftValue = extractEnumJsonPaths({ schema: left, zodRuntime, currentPath, zodTypes }); const rightValue = extractEnumJsonPaths({ schema: right, zodRuntime, currentPath, zodTypes }); return [...leftValue, ...rightValue]; } case zodRuntime.ZodFirstPartyTypeKind.ZodTuple: { return def.items.map((item, i) => extractEnumJsonPaths({ schema: item, zodRuntime, currentPath: [...currentPath, i], zodTypes })).flat(1); } case zodRuntime.ZodFirstPartyTypeKind.ZodRecord: { const values = extractEnumJsonPaths({ schema: def.valueType, zodRuntime, currentPath: [...currentPath, "{}"], zodTypes }); return values; } case zodRuntime.ZodFirstPartyTypeKind.ZodFunction: { throw new Error("Cannot create a value for type function"); } case zodRuntime.ZodFirstPartyTypeKind.ZodEnum: { return [currentPath]; } case zodRuntime.ZodFirstPartyTypeKind.ZodNativeEnum: { return []; } case zodRuntime.ZodFirstPartyTypeKind.ZodOptional: { const defType = def; const value = extractEnumJsonPaths({ schema: defType.innerType, zodRuntime, currentPath, zodTypes }); return value; } case zodRuntime.ZodFirstPartyTypeKind.ZodNullable: { const defType = def; const value = extractEnumJsonPaths({ schema: defType.innerType, zodRuntime, currentPath, zodTypes }); return value; } case zodRuntime.ZodFirstPartyTypeKind.ZodDefault: { const defType = def; return extractEnumJsonPaths({ schema: defType.innerType, zodRuntime, currentPath, zodTypes }); } case zodRuntime.ZodFirstPartyTypeKind.ZodCatch: { const defType = def; return extractEnumJsonPaths({ schema: defType.innerType, zodRuntime, currentPath, zodTypes }); } case zodRuntime.ZodFirstPartyTypeKind.ZodPromise: { return []; } case zodRuntime.ZodFirstPartyTypeKind.ZodBranded: { const defType = def; const value = extractEnumJsonPaths({ schema: defType.type, zodRuntime, currentPath, zodTypes }); return value; } case zodRuntime.ZodFirstPartyTypeKind.ZodPipeline: { const defType = def; const value = extractEnumJsonPaths({ schema: defType.out, zodRuntime, currentPath, zodTypes }); return value; } case zodRuntime.ZodFirstPartyTypeKind.ZodString: case zodRuntime.ZodFirstPartyTypeKind.ZodNumber: case zodRuntime.ZodFirstPartyTypeKind.ZodBigInt: case zodRuntime.ZodFirstPartyTypeKind.ZodBoolean: case zodRuntime.ZodFirstPartyTypeKind.ZodNaN: case zodRuntime.ZodFirstPartyTypeKind.ZodDate: case zodRuntime.ZodFirstPartyTypeKind.ZodSymbol: case zodRuntime.ZodFirstPartyTypeKind.ZodUndefined: case zodRuntime.ZodFirstPartyTypeKind.ZodNull: case zodRuntime.ZodFirstPartyTypeKind.ZodAny: case zodRuntime.ZodFirstPartyTypeKind.ZodUnknown: case zodRuntime.ZodFirstPartyTypeKind.ZodNever: case zodRuntime.ZodFirstPartyTypeKind.ZodVoid: case zodRuntime.ZodFirstPartyTypeKind.ZodMap: case zodRuntime.ZodFirstPartyTypeKind.ZodLazy: case zodRuntime.ZodFirstPartyTypeKind.ZodSet: { return []; } default: throw new Error("Not implemented: " + typeName); } }; // src/components/RenderQueue/actions.ts import { NoReactInternals } from "remotion/no-react"; var callUpdateDefaultPropsApi = (compositionId, defaultProps, enumPaths) => { return callApi("/api/update-default-props", { compositionId, defaultProps: NoReactInternals.serializeJSONWithSpecialTypes({ data: defaultProps, indent: undefined, staticBase: window.remotion_staticBase }).serializedString, enumPaths }); }; // src/api/save-default-props.ts var saveDefaultProps = async ({ compositionId, defaultProps }) => { if (!getRemotionEnvironment4().isStudio) { throw new Error("saveDefaultProps() is only available in the Studio"); } if (window.remotion_isReadOnlyStudio) { throw new Error("saveDefaultProps() is not available in read-only Studio"); } try { await import("zod"); } catch { throw new Error('"zod" is required to use saveDefaultProps(), but is not installed.'); } const z = await import("zod"); let zodTypes = null; try { zodTypes = await import("@remotion/zod-types"); } catch {} const { generatedDefaultProps, composition } = calcNewProps(compositionId, defaultProps); const res = await callUpdateDefaultPropsApi(compositionId, generatedDefaultProps, composition.schema ? extractEnumJsonPaths({ schema: composition.schema, zodRuntime: z, currentPath: [], zodTypes }) : []); if (res.success) { return Promise.resolve(); } const err = new Error(res.reason); err.stack = res.stack; return Promise.reject(err); }; // src/api/seek.ts import { Internals as Internals6 } from "remotion"; var seek = (frame) => { Internals6.timeValueRef.current?.seek(Math.max(0, frame)); }; // src/api/toggle.ts import { Internals as Internals7 } from "remotion"; var toggle = (e) => { Internals7.timeValueRef.current?.toggle(e); }; // src/api/update-default-props.ts import { Internals as Internals8 } from "remotion"; var updateDefaultProps = ({ compositionId, defaultProps }) => { const { generatedDefaultProps, composition } = calcNewProps(compositionId, defaultProps); const propsStore = Internals8.editorPropsProviderRef.current; if (!propsStore) { throw new Error("No props store found. Are you in the Remotion Studio and are the Remotion versions aligned?"); } propsStore.setProps((prev) => { return { ...prev, [composition.id]: generatedDefaultProps }; }); window.dispatchEvent(new CustomEvent(Internals8.PROPS_UPDATED_EXTERNALLY, { detail: { resetUnsaved: null } })); }; // src/api/visual-control.ts import { getRemotionEnvironment as getRemotionEnvironment5 } from "remotion"; // src/visual-controls/VisualControls.tsx import { createContext, createRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react"; import { useRemotionEnvironment } from "remotion"; import { jsx as jsx2 } from "react/jsx-runtime"; var VisualControlsTabActivatedContext = createContext(false); var VisualControlsContext = createContext({ handles: {} }); var visualControlRef = createRef(); var SetVisualControlsContext = createContext({ updateHandles: () => { throw new Error("updateHandles is not implemented"); }, updateValue: () => { throw new Error("updateValue is not implemented"); }, visualControl: () => { throw new Error("visualControl is not implemented"); } }); // src/api/visual-control.ts var visualControl = (key, value, schema) => { if (getRemotionEnvironment5().isRendering) { return value; } if (!visualControlRef.current) { throw new Error("visualControlRef is not set"); } return visualControlRef.current.globalVisualControl(key, value, schema); }; // src/api/watch-public-folder.ts import { getRemotionEnvironment as getRemotionEnvironment6 } from "remotion"; var WATCH_REMOTION_STATIC_FILES = "remotion_staticFilesChanged"; var watchPublicFolder = (callback) => { if (!getRemotionEnvironment6().isStudio) { console.warn("The watchPublicFolder() API is only available while using the Remotion Studio."); return { cancel: () => { return; } }; } if (window.remotion_isReadOnlyStudio) { throw new Error("watchPublicFolder() is not available in read-only Studio"); } const emitUpdate = () => { callback(getStaticFiles()); }; window.addEventListener(WATCH_REMOTION_STATIC_FILES, emitUpdate); const cancel = () => { return window.removeEventListener(WATCH_REMOTION_STATIC_FILES, emitUpdate); }; return { cancel }; }; // src/api/watch-static-file.ts import { getRemotionEnvironment as getRemotionEnvironment7 } from "remotion"; var watchStaticFile = (fileName, callback) => { if (!getRemotionEnvironment7().isStudio) { console.warn("watchStaticFile() is only available while using the Remotion Studio."); return { cancel: () => { return; } }; } if (window.remotion_isReadOnlyStudio) { console.warn("watchStaticFile() is only available in an interactive Studio."); return { cancel: () => { return; } }; } const withoutStaticBase = fileName.startsWith(window.remotion_staticBase) ? fileName.replace(window.remotion_staticBase, "") : fileName; const withoutLeadingSlash = withoutStaticBase.startsWith("/") ? withoutStaticBase.slice(1) : withoutStaticBase; let prevFileData = window.remotion_staticFiles.find((file) => file.name === withoutLeadingSlash); const { cancel } = watchPublicFolder((staticFiles) => { const newFileData = staticFiles.find((file) => file.name === withoutLeadingSlash); if (!newFileData) { if (prevFileData !== undefined) { callback(null); } prevFileData = undefined; return; } if (prevFileData === undefined || prevFileData.lastModified !== newFileData.lastModified) { callback(newFileData); prevFileData = newFileData; } }); return { cancel }; }; // src/api/write-static-file.ts var writeStaticFile = async ({ contents, filePath }) => { if (window.remotion_isReadOnlyStudio) { throw new Error("writeStaticFile() is not available in read-only Studio"); } const url = new URL("/api/add-asset", window.location.origin); if (filePath.includes("\\")) { return Promise.reject(new Error("File path cannot contain backslashes")); } url.search = new URLSearchParams({ filePath }).toString(); const response = await fetch(url, { method: "POST", body: contents }); if (!response.ok) { const jsonResponse = await response.json(); throw new Error(jsonResponse.error); } }; // src/index.ts var StudioInternals = { createComposition, createStill }; export { writeStaticFile, watchStaticFile, watchPublicFolder, visualControl, updateDefaultProps, toggle, seek, saveDefaultProps, restartStudio, reevaluateComposition, play, pause, goToComposition, getStaticFiles, focusDefaultPropsPath, deleteStaticFile, StudioInternals };