katwebsite/index.html

1674 lines
57 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>katOS — oiupoyt</title>
<!-- Google AdSense -->
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-3876936176422477" crossorigin="anonymous"></script>
<!-- Fonts & Icons: JetBrains Mono Nerd aesthetic -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@300;400;500;600;700&family=JetBrains+Mono:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=Space+Mono:ital,wght@0,400;0,700;1,400&display=swap" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css" rel="stylesheet">
<style>
/* ── Reset & Brutalist Geometry ─────────────────────────────────────────── */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
border-radius: 0 !important; /* Strict squared-out terminals & windows */
font-family: 'JetBrains Mono', 'Fira Code', monospace !important;
scrollbar-width: none !important;
-ms-overflow-style: none !important;
}
:root {
--bg: #000000;
--panel-bg: rgba(6, 6, 10, 0.22); /* High glass transparency */
--panel-active: rgba(10, 10, 16, 0.35); /* Focused transparency */
--border: rgba(255, 255, 255, 0.12);
--border-hover: rgba(255, 255, 255, 0.35);
--border-active: rgba(255, 255, 255, 0.7);
--text: #f0f0f0;
--text-dim: #666666;
--text-sub: #999999;
--accent: #ffffff;
--glow: 0 0 10px rgba(255, 255, 255, 0.8), 0 0 22px rgba(255, 255, 255, 0.4);
--glow-subtle: 0 0 8px rgba(255, 255, 255, 0.4);
--taskbar-h: 36px;
}
body {
background: var(--bg);
color: var(--text);
font-family: 'JetBrains Mono', 'Fira Code', monospace !important;
height: 100vh;
width: 100vw;
overflow: hidden;
user-select: none;
-webkit-font-smoothing: antialiased;
}
/* ── Background Video & Matrix Rain ─────────────────────────────────────── */
.video-bg {
position: fixed;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
z-index: 0;
pointer-events: none;
opacity: 0.55;
filter: contrast(1.15) brightness(0.88);
}
#matrixCanvas {
position: fixed;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 1;
opacity: 0;
transition: opacity 0.6s ease;
}
#matrixCanvas.active {
opacity: 0.35;
}
.desktop-grid {
position: fixed;
inset: 0;
background-image:
linear-gradient(rgba(255, 255, 255, 0.02) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
background-size: 36px 36px;
pointer-events: none;
z-index: 1;
}
/* ── Desktop Workspace ───────────────────────────────────────────────────── */
.desktop {
position: relative;
width: 100%;
height: calc(100vh - var(--taskbar-h));
z-index: 2;
overflow: hidden;
}
/* ── Transparent Squared Windows ─────────────────────────────────────────── */
.window {
position: absolute;
background: var(--panel-bg);
border: 1px solid var(--border);
backdrop-filter: blur(14px) saturate(160%);
-webkit-backdrop-filter: blur(14px) saturate(160%);
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.6), 0 0 1px rgba(255, 255, 255, 0.15) inset;
z-index: 10;
display: flex;
flex-direction: column;
transition: border-color 0.18s ease, box-shadow 0.18s ease, background 0.18s ease;
}
.window.active {
border-color: var(--border-active);
background: var(--panel-active);
box-shadow: 0 14px 50px rgba(0, 0, 0, 0.75), 0 0 14px rgba(255, 255, 255, 0.18), 0 0 1px rgba(255, 255, 255, 0.4) inset;
z-index: 30;
}
.window.minimized {
display: none !important;
}
.window.maximized {
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
}
/* Titlebar */
.titlebar {
height: 30px;
min-height: 30px;
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;
font-size: 11px;
}
.window.active .title-left {
color: #ffffff;
text-shadow: var(--glow-subtle);
}
.title-left i {
font-size: 10px;
opacity: 0.7;
}
/* Remade Minimalist Terminal Navigation Dot */
.window-controls {
display: flex;
align-items: center;
justify-content: center;
}
.win-dot-close {
width: 14px;
height: 14px;
border: 1px solid rgba(255, 255, 255, 0.22);
background: rgba(255, 255, 255, 0.03);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.16s ease;
position: relative;
}
.win-dot-close::before {
content: '';
width: 4px;
height: 4px;
background: rgba(255, 255, 255, 0.55);
box-shadow: 0 0 4px rgba(255, 255, 255, 0.35);
transition: all 0.16s ease;
}
.win-dot-close:hover {
border-color: #ffffff;
background: rgba(255, 255, 255, 0.16);
box-shadow: 0 0 10px rgba(255, 255, 255, 0.45);
}
.win-dot-close:hover::before {
background: #ffffff;
width: 6px;
height: 6px;
box-shadow: 0 0 8px #ffffff;
}
/* Window Body */
.window-body {
flex: 1;
padding: 14px 16px;
font-size: 12px;
line-height: 1.6;
overflow-y: auto;
overflow-x: hidden;
color: #d0d0d0;
background: transparent !important;
}
/* Complete scrollbar removal (clean invisible scrolling) */
* {
scrollbar-width: none !important;
-ms-overflow-style: none !important;
}
*::-webkit-scrollbar,
.window-body::-webkit-scrollbar,
.terminal-body::-webkit-scrollbar,
body::-webkit-scrollbar,
.desktop::-webkit-scrollbar {
display: none !important;
width: 0 !important;
height: 0 !important;
}
/* ── Terminal Styling ────────────────────────────────────────────────────── */
.terminal-body {
font-family: 'JetBrains Mono', 'Fira Code', monospace !important;
font-size: 11px;
line-height: 1.48;
padding: 12px 14px;
color: #e5e5e5;
background: transparent !important;
overflow-y: auto;
height: 100%;
user-select: text;
}
.fastfetch-pre {
white-space: pre;
line-height: 1.35;
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: #ffffff;
text-shadow: var(--glow-subtle);
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: #aaa;
line-height: 1.5;
white-space: pre-wrap;
}
.term-cmd {
color: #fff;
font-weight: 600;
}
/* Links & Lists in Windows */
.link-item {
display: flex;
align-items: center;
gap: 10px;
padding: 8px 10px;
margin-bottom: 6px;
background: rgba(255, 255, 255, 0.02);
border: 1px solid rgba(255, 255, 255, 0.09);
cursor: pointer;
font-size: 11px;
color: #ddd;
transition: all 0.15s ease;
text-decoration: none;
}
.link-item:hover {
background: rgba(255, 255, 255, 0.09);
border-color: #ffffff;
color: #fff;
box-shadow: 0 0 10px rgba(255, 255, 255, 0.15);
transform: translateX(3px);
}
.link-item i {
width: 16px;
text-align: center;
color: #ffffff;
opacity: 0.85;
}
.link-item .badge {
margin-left: auto;
font-size: 10px;
color: var(--text-dim);
border: 1px solid rgba(255, 255, 255, 0.15);
padding: 1px 6px;
background: rgba(0, 0, 0, 0.6);
}
.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;
transition: all 0.15s ease;
}
.skill-tag:hover {
border-color: #ffffff;
color: #ffffff;
box-shadow: 0 0 8px rgba(255, 255, 255, 0.3);
}
/* ── Visualizer Container ────────────────────────────────────────────────── */
.viz-container {
width: 100%;
height: 100%;
position: relative;
background: transparent !important;
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: 10px;
pointer-events: none;
font-size: 10px;
letter-spacing: 0.08em;
color: rgba(255, 255, 255, 0.4);
text-transform: uppercase;
}
.viz-mode-badge {
padding: 2px 6px;
border: 1px solid rgba(255, 255, 255, 0.3);
background: rgba(0, 0, 0, 0.6);
color: #ffffff;
text-shadow: var(--glow-subtle);
}
.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(4, 4, 6, 0.94);
border-top: 1px solid var(--border);
backdrop-filter: blur(20px);
z-index: 100;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 12px;
font-size: 11px;
}
.taskbar-left {
display: flex;
align-items: center;
gap: 10px;
height: 100%;
}
/* Clean KatOS button without icon */
.os-logo-btn {
font-family: 'JetBrains Mono', monospace;
font-weight: 700;
font-size: 12px;
letter-spacing: 0.05em;
color: #ffffff;
text-shadow: var(--glow-subtle);
padding: 4px 10px;
border: 1px solid rgba(255, 255, 255, 0.25);
background: rgba(255, 255, 255, 0.05);
cursor: pointer;
display: flex;
align-items: center;
transition: all 0.15s ease;
}
.os-logo-btn:hover {
background: rgba(255, 255, 255, 0.15);
border-color: #ffffff;
box-shadow: var(--glow-subtle);
}
.taskbar-divider {
width: 1px;
height: 16px;
background: rgba(255, 255, 255, 0.12);
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.08);
color: #fff;
border-color: var(--border-hover);
}
.taskbar-win-btn.active {
background: rgba(255, 255, 255, 0.12);
border-color: #ffffff;
color: #fff;
box-shadow: var(--glow-subtle);
}
.taskbar-right {
display: flex;
align-items: center;
gap: 14px;
}
/* Music Player Widget in Taskbar */
.music-bar {
display: flex;
align-items: center;
gap: 8px;
padding: 2px 8px;
border: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(255, 255, 255, 0.02);
}
.music-icon {
font-size: 11px;
color: #ffffff;
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: 160px;
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.2);
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;
box-shadow: var(--glow-subtle);
}
.volume-slider {
width: 50px;
height: 3px;
-webkit-appearance: none;
appearance: none;
background: rgba(255, 255, 255, 0.25);
outline: none;
}
.volume-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 8px;
height: 12px;
background: #ffffff;
cursor: pointer;
}
/* System Tray Clock */
.tray-time {
color: #ffffff;
font-weight: 600;
letter-spacing: 0.05em;
text-shadow: var(--glow-subtle);
}
/* ── Minimal Boot 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-minimal {
text-align: center;
}
.boot-logo {
font-family: 'JetBrains Mono', monospace;
font-size: 52px;
font-weight: 700;
letter-spacing: -0.04em;
color: #ffffff;
text-shadow: 0 0 24px rgba(255, 255, 255, 0.8), 0 0 45px rgba(255, 255, 255, 0.3);
margin-bottom: 12px;
}
.boot-sub {
font-size: 11px;
color: #777777;
letter-spacing: 0.12em;
text-transform: lowercase;
animation: pulseSub 1.8s infinite alternate;
}
@keyframes pulseSub {
from { opacity: 0.4; color: #666; }
to { opacity: 1; color: #ffffff; text-shadow: var(--glow-subtle); }
}
/* ── Desktop Right-Click Context Menu ────────────────────────────────────── */
.context-menu {
position: fixed;
z-index: 9999;
background: rgba(10, 10, 12, 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.12);
color: #ffffff;
text-shadow: var(--glow-subtle);
}
.ctx-item i {
width: 14px;
font-size: 11px;
}
.ctx-sep {
height: 1px;
background: rgba(255, 255, 255, 0.1);
margin: 4px 0;
}
/* ── Responsive Window Bounds ────────────────────────────────────────────── */
@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;
}
}
</style>
</head>
<body>
<!-- Minimal Boot Screen (Click to Start Audio & Video) -->
<div id="loadingScreen">
<div class="boot-minimal">
<div class="boot-logo">katOS</div>
<div class="boot-sub">[ click to enter ]</div>
</div>
</div>
<!-- Background Video & Ambient Canvas Layers -->
<video class="video-bg" id="bgVideo" autoplay muted loop playsinline></video>
<canvas id="matrixCanvas"></canvas>
<div class="desktop-grid"></div>
<!-- Desktop Workspace -->
<div class="desktop" id="desktop">
<!-- About Window -->
<div class="window active" id="win-about">
<div class="titlebar">
<div class="title-left">
<i class="fas fa-file-lines"></i>
<span>about.md</span>
</div>
<div class="window-controls">
<div class="win-dot-close" onclick="closeWindow('win-about')" title="Close"></div>
</div>
</div>
<div class="window-body">
<p style="color:#ffffff; font-weight:500; margin-bottom: 12px;">i cant stop loving linux, pls speed i need this</p>
<p style="color:#aaa; margin-bottom: 12px;">minecraft shyt, networking experiments, and linux customization.</p>
<p style="color:#555; margin-bottom: 12px; font-family:monospace;">i was on the ███████████████</p>
<p style="color:#fff; text-shadow:var(--glow-subtle); margin-bottom: 12px;">cats &gt; people haha.</p>
<p style="color:#bbb; margin-bottom: 12px;">i use arch yea</p>
<p style="color:#ffffff; font-weight:600; text-shadow:var(--glow-subtle);">you da real kat 🤍.</p>
</div>
</div>
<!-- Skills Window -->
<div class="window" id="win-skills">
<div class="titlebar">
<div class="title-left">
<i class="fas fa-terminal"></i>
<span>skillz.bash</span>
</div>
<div class="window-controls">
<div class="win-dot-close" onclick="closeWindow('win-skills')" title="Close"></div>
</div>
</div>
<div class="window-body">
<div style="margin-bottom: 8px; color: var(--text-dim);"># system competencies:</div>
<span class="skill-tag"><i class="fab fa-linux"></i> linux / arch</span>
<span class="skill-tag"><i class="fas fa-cube"></i> minecraft servers</span>
<span class="skill-tag"><i class="fas fa-server"></i> self hosting</span>
<span class="skill-tag"><i class="fas fa-network-wired"></i> server networking</span>
<span class="skill-tag"><i class="fab fa-java"></i> java / plugins</span>
<div style="margin: 14px 0 6px; color: var(--text-dim);"># personality traits:</div>
<span class="skill-tag">yappin</span>
<span class="skill-tag">im crine</span>
<span class="skill-tag">tweaking</span>
<span class="skill-tag">hahahahahha</span>
<span class="skill-tag">cool content</span>
<span class="skill-tag">very funny</span>
<span class="skill-tag"><i class="fas fa-cat"></i> veri fond of cats</span>
</div>
</div>
<!-- Websites & Projects Window -->
<div class="window" id="win-websites">
<div class="titlebar">
<div class="title-left">
<i class="fas fa-globe"></i>
<span>websites.html</span>
</div>
<div class="window-controls">
<div class="win-dot-close" onclick="closeWindow('win-websites')" title="Close"></div>
</div>
</div>
<div class="window-body">
<a class="link-item" href="https://katdrop.oiupoyt.space" target="_blank" rel="noopener">
<i class="fas fa-file-arrow-up"></i>
<div>
<div style="color:#fff; font-weight:500;">katdrop.oiupoyt.space</div>
<div style="font-size:10px; color:#777;">minimal 10-min file transfer</div>
</div>
<span class="badge">live</span>
</a>
<a class="link-item" href="https://kats.oiupoyt.space" target="_blank" rel="noopener">
<i class="fas fa-cat"></i>
<div>
<div style="color:#fff; font-weight:500;">kats.oiupoyt.space</div>
<div style="font-size:10px; color:#777;">look at cat. feel good.</div>
</div>
<span class="badge">live</span>
</a>
<a class="link-item" href="https://jd.oiupoyt.space" target="_blank" rel="noopener">
<i class="fas fa-download"></i>
<div>
<div style="color:#fff; font-weight:500;">jd.oiupoyt.space</div>
<div style="font-size:10px; color:#777;">just download yt &amp; ig media</div>
</div>
<span class="badge">live</span>
</a>
<a class="link-item" href="https://toolbox.oiupoyt.space" target="_blank" rel="noopener">
<i class="fas fa-wrench"></i>
<div>
<div style="color:#fff; font-weight:500;">toolbox.oiupoyt.space</div>
<div style="font-size:10px; color:#777;">client-side dev utility suite</div>
</div>
<span class="badge">live</span>
</a>
</div>
</div>
<!-- Social Links Window -->
<div class="window" id="win-links">
<div class="titlebar">
<div class="title-left">
<i class="fas fa-folder-closed"></i>
<span>links.zip</span>
</div>
<div class="window-controls">
<div class="win-dot-close" onclick="closeWindow('win-links')" title="Close"></div>
</div>
</div>
<div class="window-body">
<a class="link-item" href="https://github.com/oiupoyt" target="_blank" rel="noopener">
<i class="fab fa-github"></i>
<span>GitHub</span>
<span class="badge">@oiupoyt</span>
</a>
<a class="link-item" href="https://discordapp.com/users/1082968457559146506" target="_blank" rel="noopener">
<i class="fab fa-discord"></i>
<span>Discord</span>
<span class="badge">@oiupoyt</span>
</a>
<a class="link-item" href="https://www.instagram.com/oiupoyt/" target="_blank" rel="noopener">
<i class="fab fa-instagram"></i>
<span>Instagram</span>
<span class="badge">@oiupoyt</span>
</a>
<a class="link-item" href="https://www.youtube.com/@OIUPOYT" target="_blank" rel="noopener">
<i class="fab fa-youtube"></i>
<span>YouTube</span>
<span class="badge">@OIUPOYT</span>
</a>
<a class="link-item" href="https://www.roblox.com/users/1529210346/profile" target="_blank" rel="noopener">
<i class="fas fa-gamepad"></i>
<span>Roblox</span>
<span class="badge">oiupoyt</span>
</a>
<a class="link-item" href="https://modrinth.com/user/oiupoyt" target="_blank" rel="noopener">
<i class="fas fa-cube"></i>
<span>Modrinth</span>
<span class="badge">mods</span>
</a>
</div>
</div>
<!-- Interactive FastFetch Terminal Window -->
<div class="window active" id="win-term">
<div class="titlebar">
<div class="title-left">
<i class="fas fa-terminal"></i>
<span>~fastfetch</span>
</div>
<div class="window-controls">
<div class="win-dot-close" onclick="closeWindow('win-term')" title="Close"></div>
</div>
</div>
<div class="terminal-body" id="termBody" onclick="focusTermInput()">
<div class="fastfetch-pre" id="fastfetchArt"></div>
<div id="termHistory"></div>
<div class="term-prompt-line">
<span class="term-prompt">oiupoyt@archlinux:~$</span>
<input type="text" class="term-input" id="termInput" autocomplete="off" spellcheck="false" autofocus>
</div>
</div>
</div>
<!-- Audio Visualizer Window -->
<div class="window" id="win-viz">
<div class="titlebar">
<div class="title-left">
<i class="fas fa-wave-square"></i>
<span>visualizer</span>
</div>
<div class="window-controls">
<div class="win-dot-close" onclick="closeWindow('win-viz')" title="Close"></div>
</div>
</div>
<div class="viz-container" id="vizBox">
<canvas id="vizCanvas" title="Click to cycle visualizer mode"></canvas>
<div class="viz-overlay">
<span>mode:</span>
<span class="viz-mode-badge" id="vizModeName">spectrum bars</span>
</div>
<div class="viz-hint">[click visualizer to switch mode]</div>
<span class="viz-idle-msg" id="vizIdleMsg">play music to visualize</span>
</div>
</div>
</div>
<!-- Taskbar -->
<footer class="taskbar">
<div class="taskbar-left">
<div class="os-logo-btn" onclick="restoreAllWindows()" title="katOS Launcher">
<span>katOS</span>
</div>
<div class="taskbar-divider"></div>
<div class="taskbar-windows" id="taskbarWinContainer"></div>
</div>
<div class="taskbar-right">
<!-- Music Player Controls -->
<div class="music-bar">
<i class="fas fa-compact-disc music-icon paused" id="musicDisc"></i>
<span class="music-track" id="musicTrack">Baiaa081 - Noite Isolada</span>
<button class="player-btn" id="playBtn" onclick="togglePlay()" title="Play/Pause">
<i class="fas fa-play" id="playIcon"></i>
</button>
<input type="range" class="volume-slider" id="volSlider" min="0" max="100" value="45" title="Volume">
<button class="player-btn" onclick="cycleVizMode()" title="Switch Visualizer Mode">
<i class="fas fa-sliders"></i>
</button>
</div>
<!-- System Tray Clock (RAM removed) -->
<span class="tray-time" id="clock">00:00:00</span>
</div>
</footer>
<!-- Desktop Right-Click Context Menu -->
<div class="context-menu" id="ctxMenu">
<div class="ctx-item" onclick="spawnFastfetch()"><i class="fas fa-terminal"></i> Open Terminal</div>
<div class="ctx-item" onclick="cycleVizMode()"><i class="fas fa-sliders"></i> Cycle Visualizer Mode</div>
<div class="ctx-item" onclick="toggleMatrix()"><i class="fas fa-code"></i> Toggle Matrix Rain</div>
<div class="ctx-sep"></div>
<div class="ctx-item" onclick="togglePlay()"><i class="fas fa-music"></i> Play / Pause Music</div>
<div class="ctx-item" onclick="restoreAllWindows()"><i class="fas fa-window-restore"></i> Show All Windows</div>
<div class="ctx-item" onclick="autoSpaceWindows()"><i class="fas fa-rotate-left"></i> Reset &amp; Space Windows</div>
</div>
<!-- Audio Element -->
<audio id="bgMusic" loop preload="auto">
<source src="music.mp3" type="audio/mpeg">
</audio>
<script>
// ── Global System State ──────────────────────────────────────────────────
let topZIndex = 40;
const windowRegistry = ['win-about', 'win-skills', 'win-websites', 'win-links', 'win-term', 'win-viz'];
// ── Auto-Space Terminals on Start (Organic Staggered Layout) ───────────
function autoSpaceWindows() {
const W = window.innerWidth;
const H = window.innerHeight - 36; // leave room for taskbar
if (W >= 1500) {
// Broad monitor: organic offsets & sized generously to eliminate scrollbars
setWinPos('win-about', 32, 32, 400, 260);
setWinPos('win-skills', 325, 72, 420, 340);
setWinPos('win-websites', 55, 495, 400, 310);
setWinPos('win-links', 405, 540, 380, 370);
setWinPos('win-term', 25, 955, Math.min(900, W - 985), 465);
setWinPos('win-viz', 520, 885, Math.min(970, W - 915), 295);
} else if (W >= 1150) {
// Standard laptop / desktop: non-parallel staggered coordinates
setWinPos('win-about', 22, 24, 380, 255);
setWinPos('win-skills', 305, 60, 395, 330);
setWinPos('win-websites', 48, 440, 375, 300);
setWinPos('win-links', 380, 485, 360, 360);
setWinPos('win-term', 20, 845, Math.max(500, W - 875), 445);
setWinPos('win-viz', 495, 795, Math.max(540, W - 825), 285);
} else if (W >= 800) {
// Tablet / compact
setWinPos('win-about', 18, 16, 360, 250);
setWinPos('win-skills', 290, 45, 370, 320);
setWinPos('win-websites', 35, 415, 355, 295);
setWinPos('win-links', 355, 445, 345, 355);
setWinPos('win-term', 615, 22, W - 48, 435);
setWinPos('win-viz', 1075, 38, W - 68, 280);
}
restoreAllWindows();
bringToFront(document.getElementById('win-term'));
}
function setWinPos(id, top, left, width, height) {
const win = document.getElementById(id);
if (!win) return;
win.style.top = top + 'px';
win.style.left = left + 'px';
if (width) win.style.width = width + 'px';
if (height) win.style.height = height + 'px';
}
// ── Window Dragging & State ──────────────────────────────────────────────
function bringToFront(win) {
if (!win) return;
topZIndex++;
win.style.zIndex = topZIndex;
document.querySelectorAll('.window').forEach(w => w.classList.remove('active'));
win.classList.add('active');
updateTaskbar();
}
function initWindows() {
document.querySelectorAll('.window').forEach(win => {
const bar = win.querySelector('.titlebar');
if (!bar) return;
// Focus on click
win.addEventListener('mousedown', () => bringToFront(win));
// Dragging
bar.addEventListener('mousedown', e => {
if (e.target.closest('.win-dot-close')) return;
bringToFront(win);
if (win.classList.contains('maximized')) return;
const rect = win.getBoundingClientRect();
const shiftX = e.clientX - rect.left;
const shiftY = e.clientY - rect.top;
function onMouseMove(moveEvent) {
let newX = moveEvent.clientX - shiftX;
let newY = moveEvent.clientY - shiftY;
const maxX = window.innerWidth - 60;
const maxY = window.innerHeight - 70;
if (newX < 0) newX = 0;
if (newX > maxX) newX = maxX;
if (newY < 0) newY = 0;
if (newY > maxY) newY = maxY;
win.style.left = newX + 'px';
win.style.top = newY + 'px';
}
function onMouseUp() {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
}
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
});
});
autoSpaceWindows();
updateTaskbar();
}
function closeWindow(id) {
const win = document.getElementById(id);
if (!win) return;
win.classList.add('minimized');
updateTaskbar();
}
function restoreWindow(id) {
const win = document.getElementById(id);
if (!win) return;
if (win.classList.contains('minimized')) {
win.classList.remove('minimized');
bringToFront(win);
} else if (win.classList.contains('active')) {
win.classList.add('minimized');
} else {
bringToFront(win);
}
updateTaskbar();
}
function restoreAllWindows() {
windowRegistry.forEach(id => {
const win = document.getElementById(id);
if (win) {
win.classList.remove('minimized');
win.classList.remove('maximized');
}
});
updateTaskbar();
}
function updateTaskbar() {
const container = document.getElementById('taskbarWinContainer');
if (!container) return;
container.innerHTML = '';
windowRegistry.forEach(id => {
const win = document.getElementById(id);
if (!win) return;
const titleEl = win.querySelector('.title-left span');
const iconEl = win.querySelector('.title-left i');
const titleText = titleEl ? titleEl.textContent : id;
const iconClass = iconEl ? iconEl.className : 'fas fa-terminal';
const btn = document.createElement('div');
btn.className = 'taskbar-win-btn' + (win.classList.contains('active') && !win.classList.contains('minimized') ? ' active' : '');
btn.innerHTML = `<i class="${iconClass}"></i><span>${titleText}</span>`;
btn.onclick = () => restoreWindow(id);
container.appendChild(btn);
});
}
// ── FastFetch ASCII Art & Specs (Monochrome Glow) ─────────────────────────
const fastfetchArtEl = document.getElementById('fastfetchArt');
const fa = cls => `<i class="${cls}" style="width:1.2em;text-align:center;display:inline-block;opacity:0.75;font-size:10px;"></i>`;
const fastfetchLines = [
` ▄`,
` ▟█▙`,
` ▟███▙ <b style="color:#ffffff; text-shadow:var(--glow-subtle);">oiupoyt</b><span style="opacity:0.4">@</span><b style="color:#ffffff;">archlinux</b>`,
` ▟█████▙ <span style="opacity:0.35">────────────────────────</span>`,
` ▟███████▙ ${fa('fas fa-laptop')} <span style="opacity:0.45;font-size:10px">OS</span> Arch Linux x86_64`,
` ▂▔▀▜██████▙ ${fa('fas fa-microchip')} <span style="opacity:0.45;font-size:10px">Kernel</span> Linux 6.19.8-arch1-1`,
` ▟██▅▂▝▜█████▙ ${fa('fas fa-box-open')} <span style="opacity:0.45;font-size:10px">Packages</span> 1254 (pacman), 60 (flatpak)`,
` ▟█████████████▙ ${fa('fas fa-terminal')} <span style="opacity:0.45;font-size:10px">Shell</span> fish 4.5.0`,
` ▟███████████████▙ ${fa('fas fa-display')} <span style="opacity:0.45;font-size:10px">Terminal</span> kitty 0.46.1`,
` ▟█████████████████▙ ${fa('fas fa-window-restore')} <span style="opacity:0.45;font-size:10px">WM</span> Hyprland 0.54.2 (Wayland)`,
` ▟███████████████████▙ ${fa('fas fa-palette')} <span style="opacity:0.45;font-size:10px">Theme</span> monochrome-dark`,
` ▟█████████▛▀▀▜████████▙ ${fa('fas fa-font')} <span style="opacity:0.45;font-size:10px">Font</span> JetBrains Mono (11pt)`,
` ▟████████▛ ▜███████▙ ${fa('fas fa-clock')} <span style="opacity:0.45;font-size:10px">Uptime</span> <span id="dynUptime">12 hours, 42 mins</span>`,
` ▟█████████ ████████▙ ${fa('fas fa-music')} <span style="opacity:0.45;font-size:10px">Music</span> Baiaa081 - Noite Isolada`,
` ▟██████████ █████▆▅▄▃▂ ${fa('fas fa-cat')} <span style="opacity:0.45;font-size:10px">Status</span> you da real kat 🤍`,
` ▟██████████▛ ▜█████████▙ ${fa('fas fa-network-wired')} <span style="opacity:0.45;font-size:10px">Websites</span> katdrop • kats • jd • toolbox`,
` ▟██████▀▀▀ ▀▀██████▙`,
` ▟███▀▘ ▝▀███▙`,
` ▟▛▀ ▀▜▙`,
];
fastfetchArtEl.innerHTML = fastfetchLines.map(l => `<div class="term-row">${l}</div>`).join('');
// ── Interactive Terminal Shell ───────────────────────────────────────────
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 = `<span class="term-prompt">oiupoyt@archlinux:~$</span> <span class="term-cmd">${escapeHtml(cmdLine)}</span>`;
termHistory.appendChild(row);
const out = document.createElement('div');
out.className = 'term-output';
switch(cmd) {
case 'help':
out.innerHTML = `Available commands:
<b style="color:#ffffff">fastfetch</b> - display Arch Linux logo & system specs
<b style="color:#ffffff">ls</b> - list virtual directory contents
<b style="color:#ffffff">cat &lt;file&gt;</b> - display contents of a file (e.g. cat about.md)
<b style="color:#ffffff">projects</b> - list active web projects & links
<b style="color:#ffffff">skills</b> - show competencies & skills
<b style="color:#ffffff">music</b> - music play | pause | vol &lt;0-100&gt;
<b style="color:#ffffff">catpic</b> - fetch a fresh cat image
<b style="color:#ffffff">matrix</b> - toggle digital rain animation
<b style="color:#ffffff">whoami</b> - print current session bio
<b style="color:#ffffff">clear</b> - clear terminal screen
<b style="color:#ffffff">date</b> - show current date and time
<b style="color:#ffffff">reboot</b> - restart katOS desktop`;
break;
case 'fastfetch':
case 'neofetch':
fastfetchArtEl.style.display = 'block';
out.textContent = '';
break;
case 'ls':
out.innerHTML = `<span style="color:#ffffff">about.md</span> <span style="color:#ffffff">skillz.bash</span> <span style="color:#ffffff">websites.html</span> <span style="color:#ffffff">links.zip</span> <span style="color:#888">music.mp3</span> <span style="color:#888">backgroundVideo.mp4</span>`;
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• kats: https://kats.oiupoyt.space\n• jd: https://jd.oiupoyt.space\n• toolbox: https://toolbox.oiupoyt.space`;
} else if (arg.includes('link')) {
out.innerHTML = `• GitHub: https://github.com/oiupoyt\n• Discord: @oiupoyt\n• Instagram: @oiupoyt\n• YouTube: @OIUPOYT\n• Modrinth: oiupoyt\n• Roblox: oiupoyt`;
} else {
out.textContent = `cat: ${arg}: Permission denied or file is binary`;
}
break;
case 'projects':
out.innerHTML = `oiupoyt projects:
1. <a href="https://katdrop.oiupoyt.space" target="_blank" style="color:#ffffff; text-decoration:underline;">katdrop.oiupoyt.space</a> - minimal 10-min file transfer service
2. <a href="https://kats.oiupoyt.space" target="_blank" style="color:#ffffff; text-decoration:underline;">kats.oiupoyt.space</a> - look at cat. feel good.
3. <a href="https://jd.oiupoyt.space" target="_blank" style="color:#ffffff; text-decoration:underline;">jd.oiupoyt.space</a> - youtube & instagram media downloader
4. <a href="https://toolbox.oiupoyt.space" target="_blank" style="color:#ffffff; text-decoration:underline;">toolbox.oiupoyt.space</a> - 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':
case 'cat':
out.innerHTML = `Fetching cat...`;
fetch('https://api.thecatapi.com/v1/images/search')
.then(r => r.json())
.then(data => {
if (data && data[0] && data[0].url) {
out.innerHTML = `<img src="${data[0].url}" style="max-width:280px;max-height:200px;border:1px solid #444;margin-top:6px;display:block;"><span style="font-size:10px;color:#888;">meow</span>`;
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 '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 => ({
'&': '&amp;', '<': '&lt;', '>': '&gt;', "'": '&#39;', '"': '&quot;'
}[t] || t));
}
// ── Audio & Visualizer Engine (Glow White Monochrome) ─────────────────────
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', '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 (Glow White Spectrum) ────────────────────────────
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);
// Baseline resting line
vizCtx.strokeStyle = 'rgba(255, 255, 255, 0.1)';
vizCtx.lineWidth = 1;
vizCtx.beginPath();
vizCtx.moveTo(0, H * 0.92);
vizCtx.lineTo(W, H * 0.92);
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 Glowing White Spectrum Bars
const barCount = 26;
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(255, 255, 255, ${alpha})`);
grad.addColorStop(0.5, `rgba(220, 220, 220, ${alpha * 0.6})`);
grad.addColorStop(1, `rgba(180, 180, 180, ${alpha * 0.1})`);
vizCtx.fillStyle = grad;
vizCtx.fillRect(x, y, barW, bh);
// Glowing white peak cap
if (bh > 4) {
vizCtx.fillStyle = `rgba(255, 255, 255, ${Math.min(1, alpha + 0.3)})`;
vizCtx.shadowColor = 'rgba(255, 255, 255, 0.8)';
vizCtx.shadowBlur = 6;
vizCtx.fillRect(x, y - 3, barW, 2);
vizCtx.shadowBlur = 0;
}
}
// Base line
vizCtx.strokeStyle = 'rgba(255, 255, 255, 0.12)';
vizCtx.lineWidth = 1;
vizCtx.beginPath();
vizCtx.moveTo(0, baseY);
vizCtx.lineTo(W, baseY);
vizCtx.stroke();
} else if (mode === 'mirror pulse') {
// Mode 2: 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})`;
vizCtx.fillRect(center + i * barW, centerY - bh / 2, barW - 2, bh);
vizCtx.fillRect(center - (i + 1) * barW, centerY - bh / 2, barW - 2, bh);
}
vizCtx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
vizCtx.lineWidth = 1;
vizCtx.beginPath();
vizCtx.moveTo(0, centerY);
vizCtx.lineTo(W, centerY);
vizCtx.stroke();
}
}
// ── Matrix Rain (Monochrome White) ───────────────────────────────────────
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 = 'rgba(255, 255, 255, 0.75)';
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 Right-Click 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 ────────────────────────────────────────────────────────────────
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)
window.addEventListener('keydown', e => {
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
if (e.code === 'Space') {
e.preventDefault();
togglePlay();
}
});
// Initialize System
initWindows();
</script>
</body>
</html>