Correct the previz for the difference between spoken and filmed pace

The run-through is spoken by ElevenLabs, but the finished audio is Veo's
performance re-voiced, and Veo enunciates more slowly - it was asked to, to
make the mouth movement readable. Measured on a real clip: 17 words ran 7.02s
filmed (about 2.4 words a second) against roughly 3.0 words a second spoken.

So the raw previz number understates the filmed length by about a quarter, and
the dead-air warning was correspondingly overstated - it claimed 2.4 seconds of
silence per shot where the filmed figure is nearer one. Show both numbers and
name the factor rather than quietly applying it.
This commit is contained in:
gator 2026-09-08 13:05:14 +00:00
parent 447368e355
commit c26efbbea7

View file

@ -939,7 +939,12 @@ function pzPaint(lines) {
if (!PZ.length) { el.innerHTML = ""; return; } if (!PZ.length) { el.innerHTML = ""; return; }
var total = PZ.reduce(function (a, b) { return a + (b.seconds || 0); }, 0); var total = PZ.reduce(function (a, b) { return a + (b.seconds || 0); }, 0);
var bought = segs.length * 8; var bought = segs.length * 8;
var over = PZ.filter(function (x) { return x.over; }); // Spoken here, but filmed by Veo, which was asked to over-enunciate so the
// mouth is readable and therefore runs slower. Measured on a real clip:
// 17 words took 7.02s filmed against about 5.7s spoken, so ~1.25x.
var FILMED = 1.25;
var filmed = total * FILMED;
var over = PZ.filter(function (x) { return (x.seconds || 0) * FILMED > 8.0; });
el.innerHTML = '<div class="stage" style="margin-bottom:12px">' el.innerHTML = '<div class="stage" style="margin-bottom:12px">'
+ '<img id="pzimg" alt="opening still" style="width:100%;aspect-ratio:9/16;' + '<img id="pzimg" alt="opening still" style="width:100%;aspect-ratio:9/16;'
@ -948,32 +953,35 @@ function pzPaint(lines) {
+ '<audio id="pzaud"></audio>' + '<audio id="pzaud"></audio>'
+ '<button type="button" class="btn" id="pzplay">&#9654; Play the run-through</button>' + '<button type="button" class="btn" id="pzplay">&#9654; Play the run-through</button>'
+ '<span class="foot" style="margin-left:12px" id="pzwhere">' + '<span class="foot" style="margin-left:12px" id="pzwhere">'
+ PZ.length + ' lines &middot; ' + total.toFixed(1) + 's spoken, ' + PZ.length + ' lines &middot; ' + total.toFixed(1) + 's spoken, about '
+ bought + 's of shots</span>' + filmed.toFixed(1) + 's once filmed, against ' + bought + 's of shots</span>'
+ (total > bought + (filmed > bought
? '<div class="warn" style="margin-top:12px">Spoken, this runs ' ? '<div class="warn" style="margin-top:12px">Filmed, this would run about '
+ total.toFixed(1) + ' seconds but only ' + bought + ' seconds are being ' + filmed.toFixed(1) + ' seconds but only ' + bought + ' seconds are being '
+ 'filmed. Something will be cut off. Shorten the words, or buy more length.</div>' + 'shot. Something will be cut off. Shorten the words, or buy more length.</div>'
: (total < bought * 0.85 : (filmed < bought * 0.88
? '<div class="warn" style="margin-top:12px">Spoken, this runs only ' ? '<div class="warn" style="margin-top:12px">Filmed, this would run about '
+ total.toFixed(1) + ' seconds across ' + bought + ' seconds of video, ' + filmed.toFixed(1) + ' seconds across ' + bought + ' seconds of video, '
+ 'so roughly ' + ((bought - total) / PZ.length).toFixed(1) + ' seconds of ' + 'leaving roughly ' + ((bought - filmed) / PZ.length).toFixed(1) + ' seconds '
+ 'every shot is silence. That is where trailing sound effects and echo come ' + 'of silence at the end of every shot. That is where trailing sound effects '
+ 'from: the model is handed a gap and fills it. More words per shot is the fix.</div>' + 'and echo come from: the model is handed a gap and fills it. More words per '
+ 'shot is the fix.</div>'
: '')) : ''))
+ (over.length + (over.length
? '<div class="warn" style="margin-top:12px">Shot' + (over.length > 1 ? 's ' : ' ') ? '<div class="warn" style="margin-top:12px">Shot' + (over.length > 1 ? 's ' : ' ')
+ over.map(function (x) { return x.index; }).join(", ") + over.map(function (x) { return x.index; }).join(", ")
+ ' will not fit in eight seconds: ' + ' will not fit in eight seconds once filmed: '
+ over.map(function (x) { return x.index + " runs " + x.seconds.toFixed(1) + "s"; }).join(", ") + over.map(function (x) { return x.index + " would run " + (x.seconds * FILMED).toFixed(1) + "s"; }).join(", ")
+ '. Trim those lines before filming.</div>' + '. Trim those lines before filming.</div>'
: '') : '')
+ '<div style="margin-top:14px">' + '<div style="margin-top:14px">'
+ PZ.map(function (x) { + PZ.map(function (x) {
var f = (x.seconds || 0) * FILMED;
return '<div class="foot" style="padding:6px 0;border-top:1px solid var(--line)">' return '<div class="foot" style="padding:6px 0;border-top:1px solid var(--line)">'
+ 'shot ' + x.index + ' &middot; ' + x.seconds.toFixed(1) + 's' + 'shot ' + x.index + ' &middot; ' + x.seconds.toFixed(1) + 's spoken, ~'
+ (x.over ? ' <span style="color:var(--accent2)">over</span>' : '') + f.toFixed(1) + 's filmed'
+ ' &middot; ' + esc(x.line.slice(0, 64)) + '</div>'; + (f > 8 ? ' <span style="color:var(--accent2)">over</span>' : '')
+ ' &middot; ' + esc(x.line.slice(0, 60)) + '</div>';
}).join("") }).join("")
+ '</div>'; + '</div>';