The filmstrip fills in as it renders

A full build is a couple of minutes of GPU work, and the page spent all of it
showing an empty screen and then everything at once. The interesting failure —
a strip whose frames could be shuffled without anyone noticing — is visible in
the first row, so waiting for the seventeenth to look at the first is a
needlessly slow way to find it out.

Rows are appended as they land, in bank order, and re-sorted once at the end
when there is finally something to sort by. One row renderer handles both raw
pixels, which is what exists mid-build, and the compressed blobs the cache
holds afterwards, so what you watch appear is what you keep.

The song is announced BEFORE its render rather than only after it, too:
synthesising and rendering one is tens of seconds, and a page that says nothing
until the first one lands looks broken for exactly as long as that takes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Dejvino
2026-08-20 09:02:10 +02:00
co-authored by Claude Opus 5
parent 89e05459c0
commit 3a0cf26e6c
2 changed files with 83 additions and 35 deletions
+10 -1
View File
@@ -161,13 +161,22 @@ function momentAt(story, index) {
* times for nothing.
*/
export async function buildFilmstrip({
duration = DEFAULT_DURATION, every = DEFAULT_EVERY, names = null, onSong = null,
duration = DEFAULT_DURATION, every = DEFAULT_EVERY, names = null,
onSong = null, onSongStart = null,
} = {}) {
const list = names && names.length ? names : songNames();
const show = new Show({ ...STRIP });
const rows = [];
try {
for (let i = 0; i < list.length; i++) {
// Announced BEFORE the work, not only after it. Synthesising and
// rendering one song is tens of seconds, and a page that says
// nothing until the first one lands looks broken for exactly as
// long as the first one takes.
if (onSongStart) {
onSongStart(i + 1, list.length, list[i]);
await new Promise((r) => setTimeout(r, 0));
}
let row;
try {
row = renderSong(show, list[i], { duration, every });