screenci 0.0.68 → 0.0.70
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/README.md +45 -122
- package/dist/cli.d.ts +3 -18
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +117 -158
- package/dist/cli.js.map +1 -1
- package/dist/docs/manifest.d.ts +66 -35
- package/dist/docs/manifest.d.ts.map +1 -1
- package/dist/docs/manifest.js +22 -11
- package/dist/docs/manifest.js.map +1 -1
- package/dist/docs/video-sources/cli.screenci.d.ts +2 -0
- package/dist/docs/video-sources/cli.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/{cli.video.js → cli.screenci.js} +1 -1
- package/dist/docs/video-sources/cli.screenci.js.map +1 -0
- package/dist/docs/video-sources/installation.screenci.d.ts +2 -0
- package/dist/docs/video-sources/installation.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/{installation.video.js → installation.screenci.js} +1 -1
- package/dist/docs/video-sources/installation.screenci.js.map +1 -0
- package/dist/docs/video-sources/landing.screenci.d.ts +2 -0
- package/dist/docs/video-sources/landing.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/{landing.video.js → landing.screenci.js} +1 -1
- package/dist/docs/video-sources/landing.screenci.js.map +1 -0
- package/dist/docs/video-sources/locator-highlight-animated.screenci.d.ts +2 -0
- package/dist/docs/video-sources/locator-highlight-animated.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/locator-highlight-animated.screenci.js +53 -0
- package/dist/docs/video-sources/locator-highlight-animated.screenci.js.map +1 -0
- package/dist/docs/video-sources/locator-highlight-still.screenci.d.ts +2 -0
- package/dist/docs/video-sources/locator-highlight-still.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/locator-highlight-still.screenci.js +24 -0
- package/dist/docs/video-sources/locator-highlight-still.screenci.js.map +1 -0
- package/dist/docs/video-sources/product-pitch.screenci.d.ts +2 -0
- package/dist/docs/video-sources/product-pitch.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/product-pitch.screenci.js +136 -0
- package/dist/docs/video-sources/product-pitch.screenci.js.map +1 -0
- package/dist/docs/video-sources/public-urls.screenci.d.ts +2 -0
- package/dist/docs/video-sources/public-urls.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/public-urls.screenci.js +34 -0
- package/dist/docs/video-sources/public-urls.screenci.js.map +1 -0
- package/dist/docs/video-sources/studio.screenci.d.ts +2 -0
- package/dist/docs/video-sources/studio.screenci.d.ts.map +1 -0
- package/dist/docs/video-sources/studio.screenci.js +57 -0
- package/dist/docs/video-sources/studio.screenci.js.map +1 -0
- package/dist/docs/videos.d.ts +36 -15
- package/dist/docs/videos.d.ts.map +1 -1
- package/dist/docs/videos.js +27 -2
- package/dist/docs/videos.js.map +1 -1
- package/dist/e2e/htmlRasterizer.e2e.d.ts +2 -0
- package/dist/e2e/htmlRasterizer.e2e.d.ts.map +1 -0
- package/dist/e2e/htmlRasterizer.e2e.js +107 -0
- package/dist/e2e/htmlRasterizer.e2e.js.map +1 -0
- package/dist/e2e/screenshot.e2e.d.ts +2 -0
- package/dist/e2e/screenshot.e2e.d.ts.map +1 -0
- package/dist/e2e/screenshot.e2e.js +73 -0
- package/dist/e2e/screenshot.e2e.js.map +1 -0
- package/dist/index.d.ts +10 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -2
- package/dist/index.js.map +1 -1
- package/dist/src/asset.d.ts +245 -53
- package/dist/src/asset.d.ts.map +1 -1
- package/dist/src/asset.js +718 -77
- package/dist/src/asset.js.map +1 -1
- package/dist/src/audio.d.ts +127 -0
- package/dist/src/audio.d.ts.map +1 -0
- package/dist/src/audio.js +207 -0
- package/dist/src/audio.js.map +1 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/config.js +9 -3
- package/dist/src/config.js.map +1 -1
- package/dist/src/contextOptions.d.ts +48 -0
- package/dist/src/contextOptions.d.ts.map +1 -0
- package/dist/src/contextOptions.js +71 -0
- package/dist/src/contextOptions.js.map +1 -0
- package/dist/src/crop.d.ts +93 -0
- package/dist/src/crop.d.ts.map +1 -0
- package/dist/src/crop.js +133 -0
- package/dist/src/crop.js.map +1 -0
- package/dist/src/cue.d.ts +17 -4
- package/dist/src/cue.d.ts.map +1 -1
- package/dist/src/cue.js +31 -3
- package/dist/src/cue.js.map +1 -1
- package/dist/src/defaults.d.ts +13 -1
- package/dist/src/defaults.d.ts.map +1 -1
- package/dist/src/defaults.js +13 -0
- package/dist/src/defaults.js.map +1 -1
- package/dist/src/dimensions.d.ts +6 -0
- package/dist/src/dimensions.d.ts.map +1 -1
- package/dist/src/dimensions.js +15 -0
- package/dist/src/dimensions.js.map +1 -1
- package/dist/src/events.d.ts +283 -13
- package/dist/src/events.d.ts.map +1 -1
- package/dist/src/events.js +134 -5
- package/dist/src/events.js.map +1 -1
- package/dist/src/htmlRasterizer.d.ts +153 -0
- package/dist/src/htmlRasterizer.d.ts.map +1 -0
- package/dist/src/htmlRasterizer.js +386 -0
- package/dist/src/htmlRasterizer.js.map +1 -0
- package/dist/src/init.d.ts +17 -0
- package/dist/src/init.d.ts.map +1 -1
- package/dist/src/init.js +131 -11
- package/dist/src/init.js.map +1 -1
- package/dist/src/linkSession.d.ts +36 -0
- package/dist/src/linkSession.d.ts.map +1 -0
- package/dist/src/linkSession.js +122 -0
- package/dist/src/linkSession.js.map +1 -0
- package/dist/src/overlayFlush.d.ts +18 -0
- package/dist/src/overlayFlush.d.ts.map +1 -0
- package/dist/src/overlayFlush.js +56 -0
- package/dist/src/overlayFlush.js.map +1 -0
- package/dist/src/overlayRect.d.ts +69 -0
- package/dist/src/overlayRect.d.ts.map +1 -0
- package/dist/src/overlayRect.js +55 -0
- package/dist/src/overlayRect.js.map +1 -0
- package/dist/src/performance.d.ts +1 -3
- package/dist/src/performance.d.ts.map +1 -1
- package/dist/src/performance.js +0 -12
- package/dist/src/performance.js.map +1 -1
- package/dist/src/recording.d.ts +3 -2
- package/dist/src/recording.d.ts.map +1 -1
- package/dist/src/recordingData.d.ts +22 -2
- package/dist/src/recordingData.d.ts.map +1 -1
- package/dist/src/runtimeContext.d.ts +57 -1
- package/dist/src/runtimeContext.d.ts.map +1 -1
- package/dist/src/runtimeContext.js +40 -0
- package/dist/src/runtimeContext.js.map +1 -1
- package/dist/src/screenshot.d.ts +105 -0
- package/dist/src/screenshot.d.ts.map +1 -0
- package/dist/src/screenshot.js +188 -0
- package/dist/src/screenshot.js.map +1 -0
- package/dist/src/stillCapture.d.ts +68 -0
- package/dist/src/stillCapture.d.ts.map +1 -0
- package/dist/src/stillCapture.js +119 -0
- package/dist/src/stillCapture.js.map +1 -0
- package/dist/src/studio.d.ts +8 -11
- package/dist/src/studio.d.ts.map +1 -1
- package/dist/src/studio.js +2 -25
- package/dist/src/studio.js.map +1 -1
- package/dist/src/types.d.ts +125 -15
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/video.d.ts +54 -1
- package/dist/src/video.d.ts.map +1 -1
- package/dist/src/video.js +190 -42
- package/dist/src/video.js.map +1 -1
- package/dist/src/voices.d.ts +22 -9
- package/dist/src/voices.d.ts.map +1 -1
- package/dist/src/voices.js +6 -24
- package/dist/src/voices.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -2
- package/skills/screenci/SKILL.md +37 -15
- package/skills/screenci/references/init.md +3 -1
- package/skills/screenci/references/record.md +8 -3
- package/dist/docs/video-sources/cli.video.d.ts +0 -2
- package/dist/docs/video-sources/cli.video.d.ts.map +0 -1
- package/dist/docs/video-sources/cli.video.js.map +0 -1
- package/dist/docs/video-sources/installation.video.d.ts +0 -2
- package/dist/docs/video-sources/installation.video.d.ts.map +0 -1
- package/dist/docs/video-sources/installation.video.js.map +0 -1
- package/dist/docs/video-sources/landing.video.d.ts +0 -2
- package/dist/docs/video-sources/landing.video.d.ts.map +0 -1
- package/dist/docs/video-sources/landing.video.js.map +0 -1
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { spawn } from 'child_process';
|
|
2
|
+
import { createHash } from 'crypto';
|
|
3
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
4
|
+
import { mkdtemp, readFile, rm, writeFile } from 'fs/promises';
|
|
5
|
+
import { tmpdir } from 'os';
|
|
6
|
+
import { dirname, join } from 'path';
|
|
7
|
+
import ffmpegStatic from 'ffmpeg-static';
|
|
8
|
+
import { getRuntimePage, getRuntimeRecordingDir } from './runtimeContext.js';
|
|
9
|
+
const ffmpegPath = ffmpegStatic;
|
|
10
|
+
const OVERLAY_ROOT_ID = 'screenci-overlay-root';
|
|
11
|
+
// Render overlays at 2x pixel density so the PNG carries more detail than the
|
|
12
|
+
// on-screen overlay size. The renderer then downscales it to the placement box,
|
|
13
|
+
// which keeps text and edges crisp. 2x keeps overlays sharp at typical sizes
|
|
14
|
+
// while roughly quartering the byte cost of the previous 4x density. Overlay
|
|
15
|
+
// content is bounded by the off-screen page viewport, so the screenshot stays
|
|
16
|
+
// well under GPU texture limits.
|
|
17
|
+
export const DEFAULT_OVERLAY_DEVICE_SCALE_FACTOR = 2;
|
|
18
|
+
// Bump when anything that affects rasterized output changes (the HTML wrapper,
|
|
19
|
+
// screenshot options, default density) so stale cache entries are invalidated.
|
|
20
|
+
const RASTERIZE_CACHE_VERSION = 2;
|
|
21
|
+
let rasterizer = playwrightHtmlRasterizer;
|
|
22
|
+
// Cache only the real (browser) rasterizer. Injected rasterizers are used by
|
|
23
|
+
// tests, where caching across a shared tmp dir would leak between cases.
|
|
24
|
+
let cacheEnabled = true;
|
|
25
|
+
export function setHtmlRasterizer(fn) {
|
|
26
|
+
rasterizer = fn;
|
|
27
|
+
cacheEnabled = false;
|
|
28
|
+
}
|
|
29
|
+
/** Test hook: re-enable caching after injecting a (counting) rasterizer. */
|
|
30
|
+
export function setOverlayCacheEnabled(enabled) {
|
|
31
|
+
cacheEnabled = enabled;
|
|
32
|
+
}
|
|
33
|
+
// CSS injected into every overlay document, on top of the minimal reset. Set it
|
|
34
|
+
// once (e.g. to your compiled Tailwind stylesheet) so overlays can be styled
|
|
35
|
+
// with `className`. Per-overlay `css` is merged on top of this.
|
|
36
|
+
let defaultOverlayCss = '';
|
|
37
|
+
/**
|
|
38
|
+
* Sets CSS injected into every HTML/React overlay document. Pass a compiled
|
|
39
|
+
* stylesheet (for example Tailwind's output) so overlays can use `className`.
|
|
40
|
+
* Per-overlay `css` is appended after this.
|
|
41
|
+
*/
|
|
42
|
+
export function setOverlayCss(css) {
|
|
43
|
+
defaultOverlayCss = css;
|
|
44
|
+
}
|
|
45
|
+
/** Merges the global default overlay CSS with a per-overlay override. */
|
|
46
|
+
export function resolveOverlayCss(css) {
|
|
47
|
+
return [defaultOverlayCss, css]
|
|
48
|
+
.filter((part) => part !== undefined && part.length > 0)
|
|
49
|
+
.join('\n');
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Content hash that uniquely identifies a rasterized overlay's output. The
|
|
53
|
+
* single source of truth for both the on-disk cache key and the in-run dedupe
|
|
54
|
+
* key, so the two can never drift apart.
|
|
55
|
+
*/
|
|
56
|
+
export function overlayInputHash(input) {
|
|
57
|
+
const body = input.kind === 'image'
|
|
58
|
+
? `${RASTERIZE_CACHE_VERSION} ${input.deviceScaleFactor} ${input.capturePadding} ${input.css} ${input.html}`
|
|
59
|
+
: `${RASTERIZE_CACHE_VERSION} anim ${input.deviceScaleFactor} ${input.capturePadding} ${input.fps} ${input.durationMs} ${input.css} ${input.html}`;
|
|
60
|
+
return createHash('sha256').update(body).digest('hex');
|
|
61
|
+
}
|
|
62
|
+
function wrapOverlayHtml(html, options = {}) {
|
|
63
|
+
const { css, capturePadding } = options;
|
|
64
|
+
// capturePadding is transparent padding on the root, so the captured box (the
|
|
65
|
+
// element/clip bounding box) grows by it on every side. Animations can then
|
|
66
|
+
// translate/scale/rotate within that margin without being clipped, replacing
|
|
67
|
+
// the manual "stage" wrapper.
|
|
68
|
+
const padding = capturePadding !== undefined && capturePadding > 0
|
|
69
|
+
? `;padding:${capturePadding}px`
|
|
70
|
+
: '';
|
|
71
|
+
const userStyle = css !== undefined && css.length > 0 ? `<style>${css}</style>` : '';
|
|
72
|
+
return ('<!doctype html><html><head><meta charset="utf-8"><style>' +
|
|
73
|
+
'html,body{margin:0;padding:0;background:transparent}' +
|
|
74
|
+
`#${OVERLAY_ROOT_ID}{display:inline-block${padding}}` +
|
|
75
|
+
`</style>${userStyle}</head><body><div id="${OVERLAY_ROOT_ID}">${html}</div></body></html>`);
|
|
76
|
+
}
|
|
77
|
+
async function playwrightHtmlRasterizer(request) {
|
|
78
|
+
const page = getRuntimePage();
|
|
79
|
+
if (page === null) {
|
|
80
|
+
throw new Error('[screenci] Cannot rasterize an HTML overlay without an active recording page.');
|
|
81
|
+
}
|
|
82
|
+
const browser = page.context().browser();
|
|
83
|
+
if (browser === null) {
|
|
84
|
+
throw new Error('[screenci] Cannot rasterize an HTML overlay: the browser is not available.');
|
|
85
|
+
}
|
|
86
|
+
// A dedicated context with no video recording so the overlay render never
|
|
87
|
+
// leaks into the recording page or its captured video.
|
|
88
|
+
const overlayContext = await browser.newContext({
|
|
89
|
+
deviceScaleFactor: request.deviceScaleFactor ?? DEFAULT_OVERLAY_DEVICE_SCALE_FACTOR,
|
|
90
|
+
});
|
|
91
|
+
try {
|
|
92
|
+
const overlayPage = await overlayContext.newPage();
|
|
93
|
+
await overlayPage.setContent(wrapOverlayHtml(request.html, {
|
|
94
|
+
...(request.css !== undefined && { css: request.css }),
|
|
95
|
+
...(request.capturePadding !== undefined && {
|
|
96
|
+
capturePadding: request.capturePadding,
|
|
97
|
+
}),
|
|
98
|
+
}), { waitUntil: 'load' });
|
|
99
|
+
const root = overlayPage.locator(`#${OVERLAY_ROOT_ID}`);
|
|
100
|
+
const box = await root.boundingBox();
|
|
101
|
+
const buffer = await root.screenshot({ omitBackground: true, type: 'png' });
|
|
102
|
+
return {
|
|
103
|
+
buffer,
|
|
104
|
+
width: box ? Math.round(box.width) : 0,
|
|
105
|
+
height: box ? Math.round(box.height) : 0,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
await overlayContext.close().catch(() => { });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function sanitizeName(name) {
|
|
113
|
+
return name.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Renders the overlay, reusing a cached PNG when the same input (markup +
|
|
117
|
+
* density) was already rendered in a previous run. The per-recording directory
|
|
118
|
+
* is wiped each run, so the cache lives one level up (`.screenci/.overlay-cache`)
|
|
119
|
+
* and survives across runs. Rendering an overlay launches a browser context, so
|
|
120
|
+
* skipping unchanged ones speeds up the author loop noticeably.
|
|
121
|
+
*/
|
|
122
|
+
async function renderOverlay(recordingDir, deviceScaleFactor, html, css, capturePadding) {
|
|
123
|
+
const request = {
|
|
124
|
+
html,
|
|
125
|
+
deviceScaleFactor,
|
|
126
|
+
...(css.length > 0 && { css }),
|
|
127
|
+
...(capturePadding > 0 && { capturePadding }),
|
|
128
|
+
};
|
|
129
|
+
if (!cacheEnabled) {
|
|
130
|
+
return rasterizer(request);
|
|
131
|
+
}
|
|
132
|
+
const inputHash = overlayInputHash({
|
|
133
|
+
kind: 'image',
|
|
134
|
+
deviceScaleFactor,
|
|
135
|
+
capturePadding,
|
|
136
|
+
css,
|
|
137
|
+
html,
|
|
138
|
+
});
|
|
139
|
+
const cacheDir = join(dirname(recordingDir), '.overlay-cache');
|
|
140
|
+
const pngPath = join(cacheDir, `${inputHash}.png`);
|
|
141
|
+
const metaPath = join(cacheDir, `${inputHash}.json`);
|
|
142
|
+
if (existsSync(pngPath) && existsSync(metaPath)) {
|
|
143
|
+
const { width, height } = JSON.parse(readFileSync(metaPath, 'utf-8'));
|
|
144
|
+
return { buffer: readFileSync(pngPath), width, height };
|
|
145
|
+
}
|
|
146
|
+
const result = await rasterizer(request);
|
|
147
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
148
|
+
writeFileSync(pngPath, result.buffer);
|
|
149
|
+
writeFileSync(metaPath, JSON.stringify({ width: result.width, height: result.height }));
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Rasterizes overlay HTML to a transparent PNG written into the per-recording
|
|
154
|
+
* directory so the upload step picks it up alongside the recording. Returns the
|
|
155
|
+
* path, content hash, and intrinsic pixel size. Unchanged overlays are served
|
|
156
|
+
* from a cross-run cache instead of re-rendering.
|
|
157
|
+
*/
|
|
158
|
+
export async function rasterizeHtmlOverlay(opts) {
|
|
159
|
+
const recordingDir = getRuntimeRecordingDir();
|
|
160
|
+
if (recordingDir === null) {
|
|
161
|
+
throw new Error('[screenci] Cannot write a generated overlay: no active recording directory.');
|
|
162
|
+
}
|
|
163
|
+
const deviceScaleFactor = opts.deviceScaleFactor ?? DEFAULT_OVERLAY_DEVICE_SCALE_FACTOR;
|
|
164
|
+
const css = opts.cssResolved === true ? (opts.css ?? '') : resolveOverlayCss(opts.css);
|
|
165
|
+
const { buffer, width, height } = await renderOverlay(recordingDir, deviceScaleFactor, opts.html, css, opts.capturePadding ?? 0);
|
|
166
|
+
const fileHash = createHash('sha256').update(buffer).digest('hex');
|
|
167
|
+
const dir = join(recordingDir, 'generated');
|
|
168
|
+
mkdirSync(dir, { recursive: true });
|
|
169
|
+
const path = join(dir, `${sanitizeName(opts.name)}-${fileHash.slice(0, 16)}.png`);
|
|
170
|
+
writeFileSync(path, buffer);
|
|
171
|
+
return { path, fileHash, width, height };
|
|
172
|
+
}
|
|
173
|
+
// ─── Animated overlays ────────────────────────────────────────────────────────
|
|
174
|
+
export const DEFAULT_ANIMATION_FPS = 30;
|
|
175
|
+
/**
|
|
176
|
+
* Number of frames captured for an animation of `durationMs` at `fps`. At least
|
|
177
|
+
* one frame so a zero-length capture still produces a valid clip. Pure so the
|
|
178
|
+
* sampling math can be unit-tested without a browser.
|
|
179
|
+
*/
|
|
180
|
+
export function framesForDuration(durationMs, fps) {
|
|
181
|
+
if (!Number.isFinite(durationMs) || durationMs < 0) {
|
|
182
|
+
throw new Error(`[screenci] Animated overlay durationMs must be a finite number >= 0. Received: ${String(durationMs)}`);
|
|
183
|
+
}
|
|
184
|
+
if (!Number.isFinite(fps) || fps <= 0) {
|
|
185
|
+
throw new Error(`[screenci] Animated overlay fps must be a finite number > 0. Received: ${String(fps)}`);
|
|
186
|
+
}
|
|
187
|
+
return Math.max(1, Math.round(durationMs / (1000 / fps)));
|
|
188
|
+
}
|
|
189
|
+
let animatedRasterizer = playwrightAnimatedHtmlRasterizer;
|
|
190
|
+
export function setAnimatedHtmlRasterizer(fn) {
|
|
191
|
+
animatedRasterizer = fn;
|
|
192
|
+
cacheEnabled = false;
|
|
193
|
+
}
|
|
194
|
+
// Single ffmpeg graph that turns the RGBA PNG sequence into one MP4 carrying two
|
|
195
|
+
// NVDEC-decodable H.264 streams: stream 0 is the opaque color, stream 1 is the
|
|
196
|
+
// alpha matte (its luma IS the alpha plane). Dimensions are padded to even so
|
|
197
|
+
// yuv420p is valid. The matte is converted full-range then tagged tv (a
|
|
198
|
+
// metadata-only label) so the renderer's CUDA graph never range-converts it and
|
|
199
|
+
// the alpha reaches full opacity — the same recipe NarrationRenderer uses for
|
|
200
|
+
// its shape mask (a limited-range matte caps opacity at ~92%).
|
|
201
|
+
const ANIMATION_FILTER_COMPLEX = '[0:v]pad=ceil(iw/2)*2:ceil(ih/2)*2:0:0:color=black@0,split=2[a][b];' +
|
|
202
|
+
'[a]format=yuv420p[col];' +
|
|
203
|
+
'[b]alphaextract,scale=in_range=full:out_range=full,format=yuv420p,setparams=range=tv[alp]';
|
|
204
|
+
async function captureAnimationFrames(request) {
|
|
205
|
+
const page = getRuntimePage();
|
|
206
|
+
if (page === null) {
|
|
207
|
+
throw new Error('[screenci] Cannot rasterize an animated overlay without an active recording page.');
|
|
208
|
+
}
|
|
209
|
+
const browser = page.context().browser();
|
|
210
|
+
if (browser === null) {
|
|
211
|
+
throw new Error('[screenci] Cannot rasterize an animated overlay: the browser is not available.');
|
|
212
|
+
}
|
|
213
|
+
const overlayContext = await browser.newContext({
|
|
214
|
+
deviceScaleFactor: request.deviceScaleFactor ?? DEFAULT_OVERLAY_DEVICE_SCALE_FACTOR,
|
|
215
|
+
});
|
|
216
|
+
try {
|
|
217
|
+
const overlayPage = await overlayContext.newPage();
|
|
218
|
+
// Install a virtual clock at t=0 before loading so the animation starts from
|
|
219
|
+
// its first frame; advancing the clock deterministically samples each frame.
|
|
220
|
+
await overlayPage.clock.install({ time: 0 });
|
|
221
|
+
await overlayPage.setContent(wrapOverlayHtml(request.html, {
|
|
222
|
+
...(request.css !== undefined && { css: request.css }),
|
|
223
|
+
...(request.capturePadding !== undefined && {
|
|
224
|
+
capturePadding: request.capturePadding,
|
|
225
|
+
}),
|
|
226
|
+
}), { waitUntil: 'load' });
|
|
227
|
+
const root = overlayPage.locator(`#${OVERLAY_ROOT_ID}`);
|
|
228
|
+
const box = await root.boundingBox();
|
|
229
|
+
// Capture a fixed clip (the initial layout box) for every frame so the
|
|
230
|
+
// encoded stream has constant dimensions. Animate transform/opacity rather
|
|
231
|
+
// than layout size to stay within the box.
|
|
232
|
+
const clip = box !== null
|
|
233
|
+
? { x: box.x, y: box.y, width: box.width, height: box.height }
|
|
234
|
+
: undefined;
|
|
235
|
+
const frames = [];
|
|
236
|
+
const frameCount = framesForDuration(request.durationMs, request.fps);
|
|
237
|
+
let elapsed = 0;
|
|
238
|
+
for (let i = 0; i < frameCount; i++) {
|
|
239
|
+
frames.push(await overlayPage.screenshot({
|
|
240
|
+
omitBackground: true,
|
|
241
|
+
type: 'png',
|
|
242
|
+
...(clip !== undefined && { clip }),
|
|
243
|
+
}));
|
|
244
|
+
// Advance to the next exact frame timestamp (integer ms, no drift).
|
|
245
|
+
const next = Math.round(((i + 1) * 1000) / request.fps);
|
|
246
|
+
await overlayPage.clock.runFor(next - elapsed);
|
|
247
|
+
elapsed = next;
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
frames,
|
|
251
|
+
width: box ? Math.round(box.width) : 0,
|
|
252
|
+
height: box ? Math.round(box.height) : 0,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
finally {
|
|
256
|
+
await overlayContext.close().catch(() => { });
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function runFfmpeg(args) {
|
|
260
|
+
return new Promise((resolve, reject) => {
|
|
261
|
+
if (ffmpegPath === null) {
|
|
262
|
+
reject(new Error('[screenci] ffmpeg binary not found; cannot encode an animated overlay.'));
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const child = spawn(ffmpegPath, args, {
|
|
266
|
+
stdio: ['ignore', 'ignore', 'pipe'],
|
|
267
|
+
});
|
|
268
|
+
let stderr = '';
|
|
269
|
+
child.stderr?.on('data', (chunk) => {
|
|
270
|
+
stderr += chunk.toString();
|
|
271
|
+
});
|
|
272
|
+
child.on('error', reject);
|
|
273
|
+
child.on('close', (code) => {
|
|
274
|
+
if (code === 0) {
|
|
275
|
+
resolve();
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
reject(new Error(`[screenci] ffmpeg exited with code ${String(code)} while encoding an animated overlay.\n${stderr.slice(-2000)}`));
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
async function encodeAnimationFrames(frames, fps) {
|
|
283
|
+
const tmp = await mkdtemp(join(tmpdir(), 'screenci-anim-'));
|
|
284
|
+
try {
|
|
285
|
+
await Promise.all(frames.map((buffer, i) => writeFile(join(tmp, `frame_${String(i + 1).padStart(5, '0')}.png`), buffer)));
|
|
286
|
+
const outPath = join(tmp, 'overlay.mp4');
|
|
287
|
+
await runFfmpeg([
|
|
288
|
+
'-y',
|
|
289
|
+
'-framerate',
|
|
290
|
+
String(fps),
|
|
291
|
+
'-i',
|
|
292
|
+
join(tmp, 'frame_%05d.png'),
|
|
293
|
+
'-filter_complex',
|
|
294
|
+
ANIMATION_FILTER_COMPLEX,
|
|
295
|
+
'-map',
|
|
296
|
+
'[col]',
|
|
297
|
+
'-map',
|
|
298
|
+
'[alp]',
|
|
299
|
+
'-c:v',
|
|
300
|
+
'libx264',
|
|
301
|
+
'-pix_fmt',
|
|
302
|
+
'yuv420p',
|
|
303
|
+
'-preset',
|
|
304
|
+
'veryfast',
|
|
305
|
+
'-movflags',
|
|
306
|
+
'+faststart',
|
|
307
|
+
outPath,
|
|
308
|
+
]);
|
|
309
|
+
return await readFile(outPath);
|
|
310
|
+
}
|
|
311
|
+
finally {
|
|
312
|
+
await rm(tmp, { recursive: true, force: true });
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
async function playwrightAnimatedHtmlRasterizer(request) {
|
|
316
|
+
const { frames, width, height } = await captureAnimationFrames(request);
|
|
317
|
+
const buffer = await encodeAnimationFrames(frames, request.fps);
|
|
318
|
+
return { buffer, width, height };
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Renders an animated overlay, reusing a cached clip when the same input
|
|
322
|
+
* (markup + density + fps + duration) was already rendered in a previous run.
|
|
323
|
+
* Mirrors {@link renderOverlay} but caches the encoded .mp4.
|
|
324
|
+
*/
|
|
325
|
+
async function renderAnimatedOverlay(recordingDir, request) {
|
|
326
|
+
if (!cacheEnabled) {
|
|
327
|
+
return animatedRasterizer(request);
|
|
328
|
+
}
|
|
329
|
+
const deviceScaleFactor = request.deviceScaleFactor ?? DEFAULT_OVERLAY_DEVICE_SCALE_FACTOR;
|
|
330
|
+
const inputHash = overlayInputHash({
|
|
331
|
+
kind: 'animation',
|
|
332
|
+
deviceScaleFactor,
|
|
333
|
+
capturePadding: request.capturePadding ?? 0,
|
|
334
|
+
fps: request.fps,
|
|
335
|
+
durationMs: request.durationMs,
|
|
336
|
+
css: request.css ?? '',
|
|
337
|
+
html: request.html,
|
|
338
|
+
});
|
|
339
|
+
const cacheDir = join(dirname(recordingDir), '.overlay-cache');
|
|
340
|
+
const clipPath = join(cacheDir, `${inputHash}.mp4`);
|
|
341
|
+
const metaPath = join(cacheDir, `${inputHash}.anim.json`);
|
|
342
|
+
if (existsSync(clipPath) && existsSync(metaPath)) {
|
|
343
|
+
const { width, height } = JSON.parse(readFileSync(metaPath, 'utf-8'));
|
|
344
|
+
return { buffer: readFileSync(clipPath), width, height };
|
|
345
|
+
}
|
|
346
|
+
const result = await animatedRasterizer(request);
|
|
347
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
348
|
+
writeFileSync(clipPath, result.buffer);
|
|
349
|
+
writeFileSync(metaPath, JSON.stringify({ width: result.width, height: result.height }));
|
|
350
|
+
return result;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Rasterizes an animated HTML/React overlay to a transparent clip (a single
|
|
354
|
+
* .mp4 with a color stream and an alpha-matte stream) written into the
|
|
355
|
+
* per-recording directory for upload. Returns the path, content hash, intrinsic
|
|
356
|
+
* size, and capture duration. Unchanged overlays are served from the cross-run
|
|
357
|
+
* cache instead of re-rendering.
|
|
358
|
+
*/
|
|
359
|
+
export async function rasterizeAnimatedHtmlOverlay(opts) {
|
|
360
|
+
const recordingDir = getRuntimeRecordingDir();
|
|
361
|
+
if (recordingDir === null) {
|
|
362
|
+
throw new Error('[screenci] Cannot write a generated overlay: no active recording directory.');
|
|
363
|
+
}
|
|
364
|
+
const fps = opts.fps ?? DEFAULT_ANIMATION_FPS;
|
|
365
|
+
const deviceScaleFactor = opts.deviceScaleFactor ?? DEFAULT_OVERLAY_DEVICE_SCALE_FACTOR;
|
|
366
|
+
// Validate sampling parameters up front (also exercised by the real capture).
|
|
367
|
+
framesForDuration(opts.durationMs, fps);
|
|
368
|
+
const css = opts.cssResolved === true ? (opts.css ?? '') : resolveOverlayCss(opts.css);
|
|
369
|
+
const { buffer, width, height } = await renderAnimatedOverlay(recordingDir, {
|
|
370
|
+
html: opts.html,
|
|
371
|
+
durationMs: opts.durationMs,
|
|
372
|
+
fps,
|
|
373
|
+
deviceScaleFactor,
|
|
374
|
+
...(css.length > 0 && { css }),
|
|
375
|
+
...(opts.capturePadding !== undefined && {
|
|
376
|
+
capturePadding: opts.capturePadding,
|
|
377
|
+
}),
|
|
378
|
+
});
|
|
379
|
+
const fileHash = createHash('sha256').update(buffer).digest('hex');
|
|
380
|
+
const dir = join(recordingDir, 'generated');
|
|
381
|
+
mkdirSync(dir, { recursive: true });
|
|
382
|
+
const path = join(dir, `${sanitizeName(opts.name)}-${fileHash.slice(0, 16)}.mp4`);
|
|
383
|
+
writeFileSync(path, buffer);
|
|
384
|
+
return { path, fileHash, width, height, durationMs: opts.durationMs };
|
|
385
|
+
}
|
|
386
|
+
//# sourceMappingURL=htmlRasterizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"htmlRasterizer.js","sourceRoot":"","sources":["../../src/htmlRasterizer.ts"],"names":[],"mappings":"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"}
|
package/dist/src/init.d.ts
CHANGED
|
@@ -28,10 +28,27 @@ export declare function parsePackageManager(value: string | undefined, cwd?: str
|
|
|
28
28
|
* when the slug is empty or would collide with `screenci`.
|
|
29
29
|
*/
|
|
30
30
|
export declare function toIslandPackageName(projectName: string): string;
|
|
31
|
+
export declare function generateIslandTsconfig(withReact?: boolean): string;
|
|
31
32
|
export declare function generateIslandReadme(projectName: string, packageManager: PackageManager): string;
|
|
32
33
|
export declare function parsePnpmVersionSupport(versionOutput: string): PnpmVersionSupport;
|
|
33
34
|
export declare function parseYarnVersionSupport(versionOutput: string): YarnVersionSupport;
|
|
35
|
+
/**
|
|
36
|
+
* Pre-creates a CLI sign-in link during init and persists it into the new
|
|
37
|
+
* project's `.screenci/link-session.json`, so the user can sign in while their
|
|
38
|
+
* first video is being authored and a later `screenci record` reuses the same
|
|
39
|
+
* link (it just polls and continues once sign-in completes).
|
|
40
|
+
*
|
|
41
|
+
* Best-effort: a network failure here must never fail `init`. If a secret is
|
|
42
|
+
* already configured there is nothing to sign in for, so we skip silently.
|
|
43
|
+
*
|
|
44
|
+
* Returns the sign-in URL when one was created, otherwise null.
|
|
45
|
+
*/
|
|
46
|
+
export declare function createInitLinkSession(islandDir: string, options?: {
|
|
47
|
+
env?: NodeJS.ProcessEnv;
|
|
48
|
+
}): Promise<string | null>;
|
|
34
49
|
export declare function generateExampleVideo(): string;
|
|
50
|
+
export declare function generateReactExampleVideo(): string;
|
|
35
51
|
export declare function runInit(projectNameArg: string | undefined, options: InitOptions): Promise<void>;
|
|
36
52
|
export declare function runCreateScreenciCli(argv?: string[]): Promise<void>;
|
|
53
|
+
export declare function generateConfig(projectName: string): string;
|
|
37
54
|
//# sourceMappingURL=init.d.ts.map
|
package/dist/src/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/init.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/init.ts"],"names":[],"mappings":"AA2BA,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;AAEpD,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,OAAO,CAAA;IAChB,GAAG,EAAE,OAAO,CAAA;IACZ,cAAc,EAAE,cAAc,CAAA;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAKD,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAE,OAAO,CAAA;IAClB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,MAAM,EACF,WAAW,GACX,gBAAgB,GAChB,mBAAmB,GACnB,iBAAiB,CAAA;CACtB,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,SAAS,EAAE,OAAO,CAAA;IAClB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,MAAM,EACF,WAAW,GACX,gBAAgB,GAChB,mBAAmB,GACnB,iBAAiB,CAAA;CACtB,CAAA;AAED,wBAAgB,gCAAgC,CAC9C,GAAG,EAAE,MAAM,GACV,cAAc,GAAG,IAAI,CAUvB;AAED,wBAAgB,mCAAmC,CACjD,GAAG,EAAE,MAAM,GACV,cAAc,GAAG,IAAI,CAavB;AAED,wBAAgB,uBAAuB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,cAAc,CAwBpE;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CASxD;AAmSD,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,GAAG,CAAC,EAAE,MAAM,GACX,cAAc,CAUhB;AAoID;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAS/D;AAoBD,wBAAgB,sBAAsB,CAAC,SAAS,UAAQ,GAAG,MAAM,CA6BhE;AAiCD,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,cAAc,GAC7B,MAAM,CAiBR;AA4DD,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,GACpB,kBAAkB,CA6BpB;AA0ED,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,GACpB,kBAAkB,CAapB;AA0MD;;;;;;;;;;GAUG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAA;CAAO,GACxC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA2BxB;AA+HD,wBAAgB,oBAAoB,IAAI,MAAM,CA+B7C;AAED,wBAAgB,yBAAyB,IAAI,MAAM,CA0ClD;AAyGD,wBAAsB,OAAO,CAC3B,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAwPf;AAeD,wBAAsB,oBAAoB,CACxC,IAAI,GAAE,MAAM,EAAiB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAqCf;AAED,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAgC1D"}
|