ugcinc 3.84.6 → 3.85.1

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 +137 -18
  119. package/dist/types.js +58 -0
  120. package/package.json +20 -6
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Base DM Composition Component
3
+ *
4
+ * Shared component for DM-style compositions (Instagram, iMessage, etc.)
5
+ * Provides zoom/pan, debug overlay with crosshair, reference image overlay,
6
+ * font loading, and shared iOS chrome (status bar, home indicator).
7
+ */
8
+ import React from 'react';
9
+ export interface BaseDmCompositionProps {
10
+ /** Canvas width */
11
+ width: number;
12
+ /** Canvas height */
13
+ height: number;
14
+ /** Background color */
15
+ backgroundColor: string;
16
+ /** Show debug overlay with crosshair and coordinates */
17
+ showDebugOverlay?: boolean;
18
+ /** Reference image URL for overlay comparison */
19
+ referenceImageUrl?: string;
20
+ /** Show reference image overlay */
21
+ showReferenceImage?: boolean;
22
+ /** Reference image opacity (0-100) */
23
+ referenceOpacity?: number;
24
+ /** Current props for copy-to-clipboard feature in debug overlay */
25
+ currentProps?: Record<string, unknown>;
26
+ /** Children to render inside the zoomable/pannable content area */
27
+ children: React.ReactNode;
28
+ /** Time text to display */
29
+ time?: string;
30
+ /** Time text right X (right-aligned) */
31
+ timeRight?: number;
32
+ /** Time text bottom Y */
33
+ timeBottom?: number;
34
+ /** Time font size */
35
+ timeFontSize?: number;
36
+ /** Time letter spacing */
37
+ timeLetterSpacing?: number;
38
+ /** Time text color */
39
+ timeColor?: string;
40
+ /** No notifications icon top Y */
41
+ noNotisTop?: number;
42
+ /** No notifications icon bottom Y */
43
+ noNotisBottom?: number;
44
+ /** No notifications icon left X */
45
+ noNotisLeft?: number;
46
+ /** No notifications icon right X */
47
+ noNotisRight?: number;
48
+ /** Cell signal level (0-4) */
49
+ cellLevel?: number;
50
+ /** Cell bar 1 top Y */
51
+ cell1Top?: number;
52
+ /** Cell bar 1 bottom Y */
53
+ cell1Bottom?: number;
54
+ /** Cell bar 1 left X */
55
+ cell1Left?: number;
56
+ /** Cell bar 1 right X */
57
+ cell1Right?: number;
58
+ /** Cell bar 2 top Y */
59
+ cell2Top?: number;
60
+ /** Cell bar 2 bottom Y */
61
+ cell2Bottom?: number;
62
+ /** Cell bar 2 left X */
63
+ cell2Left?: number;
64
+ /** Cell bar 2 right X */
65
+ cell2Right?: number;
66
+ /** Cell bar 3 top Y */
67
+ cell3Top?: number;
68
+ /** Cell bar 3 bottom Y */
69
+ cell3Bottom?: number;
70
+ /** Cell bar 3 left X */
71
+ cell3Left?: number;
72
+ /** Cell bar 3 right X */
73
+ cell3Right?: number;
74
+ /** Cell bar 4 top Y */
75
+ cell4Top?: number;
76
+ /** Cell bar 4 bottom Y */
77
+ cell4Bottom?: number;
78
+ /** Cell bar 4 left X */
79
+ cell4Left?: number;
80
+ /** Cell bar 4 right X */
81
+ cell4Right?: number;
82
+ /** WiFi icon top Y */
83
+ wifiTop?: number;
84
+ /** WiFi icon bottom Y */
85
+ wifiBottom?: number;
86
+ /** WiFi icon left X */
87
+ wifiLeft?: number;
88
+ /** WiFi icon right X */
89
+ wifiRight?: number;
90
+ /** Battery icon top Y */
91
+ batteryTop?: number;
92
+ /** Battery icon bottom Y */
93
+ batteryBottom?: number;
94
+ /** Battery icon left X */
95
+ batteryLeft?: number;
96
+ /** Battery icon right X */
97
+ batteryRight?: number;
98
+ /** Home indicator top Y */
99
+ homeIndicatorTop?: number;
100
+ /** Home indicator bottom Y */
101
+ homeIndicatorBottom?: number;
102
+ /** Home indicator left X */
103
+ homeIndicatorLeft?: number;
104
+ /** Home indicator right X */
105
+ homeIndicatorRight?: number;
106
+ /** Home indicator color */
107
+ homeIndicatorColor?: string;
108
+ /** Status bar elements color (time, cell bars, icons) - defaults to white */
109
+ statusBarColor?: string;
110
+ }
111
+ export declare function BaseDmComposition({ width, height, backgroundColor, showDebugOverlay, referenceImageUrl, showReferenceImage, referenceOpacity, currentProps, children, time, timeRight, timeBottom, timeFontSize, timeLetterSpacing, timeColor, noNotisTop, noNotisBottom, noNotisLeft, noNotisRight, cellLevel, cell1Top, cell1Bottom, cell1Left, cell1Right, cell2Top, cell2Bottom, cell2Left, cell2Right, cell3Top, cell3Bottom, cell3Left, cell3Right, cell4Top, cell4Bottom, cell4Left, cell4Right, wifiTop, wifiBottom, wifiLeft, wifiRight, batteryTop, batteryBottom, batteryLeft, batteryRight, homeIndicatorTop, homeIndicatorBottom, homeIndicatorLeft, homeIndicatorRight, homeIndicatorColor, statusBarColor, }: BaseDmCompositionProps): import("react/jsx-runtime").JSX.Element | null;
112
+ export default BaseDmComposition;
@@ -0,0 +1,212 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BaseDmComposition = BaseDmComposition;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ /**
6
+ * Base DM Composition Component
7
+ *
8
+ * Shared component for DM-style compositions (Instagram, iMessage, etc.)
9
+ * Provides zoom/pan, debug overlay with crosshair, reference image overlay,
10
+ * font loading, and shared iOS chrome (status bar, home indicator).
11
+ */
12
+ const react_1 = require("react");
13
+ const remotion_1 = require("remotion");
14
+ const fonts_1 = require("../../utils/fonts");
15
+ const DebugOverlay_1 = require("./DebugOverlay");
16
+ function BaseDmComposition({ width, height, backgroundColor, showDebugOverlay = false, referenceImageUrl, showReferenceImage = false, referenceOpacity = 50, currentProps, children,
17
+ // Status bar - Time (defaults from IG DM)
18
+ time = '9:41', timeRight = 262, timeBottom = 125, timeFontSize = 52, timeLetterSpacing = 1.6, timeColor = '#ffffff',
19
+ // Status bar - No notifications
20
+ noNotisTop = 77, noNotisBottom = 120, noNotisLeft = 272, noNotisRight = 312,
21
+ // Status bar - Cell signal
22
+ cellLevel = 4, cell1Top = 102, cell1Bottom = 116, cell1Left = 865, cell1Right = 875, cell2Top = 95, cell2Bottom = 116, cell2Left = 881, cell2Right = 891, cell3Top = 87, cell3Bottom = 116, cell3Left = 897, cell3Right = 907, cell4Top = 79, cell4Bottom = 116, cell4Left = 913, cell4Right = 923,
23
+ // Status bar - WiFi
24
+ wifiTop = 79, wifiBottom = 116, wifiLeft = 945, wifiRight = 996,
25
+ // Status bar - Battery
26
+ batteryTop = 78, batteryBottom = 117, batteryLeft = 1018, batteryRight = 1100,
27
+ // Home indicator
28
+ homeIndicatorTop = 2583, homeIndicatorBottom = 2597, homeIndicatorLeft = 387, homeIndicatorRight = 818, homeIndicatorColor = '#ffffff',
29
+ // Status bar color
30
+ statusBarColor = '#ffffff', }) {
31
+ const [zoom, setZoom] = (0, react_1.useState)(100);
32
+ const [scrollX, setScrollX] = (0, react_1.useState)(0);
33
+ const [scrollY, setScrollY] = (0, react_1.useState)(0);
34
+ const [referenceVisible, setReferenceVisible] = (0, react_1.useState)(true);
35
+ const [fontsLoaded, setFontsLoaded] = (0, react_1.useState)(false);
36
+ // Clamp values to valid ranges
37
+ const clampedReferenceOpacity = Math.max(0, Math.min(100, referenceOpacity));
38
+ // Load fonts before rendering - required for accurate text measurement
39
+ (0, react_1.useEffect)(() => {
40
+ const handle = (0, remotion_1.delayRender)('Loading fonts for DmComposition');
41
+ const loadFonts = async () => {
42
+ await (0, fonts_1.preloadFonts)();
43
+ // Wait for document.fonts.ready to ensure fonts are fully available for DOM measurement
44
+ if (typeof document !== 'undefined' && document.fonts?.ready) {
45
+ await document.fonts.ready;
46
+ }
47
+ // Verify fonts are actually loaded
48
+ if (typeof document !== 'undefined' && document.fonts) {
49
+ const sfProLoaded = document.fonts.check('normal 51px "SF Pro"');
50
+ const sfProDisplayLoaded = document.fonts.check('normal 51px "SF Pro Display"');
51
+ const appleEmojiLoaded = document.fonts.check('normal 51px "Apple Color Emoji"');
52
+ console.log('[BaseDmComposition] Font check - SF Pro:', sfProLoaded, 'SF Pro Display:', sfProDisplayLoaded, 'Apple Color Emoji:', appleEmojiLoaded);
53
+ }
54
+ };
55
+ loadFonts()
56
+ .then(() => {
57
+ setFontsLoaded(true);
58
+ (0, remotion_1.continueRender)(handle);
59
+ })
60
+ .catch((err) => {
61
+ console.error('Failed to load fonts:', err);
62
+ // Continue anyway to avoid hanging
63
+ setFontsLoaded(true);
64
+ (0, remotion_1.continueRender)(handle);
65
+ });
66
+ }, []);
67
+ // Zoom callback for debug overlay
68
+ const handleZoomChange = (0, react_1.useCallback)((newZoom, newScrollX, newScrollY) => {
69
+ setZoom(newZoom);
70
+ setScrollX(newScrollX);
71
+ setScrollY(newScrollY);
72
+ }, []);
73
+ // Toggle reference image visibility
74
+ const handleToggleReference = (0, react_1.useCallback)(() => {
75
+ setReferenceVisible((prev) => !prev);
76
+ }, []);
77
+ const zoomScale = zoom / 100;
78
+ // Determine if we need to invert icons for dark status bar color
79
+ // If statusBarColor is black or very dark, invert the white icons
80
+ const isStatusBarDark = statusBarColor === '#000000' || statusBarColor === '#000' || statusBarColor.toLowerCase() === 'black';
81
+ const iconFilter = isStatusBarDark ? 'invert(1)' : 'none';
82
+ // Cell bar colors based on status bar color
83
+ const cellBarActiveColor = statusBarColor;
84
+ const cellBarInactiveColor = isStatusBarDark ? '#c0c0c0' : '#3c4043';
85
+ // Don't render until fonts are loaded
86
+ if (!fontsLoaded) {
87
+ return null;
88
+ }
89
+ return ((0, jsx_runtime_1.jsxs)(remotion_1.AbsoluteFill, { style: {
90
+ backgroundColor,
91
+ overflow: 'hidden',
92
+ }, children: [(0, jsx_runtime_1.jsxs)("div", { style: {
93
+ position: 'absolute',
94
+ top: 0,
95
+ left: 0,
96
+ width: width,
97
+ height: height,
98
+ transform: `translate(${-scrollX}px, ${-scrollY}px) scale(${zoomScale})`,
99
+ transformOrigin: 'top left',
100
+ }, children: [children, (0, jsx_runtime_1.jsx)("div", { style: {
101
+ position: 'absolute',
102
+ top: timeBottom - timeFontSize,
103
+ left: 0,
104
+ width: timeRight,
105
+ height: timeFontSize,
106
+ display: 'flex',
107
+ alignItems: 'center',
108
+ justifyContent: 'flex-end',
109
+ fontFamily: '"SF Pro", "SF Pro Display", -apple-system, BlinkMacSystemFont, sans-serif',
110
+ fontWeight: 600,
111
+ fontSize: timeFontSize,
112
+ letterSpacing: timeLetterSpacing,
113
+ color: statusBarColor,
114
+ zIndex: 30,
115
+ pointerEvents: 'none',
116
+ }, children: time }), (0, jsx_runtime_1.jsx)(remotion_1.Img, { src: (0, remotion_1.staticFile)('ig-no-notis.png'), style: {
117
+ position: 'absolute',
118
+ top: noNotisTop,
119
+ left: noNotisLeft,
120
+ width: noNotisRight - noNotisLeft,
121
+ height: noNotisBottom - noNotisTop,
122
+ objectFit: 'fill',
123
+ pointerEvents: 'none',
124
+ zIndex: 50,
125
+ filter: iconFilter,
126
+ } }), (0, jsx_runtime_1.jsx)("div", { style: {
127
+ position: 'absolute',
128
+ top: cell1Top,
129
+ left: cell1Left,
130
+ width: cell1Right - cell1Left,
131
+ height: cell1Bottom - cell1Top,
132
+ backgroundColor: cellLevel >= 1 ? cellBarActiveColor : cellBarInactiveColor,
133
+ borderRadius: 2,
134
+ pointerEvents: 'none',
135
+ zIndex: 50,
136
+ } }), (0, jsx_runtime_1.jsx)("div", { style: {
137
+ position: 'absolute',
138
+ top: cell2Top,
139
+ left: cell2Left,
140
+ width: cell2Right - cell2Left,
141
+ height: cell2Bottom - cell2Top,
142
+ backgroundColor: cellLevel >= 2 ? cellBarActiveColor : cellBarInactiveColor,
143
+ borderRadius: 2,
144
+ pointerEvents: 'none',
145
+ zIndex: 50,
146
+ } }), (0, jsx_runtime_1.jsx)("div", { style: {
147
+ position: 'absolute',
148
+ top: cell3Top,
149
+ left: cell3Left,
150
+ width: cell3Right - cell3Left,
151
+ height: cell3Bottom - cell3Top,
152
+ backgroundColor: cellLevel >= 3 ? cellBarActiveColor : cellBarInactiveColor,
153
+ borderRadius: 2,
154
+ pointerEvents: 'none',
155
+ zIndex: 50,
156
+ } }), (0, jsx_runtime_1.jsx)("div", { style: {
157
+ position: 'absolute',
158
+ top: cell4Top,
159
+ left: cell4Left,
160
+ width: cell4Right - cell4Left,
161
+ height: cell4Bottom - cell4Top,
162
+ backgroundColor: cellLevel >= 4 ? cellBarActiveColor : cellBarInactiveColor,
163
+ borderRadius: 2,
164
+ pointerEvents: 'none',
165
+ zIndex: 50,
166
+ } }), (0, jsx_runtime_1.jsx)(remotion_1.Img, { src: (0, remotion_1.staticFile)('ig-wifi.png'), style: {
167
+ position: 'absolute',
168
+ top: wifiTop,
169
+ left: wifiLeft,
170
+ width: wifiRight - wifiLeft,
171
+ height: wifiBottom - wifiTop,
172
+ objectFit: 'fill',
173
+ pointerEvents: 'none',
174
+ zIndex: 50,
175
+ filter: iconFilter,
176
+ } }), (0, jsx_runtime_1.jsx)(remotion_1.Img, { src: (0, remotion_1.staticFile)('ig-battery.png'), style: {
177
+ position: 'absolute',
178
+ top: batteryTop,
179
+ left: batteryLeft,
180
+ width: batteryRight - batteryLeft,
181
+ height: batteryBottom - batteryTop,
182
+ objectFit: 'fill',
183
+ pointerEvents: 'none',
184
+ zIndex: 50,
185
+ filter: iconFilter,
186
+ } }), (0, jsx_runtime_1.jsx)("div", { style: {
187
+ position: 'absolute',
188
+ top: homeIndicatorTop,
189
+ left: homeIndicatorLeft,
190
+ width: homeIndicatorRight - homeIndicatorLeft,
191
+ height: homeIndicatorBottom - homeIndicatorTop,
192
+ backgroundColor: homeIndicatorColor,
193
+ borderRadius: (homeIndicatorBottom - homeIndicatorTop) / 2,
194
+ pointerEvents: 'none',
195
+ zIndex: 50,
196
+ } }), referenceImageUrl && showReferenceImage && (!showDebugOverlay || referenceVisible) && ((0, jsx_runtime_1.jsx)("div", { style: {
197
+ position: 'absolute',
198
+ top: 0,
199
+ left: 0,
200
+ right: 0,
201
+ bottom: 0,
202
+ zIndex: 100,
203
+ pointerEvents: 'none',
204
+ opacity: clampedReferenceOpacity / 100,
205
+ }, children: (0, jsx_runtime_1.jsx)(remotion_1.Img, { src: referenceImageUrl, style: {
206
+ width: '100%',
207
+ height: '100%',
208
+ objectFit: 'cover',
209
+ imageRendering: 'pixelated',
210
+ } }) }))] }), showDebugOverlay && ((0, jsx_runtime_1.jsx)(DebugOverlay_1.DebugOverlay, { width: width, height: height, zoom: zoom, scrollX: scrollX, scrollY: scrollY, referenceVisible: referenceVisible, onZoomChange: handleZoomChange, onToggleReference: handleToggleReference, currentProps: currentProps }))] }));
211
+ }
212
+ exports.default = BaseDmComposition;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Debug Overlay Component
3
+ *
4
+ * Shows mouse coordinates, zoom controls, and pixel-snapped crosshair.
5
+ * Useful for matching elements to a reference screenshot.
6
+ */
7
+ interface DebugOverlayProps {
8
+ width: number;
9
+ height: number;
10
+ zoom: number;
11
+ scrollX: number;
12
+ scrollY: number;
13
+ referenceVisible: boolean;
14
+ onZoomChange: (zoom: number, scrollX: number, scrollY: number) => void;
15
+ onToggleReference: () => void;
16
+ /** Current prop values for copy-to-clipboard feature */
17
+ currentProps?: Record<string, unknown>;
18
+ }
19
+ export declare function DebugOverlay({ width, height, zoom, scrollX, scrollY, referenceVisible, onZoomChange, onToggleReference, currentProps, }: DebugOverlayProps): import("react/jsx-runtime").JSX.Element;
20
+ export {};
@@ -0,0 +1,258 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DebugOverlay = DebugOverlay;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ /**
6
+ * Debug Overlay Component
7
+ *
8
+ * Shows mouse coordinates, zoom controls, and pixel-snapped crosshair.
9
+ * Useful for matching elements to a reference screenshot.
10
+ */
11
+ const react_1 = require("react");
12
+ function DebugOverlay({ width, height, zoom, scrollX, scrollY, referenceVisible, onZoomChange, onToggleReference, currentProps, }) {
13
+ const [mousePos, setMousePos] = (0, react_1.useState)(null);
14
+ const [copyFeedback, setCopyFeedback] = (0, react_1.useState)(null);
15
+ // Store the screen position for crosshair (in percentage for accurate positioning)
16
+ const [crosshairPos, setCrosshairPos] = (0, react_1.useState)(null);
17
+ // Store viewport position for zoom calculations
18
+ const [viewportPos, setViewportPos] = (0, react_1.useState)(null);
19
+ // Pinned crosshair state (canvas coordinates)
20
+ const [pinnedPos, setPinnedPos] = (0, react_1.useState)(null);
21
+ const [pinnedCrosshairPos, setPinnedCrosshairPos] = (0, react_1.useState)(null);
22
+ // Drag state
23
+ const [isDragging, setIsDragging] = (0, react_1.useState)(false);
24
+ const lastDragPos = (0, react_1.useRef)(null);
25
+ const zoomScale = zoom / 100;
26
+ // Recalculate crosshair position when zoom/scroll changes
27
+ (0, react_1.useEffect)(() => {
28
+ if (mousePos === null)
29
+ return;
30
+ // Convert snapped canvas position back to screen position for crosshair
31
+ const snappedScreenX = (mousePos.x + 0.5) * zoomScale - scrollX;
32
+ const snappedScreenY = (mousePos.y + 0.5) * zoomScale - scrollY;
33
+ // Calculate the size of 1 canvas pixel in viewport space
34
+ const pixelWidth = zoomScale;
35
+ const pixelHeight = zoomScale;
36
+ setCrosshairPos({
37
+ xPercent: (snappedScreenX / width) * 100,
38
+ yPercent: (snappedScreenY / height) * 100,
39
+ pixelWidthPercent: (pixelWidth / width) * 100,
40
+ pixelHeightPercent: (pixelHeight / height) * 100,
41
+ });
42
+ }, [mousePos, zoomScale, scrollX, scrollY, width, height]);
43
+ // Recalculate pinned crosshair position when zoom/scroll changes
44
+ (0, react_1.useEffect)(() => {
45
+ if (pinnedPos === null) {
46
+ setPinnedCrosshairPos(null);
47
+ return;
48
+ }
49
+ // Convert pinned canvas position back to screen position
50
+ const snappedScreenX = (pinnedPos.x + 0.5) * zoomScale - scrollX;
51
+ const snappedScreenY = (pinnedPos.y + 0.5) * zoomScale - scrollY;
52
+ // Calculate the size of 1 canvas pixel in viewport space
53
+ const pixelWidth = zoomScale;
54
+ const pixelHeight = zoomScale;
55
+ setPinnedCrosshairPos({
56
+ xPercent: (snappedScreenX / width) * 100,
57
+ yPercent: (snappedScreenY / height) * 100,
58
+ pixelWidthPercent: (pixelWidth / width) * 100,
59
+ pixelHeightPercent: (pixelHeight / height) * 100,
60
+ });
61
+ }, [pinnedPos, zoomScale, scrollX, scrollY, width, height]);
62
+ const handleMouseMove = (0, react_1.useCallback)((e) => {
63
+ const rect = e.currentTarget.getBoundingClientRect();
64
+ // Screen position relative to overlay
65
+ const screenX = e.clientX - rect.left;
66
+ const screenY = e.clientY - rect.top;
67
+ // Remotion scales the preview to fit the panel
68
+ const remotionScaleX = width / rect.width;
69
+ const remotionScaleY = height / rect.height;
70
+ // Convert screen position to viewport position (in canvas coordinate space)
71
+ const vpX = screenX * remotionScaleX;
72
+ const vpY = screenY * remotionScaleY;
73
+ setViewportPos({ x: vpX, y: vpY });
74
+ // Apply zoom/scroll to get actual canvas position
75
+ const canvasX = (vpX + scrollX) / zoomScale;
76
+ const canvasY = (vpY + scrollY) / zoomScale;
77
+ // Snap to pixel grid (floor to get the pixel we're hovering over)
78
+ const snappedCanvasX = Math.floor(canvasX);
79
+ const snappedCanvasY = Math.floor(canvasY);
80
+ setMousePos({ x: snappedCanvasX, y: snappedCanvasY });
81
+ // Handle dragging
82
+ if (isDragging && lastDragPos.current) {
83
+ const deltaX = (e.clientX - lastDragPos.current.x) * remotionScaleX;
84
+ const deltaY = (e.clientY - lastDragPos.current.y) * remotionScaleY;
85
+ const newScrollX = Math.max(0, scrollX - deltaX);
86
+ const newScrollY = Math.max(0, scrollY - deltaY);
87
+ onZoomChange(zoom, newScrollX, newScrollY);
88
+ lastDragPos.current = { x: e.clientX, y: e.clientY };
89
+ }
90
+ }, [width, height, zoomScale, scrollX, scrollY, isDragging, zoom, onZoomChange]);
91
+ const handleMouseDown = (0, react_1.useCallback)((e) => {
92
+ // Don't start drag if clicking on interactive elements
93
+ const tagName = e.target.tagName;
94
+ if (tagName === 'BUTTON' || tagName === 'INPUT' || tagName === 'LABEL')
95
+ return;
96
+ e.preventDefault();
97
+ // Ctrl+click to pin crosshair
98
+ if (e.ctrlKey || e.metaKey) {
99
+ if (mousePos) {
100
+ setPinnedPos({ x: mousePos.x, y: mousePos.y });
101
+ }
102
+ return;
103
+ }
104
+ // Regular click clears pinned crosshair
105
+ if (pinnedPos) {
106
+ setPinnedPos(null);
107
+ return;
108
+ }
109
+ setIsDragging(true);
110
+ lastDragPos.current = { x: e.clientX, y: e.clientY };
111
+ }, [mousePos, pinnedPos]);
112
+ const handleMouseUp = (0, react_1.useCallback)(() => {
113
+ setIsDragging(false);
114
+ lastDragPos.current = null;
115
+ }, []);
116
+ const handleMouseLeave = (0, react_1.useCallback)(() => {
117
+ setMousePos(null);
118
+ setCrosshairPos(null);
119
+ setViewportPos(null);
120
+ setIsDragging(false);
121
+ lastDragPos.current = null;
122
+ }, []);
123
+ const handleWheel = (0, react_1.useCallback)((e) => {
124
+ e.preventDefault();
125
+ e.stopPropagation();
126
+ if (!viewportPos)
127
+ return;
128
+ const { x: vpX, y: vpY } = viewportPos;
129
+ // Calculate canvas position under mouse at current zoom
130
+ const canvasX = (vpX + scrollX) / zoomScale;
131
+ const canvasY = (vpY + scrollY) / zoomScale;
132
+ // Calculate new zoom (multiplicative 10% per scroll, max 10000% to see individual pixels)
133
+ const zoomFactor = e.deltaY > 0 ? 0.9 : 1.1;
134
+ const newZoom = Math.max(100, Math.min(10000, Math.round(zoom * zoomFactor)));
135
+ const newZoomScale = newZoom / 100;
136
+ // Calculate new scroll to keep canvas point under mouse
137
+ const newScrollX = Math.max(0, canvasX * newZoomScale - vpX);
138
+ const newScrollY = Math.max(0, canvasY * newZoomScale - vpY);
139
+ onZoomChange(newZoom, newScrollX, newScrollY);
140
+ }, [zoom, zoomScale, scrollX, scrollY, viewportPos, onZoomChange]);
141
+ const handleCopyDefaults = (0, react_1.useCallback)(() => {
142
+ if (!currentProps)
143
+ return;
144
+ // Format as TypeScript code for easy pasting
145
+ const lines = Object.entries(currentProps)
146
+ .filter(([key]) => !['showDebugOverlay', 'referenceImageUrl', 'showReferenceImage', 'referenceOpacity', 'durationInFrames', 'fps'].includes(key))
147
+ .map(([key, value]) => {
148
+ if (typeof value === 'string') {
149
+ return ` ${key}: '${value}',`;
150
+ }
151
+ return ` ${key}: ${value},`;
152
+ });
153
+ const code = lines.join('\n');
154
+ navigator.clipboard.writeText(code).then(() => {
155
+ setCopyFeedback('Copied!');
156
+ setTimeout(() => setCopyFeedback(null), 2000);
157
+ }).catch(() => {
158
+ setCopyFeedback('Failed to copy');
159
+ setTimeout(() => setCopyFeedback(null), 2000);
160
+ });
161
+ }, [currentProps]);
162
+ return ((0, jsx_runtime_1.jsxs)("div", { "data-debug-overlay-root": true, style: {
163
+ position: 'absolute',
164
+ top: 0,
165
+ left: 0,
166
+ right: 0,
167
+ bottom: 0,
168
+ zIndex: 200,
169
+ }, onMouseMove: handleMouseMove, onMouseDown: handleMouseDown, onMouseUp: handleMouseUp, onMouseLeave: handleMouseLeave, onWheel: handleWheel, children: [(0, jsx_runtime_1.jsx)("style", { children: `
170
+ [data-debug-overlay-root], [data-debug-overlay-root] * {
171
+ cursor: none !important;
172
+ }
173
+ ` }), pinnedCrosshairPos && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: {
174
+ position: 'absolute',
175
+ top: 0,
176
+ left: `${pinnedCrosshairPos.xPercent}%`,
177
+ width: `${Math.max(pinnedCrosshairPos.pixelWidthPercent, 0.1)}%`,
178
+ height: '100%',
179
+ backgroundColor: '#00FFFF',
180
+ pointerEvents: 'none',
181
+ transform: 'translateX(-50%)',
182
+ } }), (0, jsx_runtime_1.jsx)("div", { style: {
183
+ position: 'absolute',
184
+ top: `${pinnedCrosshairPos.yPercent}%`,
185
+ left: 0,
186
+ width: '100%',
187
+ height: `${Math.max(pinnedCrosshairPos.pixelHeightPercent, 0.1)}%`,
188
+ backgroundColor: '#00FFFF',
189
+ pointerEvents: 'none',
190
+ transform: 'translateY(-50%)',
191
+ } })] })), crosshairPos && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", { style: {
192
+ position: 'absolute',
193
+ top: 0,
194
+ left: `${crosshairPos.xPercent}%`,
195
+ width: `${Math.max(crosshairPos.pixelWidthPercent, 0.1)}%`,
196
+ height: '100%',
197
+ backgroundColor: '#FF0000',
198
+ pointerEvents: 'none',
199
+ transform: 'translateX(-50%)',
200
+ } }), (0, jsx_runtime_1.jsx)("div", { style: {
201
+ position: 'absolute',
202
+ top: `${crosshairPos.yPercent}%`,
203
+ left: 0,
204
+ width: '100%',
205
+ height: `${Math.max(crosshairPos.pixelHeightPercent, 0.1)}%`,
206
+ backgroundColor: '#FF0000',
207
+ pointerEvents: 'none',
208
+ transform: 'translateY(-50%)',
209
+ } })] })), mousePos && ((0, jsx_runtime_1.jsxs)("div", { style: {
210
+ position: 'absolute',
211
+ bottom: 32,
212
+ left: 32,
213
+ backgroundColor: 'rgba(0, 0, 0, 0.9)',
214
+ color: '#00FF00',
215
+ fontFamily: 'monospace',
216
+ fontSize: 48,
217
+ fontWeight: 'bold',
218
+ padding: '20px 32px',
219
+ borderRadius: 12,
220
+ pointerEvents: 'none',
221
+ border: '3px solid rgba(0, 255, 0, 0.5)',
222
+ minWidth: 280,
223
+ }, children: [(0, jsx_runtime_1.jsxs)("div", { children: ["X: ", mousePos.x] }), (0, jsx_runtime_1.jsxs)("div", { children: ["Y: ", mousePos.y] }), pinnedPos && ((0, jsx_runtime_1.jsxs)("div", { style: { marginTop: 16, paddingTop: 16, borderTop: '2px solid rgba(0, 255, 255, 0.5)' }, children: [(0, jsx_runtime_1.jsx)("div", { style: { color: '#00FFFF', fontSize: 32 }, children: "Pinned:" }), (0, jsx_runtime_1.jsxs)("div", { style: { color: '#00FFFF' }, children: ["X: ", pinnedPos.x] }), (0, jsx_runtime_1.jsxs)("div", { style: { color: '#00FFFF' }, children: ["Y: ", pinnedPos.y] })] }))] })), (0, jsx_runtime_1.jsxs)("div", { style: {
224
+ position: 'absolute',
225
+ bottom: 32,
226
+ right: 32,
227
+ backgroundColor: 'rgba(0, 0, 0, 0.9)',
228
+ color: '#FFFF00',
229
+ fontFamily: 'monospace',
230
+ fontSize: 40,
231
+ fontWeight: 'bold',
232
+ padding: '20px 32px',
233
+ borderRadius: 12,
234
+ border: '3px solid rgba(255, 255, 0, 0.5)',
235
+ }, children: [(0, jsx_runtime_1.jsxs)("div", { style: { pointerEvents: 'none' }, children: [width, " x ", height] }), (0, jsx_runtime_1.jsxs)("div", { style: { color: '#00FFFF', marginTop: 12, pointerEvents: 'none' }, children: ["Zoom: ", zoom, "%"] }), (0, jsx_runtime_1.jsx)("div", { style: { color: '#888', fontSize: 24, marginTop: 8, pointerEvents: 'none' }, children: "Scroll to zoom, drag to pan" }), (0, jsx_runtime_1.jsxs)("label", { style: {
236
+ display: 'flex',
237
+ alignItems: 'center',
238
+ gap: 12,
239
+ marginTop: 16,
240
+ cursor: 'pointer',
241
+ userSelect: 'none',
242
+ }, children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: referenceVisible, onChange: onToggleReference, style: {
243
+ width: 28,
244
+ height: 28,
245
+ cursor: 'pointer',
246
+ accentColor: '#4CAF50',
247
+ } }), (0, jsx_runtime_1.jsx)("span", { style: { color: '#FFFFFF', fontSize: 28 }, children: "Show Reference" })] }), currentProps && ((0, jsx_runtime_1.jsx)("button", { onClick: handleCopyDefaults, style: {
248
+ marginTop: 16,
249
+ padding: '12px 24px',
250
+ backgroundColor: copyFeedback === 'Copied!' ? '#4CAF50' : '#333',
251
+ color: '#FFFFFF',
252
+ border: '2px solid #555',
253
+ borderRadius: 6,
254
+ cursor: 'pointer',
255
+ fontSize: 24,
256
+ fontFamily: 'monospace',
257
+ }, children: copyFeedback || 'Copy Defaults' }))] })] }));
258
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * DmComposition - Shared components for DM-style compositions
3
+ */
4
+ export { BaseDmComposition } from './BaseDmComposition';
5
+ export type { BaseDmCompositionProps } from './BaseDmComposition';
6
+ export { DebugOverlay } from './DebugOverlay';
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ /**
3
+ * DmComposition - Shared components for DM-style compositions
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DebugOverlay = exports.BaseDmComposition = void 0;
7
+ var BaseDmComposition_1 = require("./BaseDmComposition");
8
+ Object.defineProperty(exports, "BaseDmComposition", { enumerable: true, get: function () { return BaseDmComposition_1.BaseDmComposition; } });
9
+ var DebugOverlay_1 = require("./DebugOverlay");
10
+ Object.defineProperty(exports, "DebugOverlay", { enumerable: true, get: function () { return DebugOverlay_1.DebugOverlay; } });
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Convert iMessage DM Composition props to ImageEditorElements
3
+ *
4
+ * This module transforms the composition props into renderable message elements.
5
+ * Header, footer, and status bar elements are rendered directly in the composition JSX.
6
+ */
7
+ import type { ImageEditorElement } from '../../types/element';
8
+ import type { IMessageDmCompositionProps } from './types';
9
+ /** Tail render data for SVG rendering */
10
+ export interface TailRenderData {
11
+ id: string;
12
+ isUser: boolean;
13
+ messageLeft: number;
14
+ messageRight: number;
15
+ messageBottom: number;
16
+ }
17
+ /** Result of converting props to elements */
18
+ export interface ConversionResult {
19
+ elements: ImageEditorElement[];
20
+ imageUrls: Record<string, string>;
21
+ tails: TailRenderData[];
22
+ width: number;
23
+ height: number;
24
+ }
25
+ /** Input ID prefix for sender images */
26
+ export declare const SENDER_IMAGE_INPUT_ID_PREFIX = "sender-image-";
27
+ export declare function convertPropsToElements(props: IMessageDmCompositionProps): ConversionResult;