*, *::before, *::after {
box-sizing: border-box;
}
body {
font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
margin: 0;
background: #020617;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
}
.radar-board {
display: flex;
flex-direction: column;
align-items: center;
gap: 30px;
}
.radar-frame {
position: relative;
width: 300px;
height: 300px;
border-radius: 50%;
background: #0f172a;
border: 4px solid #1e293b;
box-shadow: 0 0 50px rgba(16, 185, 129, 0.2);
overflow: hidden;
}
#radar-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.radar-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border-radius: 50%;
background:
radial-gradient(circle, transparent 20%, rgba(16, 185, 129, 0.1) 80%),
linear-gradient(90deg, transparent 49.5%, rgba(16, 185, 129, 0.3) 49.5%, rgba(16, 185, 129, 0.3) 50.5%, transparent 50.5%),
linear-gradient(0deg, transparent 49.5%, rgba(16, 185, 129, 0.3) 49.5%, rgba(16, 185, 129, 0.3) 50.5%, transparent 50.5%);
z-index: 2;
pointer-events: none;
}
.radar-text {
color: #10b981;
margin: 0;
letter-spacing: 4px;
text-transform: uppercase;
font-weight: 600;
animation: pulse-text 2s infinite alternate;
}
@keyframes pulse-text {
0% { opacity: 0.5; }
100% { opacity: 1; text-shadow: 0 0 10px #10b981; }
}
const canvas = document.getElementById("radar-canvas");
const ctx = canvas.getContext("2d");
const size = 300;
canvas.width = size;
canvas.height = size;
let angle = 0;
const blips = new Array();
function spawnBlip() {
const blip = new Object();
const distance = Math.random() * 100 + 20;
const blipAngle = Math.random() * Math.PI * 2;
blip.x = (size / 2) + Math.cos(blipAngle) * distance;
blip.y = (size / 2) + Math.sin(blipAngle) * distance;
blip.alpha = 1;
blips.push(blip);
}
/* Spawn a blip randomly every 2 seconds safely */
setInterval(spawnBlip, 2000);
function drawRadar() {
/* Create trailing effect */
ctx.fillStyle = "rgba(15, 23, 42, 0.1)";
ctx.fillRect(0, 0, size, size);
const cx = size / 2;
const cy = size / 2;
/* Draw Sweeping Beam */
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(angle);
const gradient = ctx.createLinearGradient(0, 0, 150, 0);
gradient.addColorStop(0, "rgba(16, 185, 129, 0.8)");
gradient.addColorStop(1, "rgba(16, 185, 129, 0)");
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.arc(0, 0, 150, 0, 0.2);
ctx.closePath();
ctx.fillStyle = gradient;
ctx.fill();
/* Solid Leading Line */
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(150, 0);
ctx.strokeStyle = "#10b981";
ctx.lineWidth = 2;
ctx.stroke();
ctx.restore();
/* Draw Blips */
for (let i = 0; i < blips.length; i++) {
const b = blips.at(i);
if (b.alpha > 0) {
ctx.beginPath();
ctx.arc(b.x, b.y, 4, 0, Math.PI * 2);
ctx.fillStyle = "rgba(16, 185, 129, " + b.alpha + ")";
ctx.shadowBlur = 10;
ctx.shadowColor = "#10b981";
ctx.fill();
ctx.shadowBlur = 0; /* Reset */
b.alpha -= 0.005; /* Fade out slowly */
}
}
/* Clean array cleanly */
while (blips.length > 0 && blips.at(0).alpha <= 0) {
blips.shift();
}
angle -= 0.03;
window.requestAnimationFrame(drawRadar);
}
drawRadar();