update: intro flow overlays

This commit is contained in:
Tom Boullay
2026-05-30 04:00:20 +02:00
parent a2cff0567e
commit ce5dc8ada0
5 changed files with 221 additions and 1 deletions
@@ -0,0 +1,50 @@
import { useEffect, useRef } from "react";
import { AudioManager } from "@/managers/AudioManager";
import { useGameStore } from "@/managers/stores/useGameStore";
const INTRO_DIALOGUE_PATH = "/sounds/dialogue/narrateur_ordreebike.mp3";
/**
* Black screen overlay with dialogue audio
* - Plays narrateur_ordreebike.mp3
* - Transitions to reveal step when dialogue ends
*/
export function IntroDialogueOverlay(): React.JSX.Element {
const setIntroStep = useGameStore((state) => state.setIntroStep);
const dialogueStarted = useRef(false);
useEffect(() => {
if (dialogueStarted.current) return;
dialogueStarted.current = true;
// Play dialogue then transition to reveal
const audio = AudioManager.getInstance();
audio.playSoundWithCallback(INTRO_DIALOGUE_PATH, 0.8, () => {
setIntroStep("reveal");
});
}, [setIntroStep]);
return (
<div
style={{
position: "fixed",
inset: 0,
background: "#000",
zIndex: 999,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<span
style={{
color: "rgba(255, 255, 255, 0.5)",
fontSize: 16,
fontFamily: "system-ui, sans-serif",
}}
>
...
</span>
</div>
);
}
@@ -0,0 +1,48 @@
import { useEffect, useState } from "react";
import { useGameStore } from "@/managers/stores/useGameStore";
const REVEAL_DURATION_MS = 2000;
/**
* Fade-out overlay for reveal transition
* - Starts fully black
* - Fades out to reveal the game world
* - Transitions to playing step when done
*/
export function IntroRevealOverlay(): React.JSX.Element {
const setIntroStep = useGameStore((state) => state.setIntroStep);
const completeIntro = useGameStore((state) => state.completeIntro);
const [opacity, setOpacity] = useState(1);
useEffect(() => {
// Start fade out
const fadeTimeout = window.setTimeout(() => {
setOpacity(0);
}, 100);
// Complete intro after fade
const completeTimeout = window.setTimeout(() => {
setIntroStep("playing");
completeIntro();
}, REVEAL_DURATION_MS);
return () => {
window.clearTimeout(fadeTimeout);
window.clearTimeout(completeTimeout);
};
}, [setIntroStep, completeIntro]);
return (
<div
style={{
position: "fixed",
inset: 0,
background: "#000",
opacity,
transition: `opacity ${REVEAL_DURATION_MS}ms ease-out`,
zIndex: 998,
pointerEvents: "none",
}}
/>
);
}
@@ -0,0 +1,80 @@
import { useCallback, useRef, useEffect } from "react";
import { useGameStore } from "@/managers/stores/useGameStore";
const INTRO_VIDEO_PATH = "/cinematics/intro.mp4";
/**
* Full-screen video player for intro cinematic
* - Plays intro.mp4 in fullscreen
* - Automatically advances to dialogue-intro step when video ends
* - Allows skipping with Enter/Space/Click
*/
export function IntroVideoPlayer(): React.JSX.Element {
const videoRef = useRef<HTMLVideoElement>(null);
const setIntroStep = useGameStore((state) => state.setIntroStep);
const handleVideoEnd = useCallback(() => {
setIntroStep("dialogue-intro");
}, [setIntroStep]);
const handleSkip = useCallback(() => {
if (videoRef.current) {
videoRef.current.pause();
}
setIntroStep("dialogue-intro");
}, [setIntroStep]);
// Handle keyboard skip (Enter/Space)
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault();
handleSkip();
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [handleSkip]);
return (
<div
onClick={handleSkip}
style={{
position: "fixed",
inset: 0,
background: "#000",
zIndex: 1000,
cursor: "pointer",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<video
ref={videoRef}
src={INTRO_VIDEO_PATH}
autoPlay
playsInline
onEnded={handleVideoEnd}
style={{
width: "100%",
height: "100%",
objectFit: "cover",
}}
/>
<span
style={{
position: "absolute",
bottom: 32,
right: 32,
color: "rgba(255, 255, 255, 0.6)",
fontSize: 14,
fontFamily: "system-ui, sans-serif",
}}
>
Appuyez pour passer
</span>
</div>
);
}
+3
View File
@@ -0,0 +1,3 @@
export { IntroVideoPlayer } from "./IntroVideoPlayer";
export { IntroDialogueOverlay } from "./IntroDialogueOverlay";
export { IntroRevealOverlay } from "./IntroRevealOverlay";