@remotion/studio 4.0.474 → 4.0.476
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/Canvas.js +6 -0
- package/dist/components/ColorPicker/ColorPicker.js +4 -31
- package/dist/components/ColorPicker/ColorPickerPopup.d.ts +6 -0
- package/dist/components/ColorPicker/ColorPickerPopup.js +11 -6
- package/dist/components/CompositionSelectorItem.js +4 -4
- package/dist/components/Editor.js +4 -1
- package/dist/components/GlobalKeybindings.js +12 -0
- package/dist/components/KeyboardShortcutsExplainer.js +24 -0
- package/dist/components/Modals.js +2 -1
- package/dist/components/NewComposition/ComboBox.js +1 -0
- package/dist/components/NewComposition/InputDragger.d.ts +6 -0
- package/dist/components/NewComposition/InputDragger.js +40 -14
- package/dist/components/NewComposition/RenameComposition.js +8 -1
- package/dist/components/NewComposition/RenameFolder.js +8 -1
- package/dist/components/NewComposition/RenameStaticFile.js +11 -1
- package/dist/components/Notifications/Notification.js +5 -4
- package/dist/components/Notifications/NotificationCenter.js +1 -1
- package/dist/components/ObserveDefaultPropsContext.js +6 -2
- package/dist/components/PlayPause.js +22 -66
- package/dist/components/PreviewToolbar.js +17 -3
- package/dist/components/RenderModal/RenderModalJSONPropsEditor.js +2 -1
- package/dist/components/SelectedOutlineOverlay.d.ts +104 -42
- package/dist/components/SelectedOutlineOverlay.js +1278 -336
- package/dist/components/SelectedOutlineUvControls.d.ts +17 -0
- package/dist/components/SelectedOutlineUvControls.js +167 -0
- package/dist/components/StudioCanvasCapture.d.ts +5 -0
- package/dist/components/StudioCanvasCapture.js +40 -0
- package/dist/components/Timeline/EasingEditorModal.d.ts +11 -0
- package/dist/components/Timeline/EasingEditorModal.js +247 -0
- package/dist/components/Timeline/KeyframeSettingsModal.js +1 -0
- package/dist/components/Timeline/Timeline.js +10 -7
- package/dist/components/Timeline/TimelineDeleteKeybindings.js +64 -35
- package/dist/components/Timeline/TimelineDragHandler.js +2 -2
- package/dist/components/Timeline/TimelineEffectItem.js +1 -2
- package/dist/components/Timeline/TimelineEffectPropItem.js +1 -1
- package/dist/components/Timeline/TimelineExpandedKeyframeRow.d.ts +1 -0
- package/dist/components/Timeline/TimelineExpandedKeyframeRow.js +2 -2
- package/dist/components/Timeline/TimelineExpandedTrackKeyframes.js +1 -1
- package/dist/components/Timeline/TimelineHeightContainer.js +2 -0
- package/dist/components/Timeline/TimelineItemStack.js +3 -56
- package/dist/components/Timeline/TimelineKeyframeControls.d.ts +7 -0
- package/dist/components/Timeline/TimelineKeyframeControls.js +259 -62
- package/dist/components/Timeline/TimelineKeyframeDiamond.js +4 -2
- package/dist/components/Timeline/TimelineKeyframeEasingLine.js +128 -3
- package/dist/components/Timeline/TimelineKeyframeTracksContext.d.ts +7 -0
- package/dist/components/Timeline/TimelineKeyframeTracksContext.js +17 -0
- package/dist/components/Timeline/TimelineMediaInfo.js +4 -24
- package/dist/components/Timeline/TimelinePrimitiveFieldValue.js +4 -0
- package/dist/components/Timeline/TimelineRotationField.js +21 -39
- package/dist/components/Timeline/TimelineScaleField.js +1 -1
- package/dist/components/Timeline/TimelineScrollable.js +19 -3
- package/dist/components/Timeline/TimelineSelection.d.ts +67 -3
- package/dist/components/Timeline/TimelineSelection.js +289 -32
- package/dist/components/Timeline/TimelineSequence.js +17 -9
- package/dist/components/Timeline/TimelineSequenceItem.js +328 -168
- package/dist/components/Timeline/TimelineSequenceName.d.ts +4 -2
- package/dist/components/Timeline/TimelineSequenceName.js +70 -19
- package/dist/components/Timeline/TimelineSequencePropItem.js +1 -1
- package/dist/components/Timeline/TimelineTimeIndicators.js +4 -2
- package/dist/components/Timeline/TimelineTransformOriginField.d.ts +11 -0
- package/dist/components/Timeline/TimelineTransformOriginField.js +138 -0
- package/dist/components/Timeline/TimelineTranslateField.js +1 -1
- package/dist/components/Timeline/TimelineUvCoordinateField.js +1 -1
- package/dist/components/Timeline/call-add-keyframe.d.ts +17 -0
- package/dist/components/Timeline/call-add-keyframe.js +65 -1
- package/dist/components/Timeline/delete-selected-timeline-item.js +23 -13
- package/dist/components/Timeline/disable-sequence-interactivity.d.ts +8 -0
- package/dist/components/Timeline/disable-sequence-interactivity.js +24 -0
- package/dist/components/Timeline/reset-selected-timeline-props.js +15 -7
- package/dist/components/Timeline/timeline-rotation-utils.d.ts +2 -0
- package/dist/components/Timeline/timeline-rotation-utils.js +34 -0
- package/dist/components/Timeline/transform-origin-utils.d.ts +24 -0
- package/dist/components/Timeline/transform-origin-utils.js +170 -0
- package/dist/components/Timeline/update-selected-easing.d.ts +35 -0
- package/dist/components/Timeline/update-selected-easing.js +133 -0
- package/dist/components/Timeline/use-expanded-track-keyframe-rows.d.ts +1 -0
- package/dist/components/Timeline/use-expanded-track-keyframe-rows.js +28 -0
- package/dist/components/Timeline/use-timeline-keyframe-drag.js +8 -13
- package/dist/components/canvas-capture-enabled.d.ts +1 -0
- package/dist/components/canvas-capture-enabled.js +4 -0
- package/dist/components/effect-drag-and-drop.d.ts +11 -0
- package/dist/components/effect-drag-and-drop.js +73 -0
- package/dist/components/selected-outline-geometry.d.ts +20 -0
- package/dist/components/selected-outline-geometry.js +18 -0
- package/dist/components/selected-outline-uv.d.ts +46 -0
- package/dist/components/selected-outline-uv.js +240 -0
- package/dist/esm/{chunk-xjvc8qen.js → chunk-0atarw3p.js} +8779 -5352
- package/dist/esm/internals.mjs +8779 -5352
- package/dist/esm/previewEntry.mjs +8789 -5362
- package/dist/esm/renderEntry.mjs +1 -1
- package/dist/helpers/colors.d.ts +0 -1
- package/dist/helpers/colors.js +1 -2
- package/dist/state/modals.d.ts +2 -1
- package/package.json +11 -10
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { SelectedOutline } from './selected-outline-geometry';
|
|
3
|
+
import { type SelectedOutlineUvHandle } from './selected-outline-uv';
|
|
4
|
+
type UvTarget = {
|
|
5
|
+
readonly containsSelection: boolean;
|
|
6
|
+
readonly uvHandles: readonly SelectedOutlineUvHandle[];
|
|
7
|
+
};
|
|
8
|
+
export declare const SelectedOutlineUvHandleConnectionLayer: React.FC<{
|
|
9
|
+
readonly outline: SelectedOutline;
|
|
10
|
+
readonly target: UvTarget | undefined;
|
|
11
|
+
}>;
|
|
12
|
+
export declare const SelectedOutlineUvHandleCircleLayer: React.FC<{
|
|
13
|
+
readonly onDraggingChange: (dragging: boolean) => void;
|
|
14
|
+
readonly outline: SelectedOutline;
|
|
15
|
+
readonly target: UvTarget | undefined;
|
|
16
|
+
}>;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.SelectedOutlineUvHandleCircleLayer = exports.SelectedOutlineUvHandleConnectionLayer = void 0;
|
|
37
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
38
|
+
const react_1 = __importStar(require("react"));
|
|
39
|
+
const remotion_1 = require("remotion");
|
|
40
|
+
const colors_1 = require("../helpers/colors");
|
|
41
|
+
const selected_outline_uv_1 = require("./selected-outline-uv");
|
|
42
|
+
const call_add_keyframe_1 = require("./Timeline/call-add-keyframe");
|
|
43
|
+
const save_effect_prop_1 = require("./Timeline/save-effect-prop");
|
|
44
|
+
const getSvgPointFromPointerEvent = ({ event, rect, }) => {
|
|
45
|
+
return {
|
|
46
|
+
x: event.clientX - rect.left,
|
|
47
|
+
y: event.clientY - rect.top,
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
const SelectedUvHandleConnectionLines = ({ handles, outline }) => {
|
|
51
|
+
const lines = (0, react_1.useMemo)(() => (0, selected_outline_uv_1.getUvHandleConnectionLines)({ handles, points: outline.points }), [handles, outline.points]);
|
|
52
|
+
return (jsx_runtime_1.jsx(jsx_runtime_1.Fragment, { children: lines.map((line) => (jsx_runtime_1.jsx("line", { x1: line.from.x, y1: line.from.y, x2: line.to.x, y2: line.to.y, stroke: colors_1.BLUE, strokeWidth: 2, vectorEffect: "non-scaling-stroke", pointerEvents: "none" }, line.key))) }));
|
|
53
|
+
};
|
|
54
|
+
const SelectedUvHandleCircle = ({ handle, onDraggingChange, outline }) => {
|
|
55
|
+
const { setEffectDragOverrides, clearEffectDragOverrides, setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
|
|
56
|
+
const position = (0, react_1.useMemo)(() => (0, selected_outline_uv_1.getUvHandlePosition)(outline.points, handle.value), [handle.value, outline.points]);
|
|
57
|
+
const onPointerDown = react_1.default.useCallback((event) => {
|
|
58
|
+
if (event.button !== 0) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
event.preventDefault();
|
|
62
|
+
event.stopPropagation();
|
|
63
|
+
const svg = event.currentTarget.ownerSVGElement;
|
|
64
|
+
if (svg === null) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const svgRect = svg.getBoundingClientRect();
|
|
68
|
+
let lastValue = null;
|
|
69
|
+
onDraggingChange(true);
|
|
70
|
+
const defaultValue = handle.fieldDefault !== undefined
|
|
71
|
+
? JSON.stringify(handle.fieldDefault)
|
|
72
|
+
: null;
|
|
73
|
+
const updateFromPointerEvent = (pointerEvent) => {
|
|
74
|
+
const point = getSvgPointFromPointerEvent({
|
|
75
|
+
event: pointerEvent,
|
|
76
|
+
rect: svgRect,
|
|
77
|
+
});
|
|
78
|
+
const nextValue = (0, selected_outline_uv_1.constrainUv)((0, selected_outline_uv_1.getUvCoordinateForPoint)(outline.points, point), handle.fieldSchema);
|
|
79
|
+
lastValue = nextValue;
|
|
80
|
+
setEffectDragOverrides(handle.nodePath, handle.effectIndex, handle.fieldKey, handle.propStatus.status === 'keyframed'
|
|
81
|
+
? remotion_1.Internals.makeKeyframedDragOverride({
|
|
82
|
+
status: handle.propStatus,
|
|
83
|
+
frame: handle.sourceFrame,
|
|
84
|
+
value: nextValue,
|
|
85
|
+
})
|
|
86
|
+
: remotion_1.Internals.makeStaticDragOverride(nextValue));
|
|
87
|
+
};
|
|
88
|
+
updateFromPointerEvent(event);
|
|
89
|
+
const onPointerMove = (moveEvent) => {
|
|
90
|
+
moveEvent.preventDefault();
|
|
91
|
+
updateFromPointerEvent(moveEvent);
|
|
92
|
+
};
|
|
93
|
+
const onPointerUp = () => {
|
|
94
|
+
window.removeEventListener('pointermove', onPointerMove);
|
|
95
|
+
window.removeEventListener('pointerup', onPointerUp);
|
|
96
|
+
window.removeEventListener('pointercancel', onPointerUp);
|
|
97
|
+
onDraggingChange(false);
|
|
98
|
+
const stringifiedValue = lastValue === null ? null : JSON.stringify(lastValue);
|
|
99
|
+
const shouldSave = (() => {
|
|
100
|
+
if (lastValue === null) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
if (handle.propStatus.status === 'keyframed') {
|
|
104
|
+
return !(0, selected_outline_uv_1.tuplesEqual)(handle.value, lastValue);
|
|
105
|
+
}
|
|
106
|
+
return (!(0, selected_outline_uv_1.tuplesEqual)(handle.propStatus.codeValue, lastValue) &&
|
|
107
|
+
!(defaultValue === stringifiedValue &&
|
|
108
|
+
handle.propStatus.codeValue === undefined));
|
|
109
|
+
})();
|
|
110
|
+
if (!shouldSave) {
|
|
111
|
+
clearEffectDragOverrides(handle.nodePath, handle.effectIndex);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
(handle.propStatus.status === 'keyframed'
|
|
115
|
+
? (0, call_add_keyframe_1.callAddEffectKeyframe)({
|
|
116
|
+
fileName: handle.nodePath.absolutePath,
|
|
117
|
+
nodePath: handle.nodePath,
|
|
118
|
+
effectIndex: handle.effectIndex,
|
|
119
|
+
fieldKey: handle.fieldKey,
|
|
120
|
+
sourceFrame: handle.sourceFrame,
|
|
121
|
+
value: lastValue,
|
|
122
|
+
schema: handle.schema,
|
|
123
|
+
setPropStatuses,
|
|
124
|
+
clientId: handle.clientId,
|
|
125
|
+
})
|
|
126
|
+
: (0, save_effect_prop_1.saveEffectProp)({
|
|
127
|
+
type: 'value',
|
|
128
|
+
fileName: handle.nodePath.absolutePath,
|
|
129
|
+
nodePath: handle.nodePath,
|
|
130
|
+
effectIndex: handle.effectIndex,
|
|
131
|
+
fieldKey: handle.fieldKey,
|
|
132
|
+
value: lastValue,
|
|
133
|
+
defaultValue,
|
|
134
|
+
schema: handle.schema,
|
|
135
|
+
setPropStatuses,
|
|
136
|
+
clientId: handle.clientId,
|
|
137
|
+
})).finally(() => {
|
|
138
|
+
clearEffectDragOverrides(handle.nodePath, handle.effectIndex);
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
window.addEventListener('pointermove', onPointerMove);
|
|
142
|
+
window.addEventListener('pointerup', onPointerUp);
|
|
143
|
+
window.addEventListener('pointercancel', onPointerUp);
|
|
144
|
+
}, [
|
|
145
|
+
clearEffectDragOverrides,
|
|
146
|
+
handle,
|
|
147
|
+
onDraggingChange,
|
|
148
|
+
outline.points,
|
|
149
|
+
setPropStatuses,
|
|
150
|
+
setEffectDragOverrides,
|
|
151
|
+
]);
|
|
152
|
+
return (jsx_runtime_1.jsx("circle", { cx: position.x, cy: position.y, r: 6, fill: "white", stroke: colors_1.BLUE, strokeWidth: 2, vectorEffect: "non-scaling-stroke", pointerEvents: "all", cursor: "default", onPointerDown: onPointerDown }));
|
|
153
|
+
};
|
|
154
|
+
const SelectedOutlineUvHandleConnectionLayer = ({ outline, target }) => {
|
|
155
|
+
if (!(target === null || target === void 0 ? void 0 : target.containsSelection) || target.uvHandles.length === 0) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
return (jsx_runtime_1.jsx(SelectedUvHandleConnectionLines, { handles: target.uvHandles, outline: outline }));
|
|
159
|
+
};
|
|
160
|
+
exports.SelectedOutlineUvHandleConnectionLayer = SelectedOutlineUvHandleConnectionLayer;
|
|
161
|
+
const SelectedOutlineUvHandleCircleLayer = ({ onDraggingChange, outline, target }) => {
|
|
162
|
+
if (!(target === null || target === void 0 ? void 0 : target.containsSelection) || target.uvHandles.length === 0) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
return (jsx_runtime_1.jsx(jsx_runtime_1.Fragment, { children: target.uvHandles.map((handle) => (jsx_runtime_1.jsx(SelectedUvHandleCircle, { handle: handle, onDraggingChange: onDraggingChange, outline: outline }, `${handle.effectIndex}-${handle.fieldKey}`))) }));
|
|
166
|
+
};
|
|
167
|
+
exports.SelectedOutlineUvHandleCircleLayer = SelectedOutlineUvHandleCircleLayer;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StudioCanvasCapture = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const canvas_capture_1 = require("@remotion/canvas-capture");
|
|
6
|
+
const react_1 = require("react");
|
|
7
|
+
const use_keybinding_1 = require("../helpers/use-keybinding");
|
|
8
|
+
const logCaptureError = (message, err) => {
|
|
9
|
+
// eslint-disable-next-line no-console
|
|
10
|
+
console.error(message, err instanceof Error ? err.message : String(err));
|
|
11
|
+
};
|
|
12
|
+
const StudioCanvasCapture = ({ children, density }) => {
|
|
13
|
+
const captureRef = (0, react_1.useRef)(null);
|
|
14
|
+
const isSupported = (0, react_1.useMemo)(() => (0, canvas_capture_1.isHtmlInCanvasAvailable)(), []);
|
|
15
|
+
const keybindings = (0, use_keybinding_1.useKeybinding)();
|
|
16
|
+
(0, react_1.useEffect)(() => {
|
|
17
|
+
if (!isSupported) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const binding = keybindings.registerKeybinding({
|
|
21
|
+
event: 'keydown',
|
|
22
|
+
key: 'p',
|
|
23
|
+
commandCtrlKey: true,
|
|
24
|
+
callback: () => {
|
|
25
|
+
var _a;
|
|
26
|
+
(_a = captureRef.current) === null || _a === void 0 ? void 0 : _a.toggleRecording().catch((err) => {
|
|
27
|
+
logCaptureError('Could not toggle Studio canvas recording:', err);
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
preventDefault: true,
|
|
31
|
+
triggerIfInputFieldFocused: true,
|
|
32
|
+
keepRegisteredWhenNotHighestContext: true,
|
|
33
|
+
});
|
|
34
|
+
return () => {
|
|
35
|
+
binding.unregister();
|
|
36
|
+
};
|
|
37
|
+
}, [isSupported, keybindings]);
|
|
38
|
+
return (jsx_runtime_1.jsx(canvas_capture_1.HtmlInCanvasCapture, { ref: captureRef, density: density, filename: "remotion-studio-canvas-recording.webm", children: children }));
|
|
39
|
+
};
|
|
40
|
+
exports.StudioCanvasCapture = StudioCanvasCapture;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { TimelineSelection } from './TimelineSelection';
|
|
3
|
+
import type { TimelineEasingValue } from './update-selected-easing';
|
|
4
|
+
export type EasingEditorModalState = {
|
|
5
|
+
type: 'easing-editor';
|
|
6
|
+
initialEasing: TimelineEasingValue;
|
|
7
|
+
selections: TimelineSelection[];
|
|
8
|
+
};
|
|
9
|
+
export declare const EasingEditorModal: React.FC<{
|
|
10
|
+
readonly state: EasingEditorModalState;
|
|
11
|
+
}>;
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EasingEditorModal = void 0;
|
|
4
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
|
+
const react_1 = require("react");
|
|
6
|
+
const remotion_1 = require("remotion");
|
|
7
|
+
const client_id_1 = require("../../helpers/client-id");
|
|
8
|
+
const colors_1 = require("../../helpers/colors");
|
|
9
|
+
const modals_1 = require("../../state/modals");
|
|
10
|
+
const Button_1 = require("../Button");
|
|
11
|
+
const layout_1 = require("../layout");
|
|
12
|
+
const ModalButton_1 = require("../ModalButton");
|
|
13
|
+
const ModalFooter_1 = require("../ModalFooter");
|
|
14
|
+
const ModalHeader_1 = require("../ModalHeader");
|
|
15
|
+
const DismissableModal_1 = require("../NewComposition/DismissableModal");
|
|
16
|
+
const InputDragger_1 = require("../NewComposition/InputDragger");
|
|
17
|
+
const update_selected_easing_1 = require("./update-selected-easing");
|
|
18
|
+
const SVG_WIDTH = 560;
|
|
19
|
+
const SVG_HEIGHT = 320;
|
|
20
|
+
const PLOT_LEFT = 42;
|
|
21
|
+
const PLOT_TOP = 8;
|
|
22
|
+
const PLOT_WIDTH = 500;
|
|
23
|
+
const PLOT_HEIGHT = 304;
|
|
24
|
+
const Y_MIN = -2;
|
|
25
|
+
const Y_MAX = 3;
|
|
26
|
+
const LINEAR_BEZIER = [0.25, 0.25, 0.75, 0.75];
|
|
27
|
+
const container = {
|
|
28
|
+
width: 600,
|
|
29
|
+
};
|
|
30
|
+
const coordinatesGrid = {
|
|
31
|
+
display: 'grid',
|
|
32
|
+
gridTemplateColumns: 'repeat(4, minmax(0, 1fr))',
|
|
33
|
+
gap: 10,
|
|
34
|
+
marginTop: 12,
|
|
35
|
+
padding: '0 16px 16px',
|
|
36
|
+
};
|
|
37
|
+
const coordinateRow = {
|
|
38
|
+
gap: 4,
|
|
39
|
+
};
|
|
40
|
+
const coordinateLabel = {
|
|
41
|
+
fontSize: 13,
|
|
42
|
+
color: 'rgba(255, 255, 255, 0.72)',
|
|
43
|
+
paddingLeft: 6,
|
|
44
|
+
};
|
|
45
|
+
const coordinateInputWrapper = {
|
|
46
|
+
height: 34,
|
|
47
|
+
display: 'flex',
|
|
48
|
+
alignItems: 'center',
|
|
49
|
+
};
|
|
50
|
+
const numberInputStyle = {
|
|
51
|
+
backgroundColor: colors_1.INPUT_BACKGROUND,
|
|
52
|
+
borderRadius: 4,
|
|
53
|
+
width: '100%',
|
|
54
|
+
};
|
|
55
|
+
const svgStyle = {
|
|
56
|
+
display: 'block',
|
|
57
|
+
width: '100%',
|
|
58
|
+
};
|
|
59
|
+
const hiddenSubmit = {
|
|
60
|
+
display: 'none',
|
|
61
|
+
};
|
|
62
|
+
const clamp = (value, min, max) => {
|
|
63
|
+
return Math.min(max, Math.max(min, value));
|
|
64
|
+
};
|
|
65
|
+
const sanitizeBezier = (bezier) => [
|
|
66
|
+
clamp(bezier[0], 0, 1),
|
|
67
|
+
clamp(bezier[1], Y_MIN, Y_MAX),
|
|
68
|
+
clamp(bezier[2], 0, 1),
|
|
69
|
+
clamp(bezier[3], Y_MIN, Y_MAX),
|
|
70
|
+
];
|
|
71
|
+
const easingToBezier = (easing) => {
|
|
72
|
+
return easing === 'linear' ? LINEAR_BEZIER : sanitizeBezier(easing);
|
|
73
|
+
};
|
|
74
|
+
const roundCoordinate = (value) => Math.round(value * 10000) / 10000;
|
|
75
|
+
const serializeBezier = (bezier) => {
|
|
76
|
+
const rounded = sanitizeBezier(bezier).map(roundCoordinate);
|
|
77
|
+
if (rounded[0] === rounded[1] && rounded[2] === rounded[3]) {
|
|
78
|
+
return 'linear';
|
|
79
|
+
}
|
|
80
|
+
return rounded;
|
|
81
|
+
};
|
|
82
|
+
const formatNumber = (value) => {
|
|
83
|
+
const numericValue = Number(value);
|
|
84
|
+
if (!Number.isFinite(numericValue)) {
|
|
85
|
+
return String(value);
|
|
86
|
+
}
|
|
87
|
+
return String(roundCoordinate(numericValue));
|
|
88
|
+
};
|
|
89
|
+
const xToSvg = (value) => PLOT_LEFT + value * PLOT_WIDTH;
|
|
90
|
+
const yToSvg = (value) => PLOT_TOP + ((Y_MAX - value) / (Y_MAX - Y_MIN)) * PLOT_HEIGHT;
|
|
91
|
+
const pointFromBezier = (bezier, handle) => {
|
|
92
|
+
const x = handle === 0 ? bezier[0] : bezier[2];
|
|
93
|
+
const y = handle === 0 ? bezier[1] : bezier[3];
|
|
94
|
+
return { x: xToSvg(x), y: yToSvg(y) };
|
|
95
|
+
};
|
|
96
|
+
const startPoint = { x: xToSvg(0), y: yToSvg(0) };
|
|
97
|
+
const endPoint = { x: xToSvg(1), y: yToSvg(1) };
|
|
98
|
+
const EasingEditorModal = ({ state }) => {
|
|
99
|
+
const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
|
|
100
|
+
const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
|
|
101
|
+
const sequencesRef = (0, react_1.useContext)(remotion_1.Internals.SequenceManagerRefContext);
|
|
102
|
+
const propStatusesRef = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesRefContext);
|
|
103
|
+
const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
|
|
104
|
+
const { overrideIdToNodePathMappings } = (0, react_1.useContext)(remotion_1.Internals.OverrideIdsToNodePathsGettersContext);
|
|
105
|
+
const svgRef = (0, react_1.useRef)(null);
|
|
106
|
+
const [bezier, setBezier] = (0, react_1.useState)(() => easingToBezier(state.initialEasing));
|
|
107
|
+
const [saving, setSaving] = (0, react_1.useState)(false);
|
|
108
|
+
const [activeHandle, setActiveHandle] = (0, react_1.useState)(null);
|
|
109
|
+
const close = (0, react_1.useCallback)(() => {
|
|
110
|
+
setSelectedModal(null);
|
|
111
|
+
}, [setSelectedModal]);
|
|
112
|
+
const setCoordinate = (0, react_1.useCallback)((handle, coordinate, value) => {
|
|
113
|
+
setBezier((previous) => {
|
|
114
|
+
const next = [...previous];
|
|
115
|
+
const index = handle === 0
|
|
116
|
+
? coordinate === 'x'
|
|
117
|
+
? 0
|
|
118
|
+
: 1
|
|
119
|
+
: coordinate === 'x'
|
|
120
|
+
? 2
|
|
121
|
+
: 3;
|
|
122
|
+
next[index] =
|
|
123
|
+
coordinate === 'x' ? clamp(value, 0, 1) : clamp(value, Y_MIN, Y_MAX);
|
|
124
|
+
return next;
|
|
125
|
+
});
|
|
126
|
+
}, []);
|
|
127
|
+
const getValueFromPointer = (0, react_1.useCallback)((event) => {
|
|
128
|
+
const svg = svgRef.current;
|
|
129
|
+
if (!svg) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
const rect = svg.getBoundingClientRect();
|
|
133
|
+
const svgX = ((event.clientX - rect.left) / rect.width) * SVG_WIDTH;
|
|
134
|
+
const svgY = ((event.clientY - rect.top) / rect.height) * SVG_HEIGHT;
|
|
135
|
+
const x = clamp((svgX - PLOT_LEFT) / PLOT_WIDTH, 0, 1);
|
|
136
|
+
const y = clamp(Y_MAX - ((svgY - PLOT_TOP) / PLOT_HEIGHT) * (Y_MAX - Y_MIN), Y_MIN, Y_MAX);
|
|
137
|
+
return { x, y };
|
|
138
|
+
}, []);
|
|
139
|
+
const updateHandleFromPointer = (0, react_1.useCallback)((handle, event) => {
|
|
140
|
+
const value = getValueFromPointer(event);
|
|
141
|
+
if (!value) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
setBezier((previous) => {
|
|
145
|
+
const next = [...previous];
|
|
146
|
+
if (handle === 0) {
|
|
147
|
+
next[0] = value.x;
|
|
148
|
+
next[1] = value.y;
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
next[2] = value.x;
|
|
152
|
+
next[3] = value.y;
|
|
153
|
+
}
|
|
154
|
+
return next;
|
|
155
|
+
});
|
|
156
|
+
}, [getValueFromPointer]);
|
|
157
|
+
(0, react_1.useEffect)(() => {
|
|
158
|
+
if (activeHandle === null) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const onPointerMove = (event) => {
|
|
162
|
+
updateHandleFromPointer(activeHandle, event);
|
|
163
|
+
};
|
|
164
|
+
const onPointerUp = () => {
|
|
165
|
+
setActiveHandle(null);
|
|
166
|
+
};
|
|
167
|
+
window.addEventListener('pointermove', onPointerMove);
|
|
168
|
+
window.addEventListener('pointerup', onPointerUp, { once: true });
|
|
169
|
+
return () => {
|
|
170
|
+
window.removeEventListener('pointermove', onPointerMove);
|
|
171
|
+
window.removeEventListener('pointerup', onPointerUp);
|
|
172
|
+
};
|
|
173
|
+
}, [activeHandle, updateHandleFromPointer]);
|
|
174
|
+
const onHandlePointerDown = (0, react_1.useCallback)((handle, event) => {
|
|
175
|
+
event.preventDefault();
|
|
176
|
+
event.stopPropagation();
|
|
177
|
+
setActiveHandle(handle);
|
|
178
|
+
updateHandleFromPointer(handle, event);
|
|
179
|
+
}, [updateHandleFromPointer]);
|
|
180
|
+
const onSave = (0, react_1.useCallback)(() => {
|
|
181
|
+
if (previewServerState.type !== 'connected' || saving) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
setSaving(true);
|
|
185
|
+
const promise = (0, update_selected_easing_1.updateSelectedTimelineEasings)({
|
|
186
|
+
selections: state.selections,
|
|
187
|
+
sequences: sequencesRef.current,
|
|
188
|
+
overrideIdsToNodePaths: overrideIdToNodePathMappings,
|
|
189
|
+
propStatuses: propStatusesRef.current,
|
|
190
|
+
setPropStatuses,
|
|
191
|
+
clientId: previewServerState.clientId,
|
|
192
|
+
easing: serializeBezier(bezier),
|
|
193
|
+
});
|
|
194
|
+
if (promise === null) {
|
|
195
|
+
setSaving(false);
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
promise.catch(() => undefined);
|
|
199
|
+
close();
|
|
200
|
+
}, [
|
|
201
|
+
bezier,
|
|
202
|
+
close,
|
|
203
|
+
overrideIdToNodePathMappings,
|
|
204
|
+
previewServerState,
|
|
205
|
+
propStatusesRef,
|
|
206
|
+
saving,
|
|
207
|
+
sequencesRef,
|
|
208
|
+
setPropStatuses,
|
|
209
|
+
state.selections,
|
|
210
|
+
]);
|
|
211
|
+
const onSubmit = (0, react_1.useCallback)((event) => {
|
|
212
|
+
event.preventDefault();
|
|
213
|
+
onSave();
|
|
214
|
+
}, [onSave]);
|
|
215
|
+
const path = (0, react_1.useMemo)(() => {
|
|
216
|
+
const curveFirstHandle = pointFromBezier(bezier, 0);
|
|
217
|
+
const curveSecondHandle = pointFromBezier(bezier, 1);
|
|
218
|
+
return `M ${startPoint.x} ${startPoint.y} C ${curveFirstHandle.x} ${curveFirstHandle.y}, ${curveSecondHandle.x} ${curveSecondHandle.y}, ${endPoint.x} ${endPoint.y}`;
|
|
219
|
+
}, [bezier]);
|
|
220
|
+
const firstHandle = pointFromBezier(bezier, 0);
|
|
221
|
+
const secondHandle = pointFromBezier(bezier, 1);
|
|
222
|
+
const yZero = yToSvg(0);
|
|
223
|
+
const yOne = yToSvg(1);
|
|
224
|
+
const saveDisabled = saving || previewServerState.type !== 'connected';
|
|
225
|
+
return (jsx_runtime_1.jsxs(DismissableModal_1.DismissableModal, { children: [
|
|
226
|
+
jsx_runtime_1.jsx(ModalHeader_1.ModalHeader, { title: "Edit easing" }), jsx_runtime_1.jsxs("form", { onSubmit: onSubmit, children: [
|
|
227
|
+
jsx_runtime_1.jsxs("div", { style: container, children: [
|
|
228
|
+
jsx_runtime_1.jsxs("svg", { ref: svgRef, width: SVG_WIDTH, height: SVG_HEIGHT, viewBox: `0 0 ${SVG_WIDTH} ${SVG_HEIGHT}`, style: svgStyle, "aria-label": "Bezier curve editor", children: [
|
|
229
|
+
jsx_runtime_1.jsx("line", { x1: PLOT_LEFT, y1: yZero, x2: PLOT_LEFT + PLOT_WIDTH, y2: yZero, stroke: colors_1.INPUT_BORDER_COLOR_HOVERED, strokeWidth: 1 }), jsx_runtime_1.jsx("line", { x1: PLOT_LEFT, y1: yOne, x2: PLOT_LEFT + PLOT_WIDTH, y2: yOne, stroke: colors_1.INPUT_BORDER_COLOR_HOVERED, strokeWidth: 1 }), jsx_runtime_1.jsx("line", { x1: startPoint.x, y1: startPoint.y, x2: firstHandle.x, y2: firstHandle.y, stroke: "rgba(255, 255, 255, 0.35)", strokeWidth: 1 }), jsx_runtime_1.jsx("line", { x1: endPoint.x, y1: endPoint.y, x2: secondHandle.x, y2: secondHandle.y, stroke: "rgba(255, 255, 255, 0.35)", strokeWidth: 1 }), jsx_runtime_1.jsx("path", { d: path, fill: "none", stroke: colors_1.BLUE, strokeWidth: 3 }), jsx_runtime_1.jsx("circle", { cx: startPoint.x, cy: startPoint.y, r: 4, fill: "white" }), jsx_runtime_1.jsx("circle", { cx: endPoint.x, cy: endPoint.y, r: 4, fill: "white" }), jsx_runtime_1.jsx("circle", { cx: firstHandle.x, cy: firstHandle.y, r: 6, fill: "white", stroke: colors_1.BLUE, strokeWidth: 2, vectorEffect: "non-scaling-stroke", pointerEvents: "all", cursor: activeHandle === 0 ? 'grabbing' : 'default', onPointerDown: (event) => onHandlePointerDown(0, event) }), jsx_runtime_1.jsx("circle", { cx: secondHandle.x, cy: secondHandle.y, r: 6, fill: "white", stroke: colors_1.BLUE, strokeWidth: 2, vectorEffect: "non-scaling-stroke", pointerEvents: "all", cursor: activeHandle === 1 ? 'grabbing' : 'default', onPointerDown: (event) => onHandlePointerDown(1, event) }), jsx_runtime_1.jsx("text", { x: PLOT_LEFT - 22, y: yZero + 3, fill: colors_1.LIGHT_TEXT, fontSize: 9, children: "0" }), jsx_runtime_1.jsx("text", { x: PLOT_LEFT - 22, y: yOne + 3, fill: colors_1.LIGHT_TEXT, fontSize: 9, children: "1" })
|
|
230
|
+
] }), jsx_runtime_1.jsxs("div", { style: coordinatesGrid, children: [
|
|
231
|
+
jsx_runtime_1.jsxs("div", { style: coordinateRow, children: [
|
|
232
|
+
jsx_runtime_1.jsx("div", { style: coordinateLabel, children: "X1" }), jsx_runtime_1.jsx("div", { style: coordinateInputWrapper, children: jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: bezier[0], status: "ok", onValueChange: (value) => setCoordinate(0, 'x', value), onValueChangeEnd: (value) => setCoordinate(0, 'x', value), onTextChange: () => undefined, min: 0, max: 1, step: 0.01, formatter: formatNumber, rightAlign: false, style: numberInputStyle, snapToStep: false }) })
|
|
233
|
+
] }), jsx_runtime_1.jsxs("div", { style: coordinateRow, children: [
|
|
234
|
+
jsx_runtime_1.jsx("div", { style: coordinateLabel, children: "Y1" }), jsx_runtime_1.jsx("div", { style: coordinateInputWrapper, children: jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: bezier[1], status: "ok", onValueChange: (value) => setCoordinate(0, 'y', value), onValueChangeEnd: (value) => setCoordinate(0, 'y', value), onTextChange: () => undefined, min: Y_MIN, max: Y_MAX, step: 0.01, formatter: formatNumber, rightAlign: false, style: numberInputStyle, snapToStep: false }) })
|
|
235
|
+
] }), jsx_runtime_1.jsxs("div", { style: coordinateRow, children: [
|
|
236
|
+
jsx_runtime_1.jsx("div", { style: coordinateLabel, children: "X2" }), jsx_runtime_1.jsx("div", { style: coordinateInputWrapper, children: jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: bezier[2], status: "ok", onValueChange: (value) => setCoordinate(1, 'x', value), onValueChangeEnd: (value) => setCoordinate(1, 'x', value), onTextChange: () => undefined, min: 0, max: 1, step: 0.01, formatter: formatNumber, rightAlign: false, style: numberInputStyle, snapToStep: false }) })
|
|
237
|
+
] }), jsx_runtime_1.jsxs("div", { style: coordinateRow, children: [
|
|
238
|
+
jsx_runtime_1.jsx("div", { style: coordinateLabel, children: "Y2" }), jsx_runtime_1.jsx("div", { style: coordinateInputWrapper, children: jsx_runtime_1.jsx(InputDragger_1.InputDragger, { type: "number", value: bezier[3], status: "ok", onValueChange: (value) => setCoordinate(1, 'y', value), onValueChangeEnd: (value) => setCoordinate(1, 'y', value), onTextChange: () => undefined, min: Y_MIN, max: Y_MAX, step: 0.01, formatter: formatNumber, rightAlign: false, style: numberInputStyle, snapToStep: false }) })
|
|
239
|
+
] })
|
|
240
|
+
] })
|
|
241
|
+
] }), jsx_runtime_1.jsx(ModalFooter_1.ModalFooterContainer, { children: jsx_runtime_1.jsxs(layout_1.Row, { justify: "flex-end", align: "center", children: [
|
|
242
|
+
jsx_runtime_1.jsx(Button_1.Button, { onClick: close, children: "Discard" }), jsx_runtime_1.jsx(layout_1.Spacing, { x: 1 }), jsx_runtime_1.jsx(ModalButton_1.ModalButton, { onClick: onSave, disabled: saveDisabled, children: "Save" })
|
|
243
|
+
] }) }), jsx_runtime_1.jsx("button", { type: "submit", style: hiddenSubmit, disabled: saveDisabled, "aria-hidden": true, tabIndex: -1 })
|
|
244
|
+
] })
|
|
245
|
+
] }));
|
|
246
|
+
};
|
|
247
|
+
exports.EasingEditorModal = EasingEditorModal;
|
|
@@ -59,6 +59,7 @@ const TimelineDragHandler_1 = require("./TimelineDragHandler");
|
|
|
59
59
|
const TimelineHeightContainer_1 = require("./TimelineHeightContainer");
|
|
60
60
|
const TimelineInOutDragHandler_1 = require("./TimelineInOutDragHandler");
|
|
61
61
|
const TimelineInOutPointer_1 = require("./TimelineInOutPointer");
|
|
62
|
+
const TimelineKeyframeTracksContext_1 = require("./TimelineKeyframeTracksContext");
|
|
62
63
|
const TimelineList_1 = require("./TimelineList");
|
|
63
64
|
const TimelinePinchZoom_1 = require("./TimelinePinchZoom");
|
|
64
65
|
const TimelinePlayCursorSyncer_1 = require("./TimelinePlayCursorSyncer");
|
|
@@ -228,13 +229,15 @@ const TimelineInner = () => {
|
|
|
228
229
|
return null;
|
|
229
230
|
}
|
|
230
231
|
return (jsx_runtime_1.jsx(SubscribeToNodePaths_1.SubscribeToNodePaths, { overrideId: sequence.controls.overrideId, schema: sequence.controls.schema, getStack: sequence.getStack, effects: sequence.effects }, sequence.id));
|
|
231
|
-
}), jsx_runtime_1.jsx(SequencePropsObserver_1.SequencePropsObserver, {}), jsx_runtime_1.
|
|
232
|
-
|
|
233
|
-
jsx_runtime_1.jsx(
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
232
|
+
}), jsx_runtime_1.jsx(SequencePropsObserver_1.SequencePropsObserver, {}), jsx_runtime_1.jsxs(TimelineKeyframeTracksContext_1.TimelineKeyframeTracksProvider, { tracks: filtered, children: [
|
|
233
|
+
jsx_runtime_1.jsx(TimelineSelection_1.TimelineSelectAllKeybindings, { timeline: shown }), jsx_runtime_1.jsx(TimelineHeightContainer_1.TimelineHeightContainer, { shown: shown, hasBeenCut: hasBeenCut, children: isStill ? (jsx_runtime_1.jsx(TimelineList_1.TimelineList, { timeline: shown })) : (jsx_runtime_1.jsxs(TimelineWidthProvider_1.TimelineWidthProvider, { children: [
|
|
234
|
+
jsx_runtime_1.jsx(TimelinePinchZoom_1.TimelinePinchZoom, {}), jsx_runtime_1.jsxs(SplitterContainer_1.SplitterContainer, { orientation: "vertical", defaultFlex: 0.2, id: "names-to-timeline", maxFlex: 0.5, minFlex: 0.15, children: [
|
|
235
|
+
jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { type: "flexer", sticky: jsx_runtime_1.jsx(TimelineTimeIndicators_1.TimelineTimePlaceholders, {}), children: jsx_runtime_1.jsx(TimelineList_1.TimelineList, { timeline: shown }) }), jsx_runtime_1.jsx(SplitterHandle_1.SplitterHandle, { onCollapse: noop, allowToCollapse: "none" }), jsx_runtime_1.jsx(SplitterElement_1.SplitterElement, { type: "anti-flexer", sticky: null, children: jsx_runtime_1.jsxs(TimelineScrollable_1.TimelineScrollable, { children: [
|
|
236
|
+
jsx_runtime_1.jsx(TimelineTracks_1.TimelineTracks, { timeline: shown, hasBeenCut: hasBeenCut }), jsx_runtime_1.jsx(TimelinePlayCursorSyncer_1.TimelinePlayCursorSyncer, {}), jsx_runtime_1.jsx(TimelineInOutPointer_1.TimelineInOutPointer, {}), jsx_runtime_1.jsx(TimelineTimeIndicators_1.TimelineTimeIndicators, {}), jsx_runtime_1.jsx(TimelineDragHandler_1.TimelineDragHandler, {}), jsx_runtime_1.jsx(TimelineInOutDragHandler_1.TimelineInOutDragHandler, {}), jsx_runtime_1.jsx(TimelineSlider_1.TimelineSlider, {})
|
|
237
|
+
] }) })
|
|
238
|
+
] })
|
|
239
|
+
] })) })
|
|
240
|
+
] })
|
|
238
241
|
] }));
|
|
239
242
|
};
|
|
240
243
|
exports.Timeline = react_1.default.memo(TimelineInner);
|