@remotion/studio 4.0.516 → 4.0.518
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.
- package/dist/components/AssetSelector.js +63 -22
- package/dist/components/AssetSelectorItem.d.ts +2 -1
- package/dist/components/AssetSelectorItem.js +41 -10
- package/dist/components/Canvas.js +15 -12
- package/dist/components/CanvasCaptureDropHandler.d.ts +4 -0
- package/dist/components/CanvasCaptureDropHandler.js +42 -0
- package/dist/components/CanvasOrLoading.js +4 -3
- package/dist/components/CaptionInspector.js +1 -1
- package/dist/components/CaptionTextEditor.js +32 -8
- package/dist/components/CheckboardToggle.js +1 -1
- package/dist/components/Checkbox.d.ts +0 -1
- package/dist/components/Checkbox.js +2 -19
- package/dist/components/CompositionContextButton.js +2 -1
- package/dist/components/CompositionSelector.js +1 -1
- package/dist/components/ConfigureLicenseModal.js +79 -46
- package/dist/components/CurrentAsset.d.ts +1 -1
- package/dist/components/CurrentAsset.js +9 -4
- package/dist/components/Editor.js +2 -1
- package/dist/components/EditorContent.js +11 -5
- package/dist/components/EditorContexts.js +2 -1
- package/dist/components/EditorRuler/Ruler.d.ts +1 -0
- package/dist/components/EditorRuler/Ruler.js +9 -8
- package/dist/components/EditorRuler/index.d.ts +1 -0
- package/dist/components/EditorRuler/index.js +3 -4
- package/dist/components/EditorRuler/use-is-ruler-visible.d.ts +1 -1
- package/dist/components/EditorRuler/use-is-ruler-visible.js +8 -2
- package/dist/components/ElementInstallConfirmation.d.ts +5 -0
- package/dist/components/ElementInstallConfirmation.js +25 -1
- package/dist/components/ElementLibraryModal.d.ts +5 -0
- package/dist/components/ElementLibraryModal.js +40 -0
- package/dist/components/FilePreview.js +71 -0
- package/dist/components/InlineCaptionInspector.js +13 -2
- package/dist/components/InlineEditableTitle.js +2 -2
- package/dist/components/InspectorPanel/CompositionInspector.js +11 -38
- package/dist/components/InspectorPanel/CompositionInspectorHeader.js +2 -2
- package/dist/components/InspectorPanel/CompositionMetadata.js +11 -4
- package/dist/components/InspectorPanel/EasingInspector.js +2 -2
- package/dist/components/InspectorPanel/ElementLibraryButton.d.ts +2 -0
- package/dist/components/InspectorPanel/ElementLibraryButton.js +139 -0
- package/dist/components/InspectorPanel/KeyframeInspector.js +1 -1
- package/dist/components/InspectorPanel/SequenceInspectorHeader.js +12 -5
- package/dist/components/InspectorPanel/SequenceSelectionInspector.js +1 -3
- package/dist/components/InspectorPanel/common.d.ts +0 -1
- package/dist/components/InspectorPanel/common.js +3 -7
- package/dist/components/InspectorPanel/inspector-selection.d.ts +2 -2
- package/dist/components/InspectorPanel/styles.d.ts +0 -1
- package/dist/components/InspectorPanel/styles.js +3 -4
- package/dist/components/InspectorPanel/use-track-for-selection.d.ts +1 -2
- package/dist/components/InspectorSequenceSection.d.ts +1 -2
- package/dist/components/InspectorSourceLocation.js +1 -1
- package/dist/components/Menu/MenuItem.js +15 -6
- package/dist/components/MenuToolbar.js +7 -3
- package/dist/components/Modals.js +51 -1
- package/dist/components/PlaybackRateSelector.js +3 -6
- package/dist/components/Preview.js +83 -5
- package/dist/components/PreviewToolbar.js +10 -4
- package/dist/components/PreviewToolbarOverflowButton.d.ts +1 -0
- package/dist/components/PreviewToolbarOverflowButton.js +9 -2
- package/dist/components/QuickSwitcher/ExplorerQuickSwitcherTrigger.d.ts +2 -0
- package/dist/components/QuickSwitcher/ExplorerQuickSwitcherTrigger.js +28 -8
- package/dist/components/RadioButton.d.ts +6 -0
- package/dist/components/RadioButton.js +62 -0
- package/dist/components/RenderButton.js +2 -1
- package/dist/components/RulersAndGuidesToggle.d.ts +3 -1
- package/dist/components/RulersAndGuidesToggle.js +18 -7
- package/dist/components/SelectedOutlineKeyboardControls.d.ts +2 -2
- package/dist/components/SelectedOutlineOverlay.d.ts +1 -3
- package/dist/components/SelectedOutlineOverlay.js +21 -17
- package/dist/components/SelectedOutlinePolygon.d.ts +1 -2
- package/dist/components/SelectedOutlineRenderer.d.ts +2 -3
- package/dist/components/SelectedOutlineRenderer.js +9 -78
- package/dist/components/SelectedOutlineUvControls.d.ts +1 -1
- package/dist/components/SettingsModal.js +1 -1
- package/dist/components/SettingsModalFooter.d.ts +3 -1
- package/dist/components/SettingsModalFooter.js +19 -4
- package/dist/components/ShowPixelGridProvider.d.ts +4 -0
- package/dist/components/ShowPixelGridProvider.js +24 -0
- package/dist/components/SidebarCollapserControls.js +2 -2
- package/dist/components/SidebarRenderButton.js +2 -1
- package/dist/components/Timeline/Timeline.js +41 -0
- package/dist/components/Timeline/TimelineClipboardKeybindings.d.ts +6 -7
- package/dist/components/Timeline/TimelineDragHandler.js +11 -4
- package/dist/components/Timeline/TimelineKeyframeControls.d.ts +1 -2
- package/dist/components/Timeline/TimelinePlayCursorSyncer.js +4 -2
- package/dist/components/Timeline/TimelineSelection.d.ts +29 -66
- package/dist/components/Timeline/TimelineSelection.js +30 -170
- package/dist/components/Timeline/TimelineSequenceItem.d.ts +1 -0
- package/dist/components/Timeline/TimelineSequenceItem.js +8 -6
- package/dist/components/Timeline/TimelineSequenceRightEdgeDragHandle.d.ts +3 -4
- package/dist/components/Timeline/delete-selected-timeline-item.d.ts +3 -4
- package/dist/components/Timeline/duplicate-selected-timeline-item.d.ts +3 -4
- package/dist/components/Timeline/find-track-for-node-path-info.d.ts +1 -1
- package/dist/components/Timeline/keyframe-clipboard.d.ts +2 -3
- package/dist/components/Timeline/reset-selected-timeline-props.d.ts +2 -3
- package/dist/components/Timeline/sequence-prop-clipboard.d.ts +2 -3
- package/dist/components/Timeline/split-selected-timeline-item.d.ts +2 -3
- package/dist/components/Timeline/timeline-expanded-filter.d.ts +1 -2
- package/dist/components/Timeline/timeline-scroll-logic.d.ts +7 -5
- package/dist/components/Timeline/timeline-scroll-logic.js +12 -7
- package/dist/components/Timeline/update-selected-easing.d.ts +7 -7
- package/dist/components/Timeline/use-timeline-asset-drop.js +24 -1
- package/dist/components/Timeline/use-timeline-keyframe-drag.d.ts +6 -7
- package/dist/components/WebMcp.d.ts +2 -0
- package/dist/components/WebMcp.js +945 -0
- package/dist/components/canvas-capture-drop.d.ts +4 -0
- package/dist/components/canvas-capture-drop.js +22 -0
- package/dist/components/composition-menu-items.js +26 -0
- package/dist/components/selected-outline-geometry.d.ts +2 -21
- package/dist/components/selected-outline-geometry.js +5 -16
- package/dist/components/selected-outline-measurement.d.ts +8 -37
- package/dist/components/selected-outline-measurement.js +1 -231
- package/dist/components/selected-outline-types.d.ts +2 -15
- package/dist/components/selected-outline-uv.js +3 -106
- package/dist/esm/{chunk-w4244j4n.js → chunk-7prjt5n5.js} +32831 -26820
- package/dist/esm/internals.mjs +32831 -26820
- package/dist/esm/previewEntry.mjs +17304 -11293
- package/dist/esm/renderEntry.mjs +1 -1
- package/dist/helpers/calculate-timeline.d.ts +1 -7
- package/dist/helpers/calculate-timeline.js +2 -146
- package/dist/helpers/create-folder-tree.js +16 -1
- package/dist/helpers/editor-ruler.js +6 -5
- package/dist/helpers/format-file-location.d.ts +8 -0
- package/dist/helpers/format-file-location.js +14 -3
- package/dist/helpers/get-asset-metadata.d.ts +19 -0
- package/dist/helpers/get-asset-metadata.js +51 -6
- package/dist/helpers/get-connected-compositions.d.ts +1 -6
- package/dist/helpers/get-connected-compositions.js +2 -8
- package/dist/helpers/get-sequence-visible-range.d.ts +1 -5
- package/dist/helpers/get-sequence-visible-range.js +6 -51
- package/dist/helpers/get-timeline-max-zoom.d.ts +8 -0
- package/dist/helpers/get-timeline-max-zoom.js +17 -6
- package/dist/helpers/get-timeline-nestedness.d.ts +1 -2
- package/dist/helpers/get-timeline-nestedness.js +2 -12
- package/dist/helpers/get-timeline-sequence-sort-key.d.ts +2 -22
- package/dist/helpers/get-timeline-sequence-sort-key.js +2 -16
- package/dist/helpers/hoverable.d.ts +1 -0
- package/dist/helpers/hoverable.js +4 -1
- package/dist/helpers/is-current-selected-still.js +4 -2
- package/dist/helpers/sort-by-nonce-history.d.ts +1 -5
- package/dist/helpers/sort-by-nonce-history.js +3 -148
- package/dist/helpers/timeline-node-path-key.d.ts +1 -2
- package/dist/helpers/timeline-node-path-key.js +2 -2
- package/dist/helpers/use-menu-structure.js +20 -0
- package/dist/icons/enter.d.ts +4 -0
- package/dist/icons/enter.js +10 -0
- package/dist/state/editor-pixel-grid.d.ts +8 -0
- package/dist/state/editor-pixel-grid.js +18 -0
- package/dist/state/modals.d.ts +4 -0
- package/dist/state/playbackrate.d.ts +1 -0
- package/dist/state/playbackrate.js +4 -1
- package/package.json +14 -12
- package/dist/components/selected-outline-order.d.ts +0 -12
- package/dist/components/selected-outline-order.js +0 -251
- package/dist/helpers/get-box-quads-polyfill-internals.d.ts +0 -82
- package/dist/helpers/get-box-quads-polyfill-internals.js +0 -2403
- package/dist/helpers/get-box-quads-ponyfill.d.ts +0 -10
- package/dist/helpers/get-box-quads-ponyfill.js +0 -23
|
@@ -0,0 +1,945 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebMcp = void 0;
|
|
4
|
+
const canvas_1 = require("@remotion/canvas");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const remotion_1 = require("remotion");
|
|
7
|
+
const pause_1 = require("../api/pause");
|
|
8
|
+
const play_1 = require("../api/play");
|
|
9
|
+
const seek_1 = require("../api/seek");
|
|
10
|
+
const calculate_timeline_1 = require("../helpers/calculate-timeline");
|
|
11
|
+
const create_folder_tree_1 = require("../helpers/create-folder-tree");
|
|
12
|
+
const format_file_location_1 = require("../helpers/format-file-location");
|
|
13
|
+
const get_timeline_max_zoom_1 = require("../helpers/get-timeline-max-zoom");
|
|
14
|
+
const editor_guides_1 = require("../state/editor-guides");
|
|
15
|
+
const loop_1 = require("../state/loop");
|
|
16
|
+
const mute_1 = require("../state/mute");
|
|
17
|
+
const playbackrate_1 = require("../state/playbackrate");
|
|
18
|
+
const timeline_zoom_1 = require("../state/timeline-zoom");
|
|
19
|
+
const InitialCompositionLoader_1 = require("./InitialCompositionLoader");
|
|
20
|
+
const find_track_for_node_path_info_1 = require("./Timeline/find-track-for-node-path-info");
|
|
21
|
+
const imperative_state_1 = require("./Timeline/imperative-state");
|
|
22
|
+
const parse_keyframe_field_from_node_path_1 = require("./Timeline/parse-keyframe-field-from-node-path");
|
|
23
|
+
const should_show_track_in_timeline_1 = require("./Timeline/should-show-track-in-timeline");
|
|
24
|
+
const TimelineSelection_1 = require("./Timeline/TimelineSelection");
|
|
25
|
+
const get_stack_1 = require("./Timeline/TimelineStack/get-stack");
|
|
26
|
+
const use_resolved_stack_react_to_change_1 = require("./Timeline/use-resolved-stack-react-to-change");
|
|
27
|
+
const serializeSequence = (track) => {
|
|
28
|
+
var _a;
|
|
29
|
+
return {
|
|
30
|
+
sequenceId: track.sequence.id,
|
|
31
|
+
name: track.sequence.displayName ||
|
|
32
|
+
((_a = track.sequence.controls) === null || _a === void 0 ? void 0 : _a.componentName) ||
|
|
33
|
+
null,
|
|
34
|
+
type: track.sequence.type,
|
|
35
|
+
parentSequenceId: track.sequence.parent,
|
|
36
|
+
depth: track.depth,
|
|
37
|
+
startFrame: track.sequence.from,
|
|
38
|
+
endFrame: track.sequence.from + track.sequence.duration - 1,
|
|
39
|
+
durationInFrames: track.sequence.duration,
|
|
40
|
+
stack: track.sequence.getStack(),
|
|
41
|
+
selectable: track.nodePathInfo !== null,
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
const serializeCompositionTree = (items) => {
|
|
45
|
+
return items.map((item) => {
|
|
46
|
+
if (item.type === 'composition') {
|
|
47
|
+
return {
|
|
48
|
+
type: 'composition',
|
|
49
|
+
compositionName: item.composition.id,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
type: 'folder',
|
|
54
|
+
folderName: item.folderName,
|
|
55
|
+
children: serializeCompositionTree(item.items),
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
const getNoStack = () => null;
|
|
60
|
+
const MAX_CANVAS_HTML_LENGTH = 100000;
|
|
61
|
+
const WebMcp = () => {
|
|
62
|
+
var _a;
|
|
63
|
+
var _b, _c, _d, _e, _f;
|
|
64
|
+
const { canSelect, clearSelection, selectedItems, selectItems } = (0, TimelineSelection_1.useTimelineSelection)();
|
|
65
|
+
const { canvasContent, compositions, currentCompositionMetadata, folders } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
|
|
66
|
+
const { playbackRate: currentPlaybackRate, setPlaybackRate } = remotion_1.Internals.usePlaybackRate();
|
|
67
|
+
const [, , imperativePlaying] = remotion_1.Internals.Timeline.usePlayingState();
|
|
68
|
+
const { mediaVolume, playerMuted } = (0, react_1.useContext)(remotion_1.Internals.MediaVolumeContext);
|
|
69
|
+
const { setPlayerMuted } = (0, react_1.useContext)(remotion_1.Internals.SetMediaVolumeContext);
|
|
70
|
+
const { setZoom: setTimelineZoom, zoom: timelineZoomMap } = (0, react_1.useContext)(timeline_zoom_1.TimelineZoomCtx);
|
|
71
|
+
const selectComposition = (0, InitialCompositionLoader_1.useSelectComposition)();
|
|
72
|
+
const { editorShowGuides, guidesList, setEditorShowGuides, setGuidesList } = (0, react_1.useContext)(editor_guides_1.EditorShowGuidesContext);
|
|
73
|
+
const { sequences } = (0, react_1.useContext)(remotion_1.Internals.SequenceManager);
|
|
74
|
+
const { overrideIdToNodePathMappings } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsGettersContext);
|
|
75
|
+
const selectedItem = selectedItems.length === 1 ? selectedItems[0] : null;
|
|
76
|
+
const track = (0, react_1.useMemo)(() => {
|
|
77
|
+
var _a;
|
|
78
|
+
if (selectedItem === null || selectedItem.type === 'guide') {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return ((_a = (0, find_track_for_node_path_info_1.findTrackForNodePathInfo)({
|
|
82
|
+
sequences,
|
|
83
|
+
overrideIdsToNodePaths: overrideIdToNodePathMappings,
|
|
84
|
+
nodePathInfo: selectedItem.nodePathInfo,
|
|
85
|
+
})) !== null && _a !== void 0 ? _a : null);
|
|
86
|
+
}, [overrideIdToNodePathMappings, selectedItem, sequences]);
|
|
87
|
+
const { resolvedLocation, stack } = (0, use_resolved_stack_react_to_change_1.useResolveStackAndReactToChange)((_b = track === null || track === void 0 ? void 0 : track.sequence.getStack) !== null && _b !== void 0 ? _b : getNoStack, (_d = (_c = (_a = track === null || track === void 0 ? void 0 : track.sequence.controls) === null || _a === void 0 ? void 0 : _a.overrideId) !== null && _c !== void 0 ? _c : track === null || track === void 0 ? void 0 : track.sequence.id) !== null && _d !== void 0 ? _d : 'no-selection');
|
|
88
|
+
const currentStack = (_e = track === null || track === void 0 ? void 0 : track.sequence.getStack()) !== null && _e !== void 0 ? _e : null;
|
|
89
|
+
const currentResolvedLocation = stack === currentStack ? resolvedLocation : null;
|
|
90
|
+
const currentSelection = (0, react_1.useMemo)(() => {
|
|
91
|
+
var _a;
|
|
92
|
+
if (selectedItems.length === 0) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
if (selectedItems.length > 1) {
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
if (selectedItem === null || selectedItem.type === 'guide') {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
if (track === null) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
let name;
|
|
105
|
+
if (selectedItem.type === 'sequence') {
|
|
106
|
+
name =
|
|
107
|
+
track.sequence.displayName ||
|
|
108
|
+
((_a = track.sequence.controls) === null || _a === void 0 ? void 0 : _a.componentName) ||
|
|
109
|
+
null;
|
|
110
|
+
}
|
|
111
|
+
else if (selectedItem.type === 'sequence-prop') {
|
|
112
|
+
name = `Property "${selectedItem.key}"`;
|
|
113
|
+
}
|
|
114
|
+
else if (selectedItem.type === 'sequence-all-effects') {
|
|
115
|
+
name = 'Effects';
|
|
116
|
+
}
|
|
117
|
+
else if (selectedItem.type === 'sequence-effect') {
|
|
118
|
+
const { effects } = track.sequence;
|
|
119
|
+
const effect = effects[selectedItem.i];
|
|
120
|
+
name = effect ? `Effect "${effect.label}"` : null;
|
|
121
|
+
}
|
|
122
|
+
else if (selectedItem.type === 'sequence-effect-prop') {
|
|
123
|
+
name = `Effect property "${selectedItem.key}"`;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
const field = (0, parse_keyframe_field_from_node_path_1.parseKeyframeFieldFromNodePath)(selectedItem.nodePathInfo.auxiliaryKeys);
|
|
127
|
+
name =
|
|
128
|
+
(field === null || field === void 0 ? void 0 : field.type) === 'sequence'
|
|
129
|
+
? `Property "${field.fieldKey}"`
|
|
130
|
+
: (field === null || field === void 0 ? void 0 : field.type) === 'effect'
|
|
131
|
+
? `Effect property "${field.fieldKey}"`
|
|
132
|
+
: null;
|
|
133
|
+
}
|
|
134
|
+
return (0, format_file_location_1.formatContextForAgents)({
|
|
135
|
+
location: currentResolvedLocation,
|
|
136
|
+
name,
|
|
137
|
+
root: window.remotion_cwd,
|
|
138
|
+
});
|
|
139
|
+
}, [currentResolvedLocation, selectedItem, selectedItems.length, track]);
|
|
140
|
+
const currentSelectionRef = (0, react_1.useRef)(currentSelection);
|
|
141
|
+
currentSelectionRef.current = currentSelection;
|
|
142
|
+
const selectedSequence = (0, react_1.useMemo)(() => (track === null ? null : serializeSequence(track)), [track]);
|
|
143
|
+
const selectedSequenceRef = (0, react_1.useRef)(selectedSequence);
|
|
144
|
+
selectedSequenceRef.current = selectedSequence;
|
|
145
|
+
const selectedItemsRef = (0, react_1.useRef)(selectedItems);
|
|
146
|
+
selectedItemsRef.current = selectedItems;
|
|
147
|
+
const canSelectRef = (0, react_1.useRef)(canSelect);
|
|
148
|
+
canSelectRef.current = canSelect;
|
|
149
|
+
const currentCompositionDefinition = (0, react_1.useMemo)(() => {
|
|
150
|
+
var _a;
|
|
151
|
+
if ((canvasContent === null || canvasContent === void 0 ? void 0 : canvasContent.type) !== 'composition') {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
return ((_a = compositions.find((composition) => composition.id === canvasContent.compositionId)) !== null && _a !== void 0 ? _a : null);
|
|
155
|
+
}, [canvasContent, compositions]);
|
|
156
|
+
const currentComposition = (_f = currentCompositionDefinition === null || currentCompositionDefinition === void 0 ? void 0 : currentCompositionDefinition.id) !== null && _f !== void 0 ? _f : null;
|
|
157
|
+
const currentCompositionRef = (0, react_1.useRef)(currentComposition);
|
|
158
|
+
currentCompositionRef.current = currentComposition;
|
|
159
|
+
const currentCompositionDefinitionRef = (0, react_1.useRef)(currentCompositionDefinition);
|
|
160
|
+
currentCompositionDefinitionRef.current = currentCompositionDefinition;
|
|
161
|
+
const compositionsRef = (0, react_1.useRef)(compositions);
|
|
162
|
+
compositionsRef.current = compositions;
|
|
163
|
+
const sequencesRef = (0, react_1.useRef)(sequences);
|
|
164
|
+
sequencesRef.current = sequences;
|
|
165
|
+
const overrideIdToNodePathMappingsRef = (0, react_1.useRef)(overrideIdToNodePathMappings);
|
|
166
|
+
overrideIdToNodePathMappingsRef.current = overrideIdToNodePathMappings;
|
|
167
|
+
const foldersRef = (0, react_1.useRef)(folders);
|
|
168
|
+
foldersRef.current = folders;
|
|
169
|
+
const currentCompositionMetadataRef = (0, react_1.useRef)(currentCompositionMetadata);
|
|
170
|
+
currentCompositionMetadataRef.current = currentCompositionMetadata;
|
|
171
|
+
const guidesListRef = (0, react_1.useRef)(guidesList);
|
|
172
|
+
guidesListRef.current = guidesList;
|
|
173
|
+
const editorShowGuidesRef = (0, react_1.useRef)(editorShowGuides);
|
|
174
|
+
editorShowGuidesRef.current = editorShowGuides;
|
|
175
|
+
const mediaVolumeRef = (0, react_1.useRef)(mediaVolume);
|
|
176
|
+
mediaVolumeRef.current = mediaVolume;
|
|
177
|
+
const playbackRateRef = (0, react_1.useRef)(currentPlaybackRate);
|
|
178
|
+
playbackRateRef.current = currentPlaybackRate;
|
|
179
|
+
const playerMutedRef = (0, react_1.useRef)(playerMuted);
|
|
180
|
+
playerMutedRef.current = playerMuted;
|
|
181
|
+
const timelineZoomRef = (0, react_1.useRef)(timelineZoomMap);
|
|
182
|
+
timelineZoomRef.current = timelineZoomMap;
|
|
183
|
+
(0, react_1.useEffect)(() => {
|
|
184
|
+
const { modelContext } = document;
|
|
185
|
+
if (typeof (modelContext === null || modelContext === void 0 ? void 0 : modelContext.registerTool) !== 'function') {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const controller = new AbortController();
|
|
189
|
+
const getCurrentTimeline = () => {
|
|
190
|
+
var _a;
|
|
191
|
+
var _b, _c;
|
|
192
|
+
const composition = currentCompositionDefinitionRef.current;
|
|
193
|
+
if (composition === null) {
|
|
194
|
+
return [];
|
|
195
|
+
}
|
|
196
|
+
const durationInFrames = (_c = (_b = (_a = currentCompositionMetadataRef.current) === null || _a === void 0 ? void 0 : _a.durationInFrames) !== null && _b !== void 0 ? _b : composition.durationInFrames) !== null && _c !== void 0 ? _c : (0, imperative_state_1.getCurrentDuration)();
|
|
197
|
+
return (0, calculate_timeline_1.calculateTimeline)({
|
|
198
|
+
sequences: sequencesRef.current,
|
|
199
|
+
overrideIdsToNodePaths: overrideIdToNodePathMappingsRef.current,
|
|
200
|
+
compositions: compositionsRef.current,
|
|
201
|
+
}).filter((timelineTrack) => (0, should_show_track_in_timeline_1.shouldShowTrackInTimeline)(timelineTrack, durationInFrames));
|
|
202
|
+
};
|
|
203
|
+
Promise.all([
|
|
204
|
+
modelContext.registerTool({
|
|
205
|
+
name: 'get_compositions',
|
|
206
|
+
title: 'Get Studio compositions',
|
|
207
|
+
description: 'Read the mounted Remotion Studio compositions as the nested folder tree shown in the sidebar.',
|
|
208
|
+
inputSchema: {
|
|
209
|
+
type: 'object',
|
|
210
|
+
properties: {},
|
|
211
|
+
additionalProperties: false,
|
|
212
|
+
},
|
|
213
|
+
annotations: { readOnlyHint: true },
|
|
214
|
+
execute: () => {
|
|
215
|
+
const tree = (0, create_folder_tree_1.createFolderTree)(compositionsRef.current, foldersRef.current, {});
|
|
216
|
+
return Promise.resolve({
|
|
217
|
+
compositions: serializeCompositionTree(tree),
|
|
218
|
+
});
|
|
219
|
+
},
|
|
220
|
+
}, { signal: controller.signal }),
|
|
221
|
+
modelContext.registerTool({
|
|
222
|
+
name: 'select_composition',
|
|
223
|
+
title: 'Select Studio composition',
|
|
224
|
+
description: 'Open a registered composition in Remotion Studio by name.',
|
|
225
|
+
inputSchema: {
|
|
226
|
+
type: 'object',
|
|
227
|
+
properties: {
|
|
228
|
+
compositionName: {
|
|
229
|
+
type: 'string',
|
|
230
|
+
description: 'The name of the composition to open.',
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
required: ['compositionName'],
|
|
234
|
+
additionalProperties: false,
|
|
235
|
+
},
|
|
236
|
+
annotations: { readOnlyHint: false },
|
|
237
|
+
execute: ({ compositionName }) => {
|
|
238
|
+
if (typeof compositionName !== 'string') {
|
|
239
|
+
throw new Error('compositionName must be a string.');
|
|
240
|
+
}
|
|
241
|
+
const composition = compositionsRef.current.find((candidate) => candidate.id === compositionName);
|
|
242
|
+
if (!composition) {
|
|
243
|
+
throw new Error(`Composition ${compositionName} not found.`);
|
|
244
|
+
}
|
|
245
|
+
selectComposition(composition, true);
|
|
246
|
+
return Promise.resolve({ currentComposition: composition.id });
|
|
247
|
+
},
|
|
248
|
+
}, { signal: controller.signal }),
|
|
249
|
+
modelContext.registerTool({
|
|
250
|
+
name: 'get_sequences',
|
|
251
|
+
title: 'Get Studio sequences',
|
|
252
|
+
description: 'Read the mounted sequences in the current Remotion Studio timeline, including their IDs, hierarchy, timing, type, source stack, and whether they can be selected.',
|
|
253
|
+
inputSchema: {
|
|
254
|
+
type: 'object',
|
|
255
|
+
properties: {},
|
|
256
|
+
additionalProperties: false,
|
|
257
|
+
},
|
|
258
|
+
annotations: { readOnlyHint: true },
|
|
259
|
+
execute: () => {
|
|
260
|
+
const compositionId = currentCompositionRef.current;
|
|
261
|
+
return Promise.resolve({
|
|
262
|
+
currentComposition: compositionId,
|
|
263
|
+
sequences: compositionId === null
|
|
264
|
+
? []
|
|
265
|
+
: getCurrentTimeline().map(serializeSequence),
|
|
266
|
+
});
|
|
267
|
+
},
|
|
268
|
+
}, { signal: controller.signal }),
|
|
269
|
+
modelContext.registerTool({
|
|
270
|
+
name: 'select_sequence',
|
|
271
|
+
title: 'Select Studio sequence',
|
|
272
|
+
description: 'Select and reveal a sequence in the current Remotion Studio timeline by the sequence ID returned by get_sequences.',
|
|
273
|
+
inputSchema: {
|
|
274
|
+
type: 'object',
|
|
275
|
+
properties: {
|
|
276
|
+
sequenceId: {
|
|
277
|
+
type: 'string',
|
|
278
|
+
minLength: 1,
|
|
279
|
+
description: 'The sequence ID returned by get_sequences.',
|
|
280
|
+
},
|
|
281
|
+
},
|
|
282
|
+
required: ['sequenceId'],
|
|
283
|
+
additionalProperties: false,
|
|
284
|
+
},
|
|
285
|
+
annotations: { readOnlyHint: false },
|
|
286
|
+
execute: ({ sequenceId }) => {
|
|
287
|
+
if (typeof sequenceId !== 'string' || sequenceId.length === 0) {
|
|
288
|
+
throw new Error('sequenceId must be a non-empty string.');
|
|
289
|
+
}
|
|
290
|
+
const compositionId = currentCompositionRef.current;
|
|
291
|
+
if (compositionId === null) {
|
|
292
|
+
throw new Error('No composition is currently selected.');
|
|
293
|
+
}
|
|
294
|
+
if (!canSelectRef.current) {
|
|
295
|
+
throw new Error('Studio sequence selection is unavailable.');
|
|
296
|
+
}
|
|
297
|
+
const timelineTrack = getCurrentTimeline().find((candidate) => candidate.sequence.id === sequenceId);
|
|
298
|
+
if (!timelineTrack) {
|
|
299
|
+
throw new Error(`Sequence ${sequenceId} not found in the current composition.`);
|
|
300
|
+
}
|
|
301
|
+
const selection = (0, TimelineSelection_1.getTimelineSelectionFromNodePathInfo)(timelineTrack.nodePathInfo);
|
|
302
|
+
if (selection === null) {
|
|
303
|
+
throw new Error(`Sequence ${sequenceId} cannot be selected.`);
|
|
304
|
+
}
|
|
305
|
+
selectItems([selection], { reveal: true });
|
|
306
|
+
return Promise.resolve({
|
|
307
|
+
currentComposition: compositionId,
|
|
308
|
+
selectedSequence: serializeSequence(timelineTrack),
|
|
309
|
+
});
|
|
310
|
+
},
|
|
311
|
+
}, { signal: controller.signal }),
|
|
312
|
+
modelContext.registerTool({
|
|
313
|
+
name: 'get_composition',
|
|
314
|
+
title: 'Get Studio composition',
|
|
315
|
+
description: 'Read the name, source stack, duration, dimensions, frame rate, and current frame of the composition open in Remotion Studio. All fields are null when the canvas is not showing a composition.',
|
|
316
|
+
inputSchema: {
|
|
317
|
+
type: 'object',
|
|
318
|
+
properties: {},
|
|
319
|
+
additionalProperties: false,
|
|
320
|
+
},
|
|
321
|
+
annotations: { readOnlyHint: true },
|
|
322
|
+
execute: () => {
|
|
323
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
324
|
+
const composition = currentCompositionDefinitionRef.current;
|
|
325
|
+
if (composition === null) {
|
|
326
|
+
return Promise.resolve({
|
|
327
|
+
compositionName: null,
|
|
328
|
+
stack: null,
|
|
329
|
+
durationInFrames: null,
|
|
330
|
+
height: null,
|
|
331
|
+
width: null,
|
|
332
|
+
fps: null,
|
|
333
|
+
currentFrame: null,
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
const metadata = currentCompositionMetadataRef.current;
|
|
337
|
+
return Promise.resolve({
|
|
338
|
+
compositionName: composition.id,
|
|
339
|
+
stack: composition.stack,
|
|
340
|
+
durationInFrames: (_b = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.durationInFrames) !== null && _a !== void 0 ? _a : composition.durationInFrames) !== null && _b !== void 0 ? _b : null,
|
|
341
|
+
height: (_d = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.height) !== null && _c !== void 0 ? _c : composition.height) !== null && _d !== void 0 ? _d : null,
|
|
342
|
+
width: (_f = (_e = metadata === null || metadata === void 0 ? void 0 : metadata.width) !== null && _e !== void 0 ? _e : composition.width) !== null && _f !== void 0 ? _f : null,
|
|
343
|
+
fps: (_h = (_g = metadata === null || metadata === void 0 ? void 0 : metadata.fps) !== null && _g !== void 0 ? _g : composition.fps) !== null && _h !== void 0 ? _h : null,
|
|
344
|
+
currentFrame: (0, imperative_state_1.getCurrentFrame)(),
|
|
345
|
+
});
|
|
346
|
+
},
|
|
347
|
+
}, { signal: controller.signal }),
|
|
348
|
+
modelContext.registerTool({
|
|
349
|
+
name: 'get_canvas_html',
|
|
350
|
+
title: 'Get Studio canvas HTML',
|
|
351
|
+
description: 'Read the HTML of the rendered composition at the current frame. The result is limited to the composition canvas and does not include the Studio interface. Canvas and WebGL pixels are not included.',
|
|
352
|
+
inputSchema: {
|
|
353
|
+
type: 'object',
|
|
354
|
+
properties: {},
|
|
355
|
+
additionalProperties: false,
|
|
356
|
+
},
|
|
357
|
+
annotations: { readOnlyHint: true },
|
|
358
|
+
execute: () => {
|
|
359
|
+
const compositionId = currentCompositionRef.current;
|
|
360
|
+
if (compositionId === null) {
|
|
361
|
+
return Promise.resolve({
|
|
362
|
+
currentComposition: null,
|
|
363
|
+
currentFrame: null,
|
|
364
|
+
html: null,
|
|
365
|
+
htmlLength: null,
|
|
366
|
+
truncated: false,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
const outerHtml = remotion_1.Internals.portalNode().outerHTML;
|
|
370
|
+
return Promise.resolve({
|
|
371
|
+
currentComposition: compositionId,
|
|
372
|
+
currentFrame: (0, imperative_state_1.getCurrentFrame)(),
|
|
373
|
+
html: outerHtml.slice(0, MAX_CANVAS_HTML_LENGTH),
|
|
374
|
+
htmlLength: outerHtml.length,
|
|
375
|
+
truncated: outerHtml.length > MAX_CANVAS_HTML_LENGTH,
|
|
376
|
+
});
|
|
377
|
+
},
|
|
378
|
+
}, { signal: controller.signal }),
|
|
379
|
+
modelContext.registerTool({
|
|
380
|
+
name: 'get_outlines',
|
|
381
|
+
title: 'Get Studio canvas outlines',
|
|
382
|
+
description: 'Read the active selectable component outlines in the current Remotion Studio canvas, including sequence identity, source-code location, and geometry in composition pixels.',
|
|
383
|
+
inputSchema: {
|
|
384
|
+
type: 'object',
|
|
385
|
+
properties: {},
|
|
386
|
+
additionalProperties: false,
|
|
387
|
+
},
|
|
388
|
+
annotations: { readOnlyHint: true },
|
|
389
|
+
execute: async () => {
|
|
390
|
+
var _a, _b, _c, _d;
|
|
391
|
+
const composition = currentCompositionDefinitionRef.current;
|
|
392
|
+
if (composition === null) {
|
|
393
|
+
return {
|
|
394
|
+
currentComposition: null,
|
|
395
|
+
currentFrame: null,
|
|
396
|
+
outlines: [],
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
const currentFrame = (0, imperative_state_1.getCurrentFrame)();
|
|
400
|
+
const selectableOutlines = (0, canvas_1.getCanvasSelectableOutlines)({
|
|
401
|
+
sequences: sequencesRef.current,
|
|
402
|
+
overrideIdsToNodePaths: overrideIdToNodePathMappingsRef.current,
|
|
403
|
+
compositions: compositionsRef.current,
|
|
404
|
+
timelinePosition: currentFrame,
|
|
405
|
+
});
|
|
406
|
+
const portalNode = remotion_1.Internals.portalNode();
|
|
407
|
+
const portalRect = portalNode.getBoundingClientRect();
|
|
408
|
+
const metadata = currentCompositionMetadataRef.current;
|
|
409
|
+
const compositionWidth = (_b = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.width) !== null && _a !== void 0 ? _a : composition.width) !== null && _b !== void 0 ? _b : portalNode.offsetWidth;
|
|
410
|
+
const compositionHeight = (_d = (_c = metadata === null || metadata === void 0 ? void 0 : metadata.height) !== null && _c !== void 0 ? _c : composition.height) !== null && _d !== void 0 ? _d : portalNode.offsetHeight;
|
|
411
|
+
const scaleX = portalRect.width / compositionWidth;
|
|
412
|
+
const scaleY = portalRect.height / compositionHeight;
|
|
413
|
+
if (!Number.isFinite(scaleX) ||
|
|
414
|
+
scaleX === 0 ||
|
|
415
|
+
!Number.isFinite(scaleY) ||
|
|
416
|
+
scaleY === 0) {
|
|
417
|
+
throw new Error('The Studio canvas is not ready to be measured.');
|
|
418
|
+
}
|
|
419
|
+
const measuredOutlines = (0, canvas_1.measureCanvasOutlines)(portalNode, selectableOutlines.map((outline) => {
|
|
420
|
+
if (outline.sequence.refForOutline === null) {
|
|
421
|
+
throw new Error('Expected an outline ref.');
|
|
422
|
+
}
|
|
423
|
+
return {
|
|
424
|
+
key: outline.key,
|
|
425
|
+
ref: outline.sequence.refForOutline,
|
|
426
|
+
crop: { left: 0, right: 0, top: 0, bottom: 0 },
|
|
427
|
+
includeOutsideContainer: true,
|
|
428
|
+
};
|
|
429
|
+
}));
|
|
430
|
+
const measurementsByKey = new Map(measuredOutlines.map((outline) => [outline.key, outline]));
|
|
431
|
+
const contextByStack = new Map();
|
|
432
|
+
const outlines = await Promise.all(selectableOutlines.map(async (outline) => {
|
|
433
|
+
var _a;
|
|
434
|
+
const measurement = measurementsByKey.get(outline.key);
|
|
435
|
+
if (!measurement) {
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
438
|
+
const outlineStack = outline.sequence.getStack();
|
|
439
|
+
let location = null;
|
|
440
|
+
if (outlineStack !== null) {
|
|
441
|
+
let promise = contextByStack.get(outlineStack);
|
|
442
|
+
if (!promise) {
|
|
443
|
+
promise = (0, get_stack_1.getOriginalLocationFromStack)(outlineStack, 'sequence').catch(() => null);
|
|
444
|
+
contextByStack.set(outlineStack, promise);
|
|
445
|
+
}
|
|
446
|
+
location = await promise;
|
|
447
|
+
}
|
|
448
|
+
const name = outline.sequence.displayName ||
|
|
449
|
+
((_a = outline.sequence.controls) === null || _a === void 0 ? void 0 : _a.componentName) ||
|
|
450
|
+
null;
|
|
451
|
+
const points = measurement.points.map((point) => ({
|
|
452
|
+
x: point.x / scaleX,
|
|
453
|
+
y: point.y / scaleY,
|
|
454
|
+
}));
|
|
455
|
+
const xValues = points.map((point) => point.x);
|
|
456
|
+
const yValues = points.map((point) => point.y);
|
|
457
|
+
const left = Math.min(...xValues);
|
|
458
|
+
const top = Math.min(...yValues);
|
|
459
|
+
const right = Math.max(...xValues);
|
|
460
|
+
const bottom = Math.max(...yValues);
|
|
461
|
+
return {
|
|
462
|
+
sequenceId: outline.sequence.id,
|
|
463
|
+
parentSequenceId: outline.sequence.parent,
|
|
464
|
+
name,
|
|
465
|
+
location: (0, format_file_location_1.getRelativeFileLocation)({
|
|
466
|
+
location,
|
|
467
|
+
root: window.remotion_cwd,
|
|
468
|
+
}),
|
|
469
|
+
geometry: {
|
|
470
|
+
points,
|
|
471
|
+
boundingBox: {
|
|
472
|
+
x: left,
|
|
473
|
+
y: top,
|
|
474
|
+
width: right - left,
|
|
475
|
+
height: bottom - top,
|
|
476
|
+
},
|
|
477
|
+
},
|
|
478
|
+
};
|
|
479
|
+
}));
|
|
480
|
+
return {
|
|
481
|
+
currentComposition: composition.id,
|
|
482
|
+
currentFrame,
|
|
483
|
+
outlines: outlines.filter((outline) => outline !== null),
|
|
484
|
+
};
|
|
485
|
+
},
|
|
486
|
+
}, { signal: controller.signal }),
|
|
487
|
+
modelContext.registerTool({
|
|
488
|
+
name: 'get_playback_state',
|
|
489
|
+
title: 'Get Studio playback state',
|
|
490
|
+
description: 'Read the current frame, playing state, audio state, playback rate, looping state, and normalized timeline zoom for the composition open in Remotion Studio. All playback fields are null when the canvas is not showing a composition.',
|
|
491
|
+
inputSchema: {
|
|
492
|
+
type: 'object',
|
|
493
|
+
properties: {},
|
|
494
|
+
additionalProperties: false,
|
|
495
|
+
},
|
|
496
|
+
annotations: { readOnlyHint: true },
|
|
497
|
+
execute: () => {
|
|
498
|
+
var _a;
|
|
499
|
+
const compositionId = currentCompositionRef.current;
|
|
500
|
+
if (compositionId === null) {
|
|
501
|
+
return Promise.resolve({
|
|
502
|
+
currentComposition: null,
|
|
503
|
+
currentFrame: null,
|
|
504
|
+
playing: null,
|
|
505
|
+
muted: null,
|
|
506
|
+
volume: null,
|
|
507
|
+
playbackRate: null,
|
|
508
|
+
looping: null,
|
|
509
|
+
timelineZoom: null,
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
return Promise.resolve({
|
|
513
|
+
currentComposition: compositionId,
|
|
514
|
+
currentFrame: (0, imperative_state_1.getCurrentFrame)(),
|
|
515
|
+
playing: imperativePlaying.current,
|
|
516
|
+
muted: playerMutedRef.current,
|
|
517
|
+
volume: mediaVolumeRef.current,
|
|
518
|
+
playbackRate: playbackRateRef.current,
|
|
519
|
+
looping: (0, loop_1.loadLoopOption)(),
|
|
520
|
+
timelineZoom: (0, get_timeline_max_zoom_1.timelineZoomToNormalized)({
|
|
521
|
+
zoom: (_a = timelineZoomRef.current[compositionId]) !== null && _a !== void 0 ? _a : get_timeline_max_zoom_1.TIMELINE_MIN_ZOOM,
|
|
522
|
+
maxZoom: (0, get_timeline_max_zoom_1.getTimelineMaxZoom)((0, imperative_state_1.getCurrentDuration)()),
|
|
523
|
+
}),
|
|
524
|
+
});
|
|
525
|
+
},
|
|
526
|
+
}, { signal: controller.signal }),
|
|
527
|
+
modelContext.registerTool({
|
|
528
|
+
name: 'get_selection',
|
|
529
|
+
title: 'Get Studio selection',
|
|
530
|
+
description: 'Read the current frame, composition, and source-code context for the item currently selected in Remotion Studio. The selection matches "Copy context for agents".',
|
|
531
|
+
inputSchema: {
|
|
532
|
+
type: 'object',
|
|
533
|
+
properties: {},
|
|
534
|
+
additionalProperties: false,
|
|
535
|
+
},
|
|
536
|
+
annotations: { readOnlyHint: true },
|
|
537
|
+
execute: () => Promise.resolve({
|
|
538
|
+
currentFrame: (0, imperative_state_1.getCurrentFrame)(),
|
|
539
|
+
currentSelection: currentSelectionRef.current,
|
|
540
|
+
currentComposition: currentCompositionRef.current,
|
|
541
|
+
selectionType: selectedItemsRef.current.length === 1
|
|
542
|
+
? selectedItemsRef.current[0].type
|
|
543
|
+
: null,
|
|
544
|
+
selectedSequence: selectedSequenceRef.current,
|
|
545
|
+
}),
|
|
546
|
+
}, { signal: controller.signal }),
|
|
547
|
+
modelContext.registerTool({
|
|
548
|
+
name: 'get_guides',
|
|
549
|
+
title: 'Get Studio guides',
|
|
550
|
+
description: 'Read the guides for the current Remotion Studio composition. Vertical guide positions are x-coordinates from the left edge and horizontal guide positions are y-coordinates from the top edge, in composition pixels.',
|
|
551
|
+
inputSchema: {
|
|
552
|
+
type: 'object',
|
|
553
|
+
properties: {},
|
|
554
|
+
additionalProperties: false,
|
|
555
|
+
},
|
|
556
|
+
annotations: { readOnlyHint: true },
|
|
557
|
+
execute: () => {
|
|
558
|
+
const compositionId = currentCompositionRef.current;
|
|
559
|
+
const guidesAreVisible = editorShowGuidesRef.current;
|
|
560
|
+
return Promise.resolve({
|
|
561
|
+
currentComposition: compositionId,
|
|
562
|
+
guidesVisible: guidesAreVisible,
|
|
563
|
+
guides: compositionId === null
|
|
564
|
+
? []
|
|
565
|
+
: guidesListRef.current
|
|
566
|
+
.filter((guide) => guide.compositionId === compositionId)
|
|
567
|
+
.map((guide) => ({
|
|
568
|
+
id: guide.id,
|
|
569
|
+
orientation: guide.orientation,
|
|
570
|
+
position: guide.position,
|
|
571
|
+
visible: guidesAreVisible && guide.show,
|
|
572
|
+
})),
|
|
573
|
+
});
|
|
574
|
+
},
|
|
575
|
+
}, { signal: controller.signal }),
|
|
576
|
+
modelContext.registerTool({
|
|
577
|
+
name: 'set_guides_visible',
|
|
578
|
+
title: 'Set Studio guides visibility',
|
|
579
|
+
description: 'Show or hide all guides for the current Remotion Studio composition.',
|
|
580
|
+
inputSchema: {
|
|
581
|
+
type: 'object',
|
|
582
|
+
properties: {
|
|
583
|
+
visible: {
|
|
584
|
+
type: 'boolean',
|
|
585
|
+
description: 'Whether guides should be visible.',
|
|
586
|
+
},
|
|
587
|
+
},
|
|
588
|
+
required: ['visible'],
|
|
589
|
+
additionalProperties: false,
|
|
590
|
+
},
|
|
591
|
+
annotations: { readOnlyHint: false },
|
|
592
|
+
execute: ({ visible }) => {
|
|
593
|
+
if (typeof visible !== 'boolean') {
|
|
594
|
+
throw new Error('visible must be a boolean.');
|
|
595
|
+
}
|
|
596
|
+
const compositionId = currentCompositionRef.current;
|
|
597
|
+
if (compositionId === null) {
|
|
598
|
+
throw new Error('No composition is currently selected.');
|
|
599
|
+
}
|
|
600
|
+
editorShowGuidesRef.current = visible;
|
|
601
|
+
setEditorShowGuides(() => visible);
|
|
602
|
+
return Promise.resolve({
|
|
603
|
+
currentComposition: compositionId,
|
|
604
|
+
guidesVisible: visible,
|
|
605
|
+
});
|
|
606
|
+
},
|
|
607
|
+
}, { signal: controller.signal }),
|
|
608
|
+
modelContext.registerTool({
|
|
609
|
+
name: 'add_guide',
|
|
610
|
+
title: 'Add Studio guide',
|
|
611
|
+
description: 'Add a guide to the current Remotion Studio composition. A vertical guide position is an x-coordinate from the left edge and a horizontal guide position is a y-coordinate from the top edge, in composition pixels.',
|
|
612
|
+
inputSchema: {
|
|
613
|
+
type: 'object',
|
|
614
|
+
properties: {
|
|
615
|
+
orientation: {
|
|
616
|
+
type: 'string',
|
|
617
|
+
enum: ['horizontal', 'vertical'],
|
|
618
|
+
description: 'The orientation of the guide.',
|
|
619
|
+
},
|
|
620
|
+
position: {
|
|
621
|
+
type: 'number',
|
|
622
|
+
description: 'The guide position in composition pixels. Vertical guides use an x-coordinate and horizontal guides use a y-coordinate.',
|
|
623
|
+
},
|
|
624
|
+
},
|
|
625
|
+
required: ['orientation', 'position'],
|
|
626
|
+
additionalProperties: false,
|
|
627
|
+
},
|
|
628
|
+
annotations: { readOnlyHint: false },
|
|
629
|
+
execute: ({ orientation, position }) => {
|
|
630
|
+
if (orientation !== 'horizontal' && orientation !== 'vertical') {
|
|
631
|
+
throw new Error('orientation must be either "horizontal" or "vertical".');
|
|
632
|
+
}
|
|
633
|
+
if (typeof position !== 'number' || !Number.isFinite(position)) {
|
|
634
|
+
throw new Error('position must be a finite number.');
|
|
635
|
+
}
|
|
636
|
+
const compositionId = currentCompositionRef.current;
|
|
637
|
+
if (compositionId === null) {
|
|
638
|
+
throw new Error('No composition is currently selected.');
|
|
639
|
+
}
|
|
640
|
+
const guide = {
|
|
641
|
+
id: crypto.randomUUID(),
|
|
642
|
+
orientation,
|
|
643
|
+
position,
|
|
644
|
+
show: true,
|
|
645
|
+
compositionId,
|
|
646
|
+
};
|
|
647
|
+
const nextGuides = [...guidesListRef.current, guide];
|
|
648
|
+
guidesListRef.current = nextGuides;
|
|
649
|
+
setGuidesList(() => nextGuides);
|
|
650
|
+
(0, editor_guides_1.persistGuidesList)(nextGuides);
|
|
651
|
+
editorShowGuidesRef.current = true;
|
|
652
|
+
setEditorShowGuides(() => true);
|
|
653
|
+
return Promise.resolve({
|
|
654
|
+
currentComposition: compositionId,
|
|
655
|
+
guide: {
|
|
656
|
+
id: guide.id,
|
|
657
|
+
orientation: guide.orientation,
|
|
658
|
+
position: guide.position,
|
|
659
|
+
visible: true,
|
|
660
|
+
},
|
|
661
|
+
});
|
|
662
|
+
},
|
|
663
|
+
}, { signal: controller.signal }),
|
|
664
|
+
modelContext.registerTool({
|
|
665
|
+
name: 'remove_guide',
|
|
666
|
+
title: 'Remove Studio guide',
|
|
667
|
+
description: 'Remove a guide from the current Remotion Studio composition by its guide ID.',
|
|
668
|
+
inputSchema: {
|
|
669
|
+
type: 'object',
|
|
670
|
+
properties: {
|
|
671
|
+
guideId: {
|
|
672
|
+
type: 'string',
|
|
673
|
+
minLength: 1,
|
|
674
|
+
description: 'The guide ID returned by get_guides or add_guide.',
|
|
675
|
+
},
|
|
676
|
+
},
|
|
677
|
+
required: ['guideId'],
|
|
678
|
+
additionalProperties: false,
|
|
679
|
+
},
|
|
680
|
+
annotations: { readOnlyHint: false },
|
|
681
|
+
execute: ({ guideId }) => {
|
|
682
|
+
if (typeof guideId !== 'string' || guideId.length === 0) {
|
|
683
|
+
throw new Error('guideId must be a non-empty string.');
|
|
684
|
+
}
|
|
685
|
+
const compositionId = currentCompositionRef.current;
|
|
686
|
+
if (compositionId === null) {
|
|
687
|
+
throw new Error('No composition is currently selected.');
|
|
688
|
+
}
|
|
689
|
+
const guideExists = guidesListRef.current.some((guide) => guide.id === guideId && guide.compositionId === compositionId);
|
|
690
|
+
if (!guideExists) {
|
|
691
|
+
throw new Error(`Guide ${guideId} not found in the current composition.`);
|
|
692
|
+
}
|
|
693
|
+
const nextGuides = guidesListRef.current.filter((guide) => guide.id !== guideId || guide.compositionId !== compositionId);
|
|
694
|
+
guidesListRef.current = nextGuides;
|
|
695
|
+
setGuidesList(() => nextGuides);
|
|
696
|
+
(0, editor_guides_1.persistGuidesList)(nextGuides);
|
|
697
|
+
const removedGuideWasSelected = selectedItemsRef.current.some((item) => item.type === 'guide' && item.guideId === guideId);
|
|
698
|
+
if (removedGuideWasSelected) {
|
|
699
|
+
clearSelection();
|
|
700
|
+
}
|
|
701
|
+
return Promise.resolve({
|
|
702
|
+
currentComposition: compositionId,
|
|
703
|
+
guideId,
|
|
704
|
+
removed: true,
|
|
705
|
+
});
|
|
706
|
+
},
|
|
707
|
+
}, { signal: controller.signal }),
|
|
708
|
+
modelContext.registerTool({
|
|
709
|
+
name: 'play',
|
|
710
|
+
title: 'Play Studio composition',
|
|
711
|
+
description: 'Start playing the current Remotion Studio composition from the current frame.',
|
|
712
|
+
inputSchema: {
|
|
713
|
+
type: 'object',
|
|
714
|
+
properties: {},
|
|
715
|
+
additionalProperties: false,
|
|
716
|
+
},
|
|
717
|
+
annotations: { readOnlyHint: false },
|
|
718
|
+
execute: () => {
|
|
719
|
+
const compositionId = currentCompositionRef.current;
|
|
720
|
+
if (compositionId === null) {
|
|
721
|
+
throw new Error('No composition is currently selected.');
|
|
722
|
+
}
|
|
723
|
+
if ((0, imperative_state_1.getCurrentDuration)() <= 1) {
|
|
724
|
+
throw new Error('The current composition is a still and cannot play.');
|
|
725
|
+
}
|
|
726
|
+
if (remotion_1.Internals.timeValueRef.current === null) {
|
|
727
|
+
throw new Error('Studio playback controls are not ready.');
|
|
728
|
+
}
|
|
729
|
+
(0, play_1.play)();
|
|
730
|
+
return Promise.resolve({
|
|
731
|
+
currentComposition: compositionId,
|
|
732
|
+
playing: true,
|
|
733
|
+
});
|
|
734
|
+
},
|
|
735
|
+
}, { signal: controller.signal }),
|
|
736
|
+
modelContext.registerTool({
|
|
737
|
+
name: 'pause',
|
|
738
|
+
title: 'Pause Studio composition',
|
|
739
|
+
description: 'Pause the current Remotion Studio composition at the current frame.',
|
|
740
|
+
inputSchema: {
|
|
741
|
+
type: 'object',
|
|
742
|
+
properties: {},
|
|
743
|
+
additionalProperties: false,
|
|
744
|
+
},
|
|
745
|
+
annotations: { readOnlyHint: false },
|
|
746
|
+
execute: () => {
|
|
747
|
+
const compositionId = currentCompositionRef.current;
|
|
748
|
+
if (compositionId === null) {
|
|
749
|
+
throw new Error('No composition is currently selected.');
|
|
750
|
+
}
|
|
751
|
+
if (remotion_1.Internals.timeValueRef.current === null) {
|
|
752
|
+
throw new Error('Studio playback controls are not ready.');
|
|
753
|
+
}
|
|
754
|
+
(0, pause_1.pause)();
|
|
755
|
+
return Promise.resolve({
|
|
756
|
+
currentComposition: compositionId,
|
|
757
|
+
playing: false,
|
|
758
|
+
});
|
|
759
|
+
},
|
|
760
|
+
}, { signal: controller.signal }),
|
|
761
|
+
modelContext.registerTool({
|
|
762
|
+
name: 'mute',
|
|
763
|
+
title: 'Mute Studio composition',
|
|
764
|
+
description: 'Mute audio playback for the current Remotion Studio composition.',
|
|
765
|
+
inputSchema: {
|
|
766
|
+
type: 'object',
|
|
767
|
+
properties: {},
|
|
768
|
+
additionalProperties: false,
|
|
769
|
+
},
|
|
770
|
+
annotations: { readOnlyHint: false },
|
|
771
|
+
execute: () => {
|
|
772
|
+
const compositionId = currentCompositionRef.current;
|
|
773
|
+
if (compositionId === null) {
|
|
774
|
+
throw new Error('No composition is currently selected.');
|
|
775
|
+
}
|
|
776
|
+
setPlayerMuted(true);
|
|
777
|
+
(0, mute_1.persistMuteOption)(true);
|
|
778
|
+
return Promise.resolve({
|
|
779
|
+
currentComposition: compositionId,
|
|
780
|
+
muted: true,
|
|
781
|
+
});
|
|
782
|
+
},
|
|
783
|
+
}, { signal: controller.signal }),
|
|
784
|
+
modelContext.registerTool({
|
|
785
|
+
name: 'unmute',
|
|
786
|
+
title: 'Unmute Studio composition',
|
|
787
|
+
description: 'Unmute audio playback for the current Remotion Studio composition.',
|
|
788
|
+
inputSchema: {
|
|
789
|
+
type: 'object',
|
|
790
|
+
properties: {},
|
|
791
|
+
additionalProperties: false,
|
|
792
|
+
},
|
|
793
|
+
annotations: { readOnlyHint: false },
|
|
794
|
+
execute: () => {
|
|
795
|
+
const compositionId = currentCompositionRef.current;
|
|
796
|
+
if (compositionId === null) {
|
|
797
|
+
throw new Error('No composition is currently selected.');
|
|
798
|
+
}
|
|
799
|
+
setPlayerMuted(false);
|
|
800
|
+
(0, mute_1.persistMuteOption)(false);
|
|
801
|
+
return Promise.resolve({
|
|
802
|
+
currentComposition: compositionId,
|
|
803
|
+
muted: false,
|
|
804
|
+
});
|
|
805
|
+
},
|
|
806
|
+
}, { signal: controller.signal }),
|
|
807
|
+
modelContext.registerTool({
|
|
808
|
+
name: 'set_timeline_zoom',
|
|
809
|
+
title: 'Set Studio timeline zoom',
|
|
810
|
+
description: 'Set the timeline zoom for the current Remotion Studio composition. Use 0 for fully zoomed out and 1 for the maximum zoom supported by the composition duration.',
|
|
811
|
+
inputSchema: {
|
|
812
|
+
type: 'object',
|
|
813
|
+
properties: {
|
|
814
|
+
zoom: {
|
|
815
|
+
type: 'number',
|
|
816
|
+
minimum: 0,
|
|
817
|
+
maximum: 1,
|
|
818
|
+
description: 'The normalized timeline zoom, from 0 (fully zoomed out) to 1 (maximum zoom).',
|
|
819
|
+
},
|
|
820
|
+
},
|
|
821
|
+
required: ['zoom'],
|
|
822
|
+
additionalProperties: false,
|
|
823
|
+
},
|
|
824
|
+
annotations: { readOnlyHint: false },
|
|
825
|
+
execute: ({ zoom }) => {
|
|
826
|
+
if (typeof zoom !== 'number' ||
|
|
827
|
+
!Number.isFinite(zoom) ||
|
|
828
|
+
zoom < 0 ||
|
|
829
|
+
zoom > 1) {
|
|
830
|
+
throw new Error('zoom must be a finite number between 0 and 1.');
|
|
831
|
+
}
|
|
832
|
+
const compositionId = currentCompositionRef.current;
|
|
833
|
+
if (compositionId === null) {
|
|
834
|
+
throw new Error('No composition is currently selected.');
|
|
835
|
+
}
|
|
836
|
+
const durationInFrames = (0, imperative_state_1.getCurrentDuration)();
|
|
837
|
+
if (durationInFrames <= 1) {
|
|
838
|
+
throw new Error('The current composition is a still and has no timeline zoom.');
|
|
839
|
+
}
|
|
840
|
+
const maxZoom = (0, get_timeline_max_zoom_1.getTimelineMaxZoom)(durationInFrames);
|
|
841
|
+
const timelineZoom = (0, get_timeline_max_zoom_1.clampTimelineZoom)({
|
|
842
|
+
zoom: (0, get_timeline_max_zoom_1.normalizedToTimelineZoom)({
|
|
843
|
+
normalized: zoom,
|
|
844
|
+
maxZoom,
|
|
845
|
+
}),
|
|
846
|
+
durationInFrames,
|
|
847
|
+
});
|
|
848
|
+
setTimelineZoom(compositionId, () => timelineZoom, {
|
|
849
|
+
anchorFrame: null,
|
|
850
|
+
anchorContentX: null,
|
|
851
|
+
});
|
|
852
|
+
return Promise.resolve({
|
|
853
|
+
currentComposition: compositionId,
|
|
854
|
+
timelineZoom: (0, get_timeline_max_zoom_1.timelineZoomToNormalized)({
|
|
855
|
+
zoom: timelineZoom,
|
|
856
|
+
maxZoom,
|
|
857
|
+
}),
|
|
858
|
+
});
|
|
859
|
+
},
|
|
860
|
+
}, { signal: controller.signal }),
|
|
861
|
+
modelContext.registerTool({
|
|
862
|
+
name: 'set_playback_rate',
|
|
863
|
+
title: 'Set Studio playback rate',
|
|
864
|
+
description: 'Set the playback rate for the current Remotion Studio composition. Negative values play the composition backwards.',
|
|
865
|
+
inputSchema: {
|
|
866
|
+
type: 'object',
|
|
867
|
+
properties: {
|
|
868
|
+
playbackRate: {
|
|
869
|
+
type: 'number',
|
|
870
|
+
enum: playbackrate_1.commonPlaybackRates,
|
|
871
|
+
description: 'The playback multiplier. Negative values play backwards.',
|
|
872
|
+
},
|
|
873
|
+
},
|
|
874
|
+
required: ['playbackRate'],
|
|
875
|
+
additionalProperties: false,
|
|
876
|
+
},
|
|
877
|
+
annotations: { readOnlyHint: false },
|
|
878
|
+
execute: ({ playbackRate }) => {
|
|
879
|
+
if (typeof playbackRate !== 'number' ||
|
|
880
|
+
!playbackrate_1.commonPlaybackRates.includes(playbackRate)) {
|
|
881
|
+
throw new Error(`playbackRate must be one of: ${playbackrate_1.commonPlaybackRates.join(', ')}.`);
|
|
882
|
+
}
|
|
883
|
+
const compositionId = currentCompositionRef.current;
|
|
884
|
+
if (compositionId === null) {
|
|
885
|
+
throw new Error('No composition is currently selected.');
|
|
886
|
+
}
|
|
887
|
+
setPlaybackRate(() => playbackRate);
|
|
888
|
+
(0, playbackrate_1.persistPlaybackRate)(playbackRate);
|
|
889
|
+
return Promise.resolve({
|
|
890
|
+
currentComposition: compositionId,
|
|
891
|
+
playbackRate,
|
|
892
|
+
});
|
|
893
|
+
},
|
|
894
|
+
}, { signal: controller.signal }),
|
|
895
|
+
modelContext.registerTool({
|
|
896
|
+
name: 'seek_to_frame',
|
|
897
|
+
title: 'Seek Studio timeline',
|
|
898
|
+
description: 'Seek the current Remotion Studio composition to a frame. Frames past the end of the composition are clamped to the final frame.',
|
|
899
|
+
inputSchema: {
|
|
900
|
+
type: 'object',
|
|
901
|
+
properties: {
|
|
902
|
+
frame: {
|
|
903
|
+
type: 'integer',
|
|
904
|
+
minimum: 0,
|
|
905
|
+
description: 'The zero-based frame to seek to.',
|
|
906
|
+
},
|
|
907
|
+
},
|
|
908
|
+
required: ['frame'],
|
|
909
|
+
additionalProperties: false,
|
|
910
|
+
},
|
|
911
|
+
annotations: { readOnlyHint: false },
|
|
912
|
+
execute: ({ frame }) => {
|
|
913
|
+
if (typeof frame !== 'number' || !Number.isInteger(frame)) {
|
|
914
|
+
throw new Error('frame must be an integer.');
|
|
915
|
+
}
|
|
916
|
+
const compositionId = currentCompositionRef.current;
|
|
917
|
+
if (compositionId === null) {
|
|
918
|
+
throw new Error('No composition is currently selected.');
|
|
919
|
+
}
|
|
920
|
+
const currentFrame = Math.min(Math.max(0, frame), (0, imperative_state_1.getCurrentDuration)() - 1);
|
|
921
|
+
(0, seek_1.seek)(currentFrame);
|
|
922
|
+
return Promise.resolve({
|
|
923
|
+
currentFrame,
|
|
924
|
+
currentComposition: compositionId,
|
|
925
|
+
});
|
|
926
|
+
},
|
|
927
|
+
}, { signal: controller.signal }),
|
|
928
|
+
]).catch(() => undefined);
|
|
929
|
+
return () => {
|
|
930
|
+
controller.abort();
|
|
931
|
+
};
|
|
932
|
+
}, [
|
|
933
|
+
clearSelection,
|
|
934
|
+
imperativePlaying,
|
|
935
|
+
selectComposition,
|
|
936
|
+
selectItems,
|
|
937
|
+
setEditorShowGuides,
|
|
938
|
+
setGuidesList,
|
|
939
|
+
setPlaybackRate,
|
|
940
|
+
setPlayerMuted,
|
|
941
|
+
setTimelineZoom,
|
|
942
|
+
]);
|
|
943
|
+
return null;
|
|
944
|
+
};
|
|
945
|
+
exports.WebMcp = WebMcp;
|