diff --git a/trailer.html b/trailer.html index e6677e5..5d230cb 100644 --- a/trailer.html +++ b/trailer.html @@ -17,11 +17,14 @@ .head h2{margin:0;font-size:22px} .tag{color:var(--muted);font-style:italic} .facts{color:var(--muted);font-size:13px;margin:2px 0 18px} - .cast{display:flex;flex-wrap:wrap;gap:10px;margin:0 0 22px} - .ch{border:1px solid var(--line);border-radius:10px;padding:9px 12px;font-size:13px;max-width:330px} + .cast{display:flex;flex-wrap:wrap;gap:14px;margin:0 0 22px} + .ch{border:1px solid var(--line);border-radius:10px;padding:10px;font-size:13px;width:250px} .ch b{display:block} .ch .vo{color:var(--muted);font-size:12px} - .ch .ap{color:var(--muted);font-size:12px;margin-top:3px} + .ch .ap{color:var(--muted);font-size:12px;margin-top:4px} + .sheets{display:flex;gap:5px;margin-bottom:8px} + .sheets img{width:33%;border-radius:6px;border:1px solid var(--line);display:block; + aspect-ratio:16/9;object-fit:cover} .shot{border-top:1px solid var(--line);padding:16px 0;display:flex;gap:16px} .shot .num{width:34px;flex:none;color:var(--muted);font-variant-numeric:tabular-nums} .shot .body{flex:1;min-width:0} @@ -83,36 +86,51 @@ if (!runId) { showMsg("msg", "No run was named in the link."); return; } - // ------------------------------------------------------------ polling + // A draft is busy while it is being written or drawn. Both are minutes long + // and both report progress on the row, so one poll covers them. + function busyState(d) { + var s = String(d.draw_state || ""); + return d.state === "writing" || (s && !/^(drawn|failed)/.test(s)); + } - async function load() { + async function load(repaint) { var r = await api("run_status", { run_id: runId }); if (!r.ok) { showMsg("msg", r.error || "Could not load that run."); return; } + var wasBusy = DRAFTS.length && DRAFTS.some(busyState); RUN = r.run; DRAFTS = r.drafts || []; document.getElementById("title").textContent = RUN.book_title || "Trailers"; document.getElementById("sub").textContent = sub(); if (!CUR && DRAFTS.length) CUR = DRAFTS[0].id; paintTabs(); - var busy = DRAFTS.some(function (d) { return d.state === "writing"; }); - if (busy && !timer) timer = setInterval(load, 4000); + + var busy = DRAFTS.some(busyState); + if (busy && !timer) timer = setInterval(load, 5000); if (!busy && timer) { clearInterval(timer); timer = null; } - if (!busy) openTab(CUR); - else paintWriting(); + + var me = DRAFTS.filter(function (d) { return d.id === CUR; })[0]; + if (me && me.state === "writing") { paintWriting(); return; } + // Repaint when asked, on first paint, or when work has just finished. + if (repaint !== false && (wasBusy || !document.querySelector(".shot"))) openTab(CUR); + else paintBar(); } function sub() { var bits = []; if (RUN.stage) bits.push(RUN.stage); bits.push(DRAFTS.length + " writer" + (DRAFTS.length === 1 ? "" : "s")); - if (RUN.cost_usd) bits.push("$" + Number(RUN.cost_usd).toFixed(2) + " so far"); + var spent = DRAFTS.reduce(function (a, d) { + return a + Number(d.write_usd || 0) + Number(d.draw_usd || 0); }, 0); + if (spent) bits.push("$" + spent.toFixed(2) + " so far"); if (RUN.created_at) bits.push(when(RUN.created_at)); return bits.join(" · "); } function paintTabs() { document.getElementById("tabs").innerHTML = DRAFTS.map(function (d) { + var s = String(d.draw_state || ""); var extra = d.state === "writing" ? 'writing…' : d.state === "failed" ? 'failed' + : (s && !/^(drawn|failed)/.test(s)) ? '' + esc(s) + '' : d.score ? '' + d.score + '' : ''; return 'Cast sheets first, then every shot. ' + + 'This takes a few minutes.'; + } + if (/^drawn/.test(s)) { + return '' + + '' + esc(s) + + (meta.draw_usd ? ' · $' + Number(meta.draw_usd).toFixed(2) + ' spent' : '') + + ''; + } + return '' + + '' + imgs + ' pictures — ' + cast + + ' cast sheets and ' + shots + ' shots, opening and closing.' + + (s === "failed" && meta.note ? '' + esc(meta.note) + '' : ''); + } + + function paintBar() { + var el = document.querySelector(".bar"); + var meta = DRAFTS.filter(function (d) { return d.id === CUR; })[0]; + if (el && meta) el.innerHTML = drawBtn(meta); + } + function paneHtml(meta, draft) { var p = PKG, shots = p.shots || [], cast = p.characters || []; var voice = {}; cast.forEach(function (c) { voice[c.id] = c; }); var secs = shots.reduce(function (a, s) { return a + (Number(s.edit_seconds) || 0); }, 0); - // Drawing is priced off what this writer actually wrote, not an estimate: - // three sheets a character plus an opening and a closing frame a shot. - var imgs = cast.length * 3 + shots.length * 2; - var price = imgs * 0.068; var head = '

' + esc(p.title || meta.label) + '

' + (p.tagline ? '' + esc(p.tagline) + '' : '') + '
' @@ -182,25 +226,26 @@ + ''; } - var bar = '
' - + '' - + '' + imgs + ' pictures. Not wired up yet.' - + '
'; - var castHtml = '
' + cast.map(function (c) { - return '
' + esc(c.name || c.id) + '' + var sheets = ""; + if (c.head_url || c.front_url || c.side_url) { + sheets = '
' + + [c.head_url, c.front_url, c.side_url].map(function (u) { + return u ? '' : ''; }).join("") + + '
'; + } + return '
' + sheets + '' + esc(c.name || c.id) + '' + '' + esc(c.role || "") + (c.age ? " · " + esc(c.age) : "") + (c.voice_id ? " · voiced" : " · silent") + '' + '
' + esc((c.appearance || "").slice(0, 150)) + '
'; }).join("") + '
'; - return head + probs + bar + castHtml + return head + probs + '
' + drawBtn(meta) + '
' + castHtml + shots.map(function (s) { return shotHtml(s, voice); }).join(""); } function shotHtml(s, voice) { - var lines = (s.audio || []).map(function (a, i) { + var lines = (s.audio || []).map(function (a) { var who = voice[a.character_id] || {}; return '
' + '' @@ -234,9 +279,19 @@ + '
'; } - // ------------------------------------------------------------ play + notes + // ------------------------------------------------------------ actions document.getElementById("pane").addEventListener("click", async function (e) { + var draw = e.target.closest ? e.target.closest("[data-draw]") : null; + if (draw) { + draw.disabled = true; + var d = await api("draw_storyboard", { draft_id: draw.getAttribute("data-draw") }); + if (!d.ok) { draw.disabled = false; showMsg("msg", d.error || "That did not start."); return; } + hideMsg("msg"); + load(); + return; + } + var btn = e.target.closest ? e.target.closest(".play") : null; if (!btn) return; var sid = btn.getAttribute("data-shot");