fix(perf): prevent Canvas double-mount on /site redirect
HomePage used to mount the Canvas before its effect fired the redirect to /site, then unmount it as soon as the route changed. That left the WebGL context torn down mid-load with GLTF requests still in flight, which on slow GPUs ended in a 'Context Lost' and a stuck 1 FPS render once the user came back from /site. The fix is a synchronous cookie check after all hooks: if the user has not visited /site today we return null and let the redirect happen without ever creating a GL context. Also drops the GameMap 'lite map skipped' log from warn to info: it is an expected lite-loading path, not a problem worth a yellow warning.
This commit is contained in:
+14
-8
@@ -19,17 +19,10 @@ import { hasSiteBeenVisitedToday } from "@/utils/cookies/siteVisitCookie";
|
||||
import { logger } from "@/utils/core/Logger";
|
||||
import { World } from "@/world/World";
|
||||
|
||||
export function HomePage(): React.JSX.Element {
|
||||
export function HomePage(): React.JSX.Element | null {
|
||||
const navigate = useNavigate();
|
||||
const introStep = useGameStore((state) => state.intro.currentStep);
|
||||
const setIntroStep = useGameStore((state) => state.setIntroStep);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasSiteBeenVisitedToday()) {
|
||||
navigate({ to: "/site", replace: true });
|
||||
}
|
||||
}, [navigate]);
|
||||
|
||||
const dialogMessage = useGameStore(
|
||||
(state) => state.missionFlow.dialogMessage,
|
||||
);
|
||||
@@ -38,6 +31,12 @@ export function HomePage(): React.JSX.Element {
|
||||
INITIAL_SCENE_LOADING_STATE,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hasSiteBeenVisitedToday()) {
|
||||
navigate({ to: "/site", replace: true });
|
||||
}
|
||||
}, [navigate]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!dialogMessage) return undefined;
|
||||
|
||||
@@ -98,6 +97,13 @@ export function HomePage(): React.JSX.Element {
|
||||
[],
|
||||
);
|
||||
|
||||
// Don't mount the Canvas until we know we will not redirect to /site.
|
||||
// Without this guard the Canvas would mount, the effect above would fire
|
||||
// navigate, and the Canvas would unmount mid-load — leaking GLTF requests
|
||||
// and a WebGL context. The synchronous cookie check happens here AFTER
|
||||
// all hooks (rules of hooks) but BEFORE any expensive render.
|
||||
if (!hasSiteBeenVisitedToday()) return null;
|
||||
|
||||
const renderIntroOverlay = () => {
|
||||
switch (introStep) {
|
||||
case "video":
|
||||
|
||||
@@ -175,7 +175,7 @@ export function GameMap({
|
||||
sceneData.mapNodes.length - visibleMapNodes.length;
|
||||
|
||||
if (skippedMapNodeCount > 0) {
|
||||
logger.warn("GameMap", "Lite map skipped heavy map nodes", {
|
||||
logger.info("GameMap", "Lite map skipped heavy map nodes", {
|
||||
skippedMapNodeCount,
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user