function waitForAnimationEnd(elem, animationName) { return new Promise(resolve => { function handleAnimationEnd(evt) { if (evt.animationName === animationName) { elem.onanimationend = null; resolve(); } } elem.onanimationend = handleAnimationEnd; }); } let sound = new Audio("../assets/game-boy-advance-startup-sound.mp3"); async function sessionStartupAnimation() { // Page setup let all_default_elements = document.body.querySelectorAll("*"); all_default_elements.forEach((elem) => elem.style.opacity = 0); let xmlhttp = new XMLHttpRequest(); // Not the most optimised way, but it's working xmlhttp.open("GET", "assets/startup_quotes.json", false); xmlhttp.send(); if(xmlhttp.status != 200) { throw WebTransportError("The file 'assets/startup_quots.json' is not available"); } let quotes = JSON.parse(xmlhttp.responseText)["quotes"]; let quote = quotes[Math.floor(Math.random() * quotes.length)]; // First the author let author_elem = document.createElement("h2"); author_elem.className = "startup-animation-author"; author_elem.innerHTML = quote.author + "®"; document.body.appendChild(author_elem); await waitForAnimationEnd(author_elem, "opacity-fade-in") // Then the text and sound let text_elem = document.createElement("h1"); text_elem.className = "startup-animation-text"; let time_between_chars = 200 / quote.text.length; // ms for(let i = 0; i < quote.text.length; i++) { let char_elem = document.createElement("div"); char_elem.className = "startup-animation-char" char_elem.style.animation = "char-animation 3s ease-in-out " + String(i * time_between_chars) + "ms, opacity-fade-in 1s " + String(i * time_between_chars) + "ms"; if(quote.text[i] == " ") char_elem.innerHTML = "
" + quote.text[i] + ""; else char_elem.textContent = quote.text[i]; console.log(char_elem.onanimationend); text_elem.appendChild(char_elem); } document.body.appendChild(text_elem); sound.play(); await waitForAnimationEnd(text_elem.firstChild, "opacity-fade-in"); text_elem.childNodes.forEach((char_elem) => char_elem.style.opacity = 1); await waitForAnimationEnd(text_elem.lastChild, "char-animation"); // Fade out for both text_elem.style.animation = "opacity-fade-out 1s ease-in"; text_elem.style.opacity = 0; author_elem.style.animation = "opacity-fade-out 1s ease-in"; author_elem.style.opacity = 0; await waitForAnimationEnd(text_elem, "opacity-fade-out"); // Remove them and fade in for page content document.body.removeChild(author_elem); document.body.removeChild(text_elem); all_default_elements.forEach((elem) => elem.style.animation = "opacity-fade-in 0.5s"); all_default_elements.forEach((elem) => elem.style.opacity = 1); } function interruptStartingAnimation() { let author_elem = document.body.querySelector(".startup-animation-author"); author_elem.getAnimations().forEach((animation) => animation.finish()); let text_elem = document.body.querySelector(".startup-animation-text"); text_elem.getAnimations().forEach((animation) => animation.finish()); if(sound.currentTime < 2.75) { sound.currentTime = 2.75; } } window.onkeydown = () => { interruptStartingAnimation(); window.onkeydown = null; } // Only start animation once per session window.onload = () => { document.body.style.opacity = 1; if(!sessionStorage.getItem("hasExecutedSessionStartupAnimation")) { sessionStorage.setItem("hasExecutedSessionStartupAnimation", "true"); sessionStartupAnimation(); } }