diff --git a/content/javascripts/hero.js b/content/javascripts/hero.js index b7bce89..b33ba22 100644 --- a/content/javascripts/hero.js +++ b/content/javascripts/hero.js @@ -1,6 +1,7 @@ /** * This script applies to index.md. */ +"use strict"; (async () => { // DOM guard // if (!document.querySelector(".hero-page")) @@ -87,29 +88,67 @@ const iResolutionLoc = gl.getUniformLocation(program, "iResolution"); const iTimeLoc = gl.getUniformLocation(program, "iTime"); + const isMobile = window.matchMedia("(pointer: coarse)").matches && !window.matchMedia("(hover: hover)").matches; + const targetMobileDeltaTime = 33.33; // 33.33ms ~ 30 FPS + const targetDesktopDeltaTime = 16.67; // 16.67ms ~ 60 FPS + + let lastFrameTime = 0; + let renderQuality = 1.0; // Full desktop quality by default + + function determineBestRenderQuality() + { + const start = performance.now(); + render(0.0) + const deltaTime = performance.now() - start; + + if (deltaTime > 16) + renderQuality = 0.4; // Low quality, 40% resolution + else if (deltaTime > 8) + renderQuality = 0.7; // Medium quality, 70% resolution + else + renderQuality = 1.0; // High quality, full resolution + + console.log("Using render quality: %f", renderQuality); + } + // Render loop + function frame(time) + { + // Lock framerate to 30 FPS on mobile, and 60 FPS for desktop + const targetDeltaTime = isMobile ? targetMobileDeltaTime : targetDesktopDeltaTime; + + // Framerate limiting + if ((time - lastFrameTime) >= targetDeltaTime) + { + lastFrameTime = time; + render(time); + } + + requestAnimationFrame(frame); + } + function render(time) { // Resize handling (High-DPI / Retina aware) const dpr = Math.min(window.devicePixelRatio || 1, 1.25); // Clamp resolution on mobile - const displayWidth = Math.floor(canvas.clientWidth * dpr); const displayHeight = Math.floor(canvas.clientHeight * dpr); - if ((canvas.width !== displayWidth) || (canvas.height !== displayHeight)) - { - canvas.width = displayWidth; - canvas.height = displayHeight; - gl.viewport(0, 0, canvas.width, canvas.height); - } + // NOTE: Previously, this was conditionally resized based on: + // if ((canvas.width !== displayWidth) || (canvas.height !== displayHeight)) + // But we removed this to make renderQuality updates easier. This system doesn't need anymore complexity! + canvas.width = displayWidth * renderQuality; + canvas.height = displayHeight * renderQuality; + gl.viewport(0, 0, canvas.width, canvas.height); gl.uniform3f(iResolutionLoc, canvas.width, canvas.height, 1.0); gl.uniform1f(iTimeLoc, time * 0.001); // Convert time to seconds gl.drawArrays(gl.TRIANGLES, 0, 6); - requestAnimationFrame(render); } + determineBestRenderQuality(); + // Start the render loop - requestAnimationFrame(render); + requestAnimationFrame(frame); })();