demobites 1.29.0 → 1.30.1
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/package.json +1 -1
- package/scripts/calibrate.mjs +4 -2
- package/scripts/record.mjs +12 -4
- package/scripts/trim.mjs +28 -5
package/package.json
CHANGED
package/scripts/calibrate.mjs
CHANGED
|
@@ -45,8 +45,10 @@ const tb = man.timebase;
|
|
|
45
45
|
// of it compounded two shifts (-0.71 then -1.67 on one take) and produced a
|
|
46
46
|
// clock that matched nothing. Re-base first, then anchor once.
|
|
47
47
|
if (tb && typeof man.record_from === "number") {
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
// The base keeps the take's speed (trim.mjs 1.30.0: one uniform compression to fit the plan): video = (wall - record_from) / speed.
|
|
49
|
+
const speed = typeof man.speed === "number" && man.speed > 0 ? man.speed : 1;
|
|
50
|
+
tb.a = 1 / speed; tb.k = 1; tb.speed = speed; tb.b = -man.record_from / speed; tb.videoRecordFrom = man.record_from;
|
|
51
|
+
tb.method = speed === 1 ? "identity (raw is wall-rate; see 2026-08-09 four-lane verification)" : `identity, then one uniform ${speed}x compression to fit the plan`;
|
|
50
52
|
}
|
|
51
53
|
if (!tb || typeof tb.a !== "number" || typeof tb.b !== "number") {
|
|
52
54
|
console.error("manifest.json has no timebase stamp. Run trim.mjs first.");
|
package/scripts/record.mjs
CHANGED
|
@@ -1286,13 +1286,21 @@ try {
|
|
|
1286
1286
|
}
|
|
1287
1287
|
// Closing beat so the last action breathes before the cut ends.
|
|
1288
1288
|
await page.waitForTimeout(CLOSING_BEAT_MS);
|
|
1289
|
-
// THE TAKE SAYS WHAT IT COST (2026-10-18): per step, so a slow take explains itself.
|
|
1290
|
-
const glides = manifest.camera.filter((c) => c.glide).map((c) => c.glide.t_end - c.glide.t_start);
|
|
1291
|
-
manifest.timing = { filmed_s: Math.round(t() * 100) / 100, steps: manifest.steps.map((st) => ({ n: st.n, action: st.action, s: Math.round(((st.t_end ?? 0) - (st.t_start ?? 0)) * 100) / 100 })), glide_s: Math.round(glides.reduce((a, b) => a + b, 0) * 100) / 100, glides: glides.length };
|
|
1292
|
-
console.log(`timing: filmed ${manifest.timing.filmed_s}s; steps ${manifest.timing.steps.map((st) => `${st.n}:${st.s}s`).join(" ")}; glides ${glides.length} totalling ${manifest.timing.glide_s}s`);
|
|
1293
1289
|
} catch (e) {
|
|
1294
1290
|
failure = e;
|
|
1295
1291
|
}
|
|
1292
|
+
// THE TAKE SAYS WHAT IT COST (2026-10-18): per step, so a slow take explains itself. A SUMMARY NEVER FAILS A TAKE
|
|
1293
|
+
// (1.30.1: the founder's first take through the new chain filmed all nine steps and died here, on a key that never
|
|
1294
|
+
// existed — `manifest.camera`; the glides live on the shots). Outside the filming try, in its own.
|
|
1295
|
+
try {
|
|
1296
|
+
if (!failure) {
|
|
1297
|
+
const glides = (manifest.shots ?? []).filter((c) => c.glide).map((c) => c.glide.t_end - c.glide.t_start);
|
|
1298
|
+
manifest.timing = { filmed_s: Math.round(t() * 100) / 100, steps: manifest.steps.map((st) => ({ n: st.n, action: st.action, s: Math.round(((st.t_end ?? 0) - (st.t_start ?? 0)) * 100) / 100 })), glide_s: Math.round(glides.reduce((a, b) => a + b, 0) * 100) / 100, glides: glides.length };
|
|
1299
|
+
console.log(`timing: filmed ${manifest.timing.filmed_s}s; steps ${manifest.timing.steps.map((st) => `${st.n}:${st.s}s`).join(" ")}; glides ${glides.length} totalling ${manifest.timing.glide_s}s`);
|
|
1300
|
+
}
|
|
1301
|
+
} catch (e) {
|
|
1302
|
+
console.log(`timing summary skipped: ${e.message}`);
|
|
1303
|
+
}
|
|
1296
1304
|
|
|
1297
1305
|
clearInterval(sampler);
|
|
1298
1306
|
clearInterval(framer);
|
package/scripts/trim.mjs
CHANGED
|
@@ -129,21 +129,44 @@ if (lastStepEnd > r0) {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
if (cutAt !== r0 - beaconDelta) console.log("beacon: corrected cut clamped at 0 — head shorter than the anchor error");
|
|
132
|
+
|
|
133
|
+
// THE TAKE FITS ITS PLAN (founder 2026-10-18: "it's no shame to run it via ffmpeg and make it 1.4 times faster… planned
|
|
134
|
+
// 30, took 46 — make it 33 or 34"). When the filmed story runs past the storyboard's own clock, the whole take is
|
|
135
|
+
// sped up by ONE factor (1.5 at most) so it lands near the plan, and the timebase carries that factor: every stamped
|
|
136
|
+
// moment (steps, cursor, shots) maps through video = (wall - record_from) / speed, so nothing drifts. Not a rate
|
|
137
|
+
// fit (the identity law stands): a known, deliberate, uniform compression, recorded in the manifest.
|
|
138
|
+
let speed = 1;
|
|
139
|
+
try {
|
|
140
|
+
const { estimateTake } = await import("../skill/scripts/clock.mjs");
|
|
141
|
+
const sb = JSON.parse(fs.readFileSync(path.join(dir, "storyboard.json"), "utf8"));
|
|
142
|
+
const planned = estimateTake(sb.steps);
|
|
143
|
+
const filmed = lastStepEnd > r0 ? lastStepEnd - r0 + TAIL_BEAT_S : 0;
|
|
144
|
+
const target = planned * 1.1;
|
|
145
|
+
if (planned > 5 && filmed > target * 1.03) {
|
|
146
|
+
speed = Math.min(1.5, Math.round((filmed / target) * 100) / 100);
|
|
147
|
+
console.log(`speed: planned ${planned.toFixed(1)}s, filmed ${filmed.toFixed(1)}s — the take is sped up ${speed}x to ${(filmed / speed).toFixed(1)}s`);
|
|
148
|
+
void postEvent("finishing", { text: `Fitting the take to its plan (${speed}x)…` });
|
|
149
|
+
} else console.log(`speed: planned ${planned.toFixed(1)}s, filmed ${filmed.toFixed(1)}s — as filmed`);
|
|
150
|
+
} catch (e) {
|
|
151
|
+
console.log("speed: as filmed (" + String(e?.message ?? e).split("\n")[0] + ")");
|
|
152
|
+
}
|
|
153
|
+
man.speed = speed;
|
|
132
154
|
man.timebase = {
|
|
133
|
-
a: 1,
|
|
134
|
-
b: -r0,
|
|
135
|
-
method: "identity (raw is wall-rate; see 2026-08-09 four-lane verification)" + beaconMethod,
|
|
155
|
+
a: 1 / speed,
|
|
156
|
+
b: -r0 / speed,
|
|
157
|
+
method: (speed === 1 ? "identity (raw is wall-rate; see 2026-08-09 four-lane verification)" : `identity, then one uniform ${speed}x compression to fit the plan`) + beaconMethod,
|
|
136
158
|
k: 1,
|
|
159
|
+
speed,
|
|
137
160
|
videoRecordFrom: r0,
|
|
138
161
|
...(beaconMethod ? { beaconDelta } : {}),
|
|
139
162
|
};
|
|
140
163
|
fs.writeFileSync(manPath, JSON.stringify(man, null, 2));
|
|
141
|
-
console.log(`timebase:
|
|
164
|
+
console.log(`timebase: video = (wall - ${r0.toFixed(3)})${speed === 1 ? "" : ` / ${speed}`}${beaconMethod ? ` (cut at raw ${cutAt.toFixed(3)}s)` : ""}`);
|
|
142
165
|
|
|
143
166
|
execFileSync(FFMPEG(), [
|
|
144
167
|
"-y", "-loglevel", "error",
|
|
145
168
|
"-i", raw,
|
|
146
|
-
"-filter_complex", `[0:v]trim=${tailCut ? `start=${cutAt}:end=${tailCut}` : `start=${cutAt}`},setpts=PTS-STARTPTS,fps=30,format=yuv420p[out]`,
|
|
169
|
+
"-filter_complex", `[0:v]trim=${tailCut ? `start=${cutAt}:end=${tailCut}` : `start=${cutAt}`},setpts=(PTS-STARTPTS)/${speed},fps=30,format=yuv420p[out]`,
|
|
147
170
|
"-map", "[out]",
|
|
148
171
|
"-c:v", "libx264", "-preset", "medium", "-crf", "19",
|
|
149
172
|
"-movflags", "+faststart",
|