@flighthq/tool-capture 0.2.1-next.444.a313478 → 0.2.1-next.448.afbdd31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +87 -0
  2. package/dist/baselineStore.d.ts.map +1 -1
  3. package/dist/baselineStore.js +7 -21
  4. package/dist/baselineStore.js.map +1 -1
  5. package/dist/bin.js +187 -27
  6. package/dist/bin.js.map +1 -1
  7. package/dist/captureBrowser.d.ts.map +1 -1
  8. package/dist/captureBrowser.js +8 -0
  9. package/dist/captureBrowser.js.map +1 -1
  10. package/dist/captureEntries.d.ts +1 -0
  11. package/dist/captureEntries.d.ts.map +1 -1
  12. package/dist/captureEntries.js +1 -1
  13. package/dist/captureEntries.js.map +1 -1
  14. package/dist/captureEntry.d.ts +4 -4
  15. package/dist/captureEntry.d.ts.map +1 -1
  16. package/dist/captureEntry.js +22 -8
  17. package/dist/captureEntry.js.map +1 -1
  18. package/dist/captureFormat.js +1 -1
  19. package/dist/captureFormat.js.map +1 -1
  20. package/dist/captureManifest.d.ts +12 -0
  21. package/dist/captureManifest.d.ts.map +1 -0
  22. package/dist/captureManifest.js +44 -0
  23. package/dist/captureManifest.js.map +1 -0
  24. package/dist/captureRenderTarget.d.ts +1 -2
  25. package/dist/captureRenderTarget.d.ts.map +1 -1
  26. package/dist/captureRenderTarget.js.map +1 -1
  27. package/dist/captureServer.d.ts +3 -1
  28. package/dist/captureServer.d.ts.map +1 -1
  29. package/dist/captureServer.js +11 -2
  30. package/dist/captureServer.js.map +1 -1
  31. package/dist/captureSuite.d.ts +32 -0
  32. package/dist/captureSuite.d.ts.map +1 -0
  33. package/dist/captureSuite.js +103 -0
  34. package/dist/captureSuite.js.map +1 -0
  35. package/dist/captureValidation.d.ts +35 -0
  36. package/dist/captureValidation.d.ts.map +1 -0
  37. package/dist/captureValidation.js +363 -0
  38. package/dist/captureValidation.js.map +1 -0
  39. package/dist/index.d.ts +3 -0
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +3 -0
  42. package/dist/index.js.map +1 -1
  43. package/dist/referenceCapture.d.ts.map +1 -1
  44. package/dist/referenceCapture.js +6 -7
  45. package/dist/referenceCapture.js.map +1 -1
  46. package/package.json +6 -5
  47. package/src/captureEntries.test.ts +7 -0
  48. package/src/captureManifest.test.ts +59 -0
  49. package/src/captureServer.test.ts +19 -1
  50. package/src/captureSuite.test.ts +11 -0
  51. package/src/captureValidation.test.ts +9 -0
package/README.md ADDED
@@ -0,0 +1,87 @@
1
+ # `@flighthq/tool-capture`
2
+
3
+ Deterministic browser capture and reporting for canvas, DOM, WebGL, and WebGPU pages.
4
+
5
+ ## Capture a suite
6
+
7
+ Add a `tool-capture.json` manifest to a package:
8
+
9
+ ```json
10
+ {
11
+ "subject": "my-app",
12
+ "entries": [
13
+ {
14
+ "name": "home",
15
+ "renderers": ["canvas", "webgl"],
16
+ "routes": {
17
+ "canvas": "pages/home/canvas/",
18
+ "webgl": "pages/home/webgl/"
19
+ }
20
+ }
21
+ ]
22
+ }
23
+ ```
24
+
25
+ Then capture either an existing server or an already-built directory:
26
+
27
+ ```sh
28
+ tool-capture capture --url http://localhost:5173
29
+ tool-capture capture --dir dist
30
+ ```
31
+
32
+ Each target writes `screenshot.png`, `logs.jsonl`, and `status.json` beneath `.artifacts/<subject>/<entry>/<renderer>/`. Common reporting controls are built in:
33
+
34
+ ```sh
35
+ tool-capture capture --dir dist --frames 1 --fail-on-error
36
+ tool-capture capture --dir dist --update-baseline
37
+ tool-capture capture --dir dist --fail-on-changed
38
+ tool-capture capture --dir dist --renderer webgl,webgpu --parallel 4
39
+ ```
40
+
41
+ Use `runCaptureSuite` when entries or server lifecycle are generated programmatically. It owns browser setup and teardown, deterministic frame synchronization, parallel or sequential scheduling, baseline policy, interruption, summaries, and the final verdict.
42
+
43
+ ## Validate fingerprints
44
+
45
+ The same manifest and server options drive the tolerant parity/regression pass when pages publish a render fingerprint:
46
+
47
+ ```js
48
+ window.__ftVerification = {
49
+ render: 'webgl',
50
+ coverage: 1,
51
+ fingerprint: '1:25acc0',
52
+ };
53
+ ```
54
+
55
+ Fingerprints use the `<grid-size>:<rgb-hex>` format produced by `formatSurfaceFingerprint`. Once the page exposes a non-null fingerprint, validation is turn-key:
56
+
57
+ ```sh
58
+ tool-capture validate --dir dist --no-regression
59
+ tool-capture validate --dir dist --no-parity
60
+ tool-capture validate --dir dist --update-fingerprints
61
+ ```
62
+
63
+ Optional manifest policy keeps intentional exceptions beside the suite:
64
+
65
+ ```json
66
+ {
67
+ "subject": "my-app",
68
+ "entries": [],
69
+ "validation": {
70
+ "fingerprintSkip": ["audio-only"],
71
+ "paritySkip": {
72
+ "video": "all",
73
+ "approximate-effect": ["canvas"]
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ `runCaptureValidation` exposes the same validation lifecycle programmatically. Comparison tolerances and baseline formats come from `@flighthq/capture`; `tool-capture` owns browser execution and reporting.
80
+
81
+ ## Observe one page
82
+
83
+ `observe` is the zero-integration eyes primitive. It always emits the best available screenshot and diagnostics rather than enforcing a suite gate:
84
+
85
+ ```sh
86
+ tool-capture observe http://localhost:5173/example --out capture
87
+ ```
@@ -1 +1 @@
1
- {"version":3,"file":"baselineStore.d.ts","sourceRoot":"","sources":["../src/baselineStore.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,QAAQ,CAAC;AAWrD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGhF;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,aAAa,GACnB,MAAM,GAAG,IAAI,CAEf;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,MAAM,GACZ,IAAI,CAKN"}
1
+ {"version":3,"file":"baselineStore.d.ts","sourceRoot":"","sources":["../src/baselineStore.ts"],"names":[],"mappings":"AAkBA,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,QAAQ,CAAC;AASrD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGhF;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,aAAa,GACnB,MAAM,GAAG,IAAI,CAEf;AAED,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,MAAM,GACZ,IAAI,CAKN"}
@@ -1,11 +1,12 @@
1
1
  // Per-test committed baseline store: one JSON file per test at <subject-root>/baselines/<name>.json,
2
2
  // holding every column's values, e.g. { "canvas": { "fingerprint": "…", "sha256": "…" }, "flight:webgl": {…} }.
3
- // captureEntry writes each column's `sha256` (screenshot hash); compare-render writes its `fingerprint`
3
+ // captureEntry writes each column's `sha256` (screenshot hash); captureValidation writes its `fingerprint`
4
4
  // (coarse render fingerprint). Both read-merge-write so they preserve each other's fields and the other
5
5
  // columns. Output is prettier-compatible (sorted keys, 2-space, trailing newline) so it never churns the
6
6
  // format gate. Replaces the old tools/baselines/<subject>/<name>/<renderer>/{fingerprint.txt,baseline.sha256}.
7
7
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
8
8
  import { dirname, join } from 'node:path';
9
+ import { createCaptureBaseline, formatCaptureBaseline, getCaptureBaselineField, parseCaptureBaseline, setCaptureBaselineField, } from '@flighthq/capture';
9
10
  // Per-subject baseline root: baselines colocate with their suite (functional/examples are
10
11
  // top-level). One JSON file per test under the root's baselines/ dir.
11
12
  const BASELINE_ROOTS = {
@@ -17,38 +18,23 @@ export function baselinePath(root, subject, name) {
17
18
  return join(root, base, 'baselines', `${name}.json`);
18
19
  }
19
20
  export function getBaselineField(root, subject, name, column, field) {
20
- return readBaseline(baselinePath(root, subject, name))[column]?.[field] ?? null;
21
+ return getCaptureBaselineField(readBaseline(baselinePath(root, subject, name)), column, field);
21
22
  }
22
23
  export function setBaselineField(root, subject, name, column, field, value) {
23
24
  const path = baselinePath(root, subject, name);
24
25
  const data = readBaseline(path);
25
- (data[column] ??= {})[field] = value;
26
+ setCaptureBaselineField(data, column, field, value);
26
27
  writeBaseline(path, data);
27
28
  }
28
29
  function readBaseline(path) {
29
30
  if (!existsSync(path))
30
- return {};
31
- try {
32
- return JSON.parse(readFileSync(path, 'utf8'));
33
- }
34
- catch {
35
- return {};
36
- }
31
+ return createCaptureBaseline();
32
+ return parseCaptureBaseline(readFileSync(path, 'utf8')) ?? createCaptureBaseline();
37
33
  }
38
34
  // Stable, prettier-compatible serialisation: columns and fields in sorted order so a re-baseline of one
39
35
  // column produces a minimal diff and the format gate stays green.
40
36
  function writeBaseline(path, data) {
41
37
  mkdirSync(dirname(path), { recursive: true });
42
- const sorted = {};
43
- for (const column of Object.keys(data).sort()) {
44
- const entry = data[column];
45
- const out = {};
46
- if (entry.fingerprint !== undefined)
47
- out.fingerprint = entry.fingerprint;
48
- if (entry.sha256 !== undefined)
49
- out.sha256 = entry.sha256;
50
- sorted[column] = out;
51
- }
52
- writeFileSync(path, JSON.stringify(sorted, null, 2) + '\n');
38
+ writeFileSync(path, formatCaptureBaseline(data));
53
39
  }
54
40
  //# sourceMappingURL=baselineStore.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"baselineStore.js","sourceRoot":"","sources":["../src/baselineStore.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,gHAAgH;AAChH,wGAAwG;AACxG,wGAAwG;AACxG,yGAAyG;AACzG,+GAA+G;AAC/G,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAM1C,0FAA0F;AAC1F,sEAAsE;AACtE,MAAM,cAAc,GAA2B;IAC7C,UAAU,EAAE,YAAY;IACxB,QAAQ,EAAE,UAAU;CACrB,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,OAAe,EAAE,IAAY;IACtE,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC;IAChD,OAAO,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,IAAY,EACZ,OAAe,EACf,IAAY,EACZ,MAAc,EACd,KAAoB;IAEpB,OAAO,YAAY,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC;AAClF,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,IAAY,EACZ,OAAe,EACf,IAAY,EACZ,MAAc,EACd,KAAoB,EACpB,KAAa;IAEb,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC;IACrC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAiB,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,wGAAwG;AACxG,kEAAkE;AAClE,SAAS,aAAa,CAAC,IAAY,EAAE,IAAkB;IACrD,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3B,MAAM,GAAG,GAAmB,EAAE,CAAC;QAC/B,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS;YAAE,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;QACzE,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS;YAAE,GAAG,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC1D,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC;IACvB,CAAC;IACD,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AAC9D,CAAC"}
1
+ {"version":3,"file":"baselineStore.js","sourceRoot":"","sources":["../src/baselineStore.ts"],"names":[],"mappings":"AAAA,qGAAqG;AACrG,gHAAgH;AAChH,2GAA2G;AAC3G,wGAAwG;AACxG,yGAAyG;AACzG,+GAA+G;AAC/G,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EACL,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAK3B,0FAA0F;AAC1F,sEAAsE;AACtE,MAAM,cAAc,GAA2B;IAC7C,UAAU,EAAE,YAAY;IACxB,QAAQ,EAAE,UAAU;CACrB,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,OAAe,EAAE,IAAY;IACtE,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,IAAI,OAAO,CAAC;IAChD,OAAO,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,IAAY,EACZ,OAAe,EACf,IAAY,EACZ,MAAc,EACd,KAAoB;IAEpB,OAAO,uBAAuB,CAAC,YAAY,CAAC,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;AACjG,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,IAAY,EACZ,OAAe,EACf,IAAY,EACZ,MAAc,EACd,KAAoB,EACpB,KAAa;IAEb,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAChC,uBAAuB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACpD,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,YAAY,CAAC,IAAY;IAChC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,qBAAqB,EAAE,CAAC;IACtD,OAAO,oBAAoB,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,qBAAqB,EAAE,CAAC;AACrF,CAAC;AAED,wGAAwG;AACxG,kEAAkE;AAClE,SAAS,aAAa,CAAC,IAAY,EAAE,IAA+B;IAClE,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,aAAa,CAAC,IAAI,EAAE,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC;AACnD,CAAC"}
package/dist/bin.js CHANGED
@@ -1,38 +1,198 @@
1
1
  #!/usr/bin/env node
2
- // The tool-capture CLI. First (and currently only) command: `observe <url>` — the standalone eyes
3
- // primitive. Point it at any running page and it drives a deterministic headless render, grabs the
4
- // present frame (via the getContext intercept — zero page integration), and writes screenshot.png +
5
- // logs.jsonl + status.json (with the observe diagnostics block). No capture script or discovery needed
6
- // in the consumer; a repo just adds `"capture:observe": "tool-capture observe"` and points it at a URL.
2
+ // Turn-key capture CLI:
3
+ // - observe <url>: one arbitrary page, zero integration, always emit eyes + diagnostics.
4
+ // - capture: a full entry × renderer report from a JSON manifest or Flight's built-in suites.
5
+ import { existsSync } from 'node:fs';
7
6
  import { resolve } from 'node:path';
7
+ import { discoverEntries } from './captureEntries.js';
8
8
  import { captureUrl } from './captureEntry.js';
9
- const USAGE = 'usage: tool-capture observe <url> [--out <dir>] [--wait <ms>] [--frames <n>]';
9
+ import { isBrowserClosedError } from './captureInterrupt.js';
10
+ import { readCaptureManifest } from './captureManifest.js';
11
+ import { resolveCaptureDirectoryServer, resolveServer, resolveStaticServer } from './captureServer.js';
12
+ import { runCaptureSuite } from './captureSuite.js';
13
+ import { runCaptureValidation } from './captureValidation.js';
14
+ const USAGE = `usage:
15
+ tool-capture observe <url> [--out <dir>] [--wait <ms>] [--frames <n>]
16
+ tool-capture capture [--manifest <file>] (--url <url> | --dir <built-dir>) [options]
17
+ tool-capture capture --tool <examples|functional> [options]
18
+ tool-capture validate [--manifest <file>] (--url <url> | --dir <built-dir>) [options]
19
+ tool-capture validate --tool <examples|functional> [options]
20
+
21
+ capture options:
22
+ --filter <name> --renderer <ids> --out <dir> --wait <ms> --frames <n>
23
+ --parallel <n> --sequential --dev --build --update-baseline --fail-on-changed
24
+ --fail-on-error --verify --no-verify --observe
25
+
26
+ validation options:
27
+ --report --update-fingerprints --no-regression --no-parity
28
+ --stability-epsilon <n> --regression-tolerance <n> --parity-tolerance <n>
29
+
30
+ Manifest: { "subject": "app", "entries": [{ "name": "home", "renderers": ["webgl"],
31
+ "routes": { "webgl": "pages/home/" } }] }`;
10
32
  function flag(argv, key) {
11
- const i = argv.indexOf(`--${key}`);
12
- return i >= 0 && argv[i + 1] !== undefined ? argv[i + 1] : undefined;
33
+ const equals = argv.find((arg) => arg.startsWith(`--${key}=`));
34
+ if (equals !== undefined)
35
+ return equals.slice(key.length + 3);
36
+ const index = argv.indexOf(`--${key}`);
37
+ return index >= 0 && argv[index + 1] !== undefined ? argv[index + 1] : undefined;
38
+ }
39
+ function hasFlag(argv, key) {
40
+ return argv.includes(`--${key}`);
41
+ }
42
+ async function resolveCaptureCliSuite(argv) {
43
+ const root = resolve(flag(argv, 'root') ?? process.cwd());
44
+ const manifestPath = flag(argv, 'manifest');
45
+ const toolName = flag(argv, 'tool');
46
+ let manifest = null;
47
+ let subject;
48
+ let entries;
49
+ if (manifestPath !== undefined) {
50
+ manifest = readCaptureManifest(resolve(root, manifestPath));
51
+ subject = flag(argv, 'subject') ?? manifest.subject;
52
+ entries = manifest.entries;
53
+ }
54
+ else if (toolName === 'examples' || toolName === 'functional') {
55
+ subject = flag(argv, 'subject') ?? toolName;
56
+ entries = discoverEntries(toolName, root);
57
+ }
58
+ else {
59
+ const conventionalManifest = resolve(root, 'tool-capture.json');
60
+ if (!existsSync(conventionalManifest))
61
+ throw new Error(`capture/validate requires --manifest or --tool\n${USAGE}`);
62
+ manifest = readCaptureManifest(conventionalManifest);
63
+ subject = flag(argv, 'subject') ?? manifest.subject;
64
+ entries = manifest.entries;
65
+ }
66
+ const externalUrl = flag(argv, 'url');
67
+ const directory = flag(argv, 'dir');
68
+ let server;
69
+ if (externalUrl !== undefined) {
70
+ console.log(`Using server at ${externalUrl}\n`);
71
+ server = await resolveServer({ root, externalUrl });
72
+ }
73
+ else if (directory !== undefined) {
74
+ console.log(`Serving ${resolve(root, directory)}…`);
75
+ server = await resolveCaptureDirectoryServer(resolve(root, directory));
76
+ console.log(`Ready at ${server.url}\n`);
77
+ }
78
+ else if (toolName === 'examples' || toolName === 'functional') {
79
+ if (hasFlag(argv, 'dev'))
80
+ console.log(`Starting ${toolName} dev server…`);
81
+ else if (hasFlag(argv, 'build'))
82
+ console.log(`Building and serving ${toolName} dist…`);
83
+ else
84
+ console.log(`Serving ${toolName} dist (use --build to rebuild, --dev for Vite)…`);
85
+ server = hasFlag(argv, 'dev')
86
+ ? await resolveServer({ tool: toolName, root })
87
+ : await resolveStaticServer({ tool: toolName, root, forceBuild: hasFlag(argv, 'build') });
88
+ console.log(`Ready at ${server.url}\n`);
89
+ }
90
+ else {
91
+ throw new Error(`capture/validate requires --url or --dir for manifest suites\n${USAGE}`);
92
+ }
93
+ return { entries, manifest, root, server, subject };
94
+ }
95
+ async function capture(argv) {
96
+ const { subject, entries, server, root } = await resolveCaptureCliSuite(argv);
97
+ const frames = flag(argv, 'frames');
98
+ const parallel = flag(argv, 'parallel');
99
+ const result = await runCaptureSuite({
100
+ subject,
101
+ entries,
102
+ server,
103
+ root,
104
+ outBase: flag(argv, 'out') ?? '.artifacts',
105
+ filter: flag(argv, 'filter'),
106
+ rendererFilter: (flag(argv, 'renderer') ?? '').split(',').filter(Boolean),
107
+ extraWait: parseNonNegativeInteger(flag(argv, 'wait'), 0),
108
+ captureFrames: parseNonNegativeInteger(frames?.split(',')[0], 0),
109
+ workerCount: Math.max(1, parseNonNegativeInteger(parallel, 6)),
110
+ sequential: hasFlag(argv, 'sequential'),
111
+ updateBaseline: hasFlag(argv, 'update-baseline'),
112
+ failOnChanged: hasFlag(argv, 'fail-on-changed'),
113
+ failOnError: hasFlag(argv, 'fail-on-error'),
114
+ observe: hasFlag(argv, 'observe'),
115
+ verify: hasFlag(argv, 'verify') ? true : hasFlag(argv, 'no-verify') ? false : undefined,
116
+ });
117
+ if (result.aborted)
118
+ return 130;
119
+ return result.shouldFail ? 1 : 0;
120
+ }
121
+ async function validate(argv) {
122
+ const { subject, entries, server, root, manifest } = await resolveCaptureCliSuite(argv);
123
+ const result = await runCaptureValidation({
124
+ subject,
125
+ entries,
126
+ server,
127
+ root,
128
+ filter: flag(argv, 'filter'),
129
+ rendererFilter: (flag(argv, 'renderer') ?? '').split(',').filter(Boolean),
130
+ captureFrames: Math.max(1, parseNonNegativeInteger(flag(argv, 'frames'), 1)),
131
+ report: hasFlag(argv, 'report'),
132
+ updateFingerprints: hasFlag(argv, 'update-fingerprints'),
133
+ gateRegression: !hasFlag(argv, 'no-regression'),
134
+ gateParity: !hasFlag(argv, 'no-parity'),
135
+ stabilityEpsilon: parseNumber(flag(argv, 'stability-epsilon')),
136
+ regressionTolerance: parseNumber(flag(argv, 'regression-tolerance')),
137
+ parityTolerance: parseNumber(flag(argv, 'parity-tolerance')),
138
+ sequential: hasFlag(argv, 'sequential'),
139
+ workerCount: Math.max(1, parseNonNegativeInteger(flag(argv, 'parallel'), 6)),
140
+ fingerprintSkip: manifest?.validation?.fingerprintSkip ?? (manifest === null && subject === 'examples' ? ['playingsound'] : []),
141
+ paritySkip: manifest?.validation?.paritySkip ?? (manifest === null ? FLIGHT_PARITY_SKIP : {}),
142
+ });
143
+ if (result.aborted)
144
+ return 130;
145
+ return result.shouldFail ? 1 : 0;
13
146
  }
14
147
  async function main() {
15
- const argv = process.argv.slice(2);
16
- if (argv[0] !== 'observe') {
17
- console.error(USAGE);
18
- process.exit(2);
19
- }
20
- const url = argv[1];
21
- if (url === undefined || url.startsWith('--')) {
22
- console.error(`observe requires a <url>\n${USAGE}`);
23
- process.exit(2);
24
- }
25
- const outDir = resolve(flag(argv, 'out') ?? './capture');
26
- const wait = Number.parseInt(flag(argv, 'wait') ?? '0', 10) || 0;
27
- const captureFrames = Number.parseInt(flag(argv, 'frames') ?? '1', 10) || 1;
28
- const diagnostics = await captureUrl(url, { outDir, wait, captureFrames });
29
- console.log(`captured → ${resolve(outDir, 'screenshot.png')}`);
30
- console.log(`observe ${JSON.stringify(diagnostics)}`);
31
- // Exit explicitly — the browser's live handles would otherwise keep the event loop alive after
32
- // teardown and hang the process (the same trap the capture scripts hit).
33
- process.exit(0);
148
+ const [command, ...argv] = process.argv.slice(2);
149
+ if (command === 'observe') {
150
+ const url = argv[0];
151
+ if (url === undefined || url.startsWith('--'))
152
+ throw new Error(`observe requires a <url>\n${USAGE}`);
153
+ const outDir = resolve(flag(argv, 'out') ?? './capture');
154
+ const diagnostics = await captureUrl(url, {
155
+ outDir,
156
+ wait: parseNonNegativeInteger(flag(argv, 'wait'), 0),
157
+ captureFrames: parseNonNegativeInteger(flag(argv, 'frames'), 1) || 1,
158
+ });
159
+ console.log(`captured → ${resolve(outDir, 'screenshot.png')}`);
160
+ console.log(`observe ${JSON.stringify(diagnostics)}`);
161
+ process.exit(0);
162
+ }
163
+ if (command === 'capture')
164
+ process.exit(await capture(argv));
165
+ if (command === 'validate')
166
+ process.exit(await validate(argv));
167
+ console.error(USAGE);
168
+ process.exit(2);
169
+ }
170
+ function parseNonNegativeInteger(value, fallback) {
171
+ if (value === undefined)
172
+ return fallback;
173
+ const parsed = Number.parseInt(value, 10);
174
+ return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
175
+ }
176
+ function parseNumber(value) {
177
+ if (value === undefined)
178
+ return undefined;
179
+ const parsed = Number.parseFloat(value);
180
+ return Number.isFinite(parsed) ? parsed : undefined;
34
181
  }
182
+ const FLIGHT_PARITY_SKIP = {
183
+ playingvideo: 'all',
184
+ 'effect-hue-saturation': ['canvas'],
185
+ 'effect-lens-distortion': ['canvas'],
186
+ 'effect-lens-flare': ['canvas'],
187
+ 'effect-posterize': ['canvas'],
188
+ 'effect-vignette': ['canvas'],
189
+ 'effect-displacement': 'all',
190
+ 'effect-god-rays': 'all',
191
+ 'effect-screen-space-fog': 'all',
192
+ };
35
193
  main().catch((err) => {
194
+ if (isBrowserClosedError(err))
195
+ process.exit(130);
36
196
  console.error(err);
37
197
  process.exit(1);
38
198
  });
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,kGAAkG;AAClG,mGAAmG;AACnG,oGAAoG;AACpG,uGAAuG;AACvG,wGAAwG;AAExG,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,KAAK,GAAG,8EAA8E,CAAC;AAE7F,SAAS,IAAI,CAAC,IAAuB,EAAE,GAAW;IAChD,MAAM,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACvE,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC9C,OAAO,CAAC,KAAK,CAAC,6BAA6B,KAAK,EAAE,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,WAAW,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IACjE,MAAM,aAAa,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAE5E,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,cAAc,OAAO,CAAC,MAAM,EAAE,gBAAgB,CAAC,EAAE,CAAC,CAAC;IAC/D,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IACxD,+FAA+F;IAC/F,yEAAyE;IACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"captureBrowser.d.ts","sourceRoot":"","sources":["../src/captureBrowser.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEhE,wBAAsB,aAAa,CACjC,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAC5E,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,CAAC,CAwLxD"}
1
+ {"version":3,"file":"captureBrowser.d.ts","sourceRoot":"","sources":["../src/captureBrowser.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAEhE,wBAAsB,aAAa,CACjC,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO,GAC5E,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,cAAc,CAAA;CAAE,CAAC,CAgMxD"}
@@ -98,6 +98,14 @@ export async function launchBrowser(options = {}) {
98
98
  window.requestAnimationFrame = (callback) => realRequestAnimationFrame((time) => {
99
99
  if (flags.__captureFramesReached)
100
100
  return; // halted: scene holds its last frame
101
+ // Harness/bootstrap scripts can request frames before the renderer has even created its
102
+ // canvas or registered a verification target. Those are not render frames: counting them can
103
+ // exhaust a small --frames value before an async application module starts, freezing its first
104
+ // real draw as a blank canvas. Let bootstrap callbacks run without advancing the capture count.
105
+ if (flags.__ftTarget === undefined && document.querySelector('canvas') === null) {
106
+ callback(time);
107
+ return;
108
+ }
101
109
  if (count >= frames) {
102
110
  const targetKind = flags.__ftTarget?.kind;
103
111
  const gpuVerifying = verify && (targetKind === 'webgl' || targetKind === 'webgpu');
@@ -1 +1 @@
1
- {"version":3,"file":"captureBrowser.js","sourceRoot":"","sources":["../src/captureBrowser.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"captureBrowser.js","sourceRoot":"","sources":["../src/captureBrowser.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ export type Tool = 'examples' | 'functional' | 'reference';
3
3
  export interface Entry {
4
4
  name: string;
5
5
  renderers: string[];
6
+ routes?: Readonly<Record<string, string>>;
6
7
  route?: (renderer: string) => string;
7
8
  }
8
9
  export declare const BACKEND_UNAVAILABLE: RegExp;
@@ -1 +1 @@
1
- {"version":3,"file":"captureEntries.d.ts","sourceRoot":"","sources":["../src/captureEntries.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,SAAS,+CAAgD,CAAC;AAIvE,MAAM,MAAM,IAAI,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,CAAC;AAE3D,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;IAIpB,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;CACtC;AASD,eAAO,MAAM,mBAAmB,QACgJ,CAAC;AAEjL,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE,CAqBjE;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAI1F;AAID,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErD"}
1
+ {"version":3,"file":"captureEntries.d.ts","sourceRoot":"","sources":["../src/captureEntries.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,SAAS,+CAAgD,CAAC;AAIvE,MAAM,MAAM,IAAI,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,CAAC;AAE3D,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;IAGpB,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAI1C,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;CACtC;AASD,eAAO,MAAM,mBAAmB,QACgJ,CAAC;AAEjL,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,KAAK,EAAE,CAqBjE;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAI1F;AAID,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErD"}
@@ -9,7 +9,7 @@ export const RENDERERS = ['dom', 'canvas', 'webgl', 'webgpu'];
9
9
  // null-fingerprint / page-error outcomes that may be skipped rather than failed — the gate verifies
10
10
  // backends where they exist and stays green on machines without them. A real render bug still fails:
11
11
  // a validation error (bad writeBuffer/copy) is logged before the device dies, and is matched first.
12
- // Shared with compare-render.ts so the smoke gate and the parity/regression gate agree on what counts
12
+ // Shared by capture and validation so the smoke gate and the parity/regression gate agree on what counts
13
13
  // as "unavailable".
14
14
  export const BACKEND_UNAVAILABLE = /WebGPU adapter|WebGPU device|requestAdapter|requestDevice|GPUAdapter|WebGPU is not supported|external Instance reference no longer exists|device (was )?lost|device is lost/i;
15
15
  export function discoverEntries(tool, root) {
@@ -1 +1 @@
1
- {"version":3,"file":"captureEntries.js","sourceRoot":"","sources":["../src/captureEntries.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,uEAAuE;AAEvE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAU,CAAC;AAevE,oGAAoG;AACpG,+FAA+F;AAC/F,oGAAoG;AACpG,qGAAqG;AACrG,oGAAoG;AACpG,sGAAsG;AACtG,oBAAoB;AACpB,MAAM,CAAC,MAAM,mBAAmB,GAC9B,8KAA8K,CAAC;AAEjL,MAAM,UAAU,eAAe,CAAC,IAAU,EAAE,IAAY;IACtD,qGAAqG;IACrG,qDAAqD;IACrD,IAAI,IAAI,KAAK,WAAW;QAAE,OAAO,EAAE,CAAC;IACpC,gGAAgG;IAChG,kEAAkE;IAClE,IAAI,IAAI,KAAK,YAAY;QAAE,OAAO,wBAAwB,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE/F,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SAC7C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC;SAC/E,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;SAC5C,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;QAChB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAChC,MAAM,eAAe,GAAI,SAA+B,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACpE,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAChD,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;IAC9C,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,QAAgB,EAAE,MAAyB;IAC/E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC9F,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC/D,CAAC;AAED,iFAAiF;AACjF,qEAAqE;AACrE,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC"}
1
+ {"version":3,"file":"captureEntries.js","sourceRoot":"","sources":["../src/captureEntries.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,uEAAuE;AAEvE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEjE,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAU,CAAC;AAkBvE,oGAAoG;AACpG,+FAA+F;AAC/F,oGAAoG;AACpG,qGAAqG;AACrG,oGAAoG;AACpG,yGAAyG;AACzG,oBAAoB;AACpB,MAAM,CAAC,MAAM,mBAAmB,GAC9B,8KAA8K,CAAC;AAEjL,MAAM,UAAU,eAAe,CAAC,IAAU,EAAE,IAAY;IACtD,qGAAqG;IACrG,qDAAqD;IACrD,IAAI,IAAI,KAAK,WAAW;QAAE,OAAO,EAAE,CAAC;IACpC,gGAAgG;IAChG,kEAAkE;IAClE,IAAI,IAAI,KAAK,YAAY;QAAE,OAAO,wBAAwB,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE/F,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAC/C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SAC7C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC;SAC/E,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;SAC5C,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;QAChB,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAChC,MAAM,eAAe,GAAI,SAA+B,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACpE,UAAU,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,CAChD,CAAC;QACF,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;IAC9C,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,QAAgB,EAAE,MAAyB;IAC/E,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC9F,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC/D,CAAC;AAED,iFAAiF;AACjF,qEAAqE;AACrE,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,OAAO,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACpC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import type { BrowserContext } from '@playwright/test';
2
- import type { Entry, Tool } from './captureEntries.js';
2
+ import type { Entry } from './captureEntries.js';
3
3
  export interface CaptureStatus {
4
4
  state: 'ready' | 'error';
5
5
  capturedAt: number;
@@ -45,7 +45,7 @@ export interface CaptureEntryOptions {
45
45
  entry: Entry;
46
46
  renderers: string[];
47
47
  baseUrl: string;
48
- tool: Tool;
48
+ tool: string;
49
49
  outBase: string;
50
50
  /** Repo root — committed baselines live at tests/<tool>/baselines/<name>.json. */
51
51
  root: string;
@@ -96,7 +96,7 @@ export interface ParallelCaptureOptions {
96
96
  entries: Entry[];
97
97
  rendererFilter: string[];
98
98
  baseUrl: string;
99
- tool: Tool;
99
+ tool: string;
100
100
  outBase: string;
101
101
  root: string;
102
102
  updateBaseline?: boolean;
@@ -143,5 +143,5 @@ export interface CaptureUrlOptions {
143
143
  /** Frame-halt minimum (see launchBrowser); 1 is the robust default. */
144
144
  captureFrames?: number;
145
145
  }
146
- export declare function getCaptureOutputPaths(outBase: string, tool: Tool, name: string, renderer: string): CaptureOutputPaths;
146
+ export declare function getCaptureOutputPaths(outBase: string, tool: string, name: string, renderer: string): CaptureOutputPaths;
147
147
  //# sourceMappingURL=captureEntry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"captureEntry.d.ts","sourceRoot":"","sources":["../src/captureEntry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"captureEntry.d.ts","sourceRoot":"","sources":["../src/captureEntry.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAQ,MAAM,kBAAkB,CAAC;AAK7D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAMjD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,sGAAsG;IACtG,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,yBAAyB,CAAC;CACrC;AAED,oGAAoG;AACpG,MAAM,WAAW,yBAAyB;IACxC,2GAA2G;IAC3G,KAAK,EAAE,OAAO,CAAC;IACf,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAC;IAChB,8FAA8F;IAC9F,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,2FAA2F;IAC3F,eAAe,EAAE,OAAO,CAAC;IACzB,6FAA6F;IAC7F,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,yGAAyG;IACzG,cAAc,EAAE,MAAM,CAAC;IACvB,+FAA+F;IAC/F,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,cAAc,CAAC;IACxB,KAAK,EAAE,KAAK,CAAC;IACb,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,8FAA8F;IAC9F,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IAC1B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,cAAc,CAAC;IACxB,OAAO,EAAE,KAAK,EAAE,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kEAAkE;IAClE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wGAAwG;AACxG,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAqBD,wBAAgB,8BAA8B,CAAC,IAAI,EAAE;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,SAAS,OAAO,EAAE,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,yBAAyB,CAmB5B;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,GAAG,SAAS,GAAG,OAAO,CAAC,CAsVjG;AAkLD,wBAAsB,eAAe,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAgDlG;AAOD,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,GACnC,OAAO,CAAC,yBAAyB,CAAC,CA6EpC;AAED,MAAM,WAAW,iBAAiB;IAChC,0FAA0F;IAC1F,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAKD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,GACf,kBAAkB,CAUpB"}
@@ -60,7 +60,7 @@ export async function captureEntry(opts) {
60
60
  let anyFailed = false;
61
61
  let anyChanged = false;
62
62
  // Detail lines below the caller's [N/M] header drop the entry name (the header carries it) and
63
- // column-align on the renderer label, matching compare-render.ts. The renderer name carries the
63
+ // column-align on the renderer label, matching the validation report. The renderer name carries the
64
64
  // verdict color; routine confirmations dim (see formatStatusLine).
65
65
  // displayLabel overrides the renderer name when set (used by captureParallel).
66
66
  const labelWidth = displayLabel ? Math.max(6, displayLabel.length) : Math.max(6, ...renderers.map((r) => r.length));
@@ -70,13 +70,14 @@ export async function captureEntry(opts) {
70
70
  // Stop launching pages once an interrupt has begun; the partial result is reported by the caller.
71
71
  if (isAborted())
72
72
  break;
73
- const urlPath = entry.route
74
- ? entry.route(renderer)
75
- : tool === 'examples'
76
- ? `examples/${entry.name}/${routeSegment(renderer)}/`
77
- : tool === 'functional'
78
- ? `tests/${entry.name}/${routeSegment(renderer)}/`
79
- : ''; // landing: the single page is served at the server root
73
+ const urlPath = entry.routes?.[renderer] ??
74
+ (entry.route
75
+ ? entry.route(renderer)
76
+ : tool === 'examples'
77
+ ? `examples/${entry.name}/${routeSegment(renderer)}/`
78
+ : tool === 'functional'
79
+ ? `tests/${entry.name}/${routeSegment(renderer)}/`
80
+ : ''); // landing: the single page is served at the server root
80
81
  const url = `${baseUrl}/${urlPath}`;
81
82
  const { outDir, tmpScreenshot, finalScreenshot, tmpLogs, finalLogs, statusPath } = getCaptureOutputPaths(outBase, tool, entry.name, renderer);
82
83
  mkdirSync(outDir, { recursive: true });
@@ -221,6 +222,16 @@ export async function captureEntry(opts) {
221
222
  .screenshot()
222
223
  .catch(() => page.screenshot());
223
224
  }
225
+ else if (backend === 'webgl' && captureFrames > 0) {
226
+ // launchBrowser forces preserveDrawingBuffer in deterministic frame mode, so read the canvas
227
+ // itself instead of Chromium's compositor. Headless SwiftShader can display a WebGL canvas in
228
+ // an interactive browser while returning an entirely blank locator screenshot; reference pages
229
+ // that do not register a verifier otherwise produce a false-green white capture here.
230
+ const canvasDataUrl = await getCanvasImageDataUrl(page);
231
+ if (canvasDataUrl === null)
232
+ throw new Error('WebGL canvas did not produce a capture image');
233
+ screenshotBuffer = Buffer.from(canvasDataUrl.split(',')[1], 'base64');
234
+ }
224
235
  else {
225
236
  screenshotBuffer = await page
226
237
  .locator('canvas')
@@ -377,6 +388,9 @@ async function getRenderImageDataUrl(page) {
377
388
  .evaluate(() => window.__ftRenderImage ?? null)
378
389
  .catch(() => null);
379
390
  }
391
+ async function getCanvasImageDataUrl(page) {
392
+ return page.evaluate(() => document.querySelector('canvas')?.toDataURL('image/png') ?? null).catch(() => null);
393
+ }
380
394
  // The kind of functional target the page registered (webgl / webgpu / canvas / dom), or null if it
381
395
  // registered none. A registered target is the page's claim that it verifies its own render; the
382
396
  // screenshot selection uses it to tell "opted into verification but drew blank" (a failure) from