diff --git a/static/css/style.css b/static/css/style.css index fa7722e..fbe8562 100644 --- a/static/css/style.css +++ b/static/css/style.css @@ -12,8 +12,9 @@ --radius: 12px; --radius-sm: 8px; --shadow: 0 8px 30px rgba(0, 0, 0, 0.5); - --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, - Helvetica, Arial, sans-serif; + --font: + "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, + Arial, sans-serif; } * { @@ -95,7 +96,9 @@ header { color: var(--text-primary); font-size: 14px; outline: none; - transition: border-color 0.2s, box-shadow 0.2s; + transition: + border-color 0.2s, + box-shadow 0.2s; } .search-wrap input:focus { border-color: var(--accent); @@ -166,6 +169,20 @@ header { object-fit: contain; background: #000; } +.noise-canvas { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + z-index: 1; + pointer-events: none; + opacity: 1; + image-rendering: pixelated; + transition: opacity 0.3s ease; +} +.noise-canvas.hidden { + opacity: 0; +} .video-placeholder { position: absolute; inset: 0; @@ -502,4 +519,4 @@ header { [hidden] { display: none !important; -} \ No newline at end of file +} diff --git a/static/js/app.js b/static/js/app.js index f9158b5..845eec2 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -30,6 +30,7 @@ }); const player = document.getElementById("player"); + const noiseCanvas = document.getElementById("noiseCanvas"); const placeholder = document.getElementById("videoPlaceholder"); const badge = document.getElementById("videoBadge"); const badgeText = document.getElementById("badgeText"); @@ -50,6 +51,65 @@ let sortMode = "oldest"; let current = null; + // ---- Static noise canvas for loading indicator ---- + + var noiseCtx = noiseCanvas.getContext("2d"); + var noiseAnimId = null; + var noiseRunning = false; + + function noiseStart() { + if (noiseRunning) return; + noiseRunning = true; + noiseCanvas.classList.remove("hidden"); + noiseAnimId = null; + noiseTick(); + } + + function noiseStop() { + noiseRunning = false; + noiseCanvas.classList.add("hidden"); + if (noiseAnimId) { + cancelAnimationFrame(noiseAnimId); + noiseAnimId = null; + } + } + + function noiseTick() { + if (!noiseRunning) return; + var w = noiseCanvas.width; + var h = noiseCanvas.height; + var rect = noiseCanvas.getBoundingClientRect(); + // Render at reduced resolution (160px wide) for performance, + // CSS image-rendering: pixelated handles the upscale. + var targetW = Math.max(1, Math.min(160, (rect.width * 0.25) | 0)); + var ratio = rect.height / Math.max(1, rect.width); + var targetH = Math.max(1, (targetW * ratio) | 0); + if (w !== targetW || h !== targetH) { + noiseCanvas.width = targetW; + noiseCanvas.height = targetH; + w = targetW; + h = targetH; + } + if (w === 0 || h === 0) { + noiseAnimId = requestAnimationFrame(noiseTick); + return; + } + var imageData = noiseCtx.createImageData(w, h); + var data = imageData.data; + for (var i = 0; i < data.length; i += 4) { + var v = (Math.random() * 255) | 0; + data[i] = v; + data[i + 1] = v; + data[i + 2] = v; + data[i + 3] = 255; + } + noiseCtx.putImageData(imageData, 0, 0); + noiseAnimId = requestAnimationFrame(noiseTick); + } + + // Start noise immediately on page load (no video selected yet) + noiseStart(); + // ---- Prefetch helpers ---- // Track already-prefetched URLs so we don't re-fetch @@ -262,9 +322,11 @@ player.src = clip.url; player.load(); - // Start playback first, prefetch only after the video is actually playing + // Show noise while loading, stop when video starts playing + noiseStart(); var prefetchDone = false; function onPlaying() { + noiseStop(); if (prefetchDone) return; prefetchDone = true; player.removeEventListener("playing", onPlaying); @@ -273,6 +335,7 @@ player.addEventListener("playing", onPlaying); player.play().catch(function () { // Even if autoplay is blocked, still prefetch for when the user clicks play + noiseStop(); if (!prefetchDone) { prefetchDone = true; player.removeEventListener("playing", onPlaying); diff --git a/templates/index.html b/templates/index.html index 5d7c6b0..d1146fb 100644 --- a/templates/index.html +++ b/templates/index.html @@ -4,7 +4,10 @@ TeslaCam Video Player - + @@ -56,6 +59,7 @@
+
Front