From 6788de2f6eff041c6f50d24bd069239500cf8edb Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Sun, 23 Aug 2026 18:35:15 -0400 Subject: [PATCH] The chronicle remembers everything, and holds still while you read it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The game log's sixty-line window was a render cap, not a limit of what the client holds — a rejoin replays the whole game into memory. The chronicle now renders every line back to the deal, and its auto-scroll grows manners: it follows the newest line only while the reader sits at the bottom, and holds its place once they scroll up into history. Co-Authored-By: Claude Fable 5 --- packages/web/src/App.svelte | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/web/src/App.svelte b/packages/web/src/App.svelte index 7d055f3..81b79a7 100644 --- a/packages/web/src/App.svelte +++ b/packages/web/src/App.svelte @@ -1192,10 +1192,18 @@ ); let chronicleEl = $state(null); + /** The chronicle follows the newest line only while the reader is at + * the bottom; scrolled back into history, it holds still. */ + let chronicleStick = true; + function onChronicleScroll() { + if (!chronicleEl) return; + chronicleStick = + chronicleEl.scrollHeight - chronicleEl.scrollTop - chronicleEl.clientHeight < 60; + } $effect(() => { void net.log.length; void local.log.length; - if (chronicleEl) chronicleEl.scrollTop = chronicleEl.scrollHeight; + if (chronicleEl && chronicleStick) chronicleEl.scrollTop = chronicleEl.scrollHeight; }); // Tab title + favicon carry the turn signal even from another tab. @@ -2044,13 +2052,14 @@ -
+
{#if local.active} - {#each local.log.slice(-60) as line, i (i)} + {#each local.log as line, i (i)}
{line}
{/each} {:else} - {#each net.log.slice(-60) as line, i (i)} + {#each net.log as line, i (i)}
{line.text} {#if line.notable && line.turn !== null && prefs.instantReplay && !net.spectating}