// --------- Constants --------- const app = document.querySelector('#app'); const LINKS = [ { name: 'blog', url: 'https://blog.rikki.moe', desc: 'Who am i and what do i do.' }, { name: 'git', url: 'https://git.rikki.moe', desc: 'My personal git server.' }, { name: 'github', url: 'https://github.com/rikkix', desc: 'My github page with my projects. Follow me there ;)' }, { name: 'matrix-chat', url: 'https://chat.mtf.moe', desc: 'My personal matrix chat server.' } ]; const COMMANDS = [ ...LINKS, { name: 'email', desc: 'Get my email address.' }, { name: 'help', desc: 'Show the list of commands.' }, { name: 'clear', desc: 'Clear the terminal.' } ]; // Built-in handlers not in COMMANDS const BUILTIN_COMMANDS = ['su', 'sudo', 'shutdown', 'reboot', 'echo', 'df', 'pwd', 'cat', 'top', 'rm', 'ls', 'oiia']; // Consolidated for autocomplete const ALL_COMMANDS = [ ...COMMANDS.map(cmd => cmd.name), ...BUILTIN_COMMANDS ]; const ROASTS = { sudo: [ "You think you're the boss now? Nice try, you're still guest.", "Trying to act like root? You can't fool me!", "Permission denied, root access is for the cool kids only.", "You're not fooling anyone, buddy. You're still a guest.", "Is that a root password, or just wishful thinking?", "The root can't hear you from down there, guest.", "I see you're trying to hack your way into being the boss... nice try!", "Rooting for root? Sorry, but you're still stuck as a guest." ], shutdown: [ "Shutting down? Is your internet even working?", "You want to shut down? The system is already shutting down your self-esteem.", "Oh, you want to shut me down? Good luck with that.", "I’m not shutting down, you’re just pressing random keys.", "Trying to shutdown, but all you’ve achieved is pressing your own buttons.", "Shut down? Oh, you mean like your attempts at this command?", "Shutdown initiated... just kidding, it's still not happening." ], reboot: [ "Rebooting? You're just hitting keys for fun, aren't you?", "You want to reboot, but your life is already stuck in an endless loop.", "Rebooting... Yeah, sure, just like that’ll fix everything.", "Your system is rebooting... but not your sense of reality.", "Trying to reboot? Maybe reboot your confidence instead.", "Rebooting is a nice thought, but I’m still not impressed.", "Let me guess, you’re trying to reboot me. Not gonna work!" ] }; // --------- Utilities --------- const delay = ms => { scrollToBottom(); return new Promise(resolve => setTimeout(resolve, ms)); }; const randomElement = arr => arr[Math.floor(Math.random() * arr.length)]; // --------- Audio Playback --------- function unlockAudio() { const ctx = getAudioCtx(); if (ctx.state === 'suspended') { ctx.resume() } } const AudioCtx = window.AudioContext ?? window.webkitAudioContext; let audioCtx; function getAudioCtx() { if (!audioCtx) audioCtx = new AudioCtx(); return audioCtx; } async function playSound(file, speed = 1, loops = 1) { if (loops <= 0) return; const ctx = getAudioCtx(); if (ctx.state === 'suspended') { await ctx.resume(); } try { const resp = await fetch(file, { mode: 'cors' }); if (!resp.ok) throw new Error(`HTTP ${resp.status}`); const data = await resp.arrayBuffer(); const buffer = await ctx.decodeAudioData(data); const src = ctx.createBufferSource(); src.buffer = buffer; src.playbackRate.value = speed; src.loop = loops > 1; src.connect(ctx.destination); src.start(); if (loops > 1) { const totalTime = (buffer.duration / speed) * loops; src.stop(ctx.currentTime + totalTime); } return new Promise((resolve, reject) => { src.onended = () => { resolve(); }; }); } catch (err) { // console.warn('⚠️ WebAudio path failed, falling back to HTMLAudioElement:', err); // return _playWithAudioElement(file, speed, loops); console.error('❌ Failed to play sound:', err); return Promise.reject(err); } } // function _playWithAudioElement(file, speed, loops) { // if (loops <= 0) return Promise.resolve(); // const audio = new Audio(file); // audio.preload = 'auto'; // audio.crossOrigin = 'anonymous'; // audio.playbackRate = speed; // let remaining = loops; // audio.addEventListener('ended', onEnded); // audio.addEventListener('error', onError); // function onEnded() { // remaining--; // if (remaining > 0) { // audio.currentTime = 0; // audio.play().catch(onError); // } else { // cleanup(); // resolvePromise(); // } // } // function onError(e) { // cleanup(); // rejectPromise(e); // } // function cleanup() { // audio.pause(); // audio.currentTime = 0; // audio.removeEventListener('ended', onEnded); // audio.removeEventListener('error', onError); // } // let resolvePromise, rejectPromise; // const p = new Promise((res, rej) => { // resolvePromise = res; // rejectPromise = rej; // }); // // kick it off // audio.play() // .catch(err => { // console.error('❌