@remotion/studio 4.0.477 → 4.0.478
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/CanvasIfSizeIsAvailable.js +2 -6
- package/dist/components/EditorGuides/Guide.js +37 -9
- package/dist/components/EditorRuler/Ruler.js +4 -14
- package/dist/components/EditorRuler/index.js +9 -4
- package/dist/components/InlineAction.js +1 -0
- package/dist/components/MenuToolbar.d.ts +1 -0
- package/dist/components/MenuToolbar.js +4 -1
- package/dist/components/SelectedOutlineElement.js +85 -14
- package/dist/components/SelectedOutlineOverlay.d.ts +1 -1
- package/dist/components/SelectedOutlineOverlay.js +5 -1
- package/dist/components/Timeline/TimelineSequence.js +7 -15
- package/dist/components/Timeline/TimelineVideoInfo.d.ts +1 -0
- package/dist/components/Timeline/TimelineVideoInfo.js +93 -8
- package/dist/components/Timeline/duplicate-selected-timeline-item.d.ts +7 -0
- package/dist/components/Timeline/duplicate-selected-timeline-item.js +32 -3
- package/dist/components/Timeline/timeline-video-filmstrip-times.d.ts +17 -0
- package/dist/components/Timeline/timeline-video-filmstrip-times.js +22 -0
- package/dist/components/import-assets.d.ts +11 -2
- package/dist/components/import-assets.js +61 -6
- package/dist/components/selected-outline-drag.d.ts +23 -0
- package/dist/components/selected-outline-drag.js +49 -1
- package/dist/error-overlay/remotion-overlay/Overlay.js +3 -0
- package/dist/esm/{chunk-t8fjnw2d.js → chunk-hrw9799x.js} +926 -578
- package/dist/esm/internals.mjs +926 -578
- package/dist/esm/previewEntry.mjs +10204 -9852
- package/dist/esm/renderEntry.mjs +1 -1
- package/dist/helpers/editor-guide-selection.js +1 -1
- package/dist/helpers/get-preview-file-type.js +1 -1
- package/dist/helpers/ruler-canvas-size.d.ts +5 -0
- package/dist/helpers/ruler-canvas-size.js +17 -0
- package/package.json +11 -11
|
@@ -8,6 +8,7 @@ const remotion_1 = require("remotion");
|
|
|
8
8
|
const timeline_layout_1 = require("../../helpers/timeline-layout");
|
|
9
9
|
const AudioWaveform_1 = require("../AudioWaveform");
|
|
10
10
|
const get_timeline_video_info_widths_1 = require("./get-timeline-video-info-widths");
|
|
11
|
+
const timeline_video_filmstrip_times_1 = require("./timeline-video-filmstrip-times");
|
|
11
12
|
const outerStyle = {
|
|
12
13
|
width: '100%',
|
|
13
14
|
height: '100%',
|
|
@@ -22,7 +23,8 @@ const filmstripContainerStyle = {
|
|
|
22
23
|
fontSize: 10,
|
|
23
24
|
fontFamily: 'Arial, Helvetica',
|
|
24
25
|
};
|
|
25
|
-
const
|
|
26
|
+
const MAX_FROZEN_FRAME_CACHE_DEVIATION = timeline_utils_1.WEBCODECS_TIMESCALE * 0.05;
|
|
27
|
+
const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore, durationInFrames, playbackRate, volume, doesVolumeChange, premountWidth, postmountWidth, loopDisplay, frozenMediaFrame, }) => {
|
|
26
28
|
const { fps } = (0, remotion_1.useVideoConfig)();
|
|
27
29
|
const ref = (0, react_1.useRef)(null);
|
|
28
30
|
const [error, setError] = (0, react_1.useState)(null);
|
|
@@ -53,6 +55,94 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
53
55
|
return;
|
|
54
56
|
}
|
|
55
57
|
current.appendChild(canvas);
|
|
58
|
+
const drawRepeatedFrame = (frame) => {
|
|
59
|
+
const thumbnailWidth = Math.max(1, frame.displayWidth / window.devicePixelRatio);
|
|
60
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
61
|
+
for (let x = 0; x < canvas.width; x += thumbnailWidth) {
|
|
62
|
+
ctx.drawImage(frame, x, 0, thumbnailWidth, timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
const getCachedFrozenFrame = (timestamp) => {
|
|
66
|
+
const prefix = (0, timeline_utils_1.getFrameDatabaseKeyPrefix)(src);
|
|
67
|
+
const keys = Array.from(timeline_utils_1.frameDatabase.keys()).filter((k) => k.startsWith(prefix));
|
|
68
|
+
let bestDistance = Infinity;
|
|
69
|
+
let bestFrame = null;
|
|
70
|
+
for (const key of keys) {
|
|
71
|
+
const frame = timeline_utils_1.frameDatabase.get(key);
|
|
72
|
+
if (!frame) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const distance = Math.abs((0, timeline_utils_1.getTimestampFromFrameDatabaseKey)(key) - timestamp);
|
|
76
|
+
if (distance < bestDistance) {
|
|
77
|
+
bestDistance = distance;
|
|
78
|
+
bestFrame = frame.frame;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return bestDistance <= MAX_FROZEN_FRAME_CACHE_DEVIATION
|
|
82
|
+
? bestFrame
|
|
83
|
+
: null;
|
|
84
|
+
};
|
|
85
|
+
const times = (0, timeline_video_filmstrip_times_1.getTimelineVideoFilmstripTimes)({
|
|
86
|
+
trimBefore,
|
|
87
|
+
durationInFrames,
|
|
88
|
+
playbackRate,
|
|
89
|
+
fps,
|
|
90
|
+
loopDisplay,
|
|
91
|
+
frozenMediaFrame,
|
|
92
|
+
});
|
|
93
|
+
if (times.type === 'frozen') {
|
|
94
|
+
const timestamp = times.timestampInSeconds * timeline_utils_1.WEBCODECS_TIMESCALE;
|
|
95
|
+
const cachedFrame = getCachedFrozenFrame(timestamp);
|
|
96
|
+
if (cachedFrame) {
|
|
97
|
+
drawRepeatedFrame(cachedFrame);
|
|
98
|
+
return () => {
|
|
99
|
+
current.removeChild(canvas);
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
(0, timeline_utils_1.extractFrames)({
|
|
103
|
+
timestampsInSeconds: ({ track, }) => {
|
|
104
|
+
aspectRatio.current = track.width / track.height;
|
|
105
|
+
timeline_utils_1.aspectRatioCache.set(src, aspectRatio.current);
|
|
106
|
+
return [times.timestampInSeconds];
|
|
107
|
+
},
|
|
108
|
+
src,
|
|
109
|
+
onVideoSample: (sample) => {
|
|
110
|
+
let frame;
|
|
111
|
+
try {
|
|
112
|
+
frame = sample.toVideoFrame();
|
|
113
|
+
const scale = (timeline_layout_1.TIMELINE_LAYER_FILMSTRIP_HEIGHT / frame.displayHeight) *
|
|
114
|
+
window.devicePixelRatio;
|
|
115
|
+
const transformed = (0, timeline_utils_1.resizeVideoFrame)({
|
|
116
|
+
frame,
|
|
117
|
+
scale,
|
|
118
|
+
});
|
|
119
|
+
if (transformed !== frame) {
|
|
120
|
+
frame.close();
|
|
121
|
+
}
|
|
122
|
+
frame = undefined;
|
|
123
|
+
const databaseKey = (0, timeline_utils_1.makeFrameDatabaseKey)(src, transformed.timestamp);
|
|
124
|
+
(0, timeline_utils_1.addFrameToCache)(databaseKey, transformed);
|
|
125
|
+
drawRepeatedFrame(transformed);
|
|
126
|
+
}
|
|
127
|
+
catch (e) {
|
|
128
|
+
if (frame) {
|
|
129
|
+
frame.close();
|
|
130
|
+
}
|
|
131
|
+
throw e;
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
sample.close();
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
signal: controller.signal,
|
|
138
|
+
}).catch((e) => {
|
|
139
|
+
setError(e);
|
|
140
|
+
});
|
|
141
|
+
return () => {
|
|
142
|
+
controller.abort();
|
|
143
|
+
current.removeChild(canvas);
|
|
144
|
+
};
|
|
145
|
+
}
|
|
56
146
|
const loopWidth = (0, timeline_utils_1.getLoopDisplayWidth)({
|
|
57
147
|
visualizationWidth: mediaNaturalWidth,
|
|
58
148
|
loopDisplay,
|
|
@@ -85,13 +175,7 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
85
175
|
};
|
|
86
176
|
// desired-timestamp -> filled-timestamp
|
|
87
177
|
const filledSlots = new Map();
|
|
88
|
-
const fromSeconds
|
|
89
|
-
const visibleDurationInFrames = shouldRepeatVideo && loopDisplay
|
|
90
|
-
? loopDisplay.durationInFrames
|
|
91
|
-
: durationInFrames;
|
|
92
|
-
// Trim is applied first, then playbackRate. Each composition frame
|
|
93
|
-
// advances the source video by `playbackRate` source frames.
|
|
94
|
-
const toSeconds = fromSeconds + (visibleDurationInFrames * playbackRate) / fps;
|
|
178
|
+
const { fromSeconds, toSeconds } = times;
|
|
95
179
|
const targetWidth = shouldRepeatVideo
|
|
96
180
|
? targetCanvas.width
|
|
97
181
|
: mediaNaturalWidth;
|
|
@@ -216,6 +300,7 @@ const TimelineVideoInfo = ({ src, visualizationWidth, naturalWidth, trimBefore,
|
|
|
216
300
|
durationInFrames,
|
|
217
301
|
error,
|
|
218
302
|
fps,
|
|
303
|
+
frozenMediaFrame,
|
|
219
304
|
loopDisplay,
|
|
220
305
|
mediaNaturalWidth,
|
|
221
306
|
mediaVisualizationWidth,
|
|
@@ -8,6 +8,13 @@ export declare const isDuplicatableSequenceRowSelection: (selection: TimelineSel
|
|
|
8
8
|
} & {
|
|
9
9
|
type: "sequence";
|
|
10
10
|
};
|
|
11
|
+
export declare const isDuplicatableEffectSelection: (selection: TimelineSelection) => selection is {
|
|
12
|
+
readonly type: "sequence-effect";
|
|
13
|
+
readonly nodePathInfo: SequenceNodePathInfo;
|
|
14
|
+
readonly i: number;
|
|
15
|
+
} & {
|
|
16
|
+
type: "sequence-effect";
|
|
17
|
+
};
|
|
11
18
|
export declare const duplicateSelectedTimelineItems: ({ selections, confirm, }: {
|
|
12
19
|
selections: readonly TimelineSelection[];
|
|
13
20
|
confirm: ConfirmationDialogFunction;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.duplicateSelectedTimelineItems = exports.isDuplicatableSequenceRowSelection = exports.duplicateSequencesFromSource = void 0;
|
|
3
|
+
exports.duplicateSelectedTimelineItems = exports.isDuplicatableEffectSelection = exports.isDuplicatableSequenceRowSelection = exports.duplicateSequencesFromSource = void 0;
|
|
4
4
|
const call_api_1 = require("../call-api");
|
|
5
5
|
const NotificationCenter_1 = require("../Notifications/NotificationCenter");
|
|
6
6
|
const confirmDuplicatingProgrammaticallyDuplicatedSequences = (nodePathInfos, confirm) => {
|
|
@@ -61,11 +61,40 @@ const duplicateSequencesFromSource = (nodePathInfos, confirm) => {
|
|
|
61
61
|
exports.duplicateSequencesFromSource = duplicateSequencesFromSource;
|
|
62
62
|
const isDuplicatableSequenceRowSelection = (selection) => selection.type === 'sequence';
|
|
63
63
|
exports.isDuplicatableSequenceRowSelection = isDuplicatableSequenceRowSelection;
|
|
64
|
+
const isDuplicatableEffectSelection = (selection) => selection.type === 'sequence-effect';
|
|
65
|
+
exports.isDuplicatableEffectSelection = isDuplicatableEffectSelection;
|
|
66
|
+
const duplicateEffectsFromSource = (effects) => {
|
|
67
|
+
return (0, call_api_1.callApi)('/api/duplicate-effect', effects.map((effect) => {
|
|
68
|
+
const nodePath = effect.nodePathInfo.sequenceSubscriptionKey;
|
|
69
|
+
return {
|
|
70
|
+
fileName: nodePath.absolutePath,
|
|
71
|
+
sequenceNodePath: nodePath,
|
|
72
|
+
effectIndex: effect.i,
|
|
73
|
+
};
|
|
74
|
+
}))
|
|
75
|
+
.then((result) => {
|
|
76
|
+
if (result.success) {
|
|
77
|
+
(0, NotificationCenter_1.showNotification)(effects.length === 1
|
|
78
|
+
? 'Duplicated effect in source file'
|
|
79
|
+
: 'Duplicated effects in source files', 2000);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
(0, NotificationCenter_1.showNotification)(result.reason, 4000);
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
.catch((err) => {
|
|
86
|
+
(0, NotificationCenter_1.showNotification)(err.message, 4000);
|
|
87
|
+
});
|
|
88
|
+
};
|
|
64
89
|
const duplicateSelectedTimelineItems = ({ selections, confirm, }) => {
|
|
65
90
|
const sequenceSelections = selections.filter(exports.isDuplicatableSequenceRowSelection);
|
|
66
|
-
if (sequenceSelections.length
|
|
91
|
+
if (sequenceSelections.length > 0) {
|
|
92
|
+
return (0, exports.duplicateSequencesFromSource)(sequenceSelections.map((selection) => selection.nodePathInfo), confirm);
|
|
93
|
+
}
|
|
94
|
+
const effectSelections = selections.filter(exports.isDuplicatableEffectSelection);
|
|
95
|
+
if (effectSelections.length === 0) {
|
|
67
96
|
return null;
|
|
68
97
|
}
|
|
69
|
-
return (
|
|
98
|
+
return duplicateEffectsFromSource(effectSelections);
|
|
70
99
|
};
|
|
71
100
|
exports.duplicateSelectedTimelineItems = duplicateSelectedTimelineItems;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { LoopDisplay } from 'remotion';
|
|
2
|
+
export type TimelineVideoFilmstripTimes = {
|
|
3
|
+
type: 'frozen';
|
|
4
|
+
timestampInSeconds: number;
|
|
5
|
+
} | {
|
|
6
|
+
type: 'range';
|
|
7
|
+
fromSeconds: number;
|
|
8
|
+
toSeconds: number;
|
|
9
|
+
};
|
|
10
|
+
export declare const getTimelineVideoFilmstripTimes: ({ trimBefore, durationInFrames, playbackRate, fps, loopDisplay, frozenMediaFrame, }: {
|
|
11
|
+
trimBefore: number;
|
|
12
|
+
durationInFrames: number;
|
|
13
|
+
playbackRate: number;
|
|
14
|
+
fps: number;
|
|
15
|
+
loopDisplay: LoopDisplay | undefined;
|
|
16
|
+
frozenMediaFrame: number | null;
|
|
17
|
+
}) => TimelineVideoFilmstripTimes;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTimelineVideoFilmstripTimes = void 0;
|
|
4
|
+
const timeline_utils_1 = require("@remotion/timeline-utils");
|
|
5
|
+
const getTimelineVideoFilmstripTimes = ({ trimBefore, durationInFrames, playbackRate, fps, loopDisplay, frozenMediaFrame, }) => {
|
|
6
|
+
if (frozenMediaFrame !== null) {
|
|
7
|
+
return {
|
|
8
|
+
type: 'frozen',
|
|
9
|
+
timestampInSeconds: Math.max(0, frozenMediaFrame / fps),
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
const fromSeconds = trimBefore / fps;
|
|
13
|
+
const visibleDurationInFrames = (0, timeline_utils_1.shouldTileLoopDisplay)(loopDisplay) && loopDisplay
|
|
14
|
+
? loopDisplay.durationInFrames
|
|
15
|
+
: durationInFrames;
|
|
16
|
+
return {
|
|
17
|
+
type: 'range',
|
|
18
|
+
fromSeconds,
|
|
19
|
+
toSeconds: fromSeconds + (visibleDurationInFrames * playbackRate) / fps,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
exports.getTimelineVideoFilmstripTimes = getTimelineVideoFilmstripTimes;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type ComponentProp, type FileType, type InsertableCompositionElementPosition } from '@remotion/studio-shared';
|
|
2
|
+
import type { Dimensions } from '../helpers/is-current-selected-still';
|
|
2
3
|
export type InsertElementDropPosition = {
|
|
3
4
|
readonly centerX: number;
|
|
4
5
|
readonly centerY: number;
|
|
@@ -8,7 +9,7 @@ export declare const getAssetElement: ({ fileType, src, }: {
|
|
|
8
9
|
src: string;
|
|
9
10
|
}) => {
|
|
10
11
|
type: "asset";
|
|
11
|
-
assetType: "audio" | "gif" | "image" | "video";
|
|
12
|
+
assetType: "animated-image" | "audio" | "gif" | "image" | "video";
|
|
12
13
|
src: string;
|
|
13
14
|
srcType: "remote" | "static";
|
|
14
15
|
dimensions: {
|
|
@@ -19,7 +20,7 @@ export declare const getAssetElement: ({ fileType, src, }: {
|
|
|
19
20
|
} | null;
|
|
20
21
|
export declare const getAssetElementFromPath: (assetPath: string) => {
|
|
21
22
|
type: "asset";
|
|
22
|
-
assetType: "audio" | "gif" | "image" | "video";
|
|
23
|
+
assetType: "animated-image" | "audio" | "gif" | "image" | "video";
|
|
23
24
|
src: string;
|
|
24
25
|
srcType: "remote" | "static";
|
|
25
26
|
dimensions: {
|
|
@@ -28,6 +29,13 @@ export declare const getAssetElementFromPath: (assetPath: string) => {
|
|
|
28
29
|
} | null;
|
|
29
30
|
position: InsertableCompositionElementPosition | null;
|
|
30
31
|
} | null;
|
|
32
|
+
export declare const getComponentDimensions: (component: {
|
|
33
|
+
componentName: string;
|
|
34
|
+
dimensions?: import("@remotion/studio-shared").ComponentDimensions | undefined;
|
|
35
|
+
importName: string;
|
|
36
|
+
importPath: string;
|
|
37
|
+
props: ComponentProp[];
|
|
38
|
+
}) => Dimensions | null;
|
|
31
39
|
export declare const pickFilesToImport: () => Promise<File[]>;
|
|
32
40
|
export declare const importAssets: ({ compositionFile, compositionId, dropPosition, files, }: {
|
|
33
41
|
compositionFile: string;
|
|
@@ -55,6 +63,7 @@ export declare const insertExistingAssets: ({ assetPaths, compositionFile, compo
|
|
|
55
63
|
export declare const insertComponent: ({ component, compositionFile, compositionId, dropPosition, }: {
|
|
56
64
|
component: {
|
|
57
65
|
componentName: string;
|
|
66
|
+
dimensions?: import("@remotion/studio-shared").ComponentDimensions | undefined;
|
|
58
67
|
importName: string;
|
|
59
68
|
importPath: string;
|
|
60
69
|
props: ComponentProp[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.insertComponent = exports.insertExistingAssets = exports.insertRemoteAudio = exports.importRemoteAsset = exports.importAssets = exports.pickFilesToImport = exports.getAssetElementFromPath = exports.getAssetElement = void 0;
|
|
3
|
+
exports.insertComponent = exports.insertExistingAssets = exports.insertRemoteAudio = exports.importRemoteAsset = exports.importAssets = exports.pickFilesToImport = exports.getComponentDimensions = exports.getAssetElementFromPath = exports.getAssetElement = void 0;
|
|
4
4
|
const media_utils_1 = require("@remotion/media-utils");
|
|
5
5
|
const studio_shared_1 = require("@remotion/studio-shared");
|
|
6
6
|
const remotion_1 = require("remotion");
|
|
@@ -23,6 +23,16 @@ const getAssetElement = ({ fileType, src, }) => {
|
|
|
23
23
|
position: null,
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
|
+
if (fileType.type === 'apng') {
|
|
27
|
+
return {
|
|
28
|
+
type: 'asset',
|
|
29
|
+
assetType: 'animated-image',
|
|
30
|
+
src,
|
|
31
|
+
srcType: 'static',
|
|
32
|
+
dimensions: fileType.dimensions,
|
|
33
|
+
position: null,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
26
36
|
if (fileType.type === 'gif') {
|
|
27
37
|
return {
|
|
28
38
|
type: 'asset',
|
|
@@ -81,6 +91,16 @@ const getAssetElementFromPath = (assetPath) => {
|
|
|
81
91
|
position: null,
|
|
82
92
|
};
|
|
83
93
|
}
|
|
94
|
+
if (extension === 'apng') {
|
|
95
|
+
return {
|
|
96
|
+
type: 'asset',
|
|
97
|
+
assetType: 'animated-image',
|
|
98
|
+
src: assetPath,
|
|
99
|
+
srcType: 'static',
|
|
100
|
+
dimensions: null,
|
|
101
|
+
position: null,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
84
104
|
if (extension === 'gif') {
|
|
85
105
|
return {
|
|
86
106
|
type: 'asset',
|
|
@@ -127,6 +147,9 @@ const getAssetLabel = (element) => {
|
|
|
127
147
|
if (element.assetType === 'gif') {
|
|
128
148
|
return '<Gif>';
|
|
129
149
|
}
|
|
150
|
+
if (element.assetType === 'animated-image') {
|
|
151
|
+
return '<AnimatedImage>';
|
|
152
|
+
}
|
|
130
153
|
if (element.assetType === 'audio') {
|
|
131
154
|
return '<Audio>';
|
|
132
155
|
}
|
|
@@ -155,6 +178,9 @@ const getComponentPropNumber = (props, name) => {
|
|
|
155
178
|
return typeof (prop === null || prop === void 0 ? void 0 : prop.value) === 'number' ? prop.value : null;
|
|
156
179
|
};
|
|
157
180
|
const getComponentDimensions = (component) => {
|
|
181
|
+
if (component.dimensions) {
|
|
182
|
+
return component.dimensions;
|
|
183
|
+
}
|
|
158
184
|
const width = getComponentPropNumber(component.props, 'width');
|
|
159
185
|
const height = getComponentPropNumber(component.props, 'height');
|
|
160
186
|
if (width !== null && height !== null) {
|
|
@@ -166,6 +192,7 @@ const getComponentDimensions = (component) => {
|
|
|
166
192
|
}
|
|
167
193
|
return null;
|
|
168
194
|
};
|
|
195
|
+
exports.getComponentDimensions = getComponentDimensions;
|
|
169
196
|
const getImageDimensions = ({ revokeObjectUrl, src, }) => {
|
|
170
197
|
return new Promise((resolve, reject) => {
|
|
171
198
|
const image = new Image();
|
|
@@ -199,6 +226,7 @@ const getFileDimensions = async ({ file, fileType, }) => {
|
|
|
199
226
|
fileType.type === 'jpeg' ||
|
|
200
227
|
fileType.type === 'webp' ||
|
|
201
228
|
fileType.type === 'bmp' ||
|
|
229
|
+
fileType.type === 'apng' ||
|
|
202
230
|
fileType.type === 'gif') {
|
|
203
231
|
if (fileType.dimensions) {
|
|
204
232
|
return fileType.dimensions;
|
|
@@ -225,7 +253,7 @@ const getStaticAssetDimensions = (assetPath) => {
|
|
|
225
253
|
const extension = (_a = assetPath.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
226
254
|
const src = (0, remotion_1.staticFile)(assetPath);
|
|
227
255
|
if (extension &&
|
|
228
|
-
['png', 'jpg', 'jpeg', 'webp', 'bmp', 'gif'].includes(extension)) {
|
|
256
|
+
['png', 'jpg', 'jpeg', 'webp', 'bmp', 'gif', 'apng'].includes(extension)) {
|
|
229
257
|
return getImageDimensions({ revokeObjectUrl: false, src });
|
|
230
258
|
}
|
|
231
259
|
if (extension &&
|
|
@@ -250,6 +278,33 @@ const getStaticAssetDimensionsOrNull = async (assetPath) => {
|
|
|
250
278
|
return null;
|
|
251
279
|
}
|
|
252
280
|
};
|
|
281
|
+
const getStaticAssetFileType = async (assetPath) => {
|
|
282
|
+
var _a;
|
|
283
|
+
const extension = (_a = assetPath.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
284
|
+
if (extension !== 'png' && extension !== 'apng') {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
try {
|
|
288
|
+
const response = await fetch((0, remotion_1.staticFile)(assetPath));
|
|
289
|
+
if (!response.ok) {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
return (0, studio_shared_1.detectFileType)(new Uint8Array(await response.arrayBuffer()));
|
|
293
|
+
}
|
|
294
|
+
catch (_b) {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
const getAssetElementFromStaticAsset = async (assetPath) => {
|
|
299
|
+
const fileType = await getStaticAssetFileType(assetPath);
|
|
300
|
+
if (fileType) {
|
|
301
|
+
const element = (0, exports.getAssetElement)({ fileType, src: assetPath });
|
|
302
|
+
if (element) {
|
|
303
|
+
return element;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return (0, exports.getAssetElementFromPath)(assetPath);
|
|
307
|
+
};
|
|
253
308
|
const pickFilesToImport = () => {
|
|
254
309
|
return new Promise((resolve) => {
|
|
255
310
|
const input = document.createElement('input');
|
|
@@ -456,18 +511,18 @@ const insertExistingAssets = async ({ assetPaths, compositionFile, compositionId
|
|
|
456
511
|
const unsupportedFiles = [];
|
|
457
512
|
try {
|
|
458
513
|
for (const assetPath of assetPaths) {
|
|
459
|
-
const element =
|
|
514
|
+
const element = await getAssetElementFromStaticAsset(assetPath);
|
|
460
515
|
if (element === null) {
|
|
461
516
|
unsupportedFiles.push(assetPath);
|
|
462
517
|
continue;
|
|
463
518
|
}
|
|
464
|
-
const dimensions = await getStaticAssetDimensionsOrNull(assetPath);
|
|
519
|
+
const dimensions = (_a = element.dimensions) !== null && _a !== void 0 ? _a : (await getStaticAssetDimensionsOrNull(assetPath));
|
|
465
520
|
const inserted = await insertAssetElement({
|
|
466
521
|
compositionFile,
|
|
467
522
|
compositionId,
|
|
468
523
|
element: {
|
|
469
524
|
...element,
|
|
470
|
-
dimensions
|
|
525
|
+
dimensions,
|
|
471
526
|
position: getCenteredPosition({
|
|
472
527
|
dimensions,
|
|
473
528
|
dropPosition,
|
|
@@ -499,7 +554,7 @@ const insertComponent = async ({ component, compositionFile, compositionId, drop
|
|
|
499
554
|
importPath: component.importPath,
|
|
500
555
|
props: component.props,
|
|
501
556
|
position: getCenteredPosition({
|
|
502
|
-
dimensions: getComponentDimensions(component),
|
|
557
|
+
dimensions: (0, exports.getComponentDimensions)(component),
|
|
503
558
|
dropPosition,
|
|
504
559
|
}),
|
|
505
560
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { GetDragOverrides, SequencePropsSubscriptionKey, SequenceSchema } from 'remotion';
|
|
2
2
|
import { type OutlinePoint } from './selected-outline-geometry';
|
|
3
3
|
import type { SelectedOutlineDragState, SelectedOutlineRotationDragState, SelectedOutlineRotationDragTarget, SelectedOutlineScaleDragState, SelectedOutlineScaleDragTarget, SelectedOutlineDragTarget } from './selected-outline-types';
|
|
4
|
+
import { type UvCoordinate } from './selected-outline-uv';
|
|
4
5
|
import type { SaveSequencePropChange } from './Timeline/save-sequence-prop';
|
|
5
6
|
export declare const getSelectedOutlineDragStates: ({ dragTargets, getDragOverrides, timelinePosition, }: {
|
|
6
7
|
readonly dragTargets: readonly SelectedOutlineDragTarget[];
|
|
@@ -114,4 +115,26 @@ export declare const compensateTranslateForTransformOrigin: ({ startTranslate, d
|
|
|
114
115
|
readonly scale: readonly [number, number];
|
|
115
116
|
}) => readonly [number, number];
|
|
116
117
|
export declare const uvsEqual: (left: readonly [number, number], right: readonly [number, number]) => boolean;
|
|
118
|
+
export type SelectedOutlineTransformOriginLockedAxis = 'x' | 'y' | null;
|
|
119
|
+
export declare const getSelectedOutlineTransformOriginLockedAxis: ({ axisLocked, dimensions, startUv, uv, }: {
|
|
120
|
+
readonly axisLocked: boolean;
|
|
121
|
+
readonly dimensions: {
|
|
122
|
+
readonly width: number;
|
|
123
|
+
readonly height: number;
|
|
124
|
+
};
|
|
125
|
+
readonly startUv: UvCoordinate;
|
|
126
|
+
readonly uv: UvCoordinate;
|
|
127
|
+
}) => SelectedOutlineTransformOriginLockedAxis;
|
|
128
|
+
export declare const applySelectedOutlineTransformOriginAxisLock: ({ lockedAxis, startUv, uv, }: {
|
|
129
|
+
readonly lockedAxis: SelectedOutlineTransformOriginLockedAxis;
|
|
130
|
+
readonly startUv: UvCoordinate;
|
|
131
|
+
readonly uv: UvCoordinate;
|
|
132
|
+
}) => UvCoordinate;
|
|
133
|
+
export declare const selectedOutlineTransformOriginSnapThresholdPx = 10;
|
|
134
|
+
export declare const snapSelectedOutlineTransformOriginUv: ({ point, points, thresholdPx, uv, }: {
|
|
135
|
+
readonly point: OutlinePoint;
|
|
136
|
+
readonly points: readonly [OutlinePoint, OutlinePoint, OutlinePoint, OutlinePoint];
|
|
137
|
+
readonly thresholdPx?: number | undefined;
|
|
138
|
+
readonly uv: UvCoordinate;
|
|
139
|
+
}) => UvCoordinate;
|
|
117
140
|
export {};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.uvsEqual = exports.compensateTranslateForTransformOrigin = exports.parseCssRotationToRadians = exports.clearSelectedOutlineRotationDragOverrides = exports.clearSelectedOutlineScaleDragOverrides = exports.getSelectedOutlineKeyboardNudgeDirection = exports.clearSelectedOutlineDragOverrides = exports.getSelectedOutlineRotationDragChanges = exports.getSelectedOutlineRotationDragValues = exports.getSelectedOutlineRotationDragStates = exports.getSelectedOutlineScaleDragChanges = exports.getSelectedOutlineScaleDragValues = exports.getSelectedOutlineScaleDragStates = exports.getSelectedOutlineScaleEdgeInfo = exports.getSelectedOutlineKeyboardNudgeDeltas = exports.getSelectedOutlineKeyboardNudgeDelta = exports.getSelectedOutlineDragChanges = exports.isSelectedOutlineDragPastThreshold = exports.applySelectedOutlineDragAxisLock = exports.getSelectedOutlineDragValues = exports.getSelectedOutlineDragStates = void 0;
|
|
3
|
+
exports.snapSelectedOutlineTransformOriginUv = exports.selectedOutlineTransformOriginSnapThresholdPx = exports.applySelectedOutlineTransformOriginAxisLock = exports.getSelectedOutlineTransformOriginLockedAxis = exports.uvsEqual = exports.compensateTranslateForTransformOrigin = exports.parseCssRotationToRadians = exports.clearSelectedOutlineRotationDragOverrides = exports.clearSelectedOutlineScaleDragOverrides = exports.getSelectedOutlineKeyboardNudgeDirection = exports.clearSelectedOutlineDragOverrides = exports.getSelectedOutlineRotationDragChanges = exports.getSelectedOutlineRotationDragValues = exports.getSelectedOutlineRotationDragStates = exports.getSelectedOutlineScaleDragChanges = exports.getSelectedOutlineScaleDragValues = exports.getSelectedOutlineScaleDragStates = exports.getSelectedOutlineScaleEdgeInfo = exports.getSelectedOutlineKeyboardNudgeDeltas = exports.getSelectedOutlineKeyboardNudgeDelta = exports.getSelectedOutlineDragChanges = exports.isSelectedOutlineDragPastThreshold = exports.applySelectedOutlineDragAxisLock = exports.getSelectedOutlineDragValues = exports.getSelectedOutlineDragStates = void 0;
|
|
4
4
|
const remotion_1 = require("remotion");
|
|
5
5
|
const no_react_1 = require("remotion/no-react");
|
|
6
6
|
const selected_outline_geometry_1 = require("./selected-outline-geometry");
|
|
7
7
|
const selected_outline_measurement_1 = require("./selected-outline-measurement");
|
|
8
8
|
const selected_outline_types_1 = require("./selected-outline-types");
|
|
9
|
+
const selected_outline_uv_1 = require("./selected-outline-uv");
|
|
9
10
|
const timeline_field_utils_1 = require("./Timeline/timeline-field-utils");
|
|
10
11
|
const timeline_rotation_utils_1 = require("./Timeline/timeline-rotation-utils");
|
|
11
12
|
const timeline_translate_utils_1 = require("./Timeline/timeline-translate-utils");
|
|
@@ -425,3 +426,50 @@ exports.compensateTranslateForTransformOrigin = compensateTranslateForTransformO
|
|
|
425
426
|
const uvsEqual = (left, right) => Math.abs(left[0] - right[0]) < 0.000001 &&
|
|
426
427
|
Math.abs(left[1] - right[1]) < 0.000001;
|
|
427
428
|
exports.uvsEqual = uvsEqual;
|
|
429
|
+
const getSelectedOutlineTransformOriginLockedAxis = ({ axisLocked, dimensions, startUv, uv, }) => {
|
|
430
|
+
if (!axisLocked) {
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
const deltaX = (uv[0] - startUv[0]) * dimensions.width;
|
|
434
|
+
const deltaY = (uv[1] - startUv[1]) * dimensions.height;
|
|
435
|
+
return Math.abs(deltaX) >= Math.abs(deltaY) ? 'x' : 'y';
|
|
436
|
+
};
|
|
437
|
+
exports.getSelectedOutlineTransformOriginLockedAxis = getSelectedOutlineTransformOriginLockedAxis;
|
|
438
|
+
const applySelectedOutlineTransformOriginAxisLock = ({ lockedAxis, startUv, uv, }) => {
|
|
439
|
+
if (lockedAxis === 'x') {
|
|
440
|
+
return [uv[0], startUv[1]];
|
|
441
|
+
}
|
|
442
|
+
if (lockedAxis === 'y') {
|
|
443
|
+
return [startUv[0], uv[1]];
|
|
444
|
+
}
|
|
445
|
+
return uv;
|
|
446
|
+
};
|
|
447
|
+
exports.applySelectedOutlineTransformOriginAxisLock = applySelectedOutlineTransformOriginAxisLock;
|
|
448
|
+
const transformOriginSnapTargets = [
|
|
449
|
+
[0, 0],
|
|
450
|
+
[0.5, 0],
|
|
451
|
+
[1, 0],
|
|
452
|
+
[1, 0.5],
|
|
453
|
+
[1, 1],
|
|
454
|
+
[0.5, 1],
|
|
455
|
+
[0, 1],
|
|
456
|
+
[0, 0.5],
|
|
457
|
+
[0.5, 0.5],
|
|
458
|
+
];
|
|
459
|
+
exports.selectedOutlineTransformOriginSnapThresholdPx = 10;
|
|
460
|
+
const snapSelectedOutlineTransformOriginUv = ({ point, points, thresholdPx = exports.selectedOutlineTransformOriginSnapThresholdPx, uv, }) => {
|
|
461
|
+
var _a;
|
|
462
|
+
let best = null;
|
|
463
|
+
for (const snapUv of transformOriginSnapTargets) {
|
|
464
|
+
const snapPoint = (0, selected_outline_uv_1.getUvHandlePosition)(points, snapUv);
|
|
465
|
+
const distance = Math.hypot(point.x - snapPoint.x, point.y - snapPoint.y);
|
|
466
|
+
if (distance > thresholdPx) {
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
if (best === null || distance < best.distance) {
|
|
470
|
+
best = { distance, uv: snapUv };
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return (_a = best === null || best === void 0 ? void 0 : best.uv) !== null && _a !== void 0 ? _a : uv;
|
|
474
|
+
};
|
|
475
|
+
exports.snapSelectedOutlineTransformOriginUv = snapSelectedOutlineTransformOriginUv;
|
|
@@ -4,6 +4,7 @@ exports.Overlay = exports.setErrorsRef = void 0;
|
|
|
4
4
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
5
5
|
const react_1 = require("react");
|
|
6
6
|
const remotion_1 = require("remotion");
|
|
7
|
+
const MenuToolbar_1 = require("../../components/MenuToolbar");
|
|
7
8
|
const keybindings_1 = require("../../state/keybindings");
|
|
8
9
|
const ErrorLoader_1 = require("./ErrorLoader");
|
|
9
10
|
exports.setErrorsRef = (0, react_1.createRef)();
|
|
@@ -43,6 +44,8 @@ const Overlay = () => {
|
|
|
43
44
|
backgroundColor: BACKGROUND_COLOR,
|
|
44
45
|
overflow: 'auto',
|
|
45
46
|
color: 'white',
|
|
47
|
+
top: MenuToolbar_1.MENU_TOOLBAR_HEIGHT,
|
|
48
|
+
height: `calc(100% - ${MenuToolbar_1.MENU_TOOLBAR_HEIGHT}px)`,
|
|
46
49
|
}, children: errors.errors.map((err, i) => {
|
|
47
50
|
var _a;
|
|
48
51
|
return (jsx_runtime_1.jsx(ErrorLoader_1.ErrorLoader
|