diff --git a/app.js b/app.js index 6e85528..932932e 100644 --- a/app.js +++ b/app.js @@ -126,11 +126,44 @@ window.addEventListener('resize', () => { renderer.setSize(window.innerWidth, window.innerHeight); }); +// === PERFORMANCE MONITOR === +const PERF = { + frameTimeLimit: 33, // ms — ~30fps minimum + slowFrameThreshold: 5, // consecutive slow frames before alerting + slowFrameCount: 0, + lastTime: performance.now(), + warned: false, +}; + +const perfWarning = document.getElementById('perf-warning'); + +function checkFrameTime(now) { + const frameTime = now - PERF.lastTime; + PERF.lastTime = now; + + if (frameTime > PERF.frameTimeLimit) { + PERF.slowFrameCount++; + if (PERF.slowFrameCount >= PERF.slowFrameThreshold && !PERF.warned) { + PERF.warned = true; + console.warn(`[Nexus] Performance regression: frame time ${frameTime.toFixed(1)}ms exceeds ${PERF.frameTimeLimit}ms limit`); + if (perfWarning) perfWarning.hidden = false; + } + } else { + PERF.slowFrameCount = 0; + if (PERF.warned) { + PERF.warned = false; + if (perfWarning) perfWarning.hidden = true; + } + } +} + // === ANIMATION LOOP === const clock = new THREE.Clock(); function animate() { requestAnimationFrame(animate); + const now = performance.now(); + checkFrameTime(now); const elapsed = clock.getElapsedTime(); // Slow auto-rotation diff --git a/index.html b/index.html index 2006413..70ea233 100644 --- a/index.html +++ b/index.html @@ -36,6 +36,8 @@ + + diff --git a/style.css b/style.css index 948c916..17a4277 100644 --- a/style.css +++ b/style.css @@ -56,6 +56,23 @@ canvas { background-color: var(--color-text-muted); } +/* === PERFORMANCE WARNING === */ +#perf-warning { + position: fixed; + bottom: 12px; + left: 50%; + transform: translateX(-50%); + background: rgba(255, 60, 60, 0.85); + color: #fff; + font-family: var(--font-body); + font-size: 11px; + letter-spacing: 0.1em; + padding: 4px 12px; + border-radius: 4px; + z-index: 100; + pointer-events: none; +} + /* === DEBUG MODE === */ #debug-toggle { margin-left: 8px;