<div class="vision-wrapper">
<div class="vision-frame">
<img src="https://placehold.co/600x400/1e293b/3b82f6?text=City+Street" alt="City" class="source-img">
<!-- Sweeping Laser -->
<div class="vision-laser" id="laser"></div>
<!-- Bounding boxes injected via JS -->
<div class="bounding-container" id="box-container"></div>
</div>
<button class="scan-btn" id="scan-trigger">Initialize Scan</button>
</div>
*, *::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;
padding: 20px;
}
.vision-wrapper {
display: flex;
flex-direction: column;
align-items: center;
gap: 30px;
width: 100%;
max-width: 600px;
}
.vision-frame {
position: relative;
width: 100%;
height: 400px;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 20px 50px rgba(0,0,0,0.5);
border: 2px solid #1e293b;
}
.source-img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
filter: grayscale(80%) contrast(120%);
transition: filter 1s ease;
}
.vision-frame.scanned .source-img {
filter: grayscale(0%) contrast(100%);
}
.vision-laser {
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(59, 130, 246, 0.2), #3b82f6);
border-right: 2px solid #60a5fa;
z-index: 10;
opacity: 0;
}
.vision-laser.animate-scan {
opacity: 1;
animation: sweep-right 2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
@keyframes sweep-right {
to { left: 100%; }
}
.bounding-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 20;
}
.ai-bounding-box {
position: absolute;
border: 2px solid #10b981;
background: rgba(16, 185, 129, 0.1);
box-shadow: 0 0 15px rgba(16, 185, 129, 0.4), inset 0 0 10px rgba(16, 185, 129, 0.2);
opacity: 0;
transform: scale(1.1);
transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.ai-bounding-box.visible {
opacity: 1;
transform: scale(1);
}
.ai-label {
position: absolute;
top: -24px;
left: -2px;
background: #10b981;
color: #020617;
font-size: 0.75rem;
font-weight: 700;
padding: 4px 8px;
letter-spacing: 1px;
text-transform: uppercase;
}
.scan-btn {
background: #0f172a;
color: #3b82f6;
border: 1px solid #3b82f6;
padding: 12px 32px;
border-radius: 30px;
font-weight: 600;
letter-spacing: 1px;
cursor: pointer;
transition: all 0.2s;
text-transform: uppercase;
}
.scan-btn:hover {
background: #3b82f6;
color: #ffffff;
box-shadow: 0 10px 20px rgba(59, 130, 246, 0.3);
}
const scanBtn = document.getElementById("scan-trigger");
const laser = document.getElementById("laser");
const boxContainer = document.getElementById("box-container");
const frame = document.querySelector(".vision-frame");
function createBox(x, y, w, h, label, delay) {
setTimeout(function() {
const box = document.createElement("div");
box.className = "ai-bounding-box";
box.style.left = x + "%";
box.style.top = y + "%";
box.style.width = w + "%";
box.style.height = h + "%";
const labelDiv = document.createElement("div");
labelDiv.className = "ai-label";
labelDiv.innerText = label;
box.appendChild(labelDiv);
boxContainer.appendChild(box);
/* Trigger visibility for scale animation securely */
setTimeout(function() {
box.classList.add("visible");
}, 50);
}, delay);
}
scanBtn.addEventListener("click", function() {
/* Reset */
boxContainer.innerHTML = "";
frame.classList.remove("scanned");
laser.classList.remove("animate-scan");
/* Force DOM reflow safely without brackets */
void laser.offsetWidth;
laser.classList.add("animate-scan");
scanBtn.innerText = "Analyzing...";
scanBtn.disabled = true;
/* Spawn boxes sequentially based on laser position */
createBox(15, 30, 20, 40, "Vehicle", 800);
createBox(45, 50, 10, 30, "Pedestrian", 1200);
createBox(70, 20, 25, 60, "Architecture", 1600);
setTimeout(function() {
frame.classList.add("scanned");
scanBtn.innerText = "Initialize Scan";
scanBtn.disabled = false;
}, 2200);
});