Commit graph

152 commits

Author SHA1 Message Date
a66c6b352e Picture tools stay available on a filmed shot; a stale clip says so 2026-09-19 17:47:00 +00:00
797fa52b87 A note to the camera per shot: changes how it is filmed, not the pictures 2026-09-19 17:41:28 +00:00
b66e665f3f Try 4 versions of a picture, graded side by side, and pick one 2026-09-19 17:34:30 +00:00
3d34667b35 A 'what to do next' guide, and the picture checker's findings with a Fix button
The page never said what the next step was, and finding faulty pictures was
left to the author although every frame is already checked by a model.
2026-09-19 16:11:11 +00:00
39c41c689d Show why a picture could not be redrawn 2026-09-19 15:38:51 +00:00
03052f7182 The author can say what is wrong with a picture, and have it redrawn
report_frame_fault existed in the worker and was on no page.
2026-09-19 15:33:35 +00:00
00c4bc38b5 Say that the revision has started when Revise is pressed 2026-09-19 15:19:03 +00:00
c89a92e72f The price on Draw is the worker's own picture count, looks and back views included 2026-09-19 15:17:16 +00:00
c02eb5d511 Looks per scene, a change prompt on every character picture, click to enlarge
Each scene now shows who is in it as they look IN THAT SCENE, with one box:
'Change how Stewart looks from this scene on'. Cast cards show every look
front, side and back. Every picture opens large. The storyboard waits until
all pictures exist. A box for the author's notes on the script as a whole,
and Revise is always on offer.
2026-09-19 15:16:26 +00:00
a5ee10e99b Remove the duplicated page tail left after the closing html tag
A dollar sign before a quote is a substitution token to patch_git_file, so a
price label spliced the rest of the page in after itself. trailer.html carried
33 KB of raw JavaScript after its closing tag, which rendered as garbled text
in the page body; script.html carried 65 KB, commented out. The copy above the
first closing tag was verified complete: it parses, and it defines every
function and calls every action the removed text did.
2026-09-19 13:51:24 +00:00
3f5bd70f24 Remove the duplicated page tail left after the closing html tag
A dollar sign before a quote is a substitution token to patch_git_file, so a
price label spliced the rest of the page in after itself. trailer.html carried
33 KB of raw JavaScript after its closing tag, which rendered as garbled text
in the page body; script.html carried 65 KB, commented out. The copy above the
first closing tag was verified complete: it parses, and it defines every
function and calls every action the removed text did.
2026-09-19 13:51:23 +00:00
f8c72e94ae admin: show each reference as Image N with the name the prompt gives it 2026-09-19 02:47:53 +00:00
5d342cb2c6 admin: play the clip, the raw take, the seed frame and the audio per shot 2026-09-18 19:43:09 +00:00
f468604438 Make Download actually download
The `download` attribute is ignored by every browser when the href is
cross-origin, and the file we redirect to is signed with an inline
disposition - so clicking Download opened the mp4 in a tab instead of
saving it. ?dl=1 asks the worker to serve it as an attachment.
2026-09-18 01:57:19 +00:00
f115eca329 Point the home page's media at the worker, not the broken file proxy
Six URLs are baked into this page as static HTML, so they never pass through
the API where the rewrite happens - the videos and both photos have been
dead for as long as api.corben.world/files has been returning 500. The
worker signs and redirects, which works regardless of that proxy's state.
2026-09-18 00:36:49 +00:00
d7ac094c9c Recover a shot left stuck on "filming" by a worker restart
Third occurrence of this shape after cuts and the storyboard reel: a flag
meaning "work is happening" set before an in-memory thread starts, never
cleared when a deploy kills it, and a page that then hides the buttons for
ever. Anything older than 25 minutes is treated as gone.
2026-09-17 22:20:15 +00:00
a1ededf9c5 Repair the picture-check button, broken by a $-quote in patch text
A literal $' in replacement text is consumed as a special pattern by the
patch API, which truncated the block mid-string and swallowed the
if (unfilmed) line with it. BROWSER_TESTS.md records this exact hazard.
The price is now built by concatenating the dollar sign separately so no
$-quote sequence appears in patch text at all.
2026-09-17 20:58:07 +00:00
ac4ece69a5 Add the button that runs the picture check
Separate from filming on purpose: a re-film decision wants the audio and
picture verdicts together, and an existing film can be checked without
paying to shoot it again.
2026-09-17 20:57:20 +00:00
5eb4aac2cc Show what the picture check found, beside what the audio check found
Every clip has been transcribed and compared with its script since the first
film. Nothing looked at the picture, which is where this engine actually
fails - two identical photographs on a mantel, half a car, a person nobody
asked for. This renders the visual verdict the same way, and lists each
fault with the wording change that would have prevented it.
2026-09-17 20:57:07 +00:00
4d0d375dbb Honour the "and play" half once the audio is ready 2026-09-17 18:24:53 +00:00
f3cfb15d51 Play automatically when preparation finishes, and stop implying failure
"Prepare and play" only prepared. And a shot with no dialogue has no audio
by design, so 13 of 20 spoken is not 7 failures - say how many are silent.
2026-09-17 18:24:46 +00:00
acfc51b2d9 Keep refreshing while the storyboard audio is being prepared
The page polls only while it believes something is working, and preparing
the reel was not on that list - so the progress froze at whatever the last
manual refresh had seen (5/20) while the job ran happily to completion.

Also: treat a reel job older than 15 minutes as gone, the way cuts already
are, so a worker restart cannot leave the button disabled for ever; and
start playing automatically once preparation finishes, since "Prepare and
play" promised both.
2026-09-17 18:24:19 +00:00
153c38e6b8 Quote the storyboard from what will actually be drawn
The estimate was cast x 3 + shots x 2. It counted characters who appear in
no shot, whose sheets are skipped, and knew nothing about the per-day
wardrobe sheets a multi-day story needs. On the Memory Road board that is
73 quoted against 82 drawn.
2026-09-17 17:34:33 +00:00
0b11c4c262 Wire the storyboard player's controls
Jump-to scrolls to the shot and highlights it, so a note can be written
against the moment that was just heard.
2026-09-17 14:08:03 +00:00
fc858729f3 Play the storyboard: frames and narration, in order, at the top
Reviewing meant scrolling to a shot, pressing play, listening, scrolling to
the next - which destroys exactly the flow a trailer is made of, so faults of
sequence were the hardest to notice and the ones we kept shipping.

This plays the whole thing: opening frame, then closing frame, while the
shot's lines are spoken, then on to the next. Stop, or jump to any shot to
leave a note. It is the trailer before it is filmed, for cents of speech
rather than dollars of video.
2026-09-17 14:07:50 +00:00
70bf7758e3 Styles for the storyboard player, and make the tab score readable
"Claude Opus 5 ★75" is unreadable when the model's own name ends in a digit -
it was read as a score of 5. The score now sits in its own bordered pill.
2026-09-17 14:07:20 +00:00
efa861f227 Recover from a job killed by a deploy, and show when a cut reorders
cuts_state is set before the thread starts and cleared when it finishes, so
a deploy in between left the page waiting forever on work that was no longer
running, with the retry button hidden. Fifteen minutes is longer than the
work can legitimately take.

A cut may reorder as well as drop, which changes what it is - worth saying
rather than leaving the reader to spot it in the id list.
2026-09-17 12:51:27 +00:00
8a3e257637 Await the repaint before playing, and show each shot's day
openTab fetches the draft, so the video element did not exist 60ms later and
the first play was a no-op.
2026-09-17 12:45:04 +00:00
fabb7d2ed8 Load the watch-through numbers alongside the cuts
The views table already records how far every viewer of a share page got.
Once each published cut has its own page, "which version holds people" is a
query, and this is where the answer is shown.
2026-09-17 12:44:52 +00:00
7b4ee1895a Wire up the cuts: propose, play in order, publish
playCut steps one video element through the cut's clips. No render, no
upload, no cost - which is the whole reason ten proposals are worth looking
at rather than one.
2026-09-17 12:44:44 +00:00
73a8f5d166 Render the proposed cuts, with a free in-browser preview
A cut is an ordered list of shot ids, so previewing one costs nothing: the
page plays that cut's clips back to back. That is what makes asking for ten
proposals reasonable. Only a cut somebody chooses gets joined into a real
mp4 with its own share page, which is also what makes the watch-through
numbers comparable - one page per version.
2026-09-17 12:44:23 +00:00
800ba28387 Styles for the cuts panel and its player 2026-09-17 12:44:02 +00:00
170895644d Offer the revision when the script is over its running time
Revising was reachable only after readers had reviewed it or the author had
left a note. Being ninety seconds over budget is a reason to revise on its
own, and the button now says how much it will cut.
2026-09-17 12:18:09 +00:00
d94390d135 Put "Time it for real" on the bar and the result under the header
Nothing on the page could trigger the measurement, so the running time a
revision cuts against was only reachable through the API.
2026-09-17 12:16:10 +00:00
9a00b66b68 Show the script's measured running time, not the writer's estimate
The runtime in the header is the sum of the edit_seconds the writer typed,
which is a guess made from a word count. timingHtml renders what the lines
actually take when the cast speaks them, and how far over the target that
puts the trailer - which is the number a revision has to cut to.
2026-09-17 12:16:00 +00:00
8a668a9b25 Add the timing panel styles 2026-09-17 12:15:49 +00:00
e0301dc514 Show each shot's scene slug, so a wrong grouping is visible
Shots sharing a scene are drawn from one frame of that place. When the
grouping is wrong the symptom is a set that drifts, and until now the
slug doing the grouping was not on the page at all.
2026-09-17 12:14:36 +00:00
c900dce0aa trailer.html: show the story the writer worked out, above the script
The writer now reads the book and commits to what the story IS before writing
a single shot - premise, protagonist, the emotional engine stated as a moment,
what a viewer must understand, which moments have to be SHOWN rather than
narrated, and how it ends so it knows what it is withholding.

That document is worth more to an author than the script is. It is where a
misreading of the book is visible and cheap to fix; by the time it is
twenty-six shots and a storyboard it is neither. So it sits above the shots,
collapsed, and the two lists that decide whether the trailer works - what a
viewer must understand, and what must be dramatised - are open by default.

"What a viewer must understand" is also literally the checklist the
comprehension test measures against, so the two panels now read as a pair: here
is what it must convey, and here is what three readers actually took away.
2026-09-17 07:25:34 +00:00
50157f0d5b trailer.html: show what viewers understood, not what reviewers thought
The review panel rendered the old critique shape - errors, suggestions,
strengths. The comprehension test produces something else: three summaries
written by readers who saw only the script, and the writer's own list of what
the trailer failed to convey.

The gap list leads, because that is what the revision consumes and what the
author needs to decide about. Each reader's summary is then shown verbatim,
with what they were still asking and whether they would watch the film -
reading three strangers describe your trailer badly is the most persuasive
evidence there is that it does not tell the story.

"Got wrong" is called out separately from "missed". A trailer that leaves
something out is incomplete; one that leads a viewer to the wrong conclusion is
worse, and they are different problems to fix.
2026-09-17 06:45:22 +00:00
d21360ea2b trailer.html: edit, draw, film and reassemble one shot at a time
The trailer was all-or-nothing. If one shot was wrong - a line cut short, a
character duplicated, a scene missing from the front - the only lever was to
film all twenty-four again.

Every shot now carries its own controls: describe a change and have the writer
turn it into a proper shot, draw its two frames, film just that one, watch the
clip that came back, and read the machine check that compared what it says with
what the script says. "Add a scene here" sits between shots, because the note
that prompted this was that the trailer needed an opening the writer never
thought to include.

Assemble is separate and cheap - it joins whatever has been filmed - so
re-cutting after changing one shot costs nothing but the one shot.

Prices are on the buttons because they differ by two orders of magnitude:
rewriting a shot is cents, drawing it is fourteen, filming it is about a
dollar.
2026-09-17 06:31:29 +00:00
a20ed2d57b trailer.html: pick a head writer, read the reviews, revise, film
The four scripts had no next step. Everything after "read them" lived in the
API and nothing on the page reached it.

The choice of head writer is the author's, and it is a judgement about concept
rather than a score, so it is a button on each tab rather than a leaderboard.
Naming the lead first also changes what the reviews are for: three models
arguing about how to fix THIS script is a more useful argument than three
models arguing about whose is better.

Reviews are split the way they come back - errors are things that are wrong
and are worth fixing, suggestions are matters of judgement, and "keeps" is
what a revision must not quietly remove. The author's shot notes outrank all
of it and the revise button says so.

Film is priced and gated on having a storyboard, because every shot needs an
opening frame to film from.
2026-09-17 03:08:17 +00:00
31b3474f8f book.html: list the trailers already run, because there was no way back
Once you navigated away from a trailer, the only route back to it was the URL.
The page offered a way to start work and no way to return to it, which meant
every finished run was effectively lost the moment you closed the tab.

The list leads with what someone actually wants to know at a glance - is it
finished, did every writer survive, has anything been drawn, what has it cost -
rather than with an id and a timestamp. A run still working shows what it is
doing and keeps polling, so this is also the page you land on to check
progress.

trailer.html gets a link back, so the two pages are a loop rather than a
one-way trip.
2026-09-17 02:48:38 +00:00
fa1992f200 book.html: let a book be named, because a filename is not a title
Uploading "Memory Road interior 12-28.pdf" produced a book, a run and a
storyboard all headed "Memory Road interior 12-28". The title is derived from
the filename because that is the only thing an upload carries, and publishers
name files after print runs.

Guessing harder is the wrong fix - stripping "interior 12-28" would be a rule
that works on one file. Letting the author type the title takes eight lines and
is right for every file. The author field goes in at the same time; it costs
nothing and a trailer should know whose book it is.
2026-09-17 02:43:12 +00:00
c6788afba5 trailer.html: draw the storyboard, and show the cast sheets
The draw button is live and priced from what that writer actually wrote -
three sheets a character plus an opening and a closing frame a shot - so a
14-shot trailer costs $3.33 and a 30-shot one costs more, rather than both
being quoted an average.

Cast sheets render as head/front/side, because they are the thing that stops a
face drifting between shots and the author should be able to reject a face
before seventy pictures are drawn from it.

Progress is per picture rather than a spinner: drawing takes minutes and a
spinner that might mean "working" or "hung" is worse than a count.
2026-09-17 02:23:59 +00:00
d1c9320966 book.html: a real Choose file button, and drop the paste box
"Drop the manuscript here or click to choose a file" is a drop zone pretending
to be a button - it reads as an instruction rather than a control, and on a
laptop nobody drags a file from anywhere. There is now an actual button. The
zone still accepts a drop, because that costs nothing once the button exists.

The paste box is gone. It was there for a manuscript that would not upload
cleanly, but a book is 100,000 words and nobody pastes that; keeping it meant
offering a route that only works for the case it was not for. Word and PDF
cover it, and a PDF that turns out to be a scan is refused with the reason.
2026-09-17 02:22:45 +00:00
d5e6df23d2 book.html: upload a manuscript and start a writers' room
Takes a .docx, a text .pdf or a .txt up to 6MB, or pasted text for anything
that will not upload cleanly. The upload itself only stores the file and writes
a row - extraction runs afterwards on the server, because ptl_api is
synchronous with a five second budget and parsing a novel is not a five second
job. The page polls until the book says ready, or says why it could not be
read.

readFileB64 lives here rather than in app.js: app.js's resizeImage goes through
an <img> and a canvas, which is right for a phone photo and fatal for a .docx,
and this is the only page that uploads a document.
2026-09-17 01:36:33 +00:00
5ea49c386c trailer.html: one tab per writer, with a play button and a note box
Reading a trailer tells you what happens; hearing it tells you the line is
four seconds too long and the grandmother sounds thirty. So the play button
ships before the draw button - speaking a whole trailer costs fractions of a
cent against five dollars to draw it - and it prints the spoken length against
the length the writer planned, which is the most common fault in these scripts.

The note box saves as you stop typing. A note you have to remember to save is
a note that gets lost when you switch tabs.

The draw button is priced from what the writer actually wrote - three sheets a
character plus an opening and a closing frame a shot - rather than from an
estimate, and is disabled until that stage lands.
2026-09-17 01:35:29 +00:00
a24f8182f7 Remove the spliced duplicate, part 1 of 4
The page has carried a commented-out copy of its own tail since a bad patch
spliced it in. It is inert, but 66KB of duplicated source in a file that gets
patched regularly is a hazard worth removing. Deleted in parts because the
patch API can only remove text by quoting all of it.
2026-09-15 03:55:51 +00:00
9f7114ddbb Remove the duplicated var price declaration from inside the head expression
The previous repair re-inserted "var price = ..." at the point it replaced,
which landed between "var head = '...'" and its continuation. Semicolon
insertion then ended the head statement early, so the price and everything
after it fell out of the string and head rendered as a bare opening div.

var price is already declared above; the continuation line just needs to follow
the head assignment directly.
2026-09-15 02:27:11 +00:00
dc336db708 Repair the page a bad patch doubled, and fix the price properly
My previous patch put a dollar sign next to a quote in the REPLACEMENT text.
That is a substitution token, so the whole rest of the file was spliced in and
script.html went from 82KB to 148KB with render() cut in half. Writing it as a
$ escape did not avoid it either - that is decoded before the substitution
runs and springs exactly the same trap.

- The broken line is restored, with the currency sign as the HTML entity &#36;
  which contains no dollar character at all.
- The spliced duplicate is commented out to end of file. The live copy is the
  one above it, so every future anchor still matches the live code first.
- Price now comes from the fresh quote get_project returns rather than the
  price_usd stamped on the row at creation, which ignored the markup change.

Patch order matters here: the corrected line itself contains the fragment text,
so the fragment is dealt with first.
2026-09-15 02:26:12 +00:00