diff --git a/script.html b/script.html index b99f413..6426ec9 100644 --- a/script.html +++ b/script.html @@ -49,6 +49,12 @@ .tlhead{position:absolute;top:0;bottom:0;width:2px;background:var(--accent2);pointer-events:none} .tlruler{position:absolute;left:0;right:0;bottom:0;height:14px;font:9px/14px var(--mono);color:var(--muted)} .tlruler span{position:absolute;transform:translateX(-50%)} + .steps{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:24px} + .steps button{background:#0f1117;border:1px solid var(--line);color:var(--muted); + border-radius:999px;padding:8px 15px;font:12px/1 var(--mono);cursor:pointer} + .steps button.done{color:var(--ink)} + .steps button.on{background:var(--accent);border-color:var(--accent);color:#fff;cursor:default} + .steps button[disabled]{opacity:.35;cursor:not-allowed} .stage{position:relative;width:100%;max-width:300px} .stage>video{width:100%;aspect-ratio:9/16;border-radius:10px;background:#000;display:block} .ovl{position:absolute;inset:0;border-radius:10px;overflow:hidden;background:#000;display:none} @@ -161,6 +167,38 @@ function shotHtml(s, locked) { + ''; } +// Four jobs, one at a time. Which one you are on follows from the project's +// status; VIEW lets you step back to look at an earlier one without pretending +// the work has been undone. +var STAGES = ["The words", "The layout", "Filming", "The cut"]; +var VIEW = null; + +function stageOf(st) { + if (st === "ready" || st === "film_failed") return 4; + if (st === "queued_to_film" || st === "filming") return 3; + if (st === "approved") return 2; + return 1; +} + +function stepper(stage, view) { + return '
' + STAGES.map(function (n, k) { + var i = k + 1; + var cls = i === view ? "on" : (i <= stage ? "done" : ""); + return ''; + }).join("") + '
'; +} + +// Stage one shows the writing and nothing else: no frames, no camera, no +// settings. Just what the pet actually says. +function linesHtml(s) { + return '
' + + 'Shot ' + (s.index || "") + '' + + '

' + esc(s.line || "") + '

' + + '

' + (s.word_count || 0) + ' words · about ' + + (s.est_seconds || 0) + 's

'; +} + function render(r) { DATA = r; var p = r.project, s = r.script, out = document.getElementById("out"); @@ -190,7 +228,12 @@ function render(r) { document.getElementById("title").textContent = s.title || "The script"; document.getElementById("sub").textContent = s.premise || ""; - var locked = p.status === "approved"; + var stage = stageOf(p.status); + if (VIEW === null || VIEW > stage) VIEW = stage; + // Shot controls belong to the layout stage. Elsewhere the shots are shown + // but not touchable, which is what "locked" means to shotHtml. + var locked = VIEW !== 2; + var canEditScript = (stage === 1); var warn = (s._warnings && s._warnings.length) ? '
Worth a look: ' + s._warnings.map(esc).join(" ยท ") + '
' : ""; @@ -299,8 +342,9 @@ function render(r) { + ''; } - var actions = locked - ? '

Approved. Filming is switched on once payment is live. Nothing has been charged.

' + var actions = !canEditScript + ? '

These words are settled. ' + + 'Everything after this arranges how they are shot, so the writing is left alone.

' : '
' + '

Change the words

' + '
' @@ -312,13 +356,30 @@ function render(r) { + '' + '
'; - out.innerHTML = cams + head + warn + full - + '

The shots

' - + s.segments.map(function (x) { return shotHtml(x, locked); }).join("") - + own - + film - + post - + actions; + var body; + if (VIEW === 1) { + body = head + warn + full + + '

The words, shot by shot

' + + s.segments.map(linesHtml).join("") + + actions; + } else if (VIEW === 2) { + body = head + + '

How it will be laid out. ' + + 'Each shot has a setting, a camera move and an opening frame that carries your ' + + 'pet’s likeness. Cutaways sit across the joins so the cut is never on screen. ' + + 'All of it has been chosen for you — change anything you disagree with, or ' + + 'go straight to filming.

' + + '

The shots

' + + s.segments.map(function (x) { return shotHtml(x, false); }).join("") + + own + + film; + } else if (VIEW === 3) { + body = head + film; + } else { + body = head + post + film; + } + + out.innerHTML = cams + stepper(stage, VIEW) + body; wire(locked); } @@ -447,6 +508,16 @@ function bindPics() { } function wire(locked) { + [].forEach.call(document.querySelectorAll("[data-stage]"), function (b) { + b.onclick = function () { + var want = parseInt(b.getAttribute("data-stage"), 10); + if (want === VIEW) return; + VIEW = want; + hideMsg("msg"); + render(DATA); + window.scrollTo({ top: 0, behavior: "smooth" }); + }; + }); bindPics(); bindFilm((DATA && DATA.project) || {}); bindPost();