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.
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +14 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/src/agent/loop.d.ts +21 -0
- package/dist/src/agent/loop.d.ts.map +1 -0
- package/dist/src/agent/loop.js +119 -0
- package/dist/src/agent/loop.js.map +1 -0
- package/dist/src/agent/system-prompt.d.ts +2 -0
- package/dist/src/agent/system-prompt.d.ts.map +1 -0
- package/dist/src/agent/system-prompt.js +43 -0
- package/dist/src/agent/system-prompt.js.map +1 -0
- package/dist/src/agent/tool-handlers.d.ts +44 -0
- package/dist/src/agent/tool-handlers.d.ts.map +1 -0
- package/dist/src/agent/tool-handlers.js +242 -0
- package/dist/src/agent/tool-handlers.js.map +1 -0
- package/dist/src/agent/tools.d.ts +5 -0
- package/dist/src/agent/tools.d.ts.map +1 -0
- package/dist/src/agent/tools.js +251 -0
- package/dist/src/agent/tools.js.map +1 -0
- package/dist/src/browser/accessibility.d.ts +28 -0
- package/dist/src/browser/accessibility.d.ts.map +1 -0
- package/dist/src/browser/accessibility.js +47 -0
- package/dist/src/browser/accessibility.js.map +1 -0
- package/dist/src/browser/actions.d.ts +32 -0
- package/dist/src/browser/actions.d.ts.map +1 -0
- package/dist/src/browser/actions.js +122 -0
- package/dist/src/browser/actions.js.map +1 -0
- package/dist/src/browser/auth.d.ts +12 -0
- package/dist/src/browser/auth.d.ts.map +1 -0
- package/dist/src/browser/auth.js +53 -0
- package/dist/src/browser/auth.js.map +1 -0
- package/dist/src/browser/resolve-locator.d.ts +15 -0
- package/dist/src/browser/resolve-locator.d.ts.map +1 -0
- package/dist/src/browser/resolve-locator.js +27 -0
- package/dist/src/browser/resolve-locator.js.map +1 -0
- package/dist/src/browser/session.d.ts +16 -0
- package/dist/src/browser/session.d.ts.map +1 -0
- package/dist/src/browser/session.js +47 -0
- package/dist/src/browser/session.js.map +1 -0
- package/dist/src/cli/commands/export.d.ts +3 -0
- package/dist/src/cli/commands/export.d.ts.map +1 -0
- package/dist/src/cli/commands/export.js +76 -0
- package/dist/src/cli/commands/export.js.map +1 -0
- package/dist/src/cli/commands/init.d.ts +8 -0
- package/dist/src/cli/commands/init.d.ts.map +1 -0
- package/dist/src/cli/commands/init.js +64 -0
- package/dist/src/cli/commands/init.js.map +1 -0
- package/dist/src/cli/commands/record.d.ts +3 -0
- package/dist/src/cli/commands/record.d.ts.map +1 -0
- package/dist/src/cli/commands/record.js +215 -0
- package/dist/src/cli/commands/record.js.map +1 -0
- package/dist/src/cli/options.d.ts +24 -0
- package/dist/src/cli/options.d.ts.map +1 -0
- package/dist/src/cli/options.js +35 -0
- package/dist/src/cli/options.js.map +1 -0
- package/dist/src/cli/output.d.ts +10 -0
- package/dist/src/cli/output.d.ts.map +1 -0
- package/dist/src/cli/output.js +29 -0
- package/dist/src/cli/output.js.map +1 -0
- package/dist/src/export/exporter.d.ts +16 -0
- package/dist/src/export/exporter.d.ts.map +1 -0
- package/dist/src/export/exporter.js +66 -0
- package/dist/src/export/exporter.js.map +1 -0
- package/dist/src/export/gif.d.ts +3 -0
- package/dist/src/export/gif.d.ts.map +1 -0
- package/dist/src/export/gif.js +36 -0
- package/dist/src/export/gif.js.map +1 -0
- package/dist/src/export/presets.d.ts +4 -0
- package/dist/src/export/presets.d.ts.map +1 -0
- package/dist/src/export/presets.js +68 -0
- package/dist/src/export/presets.js.map +1 -0
- package/dist/src/export/smart-crop.d.ts +10 -0
- package/dist/src/export/smart-crop.d.ts.map +1 -0
- package/dist/src/export/smart-crop.js +50 -0
- package/dist/src/export/smart-crop.js.map +1 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +9 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/recording/chapters.d.ts +3 -0
- package/dist/src/recording/chapters.d.ts.map +1 -0
- package/dist/src/recording/chapters.js +37 -0
- package/dist/src/recording/chapters.js.map +1 -0
- package/dist/src/recording/event-log.d.ts +20 -0
- package/dist/src/recording/event-log.d.ts.map +1 -0
- package/dist/src/recording/event-log.js +37 -0
- package/dist/src/recording/event-log.js.map +1 -0
- package/dist/src/recording/metadata.d.ts +4 -0
- package/dist/src/recording/metadata.d.ts.map +1 -0
- package/dist/src/recording/metadata.js +8 -0
- package/dist/src/recording/metadata.js.map +1 -0
- package/dist/src/recording/types.d.ts +81 -0
- package/dist/src/recording/types.d.ts.map +1 -0
- package/dist/src/recording/types.js +2 -0
- package/dist/src/recording/types.js.map +1 -0
- package/dist/src/utils/config.d.ts +13 -0
- package/dist/src/utils/config.d.ts.map +1 -0
- package/dist/src/utils/config.js +37 -0
- package/dist/src/utils/config.js.map +1 -0
- package/dist/src/utils/errors.d.ts +20 -0
- package/dist/src/utils/errors.d.ts.map +1 -0
- package/dist/src/utils/errors.js +39 -0
- package/dist/src/utils/errors.js.map +1 -0
- package/dist/src/utils/logger.d.ts +9 -0
- package/dist/src/utils/logger.d.ts.map +1 -0
- package/dist/src/utils/logger.js +40 -0
- package/dist/src/utils/logger.js.map +1 -0
- package/dist/src/utils/paths.d.ts +9 -0
- package/dist/src/utils/paths.d.ts.map +1 -0
- package/dist/src/utils/paths.js +28 -0
- package/dist/src/utils/paths.js.map +1 -0
- package/dist/src/video/background.d.ts +39 -0
- package/dist/src/video/background.d.ts.map +1 -0
- package/dist/src/video/background.js +141 -0
- package/dist/src/video/background.js.map +1 -0
- package/dist/src/video/compose.d.ts +14 -0
- package/dist/src/video/compose.d.ts.map +1 -0
- package/dist/src/video/compose.js +149 -0
- package/dist/src/video/compose.js.map +1 -0
- package/dist/src/video/cursor.d.ts +10 -0
- package/dist/src/video/cursor.d.ts.map +1 -0
- package/dist/src/video/cursor.js +31 -0
- package/dist/src/video/cursor.js.map +1 -0
- package/dist/src/video/ffmpeg.d.ts +10 -0
- package/dist/src/video/ffmpeg.d.ts.map +1 -0
- package/dist/src/video/ffmpeg.js +71 -0
- package/dist/src/video/ffmpeg.js.map +1 -0
- package/dist/src/video/highlight.d.ts +3 -0
- package/dist/src/video/highlight.d.ts.map +1 -0
- package/dist/src/video/highlight.js +21 -0
- package/dist/src/video/highlight.js.map +1 -0
- package/dist/src/video/trim.d.ts +19 -0
- package/dist/src/video/trim.d.ts.map +1 -0
- package/dist/src/video/trim.js +47 -0
- package/dist/src/video/trim.js.map +1 -0
- package/dist/src/video/zoom.d.ts +11 -0
- package/dist/src/video/zoom.d.ts.map +1 -0
- package/dist/src/video/zoom.js +88 -0
- package/dist/src/video/zoom.js.map +1 -0
- 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 @@
|
|
|
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
|
+
}
|