versioncam 0.1.3 → 0.2.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 (74) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/README.md +116 -13
  3. package/dist/cli/commands/doctor.js +39 -2
  4. package/dist/cli/commands/doctor.js.map +1 -1
  5. package/dist/cli/commands/init.js +25 -0
  6. package/dist/cli/commands/init.js.map +1 -1
  7. package/dist/cli/commands/preview.js +10 -1
  8. package/dist/cli/commands/preview.js.map +1 -1
  9. package/dist/cli/commands/render.d.ts +17 -0
  10. package/dist/cli/commands/render.js +78 -21
  11. package/dist/cli/commands/render.js.map +1 -1
  12. package/dist/cli/cwd.d.ts +46 -0
  13. package/dist/cli/cwd.js +102 -0
  14. package/dist/cli/cwd.js.map +1 -0
  15. package/dist/cli/main.js +11 -2
  16. package/dist/cli/main.js.map +1 -1
  17. package/dist/cli/usage.d.ts +3 -2
  18. package/dist/cli/usage.js +9 -4
  19. package/dist/cli/usage.js.map +1 -1
  20. package/dist/config.d.ts +24 -0
  21. package/dist/config.js +25 -0
  22. package/dist/config.js.map +1 -1
  23. package/dist/core/camera-track.d.ts +63 -0
  24. package/dist/core/camera-track.js +230 -0
  25. package/dist/core/camera-track.js.map +1 -0
  26. package/dist/core/camera.d.ts +14 -1
  27. package/dist/core/camera.js +18 -2
  28. package/dist/core/camera.js.map +1 -1
  29. package/dist/core/follow.d.ts +129 -0
  30. package/dist/core/follow.js +151 -0
  31. package/dist/core/follow.js.map +1 -0
  32. package/dist/core/motion-defaults.d.ts +29 -0
  33. package/dist/core/motion-defaults.js +29 -0
  34. package/dist/core/motion-defaults.js.map +1 -1
  35. package/dist/core/timeline.d.ts +10 -2
  36. package/dist/core/timeline.js.map +1 -1
  37. package/dist/driver/session.d.ts +22 -1
  38. package/dist/driver/session.js +48 -12
  39. package/dist/driver/session.js.map +1 -1
  40. package/dist/index.d.ts +2 -2
  41. package/dist/index.js +1 -1
  42. package/dist/index.js.map +1 -1
  43. package/dist/loader.d.ts +7 -1
  44. package/dist/loader.js +23 -8
  45. package/dist/loader.js.map +1 -1
  46. package/dist/page/assets/index-fZtacWyp.js +2 -0
  47. package/dist/page/index.html +1 -1
  48. package/dist/render/encode.d.ts +12 -1
  49. package/dist/render/encode.js +94 -35
  50. package/dist/render/encode.js.map +1 -1
  51. package/dist/render/presentation.d.ts +12 -0
  52. package/dist/render/presentation.js +15 -0
  53. package/dist/render/presentation.js.map +1 -1
  54. package/dist/render/render.js +18 -1
  55. package/dist/render/render.js.map +1 -1
  56. package/dist/render/sampling.d.ts +13 -0
  57. package/dist/render/sampling.js +47 -19
  58. package/dist/render/sampling.js.map +1 -1
  59. package/dist/render/scenes.d.ts +16 -0
  60. package/dist/render/scenes.js +108 -0
  61. package/dist/render/scenes.js.map +1 -0
  62. package/dist/render/sequence.d.ts +18 -0
  63. package/dist/render/sequence.js +67 -13
  64. package/dist/render/sequence.js.map +1 -1
  65. package/dist/review/review.js +46 -21
  66. package/dist/review/review.js.map +1 -1
  67. package/dsl.md +37 -0
  68. package/package.json +1 -1
  69. package/plugin/README.md +7 -2
  70. package/plugin/agents/versioncam-reviewer.md +3 -2
  71. package/plugin/skills/versioncam/SKILL.md +60 -14
  72. package/plugin/skills/versioncam/authoring.md +6 -1
  73. package/plugin/skills/versioncam/onboarding.md +17 -17
  74. package/dist/page/assets/index-DUom5amc.js +0 -1
@@ -1,16 +1,16 @@
1
1
  import { spawn } from "node:child_process";
2
- import { mkdirSync, writeFileSync } from "node:fs";
2
+ import { existsSync, mkdirSync, renameSync, rmSync, writeFileSync, } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { ffmpegPath } from "./ffmpeg.js";
5
5
  import { uniformFrames } from "./sampling.js";
6
6
  /**
7
- * Pipe PNG frames into ffmpeg twice — once for H.264, once for VP9.
7
+ * Pipe PNG frames into ffmpeg twice: once for H.264, once for VP9.
8
8
  *
9
9
  * Two encoders rather than a transcode because both come from the same
10
10
  * lossless frames; transcoding the mp4 into a webm would compound artefacts
11
11
  * for no saving worth having on a ten-second clip.
12
12
  */
13
- function startEncoder(args) {
13
+ function startEncoder(args, what) {
14
14
  const child = spawn(ffmpegPath(), args, {
15
15
  stdio: ["pipe", "ignore", "pipe"],
16
16
  });
@@ -18,17 +18,32 @@ function startEncoder(args) {
18
18
  child.stderr?.on("data", (chunk) => {
19
19
  stderr += chunk.toString();
20
20
  });
21
- child.on("error", (error) => {
22
- throw new Error(`ffmpeg could not be started (${error.message}). Install it, or add ` +
23
- "the optional ffmpeg-static dependency.");
24
- });
25
- child.on("close", (code) => {
26
- if (code !== 0) {
27
- console.error(stderr.split("\n").slice(-25).join("\n"));
28
- throw new Error(`ffmpeg exited with ${code}`);
29
- }
21
+ // A write to an encoder that has exited fails with EPIPE. The write's own
22
+ // callback and `done` both report it; left unhandled here, it would crash.
23
+ child.stdin?.on("error", () => { });
24
+ const done = new Promise((resolveDone, rejectDone) => {
25
+ child.once("error", (error) => rejectDone(new Error(`ffmpeg could not be started (${error.message}). Install it, or add ` +
26
+ "the optional ffmpeg-static dependency.")));
27
+ child.once("close", (code, signal) => {
28
+ if (code === 0)
29
+ return resolveDone();
30
+ const how = signal ? `was stopped (${signal})` : `exited with ${code}`;
31
+ const tail = stderr.split("\n").slice(-25).join("\n");
32
+ rejectDone(new Error(`ffmpeg (${what}) ${how}:\n${tail}`));
33
+ });
30
34
  });
31
- return child;
35
+ // Whoever finishes the encode awaits `done`. A render stopped early only
36
+ // waits for it to settle, and must not leave it an unhandled rejection.
37
+ done.catch(() => { });
38
+ return { child, done };
39
+ }
40
+ /**
41
+ * Where `name.ext` is written until it is whole: `name.partial.ext`, the
42
+ * sequence's convention. ffmpeg picks its muxer from the extension, so the
43
+ * extension stays last.
44
+ */
45
+ function partial(file) {
46
+ return file.replace(/(\.[^./]+)$/, ".partial$1");
32
47
  }
33
48
  function mp4Args(fps, out) {
34
49
  return [
@@ -93,18 +108,30 @@ function writeAll(stream, buffer) {
93
108
  stream.once("drain", () => resolveWrite());
94
109
  });
95
110
  }
96
- function closeEncoder(child) {
97
- return new Promise((resolveClose, rejectClose) => {
98
- child.on("close", (code) => code === 0
99
- ? resolveClose()
100
- : rejectClose(new Error(`ffmpeg exited ${code}`)));
101
- child.stdin?.end();
102
- });
111
+ /**
112
+ * One frame into one encoder. An encoder that exits early fails the write
113
+ * with ffmpeg's own account of why, rather than leaving it waiting on a
114
+ * `drain` that will never come.
115
+ */
116
+ function feed(encoder, buffer) {
117
+ return Promise.race([
118
+ writeAll(encoder.child.stdin, buffer),
119
+ encoder.done.then(() => {
120
+ throw new Error("ffmpeg finished before the last frame was sent");
121
+ }),
122
+ ]);
103
123
  }
104
124
  /**
105
125
  * Walk the render page frame by frame, screenshotting each one into both
106
126
  * encoders. The page is a pure function of the frame number, so this loop can
107
127
  * be re-run, interrupted or parallelised without changing its output.
128
+ *
129
+ * Nothing the last good render left is touched until this one has finished.
130
+ * The clip, its webm and its poster are written beside them, as
131
+ * `.partial` files, and moved over them only once both encoders have
132
+ * exited cleanly. Written in place, a scene that threw at frame 30 of 60
133
+ * left a playable half-clip, and the failed run's poster, where the last
134
+ * good render had been.
108
135
  */
109
136
  export async function encodeFromPage(page, options) {
110
137
  const outDir = options.outDir;
@@ -113,21 +140,47 @@ export async function encodeFromPage(page, options) {
113
140
  const webm = join(outDir, `${options.id}.webm`);
114
141
  const poster = join(outDir, `${options.id}-poster.png`);
115
142
  const posterFrame = options.posterFrame ?? Math.floor(options.durationFrames / 3);
116
- const h264 = startEncoder(mp4Args(options.fps, mp4));
117
- const vp9 = startEncoder(webmArgs(options.fps, webm));
118
- const stage = page.locator("#stage");
119
- for (let frame = 0; frame < options.durationFrames; frame += 1) {
120
- await page.evaluate((n) => window.__render?.setFrame(n), frame);
121
- const buffer = await stage.screenshot({
122
- type: "png",
123
- animations: "disabled",
124
- });
125
- if (frame === posterFrame)
126
- writeFileSync(poster, buffer);
127
- await writeAll(h264.stdin, buffer);
128
- await writeAll(vp9.stdin, buffer);
143
+ const outputs = [mp4, webm, poster];
144
+ const encoders = [
145
+ startEncoder(mp4Args(options.fps, partial(mp4)), "H.264"),
146
+ startEncoder(webmArgs(options.fps, partial(webm)), "VP9"),
147
+ ];
148
+ try {
149
+ const stage = page.locator("#stage");
150
+ for (let frame = 0; frame < options.durationFrames; frame += 1) {
151
+ await page.evaluate((n) => window.__render?.setFrame(n), frame);
152
+ const buffer = await stage.screenshot({
153
+ type: "png",
154
+ animations: "disabled",
155
+ });
156
+ if (frame === posterFrame)
157
+ writeFileSync(partial(poster), buffer);
158
+ for (const encoder of encoders)
159
+ await feed(encoder, buffer);
160
+ }
161
+ for (const encoder of encoders)
162
+ encoder.child.stdin?.end();
163
+ await Promise.all(encoders.map((encoder) => encoder.done));
164
+ }
165
+ catch (error) {
166
+ // Both encoders are waiting for frames that will never come. Left
167
+ // running, they held the process open after the error was reported:
168
+ // `render` said what had failed and then never exited, which in CI is a
169
+ // job that hangs until it is killed.
170
+ for (const encoder of encoders) {
171
+ encoder.child.stdin?.destroy();
172
+ encoder.child.kill("SIGKILL");
173
+ }
174
+ await Promise.allSettled(encoders.map((encoder) => encoder.done));
175
+ for (const file of outputs)
176
+ rmSync(partial(file), { force: true });
177
+ throw error;
178
+ }
179
+ for (const file of outputs) {
180
+ // No poster when the poster frame is past the end: the last one stays.
181
+ if (existsSync(partial(file)))
182
+ renameSync(partial(file), file);
129
183
  }
130
- await Promise.all([closeEncoder(h264), closeEncoder(vp9)]);
131
184
  return { frames: options.durationFrames, mp4, webm, poster };
132
185
  }
133
186
  /** A strip of frames, for reviewing a clip in a pull request. */
@@ -165,19 +218,25 @@ export async function contactSheet(page, options) {
165
218
  `scale=960:-1,tile=${columns}x${rows}`,
166
219
  "-frames:v",
167
220
  "1",
168
- sheet,
221
+ partial(sheet),
169
222
  ], { stdio: ["ignore", "ignore", "pipe"] });
170
223
  let stderr = "";
171
224
  child.stderr.on("data", (c) => {
172
225
  stderr += c.toString();
173
226
  });
227
+ child.once("error", (error) => rejectSheet(new Error(`ffmpeg could not be started (${error.message})`)));
174
228
  child.on("close", (code) => {
175
229
  if (code === 0)
176
230
  resolveSheet();
177
231
  else
178
232
  rejectSheet(new Error(`contact sheet failed:\n${stderr.slice(-800)}`));
179
233
  });
234
+ }).catch((error) => {
235
+ rmSync(partial(sheet), { force: true });
236
+ throw error;
180
237
  });
238
+ // Like the clip: the last good sheet stays until this one is whole.
239
+ renameSync(partial(sheet), sheet);
181
240
  return sheet;
182
241
  }
183
242
  //# sourceMappingURL=encode.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"encode.js","sourceRoot":"","sources":["../../src/render/encode.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"encode.js","sourceRoot":"","sources":["../../src/render/encode.ts"],"names":[],"mappings":"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"}
@@ -17,3 +17,15 @@ export declare function frameAreaFor(canvas: {
17
17
  }, presentation: Presentation | null): Rect;
18
18
  /** Whether the caption sits under the app or over it. */
19
19
  export declare function captionPlacement(presentation: Presentation | null): "below" | "overlay" | "none";
20
+ /**
21
+ * Where an overlay caption's text is anchored, and which way it runs from
22
+ * there: from `x` rightwards, or leftwards to it.
23
+ *
24
+ * Measured from the video's edge rather than the app's, so the default is
25
+ * exactly where the caption sat before it could be moved, padded or not:
26
+ * 40 pixels in from the left.
27
+ */
28
+ export declare function overlayCaptionAnchor(presentation: Presentation | null, canvasWidth: number): {
29
+ x: number;
30
+ align: "left" | "right";
31
+ };
@@ -24,4 +24,19 @@ export function captionPlacement(presentation) {
24
24
  // "auto": there is only room below the app if something made room.
25
25
  return (presentation?.padding ?? 0) > 0 ? "below" : "overlay";
26
26
  }
27
+ /**
28
+ * Where an overlay caption's text is anchored, and which way it runs from
29
+ * there: from `x` rightwards, or leftwards to it.
30
+ *
31
+ * Measured from the video's edge rather than the app's, so the default is
32
+ * exactly where the caption sat before it could be moved, padded or not:
33
+ * 40 pixels in from the left.
34
+ */
35
+ export function overlayCaptionAnchor(presentation, canvasWidth) {
36
+ const inset = presentation?.captionInset;
37
+ if (inset?.right !== undefined) {
38
+ return { x: canvasWidth - inset.right, align: "right" };
39
+ }
40
+ return { x: inset?.left ?? 40, align: "left" };
41
+ }
27
42
  //# sourceMappingURL=presentation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"presentation.js","sourceRoot":"","sources":["../../src/render/presentation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIlD;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAyC,EACzC,QAA2C,EAC3C,YAAiC;IAEjC,MAAM,OAAO,GAAG,YAAY,EAAE,OAAO,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,YAAY,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;QAClC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IAC3D,CAAC;IACD,OAAO,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AACjD,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,gBAAgB,CAC9B,YAAiC;IAEjC,MAAM,IAAI,GAAG,YAAY,EAAE,OAAO,IAAI,MAAM,CAAC;IAC7C,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IACnC,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACxD,mEAAmE;IACnE,OAAO,CAAC,YAAY,EAAE,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AAChE,CAAC"}
1
+ {"version":3,"file":"presentation.js","sourceRoot":"","sources":["../../src/render/presentation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIlD;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAyC,EACzC,QAA2C,EAC3C,YAAiC;IAEjC,MAAM,OAAO,GAAG,YAAY,EAAE,OAAO,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,YAAY,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;QAClC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IAC3D,CAAC;IACD,OAAO,YAAY,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AACjD,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,gBAAgB,CAC9B,YAAiC;IAEjC,MAAM,IAAI,GAAG,YAAY,EAAE,OAAO,IAAI,MAAM,CAAC;IAC7C,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IACnC,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACxD,mEAAmE;IACnE,OAAO,CAAC,YAAY,EAAE,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AAChE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,oBAAoB,CAClC,YAAiC,EACjC,WAAmB;IAEnB,MAAM,KAAK,GAAG,YAAY,EAAE,YAAY,CAAC;IACzC,IAAI,KAAK,EAAE,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,EAAE,CAAC,EAAE,WAAW,GAAG,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAC1D,CAAC;IACD,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;AACjD,CAAC"}
@@ -5,6 +5,7 @@ import { launchBrowser } from "../driver/launch.js";
5
5
  import { renderConfigOf } from "../config.js";
6
6
  import { bundleScenes } from "../loader.js";
7
7
  import { contactSheet as encodeContactSheet, encodeFromPage, } from "./encode.js";
8
+ import { evenFrames } from "./sampling.js";
8
9
  import { distPageDir, installRenderRoutes, RENDER_ORIGIN } from "./serve.js";
9
10
  /**
10
11
  * Open the render page at the exact output size, at DPR 1.
@@ -61,6 +62,21 @@ export async function openRenderPage(browser, config, target) {
61
62
  }
62
63
  return { page, ...info };
63
64
  }
65
+ /**
66
+ * The frames a sheet shows when nobody chose them.
67
+ *
68
+ * For a recording, evenly spread and moved past the renderer's dissolves,
69
+ * which only the recording's own cuts can say where they are. Read from its
70
+ * directory rather than by id, since a target can be a recording anywhere. A
71
+ * scene draws every frame itself and never dissolves, so its sheet is the
72
+ * plain even spread the encoder falls back on.
73
+ */
74
+ async function sheetFrames(config, target, durationFrames) {
75
+ if (target.kind !== "recording")
76
+ return undefined;
77
+ const timeline = JSON.parse(await readFile(join(target.dir, "timeline.json"), "utf8"));
78
+ return evenFrames(durationFrames, undefined, config.motion.crossfadeFrames, timeline.cuts);
79
+ }
64
80
  async function renderTarget(browser, config, target) {
65
81
  const { page, durationFrames, fps } = await openRenderPage(browser, config, target);
66
82
  try {
@@ -73,6 +89,7 @@ async function renderTarget(browser, config, target) {
73
89
  const sheet = await encodeContactSheet(page, {
74
90
  id: target.id,
75
91
  durationFrames,
92
+ frames: await sheetFrames(config, target, durationFrames),
76
93
  outDir: config.outputDir,
77
94
  });
78
95
  return { ...encoded, id: target.id, durationFrames, fps, sheet };
@@ -97,7 +114,7 @@ export async function contactSheet(browser, config, target, options = {}) {
97
114
  return await encodeContactSheet(page, {
98
115
  id: target.id,
99
116
  durationFrames,
100
- frames: options.frames,
117
+ frames: options.frames ?? (await sheetFrames(config, target, durationFrames)),
101
118
  outDir: config.outputDir,
102
119
  });
103
120
  }
@@ -1 +1 @@
1
- {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/render/render.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/render/render.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,19 @@ import type { Mark } from "../core/timeline.js";
8
8
  export declare const SHEET_TILES = 8;
9
9
  /** Evenly spaced, ends included: the shape of the clip, knowing nothing about it. */
10
10
  export declare function uniformFrames(durationFrames: number, count?: number): number[];
11
+ /**
12
+ * Evenly spaced, ends included, and none of them inside a dissolve: the
13
+ * frames a sheet shows when nobody chose them.
14
+ *
15
+ * An even spread knows nothing about the clip, so it lands wherever the
16
+ * spacing puts it, and after a settle that can be the renderer's crossfade: a
17
+ * plain sheet of the example app showed two tiles with one page ghosting
18
+ * through the next, which `--at-marks` had stopped doing for its own tiles
19
+ * long before. A tile inside a dissolve moves to the first frame after it.
20
+ * The first frame is never inside one, the last stays the last, and two
21
+ * tiles that land on the same frame are one.
22
+ */
23
+ export declare function evenFrames(durationFrames: number, count?: number, crossfadeFrames?: number, cuts?: readonly number[]): number[];
11
24
  /**
12
25
  * Frame 0, every beat, and the last frame.
13
26
  *
@@ -10,6 +10,44 @@ export function uniformFrames(durationFrames, count = SHEET_TILES) {
10
10
  const tiles = Math.max(2, Math.min(count, durationFrames));
11
11
  return Array.from({ length: tiles }, (_, i) => Math.round((i / (tiles - 1)) * (durationFrames - 1)));
12
12
  }
13
+ /**
14
+ * The first frame at or after `frame` that is not inside a dissolve.
15
+ *
16
+ * The renderer dissolves between states for `crossfadeFrames` after every
17
+ * cut, and a tile taken inside that window is two pages at once. A reviewer
18
+ * shown one said so and declined to judge the beat from it, which is the
19
+ * right answer to a question that should not have been asked.
20
+ *
21
+ * Two settles a few frames apart overlap their dissolves, and the first frame
22
+ * after one can be inside the next, so the frame moves on until it is clear
23
+ * of all of them. Never past the last frame, which has nothing after it.
24
+ */
25
+ function pastCrossfade(frame, durationFrames, crossfadeFrames, cuts) {
26
+ let clear = frame;
27
+ for (;;) {
28
+ const cut = cuts.find((c) => clear > c && clear <= c + crossfadeFrames);
29
+ if (cut === undefined)
30
+ break;
31
+ clear = cut + crossfadeFrames + 1;
32
+ }
33
+ return Math.min(clear, durationFrames - 1);
34
+ }
35
+ /**
36
+ * Evenly spaced, ends included, and none of them inside a dissolve: the
37
+ * frames a sheet shows when nobody chose them.
38
+ *
39
+ * An even spread knows nothing about the clip, so it lands wherever the
40
+ * spacing puts it, and after a settle that can be the renderer's crossfade: a
41
+ * plain sheet of the example app showed two tiles with one page ghosting
42
+ * through the next, which `--at-marks` had stopped doing for its own tiles
43
+ * long before. A tile inside a dissolve moves to the first frame after it.
44
+ * The first frame is never inside one, the last stays the last, and two
45
+ * tiles that land on the same frame are one.
46
+ */
47
+ export function evenFrames(durationFrames, count = SHEET_TILES, crossfadeFrames = 0, cuts = []) {
48
+ const tiles = uniformFrames(durationFrames, count).map((frame) => pastCrossfade(frame, durationFrames, crossfadeFrames, cuts));
49
+ return [...new Set(tiles)].sort((a, b) => a - b);
50
+ }
13
51
  /**
14
52
  * Frame 0, every beat, and the last frame.
15
53
  *
@@ -23,23 +61,13 @@ export function uniformFrames(durationFrames, count = SHEET_TILES) {
23
61
  */
24
62
  export function markedFrames(durationFrames, marks, count = SHEET_TILES, crossfadeFrames = 0, cuts = []) {
25
63
  const inRange = (frame) => Number.isInteger(frame) && frame >= 0 && frame < durationFrames;
26
- // Past the crossfade, wherever a frame would land inside one.
27
- //
28
- // The renderer dissolves between states for `crossfadeFrames` after every
29
- // cut, and a tile taken inside that window is two pages at once. A reviewer
30
- // shown one said so and declined to judge the beat from it, which is the
31
- // right answer to a question that should not have been asked.
32
- //
33
- // A mark is the worst case — it sits on the cut's first frame, where the
34
- // blend has barely begun and the tile still shows what was on screen
35
- // *before* the wait — but any evenly spread tile can land there too. Marks
36
- // stay where they are, because `review` wants the state boundary; only the
37
- // picture waits for the dissolve to finish.
38
- const settled = (frame) => {
39
- const cut = cuts.find((c) => frame > c && frame <= c + crossfadeFrames);
40
- const clear = cut === undefined ? frame : cut + crossfadeFrames + 1;
41
- return Math.min(clear, durationFrames - 1);
42
- };
64
+ // A mark is the worst case of a tile inside a dissolve: it sits on the
65
+ // cut's first frame, where the blend has barely begun and the tile still
66
+ // shows what was on screen *before* the wait. `beatFrame` moves its tile
67
+ // past the dissolve that starts there; the marks themselves stay where
68
+ // they are, because `review` wants the state boundary. The spare tiles
69
+ // below come from `evenFrames`, which moves them past any dissolve they
70
+ // land in.
43
71
  const wanted = [
44
72
  0,
45
73
  ...marks.map((m) => beatFrame(m, durationFrames, crossfadeFrames)),
@@ -55,10 +83,10 @@ export function markedFrames(durationFrames, marks, count = SHEET_TILES, crossfa
55
83
  // the shape of the clip around them.
56
84
  if (unique.length < count) {
57
85
  const filled = new Set(unique);
58
- for (const frame of uniformFrames(durationFrames, count)) {
86
+ for (const frame of evenFrames(durationFrames, count, crossfadeFrames, cuts)) {
59
87
  if (filled.size >= count)
60
88
  break;
61
- filled.add(settled(frame));
89
+ filled.add(frame);
62
90
  }
63
91
  return [...filled].sort((a, b) => a - b);
64
92
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sampling.js","sourceRoot":"","sources":["../../src/render/sampling.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sampling.js","sourceRoot":"","sources":["../../src/render/sampling.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { Scene } from "../scene.js";
2
+ /**
3
+ * The scenes a module defines, by id, or why there are none to read.
4
+ *
5
+ * `file` names the module in the message: its path, wherever the path is
6
+ * known. The message is three lines at most (what is wrong, the shape, and
7
+ * the one-line fix when there is an obvious one), so `doctor` can print the
8
+ * first as its finding and the rest beneath it.
9
+ */
10
+ export declare function readScenes(module: Record<string, unknown>, file: string): {
11
+ scenes: Record<string, Scene>;
12
+ } | {
13
+ error: string;
14
+ };
15
+ /** What to say when scenes are asked for that the module does not define. */
16
+ export declare function missingScenes(asked: string[], defined: string[], file: string | null): string;
@@ -0,0 +1,108 @@
1
+ /**
2
+ * What a scenes module has to export, checked the same way wherever one is
3
+ * read: in Node, where the CLI lists the ids to render and filter, and in the
4
+ * render page, which draws them.
5
+ *
6
+ * Both used to take `module.default` and carry on with whatever it was. A
7
+ * module whose record of scenes was a named export gave them nothing at all:
8
+ * `render` found no scenes, said nothing, and stitched a film without them.
9
+ * Anything that is not a record of scenes now stops the command, naming the
10
+ * file and the shape it should have.
11
+ *
12
+ * A record with nothing in it is still a record, and renders no scenes, which
13
+ * is what it says.
14
+ */
15
+ /** The shape, as the second line of every refusal. */
16
+ const SHAPE = "versioncam reads scenes from a module's default export: a Record<string, Scene> " +
17
+ "keyed by scene id, as in `export default { [intro.id]: intro }`.";
18
+ /** For anything but a plain object, which is never what is being described. */
19
+ function describe(value) {
20
+ if (value === null || value === undefined)
21
+ return String(value);
22
+ if (Array.isArray(value))
23
+ return "an array";
24
+ return `a ${typeof value}`;
25
+ }
26
+ /** A value as it was written, so `"60"` does not read as the number 60. */
27
+ function shown(value) {
28
+ return typeof value === "string" ? JSON.stringify(value) : String(value);
29
+ }
30
+ function isPlainObject(value) {
31
+ return value !== null && typeof value === "object" && !Array.isArray(value);
32
+ }
33
+ /** What is wrong with one entry, or null when it can be drawn. */
34
+ function entryProblem(key, value) {
35
+ if (!isPlainObject(value))
36
+ return `"${key}" is ${describe(value)}, not a scene`;
37
+ const { draw, durationFrames, fps } = value;
38
+ if (typeof draw !== "function") {
39
+ return `"${key}" has no draw(ctx, frame, canvas)`;
40
+ }
41
+ if (!Number.isInteger(durationFrames) || durationFrames < 1) {
42
+ return `"${key}" has durationFrames ${shown(durationFrames)}, where a whole number of frames, 1 or more, belongs`;
43
+ }
44
+ if (typeof fps !== "number" || !Number.isFinite(fps) || fps <= 0) {
45
+ return `"${key}" has fps ${shown(fps)}, where a number above 0 belongs`;
46
+ }
47
+ return null;
48
+ }
49
+ /**
50
+ * What is wrong with a would-be record of scenes, as the end of a sentence
51
+ * that starts "default-exports", or null when nothing is.
52
+ *
53
+ * A single scene and an array are singled out because they are the two
54
+ * mistakes a clip file invites: a clip file default-exports one clip or an
55
+ * array of them, and a scenes module does neither.
56
+ */
57
+ function recordProblem(value) {
58
+ if (!isPlainObject(value))
59
+ return describe(value);
60
+ if (typeof value.draw === "function") {
61
+ return "a single scene rather than a record of them";
62
+ }
63
+ for (const [key, entry] of Object.entries(value)) {
64
+ const problem = entryProblem(key, entry);
65
+ if (problem)
66
+ return `a record in which ${problem}`;
67
+ }
68
+ return null;
69
+ }
70
+ /**
71
+ * The scenes a module defines, by id, or why there are none to read.
72
+ *
73
+ * `file` names the module in the message: its path, wherever the path is
74
+ * known. The message is three lines at most (what is wrong, the shape, and
75
+ * the one-line fix when there is an obvious one), so `doctor` can print the
76
+ * first as its finding and the rest beneath it.
77
+ */
78
+ export function readScenes(module, file) {
79
+ if (module.default === undefined) {
80
+ const named = Object.keys(module).filter((name) => name !== "default");
81
+ const lines = [
82
+ `${file} has no default export.` +
83
+ (named.length > 0 ? ` It exports ${named.join(", ")}.` : ""),
84
+ SHAPE,
85
+ ];
86
+ // The failure that made this check: the record was there, under a name.
87
+ const records = named.filter((name) => recordProblem(module[name]) === null &&
88
+ Object.keys(module[name]).length > 0);
89
+ if (records.length === 1) {
90
+ lines.push(`${records[0]} is one: add \`export default ${records[0]}\`.`);
91
+ }
92
+ return { error: lines.join("\n") };
93
+ }
94
+ const problem = recordProblem(module.default);
95
+ if (problem) {
96
+ return { error: `${file} default-exports ${problem}.\n${SHAPE}` };
97
+ }
98
+ return { scenes: module.default };
99
+ }
100
+ /** What to say when scenes are asked for that the module does not define. */
101
+ export function missingScenes(asked, defined, file) {
102
+ const names = asked.map((id) => `"${id}"`).join(", ");
103
+ const head = `No scene${asked.length === 1 ? "" : "s"} called ${names}.`;
104
+ if (file === null)
105
+ return `${head} The config names no \`scenes\` module.`;
106
+ return `${head} ${file} defines ${defined.length > 0 ? defined.join(", ") : "none"}.`;
107
+ }
108
+ //# sourceMappingURL=scenes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scenes.js","sourceRoot":"","sources":["../../src/render/scenes.ts"],"names":[],"mappings":"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"}