From e98db06102a8eacc30e26bd177b8aef6be13a83e Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sat, 16 May 2026 17:47:13 +0000 Subject: [PATCH 1/3] fix(app): eliminate 170ms session switch delay from deferRender + composer timeout Remove the deferRender mechanism that blanked the review panel and composer for one animation frame on every session switch. Remove the 140ms artificial setTimeout in session-composer-region that stacked on top, causing a total ~170ms gap where the composer was invisible. The composer now re-shows after a single rAF yield (~16ms). --- packages/app/src/pages/session.tsx | 10 ++-------- .../pages/session/composer/session-composer-region.tsx | 6 +----- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index 1e73ed590fc5..f1266e8062b5 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -536,12 +536,6 @@ export default function Page() { createComputed((prev) => { const key = sessionKey() - if (key !== prev) { - setStore("deferRender", true) - requestAnimationFrame(() => { - setTimeout(() => setStore("deferRender", false), 0) - }) - } return key }, sessionKey()) @@ -1124,7 +1118,7 @@ export default function Page() { loadingClass: string emptyClass: string }) => ( - + { inputRef = el diff --git a/packages/app/src/pages/session/composer/session-composer-region.tsx b/packages/app/src/pages/session/composer/session-composer-region.tsx index e6bfd05ec405..1829d83daaa2 100644 --- a/packages/app/src/pages/session/composer/session-composer-region.tsx +++ b/packages/app/src/pages/session/composer/session-composer-region.tsx @@ -99,7 +99,6 @@ export function SessionComposerRegion(props: { createEffect(() => { route.sessionKey() const ready = props.ready - const delay = 140 clear() setStore("ready", false) @@ -107,10 +106,7 @@ export function SessionComposerRegion(props: { frame = requestAnimationFrame(() => { frame = undefined - timer = window.setTimeout(() => { - setStore("ready", true) - timer = undefined - }, delay) + setStore("ready", true) }) }) From c53fb128aef881bcb9acd3bc112ba0efb3dba588 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sat, 16 May 2026 17:47:30 +0000 Subject: [PATCH 2/3] fix(app): prevent session switch from triggering Suspense splash screen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The sessionSync createResource was read in JSX ({sessionSync() ?? ""}), which triggered the nearest boundary (the app-level splash screen) on every session switch while the sync Promise was pending. Since the resource returns void (contributes nothing to the DOM), remove the JSX read entirely — the fetcher still runs reactively from its source signal regardless. --- packages/app/src/pages/session.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index f1266e8062b5..76b05a22bad4 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -749,7 +749,7 @@ export default function Page() { const hasScrollGesture = () => Date.now() - ui.scrollGesture < scrollGestureWindowMs - const [sessionSync] = createResource( + createResource( () => [sdk.directory, params.id] as const, ([directory, id]) => { if (refreshFrame !== undefined) cancelAnimationFrame(refreshFrame) @@ -1783,7 +1783,6 @@ export default function Page() { return (
- {sessionSync() ?? ""}
From e815cbd3ec21d4075beb98af88b42d42b0d47c62 Mon Sep 17 00:00:00 2001 From: Burak Yigit Kaya Date: Sat, 16 May 2026 17:47:49 +0000 Subject: [PATCH 3/3] =?UTF-8?q?fix(app):=20instant=20session=20switching?= =?UTF-8?q?=20=E2=80=94=20render=20immediately=20with=20cached=20session?= =?UTF-8?q?=20data?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Widen the messagesReady gate to allow rendering when the session exists in the session list, even before messages have loaded. This eliminates the blank screen on session switch over slow connections. A spinner is shown in the timeline while messages load in the background. --- packages/app/src/pages/session.tsx | 3 ++- packages/app/src/pages/session/message-timeline.tsx | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index 76b05a22bad4..9e79a99e4d28 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -450,7 +450,8 @@ export default function Page() { const messagesReady = createMemo(() => { const id = params.id if (!id) return true - return sync.data.message[id] !== undefined + // Ready if messages are loaded OR the session exists in the list (show immediately, load in background) + return sync.data.message[id] !== undefined || sync.session.get(id) !== undefined }) const historyMore = createMemo(() => { const id = params.id diff --git a/packages/app/src/pages/session/message-timeline.tsx b/packages/app/src/pages/session/message-timeline.tsx index 8bbaafb4e433..8f470fe65ddc 100644 --- a/packages/app/src/pages/session/message-timeline.tsx +++ b/packages/app/src/pages/session/message-timeline.tsx @@ -1021,6 +1021,11 @@ export function MessageTimeline(props: {
+ +
+ +
+
{(messageID) => { const active = createMemo(() => activeMessageID() === messageID)