1<!doctype html> 2<html lang="en"> 3 <head> 4 <meta charset="UTF-8" /> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" /> 6 <meta name="theme-color" content="#05070d" /> 7 <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> 8 <link rel="preconnect" href="https://fonts.googleapis.com" /> 9 <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> 10 <link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&display=swap" rel="stylesheet" /> 11 <title>LaserNuke - Launch Laser-Guided Tactical Nukes</title> 12 13 <!-- =================================================================== 14 Boot loader â pure HTML/CSS/JS so it paints on first HTML parse, 15 BEFORE the (large) JS bundle downloads and the WebGPU scene boots. 16 Dark scheme matches the in-scene near-black background + holographic 17 cyan/orange accents. The app raises progress + triggers the 18 crossfade-out via window.__bootLoader (see the inline script below). 19 =================================================================== --> 20 <style> 21 #boot-loader { 22 position: fixed; 23 inset: 0; 24 z-index: 9999; 25 display: flex; 26 align-items: center; 27 justify-content: center; 28 overflow: hidden; 29 background: 30 radial-gradient(ellipse 120% 85% at 50% 42%, 31 #0b1018 0%, #06080f 52%, #02030a 100%); 32 font-family: 'Bebas Neue', ui-monospace, 'JetBrains Mono', Menlo, Consolas, monospace; 33 /* Crossfade out â the camera dolly + menu intro play through this. */ 34 opacity: 1; 35 transition: opacity 0.7s ease; 36 cursor: default; 37 } 38 #boot-loader.bl-hide { 39 opacity: 0; 40 pointer-events: none; 41 } 42 43 /* Soft edge darkening for depth â echoes the scene's vignette. */ 44 #boot-loader .bl-vignette { 45 position: absolute; 46 inset: 0; 47 pointer-events: none; 48 background: radial-gradient(ellipse 100% 100% at 50% 50%, 49 transparent 52%, rgba(0, 0, 0, 0.55) 100%); 50 } 51 52 /* Faint scanline sweeping topâbottom â a quiet holographic cue. */ 53 #boot-loader .bl-scan { 54 position: absolute; 55 left: 0; 56 right: 0; 57 top: -160px; 58 height: 160px; 59 pointer-events: none; 60 background: linear-gradient(to bottom, 61 transparent, rgba(92, 224, 255, 0.05), transparent); 62 animation: bl-sweep 5.5s linear infinite; 63 } 64 @keyframes bl-sweep { 65 from { transform: translateY(0); } 66 to { transform: translateY(110vh); } 67 } 68 69 #boot-loader .bl-stack { 70 position: relative; 71 z-index: 2; 72 display: flex; 73 flex-direction: column; 74 align-items: center; 75 gap: 30px; 76 width: min(360px, 72vw); 77 } 78 79 #boot-loader .bl-logo { 80 width: 100%; 81 aspect-ratio: 1671 / 561; /* logo.svg viewBox â reserves height */ 82 /* Recolor the logo to the brand red (#ff0013 â the same red the 83 in-scene 3D logo uses) by using the SVG as an alpha mask over a red 84 fill, rather than rendering the SVG's own (pinker #FF0048) paint. 85 A matching red glow ties it to the menu. */ 86 background-color: #ff0013; 87 -webkit-mask: url(/logo.svg) no-repeat center / contain; 88 mask: url(/logo.svg) no-repeat center / contain; 89 filter: drop-shadow(0 0 18px rgba(255, 0, 40, 0.5)); 90 opacity: 0.97; 91 animation: bl-float 4.6s ease-in-out infinite; 92 } 93 @keyframes bl-float { 94 0%, 100% { transform: translateY(0); } 95 50% { transform: translateY(-6px); } 96 } 97 98 #boot-loader .bl-bar { 99 position: relative; 100 width: 100%; 101 height: 3px; 102 border-radius: 2px; 103 background: rgba(140, 180, 220, 0.13); 104 overflow: hidden; 105 } 106 #boot-loader .bl-bar-fill { 107 position: absolute; 108 left: 0; 109 top: 0; 110 bottom: 0; 111 width: 0%; 112 border-radius: 2px; 113 background: linear-gradient(90deg, 114 #2b6f8c 0%, #5ce0ff 70%, #aef4ff 100%); 115 box-shadow: 0 0 10px rgba(92, 224, 255, 0.7), 116 0 0 2px rgba(92, 224, 255, 0.9); 117 } 118 119 #boot-loader .bl-status { 120 display: flex; 121 justify-content: space-between; 122 align-items: baseline; 123 width: 100%; 124 font-size: 13px; 125 letter-spacing: 0.3em; 126 text-transform: uppercase; 127 color: rgba(92, 224, 255, 0.72); 128 } 129 #boot-loader .bl-pct { 130 color: rgba(255, 138, 61, 0.9); 131 letter-spacing: 0.18em; 132 } 133 134 @media (prefers-reduced-motion: reduce) { 135 #boot-loader .bl-logo, 136 #boot-loader .bl-scan { animation: none; } 137 } 138 </style> 139
139<script type="module" crossorigin src="/assets/index-8I8pi1mS.js"></script>
139 140 <link rel="stylesheet" crossorigin href="/assets/index-WBap1jxa.css"> 141 </head> 142 <body> 143 <!-- Removed from the DOM by the inline controller once the scene has 144 revealed, so it never sits on top eating pointer events. --> 145 <div id="boot-loader" role="progressbar" aria-label="Loading Laser Nuke" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"> 146 <div class="bl-vignette"></div> 147 <div class="bl-scan"></div> 148 <div class="bl-stack"> 149 <div class="bl-logo" role="img" aria-label="Laser Nuke"></div> 150 <div class="bl-bar"><div class="bl-bar-fill" id="bl-fill"></div></div> 151 <div class="bl-status"> 152 <span id="bl-status-text">Initializing</span> 153 <span class="bl-pct" id="bl-pct">0%</span> 154 </div> 155 </div> 156 </div> 157 158 <div id="root"></div> 159 160 <!-- Loader controller. Classic (non-module) script: runs in document order 161 BEFORE the deferred module bundle, so window.__bootLoader exists by the 162 time the app boots. --> 163
163<script> 164 (function () { 165 var el = document.getElementById('boot-loader') 166 var fill = document.getElementById('bl-fill') 167 var pct = document.getElementById('bl-pct') 168 var statusText = document.getElementById('bl-status-text') 169 if (!el || !fill) return 170 171 var current = 0 // displayed 0..1 172 var target = 0 // target 0..1 173 var ceiling = 0.9 // auto-creep ceiling until the app reports real progress 174 var filled = false // complete() called â allow reaching 100% 175 var hiding = false 176 var startTime = Date.now() 177 var MIN_VISIBLE_MS = 500 // anti-flash floor on very fast (warm) loads 178 179 function render(p) { 180 var w = (p * 100).toFixed(1) 181 fill.style.width = w + '%' 182 if (pct) pct.textContent = Math.round(p * 100) + '%' 183 el.setAttribute('aria-valuenow', String(Math.round(p * 100))) 184 } 185 186 function tick() { 187 // Creep the target toward the ceiling so the bar always feels alive 188 // during the bundle download, even before the app checks in. 189 if (!filled && target < ceiling) { 190 target = Math.min(ceiling, target + (ceiling - target) * 0.018 + 0.0015) 191 } 192 current += (target - current) * 0.14 193 if (current > 0.9995) current = 1 194 render(Math.max(0, Math.min(1, current))) 195 requestAnimationFrame(tick) 196 } 197 198 function doHide() { 199 if (hiding) return 200 hiding = true 201 var wait = Math.max(0, MIN_VISIBLE_MS - (Date.now() - startTime)) 202 setTimeout(function () { 203 if (statusText) statusText.textContent = 'Online' 204 el.classList.add('bl-hide') 205 // Drop from the DOM after the fade completes. 206 setTimeout(function () { 207 if (el && el.parentNode) el.parentNode.removeChild(el) 208 }, 800) 209 }, wait) 210 } 211 212 window.__bootLoader = { 213 // Raise the progress target (monotonic â never goes backward). 214 setProgress: function (p) { 215 if (typeof p === 'number') target = Math.max(target, Math.min(1, p)) 216 }, 217 setStatus: function (t) { 218 if (statusText && typeof t === 'string') statusText.textContent = t 219 }, 220 // Fill the bar to 100% (does NOT fade â call hide() to dismiss). 221 complete: function () { 222 filled = true 223 target = 1 224 }, 225 // Crossfade out + remove. The scene reveal animates through this. 226 hide: function () { 227 filled = true 228 target = 1 229 doHide() 230 }, 231 } 232 233 requestAnimationFrame(tick) 234 235 // Safety net â never trap the user behind the loader if the app fails 236 // to signal readiness (e.g. WebGPU init throws before BootSequencer 237 // mounts). Auto-dismiss after 12s. 238 setTimeout(function () { 239 if (window.__bootLoader) window.__bootLoader.hide() 240 }, 12000) 241 })() 242 </script>
242 243 </body> 244</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.