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.
- package/CHANGELOG.md +124 -0
- package/README.md +116 -13
- package/dist/cli/commands/doctor.js +39 -2
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/init.js +25 -0
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/preview.js +10 -1
- package/dist/cli/commands/preview.js.map +1 -1
- package/dist/cli/commands/render.d.ts +17 -0
- package/dist/cli/commands/render.js +78 -21
- package/dist/cli/commands/render.js.map +1 -1
- package/dist/cli/cwd.d.ts +46 -0
- package/dist/cli/cwd.js +102 -0
- package/dist/cli/cwd.js.map +1 -0
- package/dist/cli/main.js +11 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/usage.d.ts +3 -2
- package/dist/cli/usage.js +9 -4
- package/dist/cli/usage.js.map +1 -1
- package/dist/config.d.ts +24 -0
- package/dist/config.js +25 -0
- package/dist/config.js.map +1 -1
- package/dist/core/camera-track.d.ts +63 -0
- package/dist/core/camera-track.js +230 -0
- package/dist/core/camera-track.js.map +1 -0
- package/dist/core/camera.d.ts +14 -1
- package/dist/core/camera.js +18 -2
- package/dist/core/camera.js.map +1 -1
- package/dist/core/follow.d.ts +129 -0
- package/dist/core/follow.js +151 -0
- package/dist/core/follow.js.map +1 -0
- package/dist/core/motion-defaults.d.ts +29 -0
- package/dist/core/motion-defaults.js +29 -0
- package/dist/core/motion-defaults.js.map +1 -1
- package/dist/core/timeline.d.ts +10 -2
- package/dist/core/timeline.js.map +1 -1
- package/dist/driver/session.d.ts +22 -1
- package/dist/driver/session.js +48 -12
- package/dist/driver/session.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +7 -1
- package/dist/loader.js +23 -8
- package/dist/loader.js.map +1 -1
- package/dist/page/assets/index-fZtacWyp.js +2 -0
- package/dist/page/index.html +1 -1
- package/dist/render/encode.d.ts +12 -1
- package/dist/render/encode.js +94 -35
- package/dist/render/encode.js.map +1 -1
- package/dist/render/presentation.d.ts +12 -0
- package/dist/render/presentation.js +15 -0
- package/dist/render/presentation.js.map +1 -1
- package/dist/render/render.js +18 -1
- package/dist/render/render.js.map +1 -1
- package/dist/render/sampling.d.ts +13 -0
- package/dist/render/sampling.js +47 -19
- package/dist/render/sampling.js.map +1 -1
- package/dist/render/scenes.d.ts +16 -0
- package/dist/render/scenes.js +108 -0
- package/dist/render/scenes.js.map +1 -0
- package/dist/render/sequence.d.ts +18 -0
- package/dist/render/sequence.js +67 -13
- package/dist/render/sequence.js.map +1 -1
- package/dist/review/review.js +46 -21
- package/dist/review/review.js.map +1 -1
- package/dsl.md +37 -0
- package/package.json +1 -1
- package/plugin/README.md +7 -2
- package/plugin/agents/versioncam-reviewer.md +3 -2
- package/plugin/skills/versioncam/SKILL.md +60 -14
- package/plugin/skills/versioncam/authoring.md +6 -1
- package/plugin/skills/versioncam/onboarding.md +17 -17
- package/dist/page/assets/index-DUom5amc.js +0 -1
|
@@ -4,18 +4,40 @@ import { join } from "node:path";
|
|
|
4
4
|
import { launchBrowser } from "../../driver/launch.js";
|
|
5
5
|
import { loadConfig, loadSceneIds } from "../../loader.js";
|
|
6
6
|
import { renderRecording, renderScene } from "../../render/render.js";
|
|
7
|
+
import { missingScenes } from "../../render/scenes.js";
|
|
7
8
|
import { buildSequence } from "../../render/sequence.js";
|
|
8
|
-
/**
|
|
9
|
-
function recordedIds(recordingsDir
|
|
9
|
+
/** Every recording on disk, by id. */
|
|
10
|
+
function recordedIds(recordingsDir) {
|
|
10
11
|
if (!existsSync(recordingsDir))
|
|
11
12
|
return [];
|
|
12
13
|
return readdirSync(recordingsDir, { withFileTypes: true })
|
|
13
14
|
.filter((e) => e.isDirectory())
|
|
14
15
|
.map((e) => e.name)
|
|
15
16
|
.filter((id) => existsSync(join(recordingsDir, id, "timeline.json")))
|
|
16
|
-
.filter((id) => only.length === 0 || only.some((n) => id.includes(n)))
|
|
17
17
|
.sort();
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* What `render` renders, from what there is and what was asked for.
|
|
21
|
+
*
|
|
22
|
+
* Ids are substrings, as everywhere else (`render 05` is the clip with 05 in
|
|
23
|
+
* its id), and they choose among the recordings and the scenes alike. A
|
|
24
|
+
* `--scene` names one scene exactly, and it renders whatever the ids say: it
|
|
25
|
+
* used to be filtered by them as well, so `render 02 04 --scene 01-intro`
|
|
26
|
+
* rendered no scene at all. With no ids, every recording on disk renders,
|
|
27
|
+
* and every scene unless `--scene` named the ones wanted.
|
|
28
|
+
*
|
|
29
|
+
* `unmatched` is the ids that choose nothing.
|
|
30
|
+
*/
|
|
31
|
+
export function chooseTargets(recorded, defined, ids, named) {
|
|
32
|
+
const matches = (id) => ids.some((n) => id.includes(n));
|
|
33
|
+
return {
|
|
34
|
+
recordings: ids.length > 0 ? recorded.filter(matches) : recorded,
|
|
35
|
+
scenes: defined.filter((id) => named.includes(id) ||
|
|
36
|
+
(ids.length > 0 ? matches(id) : named.length === 0)),
|
|
37
|
+
unmatched: ids.filter((n) => !recorded.some((id) => id.includes(n)) &&
|
|
38
|
+
!defined.some((id) => id.includes(n))),
|
|
39
|
+
};
|
|
40
|
+
}
|
|
19
41
|
export async function render(argv) {
|
|
20
42
|
const { positionals, values } = parseArgs({
|
|
21
43
|
args: argv,
|
|
@@ -27,13 +49,34 @@ export async function render(argv) {
|
|
|
27
49
|
allowPositionals: true,
|
|
28
50
|
});
|
|
29
51
|
const config = await loadConfig(process.cwd());
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
//
|
|
33
|
-
//
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
52
|
+
const ids = positionals;
|
|
53
|
+
const named = values.scene ?? [];
|
|
54
|
+
// Everything asked for is checked before anything renders. A render takes
|
|
55
|
+
// minutes, and the output of one missing a clip looks finished: a film
|
|
56
|
+
// stitched from four clips of six says nothing about the other two.
|
|
57
|
+
const defined = await loadSceneIds(config);
|
|
58
|
+
const unknown = named.filter((id) => !defined.includes(id));
|
|
59
|
+
if (unknown.length > 0) {
|
|
60
|
+
process.stderr.write(`${missingScenes(unknown, defined, config.scenes)}\n`);
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
const recorded = recordedIds(config.recordingsDir);
|
|
64
|
+
const { recordings, scenes, unmatched } = chooseTargets(recorded, defined, ids, named);
|
|
65
|
+
// An id that chooses nothing is a typo, or a clip not recorded yet.
|
|
66
|
+
if (unmatched.length > 0) {
|
|
67
|
+
for (const id of unmatched) {
|
|
68
|
+
process.stderr.write(`No recording or scene has "${id}" in its id.\n`);
|
|
69
|
+
}
|
|
70
|
+
process.stderr.write(`Recorded, in ${config.recordingsDir}: ` +
|
|
71
|
+
(recorded.length > 0
|
|
72
|
+
? `${recorded.join(", ")}.\n`
|
|
73
|
+
: "nothing yet. Run `versioncam record` first.\n"));
|
|
74
|
+
if (config.scenes) {
|
|
75
|
+
process.stderr.write(`Scenes, in ${config.scenes}: ${defined.join(", ") || "none"}.\n`);
|
|
76
|
+
}
|
|
77
|
+
return 1;
|
|
78
|
+
}
|
|
79
|
+
if (recordings.length === 0 && scenes.length === 0) {
|
|
37
80
|
process.stderr.write(`Nothing to render. Run \`versioncam record\` first; recordings live in ${config.recordingsDir}.\n`);
|
|
38
81
|
return 1;
|
|
39
82
|
}
|
|
@@ -52,9 +95,7 @@ export async function render(argv) {
|
|
|
52
95
|
failures.push({ id, error: error });
|
|
53
96
|
}
|
|
54
97
|
}
|
|
55
|
-
for (const id of
|
|
56
|
-
if (only.length > 0 && !only.some((n) => id.includes(n)))
|
|
57
|
-
continue;
|
|
98
|
+
for (const id of scenes) {
|
|
58
99
|
try {
|
|
59
100
|
const out = await renderScene(browser, config, id);
|
|
60
101
|
rendered.push(id);
|
|
@@ -68,18 +109,34 @@ export async function render(argv) {
|
|
|
68
109
|
finally {
|
|
69
110
|
await browser.close();
|
|
70
111
|
}
|
|
71
|
-
if (values.sequence
|
|
112
|
+
if (values.sequence) {
|
|
72
113
|
// The config's order when it states one, since a sequence is an argument
|
|
73
114
|
// and not an accident of how the directory happens to sort.
|
|
74
115
|
const order = config.sequence ?? rendered;
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
if (
|
|
78
|
-
|
|
116
|
+
const stitched = order.filter((id) => rendered.includes(id));
|
|
117
|
+
let unusable = [];
|
|
118
|
+
if (stitched.length >= 2) {
|
|
119
|
+
const result = await buildSequence(stitched, config.outputDir);
|
|
120
|
+
unusable = result.missing;
|
|
121
|
+
process.stdout.write(` sequence: ${result.used.length} clips, ${result.total.toFixed(1)}s\n`);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
process.stderr.write(" sequence needs at least two rendered clips.\n");
|
|
125
|
+
}
|
|
126
|
+
// What the piece was stitched without, as plainly as what it was
|
|
127
|
+
// stitched from: four clips of six look finished. The config's sequence
|
|
128
|
+
// says what belongs in it, and a run can render less than that, or more.
|
|
129
|
+
const absent = [
|
|
130
|
+
...order.filter((id) => !rendered.includes(id)),
|
|
131
|
+
...unusable,
|
|
132
|
+
];
|
|
133
|
+
if (absent.length > 0) {
|
|
134
|
+
process.stdout.write(` (not rendered: ${absent.join(", ")})\n`);
|
|
135
|
+
}
|
|
136
|
+
const unlisted = rendered.filter((id) => !order.includes(id));
|
|
137
|
+
if (unlisted.length > 0) {
|
|
138
|
+
process.stdout.write(` (not in the config's sequence: ${unlisted.join(", ")})\n`);
|
|
79
139
|
}
|
|
80
|
-
}
|
|
81
|
-
else if (values.sequence) {
|
|
82
|
-
process.stderr.write(" sequence needs at least two rendered clips.\n");
|
|
83
140
|
}
|
|
84
141
|
if (failures.length > 0) {
|
|
85
142
|
process.stderr.write("\n");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/cli/commands/render.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEzD,
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/cli/commands/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `--cwd <dir>`: run a command as if from `<dir>`.
|
|
3
|
+
*
|
|
4
|
+
* Every command works in the directory that holds `versioncam.config.ts`:
|
|
5
|
+
* the config, `.env.recording` and `.env`, `.versioncam/`, and any relative
|
|
6
|
+
* path a command is given or prints are that directory's. In a monorepo the
|
|
7
|
+
* app is one directory among many, and whatever runs versioncam may be
|
|
8
|
+
* somewhere else: a script at the repository root, or an agent whose session
|
|
9
|
+
* started inside the app, below its config, and which may not `cd` out of
|
|
10
|
+
* the directory it started in.
|
|
11
|
+
*
|
|
12
|
+
* Its own module so a test can reach it without running the CLI.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* `--cwd <dir>` or `--cwd=<dir>`, taken out of the arguments, from anywhere
|
|
16
|
+
* among them. If it is given twice, the last one counts.
|
|
17
|
+
*
|
|
18
|
+
* Anywhere, not only before the command's name, because what an agent may
|
|
19
|
+
* run is a prefix: the reviewer is allowed `npx versioncam frame *` and
|
|
20
|
+
* nothing else, so its flag has to be able to come after `frame`.
|
|
21
|
+
*/
|
|
22
|
+
export declare function takeCwd(argv: string[]): {
|
|
23
|
+
cwd: string | undefined;
|
|
24
|
+
rest: string[];
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* The versioncam a config in `dir` imports: the first `node_modules/versioncam`
|
|
28
|
+
* from `dir` up, which is where Node looks for a bare `import "versioncam"`.
|
|
29
|
+
* Null where there is none.
|
|
30
|
+
*
|
|
31
|
+
* Resolved through symlinks, so an `npm link` or a pnpm store compares as
|
|
32
|
+
* the directory it really is.
|
|
33
|
+
*/
|
|
34
|
+
export declare function versioncamFrom(dir: string): string | null;
|
|
35
|
+
/**
|
|
36
|
+
* Move into `dir` for the rest of the command, or say why not.
|
|
37
|
+
*
|
|
38
|
+
* Only the directory moves, though, and not the versioncam running: `npx`
|
|
39
|
+
* finds the binary in the directory it runs in and in those above it, never
|
|
40
|
+
* below. Run from above an app that has versioncam in its own
|
|
41
|
+
* `node_modules`, it runs another copy, or downloads the latest one, and that
|
|
42
|
+
* copy would record with a Chromium the app never pinned, beside a config
|
|
43
|
+
* that imports the app's own. So a directory whose own versioncam is not the
|
|
44
|
+
* one running is refused, with how to run its own.
|
|
45
|
+
*/
|
|
46
|
+
export declare function enterCwd(dir: string): void;
|
package/dist/cli/cwd.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { existsSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
2
|
+
import { dirname, join, relative, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
/**
|
|
5
|
+
* `--cwd <dir>`: run a command as if from `<dir>`.
|
|
6
|
+
*
|
|
7
|
+
* Every command works in the directory that holds `versioncam.config.ts`:
|
|
8
|
+
* the config, `.env.recording` and `.env`, `.versioncam/`, and any relative
|
|
9
|
+
* path a command is given or prints are that directory's. In a monorepo the
|
|
10
|
+
* app is one directory among many, and whatever runs versioncam may be
|
|
11
|
+
* somewhere else: a script at the repository root, or an agent whose session
|
|
12
|
+
* started inside the app, below its config, and which may not `cd` out of
|
|
13
|
+
* the directory it started in.
|
|
14
|
+
*
|
|
15
|
+
* Its own module so a test can reach it without running the CLI.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* `--cwd <dir>` or `--cwd=<dir>`, taken out of the arguments, from anywhere
|
|
19
|
+
* among them. If it is given twice, the last one counts.
|
|
20
|
+
*
|
|
21
|
+
* Anywhere, not only before the command's name, because what an agent may
|
|
22
|
+
* run is a prefix: the reviewer is allowed `npx versioncam frame *` and
|
|
23
|
+
* nothing else, so its flag has to be able to come after `frame`.
|
|
24
|
+
*/
|
|
25
|
+
export function takeCwd(argv) {
|
|
26
|
+
let cwd;
|
|
27
|
+
const rest = [];
|
|
28
|
+
for (let i = 0; i < argv.length; i++) {
|
|
29
|
+
const arg = argv[i];
|
|
30
|
+
if (arg !== "--cwd" && !arg.startsWith("--cwd=")) {
|
|
31
|
+
rest.push(arg);
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const value = arg === "--cwd" ? argv[++i] : arg.slice("--cwd=".length);
|
|
35
|
+
// A flag where the directory should be is a directory left out, not a
|
|
36
|
+
// directory called `--draft`.
|
|
37
|
+
if (!value || value.startsWith("-")) {
|
|
38
|
+
throw new Error("`--cwd` needs a directory: versioncam <command> --cwd <dir>");
|
|
39
|
+
}
|
|
40
|
+
cwd = value;
|
|
41
|
+
}
|
|
42
|
+
return { cwd, rest };
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The versioncam a config in `dir` imports: the first `node_modules/versioncam`
|
|
46
|
+
* from `dir` up, which is where Node looks for a bare `import "versioncam"`.
|
|
47
|
+
* Null where there is none.
|
|
48
|
+
*
|
|
49
|
+
* Resolved through symlinks, so an `npm link` or a pnpm store compares as
|
|
50
|
+
* the directory it really is.
|
|
51
|
+
*/
|
|
52
|
+
export function versioncamFrom(dir) {
|
|
53
|
+
for (let at = resolve(dir);; at = dirname(at)) {
|
|
54
|
+
const candidate = join(at, "node_modules", "versioncam");
|
|
55
|
+
if (existsSync(join(candidate, "package.json"))) {
|
|
56
|
+
return realpathSync(candidate);
|
|
57
|
+
}
|
|
58
|
+
if (dirname(at) === at)
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** This package, where it really is: two levels above this file. */
|
|
63
|
+
const RUNNING = realpathSync(resolve(dirname(fileURLToPath(import.meta.url)), "..", ".."));
|
|
64
|
+
/** "versioncam 0.1.3 in <dir>", without the version if it cannot be read. */
|
|
65
|
+
function nameOf(pkg) {
|
|
66
|
+
try {
|
|
67
|
+
const { version } = JSON.parse(readFileSync(join(pkg, "package.json"), "utf8"));
|
|
68
|
+
if (version)
|
|
69
|
+
return `versioncam ${version} in ${pkg}`;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Named by its directory alone, which is the part that matters.
|
|
73
|
+
}
|
|
74
|
+
return `versioncam in ${pkg}`;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Move into `dir` for the rest of the command, or say why not.
|
|
78
|
+
*
|
|
79
|
+
* Only the directory moves, though, and not the versioncam running: `npx`
|
|
80
|
+
* finds the binary in the directory it runs in and in those above it, never
|
|
81
|
+
* below. Run from above an app that has versioncam in its own
|
|
82
|
+
* `node_modules`, it runs another copy, or downloads the latest one, and that
|
|
83
|
+
* copy would record with a Chromium the app never pinned, beside a config
|
|
84
|
+
* that imports the app's own. So a directory whose own versioncam is not the
|
|
85
|
+
* one running is refused, with how to run its own.
|
|
86
|
+
*/
|
|
87
|
+
export function enterCwd(dir) {
|
|
88
|
+
const target = resolve(dir);
|
|
89
|
+
if (!existsSync(target) || !statSync(target).isDirectory()) {
|
|
90
|
+
throw new Error(`\`--cwd ${dir}\`: there is no directory ${target}.`);
|
|
91
|
+
}
|
|
92
|
+
const theirs = versioncamFrom(target);
|
|
93
|
+
if (theirs !== null && theirs !== RUNNING) {
|
|
94
|
+
const shown = relative(process.cwd(), target) || ".";
|
|
95
|
+
throw new Error(`\`--cwd ${dir}\`: that directory has its own ${nameOf(theirs)}, ` +
|
|
96
|
+
`and this is ${nameOf(RUNNING)}.\n` +
|
|
97
|
+
"npx looks for versioncam in the directory it runs in and in those above it, never below.\n" +
|
|
98
|
+
`Run the directory's own instead: cd ${shown}, then the same command without --cwd.`);
|
|
99
|
+
}
|
|
100
|
+
process.chdir(target);
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=cwd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cwd.js","sourceRoot":"","sources":["../../src/cli/cwd.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/main.js
CHANGED
|
@@ -16,6 +16,7 @@ import { review } from "./commands/review.js";
|
|
|
16
16
|
import { sheet } from "./commands/sheet.js";
|
|
17
17
|
import { stability } from "./commands/stability.js";
|
|
18
18
|
import { loadEnvFiles } from "../env.js";
|
|
19
|
+
import { enterCwd, takeCwd } from "./cwd.js";
|
|
19
20
|
import { USAGE } from "./usage.js";
|
|
20
21
|
const COMMANDS = {
|
|
21
22
|
record,
|
|
@@ -35,7 +36,9 @@ const COMMANDS = {
|
|
|
35
36
|
init,
|
|
36
37
|
};
|
|
37
38
|
async function main() {
|
|
38
|
-
|
|
39
|
+
// `--cwd` comes out first: it takes a value, which the parsing below would
|
|
40
|
+
// otherwise read as the command's name.
|
|
41
|
+
const { cwd, rest: argv } = takeCwd(process.argv.slice(2));
|
|
39
42
|
// `--help` is a flag, not a positional, so it never reaches `positionals`.
|
|
40
43
|
// Asking for help is a success; being given nothing is not.
|
|
41
44
|
if (argv.some((a) => a === "--help" || a === "-h" || a === "help")) {
|
|
@@ -57,8 +60,14 @@ async function main() {
|
|
|
57
60
|
process.stderr.write(`Unknown command "${name}".\n\n${USAGE}`);
|
|
58
61
|
return 1;
|
|
59
62
|
}
|
|
63
|
+
// Before the environment files, which are that directory's too.
|
|
64
|
+
if (cwd !== undefined)
|
|
65
|
+
enterCwd(cwd);
|
|
60
66
|
loadEnvFiles(process.cwd());
|
|
61
|
-
|
|
67
|
+
// The command's own arguments: everything but its name, wherever the name
|
|
68
|
+
// was, which is first unless a flag came before it.
|
|
69
|
+
const at = argv.indexOf(name);
|
|
70
|
+
return command([...argv.slice(0, at), ...argv.slice(at + 1)]);
|
|
62
71
|
}
|
|
63
72
|
main().then((code) => {
|
|
64
73
|
process.exitCode = code;
|
package/dist/cli/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAInC,MAAM,QAAQ,GAA4B;IACxC,MAAM;IACN,MAAM;IACN,KAAK;IACL,SAAS;IACT,KAAK;IACL,KAAK;IACL,OAAO;IACP,MAAM;IACN,OAAO;IACP,OAAO;IACP,GAAG;IACH,KAAK;IACL,MAAM;IACN,OAAO;IACP,IAAI;CACL,CAAC;AAEF,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/usage.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Grouped by the stage of the work each command belongs to, in the order a
|
|
11
11
|
* repository meets them. A flat list of seventeen commands left a newcomer to
|
|
12
|
-
* work out that `inspect` comes before `record` and `sheet` after it.
|
|
12
|
+
* work out that `inspect` comes before `record` and `sheet` after it. The
|
|
13
|
+
* last group is not a stage but a way to run any of them.
|
|
13
14
|
*/
|
|
14
|
-
export declare const USAGE = "versioncam: record and render demo clips of a real app\n\nSet up\n versioncam install the Chromium this version of versioncam records with\n --with-deps and its system libraries (Linux CI)\n versioncam init install the authoring skill into .claude/\n --into <dir> into <dir>/versioncam/ instead, for another host\n --force overwrite files that are already there\n versioncam doctor check this machine can record, and that the app starts\n versioncam login sign in once and save the browser session\n\nWrite\n versioncam inspect <path> what a clip can click, and where each name came from\n --json machine-readable\n versioncam measure <path> <sel> where a selector's matches are, and what they say\n versioncam dsl the clip DSL: every method, its options and defaults\n\nRecord\n versioncam record [id\u2026] drive the app and capture frames\n --draft 15fps at CSS scale: cheap, for writing clips\n versioncam check [id\u2026] record every clip; exit 1 if any breaks\n versioncam stability [id\u2026] record each clip twice the same way; stable or not\n --runs <n> how many times (default 2)\n --full at full quality rather than draft\n\nReview\n versioncam sheet <id> an eight-frame contact sheet\n --at-marks sample the beats instead of even spacing\n versioncam frame <id> <n> one frame at output size, to a png\n --t <seconds> pick the frame by time instead\n --at <label> or by the beat it shows\n versioncam review <id> the checks that need no eyes; PASS/FAIL, exit 0/1\n --beats <file> [{ label, expect }] the clip promised\n --min <s> --max <s> duration bounds (default 9 and 11)\n versioncam preview <id> open the scrubber in a real browser\n --scene <id> preview a scene instead\n --frame <n> start at this frame\n\nOutput\n versioncam render [id\u2026] composite and encode
|
|
15
|
+
export declare const USAGE = "versioncam: record and render demo clips of a real app\n\nSet up\n versioncam install the Chromium this version of versioncam records with\n --with-deps and its system libraries (Linux CI)\n versioncam init install the authoring skill into .claude/\n --into <dir> into <dir>/versioncam/ instead, for another host\n --force overwrite files that are already there\n versioncam doctor check this machine can record, and that the app starts\n versioncam login sign in once and save the browser session\n\nWrite\n versioncam inspect <path> what a clip can click, and where each name came from\n --json machine-readable\n versioncam measure <path> <sel> where a selector's matches are, and what they say\n versioncam dsl the clip DSL: every method, its options and defaults\n\nRecord\n versioncam record [id\u2026] drive the app and capture frames\n --draft 15fps at CSS scale: cheap, for writing clips\n versioncam check [id\u2026] record every clip; exit 1 if any breaks\n versioncam stability [id\u2026] record each clip twice the same way; stable or not\n --runs <n> how many times (default 2)\n --full at full quality rather than draft\n\nReview\n versioncam sheet <id> an eight-frame contact sheet\n --at-marks sample the beats instead of even spacing\n versioncam frame <id> <n> one frame at output size, to a png\n --t <seconds> pick the frame by time instead\n --at <label> or by the beat it shows\n versioncam review <id> the checks that need no eyes; PASS/FAIL, exit 0/1\n --beats <file> [{ label, expect }] the clip promised\n --min <s> --max <s> duration bounds (default 9 and 11)\n versioncam preview <id> open the scrubber in a real browser\n --scene <id> preview a scene instead\n --frame <n> start at this frame\n\nOutput\n versioncam render [id\u2026] composite and encode recordings and scenes\n no ids: every one, stale recordings included\n --scene <id> and this scene, whatever the ids say (repeatable)\n --sequence stitch the results into one piece\n\nFrom another directory\n versioncam <command> --cwd <dir> as if run in <dir>, which holds versioncam.config.ts\n\nRun from a directory containing versioncam.config.ts, or name it with --cwd.\n";
|
package/dist/cli/usage.js
CHANGED
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Grouped by the stage of the work each command belongs to, in the order a
|
|
11
11
|
* repository meets them. A flat list of seventeen commands left a newcomer to
|
|
12
|
-
* work out that `inspect` comes before `record` and `sheet` after it.
|
|
12
|
+
* work out that `inspect` comes before `record` and `sheet` after it. The
|
|
13
|
+
* last group is not a stage but a way to run any of them.
|
|
13
14
|
*/
|
|
14
15
|
export const USAGE = `versioncam: record and render demo clips of a real app
|
|
15
16
|
|
|
@@ -50,10 +51,14 @@ Review
|
|
|
50
51
|
--frame <n> start at this frame
|
|
51
52
|
|
|
52
53
|
Output
|
|
53
|
-
versioncam render [id…] composite and encode
|
|
54
|
-
|
|
54
|
+
versioncam render [id…] composite and encode recordings and scenes
|
|
55
|
+
no ids: every one, stale recordings included
|
|
56
|
+
--scene <id> and this scene, whatever the ids say (repeatable)
|
|
55
57
|
--sequence stitch the results into one piece
|
|
56
58
|
|
|
57
|
-
|
|
59
|
+
From another directory
|
|
60
|
+
versioncam <command> --cwd <dir> as if run in <dir>, which holds versioncam.config.ts
|
|
61
|
+
|
|
62
|
+
Run from a directory containing versioncam.config.ts, or name it with --cwd.
|
|
58
63
|
`;
|
|
59
64
|
//# sourceMappingURL=usage.js.map
|
package/dist/cli/usage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/cli/usage.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/cli/usage.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgDpB,CAAC"}
|
package/dist/config.d.ts
CHANGED
|
@@ -31,6 +31,25 @@ export type Presentation = {
|
|
|
31
31
|
padding?: number;
|
|
32
32
|
/** "auto" puts it below the app when padded, and over it when not. */
|
|
33
33
|
caption?: "auto" | "below" | "overlay" | "none";
|
|
34
|
+
/**
|
|
35
|
+
* Where a caption over the app sits: `{ left: n }` or `{ right: n }`,
|
|
36
|
+
* pixels of the video in from that side, which also picks the bottom
|
|
37
|
+
* corner. Default `{ left: 40 }`.
|
|
38
|
+
*
|
|
39
|
+
* An app keeps its own controls in a corner as often as not (an account
|
|
40
|
+
* menu at the foot of a sidebar, a map's legend), and a caption fixed over
|
|
41
|
+
* one hides what a clip may be pointing at. Ignored when the caption sits
|
|
42
|
+
* below the app, where there is nothing of the app to cover.
|
|
43
|
+
*/
|
|
44
|
+
captionInset?: CaptionInset;
|
|
45
|
+
};
|
|
46
|
+
/** One side and a distance from it, as CSS's `left` and `right` say it. */
|
|
47
|
+
export type CaptionInset = {
|
|
48
|
+
left: number;
|
|
49
|
+
right?: never;
|
|
50
|
+
} | {
|
|
51
|
+
right: number;
|
|
52
|
+
left?: never;
|
|
34
53
|
};
|
|
35
54
|
export type AuthConfig = {
|
|
36
55
|
storageState: string;
|
|
@@ -246,5 +265,10 @@ export type RenderConfig = {
|
|
|
246
265
|
presentation: Presentation | null;
|
|
247
266
|
};
|
|
248
267
|
motion: Motion;
|
|
268
|
+
/**
|
|
269
|
+
* The scenes module's path. The page is served a bundle of it, and names
|
|
270
|
+
* the file it came from when it cannot read the scenes out of it.
|
|
271
|
+
*/
|
|
272
|
+
scenes: string | null;
|
|
249
273
|
};
|
|
250
274
|
export declare function renderConfigOf(config: ResolvedConfig): RenderConfig;
|
package/dist/config.js
CHANGED
|
@@ -13,6 +13,27 @@ function positiveInt(value, field) {
|
|
|
13
13
|
}
|
|
14
14
|
return value;
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* A caption inset names one side, and a distance that keeps the caption on
|
|
18
|
+
* the video.
|
|
19
|
+
*
|
|
20
|
+
* Checked because a caption placed off the video fails the way nothing in
|
|
21
|
+
* the presentation layer should: without an error, and without a caption.
|
|
22
|
+
*/
|
|
23
|
+
function checkCaptionInset(inset, outputWidth) {
|
|
24
|
+
const field = "theme.presentation.captionInset";
|
|
25
|
+
const given = inset;
|
|
26
|
+
const sides = ["left", "right"].filter((side) => given?.[side] !== undefined);
|
|
27
|
+
if (given === null || sides.length !== 1) {
|
|
28
|
+
fail(field, "must be `{ left: n }` or `{ right: n }`, one side only");
|
|
29
|
+
}
|
|
30
|
+
const px = given[sides[0]];
|
|
31
|
+
if (typeof px !== "number" || !(px >= 0 && px < outputWidth)) {
|
|
32
|
+
// Quoted when it is a string, or `"40"` would read as the 40 it is not.
|
|
33
|
+
const got = typeof px === "string" ? JSON.stringify(px) : String(px);
|
|
34
|
+
fail(`${field}.${sides[0]}`, `must be pixels of the video, from 0 to under its width of ${outputWidth}, got ${got}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
16
37
|
/**
|
|
17
38
|
* Output dimensions follow the viewport's aspect.
|
|
18
39
|
*
|
|
@@ -90,6 +111,9 @@ export function resolveConfig(config, root) {
|
|
|
90
111
|
const outputWidth = config.output?.width ?? 1920;
|
|
91
112
|
positiveInt(outputWidth, "output.width");
|
|
92
113
|
const baseUrl = config.baseUrl.replace(/\/+$/, "");
|
|
114
|
+
if (presentation?.captionInset !== undefined) {
|
|
115
|
+
checkCaptionInset(presentation.captionInset, outputWidth);
|
|
116
|
+
}
|
|
93
117
|
return {
|
|
94
118
|
root,
|
|
95
119
|
baseUrl,
|
|
@@ -149,6 +173,7 @@ export function renderConfigOf(config) {
|
|
|
149
173
|
output: config.output,
|
|
150
174
|
theme: config.theme,
|
|
151
175
|
motion: config.motion,
|
|
176
|
+
scenes: config.scenes,
|
|
152
177
|
};
|
|
153
178
|
}
|
|
154
179
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { Viewport } from "./camera.js";
|
|
2
|
+
import type { FollowSpec } from "./follow.js";
|
|
3
|
+
import type { CameraKey, CursorTrack, Rect, Vec2 } from "./timeline.js";
|
|
4
|
+
/**
|
|
5
|
+
* What a clip asked the camera to do, and when: one per `s.camera.*` call.
|
|
6
|
+
*
|
|
7
|
+
* The session keeps these rather than writing camera keys as it goes,
|
|
8
|
+
* because a camera that follows the cursor depends on where the cursor goes
|
|
9
|
+
* *after* the write, and that is only known once the clip has run. The
|
|
10
|
+
* driver never needs the camera while it records: it captures the whole
|
|
11
|
+
* viewport, and the camera is a crop drawn afterwards.
|
|
12
|
+
*/
|
|
13
|
+
export type CameraWrite =
|
|
14
|
+
/** `zoom`, `to` and `reset`: glide to a framing and stay there. */
|
|
15
|
+
{
|
|
16
|
+
t: number;
|
|
17
|
+
kind: "frame";
|
|
18
|
+
rect: Rect;
|
|
19
|
+
durationMs: number;
|
|
20
|
+
}
|
|
21
|
+
/** Follow the cursor, until the next write. */
|
|
22
|
+
| {
|
|
23
|
+
t: number;
|
|
24
|
+
kind: "follow";
|
|
25
|
+
spec: FollowSpec;
|
|
26
|
+
durationMs: number;
|
|
27
|
+
}
|
|
28
|
+
/** Stop following, and come to rest on the framing the follow was heading for. */
|
|
29
|
+
| {
|
|
30
|
+
t: number;
|
|
31
|
+
kind: "release";
|
|
32
|
+
};
|
|
33
|
+
export type TrackContext = {
|
|
34
|
+
viewport: Viewport;
|
|
35
|
+
fps: number;
|
|
36
|
+
durationFrames: number;
|
|
37
|
+
cursor: CursorTrack;
|
|
38
|
+
/** Where the cursor rests before the track's first step. */
|
|
39
|
+
cursorStart: Vec2;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Turn a clip's camera writes into the keys the renderer interpolates.
|
|
43
|
+
*
|
|
44
|
+
* Every write starts from where the camera is, moving or not, and blends
|
|
45
|
+
* from there to where it is going:
|
|
46
|
+
*
|
|
47
|
+
* camera(t) = interpolateRect(before(t), destination(t), minjerk(u))
|
|
48
|
+
*
|
|
49
|
+
* where `before` is the camera as it would have gone on without this write,
|
|
50
|
+
* and `u` runs from 0 to 1 over the write's duration. Min-jerk has no slope
|
|
51
|
+
* at either end, so the camera's velocity is continuous where a blend starts
|
|
52
|
+
* and where it ends: entering a follow from a keyed zoom, leaving it for a
|
|
53
|
+
* reset, or a zoom written while another is still under way. That last one
|
|
54
|
+
* used to wait for the move before it to finish and then run short, because
|
|
55
|
+
* each glide set off from the previous glide's target.
|
|
56
|
+
*
|
|
57
|
+
* A clip that never follows and never writes a move while another is under
|
|
58
|
+
* way gets exactly the keys it always got: a hold where each write starts and
|
|
59
|
+
* a min-jerk key where it ends. Every other clip gets the camera sampled at
|
|
60
|
+
* each frame (the `"linear"` keys), since a blend between two moving framings
|
|
61
|
+
* is no longer a glide between two keys.
|
|
62
|
+
*/
|
|
63
|
+
export declare function cameraTrack(writes: readonly CameraWrite[], context: TrackContext): CameraKey[];
|