From b40dfe54b551bf7a87e088b4755231f709377677 Mon Sep 17 00:00:00 2001 From: Dmitri Date: Thu, 16 Apr 2026 09:28:57 +0400 Subject: [PATCH] go on with safari ui optimization --- .../src/components/RuntimePresentation.tsx | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/frontend/src/components/RuntimePresentation.tsx b/frontend/src/components/RuntimePresentation.tsx index 66f8540..c13a51a 100644 --- a/frontend/src/components/RuntimePresentation.tsx +++ b/frontend/src/components/RuntimePresentation.tsx @@ -42,6 +42,7 @@ import { useTransitionPlayback } from '../hooks/useTransitionPlayback'; import { useBackgroundTransition } from '../hooks/useBackgroundTransition'; import { useBackgroundUrls } from '../hooks/useBackgroundUrls'; import { resolveAssetPlaybackUrl } from '../lib/assetUrl'; +import { isSafari } from '../lib/browserUtils'; import { logger } from '../lib/logger'; import { resolveNavigationTarget, @@ -115,6 +116,11 @@ export default function RuntimePresentation({ initialIndex: number; } | null>(null); + // Safari Black Flash Prevention (video transitions only): + // Track the last successfully displayed background to use as a "snapshot" layer. + // Only shown during video transitions to prevent black flashes. + // NOT shown during crossfade navigation (would interfere with smooth animation). + const [lastKnownBgUrl, setLastKnownBgUrl] = useState(''); const transitionVideoRef = useRef(null); const lastInitializedPageIdRef = useRef(null); @@ -344,6 +350,20 @@ export default function RuntimePresentation({ } }, [pendingTransitionComplete, isBackgroundReady]); + // Safari Black Flash Prevention (video transitions only): + // Update lastKnownBgUrl when a background is successfully displayed. + // This creates a "snapshot" that persists through video transitions. + useEffect(() => { + if (isBackgroundReady && pageSwitch.isNewBgReady) { + if (pageSwitch.currentBgImageUrl) { + setLastKnownBgUrl(pageSwitch.currentBgImageUrl); + } + } + }, [ + isBackgroundReady, + pageSwitch.isNewBgReady, + pageSwitch.currentBgImageUrl, + ]); const navigateToPage = useCallback( async ( @@ -554,6 +574,25 @@ export default function RuntimePresentation({ }} > + {/* Safari Black Flash Prevention (video transitions only): + Persistent snapshot layer shown ONLY during video transitions. + NOT shown during crossfade navigation (would interfere with animation). + z-[-1] keeps it behind all dynamic content layers. */} + {lastKnownBgUrl && + isSafari() && + (transitionPreview || pendingTransitionComplete) && ( +
+ )} + {/* Page background wrapper - z-5 keeps it BELOW carousel slide (z-10). Fades in for non-transition navigation. Uses shared CanvasBackground component for single source of truth with constructor (same transitions, same structure). */}