ugcinc-render 1.3.5
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/README.md +257 -0
- package/dist/index.d.mts +1200 -0
- package/dist/index.d.ts +1200 -0
- package/dist/index.js +1487 -0
- package/dist/index.mjs +1425 -0
- package/package.json +66 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,1200 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Base types used throughout the rendering system
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Time value - can be absolute (milliseconds) or relative (0-1 percentage)
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* // Absolute: 500 milliseconds
|
|
12
|
+
* { type: 'absolute', value: 500 }
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* // Relative: 50% of total duration
|
|
16
|
+
* { type: 'relative', value: 0.5 }
|
|
17
|
+
*/
|
|
18
|
+
interface TimeValue {
|
|
19
|
+
type: 'absolute' | 'relative';
|
|
20
|
+
value: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Border radius configuration for individual corners.
|
|
24
|
+
* All values in pixels, default 0 (no rounding).
|
|
25
|
+
*/
|
|
26
|
+
interface BorderRadiusConfig {
|
|
27
|
+
/** Top-left corner radius in pixels */
|
|
28
|
+
topLeft?: number;
|
|
29
|
+
/** Top-right corner radius in pixels */
|
|
30
|
+
topRight?: number;
|
|
31
|
+
/** Bottom-right corner radius in pixels */
|
|
32
|
+
bottomRight?: number;
|
|
33
|
+
/** Bottom-left corner radius in pixels */
|
|
34
|
+
bottomLeft?: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Fit mode for media (images/videos)
|
|
38
|
+
* - cover: Fill the area, cropping if necessary
|
|
39
|
+
* - contain: Fit within the area, letterboxing if necessary
|
|
40
|
+
* - fill: Stretch to fill the area exactly
|
|
41
|
+
*/
|
|
42
|
+
type FitMode = 'cover' | 'contain' | 'fill';
|
|
43
|
+
/**
|
|
44
|
+
* Segment type identifiers
|
|
45
|
+
*/
|
|
46
|
+
type SegmentType = 'video' | 'image' | 'text' | 'audio' | 'editor';
|
|
47
|
+
/**
|
|
48
|
+
* Font type identifiers
|
|
49
|
+
*/
|
|
50
|
+
type FontType = 'arial' | 'tiktok' | 'apple';
|
|
51
|
+
/**
|
|
52
|
+
* Font weight options
|
|
53
|
+
*/
|
|
54
|
+
type FontWeight = 'normal' | 'bold';
|
|
55
|
+
/**
|
|
56
|
+
* Text alignment options
|
|
57
|
+
*/
|
|
58
|
+
type TextAlignment = 'left' | 'center' | 'right' | 'justify';
|
|
59
|
+
/**
|
|
60
|
+
* Vertical alignment options
|
|
61
|
+
*/
|
|
62
|
+
type VerticalAlignment = 'top' | 'middle' | 'bottom';
|
|
63
|
+
/**
|
|
64
|
+
* Text direction
|
|
65
|
+
*/
|
|
66
|
+
type TextDirection = 'ltr' | 'rtl';
|
|
67
|
+
/**
|
|
68
|
+
* Text wrapping mode
|
|
69
|
+
*/
|
|
70
|
+
type TextWrap = 'word' | 'char' | 'none';
|
|
71
|
+
/**
|
|
72
|
+
* Word break behavior
|
|
73
|
+
*/
|
|
74
|
+
type WordBreak = 'normal' | 'break-all' | 'break-word';
|
|
75
|
+
/**
|
|
76
|
+
* Hyphenation mode
|
|
77
|
+
*/
|
|
78
|
+
type Hyphenation = 'none' | 'auto';
|
|
79
|
+
/**
|
|
80
|
+
* Text overflow behavior
|
|
81
|
+
*/
|
|
82
|
+
type TextOverflow = 'clip' | 'ellipsis';
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Position and anchor types for relative element positioning
|
|
86
|
+
*/
|
|
87
|
+
/**
|
|
88
|
+
* Vertical anchor for Y positioning (parent element)
|
|
89
|
+
* Specifies which vertical edge of the reference element to anchor to
|
|
90
|
+
*/
|
|
91
|
+
type VerticalAnchor = 'top' | 'bottom';
|
|
92
|
+
/**
|
|
93
|
+
* Horizontal anchor for X positioning (parent element)
|
|
94
|
+
* Specifies which horizontal edge of the reference element to anchor to
|
|
95
|
+
*/
|
|
96
|
+
type HorizontalAnchor = 'left' | 'right';
|
|
97
|
+
/**
|
|
98
|
+
* Self anchor for X positioning
|
|
99
|
+
* Specifies which horizontal edge of THIS element to use for positioning
|
|
100
|
+
*/
|
|
101
|
+
type HorizontalSelfAnchor = 'left' | 'center' | 'right';
|
|
102
|
+
/**
|
|
103
|
+
* Self anchor for Y positioning
|
|
104
|
+
* Specifies which vertical edge of THIS element to use for positioning
|
|
105
|
+
*/
|
|
106
|
+
type VerticalSelfAnchor = 'top' | 'middle' | 'bottom';
|
|
107
|
+
/**
|
|
108
|
+
* Relative X position configuration
|
|
109
|
+
* When set, the segment's X position is calculated relative to another segment
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* // Position this segment to the right of another segment with 10px gap
|
|
113
|
+
* { elementId: 'other-element', anchor: 'right', selfAnchor: 'left', offset: 10 }
|
|
114
|
+
*/
|
|
115
|
+
interface RelativePositionConfigX {
|
|
116
|
+
/** ID of the segment to position relative to */
|
|
117
|
+
elementId: string;
|
|
118
|
+
/** Which horizontal edge of the reference segment to anchor to */
|
|
119
|
+
anchor: HorizontalAnchor;
|
|
120
|
+
/** Which horizontal edge of THIS segment to use (default: opposite of anchor) */
|
|
121
|
+
selfAnchor?: HorizontalSelfAnchor;
|
|
122
|
+
/** Offset in pixels from the anchor point */
|
|
123
|
+
offset: number;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Relative Y position configuration
|
|
127
|
+
* When set, the segment's Y position is calculated relative to another segment
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* // Position this segment below another segment with a 10px gap
|
|
131
|
+
* { elementId: 'message-1', anchor: 'bottom', selfAnchor: 'top', offset: 10 }
|
|
132
|
+
*/
|
|
133
|
+
interface RelativePositionConfigY {
|
|
134
|
+
/** ID of the segment to position relative to */
|
|
135
|
+
elementId: string;
|
|
136
|
+
/** Which vertical edge of the reference segment to anchor to */
|
|
137
|
+
anchor: VerticalAnchor;
|
|
138
|
+
/** Which vertical edge of THIS segment to use (default: opposite of anchor) */
|
|
139
|
+
selfAnchor?: VerticalSelfAnchor;
|
|
140
|
+
/** Offset in pixels from the anchor point */
|
|
141
|
+
offset: number;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Dynamic cropping configuration types
|
|
146
|
+
*
|
|
147
|
+
* Dynamic cropping allows the output dimensions to be calculated
|
|
148
|
+
* based on element positions at render time.
|
|
149
|
+
*/
|
|
150
|
+
/**
|
|
151
|
+
* Crop boundary - can be static (element ID) or dynamic (input reference)
|
|
152
|
+
*/
|
|
153
|
+
interface CropBoundary {
|
|
154
|
+
/** Static: reference a specific element by ID */
|
|
155
|
+
elementId?: string;
|
|
156
|
+
/** Variable: get element ID from input (creates an input port) */
|
|
157
|
+
inputRef?: string;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Configuration for cropping along one axis (vertical = height, horizontal = width)
|
|
161
|
+
*/
|
|
162
|
+
interface CropAxisConfig {
|
|
163
|
+
/** Whether cropping is enabled for this axis */
|
|
164
|
+
enabled: boolean;
|
|
165
|
+
/**
|
|
166
|
+
* Crop mode:
|
|
167
|
+
* - 'all-elements': Crop to bounding box of all visible elements
|
|
168
|
+
* - 'between-elements': Crop between specific boundary elements
|
|
169
|
+
*/
|
|
170
|
+
mode: 'all-elements' | 'between-elements';
|
|
171
|
+
/** Top/left element boundary (between-elements mode only) */
|
|
172
|
+
startBoundary?: CropBoundary;
|
|
173
|
+
/** Bottom/right element boundary (between-elements mode only) */
|
|
174
|
+
endBoundary?: CropBoundary;
|
|
175
|
+
/** Padding before (top/left) in pixels */
|
|
176
|
+
paddingStart?: number;
|
|
177
|
+
/** Padding after (bottom/right) in pixels */
|
|
178
|
+
paddingEnd?: number;
|
|
179
|
+
/** Minimum dimension (prevents cropping too small) */
|
|
180
|
+
minSize?: number;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Dynamic crop configuration for image/video editor
|
|
184
|
+
*/
|
|
185
|
+
interface DynamicCropConfig {
|
|
186
|
+
/** Crop height based on elements */
|
|
187
|
+
vertical?: CropAxisConfig;
|
|
188
|
+
/** Crop width based on elements */
|
|
189
|
+
horizontal?: CropAxisConfig;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Result of crop bounds calculation
|
|
193
|
+
*/
|
|
194
|
+
interface CropBounds {
|
|
195
|
+
/** Left edge of crop area */
|
|
196
|
+
x: number;
|
|
197
|
+
/** Top edge of crop area */
|
|
198
|
+
y: number;
|
|
199
|
+
/** Width of cropped output */
|
|
200
|
+
width: number;
|
|
201
|
+
/** Height of cropped output */
|
|
202
|
+
height: number;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Raw element types for editor input
|
|
207
|
+
*
|
|
208
|
+
* These types represent the raw configuration that users define in the editor.
|
|
209
|
+
* They include relative positioning which gets resolved to absolute positions
|
|
210
|
+
* before rendering.
|
|
211
|
+
*/
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Dimension preset keys for image editor
|
|
215
|
+
*/
|
|
216
|
+
type DimensionPresetKey = 'tiktok' | 'instagram-square' | 'instagram-post' | 'youtube' | 'twitter' | 'custom';
|
|
217
|
+
/**
|
|
218
|
+
* Dimension preset configuration
|
|
219
|
+
*/
|
|
220
|
+
interface DimensionPreset {
|
|
221
|
+
width: number;
|
|
222
|
+
height: number;
|
|
223
|
+
label: string;
|
|
224
|
+
ratio: string;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Standard dimension presets
|
|
228
|
+
*/
|
|
229
|
+
declare const DIMENSION_PRESETS: Record<Exclude<DimensionPresetKey, 'custom'>, DimensionPreset>;
|
|
230
|
+
/**
|
|
231
|
+
* Image editor element - a raw image or text layer in the editor
|
|
232
|
+
*
|
|
233
|
+
* This is the input format that includes relative positioning.
|
|
234
|
+
* It gets resolved to absolute positions before being converted to segments.
|
|
235
|
+
*/
|
|
236
|
+
interface ImageEditorElement {
|
|
237
|
+
/** Unique element identifier */
|
|
238
|
+
id: string;
|
|
239
|
+
/** Element type */
|
|
240
|
+
type: 'image' | 'text';
|
|
241
|
+
/** X position in pixels (may be overridden by relativePositionX) */
|
|
242
|
+
x: number;
|
|
243
|
+
/** Y position in pixels (may be overridden by relativePositionY) */
|
|
244
|
+
y: number;
|
|
245
|
+
/** Width in pixels */
|
|
246
|
+
width: number;
|
|
247
|
+
/** Height in pixels */
|
|
248
|
+
height: number;
|
|
249
|
+
/** Z-index for layering */
|
|
250
|
+
zIndex: number;
|
|
251
|
+
/** Rotation in degrees clockwise */
|
|
252
|
+
rotation?: number;
|
|
253
|
+
/** Whether the element is locked from editing */
|
|
254
|
+
locked?: boolean;
|
|
255
|
+
/** Relative X positioning config - when set, x is calculated from the reference element */
|
|
256
|
+
relativePositionX?: RelativePositionConfigX;
|
|
257
|
+
/** Relative Y positioning config - when set, y is calculated from the reference element */
|
|
258
|
+
relativePositionY?: RelativePositionConfigY;
|
|
259
|
+
/** Text content */
|
|
260
|
+
text?: string;
|
|
261
|
+
/** Maps to text input port for variable text (e.g., "text_1") */
|
|
262
|
+
textInputId?: string;
|
|
263
|
+
/** Text color (hex) */
|
|
264
|
+
color?: string;
|
|
265
|
+
/** Outline width in pixels (0 = no outline) */
|
|
266
|
+
outlineWidth?: number;
|
|
267
|
+
/** Outline color */
|
|
268
|
+
strokeColor?: string;
|
|
269
|
+
/** Font family */
|
|
270
|
+
font?: FontType;
|
|
271
|
+
/** Font size in pixels */
|
|
272
|
+
fontSize?: number;
|
|
273
|
+
/** Font weight */
|
|
274
|
+
fontWeight?: FontWeight;
|
|
275
|
+
/** Line height multiplier */
|
|
276
|
+
lineHeight?: number;
|
|
277
|
+
/** Letter spacing in pixels */
|
|
278
|
+
letterSpacing?: number;
|
|
279
|
+
/** Horizontal text alignment */
|
|
280
|
+
textAlign?: TextAlignment;
|
|
281
|
+
/** Vertical text alignment within bounds */
|
|
282
|
+
verticalAlign?: VerticalAlignment;
|
|
283
|
+
/** Background color for text box (hex) */
|
|
284
|
+
backgroundColor?: string;
|
|
285
|
+
/** Background opacity 0-100 */
|
|
286
|
+
backgroundOpacity?: number;
|
|
287
|
+
/** Corner radius for background box */
|
|
288
|
+
backgroundBorderRadius?: BorderRadiusConfig;
|
|
289
|
+
paddingTop?: number;
|
|
290
|
+
paddingRight?: number;
|
|
291
|
+
paddingBottom?: number;
|
|
292
|
+
paddingLeft?: number;
|
|
293
|
+
/** When true, box shrinks to fit content (width becomes max width) */
|
|
294
|
+
autoWidth?: boolean;
|
|
295
|
+
/** Which side the box anchors to when autoWidth is true */
|
|
296
|
+
boxAlign?: 'left' | 'center' | 'right';
|
|
297
|
+
/** Maps to input port (e.g., "image_1", "image_2") */
|
|
298
|
+
inputId?: string;
|
|
299
|
+
/** How the image fits its container */
|
|
300
|
+
fit?: FitMode;
|
|
301
|
+
/** Opacity percentage 0-100 */
|
|
302
|
+
opacity?: number;
|
|
303
|
+
/** Corner radius - single number for all corners, or object for individual */
|
|
304
|
+
borderRadius?: number | BorderRadiusConfig;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Image editor node configuration
|
|
308
|
+
*
|
|
309
|
+
* This is the complete configuration for an image editor node,
|
|
310
|
+
* including canvas dimensions, elements, and crop settings.
|
|
311
|
+
*/
|
|
312
|
+
interface ImageEditorNodeConfig {
|
|
313
|
+
/** Canvas width in pixels */
|
|
314
|
+
width: number;
|
|
315
|
+
/** Canvas height in pixels */
|
|
316
|
+
height: number;
|
|
317
|
+
/** Aspect ratio string (e.g., "9:16") */
|
|
318
|
+
aspectRatio: string;
|
|
319
|
+
/** Dimension preset key */
|
|
320
|
+
dimensionPreset: DimensionPresetKey;
|
|
321
|
+
/** Elements to render */
|
|
322
|
+
elements: ImageEditorElement[];
|
|
323
|
+
/** How the background image fits the canvas */
|
|
324
|
+
backgroundFit?: FitMode;
|
|
325
|
+
/** Cached background image URL for consistent preview */
|
|
326
|
+
previewBackgroundUrl?: string;
|
|
327
|
+
/** Cached image URLs for image elements (keyed by inputId) */
|
|
328
|
+
previewImageUrls?: Record<string, string>;
|
|
329
|
+
/** Cached text values for text elements (keyed by textInputId) */
|
|
330
|
+
previewTextValues?: Record<string, string>;
|
|
331
|
+
/** Dynamic cropping configuration */
|
|
332
|
+
dynamicCrop?: DynamicCropConfig;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Video editor types for rendering
|
|
337
|
+
*/
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* UI helper for timing mode
|
|
341
|
+
*/
|
|
342
|
+
type TimeMode = 'fixed' | 'flexible';
|
|
343
|
+
/**
|
|
344
|
+
* Base properties for all video editor segments
|
|
345
|
+
*/
|
|
346
|
+
interface VideoEditorBaseSegment {
|
|
347
|
+
id: string;
|
|
348
|
+
order: number;
|
|
349
|
+
offset: TimeValue;
|
|
350
|
+
duration?: TimeValue;
|
|
351
|
+
startTrim?: number;
|
|
352
|
+
endTrim?: number;
|
|
353
|
+
timeMode?: TimeMode;
|
|
354
|
+
parentId?: string;
|
|
355
|
+
relativeStart?: number;
|
|
356
|
+
relativeEnd?: number;
|
|
357
|
+
fadeIn?: number;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Base properties for visual segments
|
|
361
|
+
*/
|
|
362
|
+
interface VideoEditorVisualSegment extends VideoEditorBaseSegment {
|
|
363
|
+
xOffset: number;
|
|
364
|
+
yOffset: number;
|
|
365
|
+
width: number;
|
|
366
|
+
height: number;
|
|
367
|
+
zIndex?: number;
|
|
368
|
+
scale?: number;
|
|
369
|
+
rotation?: number;
|
|
370
|
+
opacity?: number;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Video segment
|
|
374
|
+
*/
|
|
375
|
+
interface VideoEditorVideoSegment extends VideoEditorVisualSegment {
|
|
376
|
+
type: 'video';
|
|
377
|
+
inputRef?: string;
|
|
378
|
+
source?: string;
|
|
379
|
+
fit?: FitMode;
|
|
380
|
+
speed?: number;
|
|
381
|
+
volume?: number;
|
|
382
|
+
borderRadius?: number | BorderRadiusConfig;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Audio segment
|
|
386
|
+
*/
|
|
387
|
+
interface VideoEditorAudioSegment extends VideoEditorBaseSegment {
|
|
388
|
+
type: 'audio';
|
|
389
|
+
inputRef?: string;
|
|
390
|
+
source?: string;
|
|
391
|
+
volume?: number;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* Image segment
|
|
395
|
+
*/
|
|
396
|
+
interface VideoEditorImageSegment extends VideoEditorVisualSegment {
|
|
397
|
+
type: 'image';
|
|
398
|
+
inputRef?: string;
|
|
399
|
+
source?: string;
|
|
400
|
+
fit?: FitMode;
|
|
401
|
+
loop?: boolean;
|
|
402
|
+
borderRadius?: number | BorderRadiusConfig;
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Text segment
|
|
406
|
+
*/
|
|
407
|
+
interface VideoEditorTextSegment extends VideoEditorVisualSegment {
|
|
408
|
+
type: 'text';
|
|
409
|
+
textInputRef?: string;
|
|
410
|
+
text?: string;
|
|
411
|
+
alignment?: 'left' | 'center' | 'right' | 'justify';
|
|
412
|
+
verticalAlign?: 'top' | 'middle' | 'bottom';
|
|
413
|
+
direction?: 'ltr' | 'rtl';
|
|
414
|
+
padding?: number;
|
|
415
|
+
fontType?: 'tiktok' | 'apple' | 'arial';
|
|
416
|
+
fontSize?: number;
|
|
417
|
+
fontWeight?: 'normal' | 'bold';
|
|
418
|
+
lineHeight?: number;
|
|
419
|
+
letterSpacing?: number;
|
|
420
|
+
textWrap?: 'word' | 'char' | 'none';
|
|
421
|
+
wordBreak?: 'normal' | 'break-all' | 'break-word';
|
|
422
|
+
hyphenation?: 'none' | 'auto';
|
|
423
|
+
maxLines?: number;
|
|
424
|
+
textOverflow?: 'clip' | 'ellipsis';
|
|
425
|
+
ellipsis?: string;
|
|
426
|
+
color?: string;
|
|
427
|
+
backgroundColor?: string;
|
|
428
|
+
strokeColor?: string;
|
|
429
|
+
strokeWidth?: number;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Union of all video editor segment types
|
|
433
|
+
*/
|
|
434
|
+
type VideoEditorSegment = VideoEditorVideoSegment | VideoEditorAudioSegment | VideoEditorImageSegment | VideoEditorTextSegment;
|
|
435
|
+
/**
|
|
436
|
+
* Video editor channel
|
|
437
|
+
*/
|
|
438
|
+
interface VideoEditorChannel {
|
|
439
|
+
id: string;
|
|
440
|
+
name: string;
|
|
441
|
+
segments: VideoEditorSegment[];
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Video editor node configuration
|
|
445
|
+
*/
|
|
446
|
+
interface VideoEditorNodeConfig {
|
|
447
|
+
width: number;
|
|
448
|
+
height: number;
|
|
449
|
+
fps: number;
|
|
450
|
+
duration?: number;
|
|
451
|
+
dimensionPreset: DimensionPresetKey;
|
|
452
|
+
channels: VideoEditorChannel[];
|
|
453
|
+
previewUrls?: Record<string, string>;
|
|
454
|
+
previewTextValues?: Record<string, string>;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Segment types for the rendering system
|
|
459
|
+
*
|
|
460
|
+
* Segments are the building blocks of compositions - they represent
|
|
461
|
+
* individual elements like text, images, videos, and audio.
|
|
462
|
+
*/
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Base properties for all segments
|
|
466
|
+
*/
|
|
467
|
+
interface BaseSegment {
|
|
468
|
+
/** Unique segment identifier */
|
|
469
|
+
id: string;
|
|
470
|
+
/** Segment type */
|
|
471
|
+
type: SegmentType;
|
|
472
|
+
/** Public URL to media file (empty string for text/editor segments) */
|
|
473
|
+
source: string;
|
|
474
|
+
/** Sequence order within channel (0-based) */
|
|
475
|
+
order: number;
|
|
476
|
+
/** Time offset after previous segment starts */
|
|
477
|
+
offset: TimeValue;
|
|
478
|
+
/** Trim from start in milliseconds (default: 0) */
|
|
479
|
+
startTrim?: number;
|
|
480
|
+
/** Trim from end in milliseconds (default: 0) */
|
|
481
|
+
endTrim?: number;
|
|
482
|
+
/** Override segment duration (auto-calculated if omitted) */
|
|
483
|
+
duration?: TimeValue;
|
|
484
|
+
/** ID of the parent segment this overlays (timing calculated relative to parent) */
|
|
485
|
+
parentId?: string;
|
|
486
|
+
/** Start time as fraction of parent duration (0-1, default: 0). Only used when parentId is set. */
|
|
487
|
+
relativeStart?: number;
|
|
488
|
+
/** End time as fraction of parent duration (0-1, default: 1). Only used when parentId is set. */
|
|
489
|
+
relativeEnd?: number;
|
|
490
|
+
/** Duration in milliseconds for the fade-in effect (0 or undefined = no fade) */
|
|
491
|
+
fadeIn?: number;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Visual segment properties (video, image, text)
|
|
495
|
+
*/
|
|
496
|
+
interface VisualSegment extends BaseSegment {
|
|
497
|
+
type: 'video' | 'image' | 'text';
|
|
498
|
+
/** Horizontal position from left edge in pixels */
|
|
499
|
+
xOffset: number;
|
|
500
|
+
/** Vertical position from top edge in pixels */
|
|
501
|
+
yOffset: number;
|
|
502
|
+
/** Width in pixels */
|
|
503
|
+
width: number;
|
|
504
|
+
/** Height in pixels */
|
|
505
|
+
height: number;
|
|
506
|
+
/** Layer order - higher values appear on top (default: 0) */
|
|
507
|
+
zIndex?: number;
|
|
508
|
+
/** Scale multiplier (1.0 = 100%, 2.0 = 200%) (default: 1) */
|
|
509
|
+
scale?: number;
|
|
510
|
+
/** Rotation in degrees clockwise (default: 0) */
|
|
511
|
+
rotation?: number;
|
|
512
|
+
/** Opacity percentage 0-100 (default: 100) */
|
|
513
|
+
opacity?: number;
|
|
514
|
+
/** Relative X positioning - when set, xOffset is calculated from the reference segment */
|
|
515
|
+
relativePositionX?: RelativePositionConfigX;
|
|
516
|
+
/** Relative Y positioning - when set, yOffset is calculated from the reference segment */
|
|
517
|
+
relativePositionY?: RelativePositionConfigY;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Picture segment properties (shared by video and image)
|
|
521
|
+
*/
|
|
522
|
+
interface PictureSegment extends VisualSegment {
|
|
523
|
+
type: 'video' | 'image';
|
|
524
|
+
/** How media fits in bounds: cover (fill+crop), contain (fit+letterbox), fill (stretch) (default: 'cover') */
|
|
525
|
+
fit?: FitMode;
|
|
526
|
+
/** Playback speed multiplier (0.5 = half speed, 2.0 = double speed) (default: 1) */
|
|
527
|
+
speed?: number;
|
|
528
|
+
/** Corner radius - single number for all corners, or object for individual corners (default: 0) */
|
|
529
|
+
borderRadius?: number | BorderRadiusConfig;
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Video segment - displays video content with optional audio
|
|
533
|
+
*/
|
|
534
|
+
interface VideoSegment extends PictureSegment {
|
|
535
|
+
type: 'video';
|
|
536
|
+
/** Audio volume percentage 0-100 (0 = muted, 100 = full) (default: 100) */
|
|
537
|
+
volume?: number;
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Image segment - static images or animated GIFs
|
|
541
|
+
*/
|
|
542
|
+
interface ImageSegment extends PictureSegment {
|
|
543
|
+
type: 'image';
|
|
544
|
+
/** Loop animated GIFs (default: false) */
|
|
545
|
+
loop?: boolean;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Text segment - rich text overlays with full typography control
|
|
549
|
+
*/
|
|
550
|
+
interface TextSegment extends VisualSegment {
|
|
551
|
+
type: 'text';
|
|
552
|
+
source: '';
|
|
553
|
+
/** The text content (supports emojis) */
|
|
554
|
+
text: string;
|
|
555
|
+
/** Horizontal alignment (default: 'left') */
|
|
556
|
+
alignment?: TextAlignment;
|
|
557
|
+
/** Vertical alignment within bounds (default: 'top') */
|
|
558
|
+
verticalAlign?: VerticalAlignment;
|
|
559
|
+
/** Text direction (default: 'ltr') */
|
|
560
|
+
direction?: TextDirection;
|
|
561
|
+
/** Inner padding in pixels - uniform for all sides (default: 0). Overridden by individual padding values if set. */
|
|
562
|
+
padding?: number;
|
|
563
|
+
/** Top padding in pixels (overrides uniform padding) */
|
|
564
|
+
paddingTop?: number;
|
|
565
|
+
/** Right padding in pixels (overrides uniform padding) */
|
|
566
|
+
paddingRight?: number;
|
|
567
|
+
/** Bottom padding in pixels (overrides uniform padding) */
|
|
568
|
+
paddingBottom?: number;
|
|
569
|
+
/** Left padding in pixels (overrides uniform padding) */
|
|
570
|
+
paddingLeft?: number;
|
|
571
|
+
/** Font family (default: 'arial') */
|
|
572
|
+
fontType?: FontType;
|
|
573
|
+
/** Font size in pixels (default: 40) */
|
|
574
|
+
fontSize?: number;
|
|
575
|
+
/** Font weight (default: 'normal') */
|
|
576
|
+
fontWeight?: FontWeight;
|
|
577
|
+
/** Line height multiplier (default: 1.2) */
|
|
578
|
+
lineHeight?: number;
|
|
579
|
+
/** Letter spacing in pixels (default: 0) */
|
|
580
|
+
letterSpacing?: number;
|
|
581
|
+
/** How text wraps to new lines (default: 'word') */
|
|
582
|
+
textWrap?: TextWrap;
|
|
583
|
+
/** How words break across lines (default: 'normal') */
|
|
584
|
+
wordBreak?: WordBreak;
|
|
585
|
+
/** Automatic hyphenation (default: 'none') */
|
|
586
|
+
hyphenation?: Hyphenation;
|
|
587
|
+
/** Maximum lines (0 = unlimited) (default: 0) */
|
|
588
|
+
maxLines?: number;
|
|
589
|
+
/** How overflow is handled (default: 'clip') */
|
|
590
|
+
textOverflow?: TextOverflow;
|
|
591
|
+
/** Ellipsis string for overflow (default: '...') */
|
|
592
|
+
ellipsis?: string;
|
|
593
|
+
/** Text color (default: '#000000') */
|
|
594
|
+
color?: string;
|
|
595
|
+
/** Background color in hex format #RRGGBB (default: transparent) */
|
|
596
|
+
backgroundColor?: string;
|
|
597
|
+
/** Background opacity 0-100 (default: 100) */
|
|
598
|
+
backgroundOpacity?: number;
|
|
599
|
+
/** Border radius for background box - individual corners (default: 0) */
|
|
600
|
+
backgroundBorderRadius?: BorderRadiusConfig;
|
|
601
|
+
/** Text outline color (default: none) */
|
|
602
|
+
strokeColor?: string;
|
|
603
|
+
/** Outline width in pixels (default: 0) */
|
|
604
|
+
strokeWidth?: number;
|
|
605
|
+
/** When true, box shrinks to fit content (width becomes max width) */
|
|
606
|
+
autoWidth?: boolean;
|
|
607
|
+
/** Which side the box anchors to when autoWidth is true (default: 'left') */
|
|
608
|
+
boxAlign?: 'left' | 'center' | 'right';
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Audio segment - background audio or music
|
|
612
|
+
*/
|
|
613
|
+
interface AudioSegment extends BaseSegment {
|
|
614
|
+
type: 'audio';
|
|
615
|
+
/** Audio volume percentage 0-100 (default: 100) */
|
|
616
|
+
volume?: number;
|
|
617
|
+
/** Playback speed multiplier (default: 1) */
|
|
618
|
+
speed?: number;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Union type for all segment types
|
|
622
|
+
*/
|
|
623
|
+
type Segment = VideoSegment | ImageSegment | TextSegment | AudioSegment;
|
|
624
|
+
/**
|
|
625
|
+
* Union type for visual segments only (for rendering)
|
|
626
|
+
*/
|
|
627
|
+
type VisualSegmentUnion = VideoSegment | ImageSegment | TextSegment;
|
|
628
|
+
/**
|
|
629
|
+
* Static segments (for image output - no video/audio)
|
|
630
|
+
*/
|
|
631
|
+
type StaticSegment = ImageSegment | TextSegment;
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Editor configuration types
|
|
635
|
+
*
|
|
636
|
+
* Editors are the top-level containers that define the canvas dimensions,
|
|
637
|
+
* timing, and channels containing segments.
|
|
638
|
+
*/
|
|
639
|
+
|
|
640
|
+
/**
|
|
641
|
+
* A channel (track) containing segments
|
|
642
|
+
* Channels allow for parallel playback of segments
|
|
643
|
+
*/
|
|
644
|
+
interface Channel<T extends Segment = Segment> {
|
|
645
|
+
/** Unique channel identifier */
|
|
646
|
+
id: string;
|
|
647
|
+
/** Segments in this channel */
|
|
648
|
+
segments: T[];
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Base editor configuration shared by all editor types
|
|
652
|
+
*/
|
|
653
|
+
interface BaseEditorConfig {
|
|
654
|
+
/** Canvas width in pixels */
|
|
655
|
+
width: number;
|
|
656
|
+
/** Canvas height in pixels */
|
|
657
|
+
height: number;
|
|
658
|
+
/** Frames per second (video only) */
|
|
659
|
+
fps: number;
|
|
660
|
+
/** Total duration in milliseconds (auto-calculated if 0 or undefined) */
|
|
661
|
+
duration?: number;
|
|
662
|
+
}
|
|
663
|
+
/**
|
|
664
|
+
* Full editor configuration with all segment types
|
|
665
|
+
* Used for video output
|
|
666
|
+
*/
|
|
667
|
+
interface EditorConfig extends BaseEditorConfig {
|
|
668
|
+
channels: Channel[];
|
|
669
|
+
/** Dynamic crop configuration (optional) */
|
|
670
|
+
dynamicCrop?: DynamicCropConfig;
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Video editor configuration
|
|
674
|
+
* Supports all segment types including video and audio
|
|
675
|
+
*/
|
|
676
|
+
interface VideoEditorConfig extends BaseEditorConfig {
|
|
677
|
+
channels: Channel<VideoSegment | ImageSegment | TextSegment | AudioSegment>[];
|
|
678
|
+
/** Dynamic crop configuration (optional) */
|
|
679
|
+
dynamicCrop?: DynamicCropConfig;
|
|
680
|
+
}
|
|
681
|
+
/**
|
|
682
|
+
* Image editor configuration
|
|
683
|
+
* Only supports text and image segments (no video/audio)
|
|
684
|
+
*/
|
|
685
|
+
interface ImageEditorConfig extends BaseEditorConfig {
|
|
686
|
+
channels: Channel<StaticSegment>[];
|
|
687
|
+
/** Dynamic crop configuration (optional) */
|
|
688
|
+
dynamicCrop?: DynamicCropConfig;
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Editor segment - a nested composition within another editor
|
|
692
|
+
* Allows for compositing multiple editors together
|
|
693
|
+
*/
|
|
694
|
+
interface EditorSegment {
|
|
695
|
+
type: 'editor';
|
|
696
|
+
/** Unique segment identifier */
|
|
697
|
+
id: string;
|
|
698
|
+
/** Empty source (editor segments don't have external sources) */
|
|
699
|
+
source: '';
|
|
700
|
+
/** Sequence order within channel */
|
|
701
|
+
order: number;
|
|
702
|
+
/** Time offset */
|
|
703
|
+
offset: {
|
|
704
|
+
type: 'absolute' | 'relative';
|
|
705
|
+
value: number;
|
|
706
|
+
};
|
|
707
|
+
/** Position and size */
|
|
708
|
+
xOffset: number;
|
|
709
|
+
yOffset: number;
|
|
710
|
+
width: number;
|
|
711
|
+
height: number;
|
|
712
|
+
/** Layer order */
|
|
713
|
+
zIndex?: number;
|
|
714
|
+
/** Scale multiplier */
|
|
715
|
+
scale?: number;
|
|
716
|
+
/** Rotation in degrees */
|
|
717
|
+
rotation?: number;
|
|
718
|
+
/** The nested editor configuration */
|
|
719
|
+
editor: EditorConfig;
|
|
720
|
+
/** How the rendered sub-editor fits in bounds */
|
|
721
|
+
fit?: 'cover' | 'contain' | 'fill';
|
|
722
|
+
/** Opacity 0-100 */
|
|
723
|
+
opacity?: number;
|
|
724
|
+
/** Playback speed for the nested composition */
|
|
725
|
+
speed?: number;
|
|
726
|
+
/** Audio volume for the nested composition */
|
|
727
|
+
volume?: number;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
interface ImageEditorCompositionProps {
|
|
731
|
+
/** The editor configuration to render (legacy format with pre-resolved segments) */
|
|
732
|
+
config?: ImageEditorConfig;
|
|
733
|
+
/** Map of source URLs keyed by segment ID or input reference */
|
|
734
|
+
sources?: Record<string, string>;
|
|
735
|
+
/** Optional scale multiplier for high-DPI rendering */
|
|
736
|
+
scale?: number;
|
|
737
|
+
/** Raw elements with relative positioning (will be resolved internally) */
|
|
738
|
+
elements?: ImageEditorElement[];
|
|
739
|
+
/** Canvas width (required when using elements) */
|
|
740
|
+
width?: number;
|
|
741
|
+
/** Canvas height (required when using elements) */
|
|
742
|
+
height?: number;
|
|
743
|
+
/** Background fit mode (when using elements) */
|
|
744
|
+
backgroundFit?: FitMode;
|
|
745
|
+
/** Background image URL (when using elements) */
|
|
746
|
+
backgroundUrl?: string;
|
|
747
|
+
/** Image URLs keyed by inputId (when using elements) */
|
|
748
|
+
imageUrls?: Record<string, string | null>;
|
|
749
|
+
/** Text values keyed by textInputId (when using elements, for autoWidth calculation) */
|
|
750
|
+
textValues?: Record<string, string>;
|
|
751
|
+
}
|
|
752
|
+
/**
|
|
753
|
+
* ImageEditorComposition renders a complete image editor configuration.
|
|
754
|
+
*
|
|
755
|
+
* Features:
|
|
756
|
+
* - Background image with fit mode
|
|
757
|
+
* - Multiple text and image elements
|
|
758
|
+
* - Z-index ordering
|
|
759
|
+
* - All text styling (fonts, colors, stroke, background, etc.)
|
|
760
|
+
* - All image styling (fit, opacity, rotation, border radius)
|
|
761
|
+
* - Automatic position resolution for relative positioning
|
|
762
|
+
*
|
|
763
|
+
* @example
|
|
764
|
+
* ```tsx
|
|
765
|
+
* import { Player } from '@remotion/player';
|
|
766
|
+
* import { ImageEditorComposition } from '@ugcinc/remotion';
|
|
767
|
+
*
|
|
768
|
+
* // NEW: Pass raw elements directly (preferred)
|
|
769
|
+
* <Player
|
|
770
|
+
* component={ImageEditorComposition}
|
|
771
|
+
* inputProps={{
|
|
772
|
+
* elements,
|
|
773
|
+
* width: 1080,
|
|
774
|
+
* height: 1920,
|
|
775
|
+
* backgroundUrl,
|
|
776
|
+
* imageUrls,
|
|
777
|
+
* textValues
|
|
778
|
+
* }}
|
|
779
|
+
* durationInFrames={1}
|
|
780
|
+
* fps={1}
|
|
781
|
+
* compositionWidth={1080}
|
|
782
|
+
* compositionHeight={1920}
|
|
783
|
+
* />
|
|
784
|
+
* ```
|
|
785
|
+
*/
|
|
786
|
+
declare function ImageEditorComposition({ config, sources, scale, elements, width, height, backgroundFit, backgroundUrl, imageUrls, textValues, }: ImageEditorCompositionProps): react_jsx_runtime.JSX.Element;
|
|
787
|
+
|
|
788
|
+
interface VideoEditorCompositionProps {
|
|
789
|
+
/** The editor configuration to render */
|
|
790
|
+
config: VideoEditorConfig;
|
|
791
|
+
/** Map of source URLs keyed by segment ID or input reference */
|
|
792
|
+
sources?: Record<string, string>;
|
|
793
|
+
/** Map of text content keyed by segment ID or input reference */
|
|
794
|
+
textContent?: Record<string, string>;
|
|
795
|
+
/** Optional scale multiplier for high-DPI rendering */
|
|
796
|
+
scale?: number;
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* VideoEditorComposition renders a complete video editor configuration.
|
|
800
|
+
*
|
|
801
|
+
* Features:
|
|
802
|
+
* - Multiple channels with segments
|
|
803
|
+
* - Video, image, text, and audio segments
|
|
804
|
+
* - Timeline-based playback
|
|
805
|
+
* - Overlay segments with relative timing
|
|
806
|
+
* - Fade-in effects
|
|
807
|
+
* - Z-index ordering
|
|
808
|
+
*
|
|
809
|
+
* @example
|
|
810
|
+
* ```tsx
|
|
811
|
+
* import { Player } from '@remotion/player';
|
|
812
|
+
* import { VideoEditorComposition } from '@ugcinc/remotion';
|
|
813
|
+
*
|
|
814
|
+
* <Player
|
|
815
|
+
* component={VideoEditorComposition}
|
|
816
|
+
* inputProps={{ config, sources, textContent }}
|
|
817
|
+
* durationInFrames={durationInFrames}
|
|
818
|
+
* fps={config.fps}
|
|
819
|
+
* compositionWidth={config.width}
|
|
820
|
+
* compositionHeight={config.height}
|
|
821
|
+
* />
|
|
822
|
+
* ```
|
|
823
|
+
*/
|
|
824
|
+
declare function VideoEditorComposition({ config, sources, textContent, }: VideoEditorCompositionProps): react_jsx_runtime.JSX.Element;
|
|
825
|
+
|
|
826
|
+
interface TextElementProps {
|
|
827
|
+
segment: TextSegment;
|
|
828
|
+
/** Optional scale for high-DPI rendering */
|
|
829
|
+
scale?: number;
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* TextElement renders text with full styling support including:
|
|
833
|
+
* - Font family, size, weight, color
|
|
834
|
+
* - Letter spacing, line height
|
|
835
|
+
* - Horizontal and vertical alignment
|
|
836
|
+
* - Text stroke/outline
|
|
837
|
+
* - Background with opacity and border radius
|
|
838
|
+
* - Padding (uniform and individual)
|
|
839
|
+
* - Auto-width with box alignment
|
|
840
|
+
* - Rotation
|
|
841
|
+
*/
|
|
842
|
+
declare function TextElement({ segment, scale }: TextElementProps): react_jsx_runtime.JSX.Element;
|
|
843
|
+
|
|
844
|
+
interface ImageElementProps {
|
|
845
|
+
segment: ImageSegment;
|
|
846
|
+
/** The source URL of the image */
|
|
847
|
+
src: string;
|
|
848
|
+
/** Optional scale for high-DPI rendering */
|
|
849
|
+
scale?: number;
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* ImageElement renders images with:
|
|
853
|
+
* - Fit modes (cover, contain, fill)
|
|
854
|
+
* - Opacity
|
|
855
|
+
* - Rotation
|
|
856
|
+
* - Border radius (uniform or per-corner)
|
|
857
|
+
*/
|
|
858
|
+
declare function ImageElement({ segment, src, scale }: ImageElementProps): react_jsx_runtime.JSX.Element;
|
|
859
|
+
|
|
860
|
+
interface VideoElementProps {
|
|
861
|
+
segment: VideoSegment;
|
|
862
|
+
/** The source URL of the video */
|
|
863
|
+
src: string;
|
|
864
|
+
/** Start frame of this segment in the composition */
|
|
865
|
+
startFrame: number;
|
|
866
|
+
/** Duration of this segment in frames */
|
|
867
|
+
durationInFrames: number;
|
|
868
|
+
/** Optional scale for high-DPI rendering */
|
|
869
|
+
scale?: number;
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* VideoElement renders videos with:
|
|
873
|
+
* - Playback speed control
|
|
874
|
+
* - Volume control
|
|
875
|
+
* - Fit modes (cover, contain, fill)
|
|
876
|
+
* - Opacity
|
|
877
|
+
* - Rotation
|
|
878
|
+
* - Border radius
|
|
879
|
+
* - Fade-in effect
|
|
880
|
+
*/
|
|
881
|
+
declare function VideoElement({ segment, src, startFrame, durationInFrames, scale }: VideoElementProps): react_jsx_runtime.JSX.Element;
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* Font utilities for the rendering system
|
|
885
|
+
*/
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Font family CSS strings for each font type
|
|
889
|
+
* These match the fonts registered in the rendering system
|
|
890
|
+
*/
|
|
891
|
+
declare const FONT_FAMILIES: Record<FontType, string>;
|
|
892
|
+
/**
|
|
893
|
+
* Get the CSS font family string for a font type
|
|
894
|
+
*/
|
|
895
|
+
declare function getFontFamily(fontType: FontType): string;
|
|
896
|
+
/**
|
|
897
|
+
* Build a CSS font string
|
|
898
|
+
*/
|
|
899
|
+
declare function buildFontString({ fontType, fontSize, fontWeight, }: {
|
|
900
|
+
fontType: FontType;
|
|
901
|
+
fontSize: number;
|
|
902
|
+
fontWeight: 'normal' | 'bold';
|
|
903
|
+
}): string;
|
|
904
|
+
/**
|
|
905
|
+
* Font URLs for loading web fonts
|
|
906
|
+
* These are the public URLs to the font files
|
|
907
|
+
*/
|
|
908
|
+
declare const FONT_URLS: {
|
|
909
|
+
tiktok: {
|
|
910
|
+
regular: string;
|
|
911
|
+
bold: string;
|
|
912
|
+
};
|
|
913
|
+
apple: {
|
|
914
|
+
regular: string;
|
|
915
|
+
};
|
|
916
|
+
};
|
|
917
|
+
/**
|
|
918
|
+
* Preload fonts for Remotion rendering
|
|
919
|
+
* Call this in your Root component or composition
|
|
920
|
+
*/
|
|
921
|
+
declare function preloadFonts(): Promise<void>;
|
|
922
|
+
/**
|
|
923
|
+
* Check if fonts are loaded
|
|
924
|
+
*/
|
|
925
|
+
declare function areFontsLoaded(): boolean;
|
|
926
|
+
|
|
927
|
+
/**
|
|
928
|
+
* Fit calculation utilities for media positioning
|
|
929
|
+
*/
|
|
930
|
+
|
|
931
|
+
/**
|
|
932
|
+
* Result of fit dimension calculation
|
|
933
|
+
*/
|
|
934
|
+
interface FitDimensions {
|
|
935
|
+
/** X offset within target area */
|
|
936
|
+
x: number;
|
|
937
|
+
/** Y offset within target area */
|
|
938
|
+
y: number;
|
|
939
|
+
/** Rendered width */
|
|
940
|
+
width: number;
|
|
941
|
+
/** Rendered height */
|
|
942
|
+
height: number;
|
|
943
|
+
/** Source X offset (for cropping) */
|
|
944
|
+
sourceX: number;
|
|
945
|
+
/** Source Y offset (for cropping) */
|
|
946
|
+
sourceY: number;
|
|
947
|
+
/** Source width to use */
|
|
948
|
+
sourceWidth: number;
|
|
949
|
+
/** Source height to use */
|
|
950
|
+
sourceHeight: number;
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Calculate dimensions for fit modes (cover, contain, fill)
|
|
954
|
+
*/
|
|
955
|
+
declare function calculateFitDimensions({ sourceWidth, sourceHeight, targetWidth, targetHeight, fit, }: {
|
|
956
|
+
sourceWidth: number;
|
|
957
|
+
sourceHeight: number;
|
|
958
|
+
targetWidth: number;
|
|
959
|
+
targetHeight: number;
|
|
960
|
+
fit: FitMode;
|
|
961
|
+
}): FitDimensions;
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* Default values for segment properties
|
|
965
|
+
*
|
|
966
|
+
* These defaults match the server-side rendering defaults exactly
|
|
967
|
+
* to ensure consistent behavior between client preview and server render.
|
|
968
|
+
*/
|
|
969
|
+
|
|
970
|
+
/**
|
|
971
|
+
* Default values for text segments
|
|
972
|
+
*/
|
|
973
|
+
declare const TEXT_DEFAULTS: {
|
|
974
|
+
fontType: FontType;
|
|
975
|
+
fontSize: number;
|
|
976
|
+
fontWeight: FontWeight;
|
|
977
|
+
color: string;
|
|
978
|
+
alignment: TextAlignment;
|
|
979
|
+
verticalAlign: VerticalAlignment;
|
|
980
|
+
direction: TextDirection;
|
|
981
|
+
lineHeight: number;
|
|
982
|
+
letterSpacing: number;
|
|
983
|
+
padding: number;
|
|
984
|
+
textWrap: TextWrap;
|
|
985
|
+
wordBreak: WordBreak;
|
|
986
|
+
hyphenation: Hyphenation;
|
|
987
|
+
maxLines: number;
|
|
988
|
+
textOverflow: TextOverflow;
|
|
989
|
+
ellipsis: string;
|
|
990
|
+
strokeWidth: number;
|
|
991
|
+
backgroundOpacity: number;
|
|
992
|
+
autoWidth: boolean;
|
|
993
|
+
boxAlign: "left";
|
|
994
|
+
};
|
|
995
|
+
/**
|
|
996
|
+
* Default values for image segments
|
|
997
|
+
*/
|
|
998
|
+
declare const IMAGE_DEFAULTS: {
|
|
999
|
+
fit: FitMode;
|
|
1000
|
+
opacity: number;
|
|
1001
|
+
loop: boolean;
|
|
1002
|
+
speed: number;
|
|
1003
|
+
};
|
|
1004
|
+
/**
|
|
1005
|
+
* Default values for video segments
|
|
1006
|
+
*/
|
|
1007
|
+
declare const VIDEO_DEFAULTS: {
|
|
1008
|
+
volume: number;
|
|
1009
|
+
fit: FitMode;
|
|
1010
|
+
opacity: number;
|
|
1011
|
+
loop: boolean;
|
|
1012
|
+
speed: number;
|
|
1013
|
+
};
|
|
1014
|
+
/**
|
|
1015
|
+
* Default values for visual segment positioning
|
|
1016
|
+
*/
|
|
1017
|
+
declare const VISUAL_DEFAULTS: {
|
|
1018
|
+
xOffset: number;
|
|
1019
|
+
yOffset: number;
|
|
1020
|
+
zIndex: number;
|
|
1021
|
+
scale: number;
|
|
1022
|
+
rotation: number;
|
|
1023
|
+
opacity: number;
|
|
1024
|
+
};
|
|
1025
|
+
/**
|
|
1026
|
+
* Apply default values to a text segment
|
|
1027
|
+
*/
|
|
1028
|
+
declare function applyTextDefaults<T extends Record<string, unknown>>(segment: T): T & typeof TEXT_DEFAULTS;
|
|
1029
|
+
/**
|
|
1030
|
+
* Apply default values to an image segment
|
|
1031
|
+
*/
|
|
1032
|
+
declare function applyImageDefaults<T extends Record<string, unknown>>(segment: T): T & typeof IMAGE_DEFAULTS;
|
|
1033
|
+
/**
|
|
1034
|
+
* Apply default values to a video segment
|
|
1035
|
+
*/
|
|
1036
|
+
declare function applyVideoDefaults<T extends Record<string, unknown>>(segment: T): T & typeof VIDEO_DEFAULTS;
|
|
1037
|
+
|
|
1038
|
+
/**
|
|
1039
|
+
* Text utilities for measuring and wrapping text
|
|
1040
|
+
*/
|
|
1041
|
+
|
|
1042
|
+
/**
|
|
1043
|
+
* Wrap text to fit within a specific width
|
|
1044
|
+
* Accounts for letter spacing when measuring text width
|
|
1045
|
+
*/
|
|
1046
|
+
declare function wrapText({ text, maxWidth, letterSpacing, textWrap, maxLines, measureText, }: {
|
|
1047
|
+
text: string;
|
|
1048
|
+
maxWidth: number;
|
|
1049
|
+
letterSpacing?: number;
|
|
1050
|
+
textWrap?: 'word' | 'char' | 'none';
|
|
1051
|
+
maxLines?: number;
|
|
1052
|
+
measureText: (text: string) => number;
|
|
1053
|
+
}): string[];
|
|
1054
|
+
/**
|
|
1055
|
+
* Calculate line width with letter spacing
|
|
1056
|
+
*/
|
|
1057
|
+
declare function calculateLineWidth({ line, letterSpacing, measureText, }: {
|
|
1058
|
+
line: string;
|
|
1059
|
+
letterSpacing: number;
|
|
1060
|
+
measureText: (text: string) => number;
|
|
1061
|
+
}): number;
|
|
1062
|
+
/**
|
|
1063
|
+
* Convert borderRadius value to array format for roundRect()
|
|
1064
|
+
* Returns [topLeft, topRight, bottomRight, bottomLeft] or null if no rounding needed
|
|
1065
|
+
*/
|
|
1066
|
+
declare function getBorderRadii(borderRadius: number | BorderRadiusConfig | undefined): number[] | null;
|
|
1067
|
+
/**
|
|
1068
|
+
* Parse hex color to RGB values
|
|
1069
|
+
*/
|
|
1070
|
+
declare function parseHexColor(hex: string): {
|
|
1071
|
+
r: number;
|
|
1072
|
+
g: number;
|
|
1073
|
+
b: number;
|
|
1074
|
+
};
|
|
1075
|
+
/**
|
|
1076
|
+
* Convert hex color and opacity to rgba string
|
|
1077
|
+
*/
|
|
1078
|
+
declare function hexToRgba(hex: string, opacity?: number): string;
|
|
1079
|
+
|
|
1080
|
+
/**
|
|
1081
|
+
* Position Resolution Utility
|
|
1082
|
+
*
|
|
1083
|
+
* Resolves relative element positions to absolute coordinates.
|
|
1084
|
+
* X and Y positions can be independently set to relative or absolute.
|
|
1085
|
+
* Handles dependency resolution, circular dependency detection, and cascading updates.
|
|
1086
|
+
*/
|
|
1087
|
+
|
|
1088
|
+
/**
|
|
1089
|
+
* Calculate the actual width of a text element when autoWidth is enabled
|
|
1090
|
+
* Returns { actualWidth, actualX } where actualX is adjusted based on boxAlign
|
|
1091
|
+
*/
|
|
1092
|
+
declare function calculateAutoWidthDimensions(elem: ImageEditorElement, textContent: string, ctx?: CanvasRenderingContext2D | null): {
|
|
1093
|
+
actualWidth: number;
|
|
1094
|
+
actualX: number;
|
|
1095
|
+
} | null;
|
|
1096
|
+
interface PositionResolutionError {
|
|
1097
|
+
elementId: string;
|
|
1098
|
+
type: 'circular_dependency' | 'missing_reference' | 'invalid_config';
|
|
1099
|
+
message: string;
|
|
1100
|
+
/** Which axis the error is for */
|
|
1101
|
+
axis?: 'x' | 'y';
|
|
1102
|
+
/** For circular dependencies, the cycle path */
|
|
1103
|
+
cyclePath?: string[];
|
|
1104
|
+
}
|
|
1105
|
+
interface PositionResolutionResult {
|
|
1106
|
+
/** Elements with resolved absolute positions */
|
|
1107
|
+
elements: ImageEditorElement[];
|
|
1108
|
+
/** Any errors encountered during resolution */
|
|
1109
|
+
errors: PositionResolutionError[];
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Resolve all relative positions to absolute coordinates
|
|
1113
|
+
*
|
|
1114
|
+
* X and Y are resolved independently, allowing:
|
|
1115
|
+
* - X absolute, Y relative (common for vertical stacking)
|
|
1116
|
+
* - X relative, Y absolute (common for horizontal stacking)
|
|
1117
|
+
* - Both relative (can be to different elements)
|
|
1118
|
+
* - Both absolute
|
|
1119
|
+
*
|
|
1120
|
+
* @param elements - Array of elements to resolve
|
|
1121
|
+
* @param textValues - Optional map of textInputId -> text content for autoWidth calculation
|
|
1122
|
+
*/
|
|
1123
|
+
declare function resolveElementPositions(elements: ImageEditorElement[], textValues?: Record<string, string>): PositionResolutionResult;
|
|
1124
|
+
/**
|
|
1125
|
+
* Check if an element can be set as a reference for another element on a specific axis
|
|
1126
|
+
*/
|
|
1127
|
+
declare function canSetAsReference(elements: ImageEditorElement[], elementId: string, proposedReferenceId: string, axis: 'x' | 'y'): boolean;
|
|
1128
|
+
/**
|
|
1129
|
+
* Get all elements that would be affected if a given element's position/size changes
|
|
1130
|
+
*/
|
|
1131
|
+
declare function getDependentElements(elements: ImageEditorElement[], elementId: string): string[];
|
|
1132
|
+
/**
|
|
1133
|
+
* Get the element that a given element references for X position (if any)
|
|
1134
|
+
*/
|
|
1135
|
+
declare function getReferenceElementX(elements: ImageEditorElement[], elementId: string): ImageEditorElement | null;
|
|
1136
|
+
/**
|
|
1137
|
+
* Get the element that a given element references for Y position (if any)
|
|
1138
|
+
*/
|
|
1139
|
+
declare function getReferenceElementY(elements: ImageEditorElement[], elementId: string): ImageEditorElement | null;
|
|
1140
|
+
|
|
1141
|
+
/**
|
|
1142
|
+
* Hook exports for @ugcinc/remotion
|
|
1143
|
+
*
|
|
1144
|
+
* Hooks for common operations like font loading, media preloading,
|
|
1145
|
+
* and position resolution.
|
|
1146
|
+
*/
|
|
1147
|
+
|
|
1148
|
+
/**
|
|
1149
|
+
* Hook to ensure fonts are loaded before rendering
|
|
1150
|
+
* Returns true when fonts are ready
|
|
1151
|
+
*/
|
|
1152
|
+
declare function useFontsLoaded(): boolean;
|
|
1153
|
+
/**
|
|
1154
|
+
* Hook to load an image and return it when ready
|
|
1155
|
+
*/
|
|
1156
|
+
declare function useImageLoader(src: string | undefined): HTMLImageElement | null;
|
|
1157
|
+
/**
|
|
1158
|
+
* Hook to preload multiple images
|
|
1159
|
+
*/
|
|
1160
|
+
declare function useImagePreloader(sources: Record<string, string>): {
|
|
1161
|
+
loaded: boolean;
|
|
1162
|
+
images: Record<string, HTMLImageElement>;
|
|
1163
|
+
};
|
|
1164
|
+
/**
|
|
1165
|
+
* Hook to resolve element positions for UI overlay positioning
|
|
1166
|
+
*
|
|
1167
|
+
* Use this hook in the webapp to get the resolved positions of elements
|
|
1168
|
+
* for positioning interaction overlays (drag handles, selection outlines, etc.)
|
|
1169
|
+
*
|
|
1170
|
+
* @param elements - Raw elements with relative positioning
|
|
1171
|
+
* @param textValues - Optional map of textInputId -> text content for autoWidth calculation
|
|
1172
|
+
* @returns Object with resolved elements and any resolution errors
|
|
1173
|
+
*
|
|
1174
|
+
* @example
|
|
1175
|
+
* ```tsx
|
|
1176
|
+
* const { elements: resolvedElements, errors } = useResolvedPositions(
|
|
1177
|
+
* elements,
|
|
1178
|
+
* previewTextValues
|
|
1179
|
+
* );
|
|
1180
|
+
*
|
|
1181
|
+
* // Use resolvedElements for positioning overlays
|
|
1182
|
+
* resolvedElements.map(elem => (
|
|
1183
|
+
* <div style={{ left: elem.x, top: elem.y, width: elem.width, height: elem.height }}>
|
|
1184
|
+
* {/* Drag handles, selection outline, etc. *\/}
|
|
1185
|
+
* </div>
|
|
1186
|
+
* ))
|
|
1187
|
+
* ```
|
|
1188
|
+
*/
|
|
1189
|
+
declare function useResolvedPositions(elements: ImageEditorElement[], textValues?: Record<string, string>): PositionResolutionResult;
|
|
1190
|
+
|
|
1191
|
+
/**
|
|
1192
|
+
* Remotion Root Component
|
|
1193
|
+
*
|
|
1194
|
+
* This file registers all available compositions with Remotion.
|
|
1195
|
+
* It serves as the entry point for the Remotion bundler.
|
|
1196
|
+
*/
|
|
1197
|
+
|
|
1198
|
+
declare const RemotionRoot: React.FC;
|
|
1199
|
+
|
|
1200
|
+
export { type AudioSegment, type BaseEditorConfig, type BaseSegment, type BorderRadiusConfig, type Channel, type CropAxisConfig, type CropBoundary, type CropBounds, DIMENSION_PRESETS, type DimensionPreset, type DimensionPresetKey, type DynamicCropConfig, type EditorConfig, type EditorSegment, FONT_FAMILIES, FONT_URLS, type FitDimensions, type FitMode, type FontType, type FontWeight, type HorizontalAnchor, type HorizontalSelfAnchor, type Hyphenation, IMAGE_DEFAULTS, ImageEditorComposition, type ImageEditorCompositionProps, type ImageEditorConfig, type ImageEditorElement, type ImageEditorNodeConfig, ImageElement, type ImageElementProps, type ImageSegment, type PictureSegment, type PositionResolutionError, type PositionResolutionResult, type RelativePositionConfigX, type RelativePositionConfigY, RemotionRoot, type Segment, type SegmentType, type StaticSegment, TEXT_DEFAULTS, type TextAlignment, type TextDirection, TextElement, type TextElementProps, type TextOverflow, type TextSegment, type TextWrap, type TimeMode, type TimeValue, VIDEO_DEFAULTS, VISUAL_DEFAULTS, type VerticalAlignment, type VerticalAnchor, type VerticalSelfAnchor, type VideoEditorAudioSegment, type VideoEditorBaseSegment, type VideoEditorChannel, VideoEditorComposition, type VideoEditorCompositionProps, type VideoEditorConfig, type VideoEditorImageSegment, type VideoEditorNodeConfig, type VideoEditorSegment, type VideoEditorTextSegment, type VideoEditorVideoSegment, type VideoEditorVisualSegment, VideoElement, type VideoElementProps, type VideoSegment, type VisualSegment, type VisualSegmentUnion, type WordBreak, applyImageDefaults, applyTextDefaults, applyVideoDefaults, areFontsLoaded, buildFontString, calculateAutoWidthDimensions, calculateFitDimensions, calculateLineWidth, canSetAsReference, getBorderRadii, getDependentElements, getFontFamily, getReferenceElementX, getReferenceElementY, hexToRgba, parseHexColor, preloadFonts, resolveElementPositions, useFontsLoaded, useImageLoader, useImagePreloader, useResolvedPositions, wrapText };
|