screencli 0.1.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 (141) hide show
  1. package/dist/bin/cli.d.ts +3 -0
  2. package/dist/bin/cli.d.ts.map +1 -0
  3. package/dist/bin/cli.js +14 -0
  4. package/dist/bin/cli.js.map +1 -0
  5. package/dist/src/agent/loop.d.ts +21 -0
  6. package/dist/src/agent/loop.d.ts.map +1 -0
  7. package/dist/src/agent/loop.js +119 -0
  8. package/dist/src/agent/loop.js.map +1 -0
  9. package/dist/src/agent/system-prompt.d.ts +2 -0
  10. package/dist/src/agent/system-prompt.d.ts.map +1 -0
  11. package/dist/src/agent/system-prompt.js +43 -0
  12. package/dist/src/agent/system-prompt.js.map +1 -0
  13. package/dist/src/agent/tool-handlers.d.ts +44 -0
  14. package/dist/src/agent/tool-handlers.d.ts.map +1 -0
  15. package/dist/src/agent/tool-handlers.js +242 -0
  16. package/dist/src/agent/tool-handlers.js.map +1 -0
  17. package/dist/src/agent/tools.d.ts +5 -0
  18. package/dist/src/agent/tools.d.ts.map +1 -0
  19. package/dist/src/agent/tools.js +251 -0
  20. package/dist/src/agent/tools.js.map +1 -0
  21. package/dist/src/browser/accessibility.d.ts +28 -0
  22. package/dist/src/browser/accessibility.d.ts.map +1 -0
  23. package/dist/src/browser/accessibility.js +47 -0
  24. package/dist/src/browser/accessibility.js.map +1 -0
  25. package/dist/src/browser/actions.d.ts +32 -0
  26. package/dist/src/browser/actions.d.ts.map +1 -0
  27. package/dist/src/browser/actions.js +122 -0
  28. package/dist/src/browser/actions.js.map +1 -0
  29. package/dist/src/browser/auth.d.ts +12 -0
  30. package/dist/src/browser/auth.d.ts.map +1 -0
  31. package/dist/src/browser/auth.js +53 -0
  32. package/dist/src/browser/auth.js.map +1 -0
  33. package/dist/src/browser/resolve-locator.d.ts +15 -0
  34. package/dist/src/browser/resolve-locator.d.ts.map +1 -0
  35. package/dist/src/browser/resolve-locator.js +27 -0
  36. package/dist/src/browser/resolve-locator.js.map +1 -0
  37. package/dist/src/browser/session.d.ts +16 -0
  38. package/dist/src/browser/session.d.ts.map +1 -0
  39. package/dist/src/browser/session.js +47 -0
  40. package/dist/src/browser/session.js.map +1 -0
  41. package/dist/src/cli/commands/export.d.ts +3 -0
  42. package/dist/src/cli/commands/export.d.ts.map +1 -0
  43. package/dist/src/cli/commands/export.js +76 -0
  44. package/dist/src/cli/commands/export.js.map +1 -0
  45. package/dist/src/cli/commands/init.d.ts +8 -0
  46. package/dist/src/cli/commands/init.d.ts.map +1 -0
  47. package/dist/src/cli/commands/init.js +64 -0
  48. package/dist/src/cli/commands/init.js.map +1 -0
  49. package/dist/src/cli/commands/record.d.ts +3 -0
  50. package/dist/src/cli/commands/record.d.ts.map +1 -0
  51. package/dist/src/cli/commands/record.js +215 -0
  52. package/dist/src/cli/commands/record.js.map +1 -0
  53. package/dist/src/cli/options.d.ts +24 -0
  54. package/dist/src/cli/options.d.ts.map +1 -0
  55. package/dist/src/cli/options.js +35 -0
  56. package/dist/src/cli/options.js.map +1 -0
  57. package/dist/src/cli/output.d.ts +10 -0
  58. package/dist/src/cli/output.d.ts.map +1 -0
  59. package/dist/src/cli/output.js +29 -0
  60. package/dist/src/cli/output.js.map +1 -0
  61. package/dist/src/export/exporter.d.ts +16 -0
  62. package/dist/src/export/exporter.d.ts.map +1 -0
  63. package/dist/src/export/exporter.js +66 -0
  64. package/dist/src/export/exporter.js.map +1 -0
  65. package/dist/src/export/gif.d.ts +3 -0
  66. package/dist/src/export/gif.d.ts.map +1 -0
  67. package/dist/src/export/gif.js +36 -0
  68. package/dist/src/export/gif.js.map +1 -0
  69. package/dist/src/export/presets.d.ts +4 -0
  70. package/dist/src/export/presets.d.ts.map +1 -0
  71. package/dist/src/export/presets.js +68 -0
  72. package/dist/src/export/presets.js.map +1 -0
  73. package/dist/src/export/smart-crop.d.ts +10 -0
  74. package/dist/src/export/smart-crop.d.ts.map +1 -0
  75. package/dist/src/export/smart-crop.js +50 -0
  76. package/dist/src/export/smart-crop.js.map +1 -0
  77. package/dist/src/index.d.ts +10 -0
  78. package/dist/src/index.d.ts.map +1 -0
  79. package/dist/src/index.js +9 -0
  80. package/dist/src/index.js.map +1 -0
  81. package/dist/src/recording/chapters.d.ts +3 -0
  82. package/dist/src/recording/chapters.d.ts.map +1 -0
  83. package/dist/src/recording/chapters.js +37 -0
  84. package/dist/src/recording/chapters.js.map +1 -0
  85. package/dist/src/recording/event-log.d.ts +20 -0
  86. package/dist/src/recording/event-log.d.ts.map +1 -0
  87. package/dist/src/recording/event-log.js +37 -0
  88. package/dist/src/recording/event-log.js.map +1 -0
  89. package/dist/src/recording/metadata.d.ts +4 -0
  90. package/dist/src/recording/metadata.d.ts.map +1 -0
  91. package/dist/src/recording/metadata.js +8 -0
  92. package/dist/src/recording/metadata.js.map +1 -0
  93. package/dist/src/recording/types.d.ts +81 -0
  94. package/dist/src/recording/types.d.ts.map +1 -0
  95. package/dist/src/recording/types.js +2 -0
  96. package/dist/src/recording/types.js.map +1 -0
  97. package/dist/src/utils/config.d.ts +13 -0
  98. package/dist/src/utils/config.d.ts.map +1 -0
  99. package/dist/src/utils/config.js +37 -0
  100. package/dist/src/utils/config.js.map +1 -0
  101. package/dist/src/utils/errors.d.ts +20 -0
  102. package/dist/src/utils/errors.d.ts.map +1 -0
  103. package/dist/src/utils/errors.js +39 -0
  104. package/dist/src/utils/errors.js.map +1 -0
  105. package/dist/src/utils/logger.d.ts +9 -0
  106. package/dist/src/utils/logger.d.ts.map +1 -0
  107. package/dist/src/utils/logger.js +40 -0
  108. package/dist/src/utils/logger.js.map +1 -0
  109. package/dist/src/utils/paths.d.ts +9 -0
  110. package/dist/src/utils/paths.d.ts.map +1 -0
  111. package/dist/src/utils/paths.js +28 -0
  112. package/dist/src/utils/paths.js.map +1 -0
  113. package/dist/src/video/background.d.ts +39 -0
  114. package/dist/src/video/background.d.ts.map +1 -0
  115. package/dist/src/video/background.js +141 -0
  116. package/dist/src/video/background.js.map +1 -0
  117. package/dist/src/video/compose.d.ts +14 -0
  118. package/dist/src/video/compose.d.ts.map +1 -0
  119. package/dist/src/video/compose.js +149 -0
  120. package/dist/src/video/compose.js.map +1 -0
  121. package/dist/src/video/cursor.d.ts +10 -0
  122. package/dist/src/video/cursor.d.ts.map +1 -0
  123. package/dist/src/video/cursor.js +31 -0
  124. package/dist/src/video/cursor.js.map +1 -0
  125. package/dist/src/video/ffmpeg.d.ts +10 -0
  126. package/dist/src/video/ffmpeg.d.ts.map +1 -0
  127. package/dist/src/video/ffmpeg.js +71 -0
  128. package/dist/src/video/ffmpeg.js.map +1 -0
  129. package/dist/src/video/highlight.d.ts +3 -0
  130. package/dist/src/video/highlight.d.ts.map +1 -0
  131. package/dist/src/video/highlight.js +21 -0
  132. package/dist/src/video/highlight.js.map +1 -0
  133. package/dist/src/video/trim.d.ts +19 -0
  134. package/dist/src/video/trim.d.ts.map +1 -0
  135. package/dist/src/video/trim.js +47 -0
  136. package/dist/src/video/trim.js.map +1 -0
  137. package/dist/src/video/zoom.d.ts +11 -0
  138. package/dist/src/video/zoom.d.ts.map +1 -0
  139. package/dist/src/video/zoom.js +88 -0
  140. package/dist/src/video/zoom.js.map +1 -0
  141. package/package.json +63 -0
@@ -0,0 +1,71 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { FFmpegError } from '../utils/errors.js';
3
+ import { logger } from '../utils/logger.js';
4
+ export async function runFFmpeg(options) {
5
+ const args = [
6
+ '-y',
7
+ '-i', options.input,
8
+ ];
9
+ if (options.filterComplex) {
10
+ args.push('-filter_complex', options.filterComplex);
11
+ }
12
+ if (options.outputArgs) {
13
+ args.push(...options.outputArgs);
14
+ }
15
+ args.push(options.output);
16
+ logger.debug(`ffmpeg ${args.join(' ')}`);
17
+ return new Promise((resolve, reject) => {
18
+ const proc = spawn('ffmpeg', args, { stdio: ['pipe', 'pipe', 'pipe'] });
19
+ let stderr = '';
20
+ proc.stderr?.on('data', (data) => {
21
+ const text = data.toString();
22
+ stderr += text;
23
+ // Parse progress from ffmpeg output
24
+ const timeMatch = text.match(/time=(\d{2}):(\d{2}):(\d{2})\.(\d{2})/);
25
+ if (timeMatch && options.onProgress) {
26
+ const seconds = parseInt(timeMatch[1]) * 3600 +
27
+ parseInt(timeMatch[2]) * 60 +
28
+ parseInt(timeMatch[3]) +
29
+ parseInt(timeMatch[4]) / 100;
30
+ options.onProgress(seconds);
31
+ }
32
+ });
33
+ proc.on('close', (code) => {
34
+ if (code === 0) {
35
+ resolve();
36
+ }
37
+ else {
38
+ reject(new FFmpegError(`FFmpeg exited with code ${code}:\n${stderr.slice(-500)}`));
39
+ }
40
+ });
41
+ proc.on('error', (err) => {
42
+ reject(new FFmpegError(`FFmpeg not found or failed to spawn: ${err.message}`));
43
+ });
44
+ });
45
+ }
46
+ export async function getVideoDuration(filePath) {
47
+ return new Promise((resolve, reject) => {
48
+ const proc = spawn('ffprobe', [
49
+ '-v', 'error',
50
+ '-show_entries', 'format=duration',
51
+ '-of', 'default=noprint_wrappers=1:nokey=1',
52
+ filePath,
53
+ ]);
54
+ let stdout = '';
55
+ proc.stdout?.on('data', (data) => {
56
+ stdout += data.toString();
57
+ });
58
+ proc.on('close', (code) => {
59
+ if (code === 0) {
60
+ resolve(parseFloat(stdout.trim()));
61
+ }
62
+ else {
63
+ reject(new FFmpegError('Failed to get video duration'));
64
+ }
65
+ });
66
+ proc.on('error', (err) => {
67
+ reject(new FFmpegError(`ffprobe not found: ${err.message}`));
68
+ });
69
+ });
70
+ }
71
+ //# sourceMappingURL=ffmpeg.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ffmpeg.js","sourceRoot":"","sources":["../../../src/video/ffmpeg.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { RecordingEvent, Viewport } from '../recording/types.js';
2
+ export declare function buildHighlightFilters(events: RecordingEvent[], _viewport: Viewport): string[];
3
+ //# sourceMappingURL=highlight.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlight.d.ts","sourceRoot":"","sources":["../../../src/video/highlight.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAQtE,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,SAAS,EAAE,QAAQ,GAAG,MAAM,EAAE,CAuB7F"}
@@ -0,0 +1,21 @@
1
+ const HIGHLIGHT_DURATION_S = 0.8;
2
+ const HIGHLIGHT_THICKNESS = 3;
3
+ const HIGHLIGHT_PADDING = 6;
4
+ const CLICK_COLOR = 'blue@0.7';
5
+ const TYPE_COLOR = 'green@0.7';
6
+ export function buildHighlightFilters(events, _viewport) {
7
+ const filters = [];
8
+ const highlightEvents = events.filter((e) => (e.type === 'click' || e.type === 'type') && e.bounding_box);
9
+ for (const event of highlightEvents) {
10
+ const box = event.bounding_box;
11
+ const t = event.timestamp_ms / 1000;
12
+ const color = event.type === 'click' ? CLICK_COLOR : TYPE_COLOR;
13
+ const x = Math.max(0, Math.round(box.x - HIGHLIGHT_PADDING));
14
+ const y = Math.max(0, Math.round(box.y - HIGHLIGHT_PADDING));
15
+ const w = Math.round(box.width + HIGHLIGHT_PADDING * 2);
16
+ const h = Math.round(box.height + HIGHLIGHT_PADDING * 2);
17
+ filters.push(`drawbox=x=${x}:y=${y}:w=${w}:h=${h}:color=${color}:t=${HIGHLIGHT_THICKNESS}:enable='between(t,${t.toFixed(3)},${(t + HIGHLIGHT_DURATION_S).toFixed(3)})'`);
18
+ }
19
+ return filters;
20
+ }
21
+ //# sourceMappingURL=highlight.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"highlight.js","sourceRoot":"","sources":["../../../src/video/highlight.ts"],"names":[],"mappings":"AAEA,MAAM,oBAAoB,GAAG,GAAG,CAAC;AACjC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAC9B,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAC5B,MAAM,WAAW,GAAG,UAAU,CAAC;AAC/B,MAAM,UAAU,GAAG,WAAW,CAAC;AAE/B,MAAM,UAAU,qBAAqB,CAAC,MAAwB,EAAE,SAAmB;IACjF,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CACnC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CACnE,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;QACpC,MAAM,GAAG,GAAG,KAAK,CAAC,YAAa,CAAC;QAChC,MAAM,CAAC,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC;QACpC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC;QAEhE,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC;QAC7D,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC;QAC7D,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,iBAAiB,GAAG,CAAC,CAAC,CAAC;QACxD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,GAAG,iBAAiB,GAAG,CAAC,CAAC,CAAC;QAEzD,OAAO,CAAC,IAAI,CACV,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,UAAU,KAAK,MAAM,mBAAmB,sBAAsB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,oBAAoB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAC3J,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { RecordingEvent } from '../recording/types.js';
2
+ export interface Segment {
3
+ start_s: number;
4
+ end_s: number;
5
+ }
6
+ /**
7
+ * Compute active segments from events, merging overlaps.
8
+ * Any gap longer than MIN_GAP_TO_TRIM_S gets trimmed down.
9
+ */
10
+ export declare function computeActiveSegments(events: RecordingEvent[], videoDuration_s: number): Segment[];
11
+ /**
12
+ * Build FFmpeg select + setpts filter to keep only active segments.
13
+ */
14
+ export declare function buildTrimFilter(segments: Segment[]): string;
15
+ /**
16
+ * Estimate the trimmed duration.
17
+ */
18
+ export declare function estimateTrimmedDuration(segments: Segment[]): number;
19
+ //# sourceMappingURL=trim.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trim.d.ts","sourceRoot":"","sources":["../../../src/video/trim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAMD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,cAAc,EAAE,EACxB,eAAe,EAAE,MAAM,GACtB,OAAO,EAAE,CA0BX;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAQ3D;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,CAEnE"}
@@ -0,0 +1,47 @@
1
+ const BUFFER_BEFORE_S = 0.8;
2
+ const BUFFER_AFTER_S = 1.5;
3
+ const MIN_GAP_TO_TRIM_S = 3.0;
4
+ /**
5
+ * Compute active segments from events, merging overlaps.
6
+ * Any gap longer than MIN_GAP_TO_TRIM_S gets trimmed down.
7
+ */
8
+ export function computeActiveSegments(events, videoDuration_s) {
9
+ if (events.length === 0)
10
+ return [{ start_s: 0, end_s: videoDuration_s }];
11
+ // Build raw segments around each event
12
+ const raw = events.map((e) => ({
13
+ start_s: Math.max(0, e.timestamp_ms / 1000 - BUFFER_BEFORE_S),
14
+ end_s: Math.min(videoDuration_s, e.timestamp_ms / 1000 + BUFFER_AFTER_S),
15
+ }));
16
+ // Merge overlapping / close segments
17
+ raw.sort((a, b) => a.start_s - b.start_s);
18
+ const merged = [raw[0]];
19
+ for (let i = 1; i < raw.length; i++) {
20
+ const prev = merged[merged.length - 1];
21
+ const curr = raw[i];
22
+ // If gap between segments is small, keep it continuous
23
+ if (curr.start_s - prev.end_s < MIN_GAP_TO_TRIM_S) {
24
+ prev.end_s = Math.max(prev.end_s, curr.end_s);
25
+ }
26
+ else {
27
+ merged.push({ ...curr });
28
+ }
29
+ }
30
+ return merged;
31
+ }
32
+ /**
33
+ * Build FFmpeg select + setpts filter to keep only active segments.
34
+ */
35
+ export function buildTrimFilter(segments) {
36
+ if (segments.length === 0)
37
+ return '';
38
+ const selectParts = segments.map((s) => `between(t,${s.start_s.toFixed(3)},${s.end_s.toFixed(3)})`);
39
+ return `select='${selectParts.join('+')}',setpts=N/FRAME_RATE/TB`;
40
+ }
41
+ /**
42
+ * Estimate the trimmed duration.
43
+ */
44
+ export function estimateTrimmedDuration(segments) {
45
+ return segments.reduce((sum, s) => sum + (s.end_s - s.start_s), 0);
46
+ }
47
+ //# sourceMappingURL=trim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trim.js","sourceRoot":"","sources":["../../../src/video/trim.ts"],"names":[],"mappings":"AAOA,MAAM,eAAe,GAAG,GAAG,CAAC;AAC5B,MAAM,cAAc,GAAG,GAAG,CAAC;AAC3B,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAwB,EACxB,eAAuB;IAEvB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC,CAAC;IAEzE,uCAAuC;IACvC,MAAM,GAAG,GAAc,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACxC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,YAAY,GAAG,IAAI,GAAG,eAAe,CAAC;QAC7D,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,eAAe,EAAE,CAAC,CAAC,YAAY,GAAG,IAAI,GAAG,cAAc,CAAC;KACzE,CAAC,CAAC,CAAC;IAEJ,qCAAqC;IACrC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAc,CAAC,GAAG,CAAC,CAAC,CAAE,CAAC,CAAC;IAEpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;QACxC,MAAM,IAAI,GAAG,GAAG,CAAC,CAAC,CAAE,CAAC;QAErB,uDAAuD;QACvD,IAAI,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,GAAG,iBAAiB,EAAE,CAAC;YAClD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;QAChD,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,QAAmB;IACjD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAC9B,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAClE,CAAC;IAEF,OAAO,WAAW,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,0BAA0B,CAAC;AACpE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,QAAmB;IACzD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC;AACrE,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { RecordingEvent, Viewport } from '../recording/types.js';
2
+ export interface ZoomKeyframe {
3
+ time_s: number;
4
+ x: number;
5
+ y: number;
6
+ w: number;
7
+ h: number;
8
+ }
9
+ export declare function generateZoomKeyframes(events: RecordingEvent[], viewport: Viewport): ZoomKeyframe[];
10
+ export declare function buildZoomFilterExpr(keyframes: ZoomKeyframe[], viewport: Viewport): string;
11
+ //# sourceMappingURL=zoom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zoom.d.ts","sourceRoot":"","sources":["../../../src/video/zoom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEtE,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAQD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,cAAc,EAAE,EACxB,QAAQ,EAAE,QAAQ,GACjB,YAAY,EAAE,CA6DhB;AAED,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,YAAY,EAAE,EACzB,QAAQ,EAAE,QAAQ,GACjB,MAAM,CAmCR"}
@@ -0,0 +1,88 @@
1
+ const APPROACH_MS = 300;
2
+ const HOLD_MS = 600;
3
+ const RELEASE_MS = 500;
4
+ const PADDING_RATIO = 0.3;
5
+ const MIN_ZOOM_RATIO = 0.4; // Don't zoom in more than 40% of viewport
6
+ export function generateZoomKeyframes(events, viewport) {
7
+ const keyframes = [];
8
+ const eventsWithBoxes = events.filter((e) => e.bounding_box);
9
+ if (eventsWithBoxes.length === 0)
10
+ return keyframes;
11
+ // Start fully zoomed out
12
+ keyframes.push({ time_s: 0, x: 0, y: 0, w: viewport.width, h: viewport.height });
13
+ for (const event of eventsWithBoxes) {
14
+ const box = event.bounding_box;
15
+ const t = event.timestamp_ms / 1000;
16
+ // Calculate padded crop region
17
+ const padX = box.width * PADDING_RATIO;
18
+ const padY = box.height * PADDING_RATIO;
19
+ let cropW = box.width + padX * 2;
20
+ let cropH = box.height + padY * 2;
21
+ // Ensure minimum zoom size
22
+ const minW = viewport.width * MIN_ZOOM_RATIO;
23
+ const minH = viewport.height * MIN_ZOOM_RATIO;
24
+ cropW = Math.max(cropW, minW);
25
+ cropH = Math.max(cropH, minH);
26
+ // Maintain aspect ratio of viewport
27
+ const aspect = viewport.width / viewport.height;
28
+ if (cropW / cropH < aspect) {
29
+ cropW = cropH * aspect;
30
+ }
31
+ else {
32
+ cropH = cropW / aspect;
33
+ }
34
+ // Don't exceed viewport
35
+ cropW = Math.min(cropW, viewport.width);
36
+ cropH = Math.min(cropH, viewport.height);
37
+ // Center on bounding box
38
+ let cropX = box.x + box.width / 2 - cropW / 2;
39
+ let cropY = box.y + box.height / 2 - cropH / 2;
40
+ // Clamp to viewport bounds
41
+ cropX = Math.max(0, Math.min(cropX, viewport.width - cropW));
42
+ cropY = Math.max(0, Math.min(cropY, viewport.height - cropH));
43
+ // Approach keyframe (zoom in)
44
+ const approachT = Math.max(0, t - APPROACH_MS / 1000);
45
+ keyframes.push({ time_s: approachT, x: cropX, y: cropY, w: cropW, h: cropH });
46
+ // Hold keyframe (stay zoomed)
47
+ keyframes.push({ time_s: t, x: cropX, y: cropY, w: cropW, h: cropH });
48
+ // Release keyframe (zoom out)
49
+ const releaseT = t + HOLD_MS / 1000;
50
+ keyframes.push({ time_s: releaseT, x: cropX, y: cropY, w: cropW, h: cropH });
51
+ const resetT = releaseT + RELEASE_MS / 1000;
52
+ keyframes.push({ time_s: resetT, x: 0, y: 0, w: viewport.width, h: viewport.height });
53
+ }
54
+ return keyframes;
55
+ }
56
+ export function buildZoomFilterExpr(keyframes, viewport) {
57
+ if (keyframes.length === 0)
58
+ return '';
59
+ // Build expressions for x, y, w, h using linear interpolation between keyframes
60
+ const buildExpr = (prop) => {
61
+ if (keyframes.length === 1)
62
+ return String(Math.round(keyframes[0][prop]));
63
+ let expr = '';
64
+ for (let i = 0; i < keyframes.length - 1; i++) {
65
+ const k0 = keyframes[i];
66
+ const k1 = keyframes[i + 1];
67
+ const v0 = k0[prop];
68
+ const v1 = k1[prop];
69
+ const t0 = k0.time_s;
70
+ const t1 = k1.time_s;
71
+ if (t1 === t0)
72
+ continue;
73
+ // Linear interpolation: v0 + (v1 - v0) * (t - t0) / (t1 - t0)
74
+ const segment = `if(between(t,${t0.toFixed(3)},${t1.toFixed(3)}),${v0.toFixed(1)}+(${(v1 - v0).toFixed(1)})*(t-${t0.toFixed(3)})/${(t1 - t0).toFixed(3)}`;
75
+ expr = expr ? `${expr},${segment}` : segment;
76
+ }
77
+ // Close all the if-parens and use the last value as default
78
+ const lastVal = keyframes[keyframes.length - 1][prop];
79
+ const closingParens = ')'.repeat(keyframes.length - 1);
80
+ return `${expr},${lastVal.toFixed(1)}${closingParens}`;
81
+ };
82
+ const cropX = buildExpr('x');
83
+ const cropY = buildExpr('y');
84
+ const cropW = buildExpr('w');
85
+ const cropH = buildExpr('h');
86
+ return `crop=w='${cropW}':h='${cropH}':x='${cropX}':y='${cropY}',scale=${viewport.width}:${viewport.height}`;
87
+ }
88
+ //# sourceMappingURL=zoom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zoom.js","sourceRoot":"","sources":["../../../src/video/zoom.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "screencli",
3
+ "version": "0.1.0",
4
+ "description": "AI-powered screen recording CLI tool",
5
+ "type": "module",
6
+ "bin": {
7
+ "screencli": "./dist/bin/cli.js"
8
+ },
9
+ "main": "./dist/src/index.js",
10
+ "types": "./dist/src/index.d.ts",
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "dev": "tsx bin/cli.ts",
14
+ "start": "node dist/bin/cli.js",
15
+ "test": "vitest run",
16
+ "test:watch": "vitest",
17
+ "lint": "eslint . --ext .ts",
18
+ "format": "prettier --write '**/*.ts'"
19
+ },
20
+ "dependencies": {
21
+ "@anthropic-ai/sdk": "^0.39.0",
22
+ "chalk": "^5.4.1",
23
+ "commander": "^13.1.0",
24
+ "ora": "^8.2.0",
25
+ "playwright": "^1.50.0",
26
+ "uuid": "^11.1.0",
27
+ "zod": "^3.24.2"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^22.13.0",
31
+ "@types/uuid": "^10.0.0",
32
+ "eslint": "^9.19.0",
33
+ "prettier": "^3.4.2",
34
+ "tsx": "^4.19.2",
35
+ "typescript": "^5.7.3",
36
+ "vitest": "^3.0.5"
37
+ },
38
+ "engines": {
39
+ "node": ">=18"
40
+ },
41
+ "files": [
42
+ "dist",
43
+ "README.md",
44
+ "LICENSE"
45
+ ],
46
+ "keywords": [
47
+ "screen-recording",
48
+ "ai-agent",
49
+ "browser-recording",
50
+ "cli",
51
+ "playwright",
52
+ "claude",
53
+ "demo",
54
+ "screencast",
55
+ "video"
56
+ ],
57
+ "license": "MIT",
58
+ "repository": {
59
+ "type": "git",
60
+ "url": "https://github.com/danleshem/screencli"
61
+ },
62
+ "homepage": "https://screencli.sh"
63
+ }