ugcinc 3.84.6 → 3.85.0

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.
Files changed (120) hide show
  1. package/dist/index.d.ts +2 -1
  2. package/dist/index.js +6 -1
  3. package/dist/render/Root.d.ts +12 -0
  4. package/dist/render/Root.js +508 -0
  5. package/dist/render/components/CaptionOverlay.d.ts +21 -0
  6. package/dist/render/components/CaptionOverlay.js +210 -0
  7. package/dist/render/components/ImageElement.d.ts +26 -0
  8. package/dist/render/components/ImageElement.js +88 -0
  9. package/dist/render/components/TextElement.d.ts +30 -0
  10. package/dist/render/components/TextElement.js +390 -0
  11. package/dist/render/components/VideoElement.d.ts +30 -0
  12. package/dist/render/components/VideoElement.js +108 -0
  13. package/dist/render/components/index.d.ts +7 -0
  14. package/dist/render/components/index.js +14 -0
  15. package/dist/render/compositions/AutoCaptionComposition.d.ts +42 -0
  16. package/dist/render/compositions/AutoCaptionComposition.js +29 -0
  17. package/dist/render/compositions/DmComposition/BaseDmComposition.d.ts +112 -0
  18. package/dist/render/compositions/DmComposition/BaseDmComposition.js +212 -0
  19. package/dist/render/compositions/DmComposition/DebugOverlay.d.ts +20 -0
  20. package/dist/render/compositions/DmComposition/DebugOverlay.js +258 -0
  21. package/dist/render/compositions/DmComposition/index.d.ts +6 -0
  22. package/dist/render/compositions/DmComposition/index.js +10 -0
  23. package/dist/render/compositions/IMessageDmComposition/convertPropsToElements.d.ts +27 -0
  24. package/dist/render/compositions/IMessageDmComposition/convertPropsToElements.js +629 -0
  25. package/dist/render/compositions/IMessageDmComposition/index.d.ts +20 -0
  26. package/dist/render/compositions/IMessageDmComposition/index.js +485 -0
  27. package/dist/render/compositions/IMessageDmComposition/types.d.ts +756 -0
  28. package/dist/render/compositions/IMessageDmComposition/types.js +225 -0
  29. package/dist/render/compositions/ImageEditorComposition.d.ts +74 -0
  30. package/dist/render/compositions/ImageEditorComposition.js +351 -0
  31. package/dist/render/compositions/InstagramDmComposition/convertPropsToElements.d.ts +60 -0
  32. package/dist/render/compositions/InstagramDmComposition/convertPropsToElements.js +1318 -0
  33. package/dist/render/compositions/InstagramDmComposition/convertPublicToProps.d.ts +30 -0
  34. package/dist/render/compositions/InstagramDmComposition/convertPublicToProps.js +131 -0
  35. package/dist/render/compositions/InstagramDmComposition/index.d.ts +16 -0
  36. package/dist/render/compositions/InstagramDmComposition/index.js +374 -0
  37. package/dist/render/compositions/InstagramDmComposition/theme.d.ts +42 -0
  38. package/dist/render/compositions/InstagramDmComposition/theme.js +55 -0
  39. package/dist/render/compositions/InstagramDmComposition/types.d.ts +215 -0
  40. package/dist/render/compositions/InstagramDmComposition/types.js +7 -0
  41. package/dist/render/compositions/ScreenshotAnimation.d.ts +14 -0
  42. package/dist/render/compositions/ScreenshotAnimation.js +268 -0
  43. package/dist/render/compositions/VideoEditorComposition.d.ts +45 -0
  44. package/dist/render/compositions/VideoEditorComposition.js +307 -0
  45. package/dist/render/compositions/index.d.ts +12 -0
  46. package/dist/render/compositions/index.js +43 -0
  47. package/dist/render/compositions/messaging/components/MediaBubble.d.ts +22 -0
  48. package/dist/render/compositions/messaging/components/MediaBubble.js +25 -0
  49. package/dist/render/compositions/messaging/components/MessageBubble.d.ts +35 -0
  50. package/dist/render/compositions/messaging/components/MessageBubble.js +34 -0
  51. package/dist/render/compositions/messaging/components/ProfilePic.d.ts +23 -0
  52. package/dist/render/compositions/messaging/components/ProfilePic.js +37 -0
  53. package/dist/render/compositions/messaging/components/Reaction.d.ts +23 -0
  54. package/dist/render/compositions/messaging/components/Reaction.js +19 -0
  55. package/dist/render/compositions/messaging/components/TypingIndicator.d.ts +25 -0
  56. package/dist/render/compositions/messaging/components/TypingIndicator.js +66 -0
  57. package/dist/render/compositions/messaging/index.d.ts +14 -0
  58. package/dist/render/compositions/messaging/index.js +43 -0
  59. package/dist/render/compositions/messaging/types.d.ts +148 -0
  60. package/dist/render/compositions/messaging/types.js +21 -0
  61. package/dist/render/compositions/messaging/utils/bubbleRadius.d.ts +45 -0
  62. package/dist/render/compositions/messaging/utils/bubbleRadius.js +84 -0
  63. package/dist/render/compositions/messaging/utils/groupMessages.d.ts +41 -0
  64. package/dist/render/compositions/messaging/utils/groupMessages.js +110 -0
  65. package/dist/render/data/phone-top-nav.d.ts +1 -0
  66. package/dist/render/data/phone-top-nav.js +4 -0
  67. package/dist/render/data/screenshot.d.ts +164 -0
  68. package/dist/render/data/screenshot.js +63 -0
  69. package/dist/render/hooks/index.d.ts +54 -0
  70. package/dist/render/hooks/index.js +132 -0
  71. package/dist/render/index.d.ts +12 -0
  72. package/dist/render/index.js +36 -0
  73. package/dist/render/types/base.d.ts +148 -0
  74. package/dist/render/types/base.js +5 -0
  75. package/dist/render/types/caption.d.ts +105 -0
  76. package/dist/render/types/caption.js +8 -0
  77. package/dist/render/types/crop.d.ts +60 -0
  78. package/dist/render/types/crop.js +8 -0
  79. package/dist/render/types/deduplication.d.ts +284 -0
  80. package/dist/render/types/deduplication.js +240 -0
  81. package/dist/render/types/editor.d.ts +97 -0
  82. package/dist/render/types/editor.js +10 -0
  83. package/dist/render/types/element.d.ts +139 -0
  84. package/dist/render/types/element.js +19 -0
  85. package/dist/render/types/index.d.ts +20 -0
  86. package/dist/render/types/index.js +24 -0
  87. package/dist/render/types/instagram-dm-public.d.ts +60 -0
  88. package/dist/render/types/instagram-dm-public.js +8 -0
  89. package/dist/render/types/position.d.ts +59 -0
  90. package/dist/render/types/position.js +5 -0
  91. package/dist/render/types/screenshot.d.ts +57 -0
  92. package/dist/render/types/screenshot.js +34 -0
  93. package/dist/render/types/segment.d.ts +163 -0
  94. package/dist/render/types/segment.js +8 -0
  95. package/dist/render/types/video.d.ts +192 -0
  96. package/dist/render/types/video.js +14 -0
  97. package/dist/render/utils/captionPresets.d.ts +38 -0
  98. package/dist/render/utils/captionPresets.js +168 -0
  99. package/dist/render/utils/cropBounds.d.ts +20 -0
  100. package/dist/render/utils/cropBounds.js +166 -0
  101. package/dist/render/utils/defaults.d.ts +74 -0
  102. package/dist/render/utils/defaults.js +91 -0
  103. package/dist/render/utils/emoji.d.ts +40 -0
  104. package/dist/render/utils/emoji.js +105 -0
  105. package/dist/render/utils/fit.d.ts +35 -0
  106. package/dist/render/utils/fit.js +63 -0
  107. package/dist/render/utils/fonts.d.ts +55 -0
  108. package/dist/render/utils/fonts.js +191 -0
  109. package/dist/render/utils/index.d.ts +14 -0
  110. package/dist/render/utils/index.js +73 -0
  111. package/dist/render/utils/positionResolver.d.ts +64 -0
  112. package/dist/render/utils/positionResolver.js +508 -0
  113. package/dist/render/utils/text.d.ts +50 -0
  114. package/dist/render/utils/text.js +177 -0
  115. package/dist/render/utils/timeline.d.ts +62 -0
  116. package/dist/render/utils/timeline.js +172 -0
  117. package/dist/render.d.ts +1 -1
  118. package/dist/types.d.ts +136 -17
  119. package/dist/types.js +58 -0
  120. package/package.json +20 -6
@@ -0,0 +1,225 @@
1
+ "use strict";
2
+ /**
3
+ * iMessage DM Composition Types
4
+ *
5
+ * Types for the iMessage DM conversation composition.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.iMessageDmPropsSchema = void 0;
9
+ const zod_1 = require("zod");
10
+ /**
11
+ * Zod schema for iMessage DM composition props (for Remotion)
12
+ */
13
+ exports.iMessageDmPropsSchema = zod_1.z.object({
14
+ // Canvas
15
+ width: zod_1.z.number().optional(),
16
+ height: zod_1.z.number().optional(),
17
+ durationInFrames: zod_1.z.number().optional(),
18
+ fps: zod_1.z.number().optional(),
19
+ // Debug
20
+ showDebugOverlay: zod_1.z.boolean().optional(),
21
+ referenceImageUrl: zod_1.z.string().optional(),
22
+ showReferenceImage: zod_1.z.boolean().optional(),
23
+ referenceOpacity: zod_1.z.number().optional(),
24
+ // Light mode
25
+ lightMode: zod_1.z.boolean().optional(),
26
+ // iMessage header
27
+ headerTop: zod_1.z.number().optional(),
28
+ headerBottom: zod_1.z.number().optional(),
29
+ headerBackgroundColor: zod_1.z.string().optional(),
30
+ // Header profile section
31
+ profilePicUrl: zod_1.z.string().optional(),
32
+ profilePicTop: zod_1.z.number().optional(),
33
+ profilePicBottom: zod_1.z.number().optional(),
34
+ profilePicLeft: zod_1.z.number().optional(),
35
+ profilePicRight: zod_1.z.number().optional(),
36
+ username: zod_1.z.string().optional(),
37
+ usernameTop: zod_1.z.number().optional(),
38
+ usernameBottom: zod_1.z.number().optional(),
39
+ usernameLeft: zod_1.z.number().optional(),
40
+ usernameRight: zod_1.z.number().optional(),
41
+ usernameFontSize: zod_1.z.number().optional(),
42
+ usernameLetterSpacing: zod_1.z.number().optional(),
43
+ usernameColor: zod_1.z.string().optional(),
44
+ usernameArrowOffsetX: zod_1.z.number().optional(),
45
+ usernameArrowOffsetY: zod_1.z.number().optional(),
46
+ usernameArrowWidth: zod_1.z.number().optional(),
47
+ usernameArrowHeight: zod_1.z.number().optional(),
48
+ // Back arrow
49
+ backArrowTop: zod_1.z.number().optional(),
50
+ backArrowBottom: zod_1.z.number().optional(),
51
+ backArrowLeft: zod_1.z.number().optional(),
52
+ backArrowRight: zod_1.z.number().optional(),
53
+ // Unread badge
54
+ unreadBadgeText: zod_1.z.string().optional(),
55
+ unreadBadgeTop: zod_1.z.number().optional(),
56
+ unreadBadgeBottom: zod_1.z.number().optional(),
57
+ unreadBadgeLeft: zod_1.z.number().optional(),
58
+ unreadBadgeFontSize: zod_1.z.number().optional(),
59
+ unreadBadgeLetterSpacing: zod_1.z.number().optional(),
60
+ unreadBadgeTextColor: zod_1.z.string().optional(),
61
+ unreadBadgeBorderRadius: zod_1.z.number().optional(),
62
+ unreadBadgePaddingLeft: zod_1.z.number().optional(),
63
+ unreadBadgePaddingRight: zod_1.z.number().optional(),
64
+ // Camera icon
65
+ cameraIconTop: zod_1.z.number().optional(),
66
+ cameraIconBottom: zod_1.z.number().optional(),
67
+ cameraIconLeft: zod_1.z.number().optional(),
68
+ cameraIconRight: zod_1.z.number().optional(),
69
+ dividerLineY: zod_1.z.number().optional(),
70
+ dividerLineColor: zod_1.z.string().optional(),
71
+ backgroundColor: zod_1.z.string().optional(),
72
+ // Status bar - Time
73
+ time: zod_1.z.string().optional(),
74
+ timeRight: zod_1.z.number().optional(),
75
+ timeBottom: zod_1.z.number().optional(),
76
+ timeFontSize: zod_1.z.number().optional(),
77
+ timeLetterSpacing: zod_1.z.number().optional(),
78
+ timeColor: zod_1.z.string().optional(),
79
+ // Status bar - No notifications
80
+ noNotisTop: zod_1.z.number().optional(),
81
+ noNotisBottom: zod_1.z.number().optional(),
82
+ noNotisLeft: zod_1.z.number().optional(),
83
+ noNotisRight: zod_1.z.number().optional(),
84
+ // Status bar - Cell signal
85
+ cellLevel: zod_1.z.number().min(0).max(4).optional(),
86
+ cell1Top: zod_1.z.number().optional(),
87
+ cell1Bottom: zod_1.z.number().optional(),
88
+ cell1Left: zod_1.z.number().optional(),
89
+ cell1Right: zod_1.z.number().optional(),
90
+ cell2Top: zod_1.z.number().optional(),
91
+ cell2Bottom: zod_1.z.number().optional(),
92
+ cell2Left: zod_1.z.number().optional(),
93
+ cell2Right: zod_1.z.number().optional(),
94
+ cell3Top: zod_1.z.number().optional(),
95
+ cell3Bottom: zod_1.z.number().optional(),
96
+ cell3Left: zod_1.z.number().optional(),
97
+ cell3Right: zod_1.z.number().optional(),
98
+ cell4Top: zod_1.z.number().optional(),
99
+ cell4Bottom: zod_1.z.number().optional(),
100
+ cell4Left: zod_1.z.number().optional(),
101
+ cell4Right: zod_1.z.number().optional(),
102
+ // Status bar - WiFi
103
+ wifiTop: zod_1.z.number().optional(),
104
+ wifiBottom: zod_1.z.number().optional(),
105
+ wifiLeft: zod_1.z.number().optional(),
106
+ wifiRight: zod_1.z.number().optional(),
107
+ // Status bar - Battery
108
+ batteryTop: zod_1.z.number().optional(),
109
+ batteryBottom: zod_1.z.number().optional(),
110
+ batteryLeft: zod_1.z.number().optional(),
111
+ batteryRight: zod_1.z.number().optional(),
112
+ // Home indicator
113
+ homeIndicatorTop: zod_1.z.number().optional(),
114
+ homeIndicatorBottom: zod_1.z.number().optional(),
115
+ homeIndicatorLeft: zod_1.z.number().optional(),
116
+ homeIndicatorRight: zod_1.z.number().optional(),
117
+ homeIndicatorColor: zod_1.z.string().optional(),
118
+ // iMessage footer
119
+ plusButtonTop: zod_1.z.number().optional(),
120
+ plusButtonBottom: zod_1.z.number().optional(),
121
+ plusButtonLeft: zod_1.z.number().optional(),
122
+ plusButtonRight: zod_1.z.number().optional(),
123
+ footerTop: zod_1.z.number().optional(),
124
+ footerBottom: zod_1.z.number().optional(),
125
+ footerLeft: zod_1.z.number().optional(),
126
+ footerRight: zod_1.z.number().optional(),
127
+ footerBgColor: zod_1.z.string().optional(),
128
+ footerBorderRadius: zod_1.z.number().optional(),
129
+ footerBorderColor: zod_1.z.string().optional(),
130
+ footerBorderWidth: zod_1.z.number().optional(),
131
+ messageTextTop: zod_1.z.number().optional(),
132
+ messageTextBottom: zod_1.z.number().optional(),
133
+ messageTextLeft: zod_1.z.number().optional(),
134
+ messageTextRight: zod_1.z.number().optional(),
135
+ messageTextFontSize: zod_1.z.number().optional(),
136
+ messageTextLetterSpacing: zod_1.z.number().optional(),
137
+ messageTextColor: zod_1.z.string().optional(),
138
+ messageText: zod_1.z.string().optional(),
139
+ // Message area bounds
140
+ messageAreaTop: zod_1.z.number().optional(),
141
+ messageAreaBottom: zod_1.z.number().optional(),
142
+ // Message colors
143
+ senderBubbleColor: zod_1.z.string().optional(),
144
+ recipientBubbleColor: zod_1.z.string().optional(),
145
+ bubbleTextColor: zod_1.z.string().optional(),
146
+ recipientTextColor: zod_1.z.string().optional(),
147
+ // Message typography
148
+ messageFontSize: zod_1.z.number().optional(),
149
+ messageLineHeight: zod_1.z.number().optional(),
150
+ messageLetterSpacing: zod_1.z.number().optional(),
151
+ // Message padding (inside bubble)
152
+ messagePaddingTop: zod_1.z.number().optional(),
153
+ messagePaddingBottom: zod_1.z.number().optional(),
154
+ senderPaddingLeft: zod_1.z.number().optional(),
155
+ senderPaddingRight: zod_1.z.number().optional(),
156
+ multiLineSenderPaddingLeft: zod_1.z.number().optional(),
157
+ recipientPaddingLeft: zod_1.z.number().optional(),
158
+ recipientPaddingRight: zod_1.z.number().optional(),
159
+ multiLineRecipientPaddingRight: zod_1.z.number().optional(),
160
+ // Bubble corner radii
161
+ bubbleRadiusNormal: zod_1.z.number().optional(),
162
+ bubbleRadiusGrouped: zod_1.z.number().optional(),
163
+ // Message spacing
164
+ messageGapInGroup: zod_1.z.number().optional(),
165
+ messageGapSameUser: zod_1.z.number().optional(),
166
+ messageGapDifferentUser: zod_1.z.number().optional(),
167
+ // Bubble positioning
168
+ recipientBubbleLeft: zod_1.z.number().optional(),
169
+ senderBubbleRight: zod_1.z.number().optional(),
170
+ bubbleMaxWidth: zod_1.z.number().optional(),
171
+ // Sender image attachment
172
+ senderImageLeft: zod_1.z.number().optional(),
173
+ senderImageHeight: zod_1.z.number().optional(),
174
+ senderImageGapToText: zod_1.z.number().optional(),
175
+ senderImageBorderRadius: zod_1.z.number().optional(),
176
+ // Message area header text
177
+ messageHeaderImessageText: zod_1.z.string().optional(),
178
+ messageHeaderTimestampText: zod_1.z.string().optional(),
179
+ messageHeaderTimestampGap: zod_1.z.number().optional(),
180
+ messageHeaderImessageGap: zod_1.z.number().optional(),
181
+ messageHeaderTextColor: zod_1.z.string().optional(),
182
+ messageHeaderFontSize: zod_1.z.number().optional(),
183
+ messageHeaderLetterSpacing: zod_1.z.number().optional(),
184
+ messageHeaderLeft: zod_1.z.number().optional(),
185
+ messageHeaderRight: zod_1.z.number().optional(),
186
+ // Message tails (SVG-based)
187
+ showMessageTails: zod_1.z.boolean().optional(),
188
+ // Recipient tail anchor points
189
+ recipientTailSideY: zod_1.z.number().optional(),
190
+ recipientTailCurveStartY: zod_1.z.number().optional(),
191
+ recipientTailTipX: zod_1.z.number().optional(),
192
+ recipientTailTipY: zod_1.z.number().optional(),
193
+ recipientTailBottomX: zod_1.z.number().optional(),
194
+ recipientTailBottomY: zod_1.z.number().optional(),
195
+ // Recipient tail curve bend
196
+ recipientTailTopBend: zod_1.z.number().optional(),
197
+ recipientTailBottomBend: zod_1.z.number().optional(),
198
+ // Sender tail anchor points
199
+ senderTailSideY: zod_1.z.number().optional(),
200
+ senderTailCurveStartY: zod_1.z.number().optional(),
201
+ senderTailTipX: zod_1.z.number().optional(),
202
+ senderTailTipY: zod_1.z.number().optional(),
203
+ senderTailBottomX: zod_1.z.number().optional(),
204
+ senderTailBottomY: zod_1.z.number().optional(),
205
+ // Sender tail curve bend
206
+ senderTailTopBend: zod_1.z.number().optional(),
207
+ senderTailBottomBend: zod_1.z.number().optional(),
208
+ // Read receipt
209
+ showReadReceipt: zod_1.z.boolean().optional(),
210
+ readReceiptText: zod_1.z.string().optional(),
211
+ readReceiptGap: zod_1.z.number().optional(),
212
+ readReceiptFontSize: zod_1.z.number().optional(),
213
+ readReceiptLetterSpacing: zod_1.z.number().optional(),
214
+ readReceiptColor: zod_1.z.string().optional(),
215
+ readReceiptLeft: zod_1.z.number().optional(),
216
+ readReceiptRight: zod_1.z.number().optional(),
217
+ // Messages
218
+ messages: zod_1.z.array(zod_1.z.object({
219
+ id: zod_1.z.string(),
220
+ sender: zod_1.z.enum(['user', 'recipient']),
221
+ text: zod_1.z.string(),
222
+ imageUrl: zod_1.z.string().optional(),
223
+ groupWithPrevious: zod_1.z.boolean().optional(),
224
+ })).optional(),
225
+ });
@@ -0,0 +1,74 @@
1
+ /**
2
+ * ImageEditorComposition
3
+ *
4
+ * A composition that renders a static image from an ImageEditorConfig.
5
+ * This composition can be used with both client preview and server rendering
6
+ * for pixel-perfect consistency.
7
+ *
8
+ * NEW: Can also accept raw ImageEditorElement[] with relative positioning,
9
+ * which will be resolved internally for true single-source rendering.
10
+ */
11
+ import type { ImageEditorConfig, ImageEditorElement, FitMode, DynamicCropConfig } from '../types';
12
+ export interface ImageEditorCompositionProps {
13
+ /** The editor configuration to render (legacy format with pre-resolved segments) */
14
+ config?: ImageEditorConfig;
15
+ /** Map of source URLs keyed by segment ID or input reference */
16
+ sources?: Record<string, string>;
17
+ /** Optional scale multiplier for high-DPI rendering */
18
+ scale?: number;
19
+ /** Raw elements with relative positioning (will be resolved internally) */
20
+ elements?: ImageEditorElement[];
21
+ /** Canvas width (required when using elements) */
22
+ width?: number;
23
+ /** Canvas height (required when using elements) */
24
+ height?: number;
25
+ /** Background type: 'image' for image input, 'color' for solid color */
26
+ backgroundType?: 'image' | 'color';
27
+ /** Background color (hex) when backgroundType is 'color' */
28
+ backgroundColor?: string;
29
+ /** Background fit mode (when using elements) */
30
+ backgroundFit?: FitMode;
31
+ /** Background image URL (when using elements) */
32
+ backgroundUrl?: string;
33
+ /** Image URLs keyed by inputId (when using elements) */
34
+ imageUrls?: Record<string, string | null>;
35
+ /** Text values keyed by textInputId (when using elements, for autoWidth calculation) */
36
+ textValues?: Record<string, string>;
37
+ /** Dynamic crop configuration */
38
+ dynamicCrop?: DynamicCropConfig;
39
+ }
40
+ /**
41
+ * ImageEditorComposition renders a complete image editor configuration.
42
+ *
43
+ * Features:
44
+ * - Background image with fit mode
45
+ * - Multiple text and image elements
46
+ * - Z-index ordering
47
+ * - All text styling (fonts, colors, stroke, background, etc.)
48
+ * - All image styling (fit, opacity, rotation, border radius)
49
+ * - Automatic position resolution for relative positioning
50
+ *
51
+ * @example
52
+ * ```tsx
53
+ * import { ImageEditorComposition } from 'ugcinc-render/compositions';
54
+ *
55
+ * // NEW: Pass raw elements directly (preferred)
56
+ * <Player
57
+ * component={ImageEditorComposition}
58
+ * inputProps={{
59
+ * elements,
60
+ * width: 1080,
61
+ * height: 1920,
62
+ * backgroundUrl,
63
+ * imageUrls,
64
+ * textValues
65
+ * }}
66
+ * durationInFrames={1}
67
+ * fps={1}
68
+ * compositionWidth={1080}
69
+ * compositionHeight={1920}
70
+ * />
71
+ * ```
72
+ */
73
+ export declare function ImageEditorComposition({ config, sources, scale, elements, width, height, backgroundType, backgroundColor, backgroundFit, backgroundUrl, imageUrls, textValues, dynamicCrop, }: ImageEditorCompositionProps): import("react/jsx-runtime").JSX.Element;
74
+ export default ImageEditorComposition;
@@ -0,0 +1,351 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ImageEditorComposition = ImageEditorComposition;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ /**
6
+ * ImageEditorComposition
7
+ *
8
+ * A composition that renders a static image from an ImageEditorConfig.
9
+ * This composition can be used with both client preview and server rendering
10
+ * for pixel-perfect consistency.
11
+ *
12
+ * NEW: Can also accept raw ImageEditorElement[] with relative positioning,
13
+ * which will be resolved internally for true single-source rendering.
14
+ */
15
+ const react_1 = require("react");
16
+ const remotion_1 = require("remotion");
17
+ const TextElement_1 = require("../components/TextElement");
18
+ const ImageElement_1 = require("../components/ImageElement");
19
+ const positionResolver_1 = require("../utils/positionResolver");
20
+ const cropBounds_1 = require("../utils/cropBounds");
21
+ /**
22
+ * Get all segments from all channels, sorted by zIndex
23
+ */
24
+ function getSortedSegments(config) {
25
+ const allSegments = [];
26
+ for (const channel of config.channels) {
27
+ allSegments.push(...channel.segments);
28
+ }
29
+ // Sort by zIndex (lower first, so higher zIndex renders on top)
30
+ return allSegments.sort((a, b) => {
31
+ const aZ = a.zIndex ?? 0;
32
+ const bZ = b.zIndex ?? 0;
33
+ return aZ - bZ;
34
+ });
35
+ }
36
+ /**
37
+ * Convert a resolved ImageEditorElement to a TextSegment
38
+ */
39
+ function elementToTextSegment(elem) {
40
+ const segment = {
41
+ id: elem.id,
42
+ type: 'text',
43
+ source: '',
44
+ order: elem.zIndex,
45
+ offset: { type: 'absolute', value: 0 },
46
+ xOffset: elem.x,
47
+ yOffset: elem.y,
48
+ width: elem.width,
49
+ height: elem.height,
50
+ zIndex: elem.zIndex,
51
+ rotation: elem.rotation,
52
+ opacity: elem.opacity,
53
+ text: elem.text ?? '',
54
+ fontType: elem.font ?? 'tiktok',
55
+ fontSize: elem.fontSize ?? 40,
56
+ fontWeight: elem.fontWeight ?? 'normal',
57
+ color: elem.color ?? '#FFFFFF',
58
+ strokeColor: elem.strokeColor ?? '#000000',
59
+ strokeWidth: elem.outlineWidth ?? 0,
60
+ lineHeight: elem.lineHeight ?? 1.2,
61
+ letterSpacing: elem.letterSpacing ?? 0,
62
+ alignment: elem.textAlign ?? 'center',
63
+ verticalAlign: elem.verticalAlign ?? 'middle',
64
+ backgroundColor: elem.backgroundColor,
65
+ backgroundOpacity: elem.backgroundOpacity,
66
+ backgroundBorderRadius: typeof elem.backgroundBorderRadius === 'object' ? elem.backgroundBorderRadius : undefined,
67
+ paddingTop: elem.paddingTop,
68
+ paddingRight: elem.paddingRight,
69
+ paddingBottom: elem.paddingBottom,
70
+ paddingLeft: elem.paddingLeft,
71
+ multiLineExtraPaddingTop: elem.multiLineExtraPaddingTop,
72
+ multiLineExtraPaddingRight: elem.multiLineExtraPaddingRight,
73
+ multiLineExtraPaddingBottom: elem.multiLineExtraPaddingBottom,
74
+ multiLineExtraPaddingLeft: elem.multiLineExtraPaddingLeft,
75
+ autoWidth: elem.autoWidth,
76
+ boxAlign: elem.boxAlign,
77
+ };
78
+ // CONDENSED DEBUG LOG
79
+ console.log('[Composition] ELEMENT:', JSON.stringify({
80
+ id: elem.id,
81
+ text: (elem.text ?? '').substring(0, 20),
82
+ w: elem.width,
83
+ h: elem.height,
84
+ font: elem.font,
85
+ fontSize: elem.fontSize,
86
+ autoWidth: elem.autoWidth,
87
+ pL: elem.paddingLeft,
88
+ pR: elem.paddingRight,
89
+ }));
90
+ return segment;
91
+ }
92
+ /**
93
+ * Convert a resolved ImageEditorElement to an ImageSegment
94
+ */
95
+ function elementToImageSegment(elem, source) {
96
+ return {
97
+ id: elem.id,
98
+ type: 'image',
99
+ source,
100
+ order: elem.zIndex,
101
+ offset: { type: 'absolute', value: 0 },
102
+ xOffset: elem.x,
103
+ yOffset: elem.y,
104
+ width: elem.width,
105
+ height: elem.height,
106
+ zIndex: elem.zIndex,
107
+ rotation: elem.rotation,
108
+ opacity: elem.opacity,
109
+ fit: elem.fit ?? 'cover',
110
+ borderRadius: elem.borderRadius,
111
+ };
112
+ }
113
+ /**
114
+ * ImageEditorComposition renders a complete image editor configuration.
115
+ *
116
+ * Features:
117
+ * - Background image with fit mode
118
+ * - Multiple text and image elements
119
+ * - Z-index ordering
120
+ * - All text styling (fonts, colors, stroke, background, etc.)
121
+ * - All image styling (fit, opacity, rotation, border radius)
122
+ * - Automatic position resolution for relative positioning
123
+ *
124
+ * @example
125
+ * ```tsx
126
+ * import { ImageEditorComposition } from 'ugcinc-render/compositions';
127
+ *
128
+ * // NEW: Pass raw elements directly (preferred)
129
+ * <Player
130
+ * component={ImageEditorComposition}
131
+ * inputProps={{
132
+ * elements,
133
+ * width: 1080,
134
+ * height: 1920,
135
+ * backgroundUrl,
136
+ * imageUrls,
137
+ * textValues
138
+ * }}
139
+ * durationInFrames={1}
140
+ * fps={1}
141
+ * compositionWidth={1080}
142
+ * compositionHeight={1920}
143
+ * />
144
+ * ```
145
+ */
146
+ function ImageEditorComposition({ config, sources = {}, scale = 1,
147
+ // New direct element props
148
+ elements, width, height, backgroundType = 'image', backgroundColor, backgroundFit = 'cover', backgroundUrl, imageUrls = {}, textValues = {}, dynamicCrop, }) {
149
+ // Wait for fonts to load before rendering
150
+ // This prevents measurement using fallback fonts
151
+ const [fontsLoaded, setFontsLoaded] = (0, react_1.useState)(false);
152
+ (0, react_1.useEffect)(() => {
153
+ // Delay render until fonts are loaded
154
+ const handle = (0, remotion_1.delayRender)('Loading fonts...');
155
+ const loadFonts = async () => {
156
+ try {
157
+ // Check if we're in a browser environment
158
+ if (typeof document !== 'undefined' && document.fonts) {
159
+ console.log('[Composition] Waiting for fonts to load...');
160
+ // Wait for all fonts to be ready (this waits for CSS @font-face fonts)
161
+ await document.fonts.ready;
162
+ // Explicitly trigger loading of all our fonts at various weights
163
+ // This ensures the fonts are actually fetched, not just declared
164
+ const fontsToLoad = [
165
+ // SF Pro
166
+ 'normal 48px "SF Pro"',
167
+ 'bold 48px "SF Pro"',
168
+ '100 48px "SF Pro"',
169
+ '200 48px "SF Pro"',
170
+ '300 48px "SF Pro"',
171
+ '400 48px "SF Pro"',
172
+ '500 48px "SF Pro"',
173
+ '600 48px "SF Pro"',
174
+ '700 48px "SF Pro"',
175
+ '800 48px "SF Pro"',
176
+ '900 48px "SF Pro"',
177
+ // TikTok Sans
178
+ 'normal 48px "TikTok Sans"',
179
+ 'bold 48px "TikTok Sans"',
180
+ '400 48px "TikTok Sans"',
181
+ '500 48px "TikTok Sans"',
182
+ '600 48px "TikTok Sans"',
183
+ '700 48px "TikTok Sans"',
184
+ '800 48px "TikTok Sans"',
185
+ '900 48px "TikTok Sans"',
186
+ // Apple Color Emoji
187
+ 'normal 48px "Apple Color Emoji"',
188
+ ];
189
+ // Load all fonts in parallel, ignore failures (some weights may not exist)
190
+ await Promise.all(fontsToLoad.map(font => document.fonts.load(font).catch(() => [])));
191
+ // Wait again after loading to ensure they're all ready
192
+ await document.fonts.ready;
193
+ // Log final status
194
+ console.log('[Composition] Fonts loaded:', {
195
+ sfPro: document.fonts.check('normal 48px "SF Pro"'),
196
+ tiktok: document.fonts.check('normal 48px "TikTok Sans"'),
197
+ emoji: document.fonts.check('normal 48px "Apple Color Emoji"'),
198
+ totalFonts: document.fonts.size,
199
+ });
200
+ }
201
+ setFontsLoaded(true);
202
+ (0, remotion_1.continueRender)(handle);
203
+ }
204
+ catch (err) {
205
+ console.error('[Composition] Font loading error:', err);
206
+ // Continue anyway to avoid hanging
207
+ setFontsLoaded(true);
208
+ (0, remotion_1.continueRender)(handle);
209
+ }
210
+ };
211
+ loadFonts();
212
+ // Cleanup in case component unmounts
213
+ return () => {
214
+ try {
215
+ (0, remotion_1.continueRender)(handle);
216
+ }
217
+ catch {
218
+ // Handle may have already been continued
219
+ }
220
+ };
221
+ }, []);
222
+ // Get dimensions (from new props or legacy config)
223
+ const canvasWidth = width ?? config?.width ?? 1080;
224
+ const canvasHeight = height ?? config?.height ?? 1920;
225
+ // Resolve positions for raw elements (if provided)
226
+ const resolvedElements = (0, react_1.useMemo)(() => {
227
+ if (!elements)
228
+ return null;
229
+ const result = (0, positionResolver_1.resolveElementPositions)(elements, textValues);
230
+ if (result.errors.length > 0) {
231
+ console.warn('Position resolution errors:', result.errors);
232
+ }
233
+ return result.elements;
234
+ }, [elements, textValues]);
235
+ // Calculate crop bounds when dynamic crop is enabled
236
+ const cropBounds = (0, react_1.useMemo)(() => {
237
+ if (!(0, cropBounds_1.isDynamicCropEnabled)(dynamicCrop) || !resolvedElements)
238
+ return null;
239
+ return (0, cropBounds_1.calculateCropBounds)(resolvedElements, dynamicCrop, canvasWidth, canvasHeight, textValues);
240
+ }, [resolvedElements, dynamicCrop, canvasWidth, canvasHeight, textValues]);
241
+ // Convert resolved elements to segments (when using new format)
242
+ const segmentsFromElements = (0, react_1.useMemo)(() => {
243
+ if (!resolvedElements)
244
+ return null;
245
+ const segments = [];
246
+ for (const elem of resolvedElements) {
247
+ if (elem.type === 'text') {
248
+ // Get text content (either from textValues or element itself)
249
+ // If no text value and no elem.text, show {{textInputId}} as placeholder
250
+ const text = elem.textInputId && textValues[elem.textInputId]
251
+ ? textValues[elem.textInputId]
252
+ : elem.text ?? `{{${elem.textInputId ?? 'text'}}}`;
253
+ segments.push(elementToTextSegment({ ...elem, text }));
254
+ }
255
+ else if (elem.type === 'image') {
256
+ // Get image URL
257
+ const url = elem.inputId ? imageUrls[elem.inputId] ?? '' : '';
258
+ if (url) {
259
+ segments.push(elementToImageSegment(elem, url));
260
+ }
261
+ }
262
+ }
263
+ return segments.sort((a, b) => (a.zIndex ?? 0) - (b.zIndex ?? 0));
264
+ }, [resolvedElements, imageUrls, textValues]);
265
+ const bgFit = backgroundFit ?? 'cover';
266
+ const bgUrl = backgroundUrl ?? sources.background;
267
+ // Calculate crop offset for rendering
268
+ const cropOffsetX = cropBounds?.x ?? 0;
269
+ const cropOffsetY = cropBounds?.y ?? 0;
270
+ // Use new format if elements provided, otherwise use legacy config
271
+ const contentSegments = segmentsFromElements ?? (() => {
272
+ if (!config)
273
+ return [];
274
+ const sorted = getSortedSegments(config);
275
+ return sorted.filter((s) => s.id !== 'background');
276
+ })();
277
+ // Get legacy background segment (if using config)
278
+ const legacyBackgroundSegment = (0, react_1.useMemo)(() => {
279
+ if (!config || segmentsFromElements)
280
+ return null;
281
+ const sorted = getSortedSegments(config);
282
+ return sorted.find((s) => s.id === 'background' && s.type === 'image');
283
+ }, [config, segmentsFromElements]);
284
+ // Get source URL for a segment (legacy format)
285
+ const getSource = (segment) => {
286
+ if (segment.source)
287
+ return segment.source;
288
+ if (sources[segment.id])
289
+ return sources[segment.id];
290
+ const segmentAny = segment;
291
+ if (segmentAny.inputRef && sources[segmentAny.inputRef]) {
292
+ return sources[segmentAny.inputRef];
293
+ }
294
+ return undefined;
295
+ };
296
+ // Determine background color for the container
297
+ const containerBgColor = backgroundType === 'color' && backgroundColor
298
+ ? backgroundColor
299
+ : '#000000';
300
+ // Don't render content until fonts are loaded (prevents incorrect measurements)
301
+ if (!fontsLoaded) {
302
+ return ((0, jsx_runtime_1.jsx)(remotion_1.AbsoluteFill, { style: { backgroundColor: containerBgColor } }));
303
+ }
304
+ return ((0, jsx_runtime_1.jsx)(remotion_1.AbsoluteFill, { style: { backgroundColor: containerBgColor }, children: (0, jsx_runtime_1.jsxs)("div", { style: {
305
+ position: 'absolute',
306
+ left: -cropOffsetX * scale,
307
+ top: -cropOffsetY * scale,
308
+ width: canvasWidth * scale,
309
+ height: canvasHeight * scale,
310
+ }, children: [backgroundType === 'image' && bgUrl && segmentsFromElements && ((0, jsx_runtime_1.jsx)(remotion_1.Img, { src: bgUrl, style: {
311
+ position: 'absolute',
312
+ left: 0,
313
+ top: 0,
314
+ width: canvasWidth * scale,
315
+ height: canvasHeight * scale,
316
+ objectFit: bgFit,
317
+ } })), legacyBackgroundSegment && !segmentsFromElements && ((0, jsx_runtime_1.jsx)(BackgroundImage, { segment: legacyBackgroundSegment, src: getSource(legacyBackgroundSegment), width: canvasWidth, height: canvasHeight, scale: scale })), contentSegments.map((segment) => {
318
+ if (segment.type === 'text') {
319
+ return ((0, jsx_runtime_1.jsx)(TextElement_1.TextElement, { segment: segment, scale: scale }, segment.id));
320
+ }
321
+ if (segment.type === 'image') {
322
+ // For new format, source is already in segment
323
+ // For legacy format, look it up
324
+ const src = segment.source || getSource(segment);
325
+ if (!src) {
326
+ console.warn(`No source found for image segment: ${segment.id}`);
327
+ return null;
328
+ }
329
+ return ((0, jsx_runtime_1.jsx)(ImageElement_1.ImageElement, { segment: segment, src: src, scale: scale }, segment.id));
330
+ }
331
+ return null;
332
+ })] }) }));
333
+ }
334
+ /**
335
+ * Background image component
336
+ */
337
+ function BackgroundImage({ segment, src, width, height, scale, }) {
338
+ if (!src) {
339
+ return null;
340
+ }
341
+ const fit = segment.fit ?? 'cover';
342
+ return ((0, jsx_runtime_1.jsx)(remotion_1.Img, { src: src, style: {
343
+ position: 'absolute',
344
+ left: 0,
345
+ top: 0,
346
+ width: width * scale,
347
+ height: height * scale,
348
+ objectFit: fit,
349
+ } }));
350
+ }
351
+ exports.default = ImageEditorComposition;