screenci 0.0.68 → 0.0.69
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 +1 -1
- package/dist/cli.d.ts +3 -18
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +105 -154
- package/dist/cli.js.map +1 -1
- package/dist/docs/manifest.d.ts +13 -13
- package/dist/docs/manifest.js +4 -4
- package/dist/docs/manifest.js.map +1 -1
- package/dist/docs/video-sources/studio.video.d.ts +2 -0
- package/dist/docs/video-sources/studio.video.d.ts.map +1 -0
- package/dist/docs/video-sources/studio.video.js +57 -0
- package/dist/docs/video-sources/studio.video.js.map +1 -0
- 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/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/src/asset.d.ts +141 -53
- package/dist/src/asset.d.ts.map +1 -1
- package/dist/src/asset.js +533 -78
- package/dist/src/asset.js.map +1 -1
- package/dist/src/audio.d.ts +113 -0
- package/dist/src/audio.d.ts.map +1 -0
- package/dist/src/audio.js +204 -0
- package/dist/src/audio.js.map +1 -0
- package/dist/src/defaults.d.ts +7 -1
- package/dist/src/defaults.d.ts.map +1 -1
- package/dist/src/defaults.js +7 -0
- package/dist/src/defaults.js.map +1 -1
- package/dist/src/events.d.ts +134 -6
- package/dist/src/events.d.ts.map +1 -1
- package/dist/src/events.js +73 -2
- package/dist/src/events.js.map +1 -1
- package/dist/src/htmlRasterizer.d.ts +110 -0
- package/dist/src/htmlRasterizer.d.ts.map +1 -0
- package/dist/src/htmlRasterizer.js +364 -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 +127 -7
- 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/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 +1 -1
- package/dist/src/recording.d.ts.map +1 -1
- package/dist/src/recordingData.d.ts +2 -2
- package/dist/src/recordingData.d.ts.map +1 -1
- package/dist/src/runtimeContext.d.ts +38 -0
- package/dist/src/runtimeContext.d.ts.map +1 -1
- package/dist/src/runtimeContext.js +25 -0
- package/dist/src/runtimeContext.js.map +1 -1
- package/dist/src/types.d.ts +25 -7
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/dist/src/video.d.ts +34 -1
- package/dist/src/video.d.ts.map +1 -1
- package/dist/src/video.js +120 -19
- 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 +27 -5
- package/skills/screenci/references/init.md +2 -0
- package/skills/screenci/references/record.md +6 -1
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { test, expect } from '@playwright/test';
|
|
2
|
+
import { mkdtemp, rm, readFile } from 'fs/promises';
|
|
3
|
+
import { tmpdir } from 'os';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
import { spawnSync } from 'child_process';
|
|
6
|
+
import ffmpegStatic from 'ffmpeg-static';
|
|
7
|
+
import { rasterizeAnimatedHtmlOverlay, rasterizeHtmlOverlay, } from '../src/htmlRasterizer.js';
|
|
8
|
+
import { createScreenCIRuntimeContext, runWithScreenCIRuntimeContext, } from '../src/runtimeContext.js';
|
|
9
|
+
const PNG_SIGNATURE = Buffer.from([
|
|
10
|
+
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
|
|
11
|
+
]);
|
|
12
|
+
test('rasterizes HTML to a transparent PNG sized to its content', async ({ page, }) => {
|
|
13
|
+
const dir = await mkdtemp(join(tmpdir(), 'screenci-html-e2e-'));
|
|
14
|
+
try {
|
|
15
|
+
const result = await runWithScreenCIRuntimeContext(createScreenCIRuntimeContext({ page, recordingDir: dir }), () => rasterizeHtmlOverlay({
|
|
16
|
+
name: 'badge',
|
|
17
|
+
html: '<div style="width:200px;height:80px;background:#f00">hi</div>',
|
|
18
|
+
}));
|
|
19
|
+
// boundingBox is reported in CSS pixels (the underlying PNG is rendered at
|
|
20
|
+
// the device scale factor for crispness).
|
|
21
|
+
expect(result.width).toBe(200);
|
|
22
|
+
expect(result.height).toBe(80);
|
|
23
|
+
const buffer = await readFile(result.path);
|
|
24
|
+
expect(buffer.subarray(0, 8)).toEqual(PNG_SIGNATURE);
|
|
25
|
+
expect(buffer.length).toBeGreaterThan(0);
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
await rm(dir, { recursive: true, force: true });
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
test('does not require a fixed viewport: content larger than the default viewport still renders', async ({ page, }) => {
|
|
32
|
+
const dir = await mkdtemp(join(tmpdir(), 'screenci-html-e2e-'));
|
|
33
|
+
try {
|
|
34
|
+
const result = await runWithScreenCIRuntimeContext(createScreenCIRuntimeContext({ page, recordingDir: dir }), () => rasterizeHtmlOverlay({
|
|
35
|
+
name: 'wide',
|
|
36
|
+
html: '<div style="width:640px;height:120px;background:#0a0"></div>',
|
|
37
|
+
}));
|
|
38
|
+
expect(result.width).toBe(640);
|
|
39
|
+
expect(result.height).toBe(120);
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
await rm(dir, { recursive: true, force: true });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
test('rasterizes an animated overlay to a two-stream transparent clip', async ({ page, }) => {
|
|
46
|
+
const dir = await mkdtemp(join(tmpdir(), 'screenci-anim-e2e-'));
|
|
47
|
+
try {
|
|
48
|
+
const result = await runWithScreenCIRuntimeContext(createScreenCIRuntimeContext({ page, recordingDir: dir }), () => rasterizeAnimatedHtmlOverlay({
|
|
49
|
+
name: 'intro',
|
|
50
|
+
html: '<div style="width:200px;height:80px;background:#f00;' +
|
|
51
|
+
'animation:fade 1s linear">hi' +
|
|
52
|
+
'<style>@keyframes fade{from{opacity:0}to{opacity:1}}</style></div>',
|
|
53
|
+
durationMs: 500,
|
|
54
|
+
fps: 30,
|
|
55
|
+
}));
|
|
56
|
+
expect(result.width).toBe(200);
|
|
57
|
+
expect(result.height).toBe(80);
|
|
58
|
+
expect(result.durationMs).toBe(500);
|
|
59
|
+
expect(result.path.endsWith('.mp4')).toBe(true);
|
|
60
|
+
const buffer = await readFile(result.path);
|
|
61
|
+
expect(buffer.length).toBeGreaterThan(0);
|
|
62
|
+
// The clip must carry two video streams: color + alpha matte.
|
|
63
|
+
const ffmpegPath = ffmpegStatic;
|
|
64
|
+
const probe = spawnSync(ffmpegPath, ['-hide_banner', '-i', result.path], {
|
|
65
|
+
encoding: 'utf8',
|
|
66
|
+
});
|
|
67
|
+
const info = `${probe.stdout ?? ''}${probe.stderr ?? ''}`;
|
|
68
|
+
const videoStreams = (info.match(/Stream #0:\d+.*Video:/g) ?? []).length;
|
|
69
|
+
expect(videoStreams).toBe(2);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
await rm(dir, { recursive: true, force: true });
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
test('applies injected css so overlays can be styled with className', async ({ page, }) => {
|
|
76
|
+
const dir = await mkdtemp(join(tmpdir(), 'screenci-css-e2e-'));
|
|
77
|
+
try {
|
|
78
|
+
const result = await runWithScreenCIRuntimeContext(createScreenCIRuntimeContext({ page, recordingDir: dir }), () => rasterizeHtmlOverlay({
|
|
79
|
+
name: 'card',
|
|
80
|
+
html: '<div class="box"></div>',
|
|
81
|
+
css: '.box{width:120px;height:60px;background:#f00}',
|
|
82
|
+
}));
|
|
83
|
+
// Without injected CSS the bare <div> would collapse; the className sizes it.
|
|
84
|
+
expect(result.width).toBe(120);
|
|
85
|
+
expect(result.height).toBe(60);
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
await rm(dir, { recursive: true, force: true });
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
test('capturePadding grows the captured box around the content', async ({ page, }) => {
|
|
92
|
+
const dir = await mkdtemp(join(tmpdir(), 'screenci-pad-e2e-'));
|
|
93
|
+
try {
|
|
94
|
+
const result = await runWithScreenCIRuntimeContext(createScreenCIRuntimeContext({ page, recordingDir: dir }), () => rasterizeHtmlOverlay({
|
|
95
|
+
name: 'padded',
|
|
96
|
+
html: '<div style="width:200px;height:80px;background:#0a0"></div>',
|
|
97
|
+
capturePadding: 40,
|
|
98
|
+
}));
|
|
99
|
+
// 40px of transparent padding on every side: 200+80 x 80+80.
|
|
100
|
+
expect(result.width).toBe(280);
|
|
101
|
+
expect(result.height).toBe(160);
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
await rm(dir, { recursive: true, force: true });
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
//# sourceMappingURL=htmlRasterizer.e2e.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"htmlRasterizer.e2e.js","sourceRoot":"","sources":["../../e2e/htmlRasterizer.e2e.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type { AspectRatio, FPS, Quality, RecordUploadPolicy, RecordOptions, RenderOptions, ScreenCIConfig, ExtendedScreenCIConfig, AutoZoomOptions, Easing, } from './src/types.js';
|
|
1
|
+
export type { AspectRatio, FPS, Quality, RecordUploadPolicy, RecordOptions, RenderOptions, ScreenCIConfig, ExtendedScreenCIConfig, AutoZoomOptions, Easing, VideoEncoderPreset, } from './src/types.js';
|
|
2
2
|
export { voices, modelTypes } from './src/voices.js';
|
|
3
3
|
export type { VoiceKey, ModelVoiceKey, ElevenLabsVoiceKey, CustomVoiceRef, ModelType, } from './src/voices.js';
|
|
4
4
|
export { defineConfig } from './src/config.js';
|
|
@@ -13,7 +13,9 @@ export { speed } from './src/speed.js';
|
|
|
13
13
|
export { time } from './src/time.js';
|
|
14
14
|
export { autoZoom } from './src/autoZoom.js';
|
|
15
15
|
export { zoomTo, resetZoom } from './src/manualZoom.js';
|
|
16
|
-
export {
|
|
17
|
-
export type {
|
|
16
|
+
export { createOverlays, createStudioOverlays, setOverlayCss, MAX_AUDIO_LEVEL, } from './src/asset.js';
|
|
17
|
+
export type { OverlayController, OverlayConfig, OverlayInput, Overlays, ReactElementLike, OverlayPlacement, } from './src/asset.js';
|
|
18
|
+
export { createAudio, createStudioAudio } from './src/audio.js';
|
|
19
|
+
export type { AudioController, AudioConfig, AudioInput, AudioTracks, } from './src/audio.js';
|
|
18
20
|
export type { ZoomTarget, ZoomTargetPoint } from './src/manualZoom.js';
|
|
19
21
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,WAAW,EACX,GAAG,EACH,OAAO,EACP,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,eAAe,EACf,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,WAAW,EACX,GAAG,EACH,OAAO,EACP,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,eAAe,EACf,MAAM,EACN,kBAAkB,GACnB,MAAM,gBAAgB,CAAA;AAGvB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AACpD,YAAY,EACV,QAAQ,EACR,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,SAAS,GACV,MAAM,iBAAiB,CAAA;AAGxB,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAG9C,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,YAAY,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACnE,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AACrE,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAC3E,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAC9E,YAAY,EAAE,2BAA2B,EAAE,MAAM,iBAAiB,CAAA;AAClE,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,eAAe,GAChB,MAAM,gBAAgB,CAAA;AACvB,YAAY,EACV,iBAAiB,EACjB,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAC/D,YAAY,EACV,eAAe,EACf,WAAW,EACX,UAAU,EACV,WAAW,GACZ,MAAM,gBAAgB,CAAA;AACvB,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -11,5 +11,6 @@ export { speed } from './src/speed.js';
|
|
|
11
11
|
export { time } from './src/time.js';
|
|
12
12
|
export { autoZoom } from './src/autoZoom.js';
|
|
13
13
|
export { zoomTo, resetZoom } from './src/manualZoom.js';
|
|
14
|
-
export {
|
|
14
|
+
export { createOverlays, createStudioOverlays, setOverlayCss, MAX_AUDIO_LEVEL, } from './src/asset.js';
|
|
15
|
+
export { createAudio, createStudioAudio } from './src/audio.js';
|
|
15
16
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAeA,mBAAmB;AACnB,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AASpD,4BAA4B;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAE9C,4CAA4C;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AAEtC,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAErE,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAE9E,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAA;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAC5C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,EACL,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,eAAe,GAChB,MAAM,gBAAgB,CAAA;AASvB,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA"}
|
package/dist/src/asset.d.ts
CHANGED
|
@@ -1,85 +1,174 @@
|
|
|
1
1
|
import type { IEventRecorder } from './events.js';
|
|
2
|
-
export
|
|
3
|
-
export type
|
|
4
|
-
export type Mp4Path = `${string}.mp4`;
|
|
2
|
+
export { setOverlayCss } from './htmlRasterizer.js';
|
|
3
|
+
export type { OverlayPlacement } from './events.js';
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Minimal structural stand-in for a React element. Defined here so the core SDK
|
|
6
|
+
* never has to depend on `@types/react`: any JSX element is assignable to this,
|
|
7
|
+
* while a plain {@link OverlayConfig} object is not (it has no `type`/`props`).
|
|
8
|
+
* React itself is detected structurally at runtime and rendered lazily, so it
|
|
9
|
+
* stays an optional peer dependency.
|
|
8
10
|
*/
|
|
9
|
-
export type
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
audio?: never;
|
|
11
|
+
export type ReactElementLike = {
|
|
12
|
+
type: unknown;
|
|
13
|
+
props: unknown;
|
|
14
|
+
key?: string | null;
|
|
14
15
|
};
|
|
15
16
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
17
|
+
* Display options for an overlay. Placement fields are flat (not nested) and
|
|
18
|
+
* each defaults independently: `relativeTo: 'recording'`, `x: 0`, `y: 0`, and
|
|
19
|
+
* `width: 1` when neither `width` nor `height` is given. The default box fills
|
|
20
|
+
* the recording area, whose final size is chosen later in the studio.
|
|
19
21
|
*/
|
|
20
|
-
export type
|
|
21
|
-
path:
|
|
22
|
+
export type OverlayConfig = {
|
|
23
|
+
/** File path: `.html` (rendered), `.svg`/`.png` (image), or `.mp4` (video). */
|
|
24
|
+
path?: string;
|
|
25
|
+
/** A React element, rendered to a transparent PNG. Mutually exclusive with `path`. */
|
|
26
|
+
element?: ReactElementLike;
|
|
27
|
+
/** Reference box for placement coordinates. Defaults to `'recording'`. */
|
|
28
|
+
relativeTo?: 'screen' | 'recording';
|
|
29
|
+
/** Left edge as a 0..1 fraction of the reference box. Defaults to `0`. */
|
|
30
|
+
x?: number;
|
|
31
|
+
/** Top edge as a 0..1 fraction of the reference box. Defaults to `0`. */
|
|
32
|
+
y?: number;
|
|
33
|
+
/** Width as a 0..1 fraction. Defaults to `1` when `height` is not set. */
|
|
34
|
+
width?: number;
|
|
35
|
+
/** Height as a 0..1 fraction. Provide instead of `width` (exactly one). */
|
|
36
|
+
height?: number;
|
|
37
|
+
/** Fill the whole output frame. Overrides x/y/width/height. */
|
|
38
|
+
fullScreen?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Visible length for the blocking call form (`await overlays.logo(1200)`).
|
|
41
|
+
* Omit when driving with `start()`/`end()`. Image/HTML/React overlays only.
|
|
42
|
+
*
|
|
43
|
+
* For animated overlays (`animate: true`) this is also the capture length: it
|
|
44
|
+
* is required when driving with `start()`/`end()` (the capture length is
|
|
45
|
+
* otherwise unknown).
|
|
46
|
+
*/
|
|
47
|
+
durationMs?: number;
|
|
48
|
+
/**
|
|
49
|
+
* Capture the overlay as an animation so its CSS/JS animation plays back in
|
|
50
|
+
* the video (HTML files and React elements only). The animation is sampled
|
|
51
|
+
* over the resolved duration with a transparent background preserved.
|
|
52
|
+
*/
|
|
53
|
+
animate?: boolean;
|
|
54
|
+
/** Animation capture frame rate. Only valid with `animate`. Defaults to `30`. */
|
|
55
|
+
fps?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Extra CSS injected into the overlay document so it can be styled with
|
|
58
|
+
* `className` (for example a compiled Tailwind stylesheet). Merged on top of
|
|
59
|
+
* any global CSS set via `setOverlayCss`. HTML files and React elements only.
|
|
60
|
+
*/
|
|
61
|
+
css?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Transparent padding (CSS px) added around the overlay content. Lets an
|
|
64
|
+
* animation move, scale, or rotate beyond its box without being clipped (an
|
|
65
|
+
* automatic "stage"), at the cost of the placement sizing the padded box.
|
|
66
|
+
* HTML files and React elements only.
|
|
67
|
+
*/
|
|
68
|
+
capturePadding?: number;
|
|
69
|
+
/**
|
|
70
|
+
* Soundtrack level for `.mp4` overlays as a linear gain. `1` (the default)
|
|
71
|
+
* plays the source at its natural level, `0` mutes it, and values above `1`
|
|
72
|
+
* boost it (e.g. `2` is twice the natural level). Capped at
|
|
73
|
+
* {@link MAX_AUDIO_LEVEL}.
|
|
74
|
+
*/
|
|
22
75
|
audio?: number;
|
|
23
|
-
fullScreen: boolean;
|
|
24
|
-
durationMs?: never;
|
|
25
76
|
};
|
|
26
|
-
|
|
27
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Upper bound for an audio level (linear gain). `4` is +12 dB, plenty of
|
|
79
|
+
* headroom for a boost while guarding against accidental extreme distortion.
|
|
80
|
+
*/
|
|
81
|
+
export declare const MAX_AUDIO_LEVEL = 4;
|
|
82
|
+
/**
|
|
83
|
+
* A value accepted by {@link createOverlays} for each key:
|
|
84
|
+
*
|
|
85
|
+
* - a `string` file path (`.html`/`.svg`/`.png`/`.mp4`),
|
|
86
|
+
* - a React element, or
|
|
87
|
+
* - an {@link OverlayConfig} object.
|
|
88
|
+
*/
|
|
89
|
+
export type OverlayInput = string | ReactElementLike | OverlayConfig;
|
|
90
|
+
export declare function setAssetSleepFn(fn: (ms: number) => void): void;
|
|
28
91
|
export declare function setActiveAssetRecorder(recorder: IEventRecorder | null): void;
|
|
29
92
|
export declare function resetRegisteredAssetPaths(): void;
|
|
93
|
+
export declare function resetAssetChain(): void;
|
|
30
94
|
export declare function validateRegisteredAssetPaths(testFilePath: string): Promise<void>;
|
|
31
95
|
/**
|
|
32
|
-
* An
|
|
96
|
+
* An overlay controller.
|
|
97
|
+
*
|
|
98
|
+
* Calling it shows the overlay over a frozen frame for a fixed duration
|
|
99
|
+
* (blocking). Use `start()`/`end()` to keep the overlay on screen while the page
|
|
100
|
+
* is driven underneath.
|
|
33
101
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
102
|
+
* Overlays may overlap: several can be live at once (interleaved, not just
|
|
103
|
+
* nested), and a blocking overlay can run while others stay live. Each overlay
|
|
104
|
+
* you `start()` must be `end()`ed before the video function returns, and the
|
|
105
|
+
* same overlay cannot be started twice without ending it in between.
|
|
37
106
|
*
|
|
38
107
|
* @example
|
|
39
108
|
* ```ts
|
|
40
|
-
*
|
|
41
|
-
* await
|
|
42
|
-
*
|
|
109
|
+
* // Blocking: hold the overlay for 1.2s, then continue.
|
|
110
|
+
* await overlays.logo(1200)
|
|
111
|
+
*
|
|
112
|
+
* // Live: keep the overlay up while interacting with the page.
|
|
113
|
+
* await overlays.badge.start()
|
|
114
|
+
* await page.click('#next')
|
|
115
|
+
* await overlays.badge.end()
|
|
116
|
+
*
|
|
117
|
+
* // Overlapping: two overlays live at the same time, ended independently.
|
|
118
|
+
* await overlays.badge.start()
|
|
119
|
+
* await overlays.logo.start()
|
|
120
|
+
* await page.click('#next')
|
|
121
|
+
* await overlays.badge.end()
|
|
122
|
+
* await overlays.logo.end()
|
|
43
123
|
* ```
|
|
44
124
|
*/
|
|
45
|
-
export type
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
125
|
+
export type OverlayController = {
|
|
126
|
+
(durationMs?: number): Promise<void>;
|
|
127
|
+
start(): Promise<void>;
|
|
128
|
+
end(): Promise<void>;
|
|
129
|
+
};
|
|
130
|
+
/** Typed overlay controllers keyed by the names passed to {@link createOverlays}. */
|
|
131
|
+
export type Overlays<T extends Record<string, OverlayInput>> = {
|
|
132
|
+
[K in keyof T]: OverlayController;
|
|
49
133
|
};
|
|
50
134
|
/**
|
|
51
|
-
* Creates a set of typed
|
|
135
|
+
* Creates a set of typed overlay controllers, one per key in the map. Each value
|
|
136
|
+
* is a file path string, a React element, or an {@link OverlayConfig} object.
|
|
52
137
|
*
|
|
53
|
-
* Calling a controller
|
|
54
|
-
* `.svg`/`.png`
|
|
55
|
-
*
|
|
138
|
+
* Calling a controller shows the overlay in the recording timeline. Image
|
|
139
|
+
* (`.svg`/`.png`), HTML, and React overlays need a `durationMs` (in the config
|
|
140
|
+
* or passed to the blocking call) unless driven with `start()`/`end()`; `.mp4`
|
|
141
|
+
* overlays use their natural duration and default `audio` to `1` (natural level).
|
|
142
|
+
*
|
|
143
|
+
* Placement defaults to the full recording area (`relativeTo: 'recording',
|
|
144
|
+
* x: 0, y: 0, width: 1`); override any field independently.
|
|
56
145
|
*
|
|
57
146
|
* @example
|
|
58
|
-
* ```
|
|
59
|
-
* const
|
|
60
|
-
*
|
|
61
|
-
*
|
|
147
|
+
* ```tsx
|
|
148
|
+
* const overlays = createOverlays({
|
|
149
|
+
* hint: 'callout.html', // HTML file
|
|
150
|
+
* badge: <Badge label="New" />, // React element
|
|
151
|
+
* logo: { path: 'logo.png', x: 0.05, y: 0.05, width: 0.2 },
|
|
152
|
+
* intro: { path: 'intro.mp4', fullScreen: true },
|
|
62
153
|
* })
|
|
63
154
|
*
|
|
64
155
|
* video('Product demo', async ({ page }) => {
|
|
65
|
-
* await
|
|
156
|
+
* await overlays.intro()
|
|
66
157
|
* await page.goto('/dashboard')
|
|
67
|
-
* await
|
|
158
|
+
* await overlays.logo(1200)
|
|
68
159
|
* })
|
|
69
160
|
* ```
|
|
70
161
|
*/
|
|
71
|
-
export declare function
|
|
72
|
-
[K in keyof T]: AssetConfigForPath<T[K]['path']>;
|
|
73
|
-
}): Assets<T>;
|
|
162
|
+
export declare function createOverlays<const T extends Record<string, OverlayInput>>(overlays: T): Overlays<T>;
|
|
74
163
|
/**
|
|
75
|
-
* Creates typed
|
|
164
|
+
* Creates typed overlay controllers whose files and display options are
|
|
76
165
|
* configured on the ScreenCI Studio page instead of in code. Business tier
|
|
77
166
|
* only.
|
|
78
167
|
*
|
|
79
|
-
* Each key becomes a callable
|
|
80
|
-
* behavior as {@link
|
|
81
|
-
* `.mp4`),
|
|
82
|
-
* from Studio.
|
|
168
|
+
* Each key becomes a callable overlay controller with the same timeline
|
|
169
|
+
* behavior as {@link createOverlays} controllers, including `start()`/`end()`.
|
|
170
|
+
* The file (`.svg`, `.png`, or `.mp4`), placement, image duration, and video
|
|
171
|
+
* audio level all come from Studio.
|
|
83
172
|
*
|
|
84
173
|
* On the first upload of a studio-mode video, rendering is held until the
|
|
85
174
|
* video is configured in Studio (the CLI prints a direct link). Later uploads
|
|
@@ -87,15 +176,14 @@ export declare function createAssets<const T extends Record<string, AssetConfig>
|
|
|
87
176
|
*
|
|
88
177
|
* @example
|
|
89
178
|
* ```ts
|
|
90
|
-
* const
|
|
179
|
+
* const overlays = createStudioOverlays('intro', 'logo')
|
|
91
180
|
*
|
|
92
181
|
* video('Product demo', async ({ page }) => {
|
|
93
|
-
* await
|
|
182
|
+
* await overlays.intro()
|
|
94
183
|
* await page.goto('/dashboard')
|
|
95
|
-
* await
|
|
184
|
+
* await overlays.logo()
|
|
96
185
|
* })
|
|
97
186
|
* ```
|
|
98
187
|
*/
|
|
99
|
-
export declare function
|
|
100
|
-
export {};
|
|
188
|
+
export declare function createStudioOverlays<const K extends readonly [string, ...string[]]>(...keys: K): Record<K[number], OverlayController>;
|
|
101
189
|
//# sourceMappingURL=asset.d.ts.map
|
package/dist/src/asset.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset.d.ts","sourceRoot":"","sources":["../../src/asset.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"asset.d.ts","sourceRoot":"","sources":["../../src/asset.ts"],"names":[],"mappings":"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"}
|