|
24 | 24 | <!-- Non-critical CSS - will be loaded after hero video (see loadKaTeXAfterHeroVideo function) --> |
25 | 25 |
|
26 | 26 | <!-- Preload critical JavaScript --> |
27 | | - <!-- Note: Video preloading is handled by the video element's preload attribute, not link rel="preload" --> |
28 | 27 | <link rel="preload" href="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" as="script"> |
29 | 28 | <link rel="preload" href="./static/js/index.js" as="script"> |
30 | 29 |
|
| 30 | + <!-- Preload hero video for faster loading --> |
| 31 | + <link rel="preload" href="./resources/head/head_new_firefox_720p.mp4" as="video" type="video/mp4" fetchpriority="high"> |
| 32 | + |
31 | 33 | <style> |
32 | 34 | /* System font stack - faster loading, no external fonts needed */ |
33 | 35 | :root { |
|
1177 | 1179 | } |
1178 | 1180 | })(); |
1179 | 1181 |
|
1180 | | - document.addEventListener('DOMContentLoaded', function() { |
1181 | | - // KaTeX math rendering will be initialized after hero video loads |
1182 | | - // (see loadKaTeXAfterHeroVideo function below) |
1183 | | - |
1184 | | - // Hero video fade-in when ready - PROGRESSIVE LOADING |
1185 | | - const heroVideoMain = document.getElementById('hero-video-main'); |
1186 | | - const heroVideoMobile = document.getElementById('hero-video-mobile'); |
1187 | | - |
1188 | | - function showHeroVideo(video) { |
1189 | | - if (!video) return; |
1190 | | - |
1191 | | - // Set high priority for hero video |
1192 | | - if (video.setAttribute) { |
1193 | | - video.setAttribute('fetchpriority', 'high'); |
1194 | | - } |
1195 | | - |
1196 | | - // Show video as soon as we have enough data to start playing |
1197 | | - const showVideo = () => { |
1198 | | - video.style.opacity = '1'; |
1199 | | - video.play().catch(err => { |
1200 | | - console.log('Video autoplay prevented:', err); |
1201 | | - }); |
1202 | | - }; |
| 1182 | + // Start loading hero video EARLY - before DOMContentLoaded |
| 1183 | + // This allows the browser to start fetching the video file as soon as possible |
| 1184 | + (function() { |
| 1185 | + // Try to get video elements immediately if DOM is ready, otherwise wait |
| 1186 | + const initHeroVideo = () => { |
| 1187 | + const heroVideoMain = document.getElementById('hero-video-main'); |
| 1188 | + const heroVideoMobile = document.getElementById('hero-video-mobile'); |
1203 | 1189 |
|
1204 | | - // Mark hero video as loaded early - when we have enough data (loadeddata) |
1205 | | - // This allows other videos to start loading sooner |
1206 | | - const markHeroVideoLoaded = () => { |
1207 | | - if (!window.heroVideoLoaded) { |
1208 | | - window.heroVideoLoaded = true; |
1209 | | - console.log('✅ Hero video ready! Other videos can now load.'); |
1210 | | - // Trigger event to notify other scripts |
1211 | | - window.dispatchEvent(new CustomEvent('heroVideoLoaded')); |
| 1190 | + function showHeroVideo(video) { |
| 1191 | + if (!video) return; |
| 1192 | + |
| 1193 | + // Set high priority for hero video |
| 1194 | + if (video.setAttribute) { |
| 1195 | + video.setAttribute('fetchpriority', 'high'); |
1212 | 1196 | } |
1213 | | - }; |
1214 | | - |
1215 | | - // Mark as loaded when we have enough data to play (loadeddata event) |
1216 | | - // This is earlier than canplay, allowing other videos to start loading sooner |
1217 | | - if (video.readyState >= 2) { |
1218 | | - // Already have enough data |
1219 | | - markHeroVideoLoaded(); |
1220 | | - showVideo(); |
1221 | | - } else { |
1222 | | - // Listen for loadeddata - happens when we have enough data to start playing |
1223 | | - video.addEventListener('loadeddata', () => { |
1224 | | - markHeroVideoLoaded(); |
1225 | | - showVideo(); |
1226 | | - }, { once: true }); |
1227 | 1197 |
|
1228 | | - // Fallback: also listen for canplay (when it can definitely play) |
1229 | | - video.addEventListener('canplay', showVideo, { once: true }); |
| 1198 | + // Show video as soon as we have enough data to start playing |
| 1199 | + const showVideo = () => { |
| 1200 | + video.style.opacity = '1'; |
| 1201 | + video.play().catch(err => { |
| 1202 | + console.log('Video autoplay prevented:', err); |
| 1203 | + }); |
| 1204 | + }; |
| 1205 | + |
| 1206 | + // Mark hero video as loaded VERY EARLY - when metadata is available |
| 1207 | + // This allows other videos to start loading much sooner |
| 1208 | + const markHeroVideoLoaded = () => { |
| 1209 | + if (!window.heroVideoLoaded) { |
| 1210 | + window.heroVideoLoaded = true; |
| 1211 | + console.log('✅ Hero video ready! Other videos can now load.'); |
| 1212 | + // Trigger event to notify other scripts |
| 1213 | + window.dispatchEvent(new CustomEvent('heroVideoLoaded')); |
| 1214 | + } |
| 1215 | + }; |
1230 | 1216 |
|
1231 | | - // Fallback: show after a delay even if events don't fire |
1232 | | - setTimeout(() => { |
| 1217 | + // Mark as loaded when metadata is available (much earlier than loadeddata) |
| 1218 | + // This allows other resources to start loading immediately |
| 1219 | + if (video.readyState >= 1) { |
| 1220 | + // Metadata already available |
| 1221 | + markHeroVideoLoaded(); |
1233 | 1222 | if (video.readyState >= 2) { |
1234 | | - markHeroVideoLoaded(); |
1235 | 1223 | showVideo(); |
1236 | 1224 | } |
1237 | | - }, 1000); |
| 1225 | + } else { |
| 1226 | + // Listen for loadedmetadata - happens very early, just after metadata loads |
| 1227 | + video.addEventListener('loadedmetadata', () => { |
| 1228 | + markHeroVideoLoaded(); |
| 1229 | + // If we already have enough data, show immediately |
| 1230 | + if (video.readyState >= 2) { |
| 1231 | + showVideo(); |
| 1232 | + } |
| 1233 | + }, { once: true }); |
| 1234 | + |
| 1235 | + // Also listen for loadeddata - happens when we have enough data to start playing |
| 1236 | + video.addEventListener('loadeddata', () => { |
| 1237 | + showVideo(); |
| 1238 | + }, { once: true }); |
| 1239 | + |
| 1240 | + // Fallback: also listen for canplay |
| 1241 | + video.addEventListener('canplay', showVideo, { once: true }); |
| 1242 | + |
| 1243 | + // Fallback: show after a delay even if events don't fire |
| 1244 | + setTimeout(() => { |
| 1245 | + if (video.readyState >= 1) { |
| 1246 | + markHeroVideoLoaded(); |
| 1247 | + } |
| 1248 | + if (video.readyState >= 2) { |
| 1249 | + showVideo(); |
| 1250 | + } |
| 1251 | + }, 500); |
| 1252 | + } |
1238 | 1253 | } |
1239 | | - } |
1240 | | - |
1241 | | - // Priority load hero videos immediately with metadata first |
1242 | | - if (heroVideoMain) { |
1243 | | - heroVideoMain.setAttribute('fetchpriority', 'high'); |
1244 | | - heroVideoMain.load(); // Load metadata first |
1245 | | - showHeroVideo(heroVideoMain); |
1246 | | - } |
| 1254 | + |
| 1255 | + // Priority load hero videos immediately |
| 1256 | + if (heroVideoMain) { |
| 1257 | + heroVideoMain.setAttribute('fetchpriority', 'high'); |
| 1258 | + // Force load immediately - don't wait |
| 1259 | + heroVideoMain.load(); |
| 1260 | + showHeroVideo(heroVideoMain); |
| 1261 | + } |
| 1262 | + |
| 1263 | + if (heroVideoMobile) { |
| 1264 | + heroVideoMobile.setAttribute('fetchpriority', 'high'); |
| 1265 | + // Force load immediately - don't wait |
| 1266 | + heroVideoMobile.load(); |
| 1267 | + showHeroVideo(heroVideoMobile); |
| 1268 | + } |
| 1269 | + }; |
1247 | 1270 |
|
1248 | | - if (heroVideoMobile) { |
1249 | | - heroVideoMobile.setAttribute('fetchpriority', 'high'); |
1250 | | - heroVideoMobile.load(); // Load metadata first |
1251 | | - showHeroVideo(heroVideoMobile); |
| 1271 | + // Try to initialize immediately if DOM is ready |
| 1272 | + if (document.readyState === 'loading') { |
| 1273 | + // DOM is still loading, wait for DOMContentLoaded |
| 1274 | + document.addEventListener('DOMContentLoaded', initHeroVideo); |
| 1275 | + } else { |
| 1276 | + // DOM is already ready, initialize immediately |
| 1277 | + initHeroVideo(); |
1252 | 1278 | } |
| 1279 | + })(); |
| 1280 | + |
| 1281 | + document.addEventListener('DOMContentLoaded', function() { |
| 1282 | + // KaTeX math rendering will be initialized after hero video loads |
| 1283 | + // (see loadKaTeXAfterHeroVideo function below) |
1253 | 1284 |
|
1254 | 1285 | // Restore video sources when hero video is ready |
1255 | 1286 | const restoreVideoSources = () => { |
|
0 commit comments