From e27d1f5c8d12cb36f200ae522e498134b49e436a Mon Sep 17 00:00:00 2001 From: kcar Date: Thu, 21 May 2026 18:17:52 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20prevent=20TLDraw=20topOffset=20crash=20?= =?UTF-8?q?=E2=80=94=20decouple=20store=20init=20from=20editor=20ready?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three changes to singlePlayerPage: 1. Store creation no longer waits for isEditorReady. The editor ref is already passed as optional to NavigationSnapshotService and loadNodeSnapshotFromDatabase, so we can create and populate the store without needing the editor to be mounted first. 2. only renders when store is defined: {store && }. Previously it rendered immediately with store={undefined}, which caused TLDraw to initialize with no backing store and crash reading topOffset on an unresolved internal object. 3. Loading guard also checks !user so the component never renders with a null profile before the redirect effect fires. Co-Authored-By: Claude Sonnet 4.6 --- src/pages/tldraw/singlePlayerPage.tsx | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/pages/tldraw/singlePlayerPage.tsx b/src/pages/tldraw/singlePlayerPage.tsx index 569269a..7ccf24c 100644 --- a/src/pages/tldraw/singlePlayerPage.tsx +++ b/src/pages/tldraw/singlePlayerPage.tsx @@ -85,23 +85,13 @@ export default function SinglePlayerPage() { setUserPreferences: setTldrawPreferences }); - // Initialize store + // Initialize store — runs as soon as user is ready, no editor needed for store creation useEffect(() => { - if (!isEditorReady) { - logger.debug('single-player-page', '⏳ Waiting for editor to be ready'); - return; - } - if (!user) { logger.debug('single-player-page', '⏳ Waiting for user data'); return; } - if (!editorRef.current) { - logger.debug('single-player-page', '⏳ Waiting for editor ref'); - return; - } - logger.info('single-player-page', '🔄 Starting store initialization', { isEditorReady, hasUser: !!user, @@ -221,7 +211,7 @@ export default function SinglePlayerPage() { }; initializeStoreAndSnapshot(); - }, [isEditorReady, user, context.node]); + }, [user, context.node]); // Handle initial node placement useEffect(() => { @@ -451,7 +441,7 @@ export default function SinglePlayerPage() { const uiComponents = getUiComponents(presentationMode); // Show loading state if user context is still loading - if (userLoading) { + if (userLoading || !user) { return (
- + />}
); }