diff --git a/script.html b/script.html
index fe1c37d..9e9bf17 100644
--- a/script.html
+++ b/script.html
@@ -377,7 +377,12 @@ function render(r) {
+ 'words costs about a hundredth of a cent. Run it through in your pet’s voice '
+ 'over the opening stills first, and only film once the timing and the jokes land.
'
+ ''
+ + ''
+ ''
+ + '
Cutting to the clock speaks the whole piece once, '
+ + 'measures where every word actually falls, and moves the shot boundaries to real word '
+ + 'endings. It rewrites how the lines are divided — not the words themselves.
'
+ + ''
+ ''
+ ''
+ '
The shots
'
@@ -531,6 +536,7 @@ function wire(locked) {
});
bindPics();
bindPreviz();
+ bindAlign();
bindFilm((DATA && DATA.project) || {});
bindPost();
if (locked) { bindBottom(); return; }
@@ -1013,6 +1019,67 @@ function pzPaint(lines) {
};
}
+function bindAlign() {
+ var b = document.getElementById("alignbtn");
+ if (!b) return;
+ var out = document.getElementById("alignout");
+
+ function paint(r) {
+ var bought = ((DATA && DATA.script && DATA.script.segments) || []).length * 8;
+ var filmed = r.filmed || 0;
+ out.innerHTML = '
Measured: '
+ + (r.spoken || 0).toFixed(1) + 's spoken, about ' + filmed.toFixed(1)
+ + 's filmed, against ' + bought + 's of shots.
'
+ + (r.audio ? '' : '')
+ + (r.shots || []).map(function (s) {
+ var fit = Math.abs((s.filmed || 0) - 8) <= 1.2;
+ return '
The whole piece only runs about '
+ + filmed.toFixed(1) + ' seconds filmed, but ' + bought + ' seconds are being shot. '
+ + 'No arrangement of these words fills the video — it needs more written, or a '
+ + 'shorter length.
'
+ : '')
+ + (filmed > bought + 1.5
+ ? '
The whole piece runs about '
+ + filmed.toFixed(1) + ' seconds filmed against ' + bought + ' seconds of video, so the '
+ + 'end would be cut off. Trim it, or buy more length.
'
+ : '');
+ }
+
+ b.onclick = async function () {
+ hideMsg("msg");
+ b.disabled = true; b.textContent = "Measuring…";
+ var r = await api("align_script", { email: email, project_id: pid, refresh: true });
+ if (r.ok && r.pending) {
+ var waited = 0;
+ r = await new Promise(function (done) {
+ var t = setInterval(async function () {
+ waited += 4;
+ var g = await api("align_script", { email: email, project_id: pid });
+ if (g.ok && !g.pending) { clearInterval(t); done(g); return; }
+ if (waited > 240) { clearInterval(t); done({ ok: false, error: "That is taking unusually long." }); }
+ }, 4000);
+ });
+ }
+ b.disabled = false; b.textContent = "Cut it to the clock";
+ if (!r.ok) { showMsg("msg", r.error || "Could not measure that."); return; }
+ if (r.note) { showMsg("msg", r.note); return; }
+ paint(r);
+ showMsg("msg", "Shots re-cut at real word endings.", "ok");
+ load();
+ };
+
+ api("align_script", { email: email, project_id: pid }).then(function (r) {
+ if (r && r.ok && !r.pending && r.audio) paint(r);
+ });
+}
+
function bindPreviz() {
var b = document.getElementById("pzmake");
if (!b) return;