|
50 | 50 | let phase = 'phase1'; |
51 | 51 | let cutsceneDone = false; |
52 | 52 | let cutsceneSkipBound = false; |
| 53 | + let phase3ReadyToEnter = false; |
53 | 54 |
|
54 | 55 | function playVideo(video) { |
55 | 56 | video.currentTime = 0; |
|
59 | 60 | console.warn('[Cutscene] Video playback failed:', error); |
60 | 61 | }); |
61 | 62 | } |
| 63 | + return promise; |
| 64 | + } |
| 65 | + |
| 66 | + function setPrompt(message) { |
| 67 | + if (!pressPrompt) return; |
| 68 | + pressPrompt.textContent = message; |
| 69 | + pressPrompt.style.display = 'block'; |
| 70 | + pressPrompt.style.opacity = 1; |
| 71 | + } |
| 72 | + |
| 73 | + function hidePrompt() { |
| 74 | + if (!pressPrompt) return; |
| 75 | + pressPrompt.style.opacity = 0; |
62 | 76 | } |
63 | 77 |
|
64 | 78 | function show(to, from) { |
65 | | - playVideo(to); |
| 79 | + const playPromise = playVideo(to); |
66 | 80 | requestAnimationFrame(() => { |
67 | 81 | to.style.opacity = '1'; |
68 | 82 | if (from) { |
|
71 | 85 | }, { once: true }); |
72 | 86 | } |
73 | 87 | }); |
| 88 | + return playPromise; |
74 | 89 | } |
75 | 90 |
|
76 | 91 | function goToPhase3() { |
77 | 92 | if (phase === 'phase3' || phase === 'done') return; |
78 | 93 | const from = phase === 'loop' ? v2 : v1; |
79 | 94 | phase = 'phase3'; |
| 95 | + phase3ReadyToEnter = false; |
80 | 96 | v2.loop = false; |
81 | 97 | v2.pause(); |
82 | | - if (pressPrompt) pressPrompt.style.opacity = 0; |
83 | | - unbindCutsceneSkip(); |
84 | | - show(v3, from); |
85 | | - } |
86 | | - |
87 | | - function onCutsceneSkipInput(e) { |
88 | | - if (phase === 'phase3' || phase === 'done') return; |
89 | | - if (e.type === 'keydown' && e.code !== 'Space' && e.code !== 'Enter') return; |
90 | | - if (e.type !== 'keydown' && !isTouchDevice) return; |
91 | | - if (e.cancelable) e.preventDefault(); |
92 | | - goToPhase3(); |
93 | | - } |
94 | | - |
95 | | - function bindCutsceneSkip() { |
96 | | - if (cutsceneSkipBound) return; |
97 | | - cutsceneSkipBound = true; |
98 | | - window.addEventListener('keydown', onCutsceneSkipInput); |
99 | | - window.addEventListener('touchstart', onCutsceneSkipInput, { passive: false }); |
100 | | - } |
101 | | - |
102 | | - function unbindCutsceneSkip() { |
103 | | - if (!cutsceneSkipBound) return; |
104 | | - cutsceneSkipBound = false; |
105 | | - window.removeEventListener('keydown', onCutsceneSkipInput); |
106 | | - window.removeEventListener('touchstart', onCutsceneSkipInput); |
107 | | - } |
108 | | - |
109 | | - v1.addEventListener('ended', () => { |
110 | | - if (phase !== 'phase1') return; |
111 | | - phase = 'loop'; |
112 | | - show(v2, v1); |
113 | | - setTimeout(() => { |
114 | | - if (pressPrompt) { |
115 | | - pressPrompt.style.display = 'block'; |
116 | | - pressPrompt.textContent = 'PRESS SPACE / TAP TO CONTINUE'; |
117 | | - } |
118 | | - }, 4000); |
119 | | - }, { once: true }); |
120 | | - |
121 | | - bindCutsceneSkip(); |
122 | | - |
123 | | - // jabardasti yahan bhi saare flags |
124 | | - v1.muted = true; |
125 | | - v1.defaultMuted = true; |
126 | | - v1.playsInline = true; |
127 | | - if (v1.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) { |
128 | | - playVideo(v1); |
129 | | - } else { |
130 | | - v1.addEventListener('canplay', () => playVideo(v1), { once: true }); |
| 98 | + hidePrompt(); |
| 99 | + const playPromise = show(v3, from); |
| 100 | + if (playPromise && typeof playPromise.catch === 'function') { |
| 101 | + playPromise.catch(() => { |
| 102 | + phase = 'awaiting-entry'; |
| 103 | + phase3ReadyToEnter = true; |
| 104 | + setPrompt('PRESS SPACE / TAP TO ENTER'); |
| 105 | + }); |
| 106 | + } |
131 | 107 | } |
132 | 108 |
|
133 | | - // phase3 - go to website |
134 | | - v3.addEventListener('ended', () => { |
| 109 | + function enterWebsite() { |
135 | 110 | if (cutsceneDone) return; |
136 | 111 | cutsceneDone = true; |
137 | 112 | phase = 'done'; |
| 113 | + phase3ReadyToEnter = false; |
138 | 114 | unbindCutsceneSkip(); |
| 115 | + hidePrompt(); |
139 | 116 |
|
140 | 117 | website.classList.add('visible'); |
141 | 118 |
|
|
155 | 132 | else { Audio.stopAmbient(); } |
156 | 133 | }); |
157 | 134 | } |
158 | | - |
| 135 | + |
159 | 136 | // paint website first, then crossfade cinematic out |
160 | 137 | requestAnimationFrame(() => { |
161 | 138 | requestAnimationFrame(() => { |
|
180 | 157 | }); |
181 | 158 | }); |
182 | 159 | }); |
| 160 | + } |
| 161 | + |
| 162 | + function onCutsceneSkipInput(e) { |
| 163 | + if (e.type === 'keydown' && e.code !== 'Space' && e.code !== 'Enter') return; |
| 164 | + if (e.type !== 'keydown' && !isTouchDevice) return; |
| 165 | + if (e.cancelable) e.preventDefault(); |
| 166 | + if (phase === 'phase1' || phase === 'loop') { |
| 167 | + goToPhase3(); |
| 168 | + return; |
| 169 | + } |
| 170 | + if (phase === 'awaiting-entry' && phase3ReadyToEnter) { |
| 171 | + enterWebsite(); |
| 172 | + } |
| 173 | + } |
| 174 | + |
| 175 | + function bindCutsceneSkip() { |
| 176 | + if (cutsceneSkipBound) return; |
| 177 | + cutsceneSkipBound = true; |
| 178 | + window.addEventListener('keydown', onCutsceneSkipInput); |
| 179 | + window.addEventListener('touchstart', onCutsceneSkipInput, { passive: false }); |
| 180 | + } |
| 181 | + |
| 182 | + function unbindCutsceneSkip() { |
| 183 | + if (!cutsceneSkipBound) return; |
| 184 | + cutsceneSkipBound = false; |
| 185 | + window.removeEventListener('keydown', onCutsceneSkipInput); |
| 186 | + window.removeEventListener('touchstart', onCutsceneSkipInput); |
| 187 | + } |
| 188 | + |
| 189 | + v1.addEventListener('ended', () => { |
| 190 | + if (phase !== 'phase1') return; |
| 191 | + phase = 'loop'; |
| 192 | + show(v2, v1); |
| 193 | + setTimeout(() => { |
| 194 | + setPrompt('PRESS SPACE / TAP TO SKIP'); |
| 195 | + }, 4000); |
| 196 | + }, { once: true }); |
| 197 | + |
| 198 | + bindCutsceneSkip(); |
183 | 199 |
|
| 200 | + // jabardasti yahan bhi saare flags |
| 201 | + v1.muted = true; |
| 202 | + v1.defaultMuted = true; |
| 203 | + v1.playsInline = true; |
| 204 | + v2.muted = true; |
| 205 | + v2.defaultMuted = true; |
| 206 | + v2.playsInline = true; |
| 207 | + v3.muted = true; |
| 208 | + v3.defaultMuted = true; |
| 209 | + v3.playsInline = true; |
| 210 | + if (v1.readyState >= HTMLMediaElement.HAVE_CURRENT_DATA) { |
| 211 | + playVideo(v1); |
| 212 | + } else { |
| 213 | + v1.addEventListener('canplay', () => playVideo(v1), { once: true }); |
| 214 | + } |
| 215 | + |
| 216 | + // phase3 - wait for explicit enter input |
| 217 | + v3.addEventListener('ended', () => { |
| 218 | + if (cutsceneDone) return; |
| 219 | + phase = 'awaiting-entry'; |
| 220 | + phase3ReadyToEnter = true; |
| 221 | + setPrompt('PRESS SPACE / TAP TO ENTER'); |
184 | 222 | }, { once: true }); |
185 | 223 |
|
186 | 224 | }); |
|
0 commit comments