diff --git a/script.html b/script.html index 8b7d1f9..a8e4e6d 100644 --- a/script.html +++ b/script.html @@ -253,7 +253,7 @@ function render(r) { + '
The voice: '
+ + esc(vp.formula) + '.
In the finished film: ' + esc(vp.film_voice || '') + '.
Speaks the whole piece once in your pet’s ' - + 'voice, measures where every word actually falls, and cuts the shots at real sentence ' - + 'endings. It divides the words — it does not change them. ' - // Measured, not guessed: an 80s piece came back at $0.1589 for 946 characters, - // which is the ElevenLabs rate of $22 per 131,000. "About a cent" was wrong by - // more than tenfold, so quote the real number for the words actually on screen. - + 'Costs about ' + Math.max(1, Math.round(narrative.length * 22 / 1310)) - + ' cents at this length.
' + + voiceLine + + 'Divides the piece into shots at ' + + esc(vp.engine || 'the engine') + '’s own measured speaking rate. Runs here in ' + + 'code — nothing is sent to a language model and nothing is spoken, so it is ' + + 'instant and free. Press it whenever the words change.
' + '' - + '' + + (vp.readthrough_is_standin + ? 'Reads the whole piece aloud so you can hear the timing and the jokes. ' + + 'This is ElevenLabs standing in. ' + esc(vp.engine || 'The engine') + + ' performs the real thing itself from the written description above and will ' + + 'phrase it differently — there is no way to hear its real voice without ' + + 'paying to film it.' + : 'Reads the whole piece aloud in the same voice that will be dubbed onto the film.') + // The ElevenLabs rate is 22 dollars per 131,000 characters. A measured + // run came back at 15.89 cents for 946 characters, so quote it from what + // is actually on screen. Deliberately spelled out: a dollar sign before a + // quote is a substitution token to patch_git_file and once shipped a broken + // page - BROWSER_TESTS.md:265 - so none appear in this file's patch text. + + ' Costs about ' + Math.max(1, Math.round(narrative.length * 22 / 1310)) + + ' cents at this length, and changes none of the words.
' + + '' + + '' + + '' + + ''; var staleNote = (stale && canEditScript) ? 'Approve and lock it settles ' + + 'the writing: the words, the shot division and the running order stop being editable, ' + + 'and the project moves on to setting up each shot — the scene, the camera and ' + + 'the opening frame — and then to filming. Nothing is filmed and nothing is ' + + 'charged for filming at that point. It is the point after which rewriting means ' + + 'starting a new video.
' + ''; var body; @@ -1426,16 +1477,41 @@ function bindBottom() { load(); }; - var su = document.getElementById("setupshots"); - if (su) su.onclick = async function () { - hideMsg("msg"); - // Save anything typed but not saved first, so the cut is of the words on - // screen rather than the words on file. + // Flush an unsaved edit before either button acts, so both work on the + // words that are on screen rather than the words on file. + async function flushNarrative() { var box = document.getElementById("narr"); if (box && box.value.trim().length >= 10) { await api("set_narrative", { email: email, project_id: pid, text: box.value }); } - su.disabled = true; su.textContent = "Speaking it…"; + } + + var su = document.getElementById("setupshots"); + if (su) su.onclick = async function () { + hideMsg("msg"); + su.disabled = true; su.textContent = "Dividing…"; + await flushNarrative(); + var r = await api("setup_shots", { email: email, project_id: pid }); + su.disabled = false; su.textContent = "Setup shots"; + if (!r.ok) { showMsg("msg", r.error || "Could not divide that."); return; } + // Notes are the splitter telling you the script is the wrong length for + // the shots bought. That is a writing problem and only you can fix it, so + // it is shown rather than swallowed. + var out = document.getElementById("setupout"); + if (out) { + out.innerHTML = (r.notes || []).map(function (t) { + return '' + (r.spoken || 0).toFixed(1) + + 's spoken by ElevenLabs. The shot division above is unchanged — this is a ' + + 'read-through, not a re-cut.
' + + (r.shots || []).map(function (s) { + return '