0.40.0 — 2026-08-22
Projects stop living in one browser
A project now exists on the server rather than only on the device that made it — so it opens on a second machine, survives clearing site data, and every charge that ends in a failure comes back.
Features:
- A project is a row on the server and its footage is in a bucket. Until now projects were IndexedDB and OPFS: a film existed on the device that made it and nowhere else, so clearing site data lost it and a second device could not open it at all.
- A shared project is read-only until you clone it. The clone points at the same asset objects, so a hundred forks of one film cost one film's storage.
- An upload that usually does not happen. The key is the content hash, so the question before sending anything is whether it is already there — and for a clone, a re-import after a browser was cleared, or two people with the same footage, it is.
- The dashboard is told about any change as it happens, over server-sent events rather than by asking repeatedly.
- The mini app plans a month before it films anything. It used to open on "describe your film", which is stage five of the workflow — no company, no month, and nothing anyone could approve.
- Filming carries on when the phone is gone.
- One tap past the voice gate. The dead end it produced was reported from a full production run; the message was in fact correct, and the thing it asked for was the part that could not be done on a phone.
- A 500 says which one it was. Every failure now mints a short id, logs it, and writes it to a table that survives the next deploy — because the last outage was undiagnosable, and that was the fault worth fixing rather than the bug that triggered it.
- A build refuses to serve a database it cannot write to. The drift check was a command somebody had to remember to run, which is the same category of protection as a sticky note; it is a release gate now.
Improvements:
- 1080P on Seedance holds fifteen seconds, measured twice at 1920x1080 and 15.04s. The old ceiling was five because five was all anyone had tested, and the comment in the code said so.
Fixes:
- Every charge that is followed by a failure comes back. Measured on the Telegram route as two ten-token deductions for one delivered clip, and the same hole was in every other charging path — they all bill the provider first and can still throw afterwards.
- A generation that cannot start gives the tokens back.
- Cloud saving worked exactly once.
- Two different clocks were being compared, and a delete did not stick.
- A rename never reached the cloud.
- A document with no scenes stops bricking the project, and the server stops accepting documents that are not projects in the first place. Two projects created minutes apart opened to "No active scene." and stayed that way across every reload.
- The resolution shown is the resolution that comes back.
- A request too heavy for the model steps down instead of being bought and then refused.
- The drafter writes the captions it was always meant to. Measured across six real plans before anything was changed: two captions in thirty-one shots, and a film drafted as three title cards came back with all three cards blank.
- A finished film stops re-cutting itself every six seconds. It was not stuck because a cut had failed — it already had a finished film — it was stuck because it kept cutting.
- A new storyboard stops being filmed as the previous film.
- The bot says why it failed, instead of one sentence that fits every cause.
- A post learns it is finished from the film rather than from a phone, and a post's angle is the point of the post rather than a description of it.
Technical details:
- Four quota tests that were testing nothing. Reported as ordering flake, and it was worse than flake — they passed regardless of what the code did.