@@ -66,8 +66,33 @@ function MikuMondayContent() {
6666 } , [ currentAlert , rouletteGroups ] ) ;
6767
6868 const [ stage , setStage ] = useState < StageKey > ( "waiting" ) ;
69+ const [ isVideoVisible , setIsVideoVisible ] = useState ( false ) ;
6970 const waitingTimeoutRef = useRef < number | null > ( null ) ;
7071 const stageSyncTimeoutRef = useRef < number | null > ( null ) ;
72+ const videoRef = useRef < HTMLVideoElement | null > ( null ) ;
73+
74+ // Предзагружаем видео при монтировании компонента
75+ useEffect ( ( ) => {
76+ const video = videoRef . current ;
77+ if ( video ) {
78+ video . load ( ) ; // Начинаем загрузку видео
79+ }
80+ } , [ ] ) ;
81+
82+ // Управление воспроизведением видео
83+ useEffect ( ( ) => {
84+ const video = videoRef . current ;
85+ if ( ! video ) return ;
86+
87+ if ( isVideoVisible ) {
88+ video . currentTime = 0 ; // Сбрасываем на начало
89+ video . play ( ) . catch ( err => {
90+ console . warn ( "[MikuMonday] Не удалось воспроизвести видео:" , err ) ;
91+ } ) ;
92+ } else {
93+ video . pause ( ) ;
94+ }
95+ } , [ isVideoVisible ] ) ;
7196
7297 useEffect (
7398 ( ) => ( ) => {
@@ -98,6 +123,7 @@ function MikuMondayContent() {
98123 setStage ( previousStage =>
99124 previousStage === "waiting" ? "intro" : previousStage
100125 ) ;
126+ setIsVideoVisible ( true ) ;
101127 stageSyncTimeoutRef . current = null ;
102128 } , 0 ) ;
103129 return ;
@@ -140,6 +166,7 @@ function MikuMondayContent() {
140166 displayName : currentAlert ?. twitchUser . displayName ,
141167 trackNumber : currentAlert ?. selectedTrack . number ,
142168 } ) ;
169+ setIsVideoVisible ( false ) ;
143170 setStage ( "waiting" ) ;
144171 if ( waitingTimeoutRef . current !== null ) {
145172 window . clearTimeout ( waitingTimeoutRef . current ) ;
@@ -161,16 +188,45 @@ function MikuMondayContent() {
161188 } , QUEUE_PAUSE_MS ) ;
162189 } , [ dequeueCurrent , currentAlert ] ) ;
163190
191+ // Видео-фон существует постоянно, чтобы не перемонтироваться между стейджами
192+ const videoBackground = (
193+ < div
194+ className = { `${ styles . videoBackground } ${ isVideoVisible ? styles . videoVisible : styles . videoHidden } ` }
195+ >
196+ < video
197+ ref = { videoRef }
198+ src = "/static/miku.mp4"
199+ preload = "auto"
200+ muted
201+ playsInline
202+ loop
203+ style = { {
204+ position : "absolute" ,
205+ top : "50%" ,
206+ left : "50%" ,
207+ minWidth : "100%" ,
208+ minHeight : "100%" ,
209+ width : "auto" ,
210+ height : "auto" ,
211+ transform : "translate(-50%, -50%)" ,
212+ objectFit : "cover" ,
213+ pointerEvents : "none" ,
214+ } }
215+ />
216+ </ div >
217+ ) ;
218+
219+ // Рендерим контент в зависимости от стейджа
220+ let stageContent ;
221+
164222 if ( ! currentAlert || stage === "waiting" ) {
165- return (
223+ stageContent = (
166224 < div className = { styles . layout } >
167225 < WaitingStage onComplete = { ( ) => { } } />
168226 </ div >
169227 ) ;
170- }
171-
172- if ( stage === "intro" ) {
173- return (
228+ } else if ( stage === "intro" ) {
229+ stageContent = (
174230 < div className = { styles . layout } >
175231 < IntroStage
176232 twitchUser = { currentAlert . twitchUser }
@@ -179,40 +235,41 @@ function MikuMondayContent() {
179235 />
180236 </ div >
181237 ) ;
182- }
183-
184- if ( stage === "roulette" ) {
185- return (
238+ } else if ( stage === "roulette" ) {
239+ stageContent = (
186240 < RouletteStage
187241 rouletteGroups = { rouletteGroups }
188242 shouldSkipAvailableTracksUpdate = { shouldSkipAvailableTracksUpdate }
189243 decrementAvailableTrack = { decrementAvailableTrack }
190244 onComplete = { handleRouletteComplete }
191245 />
192246 ) ;
247+ } else {
248+ const trackToDisplay = winnerTrack ?? currentAlert . selectedTrack ;
249+ console . log ( "[MikuMonday] 📺 Отправляем трек в ResultStage" , {
250+ trackId : trackToDisplay . id ,
251+ trackNumber : trackToDisplay . number ,
252+ trackTitle : trackToDisplay . title ,
253+ trackArtist : trackToDisplay . artist ,
254+ isWinnerTrack : winnerTrack !== undefined ,
255+ winnerGroupExists : rouletteGroups . some ( g => g . hasWinner ) ,
256+ } ) ;
257+ stageContent = (
258+ < div className = { styles . layout } >
259+ < ResultStage
260+ track = { trackToDisplay }
261+ twitchUser = { currentAlert . twitchUser }
262+ onComplete = { handleResultComplete }
263+ />
264+ </ div >
265+ ) ;
193266 }
194267
195268 return (
196- < div className = { styles . layout } >
197- { ( ( ) => {
198- const trackToDisplay = winnerTrack ?? currentAlert . selectedTrack ;
199- console . log ( "[MikuMonday] 📺 Отправляем трек в ResultStage" , {
200- trackId : trackToDisplay . id ,
201- trackNumber : trackToDisplay . number ,
202- trackTitle : trackToDisplay . title ,
203- trackArtist : trackToDisplay . artist ,
204- isWinnerTrack : winnerTrack !== undefined ,
205- winnerGroupExists : rouletteGroups . some ( g => g . hasWinner ) ,
206- } ) ;
207- return (
208- < ResultStage
209- track = { trackToDisplay }
210- twitchUser = { currentAlert . twitchUser }
211- onComplete = { handleResultComplete }
212- />
213- ) ;
214- } ) ( ) }
215- </ div >
269+ < >
270+ { videoBackground }
271+ { stageContent }
272+ </ >
216273 ) ;
217274}
218275
0 commit comments