@remotion/studio 4.0.514 → 4.0.515

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/api/install-package.js +14 -1
  2. package/dist/components/AssetSelectorItem.d.ts +2 -1
  3. package/dist/components/AssetSelectorItem.js +18 -14
  4. package/dist/components/AudioWaveform.js +17 -139
  5. package/dist/components/InspectorPanel/CompositionInspector.js +27 -5
  6. package/dist/components/InstallPackage.d.ts +1 -1
  7. package/dist/components/InstallPackage.js +38 -6
  8. package/dist/components/Menu/MenuDivider.js +1 -1
  9. package/dist/components/Modals.js +9 -2
  10. package/dist/components/RenderModal/GuiRenderStatus.js +3 -1
  11. package/dist/components/RenderModal/RenderModalOutputName.js +3 -3
  12. package/dist/components/RenderModal/WebRenderModal.js +4 -2
  13. package/dist/components/RenderQueue/RenderQueueItem.js +3 -1
  14. package/dist/components/RenderQueue/RenderQueueOpenInFolder.js +3 -1
  15. package/dist/components/RenderQueue/RenderQueueRemoveItem.js +1 -1
  16. package/dist/components/SelectedOutlineCanvasRotation.d.ts +1 -0
  17. package/dist/components/SelectedOutlineCanvasRotation.js +11 -4
  18. package/dist/components/SelectedOutlineElement.js +1 -1
  19. package/dist/components/SelectedOutlinePolygon.d.ts +1 -0
  20. package/dist/components/SelectedOutlinePolygon.js +3 -2
  21. package/dist/components/Timeline/TimelineClipboardKeybindings.js +6 -2
  22. package/dist/components/Timeline/TimelineEffectItem.js +23 -6
  23. package/dist/components/Timeline/TimelineEffectPropItem.js +6 -2
  24. package/dist/components/Timeline/TimelineExpandArrowButton.js +10 -7
  25. package/dist/components/Timeline/TimelineExpandedKeyframeRow.js +4 -1
  26. package/dist/components/Timeline/TimelineExpandedSection.js +8 -5
  27. package/dist/components/Timeline/TimelineRowChrome.d.ts +1 -0
  28. package/dist/components/Timeline/TimelineRowChrome.js +38 -2
  29. package/dist/components/Timeline/TimelineSelection.d.ts +8 -3
  30. package/dist/components/Timeline/TimelineSelection.js +6 -4
  31. package/dist/components/Timeline/TimelineSequenceItem.js +7 -4
  32. package/dist/components/Timeline/TimelineSequenceName.js +1 -1
  33. package/dist/components/Timeline/TimelineTrack.js +4 -1
  34. package/dist/components/Timeline/TimelineVideoInfo.js +4 -2
  35. package/dist/components/Timeline/delete-selected-timeline-item.js +6 -2
  36. package/dist/components/Timeline/duplicate-selected-timeline-item.js +4 -2
  37. package/dist/components/Timeline/save-effect-prop.js +3 -3
  38. package/dist/components/effect-drag-and-drop.js +6 -3
  39. package/dist/components/effect-operations-api.d.ts +8 -0
  40. package/dist/components/effect-operations-api.js +52 -0
  41. package/dist/error-overlay/remotion-overlay/log-studio-error.js +4 -0
  42. package/dist/esm/{chunk-r46yxrjr.js → chunk-s6k99gh2.js} +1 -1
  43. package/dist/esm/{chunk-xn2q7eem.js → chunk-v5a8vpv4.js} +3525 -3475
  44. package/dist/esm/internals.mjs +3525 -3475
  45. package/dist/esm/previewEntry.mjs +3533 -3483
  46. package/dist/esm/renderEntry.mjs +2 -2
  47. package/dist/helpers/browser-studio-operations.d.ts +3 -0
  48. package/dist/helpers/browser-studio-operations.js +18 -1
  49. package/dist/helpers/colors.d.ts +1 -1
  50. package/dist/helpers/colors.js +1 -1
  51. package/dist/helpers/inject-css.js +5 -3
  52. package/dist/helpers/use-max-media-duration.js +5 -3
  53. package/dist/helpers/use-media-metadata.js +37 -20
  54. package/dist/helpers/use-menu-structure.js +67 -80
  55. package/dist/icons/cloud-download.d.ts +4 -0
  56. package/dist/icons/cloud-download.js +8 -0
  57. package/dist/state/modals.d.ts +1 -1
  58. package/package.json +12 -12
@@ -4,7 +4,7 @@ import {
4
4
  WHITE,
5
5
  __require,
6
6
  __toESM
7
- } from "./chunk-r46yxrjr.js";
7
+ } from "./chunk-s6k99gh2.js";
8
8
 
9
9
  // src/renderEntry.tsx
10
10
  import { useContext, useEffect, useRef, useState } from "react";
@@ -213,7 +213,7 @@ var renderContent = (Root) => {
213
213
  renderToDOM(/* @__PURE__ */ jsx("div", {
214
214
  children: /* @__PURE__ */ jsx(DelayedSpinner, {})
215
215
  }));
216
- import("./chunk-xn2q7eem.js").then(({ StudioInternals }) => {
216
+ import("./chunk-v5a8vpv4.js").then(({ StudioInternals }) => {
217
217
  window.remotion_isStudio = true;
218
218
  window.remotion_isReadOnlyStudio = true;
219
219
  window.remotion_inputProps = "{}";
@@ -2,4 +2,7 @@ import type { BrowserStudioOperations } from '@remotion/studio-shared';
2
2
  export declare const BROWSER_STUDIO_OPERATIONS_READY_EVENT = "remotion-browser-studio-operations-ready";
3
3
  export declare const getBrowserStudioOperations: () => BrowserStudioOperations | null;
4
4
  export declare const getBrowserStudioKeyframeOperations: () => import("@remotion/studio-shared").BrowserStudioKeyframeOperations | null;
5
+ export declare const getBrowserStudioEffectOperations: () => import("@remotion/studio-shared").BrowserStudioEffectOperations | null;
5
6
  export declare const canUseKeyframeOperations: () => boolean;
7
+ export declare const canUseEffectOperations: () => boolean;
8
+ export declare const canInstallPackages: () => boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.canUseKeyframeOperations = exports.getBrowserStudioKeyframeOperations = exports.getBrowserStudioOperations = exports.BROWSER_STUDIO_OPERATIONS_READY_EVENT = void 0;
3
+ exports.canInstallPackages = exports.canUseEffectOperations = exports.canUseKeyframeOperations = exports.getBrowserStudioEffectOperations = exports.getBrowserStudioKeyframeOperations = exports.getBrowserStudioOperations = exports.BROWSER_STUDIO_OPERATIONS_READY_EVENT = void 0;
4
4
  // Browser Studio may be hosted by a different studio-shared version, so this
5
5
  // handshake intentionally has no shared runtime import.
6
6
  exports.BROWSER_STUDIO_OPERATIONS_READY_EVENT = 'remotion-browser-studio-operations-ready';
@@ -18,6 +18,23 @@ const getBrowserStudioKeyframeOperations = () => {
18
18
  return (_b = (_a = (0, exports.getBrowserStudioOperations)()) === null || _a === void 0 ? void 0 : _a.keyframes) !== null && _b !== void 0 ? _b : null;
19
19
  };
20
20
  exports.getBrowserStudioKeyframeOperations = getBrowserStudioKeyframeOperations;
21
+ const getBrowserStudioEffectOperations = () => {
22
+ var _a;
23
+ var _b;
24
+ return (_b = (_a = (0, exports.getBrowserStudioOperations)()) === null || _a === void 0 ? void 0 : _a.effects) !== null && _b !== void 0 ? _b : null;
25
+ };
26
+ exports.getBrowserStudioEffectOperations = getBrowserStudioEffectOperations;
21
27
  const canUseKeyframeOperations = () => !window.remotion_isReadOnlyStudio ||
22
28
  (0, exports.getBrowserStudioKeyframeOperations)() !== null;
23
29
  exports.canUseKeyframeOperations = canUseKeyframeOperations;
30
+ const canUseEffectOperations = () => !window.remotion_isReadOnlyStudio ||
31
+ (0, exports.getBrowserStudioEffectOperations)() !== null;
32
+ exports.canUseEffectOperations = canUseEffectOperations;
33
+ const canInstallPackages = () => {
34
+ const browserStudioOperations = (0, exports.getBrowserStudioOperations)();
35
+ if (browserStudioOperations !== null) {
36
+ return true;
37
+ }
38
+ return !window.remotion_isReadOnlyStudio;
39
+ };
40
+ exports.canInstallPackages = canInstallPackages;
@@ -62,7 +62,7 @@ export declare const ERROR_LINK_COLOR = "#58a6ff";
62
62
  export declare const INFO_BLUE = "#60a5fa";
63
63
  export declare const SERVER_DISCONNECTED_BACKGROUND = "#e74c3c";
64
64
  export declare const STACK_FRAME_BORDER_BLUE = "rgb(66, 144, 245)";
65
- export declare const TIMELINE_BACKGROUND_COLOR = "#0F1113";
65
+ export declare const TIMELINE_BACKGROUND_COLOR = "#15181B";
66
66
  export declare const TIMELINE_SELECTED_BACKGROUND_COLOR = "#3B3F42";
67
67
  export declare const TIMELINE_SELECTED_LABEL_BACKGROUND_COLOR = "#B0B0B0";
68
68
  export declare const TIMELINE_BLUE = "#0b84ff";
@@ -68,7 +68,7 @@ exports.ERROR_LINK_COLOR = '#58a6ff';
68
68
  exports.INFO_BLUE = '#60a5fa';
69
69
  exports.SERVER_DISCONNECTED_BACKGROUND = '#e74c3c';
70
70
  exports.STACK_FRAME_BORDER_BLUE = 'rgb(66, 144, 245)';
71
- exports.TIMELINE_BACKGROUND_COLOR = '#0F1113';
71
+ exports.TIMELINE_BACKGROUND_COLOR = '#15181B';
72
72
  exports.TIMELINE_SELECTED_BACKGROUND_COLOR = '#3B3F42';
73
73
  exports.TIMELINE_SELECTED_LABEL_BACKGROUND_COLOR = '#B0B0B0';
74
74
  exports.TIMELINE_BLUE = '#0b84ff';
@@ -58,7 +58,7 @@ const makeDefaultGlobalCSS = () => {
58
58
 
59
59
  input:focus,
60
60
  textarea:focus,
61
- button:focus:not(.__remotion_input_dragger):not(.__remotion_color_swatch):not(.__remotion-inspector-section-title),
61
+ button:focus:not(.__remotion_input_dragger):not(.__remotion_color_swatch):not(.__remotion-inspector-section-title):not(.__remotion-timeline-expand-arrow-button),
62
62
  a:focus {
63
63
  outline: none;
64
64
  box-shadow: ${colors_1.FOCUS_BOX_SHADOW};
@@ -66,14 +66,16 @@ const makeDefaultGlobalCSS = () => {
66
66
 
67
67
  .__remotion-composition-selector-item:focus,
68
68
  .__remotion-inspector-quick-action:focus,
69
- .__remotion-inspector-section-title:focus {
69
+ .__remotion-inspector-section-title:focus,
70
+ .__remotion-timeline-expand-arrow-button:focus {
70
71
  outline: none;
71
72
  box-shadow: none;
72
73
  }
73
74
 
74
75
  .__remotion-composition-selector-item:focus-visible,
75
76
  .__remotion-inspector-quick-action:focus-visible,
76
- .__remotion-inspector-section-title:focus-visible {
77
+ .__remotion-inspector-section-title:focus-visible,
78
+ .__remotion-timeline-expand-arrow-button:focus-visible {
77
79
  box-shadow: ${colors_1.FOCUS_BOX_SHADOW};
78
80
  }
79
81
 
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.useMaxMediaDuration = void 0;
4
4
  const react_1 = require("react");
5
+ const remotion_1 = require("remotion");
5
6
  const is_video_with_last_frame_hold_1 = require("./is-video-with-last-frame-hold");
6
7
  const use_media_metadata_1 = require("./use-media-metadata");
7
8
  const cache = new Map();
@@ -19,7 +20,8 @@ const useMaxMediaDuration = (s, fps) => {
19
20
  var _a;
20
21
  const holdsLastFrame = (0, is_video_with_last_frame_hold_1.isVideoWithLastFrameHold)(s);
21
22
  const src = holdsLastFrame ? null : getSrc(s);
22
- const cacheKey = src ? getCacheKey(src, fps) : null;
23
+ const resolvedSrc = remotion_1.Internals.usePreload(src !== null && src !== void 0 ? src : '');
24
+ const cacheKey = src ? getCacheKey(resolvedSrc, fps) : null;
23
25
  const [maxMediaDuration, setMaxMediaDuration] = (0, react_1.useState)(cacheKey ? ((_a = cache.get(cacheKey)) !== null && _a !== void 0 ? _a : null) : Infinity);
24
26
  (0, react_1.useEffect)(() => {
25
27
  var _a;
@@ -32,7 +34,7 @@ const useMaxMediaDuration = (s, fps) => {
32
34
  return;
33
35
  }
34
36
  let cancelled = false;
35
- (0, use_media_metadata_1.getMediaMetadata)(src)
37
+ (0, use_media_metadata_1.getMediaMetadata)(resolvedSrc)
36
38
  .then((metadata) => {
37
39
  if (cancelled || !metadata) {
38
40
  return;
@@ -50,7 +52,7 @@ const useMaxMediaDuration = (s, fps) => {
50
52
  return () => {
51
53
  cancelled = true;
52
54
  };
53
- }, [cacheKey, fps, src]);
55
+ }, [cacheKey, fps, resolvedSrc, src]);
54
56
  if (holdsLastFrame) {
55
57
  return Infinity;
56
58
  }
@@ -4,6 +4,7 @@ exports.useMediaMetadata = exports.getMediaMetadata = exports.getCachedMediaMeta
4
4
  const media_utils_1 = require("@remotion/media-utils");
5
5
  const mediabunny_1 = require("mediabunny");
6
6
  const react_1 = require("react");
7
+ const remotion_1 = require("remotion");
7
8
  const get_duration_or_compute_1 = require("./get-duration-or-compute");
8
9
  const cache = new Map();
9
10
  const pendingRequests = new Map();
@@ -22,19 +23,38 @@ const safeCall = async (fn) => {
22
23
  };
23
24
  const getMediabunnyMetadata = async (src) => {
24
25
  var _a, _b;
25
- let input;
26
- try {
27
- input = new mediabunny_1.Input({
28
- formats: mediabunny_1.ALL_FORMATS,
29
- source: new mediabunny_1.UrlSource(src),
30
- });
31
- }
32
- catch (_c) {
26
+ const lease = (() => {
27
+ try {
28
+ return remotion_1.Internals.globalMediaResourceManager.acquire({
29
+ key: remotion_1.Internals.getMediabunnyInputResourceKey({
30
+ src,
31
+ credentials: null,
32
+ requestInitFingerprint: null,
33
+ revision: null,
34
+ }),
35
+ create: () => {
36
+ const createdInput = new mediabunny_1.Input({
37
+ formats: mediabunny_1.ALL_FORMATS,
38
+ source: new mediabunny_1.UrlSource(src),
39
+ });
40
+ return {
41
+ resource: createdInput,
42
+ dispose: () => createdInput.dispose(),
43
+ };
44
+ },
45
+ });
46
+ }
47
+ catch (_a) {
48
+ return null;
49
+ }
50
+ })();
51
+ if (lease === null) {
33
52
  return null;
34
53
  }
54
+ const input = lease.resource;
35
55
  try {
36
56
  const [duration, format, videoTrack, audioTrack] = await Promise.all([
37
- safeCall(() => (0, get_duration_or_compute_1.getDurationOrCompute)(input)),
57
+ safeCall(() => lease.getOrCreateValue(remotion_1.Internals.MEDIABUNNY_DURATION_VALUE_KEY, () => (0, get_duration_or_compute_1.getDurationOrCompute)(input))),
38
58
  safeCall(() => input.getFormat()),
39
59
  safeCall(() => input.getPrimaryVideoTrack()),
40
60
  safeCall(() => input.getPrimaryAudioTrack()),
@@ -66,12 +86,7 @@ const getMediabunnyMetadata = async (src) => {
66
86
  };
67
87
  }
68
88
  finally {
69
- try {
70
- input.dispose();
71
- }
72
- catch (_d) {
73
- // ignore
74
- }
89
+ lease.release();
75
90
  }
76
91
  };
77
92
  const getFallbackVideoMetadata = async (src) => {
@@ -121,15 +136,17 @@ const getMediaMetadata = (src) => {
121
136
  };
122
137
  exports.getMediaMetadata = getMediaMetadata;
123
138
  const useMediaMetadata = (src) => {
124
- const [mediaMetadata, setMediaMetadata] = (0, react_1.useState)(src ? (0, exports.getCachedMediaMetadata)(src) : null);
139
+ const resolvedSrc = remotion_1.Internals.usePreload(src !== null && src !== void 0 ? src : '');
140
+ const metadataSrc = src === null ? null : resolvedSrc;
141
+ const [mediaMetadata, setMediaMetadata] = (0, react_1.useState)(metadataSrc ? (0, exports.getCachedMediaMetadata)(metadataSrc) : null);
125
142
  (0, react_1.useEffect)(() => {
126
- const cached = src ? (0, exports.getCachedMediaMetadata)(src) : null;
143
+ const cached = metadataSrc ? (0, exports.getCachedMediaMetadata)(metadataSrc) : null;
127
144
  setMediaMetadata(cached);
128
- if (!src || cached) {
145
+ if (!metadataSrc || cached) {
129
146
  return;
130
147
  }
131
148
  let cancelled = false;
132
- (0, exports.getMediaMetadata)(src)
149
+ (0, exports.getMediaMetadata)(metadataSrc)
133
150
  .then((metadata) => {
134
151
  if (cancelled) {
135
152
  return;
@@ -145,7 +162,7 @@ const useMediaMetadata = (src) => {
145
162
  return () => {
146
163
  cancelled = true;
147
164
  };
148
- }, [src]);
165
+ }, [metadataSrc]);
149
166
  return mediaMetadata;
150
167
  };
151
168
  exports.useMediaMetadata = useMediaMetadata;
@@ -29,7 +29,6 @@ const browser_studio_operations_1 = require("./browser-studio-operations");
29
29
  const check_fullscreen_support_1 = require("./check-fullscreen-support");
30
30
  const client_id_1 = require("./client-id");
31
31
  const colors_1 = require("./colors");
32
- const download_blob_1 = require("./download-blob");
33
32
  const get_file_manager_name_1 = require("./get-file-manager-name");
34
33
  const get_git_menu_item_1 = require("./get-git-menu-item");
35
34
  const mobile_layout_1 = require("./mobile-layout");
@@ -47,8 +46,7 @@ const ICON_SIZE = 14;
47
46
  const getFileMenu = ({ readOnlyStudio, closeMenu, editorName, editorId, previewServerState, setSelectedModal, }) => {
48
47
  const fileManagerName = (0, get_file_manager_name_1.getFileManagerName)(window.remotion_fileSystemPlatform);
49
48
  const browserStudioOperations = (0, browser_studio_operations_1.getBrowserStudioOperations)();
50
- const downloadProject = browserStudioOperations === null || browserStudioOperations === void 0 ? void 0 : browserStudioOperations.downloadProject;
51
- const items = [
49
+ const newProjectItems = [
52
50
  readOnlyStudio
53
51
  ? null
54
52
  : {
@@ -93,12 +91,8 @@ const getFileMenu = ({ readOnlyStudio, closeMenu, editorName, editorId, previewS
93
91
  quickSwitcherLabel: 'New folder...',
94
92
  disabled: previewServerState !== 'connected',
95
93
  },
96
- readOnlyStudio
97
- ? null
98
- : {
99
- type: 'divider',
100
- id: 'new-project-item-divider',
101
- },
94
+ ].filter(no_react_1.NoReactInternals.truthy);
95
+ const projectItems = [
102
96
  window.remotion_isReadOnlyStudio
103
97
  ? {
104
98
  id: 'input-props-override',
@@ -117,35 +111,6 @@ const getFileMenu = ({ readOnlyStudio, closeMenu, editorName, editorId, previewS
117
111
  quickSwitcherLabel: 'Override input props',
118
112
  }
119
113
  : null,
120
- downloadProject
121
- ? {
122
- id: 'download-project',
123
- value: 'download-project',
124
- label: 'Download project',
125
- onClick: async () => {
126
- closeMenu();
127
- try {
128
- const { data, fileName } = await downloadProject();
129
- const arrayBuffer = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
130
- (0, download_blob_1.downloadBlob)(new Blob([arrayBuffer], { type: 'application/zip' }), fileName);
131
- }
132
- catch (error) {
133
- (0, NotificationCenter_1.showNotification)(`Could not download project: ${error instanceof Error ? error.message : String(error)}`, 2000);
134
- }
135
- },
136
- type: 'item',
137
- keyHint: null,
138
- leftItem: null,
139
- subMenu: null,
140
- quickSwitcherLabel: 'Download project',
141
- }
142
- : null,
143
- !readOnlyStudio && downloadProject
144
- ? {
145
- type: 'divider',
146
- id: 'open-project-divider',
147
- }
148
- : null,
149
114
  editorName && editorId && !readOnlyStudio
150
115
  ? {
151
116
  id: 'open-in-editor',
@@ -178,7 +143,7 @@ const getFileMenu = ({ readOnlyStudio, closeMenu, editorName, editorId, previewS
178
143
  disabled: previewServerState !== 'connected',
179
144
  }
180
145
  : null,
181
- !readOnlyStudio
146
+ !readOnlyStudio && browserStudioOperations === null
182
147
  ? {
183
148
  id: 'open-project-in-explorer',
184
149
  value: 'open-project-in-explorer',
@@ -199,6 +164,16 @@ const getFileMenu = ({ readOnlyStudio, closeMenu, editorName, editorId, previewS
199
164
  : null,
200
165
  (0, get_git_menu_item_1.getGitMenuItem)(),
201
166
  ].filter(no_react_1.NoReactInternals.truthy);
167
+ const items = [
168
+ ...newProjectItems,
169
+ newProjectItems.length > 0 && projectItems.length > 0
170
+ ? {
171
+ type: 'divider',
172
+ id: 'new-project-item-divider',
173
+ }
174
+ : null,
175
+ ...projectItems,
176
+ ].filter(no_react_1.NoReactInternals.truthy);
202
177
  if (items.length === 0) {
203
178
  return null;
204
179
  }
@@ -272,6 +247,7 @@ const useMenuStructure = (closeMenu, readOnlyStudio) => {
272
247
  const sizes = (0, react_1.useMemo)(() => (0, SizeSelector_1.getUniqueSizes)(size), [size]);
273
248
  const isFullscreenSupported = (0, check_fullscreen_support_1.checkFullscreenSupport)();
274
249
  const { remotion_packageManager } = window;
250
+ const browserStudioOperations = (0, browser_studio_operations_1.getBrowserStudioOperations)();
275
251
  const sizePreselectIndex = sizes.findIndex((s) => String(size.size) === String(s.size));
276
252
  const mobileLayout = (0, mobile_layout_1.useMobileLayout)();
277
253
  const currentComposition = (0, react_1.useMemo)(() => {
@@ -328,27 +304,29 @@ const useMenuStructure = (closeMenu, readOnlyStudio) => {
328
304
  subMenu: null,
329
305
  quickSwitcherLabel: 'Help: Changelog',
330
306
  },
331
- {
332
- id: 'settings',
333
- value: 'settings',
334
- label: 'Settings...',
335
- onClick: () => {
336
- var _a;
337
- var _b;
338
- closeMenu();
339
- setSelectedModal({
340
- type: 'settings',
341
- initialTab: 'rendering',
342
- initialPublicLicenseKey: (_b = (_a = window.remotion_renderDefaults) === null || _a === void 0 ? void 0 : _a.publicLicenseKey) !== null && _b !== void 0 ? _b : null,
343
- });
344
- },
345
- type: 'item',
346
- keyHint: null,
347
- leftItem: null,
348
- subMenu: null,
349
- quickSwitcherLabel: 'Settings...',
350
- disabled: readOnlyStudio || type !== 'connected',
351
- },
307
+ browserStudioOperations === null
308
+ ? {
309
+ id: 'settings',
310
+ value: 'settings',
311
+ label: 'Settings...',
312
+ onClick: () => {
313
+ var _a;
314
+ var _b;
315
+ closeMenu();
316
+ setSelectedModal({
317
+ type: 'settings',
318
+ initialTab: 'rendering',
319
+ initialPublicLicenseKey: (_b = (_a = window.remotion_renderDefaults) === null || _a === void 0 ? void 0 : _a.publicLicenseKey) !== null && _b !== void 0 ? _b : null,
320
+ });
321
+ },
322
+ type: 'item',
323
+ keyHint: null,
324
+ leftItem: null,
325
+ subMenu: null,
326
+ quickSwitcherLabel: 'Settings...',
327
+ disabled: readOnlyStudio || type !== 'connected',
328
+ }
329
+ : null,
352
330
  {
353
331
  id: 'acknowledgements',
354
332
  value: 'acknowledgements',
@@ -363,24 +341,28 @@ const useMenuStructure = (closeMenu, readOnlyStudio) => {
363
341
  subMenu: null,
364
342
  quickSwitcherLabel: 'Help: Acknowledgements',
365
343
  },
366
- {
367
- type: 'divider',
368
- id: 'timeline-divider-1',
369
- },
370
- {
371
- id: 'restart-studio',
372
- value: 'restart-studio',
373
- label: 'Restart Studio Server',
374
- onClick: () => {
375
- closeMenu();
376
- (0, restart_studio_1.restartStudio)();
377
- },
378
- type: 'item',
379
- keyHint: null,
380
- leftItem: null,
381
- subMenu: null,
382
- quickSwitcherLabel: 'Restart Studio Server',
383
- },
344
+ browserStudioOperations === null
345
+ ? {
346
+ type: 'divider',
347
+ id: 'timeline-divider-1',
348
+ }
349
+ : null,
350
+ browserStudioOperations === null
351
+ ? {
352
+ id: 'restart-studio',
353
+ value: 'restart-studio',
354
+ label: 'Restart Studio Server',
355
+ onClick: () => {
356
+ closeMenu();
357
+ (0, restart_studio_1.restartStudio)();
358
+ },
359
+ type: 'item',
360
+ keyHint: null,
361
+ leftItem: null,
362
+ subMenu: null,
363
+ quickSwitcherLabel: 'Restart Studio Server',
364
+ }
365
+ : null,
384
366
  ].filter(no_react_1.NoReactInternals.truthy),
385
367
  quickSwitcherLabel: null,
386
368
  },
@@ -798,7 +780,9 @@ const useMenuStructure = (closeMenu, readOnlyStudio) => {
798
780
  quickSwitcherLabel: 'Show Color Picker',
799
781
  }
800
782
  : null,
801
- readOnlyStudio || remotion_packageManager === 'unknown'
783
+ !(0, browser_studio_operations_1.canInstallPackages)() ||
784
+ (browserStudioOperations === null &&
785
+ remotion_packageManager === 'unknown')
802
786
  ? null
803
787
  : {
804
788
  id: 'install-packages',
@@ -808,7 +792,9 @@ const useMenuStructure = (closeMenu, readOnlyStudio) => {
808
792
  closeMenu();
809
793
  setSelectedModal({
810
794
  type: 'install-packages',
811
- packageManager: remotion_packageManager,
795
+ packageManager: remotion_packageManager === 'unknown'
796
+ ? null
797
+ : remotion_packageManager,
812
798
  });
813
799
  },
814
800
  type: 'item',
@@ -1017,6 +1003,7 @@ const useMenuStructure = (closeMenu, readOnlyStudio) => {
1017
1003
  defaultEditorName,
1018
1004
  keyboardShortcutsDisabled,
1019
1005
  studioAskAIEnabled,
1006
+ browserStudioOperations,
1020
1007
  size.size,
1021
1008
  setSize,
1022
1009
  setEditorZoomGestures,
@@ -0,0 +1,4 @@
1
+ import type { SVGProps } from 'react';
2
+ export declare const CloudDownloadIcon: React.FC<SVGProps<SVGSVGElement> & {
3
+ readonly color: string;
4
+ }>;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CloudDownloadIcon = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const CloudDownloadIcon = ({ color, ...props }) => {
6
+ return (jsx_runtime_1.jsx("svg", { ...props, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 576 512", children: jsx_runtime_1.jsx("path", { fill: color, d: "M128 176c0-61.9 50.1-112 112-112 39.3 0 73.8 20.2 93.8 50.8 4.4 6.7 13.1 9.1 20.3 5.7 11.4-5.5 24.3-8.5 37.9-8.5 48.6 0 88 39.4 88 88 0 14.1-3.3 27.4-9.2 39.2-2 4.1-2.2 8.9-.5 13.1s5.2 7.6 9.5 9.1c37.4 13.1 64.2 48.8 64.2 90.6 0 53-43 96-96 96l-304 0c-61.9 0-112-50.1-112-112 0-53.7 37.8-98.6 88.2-109.5 4.3-.9 8.1-3.6 10.3-7.4s2.9-8.3 1.7-12.6c-2.7-9.7-4.2-19.9-4.2-30.5zM240 32c-79.5 0-144 64.5-144 144 0 8 .7 15.9 1.9 23.5-56.9 19.2-97.9 73-97.9 136.5 0 79.5 64.5 144 144 144l304 0c70.7 0 128-57.3 128-128 0-49.9-28.5-93-70.1-114.2 3.9-11.9 6.1-24.6 6.1-37.8 0-66.3-53.7-120-120-120-13.7 0-26.9 2.3-39.2 6.5-26.4-33.2-67.1-54.5-112.8-54.5zM371.3 307.3c6.2-6.2 6.2-16.4 0-22.6s-16.4-6.2-22.6 0L304 329.4 304 208c0-8.8-7.2-16-16-16s-16 7.2-16 16l0 121.4-44.7-44.7c-6.2-6.2-16.4-6.2-22.6 0s-6.2 16.4 0 22.6l72 72c6.2 6.2 16.4 6.2 22.6 0l72-72z" }) }));
7
+ };
8
+ exports.CloudDownloadIcon = CloudDownloadIcon;
@@ -170,7 +170,7 @@ export type ModalState = {
170
170
  remotionInteractivitySkillAvailable: boolean;
171
171
  } | {
172
172
  type: 'install-packages';
173
- packageManager: PackageManager;
173
+ packageManager: PackageManager | null;
174
174
  } | {
175
175
  type: 'quick-switcher';
176
176
  mode: QuickSwitcherMode;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "url": "https://github.com/remotion-dev/remotion/tree/main/packages/studio"
4
4
  },
5
5
  "name": "@remotion/studio",
6
- "version": "4.0.514",
6
+ "version": "4.0.515",
7
7
  "description": "APIs for interacting with the Remotion Studio",
8
8
  "main": "dist",
9
9
  "scripts": {
@@ -25,17 +25,17 @@
25
25
  },
26
26
  "dependencies": {
27
27
  "@tanstack/react-virtual": "3.14.9",
28
- "@remotion/studio-protocol": "4.0.514",
28
+ "@remotion/studio-protocol": "4.0.515",
29
29
  "semver": "7.5.3",
30
- "remotion": "4.0.514",
31
- "@remotion/captions": "4.0.514",
32
- "@remotion/player": "4.0.514",
33
- "@remotion/media-utils": "4.0.514",
34
- "@remotion/renderer": "4.0.514",
35
- "@remotion/web-renderer": "4.0.514",
36
- "@remotion/studio-shared": "4.0.514",
37
- "@remotion/timeline-utils": "4.0.514",
38
- "@remotion/zod-types": "4.0.514",
30
+ "remotion": "4.0.515",
31
+ "@remotion/captions": "4.0.515",
32
+ "@remotion/player": "4.0.515",
33
+ "@remotion/media-utils": "4.0.515",
34
+ "@remotion/renderer": "4.0.515",
35
+ "@remotion/web-renderer": "4.0.515",
36
+ "@remotion/studio-shared": "4.0.515",
37
+ "@remotion/timeline-utils": "4.0.515",
38
+ "@remotion/zod-types": "4.0.515",
39
39
  "@jridgewell/trace-mapping": "0.3.31",
40
40
  "mediabunny": "1.55.1",
41
41
  "memfs": "3.4.3",
@@ -46,7 +46,7 @@
46
46
  "react": "19.2.3",
47
47
  "react-dom": "19.2.3",
48
48
  "@types/semver": "7.5.3",
49
- "@remotion/eslint-config-internal": "4.0.514",
49
+ "@remotion/eslint-config-internal": "4.0.515",
50
50
  "eslint": "9.19.0",
51
51
  "@typescript/native-preview": "7.0.0-dev.20260217.1"
52
52
  },