About this snippet

Click the scan button and a laser line sweeps down the image, then three labeled boxes appear over it in sequence. The button locks while the scan runs and unlocks when it finishes.

Boxes are built in JavaScript and positioned with percentage values for left, top, width and height, so they stay aligned to the image at any size. Each one is added on a setTimeout that lines up with where the laser is, then a second short timeout adds the class that triggers its scale in transition. Adding the element and its final class in one frame would skip the animation entirely.

Nothing here does real detection. The coordinates and labels are hardcoded in three createBox calls, and that is the part you replace with output from an actual model. Restarting clears the old boxes and forces a reflow through offsetWidth, so the laser animation replays instead of being ignored as unchanged.

Size
4.3 KB
Uses
HTML, CSS, JavaScript
Loads
placehold.co
Views
223
<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);
});
Esc
↑↓ moveEnter select

Start from a template

Open an .html file, or HTML, CSS, JS, Markdown, Less or TypeScript files. You can also drop them here. Styles and scripts go into their panes.

Share

Source

Keyboard shortcuts

Save