Storyboard: per-shot background - generate from an edited description, same as previous, carry through the scene
This commit is contained in:
parent
72f76c7f0f
commit
d15f469d45
1 changed files with 57 additions and 2 deletions
59
trailer.html
59
trailer.html
|
|
@ -111,6 +111,13 @@
|
||||||
.line .say{flex:1;min-width:0;font-size:14px}
|
.line .say{flex:1;min-width:0;font-size:14px}
|
||||||
.line .who{color:var(--accent);font-size:12px}
|
.line .who{color:var(--accent);font-size:12px}
|
||||||
.line .dir{color:var(--muted);font-size:12px}
|
.line .dir{color:var(--muted);font-size:12px}
|
||||||
|
.bg{display:flex;gap:12px;align-items:flex-start;border:1px dashed var(--line);border-radius:10px;padding:8px 10px;margin:8px 0}
|
||||||
|
.bg img{width:180px;border-radius:6px;border:1px solid var(--line);cursor:zoom-in}
|
||||||
|
.bg .bgtxt{flex:1;min-width:200px}
|
||||||
|
.bg .bgtxt b{font-size:13px}
|
||||||
|
.bg textarea{width:100%;box-sizing:border-box;font:inherit;font-size:13px;min-height:64px;margin:4px 0}
|
||||||
|
.bg .tools{display:flex;gap:6px;flex-wrap:wrap}
|
||||||
|
.bg .tiny{font-size:12px;color:var(--muted)}
|
||||||
.play{border:1px solid var(--line);background:none;color:var(--ink);border-radius:999px;
|
.play{border:1px solid var(--line);background:none;color:var(--ink);border-radius:999px;
|
||||||
width:30px;height:30px;flex:none;cursor:pointer;font:inherit;line-height:1}
|
width:30px;height:30px;flex:none;cursor:pointer;font:inherit;line-height:1}
|
||||||
.play:hover{border-color:var(--accent)}
|
.play:hover{border-color:var(--accent)}
|
||||||
|
|
@ -1363,6 +1370,41 @@
|
||||||
}).join("") + '</div>';
|
}).join("") + '</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// THE BACKGROUND of a shot: the place's picture with nobody in it, which
|
||||||
|
// every picture of that place is drawn from. Dialled in one shot at a time
|
||||||
|
// and carried forward until it should change ("crawl before we walk").
|
||||||
|
var BGEDIT = null;
|
||||||
|
function placeOf(s) {
|
||||||
|
if (s.place) return s.place;
|
||||||
|
var t = String(s.scene || "").toLowerCase().replace(/^(int|ext)\.?\s*\/?\s*(int|ext)?\.?\s*/, "").replace(/\s*[-–—]\s*(day|night|dawn|dusk|morning|evening|afternoon|late afternoon|continuous).*$/, "").replace(/[^a-z0-9]+/g, " ").trim();
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
function backgroundHtml(s) {
|
||||||
|
var sets = PKG.sets || {}, key = placeOf(s), st = sets[key] || {};
|
||||||
|
var url = s.set_ref || st.ref_url || "";
|
||||||
|
var busy = st.state === "drawing";
|
||||||
|
var editing = BGEDIT === s.id || (!url && !busy && BGEDIT === "auto:" + s.id);
|
||||||
|
var desc = st.description || ((s.setting || s.scene || "") + ". " + String(s.opening_image || "").replace(/\b(Dorothy|Toto|Em|Aunt Em|Henry|Uncle Henry)\b[^.]*\./g, "").trim() + " Nobody in the picture.");
|
||||||
|
var pic = url ? '<img src="' + esc(url) + '" data-zoom="' + esc("Background — " + (st.name || s.scene || key)) + '" alt="">'
|
||||||
|
: '<div class="tiny" style="width:180px">' + (busy ? 'drawing the background…' : 'no background yet') + '</div>';
|
||||||
|
var body = '<b>Background</b> <span class="tiny">' + esc(st.name || s.scene || key) + (s.place ? ' · set by you' : '') + '</span>';
|
||||||
|
if (st.error) body += '<div class="warn">' + esc(st.error) + '</div>';
|
||||||
|
if (editing) {
|
||||||
|
body += '<textarea data-bgdesc="' + esc(s.id) + '" placeholder="The place with nobody in it: what is there, where the light comes from, the time of day.">' + esc(desc) + '</textarea>'
|
||||||
|
+ '<div class="tools"><button type="button" class="btn small primary" data-bggen="' + esc(s.id) + '">' + (url ? 'Generate it again' : 'Generate background image') + ' · $0.07</button>'
|
||||||
|
+ '<button type="button" class="btn small" data-bgcancel="1">Cancel</button></div>';
|
||||||
|
} else {
|
||||||
|
body += '<div class="tools">'
|
||||||
|
+ '<button type="button" class="btn small" data-bgedit="' + esc(s.id) + '"' + (busy ? ' disabled' : '') + '>' + (url ? 'Change the background' : 'Generate background image') + '</button>'
|
||||||
|
+ '<button type="button" class="btn small" data-bgcopy="' + esc(s.id) + '" title="This shot uses the background of the shot before it">Same as the previous shot</button>'
|
||||||
|
+ (url ? '<button type="button" class="btn small" data-bgforward="' + esc(s.id) + '" title="The following shots of this scene use this background">Use it for the rest of the scene</button>' : '')
|
||||||
|
+ (s.place ? '<button type="button" class="btn small" data-bgclear="' + esc(s.id) + '">Back to the scene\'s own</button>' : '')
|
||||||
|
+ '</div>'
|
||||||
|
+ (st.description && url ? '<div class="tiny" style="margin-top:4px">' + esc(String(st.description).slice(0, 220)) + '</div>' : '');
|
||||||
|
}
|
||||||
|
return '<div class="bg">' + pic + '<div class="bgtxt">' + body + '</div></div>';
|
||||||
|
}
|
||||||
|
|
||||||
function shotHtml(s, voice) {
|
function shotHtml(s, voice) {
|
||||||
if (s.writing) {
|
if (s.writing) {
|
||||||
return '<div class="shot"><div class="num">' + esc(s.id) + '</div><div class="body">'
|
return '<div class="shot"><div class="num">' + esc(s.id) + '</div><div class="body">'
|
||||||
|
|
@ -1397,7 +1439,7 @@
|
||||||
+ '</div><span class="dur" data-dur="' + esc(s.id) + '"></span></div>';
|
+ '</div><span class="dur" data-dur="' + esc(s.id) + '"></span></div>';
|
||||||
}).join("");
|
}).join("");
|
||||||
|
|
||||||
var media = "";
|
var media = backgroundHtml(s);
|
||||||
if (s.clip_url) {
|
if (s.clip_url) {
|
||||||
media = '<div class="frames"><figure><video src="' + esc(s.clip_url) + '" controls '
|
media = '<div class="frames"><figure><video src="' + esc(s.clip_url) + '" controls '
|
||||||
+ 'preload="metadata"></video><figcaption>the filmed shot'
|
+ 'preload="metadata"></video><figcaption>the filmed shot'
|
||||||
|
|
@ -1454,7 +1496,7 @@
|
||||||
} else {
|
} else {
|
||||||
tools = '<button type="button" class="btn" data-edit="' + esc(s.id) + '">Change this shot</button>'
|
tools = '<button type="button" class="btn" data-edit="' + esc(s.id) + '">Change this shot</button>'
|
||||||
+ '<button type="button" class="btn" data-drawone="' + esc(s.id) + '">'
|
+ '<button type="button" class="btn" data-drawone="' + esc(s.id) + '">'
|
||||||
+ (s.opening_url ? 'Redraw' : 'Draw') + ' · $0.14</button>'
|
+ (s.opening_url ? 'Redraw the shot picture' : 'Draw the shot picture (actors in the background)') + ' · $0.14</button>'
|
||||||
+ (s.opening_url ? '<button type="button" class="btn" data-filmone="' + esc(s.id) + '">'
|
+ (s.opening_url ? '<button type="button" class="btn" data-filmone="' + esc(s.id) + '">'
|
||||||
+ (s.clip_url ? 'Film it again' : 'Film this shot') + ' · about $' + filmCost(s).toFixed(2) + '</button>' : '')
|
+ (s.clip_url ? 'Film it again' : 'Film this shot') + ' · about $' + filmCost(s).toFixed(2) + '</button>' : '')
|
||||||
+ (s.clip_url && s.take_url ? '<button type="button" class="btn" data-recut="' + esc(s.id)
|
+ (s.clip_url && s.take_url ? '<button type="button" class="btn" data-recut="' + esc(s.id)
|
||||||
|
|
@ -1508,6 +1550,19 @@
|
||||||
var el, r;
|
var el, r;
|
||||||
|
|
||||||
if ((el = hit("data-cancel"))) { EDITING = null; openTab(CUR); return; }
|
if ((el = hit("data-cancel"))) { EDITING = null; openTab(CUR); return; }
|
||||||
|
if ((el = hit("data-bgedit"))) { BGEDIT = el.getAttribute("data-bgedit"); openTab(CUR); return; }
|
||||||
|
if ((el = hit("data-bgcancel"))) { BGEDIT = null; openTab(CUR); return; }
|
||||||
|
if ((el = hit("data-bggen"))) {
|
||||||
|
var sidb = el.getAttribute("data-bggen"), ta = document.querySelector('[data-bgdesc="' + sidb + '"]');
|
||||||
|
el.disabled = true;
|
||||||
|
r = await act("background", { draft_id: CUR, shot_id: sidb, op: "generate", description: ta ? ta.value : "" });
|
||||||
|
if (r) { BGEDIT = null; showMsg("msg", "Drawing the background (about $" + r.usd + ").", "ok"); await refresh(); setTimeout(refresh, 25000); }
|
||||||
|
else el.disabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((el = hit("data-bgcopy"))) { r = await act("background", { draft_id: CUR, shot_id: el.getAttribute("data-bgcopy"), op: "copy" }); if (r) await refresh(); return; }
|
||||||
|
if ((el = hit("data-bgforward"))) { r = await act("background", { draft_id: CUR, shot_id: el.getAttribute("data-bgforward"), op: "forward" }); if (r) { showMsg("msg", "Carried to " + r.shots + " following shots.", "ok"); await refresh(); } return; }
|
||||||
|
if ((el = hit("data-bgclear"))) { r = await act("background", { draft_id: CUR, shot_id: el.getAttribute("data-bgclear"), op: "clear" }); if (r) await refresh(); return; }
|
||||||
if ((el = hit("data-drawcast"))) {
|
if ((el = hit("data-drawcast"))) {
|
||||||
el.disabled = true;
|
el.disabled = true;
|
||||||
r = await act("draw_cast", { draft_id: el.getAttribute("data-drawcast") });
|
r = await act("draw_cast", { draft_id: el.getAttribute("data-drawcast") });
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue