Storyboard: one long take of several shots on Seedance (to 30 s); H3 Max Turbo in the camera list

This commit is contained in:
gator 2026-10-12 02:54:04 +00:00
parent b4543b9c13
commit ebafaf6be1

View file

@ -451,6 +451,40 @@
"fal-seedance-2.5-480p": { name: "Seedance 2.5 from fal, standard picture", rate: 0.2205, min: 4, max: 30 }, "fal-seedance-2.5-480p": { name: "Seedance 2.5 from fal, standard picture", rate: 0.2205, min: 4, max: 30 },
"fal-seedance-2.5-720p": { name: "Seedance 2.5 from fal, sharper picture", rate: 0.4730, min: 4, max: 30 } }; "fal-seedance-2.5-720p": { name: "Seedance 2.5 from fal, sharper picture", rate: 0.4730, min: 4, max: 30 } };
CAMERAS["minimax-h3"] = CAMERAS[""]; CAMERAS["minimax-h3"] = CAMERAS[""];
CAMERAS["h3-max-turbo"] = { name: "the tuned camera (H3 Max Turbo)", rate: 0.04, min: 5, max: 15 };
var LONG_CAMERAS = ["hf-seedance-2.5-480p", "hf-seedance-2.5-720p", "fal-seedance-2.5-480p", "fal-seedance-2.5-720p"];
// The shots a long take would hold, and how many seconds they run together.
function longRun(fromId, toId) {
var all = (PKG.shots || []).filter(function (x) { return !x.floor; })
.sort(function (a, b) { return String(a.id) < String(b.id) ? -1 : 1; });
var ids = all.map(function (x) { return String(x.id); });
var a = ids.indexOf(String(fromId)), b = ids.indexOf(String(toId));
if (a < 0 || b <= a) return null;
var run = all.slice(a, b + 1), secs = 0;
run.forEach(function (x) { secs += Math.max(2, Math.round(Number(x.edit_seconds) || 4)); });
return { shots: run.length, seconds: secs };
}
function longTakeHtml(s) {
var lt = s.long_take || {};
var h = '<div style="margin-top:8px;border-top:1px dashed var(--line,#ccc);padding-top:6px">'
+ '<label><b>One long take</b> — this shot and the ones after it filmed as a single take of up to 30 seconds, '
+ 'the picture cutting from person to person inside it. The long-take camera speaks the lines itself, in voices like our actors’. '
+ 'It is kept here beside the shots’ own clips and replaces none of them.</label>'
+ 'from shot ' + esc(s.id) + ' through shot <input type="text" data-ltto="' + esc(s.id) + '" value="' + esc(lt.to || "") + '" style="width:56px;font:inherit;font-size:12px"> on '
+ '<select data-lteng="' + esc(s.id) + '">' + LONG_CAMERAS.map(function (k) {
return '<option value="' + k + '"' + ((lt.engine || LONG_CAMERAS[0]) === k ? ' selected' : '') + '>' + CAMERAS[k].name + ' — $' + CAMERAS[k].rate.toFixed(2) + ' a second</option>'; }).join("") + '</select> '
+ '<button type="button" class="btn small" data-longtake="' + esc(s.id) + '">' + (lt.clip_url ? 'Film the long take again' : 'Film the long take') + '</button>';
if (lt.state === "filming") h += '<p class="tiny">The long take is being filmed (started ' + esc(String(lt.since || "").replace("T", " ").slice(0, 16)) + '). It takes several minutes; reload the page to see it.</p>';
if (lt.error) h += '<p class="tiny" style="color:#b4531f">The long take could not be made: ' + esc(lt.error) + '</p>';
if (lt.unchanged) h += '<p class="tiny">Nothing that reaches the camera has changed since this long take was filmed, so it was not bought again.</p>';
if (lt.clip_url) h += '<div class="frames"><figure><video src="' + esc(lt.clip_url) + '" controls preload="metadata"></video><figcaption>one long take, shots '
+ esc((lt.shots || []).join(", ")) + ' &middot; ' + Number(lt.clip_seconds || 0).toFixed(1) + 's'
+ madeOn({ filmed_on: lt.engine, film_usd: lt.usd, film_wait: lt.wait })
+ ((lt.check || {}).verdict ? ' &middot; words: ' + esc(lt.check.verdict) : '')
+ ((lt.check || {}).heard ? '<br>heard: “' + esc(lt.check.heard) + '”' : '')
+ '</figcaption></figure></div>';
return h + '</div>';
}
function cameraOf(x) { return CAMERAS[(x && x.engine) || ""] || CAMERAS[""]; } function cameraOf(x) { return CAMERAS[(x && x.engine) || ""] || CAMERAS[""]; }
function filmCost(x) { var c = cameraOf(x); function filmCost(x) { var c = cameraOf(x);
return Math.min(c.max, Math.max(c.min, Math.ceil((Number(x.edit_seconds) || 5) + 1.5))) * c.rate; } return Math.min(c.max, Math.max(c.min, Math.ceil((Number(x.edit_seconds) || 5) + 1.5))) * c.rate; }
@ -1317,12 +1351,13 @@
+ '</select></label>') + '</select></label>')
+ '<label style="margin-top:6px">Which camera films this shot ' + '<label style="margin-top:6px">Which camera films this shot '
+ '<select data-engine="' + esc(s.id) + '">' + '<select data-engine="' + esc(s.id) + '">'
+ ["", "hf-seedance-2.5-480p", "hf-seedance-2.5-720p", "fal-seedance-2.5-480p", "fal-seedance-2.5-720p"].map(function (k) { + ["", "h3-max-turbo", "hf-seedance-2.5-480p", "hf-seedance-2.5-720p", "fal-seedance-2.5-480p", "fal-seedance-2.5-720p"].map(function (k) {
var c = CAMERAS[k]; var c = CAMERAS[k];
return '<option value="' + k + '"' + ((s.engine || "") === k ? ' selected' : '') + '>' return '<option value="' + k + '"' + ((s.engine || "") === k ? ' selected' : '') + '>'
+ (k ? 'The long-take camera: ' + c.name : 'The usual camera') + (k === "h3-max-turbo" ? 'The tuned camera (H3 Max Turbo)' : k ? 'The long-take camera: ' + c.name : 'The usual camera')
+ ' — a shot up to ' + c.max + ' seconds, about $' + c.rate.toFixed(2) + ' a second</option>'; }).join("") + ' — a shot up to ' + c.max + ' seconds, about $' + c.rate.toFixed(2) + ' a second</option>'; }).join("")
+ '</select></label>' + '</select></label>'
+ longTakeHtml(s)
+ '</div>'; + '</div>';
} }
@ -2356,6 +2391,24 @@
}, 700); }, 700);
}); });
document.getElementById("pane").addEventListener("click", async function (e) {
var b = e.target.closest && e.target.closest("[data-longtake]");
if (!b) return;
var sid = b.getAttribute("data-longtake");
var to = ((document.querySelector('[data-ltto="' + sid + '"]') || {}).value || "").trim();
var eng = (document.querySelector('[data-lteng="' + sid + '"]') || {}).value || LONG_CAMERAS[0];
var run = longRun(sid, to);
if (!run) { showMsg("msg", "Give the last shot of the long take — a later shot of this script, by its number."); return; }
if (run.seconds > 30) { showMsg("msg", "Shots " + sid + " to " + to + " run " + run.seconds + " seconds together; one take holds 30. End it on an earlier shot."); return; }
var had = ((PKG.shots || []).filter(function (x) { return String(x.id) === sid; })[0] || {}).long_take || {};
if (!confirm(run.shots + " shots as one take of " + run.seconds + " seconds on " + CAMERAS[eng].name
+ ": about $" + (run.seconds * CAMERAS[eng].rate).toFixed(2) + ". Film it?")) return;
var r = await api("long_take", { draft_id: CUR, shot_id: sid, to_shot: to, engine: eng, force: !!had.clip_url && had.to === to && had.engine === eng });
await refresh();
if (r.ok) showMsg("msg", "The long take is being filmed: " + r.shots + " shots, " + r.seconds + " seconds, about $" + Number(r.usd).toFixed(2) + ". It takes several minutes; reload the page to see it.", "ok");
else showMsg("msg", r.error || "The long take could not be started.");
});
document.getElementById("pane").addEventListener("change", async function (e) { document.getElementById("pane").addEventListener("change", async function (e) {
var el = e.target; var el = e.target;
if (el.getAttribute && el.getAttribute("data-pagepick")) { if (el.getAttribute && el.getAttribute("data-pagepick")) {