Visual shot editor: start image, scene and camera move editable per shot
This commit is contained in:
parent
34150bb264
commit
8a3324be31
2 changed files with 158 additions and 55 deletions
36
create.html
36
create.html
|
|
@ -4,7 +4,7 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>New video — PayToLaugh</title>
|
<title>New video — PayToLaugh</title>
|
||||||
<meta name="description" content="Pick your pet, paste a link, tell the director what you think.">
|
<meta name="description" content="Pick your pet, paste a link, set the scene, tell the director what you think.">
|
||||||
<link rel="stylesheet" href="/assets/app.css">
|
<link rel="stylesheet" href="/assets/app.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
<header class="page">
|
<header class="page">
|
||||||
<h1>Make a new video</h1>
|
<h1>Make a new video</h1>
|
||||||
<p>Pick the pet, paste whatever you want them to react to, and tell the director what you actually think. The opinion is yours; the delivery is theirs.</p>
|
<p>Pick the pet, paste whatever you want them to react to, and tell the director what you actually think. The opinion is yours; the delivery is theirs. You can direct every shot afterwards.</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
|
@ -38,6 +38,13 @@
|
||||||
<span class="hint">Say what you think and how you want it played. Two sentences is plenty.</span>
|
<span class="hint">Say what you think and how you want it played. Two sentences is plenty.</span>
|
||||||
<textarea id="notes" placeholder="Astro has hated our robot vacuum since day one and barks at it every time it docks. Play it like he is filing a formal grievance with management."></textarea>
|
<textarea id="notes" placeholder="Astro has hated our robot vacuum since day one and barks at it every time it docks. Play it like he is filing a formal grievance with management."></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h2 class="sec" style="margin-top:34px">3 · Where it happens</h2>
|
||||||
|
<div class="field">
|
||||||
|
<label for="scene">The setting <span style="color:var(--muted);font-weight:400">(optional)</span></label>
|
||||||
|
<span class="hint">A starting point for every shot, which you can change shot by shot later. Real or not: a podcast booth, a field of tall grass, floating on a surfboard.</span>
|
||||||
|
<input type="text" id="scene" placeholder="a podcast booth with warm lamps behind">
|
||||||
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>Do they agree or disagree?</label>
|
<label>Do they agree or disagree?</label>
|
||||||
<div class="chips" id="stance">
|
<div class="chips" id="stance">
|
||||||
|
|
@ -48,27 +55,28 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2 class="sec" style="margin-top:34px">3 · How long</h2>
|
<h2 class="sec" style="margin-top:34px">4 · How long</h2>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="chips" id="len">
|
<div class="chips" id="len">
|
||||||
<span class="chip" data-v="2">16 seconds</span>
|
<span class="chip" data-v="2">16 seconds</span>
|
||||||
<span class="chip on" data-v="4">32 seconds</span>
|
<span class="chip on" data-v="4">32 seconds</span>
|
||||||
<span class="chip" data-v="6">48 seconds</span>
|
<span class="chip" data-v="6">48 seconds</span>
|
||||||
</div>
|
</div>
|
||||||
|
<span class="hint" style="margin-top:10px;display:block">The piece is written as one continuous monologue, then cut into 8 second shots that flow into each other.</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="quote">
|
<div class="quote">
|
||||||
<div><div class="big" id="price">$8.85</div><div class="sub" id="plen">32 seconds · 4 shots</div></div>
|
<div><div class="big" id="price">$8.85</div><div class="sub" id="plen">32 seconds · 4 shots</div></div>
|
||||||
<div class="sub">You approve the script before anything is filmed.</div>
|
<div class="sub">You direct and approve before anything is filmed.</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button class="btn" id="go" type="submit" style="margin-top:26px">Submit for scripting</button>
|
<button class="btn" id="go" type="submit" style="margin-top:26px">Write the script</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p class="note" style="margin-top:22px">
|
<p class="note" style="margin-top:22px">
|
||||||
<strong>What happens next.</strong> Submitting records your request and puts it in the
|
<strong>What happens next.</strong> The writer starts straight away. You will be able to
|
||||||
queue. Nothing is charged and nothing is filmed yet. Payment and automatic
|
read it, change the setting and camera on every shot, ask for rewrites, and approve it.
|
||||||
production get switched on once proper sign-in is in place.
|
Nothing is charged and nothing is filmed yet.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
@ -129,21 +137,23 @@ document.getElementById("form").addEventListener("submit", async function (e) {
|
||||||
var btn = document.getElementById("go");
|
var btn = document.getElementById("go");
|
||||||
var url = document.getElementById("url").value.trim();
|
var url = document.getElementById("url").value.trim();
|
||||||
var notes = document.getElementById("notes").value.trim();
|
var notes = document.getElementById("notes").value.trim();
|
||||||
|
var scene = document.getElementById("scene").value.trim();
|
||||||
var opt = petSel.options[petSel.selectedIndex];
|
var opt = petSel.options[petSel.selectedIndex];
|
||||||
|
|
||||||
if (!url) { showMsg("msg", "Paste a link to whatever you want them to react to."); return; }
|
if (!url) { showMsg("msg", "Paste a link to whatever you want them to react to."); return; }
|
||||||
if (notes.length < 10) { showMsg("msg", "Tell the director what you think, in a sentence or two."); return; }
|
if (notes.length < 10) { showMsg("msg", "Tell the director what you think, in a sentence or two."); return; }
|
||||||
|
|
||||||
btn.disabled = true; btn.textContent = "Submitting…";
|
btn.disabled = true; btn.textContent = "Writing…";
|
||||||
var r = await api("create_project", {
|
var r = await api("create_project", {
|
||||||
email: email, pet_id: petSel.value,
|
email: email, pet_id: petSel.value,
|
||||||
pet_name: opt ? opt.getAttribute("data-name") : "",
|
pet_name: opt ? opt.getAttribute("data-name") : "",
|
||||||
source_url: url, owner_notes: notes, stance: stance, segments: segments
|
source_url: url, owner_notes: notes, scene: scene,
|
||||||
|
stance: stance, segments: segments
|
||||||
});
|
});
|
||||||
btn.disabled = false; btn.textContent = "Submit for scripting";
|
btn.disabled = false; btn.textContent = "Write the script";
|
||||||
if (!r.ok) { showMsg("msg", r.error || "That did not go through. Please try again."); return; }
|
if (!r.ok) { showMsg("msg", r.error || "That did not go through. Please try again."); return; }
|
||||||
showMsg("msg", "Submitted. Taking you to your videos…", "ok");
|
showMsg("msg", "Writing it now…", "ok");
|
||||||
setTimeout(function () { location.href = "/videos.html"; }, 650);
|
setTimeout(function () { location.href = "/script.html?id=" + encodeURIComponent(r.project.id); }, 500);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
177
script.html
177
script.html
|
|
@ -3,17 +3,28 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Review the script — PayToLaugh</title>
|
<title>Direct the shots — PayToLaugh</title>
|
||||||
<meta name="description" content="Read the script, ask for changes, approve it when it sounds right.">
|
<meta name="description" content="Read the script, set the scene and camera for each shot, then approve it.">
|
||||||
<link rel="stylesheet" href="/assets/app.css">
|
<link rel="stylesheet" href="/assets/app.css">
|
||||||
<style>
|
<style>
|
||||||
.seg{border:1px solid var(--line);border-radius:12px;padding:18px 20px;margin-bottom:14px;background:#0f1117}
|
.shot{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:20px;margin-bottom:18px;
|
||||||
.seg .top{display:flex;justify-content:space-between;gap:14px;align-items:baseline;margin-bottom:10px;flex-wrap:wrap}
|
display:grid;grid-template-columns:190px 1fr;gap:22px;align-items:start}
|
||||||
.seg .n{font:600 11px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--accent)}
|
@media(max-width:720px){.shot{grid-template-columns:1fr}}
|
||||||
.seg .cam{font:11px/1 var(--mono);letter-spacing:.06em;text-transform:uppercase;color:var(--muted)}
|
.shot .still{width:100%;aspect-ratio:9/16;border-radius:10px;border:1px solid var(--line);
|
||||||
.seg .line{font-size:18px;line-height:1.5;margin:0}
|
object-fit:cover;display:block;background:#000}
|
||||||
.seg .foot{font:11.5px/1 var(--mono);color:var(--muted);margin-top:10px}
|
.shot .noimg{width:100%;aspect-ratio:9/16;border-radius:10px;border:1px dashed var(--line);
|
||||||
|
background:#0f1117;display:flex;align-items:center;justify-content:center;text-align:center;
|
||||||
|
color:var(--muted);font-size:12.5px;padding:14px}
|
||||||
|
.shot .n{font:600 11px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--accent)}
|
||||||
|
.shot .cont{font:11px/1 var(--mono);color:var(--accent2);margin-left:8px}
|
||||||
|
.shot .line{font-size:17px;line-height:1.5;margin:10px 0 16px}
|
||||||
|
.shot .foot{font:11.5px/1 var(--mono);color:var(--muted)}
|
||||||
|
.mini{font-size:13px;font-weight:600;margin:0 0 5px;display:block}
|
||||||
|
.mini span{color:var(--muted);font-weight:400}
|
||||||
|
.shot textarea{min-height:62px}
|
||||||
.warn{background:#2a2112;border:1px solid #5b4520;color:#f0d9a7;border-radius:10px;padding:13px 16px;margin-bottom:16px;font-size:14px}
|
.warn{background:#2a2112;border:1px solid #5b4520;color:#f0d9a7;border-radius:10px;padding:13px 16px;margin-bottom:16px;font-size:14px}
|
||||||
|
.full{background:#0f1117;border:1px solid var(--line);border-radius:12px;padding:18px 20px;margin-bottom:24px;
|
||||||
|
color:var(--muted);font-size:15.5px;line-height:1.7}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -21,7 +32,7 @@
|
||||||
|
|
||||||
<header class="page">
|
<header class="page">
|
||||||
<h1 id="title">The script</h1>
|
<h1 id="title">The script</h1>
|
||||||
<p id="sub">Read it through. If it does not sound like your pet, say so and we will rewrite it.</p>
|
<p id="sub">Read it through, then direct it. Every shot can have its own setting and camera move.</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
|
@ -37,31 +48,60 @@
|
||||||
navBar("videos");
|
navBar("videos");
|
||||||
var email = requireSession();
|
var email = requireSession();
|
||||||
var pid = new URLSearchParams(location.search).get("id");
|
var pid = new URLSearchParams(location.search).get("id");
|
||||||
var poll = null;
|
var poll = null, PRESETS = [], PHOTOS = [], DATA = null;
|
||||||
|
|
||||||
if (!pid) {
|
if (!pid) {
|
||||||
document.getElementById("out").innerHTML =
|
document.getElementById("out").innerHTML =
|
||||||
'<div class="empty">No script chosen. <a href="/videos.html">Back to my videos</a>.</div>';
|
'<div class="empty">No script chosen. <a href="/videos.html">Back to my videos</a>.</div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
function segHtml(s) {
|
function photoOptions(sel) {
|
||||||
return '<div class="seg">'
|
if (!PHOTOS.length) return '<option value="">No photos uploaded</option>';
|
||||||
+ '<div class="top"><span class="n">Shot ' + (s.index || "") + '</span>'
|
return PHOTOS.map(function (p) {
|
||||||
+ '<span class="cam">' + esc(s.camera || "") + '</span></div>'
|
var label = p.kind.charAt(0).toUpperCase() + p.kind.slice(1);
|
||||||
+ '<p class="line">' + esc(s.line || "") + '</p>'
|
return '<option value="' + esc(p.id) + '"' + (p.id === sel ? ' selected' : '') + '>'
|
||||||
+ '<div class="foot">' + (s.word_count || 0) + ' words · about ' + (s.est_seconds || 0) + 's'
|
+ esc(label) + '</option>';
|
||||||
+ (s.note ? ' · ' + esc(s.note) : '') + '</div>'
|
}).join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function shotHtml(s, locked) {
|
||||||
|
var img = s.plate_url
|
||||||
|
? '<img class="still" src="' + esc(s.plate_url) + '" alt="Shot ' + s.index + ' opening frame">'
|
||||||
|
: '<div class="noimg">No opening frame yet.<br>Set the scene, then make one.</div>';
|
||||||
|
|
||||||
|
var controls = locked ? '' :
|
||||||
|
'<label class="mini">The setting <span>— anywhere, including places a real pet could not be</span></label>'
|
||||||
|
+ '<textarea data-scene="' + s.index + '" placeholder="a field of tall grass at golden hour">' + esc(s.scene || "") + '</textarea>'
|
||||||
|
+ '<label class="mini" style="margin-top:12px">Camera</label>'
|
||||||
|
+ '<input type="text" list="cams" data-cam="' + s.index + '" value="' + esc(s.camera || "") + '" placeholder="tight head shot, camera static">'
|
||||||
|
+ '<div class="row" style="margin-top:12px">'
|
||||||
|
+ '<div><label class="mini">Which photo of them</label>'
|
||||||
|
+ '<select data-photo="' + s.index + '">' + photoOptions(s.photo_id) + '</select></div>'
|
||||||
|
+ '<div style="display:flex;align-items:flex-end">'
|
||||||
|
+ '<button type="button" class="btn ghost" data-make="' + s.index + '" style="width:100%">'
|
||||||
|
+ (s.plate_url ? "Remake this frame" : "Make the frame") + '</button></div>'
|
||||||
+ '</div>';
|
+ '</div>';
|
||||||
|
|
||||||
|
return '<div class="shot">'
|
||||||
|
+ '<div>' + img + '</div>'
|
||||||
|
+ '<div>'
|
||||||
|
+ '<span class="n">Shot ' + (s.index || "") + '</span>'
|
||||||
|
+ (s.continues ? '<span class="cont">continues the last shot</span>' : '')
|
||||||
|
+ '<p class="line">' + esc(s.line || "") + '</p>'
|
||||||
|
+ '<p class="foot">' + (s.word_count || 0) + ' words · about ' + (s.est_seconds || 0) + 's</p>'
|
||||||
|
+ '<div style="margin-top:16px">' + controls + '</div>'
|
||||||
|
+ '</div></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
function render(r) {
|
function render(r) {
|
||||||
|
DATA = r;
|
||||||
var p = r.project, s = r.script, out = document.getElementById("out");
|
var p = r.project, s = r.script, out = document.getElementById("out");
|
||||||
var used = parseInt(p.revisions || 0, 10);
|
var used = parseInt(p.revisions || 0, 10);
|
||||||
var left = (r.max_revisions || 3) - used;
|
var left = (r.max_revisions || 3) - used;
|
||||||
|
|
||||||
if (p.status === "scripting") {
|
if (p.status === "scripting") {
|
||||||
out.innerHTML = '<div class="card"><p style="margin:0;color:var(--muted)">'
|
out.innerHTML = '<div class="card"><p style="margin:0;color:var(--muted)">'
|
||||||
+ 'Writing the script now. This usually takes under a minute — the page will update itself.</p></div>';
|
+ 'Writing now. This usually takes under a minute — the page updates itself.</p></div>';
|
||||||
if (!poll) poll = setInterval(load, 5000);
|
if (!poll) poll = setInterval(load, 5000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -72,42 +112,88 @@ function render(r) {
|
||||||
+ '<a class="btn" style="display:inline-block;text-decoration:none" href="/create.html">Start again</a></div>';
|
+ '<a class="btn" style="display:inline-block;text-decoration:none" href="/create.html">Start again</a></div>';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!s || !s.segments) {
|
if (!s || !s.segments) { out.innerHTML = '<div class="empty">No script yet.</div>'; return; }
|
||||||
out.innerHTML = '<div class="empty">No script on this project yet.</div>';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById("title").textContent = s.title || "The script";
|
document.getElementById("title").textContent = s.title || "The script";
|
||||||
document.getElementById("sub").textContent = s.premise || "";
|
document.getElementById("sub").textContent = s.premise || "";
|
||||||
|
|
||||||
var approved = p.status === "approved";
|
var locked = p.status === "approved";
|
||||||
var warn = (s._warnings && s._warnings.length)
|
var warn = (s._warnings && s._warnings.length)
|
||||||
? '<div class="warn"><strong>Worth a look:</strong> ' + s._warnings.map(esc).join(" · ") + '</div>'
|
? '<div class="warn"><strong>Worth a look:</strong> ' + s._warnings.map(esc).join(" · ") + '</div>' : "";
|
||||||
: "";
|
|
||||||
|
|
||||||
var head = '<div class="quote" style="margin-bottom:22px">'
|
var head = '<div class="quote" style="margin-bottom:22px">'
|
||||||
+ '<div><div class="big">$' + Number(p.price_usd || 0).toFixed(2) + '</div>'
|
+ '<div><div class="big">$' + Number(p.price_usd || 0).toFixed(2) + '</div>'
|
||||||
+ '<div class="sub">' + ((p.segments || 4) * 8) + ' seconds · ' + (p.segments || 4) + ' shots</div></div>'
|
+ '<div class="sub">' + ((p.segments || 4) * 8) + ' seconds · ' + (p.segments || 4) + ' shots</div></div>'
|
||||||
+ '<div class="sub">' + (approved ? "Approved" : left + " rewrite" + (left === 1 ? "" : "s") + " left") + '</div>'
|
+ '<div class="sub">' + (locked ? "Approved" : left + " rewrite" + (left === 1 ? "" : "s") + " left") + '</div></div>';
|
||||||
+ '</div>';
|
|
||||||
|
|
||||||
var actions = approved
|
var full = s.full_text
|
||||||
? '<div class="card"><p style="margin:0"><strong>Approved.</strong> Filming is switched on once payment is live. '
|
? '<h2 class="sec">The whole piece</h2><div class="full">' + esc(s.full_text) + '</div>' : "";
|
||||||
+ 'Nothing has been charged.</p></div>'
|
|
||||||
|
var cams = '<datalist id="cams">' + PRESETS.map(function (c) {
|
||||||
|
return '<option value="' + esc(c) + '">'; }).join("") + '</datalist>';
|
||||||
|
|
||||||
|
var actions = locked
|
||||||
|
? '<div class="card"><p style="margin:0"><strong>Approved.</strong> Filming is switched on once payment is live. Nothing has been charged.</p></div>'
|
||||||
: '<div class="card">'
|
: '<div class="card">'
|
||||||
+ '<h2 class="sec">Not quite right?</h2>'
|
+ '<h2 class="sec">Change the words</h2>'
|
||||||
+ '<div class="field">'
|
+ '<div class="field"><label for="fb">What would you change</label>'
|
||||||
+ '<label for="fb">What would you change</label>'
|
+ '<span class="hint">Be specific. “Too polite, he would be smugger” beats “make it funnier”. '
|
||||||
+ '<span class="hint">Be specific. “Too polite, he would be smugger about it” beats “make it funnier”.</span>'
|
+ 'Setting and camera you can just edit directly above.</span>'
|
||||||
+ '<textarea id="fb" ' + (left <= 0 ? "disabled" : "") + ' placeholder="The third shot is too wordy, and he would never admit the robot is good at anything."></textarea>'
|
+ '<textarea id="fb" ' + (left <= 0 ? "disabled" : "") + ' placeholder="Shot three is too wordy, and he would never admit the robot is good at anything."></textarea></div>'
|
||||||
+ '</div>'
|
|
||||||
+ '<button class="btn ghost" id="revise" ' + (left <= 0 ? "disabled" : "") + '>'
|
+ '<button class="btn ghost" id="revise" ' + (left <= 0 ? "disabled" : "") + '>'
|
||||||
+ (left > 0 ? "Rewrite it" : "No rewrites left") + '</button>'
|
+ (left > 0 ? "Rewrite the words" : "No rewrites left") + '</button>'
|
||||||
+ '<button class="btn" id="approve" style="margin-left:10px">Approve this script</button>'
|
+ '<button class="btn" id="approve" style="margin-left:10px">Approve and lock it</button>'
|
||||||
+ '</div>';
|
+ '</div>';
|
||||||
|
|
||||||
out.innerHTML = head + warn + s.segments.map(segHtml).join("") + actions;
|
out.innerHTML = cams + head + warn + full
|
||||||
|
+ '<h2 class="sec">The shots</h2>'
|
||||||
|
+ s.segments.map(function (x) { return shotHtml(x, locked); }).join("")
|
||||||
|
+ actions;
|
||||||
|
|
||||||
|
wire(locked);
|
||||||
|
}
|
||||||
|
|
||||||
|
function wire(locked) {
|
||||||
|
if (locked) { bindBottom(); return; }
|
||||||
|
|
||||||
|
// Save edits when the field loses focus, so typing is never interrupted.
|
||||||
|
[].forEach.call(document.querySelectorAll("[data-scene],[data-cam],[data-photo]"), function (el) {
|
||||||
|
var evt = el.tagName === "SELECT" ? "change" : "blur";
|
||||||
|
el.addEventListener(evt, async function () {
|
||||||
|
var idx = el.getAttribute("data-scene") || el.getAttribute("data-cam") || el.getAttribute("data-photo");
|
||||||
|
var body = { email: email, project_id: pid, index: parseInt(idx, 10) };
|
||||||
|
if (el.hasAttribute("data-scene")) body.scene = el.value;
|
||||||
|
if (el.hasAttribute("data-cam")) body.camera = el.value;
|
||||||
|
if (el.hasAttribute("data-photo")) body.photo_id = el.value;
|
||||||
|
var r = await api("update_shot", body);
|
||||||
|
if (!r.ok) showMsg("msg", r.error || "That change did not save.");
|
||||||
|
else hideMsg("msg");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
[].forEach.call(document.querySelectorAll("[data-make]"), function (b) {
|
||||||
|
b.addEventListener("click", async function () {
|
||||||
|
hideMsg("msg");
|
||||||
|
var idx = parseInt(b.getAttribute("data-make"), 10);
|
||||||
|
// Flush any pending edits in this card before drawing from them.
|
||||||
|
var card = b.closest(".shot");
|
||||||
|
var sc = card.querySelector("[data-scene]"), cm = card.querySelector("[data-cam]"),
|
||||||
|
ph = card.querySelector("[data-photo]");
|
||||||
|
await api("update_shot", { email: email, project_id: pid, index: idx,
|
||||||
|
scene: sc ? sc.value : undefined, camera: cm ? cm.value : undefined,
|
||||||
|
photo_id: ph ? ph.value : undefined });
|
||||||
|
b.disabled = true; b.textContent = "Drawing…";
|
||||||
|
var r = await api("make_shot_image", { email: email, project_id: pid, index: idx });
|
||||||
|
b.disabled = false;
|
||||||
|
if (!r.ok) { b.textContent = "Try again"; showMsg("msg", r.error || "Could not make that frame."); return; }
|
||||||
|
load();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
bindBottom();
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindBottom() {
|
||||||
var rv = document.getElementById("revise");
|
var rv = document.getElementById("revise");
|
||||||
if (rv) rv.onclick = async function () {
|
if (rv) rv.onclick = async function () {
|
||||||
hideMsg("msg");
|
hideMsg("msg");
|
||||||
|
|
@ -115,17 +201,16 @@ function render(r) {
|
||||||
if (fb.length < 5) { showMsg("msg", "Tell us what you would like changed."); return; }
|
if (fb.length < 5) { showMsg("msg", "Tell us what you would like changed."); return; }
|
||||||
rv.disabled = true; rv.textContent = "Sending…";
|
rv.disabled = true; rv.textContent = "Sending…";
|
||||||
var res = await api("revise_script", { email: email, project_id: pid, feedback: fb });
|
var res = await api("revise_script", { email: email, project_id: pid, feedback: fb });
|
||||||
if (!res.ok) { rv.disabled = false; rv.textContent = "Rewrite it"; showMsg("msg", res.error || "That did not go through."); return; }
|
if (!res.ok) { rv.disabled = false; rv.textContent = "Rewrite the words"; showMsg("msg", res.error || "That did not go through."); return; }
|
||||||
showMsg("msg", "Rewriting now…", "ok");
|
showMsg("msg", "Rewriting now…", "ok");
|
||||||
load();
|
load();
|
||||||
};
|
};
|
||||||
|
|
||||||
var ap = document.getElementById("approve");
|
var ap = document.getElementById("approve");
|
||||||
if (ap) ap.onclick = async function () {
|
if (ap) ap.onclick = async function () {
|
||||||
hideMsg("msg");
|
hideMsg("msg");
|
||||||
ap.disabled = true; ap.textContent = "Approving…";
|
ap.disabled = true; ap.textContent = "Approving…";
|
||||||
var res = await api("approve_script", { email: email, project_id: pid });
|
var res = await api("approve_script", { email: email, project_id: pid });
|
||||||
if (!res.ok) { ap.disabled = false; ap.textContent = "Approve this script"; showMsg("msg", res.error || "That did not go through."); return; }
|
if (!res.ok) { ap.disabled = false; ap.textContent = "Approve and lock it"; showMsg("msg", res.error || "That did not go through."); return; }
|
||||||
showMsg("msg", res.status_text || "Approved.", "ok");
|
showMsg("msg", res.status_text || "Approved.", "ok");
|
||||||
load();
|
load();
|
||||||
};
|
};
|
||||||
|
|
@ -133,8 +218,16 @@ function render(r) {
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
if (!pid || !email) return;
|
if (!pid || !email) return;
|
||||||
|
if (!PRESETS.length) {
|
||||||
|
var c = await api("camera_presets", {});
|
||||||
|
if (c.ok) PRESETS = c.presets || [];
|
||||||
|
}
|
||||||
var r = await api("get_project", { email: email, project_id: pid });
|
var r = await api("get_project", { email: email, project_id: pid });
|
||||||
if (!r.ok) { showMsg("msg", r.error || "Could not load that script."); return; }
|
if (!r.ok) { showMsg("msg", r.error || "Could not load that script."); return; }
|
||||||
|
if (!PHOTOS.length && r.project && r.project.pet_id) {
|
||||||
|
var ph = await api("list_photos", { email: email, pet_id: r.project.pet_id });
|
||||||
|
if (ph.ok) PHOTOS = ph.photos || [];
|
||||||
|
}
|
||||||
render(r);
|
render(r);
|
||||||
}
|
}
|
||||||
load();
|
load();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue