From e797b6bbee408fd571ad0dbc95f6566018483e97 Mon Sep 17 00:00:00 2001 From: oiupoyt Date: Sat, 12 Sep 2026 15:11:30 +0530 Subject: [PATCH] feat: refactor katwebsite with squared brutalist terminals, interactive shell CLI, and multi-mode visualizer --- index.html | 2190 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 1702 insertions(+), 488 deletions(-) diff --git a/index.html b/index.html index b820be3..292a23d 100644 --- a/index.html +++ b/index.html @@ -1,534 +1,1748 @@ - - -katOS + + + katOS — oiupoyt - - + + - - + + + + + - + #matrixCanvas.active { + opacity: 0.38; + } + + .desktop-grid { + position: fixed; + inset: 0; + background-image: + linear-gradient(rgba(255, 255, 255, 0.025) 1px, transparent 1px), + linear-gradient(90deg, rgba(255, 255, 255, 0.025) 1px, transparent 1px); + background-size: 40px 40px; + pointer-events: none; + z-index: 1; + } + + /* ── Desktop Canvas Area ─────────────────────────────────────────────────── */ + .desktop { + position: relative; + width: 100%; + height: calc(100vh - var(--taskbar-h)); + z-index: 2; + overflow: hidden; + } + + /* ── Windows (Squared Terminals) ─────────────────────────────────────────── */ + .window { + position: absolute; + background: var(--panel-bg); + border: 1px solid var(--border); + backdrop-filter: blur(28px) saturate(190%) brightness(1.05); + -webkit-backdrop-filter: blur(28px) saturate(190%) brightness(1.05); + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.65), 0 0 1px rgba(255, 255, 255, 0.15) inset; + z-index: 10; + display: flex; + flex-direction: column; + transition: opacity 0.2s ease, transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease; + } + + .window.active { + border-color: var(--border-active); + background: var(--panel-active); + box-shadow: 0 14px 50px rgba(0, 0, 0, 0.85), 0 0 16px rgba(255, 255, 255, 0.08), 0 0 1px rgba(255, 255, 255, 0.25) inset; + z-index: 30; + } + + .window.minimized { + display: none; + } + + .window.maximized { + top: 0 !important; + left: 0 !important; + width: 100% !important; + height: 100% !important; + } + + /* Titlebar */ + .titlebar { + height: 32px; + min-height: 32px; + background: rgba(255, 255, 255, 0.03); + border-bottom: 1px solid var(--border); + padding: 0 10px; + font-size: 11px; + letter-spacing: 0.04em; + cursor: grab; + display: flex; + align-items: center; + justify-content: space-between; + user-select: none; + } + + .window.active .titlebar { + background: rgba(255, 255, 255, 0.06); + border-bottom-color: var(--border-active); + } + + .titlebar:active { + cursor: grabbing; + } + + .title-left { + display: flex; + align-items: center; + gap: 8px; + color: var(--text-sub); + font-weight: 500; + } + + .window.active .title-left { + color: #ffffff; + } + + .title-left i { + font-size: 11px; + opacity: 0.7; + } + + /* Squared Window Controls */ + .window-controls { + display: flex; + align-items: center; + gap: 6px; + } + + .win-btn { + width: 12px; + height: 12px; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 9px; + font-weight: 700; + color: #000; + transition: all 0.12s ease; + opacity: 0.85; + line-height: 1; + } + + .win-btn:hover { + opacity: 1; + transform: scale(1.1); + } + + .win-btn-close { + background: #ff5f56; + border: 1px solid #e0443e; + } + + .win-btn-min { + background: #ffbd2e; + border: 1px solid #dea123; + } + + .win-btn-max { + background: #27c93f; + border: 1px solid #1aab29; + } + + .win-btn span { + display: none; + } + + .titlebar:hover .win-btn span { + display: block; + } + + /* Window Body Content */ + .window-body { + flex: 1; + padding: 14px 16px; + font-size: 12px; + line-height: 1.6; + overflow-y: auto; + overflow-x: hidden; + color: #d8d8d8; + } + + /* Custom Squared Scrollbar */ + .window-body::-webkit-scrollbar, + .terminal-body::-webkit-scrollbar { + width: 6px; + height: 6px; + } + .window-body::-webkit-scrollbar-track, + .terminal-body::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.4); + } + .window-body::-webkit-scrollbar-thumb, + .terminal-body::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.18); + } + .window-body::-webkit-scrollbar-thumb:hover, + .terminal-body::-webkit-scrollbar-thumb:hover { + background: rgba(255, 255, 255, 0.35); + } + + /* ── Terminal Styling ────────────────────────────────────────────────────── */ + .terminal-body { + font-family: 'JetBrains Mono', monospace; + font-size: 11px; + line-height: 1.5; + padding: 12px 14px; + color: #e5e5e5; + background: #08080a; + overflow-y: auto; + height: 100%; + user-select: text; + } + + .fastfetch-pre { + white-space: pre; + line-height: 1.38; + letter-spacing: 0.2px; + margin-bottom: 12px; + display: block; + } + + .term-row { + display: flex; + align-items: center; + gap: 6px; + } + + .term-prompt-line { + display: flex; + align-items: center; + gap: 6px; + margin-top: 8px; + } + + .term-prompt { + color: var(--accent); + font-weight: 600; + flex-shrink: 0; + } + + .term-input { + flex: 1; + background: transparent; + border: none; + color: #ffffff; + font-family: inherit; + font-size: 11px; + outline: none; + caret-color: #fff; + } + + .term-output { + margin-top: 4px; + margin-bottom: 8px; + color: #bbb; + line-height: 1.5; + white-space: pre-wrap; + } + + .term-cmd { + color: #fff; + font-weight: 500; + } + + /* Links & Lists */ + .link-item { + display: flex; + align-items: center; + gap: 10px; + padding: 7px 10px; + margin-bottom: 6px; + background: rgba(255, 255, 255, 0.025); + border: 1px solid rgba(255, 255, 255, 0.08); + cursor: pointer; + font-size: 12px; + color: #ddd; + transition: all 0.15s ease; + text-decoration: none; + } + + .link-item:hover { + background: rgba(255, 255, 255, 0.08); + border-color: var(--border-hover); + color: #fff; + transform: translateX(4px); + } + + .link-item i { + width: 16px; + text-align: center; + color: var(--accent); + } + + .link-item .badge { + margin-left: auto; + font-size: 10px; + color: var(--text-dim); + border: 1px solid #222; + padding: 1px 6px; + background: #080808; + } + + .skill-tag { + display: inline-block; + padding: 3px 8px; + margin: 3px; + background: rgba(255, 255, 255, 0.03); + border: 1px solid rgba(255, 255, 255, 0.1); + font-size: 11px; + color: #ccc; + } + + .skill-tag:hover { + border-color: var(--accent); + color: var(--accent); + } + + /* ── Audio Visualizer ────────────────────────────────────────────────────── */ + .viz-container { + width: 100%; + height: 100%; + position: relative; + background: #060608; + overflow: hidden; + display: flex; + align-items: center; + justify-content: center; + } + + #vizCanvas { + width: 100%; + height: 100%; + display: block; + background: transparent; + cursor: pointer; + } + + .viz-overlay { + position: absolute; + top: 10px; + left: 12px; + display: flex; + align-items: center; + gap: 12px; + pointer-events: none; + font-size: 10px; + letter-spacing: 0.08em; + color: rgba(255, 255, 255, 0.35); + text-transform: uppercase; + } + + .viz-mode-badge { + padding: 2px 6px; + border: 1px solid rgba(255, 255, 255, 0.15); + background: rgba(0, 0, 0, 0.5); + color: var(--accent); + } + + .viz-hint { + position: absolute; + bottom: 10px; + right: 12px; + font-size: 9px; + color: rgba(255, 255, 255, 0.25); + letter-spacing: 0.06em; + text-transform: uppercase; + pointer-events: none; + } + + .viz-idle-msg { + position: absolute; + color: rgba(255, 255, 255, 0.25); + font-size: 11px; + letter-spacing: 0.15em; + text-transform: uppercase; + pointer-events: none; + transition: opacity 0.3s ease; + } + + /* ── Taskbar ─────────────────────────────────────────────────────────────── */ + .taskbar { + position: fixed; + bottom: 0; + left: 0; + width: 100%; + height: var(--taskbar-h); + background: rgba(8, 8, 10, 0.96); + border-top: 1px solid var(--border); + backdrop-filter: blur(20px); + z-index: 100; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 10px; + font-size: 11px; + } + + .taskbar-left { + display: flex; + align-items: center; + gap: 8px; + height: 100%; + } + + .os-logo-btn { + font-family: 'Orbitron', sans-serif; + font-weight: 800; + font-size: 12px; + letter-spacing: 0.06em; + color: #fff; + padding: 4px 10px; + border: 1px solid rgba(255, 255, 255, 0.16); + background: rgba(255, 255, 255, 0.04); + cursor: pointer; + display: flex; + align-items: center; + gap: 6px; + transition: all 0.15s ease; + } + + .os-logo-btn:hover { + background: rgba(255, 255, 255, 0.12); + border-color: #fff; + } + + .os-logo-btn i { + color: var(--accent); + font-size: 11px; + } + + .taskbar-divider { + width: 1px; + height: 18px; + background: rgba(255, 255, 255, 0.1); + margin: 0 2px; + } + + .taskbar-windows { + display: flex; + align-items: center; + gap: 4px; + height: 100%; + } + + .taskbar-win-btn { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 4px 10px; + background: rgba(255, 255, 255, 0.02); + border: 1px solid rgba(255, 255, 255, 0.1); + font-size: 11px; + color: var(--text-sub); + cursor: pointer; + max-width: 140px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + transition: all 0.15s ease; + } + + .taskbar-win-btn:hover { + background: rgba(255, 255, 255, 0.06); + color: #fff; + border-color: var(--border-hover); + } + + .taskbar-win-btn.active { + background: rgba(255, 255, 255, 0.09); + border-color: var(--border-active); + color: #fff; + border-bottom: 2px solid var(--accent); + } + + .taskbar-right { + display: flex; + align-items: center; + gap: 12px; + } + + /* Music Player Taskbar Widget */ + .music-bar { + display: flex; + align-items: center; + gap: 8px; + padding: 2px 8px; + border: 1px solid rgba(255, 255, 255, 0.08); + background: rgba(255, 255, 255, 0.02); + } + + .music-icon { + font-size: 11px; + color: var(--accent); + animation: spinDisc 3s linear infinite; + } + + .music-icon.paused { + animation-play-state: paused; + color: var(--text-dim); + } + + @keyframes spinDisc { + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } + } + + .music-track { + max-width: 150px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + font-size: 10px; + color: var(--text-sub); + } + + .player-btn { + background: transparent; + border: 1px solid rgba(255, 255, 255, 0.15); + color: #fff; + width: 20px; + height: 20px; + display: inline-flex; + align-items: center; + justify-content: center; + cursor: pointer; + font-size: 9px; + transition: all 0.15s ease; + } + + .player-btn:hover { + background: #fff; + color: #000; + } + + .volume-slider { + width: 50px; + height: 3px; + -webkit-appearance: none; + appearance: none; + background: rgba(255, 255, 255, 0.2); + outline: none; + } + + .volume-slider::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 8px; + height: 12px; + background: #ffffff; + cursor: pointer; + } + + /* Tray Info */ + .tray-widget { + display: flex; + align-items: center; + gap: 10px; + font-size: 11px; + color: var(--text-dim); + } + + .tray-time { + color: #ffffff; + font-weight: 500; + } + + /* ── Desktop Context Menu ────────────────────────────────────────────────── */ + .context-menu { + position: fixed; + z-index: 9999; + background: rgba(12, 12, 14, 0.96); + border: 1px solid var(--border-active); + box-shadow: 0 10px 30px rgba(0,0,0,0.8); + backdrop-filter: blur(20px); + padding: 4px 0; + min-width: 180px; + display: none; + } + + .ctx-item { + padding: 7px 14px; + font-size: 11px; + color: #ddd; + cursor: pointer; + display: flex; + align-items: center; + gap: 8px; + transition: background 0.1s ease; + } + + .ctx-item:hover { + background: rgba(255, 255, 255, 0.08); + color: var(--accent); + } + + .ctx-item i { + width: 14px; + font-size: 11px; + } + + .ctx-sep { + height: 1px; + background: rgba(255, 255, 255, 0.08); + margin: 4px 0; + } + + /* ── Loading Screen ──────────────────────────────────────────────────────── */ + #loadingScreen { + position: fixed; + inset: 0; + background: #000000; + z-index: 10000; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + cursor: pointer; + transition: opacity 0.5s ease; + } + + #loadingScreen.hidden { + opacity: 0; + pointer-events: none; + } + + .boot-box { + border: 1px solid #333; + background: #08080a; + padding: 36px 48px; + max-width: 520px; + width: 90%; + text-align: center; + box-shadow: 0 0 50px rgba(0, 0, 0, 0.9); + } + + .boot-logo { + font-family: 'Orbitron', sans-serif; + font-size: 48px; + font-weight: 900; + letter-spacing: 0.08em; + color: #fff; + text-shadow: 0 0 20px rgba(255, 255, 255, 0.4); + margin-bottom: 18px; + } + + .boot-log { + font-size: 11px; + color: #666; + text-align: left; + line-height: 1.6; + margin-bottom: 24px; + border-top: 1px solid #1a1a1a; + padding-top: 14px; + } + + .boot-btn { + display: inline-block; + padding: 10px 24px; + border: 1px solid #555; + background: #111; + color: #fff; + font-size: 11px; + letter-spacing: 0.08em; + text-transform: uppercase; + cursor: pointer; + animation: pulseBtn 1.8s infinite alternate; + } + + @keyframes pulseBtn { + from { border-color: #444; color: #aaa; } + to { border-color: var(--accent); color: var(--accent); box-shadow: 0 0 14px rgba(77, 184, 255, 0.3); } + } + + /* ── Responsive Window Bounds for Small Screens ──────────────────────────── */ + @media (max-width: 900px) { + .window { + position: static !important; + width: 100% !important; + height: auto !important; + margin-bottom: 12px; + } + .desktop { + overflow-y: auto; + padding: 12px; + height: calc(100vh - var(--taskbar-h)); + } + .taskbar-windows { + display: none; + } + .music-track { + display: none; + } + } + - -
-
- -
Click anywhere to enter
-
-
-
- -
- katOS - -
-
- - Music Ready + +
+
+ +
+
[ OK ] Mounted /dev/nvme0n1p2 on /home/oiupoyt
+
[ OK ] Audio subsystem initialized: Baiaa081
+
[ OK ] Wayland compositor: Hyprland 0.54.2
+
[ OK ] Fastfetch terminal ready
+
+
[ click anywhere to boot ]
- -
-
- -
-
-
- about.md + + + +
+ + +
+ + +
+
+
+ + about.md +
+
+
–
+
□
+
×
+
+
+
+

i cant stop loving linux, pls speed i need this

+

minecraft shyt, networking experiments, and linux customization.

+

i was on the ███████████████

+

cats > people haha.

+

i use arch yea

+

you da real kat 🤍.

+
+
+ + +
+
+
+ + skillz.bash +
+
+
–
+
□
+
×
+
+
+
+
# system competencies:
+ linux / arch + minecraft servers + self hosting + server networking + java / plugins +
# personality traits:
+ yappin + im crine + tweaking + hahahahahha + cool content + very funny + veri fond of cats +
+
+ + + + + + + + +
+
+
+ + ~fastfetch +
+
+
–
+
□
+
×
+
+
+
+
+
+
+ oiupoyt@archlinux:~$ + +
+
+
+ + +
+
+
+ + visualizer +
+
+
–
+
□
+
×
+
+
+
+ +
+ mode: + spectrum bars +
+
[click visualizer to switch mode]
+ play music to visualize +
+
+
-
- I cant stop loving linux, pls speed i need this

- minecraft shyt, networking experiments, and linux customization.

- i was on the ███████████████

- cats > people haha.

- i use arch yea

- you da real kat 🤍. + + +
+
+
+ + katOS +
+
+
+
+ +
+ +
+ + Baiaa081 - Noite Isolada + + + +
+ + +
+ RAM: 4.2G + + 00:00:00 +
+
+
+ + +
+
Open Terminal
+
Cycle Visualizer Mode
+
Toggle Matrix Rain
+
+
Play / Pause Music
+
Show All Windows
+
Reset Window Layout
-
- -
-
-
- links.zip -
-
-
-
-
-
- -
-
+ + -
-
-
- websites.html -
- -
- -
-
-
- skillz.bash -
-
- linux / arch
Minecraft Servers
Self Hosting
server networking
Java / Plugins
yappin
im crine
tweaking
hahahahahha
cool content
very funny
veri fond of cats -
-
+ + const btn = document.createElement('div'); + btn.className = 'taskbar-win-btn' + (win.classList.contains('active') && !win.classList.contains('minimized') ? ' active' : ''); + btn.innerHTML = `${titleText}`; + btn.onclick = () => restoreWindow(id); + container.appendChild(btn); + }); + } + + // ── FastFetch ASCII Art & System Specs ──────────────────────────────────── + const fastfetchArtEl = document.getElementById('fastfetchArt'); + const fa = cls => ``; + + const fastfetchLines = [ + ` ▄`, + ` ▟█▙`, + ` ▟███▙ oiupoyt@archlinux`, + ` ▟█████▙ ────────────────────────`, + ` ▟███████▙ ${fa('fas fa-laptop')} OS Arch Linux x86_64`, + ` ▂▔▀▜██████▙ ${fa('fas fa-microchip')} Kernel Linux 6.19.8-arch1-1`, + ` ▟██▅▂▝▜█████▙ ${fa('fas fa-box-open')} Packages 1254 (pacman), 60 (flatpak)`, + ` ▟█████████████▙ ${fa('fas fa-terminal')} Shell fish 4.5.0`, + ` ▟███████████████▙ ${fa('fas fa-display')} Terminal kitty 0.46.1`, + ` ▟█████████████████▙ ${fa('fas fa-window-restore')} WM Hyprland 0.54.2 (Wayland)`, + ` ▟███████████████████▙ ${fa('fas fa-palette')} Theme breeze-dark`, + ` ▟█████████▛▀▀▜████████▙ ${fa('fas fa-font')} Font JetBrains Mono (11pt)`, + ` ▟████████▛ ▜███████▙ ${fa('fas fa-clock')} Uptime 12 hours, 42 mins`, + ` ▟█████████ ████████▙ ${fa('fas fa-music')} Music Baiaa081 - Noite Isolada`, + ` ▟██████████ █████▆▅▄▃▂ ${fa('fas fa-cat')} Status you da real kat 🤍`, + ` ▟██████████▛ ▜█████████▙ ${fa('fas fa-network-wired')} Websites katdrop • katimages • toolbox`, + ` ▟██████▀▀▀ ▀▀██████▙`, + ` ▟███▀▘ ▝▀███▙`, + ` ▟▛▀ ▀▜▙`, + ]; + fastfetchArtEl.innerHTML = fastfetchLines.map(l => `
${l}
`).join(''); + + // ── Interactive Terminal CLI ───────────────────────────────────────────── + const termInput = document.getElementById('termInput'); + const termHistory = document.getElementById('termHistory'); + const termBody = document.getElementById('termBody'); + let cmdHistory = []; + let historyIdx = -1; + + function focusTermInput() { + termInput.focus(); + } + + termInput.addEventListener('keydown', e => { + if (e.key === 'Enter') { + const cmd = termInput.value.trim(); + if (cmd) { + cmdHistory.push(cmd); + historyIdx = cmdHistory.length; + execCommand(cmd); + } + termInput.value = ''; + termBody.scrollTop = termBody.scrollHeight; + } else if (e.key === 'ArrowUp') { + if (historyIdx > 0) { + historyIdx--; + termInput.value = cmdHistory[historyIdx]; + } + } else if (e.key === 'ArrowDown') { + if (historyIdx < cmdHistory.length - 1) { + historyIdx++; + termInput.value = cmdHistory[historyIdx]; + } else { + historyIdx = cmdHistory.length; + termInput.value = ''; + } + } else if (e.key === 'Tab') { + e.preventDefault(); + const cur = termInput.value.trim().toLowerCase(); + const available = ['help', 'fastfetch', 'neofetch', 'clear', 'cat', 'ls', 'projects', 'skills', 'music', 'matrix', 'whoami', 'date', 'reboot']; + const match = available.find(c => c.startsWith(cur)); + if (match) termInput.value = match; + } + }); + + function execCommand(cmdLine) { + const parts = cmdLine.split(' '); + const cmd = parts[0].toLowerCase(); + const arg = parts.slice(1).join(' '); + + const row = document.createElement('div'); + row.innerHTML = `oiupoyt@archlinux:~$ ${escapeHtml(cmdLine)}`; + termHistory.appendChild(row); + + const out = document.createElement('div'); + out.className = 'term-output'; + + switch(cmd) { + case 'help': + out.innerHTML = `Available commands: + fastfetch - display Arch Linux logo & system specs + ls - list virtual directory contents + cat <file> - display contents of a file (e.g. cat about.md) + projects - list active web projects & links + skills - show competencies & skills + music [play|pause|vol] - control background audio + catpic - fetch a fresh cat image + matrix - toggle digital rain animation + whoami - print current session bio + clear - clear terminal screen + date - show current date and time + reboot - restart katOS desktop`; + break; + + case 'fastfetch': + case 'neofetch': + fastfetchArtEl.style.display = 'block'; + out.textContent = ''; + break; + + case 'ls': + out.innerHTML = `about.md skillz.bash websites.html links.zip music.mp3 backgroundVideo.mp4`; + break; + + case 'cat': + if (!arg) { + out.textContent = 'cat: missing file operand. try: cat about.md'; + } else if (arg.includes('about')) { + out.textContent = `i cant stop loving linux, pls speed i need this\nminecraft shyt, networking experiments, and linux customization.\ni was on the ███████████████\ncats > people haha.\ni use arch yea\nyou da real kat 🤍.`; + } else if (arg.includes('skill')) { + out.textContent = `linux / arch • Minecraft Servers • Self Hosting • server networking • Java / Plugins • yappin • im crine • tweaking • hahahahahha • cool content • very funny • veri fond of cats`; + } else if (arg.includes('website')) { + out.innerHTML = `• katdrop: https://katdrop.oiupoyt.space\n• katimages: https://kat-images.netlify.app/\n• just-download: https://justdownload.netlify.app\n• kattoolbox: https://toolbox.oiupoyt.space`; + } else { + out.textContent = `cat: ${arg}: Permission denied or file is binary`; + } + break; + + case 'projects': + out.innerHTML = `katOS Projects: + 1. katdrop - minimal 10-min file transfer service + 2. katimages - look at cat. feel good. + 3. just-download - youtube & instagram media downloader + 4. kattoolbox - client-side developer utility suite`; + break; + + case 'skills': + out.textContent = 'linux / arch, minecraft servers, self hosting, server networking, java / plugins, yappin, im crine, tweaking, cats'; + break; + + case 'music': + if (arg === 'play') { + playMusic(); + out.textContent = 'audio: playing'; + } else if (arg === 'pause') { + pauseMusic(); + out.textContent = 'audio: paused'; + } else if (arg.startsWith('vol')) { + const val = parseInt(arg.split(' ')[1]); + if (!isNaN(val) && val >= 0 && val <= 100) { + setVolume(val); + out.textContent = `audio: volume set to ${val}%`; + } else { + out.textContent = 'usage: music vol <0-100>'; + } + } else { + out.textContent = 'usage: music [play | pause | vol <0-100>]'; + } + break; + + case 'catpic': + case 'cat-image': + out.innerHTML = `Fetching cat image...`; + fetch('https://api.thecatapi.com/v1/images/search') + .then(r => r.json()) + .then(data => { + if (data && data[0] && data[0].url) { + out.innerHTML = `meow`; + termBody.scrollTop = termBody.scrollHeight; + } + }).catch(() => { + out.textContent = 'cat error: no cat found :('; + }); + break; + + case 'matrix': + toggleMatrix(); + out.textContent = `matrix digital rain: ${matrixActive ? 'ON' : 'OFF'}`; + break; + + case 'clear': + termHistory.innerHTML = ''; + fastfetchArtEl.style.display = 'none'; + return; + + case 'whoami': + out.textContent = 'oiupoyt — linux enthusiast, minecraft tinkerer, cat lover'; + break; + + case 'uname': + case 'uname -a': + out.textContent = 'Linux katOS 6.19.8-arch1-1 #1 SMP PREEMPT_DYNAMIC x86_64 GNU/Linux'; + break; + + case 'date': + out.textContent = new Date().toString(); + break; + + case 'sudo': + out.textContent = 'user oiupoyt is not in the sudoers file. this incident will be reported to kat.'; + break; + + case 'reboot': + location.reload(); + return; + + default: + out.textContent = `bash: ${cmd}: command not found. type 'help' for available commands.`; + } + + termHistory.appendChild(out); + termBody.scrollTop = termBody.scrollHeight; + } + + function spawnFastfetch() { + restoreWindow('win-term'); + fastfetchArtEl.style.display = 'block'; + } + + function escapeHtml(str) { + return String(str).replace(/[&<>'"]/g, t => ({ + '&': '&', '<': '<', '>': '>', "'": ''', '"': '"' + }[t] || t)); + } + + // ── Audio & Visualizer Engine ──────────────────────────────────────────── + const bgMusic = document.getElementById('bgMusic'); + const playBtn = document.getElementById('playBtn'); + const playIcon = document.getElementById('playIcon'); + const musicDisc = document.getElementById('musicDisc'); + const volSlider = document.getElementById('volSlider'); + const vizCanvas = document.getElementById('vizCanvas'); + const vizCtx = vizCanvas.getContext('2d'); + const vizIdleMsg = document.getElementById('vizIdleMsg'); + const vizModeName = document.getElementById('vizModeName'); + + let isPlaying = false; + let audioCtx, analyser, source, vizAnimId; + let vizConnected = false; + + const vizModes = ['spectrum bars', 'waveform beam', 'mirror pulse']; + let currentVizModeIdx = 0; + + function setupAudio() { + if (vizConnected) return; + try { + audioCtx = new (window.AudioContext || window.webkitAudioContext)(); + analyser = audioCtx.createAnalyser(); + analyser.fftSize = 256; + analyser.smoothingTimeConstant = 0.82; + source = audioCtx.createMediaElementSource(bgMusic); + source.connect(analyser); + analyser.connect(audioCtx.destination); + vizConnected = true; + } catch (err) { + console.warn('AudioContext init error:', err); + } + } + + function playMusic() { + setupAudio(); + if (audioCtx && audioCtx.state === 'suspended') { + audioCtx.resume(); + } + bgMusic.play().then(() => { + isPlaying = true; + playIcon.className = 'fas fa-pause'; + musicDisc.classList.remove('paused'); + startVisualizer(); + }).catch(err => { + console.warn('Audio play prevented:', err); + }); + } + + function pauseMusic() { + bgMusic.pause(); + isPlaying = false; + playIcon.className = 'fas fa-play'; + musicDisc.classList.add('paused'); + stopVisualizer(); + } + + function togglePlay() { + if (isPlaying) { + pauseMusic(); + } else { + playMusic(); + } + } + + function setVolume(val) { + bgMusic.volume = val / 100; + volSlider.value = val; + } + + volSlider.addEventListener('input', e => { + setVolume(e.target.value); + }); + + bgMusic.volume = volSlider.value / 100; + bgMusic.addEventListener('ended', () => { + pauseMusic(); + }); + + // ── Visualizer Rendering Modes ─────────────────────────────────────────── + function cycleVizMode() { + currentVizModeIdx = (currentVizModeIdx + 1) % vizModes.length; + vizModeName.textContent = vizModes[currentVizModeIdx]; + } + + vizCanvas.addEventListener('click', cycleVizMode); + + function resizeVizCanvas() { + const rect = vizCanvas.getBoundingClientRect(); + const dpr = window.devicePixelRatio || 1; + vizCanvas.width = rect.width * dpr; + vizCanvas.height = rect.height * dpr; + } + + function startVisualizer() { + if (!analyser) return; + vizIdleMsg.style.opacity = '0'; + cancelAnimationFrame(vizAnimId); + drawVisualizerFrame(); + } + + function stopVisualizer() { + cancelAnimationFrame(vizAnimId); + resizeVizCanvas(); + const W = vizCanvas.width; + const H = vizCanvas.height; + vizCtx.clearRect(0, 0, W, H); + + // Resting zero line + vizCtx.strokeStyle = 'rgba(255, 255, 255, 0.08)'; + vizCtx.lineWidth = 1; + vizCtx.beginPath(); + vizCtx.moveTo(0, H * 0.9); + vizCtx.lineTo(W, H * 0.9); + vizCtx.stroke(); + + vizIdleMsg.style.opacity = '1'; + } + + function drawVisualizerFrame() { + vizAnimId = requestAnimationFrame(drawVisualizerFrame); + resizeVizCanvas(); + + const W = vizCanvas.width; + const H = vizCanvas.height; + if (W === 0 || H === 0) return; + + vizCtx.clearRect(0, 0, W, H); + + const bufLen = analyser.frequencyBinCount; + const freqData = new Uint8Array(bufLen); + analyser.getByteFrequencyData(freqData); + + const mode = vizModes[currentVizModeIdx]; + + if (mode === 'spectrum bars') { + // Mode 1: Squared Spectrum Bars with floating glowing peaks + const barCount = 28; + const gap = W * 0.012; + const barW = (W - gap * (barCount + 1)) / barCount; + const step = Math.floor(bufLen / barCount); + const maxH = H * 0.82; + const baseY = H * 0.92; + + for (let i = 0; i < barCount; i++) { + let sum = 0; + for (let k = 0; k < step; k++) sum += freqData[i * step + k]; + const ratio = (sum / step) / 255; + const bh = ratio * maxH; + const x = gap + i * (barW + gap); + const y = baseY - bh; + + const alpha = 0.25 + ratio * 0.75; + const grad = vizCtx.createLinearGradient(0, y, 0, baseY); + grad.addColorStop(0, `rgba(77, 184, 255, ${alpha})`); + grad.addColorStop(0.5, `rgba(255, 255, 255, ${alpha * 0.7})`); + grad.addColorStop(1, `rgba(77, 184, 255, ${alpha * 0.1})`); + + vizCtx.fillStyle = grad; + vizCtx.fillRect(x, y, barW, bh); + + // Squared glowing peak cap + if (bh > 4) { + vizCtx.fillStyle = `rgba(255, 255, 255, ${Math.min(1, alpha + 0.2)})`; + vizCtx.fillRect(x, y - 3, barW, 2); + } + } + + // Base line + vizCtx.strokeStyle = 'rgba(255, 255, 255, 0.1)'; + vizCtx.lineWidth = 1; + vizCtx.beginPath(); + vizCtx.moveTo(0, baseY); + vizCtx.lineTo(W, baseY); + vizCtx.stroke(); + + } else if (mode === 'waveform beam') { + // Mode 2: Oscilloscope Waveform Beam + const timeData = new Uint8Array(analyser.fftSize); + analyser.getByteTimeDomainData(timeData); + + vizCtx.lineWidth = 2; + vizCtx.strokeStyle = '#4db8ff'; + vizCtx.shadowColor = 'rgba(77, 184, 255, 0.8)'; + vizCtx.shadowBlur = 10; + vizCtx.beginPath(); + + const sliceW = W / timeData.length; + let x = 0; + + for (let i = 0; i < timeData.length; i++) { + const v = timeData[i] / 128.0; + const y = (v * H) / 2; + if (i === 0) vizCtx.moveTo(x, y); + else vizCtx.lineTo(x, y); + x += sliceW; + } + + vizCtx.lineTo(W, H / 2); + vizCtx.stroke(); + vizCtx.shadowBlur = 0; + + } else if (mode === 'mirror pulse') { + // Mode 3: Symmetric Center-Out Pulse + const barCount = 18; + const center = W / 2; + const barW = (W / 2) / (barCount + 1); + const maxH = H * 0.75; + const centerY = H / 2; + + for (let i = 0; i < barCount; i++) { + const ratio = freqData[i * 4] / 255; + const bh = ratio * maxH; + const alpha = 0.2 + ratio * 0.8; + + vizCtx.fillStyle = `rgba(255, 255, 255, ${alpha})`; + // Right wing + vizCtx.fillRect(center + i * barW, centerY - bh / 2, barW - 2, bh); + // Left wing + vizCtx.fillRect(center - (i + 1) * barW, centerY - bh / 2, barW - 2, bh); + } + + vizCtx.strokeStyle = 'rgba(77, 184, 255, 0.4)'; + vizCtx.lineWidth = 1; + vizCtx.beginPath(); + vizCtx.moveTo(0, centerY); + vizCtx.lineTo(W, centerY); + vizCtx.stroke(); + } + } + + // ── Matrix Rain Effect ─────────────────────────────────────────────────── + const matrixCanvas = document.getElementById('matrixCanvas'); + const mCtx = matrixCanvas.getContext('2d'); + let matrixActive = false; + let matrixInterval = null; + const mChars = '01KATOSOIUPOYTARCHLINUXλπ#$><;:~'; + let mCols, mDrops; + + function initMatrix() { + matrixCanvas.width = window.innerWidth; + matrixCanvas.height = window.innerHeight; + mCols = Math.floor(matrixCanvas.width / 18); + mDrops = Array(mCols).fill(1); + } + initMatrix(); + window.addEventListener('resize', initMatrix); + + function drawMatrix() { + mCtx.fillStyle = 'rgba(0, 0, 0, 0.08)'; + mCtx.fillRect(0, 0, matrixCanvas.width, matrixCanvas.height); + mCtx.fillStyle = '#4db8ff'; + mCtx.font = '12px "JetBrains Mono", monospace'; + + for (let i = 0; i < mDrops.length; i++) { + const text = mChars.charAt(Math.floor(Math.random() * mChars.length)); + mCtx.fillText(text, i * 18, mDrops[i] * 18); + if (mDrops[i] * 18 > matrixCanvas.height && Math.random() > 0.975) { + mDrops[i] = 0; + } + mDrops[i]++; + } + } + + function toggleMatrix() { + matrixActive = !matrixActive; + matrixCanvas.classList.toggle('active', matrixActive); + if (matrixActive) { + if (!matrixInterval) matrixInterval = setInterval(drawMatrix, 40); + } else { + clearInterval(matrixInterval); + matrixInterval = null; + mCtx.clearRect(0, 0, matrixCanvas.width, matrixCanvas.height); + } + } + + // ── Desktop Context Menu ───────────────────────────────────────────────── + const ctxMenu = document.getElementById('ctxMenu'); + + document.addEventListener('contextmenu', e => { + if (e.target.closest('.window-body') || e.target.closest('input')) return; + e.preventDefault(); + ctxMenu.style.display = 'block'; + let x = e.clientX; + let y = e.clientY; + if (x + 190 > window.innerWidth) x = window.innerWidth - 195; + if (y + 200 > window.innerHeight) y = window.innerHeight - 205; + ctxMenu.style.left = x + 'px'; + ctxMenu.style.top = y + 'px'; + }); + + document.addEventListener('click', e => { + if (!e.target.closest('.context-menu')) { + ctxMenu.style.display = 'none'; + } + }); + + // ── Clock & System Monitor ─────────────────────────────────────────────── + function updateClock() { + const now = new Date(); + const h = String(now.getHours()).padStart(2, '0'); + const m = String(now.getMinutes()).padStart(2, '0'); + const s = String(now.getSeconds()).padStart(2, '0'); + document.getElementById('clock').textContent = `${h}:${m}:${s}`; + } + updateClock(); + setInterval(updateClock, 1000); + + // ── Background Video Loader ────────────────────────────────────────────── + const bgVideo = document.getElementById('bgVideo'); + async function tryLoadBgVideo() { + for (const name of ['backgroundVideo.mp4', 'backgroundVideo.webm']) { + try { + const res = await fetch(name); + if (res.ok) { + const url = URL.createObjectURL(await res.blob()); + bgVideo.src = url; + bgVideo.load(); + bgVideo.play().catch(() => {}); + return; + } + } catch (e) {} + } + } + + // ── Loading Screen Enter ───────────────────────────────────────────────── + const loadingScreen = document.getElementById('loadingScreen'); + loadingScreen.addEventListener('click', () => { + loadingScreen.classList.add('hidden'); + tryLoadBgVideo(); + setTimeout(() => { + playMusic(); + focusTermInput(); + }, 300); + }); + + // Keyboard Shortcut (Space to play/pause music outside text inputs) + window.addEventListener('keydown', e => { + if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; + if (e.code === 'Space') { + e.preventDefault(); + togglePlay(); + } + }); + + // Initialize System + initWindows(); +