From 63952912b5d468e81a676e5a057eb4a237a6ba3a Mon Sep 17 00:00:00 2001 From: Tom Boullay Date: Mon, 1 Jun 2026 14:14:27 +0200 Subject: [PATCH] fix(world): wrap stage and player in suspense to prevent scene remount Late asset loads inside GameStageContent (e.g. EbikeSpeedometer's useTexture) and the spawn-player block were bubbling Suspense up to the root boundary in pages/page.tsx, which unmounted World mid-load and triggered a redundant octree rebuild + shadow re-config. Localize the suspension by wrapping each block in its own Suspense fallback. Also mount DebugOctreeVisualization conditionally on the new debug toggle. --- src/world/World.tsx | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/world/World.tsx b/src/world/World.tsx index c29e0ab..0b45210 100644 --- a/src/world/World.tsx +++ b/src/world/World.tsx @@ -9,12 +9,16 @@ import { useCameraMode } from "@/hooks/debug/useCameraMode"; import { useEnvironmentDebug } from "@/hooks/debug/useEnvironmentDebug"; import { useMapPerformanceDebug } from "@/hooks/debug/useMapPerformanceDebug"; import { useCharacterDebug } from "@/hooks/debug/useCharacterDebug"; +import { useDebugVisualsDebug } from "@/hooks/debug/useDebugVisualsDebug"; import { useSceneMode } from "@/hooks/debug/useSceneMode"; import { useHandTrackingSnapshot } from "@/hooks/handTracking/useHandTrackingSnapshot"; import { useWorldSceneLoading } from "@/hooks/world/useWorldSceneLoading"; import { useGameStore } from "@/managers/stores/useGameStore"; +import { useDebugVisualsStore } from "@/managers/stores/useDebugVisualsStore"; import { DebugCameraControls } from "@/components/debug/scene/DebugCameraControls"; import { DebugHelpers } from "@/components/debug/scene/DebugHelpers"; +import { DebugOctreeVisualization } from "@/components/debug/DebugOctreeVisualization"; +import { DebugPlayerModel } from "@/components/debug/DebugPlayerModel"; import { HandTrackingGlove } from "@/components/three/handTracking/HandTrackingGlove"; import { Environment } from "@/world/Environment"; import { GameCinematics } from "@/world/GameCinematics"; @@ -36,10 +40,15 @@ export function World({ onLoadingStateChange }: WorldProps): React.JSX.Element { useEnvironmentDebug(); useMapPerformanceDebug(); useCharacterDebug(); + useDebugVisualsDebug(); const cameraMode = useCameraMode(); const sceneMode = useSceneMode(); const mainState = useGameStore((state) => state.mainState); + const showDebugPlayerModel = useDebugVisualsStore( + (state) => state.showPlayerModel, + ); + const showDebugOctree = useDebugVisualsStore((state) => state.showOctree); const { status, usageStatus } = useHandTrackingSnapshot(); const { octree, @@ -48,9 +57,6 @@ export function World({ onLoadingStateChange }: WorldProps): React.JSX.Element { handleGameStageLoaded, handleGameMapLoaded, handleOctreeReady, - handleShadowWarmupReady, - handleShadowWarmupStarted, - shouldWarmUpShadows, } = useWorldSceneLoading({ sceneMode, onLoadingStateChange }); const playerSpawnPosition = sceneMode === "game" @@ -65,15 +71,15 @@ export function World({ onLoadingStateChange }: WorldProps): React.JSX.Element { return ( <> - + + {showDebugOctree ? : null} + {showDebugPlayerModel ? ( + + + + ) : null} {showHandTrackingGloves ? ( @@ -92,11 +98,13 @@ export function World({ onLoadingStateChange }: WorldProps): React.JSX.Element { {showGameStage ? ( - + + + ) : null} {spawnPlayer ? ( - <> + {mainState === "outro" ? : null} {mainState !== "intro" ? : null} @@ -105,7 +113,7 @@ export function World({ onLoadingStateChange }: WorldProps): React.JSX.Element { octree={octree} spawnPosition={playerSpawnPosition} /> - + ) : null} ) : (