improved audio effect fix

This commit is contained in:
Dmitri 2026-06-04 11:08:23 +02:00
parent 58ebeea23b
commit 33a4abe45f

View File

@ -83,9 +83,9 @@ export function useAudioEffects({
const wasHoveredRef = useRef(false);
const wasActiveRef = useRef(false);
// Track if initial state sync is complete (skip audio on first render)
// User can't hover during mount, so any true state is stale
const didInitRef = useRef(false);
// Delay audio playback after mount/reset to avoid browser autoplay policy
// User can't hover during mount, so any true state within 100ms is stale
const [canPlay, setCanPlay] = useState(false);
// Track which URLs we've already fetched to prevent duplicate fetches
const lastFetchedHoverUrlRef = useRef<string | null>(null);
@ -99,6 +99,18 @@ export function useAudioEffects({
const [hoverAudioReady, setHoverAudioReady] = useState(false);
const [clickAudioReady, setClickAudioReady] = useState(false);
// Enable audio playback after short delay to skip stale state at mount
// Any hover/active state within 100ms of mount is not from real user interaction
useEffect(() => {
setCanPlay(false);
wasHoveredRef.current = isHovered;
wasActiveRef.current = isActive;
const timer = setTimeout(() => setCanPlay(true), 100);
return () => clearTimeout(timer);
// Only reset on resetKey change, not on isHovered/isActive changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [resetKey]);
// Initialize hover audio element - fetch with credentials for auth
useEffect(() => {
if (!hoverAudioUrl) {
@ -242,15 +254,9 @@ export function useAudioEffects({
// Play hover audio when hover starts (plays to completion, not interrupted)
useEffect(() => {
// Skip audio on initial render - sync state only
// User can't hover during mount, so any true state is stale
if (!didInitRef.current) {
didInitRef.current = true;
wasHoveredRef.current = isHovered;
return;
}
// Only play if: canPlay is true, hover changed from false→true, audio is ready
if (
canPlay &&
isHovered &&
!wasHoveredRef.current &&
hoverAudioRef.current &&
@ -265,18 +271,13 @@ export function useAudioEffects({
});
}
wasHoveredRef.current = isHovered;
}, [isHovered, hoverAudioReady]);
}, [canPlay, isHovered, hoverAudioReady]);
// Play click audio when active state begins
useEffect(() => {
// Skip audio on initial render - sync state only
// Note: didInitRef is already set by hover effect due to effect ordering
if (!didInitRef.current) {
wasActiveRef.current = isActive;
return;
}
// Only play if: canPlay is true, active changed from false→true, audio is ready
if (
canPlay &&
isActive &&
!wasActiveRef.current &&
clickAudioRef.current &&
@ -289,7 +290,7 @@ export function useAudioEffects({
});
}
wasActiveRef.current = isActive;
}, [isActive, clickAudioReady]);
}, [canPlay, isActive, clickAudioReady]);
// Manual click audio trigger
const playClickAudio = useCallback(() => {
@ -312,12 +313,10 @@ export function useAudioEffects({
}
}, []);
// Reset audio on key change (e.g., page navigation or element change)
// Stop audio on key change (e.g., page navigation or element change)
// Note: canPlay and refs are reset in the canPlay effect above
useEffect(() => {
stopAll();
wasHoveredRef.current = false;
wasActiveRef.current = false;
didInitRef.current = false; // Reset for new element
}, [resetKey, stopAll]);
return { playClickAudio, stopAll };