From 6cdb126187dd59306fe1c085b7e647009907e757 Mon Sep 17 00:00:00 2001 From: HighImKevin Date: Thu, 4 Dec 2025 16:44:59 -0500 Subject: [PATCH] Improve performance of snowflakes: Thanks wernox! --- scripts/homeScreen.js | 25 ++------ scripts/snowverlay.js | 131 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 20 deletions(-) create mode 100644 scripts/snowverlay.js diff --git a/scripts/homeScreen.js b/scripts/homeScreen.js index 8d0bd19..10ecfce 100644 --- a/scripts/homeScreen.js +++ b/scripts/homeScreen.js @@ -168,26 +168,11 @@ } if (enableSeasonalAnimations) { - // Import the Flurry module and leverage it from jQuery. /scripts/third party/flurry.js by appending it to the head - const flurryScriptSrc = (window.KefinTweaksConfig.kefinTweaksRoot || '') + 'scripts/third party/jquery.flurry.min.js'; - - // Function to run flurry safely - const startFlurry = () => { - if (window.jQuery && typeof window.jQuery.fn.flurry === 'function') { - window.jQuery("body").flurry(); - } - }; - - // Check if script is already present - if (!document.querySelector(`script[src="${flurryScriptSrc}"]`)) { - const flurryScript = document.createElement('script'); - flurryScript.src = flurryScriptSrc; - flurryScript.onload = startFlurry; // Run after load - document.head.appendChild(flurryScript); - } else { - // Script loaded, try running directly - startFlurry(); - } + // Use the snowverlay.js script to add snowflakes to the background + const snowverlayScriptSrc = (window.KefinTweaksConfig.kefinTweaksRoot || '') + 'scripts/snowverlay.js'; + const snowverlayScript = document.createElement('script'); + snowverlayScript.src = snowverlayScriptSrc; + document.head.appendChild(snowverlayScript); } } else if (isValentinesPeriod()) { diff --git a/scripts/snowverlay.js b/scripts/snowverlay.js new file mode 100644 index 0000000..ef62dff --- /dev/null +++ b/scripts/snowverlay.js @@ -0,0 +1,131 @@ +function addSnowverlay() { + // Configuration constants + const CANVAS_HEIGHT_PX = 160; + const SNOWFLAKE_AMOUNT = 15; + const SNOWFLAKE_SIZE = { min: 10, max: 22 }; + const SNOWFLAKE_SPEED = { min: 0.2, max: 0.7 }; + + // Dynamically inject styles + const style = document.createElement('style'); + style.textContent = ` + body { + height: 100svh; + margin: 0; + } + .snowverlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: ${CANVAS_HEIGHT_PX}px; + pointer-events: none; + z-index: 1000; + } + `; + document.head.appendChild(style); + + // Create and inject canvas + const canvas = document.createElement('canvas'); + canvas.className = 'snowverlay'; + document.body.appendChild(canvas); + const ctx = canvas.getContext('2d'); + + // Resize handler + const resizeCanvas = () => { + canvas.width = window.innerWidth; + canvas.height = CANVAS_HEIGHT_PX; + }; + + window.addEventListener('resize', resizeCanvas); + resizeCanvas(); + + // Snowflake factory + const createSnowflake = (isAnimated = true, index = 0) => ({ + x: Math.random() * canvas.width, + y: isAnimated + ? -20 - (index * canvas.height) / SNOWFLAKE_AMOUNT + : Math.random() * canvas.height, + size: Math.random() * (SNOWFLAKE_SIZE.max - SNOWFLAKE_SIZE.min) + SNOWFLAKE_SIZE.min, + speed: Math.random() * (SNOWFLAKE_SPEED.max - SNOWFLAKE_SPEED.min) + SNOWFLAKE_SPEED.min, + opacity: isAnimated ? null : Math.random() * 0.5 + 0.2, + sway: Math.random() * 2 * Math.PI + }); + + // Draw single snowflake + const drawSnowflake = (flake) => { + ctx.font = `${flake.size}px sans-serif`; + ctx.fillStyle = `rgba(255, 255, 255, ${flake.opacity ?? (1 - flake.y / canvas.height)})`; + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.fillText('❄', flake.x, flake.y); + }; + + // Animation control + let animationFrame; + const stopAnimation = () => { + if (animationFrame) cancelAnimationFrame(animationFrame); + }; + + // Static snow renderer + const renderStaticSnow = () => { + ctx.clearRect(0, 0, canvas.width, canvas.height); + Array.from({ length: SNOWFLAKE_AMOUNT }, () => createSnowflake(false)) + .forEach(drawSnowflake); + }; + + // Animated snow renderer + const startSnowAnimation = () => { + const snowflakes = Array.from( + { length: SNOWFLAKE_AMOUNT }, + (_, i) => createSnowflake(true, i) + ); + + const animate = () => { + ctx.clearRect(0, 0, canvas.width, canvas.height); + + snowflakes.forEach(flake => { + flake.y += flake.speed; + flake.x += Math.sin(flake.sway += 0.01) * flake.speed; + + if (flake.y > canvas.height) { + flake.y = -10; + flake.x = Math.random() * canvas.width; + } + + drawSnowflake(flake); + }); + + animationFrame = requestAnimationFrame(animate); + }; + + animate(); + return stopAnimation; + }; + + // Motion preference handler + const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)'); + let currentAnimation = null; + + const handleMotionChange = (e) => { + stopAnimation(); + if (currentAnimation) currentAnimation(); + + if (e.matches) { + renderStaticSnow(); + currentAnimation = null; + } else { + currentAnimation = startSnowAnimation(); + } + }; + + mediaQuery.addEventListener('change', handleMotionChange); + handleMotionChange(mediaQuery); + + // Cleanup on unload + window.addEventListener('beforeunload', () => { + mediaQuery.removeEventListener('change', handleMotionChange); + stopAnimation(); + }); +} + +addSnowverlay(); \ No newline at end of file