versioncam 0.2.0 → 0.4.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/CHANGELOG.md +81 -0
- package/README.md +64 -6
- package/dist/cli/commands/check.js +45 -4
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/publish.d.ts +17 -0
- package/dist/cli/commands/publish.js +203 -0
- package/dist/cli/commands/publish.js.map +1 -0
- package/dist/cli/commands/record.js +2 -0
- package/dist/cli/commands/record.js.map +1 -1
- package/dist/cli/commands/render.js +22 -2
- package/dist/cli/commands/render.js.map +1 -1
- package/dist/cli/main.js +8 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/usage.d.ts +1 -1
- package/dist/cli/usage.js +8 -0
- package/dist/cli/usage.js.map +1 -1
- package/dist/config.d.ts +32 -1
- package/dist/config.js +34 -0
- package/dist/config.js.map +1 -1
- package/dist/driver/clip.d.ts +9 -1
- package/dist/driver/clip.js +17 -5
- package/dist/driver/clip.js.map +1 -1
- package/dist/driver/page-hooks.d.ts +65 -12
- package/dist/driver/page-hooks.js +101 -15
- package/dist/driver/page-hooks.js.map +1 -1
- package/dist/driver/reports.d.ts +34 -2
- package/dist/driver/reports.js +31 -3
- package/dist/driver/reports.js.map +1 -1
- package/dist/driver/session.d.ts +23 -0
- package/dist/driver/session.js +45 -7
- package/dist/driver/session.js.map +1 -1
- package/dist/driver/settle.d.ts +2 -1
- package/dist/driver/settle.js +13 -1
- package/dist/driver/settle.js.map +1 -1
- package/dist/index.d.ts +10 -2
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/publish/client.d.ts +38 -0
- package/dist/publish/client.js +118 -0
- package/dist/publish/client.js.map +1 -0
- package/dist/publish/index.d.ts +12 -0
- package/dist/publish/index.js +11 -0
- package/dist/publish/index.js.map +1 -0
- package/dist/publish/manifest.d.ts +46 -0
- package/dist/publish/manifest.js +133 -0
- package/dist/publish/manifest.js.map +1 -0
- package/dist/publish/protocol.d.ts +203 -0
- package/dist/publish/protocol.js +56 -0
- package/dist/publish/protocol.js.map +1 -0
- package/dist/render/encode.d.ts +15 -0
- package/dist/render/encode.js +23 -4
- package/dist/render/encode.js.map +1 -1
- package/dist/render/render.js +1 -0
- package/dist/render/render.js.map +1 -1
- package/dist/render/sequence.d.ts +3 -1
- package/dist/render/sequence.js +4 -1
- package/dist/render/sequence.js.map +1 -1
- package/dist/render/serve.d.ts +15 -1
- package/dist/render/serve.js +21 -2
- package/dist/render/serve.js.map +1 -1
- package/dsl.md +3 -2
- package/package.json +6 -2
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { parseArgs } from "node:util";
|
|
2
2
|
import { existsSync, readdirSync } from "node:fs";
|
|
3
|
-
import { join } from "node:path";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
4
|
import { launchBrowser } from "../../driver/launch.js";
|
|
5
5
|
import { loadConfig, loadSceneIds } from "../../loader.js";
|
|
6
6
|
import { renderRecording, renderScene } from "../../render/render.js";
|
|
7
7
|
import { missingScenes } from "../../render/scenes.js";
|
|
8
8
|
import { buildSequence } from "../../render/sequence.js";
|
|
9
|
+
import { writeReport } from "./publish.js";
|
|
10
|
+
import { RECORDER_VERSION } from "../../driver/clip.js";
|
|
9
11
|
/** Every recording on disk, by id. */
|
|
10
12
|
function recordedIds(recordingsDir) {
|
|
11
13
|
if (!existsSync(recordingsDir))
|
|
@@ -44,6 +46,7 @@ export async function render(argv) {
|
|
|
44
46
|
options: {
|
|
45
47
|
scene: { type: "string", multiple: true },
|
|
46
48
|
sequence: { type: "boolean" },
|
|
49
|
+
report: { type: "string" },
|
|
47
50
|
},
|
|
48
51
|
strict: false,
|
|
49
52
|
allowPositionals: true,
|
|
@@ -83,11 +86,14 @@ export async function render(argv) {
|
|
|
83
86
|
const browser = await launchBrowser();
|
|
84
87
|
const rendered = [];
|
|
85
88
|
const failures = [];
|
|
89
|
+
const outputs = [];
|
|
90
|
+
let film = null;
|
|
86
91
|
try {
|
|
87
92
|
for (const id of recordings) {
|
|
88
93
|
try {
|
|
89
94
|
const out = await renderRecording(browser, config, id);
|
|
90
95
|
rendered.push(id);
|
|
96
|
+
outputs.push({ id, files: [out.mp4, out.webm, out.poster, out.sheet] });
|
|
91
97
|
process.stdout.write(` ${id}: ${out.durationFrames} frames at ${out.fps}fps ` +
|
|
92
98
|
`(${(out.durationFrames / out.fps).toFixed(1)}s)\n`);
|
|
93
99
|
}
|
|
@@ -116,8 +122,11 @@ export async function render(argv) {
|
|
|
116
122
|
const stitched = order.filter((id) => rendered.includes(id));
|
|
117
123
|
let unusable = [];
|
|
118
124
|
if (stitched.length >= 2) {
|
|
119
|
-
const result = await buildSequence(stitched, config.outputDir
|
|
125
|
+
const result = await buildSequence(stitched, config.outputDir, {
|
|
126
|
+
threads: config.encoderThreads,
|
|
127
|
+
});
|
|
120
128
|
unusable = result.missing;
|
|
129
|
+
film = result.path;
|
|
121
130
|
process.stdout.write(` sequence: ${result.used.length} clips, ${result.total.toFixed(1)}s\n`);
|
|
122
131
|
}
|
|
123
132
|
else {
|
|
@@ -138,6 +147,17 @@ export async function render(argv) {
|
|
|
138
147
|
process.stdout.write(` (not in the config's sequence: ${unlisted.join(", ")})\n`);
|
|
139
148
|
}
|
|
140
149
|
}
|
|
150
|
+
// What was made, and where, for a machine: the Action uploads these files
|
|
151
|
+
// without having to know the config's output directory.
|
|
152
|
+
if (typeof values.report === "string") {
|
|
153
|
+
writeReport(resolve(values.report), {
|
|
154
|
+
recorder: RECORDER_VERSION,
|
|
155
|
+
outputDir: config.outputDir,
|
|
156
|
+
rendered: outputs,
|
|
157
|
+
sequence: film,
|
|
158
|
+
failed: failures.map(({ id, error }) => ({ id, message: error.message })),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
141
161
|
if (failures.length > 0) {
|
|
142
162
|
process.stderr.write("\n");
|
|
143
163
|
for (const { id, error } of failures) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/cli/commands/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/cli/commands/render.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/main.js
CHANGED
|
@@ -10,6 +10,7 @@ import { install } from "./commands/install.js";
|
|
|
10
10
|
import { login } from "./commands/login.js";
|
|
11
11
|
import { measure } from "./commands/measure.js";
|
|
12
12
|
import { preview } from "./commands/preview.js";
|
|
13
|
+
import { publish } from "./commands/publish.js";
|
|
13
14
|
import { record } from "./commands/record.js";
|
|
14
15
|
import { render } from "./commands/render.js";
|
|
15
16
|
import { review } from "./commands/review.js";
|
|
@@ -18,9 +19,11 @@ import { stability } from "./commands/stability.js";
|
|
|
18
19
|
import { loadEnvFiles } from "../env.js";
|
|
19
20
|
import { enterCwd, takeCwd } from "./cwd.js";
|
|
20
21
|
import { USAGE } from "./usage.js";
|
|
22
|
+
import { RECORDER_VERSION } from "../driver/clip.js";
|
|
21
23
|
const COMMANDS = {
|
|
22
24
|
record,
|
|
23
25
|
render,
|
|
26
|
+
publish,
|
|
24
27
|
check,
|
|
25
28
|
stability,
|
|
26
29
|
sheet,
|
|
@@ -45,6 +48,11 @@ async function main() {
|
|
|
45
48
|
process.stdout.write(USAGE);
|
|
46
49
|
return 0;
|
|
47
50
|
}
|
|
51
|
+
// For a script that must know what it is driving before it drives it.
|
|
52
|
+
if (argv.length === 1 && (argv[0] === "--version" || argv[0] === "-v")) {
|
|
53
|
+
process.stdout.write(`${RECORDER_VERSION}\n`);
|
|
54
|
+
return 0;
|
|
55
|
+
}
|
|
48
56
|
const { positionals } = parseArgs({
|
|
49
57
|
args: argv,
|
|
50
58
|
strict: false,
|
package/dist/cli/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/usage.d.ts
CHANGED
|
@@ -12,4 +12,4 @@
|
|
|
12
12
|
* work out that `inspect` comes before `record` and `sheet` after it. The
|
|
13
13
|
* last group is not a stage but a way to run any of them.
|
|
14
14
|
*/
|
|
15
|
-
export declare const USAGE = "versioncam: record and render demo clips of a real app\n\nSet up\n versioncam install the Chromium this version of versioncam records with\n --with-deps and its system libraries (Linux CI)\n versioncam init install the authoring skill into .claude/\n --into <dir> into <dir>/versioncam/ instead, for another host\n --force overwrite files that are already there\n versioncam doctor check this machine can record, and that the app starts\n versioncam login sign in once and save the browser session\n\nWrite\n versioncam inspect <path> what a clip can click, and where each name came from\n --json machine-readable\n versioncam measure <path> <sel> where a selector's matches are, and what they say\n versioncam dsl the clip DSL: every method, its options and defaults\n\nRecord\n versioncam record [id\u2026] drive the app and capture frames\n --draft 15fps at CSS scale: cheap, for writing clips\n versioncam check [id\u2026] record every clip; exit 1 if any breaks\n versioncam stability [id\u2026] record each clip twice the same way; stable or not\n --runs <n> how many times (default 2)\n --full at full quality rather than draft\n\nReview\n versioncam sheet <id> an eight-frame contact sheet\n --at-marks sample the beats instead of even spacing\n versioncam frame <id> <n> one frame at output size, to a png\n --t <seconds> pick the frame by time instead\n --at <label> or by the beat it shows\n versioncam review <id> the checks that need no eyes; PASS/FAIL, exit 0/1\n --beats <file> [{ label, expect }] the clip promised\n --min <s> --max <s> duration bounds (default 9 and 11)\n versioncam preview <id> open the scrubber in a real browser\n --scene <id> preview a scene instead\n --frame <n> start at this frame\n\nOutput\n versioncam render [id\u2026] composite and encode recordings and scenes\n no ids: every one, stale recordings included\n --scene <id> and this scene, whatever the ids say (repeatable)\n --sequence stitch the results into one piece\n\nFrom another directory\n versioncam <command> --cwd <dir> as if run in <dir>, which holds versioncam.config.ts\n\nRun from a directory containing versioncam.config.ts, or name it with --cwd.\n";
|
|
15
|
+
export declare const USAGE = "versioncam: record and render demo clips of a real app\n\nSet up\n versioncam install the Chromium this version of versioncam records with\n --with-deps and its system libraries (Linux CI)\n versioncam init install the authoring skill into .claude/\n --into <dir> into <dir>/versioncam/ instead, for another host\n --force overwrite files that are already there\n versioncam doctor check this machine can record, and that the app starts\n versioncam login sign in once and save the browser session\n\nWrite\n versioncam inspect <path> what a clip can click, and where each name came from\n --json machine-readable\n versioncam measure <path> <sel> where a selector's matches are, and what they say\n versioncam dsl the clip DSL: every method, its options and defaults\n\nRecord\n versioncam record [id\u2026] drive the app and capture frames\n --draft 15fps at CSS scale: cheap, for writing clips\n versioncam check [id\u2026] record every clip; exit 1 if any breaks\n --report <file> and write each clip's result there, as JSON\n versioncam stability [id\u2026] record each clip twice the same way; stable or not\n --runs <n> how many times (default 2)\n --full at full quality rather than draft\n\nReview\n versioncam sheet <id> an eight-frame contact sheet\n --at-marks sample the beats instead of even spacing\n versioncam frame <id> <n> one frame at output size, to a png\n --t <seconds> pick the frame by time instead\n --at <label> or by the beat it shows\n versioncam review <id> the checks that need no eyes; PASS/FAIL, exit 0/1\n --beats <file> [{ label, expect }] the clip promised\n --min <s> --max <s> duration bounds (default 9 and 11)\n versioncam preview <id> open the scrubber in a real browser\n --scene <id> preview a scene instead\n --frame <n> start at this frame\n\nOutput\n versioncam render [id\u2026] composite and encode recordings and scenes\n no ids: every one, stale recordings included\n --scene <id> and this scene, whatever the ids say (repeatable)\n --sequence stitch the results into one piece\n --report <file> and write what it made there, as JSON\n\nPublish\n versioncam publish [id\u2026] send the recordings and their checks to version.cam\n --dry-run print what would be sent, and send nothing\n --report <file> and write the living URLs there, as JSON\n\nFrom another directory\n versioncam <command> --cwd <dir> as if run in <dir>, which holds versioncam.config.ts\n versioncam --version which versioncam this is\n\nRun from a directory containing versioncam.config.ts, or name it with --cwd.\n";
|
package/dist/cli/usage.js
CHANGED
|
@@ -33,6 +33,7 @@ Record
|
|
|
33
33
|
versioncam record [id…] drive the app and capture frames
|
|
34
34
|
--draft 15fps at CSS scale: cheap, for writing clips
|
|
35
35
|
versioncam check [id…] record every clip; exit 1 if any breaks
|
|
36
|
+
--report <file> and write each clip's result there, as JSON
|
|
36
37
|
versioncam stability [id…] record each clip twice the same way; stable or not
|
|
37
38
|
--runs <n> how many times (default 2)
|
|
38
39
|
--full at full quality rather than draft
|
|
@@ -55,9 +56,16 @@ Output
|
|
|
55
56
|
no ids: every one, stale recordings included
|
|
56
57
|
--scene <id> and this scene, whatever the ids say (repeatable)
|
|
57
58
|
--sequence stitch the results into one piece
|
|
59
|
+
--report <file> and write what it made there, as JSON
|
|
60
|
+
|
|
61
|
+
Publish
|
|
62
|
+
versioncam publish [id…] send the recordings and their checks to version.cam
|
|
63
|
+
--dry-run print what would be sent, and send nothing
|
|
64
|
+
--report <file> and write the living URLs there, as JSON
|
|
58
65
|
|
|
59
66
|
From another directory
|
|
60
67
|
versioncam <command> --cwd <dir> as if run in <dir>, which holds versioncam.config.ts
|
|
68
|
+
versioncam --version which versioncam this is
|
|
61
69
|
|
|
62
70
|
Run from a directory containing versioncam.config.ts, or name it with --cwd.
|
|
63
71
|
`;
|
package/dist/cli/usage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/cli/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/cli/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDpB,CAAC"}
|
package/dist/config.d.ts
CHANGED
|
@@ -89,7 +89,28 @@ export type CaptureConfig = {
|
|
|
89
89
|
* whose subject *is* a canvas should set it to 1 and pay full price.
|
|
90
90
|
*/
|
|
91
91
|
forceCaptureEvery?: number;
|
|
92
|
+
/**
|
|
93
|
+
* What the page's CSS transitions do while it is filmed.
|
|
94
|
+
*
|
|
95
|
+
* `"play"`, the default: each one runs at its authored duration and
|
|
96
|
+
* easing, on the page's own clock, from the frame the driver first sees
|
|
97
|
+
* it, so a map that zooms with a transition zooms over its frames instead
|
|
98
|
+
* of jumping. A settle waits for the ones running to finish.
|
|
99
|
+
*
|
|
100
|
+
* `"zero"`: every transition takes no time, so a change lands in the frame
|
|
101
|
+
* after it, and the renderer's crossfade at a settle is all the motion
|
|
102
|
+
* there is. What the recorder did before 0.4.0, for a clip whose app
|
|
103
|
+
* animates in ways better left out of a video.
|
|
104
|
+
*/
|
|
105
|
+
transitions?: Transitions;
|
|
92
106
|
};
|
|
107
|
+
/** See `CaptureConfig.transitions`. */
|
|
108
|
+
export type Transitions = "play" | "zero";
|
|
109
|
+
/**
|
|
110
|
+
* Checked where a value enters: in the config here, and in a clip's own
|
|
111
|
+
* `capture` by `runClip`, since nothing else checks a clip's options.
|
|
112
|
+
*/
|
|
113
|
+
export declare function isTransitions(value: unknown): value is Transitions;
|
|
93
114
|
export type ReviewConfig = {
|
|
94
115
|
/**
|
|
95
116
|
* How long a clip of this app should run, in seconds.
|
|
@@ -186,9 +207,17 @@ export type RecorderConfig = {
|
|
|
186
207
|
cursorScale?: number;
|
|
187
208
|
presentation?: Presentation;
|
|
188
209
|
};
|
|
189
|
-
/**
|
|
210
|
+
/**
|
|
211
|
+
* Output width; the height follows the viewport's aspect. `threads` fixes
|
|
212
|
+
* how many threads each encoder uses. The bytes an encoder writes depend on
|
|
213
|
+
* its thread count, which by default follows the machine's cores, so two
|
|
214
|
+
* machines render the same recording to different files; fixing it is what
|
|
215
|
+
* makes a render reproducible anywhere, and what version.cam's renderer
|
|
216
|
+
* does. `VERSIONCAM_FFMPEG_THREADS` sets it for one run.
|
|
217
|
+
*/
|
|
190
218
|
output?: {
|
|
191
219
|
width?: number;
|
|
220
|
+
threads?: number;
|
|
192
221
|
};
|
|
193
222
|
motion?: Partial<Motion>;
|
|
194
223
|
/** Module whose default export is `Record<string, Scene>`. */
|
|
@@ -232,6 +261,8 @@ export type ResolvedConfig = {
|
|
|
232
261
|
width: number;
|
|
233
262
|
height: number;
|
|
234
263
|
};
|
|
264
|
+
/** Threads per encoder, or null for ffmpeg's own choice. */
|
|
265
|
+
encoderThreads: number | null;
|
|
235
266
|
motion: Motion;
|
|
236
267
|
scenes: string | null;
|
|
237
268
|
sequence: string[] | null;
|
package/dist/config.js
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import { isAbsolute, resolve } from "node:path";
|
|
2
2
|
import { MOTION } from "./core/motion-defaults.js";
|
|
3
|
+
/**
|
|
4
|
+
* Checked where a value enters: in the config here, and in a clip's own
|
|
5
|
+
* `capture` by `runClip`, since nothing else checks a clip's options.
|
|
6
|
+
*/
|
|
7
|
+
export function isTransitions(value) {
|
|
8
|
+
return value === "play" || value === "zero";
|
|
9
|
+
}
|
|
10
|
+
function transitionsOf(value, field) {
|
|
11
|
+
if (value === undefined)
|
|
12
|
+
return "play";
|
|
13
|
+
if (isTransitions(value))
|
|
14
|
+
return value;
|
|
15
|
+
fail(field, `must be "play" or "zero", got ${JSON.stringify(value)}`);
|
|
16
|
+
}
|
|
3
17
|
/** Typed identity, so a config file gets completion and checking. */
|
|
4
18
|
export function defineRecorder(config) {
|
|
5
19
|
return config;
|
|
@@ -7,6 +21,23 @@ export function defineRecorder(config) {
|
|
|
7
21
|
function fail(field, why) {
|
|
8
22
|
throw new Error(`versioncam config: \`${field}\` ${why}`);
|
|
9
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* The environment wins over the config, so a machine (version.cam's renderer,
|
|
26
|
+
* a CI job) can pin the thread count of a repository that does not.
|
|
27
|
+
*/
|
|
28
|
+
function threadsOf(configured) {
|
|
29
|
+
const fromEnv = process.env.VERSIONCAM_FFMPEG_THREADS;
|
|
30
|
+
if (fromEnv !== undefined && fromEnv !== "") {
|
|
31
|
+
const n = Number(fromEnv);
|
|
32
|
+
if (!Number.isInteger(n) || n < 1) {
|
|
33
|
+
throw new Error(`VERSIONCAM_FFMPEG_THREADS must be a whole number of 1 or more, got "${fromEnv}".`);
|
|
34
|
+
}
|
|
35
|
+
return n;
|
|
36
|
+
}
|
|
37
|
+
if (configured === undefined)
|
|
38
|
+
return null;
|
|
39
|
+
return positiveInt(configured, "output.threads");
|
|
40
|
+
}
|
|
10
41
|
function positiveInt(value, field) {
|
|
11
42
|
if (!Number.isInteger(value) || value <= 0) {
|
|
12
43
|
fail(field, `must be a positive integer, got ${value}`);
|
|
@@ -110,6 +141,7 @@ export function resolveConfig(config, root) {
|
|
|
110
141
|
const outDir = abs(config.outDir ?? ".versioncam");
|
|
111
142
|
const outputWidth = config.output?.width ?? 1920;
|
|
112
143
|
positiveInt(outputWidth, "output.width");
|
|
144
|
+
const encoderThreads = threadsOf(config.output?.threads);
|
|
113
145
|
const baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
114
146
|
if (presentation?.captionInset !== undefined) {
|
|
115
147
|
checkCaptionInset(presentation.captionInset, outputWidth);
|
|
@@ -142,6 +174,7 @@ export function resolveConfig(config, root) {
|
|
|
142
174
|
capture: {
|
|
143
175
|
gate: config.capture?.gate ?? true,
|
|
144
176
|
forceCaptureEvery: forceCaptureEvery,
|
|
177
|
+
transitions: transitionsOf(config.capture?.transitions, "capture.transitions"),
|
|
145
178
|
},
|
|
146
179
|
review: {
|
|
147
180
|
minSeconds: config.review?.minSeconds ?? 9,
|
|
@@ -163,6 +196,7 @@ export function resolveConfig(config, root) {
|
|
|
163
196
|
presentation: presentation ?? null,
|
|
164
197
|
},
|
|
165
198
|
output: outputSize(viewport, outputWidth),
|
|
199
|
+
encoderThreads,
|
|
166
200
|
motion: { ...MOTION, ...config.motion },
|
|
167
201
|
scenes: config.scenes ? abs(config.scenes) : null,
|
|
168
202
|
sequence: config.sequence ?? null,
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/driver/clip.d.ts
CHANGED
|
@@ -21,7 +21,9 @@ export type ClipOptions = {
|
|
|
21
21
|
seed?: number;
|
|
22
22
|
/**
|
|
23
23
|
* Per-clip capture overrides. A clip that films a canvas sets
|
|
24
|
-
* `forceCaptureEvery: 1` here rather than making every other clip pay
|
|
24
|
+
* `forceCaptureEvery: 1` here rather than making every other clip pay, and
|
|
25
|
+
* a clip whose app animates in ways better left out sets
|
|
26
|
+
* `transitions: "zero"`.
|
|
25
27
|
*/
|
|
26
28
|
capture?: CaptureConfig;
|
|
27
29
|
};
|
|
@@ -39,6 +41,12 @@ export type ClipDefinition = {
|
|
|
39
41
|
* every way of recording had to go through a test runner.
|
|
40
42
|
*/
|
|
41
43
|
export declare function clip(id: string, options: ClipOptions, body: ClipBody): ClipDefinition;
|
|
44
|
+
/**
|
|
45
|
+
* This package's version, for the recording's provenance: which versioncam
|
|
46
|
+
* made it, read by whoever shows the recording rather than guessed from the
|
|
47
|
+
* latest release.
|
|
48
|
+
*/
|
|
49
|
+
export declare const RECORDER_VERSION: string;
|
|
42
50
|
export type RunClipResult = {
|
|
43
51
|
timeline: Timeline;
|
|
44
52
|
dir: string;
|
package/dist/driver/clip.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { isTransitions } from "../config.js";
|
|
5
|
+
import { MUTATION_COUNTER_SCRIPT, TRANSITION_CLOCK_SCRIPT, freezeCssScript, } from "./page-hooks.js";
|
|
6
|
+
import { writeFailure, writeSettles, writeTargets } from "./reports.js";
|
|
6
7
|
import { RecordingSession } from "./session.js";
|
|
7
8
|
/**
|
|
8
9
|
* Declare a clip.
|
|
@@ -19,7 +20,7 @@ export function clip(id, options, body) {
|
|
|
19
20
|
* made it, read by whoever shows the recording rather than guessed from the
|
|
20
21
|
* latest release.
|
|
21
22
|
*/
|
|
22
|
-
const RECORDER_VERSION = createRequire(import.meta.url)("../../package.json").version;
|
|
23
|
+
export const RECORDER_VERSION = createRequire(import.meta.url)("../../package.json").version;
|
|
23
24
|
/** The app's commit, for the recording's provenance. Best effort. */
|
|
24
25
|
function appCommit(cwd) {
|
|
25
26
|
try {
|
|
@@ -54,8 +55,16 @@ export async function runClip(browser, config, definition, runOptions = {}) {
|
|
|
54
55
|
storageState: config.auth?.storageState,
|
|
55
56
|
});
|
|
56
57
|
const page = await context.newPage();
|
|
58
|
+
// A clip's own `capture` is merged over the config's unchecked, so its
|
|
59
|
+
// switch is checked here, where a typo would otherwise play by default.
|
|
60
|
+
const transitions = capture.transitions;
|
|
61
|
+
if (!isTransitions(transitions)) {
|
|
62
|
+
throw new Error(`Clip "${id}": \`capture.transitions\` must be "play" or "zero", got ${JSON.stringify(transitions)}.`);
|
|
63
|
+
}
|
|
57
64
|
await page.addInitScript(MUTATION_COUNTER_SCRIPT);
|
|
58
|
-
await page.addInitScript(
|
|
65
|
+
await page.addInitScript(freezeCssScript(transitions));
|
|
66
|
+
if (transitions === "play")
|
|
67
|
+
await page.addInitScript(TRANSITION_CLOCK_SCRIPT);
|
|
59
68
|
// Paused, not just installed. `clock.install()` leaves Playwright's fake
|
|
60
69
|
// clock running on real time between the driver's own `runFor` calls, so
|
|
61
70
|
// every screenshot, every probe and every stall of the machine reached the
|
|
@@ -103,6 +112,7 @@ export async function runClip(browser, config, definition, runOptions = {}) {
|
|
|
103
112
|
}
|
|
104
113
|
const timeline = session.finish();
|
|
105
114
|
writeSettles(dir, session.settles);
|
|
115
|
+
writeTargets(dir, session.evidence().targets);
|
|
106
116
|
return { timeline, dir, cost: session.cost, settles: session.settles };
|
|
107
117
|
}
|
|
108
118
|
catch (error) {
|
|
@@ -112,13 +122,15 @@ export async function runClip(browser, config, definition, runOptions = {}) {
|
|
|
112
122
|
//
|
|
113
123
|
// Nothing in this block may throw, or it would replace the failure it
|
|
114
124
|
// exists to report — a disk error standing in for the locator that broke.
|
|
125
|
+
const evidence = session.evidence();
|
|
115
126
|
try {
|
|
116
127
|
writeSettles(dir, session.settles);
|
|
128
|
+
writeTargets(dir, evidence.targets);
|
|
117
129
|
}
|
|
118
130
|
catch {
|
|
119
131
|
// Said by the error on its way up, which is the more useful of the two.
|
|
120
132
|
}
|
|
121
|
-
await writeFailure(page, dir, { message: error.message, ...session.at }, { draft });
|
|
133
|
+
await writeFailure(page, dir, { message: error.message, ...session.at, step: evidence.step }, { draft });
|
|
122
134
|
throw error;
|
|
123
135
|
}
|
|
124
136
|
finally {
|
package/dist/driver/clip.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clip.js","sourceRoot":"","sources":["../../src/driver/clip.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"clip.js","sourceRoot":"","sources":["../../src/driver/clip.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,12 +4,54 @@
|
|
|
4
4
|
* These run at document start, before any app code, and must be
|
|
5
5
|
* self-contained strings — they are evaluated in the page, not here.
|
|
6
6
|
*/
|
|
7
|
+
import type { Transitions } from "../config.js";
|
|
7
8
|
/**
|
|
8
9
|
* Counts DOM mutations so `settle()` can tell "the page is still working"
|
|
9
10
|
* from "the page has finished". Counting is far cheaper than diffing and
|
|
10
11
|
* needs no cooperation from the app.
|
|
11
12
|
*/
|
|
12
|
-
export declare const MUTATION_COUNTER_SCRIPT = "(() => {\n const state = {\n mutations: 0,\n ids: new WeakMap(),\n nextId: 1,\n idOf(el) {\n if (!el) return 0;\n let id = state.ids.get(el);\n if (!id) { id = state.nextId++; state.ids.set(el, id); }\n return id;\n },\n probe(t, x, y) {\n document.documentElement.style.setProperty(\"--recorder-t\", t);\n return {\n mutations: state.mutations,\n hovered: state.idOf(document.elementFromPoint(x, y)),\n animations: document.getAnimations().length,\n };\n },\n };\n window.__recorder = state;\n\n // The driver writes --recorder-t to <html style> on every single frame. Left\n // alone that write is a mutation like any other, so the counter would move\n // every frame and anything built on it \u2014 a settle that waits for quiet, a\n // gate that skips an unchanged frame \u2014 would be reading its own footprint.\n // Anything else that touches <html style>, a scroll lock or a theme switch,\n // still counts.\n const withoutScrub = (value) =>\n (value || \"\").replace(/--recorder-t\\s*:[^;]*;?/g, \"\").trim();\n\n const start = () => {\n const root = document.documentElement;\n const isOurScrub = (record) =>\n record.type === \"attributes\" &&\n record.target === root &&\n record.attributeName === \"style\" &&\n withoutScrub(record.oldValue) === withoutScrub(root.getAttribute(\"style\"));\n\n new MutationObserver((records) => {\n for (const record of records) {\n if (!isOurScrub(record)) state.mutations += 1;\n }\n }).observe(root || document, {\n childList: true,\n attributes: true,\n attributeOldValue: true,\n characterData: true,\n subtree: true,\n });\n };\n if (document.documentElement) start();\n else document.addEventListener(\"DOMContentLoaded\", start, { once: true });\n})();";
|
|
13
|
+
export declare const MUTATION_COUNTER_SCRIPT = "(() => {\n const state = {\n mutations: 0,\n ids: new WeakMap(),\n nextId: 1,\n idOf(el) {\n if (!el) return 0;\n let id = state.ids.get(el);\n if (!id) { id = state.nextId++; state.ids.set(el, id); }\n return id;\n },\n probe(t, x, y) {\n document.documentElement.style.setProperty(\"--recorder-t\", t);\n // Before the counts: a transition whose time is up is finished here,\n // and is no longer running when the animations are counted.\n const clock = window.__recorderTransitions;\n const transitions = clock ? clock.sync() : 0;\n return {\n mutations: state.mutations,\n hovered: state.idOf(document.elementFromPoint(x, y)),\n animations: document.getAnimations().length,\n transitions,\n };\n },\n };\n window.__recorder = state;\n\n // The driver writes --recorder-t to <html style> on every single frame. Left\n // alone that write is a mutation like any other, so the counter would move\n // every frame and anything built on it \u2014 a settle that waits for quiet, a\n // gate that skips an unchanged frame \u2014 would be reading its own footprint.\n // Anything else that touches <html style>, a scroll lock or a theme switch,\n // still counts.\n const withoutScrub = (value) =>\n (value || \"\").replace(/--recorder-t\\s*:[^;]*;?/g, \"\").trim();\n\n const start = () => {\n const root = document.documentElement;\n const isOurScrub = (record) =>\n record.type === \"attributes\" &&\n record.target === root &&\n record.attributeName === \"style\" &&\n withoutScrub(record.oldValue) === withoutScrub(root.getAttribute(\"style\"));\n\n new MutationObserver((records) => {\n for (const record of records) {\n if (!isOurScrub(record)) state.mutations += 1;\n }\n }).observe(root || document, {\n childList: true,\n attributes: true,\n attributeOldValue: true,\n characterData: true,\n subtree: true,\n });\n };\n if (document.documentElement) start();\n else document.addEventListener(\"DOMContentLoaded\", start, { once: true });\n})();";
|
|
14
|
+
/**
|
|
15
|
+
* Plays the page's CSS transitions on the page's own clock.
|
|
16
|
+
*
|
|
17
|
+
* A transition's timing is fixed when it starts, at the style change, and it
|
|
18
|
+
* runs on the compositor's clock, which the fake clock does not touch. So
|
|
19
|
+
* the trick that scrubs animations, a delay read from a custom property
|
|
20
|
+
* every frame, cannot move one. The Web Animations API can: every running
|
|
21
|
+
* transition is a `CSSTransition` in `document.getAnimations()`, with a
|
|
22
|
+
* writable `currentTime`.
|
|
23
|
+
*
|
|
24
|
+
* `sync()` takes over each transition the first time it sees one: pauses it,
|
|
25
|
+
* and keeps the page's clock at that moment as its start. Then, every time
|
|
26
|
+
* it runs, it sets the transition to the page's time since that start, and
|
|
27
|
+
* once its effect's end is reached, finishes it, so `transitionend` fires and
|
|
28
|
+
* whatever waits for it runs (Leaflet ending a zoom, a dialog unmounting).
|
|
29
|
+
* It answers how many are still running.
|
|
30
|
+
*
|
|
31
|
+
* The start is the first sight, not the style change itself, which nothing
|
|
32
|
+
* sees: the driver syncs after every move of the clock, so a transition
|
|
33
|
+
* starts on the frame after the change that caused it, at most a frame late,
|
|
34
|
+
* and the same frame every run. Until then it runs a few milliseconds on the
|
|
35
|
+
* compositor in real time; setting it corrects that, and nothing is
|
|
36
|
+
* photographed in between, since the driver photographs a frame only after
|
|
37
|
+
* the probe that syncs it.
|
|
38
|
+
*
|
|
39
|
+
* The page's clock is the one the app's timers run on, not the clip's
|
|
40
|
+
* authored time, so a transition and a timer the app set beside it stay
|
|
41
|
+
* together: Leaflet ends a 250 ms zoom on a 250 ms timer.
|
|
42
|
+
*
|
|
43
|
+
* Only the top frame: the driver's probe runs there, and nothing would move
|
|
44
|
+
* a subframe's transitions, so the freeze stylesheet keeps those zeroed.
|
|
45
|
+
* CSS animations are left to their scrub, and animations a script made with
|
|
46
|
+
* `element.animate()` are the app's own.
|
|
47
|
+
*/
|
|
48
|
+
export declare const TRANSITION_CLOCK_SCRIPT = "(() => {\n if (window !== window.top) return;\n const started = new WeakMap();\n window.__recorderTransitions = {\n sync() {\n const now = performance.now();\n let running = 0;\n for (const animation of document.getAnimations()) {\n if (!(\"transitionProperty\" in animation)) continue;\n let start = started.get(animation);\n if (start === undefined) {\n start = now;\n started.set(animation, start);\n }\n const end = animation.effect\n ? animation.effect.getComputedTiming().endTime\n : 0;\n if (now - start >= end) {\n animation.finish();\n continue;\n }\n animation.pause();\n animation.currentTime = now - start;\n running += 1;\n }\n return running;\n },\n };\n})();";
|
|
49
|
+
/**
|
|
50
|
+
* Moves every running transition to the page's clock, for the driver's waits
|
|
51
|
+
* that move the clock without making a frame. The frame probe and the settle
|
|
52
|
+
* loop sync as part of what they already ask the page.
|
|
53
|
+
*/
|
|
54
|
+
export declare const SYNC_TRANSITIONS = "window.__recorderTransitions ? window.__recorderTransitions.sync() : 0";
|
|
13
55
|
/**
|
|
14
56
|
* Puts the page's CSS motion under the recorder's control.
|
|
15
57
|
*
|
|
@@ -19,8 +61,13 @@ export declare const MUTATION_COUNTER_SCRIPT = "(() => {\n const state = {\n
|
|
|
19
61
|
* depends on how busy the machine was — the exact non-determinism this
|
|
20
62
|
* recorder exists to remove.
|
|
21
63
|
*
|
|
22
|
-
* Transitions
|
|
23
|
-
*
|
|
64
|
+
* Transitions play by default, on the page's clock, through
|
|
65
|
+
* `TRANSITION_CLOCK_SCRIPT`: a map that zooms with a transition is the
|
|
66
|
+
* content of the clip, and a jump in its place reads as a broken video. With
|
|
67
|
+
* `capture.transitions: "zero"` they are zeroed instead, as they always were
|
|
68
|
+
* before: a state change lands in the frame after the one that caused it,
|
|
69
|
+
* and the renderer's crossfade at a settle is all the motion there is. A
|
|
70
|
+
* subframe's are always zeroed, since its clock is never synced.
|
|
24
71
|
*
|
|
25
72
|
* Animations are handled differently, because zeroing them is wrong. A
|
|
26
73
|
* loading spinner with `animation-duration: 0s` is a dead spinner, and a clip
|
|
@@ -34,14 +81,14 @@ export declare const MUTATION_COUNTER_SCRIPT = "(() => {\n const state = {\n
|
|
|
34
81
|
* `scroll-behavior: auto` is here for the same reason: a smooth-scrolling
|
|
35
82
|
* container animates outside our control.
|
|
36
83
|
*/
|
|
37
|
-
export declare
|
|
38
|
-
export declare
|
|
84
|
+
export declare function freezeCss(zeroTransitions: boolean): string;
|
|
85
|
+
export declare function freezeCssScript(transitions: Transitions): string;
|
|
39
86
|
/**
|
|
40
87
|
* What the driver learns from the page once per frame.
|
|
41
88
|
*
|
|
42
|
-
* One round trip does
|
|
43
|
-
* this frame's authored time
|
|
44
|
-
* this frame needs a screenshot.
|
|
89
|
+
* One round trip does four jobs: it advances the page's CSS animations to
|
|
90
|
+
* this frame's authored time and its transitions to the page's clock, and
|
|
91
|
+
* reports the two things that decide whether this frame needs a screenshot.
|
|
45
92
|
*
|
|
46
93
|
* `hovered` is the identity of the element under the cursor, as a number. The
|
|
47
94
|
* cursor glyph is drawn in post, so the pointer moving changes no pixel by
|
|
@@ -50,10 +97,11 @@ export declare const FREEZE_CSS_SCRIPT: string;
|
|
|
50
97
|
* it returns the same element as last frame, the `:hover` chain is the same
|
|
51
98
|
* chain and no hover styling can have changed.
|
|
52
99
|
*
|
|
53
|
-
* `animations` is how many animations are running. A
|
|
54
|
-
* repaints on every frame without touching the DOM, so
|
|
55
|
-
*
|
|
56
|
-
* may be
|
|
100
|
+
* `animations` is how many animations are running, transitions included. A
|
|
101
|
+
* scrubbed animation repaints on every frame without touching the DOM, and so
|
|
102
|
+
* does a transition on the clock, so while any is on screen — a spinner, a
|
|
103
|
+
* progress bar, a zoom — every frame is genuinely different and none may be
|
|
104
|
+
* skipped. `transitions` is how many of them are transitions still to finish.
|
|
57
105
|
*/
|
|
58
106
|
export declare const FRAME_PROBE: (seconds: number, x: number, y: number) => string;
|
|
59
107
|
export type FrameProbe = {
|
|
@@ -61,6 +109,8 @@ export type FrameProbe = {
|
|
|
61
109
|
/** Identity of the element under the cursor; 0 when there is none. */
|
|
62
110
|
hovered: number;
|
|
63
111
|
animations: number;
|
|
112
|
+
/** Transitions on the page's clock that have not finished; 0 when zeroed. */
|
|
113
|
+
transitions: number;
|
|
64
114
|
};
|
|
65
115
|
declare global {
|
|
66
116
|
interface Window {
|
|
@@ -68,5 +118,8 @@ declare global {
|
|
|
68
118
|
mutations: number;
|
|
69
119
|
probe(t: string, x: number, y: number): FrameProbe;
|
|
70
120
|
};
|
|
121
|
+
__recorderTransitions?: {
|
|
122
|
+
sync(): number;
|
|
123
|
+
};
|
|
71
124
|
}
|
|
72
125
|
}
|