From 1ad0c4de376d34990744b6f7ee947b5dc53bd64a Mon Sep 17 00:00:00 2001 From: Tom Boullay Date: Mon, 1 Jun 2026 14:14:03 +0200 Subject: [PATCH] revert(ui): remove narrator video on talkie --- public/assets/world/UI/talkie-video.mp4 | 3 - src/components/ui/TalkieDialogueOverlay.tsx | 198 +++----------------- src/index.css | 48 +++-- 3 files changed, 48 insertions(+), 201 deletions(-) delete mode 100644 public/assets/world/UI/talkie-video.mp4 diff --git a/public/assets/world/UI/talkie-video.mp4 b/public/assets/world/UI/talkie-video.mp4 deleted file mode 100644 index 541ed63..0000000 --- a/public/assets/world/UI/talkie-video.mp4 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:15ee3608d9d07029de48373fbafa0cb36effd25a68d2ae9dade8aaf03512d164 -size 288088 diff --git a/src/components/ui/TalkieDialogueOverlay.tsx b/src/components/ui/TalkieDialogueOverlay.tsx index 7d75a4a..d28c2cc 100644 --- a/src/components/ui/TalkieDialogueOverlay.tsx +++ b/src/components/ui/TalkieDialogueOverlay.tsx @@ -4,81 +4,20 @@ import { useGLTF } from "@react-three/drei"; import * as THREE from "three"; import { useGameStore } from "@/managers/stores/useGameStore"; import { useSubtitleStore } from "@/managers/stores/useSubtitleStore"; -import { GAME_STEPS } from "@/data/game/gameStateConfig"; -import type { Vector3Tuple } from "@/types/three/three"; const TALKIE_MODEL_PATH = "/models/talkie/model.gltf"; -const TALKIE_VIDEO_PATH = "/assets/world/UI/talkie-video.mp4"; -const TALKIE_FIRST_VISIBLE_STEP = "reveal"; -const TALKIE_FIRST_VISIBLE_STEP_INDEX = GAME_STEPS.indexOf( - TALKIE_FIRST_VISIBLE_STEP, -); +const TALKIE_REVEAL_STEPS = new Set([ + "reveal", + "await-ebike-mount", + "ebike-intro-ride", + "ebike-breakdown", + "completed", +]); -const TALKIE_REST_Y = -1.55; -const TALKIE_ACTIVE_Y = -0.92; -const TALKIE_BASE_ROTATION: Vector3Tuple = [0.08, -0.52, -0.04]; -const TALKIE_FLOAT_ROTATION_AMPLITUDE = THREE.MathUtils.degToRad(2.2); -const TALKIE_FLOAT_Y_AMPLITUDE = 0.055; -const TALKIE_SCREEN_TEXTURE_SIZE = 512; - -interface TalkieModelProps { - active: boolean; -} - -interface TalkieVideoResources { - canvas: HTMLCanvasElement; - context: CanvasRenderingContext2D | null; - material: THREE.MeshBasicMaterial; - texture: THREE.CanvasTexture; - video: HTMLVideoElement; -} - -function createTalkieVideoResources(): TalkieVideoResources { - const video = document.createElement("video"); - video.src = TALKIE_VIDEO_PATH; - video.crossOrigin = "anonymous"; - video.loop = true; - video.muted = true; - video.playsInline = true; - video.preload = "auto"; - - const canvas = document.createElement("canvas"); - canvas.width = TALKIE_SCREEN_TEXTURE_SIZE; - canvas.height = TALKIE_SCREEN_TEXTURE_SIZE; - const context = canvas.getContext("2d"); - const texture = new THREE.CanvasTexture(canvas); - texture.colorSpace = THREE.SRGBColorSpace; - texture.flipY = false; - texture.needsUpdate = true; - const material = new THREE.MeshBasicMaterial({ - map: texture, - toneMapped: false, - }); - - return { canvas, context, material, texture, video }; -} - -function TalkieModel({ active }: TalkieModelProps): React.JSX.Element { +function TalkieModel(): React.JSX.Element { const { scene } = useGLTF(TALKIE_MODEL_PATH); const model = useMemo(() => scene.clone(true), [scene]); const groupRef = useRef(null); - const screenRef = useRef(null); - const originalScreenMaterialRef = useRef(null); - const videoResourcesRef = useRef(null); - - useEffect(() => { - const videoResources = createTalkieVideoResources(); - videoResourcesRef.current = videoResources; - - return () => { - videoResources.video.pause(); - videoResources.video.removeAttribute("src"); - videoResources.video.load(); - videoResources.texture.dispose(); - videoResources.material.dispose(); - videoResourcesRef.current = null; - }; - }, []); useEffect(() => { model.traverse((child) => { @@ -88,119 +27,38 @@ function TalkieModel({ active }: TalkieModelProps): React.JSX.Element { child.frustumCulled = false; } }); - - const screen = model.getObjectByName("écran"); - if (screen instanceof THREE.Mesh) { - screenRef.current = screen; - originalScreenMaterialRef.current = Array.isArray(screen.material) - ? (screen.material[0] ?? null) - : screen.material; - } }, [model]); - useEffect(() => { - const screen = screenRef.current; - const originalMaterial = originalScreenMaterialRef.current; - const videoResources = videoResourcesRef.current; - - if (!videoResources) return; - - if (screen) { - screen.material = active - ? videoResources.material - : (originalMaterial ?? videoResources.material); - } - - if (active) { - void videoResources.video.play(); - return; - } - - videoResources.video.pause(); - }, [active]); - useFrame(({ clock }) => { if (!groupRef.current) return; const t = clock.getElapsedTime(); - const floatY = Math.sin(t * 1.2) * TALKIE_FLOAT_Y_AMPLITUDE; - const targetY = (active ? TALKIE_ACTIVE_Y : TALKIE_REST_Y) + floatY; - groupRef.current.position.y = THREE.MathUtils.lerp( - groupRef.current.position.y, - targetY, - 0.14, - ); - - groupRef.current.rotation.x = - TALKIE_BASE_ROTATION[0] + - Math.sin(t * 0.7) * TALKIE_FLOAT_ROTATION_AMPLITUDE; - groupRef.current.rotation.y = - TALKIE_BASE_ROTATION[1] + - Math.sin(t * 0.55) * TALKIE_FLOAT_ROTATION_AMPLITUDE; - groupRef.current.rotation.z = - TALKIE_BASE_ROTATION[2] + - Math.sin(t * 0.8) * TALKIE_FLOAT_ROTATION_AMPLITUDE; - - const videoResources = videoResourcesRef.current; - - if (active && videoResources?.context) { - const { canvas, context, texture, video } = videoResources; - context.fillStyle = "#02040a"; - context.fillRect(0, 0, canvas.width, canvas.height); - - if (video.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) { - const videoAspect = video.videoWidth / video.videoHeight; - const canvasAspect = canvas.width / canvas.height; - const drawWidth = - videoAspect > canvasAspect - ? canvas.width - : canvas.height * videoAspect; - const drawHeight = - videoAspect > canvasAspect - ? canvas.width / videoAspect - : canvas.height; - const drawX = (canvas.width - drawWidth) / 2; - const drawY = (canvas.height - drawHeight) / 2; - - context.drawImage(video, drawX, drawY, drawWidth, drawHeight); - } - - texture.needsUpdate = true; - } + groupRef.current.rotation.z = Math.sin(t * 22) * 0.025; + groupRef.current.position.y = Math.sin(t * 6) * 0.012; }); return ( - + ); } -interface TalkieSignalLinesProps { - side: "left" | "right"; -} - -function TalkieSignalLines({ - side, -}: TalkieSignalLinesProps): React.JSX.Element { +function TalkieSignalLines(): React.JSX.Element { return ( ); } @@ -209,23 +67,21 @@ export function TalkieDialogueOverlay(): React.JSX.Element | null { const activeSubtitle = useSubtitleStore((state) => state.activeSubtitle); const mainState = useGameStore((state) => state.mainState); const introStep = useGameStore((state) => state.intro.currentStep); - const introStepIndex = GAME_STEPS.indexOf(introStep); - const hasTalkieBeenRevealed = - mainState !== "intro" || introStepIndex >= TALKIE_FIRST_VISIBLE_STEP_INDEX; + const isAfterReveal = + mainState !== "intro" || TALKIE_REVEAL_STEPS.has(introStep); const isNarratorDialogue = activeSubtitle?.speaker === "Narrateur"; - if (!hasTalkieBeenRevealed) return null; + if (!isAfterReveal || !isNarratorDialogue) return null; return (