deio-scroll 1.0.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 (205) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -0
  3. package/dist/api/server.d.ts +3 -0
  4. package/dist/api/server.d.ts.map +1 -0
  5. package/dist/api/server.js +393 -0
  6. package/dist/api/server.js.map +1 -0
  7. package/dist/artifacts/store.d.ts +24 -0
  8. package/dist/artifacts/store.d.ts.map +1 -0
  9. package/dist/artifacts/store.js +43 -0
  10. package/dist/artifacts/store.js.map +1 -0
  11. package/dist/browser/componentInteraction.d.ts +24 -0
  12. package/dist/browser/componentInteraction.d.ts.map +1 -0
  13. package/dist/browser/componentInteraction.js +328 -0
  14. package/dist/browser/componentInteraction.js.map +1 -0
  15. package/dist/browser/composition.d.ts +42 -0
  16. package/dist/browser/composition.d.ts.map +1 -0
  17. package/dist/browser/composition.js +132 -0
  18. package/dist/browser/composition.js.map +1 -0
  19. package/dist/browser/cookies.d.ts +3 -0
  20. package/dist/browser/cookies.d.ts.map +1 -0
  21. package/dist/browser/cookies.js +20 -0
  22. package/dist/browser/cookies.js.map +1 -0
  23. package/dist/browser/curves.d.ts +4 -0
  24. package/dist/browser/curves.d.ts.map +1 -0
  25. package/dist/browser/curves.js +35 -0
  26. package/dist/browser/curves.js.map +1 -0
  27. package/dist/browser/detectScrollMode.d.ts +5 -0
  28. package/dist/browser/detectScrollMode.d.ts.map +1 -0
  29. package/dist/browser/detectScrollMode.js +61 -0
  30. package/dist/browser/detectScrollMode.js.map +1 -0
  31. package/dist/browser/directionGuardrails.d.ts +22 -0
  32. package/dist/browser/directionGuardrails.d.ts.map +1 -0
  33. package/dist/browser/directionGuardrails.js +99 -0
  34. package/dist/browser/directionGuardrails.js.map +1 -0
  35. package/dist/browser/goto.d.ts +9 -0
  36. package/dist/browser/goto.d.ts.map +1 -0
  37. package/dist/browser/goto.js +62 -0
  38. package/dist/browser/goto.js.map +1 -0
  39. package/dist/browser/hydrate.d.ts +8 -0
  40. package/dist/browser/hydrate.d.ts.map +1 -0
  41. package/dist/browser/hydrate.js +73 -0
  42. package/dist/browser/hydrate.js.map +1 -0
  43. package/dist/browser/mediaClock.d.ts +9 -0
  44. package/dist/browser/mediaClock.d.ts.map +1 -0
  45. package/dist/browser/mediaClock.js +86 -0
  46. package/dist/browser/mediaClock.js.map +1 -0
  47. package/dist/browser/motion.d.ts +21 -0
  48. package/dist/browser/motion.d.ts.map +1 -0
  49. package/dist/browser/motion.js +42 -0
  50. package/dist/browser/motion.js.map +1 -0
  51. package/dist/browser/networkPolicy.d.ts +11 -0
  52. package/dist/browser/networkPolicy.d.ts.map +1 -0
  53. package/dist/browser/networkPolicy.js +119 -0
  54. package/dist/browser/networkPolicy.js.map +1 -0
  55. package/dist/browser/prime.d.ts +3 -0
  56. package/dist/browser/prime.d.ts.map +1 -0
  57. package/dist/browser/prime.js +13 -0
  58. package/dist/browser/prime.js.map +1 -0
  59. package/dist/browser/sanitize.d.ts +3 -0
  60. package/dist/browser/sanitize.d.ts.map +1 -0
  61. package/dist/browser/sanitize.js +37 -0
  62. package/dist/browser/sanitize.js.map +1 -0
  63. package/dist/browser/scroll.d.ts +29 -0
  64. package/dist/browser/scroll.d.ts.map +1 -0
  65. package/dist/browser/scroll.js +420 -0
  66. package/dist/browser/scroll.js.map +1 -0
  67. package/dist/browser/scrollEasing.d.ts +5 -0
  68. package/dist/browser/scrollEasing.d.ts.map +1 -0
  69. package/dist/browser/scrollEasing.js +40 -0
  70. package/dist/browser/scrollEasing.js.map +1 -0
  71. package/dist/browser/scrollReadiness.d.ts +25 -0
  72. package/dist/browser/scrollReadiness.d.ts.map +1 -0
  73. package/dist/browser/scrollReadiness.js +105 -0
  74. package/dist/browser/scrollReadiness.js.map +1 -0
  75. package/dist/browser/urlGuard.d.ts +4 -0
  76. package/dist/browser/urlGuard.d.ts.map +1 -0
  77. package/dist/browser/urlGuard.js +22 -0
  78. package/dist/browser/urlGuard.js.map +1 -0
  79. package/dist/browser/virtualScroll.d.ts +19 -0
  80. package/dist/browser/virtualScroll.d.ts.map +1 -0
  81. package/dist/browser/virtualScroll.js +50 -0
  82. package/dist/browser/virtualScroll.js.map +1 -0
  83. package/dist/capture/detectMargins.d.ts +6 -0
  84. package/dist/capture/detectMargins.d.ts.map +1 -0
  85. package/dist/capture/detectMargins.js +145 -0
  86. package/dist/capture/detectMargins.js.map +1 -0
  87. package/dist/capture/frameRecorder.d.ts +29 -0
  88. package/dist/capture/frameRecorder.d.ts.map +1 -0
  89. package/dist/capture/frameRecorder.js +74 -0
  90. package/dist/capture/frameRecorder.js.map +1 -0
  91. package/dist/capture/stitchFrames.d.ts +9 -0
  92. package/dist/capture/stitchFrames.d.ts.map +1 -0
  93. package/dist/capture/stitchFrames.js +62 -0
  94. package/dist/capture/stitchFrames.js.map +1 -0
  95. package/dist/cli.d.ts +3 -0
  96. package/dist/cli.d.ts.map +1 -0
  97. package/dist/cli.js +329 -0
  98. package/dist/cli.js.map +1 -0
  99. package/dist/config/browserLaunch.d.ts +13 -0
  100. package/dist/config/browserLaunch.d.ts.map +1 -0
  101. package/dist/config/browserLaunch.js +63 -0
  102. package/dist/config/browserLaunch.js.map +1 -0
  103. package/dist/config/recordingProfile.d.ts +10 -0
  104. package/dist/config/recordingProfile.d.ts.map +1 -0
  105. package/dist/config/recordingProfile.js +25 -0
  106. package/dist/config/recordingProfile.js.map +1 -0
  107. package/dist/config/runtimeMode.d.ts +2 -0
  108. package/dist/config/runtimeMode.d.ts.map +1 -0
  109. package/dist/config/runtimeMode.js +4 -0
  110. package/dist/config/runtimeMode.js.map +1 -0
  111. package/dist/config/virtualScroll.d.ts +8 -0
  112. package/dist/config/virtualScroll.d.ts.map +1 -0
  113. package/dist/config/virtualScroll.js +19 -0
  114. package/dist/config/virtualScroll.js.map +1 -0
  115. package/dist/contracts.d.ts +157 -0
  116. package/dist/contracts.d.ts.map +1 -0
  117. package/dist/contracts.js +136 -0
  118. package/dist/contracts.js.map +1 -0
  119. package/dist/editor/compileVideo.d.ts +21 -0
  120. package/dist/editor/compileVideo.d.ts.map +1 -0
  121. package/dist/editor/compileVideo.js +104 -0
  122. package/dist/editor/compileVideo.js.map +1 -0
  123. package/dist/editor/composeComparison.d.ts +30 -0
  124. package/dist/editor/composeComparison.d.ts.map +1 -0
  125. package/dist/editor/composeComparison.js +315 -0
  126. package/dist/editor/composeComparison.js.map +1 -0
  127. package/dist/editor/composeResponsiveness.d.ts +19 -0
  128. package/dist/editor/composeResponsiveness.d.ts.map +1 -0
  129. package/dist/editor/composeResponsiveness.js +198 -0
  130. package/dist/editor/composeResponsiveness.js.map +1 -0
  131. package/dist/editor/frameVideo.d.ts +11 -0
  132. package/dist/editor/frameVideo.d.ts.map +1 -0
  133. package/dist/editor/frameVideo.js +181 -0
  134. package/dist/editor/frameVideo.js.map +1 -0
  135. package/dist/index.d.ts +3 -0
  136. package/dist/index.d.ts.map +1 -0
  137. package/dist/index.js +2 -0
  138. package/dist/index.js.map +1 -0
  139. package/dist/inspection/inspectWebsite.d.ts +21 -0
  140. package/dist/inspection/inspectWebsite.d.ts.map +1 -0
  141. package/dist/inspection/inspectWebsite.js +412 -0
  142. package/dist/inspection/inspectWebsite.js.map +1 -0
  143. package/dist/jobs/manager.d.ts +123 -0
  144. package/dist/jobs/manager.d.ts.map +1 -0
  145. package/dist/jobs/manager.js +378 -0
  146. package/dist/jobs/manager.js.map +1 -0
  147. package/dist/jobs/store.d.ts +150 -0
  148. package/dist/jobs/store.d.ts.map +1 -0
  149. package/dist/jobs/store.js +446 -0
  150. package/dist/jobs/store.js.map +1 -0
  151. package/dist/jobs/thumbnail.d.ts +2 -0
  152. package/dist/jobs/thumbnail.d.ts.map +1 -0
  153. package/dist/jobs/thumbnail.js +36 -0
  154. package/dist/jobs/thumbnail.js.map +1 -0
  155. package/dist/pipeline/processRecordingRequest.d.ts +4 -0
  156. package/dist/pipeline/processRecordingRequest.d.ts.map +1 -0
  157. package/dist/pipeline/processRecordingRequest.js +17 -0
  158. package/dist/pipeline/processRecordingRequest.js.map +1 -0
  159. package/dist/pipeline/recordComparison.d.ts +4 -0
  160. package/dist/pipeline/recordComparison.d.ts.map +1 -0
  161. package/dist/pipeline/recordComparison.js +99 -0
  162. package/dist/pipeline/recordComparison.js.map +1 -0
  163. package/dist/pipeline/recordResponsiveness.d.ts +4 -0
  164. package/dist/pipeline/recordResponsiveness.d.ts.map +1 -0
  165. package/dist/pipeline/recordResponsiveness.js +122 -0
  166. package/dist/pipeline/recordResponsiveness.js.map +1 -0
  167. package/dist/pipeline/recordWebsite.d.ts +11 -0
  168. package/dist/pipeline/recordWebsite.d.ts.map +1 -0
  169. package/dist/pipeline/recordWebsite.js +446 -0
  170. package/dist/pipeline/recordWebsite.js.map +1 -0
  171. package/dist/pipeline/styleRecording.d.ts +12 -0
  172. package/dist/pipeline/styleRecording.d.ts.map +1 -0
  173. package/dist/pipeline/styleRecording.js +59 -0
  174. package/dist/pipeline/styleRecording.js.map +1 -0
  175. package/dist/transcode/ffmpeg.d.ts +4 -0
  176. package/dist/transcode/ffmpeg.d.ts.map +1 -0
  177. package/dist/transcode/ffmpeg.js +62 -0
  178. package/dist/transcode/ffmpeg.js.map +1 -0
  179. package/dist/transcode/probe.d.ts +7 -0
  180. package/dist/transcode/probe.d.ts.map +1 -0
  181. package/dist/transcode/probe.js +91 -0
  182. package/dist/transcode/probe.js.map +1 -0
  183. package/dist/transcode/quality.d.ts +8 -0
  184. package/dist/transcode/quality.d.ts.map +1 -0
  185. package/dist/transcode/quality.js +13 -0
  186. package/dist/transcode/quality.js.map +1 -0
  187. package/dist/types.d.ts +302 -0
  188. package/dist/types.d.ts.map +1 -0
  189. package/dist/types.js +2 -0
  190. package/dist/types.js.map +1 -0
  191. package/dist/worker.d.ts +3 -0
  192. package/dist/worker.d.ts.map +1 -0
  193. package/dist/worker.js +22 -0
  194. package/dist/worker.js.map +1 -0
  195. package/package.json +63 -0
  196. package/public/assets/index-C63t4P1L.css +1 -0
  197. package/public/assets/index-Sfgf7dSH.js +9 -0
  198. package/public/background_presets/gray_noise_gradient.png +0 -0
  199. package/public/background_presets/paper_blue.png +0 -0
  200. package/public/background_presets/red_blocks_gradient.png +0 -0
  201. package/public/deio-scroll-mark.svg +12 -0
  202. package/public/favicon.svg +1 -0
  203. package/public/icons.svg +24 -0
  204. package/public/index.html +16 -0
  205. package/public/scrollizard-mark.png +0 -0
@@ -0,0 +1,315 @@
1
+ import { spawn } from "node:child_process";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ /**
5
+ * Presents two captures as equal cards on one editorial canvas. Both websites
6
+ * are still recorded at the selected full viewport; composition happens only
7
+ * after capture, so the comparison never changes either responsive breakpoint.
8
+ *
9
+ * When primaryLogoDataUrl / secondaryLogoDataUrl are provided, the image is
10
+ * decoded and placed as a scaled overlay in the header bar instead of the
11
+ * coloured text badge. The text label beside it is always shown.
12
+ */
13
+ export async function composeComparison(options) {
14
+ const { primaryPath, secondaryPath, outputPath, fps, durationMs, primaryLabel, secondaryLabel, primaryLogo, secondaryLogo, primaryLogoDataUrl, secondaryLogoDataUrl, signal, } = options;
15
+ const width = even(options.width);
16
+ const height = even(options.height);
17
+ const outerMargin = even(Math.round(width * 0.05));
18
+ const panelGap = even(Math.round(width * 0.022));
19
+ const panelTop = even(Math.round(height * 0.145));
20
+ const bottomMargin = even(Math.round(height * 0.045));
21
+ const panelWidth = even(Math.floor((width - outerMargin * 2 - panelGap) / 2));
22
+ const panelHeight = even(height - panelTop - bottomMargin);
23
+ const secondaryX = outerMargin + panelWidth + panelGap;
24
+ const fontSize = Math.max(20, Math.round(height * 0.047));
25
+ const sideBadgeSize = Math.max(22, Math.round(height * 0.045));
26
+ const cornerRadius = Math.max(12, Math.round(Math.min(panelWidth, panelHeight) * 0.035));
27
+ const durationSeconds = Math.max(0.1, durationMs / 1_000).toFixed(3);
28
+ const outputDir = path.dirname(outputPath);
29
+ await fs.mkdir(outputDir, { recursive: true });
30
+ // Subtle drop shadow: a blurred, semi-transparent copy of each panel is placed
31
+ // slightly below the panel itself — mirroring the CSS box-shadow on the UI preview.
32
+ const shadowOffsetY = Math.max(4, Math.round(height * 0.005));
33
+ const shadowBlur = Math.max(8, Math.round(height * 0.012));
34
+ const shadowAlpha = 0.22; // opacity of the blurred shadow layer
35
+ // --- Logo text fallbacks ---
36
+ const primaryLogoText = (primaryLogo || "A").trim() || "A";
37
+ const secondaryLogoText = (secondaryLogo || "B").trim() || "B";
38
+ const cleanPrimaryLogo = primaryLogoText.replaceAll("'", "\\'");
39
+ const cleanSecondaryLogo = secondaryLogoText.replaceAll("'", "\\'");
40
+ const primaryBadgeW = primaryLogoText.length > 1
41
+ ? Math.max(sideBadgeSize, Math.round(sideBadgeSize * (0.4 + 0.6 * primaryLogoText.length)))
42
+ : sideBadgeSize;
43
+ const secondaryBadgeW = secondaryLogoText.length > 1
44
+ ? Math.max(sideBadgeSize, Math.round(sideBadgeSize * (0.4 + 0.6 * secondaryLogoText.length)))
45
+ : sideBadgeSize;
46
+ // --- Temp files ---
47
+ const primaryLabelPath = path.join(outputDir, ".comparison-primary.txt");
48
+ const secondaryLabelPath = path.join(outputDir, ".comparison-secondary.txt");
49
+ const maskPath = path.join(outputDir, ".comparison-mask.png");
50
+ // Logo images: write raw bytes with the correct extension, then convert to PNG via ffmpeg.
51
+ // This handles PNG, JPEG, WebP, and SVG (if librsvg is available) uniformly since ffmpeg
52
+ // can reliably probe any of these formats when the extension matches, and the PNG output
53
+ // is guaranteed to work with -loop 1 in the main composition.
54
+ const primaryLogoRaw = primaryLogoDataUrl
55
+ ? path.join(outputDir, `.comparison-logo-primary-raw${mimeToExt(primaryLogoDataUrl)}`)
56
+ : undefined;
57
+ const primaryLogoPath = primaryLogoDataUrl
58
+ ? path.join(outputDir, ".comparison-logo-primary.png")
59
+ : undefined;
60
+ const secondaryLogoRaw = secondaryLogoDataUrl
61
+ ? path.join(outputDir, `.comparison-logo-secondary-raw${mimeToExt(secondaryLogoDataUrl)}`)
62
+ : undefined;
63
+ const secondaryLogoPath = secondaryLogoDataUrl
64
+ ? path.join(outputDir, ".comparison-logo-secondary.png")
65
+ : undefined;
66
+ await Promise.all([
67
+ fs.writeFile(primaryLabelPath, primaryLabel.replace(/\s+/g, " "), "utf8"),
68
+ fs.writeFile(secondaryLabelPath, secondaryLabel.replace(/\s+/g, " "), "utf8"),
69
+ primaryLogoRaw && primaryLogoDataUrl
70
+ ? fs.writeFile(primaryLogoRaw, dataUrlToBuffer(primaryLogoDataUrl))
71
+ : Promise.resolve(),
72
+ secondaryLogoRaw && secondaryLogoDataUrl
73
+ ? fs.writeFile(secondaryLogoRaw, dataUrlToBuffer(secondaryLogoDataUrl))
74
+ : Promise.resolve(),
75
+ ]);
76
+ // Convert raw logo images to PNG so ffmpeg can reliably decode them as still frames.
77
+ await Promise.all([
78
+ primaryLogoRaw && primaryLogoPath
79
+ ? convertImageToPng(primaryLogoRaw, primaryLogoPath, signal)
80
+ : Promise.resolve(),
81
+ secondaryLogoRaw && secondaryLogoPath
82
+ ? convertImageToPng(secondaryLogoRaw, secondaryLogoPath, signal)
83
+ : Promise.resolve(),
84
+ ]);
85
+ await createRoundedMask(maskPath, panelWidth, panelHeight, cornerRadius, signal);
86
+ // --- Build ffmpeg inputs & filter ---
87
+ const primaryText = escapeFilterPath(primaryLabelPath);
88
+ const secondaryText = escapeFilterPath(secondaryLabelPath);
89
+ // Scale each panel video to fit within the panel (letterboxed, no crop) and centre it.
90
+ // The canvas background color is used as padding so there's no black bars.
91
+ const panelBg = "0xf1f4ed";
92
+ const panel = (input, mask, output) => `[${input}]setpts=PTS-STARTPTS,tpad=stop_mode=clone:stop_duration=${durationSeconds},` +
93
+ `trim=duration=${durationSeconds},scale=${panelWidth}:${panelHeight}:force_original_aspect_ratio=decrease:` +
94
+ `flags=lanczos,pad=${panelWidth}:${panelHeight}:(ow-iw)/2:(oh-ih)/2:color=${panelBg},` +
95
+ `setsar=1,format=rgba[${output}-base];` +
96
+ `[${output}-base][${mask}]alphamerge[${output}]`;
97
+ const labelY = Math.max(8, Math.round((panelTop - fontSize) / 2));
98
+ // Logo image is scaled to a square that fits within sideBadgeSize, preserving aspect ratio.
99
+ const logoImgSize = sideBadgeSize;
100
+ // Build static input list: 0=primary video, 1=secondary video, 2=mask, then optional logos.
101
+ const extraInputs = [];
102
+ let nextInput = 3; // 0,1,2 are already used
103
+ let primaryLogoInputIdx;
104
+ if (primaryLogoPath) {
105
+ extraInputs.push("-loop", "1", "-framerate", String(fps), "-i", primaryLogoPath);
106
+ primaryLogoInputIdx = nextInput++;
107
+ }
108
+ let secondaryLogoInputIdx;
109
+ if (secondaryLogoPath) {
110
+ extraInputs.push("-loop", "1", "-framerate", String(fps), "-i", secondaryLogoPath);
111
+ secondaryLogoInputIdx = nextInput++;
112
+ }
113
+ // Build filter_complex segments
114
+ const filterParts = [
115
+ "[2:v]format=gray,split=2[mask-a][mask-b]",
116
+ panel("0:v", "mask-a", "left"),
117
+ panel("1:v", "mask-b", "right"),
118
+ `color=c=0xf1f4ed:s=${width}x${height}:r=${fps}:d=${durationSeconds}[canvas]`,
119
+ ];
120
+ // Build header filter: only draw the coloured badge box when no image logo is provided.
121
+ // When an image logo is used, the image is overlaid directly on the canvas background
122
+ // (no coloured rectangle behind it) so logos appear without any background colour.
123
+ const headerParts = [];
124
+ const gap = Math.round(width * 0.012);
125
+ // Primary Side Centering
126
+ const primaryTextW = estimateTextWidth(primaryLabel, fontSize);
127
+ const primaryLogoW = primaryLogoPath ? logoImgSize : primaryBadgeW;
128
+ const primaryTotalW = primaryLogoW + gap + primaryTextW;
129
+ const primaryCenter = outerMargin + Math.round(panelWidth / 2);
130
+ const primaryLogoX = primaryCenter - Math.round(primaryTotalW / 2);
131
+ const primaryLabelX = primaryLogoX + primaryLogoW + gap;
132
+ if (!primaryLogoPath) {
133
+ headerParts.push(`drawbox=x=${primaryLogoX}:y=${labelY}:w=${primaryBadgeW}:h=${sideBadgeSize}:color=0x3158c9:t=fill`, `drawtext=text='${cleanPrimaryLogo}':expansion=none:fontcolor=white:` +
134
+ `fontsize=${Math.round(sideBadgeSize * 0.52)}:x=${primaryLogoX}+(${primaryBadgeW}-text_w)/2:` +
135
+ `y=${labelY}+(${sideBadgeSize}-text_h)/2`);
136
+ }
137
+ headerParts.push(`drawtext=textfile='${primaryText}':expansion=none:fontcolor=0x171914:fontsize=${fontSize}:` +
138
+ `x=${primaryLabelX}:y=${labelY}+(${sideBadgeSize}-text_h)/2`);
139
+ // Secondary Side Centering
140
+ const secondaryTextW = estimateTextWidth(secondaryLabel, fontSize);
141
+ const secondaryLogoW = secondaryLogoPath ? logoImgSize : secondaryBadgeW;
142
+ const secondaryTotalW = secondaryLogoW + gap + secondaryTextW;
143
+ const secondaryCenter = secondaryX + Math.round(panelWidth / 2);
144
+ const secondaryLogoX = secondaryCenter - Math.round(secondaryTotalW / 2);
145
+ const secondaryLabelX = secondaryLogoX + secondaryLogoW + gap;
146
+ if (!secondaryLogoPath) {
147
+ headerParts.push(`drawbox=x=${secondaryLogoX}:y=${labelY}:w=${secondaryBadgeW}:h=${sideBadgeSize}:color=0x087e72:t=fill`, `drawtext=text='${cleanSecondaryLogo}':expansion=none:fontcolor=white:` +
148
+ `fontsize=${Math.round(sideBadgeSize * 0.52)}:` +
149
+ `x=${secondaryLogoX}+(${secondaryBadgeW}-text_w)/2:y=${labelY}+(${sideBadgeSize}-text_h)/2`);
150
+ }
151
+ headerParts.push(`drawtext=textfile='${secondaryText}':expansion=none:fontcolor=0x171914:fontsize=${fontSize}:` +
152
+ `x=${secondaryLabelX}:y=${labelY}+(${sideBadgeSize}-text_h)/2`);
153
+ const headerFilter = `[canvas]${headerParts.join(",")}[headed]`;
154
+ filterParts.push(headerFilter);
155
+ // Overlay logo images on top of the header if provided, chaining the stream
156
+ let currentStream = "headed";
157
+ if (primaryLogoInputIdx !== undefined) {
158
+ const logoOut = "headed-p";
159
+ // Scale logo to fit within the badge square, maintain aspect ratio, pad to square with transparent bg.
160
+ filterParts.push(`[${primaryLogoInputIdx}:v]scale=${logoImgSize}:${logoImgSize}:force_original_aspect_ratio=decrease,` +
161
+ `pad=${logoImgSize}:${logoImgSize}:(ow-iw)/2:(oh-ih)/2:color=0x00000000,format=rgba,setsar=1[logo-p]`, `[${currentStream}][logo-p]overlay=${primaryLogoX}:${labelY}:shortest=1[${logoOut}]`);
162
+ currentStream = logoOut;
163
+ }
164
+ if (secondaryLogoInputIdx !== undefined) {
165
+ const logoOut = "headed-s";
166
+ filterParts.push(`[${secondaryLogoInputIdx}:v]scale=${logoImgSize}:${logoImgSize}:force_original_aspect_ratio=decrease,` +
167
+ `pad=${logoImgSize}:${logoImgSize}:(ow-iw)/2:(oh-ih)/2:color=0x00000000,format=rgba,setsar=1[logo-s]`, `[${currentStream}][logo-s]overlay=${secondaryLogoX}:${labelY}:shortest=1[${logoOut}]`);
168
+ currentStream = logoOut;
169
+ }
170
+ // Split each panel into (original, shadow-source), blur the shadow copy, then
171
+ // overlay: shadow (offset) → original — giving a subtle soft drop shadow.
172
+ filterParts.push(`[left]split=2[left-orig][left-sh-in]`, `[left-sh-in]gblur=sigma=${shadowBlur},colorchannelmixer=aa=${shadowAlpha}[left-sh]`, `[right]split=2[right-orig][right-sh-in]`, `[right-sh-in]gblur=sigma=${shadowBlur},colorchannelmixer=aa=${shadowAlpha}[right-sh]`, `[${currentStream}][left-sh]overlay=${outerMargin}:${panelTop + shadowOffsetY}:shortest=1[with-ls]`, `[with-ls][left-orig]overlay=${outerMargin}:${panelTop}:shortest=1[first]`, `[first][right-sh]overlay=${secondaryX}:${panelTop + shadowOffsetY}:shortest=1[with-rs]`, `[with-rs][right-orig]overlay=${secondaryX}:${panelTop}:shortest=1,setsar=1,fps=${fps},format=yuv420p[video]`);
173
+ const filter = filterParts.join(";");
174
+ try {
175
+ await runFfmpeg([
176
+ "-y",
177
+ "-i", primaryPath,
178
+ "-i", secondaryPath,
179
+ "-loop", "1",
180
+ "-framerate", String(fps),
181
+ "-i", maskPath,
182
+ ...extraInputs,
183
+ "-filter_complex", filter,
184
+ "-map", "[video]",
185
+ "-an",
186
+ "-c:v", "libx264",
187
+ "-preset", "superfast",
188
+ "-crf", "18",
189
+ "-pix_fmt", "yuv420p",
190
+ "-t", durationSeconds,
191
+ "-movflags", "+faststart",
192
+ outputPath,
193
+ ], signal);
194
+ }
195
+ finally {
196
+ await Promise.all([
197
+ fs.rm(primaryLabelPath, { force: true }),
198
+ fs.rm(secondaryLabelPath, { force: true }),
199
+ fs.rm(maskPath, { force: true }),
200
+ primaryLogoPath ? fs.rm(primaryLogoPath, { force: true }) : Promise.resolve(),
201
+ secondaryLogoPath ? fs.rm(secondaryLogoPath, { force: true }) : Promise.resolve(),
202
+ primaryLogoRaw ? fs.rm(primaryLogoRaw, { force: true }) : Promise.resolve(),
203
+ secondaryLogoRaw ? fs.rm(secondaryLogoRaw, { force: true }) : Promise.resolve(),
204
+ ]);
205
+ }
206
+ }
207
+ /** Decode a data URI string into a raw Buffer. */
208
+ function dataUrlToBuffer(dataUrl) {
209
+ const commaIdx = dataUrl.indexOf(",");
210
+ if (commaIdx === -1)
211
+ throw new Error("Invalid data URI: missing comma separator");
212
+ const base64 = dataUrl.slice(commaIdx + 1);
213
+ return Buffer.from(base64, "base64");
214
+ }
215
+ /** Map a data URI MIME type to a file extension ffmpeg understands. */
216
+ function mimeToExt(dataUrl) {
217
+ if (dataUrl.startsWith("data:image/png"))
218
+ return ".png";
219
+ if (dataUrl.startsWith("data:image/jpeg"))
220
+ return ".jpg";
221
+ if (dataUrl.startsWith("data:image/webp"))
222
+ return ".webp";
223
+ if (dataUrl.startsWith("data:image/svg+xml"))
224
+ return ".svg";
225
+ return ".png"; // safe default
226
+ }
227
+ /**
228
+ * Transcodes any still image (PNG/JPEG/WebP/SVG) into a normalized PNG that
229
+ * ffmpeg can reliably decode as a looped video input.
230
+ */
231
+ async function convertImageToPng(inputPath, outputPath, signal) {
232
+ await runFfmpeg([
233
+ "-y",
234
+ "-i", inputPath,
235
+ "-vf", "format=rgba",
236
+ "-frames:v", "1",
237
+ "-c:v", "png",
238
+ outputPath,
239
+ ], signal);
240
+ }
241
+ async function createRoundedMask(outputPath, width, height, radius, signal) {
242
+ const right = `W-${radius}`;
243
+ const bottom = `H-${radius}`;
244
+ const outsideCorner = [
245
+ `lt(X,${radius})*lt(Y,${radius})*gt(hypot(X-${radius},Y-${radius}),${radius})`,
246
+ `gt(X,${right})*lt(Y,${radius})*gt(hypot(X-(${right}),Y-${radius}),${radius})`,
247
+ `lt(X,${radius})*gt(Y,${bottom})*gt(hypot(X-${radius},Y-(${bottom})),${radius})`,
248
+ `gt(X,${right})*gt(Y,${bottom})*gt(hypot(X-(${right}),Y-(${bottom})),${radius})`,
249
+ ].join("+");
250
+ await runFfmpeg([
251
+ "-y",
252
+ "-f", "lavfi",
253
+ "-i", `color=c=white:s=${width}x${height}:r=1`,
254
+ "-vf", `format=gray,geq=lum='if(gt(${outsideCorner},0),0,255)'`,
255
+ "-frames:v", "1",
256
+ "-c:v", "png",
257
+ outputPath,
258
+ ], signal);
259
+ }
260
+ function even(value) {
261
+ return value % 2 === 0 ? value : value - 1;
262
+ }
263
+ function escapeFilterPath(value) {
264
+ return value.replaceAll("\\", "\\\\").replaceAll(":", "\\:").replaceAll("'", "\\'");
265
+ }
266
+ function runFfmpeg(args, signal) {
267
+ return new Promise((resolve, reject) => {
268
+ signal?.throwIfAborted();
269
+ const child = spawn("ffmpeg", args, { stdio: ["ignore", "ignore", "pipe"] });
270
+ let stderr = "";
271
+ const abort = () => child.kill("SIGTERM");
272
+ signal?.addEventListener("abort", abort, { once: true });
273
+ child.stderr.on("data", (chunk) => {
274
+ stderr += chunk.toString();
275
+ });
276
+ child.on("error", reject);
277
+ child.on("close", (code) => {
278
+ signal?.removeEventListener("abort", abort);
279
+ if (signal?.aborted)
280
+ return reject(signal.reason ?? new Error("Comparison cancelled"));
281
+ if (code === 0)
282
+ resolve();
283
+ else
284
+ reject(new Error(`ffmpeg comparison exited with code ${code}: ${stderr.slice(-2_000)}`));
285
+ });
286
+ });
287
+ }
288
+ function estimateTextWidth(text, fontSize) {
289
+ let width = 0;
290
+ for (const char of text) {
291
+ if (/[A-Z]/.test(char)) {
292
+ width += 0.65;
293
+ }
294
+ else if (/[mw]/.test(char)) {
295
+ width += 0.75;
296
+ }
297
+ else if (/[iltfjr]/.test(char)) {
298
+ width += 0.25;
299
+ }
300
+ else if (/[a-z]/.test(char)) {
301
+ width += 0.50;
302
+ }
303
+ else if (/[0-9]/.test(char)) {
304
+ width += 0.55;
305
+ }
306
+ else if (char === " ") {
307
+ width += 0.28;
308
+ }
309
+ else {
310
+ width += 0.40;
311
+ }
312
+ }
313
+ return Math.round(width * fontSize);
314
+ }
315
+ //# sourceMappingURL=composeComparison.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composeComparison.js","sourceRoot":"","sources":["../../src/editor/composeComparison.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ interface ComposeResponsivenessOptions {
2
+ desktopPath: string;
3
+ mobilePath: string;
4
+ outputPath: string;
5
+ width: number;
6
+ height: number;
7
+ fps: number;
8
+ durationMs: number;
9
+ desktopLabel: string;
10
+ mobileLabel: string;
11
+ desktopWidth: number;
12
+ desktopHeight: number;
13
+ mobileWidth: number;
14
+ mobileHeight: number;
15
+ signal?: AbortSignal;
16
+ }
17
+ export declare function composeResponsiveness(options: ComposeResponsivenessOptions): Promise<void>;
18
+ export {};
19
+ //# sourceMappingURL=composeResponsiveness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composeResponsiveness.d.ts","sourceRoot":"","sources":["../../src/editor/composeResponsiveness.ts"],"names":[],"mappings":"AAIA,UAAU,4BAA4B;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,iBAyKhF"}
@@ -0,0 +1,198 @@
1
+ import { spawn } from "node:child_process";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ export async function composeResponsiveness(options) {
5
+ const { desktopPath, mobilePath, outputPath, fps, durationMs, desktopLabel, mobileLabel, desktopWidth, desktopHeight, mobileWidth, mobileHeight, signal, } = options;
6
+ const width = even(options.width);
7
+ const height = even(options.height);
8
+ const outerMargin = even(Math.round(width * 0.05));
9
+ const panelGap = even(Math.round(width * 0.035));
10
+ const panelTop = even(Math.round(height * 0.12));
11
+ const bottomMargin = even(Math.round(height * 0.05));
12
+ const panelHeight = even(height - panelTop - bottomMargin);
13
+ const panelWidthAvailable = width - outerMargin * 2 - panelGap;
14
+ // Aspect ratios from capture dimensions
15
+ const desktopAspect = desktopWidth / desktopHeight;
16
+ const mobileAspect = mobileWidth / mobileHeight;
17
+ // Solve layout sizing
18
+ let dH = even(Math.round(panelHeight * 0.82));
19
+ let dW = even(Math.round(dH * desktopAspect));
20
+ let mH = even(Math.round(panelHeight * 0.92));
21
+ let mW = even(Math.round(mH * mobileAspect));
22
+ const totalPanelW = dW + mW;
23
+ if (totalPanelW > panelWidthAvailable) {
24
+ const scale = panelWidthAvailable / totalPanelW;
25
+ dH = even(Math.round(dH * scale));
26
+ dW = even(Math.round(dW * scale));
27
+ mH = even(Math.round(mH * scale));
28
+ mW = even(Math.round(mW * scale));
29
+ }
30
+ // Centering coordinates
31
+ const leftoverWidth = panelWidthAvailable - (dW + mW);
32
+ const desktopX = outerMargin + Math.round(leftoverWidth / 2);
33
+ const mobileX = desktopX + dW + panelGap;
34
+ const desktopY = panelTop + Math.round((panelHeight - dH) / 2);
35
+ const mobileY = panelTop + Math.round((panelHeight - mH) / 2);
36
+ const fontSize = Math.max(18, Math.round(height * 0.038));
37
+ const labelY = Math.max(8, Math.round((panelTop - fontSize) / 2));
38
+ const dCornerRadius = Math.max(10, Math.round(Math.min(dW, dH) * 0.03));
39
+ const mCornerRadius = Math.max(10, Math.round(Math.min(mW, mH) * 0.03));
40
+ const durationSeconds = Math.max(0.1, durationMs / 1_000).toFixed(3);
41
+ const outputDir = path.dirname(outputPath);
42
+ await fs.mkdir(outputDir, { recursive: true });
43
+ // Subtle drop shadow settings
44
+ const shadowOffsetY = Math.max(4, Math.round(height * 0.005));
45
+ const shadowBlur = Math.max(8, Math.round(height * 0.012));
46
+ const shadowAlpha = 0.22;
47
+ // --- Temp files ---
48
+ const desktopLabelPath = path.join(outputDir, ".responsiveness-desktop.txt");
49
+ const mobileLabelPath = path.join(outputDir, ".responsiveness-mobile.txt");
50
+ const desktopMaskPath = path.join(outputDir, ".responsiveness-mask-desktop.png");
51
+ const mobileMaskPath = path.join(outputDir, ".responsiveness-mask-mobile.png");
52
+ await Promise.all([
53
+ fs.writeFile(desktopLabelPath, desktopLabel.replace(/\s+/g, " "), "utf8"),
54
+ fs.writeFile(mobileLabelPath, mobileLabel.replace(/\s+/g, " "), "utf8"),
55
+ createRoundedMask(desktopMaskPath, dW, dH, dCornerRadius, signal),
56
+ createRoundedMask(mobileMaskPath, mW, mH, mCornerRadius, signal),
57
+ ]);
58
+ // --- Build ffmpeg inputs & filter ---
59
+ const desktopText = escapeFilterPath(desktopLabelPath);
60
+ const mobileText = escapeFilterPath(mobileLabelPath);
61
+ const panelBg = "0xf1f4ed";
62
+ const panel = (input, mask, w, h, output) => `[${input}]setpts=PTS-STARTPTS,tpad=stop_mode=clone:stop_duration=${durationSeconds},` +
63
+ `trim=duration=${durationSeconds},scale=${w}:${h}:force_original_aspect_ratio=decrease:` +
64
+ `flags=lanczos,pad=${w}:${h}:(ow-iw)/2:(oh-ih)/2:color=${panelBg},` +
65
+ `setsar=1,format=rgba[${output}-base];` +
66
+ `[${output}-base][${mask}]alphamerge[${output}]`;
67
+ // Build filter_complex segments
68
+ const filterParts = [
69
+ `[2:v]format=gray[mask-d]`,
70
+ `[3:v]format=gray[mask-m]`,
71
+ panel("0:v", "mask-d", dW, dH, "desktop-in"),
72
+ panel("1:v", "mask-m", mW, mH, "mobile-in"),
73
+ `color=c=0xf1f4ed:s=${width}x${height}:r=${fps}:d=${durationSeconds}[canvas]`,
74
+ ];
75
+ // Render text labels centered over the desktop and mobile panels
76
+ const headerParts = [];
77
+ const primaryTextW = estimateTextWidth(desktopLabel, fontSize);
78
+ const primaryLabelX = Math.round(desktopX + (dW - primaryTextW) / 2);
79
+ headerParts.push(`drawtext=textfile='${desktopText}':expansion=none:fontcolor=0x171914:fontsize=${fontSize}:` +
80
+ `x=${primaryLabelX}:y=${labelY}`);
81
+ const secondaryTextW = estimateTextWidth(mobileLabel, fontSize);
82
+ const secondaryLabelX = Math.round(mobileX + (mW - secondaryTextW) / 2);
83
+ headerParts.push(`drawtext=textfile='${mobileText}':expansion=none:fontcolor=0x171914:fontsize=${fontSize}:` +
84
+ `x=${secondaryLabelX}:y=${labelY}`);
85
+ const headerFilter = `[canvas]${headerParts.join(",")}[headed]`;
86
+ filterParts.push(headerFilter);
87
+ let currentStream = "headed";
88
+ // Split each panel into (original, shadow-source), blur the shadow copy, then
89
+ // overlay: shadow (offset) → original — giving a subtle soft drop shadow.
90
+ filterParts.push(`[desktop-in]split=2[desktop-orig][desktop-sh-in]`, `[desktop-sh-in]gblur=sigma=${shadowBlur},colorchannelmixer=aa=${shadowAlpha}[desktop-sh]`, `[mobile-in]split=2[mobile-orig][mobile-sh-in]`, `[mobile-sh-in]gblur=sigma=${shadowBlur},colorchannelmixer=aa=${shadowAlpha}[mobile-sh]`, `[${currentStream}][desktop-sh]overlay=${desktopX}:${desktopY + shadowOffsetY}:shortest=1[with-ds]`, `[with-ds][desktop-orig]overlay=${desktopX}:${desktopY}:shortest=1[first]`, `[first][mobile-sh]overlay=${mobileX}:${mobileY + shadowOffsetY}:shortest=1[with-ms]`, `[with-ms][mobile-orig]overlay=${mobileX}:${mobileY}:shortest=1,setsar=1,fps=${fps},format=yuv420p[video]`);
91
+ const filter = filterParts.join(";");
92
+ try {
93
+ await runFfmpeg([
94
+ "-y",
95
+ "-i", desktopPath,
96
+ "-i", mobilePath,
97
+ "-loop", "1",
98
+ "-framerate", String(fps),
99
+ "-i", desktopMaskPath,
100
+ "-loop", "1",
101
+ "-framerate", String(fps),
102
+ "-i", mobileMaskPath,
103
+ "-filter_complex", filter,
104
+ "-map", "[video]",
105
+ "-an",
106
+ "-c:v", "libx264",
107
+ "-preset", "superfast",
108
+ "-crf", "18",
109
+ "-pix_fmt", "yuv420p",
110
+ "-t", durationSeconds,
111
+ "-movflags", "+faststart",
112
+ outputPath,
113
+ ], signal);
114
+ }
115
+ finally {
116
+ await Promise.all([
117
+ fs.rm(desktopLabelPath, { force: true }),
118
+ fs.rm(mobileLabelPath, { force: true }),
119
+ fs.rm(desktopMaskPath, { force: true }),
120
+ fs.rm(mobileMaskPath, { force: true }),
121
+ ]);
122
+ }
123
+ }
124
+ async function createRoundedMask(outputPath, width, height, radius, signal) {
125
+ const right = `W-${radius}`;
126
+ const bottom = `H-${radius}`;
127
+ const outsideCorner = [
128
+ `lt(X,${radius})*lt(Y,${radius})*gt(hypot(X-${radius},Y-${radius}),${radius})`,
129
+ `gt(X,${right})*lt(Y,${radius})*gt(hypot(X-(${right}),Y-${radius}),${radius})`,
130
+ `lt(X,${radius})*gt(Y,${bottom})*gt(hypot(X-${radius},Y-(${bottom})),${radius})`,
131
+ `gt(X,${right})*gt(Y,${bottom})*gt(hypot(X-(${right}),Y-(${bottom})),${radius})`,
132
+ ].join("+");
133
+ await runFfmpeg([
134
+ "-y",
135
+ "-f", "lavfi",
136
+ "-i", `color=c=white:s=${width}x${height}:r=1`,
137
+ "-vf", `format=gray,geq=lum='if(gt(${outsideCorner},0),0,255)'`,
138
+ "-frames:v", "1",
139
+ "-c:v", "png",
140
+ outputPath,
141
+ ], signal);
142
+ }
143
+ function even(value) {
144
+ return value % 2 === 0 ? value : value - 1;
145
+ }
146
+ function escapeFilterPath(value) {
147
+ return value.replaceAll("\\", "\\\\").replaceAll(":", "\\:").replaceAll("'", "\\'");
148
+ }
149
+ function runFfmpeg(args, signal) {
150
+ return new Promise((resolve, reject) => {
151
+ signal?.throwIfAborted();
152
+ const child = spawn("ffmpeg", args, { stdio: ["ignore", "ignore", "pipe"] });
153
+ let stderr = "";
154
+ const abort = () => child.kill("SIGTERM");
155
+ signal?.addEventListener("abort", abort, { once: true });
156
+ child.stderr.on("data", (chunk) => {
157
+ stderr += chunk.toString();
158
+ });
159
+ child.on("error", reject);
160
+ child.on("close", (code) => {
161
+ signal?.removeEventListener("abort", abort);
162
+ if (signal?.aborted)
163
+ return reject(signal.reason ?? new Error("Recording cancelled"));
164
+ if (code === 0)
165
+ resolve();
166
+ else
167
+ reject(new Error(`ffmpeg responsiveness exited with code ${code}: ${stderr.slice(-2_000)}`));
168
+ });
169
+ });
170
+ }
171
+ function estimateTextWidth(text, fontSize) {
172
+ let width = 0;
173
+ for (const char of text) {
174
+ if (/[A-Z]/.test(char)) {
175
+ width += 0.65;
176
+ }
177
+ else if (/[mw]/.test(char)) {
178
+ width += 0.75;
179
+ }
180
+ else if (/[iltfjr]/.test(char)) {
181
+ width += 0.25;
182
+ }
183
+ else if (/[a-z]/.test(char)) {
184
+ width += 0.50;
185
+ }
186
+ else if (/[0-9]/.test(char)) {
187
+ width += 0.55;
188
+ }
189
+ else if (char === " ") {
190
+ width += 0.28;
191
+ }
192
+ else {
193
+ width += 0.40;
194
+ }
195
+ }
196
+ return Math.round(width * fontSize);
197
+ }
198
+ //# sourceMappingURL=composeResponsiveness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composeResponsiveness.js","sourceRoot":"","sources":["../../src/editor/composeResponsiveness.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { BackgroundPreset } from "../types.js";
2
+ import type { EncodeSettings } from "../transcode/quality.js";
3
+ export declare function frameVideoOnBackground(options: {
4
+ inputPath: string;
5
+ outputPath: string;
6
+ preset: Exclude<BackgroundPreset, "none">;
7
+ addShadow: boolean;
8
+ roundedCorners?: boolean;
9
+ encode: EncodeSettings;
10
+ }): Promise<void>;
11
+ //# sourceMappingURL=frameVideo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frameVideo.d.ts","sourceRoot":"","sources":["../../src/editor/frameVideo.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAU9D,wBAAsB,sBAAsB,CAAC,OAAO,EAAE;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,cAAc,CAAC;CACxB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmFhB"}