@spark-apps/quickpeek 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 (49) hide show
  1. package/dist/api-client.d.ts +61 -0
  2. package/dist/api-client.d.ts.map +1 -0
  3. package/dist/api-client.js +180 -0
  4. package/dist/api-client.js.map +1 -0
  5. package/dist/config.d.ts +69 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/config.js +43 -0
  8. package/dist/config.js.map +1 -0
  9. package/dist/crawl.d.ts +18 -0
  10. package/dist/crawl.d.ts.map +1 -0
  11. package/dist/crawl.js +175 -0
  12. package/dist/crawl.js.map +1 -0
  13. package/dist/cursor.d.ts +6 -0
  14. package/dist/cursor.d.ts.map +1 -0
  15. package/dist/cursor.js +6 -0
  16. package/dist/cursor.js.map +1 -0
  17. package/dist/ffmpeg.d.ts +50 -0
  18. package/dist/ffmpeg.d.ts.map +1 -0
  19. package/dist/ffmpeg.js +224 -0
  20. package/dist/ffmpeg.js.map +1 -0
  21. package/dist/index.d.ts +15 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +26 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/prompts.d.ts +13 -0
  26. package/dist/prompts.d.ts.map +1 -0
  27. package/dist/prompts.js +91 -0
  28. package/dist/prompts.js.map +1 -0
  29. package/dist/styles.d.ts +16 -0
  30. package/dist/styles.d.ts.map +1 -0
  31. package/dist/styles.js +66 -0
  32. package/dist/styles.js.map +1 -0
  33. package/dist/tts.d.ts +64 -0
  34. package/dist/tts.d.ts.map +1 -0
  35. package/dist/tts.js +236 -0
  36. package/dist/tts.js.map +1 -0
  37. package/dist/utils.d.ts +25 -0
  38. package/dist/utils.d.ts.map +1 -0
  39. package/dist/utils.js +106 -0
  40. package/dist/utils.js.map +1 -0
  41. package/dist/voices.d.ts +2 -0
  42. package/dist/voices.d.ts.map +1 -0
  43. package/dist/voices.js +73 -0
  44. package/dist/voices.js.map +1 -0
  45. package/dist/watermark.d.ts +27 -0
  46. package/dist/watermark.d.ts.map +1 -0
  47. package/dist/watermark.js +57 -0
  48. package/dist/watermark.js.map +1 -0
  49. package/package.json +45 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ffmpeg.d.ts","sourceRoot":"","sources":["../src/ffmpeg.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAG5C;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkClE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqB3E;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CACjC;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAsHhE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmCrF;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA8ChE"}
package/dist/ffmpeg.js ADDED
@@ -0,0 +1,224 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { buildWatermarkFilters } from './watermark.js';
3
+ /**
4
+ * Run ffprobe to get media duration in milliseconds
5
+ */
6
+ export function getMediaDuration(filePath) {
7
+ return new Promise((resolve, reject) => {
8
+ const args = [
9
+ '-v',
10
+ 'error',
11
+ '-show_entries',
12
+ 'format=duration',
13
+ '-of',
14
+ 'default=noprint_wrappers=1:nokey=1',
15
+ filePath,
16
+ ];
17
+ const proc = spawn('ffprobe', args);
18
+ let stdout = '';
19
+ let stderr = '';
20
+ proc.stdout.on('data', (data) => {
21
+ stdout += data;
22
+ });
23
+ proc.stderr.on('data', (data) => {
24
+ stderr += data;
25
+ });
26
+ proc.on('close', (code) => {
27
+ if (code !== 0) {
28
+ reject(new Error(`ffprobe failed: ${stderr}`));
29
+ return;
30
+ }
31
+ const duration = parseFloat(stdout.trim());
32
+ resolve(Math.ceil(duration * 1000));
33
+ });
34
+ proc.on('error', reject);
35
+ });
36
+ }
37
+ /**
38
+ * Concatenate audio files using ffmpeg concat demuxer
39
+ */
40
+ export function concatMedia(listPath, output) {
41
+ return new Promise((resolve, reject) => {
42
+ const args = ['-y', '-f', 'concat', '-safe', '0', '-i', listPath, '-c', 'copy', output];
43
+ const proc = spawn('ffmpeg', args);
44
+ let stderr = '';
45
+ proc.stderr.on('data', (data) => {
46
+ stderr += data;
47
+ });
48
+ proc.on('close', (code) => {
49
+ if (code !== 0) {
50
+ reject(new Error(`ffmpeg concat failed: ${stderr}`));
51
+ return;
52
+ }
53
+ resolve();
54
+ });
55
+ proc.on('error', reject);
56
+ });
57
+ }
58
+ /**
59
+ * Compose final video with subtitles, voiceover, and music
60
+ */
61
+ export function composeVideo(opts) {
62
+ return new Promise((resolve, reject) => {
63
+ const { videoPath, assPath, outputPath, voiceoverPath, musicPath, musicVolume = 0.3, musicFadeIn = 2, musicFadeOut = 2, width, height, fps, preset, quality, fadeIn, fadeOut, videoDuration, audioBitrate = '192k', contrast = 0, trimStart = 0, userTier = 'free', } = opts;
64
+ // Trim white frames from start of Playwright recording
65
+ const args = ['-y'];
66
+ if (trimStart > 0) {
67
+ args.push('-ss', String(trimStart));
68
+ }
69
+ args.push('-i', videoPath);
70
+ // Adjust duration for trimmed content
71
+ const effectiveDuration = videoDuration - trimStart;
72
+ // Add input streams
73
+ if (voiceoverPath)
74
+ args.push('-i', voiceoverPath);
75
+ if (musicPath)
76
+ args.push('-i', musicPath);
77
+ // Build video filter
78
+ const vf = [`scale=${width}:${height}`, `fps=${fps}`];
79
+ // Add contrast filter if enabled (contrast > 0)
80
+ // Map 0-1 range to ffmpeg's eq filter: 0 = no change (1.0), 1 = double contrast (2.0)
81
+ if (contrast > 0) {
82
+ const ffmpegContrast = 1 + contrast;
83
+ vf.push(`eq=contrast=${ffmpegContrast.toFixed(2)}`);
84
+ }
85
+ // Add watermark filters for free tier videos >20 seconds
86
+ const watermarkFilters = buildWatermarkFilters({ tier: userTier, videoDuration: effectiveDuration });
87
+ if (watermarkFilters) {
88
+ vf.push(watermarkFilters);
89
+ }
90
+ vf.push(`ass=${assPath.replace(/\\/g, '/').replace(/:/g, '\\:')}`);
91
+ if (fadeIn > 0)
92
+ vf.push(`fade=t=in:st=0:d=${fadeIn}:c=black`);
93
+ if (fadeOut > 0) {
94
+ const videoFadeOutStart = Math.max(0, effectiveDuration - fadeOut);
95
+ vf.push(`fade=t=out:st=${videoFadeOutStart}:d=${fadeOut}:c=black`);
96
+ }
97
+ args.push('-vf', vf.join(','));
98
+ // Convert 0-1 quality to CRF (1.0 = CRF 18 best, 0.0 = CRF 28 smallest)
99
+ const crf = Math.round(28 - quality * 10);
100
+ args.push('-c:v', 'libx264', '-preset', preset, '-crf', String(crf), '-pix_fmt', 'yuv420p');
101
+ // Handle audio mixing
102
+ const hasVoiceover = !!voiceoverPath;
103
+ const hasMusic = !!musicPath;
104
+ const musicFadeOutStart = Math.max(0, effectiveDuration - musicFadeOut);
105
+ const voiceFadeOutStart = Math.max(0, effectiveDuration - fadeOut);
106
+ if (hasVoiceover && hasMusic) {
107
+ // Pad voiceover to video duration, loop music to video duration, then mix
108
+ const complexFilter = [
109
+ `[1:a]apad=whole_dur=${effectiveDuration},afade=t=in:st=0:d=${fadeIn},afade=t=out:st=${voiceFadeOutStart}:d=${fadeOut}[voice]`,
110
+ `[2:a]aloop=loop=-1:size=2e+09,atrim=0:${effectiveDuration},volume=${musicVolume},afade=t=in:st=0:d=${musicFadeIn},afade=t=out:st=${musicFadeOutStart}:d=${musicFadeOut}[music]`,
111
+ `[voice][music]amix=inputs=2:duration=shortest[aout]`,
112
+ ].join(';');
113
+ args.push('-filter_complex', complexFilter, '-map', '0:v', '-map', '[aout]');
114
+ args.push('-c:a', 'aac', '-b:a', audioBitrate);
115
+ }
116
+ else if (hasVoiceover) {
117
+ // Pad voiceover to video duration
118
+ const af = `apad=whole_dur=${effectiveDuration},afade=t=in:st=0:d=${fadeIn},afade=t=out:st=${voiceFadeOutStart}:d=${fadeOut}`;
119
+ args.push('-map', '0:v', '-map', '1:a', '-af', af);
120
+ args.push('-c:a', 'aac', '-b:a', audioBitrate);
121
+ }
122
+ else if (hasMusic) {
123
+ // Loop music to video duration
124
+ const musicFilter = `aloop=loop=-1:size=2e+09,atrim=0:${effectiveDuration},volume=${musicVolume},afade=t=in:st=0:d=${musicFadeIn},afade=t=out:st=${musicFadeOutStart}:d=${musicFadeOut}`;
125
+ args.push('-map', '0:v', '-map', '1:a', '-af', musicFilter);
126
+ args.push('-c:a', 'aac', '-b:a', '192k');
127
+ }
128
+ args.push(outputPath);
129
+ // Debug: log ffmpeg command
130
+ // console.log('ffmpeg', args.join(' '));
131
+ const proc = spawn('ffmpeg', args);
132
+ let stderr = '';
133
+ proc.stderr.on('data', (data) => {
134
+ stderr += data;
135
+ });
136
+ proc.on('close', (code) => {
137
+ if (code !== 0) {
138
+ reject(new Error(`ffmpeg compose failed: ${stderr}`));
139
+ return;
140
+ }
141
+ resolve();
142
+ });
143
+ proc.on('error', reject);
144
+ });
145
+ }
146
+ /**
147
+ * Generate silence audio file of specified duration
148
+ */
149
+ export function generateSilence(outputPath, durationMs) {
150
+ return new Promise((resolve, reject) => {
151
+ const durationSec = durationMs / 1000;
152
+ const args = [
153
+ '-y',
154
+ '-f',
155
+ 'lavfi',
156
+ '-i',
157
+ `anullsrc=r=24000:cl=mono`,
158
+ '-t',
159
+ String(durationSec),
160
+ '-c:a',
161
+ 'libmp3lame',
162
+ '-b:a',
163
+ '96k',
164
+ outputPath,
165
+ ];
166
+ const proc = spawn('ffmpeg', args);
167
+ let stderr = '';
168
+ proc.stderr.on('data', (data) => {
169
+ stderr += data;
170
+ });
171
+ proc.on('close', (code) => {
172
+ if (code !== 0) {
173
+ reject(new Error(`ffmpeg silence generation failed: ${stderr}`));
174
+ return;
175
+ }
176
+ resolve();
177
+ });
178
+ proc.on('error', reject);
179
+ });
180
+ }
181
+ /**
182
+ * Speed up video by a factor
183
+ */
184
+ export function speedUpVideo(opts) {
185
+ return new Promise((resolve, reject) => {
186
+ const { inputPath, outputPath, factor, preset } = opts;
187
+ // setpts for video speed
188
+ const videoFilter = `setpts=${(1 / factor).toFixed(3)}*PTS`;
189
+ // atempo only supports 0.5-2.0, so chain multiple for higher speeds
190
+ const audioFilters = [];
191
+ let remaining = factor;
192
+ while (remaining > 1) {
193
+ const tempo = Math.min(remaining, 2.0);
194
+ audioFilters.push(`atempo=${tempo.toFixed(2)}`);
195
+ remaining /= tempo;
196
+ }
197
+ const args = [
198
+ '-y',
199
+ '-i',
200
+ inputPath,
201
+ '-vf',
202
+ videoFilter,
203
+ '-af',
204
+ audioFilters.join(','),
205
+ '-preset',
206
+ preset,
207
+ outputPath,
208
+ ];
209
+ const proc = spawn('ffmpeg', args);
210
+ let stderr = '';
211
+ proc.stderr.on('data', (data) => {
212
+ stderr += data;
213
+ });
214
+ proc.on('close', (code) => {
215
+ if (code !== 0) {
216
+ reject(new Error(`ffmpeg speedup failed: ${stderr}`));
217
+ return;
218
+ }
219
+ resolve();
220
+ });
221
+ proc.on('error', reject);
222
+ });
223
+ }
224
+ //# sourceMappingURL=ffmpeg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ffmpeg.js","sourceRoot":"","sources":["../src/ffmpeg.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * QuickPeek Core - Shared library for demo video generation
3
+ */
4
+ export * from './api-client.js';
5
+ export * from './config.js';
6
+ export * from './crawl.js';
7
+ export * from './cursor.js';
8
+ export * from './ffmpeg.js';
9
+ export * from './prompts.js';
10
+ export * from './styles.js';
11
+ export * from './tts.js';
12
+ export * from './utils.js';
13
+ export * from './voices.js';
14
+ export * from './watermark.js';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,cAAc,iBAAiB,CAAC;AAGhC,cAAc,aAAa,CAAC;AAE5B,cAAc,YAAY,CAAC;AAE3B,cAAc,aAAa,CAAC;AAE5B,cAAc,aAAa,CAAC;AAG5B,cAAc,cAAc,CAAC;AAE7B,cAAc,aAAa,CAAC;AAE5B,cAAc,UAAU,CAAC;AAEzB,cAAc,YAAY,CAAC;AAE3B,cAAc,aAAa,CAAC;AAE5B,cAAc,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * QuickPeek Core - Shared library for demo video generation
3
+ */
4
+ // API client for backend communication
5
+ export * from './api-client.js';
6
+ // Configuration types and defaults
7
+ export * from './config.js';
8
+ // Page crawling (requires Playwright as peer dependency)
9
+ export * from './crawl.js';
10
+ // Cursor asset
11
+ export * from './cursor.js';
12
+ // FFmpeg video/audio processing
13
+ export * from './ffmpeg.js';
14
+ // AI prompt building
15
+ export * from './prompts.js';
16
+ // CSS/ASS styling for subtitles
17
+ export * from './styles.js';
18
+ // Text-to-speech voiceover generation
19
+ export * from './tts.js';
20
+ // Utility functions
21
+ export * from './utils.js';
22
+ // Voice mappings for TTS
23
+ export * from './voices.js';
24
+ // Watermark filter generation
25
+ export * from './watermark.js';
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,uCAAuC;AACvC,cAAc,iBAAiB,CAAC;AAEhC,mCAAmC;AACnC,cAAc,aAAa,CAAC;AAC5B,yDAAyD;AACzD,cAAc,YAAY,CAAC;AAC3B,eAAe;AACf,cAAc,aAAa,CAAC;AAC5B,gCAAgC;AAChC,cAAc,aAAa,CAAC;AAE5B,qBAAqB;AACrB,cAAc,cAAc,CAAC;AAC7B,gCAAgC;AAChC,cAAc,aAAa,CAAC;AAC5B,sCAAsC;AACtC,cAAc,UAAU,CAAC;AACzB,oBAAoB;AACpB,cAAc,YAAY,CAAC;AAC3B,yBAAyB;AACzB,cAAc,aAAa,CAAC;AAC5B,8BAA8B;AAC9B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * AI prompts for demo plan generation
3
+ */
4
+ import { getLanguageName } from './utils.js';
5
+ interface ElementInfo {
6
+ type: string;
7
+ text: string;
8
+ selector: string;
9
+ }
10
+ export { getLanguageName };
11
+ export declare function buildSystemPrompt(maxSteps: number): string;
12
+ export declare function buildUserPrompt(url: string, title: string, elements: ElementInfo[], langName: string | null, description: string | undefined, maxSteps: number): string;
13
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE7C,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,OAAO,EAAE,eAAe,EAAE,CAAC;AAE3B,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAuD1D;AAED,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,WAAW,EAAE,EACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,QAAQ,EAAE,MAAM,GACf,MAAM,CA4BR"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * AI prompts for demo plan generation
3
+ */
4
+ import { getLanguageName } from './utils.js';
5
+ export { getLanguageName };
6
+ export function buildSystemPrompt(maxSteps) {
7
+ // Tier-based scope guidance
8
+ let scope;
9
+ if (maxSteps <= 5) {
10
+ scope = `SCOPE: Minimal demo (${maxSteps} steps max) - ONE complete user journey only`;
11
+ }
12
+ else if (maxSteps <= 8) {
13
+ scope = `SCOPE: Standard demo (${maxSteps} steps max) - One journey with 1-2 options`;
14
+ }
15
+ else {
16
+ scope = `SCOPE: Extended demo (${maxSteps} steps max) - Journey plus key settings`;
17
+ }
18
+ return `You create demo video scripts for web apps.
19
+
20
+ ${scope}
21
+
22
+ CORE FLOW (always follow this structure):
23
+ 1. wait - Intro (what does this app do?)
24
+ 2. Actions - Complete ONE user journey (upload→process→result)
25
+ 3. wait - Outro (what was accomplished?)
26
+
27
+ SELECTOR RULES:
28
+ • Visible buttons: use exact text from AVAILABLE ELEMENTS
29
+ • Hidden buttons (appear after actions): use *Keyword - TRY THESE IN ORDER:
30
+ - Processing: *Extract (preferred), *Generate, *Create, *Convert, *Submit
31
+ - Results: *Download (preferred), *Save, *Export
32
+ • ONLY target real buttons/links - never labels, images, sliders, or files
33
+
34
+ SKIP THESE ELEMENTS (never include in demo):
35
+ • Navigation links: Home, About, Contact, Help, Support, FAQ
36
+ • Account links: Login, Sign In, Sign Up, Register, My Account
37
+ • Business links: Pricing, Plans, Subscribe, Buy, Upgrade
38
+ • Footer links: Privacy, Terms, Blog, Careers, Social media
39
+ • Any header/footer navigation - focus ONLY on the main app functionality
40
+
41
+ FORBIDDEN:
42
+ • Repeating actions (one upload, one process, one download)
43
+ • Clicking downloaded files or results
44
+ • Vague targets like "slider", "animation", "options"
45
+ • More steps than maxSteps allows
46
+
47
+ ACTION FORMATS (use CSS selectors, not descriptions):
48
+ • click: { "action": "click", "target": "button text or CSS selector" }
49
+ • type: { "action": "type", "target": "input[name=...] or #id", "value": "text" }
50
+ • upload: { "action": "upload", "target": "input[type=\\"file\\"]", "value": "[file]" }
51
+ • wait: { "action": "wait" } - no target needed
52
+ • scroll:
53
+ - Page: { "action": "scroll", "value": "up|down" }
54
+ - Zoom: { "action": "scroll", "value": "10|-10" } - positive=in, negative=out (or "in|out")
55
+ • drag:
56
+ - Sliders: { "action": "drag", "target": "input[type=\\"range\\"]", "value": "10" }
57
+ - Rotation: { "action": "drag", "value": "around" } - auto-targets canvas
58
+ • select: { "action": "select", "target": "select#id or select[name=...]", "value": "option" }
59
+ • check: { "action": "check", "target": "input[type=\\"checkbox\\"]" }
60
+
61
+ SELECTOR PRIORITY: CSS selectors > exact button text > *Keyword wildcard`;
62
+ }
63
+ export function buildUserPrompt(url, title, elements, langName, description, maxSteps) {
64
+ const lang = langName ? `\nLanguage: Write ALL captions in ${langName}.` : '';
65
+ const purpose = description ? `\nPurpose: ${description}` : '';
66
+ const minSteps = Math.max(3, Math.floor(maxSteps * 0.6));
67
+ return `URL: ${url}
68
+ Title: ${title}${purpose}
69
+
70
+ AVAILABLE ELEMENTS:
71
+ ${JSON.stringify(elements, null, 2)}
72
+
73
+ REQUIREMENTS:
74
+ • ${minSteps}-${maxSteps} steps total (start with wait intro, end with wait outro)
75
+ • Complete ONE user journey: input → process → output
76
+ • Use *Keyword for buttons that appear after actions
77
+ • Final action should be download/save/submit - never click results${lang}
78
+
79
+ Return JSON:
80
+ {
81
+ "url": "${url}",
82
+ "title": "Short demo title",
83
+ "description": "What this app does",
84
+ "steps": [
85
+ { "id": 1, "action": "wait", "caption": "Intro..." },
86
+ { "id": 2, "action": "click|upload|type", "target": "selector", "caption": "..." },
87
+ { "id": N, "action": "wait", "caption": "Outro..." }
88
+ ]
89
+ }`;
90
+ }
91
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAQ7C,OAAO,EAAE,eAAe,EAAE,CAAC;AAE3B,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,4BAA4B;IAC5B,IAAI,KAAa,CAAC;IAClB,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QAClB,KAAK,GAAG,wBAAwB,QAAQ,8CAA8C,CAAC;IACzF,CAAC;SAAM,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QACzB,KAAK,GAAG,yBAAyB,QAAQ,4CAA4C,CAAC;IACxF,CAAC;SAAM,CAAC;QACN,KAAK,GAAG,yBAAyB,QAAQ,yCAAyC,CAAC;IACrF,CAAC;IAED,OAAO;;EAEP,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;yEAyCkE,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,GAAW,EACX,KAAa,EACb,QAAuB,EACvB,QAAuB,EACvB,WAA+B,EAC/B,QAAgB;IAEhB,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,qCAAqC,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9E,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,cAAc,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC,CAAC;IAEzD,OAAO,QAAQ,GAAG;SACX,KAAK,GAAG,OAAO;;;EAGtB,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;;;IAG/B,QAAQ,IAAI,QAAQ;;;qEAG6C,IAAI;;;;YAI7D,GAAG;;;;;;;;EAQb,CAAC;AACH,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * CSS and ASS styling for QuickPeek
3
+ */
4
+ /**
5
+ * CSS for the custom cursor overlay
6
+ */
7
+ export declare const CURSOR_CSS = "\n #qp-cursor {\n position: fixed;\n width: 48px;\n height: 56px;\n background: url(\"data:image/png;base64,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\") no-repeat;\n background-size: contain;\n pointer-events: none;\n z-index: 2147483647;\n transform: translate(-4px, -4px);\n transition: transform 0.08s ease-out;\n filter: drop-shadow(2px 2px 2px rgba(0,0,0,0.3));\n }\n #qp-cursor.clicking {\n transform: translate(-4px, -4px) scale(0.9);\n }\n";
8
+ /**
9
+ * JavaScript to inject for cursor tracking
10
+ */
11
+ export declare const CURSOR_SCRIPT = "\n (function() {\n if (document.getElementById('qp-cursor')) return;\n const cursor = document.createElement('div');\n cursor.id = 'qp-cursor';\n document.body.appendChild(cursor);\n\n document.addEventListener('mousemove', (e) => {\n cursor.style.left = e.clientX + 'px';\n cursor.style.top = e.clientY + 'px';\n });\n\n document.addEventListener('mousedown', () => cursor.classList.add('clicking'));\n document.addEventListener('mouseup', () => cursor.classList.remove('clicking'));\n\n // Start at center\n cursor.style.left = window.innerWidth / 2 + 'px';\n cursor.style.top = window.innerHeight / 2 + 'px';\n })();\n";
12
+ /**
13
+ * Generate ASS subtitle file header
14
+ */
15
+ export declare function generateASSHeader(width: number, height: number, font: string, size: number, primaryColor: string, secondaryColor: string, outlineColor: string, backColor: string, bold: boolean, outlineWidth: number, shadow: number, marginBottom: number): string;
16
+ //# sourceMappingURL=styles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,eAAO,MAAM,UAAU,o7FAgBtB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,aAAa,+pBAmBzB,CAAC;AAEF;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,OAAO,EACb,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,GACnB,MAAM,CAcR"}
package/dist/styles.js ADDED
@@ -0,0 +1,66 @@
1
+ /**
2
+ * CSS and ASS styling for QuickPeek
3
+ */
4
+ import { CURSOR_PNG } from './cursor.js';
5
+ /**
6
+ * CSS for the custom cursor overlay
7
+ */
8
+ export const CURSOR_CSS = `
9
+ #qp-cursor {
10
+ position: fixed;
11
+ width: 48px;
12
+ height: 56px;
13
+ background: url("${CURSOR_PNG}") no-repeat;
14
+ background-size: contain;
15
+ pointer-events: none;
16
+ z-index: 2147483647;
17
+ transform: translate(-4px, -4px);
18
+ transition: transform 0.08s ease-out;
19
+ filter: drop-shadow(2px 2px 2px rgba(0,0,0,0.3));
20
+ }
21
+ #qp-cursor.clicking {
22
+ transform: translate(-4px, -4px) scale(0.9);
23
+ }
24
+ `;
25
+ /**
26
+ * JavaScript to inject for cursor tracking
27
+ */
28
+ export const CURSOR_SCRIPT = `
29
+ (function() {
30
+ if (document.getElementById('qp-cursor')) return;
31
+ const cursor = document.createElement('div');
32
+ cursor.id = 'qp-cursor';
33
+ document.body.appendChild(cursor);
34
+
35
+ document.addEventListener('mousemove', (e) => {
36
+ cursor.style.left = e.clientX + 'px';
37
+ cursor.style.top = e.clientY + 'px';
38
+ });
39
+
40
+ document.addEventListener('mousedown', () => cursor.classList.add('clicking'));
41
+ document.addEventListener('mouseup', () => cursor.classList.remove('clicking'));
42
+
43
+ // Start at center
44
+ cursor.style.left = window.innerWidth / 2 + 'px';
45
+ cursor.style.top = window.innerHeight / 2 + 'px';
46
+ })();
47
+ `;
48
+ /**
49
+ * Generate ASS subtitle file header
50
+ */
51
+ export function generateASSHeader(width, height, font, size, primaryColor, secondaryColor, outlineColor, backColor, bold, outlineWidth, shadow, marginBottom) {
52
+ return `[Script Info]
53
+ Title: QuickPeek Demo
54
+ ScriptType: v4.00+
55
+ PlayResX: ${width}
56
+ PlayResY: ${height}
57
+
58
+ [V4+ Styles]
59
+ Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
60
+ Style: Karaoke,${font},${size},${primaryColor},${secondaryColor},${outlineColor},${backColor},${bold ? 1 : 0},0,0,0,100,100,0,0,1,${outlineWidth},${shadow},2,40,40,${marginBottom},1
61
+
62
+ [Events]
63
+ Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
64
+ `;
65
+ }
66
+ //# sourceMappingURL=styles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;uBAKH,UAAU;;;;;;;;;;;CAWhC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;CAmB5B,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAa,EACb,MAAc,EACd,IAAY,EACZ,IAAY,EACZ,YAAoB,EACpB,cAAsB,EACtB,YAAoB,EACpB,SAAiB,EACjB,IAAa,EACb,YAAoB,EACpB,MAAc,EACd,YAAoB;IAEpB,OAAO;;;YAGG,KAAK;YACL,MAAM;;;;iBAID,IAAI,IAAI,IAAI,IAAI,YAAY,IAAI,cAAc,IAAI,YAAY,IAAI,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB,YAAY,IAAI,MAAM,YAAY,YAAY;;;;CAIjL,CAAC;AACF,CAAC"}
package/dist/tts.d.ts ADDED
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Text-to-Speech via Microsoft Edge TTS (free, no API key)
3
+ */
4
+ import type { Config } from './config.js';
5
+ export interface WordTiming {
6
+ word: string;
7
+ start: number;
8
+ end: number;
9
+ }
10
+ export interface StepAudio {
11
+ duration: number;
12
+ words: WordTiming[];
13
+ }
14
+ export interface AudioResult {
15
+ voiceoverPath: string;
16
+ stepAudio: Map<number, StepAudio>;
17
+ }
18
+ interface Step {
19
+ caption: string;
20
+ action?: string;
21
+ value?: string;
22
+ duration?: number;
23
+ }
24
+ /**
25
+ * Synthesize speech with retry on connection failure
26
+ */
27
+ export declare function synthesizeSpeech(text: string, outputPath: string, voice: string): Promise<void>;
28
+ export declare function estimateDurationFromText(text: string, wordsPerMinute?: number): number;
29
+ export declare function estimateWordTimings(caption: string, duration: number): WordTiming[];
30
+ export declare function resolveVoice(config: Config): string | null;
31
+ /**
32
+ * Calculate a hash of captions for change detection
33
+ */
34
+ export declare function getCaptionsHash(steps: Step[]): string;
35
+ /**
36
+ * Metadata stored alongside voiceover for reuse detection
37
+ */
38
+ export interface VoiceoverMeta {
39
+ captionsHash: string;
40
+ totalCaptionLength: number;
41
+ stepCount: number;
42
+ voice: string;
43
+ stepDurations: Record<number, number>;
44
+ }
45
+ /**
46
+ * Load existing voiceover metadata if available
47
+ */
48
+ export declare function loadVoiceoverMeta(outputDir: string): Promise<VoiceoverMeta | null>;
49
+ /**
50
+ * Check if existing voiceover can be reused
51
+ */
52
+ export declare function canReuseVoiceover(steps: Step[], voice: string, existingMeta: VoiceoverMeta | null): {
53
+ canReuse: boolean;
54
+ reason?: string;
55
+ };
56
+ /**
57
+ * Load existing voiceover and reconstruct stepAudio from metadata
58
+ */
59
+ export declare function loadExistingVoiceover(steps: Step[], outputDir: string, meta: VoiceoverMeta, config: Config): Promise<AudioResult>;
60
+ export declare function generateVoiceover(steps: Step[], config: Config, workDir: string, outputDir: string, logError: (context: string, error: unknown) => Promise<void>, task: (text: string) => {
61
+ succeed: (text?: string) => void;
62
+ }, info: (text: string) => void): Promise<AudioResult>;
63
+ export {};
64
+ //# sourceMappingURL=tts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tts.d.ts","sourceRoot":"","sources":["../src/tts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAI1C,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACnC;AAED,UAAU,IAAI;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA+BD;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBrG;AAED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,SAAM,GAAG,MAAM,CAGnF;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,CAQnF;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI1D;AAYD;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,CAQrD;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAWxF;AAWD;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,IAAI,EAAE,EACb,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,aAAa,GAAG,IAAI,GACjC;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CA+BxC;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,IAAI,EAAE,EACb,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,aAAa,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,WAAW,CAAC,CAetB;AAED,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,IAAI,EAAE,EACb,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,EAC5D,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;IAAE,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,EAC5D,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC3B,OAAO,CAAC,WAAW,CAAC,CA4EtB"}