diff --git a/apps/web/src/components/round-transition.tsx b/apps/web/src/components/round-transition.tsx new file mode 100644 index 0000000..3e4bef9 --- /dev/null +++ b/apps/web/src/components/round-transition.tsx @@ -0,0 +1,80 @@ +import { useEffect, useState } from "react" +import { createPortal } from "react-dom" +import { AnimatePresence, motion } from "framer-motion" + +const VISIBLE_MS = 1100 // durée d'affichage avant le wipe de sortie + +/** + * Transition "WarioWare" jouée entre les manches : wipe coloré plein écran, + * sunburst qui tourne, gros numéro de question qui rebondit, puis sortie. + * Montée avec une `key` qui change → rejoue à chaque manche. + */ +export function RoundTransition({ index }: { index: number }) { + const [show, setShow] = useState(true) + + useEffect(() => { + const t = setTimeout(() => setShow(false), VISIBLE_MS) + return () => clearTimeout(t) + }, []) + + return createPortal( + + {show && ( + + + + + + Question + + + {index + 1} + + + PRÊT ?! + + + + )} + , + document.body + ) +} diff --git a/apps/web/src/pages/room.tsx b/apps/web/src/pages/room.tsx index dc109ba..79e8212 100644 --- a/apps/web/src/pages/room.tsx +++ b/apps/web/src/pages/room.tsx @@ -7,12 +7,14 @@ import { GameEndView } from "@/components/game-end-view" import { PlayerCards } from "@/components/player-cards" import { RoomCode } from "@/components/room-code" import { Boom } from "@/components/boom" +import { RoundTransition } from "@/components/round-transition" export function RoomPage({ code }: { code: string }) { const snapshot = useRoomStore((s) => s.snapshot) const playerId = useRoomStore((s) => s.playerId) const connected = useRoomStore((s) => s.connected) const boomKey = useRoomStore((s) => s.boomKey) + const roundKey = useRoomStore((s) => s.roundKey) const voteProgress = useRoomStore((s) => s.voteProgress) // Pas de snapshot pour ce code (accès direct / refresh) : retour à l'accueil. @@ -61,6 +63,9 @@ export function RoomPage({ code }: { code: string }) { {boomKey > 0 && } + {roundKey > 0 && ( + + )} ) } diff --git a/apps/web/src/store/room.ts b/apps/web/src/store/room.ts index b1ca21e..70c7cb1 100644 --- a/apps/web/src/store/room.ts +++ b/apps/web/src/store/room.ts @@ -39,6 +39,8 @@ interface RoomState { finalScores: PlayerScore[] | null /** Compteur d'explosions : incrémenté à chaque fin de manche au timer (boom à 0). */ boomKey: number + /** Compteur de manches : incrémenté à chaque round:start (transition WarioWare). */ + roundKey: number createRoom: (playerName: string) => Promise joinRoom: (roomCode: string, playerName: string) => Promise @@ -61,6 +63,7 @@ export const useRoomStore = create((set, get) => ({ myChoiceIndex: null, finalScores: null, boomKey: 0, + roundKey: 0, createRoom: (playerName) => new Promise((resolve, reject) => { @@ -131,6 +134,7 @@ export const useRoomStore = create((set, get) => ({ myChoiceIndex: null, finalScores: null, boomKey: 0, + roundKey: 0, }), })) @@ -141,7 +145,7 @@ socket.on("room:state", (snapshot) => useRoomStore.setState({ snapshot })) socket.on("error", (error) => useRoomStore.setState({ lastError: error })) socket.on("round:start", (payload) => - useRoomStore.setState({ + useRoomStore.setState((s) => ({ round: { type: payload.type, djId: payload.djId, @@ -151,7 +155,8 @@ socket.on("round:start", (payload) => voteProgress: null, reveal: null, myChoiceIndex: null, - }) + roundKey: s.roundKey + 1, + })) ) socket.on("round:voteAck", (voteProgress) => useRoomStore.setState({ voteProgress })