The script

Read it through, then direct it. Every shot can have its own setting and camera move.

Loading…

+ Number(v.cost_usd).toFixed(2) : '') + '' + (v.note ? '
' + esc(v.note) + '
' : '') + '' + ''; }).join("") + ''; [].forEach.call(el.querySelectorAll("[data-restore]"), function (b) { b.onclick = async function () { if (!confirm("Bring that take back as the current video? The one you are leaving is kept.")) return; b.disabled = true; b.textContent = "Restoring…"; var s = await api("restore_version", { email: email, project_id: pid, index: parseInt(b.getAttribute("data-restore"), 10) }); if (!s.ok) { b.disabled = false; b.textContent = "Use this one"; showMsg("msg", s.error || "Could not restore that."); return; } showMsg("msg", s.status_text || "Restored.", "ok"); load(); }; }); } function bindPost() { loadTakes(); // The editing bay is opt-in. Most people want to watch the thing and leave. var eo = document.getElementById("edlopen"); if (eo) eo.onclick = function () { var w = document.getElementById("edlwrap"); var open = w.style.display === "none"; w.style.display = open ? "" : "none"; this.textContent = open ? "Close the video editor" : "Open the video editor"; if (open) { if (!EDL) loadEdl((DATA && DATA.project) || {}); else tlDraw(); w.scrollIntoView({ behavior: "smooth", block: "start" }); } }; var sb = document.getElementById("seams"); function paintSeams(r) { var el = document.getElementById("seamout"); if (!el) return; el.innerHTML = '

' + esc(r.status_text || "") + '

' + (r.seams || []).map(function (x) { var col = x.verdict === "smooth" ? "var(--good)" : (x.verdict === "visible" ? "var(--accent2)" : "var(--bad)"); return '
' + 'shot ' + x.after_shot + ' → ' + x.before_shot + ' at ' + x.at_seconds + 's · ' + 'shift ' + x.shift_x + ',' + x.shift_y + ' · drift ' + x.drift + ' · ' + '' + esc(x.verdict) + '' + (x.recommend_broll ? ' · worth a cutaway' : '') + '
'; }).join(""); } if (sb) sb.onclick = async function () { sb.disabled = true; sb.textContent = "Measuring…"; var el = document.getElementById("seamout"); var r = await api("seam_report", { email: email, project_id: pid }); if (!r.ok) { sb.disabled = false; sb.textContent = "Measure the joins"; showMsg("msg", r.error || "Could not measure."); return; } // Measuring downloads every shot and searches each join for the best // alignment, which is far too slow to answer inside one request. if (r.pending) { el.innerHTML = '

' + esc(r.status_text || "Measuring…") + '

'; var waited = 0; var t = setInterval(async function () { waited += 4; var g = await api("seam_report", { email: email, project_id: pid }); if (g.ok && !g.pending) { clearInterval(t); sb.disabled = false; sb.textContent = "Measure the joins"; paintSeams(g); return; } if (waited > 180) { clearInterval(t); sb.disabled = false; sb.textContent = "Measure the joins"; showMsg("msg", "Measuring is taking unusually long."); } }, 4000); return; } sb.disabled = false; sb.textContent = "Measure the joins"; if (!r.seams || !r.seams.length) { el.innerHTML = '

' + esc(r.status_text || "Nothing to measure.") + '

'; return; } el.innerHTML = '

' + esc(r.status_text || "") + '

' + r.seams.map(function (x) { var col = x.verdict === "smooth" ? "var(--good)" : (x.verdict === "visible" ? "var(--accent2)" : "var(--bad)"); return '
' + 'shot ' + x.after_shot + ' → ' + x.before_shot + ' at ' + x.at_seconds + 's · ' + 'shift ' + x.shift_x + ',' + x.shift_y + ' · drift ' + x.drift + ' · ' + '' + esc(x.verdict) + '' + (x.recommend_broll ? ' · worth a cutaway' : '') + '
'; }).join(""); }; var cb = document.getElementById("cut"); if (cb) cb.onclick = async function () { hideMsg("msg"); cb.disabled = true; cb.textContent = "Cutting…"; var r = await api("render_cut", { email: email, project_id: pid }); if (!r.ok) { cb.disabled = false; cb.textContent = "Cut the B-roll in"; showMsg("msg", r.error || "Could not cut."); return; } var waited = 0; var t = setInterval(async function () { waited += 5; var g = await api("get_project", { email: email, project_id: pid }); if (g.ok && g.project && g.project.cut_url) { clearInterval(t); load(); return; } if (waited > 300) { clearInterval(t); cb.disabled = false; cb.textContent = "Cut the B-roll in"; showMsg("msg", "That is taking unusually long. Try again shortly."); } }, 5000); }; } function bindBottom() { var rv = document.getElementById("revise"); if (rv) rv.onclick = async function () { hideMsg("msg"); var fb = document.getElementById("fb").value.trim(); if (fb.length < 5) { showMsg("msg", "Tell us what you would like changed."); return; } rv.disabled = true; rv.textContent = "Sending…"; var res = await api("revise_script", { email: email, project_id: pid, feedback: fb }); if (!res.ok) { rv.disabled = false; rv.textContent = "Rewrite the words"; showMsg("msg", res.error || "That did not go through."); return; } showMsg("msg", "Rewriting now…", "ok"); load(); }; var ap = document.getElementById("approve"); if (ap) ap.onclick = async function () { hideMsg("msg"); ap.disabled = true; ap.textContent = "Approving…"; var res = await api("approve_script", { email: email, project_id: pid }); if (!res.ok) { ap.disabled = false; ap.textContent = "Approve and lock it"; showMsg("msg", res.error || "That did not go through."); return; } showMsg("msg", res.status_text || "Approved.", "ok"); load(); }; } async function load() { if (!pid || !email) return; if (!PRESETS.length) { var c = await api("camera_presets", {}); if (c.ok) PRESETS = c.presets || []; } var r = await api("get_project", { email: email, project_id: pid }); if (!r.ok) { showMsg("msg", r.error || "Could not load that script."); return; } if (!PHOTOS.length && r.project && r.project.pet_id) { var ph = await api("list_photos", { email: email, pet_id: r.project.pet_id }); if (ph.ok) PHOTOS = ph.photos || []; } render(r); } load();