78 lines
3.0 KiB
React
78 lines
3.0 KiB
React
import React, { useEffect, useRef, useState } from 'react';
|
|
|
|
export default function M60Panopticon() {
|
|
const canvasRef = useRef(null);
|
|
const [threats, setThreats] = useState(0);
|
|
|
|
useEffect(() => {
|
|
const canvas = canvasRef.current;
|
|
if (!canvas) return;
|
|
const ctx = canvas.getContext('2d');
|
|
let animationId;
|
|
let t = 0;
|
|
|
|
const draw = () => {
|
|
ctx.fillStyle = 'rgba(5, 3, 10, 0.2)';
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
|
|
// Draw grid
|
|
ctx.strokeStyle = 'rgba(0, 243, 255, 0.05)';
|
|
ctx.lineWidth = 1;
|
|
ctx.beginPath();
|
|
for(let i=0; i<canvas.width; i+=50) { ctx.moveTo(i, 0); ctx.lineTo(i, canvas.height); }
|
|
for(let i=0; i<canvas.height; i+=50) { ctx.moveTo(0, i); ctx.lineTo(canvas.width, i); }
|
|
ctx.stroke();
|
|
|
|
// Sine wave (telemetry)
|
|
ctx.beginPath();
|
|
ctx.strokeStyle = 'var(--accent-cyan)';
|
|
ctx.lineWidth = 2;
|
|
for(let i=0; i<canvas.width; i++) {
|
|
const y = canvas.height/2 + Math.sin(i*0.02 + t) * 50 + (Math.random() * 10 - 5);
|
|
if (i === 0) ctx.moveTo(i, y);
|
|
else ctx.lineTo(i, y);
|
|
}
|
|
ctx.stroke();
|
|
|
|
// Anomalies (Threats)
|
|
if (Math.random() > 0.95) {
|
|
const x = Math.random() * canvas.width;
|
|
const y = Math.random() * canvas.height;
|
|
ctx.fillStyle = 'var(--accent-red)';
|
|
ctx.beginPath();
|
|
ctx.arc(x, y, 5, 0, Math.PI*2);
|
|
ctx.fill();
|
|
setThreats(prev => prev + 1);
|
|
}
|
|
|
|
t += 0.1;
|
|
animationId = requestAnimationFrame(draw);
|
|
};
|
|
draw();
|
|
|
|
return () => cancelAnimationFrame(animationId);
|
|
}, []);
|
|
|
|
return (
|
|
<div style={{animation: 'fadeIn 0.5s ease-out', color: 'var(--text-main)'}}>
|
|
<h2 style={{color: 'var(--accent-cyan)', marginBottom: '15px', textShadow: '0 0 10px var(--accent-cyan)'}}>
|
|
M60: PANOPTICON SUPREME-EYE TELEMETRY
|
|
</h2>
|
|
<div style={{display: 'flex', gap: '20px', marginBottom: '20px'}}>
|
|
<div className="glass-panel" style={{flex: 1, padding: '15px', textAlign: 'center'}}>
|
|
<div style={{fontSize: '0.8rem', color: 'var(--text-muted)'}}>eBPF PACKETS/SEC</div>
|
|
<div style={{fontSize: '2rem', color: 'var(--accent-cyan)'}}>{Math.floor(Math.random()*10000 + 50000).toLocaleString()}</div>
|
|
</div>
|
|
<div className="glass-panel" style={{flex: 1, padding: '15px', textAlign: 'center', borderColor: 'var(--accent-red)'}}>
|
|
<div style={{fontSize: '0.8rem', color: 'var(--text-muted)'}}>BLOCKED THREATS</div>
|
|
<div style={{fontSize: '2rem', color: 'var(--accent-red)'}}>{threats.toLocaleString()}</div>
|
|
</div>
|
|
</div>
|
|
<div className="glass-panel" style={{padding: '10px', height: '300px', position: 'relative'}}>
|
|
<div style={{position: 'absolute', top: 15, left: 20, zIndex: 10, fontSize: '0.8rem', color: 'var(--accent-cyan)'}}>KERNEL MEMORY ALLOCATION</div>
|
|
<canvas ref={canvasRef} width="800" height="280" style={{width: '100%', height: '100%', borderRadius: '4px'}}></canvas>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|