From adb254c20b75aa5f4285909029861a1f8b2d2848 Mon Sep 17 00:00:00 2001 From: Simon Date: Tue, 22 Sep 2026 12:14:16 +0000 Subject: [PATCH] Keep the videos already playing when a panel is split Splitting or closing a panel changes the stride, which renumbers every step, so the slides are rebuilt -- and the rebuild threw away the panes along with them. Every video on screen was fetched and buffered again to show what it was already showing. The panes are now set aside by video id first, and whoever needs that video next takes the pane that already has it: the same element, the same stream, the frames it had already decoded. It all happens in one go without yielding, so a pane is never out of the document long enough to be paused for it. Panes the new layout has no place for are torn down as before -- they are holding a stream open. Pane tools are rebindable for the same reason: a reused pane comes back under a different node in the tree, and its old buttons would otherwise split and close the one it left. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01MPZFnNdHbPGDTqQUNiE4ZN --- frontend/js/feed.js | 70 +++++++- tests/smoke_split_reuse.py | 348 +++++++++++++++++++++++++++++++++++++ 2 files changed, 412 insertions(+), 6 deletions(-) create mode 100644 tests/smoke_split_reuse.py diff --git a/frontend/js/feed.js b/frontend/js/feed.js index f1b27e8..84f7876 100644 --- a/frontend/js/feed.js +++ b/frontend/js/feed.js @@ -653,7 +653,7 @@ App.feed = App.feed || {}; // around whatever video is playing so the reader keeps their place. const rebuildLayout = function() { const keepId = state.feedActiveVideoId; - teardownAllSlides(); + reserveSlides(); const videos = state.loadedVideos || []; let videoIndex = 0; if (keepId != null) { @@ -663,23 +663,66 @@ App.feed = App.feed || {}; state.feedActiveIndex = -1; const step = Math.floor(videoIndex / paneCount()); setActive(step); + releaseReserve(); const scroller = getScroller(); if (scroller) scroller.scrollTop = step * slideHeight(); }; - const teardownAllSlides = function() { + // ------------------------------------------------------------------ + // Reusing panes across a layout change + // + // Splitting or closing a panel changes the stride, so every step is + // renumbered and the slides have to be built again -- but the videos + // haven't changed. A pane already holds one: its