mirror of
https://github.com/litruv/lit.ruv.wtf.git
synced 2026-07-24 02:36:02 +10:00
165 lines
5.7 KiB
JavaScript
165 lines
5.7 KiB
JavaScript
/**
|
|
* BIOS Boot Animation
|
|
* Displays a retro BIOS-style boot sequence before the terminal loads
|
|
*/
|
|
|
|
const BIOS_LINES = [
|
|
{ text: 'LitRuv BIOS v4.20.69', class: 'white', delay: 300 },
|
|
{ text: 'Copyright (C) 2024-2026 LitRuv Industries', class: '', delay: 200 },
|
|
{ text: '', delay: 400 },
|
|
{ text: 'CPU: Quantum Core i9-42069 @ 6.9GHz', class: '', delay: 300 },
|
|
{ text: 'Memory Test: ', class: '', inline: true, delay: 200 },
|
|
{ text: '65536K OK', class: 'highlight', delay: 600 },
|
|
{ text: '', delay: 300 },
|
|
{ text: 'Detecting Primary Master... LitDrive SSD 2TB', class: '', delay: 400 },
|
|
{ text: 'Detecting Primary Slave... None', class: '', delay: 300 },
|
|
{ text: '', delay: 400 },
|
|
{ text: 'Initializing Terminal Interface...', class: 'highlight', delay: 500 },
|
|
{ text: 'Loading modules: [', class: '', inline: true, delay: 200 },
|
|
{ text: '████████████████████', class: 'highlight', inline: true, delay: 800 },
|
|
{ text: '] 100%', class: '', delay: 300 },
|
|
{ text: '', delay: 200 },
|
|
{ text: 'Starting LIT.RUV.WTF Terminal...', class: 'highlight', delay: 400 }
|
|
];
|
|
|
|
const BOOT_STARTUP_SOUND_PATH = window.location.hostname.endsWith('neocities.org')
|
|
? 'https://lit.ruv.wtf/sounds/551405__nakkivene66__old-pc-startup-idle-shutdown.wav'
|
|
: 'sounds/551405__nakkivene66__old-pc-startup-idle-shutdown.wav';
|
|
|
|
let bootStartupSoundPlayed = false;
|
|
let bootStartupSoundUnlockBound = false;
|
|
|
|
/**
|
|
* Play the boot startup sound as early as possible.
|
|
* Falls back to first user interaction when autoplay is blocked.
|
|
* @returns {Promise<void>}
|
|
*/
|
|
async function playBootStartupSound() {
|
|
if (bootStartupSoundPlayed) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const startupSound = new Audio(BOOT_STARTUP_SOUND_PATH);
|
|
startupSound.preload = 'auto';
|
|
startupSound.volume = 0.55;
|
|
await startupSound.play();
|
|
bootStartupSoundPlayed = true;
|
|
bootStartupSoundUnlockBound = false;
|
|
return;
|
|
} catch (error) {
|
|
if (bootStartupSoundUnlockBound) {
|
|
return;
|
|
}
|
|
|
|
bootStartupSoundUnlockBound = true;
|
|
const unlockAndPlay = async () => {
|
|
if (bootStartupSoundPlayed) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const deferredSound = new Audio(BOOT_STARTUP_SOUND_PATH);
|
|
deferredSound.preload = 'auto';
|
|
deferredSound.volume = 0.55;
|
|
await deferredSound.play();
|
|
bootStartupSoundPlayed = true;
|
|
} catch (retryError) {
|
|
// Keep boot sequence running even if sound cannot play.
|
|
}
|
|
};
|
|
|
|
document.addEventListener('pointerdown', unlockAndPlay, { once: true });
|
|
document.addEventListener('keydown', unlockAndPlay, { once: true });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Run the BIOS boot animation
|
|
* @returns {Promise} Resolves when animation is complete
|
|
*/
|
|
function runBootAnimation() {
|
|
return new Promise((resolve) => {
|
|
void playBootStartupSound();
|
|
const bootScreen = document.getElementById('bootScreen');
|
|
const biosText = document.getElementById('biosText');
|
|
const pageFade = document.getElementById('pageFade');
|
|
|
|
if (!bootScreen || !biosText) {
|
|
if (pageFade) pageFade.classList.add('fade-out');
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
let skipped = false;
|
|
const timeouts = [];
|
|
|
|
// Skip animation on space key press
|
|
const skipHandler = (event) => {
|
|
if (event.code === 'Space' && !skipped) {
|
|
event.preventDefault();
|
|
skipped = true;
|
|
|
|
// Clear all pending timeouts
|
|
timeouts.forEach(timeout => clearTimeout(timeout));
|
|
|
|
// Complete the boot screen immediately
|
|
bootScreen.classList.add('fade-out');
|
|
setTimeout(() => {
|
|
bootScreen.style.display = 'none';
|
|
if (pageFade) pageFade.style.display = 'none';
|
|
document.removeEventListener('keydown', skipHandler);
|
|
resolve();
|
|
}, 100);
|
|
}
|
|
};
|
|
|
|
document.addEventListener('keydown', skipHandler);
|
|
|
|
// Start fade in from black after brief delay
|
|
timeouts.push(setTimeout(() => {
|
|
if (pageFade && !skipped) pageFade.classList.add('fade-out');
|
|
}, 200));
|
|
|
|
let lineIndex = 0;
|
|
let totalDelay = 800; // Start after fade begins
|
|
const baseDelay = 150;
|
|
|
|
BIOS_LINES.forEach((line, index) => {
|
|
const delay = totalDelay;
|
|
totalDelay += line.delay || baseDelay;
|
|
|
|
timeouts.push(setTimeout(() => {
|
|
if (skipped) return;
|
|
|
|
const span = document.createElement('span');
|
|
if (line.class) {
|
|
span.className = line.class;
|
|
}
|
|
span.textContent = line.text;
|
|
biosText.appendChild(span);
|
|
|
|
if (!line.inline) {
|
|
biosText.appendChild(document.createTextNode('\n'));
|
|
}
|
|
}, delay));
|
|
});
|
|
|
|
// Fade out and remove boot screen
|
|
timeouts.push(setTimeout(() => {
|
|
if (skipped) return;
|
|
|
|
bootScreen.classList.add('fade-out');
|
|
timeouts.push(setTimeout(() => {
|
|
bootScreen.style.display = 'none';
|
|
if (pageFade) pageFade.style.display = 'none';
|
|
document.removeEventListener('keydown', skipHandler);
|
|
resolve();
|
|
}, 500));
|
|
}, totalDelay + 300));
|
|
});
|
|
}
|
|
|
|
// Export for use in terminal.js
|
|
window.runBootAnimation = runBootAnimation;
|