diff --git a/css/style.css b/css/style.css index 9f48bc4..eebdeb0 100644 --- a/css/style.css +++ b/css/style.css @@ -287,6 +287,9 @@ a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); } } /* === HERO SECTION === */ +/* ============================ + HERO HUD GRID LAYOUT + ============================ */ .hero { min-height: 100vh; display: flex; @@ -296,48 +299,194 @@ a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); } position: relative; } -.hero-hud { - position: relative; +.hero-hud-grid { width: 100%; - max-width: 800px; - padding: 4rem; + max-width: 1200px; + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: auto auto; + gap: 1.5rem; + animation: fadeIn 1s ease both; +} + +.hud-col-left, +.hud-col-right { + display: flex; + flex-direction: column; + gap: 1.5rem; +} + +/* ============================ + PANELS (shared) + ============================ */ +.panel { border: 1px solid var(--border); - background: rgba(10, 14, 20, 0.5); + background: rgba(10, 14, 20, 0.6); + position: relative; + overflow: hidden; } -/* HUD Corners */ -.hud-corner { +.panel::before { + content: ''; position: absolute; - width: 20px; - height: 20px; + top: 0; left: 0; + width: 20px; height: 20px; + border-top: 2px solid var(--accent); + border-left: 2px solid var(--accent); + pointer-events: none; } -.hud-tl { top: -1px; left: -1px; border-top: 2px solid var(--accent); border-left: 2px solid var(--accent); } -.hud-tr { top: -1px; right: -1px; border-top: 2px solid var(--accent); border-right: 2px solid var(--accent); } -.hud-bl { bottom: -1px; left: -1px; border-bottom: 2px solid var(--accent); border-left: 2px solid var(--accent); } -.hud-br { bottom: -1px; right: -1px; border-bottom: 2px solid var(--accent); border-right: 2px solid var(--accent); } +.panel::after { + content: ''; + position: absolute; + bottom: 0; right: 0; + width: 20px; height: 20px; + border-bottom: 2px solid var(--accent); + border-right: 2px solid var(--accent); + pointer-events: none; +} -.hero-content { +.panel-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.75rem 1rem; + border-bottom: 1px solid var(--border); + background: rgba(0, 255, 200, 0.02); +} + +.panel-title { + font-family: var(--font-mono); + font-size: 0.6rem; + letter-spacing: 3px; + color: var(--text-secondary); + text-transform: uppercase; +} + +.panel-icon { + color: var(--accent); + font-size: 0.8rem; +} + +.panel-pct { + font-family: var(--font-mono); + font-size: 0.7rem; + color: var(--accent); + text-shadow: 0 0 10px var(--accent-glow); +} + +.panel-status-dot { + font-family: var(--font-mono); + font-size: 0.55rem; + letter-spacing: 1px; +} + +.status-green { color: var(--accent); } + +.panel-content { + padding: 1rem; +} + +/* ============================ + MAP PANEL + ============================ */ +.map-panel { + flex: 1; + min-height: 320px; +} + +.map-content { + position: relative; + display: flex; + align-items: center; + justify-content: center; + padding: 1rem; +} + +.uk-map-svg { + width: 100%; + max-width: 220px; + height: auto; +} + +/* Pulse rings */ +.pulse-ring { + animation: pulseRing 3s ease-out infinite; + transform-origin: center; +} + +.pulse-ring-1 { animation-delay: 0s; } +.pulse-ring-2 { animation-delay: 1s; } +.pulse-ring-3 { animation-delay: 2s; } + +@keyframes pulseRing { + 0% { opacity: 0.8; r: 8; } + 100% { opacity: 0; r: 35; } +} + +/* Map scan line */ +.map-scan-line { + animation: mapScan 4s linear infinite; +} + +@keyframes mapScan { + 0% { transform: translateY(0); opacity: 0.4; } + 50% { opacity: 0.8; } + 100% { transform: translateY(400px); opacity: 0.2; } +} + +.map-data-overlay { + position: absolute; + bottom: 0.5rem; + left: 1rem; + right: 1rem; + display: flex; + justify-content: space-around; + gap: 0.5rem; +} + +.map-coord-block { text-align: center; } +.coord-label { + display: block; + font-family: var(--font-mono); + font-size: 0.5rem; + letter-spacing: 2px; + color: var(--text-secondary); +} + +.coord-value { + display: block; + font-family: var(--font-mono); + font-size: 0.75rem; + color: var(--accent); + text-shadow: 0 0 8px var(--accent-glow); +} + +/* ============================ + IDENTITY BLOCK + ============================ */ +.hud-identity { + text-align: center; + padding: 1.5rem; +} + .hero-label { font-family: var(--font-mono); font-size: 0.65rem; letter-spacing: 4px; color: var(--text-secondary); - margin-bottom: 1.5rem; - animation: fadeInDown 1s ease 0.2s both; + margin-bottom: 1rem; } -/* Glitch Effect */ .hero-title { font-family: var(--font-display); - font-size: clamp(2.5rem, 8vw, 5rem); + font-size: clamp(2rem, 5vw, 3.5rem); font-weight: 900; letter-spacing: 8px; - margin-bottom: 1.5rem; - animation: fadeInUp 1s ease 0.4s both; + margin-bottom: 1rem; } .glitch { @@ -379,13 +528,10 @@ a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); } 97% { opacity: 0; } } -/* Typing Effect */ .hero-subtitle { font-family: var(--font-mono); - font-size: 1rem; + font-size: 0.9rem; color: var(--accent); - margin-bottom: 3rem; - animation: fadeIn 1s ease 0.8s both; } .typing-prefix { color: var(--text-secondary); } @@ -399,33 +545,326 @@ a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); } 50% { opacity: 0; } } -/* Hero Stats */ -.hero-stats { +/* ============================ + SERVER METRICS PANEL + ============================ */ +.hud-metrics { display: flex; - justify-content: center; - gap: 3rem; - animation: fadeInUp 1s ease 1s both; + flex-direction: column; + gap: 0.75rem; } -.stat-item { - text-align: center; +.metric-row { + display: grid; + grid-template-columns: 80px 1fr 45px; + align-items: center; + gap: 0.75rem; } -.stat-label { - display: block; +.metric-label { + font-family: var(--font-mono); font-size: 0.55rem; - letter-spacing: 3px; + letter-spacing: 2px; color: var(--text-secondary); +} + +.metric-bar { + height: 6px; + background: rgba(0, 255, 200, 0.08); + border: 1px solid rgba(0, 255, 200, 0.15); + position: relative; + overflow: hidden; +} + +.metric-fill { + height: 100%; + background: linear-gradient(90deg, var(--accent), rgba(0, 255, 200, 0.4)); + box-shadow: 0 0 8px var(--accent-glow); + transition: width 1.5s cubic-bezier(0.4, 0, 0.2, 1); + position: relative; +} + +.metric-fill::after { + content: ''; + position: absolute; + right: 0; top: 0; + width: 2px; height: 100%; + background: #fff; + box-shadow: 0 0 6px var(--accent); +} + +.metric-val { + font-family: var(--font-mono); + font-size: 0.65rem; + color: var(--accent); + text-align: right; + text-shadow: 0 0 6px var(--accent-glow); +} + +/* ============================ + POWER + CONTAINERS ROW + ============================ */ +.hud-row-panels { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0; + padding: 0; + border: none; + background: none; +} + +.hud-row-panels::before, +.hud-row-panels::after { display: none; } + +.hud-mini-panel { + border: 1px solid var(--border); + background: rgba(10, 14, 20, 0.6); + position: relative; +} + +.hud-mini-panel:first-child { margin-right: -0.5px; } +.hud-mini-panel:last-child { margin-left: -0.5px; } + +.hud-mini-panel::before { + content: ''; + position: absolute; + top: 0; left: 0; + width: 12px; height: 12px; + border-top: 2px solid var(--accent); + border-left: 2px solid var(--accent); + pointer-events: none; +} + +.hud-mini-panel::after { + content: ''; + position: absolute; + bottom: 0; right: 0; + width: 12px; height: 12px; + border-bottom: 2px solid var(--accent); + border-right: 2px solid var(--accent); + pointer-events: none; +} + +.power-display { + text-align: center; + padding: 0.75rem; +} + +.power-big { + font-family: var(--font-display); + font-size: 2.5rem; + font-weight: 900; + color: var(--accent); + text-shadow: 0 0 20px var(--accent-glow); + line-height: 1; +} + +.power-unit { + font-size: 1rem; + opacity: 0.6; +} + +.containers-display { + text-align: center; + padding: 0.5rem; +} + +.container-count { + font-family: var(--font-display); + font-size: 1.5rem; + font-weight: 700; + color: var(--text-primary); + margin-bottom: 0.5rem; +} + +.container-count span { + color: var(--accent); +} + +.container-total { + color: var(--text-secondary) !important; +} + +.container-bar { + height: 4px; + background: rgba(0, 255, 200, 0.08); + border: 1px solid rgba(0, 255, 200, 0.1); margin-bottom: 0.4rem; } -.stat-value { +.container-fill { + height: 100%; + width: 100%; + background: var(--accent); + box-shadow: 0 0 6px var(--accent-glow); +} + +.container-label { + font-family: var(--font-mono); + font-size: 0.5rem; + letter-spacing: 2px; + color: var(--accent); + opacity: 0.7; +} + +/* ============================ + NETWORK GRAPH PANEL + ============================ */ +.graph-container { + padding: 0.75rem; +} + +#networkGraph { + width: 100%; + height: 100px; + display: block; + border-bottom: 1px solid var(--border); + margin-bottom: 0.75rem; +} + +.graph-stats { + display: flex; + justify-content: space-between; + gap: 0.5rem; +} + +.graph-stat { + text-align: center; + flex: 1; +} + +.graph-stat-label { + display: block; + font-family: var(--font-mono); + font-size: 0.5rem; + letter-spacing: 2px; + color: var(--text-secondary); + margin-bottom: 0.25rem; +} + +.graph-stat-value { + display: block; + font-family: var(--font-mono); + font-size: 0.7rem; + color: var(--accent); + text-shadow: 0 0 6px var(--accent-glow); +} + +/* ============================ + BOTTOM STATUS BAR + ============================ */ +.hud-bottom-bar { + grid-column: 1 / -1; + display: flex; + justify-content: space-between; + align-items: center; + padding: 0.75rem 1rem; + border: 1px solid var(--border); + background: rgba(10, 14, 20, 0.6); + gap: 1rem; +} + +.hud-bottom-left { + display: flex; + align-items: center; + gap: 0.75rem; +} + +.hud-id { + font-family: var(--font-display); font-size: 0.75rem; - letter-spacing: 1px; + font-weight: 700; + letter-spacing: 2px; color: var(--text-primary); } -.stat-online { color: var(--accent); } +.hud-dot-online { + font-family: var(--font-mono); + font-size: 0.55rem; + color: var(--accent); + letter-spacing: 1px; +} + +.hud-bottom-stats { + display: flex; + gap: 2rem; +} + +.hud-bstat { + text-align: center; +} + +.hud-bstat-label { + display: block; + font-family: var(--font-mono); + font-size: 0.45rem; + letter-spacing: 2px; + color: var(--text-secondary); + margin-bottom: 0.15rem; +} + +.hud-bstat-value { + font-family: var(--font-mono); + font-size: 0.6rem; + color: var(--text-primary); + letter-spacing: 1px; +} + +.hud-online { color: var(--accent); } + +.hud-bottom-right { + display: flex; + align-items: center; + gap: 0.5rem; +} + +.hud-scan-label { + font-family: var(--font-mono); + font-size: 0.5rem; + letter-spacing: 2px; + color: var(--text-secondary); + animation: scanPulse 2s ease infinite; +} + +@keyframes scanPulse { + 0%, 100% { opacity: 0.5; } + 50% { opacity: 1; } +} + +.hud-scan-bar { + width: 60px; + height: 4px; + background: rgba(0, 255, 200, 0.08); + border: 1px solid rgba(0, 255, 200, 0.15); + overflow: hidden; +} + +.hud-scan-fill { + height: 100%; + width: 0%; + background: var(--accent); + box-shadow: 0 0 6px var(--accent-glow); + transition: width 0.3s linear; +} + +.hud-scan-pct { + font-family: var(--font-mono); + font-size: 0.55rem; + color: var(--accent); + min-width: 28px; +} + +/* Scan Line Animation */ +.scan-line { + position: absolute; + top: 0; left: 0; + width: 100%; + height: 2px; + background: linear-gradient(90deg, transparent, var(--accent), transparent); + opacity: 0.6; + animation: scan 4s linear infinite; +} + /* Scan Line Animation */ .scan-line { @@ -1063,6 +1502,7 @@ a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); } /* === RESPONSIVE === */ @media (max-width: 1024px) { + .hero-hud-grid { grid-template-columns: 1fr 1fr; gap: 1rem; max-width: 900px; } .blog-grid, .dev-grid { grid-template-columns: repeat(2, 1fr); } .panels-grid { grid-template-columns: 1fr; } .contact-grid { grid-template-columns: 1fr; } @@ -1117,8 +1557,31 @@ a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); } .nav-item.active .dropdown { max-height: 300px; } - .hero-hud { padding: 2rem; } - .hero-stats { flex-direction: column; gap: 1rem; } + /* HUD grid stacks on mobile */ + .hero-hud-grid { + grid-template-columns: 1fr; + gap: 1rem; + padding: 0; + } + + .hud-row-panels { grid-template-columns: 1fr 1fr; } + + .hero-title { font-size: clamp(1.8rem, 6vw, 2.5rem); } + + .hud-bottom-bar { + flex-direction: column; + gap: 0.75rem; + text-align: center; + } + + .hud-bottom-stats { + flex-wrap: wrap; + justify-content: center; + gap: 1rem; + } + + .hud-bottom-right { justify-content: center; } + .blog-grid, .dev-grid { grid-template-columns: 1fr; } .links-grid { grid-template-columns: 1fr; } .skill-bar { grid-template-columns: 1fr; gap: 0.3rem; } @@ -1129,7 +1592,11 @@ a:hover { color: #fff; text-shadow: 0 0 10px var(--accent-glow); } } @media (max-width: 480px) { - .hero-title { letter-spacing: 4px; } + .hero-title { letter-spacing: 4px; font-size: 1.5rem; } .section-header { flex-direction: column; align-items: flex-start; gap: 0.75rem; } .section-line { display: none; } + .hud-row-panels { grid-template-columns: 1fr; } + .hud-bottom-stats { gap: 0.5rem; } + .metric-row { grid-template-columns: 60px 1fr 35px; gap: 0.5rem; } + .graph-stats { flex-direction: column; gap: 0.5rem; } } diff --git a/index.html b/index.html index dae07b8..0e69d6a 100644 --- a/index.html +++ b/index.html @@ -84,41 +84,191 @@
-
-
-
-
-
- -
-
SYSTEM IDENTIFICATION
-

- JAESWIFT -

-
- > - - +
+ + +
+
+
+ OPERATOR LOCATION + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + MANCHESTER + 53.48°N 2.24°W + + + +
+
+ LAT + +53.48° +
+
+ LONG + -2.24° +
+
+ ALT + 78m (ASL) +
+
+
-
-
- STATUS - ● OPERATIONAL -
-
- UPTIME - 0d 00h 00m -
-
- LOCATION - EARTH // LEO + + +
+
SYSTEM IDENTIFICATION
+

+ JAESWIFT +

+
+ > + +
- -
+ +
+ +
+
+ SERVER METRICS + 98% +
+
+
+ CPU LOAD +
+ 23% +
+
+ MEMORY +
+ 67% +
+
+ DISK I/O +
+ 45% +
+
+ BANDWIDTH +
+ 78% +
+
+
+ + +
+
+
+ POWER + ● ON MAINS +
+
+
98%
+
+
+
+
+ CONTAINERS + +
+
+
8 / 8
+
+ ALL RUNNING +
+
+
+ + +
+
+ NETWORK TRAFFIC + +
+
+ +
+
+ DOWNLOAD + 1.6 Gbps +
+
+ UPLOAD + 1.2 Gbps +
+
+ PACKETS + 12 / 1.012 +
+
+
+
+
+ + +
+
+ JAE-001X + ● ONLINE +
+
+
+ STATUS + ● OPERATIONAL +
+
+ UPTIME + 0d 00h 00m +
+
+ COORDS + 53.48°N // 2.24°W +
+
+
+ SCANNING... +
+ 0% +
+
+
+
diff --git a/js/main.js b/js/main.js index 3c5e259..d4b6300 100644 --- a/js/main.js +++ b/js/main.js @@ -542,6 +542,205 @@ } // ─── INIT ─── + + // ─── NETWORK GRAPH ─── + function initNetworkGraph() { + const canvas = document.getElementById('networkGraph'); + if (!canvas) return; + const ctx = canvas.getContext('2d'); + + function resize() { + const rect = canvas.parentElement.getBoundingClientRect(); + canvas.width = rect.width; + canvas.height = 100; + } + resize(); + window.addEventListener('resize', resize); + + const dlData = []; + const ulData = []; + const maxPoints = 80; + + // Seed initial data + for (let i = 0; i < maxPoints; i++) { + dlData.push(30 + Math.random() * 40); + ulData.push(20 + Math.random() * 30); + } + + function drawLine(data, color, alpha) { + const w = canvas.width; + const h = canvas.height; + const step = w / (maxPoints - 1); + + ctx.beginPath(); + ctx.strokeStyle = color; + ctx.lineWidth = 1.5; + ctx.globalAlpha = alpha; + + for (let i = 0; i < data.length; i++) { + const x = i * step; + const y = h - (data[i] / 100) * h; + if (i === 0) ctx.moveTo(x, y); + else ctx.lineTo(x, y); + } + ctx.stroke(); + + // Fill under the line + ctx.lineTo(canvas.width, canvas.height); + ctx.lineTo(0, canvas.height); + ctx.closePath(); + ctx.fillStyle = color; + ctx.globalAlpha = alpha * 0.08; + ctx.fill(); + ctx.globalAlpha = 1; + } + + function drawGrid() { + const w = canvas.width; + const h = canvas.height; + ctx.strokeStyle = 'rgba(0,255,200,0.06)'; + ctx.lineWidth = 0.5; + + // Horizontal + for (let y = 0; y < h; y += 20) { + ctx.beginPath(); + ctx.moveTo(0, y); + ctx.lineTo(w, y); + ctx.stroke(); + } + // Vertical + for (let x = 0; x < w; x += 30) { + ctx.beginPath(); + ctx.moveTo(x, 0); + ctx.lineTo(x, h); + ctx.stroke(); + } + } + + function updateStats() { + const dl = dlData[dlData.length - 1]; + const ul = ulData[ulData.length - 1]; + const dlEl = document.getElementById('dlSpeed'); + const ulEl = document.getElementById('ulSpeed'); + const pkEl = document.getElementById('packetCount'); + if (dlEl) dlEl.textContent = (dl * 0.032).toFixed(1) + ' Gbps'; + if (ulEl) ulEl.textContent = (ul * 0.028).toFixed(1) + ' Gbps'; + if (pkEl) pkEl.textContent = Math.floor(dl * 180).toLocaleString() + ' pkt/s'; + } + + function animate() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + drawGrid(); + + // Push new data + const lastDl = dlData[dlData.length - 1]; + const lastUl = ulData[ulData.length - 1]; + dlData.push(Math.max(10, Math.min(95, lastDl + (Math.random() - 0.48) * 12))); + ulData.push(Math.max(5, Math.min(85, lastUl + (Math.random() - 0.48) * 10))); + if (dlData.length > maxPoints) dlData.shift(); + if (ulData.length > maxPoints) ulData.shift(); + + drawLine(dlData, '#00ffc8', 0.9); + drawLine(ulData, '#00a8ff', 0.6); + updateStats(); + + requestAnimationFrame(animate); + } + animate(); + } + + // ─── METRIC BARS (fluctuating) ─── + function initMetricBars() { + const metrics = [ + { bar: 'cpuBar', val: 'cpuVal', base: 23, range: 18 }, + { bar: 'memBar', val: 'memVal', base: 67, range: 8 }, + { bar: 'diskBar', val: 'diskVal', base: 45, range: 25 }, + { bar: 'bwBar', val: 'bwVal', base: 78, range: 15 }, + ]; + + function updateMetrics() { + metrics.forEach(m => { + const barEl = document.getElementById(m.bar); + const valEl = document.getElementById(m.val); + if (!barEl || !valEl) return; + + const val = Math.max(5, Math.min(98, m.base + (Math.random() - 0.5) * m.range)); + barEl.style.width = val + '%'; + valEl.textContent = Math.round(val) + '%'; + + // Colour shift for high values + if (val > 85) { + barEl.style.background = 'linear-gradient(90deg, #ff4757, rgba(255,71,87,0.4))'; + barEl.style.boxShadow = '0 0 8px rgba(255,71,87,0.4)'; + valEl.style.color = '#ff4757'; + } else if (val > 70) { + barEl.style.background = 'linear-gradient(90deg, #ffa502, rgba(255,165,2,0.4))'; + barEl.style.boxShadow = '0 0 8px rgba(255,165,2,0.3)'; + valEl.style.color = '#ffa502'; + } else { + barEl.style.background = ''; + barEl.style.boxShadow = ''; + valEl.style.color = ''; + } + }); + } + + updateMetrics(); + setInterval(updateMetrics, 2000 + Math.random() * 1000); + } + + // ─── SCAN BAR ─── + function initScanBar() { + const fill = document.getElementById('scanFill'); + const pct = document.getElementById('scanPct'); + if (!fill || !pct) return; + + let progress = 0; + function tick() { + progress += 0.5 + Math.random() * 1.5; + if (progress >= 100) { + progress = 0; + fill.style.transition = 'none'; + fill.style.width = '0%'; + pct.textContent = '0%'; + setTimeout(() => { + fill.style.transition = 'width 0.3s linear'; + requestAnimationFrame(tick); + }, 800); + return; + } + fill.style.width = progress + '%'; + pct.textContent = Math.round(progress) + '%'; + setTimeout(tick, 80 + Math.random() * 120); + } + + fill.style.transition = 'width 0.3s linear'; + tick(); + } + + // ─── POWER FLICKER ─── + function initPowerFlicker() { + const el = document.getElementById('powerPct'); + if (!el) return; + + setInterval(() => { + const vals = [97, 98, 99, 98, 100, 98, 97, 99]; + const v = vals[Math.floor(Math.random() * vals.length)]; + el.innerHTML = v + '%'; + }, 4000); + } + + // ─── SERVER HEALTH ─── + function initServerHealth() { + const el = document.getElementById('serverHealth'); + if (!el) return; + + setInterval(() => { + const v = 95 + Math.floor(Math.random() * 5); + el.textContent = v + '%'; + }, 5000); + } + document.addEventListener('DOMContentLoaded', () => { initNavbar(); initClock(); @@ -556,6 +755,12 @@ initFooterSignal(); initHUDFlickers(); initPanelGlow(); + initNetworkGraph(); + initMetricBars(); + initScanBar(); + initPowerFlicker(); + initServerHealth(); + // Page load animation document.body.style.opacity = '0';