1 2const img = new Image(); 3img.src = '/static/images/ice.jpg'; 4 5 6loadJSFile("https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js", function() { 7 console.log('loaded html2canvas') 8 loadJSFile("/static/js/disintegrate.js", function() { 9 console.log('loaded disintegrate') 10 // disintegrate.init(); 11 }) 12}); 13 14 15var scaredyFader; 16 17function scaredycat_init(initial_e) { 18 const navTitle = $('#navbar-mw-nav').attr('title'); 19 $('#navbar-mw-nav').removeAttr('title'); 20 21 const laserSound = new Audio('/static/audio/laser.mp3'); 22 laserSound.preload = 'auto'; 23 laserSound.volume = 0.3; 24 laserSound.load(); 25 26 const initSound = new Audio('/static/audio/scaredy-alert.mp3'); 27 initSound.preload = 'auto'; 28 initSound.volume = 0.5; 29 initSound.load(); 30 31 const freezeSound = new Audio('/static/audio/freeze.mp3'); 32 freezeSound.preload = 'auto'; 33 freezeSound.volume = 0.2; 34 freezeSound.load(); 35 36 37 const hitSound = new Audio('/static/audio/too-small.mp3'); 38 hitSound.preload = 'auto'; 39 hitSound.volume = 1; 40 hitSound.load(); 41 42 const splodeSound = new Audio('/static/audio/bye.mp3'); 43 splodeSound.preload = 'auto'; 44 splodeSound.volume = 1; 45 splodeSound.load(); 46 47 const tadaSound = new Audio('/static/audio/tada.mp3'); 48 tadaSound.preload = 'auto'; 49 tadaSound.volume = 1; 50 tadaSound.load(); 51 52 function playScaredySound(sound) { 53 sound.currentTime = 0; // rewind to start if needed 54 sound.play(); 55 } 56 57 const brand = $('#navbar-brand'); 58 FADER_DESTINATION_OPACITY = '0.5'; 59 60 if (brand.closest('.scaredycat-outer').length) { 61 // already initialised 62 return; 63 } 64 65 $('body').append(` 66 <div class="scaredycat-outer"> 67 <div class="scaredycat-container"> 68 <div class="scaredycat-bounds"> 69 <div class="scaredycat"></div> 70 </div> 71 </div> 72 </div> 73 `); 74 75 scaredyFader = $(`<div id="scaredy-fader"></div>`); 76 scaredyFader.on('click', endScaredy(scaredyFader)) 77 78 $('body').append(scaredyFader); 79 80 do_on_delay(function() { 81 scaredyFader.css('opacity', FADER_DESTINATION_OPACITY) 82 }, 0) 83 playScaredySound(initSound); 84 85 // init disintegrate, even though it doesn't seem to work, removing 86 // this will break things 87 disintegrate.init(); 88 89 // set boundary box for moving out the way 90 const move_box_bounds = $('.scaredycat-bounds'); 91 move_box_bounds.css({left: brand[0].getBoundingClientRect().left - 30}) 92 move_box_bounds.append(brand); 93 94 // laser stuff 95 function jumpElement(elem, { height = 100, duration = 600, gravitySteps = 30 } = {}) { 96 if (!elem) return; 97 const startTime = performance.now(); 98 const interval = duration / gravitySteps; 99 100 const heights = Array.from({ length: gravitySteps }, (_, i) => { 101 const t = i / (gravitySteps - 1); 102 return -(-4 * (t - 0.5) ** 2 + 1) * height; 103 }); 104 105 let i = 0; 106 const offsetTop = elem.offsetTop; 107 const originalPosition = window.getComputedStyle(elem).position; 108 if (originalPosition === "static") elem.style.position = "relative"; 109 110 function step() { 111 if (i < heights.length) { 112 elem.style.top = `${heights[i]}px`; 113 i++; 114 setTimeout(step, interval); 115 } else { 116 elem.style.top = "0px"; 117 } 118 } 119 120 step(); 121 } 122 123 function shootLaserBullet({ 124 targetSelector, 125 speed = 1000, 126 onBeforeHit = () => {}, 127 onHit = () => {}, 128 onPassThrough = () => {} 129 }) { 130 131 const target = document.querySelector(targetSelector); 132 if (!target) return console.warn("Target element not found"); 133 134 const mousePos = { x: window.event.clientX, y: window.event.clientY }; 135 const targetRect = target.getBoundingClientRect(); 136 const targetCenter = { 137 x: targetRect.left + targetRect.width / 2, 138 y: targetRect.top + targetRect.height / 2 139 }; 140 141 const dx = targetCenter.x - mousePos.x; 142 const dy = targetCenter.y - mousePos.y; 143 const angle = Math.atan2(dy, dx); 144 const distanceToTarget = Math.hypot(dx, dy); 145 const totalDistance = 2000; 146 147 const bullet = document.createElement("div"); 148 bullet.className = "laser-bullet"; 149 bullet.style.left = `${mousePos.x}px`; 150 bullet.style.top = `${mousePos.y}px`; 151 bullet.style.transform = `rotate(${angle}rad)`; 152 document.body.appendChild(bullet); 153 154 const fps = 60; 155 const distancePerFrame = speed / fps; 156 157 let x = mousePos.x, y = mousePos.y; 158 let distanceTraveled = 0, hitFired = false, beforeHitFired = false;
159 160 function animate() { 161 x += Math.cos(angle) * distancePerFrame; 162 y += Math.sin(angle) * distancePerFrame; 163 distanceTraveled += distancePerFrame; 164 165 bullet.style.left = `${x}px`; 166 bullet.style.top = `${y}px`; 167 168 if (!beforeHitFired && distanceTraveled >= distanceToTarget - 200) { 169 onBeforeHit(); 170 beforeHitFired = true; 171 } 172 173 if (!hitFired && distanceTraveled >= distanceToTarget) { 174 onHit(); 175 hitFired = true; 176 if (brand.hasClass('scaredycat-shifted')) { 177 bullet.remove(); 178 return; 179 } 180 } 181 182 if (distanceTraveled >= totalDistance) { 183 onPassThrough(); 184 bullet.remove(); 185 } else { 186 requestAnimationFrame(animate); 187 } 188 } 189 190 playScaredySound(laserSound); 191 requestAnimationFrame(animate); 192 } 193 194 // movement of logo 195 function scaredycat_moveDiv(mouse, edge, elem, force_animate) { 196 const width = $(elem).outerWidth(); 197 let newLeft = edge === "left" 198 ? mouse.pageX + 5 199 : mouse.pageX - width - 20; 200 201 let animateLeft = null; 202 if (newLeft < 0) animateLeft = width + 50; 203 else if (newLeft > $(window).width() - width) 204 animateLeft = mouse.pageX - (width + 30); 205 206 if (newLeft !== undefined) { 207 const left = animateLeft || newLeft; 208 (animateLeft || force_animate) 209 ? $(elem).animate({ left }, 100) 210 : $(elem).css({ left }); 211 212 const topNav = $('.top-nav-bunch'); 213 const leftEdge = topNav[0].getBoundingClientRect().left - 170; 214 topNav.toggleClass('scaredycat-passerby', parseFloat(left) > leftEdge); 215 } 216 } 217 218 function scaredycat_closestEdge(mouse, elem, force_animate) { 219 const { left, right } = elem.getBoundingClientRect(); 220 const mouseX = mouse.pageX; 221 const edge = Math.abs(left - mouseX) < Math.abs(right - mouseX) ? 'left' : 'right'; 222 scaredycat_moveDiv(mouse, edge, elem, force_animate); 223 } 224 225 function scaredycat_killLogo() { 226 playScaredySound(hitSound); 227 228 disintegrate.init(); // re-init to make sure the ice colours are correct 229 stopTremble('#navbar-brand'); // stop trembling 230 shake_element($('#navbar-brand'), 400, 100); // here we go... 231 brand.removeClass('scaredy-teasing') 232 233 killAllListeners(); 234 235 do_on_delay(() => { 236 const disObj = disintegrate.getDisObj(brand[0]); 237 disintegrate.createSimultaneousParticles(disObj); // explode! 238 playScaredySound(splodeSound); 239 240 brand.hide().find('.brand-title strong').addClass('text-danger').text($('#current-user-name .forename').text() + 'lab'); 241 brand.find('.brand-title').css('font-family', '"Rock Salt", cursive') 242 brand.find('.icon-slab').removeClass('icon-slab').addClass('fas fa-trophy-alt'); // make trophy 243 244 $(".scaredycat-bounds").css('left', ''); // move back to orig position 245 brand.removeClass('scaredycat-shifted'); 246 247 248 do_on_delay(() => { 249 brand.fadeIn(500, function() { 250 251 scaredyFader.css('opacity', '0'); 252 do_on_delay(function() { 253 scaredyFader.remove() 254 }, 1000) 255 }); 256 do_on_delay(function() { 257 playScaredySound(tadaSound); 258 confetti_burst({ seconds: 0.8, delay: 0.2 }) 259 }, 1500); 260 }, 2000); 261 }, 500); 262 } 263 264 function endScaredy(fader) { 265 return function() { 266 $('.scaredy-teasing').removeClass('scaredy-teasing'); 267 $('#navbar-mw').prepend($('#navbar-brand')); 268 $('.scaredycat-outer').remove(); 269 fader.css('opacity', '0'); 270 do_on_delay(function() { 271 fader.remove() 272 }, 1000); 273 killAllListeners(); 274 } 275 } 276 277 // listeners 278 $(document).on('click.scaredy', '#navbar-mw-nav', function() { 279 shootLaserBullet({ 280 targetSelector: "#navbar-brand", 281 onBeforeHit: () => { 282 if (!brand.hasClass('scaredycat-shifted')) { 283 jumpElement(brand[0], { height: 60, duration: 300 }); // jump out way 284 } 285 }, 286 onHit: () => { 287 if (brand.hasClass('scaredycat-shifted')) scaredycat_killLogo(); // git it! 288 }, 289 onPassThrough: () => {} 290 }); 291 }); 292 293 // click to 'splode 294 brand.on('click', e => { 295 e.preventDefault(); 296 scaredycat_killLogo(); 297 }); 298 299 // freeze 300 var canChangeFreeze = true; 301 302 $(document).on('keyup.scaredy keydown.scaredy', function(e){ 303 if(e.shiftKey) { 304 canChangeFreeze = false;
305 brand.addClass('scaredycat-shifted'); 306 playScaredySound(freezeSound); 307 // start randomly shaking 308 startTremble('#navbar-brand'); 309 do_on_delay(function() { 310 brand.removeClass('scaredycat-shifted'); 311 stopTremble('#navbar-brand'); 312 canChangeFreeze = true; 313 314 }, 700) 315 } else { 316 if (canChangeFreeze) { 317 brand.removeClass('scaredycat-shifted'); 318 stopTremble('#navbar-brand'); 319 } 320 } 321 } ); 322 323 $(document).on('mouseenter.scaredy mouseover.scaredy', ".scaredycat-bounds,.scaredycat", function(e) { 324 if (!shifted) { 325 scaredycat_closestEdge(e, move_box_bounds[0]); 326 } 327 }); 328 329 $(document).on('mouseout.scaredy', '#navbar-mw-nav', function(e) { 330 if (!e.relatedTarget || !e.currentTarget.contains(e.relatedTarget)) { 331 brand.addClass('scaredy-teasing'); 332 // console.log('fader out') 333 // fader.css('opacity', '0'); 334 } 335 }); 336 337 $(document).on('mouseover.scaredy', '#navbar-mw-nav', function(e) { 338 if (!e.relatedTarget || !e.currentTarget.contains(e.relatedTarget)) { 339 brand.removeClass('scaredy-teasing'); 340 // console.log('fader in') 341 // fader.css('opacity', FADER_DESTINATION_OPACITY); 342 } 343 }); 344 345 $(window).on('resize.scaredy', function(move_e) { 346 move_box_bounds.css({ 347 left: 10 348 }); 349 $('.top-nav-bunch').removeClass('scaredycat-passerby') 350 }) 351 352 function killAllListeners() { 353 $(document).off('.scaredy'); // stop listening for trembles 354 $(".scaredycat-bounds,.scaredycat").off('mouseenter mouseover'); // remove listeners 355 $(window).off('.scaredy'); 356 brand.off('click') 357 } 358 359 360 scaredycat_closestEdge(initial_e, move_box_bounds[0], true); 361} 362
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.