From 29a054f8c880e18b8f97bb04d7b79cfcdafcd4da Mon Sep 17 00:00:00 2001 From: gator Date: Mon, 7 Sep 2026 23:23:12 +0000 Subject: [PATCH] One stage at a time instead of the whole pipeline at once The page showed the script, every shot's directing controls, your pictures, filming, the joins and the cut simultaneously. That is four different jobs on one screen, and the first of them - reading the words and getting them right - is the one that matters most and was the easiest to skip past. It is now four stages with a stepper: the words, the layout, filming, the cut. Each shows only what belongs to it, and you can step back to look at an earlier one at any time. This also fixes something that was simply wrong: approving the script used to hide every shot control, so the setting, camera and cutaways became uneditable at exactly the moment you were meant to be arranging them. Directing now lives in its own stage, after the words are settled and before anything is filmed. --- script.html | 91 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 81 insertions(+), 10 deletions(-) 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();