Commit graph

213 commits

Author SHA1 Message Date
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
2467b779b0 Show a freshly computed price, not the one stamped at creation
price_usd is written onto the project row when it is created, so changing the
markup constant left every existing project quoting the old number - the page
still said 40.85 after the server had recomputed it to 8.13.

get_project already returns a fresh quote. Use it, and fall back to the stored
value only for a response that predates it.
2026-09-15 02:15:07 +00:00
10c1541dbc Clamp the view to what the stepper allows, not to the stage
Making step 3 clickable was not enough: render clamped VIEW back down to the
project's stage on every draw, so the click set VIEW = 3 and the redraw
immediately put it back to 2. The Filming panel stayed unreachable.
2026-09-15 02:06:51 +00:00
4292624eda Wire the Remove cutaway button
Clears the cutaway from the shot so it is not cut into the film. The subject
stays, so Make cutaway can try again with a different draw.
2026-09-15 02:05:20 +00:00
58ccf6fc6d Layout view: stop crying wolf on short shots, allow removing a cutaway, make filming reachable
- "off the clock" fired on ANY shot not within 1.2s of the clip length, so a
  7.0s line in a 10s shot was flagged alongside a genuine 11.4s overrun. Under
  is fine - the engine finishes early and waits. Only an overrun gets cut off
  mid-word, and only that is now flagged, as "runs long".
- A cutaway could be made or remade but never removed, and the subject is the
  writer's guess so it is often wrong. There is now a Remove button.
- The Filming step was disabled until the project was already filming, so the
  only way to start was a button at the bottom of the Layout page. Approved now
  reaches step 3.
- "Cutting to the clock ... rewrites how the lines are divided" is no longer
  true - it measures and no longer moves boundaries, because Setup shots does
  the division locally. Copy corrected.
- "speaking the words costs about a hundredth of a cent" was wrong by three
  orders of magnitude; a measured run is about 16 cents.
2026-09-15 02:05:07 +00:00
70fa5ae9bb Split Setup shots from Script audio; name the voice; drop the rewrite cap
The one button did two unrelated jobs and showed the result of neither.

- Setup shots is now local division only: Python at the engine's own measured
  speaking rate, ~500ms, free, no LLM and no TTS. Answers "divide with local
  code, because each voice has a different cadence".
- Script audio is a separate button that reads it aloud AND SHOWS THE PLAYER.
  The audio was always being made and uploaded, then rendered into #alignout,
  which only exists on the Layout view - so pressing the button on the Words
  view produced fifteen seconds of nothing.
- The voice is now named. With an Omni engine the film ships Omni's own native
  voice, so the ElevenLabs read-through is a stand-in and says so.
- Rewrites are no longer capped at three. The real cost from OpenRouter is
  shown beside the buttons, added to the bill at cost with no markup.
- "Approve and lock it" now explains what it does.
2026-09-14 23:26:01 +00:00
076621f809 Setup shots: quote the real TTS cost, not "about a cent"
A measured run of the 80s NIMBY script came back at $0.1589 for 946 characters
- the ElevenLabs rate of $22 per 131,000 - so the copy understated it by more
than tenfold. Compute it from the words actually in the box instead.
2026-09-14 23:00:30 +00:00
30fde992dc Review page: the narrative first, the controls under it, the shots cut on request
The whole piece is now editable at the top of the review page, the rewrite
controls sit directly under it rather than below eight shot cards, and cutting
the narrative into shots is an explicit Setup shots button.

- narrative editable via set_narrative; shots marked stale until re-cut
- writer dropdown (Grok 4.6/4.5, Claude Opus 5/Sonnet 5, GPT-5.6/5.5, Gemini 3.1)
- align no longer runs unasked on page load, which spoke the script and moved
  every shot boundary for a cent nobody asked to spend
- align's fit check reads shot length from the model instead of assuming 8s,
  which reported every Omni shot 2s short
2026-09-14 22:55:33 +00:00
f19c3ea88b create: disable shot counts an engine cannot produce 2026-09-14 19:10:56 +00:00
a5174a3546 remove the dollar-token probe file 2026-09-14 13:36:00 +00:00
bf4cc12b2f script: rebuild part 6 of 6 - corruption repaired 2026-09-14 13:35:32 +00:00
dd1ad70fb7 script: rebuild part 5 of 6 2026-09-14 13:34:44 +00:00
7ce21f6621 script: rebuild part 4 of 6 2026-09-14 13:33:51 +00:00
0dabc60006 script: rebuild part 3 of 6 2026-09-14 13:32:57 +00:00
ab1027e6db script: rebuild part 2 of 6 2026-09-14 13:32:01 +00:00
9250a559c3 script: rebuild part 1 of 3 (repairing $' corruption) 2026-09-14 13:29:39 +00:00
b3c2128a44 scratch: probe before-match token 2026-09-14 13:26:46 +00:00
ad79f668bf scratch: confirm backtick token exposes text before the match 2026-09-14 13:26:03 +00:00
b1af9ad85b scratch: probe dollar-token behaviour in replacements 2026-09-14 13:24:17 +00:00
46b35556f9 scratch: determine how patch replacement handles dollar tokens 2026-09-14 13:24:12 +00:00
d8746810cc script: price and duration follow the project's render model, not a fixed 8s 2026-09-14 13:14:13 +00:00
dd92ed7aba create: choose the render model; length and price follow it 2026-09-14 02:54:56 +00:00
0daf74cfac admin: name the engine that filmed each shot, not always Veo 2026-09-14 02:54:09 +00:00
aed4812b7e admin: redub is opt-in now, so the switch reads that way round 2026-09-10 14:00:41 +00:00
58c8e92c3a pets: the voice description Veo is given is now selectable and editable 2026-09-10 13:13:20 +00:00
89b78e5ae2 admin: show the filmed date beside the created date 2026-09-10 12:52:10 +00:00
17fe951397 videos: show when it was filmed, not only when it was submitted 2026-09-10 12:52:03 +00:00
ddf6056d43 admin: copy the prompt, and list the renditions derived from the master 2026-09-10 12:22:16 +00:00
30da437300 admin: show the delivery direction, the request actually sent, and a redub switch 2026-09-10 01:15:49 +00:00
f6f1335fff Use the rendered share address here too
The link in the message under the picture now comes from share_link, which
returns the worker-rendered page rather than a guessed path on this site.
2026-09-09 02:21:45 +00:00
6b7ef08fcc Share links come from the worker now, not from a published file
Publishing wrote an HTML file into this repository and triggered a full site
deploy on every share. The page is now rendered per request on its own
hostname, so there is nothing to publish: share_link just marks the video
shared and hands back the address.
2026-09-09 02:21:33 +00:00
7407a945ac remove routing probe 2026-09-09 02:02:00 +00:00
abb070d845 remove routing probe 2026-09-09 02:01:59 +00:00
60ce736a06 remove routing probe 2026-09-09 02:01:57 +00:00
77d76f1d7f Share the page that has preview tags, not the JavaScript route
Preview crawlers do not run JavaScript, so the /v/<code> route — which is the
home page plus a client-side redirect — gives them nothing. The published
/v/<code>.html page carries real og:image, og:video and a real video element in
the served source. Five characters longer, and the difference between a card
someone taps and a bare grey link.
2026-09-09 02:01:08 +00:00
25ad188e99 Share page for Astro Formally Protests Cleaning Robots 2026-09-09 02:00:05 +00:00
3690278211 probe 2026-09-09 01:57:00 +00:00
5a409e943f Second routing probe: an explicit .html file per code
Directory indexes fall back to the root page, but files with an extension are
served directly. If this resolves, per-video pages with real Open Graph tags in
the head are possible on a static host, at the cost of five characters.
2026-09-09 01:55:42 +00:00
8a5f3a7b1b Routing probe: does a per-code directory index serve at /v/<code>?
Throwaway file to establish whether static per-video pages with baked-in
Open Graph tags can live at the short URL, or whether the host will keep
falling back to the root index.
2026-09-09 01:55:10 +00:00
755e831891 Share the short link here too, and show the view count
The message under the picture now carries the tracked link rather than the raw
file, and the card reports how many times it has been opened.
2026-09-09 01:14:55 +00:00