versioncam 0.5.2 → 0.7.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.
Files changed (57) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.md +95 -2
  3. package/dist/cli/commands/check.js +25 -0
  4. package/dist/cli/commands/check.js.map +1 -1
  5. package/dist/cli/commands/doctor.js +54 -1
  6. package/dist/cli/commands/doctor.js.map +1 -1
  7. package/dist/cli/commands/install.d.ts +40 -3
  8. package/dist/cli/commands/install.js +66 -11
  9. package/dist/cli/commands/install.js.map +1 -1
  10. package/dist/cli/commands/record.d.ts +6 -0
  11. package/dist/cli/commands/record.js +24 -3
  12. package/dist/cli/commands/record.js.map +1 -1
  13. package/dist/cli/commands/stability.js +10 -3
  14. package/dist/cli/commands/stability.js.map +1 -1
  15. package/dist/cli/usage.d.ts +1 -1
  16. package/dist/cli/usage.js +2 -0
  17. package/dist/cli/usage.js.map +1 -1
  18. package/dist/config.d.ts +37 -1
  19. package/dist/config.js +115 -3
  20. package/dist/config.js.map +1 -1
  21. package/dist/core/cursor.d.ts +22 -0
  22. package/dist/core/cursor.js +6 -0
  23. package/dist/core/cursor.js.map +1 -1
  24. package/dist/core/motion-defaults.d.ts +8 -0
  25. package/dist/core/motion-defaults.js +8 -0
  26. package/dist/core/motion-defaults.js.map +1 -1
  27. package/dist/core/timeline.d.ts +24 -0
  28. package/dist/core/timeline.js.map +1 -1
  29. package/dist/driver/clip.d.ts +6 -0
  30. package/dist/driver/clip.js +33 -2
  31. package/dist/driver/clip.js.map +1 -1
  32. package/dist/driver/file-window.d.ts +66 -0
  33. package/dist/driver/file-window.js +245 -0
  34. package/dist/driver/file-window.js.map +1 -0
  35. package/dist/driver/page-hooks.d.ts +23 -1
  36. package/dist/driver/page-hooks.js +36 -1
  37. package/dist/driver/page-hooks.js.map +1 -1
  38. package/dist/driver/replay.d.ts +263 -0
  39. package/dist/driver/replay.js +558 -0
  40. package/dist/driver/replay.js.map +1 -0
  41. package/dist/driver/session.d.ts +70 -4
  42. package/dist/driver/session.js +267 -29
  43. package/dist/driver/session.js.map +1 -1
  44. package/dist/driver/settle.js +6 -0
  45. package/dist/driver/settle.js.map +1 -1
  46. package/dist/index.d.ts +4 -2
  47. package/dist/index.js.map +1 -1
  48. package/dist/page/assets/index-CnRDAiUz.js +2 -0
  49. package/dist/page/index.html +1 -1
  50. package/dist/publish/protocol.d.ts +12 -1
  51. package/dist/publish/protocol.js.map +1 -1
  52. package/dsl.md +68 -1
  53. package/package.json +1 -1
  54. package/plugin/.claude-plugin/plugin.json +1 -1
  55. package/plugin/skills/versioncam/authoring.md +6 -1
  56. package/plugin/skills/versioncam/onboarding.md +9 -3
  57. package/dist/page/assets/index-BtUbUEdN.js +0 -2
@@ -1 +1 @@
1
- {"version":3,"file":"timeline.js","sourceRoot":"","sources":["../../src/core/timeline.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"timeline.js","sourceRoot":"","sources":["../../src/core/timeline.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import type { Browser } from "playwright";
2
2
  import type { CaptureConfig, ResolvedConfig } from "../config.js";
3
3
  import type { Timeline } from "../core/timeline.js";
4
4
  import type { RecordingTiming } from "../core/timing.js";
5
+ import type { ReplayMode } from "./replay.js";
5
6
  import type { SettleReport } from "./settle.js";
6
7
  import { RecordingSession } from "./session.js";
7
8
  export type ClipOptions = {
@@ -78,5 +79,10 @@ export type RunClipOptions = {
78
79
  * capture it stands in for fails on a media query.
79
80
  */
80
81
  draft?: boolean;
82
+ /**
83
+ * The replay's mode for this run, over the config's: what `--replay` on
84
+ * the command line sets.
85
+ */
86
+ replay?: ReplayMode;
81
87
  };
82
88
  export declare function runClip(browser: Browser, config: ResolvedConfig, definition: ClipDefinition, runOptions?: RunClipOptions): Promise<RunClipResult>;
@@ -2,7 +2,8 @@ import { execFileSync } from "node:child_process";
2
2
  import { createRequire } from "node:module";
3
3
  import { join } from "node:path";
4
4
  import { isTransitions } from "../config.js";
5
- import { MUTATION_COUNTER_SCRIPT, TRANSITION_CLOCK_SCRIPT, freezeCssScript, } from "./page-hooks.js";
5
+ import { INSTANT_SCROLL_SCRIPT, MUTATION_COUNTER_SCRIPT, TRANSITION_CLOCK_SCRIPT, freezeCssScript, } from "./page-hooks.js";
6
+ import { ClipReplay } from "./replay.js";
6
7
  import { writeFailure, writeSettles, writeTargets } from "./reports.js";
7
8
  import { RecordingSession } from "./session.js";
8
9
  /**
@@ -43,6 +44,11 @@ export async function runClip(browser, config, definition, runOptions = {}) {
43
44
  // clip asking for 60 would quietly cost four times what the flag promises.
44
45
  const fps = draft ? 15 : (options.fps ?? config.fps);
45
46
  const capture = { ...config.capture, ...options.capture };
47
+ // Made first, because it refuses a clip told to replay a file that does
48
+ // not exist, and nothing is open yet to close.
49
+ const replay = config.replay
50
+ ? new ClipReplay(config.replay, id, RECORDER_VERSION, runOptions.replay)
51
+ : null;
46
52
  const context = await browser.newContext({
47
53
  viewport,
48
54
  deviceScaleFactor: dpr,
@@ -54,6 +60,11 @@ export async function runClip(browser, config, definition, runOptions = {}) {
54
60
  locale: config.clock.locale,
55
61
  storageState: config.auth?.storageState,
56
62
  });
63
+ // Installed on the context before the page exists, so the page's first
64
+ // request is caught. A clip's own `page.route` mocks are tried before it,
65
+ // as Playwright tries a page's routes before its context's: what a clip
66
+ // answers itself never reaches the replay.
67
+ await replay?.install(context);
57
68
  const page = await context.newPage();
58
69
  // A clip's own `capture` is merged over the config's unchecked, so its
59
70
  // switch is checked here, where a typo would otherwise play by default.
@@ -63,8 +74,12 @@ export async function runClip(browser, config, definition, runOptions = {}) {
63
74
  }
64
75
  await page.addInitScript(MUTATION_COUNTER_SCRIPT);
65
76
  await page.addInitScript(freezeCssScript(transitions));
77
+ await page.addInitScript(INSTANT_SCROLL_SCRIPT);
66
78
  if (transitions === "play")
67
79
  await page.addInitScript(TRANSITION_CLOCK_SCRIPT);
80
+ const pacing = replay?.pacingScript();
81
+ if (pacing)
82
+ await page.addInitScript(pacing);
68
83
  // Paused, not just installed. `clock.install()` leaves Playwright's fake
69
84
  // clock running on real time between the driver's own `runFor` calls, so
70
85
  // every screenshot, every probe and every stall of the machine reached the
@@ -101,9 +116,24 @@ export async function runClip(browser, config, definition, runOptions = {}) {
101
116
  capture,
102
117
  draft,
103
118
  config,
119
+ replay,
104
120
  });
105
121
  try {
106
- await body(session.forClipBody());
122
+ try {
123
+ await body(session.forClipBody());
124
+ }
125
+ catch (error) {
126
+ // A request the replay could not answer failed in the page, and the
127
+ // page then failed the clip somewhere else: a locator that never
128
+ // appeared, a settle that ran out. The missing response is the cause.
129
+ const missing = replay?.failure();
130
+ if (missing)
131
+ error.message += `\n\n${missing}`;
132
+ throw error;
133
+ }
134
+ const missing = replay?.failure();
135
+ if (missing)
136
+ throw new Error(missing);
107
137
  if (documentLoads > 1) {
108
138
  throw new Error(`The document reloaded ${documentLoads - 1} time(s) during "${id}". ` +
109
139
  "The usual cause is editing a file while recording: a dev server " +
@@ -113,6 +143,7 @@ export async function runClip(browser, config, definition, runOptions = {}) {
113
143
  const timeline = session.finish();
114
144
  writeSettles(dir, session.settles);
115
145
  writeTargets(dir, session.evidence().targets);
146
+ replay?.write();
116
147
  return { timeline, dir, cost: session.cost, settles: session.settles };
117
148
  }
118
149
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"clip.js","sourceRoot":"","sources":["../../src/driver/clip.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"clip.js","sourceRoot":"","sources":["../../src/driver/clip.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * A file window drawn over the page, to drag files from.
3
+ *
4
+ * Uploading is half of what a data app does, and the browser's own file
5
+ * dialog is outside the page: nothing can film it, and a file that simply
6
+ * appears in an upload list reads as a cut. The first app this recorded
7
+ * solved it with a small window drawn in the page, listing the files, from
8
+ * which the cursor drags them onto the app's own dropzone; nothing in it was
9
+ * that app's, so it is here. It looks like a Finder window, because the
10
+ * clips it sits in show a Mac's cursor.
11
+ *
12
+ * It is staged, and a clip that uses it should say so where its clips are
13
+ * shown. What is real is the drop: letting go over the page sends the
14
+ * element under the pointer the `dragenter`, `dragover` and `drop` events a
15
+ * real drag sends, carrying `File` objects with the names, types and
16
+ * contents given, so the app takes them through its own dropzone, its own
17
+ * accept rules and its own list, as it takes a person's.
18
+ *
19
+ * Selection works as in Finder: a click selects one row, a click with Shift
20
+ * extends to it, a click with Meta or Control adds or removes it, and a
21
+ * press on a selected row drags the whole selection. Its motion runs on
22
+ * `requestAnimationFrame`, which the recorder's clock drives, so it opens
23
+ * and closes at the same pace on every run.
24
+ */
25
+ export type StagedFile = {
26
+ /** What the window lists, and the dropped `File`'s name. */
27
+ name: string;
28
+ /** The dropped file's contents. Default empty. */
29
+ content?: string;
30
+ /** Its MIME type. Default from the extension. */
31
+ type?: string;
32
+ /** The Size column. Default from the contents. */
33
+ size?: string;
34
+ };
35
+ export type FileWindowOptions = {
36
+ /** The title bar. Default "Files". */
37
+ title?: string;
38
+ /**
39
+ * Where the window's top left corner sits, as fractions of the viewport.
40
+ * Default `{ x: 0.52, y: 0.42 }`, to the right of centre, where a sidebar's
41
+ * dropzone on the left stays in view.
42
+ */
43
+ at?: {
44
+ x: number;
45
+ y: number;
46
+ };
47
+ };
48
+ /** A row as the page draws it: every column worked out here, not there. */
49
+ export type FileRow = {
50
+ name: string;
51
+ content: string;
52
+ type: string;
53
+ size: string;
54
+ kind: string;
55
+ };
56
+ export declare function fileRows(files: readonly StagedFile[]): FileRow[];
57
+ /**
58
+ * Runs in the page: draws the window and wires its selection and its drag.
59
+ * Self-contained, as everything handed to `page.evaluate` must be.
60
+ */
61
+ export declare function drawFileWindow(args: {
62
+ rows: FileRow[];
63
+ title: string;
64
+ left: number;
65
+ top: number;
66
+ }): void;
@@ -0,0 +1,245 @@
1
+ /**
2
+ * A file window drawn over the page, to drag files from.
3
+ *
4
+ * Uploading is half of what a data app does, and the browser's own file
5
+ * dialog is outside the page: nothing can film it, and a file that simply
6
+ * appears in an upload list reads as a cut. The first app this recorded
7
+ * solved it with a small window drawn in the page, listing the files, from
8
+ * which the cursor drags them onto the app's own dropzone; nothing in it was
9
+ * that app's, so it is here. It looks like a Finder window, because the
10
+ * clips it sits in show a Mac's cursor.
11
+ *
12
+ * It is staged, and a clip that uses it should say so where its clips are
13
+ * shown. What is real is the drop: letting go over the page sends the
14
+ * element under the pointer the `dragenter`, `dragover` and `drop` events a
15
+ * real drag sends, carrying `File` objects with the names, types and
16
+ * contents given, so the app takes them through its own dropzone, its own
17
+ * accept rules and its own list, as it takes a person's.
18
+ *
19
+ * Selection works as in Finder: a click selects one row, a click with Shift
20
+ * extends to it, a click with Meta or Control adds or removes it, and a
21
+ * press on a selected row drags the whole selection. Its motion runs on
22
+ * `requestAnimationFrame`, which the recorder's clock drives, so it opens
23
+ * and closes at the same pace on every run.
24
+ */
25
+ /** The extension's kind, as Finder words it, and its MIME type. */
26
+ const KINDS = {
27
+ csv: { kind: "CSV document", type: "text/csv" },
28
+ tsv: { kind: "TSV document", type: "text/tab-separated-values" },
29
+ json: { kind: "JSON document", type: "application/json" },
30
+ txt: { kind: "Plain Text", type: "text/plain" },
31
+ fasta: { kind: "FASTA document", type: "text/plain" },
32
+ fa: { kind: "FASTA document", type: "text/plain" },
33
+ png: { kind: "PNG image", type: "image/png" },
34
+ jpg: { kind: "JPEG image", type: "image/jpeg" },
35
+ pdf: { kind: "PDF document", type: "application/pdf" },
36
+ xlsx: {
37
+ kind: "Microsoft Excel workbook",
38
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
39
+ },
40
+ };
41
+ export function fileRows(files) {
42
+ if (!Array.isArray(files) || files.length === 0) {
43
+ throw new TypeError("fileWindow: list at least one file, as { name }.");
44
+ }
45
+ return files.map((file, i) => {
46
+ if (typeof file?.name !== "string" || file.name.length === 0) {
47
+ throw new TypeError(`fileWindow: file ${i} has no name.`);
48
+ }
49
+ const ext = file.name.split(".").pop()?.toLowerCase() ?? "";
50
+ const known = KINDS[ext];
51
+ const content = file.content ?? "";
52
+ const bytes = new TextEncoder().encode(content).length;
53
+ return {
54
+ name: file.name,
55
+ content,
56
+ type: file.type ?? known?.type ?? "application/octet-stream",
57
+ size: file.size ??
58
+ (bytes === 1
59
+ ? "1 byte"
60
+ : bytes < 1024
61
+ ? `${bytes} bytes`
62
+ : `${Math.round(bytes / 1024)} KB`),
63
+ kind: known?.kind ?? "Document",
64
+ };
65
+ });
66
+ }
67
+ /**
68
+ * Runs in the page: draws the window and wires its selection and its drag.
69
+ * Self-contained, as everything handed to `page.evaluate` must be.
70
+ */
71
+ export function drawFileWindow(args) {
72
+ const doc = document;
73
+ doc.getElementById("vc-file-window")?.remove();
74
+ const style = doc.createElement("style");
75
+ style.id = "vc-file-window-style";
76
+ style.textContent = `
77
+ #vc-file-window { position: fixed; z-index: 2147483000; width: 480px; border-radius: 10px;
78
+ overflow: hidden; background: #ffffff; color: #1d1d1f; opacity: 0;
79
+ box-shadow: 0 18px 50px rgba(15, 15, 40, 0.28), 0 0 0 1px rgba(0, 0, 0, 0.12);
80
+ font: 13px/1.35 -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif; }
81
+ #vc-file-window .bar { height: 34px; display: flex; align-items: center; gap: 8px; padding: 0 12px;
82
+ background: #ececec; border-bottom: 1px solid #d9d9d9; }
83
+ #vc-file-window .dot { width: 12px; height: 12px; border-radius: 50%; }
84
+ #vc-file-window .title { flex: 1; text-align: center; margin-right: 52px; font-weight: 600; color: #4a4a4a; }
85
+ #vc-file-window .head, #vc-file-window .row { display: grid; grid-template-columns: 1fr 80px 150px;
86
+ gap: 8px; align-items: center; padding: 0 14px; }
87
+ #vc-file-window .head { height: 26px; color: #8a8a8e; font-size: 11px; border-bottom: 1px solid #eeeeee; }
88
+ #vc-file-window .row { height: 30px; cursor: default; user-select: none; }
89
+ #vc-file-window .row:nth-child(odd) { background: #f6f6f8; }
90
+ #vc-file-window .row.selected { background: #2f6fde; color: #ffffff; }
91
+ #vc-file-window .name { display: flex; align-items: center; gap: 8px; white-space: nowrap;
92
+ overflow: hidden; text-overflow: ellipsis; }
93
+ #vc-file-window .muted { color: #8a8a8e; white-space: nowrap; }
94
+ #vc-file-window .row.selected .muted { color: #dbe6ff; }
95
+ #vc-file-window .foot { height: 24px; display: flex; align-items: center; justify-content: center;
96
+ color: #8a8a8e; font-size: 11px; border-top: 1px solid #eeeeee; background: #fafafa; }
97
+ #vc-file-ghost { position: fixed; z-index: 2147483001; pointer-events: none; display: flex;
98
+ align-items: center; gap: 6px; padding: 5px 9px; border-radius: 6px; background: rgba(47, 111, 222, 0.92);
99
+ color: #ffffff; font: 12px/1.2 -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
100
+ box-shadow: 0 6px 18px rgba(0, 0, 0, 0.2); }
101
+ #vc-file-ghost .count { background: #ff3b30; border-radius: 9px; padding: 0 6px; font-weight: 600; }
102
+ `;
103
+ doc.getElementById("vc-file-window-style")?.remove();
104
+ doc.head.append(style);
105
+ const icon = (kind) => {
106
+ const colour = /image/i.test(kind)
107
+ ? "#f4b400"
108
+ : /PDF/.test(kind)
109
+ ? "#ea4335"
110
+ : "#34a853";
111
+ return `<svg width="14" height="17" viewBox="0 0 14 17" aria-hidden="true"><path d="M1 1h8l4 4v11H1z" fill="#fff" stroke="#9a9aa2"/><path d="M9 1v4h4" fill="none" stroke="#9a9aa2"/><rect x="3" y="9" width="8" height="5" rx="1" fill="${colour}"/></svg>`;
112
+ };
113
+ const text = (value) => {
114
+ const span = doc.createElement("span");
115
+ span.textContent = value;
116
+ return span.innerHTML;
117
+ };
118
+ const win = doc.createElement("div");
119
+ win.id = "vc-file-window";
120
+ win.style.left = `${args.left}px`;
121
+ win.style.top = `${args.top}px`;
122
+ win.innerHTML = `
123
+ <div class="bar"><span class="dot" style="background:#ff5f57"></span><span class="dot" style="background:#febc2e"></span>
124
+ <span class="dot" style="background:#28c840"></span><span class="title">${text(args.title)}</span></div>
125
+ <div class="head"><span>Name</span><span>Size</span><span>Kind</span></div>
126
+ <div class="rows">${args.rows
127
+ .map((row, i) => `<div class="row" data-vc-file="${i}"><span class="name">${icon(row.kind)}${text(row.name)}</span>` +
128
+ `<span class="muted">${text(row.size)}</span><span class="muted">${text(row.kind)}</span></div>`)
129
+ .join("")}</div>
130
+ <div class="foot">${args.rows.length} ${args.rows.length === 1 ? "item" : "items"}</div>`;
131
+ doc.body.append(win);
132
+ const fade = (from, to, ms, done) => {
133
+ const start = performance.now();
134
+ const step = (now) => {
135
+ const t = Math.min(1, (now - start) / ms);
136
+ const eased = 1 - Math.pow(1 - t, 3);
137
+ const value = from + (to - from) * eased;
138
+ win.style.opacity = String(value);
139
+ win.style.transform = `translateY(${(1 - value) * 10}px)`;
140
+ if (t < 1)
141
+ requestAnimationFrame(step);
142
+ else
143
+ done?.();
144
+ };
145
+ requestAnimationFrame(step);
146
+ };
147
+ fade(0, 1, 280);
148
+ const rowEls = [...win.querySelectorAll(".row")];
149
+ const selected = new Set();
150
+ let anchor = 0;
151
+ const paint = () => rowEls.forEach((el, i) => el.classList.toggle("selected", selected.has(i)));
152
+ const transfer = () => {
153
+ const dt = new DataTransfer();
154
+ for (const i of [...selected].sort((a, b) => a - b)) {
155
+ const row = args.rows[i];
156
+ dt.items.add(new File([row.content], row.name, { type: row.type }));
157
+ }
158
+ return dt;
159
+ };
160
+ const fire = (target, type, x, y) => target.dispatchEvent(new DragEvent(type, {
161
+ bubbles: true,
162
+ cancelable: true,
163
+ composed: true,
164
+ clientX: x,
165
+ clientY: y,
166
+ dataTransfer: transfer(),
167
+ }));
168
+ const underPointer = (x, y) => {
169
+ const el = doc.elementFromPoint(x, y);
170
+ return el && !win.contains(el) ? el : null;
171
+ };
172
+ let pressed = null;
173
+ let ghost = null;
174
+ let over = null;
175
+ for (const [i, el] of rowEls.entries()) {
176
+ el.addEventListener("mousedown", (event) => {
177
+ event.preventDefault();
178
+ if (event.shiftKey) {
179
+ selected.clear();
180
+ for (let k = Math.min(anchor, i); k <= Math.max(anchor, i); k += 1)
181
+ selected.add(k);
182
+ }
183
+ else if (event.metaKey || event.ctrlKey) {
184
+ if (selected.has(i))
185
+ selected.delete(i);
186
+ else
187
+ selected.add(i);
188
+ anchor = i;
189
+ }
190
+ else if (!selected.has(i)) {
191
+ selected.clear();
192
+ selected.add(i);
193
+ anchor = i;
194
+ }
195
+ paint();
196
+ pressed = selected.has(i) ? { x: event.clientX, y: event.clientY } : null;
197
+ });
198
+ }
199
+ doc.addEventListener("mousemove", (event) => {
200
+ if (!pressed)
201
+ return;
202
+ if (!ghost) {
203
+ // A few pixels first, as a real drag waits for, so a click with a
204
+ // slightly unsteady hand selects and does not drag.
205
+ if (Math.hypot(event.clientX - pressed.x, event.clientY - pressed.y) < 4)
206
+ return;
207
+ ghost = doc.createElement("div");
208
+ ghost.id = "vc-file-ghost";
209
+ const first = args.rows[Math.min(...selected)];
210
+ ghost.innerHTML =
211
+ `${icon(first.kind)}${text(first.name)}` +
212
+ (selected.size > 1
213
+ ? `<span class="count">${selected.size}</span>`
214
+ : "");
215
+ doc.body.append(ghost);
216
+ }
217
+ ghost.style.left = `${event.clientX + 12}px`;
218
+ ghost.style.top = `${event.clientY + 10}px`;
219
+ const target = underPointer(event.clientX, event.clientY);
220
+ if (over && target !== over)
221
+ fire(over, "dragleave", event.clientX, event.clientY);
222
+ if (target && target !== over)
223
+ fire(target, "dragenter", event.clientX, event.clientY);
224
+ if (target)
225
+ fire(target, "dragover", event.clientX, event.clientY);
226
+ over = target;
227
+ });
228
+ doc.addEventListener("mouseup", (event) => {
229
+ const dragging = ghost !== null;
230
+ pressed = null;
231
+ if (!dragging)
232
+ return;
233
+ ghost?.remove();
234
+ ghost = null;
235
+ const target = underPointer(event.clientX, event.clientY);
236
+ over = null;
237
+ if (!target)
238
+ return;
239
+ fire(target, "drop", event.clientX, event.clientY);
240
+ // The files have gone where they were dropped, and the window with them.
241
+ fade(1, 0, 220, () => win.remove());
242
+ });
243
+ window.__vcCloseFileWindow = () => fade(1, 0, 220, () => win.remove());
244
+ }
245
+ //# sourceMappingURL=file-window.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-window.js","sourceRoot":"","sources":["../../src/driver/file-window.ts"],"names":[],"mappings":"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"}
@@ -80,10 +80,28 @@ export declare const SYNC_TRANSITIONS: string;
80
80
  * deterministically, at exactly the rate the timeline says.
81
81
  *
82
82
  * `scroll-behavior: auto` is here for the same reason: a smooth-scrolling
83
- * container animates outside our control.
83
+ * container animates outside our control. It covers what the stylesheet
84
+ * asks for; what a script asks for, `{ behavior: "smooth" }`, is
85
+ * `INSTANT_SCROLL_SCRIPT`'s.
84
86
  */
85
87
  export declare function freezeCss(zeroTransitions: boolean): string;
86
88
  export declare function freezeCssScript(transitions: Transitions): string;
89
+ /**
90
+ * Makes a script's smooth scroll instant, as the freeze stylesheet makes a
91
+ * stylesheet's.
92
+ *
93
+ * `scroll-behavior` in CSS only decides a scroll that does not say how to
94
+ * scroll. An app that calls `scrollIntoView({ behavior: "smooth" })`, or
95
+ * `scrollTo` with it, says, and the browser animates that scroll on the
96
+ * compositor's real clock whatever the stylesheet holds: a chat that keeps
97
+ * its newest message in view does it on every message, and the frames while
98
+ * it moved showed the pane wherever the machine had got it to. So the five
99
+ * methods a script scrolls with take `"smooth"` as `"instant"`, and every
100
+ * other argument through untouched. The scroll still happens, at once,
101
+ * which is what a clip on authored time can show the same way twice;
102
+ * `s.scroll` is how a clip shows one move.
103
+ */
104
+ export declare const INSTANT_SCROLL_SCRIPT = "(() => {\n const instant = (options) =>\n options && typeof options === \"object\" && options.behavior === \"smooth\"\n ? { ...options, behavior: \"instant\" }\n : options;\n const take = (owner, name) => {\n const original = owner[name];\n if (typeof original !== \"function\") return;\n owner[name] = function (...args) {\n if (args.length === 1) args[0] = instant(args[0]);\n return original.apply(this, args);\n };\n };\n for (const name of [\"scroll\", \"scrollTo\", \"scrollBy\", \"scrollIntoView\"]) {\n take(Element.prototype, name);\n }\n for (const name of [\"scroll\", \"scrollTo\", \"scrollBy\"]) take(window, name);\n})();";
87
105
  /**
88
106
  * What the driver learns from the page once per frame.
89
107
  *
@@ -123,5 +141,9 @@ declare global {
123
141
  __recorderTransitions?: {
124
142
  sync(): number;
125
143
  };
144
+ /** Set by the replay's pacing script (replay.ts). */
145
+ __recorderReplay?: {
146
+ pending: number;
147
+ };
126
148
  }
127
149
  }
@@ -196,7 +196,9 @@ export const SYNC_TRANSITIONS = "(window.__recorder ? window.__recorder.finishEn
196
196
  * deterministically, at exactly the rate the timeline says.
197
197
  *
198
198
  * `scroll-behavior: auto` is here for the same reason: a smooth-scrolling
199
- * container animates outside our control.
199
+ * container animates outside our control. It covers what the stylesheet
200
+ * asks for; what a script asks for, `{ behavior: "smooth" }`, is
201
+ * `INSTANT_SCROLL_SCRIPT`'s.
200
202
  */
201
203
  export function freezeCss(zeroTransitions) {
202
204
  const transitions = zeroTransitions
@@ -223,6 +225,39 @@ export function freezeCssScript(transitions) {
223
225
  else document.addEventListener("DOMContentLoaded", inject, { once: true });
224
226
  })();`;
225
227
  }
228
+ /**
229
+ * Makes a script's smooth scroll instant, as the freeze stylesheet makes a
230
+ * stylesheet's.
231
+ *
232
+ * `scroll-behavior` in CSS only decides a scroll that does not say how to
233
+ * scroll. An app that calls `scrollIntoView({ behavior: "smooth" })`, or
234
+ * `scrollTo` with it, says, and the browser animates that scroll on the
235
+ * compositor's real clock whatever the stylesheet holds: a chat that keeps
236
+ * its newest message in view does it on every message, and the frames while
237
+ * it moved showed the pane wherever the machine had got it to. So the five
238
+ * methods a script scrolls with take `"smooth"` as `"instant"`, and every
239
+ * other argument through untouched. The scroll still happens, at once,
240
+ * which is what a clip on authored time can show the same way twice;
241
+ * `s.scroll` is how a clip shows one move.
242
+ */
243
+ export const INSTANT_SCROLL_SCRIPT = `(() => {
244
+ const instant = (options) =>
245
+ options && typeof options === "object" && options.behavior === "smooth"
246
+ ? { ...options, behavior: "instant" }
247
+ : options;
248
+ const take = (owner, name) => {
249
+ const original = owner[name];
250
+ if (typeof original !== "function") return;
251
+ owner[name] = function (...args) {
252
+ if (args.length === 1) args[0] = instant(args[0]);
253
+ return original.apply(this, args);
254
+ };
255
+ };
256
+ for (const name of ["scroll", "scrollTo", "scrollBy", "scrollIntoView"]) {
257
+ take(Element.prototype, name);
258
+ }
259
+ for (const name of ["scroll", "scrollTo", "scrollBy"]) take(window, name);
260
+ })();`;
226
261
  /**
227
262
  * What the driver learns from the page once per frame.
228
263
  *
@@ -1 +1 @@
1
- {"version":3,"file":"page-hooks.js","sourceRoot":"","sources":["../../src/driver/page-hooks.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAwFjC,CAAC;AAEP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA4BjC,CAAC;AAEP;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAC3B,8DAA8D;IAC9D,0EAA0E,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,UAAU,SAAS,CAAC,eAAwB;IAChD,MAAM,WAAW,GAAG,eAAe;QACjC,CAAC,CAAC,6EAA6E;QAC/E,CAAC,CAAC,EAAE,CAAC;IACP,OAAO;EACP,WAAW;;;;EAIX,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,WAAwB;IACtD,OAAO;iBACQ,WAAW,KAAK,MAAM;uBAChB,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;;;;;;;;;MAStF,CAAC;AACP,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAe,EAAE,CAAS,EAAE,CAAS,EAAU,EAAE,CAC3E,4BAA4B,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC"}
1
+ {"version":3,"file":"page-hooks.js","sourceRoot":"","sources":["../../src/driver/page-hooks.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;GAIG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAwFjC,CAAC;AAEP;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;MA4BjC,CAAC;AAEP;;;;;GAKG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAC3B,8DAA8D;IAC9D,0EAA0E,CAAC;AAE7E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,SAAS,CAAC,eAAwB;IAChD,MAAM,WAAW,GAAG,eAAe;QACjC,CAAC,CAAC,6EAA6E;QAC/E,CAAC,CAAC,EAAE,CAAC;IACP,OAAO;EACP,WAAW;;;;EAIX,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,WAAwB;IACtD,OAAO;iBACQ,WAAW,KAAK,MAAM;uBAChB,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;;;;;;;;;MAStF,CAAC;AACP,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;MAiB/B,CAAC;AAEP;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,OAAe,EAAE,CAAS,EAAE,CAAS,EAAU,EAAE,CAC3E,4BAA4B,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC"}