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.
@@ -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 };