]> gitweb.cassieko.com Git - neon-realms.git/commitdiff
Circles Of Doom: Fixed boundires, audio, and preferences
authorRadic <radic393@yahoo.com>
Wed, 19 Mar 2025 00:10:57 +0000 (20:10 -0400)
committerRadic <radic393@yahoo.com>
Wed, 19 Mar 2025 00:10:57 +0000 (20:10 -0400)
html/4-Circles/CirclesOfDoom.html

index a4c39c30a41472fa4731110fa62416fe2523f22c..968b9b49d622e0a7c6b7ab61bf22762d9d020ca8 100644 (file)
-<!DOCTYPE html>\r
-<html lang="en">\r
-<head>\r
-    <meta charset="UTF-8">\r
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">\r
-    <title>Circles Of Doom with Music by StarStabbedMoon</title>\r
-    <style>\r
-        /* Basic styling to fill the screen and show a black background */\r
-        body, html {\r
-            margin: 0;\r
-            padding: 0;\r
-            overflow: hidden;\r
-            height: 100%;\r
-        }\r
-        canvas {\r
-            display: block;\r
-            background: black;\r
-            width: 100%;\r
-            height: 100%;\r
-        }\r
-        /* UI container styling */\r
-        #ui {\r
-            position: fixed;\r
-            bottom: 0;\r
-            left: 0;\r
-            width: 100%;\r
-            background: rgba(255, 255, 255, 0);\r
-            padding: 10px;\r
-          \r
-            display: flex;\r
-            flex-direction: column;\r
-            align-items: flex-start;\r
-            gap: 10px;\r
-            transition: transform 0.3s ease-in-out;\r
-            transform: translateY(100%); /* Hidden by default */\r
-                       pointer-events: none; /* Makes UI transparent to clicks */\r
-        }\r
-               \r
-               #ui * {\r
-                       pointer-events: auto; /* Re-enable clicks for child elements */\r
-               }\r
-        /* When we add the class "visible", the UI slides up */\r
-        #ui.visible {\r
-            transform: translateY(0);\r
-        }\r
-        /* Container for sliders and labels */\r
-               .slider-container {\r
-                       display: flex;\r
-                       align-items: center;\r
-                       gap: 10px;\r
-                       margin-left: 10px; /* Reduced from 20px */\r
-                       color: white;\r
-                       width: auto;\r
-                       pointer-events: none;\r
-               }\r
-               .slider-container > * {\r
-                       pointer-events: auto;\r
-               }\r
-        label {\r
-            font-family: Arial, sans-serif;\r
-            font-size: 14px;\r
-            min-width: 150px; /* Ensure labels have consistent width */\r
-            color: white;\r
-                       flex-shrink: 0;\r
-        }\r
-               input[type="range"] {\r
-                       flex: 1; /* Take available space */\r
-                       max-width: 300px; /* Maximum width for larger screens */\r
-                       min-width: 100px; /* Minimum usable width */\r
-               }\r
-               \r
-               \r
-               /* Mobile adjustments - Untested */\r
-               @media (max-width: 600px) {\r
-                       .slider-container {\r
-                               margin-left: 5px;\r
-                               gap: 8px;\r
-                       }\r
-        \r
-                       label {\r
-                               min-width: 110px; /* Smaller min-width for mobile */\r
-                               font-size: 13px;\r
-                       }\r
-        \r
-                       input[type="range"] {\r
-                               max-width: 100%; /* Allow full width of container */\r
-                       }\r
-        \r
-                       #info, #options, #resetButton, #restoreDefaultsButton {\r
-                               margin-left: 5px;\r
-                       }\r
-               }\r
-        \r
-    \r
-        /* Information text styling */\r
-        #info {\r
-            font-family: Arial, sans-serif;\r
-            font-size: 14px;\r
-            margin-top: 10px;\r
-            text-align: left;\r
-            width: auto;\r
-            margin-left: 20px; /* Indent options text */\r
-            color: white;\r
-        }\r
-               \r
-               /* Options text styling */\r
-        #options {\r
-            font-family: Arial, sans-serif;\r
-            font-size: 14px;\r
-            margin-top: 10px;\r
-            text-align: left;\r
-            width: auto;\r
-            margin-left: 20px; /* Indent info text */\r
-            color: white;\r
-        }\r
-               \r
-               \r
-               .button-container {\r
-                       display: flex;\r
-                       gap: 10px;\r
-                       margin-left: 20px;\r
-                       margin-top: 10px;\r
-               }\r
-        /* Reset button styling */\r
-        #resetButton {\r
-            padding: 5px 10px;\r
-            font-family: Arial, sans-serif;\r
-            font-size: 14px;\r
-            cursor: pointer;\r
-            color: white;\r
-            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);\r
-            background: rgba(0, 0, 0, 255);\r
-        }\r
-               /* Restore Defaults button styling */\r
-#restoreDefaultsButton {\r
-    padding: 5px 10px;\r
-    font-family: Arial, sans-serif;\r
-    font-size: 14px;\r
-    cursor: pointer;\r
-    color: white;\r
-    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);\r
-    background: rgba(0, 0, 0, 255);\r
-}\r
-        /* Button to toggle the UI visibility */\r
-        #toggleUIButton {\r
-            position: fixed;\r
-            bottom: 10px;\r
-            right: 10px;\r
-            padding: 10px;\r
-            background: rgba(0, 0, 0, 255);\r
-            color: white;\r
-            border: none;\r
-            border-radius: 5px;\r
-            cursor: pointer;\r
-            font-family: Arial, sans-serif;\r
-            font-size: 14px;\r
-            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);\r
-        }\r
-               \r
-               \r
-               .music-credits {\r
-            font-family: Arial, sans-serif;\r
-            font-size: 12px;\r
-            color: white;\r
-            margin-left: 20px;\r
-            margin-top: 10px;\r
-            opacity: 0.8;\r
-                       text-align: center;\r
-        }\r
-\r
-        .music-credits a {\r
-            color: #ff8888;\r
-            text-decoration: none;\r
-            margin: 0 5px;\r
-        }\r
-\r
-        .music-credits a:hover {\r
-            text-decoration: underline;\r
-        }\r
-               \r
-                #fullscreenButton {\r
-            position: fixed;\r
-            bottom: 60px;\r
-            right: 10px;\r
-            padding: 10px;\r
-            background: rgba(0, 0, 0, 255);\r
-            color: white;\r
-            border: none;\r
-            border-radius: 5px;\r
-            cursor: pointer;\r
-            font-family: Arial, sans-serif;\r
-            font-size: 14px;\r
-            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);\r
-            z-index: 1000;\r
-        }\r
-               \r
-               /* Mode toggle styling */\r
-.mode-toggle {\r
-    margin-top: 10px;\r
-}\r
-\r
-.toggle-container {\r
-    display: flex;\r
-    gap: 5px;\r
-    margin-left: 10px;\r
-}\r
-\r
-.mode-button {\r
-    padding: 5px 12px;\r
-    border: none;\r
-    border-radius: 15px;\r
-    cursor: pointer;\r
-    background: rgba(255, 255, 255, 0.1);\r
-    color: white;\r
-    font-family: Arial, sans-serif;\r
-    font-size: 14px;\r
-    transition: all 0.2s ease;\r
-}\r
-\r
-.mode-button.active {\r
-    background: #ff4444;\r
-    color: white;\r
-    box-shadow: 0 0 5px rgba(255, 68, 68, 0.5);\r
-}\r
-               \r
-/* Modern slider styling with persistent red color */\r
-input[type="range"] {\r
-    accent-color: #ff0000;\r
-    background: transparent !important;\r
-    border: none !important;\r
-    box-shadow: none !important;\r
-}\r
-\r
-/* Chrome/Safari track */\r
-input[type="range"]::-webkit-slider-runnable-track {\r
-    background: rgba(255, 255, 255, 0.2);\r
-    height: 8px;\r
-    border-radius: 5px;\r
-    border: 1px solid #000000ff;\r
-    box-sizing: border-box;\r
-}\r
-\r
-/* Chrome/Safari thumb - Border workaround */\r
-input[type="range"]::-webkit-slider-thumb {\r
-    -webkit-appearance: none;\r
-    width: 16px;\r
-    height: 16px;\r
-    background: #ff0000;\r
-    border-radius: 50%;\r
-    margin-top: -4px;\r
-    box-shadow: 0 0 0 1.5px black; /* Simulated border using box-shadow */\r
-    position: relative; /* Ensure layering */\r
-    z-index: 1; /* Force border above track */\r
-}\r
-\r
-/* Firefox Track */\r
-input[type="range"]::-moz-range-track {\r
-    background: #ffffff; /* Completely transparent */\r
-    height: 8px;\r
-    border: 1px solid #000000ff;\r
-    border-radius: 5px;\r
-    box-shadow: none;\r
-}\r
-\r
-/* Firefox Progress (filled portion) */\r
-input[type="range"]::-moz-range-progress {\r
-    background: #ff0000; /* Red filled area */\r
-    height: 8px;\r
-    border-radius: 5px 0 0 5px;\r
-    border: none;\r
-}\r
-\r
-/* Firefox Thumb */\r
-input[type="range"]::-moz-range-thumb {\r
-    width: 16px;\r
-    height: 16px;\r
-    background: #ff0000 !important; /* Force red color */\r
-    border: 2px solid black;\r
-    border-radius: 50%;\r
-    box-shadow: none;\r
-    position: relative;\r
-    z-index: 1;\r
-}\r
-\r
-/* Remove focus ring */\r
-input[type="range"]:focus {\r
-    outline: none;\r
-}\r
-\r
-\r
-.stat {\r
-    display: flex;\r
-    align-items: center;\r
-    gap: 8px;\r
-    margin-bottom: 8px;\r
-}\r
-\r
-.stat-checkbox {\r
-    margin: 0;\r
-    accent-color: #ff4444; /* Red color for checkboxes */\r
-}\r
-\r
-#info {\r
-    margin-left: 10px; /* Adjust as needed */\r
-}\r
-\r
-#options {\r
-    margin-left: 10px; /* Adjust as needed */\r
-}\r
-\r
-\r
-    </style>\r
-</head>\r
-<body>\r
-    <!-- Main game canvas -->\r
-    <canvas id="gameCanvas"></canvas>\r
-\r
-    <!-- UI with sliders and info -->\r
-    <div id="ui">\r
-        <div class="slider-container">\r
-            <label for="ballCountSlider">Number of Balls:</label>\r
-            <input type="range" id="ballCountSlider" min="1" max="500" value="60" autocomplete="off">\r
-            <span id="ballCountValue">60</span>\r
-        </div>\r
-        <div class="slider-container">\r
-            <label for="ballSpeedSlider">Ball Speed:</label>\r
-            <input type="range" id="ballSpeedSlider" min="0" max="10" step="0.25" value="2" autocomplete="off">\r
-            <span id="ballSpeedValue">2</span>\r
-        </div>\r
-        <div class="slider-container">\r
-            <label for="ballRadiusSlider">Ball Radius:</label>\r
-            <input type="range" id="ballRadiusSlider" min="1" max="20" value="5" autocomplete="off">\r
-            <span id="ballRadiusValue">5</span>\r
-        </div>\r
-        <div class="slider-container">\r
-            <label for="explosionRadiusSlider">Explosion Radius:</label>\r
-            <input type="range" id="explosionRadiusSlider" min="10" max="200" value="60" autocomplete="off">\r
-            <span id="explosionRadiusValue">60</span>\r
-        </div>\r
-        <div class="slider-container">\r
-            <label for="explosionSpeedSlider">Explosion Speed:</label>\r
-            <input type="range" id="explosionSpeedSlider" min="0.25" max="4" step="0.25" value="1.0" autocomplete="off">\r
-            <span id="explosionSpeedValue">1.0</span>\r
-        </div>\r
-        <div class="slider-container">\r
-            <label for="explosionLingerSlider">Explosion Linger Time:</label>\r
-            <input type="range" id="explosionLingerSlider" min="0" max="4" step="0.1" value="0" autocomplete="off">\r
-            <span id="explosionLingerValue">0</span>\r
-        </div>\r
-               <div class="slider-container">\r
-                       <label for="explosionDragFreqSlider">Explosion Drag Freq:</label>\r
-                       <input type="range" id="explosionDragFreqSlider" min="10" max="1000" value="100" autocomplete="off">\r
-                       <span id="explosionDragFreqValue">100</span>\r
-               </div>\r
-<div id="options">     \r
-               <div class="stat">\r
-                       <input type="checkbox" class="stat-checkbox" id="autoStartCheckbox">\r
-                       <label for="autoStartCheckbox">Auto Start Reaction</label>\r
-               </div>\r
-               <div class="stat">\r
-                       <input type="checkbox" class="stat-checkbox" id="ballAfterExplosionCheckbox" checked>\r
-                       <label for="ballAfterExplosionCheckbox">Ball After Explosion</label>\r
-               </div>\r
-</div>\r
-<div id="info">\r
-    <div class="stat">\r
-        <input type="checkbox" class="stat-checkbox" id="activeExplosionsCheckbox">\r
-        <label for="activeExplosionsCheckbox">Active Explosions:</label>\r
-        <span id="activeExplosions">0</span>\r
-    </div>\r
-    <div class="stat">\r
-        <input type="checkbox" class="stat-checkbox" id="longestChainCheckbox">\r
-        <label for="longestChainCheckbox">Longest Current Chain:</label>\r
-        <span id="longestCurrentChain">0</span>\r
-    </div>\r
-       <div class="stat">\r
-               <input type="checkbox" class="stat-checkbox" id="totalExplosionsCheckbox">\r
-               <label for="totalExplosionsCheckbox">Total Explosions:</label>\r
-               <span id="totalExplosions">0</span>\r
-       </div>\r
-</div>\r
-<div class="button-container">\r
-    <button id="resetButton">Reset</button>\r
-    <button id="restoreDefaultsButton">Restore Defaults</button>\r
-</div>\r
-<div class="slider-container mode-toggle">\r
-    <label>Mode:</label>\r
-    <div class="toggle-container">\r
-        <button class="mode-button active" data-mode="click">Click</button>\r
-        <button class="mode-button" data-mode="drag">Drag</button>\r
-    </div>\r
-</div>\r
-               <div class="music-credits">\r
-                       Music by StarStabbedMoon:<br>\r
-                       <a href="mailto:StarStabbedMoon@gmail.com">Email</a> \r
-                       <a href="https://starstabbedmoon.bandcamp.com">Bandcamp</a><br>\r
-                       <a href="https://www.youtube.com/starstabbedmoon">YouTube</a>\r
-                       <a href="https://open.spotify.com/artist/71cCMapE4464Npz4TnTAT8?si=CpaYj-SUR0S_2Y6hg1B5bw">Spotify</a> \r
-                       <a href="https://www.soundclick.com/starstabbedmoon">SoundClick</a>\r
-               </div>\r
-    </div>\r
-\r
-    <!-- Button to show or hide the UI -->\r
-    <button id="toggleUIButton">Show Controls</button>\r
-       <button id="fullscreenButton">Full Screen</button>\r
-       \r
-       <button id="musicButton" style="position: fixed; bottom: 110px; right: 10px; padding: 10px; background: rgba(0, 0, 0, 255); color: white; border: none; border-radius: 5px;     cursor: pointer; font-family: Arial, sans-serif; font-size: 14px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); z-index: 1000; filter: grayscale(100%);">\r
-               ðŸ”‡\r
-       </button>\r
-       \r
-       <audio id="bgMusic" loop>\r
-               <source src="Celestial Assault.mp3" type="audio/mpeg">\r
-               Your browser does not support the audio element.\r
-       </audio>\r
-\r
-    <script>\r
-        /*************************************************************\r
-         *  GLOBAL VARIABLES & INITIAL SETUP\r
-         *************************************************************/\r
-        const canvas = document.getElementById('gameCanvas');\r
-        const ctx = canvas.getContext('2d');\r
-\r
-        // Arrays to hold balls and explosions\r
-        let balls = [];\r
-        let expandingCircles = [];\r
-\r
-        // Default values for game parameters\r
-        let maxCircleSize = 60;         // Explosion radius\r
-        let ballCount = 60;            // Number of balls\r
-        let ballRadius = 6;            // Radius of each ball\r
-        let ballSpeed = 2;             // Speed of each ball (base value)\r
-        let explosionSpeed = 1.0;      // Expansion speed of explosion\r
-        let explosionLingerTime = 0;   // Seconds to linger after reaching max size\r
-               let explosionDragFreq = 100;  // Milliseconds between explosions during drag\r
-               let isDragging = false;\r
-               let lastDragExplosionTime = 0;\r
-               let currentDragPosition = { x: 0, y: 0 };\r
-               let interactionMode = 'drag';\r
-               let muted = true;\r
-               let totalExplosions = 0;\r
-               \r
-               \r
-               \r
-\r
-       \r
-\r
-        // Track the time of the previous frame for consistent animation\r
-        let lastFrameTime = 0;\r
-               \r
-\r
-        /*************************************************************\r
-         *  UI ELEMENTS\r
-         *************************************************************/\r
-               // sliders\r
-        const ballCountSlider = document.getElementById('ballCountSlider');\r
-        const ballCountValue = document.getElementById('ballCountValue');\r
-        const ballSpeedSlider = document.getElementById('ballSpeedSlider');\r
-        const ballSpeedValue = document.getElementById('ballSpeedValue');\r
-        const ballRadiusSlider = document.getElementById('ballRadiusSlider');\r
-        const ballRadiusValue = document.getElementById('ballRadiusValue');\r
-        const explosionRadiusSlider = document.getElementById('explosionRadiusSlider');\r
-        const explosionRadiusValue = document.getElementById('explosionRadiusValue');\r
-        const explosionSpeedSlider = document.getElementById('explosionSpeedSlider');\r
-        const explosionSpeedValue = document.getElementById('explosionSpeedValue');\r
-        const explosionLingerSlider = document.getElementById('explosionLingerSlider');\r
-        const explosionLingerValue = document.getElementById('explosionLingerValue');\r
-               const explosionDragFreqSlider = document.getElementById('explosionDragFreqSlider');\r
-               const explosionDragFreqValue = document.getElementById('explosionDragFreqValue');\r
-        // stats\r
-               const activeExplosions = document.getElementById('activeExplosions');\r
-        const longestCurrentChain = document.getElementById('longestCurrentChain');\r
-               const totalExplosionsElement = document.getElementById('totalExplosions');\r
-               // options\r
-               const modeSelect = document.getElementById('modeSelect');\r
-               const autoStartCheckbox = document.getElementById('autoStartCheckbox');\r
-               const ballAfterExplosionCheckbox = document.getElementById('ballAfterExplosionCheckbox');\r
-               // other\r
-        const resetButton = document.getElementById('resetButton');\r
-               const restoreDefaultsButton = document.getElementById('restoreDefaultsButton');\r
-        const toggleUIButton = document.getElementById('toggleUIButton');\r
-               const fullscreenButton = document.getElementById('fullscreenButton');\r
-               const bgMusic = document.getElementById('bgMusic');\r
-               const musicButton = document.getElementById('musicButton');\r
-\r
-        const ui = document.getElementById('ui');\r
-               \r
-               \r
-     /*************************************************************\r
-     *  LOAD/SAVE SETTINGS\r
-     *************************************************************/\r
-    function loadSettings() {\r
-        // Sliders\r
-        ballCountSlider.value = localStorage.getItem('ballCount') || ballCountSlider.value;\r
-        ballSpeedSlider.value = localStorage.getItem('ballSpeed') || ballSpeedSlider.value;\r
-        ballRadiusSlider.value = localStorage.getItem('ballRadius') || ballRadiusSlider.value;\r
-        explosionRadiusSlider.value = localStorage.getItem('explosionRadius') || explosionRadiusSlider.value;\r
-        explosionSpeedSlider.value = localStorage.getItem('explosionSpeed') || explosionSpeedSlider.value;\r
-        explosionLingerSlider.value = localStorage.getItem('explosionLinger') || explosionLingerSlider.value;\r
-        explosionDragFreqSlider.value = localStorage.getItem('explosionDragFreq') || explosionDragFreqSlider.value;\r
-\r
-        // Checkboxes\r
-        autoStartCheckbox.checked = localStorage.getItem('autoStart') === 'true';\r
-        ballAfterExplosionCheckbox.checked = localStorage.getItem('ballAfterExplosion') === 'true';\r
-        document.getElementById('activeExplosionsCheckbox').checked = localStorage.getItem('activeExplosionsCheckbox') === 'true';\r
-        document.getElementById('longestChainCheckbox').checked = localStorage.getItem('longestChainCheckbox') === 'true';\r
-        document.getElementById('totalExplosionsCheckbox').checked = localStorage.getItem('totalExplosionsCheckbox') === 'true';\r
-\r
-        // Interaction Mode\r
-        const savedMode = localStorage.getItem('interactionMode');\r
-        if (savedMode) {\r
-            interactionMode = savedMode;\r
-        }\r
-        document.querySelectorAll('.mode-button').forEach(btn => {\r
-            btn.classList.toggle('active', btn.dataset.mode === interactionMode);\r
-        });\r
-        \r
-\r
-        // UI Visibility\r
-        const uiVisible = localStorage.getItem('uiVisible') === 'true';\r
-        ui.classList.toggle('visible', uiVisible);\r
-        toggleUIButton.textContent = uiVisible ? 'Hide Controls' : 'Show Controls';\r
-\r
-        // Music Mute State\r
-        muted = !(localStorage.getItem('muted') === 'false');\r
-        musicButton.textContent = muted ? '🔇' : '🔊';\r
-        if (!muted) bgMusic.play().catch(() => {});\r
-    }\r
-\r
-    function saveSetting(key, value) {\r
-        localStorage.setItem(key, value);\r
-    }\r
-\r
-\r
-        /*************************************************************\r
-         *  FIREFOX SLIDER FIX\r
-         *************************************************************/\r
-        const sliders = [\r
-            ballCountSlider,\r
-            ballSpeedSlider,\r
-            ballRadiusSlider,\r
-            explosionRadiusSlider,\r
-            explosionSpeedSlider,\r
-            explosionLingerSlider\r
-        ];\r
-\r
-        function resetSliderVisuals() {\r
-            sliders.forEach(slider => {\r
-                const initialValue = slider.getAttribute('value');\r
-                slider.value = initialValue;\r
-                // Force DOM refresh\r
-                const type = slider.type;\r
-                slider.type = "text";\r
-                slider.type = "range";\r
-                slider.blur();\r
-            });\r
-        }\r
-\r
-        /*************************************************************\r
-         *  INITIALIZATION\r
-         *************************************************************/\r
-        function init() {\r
-               \r
-               //restoreDefaultSettings(); // initialize defaults\r
-               \r
-               const screenArea = window.innerWidth * window.innerHeight;\r
-    const baseArea = 1920 * 1080; // Reference area for default 60 balls\r
-    let proportionalBallCount = (screenArea / baseArea) * 350;\r
-    proportionalBallCount = Math.round(proportionalBallCount / 10) * 10; // Round to nearest 10\r
-    proportionalBallCount = Math.min(proportionalBallCount, 500); // Clamp to slider max\r
-    proportionalBallCount = Math.max(proportionalBallCount, 10); // Minimum 10 balls\r
-    \r
-               ballCountSlider.value = proportionalBallCount;\r
-               \r
-               \r
-               loadSettings(); // Load before resetting the game\r
-            //resetSliderVisuals();\r
-            \r
-            \r
-\r
-            // Set parameters from HTML attributes\r
-            maxCircleSize = parseInt(explosionRadiusSlider.value);\r
-            ballCount = parseInt(ballCountSlider.value);\r
-            ballRadius = parseInt(ballRadiusSlider.value);\r
-            ballSpeed = parseFloat(ballSpeedSlider.value);\r
-            explosionSpeed = parseFloat(explosionSpeedSlider.value);\r
-            explosionLingerTime = parseFloat(explosionLingerSlider.value);\r
-                       explosionDragFreq = parseInt(explosionDragFreqSlider.value);\r
-                       \r
-            // Update displayed values\r
-            ballCountValue.textContent = ballCountSlider.value;\r
-            ballSpeedValue.textContent = ballSpeedSlider.value;\r
-            ballRadiusValue.textContent = ballRadiusSlider.value;\r
-            explosionRadiusValue.textContent = explosionRadiusSlider.value;\r
-            explosionSpeedValue.textContent = explosionSpeedSlider.value;\r
-            explosionLingerValue.textContent = explosionLingerSlider.value;\r
-                       explosionDragFreqValue.textContent = explosionDragFreqSlider.value;\r
-\r
-            resetGame();\r
-        }\r
-\r
-        /*************************************************************\r
-         *  UI EVENT LISTENERS\r
-         *************************************************************/\r
-                \r
-                restoreDefaultsButton.addEventListener('click', restoreDefaultSettings);\r
-                \r
-document.querySelectorAll('.mode-button').forEach(button => {\r
-    button.addEventListener('click', function() {\r
-       \r
-        // Remove active class from all buttons\r
-        document.querySelectorAll('.mode-button').forEach(b => b.classList.remove('active'));\r
-        // Add active class to clicked button\r
-        this.classList.add('active');\r
-        // Update interaction mode\r
-        interactionMode = this.dataset.mode;\r
-               saveSetting('interactionMode', this.dataset.mode);\r
-        endDrag(); // Cancel any ongoing drag operations\r
-    });\r
-});\r
-/*             \r
-// Attempt autoplay on page load\r
-document.addEventListener('DOMContentLoaded', () => {\r
-  bgMusic.play()\r
-    .then(() => musicButton.textContent = 'Pause Music')\r
-    .catch(() => {\r
-      musicButton.textContent = 'Play Music (Blocked)';\r
-      console.log('Autoplay blocked - click button to start');\r
-    });\r
-});\r
-*/\r
-               \r
-               // Toggle music playback\r
-musicButton.addEventListener('click', () => {\r
-  muted = !muted;\r
-  saveSetting('muted', muted);\r
-  if (!muted) {\r
-    bgMusic.play();\r
-    musicButton.textContent = '🔊';\r
-  } else {\r
-    bgMusic.pause();\r
-    musicButton.textContent = '🔇';\r
-  }\r
-});\r
-\r
-\r
-\r
-               // handle music start playing on first click\r
-               document.addEventListener('click', handleFirstClick);\r
-\r
-        // Show/hide the control panel\r
-        toggleUIButton.addEventListener('click', () => {\r
-            ui.classList.toggle('visible');\r
-                       saveSetting('uiVisible', ui.classList.contains('visible'));\r
-            toggleUIButton.textContent = ui.classList.contains('visible') ? 'Hide Controls' : 'Show Controls';\r
-        });\r
-\r
-        // Adjust ball count and reset the game\r
-        ballCountSlider.addEventListener('input', () => {\r
-                   //saveSetting('ballCount', ballCountSlider.value);\r
-            ballCountValue.textContent = ballCountSlider.value;\r
-            ballCount = parseInt(ballCountSlider.value);\r
-                       saveSetting('ballCount', ballCount);\r
-            resetGame();\r
-        });\r
-\r
-        // Adjust ball speed (time-based movement will keep it consistent)\r
-        ballSpeedSlider.addEventListener('input', () => {\r
-                       saveSetting('ballSpeed', ballSpeedSlider.value);\r
-            ballSpeedValue.textContent = ballSpeedSlider.value;\r
-            ballSpeed = parseFloat(ballSpeedSlider.value);\r
-            updateBallSpeeds();\r
-        });\r
-\r
-        // Adjust ball radius and reset balls\r
-        ballRadiusSlider.addEventListener('input', () => {\r
-                       saveSetting('ballRadius', ballRadiusSlider.value);\r
-            ballRadiusValue.textContent = ballRadiusSlider.value;\r
-            ballRadius = parseInt(ballRadiusSlider.value);\r
-            resetBalls();\r
-        });\r
-\r
-        // Adjust explosion radius (max size)\r
-        explosionRadiusSlider.addEventListener('input', () => {\r
-                       saveSetting('explosionRadius', explosionRadiusSlider.value);\r
-            explosionRadiusValue.textContent = explosionRadiusSlider.value;\r
-            maxCircleSize = parseInt(explosionRadiusSlider.value);\r
-        });\r
-\r
-        // Adjust explosion speed (for time-based growth)\r
-        explosionSpeedSlider.addEventListener('input', () => {\r
-                       saveSetting('explosionSpeed', explosionSpeedSlider.value);\r
-            explosionSpeed = parseFloat(explosionSpeedSlider.value);\r
-            explosionSpeedValue.textContent = explosionSpeed.toFixed(2);\r
-        });\r
-\r
-        // Adjust explosion lingering time\r
-        explosionLingerSlider.addEventListener('input', () => {\r
-                       saveSetting('explosionLinger', explosionLingerSlider.value);\r
-            explosionLingerValue.textContent = explosionLingerSlider.value;\r
-            explosionLingerTime = parseFloat(explosionLingerSlider.value);\r
-        });\r
-\r
-        // Reset the entire game\r
-        resetButton.addEventListener('click', () => {\r
-            resetGame();\r
-        });\r
-               \r
-               fullscreenButton.addEventListener('click', toggleFullScreen);\r
-        \r
-        // Add to existing event listeners\r
-        document.addEventListener('fullscreenchange', () => {\r
-            if (!document.fullscreenElement) {\r
-                fullscreenButton.textContent = 'Full Screen';\r
-            }\r
-        });\r
-               \r
-               explosionDragFreqSlider.addEventListener('input', () => {\r
-                       saveSetting('explosionDragFreq', explosionDragFreqSlider.value);\r
-                       explosionDragFreq = parseInt(explosionDragFreqSlider.value);\r
-                       explosionDragFreqValue.textContent = explosionDragFreq;\r
-               });\r
-               \r
-       // Checkboxes\r
-    autoStartCheckbox.addEventListener('change', () => {\r
-        saveSetting('autoStart', autoStartCheckbox.checked);\r
-    });\r
-    ballAfterExplosionCheckbox.addEventListener('change', () => {\r
-        saveSetting('ballAfterExplosion', ballAfterExplosionCheckbox.checked);\r
-    });\r
-    document.getElementById('activeExplosionsCheckbox').addEventListener('change', function() {\r
-        saveSetting('activeExplosionsCheckbox', this.checked);\r
-    });\r
-    document.getElementById('longestChainCheckbox').addEventListener('change', function() {\r
-        saveSetting('longestChainCheckbox', this.checked);\r
-    });\r
-    document.getElementById('totalExplosionsCheckbox').addEventListener('change', function() {\r
-        saveSetting('totalExplosionsCheckbox', this.checked);\r
-    });\r
-               \r
-               canvas.addEventListener('mousedown', startDrag);\r
-               canvas.addEventListener('mousemove', handleDrag);\r
-               canvas.addEventListener('mouseup', endDrag);\r
-               canvas.addEventListener('mouseleave', endDrag);\r
-\r
-        /*************************************************************\r
-         *  HELPER FUNCTIONS\r
-         *************************************************************/\r
-                \r
-                // Add this function with other helper functions\r
-function restoreDefaultSettings() {\r
-\r
-    const screenArea = window.innerWidth * window.innerHeight;\r
-    const baseArea = 1920 * 1080; // Reference area for default 60 balls\r
-    let proportionalBallCount = (screenArea / baseArea) * 350;\r
-    proportionalBallCount = Math.round(proportionalBallCount / 10) * 10; // Round to nearest 10\r
-    proportionalBallCount = Math.min(proportionalBallCount, 500); // Clamp to slider max\r
-    proportionalBallCount = Math.max(proportionalBallCount, 10); // Minimum 10 balls\r
-       \r
-    // Sliders\r
-    const sliders = [\r
-        { slider: ballCountSlider, defaultValue: proportionalBallCount.toString() },\r
-        { slider: ballSpeedSlider, defaultValue: '2' },\r
-        { slider: ballRadiusSlider, defaultValue: '6' },\r
-        { slider: explosionRadiusSlider, defaultValue: '60' },\r
-        { slider: explosionSpeedSlider, defaultValue: '1.0' },\r
-        { slider: explosionLingerSlider, defaultValue: '0' },\r
-        { slider: explosionDragFreqSlider, defaultValue: '100' }\r
-    ];\r
-    \r
-    sliders.forEach(({ slider, defaultValue }) => {\r
-        slider.value = defaultValue;\r
-        slider.dispatchEvent(new Event('input'));\r
-    });\r
-\r
-    // Checkboxes\r
-    const checkboxes = [\r
-        { element: autoStartCheckbox, defaultValue: false },\r
-        { element: ballAfterExplosionCheckbox, defaultValue: true },\r
-        { element: document.getElementById('activeExplosionsCheckbox'), defaultValue: false },\r
-        { element: document.getElementById('longestChainCheckbox'), defaultValue: false },\r
-        { element: document.getElementById('totalExplosionsCheckbox'), defaultValue: false }\r
-    ];\r
-    \r
-    checkboxes.forEach(({ element, defaultValue }) => {\r
-        element.checked = defaultValue;\r
-        element.dispatchEvent(new Event('change'));\r
-    });\r
-\r
-    // Interaction Mode\r
-    interactionMode = 'drag';\r
-    document.querySelectorAll('.mode-button').forEach(btn => {\r
-        btn.classList.toggle('active', btn.dataset.mode === 'drag');\r
-    });\r
-    saveSetting('interactionMode', 'drag');\r
-\r
-    // UI Visibility\r
-//    ui.classList.remove('visible');\r
-//    saveSetting('uiVisible', false);\r
-//    toggleUIButton.textContent = 'Show Controls';\r
-\r
-//    // Music\r
-//    muted = false;\r
-//    musicButton.textContent = '🔊';\r
-//    saveSetting('muted', false);\r
-//    bgMusic.play().catch(() => {});\r
-\r
-    resetGame();\r
-}\r
-                \r
-                function handleFirstClick(event) {\r
-                \r
-                       if (event.target === musicButton)\r
-                               return;\r
-                       \r
-                       if (!muted)\r
-                               bgMusic.play();\r
-                       \r
-                       document.removeEventListener('click', handleFirstClick);\r
-                       \r
-               }\r
-                \r
-               function toggleFullScreen() {\r
-            if (!document.fullscreenElement) {\r
-                if (canvas.requestFullscreen) {\r
-                    canvas.requestFullscreen();\r
-                } else if (canvas.webkitRequestFullscreen) { /* Safari */\r
-                    canvas.webkitRequestFullscreen();\r
-                } else if (canvas.msRequestFullscreen) { /* IE11 */\r
-                    canvas.msRequestFullscreen();\r
-                }\r
-                fullscreenButton.textContent = 'Exit Full Screen';\r
-            } else {\r
-                if (document.exitFullscreen) {\r
-                    document.exitFullscreen();\r
-                } else if (document.webkitExitFullscreen) { /* Safari */\r
-                    document.webkitExitFullscreen();\r
-                } else if (document.msExitFullscreen) { /* IE11 */\r
-                    document.msExitFullscreen();\r
-                }\r
-                fullscreenButton.textContent = 'Full Screen';\r
-            }\r
-        }\r
-        /**\r
-         * Resets all balls based on the current ballCount and ballRadius.\r
-         * Clears the balls array and spawns fresh balls.\r
-         */\r
-        function resetBalls() {\r
-            balls = [];\r
-            for (let i = 0; i < ballCount; i++) {\r
-                spawnBall();\r
-            }\r
-        }\r
-\r
-               /**\r
-               * Updates the speed (dx, dy) of each ball to match the new ballSpeed\r
-               * but preserves their direction. If speed was zero, assigns a random direction.\r
-               */\r
-               function updateBallSpeeds() {\r
-                       balls.forEach(ball => {\r
-                               const speedCurrent = Math.sqrt(ball.dx * ball.dx + ball.dy * ball.dy);\r
-                               if (speedCurrent === 0) {\r
-                                       // If speed was zero but now set to non-zero, give random direction\r
-                                       if (ballSpeed === 0) return;\r
-                                       const angle = Math.random() * 2 * Math.PI;\r
-                                       ball.dx = Math.cos(angle) * ballSpeed;\r
-                                       ball.dy = Math.sin(angle) * ballSpeed;\r
-                               } else {\r
-                                       const scale = ballSpeed / speedCurrent; \r
-                                       ball.dx *= scale;\r
-                                       ball.dy *= scale;\r
-                               }\r
-                       });\r
-               }\r
-\r
-        /**\r
-         * Resets the game state:\r
-         * - Clears all existing explosions\r
-         * - Respawns balls\r
-         * - Resets the highest chain reaction display\r
-         */\r
-        function resetGame() {\r
-            expandingCircles = [];\r
-                       totalExplosions = 0;\r
-            totalExplosionsElement.textContent = 0;\r
-            resetBalls();\r
-            longestCurrentChain.textContent = 0;\r
-        }\r
-\r
-        /**\r
-         * Generates a random color in RGB format.\r
-         * @returns {string} A string like "rgb(r, g, b)"\r
-         */\r
-        function getRandomColor() {\r
-            const r = Math.floor(Math.random() * 256);\r
-            const g = Math.floor(Math.random() * 256);\r
-            const b = Math.floor(Math.random() * 256);\r
-            return `rgb(${r}, ${g}, ${b})`;\r
-        }\r
-\r
-        /**\r
-         * Spawns a single ball at a random position within the canvas,\r
-         * given the current ballRadius and ballSpeed.\r
-         */\r
-        function spawnBall() {\r
-            const radius = ballRadius;\r
-            const x = Math.random() * (canvas.width - radius * 2) + radius;\r
-            const y = Math.random() * (canvas.height - radius * 2) + radius;\r
-            const angle = Math.random() * 2 * Math.PI;\r
-            const dx = Math.cos(angle) * ballSpeed;\r
-            const dy = Math.sin(angle) * ballSpeed;\r
-            const color = getRandomColor();\r
-            balls.push(new Ball(x, y, dx, dy, radius, color));\r
-        }\r
-\r
-        /**\r
-         * Resize the canvas to match the window size.\r
-         */\r
-        function resizeCanvas() {\r
-            canvas.width = window.innerWidth;\r
-            canvas.height = window.innerHeight;\r
-        }\r
-               \r
-       function startDrag(event) {\r
-       if (interactionMode !== 'drag') return;\r
-        isDragging = true;\r
-        updateDragPosition(event);\r
-        triggerDragExplosion();  // Trigger immediately on click\r
-    }\r
-\r
-    function handleDrag(event) {\r
-               if (interactionMode !== 'drag' || !isDragging) return;\r
\r
-        updateDragPosition(event);\r
-        \r
-        const now = Date.now();\r
-        if (now - lastDragExplosionTime >= explosionDragFreq) {\r
-            triggerDragExplosion();\r
-            lastDragExplosionTime = now;\r
-        }\r
-    }\r
-\r
-    function endDrag() {\r
-        isDragging = false;\r
-    }\r
-\r
-    function updateDragPosition(event) {\r
-        const rect = canvas.getBoundingClientRect();\r
-        const scaleX = canvas.width / rect.width;\r
-        const scaleY = canvas.height / rect.height;\r
-        currentDragPosition.x = (event.clientX - rect.left) * scaleX;\r
-        currentDragPosition.y = (event.clientY - rect.top) * scaleY;\r
-    }\r
-\r
-    function triggerDragExplosion() {\r
-        const initialIndices = {\r
-            r: 300,\r
-            g: 600,\r
-            b: 900,\r
-        };\r
-        expandingCircles.push(new ExpandingCircle(\r
-            currentDragPosition.x,\r
-            currentDragPosition.y,\r
-            1,\r
-            true,  // isMouseClickExplosion\r
-            initialIndices\r
-        ));\r
-    }\r
-\r
-        /*************************************************************\r
-         *  CLASSES\r
-         *************************************************************/\r
-        class Ball {\r
-            constructor(x, y, dx, dy, radius, color) {\r
-                this.x = x;\r
-                this.y = y;\r
-                this.dx = dx;\r
-                this.dy = dy;\r
-                this.radius = radius;\r
-                this.color = color;\r
-            }\r
-\r
-            draw() {\r
-                ctx.beginPath();\r
-                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);\r
-                ctx.fillStyle = this.color;\r
-                ctx.fill();\r
-                ctx.closePath();\r
-                               \r
-                               ctx.beginPath();\r
-                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);\r
-                ctx.strokeStyle = 'black';\r
-                ctx.lineWidth = 2;\r
-                ctx.stroke();\r
-                ctx.closePath();\r
-            }\r
-\r
-            update(frameFactor) {\r
-                if (this.x + this.radius > canvas.width || this.x - this.radius < 0) {\r
-                    this.dx = -this.dx;\r
-                }\r
-                if (this.y + this.radius > canvas.height || this.y - this.radius < 0) {\r
-                    this.dy = -this.dy;\r
-                }\r
-                this.x += this.dx * frameFactor;\r
-                this.y += this.dy * frameFactor;\r
-                this.draw();\r
-            }\r
-        }\r
-\r
-        class ExpandingCircle {\r
-            constructor(x, y, chainReactionCount = 1, isMouseClickExplosion = false, parentIndices = { r: 100, g: 200, b: 300 }) {\r
-                this.x = x;\r
-                this.y = y;\r
-                this.radius = 0;\r
-                this.growing = true;\r
-                this.lingerStartTime = null;\r
-                this.chainReactionCount = chainReactionCount;\r
-                this.isMouseClickExplosion = isMouseClickExplosion;\r
-                this.indices = {\r
-                    r: parentIndices.r + 18,\r
-                    g: parentIndices.g + 16,\r
-                    b: parentIndices.b + 14,\r
-                };\r
-                this.rgb = this.calculateRGB();\r
-                               totalExplosions++;\r
-            }\r
-\r
-            calculateRGBNeo() {\r
-                const r = Math.floor(100 + 155 * ((Math.sin(this.indices.r * Math.PI / 180) + 1) / 2));\r
-                const g = Math.floor(100 + 155 * ((Math.sin(this.indices.g * Math.PI / 180) + 1) / 2));\r
-                const b = Math.floor(100 + 155 * ((Math.sin(this.indices.b * Math.PI / 180) + 1) / 2));\r
-                return { r, g, b };\r
-            }\r
-                       \r
-                       calculateRGB() {\r
-                const r = 126*(Math.sin(0.02*(this.chainReactionCount+150)*15)+1);\r
-                const g = 126*(Math.sin(0.03*(this.chainReactionCount+150)*15)+1);\r
-                const b = 126*(Math.sin(0.01*(this.chainReactionCount+150)*15)+1);\r
-                return { r, g, b };\r
-            }\r
-\r
-            draw() {\r
-                ctx.beginPath();\r
-                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);\r
-                ctx.fillStyle = `rgba(${this.rgb.r}, ${this.rgb.g}, ${this.rgb.b}, 255)`;\r
-                ctx.fill();\r
-                ctx.closePath();\r
-\r
-                ctx.beginPath();\r
-                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);\r
-                ctx.strokeStyle = 'black';\r
-                ctx.lineWidth = 4;\r
-                ctx.stroke();\r
-                ctx.closePath();\r
-            }\r
-\r
-            update(frameFactor) {\r
-                if (this.growing) {\r
-                    this.radius += explosionSpeed * frameFactor;\r
-                    if (this.radius >= maxCircleSize) {\r
-                        this.growing = false;\r
-                        this.lingerStartTime = Date.now();\r
-                    }\r
-                }\r
-                this.draw();\r
-            }\r
-\r
-            isColliding(ball) {\r
-                const dx = this.x - ball.x;\r
-                const dy = this.y - ball.y;\r
-                const distance = Math.sqrt(dx * dx + dy * dy);\r
-                return distance < this.radius + ball.radius;\r
-            }\r
-\r
-            shouldDisappear() {\r
-                if (!this.lingerStartTime) return false;\r
-                const elapsedTime = (Date.now() - this.lingerStartTime) / 1000;\r
-                return elapsedTime >= explosionLingerTime;\r
-            }\r
-        }\r
-\r
-        /*************************************************************\r
-         *  MAIN GAME LOOP FUNCTIONS\r
-         *************************************************************/\r
-        function updateGame(frameFactor) {\r
-            balls.forEach(ball => {\r
-                ball.update(frameFactor);\r
-            });\r
-                       \r
-                       // Auto-start reaction check\r
-                       if (autoStartCheckbox.checked && expandingCircles.length === 0) {\r
-                               const initialIndices = { r: 300, g: 600, b: 900 };\r
-                               const x = Math.random() * canvas.width;\r
-                               const y = Math.random() * canvas.height;\r
-                               expandingCircles.push(new ExpandingCircle(x, y, 1, true, initialIndices));\r
-                       }\r
-\r
-            const explosionsToRemove = [];\r
-            let longestCurrentChainCount = 0;\r
-\r
-            expandingCircles.forEach((circle, circleIndex) => {\r
-                circle.update(frameFactor);\r
-\r
-                balls.forEach((ball, ballIndex) => {\r
-                    if (circle.isColliding(ball)) {\r
-                        const newIndices = {\r
-                            r: circle.indices.r + 9,\r
-                            g: circle.indices.g + 8,\r
-                            b: circle.indices.b + 7,\r
-                        };\r
-                        expandingCircles.push(\r
-                            new ExpandingCircle(\r
-                                ball.x,\r
-                                ball.y,\r
-                                circle.chainReactionCount + 1,\r
-                                false,\r
-                                newIndices\r
-                            )\r
-                        );\r
-                        balls.splice(ballIndex, 1);\r
-                    }\r
-                });\r
-\r
-                if (circle.chainReactionCount > longestCurrentChainCount) {\r
-                    longestCurrentChainCount = circle.chainReactionCount;\r
-                }\r
-\r
-                if (!circle.growing && circle.shouldDisappear()) {\r
-                    explosionsToRemove.push(circleIndex);\r
-                }\r
-            });\r
-\r
-            for (let i = explosionsToRemove.length - 1; i >= 0; i--) {\r
-                const circleIndex = explosionsToRemove[i];\r
-                const circle = expandingCircles[circleIndex];\r
-                if (!circle.isMouseClickExplosion && ballAfterExplosionCheckbox.checked) {\r
-                    spawnBall();\r
-                }\r
-                expandingCircles.splice(circleIndex, 1);\r
-            }\r
-                       \r
-                       totalExplosionsElement.textContent = totalExplosions;\r
-            activeExplosions.textContent = expandingCircles.length;\r
-            longestCurrentChain.textContent = longestCurrentChainCount;\r
-        }\r
-\r
-        function renderGame() {\r
-            ctx.clearRect(0, 0, canvas.width, canvas.height);\r
-            balls.forEach(ball => ball.draw());\r
-            expandingCircles.forEach(circle => circle.draw());\r
-                       \r
-                           // Draw stats on canvas if checkboxes are checked\r
-    const activeExplosionsCheckbox = document.getElementById('activeExplosionsCheckbox');\r
-    const longestChainCheckbox = document.getElementById('longestChainCheckbox');\r
-    \r
-    ctx.fillStyle = 'white';\r
-    ctx.font = '16px Arial';\r
-    const padding = 20;\r
-    let yPos = padding;\r
-\r
-    if (activeExplosionsCheckbox.checked) {\r
-        ctx.fillText(`Active Explosions: ${document.getElementById('activeExplosions').textContent}`, padding, yPos);\r
-        yPos += 24;\r
-    }\r
-    if (longestChainCheckbox.checked) {\r
-        ctx.fillText(`Longest Current Chain: ${document.getElementById('longestCurrentChain').textContent}`, padding, yPos);\r
-               yPos += 24;\r
-    }\r
-       \r
-       if (document.getElementById('totalExplosionsCheckbox').checked) {\r
-    ctx.fillText(`Total Explosions: ${totalExplosions}`, padding, yPos);\r
-    yPos += 24;\r
-}\r
-        }\r
-\r
-        function animate(timestamp) {\r
-            requestAnimationFrame(animate);\r
-\r
-            if (!lastFrameTime) {\r
-                lastFrameTime = timestamp;\r
-            }\r
-\r
-            const dt = timestamp - lastFrameTime;\r
-            lastFrameTime = timestamp;\r
-            const frameFactor = dt / (1000 / 60);\r
-\r
-            updateGame(frameFactor);\r
-            renderGame();\r
-        }\r
-\r
-        /*************************************************************\r
-         *  EVENT LISTENERS\r
-         *************************************************************/\r
-        canvas.addEventListener('click', (event) => {\r
-                   if (interactionMode !== 'click') return;\r
-                       \r
-            const rect = canvas.getBoundingClientRect();\r
-            const scaleX = canvas.width / rect.width;\r
-            const scaleY = canvas.height / rect.height;\r
-            const x = (event.clientX - rect.left) * scaleX;\r
-            const y = (event.clientY - rect.top) * scaleY;\r
-\r
-            if (y < canvas.height) {\r
-                const initialIndices = {\r
-                    r: 300,\r
-                    g: 600,\r
-                    b: 900,\r
-                };\r
-                expandingCircles.push(new ExpandingCircle(x, y, 1, true, initialIndices));\r
-            }\r
-        });\r
-\r
-        window.addEventListener('resize', resizeCanvas);\r
-               \r
-               \r
-               \r
-               canvas.addEventListener('touchstart', handleTouchStart);\r
-canvas.addEventListener('touchmove', handleTouchMove);\r
-canvas.addEventListener('touchend', handleTouchEnd);\r
-canvas.addEventListener('touchcancel', handleTouchEnd);\r
-\r
-               \r
-               document.body.addEventListener('touchstart', function(event) {\r
-    if (event.target === canvas) {\r
-        event.preventDefault();\r
-    }\r
-}, { passive: false });\r
-\r
-document.body.addEventListener('touchmove', function(event) {\r
-    if (event.target === canvas) {\r
-        event.preventDefault();\r
-    }\r
-}, { passive: false });\r
-\r
-function handleTouchStart(event) {\r
-    event.preventDefault(); // Prevent default touch behavior (e.g., scrolling)\r
-   // if (interactionMode !== 'drag') return;\r
-\r
-    const touches = event.touches;\r
-    for (let i = 0; i < touches.length; i++) {\r
-        const touch = touches[i];\r
-        const rect = canvas.getBoundingClientRect();\r
-        const scaleX = canvas.width / rect.width;\r
-        const scaleY = canvas.height / rect.height;\r
-        const x = (touch.clientX - rect.left) * scaleX;\r
-        const y = (touch.clientY - rect.top) * scaleY;\r
-\r
-        const initialIndices = {\r
-            r: 300,\r
-            g: 600,\r
-            b: 900,\r
-        };\r
-        expandingCircles.push(new ExpandingCircle(x, y, 1, true, initialIndices));\r
-    }\r
-}\r
-\r
-function handleTouchMove(event) {\r
-    event.preventDefault(); // Prevent default touch behavior (e.g., scrolling)\r
-    if (interactionMode !== 'drag') return;\r
-\r
-    const touches = event.touches;\r
-    for (let i = 0; i < touches.length; i++) {\r
-        const touch = touches[i];\r
-        const rect = canvas.getBoundingClientRect();\r
-        const scaleX = canvas.width / rect.width;\r
-        const scaleY = canvas.height / rect.height;\r
-        const x = (touch.clientX - rect.left) * scaleX;\r
-        const y = (touch.clientY - rect.top) * scaleY;\r
-\r
-        const initialIndices = {\r
-            r: 300,\r
-            g: 600,\r
-            b: 900,\r
-        };\r
-        expandingCircles.push(new ExpandingCircle(x, y, 1, true, initialIndices));\r
-    }\r
-}\r
-\r
-function handleTouchEnd(event) {\r
-    // You can add cleanup logic here if needed\r
-}\r
-               \r
-\r
-        /*************************************************************\r
-         *  START THE GAME\r
-         *************************************************************/\r
-        resizeCanvas();\r
-        init();\r
-        requestAnimationFrame(animate);\r
-    </script>\r
-</body>\r
-</html>\r
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Circles Of Doom with Music by StarStabbedMoon</title>
+    <style>
+        /* Basic styling to fill the screen and show a black background */
+        body, html {
+            margin: 0;
+            padding: 0;
+            overflow: hidden;
+            height: 100%;
+        }
+        canvas {
+            display: block;
+            background: black;
+            width: 100%;
+            height: 100%;
+        }
+        /* UI container styling */
+        #ui {
+            position: fixed;
+            bottom: 0;
+            left: 0;
+            width: 100%;
+            background: rgba(255, 255, 255, 0);
+            padding: 10px;
+            display: flex;
+            flex-direction: column;
+            align-items: flex-start;
+            gap: 10px;
+            transition: transform 0.3s ease-in-out;
+            transform: translateY(100%); /* Hidden by default */
+            pointer-events: none; /* Makes UI transparent to clicks */
+        }
+        
+        #ui * {
+            pointer-events: auto; /* Re-enable clicks for child elements */
+        }
+        /* When we add the class "visible", the UI slides up */
+        #ui.visible {
+            transform: translateY(0);
+        }
+        /* Container for sliders and labels */
+        .slider-container {
+            display: flex;
+            align-items: center;
+            gap: 10px;
+            margin-left: 10px;
+            color: white;
+            width: auto;
+            pointer-events: none;
+        }
+        .slider-container > * {
+            pointer-events: auto;
+        }
+        label {
+            font-family: Arial, sans-serif;
+            font-size: 14px;
+            min-width: 150px; /* Ensure labels have consistent width */
+            color: white;
+            flex-shrink: 0;
+        }
+        input[type="range"] {
+            flex: 1; /* Take available space */
+            max-width: 300px; /* Maximum width for larger screens */
+            min-width: 100px; /* Minimum usable width */
+        }
+        
+        /* Mobile adjustments */
+        @media (max-width: 600px) {
+            .slider-container {
+                margin-left: 5px;
+                gap: 8px;
+            }
+            label {
+                min-width: 110px; /* Smaller min-width for mobile */
+                font-size: 13px;
+            }
+            input[type="range"] {
+                max-width: 100%; /* Allow full width of container */
+            }
+            #info, #options, #resetButton, #restoreDefaultsButton {
+                margin-left: 5px;
+            }
+        }
+        
+        /* Information text styling */
+        #info {
+            font-family: Arial, sans-serif;
+            font-size: 14px;
+            margin-top: 10px;
+            text-align: left;
+            width: auto;
+            margin-left: 10px;
+            color: white;
+        }
+        
+        /* Options text styling */
+        #options {
+            font-family: Arial, sans-serif;
+            font-size: 14px;
+            margin-top: 10px;
+            text-align: left;
+            width: auto;
+            margin-left: 10px;
+            color: white;
+        }
+        
+        .button-container {
+            display: flex;
+            gap: 10px;
+            margin-left: 20px;
+            margin-top: 10px;
+        }
+        
+        /* Button styling */
+        #resetButton,
+        #restoreDefaultsButton {
+            padding: 5px 10px;
+            font-family: Arial, sans-serif;
+            font-size: 14px;
+            cursor: pointer;
+            color: white;
+            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
+            background: rgba(0, 0, 0, 255);
+        }
+
+        /* Style for the audio toggle button */
+        #audio-toggle {
+            position: fixed;
+            top: 16px;
+            left: 16px;
+            width: 48px;
+            height: 48px;
+            background: rgba(255, 255, 255, 0.2);
+            border: 2px solid rgba(255, 255, 255, 0.5);
+            border-radius: 50%;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            cursor: pointer;
+            z-index: 1000;
+            transition: background 0.3s, border 0.3s;
+        }
+        
+        /* Button to toggle the UI visibility */
+        #toggleUIButton {
+            position: fixed;
+            bottom: 10px;
+            right: 10px;
+            padding: 10px;
+            background: rgba(0, 0, 0, 255);
+            color: white;
+            border: none;
+            border-radius: 5px;
+            cursor: pointer;
+            font-family: Arial, sans-serif;
+            font-size: 14px;
+            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
+        }
+        
+        .music-credits {
+            font-family: Arial, sans-serif;
+            font-size: 12px;
+            color: white;
+            margin-left: 20px;
+            margin-top: 10px;
+            opacity: 0.8;
+            text-align: center;
+        }
+
+        .music-credits a {
+            color: #ff8888;
+            text-decoration: none;
+            margin: 0 5px;
+        }
+
+        .music-credits a:hover {
+            text-decoration: underline;
+        }
+        
+        #fullscreenButton {
+            position: fixed;
+            bottom: 60px;
+            right: 10px;
+            padding: 10px;
+            background: rgba(0, 0, 0, 255);
+            color: white;
+            border: none;
+            border-radius: 5px;
+            cursor: pointer;
+            font-family: Arial, sans-serif;
+            font-size: 14px;
+            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
+            z-index: 1000;
+        }
+        
+        /* Mode toggle styling */
+        .mode-toggle {
+            margin-top: 10px;
+        }
+
+        .toggle-container {
+            display: flex;
+            gap: 5px;
+            margin-left: 10px;
+        }
+
+        .mode-button {
+            padding: 5px 12px;
+            border: none;
+            border-radius: 15px;
+            cursor: pointer;
+            background: rgba(255, 255, 255, 0.1);
+            color: white;
+            font-family: Arial, sans-serif;
+            font-size: 14px;
+            transition: all 0.2s ease;
+        }
+
+        .mode-button.active {
+            background: #ff4444;
+            color: white;
+            box-shadow: 0 0 5px rgba(255, 68, 68, 0.5);
+        }
+        
+        /* Modern slider styling with persistent red color */
+        input[type="range"] {
+            accent-color: #ff0000;
+            background: transparent !important;
+            border: none !important;
+            box-shadow: none !important;
+        }
+
+        /* Chrome/Safari track */
+        input[type="range"]::-webkit-slider-runnable-track {
+            background: rgba(255, 255, 255, 0.2);
+            height: 8px;
+            border-radius: 5px;
+            border: 1px solid #000000ff;
+            box-sizing: border-box;
+        }
+
+        /* Chrome/Safari thumb */
+        input[type="range"]::-webkit-slider-thumb {
+            -webkit-appearance: none;
+            width: 16px;
+            height: 16px;
+            background: #ff0000;
+            border-radius: 50%;
+            margin-top: -4px;
+            box-shadow: 0 0 0 1.5px black; /* Simulated border using box-shadow */
+            position: relative;
+            z-index: 1;
+        }
+
+        /* Firefox Track */
+        input[type="range"]::-moz-range-track {
+            background: #ffffff;
+            height: 8px;
+            border: 1px solid #000000ff;
+            border-radius: 5px;
+            box-shadow: none;
+        }
+
+        /* Firefox Progress (filled portion) */
+        input[type="range"]::-moz-range-progress {
+            background: #ff0000;
+            height: 8px;
+            border-radius: 5px 0 0 5px;
+            border: none;
+        }
+
+        /* Firefox Thumb */
+        input[type="range"]::-moz-range-thumb {
+            width: 16px;
+            height: 16px;
+            background: #ff0000 !important;
+            border: 2px solid black;
+            border-radius: 50%;
+            box-shadow: none;
+            position: relative;
+            z-index: 1;
+        }
+
+        /* Remove focus ring */
+        input[type="range"]:focus {
+            outline: none;
+        }
+
+        .stat {
+            display: flex;
+            align-items: center;
+            gap: 8px;
+            margin-bottom: 8px;
+        }
+
+        .stat-checkbox {
+            margin: 0;
+            accent-color: #ff4444; /* Red color for checkboxes */
+        }
+    </style>
+</head>
+<body>
+    <div id="audio-toggle"><span id="musicButton">&#128266;</span></div>
+    <!-- Main game canvas -->
+    <canvas id="gameCanvas"></canvas>
+
+    <!-- UI with sliders and info -->
+    <div id="ui">
+        <div class="slider-container">
+            <label for="ballCountSlider">Number of Balls:</label>
+            <input type="range" id="ballCountSlider" min="1" max="500" value="60" autocomplete="off">
+            <span id="ballCountValue">60</span>
+        </div>
+        <div class="slider-container">
+            <label for="ballSpeedSlider">Ball Speed:</label>
+            <input type="range" id="ballSpeedSlider" min="0" max="10" step="0.25" value="2" autocomplete="off">
+            <span id="ballSpeedValue">2</span>
+        </div>
+        <div class="slider-container">
+            <label for="ballRadiusSlider">Ball Radius:</label>
+            <input type="range" id="ballRadiusSlider" min="1" max="20" value="5" autocomplete="off">
+            <span id="ballRadiusValue">5</span>
+        </div>
+        <div class="slider-container">
+            <label for="explosionRadiusSlider">Explosion Radius:</label>
+            <input type="range" id="explosionRadiusSlider" min="10" max="200" value="60" autocomplete="off">
+            <span id="explosionRadiusValue">60</span>
+        </div>
+        <div class="slider-container">
+            <label for="explosionSpeedSlider">Explosion Speed:</label>
+            <input type="range" id="explosionSpeedSlider" min="0.25" max="4" step="0.25" value="1.0" autocomplete="off">
+            <span id="explosionSpeedValue">1.0</span>
+        </div>
+        <div class="slider-container">
+            <label for="explosionLingerSlider">Explosion Linger Time:</label>
+            <input type="range" id="explosionLingerSlider" min="0" max="4" step="0.1" value="0" autocomplete="off">
+            <span id="explosionLingerValue">0</span>
+        </div>
+        <div class="slider-container">
+            <label for="explosionDragFreqSlider">Explosion Drag Freq:</label>
+            <input type="range" id="explosionDragFreqSlider" min="10" max="1000" value="100" autocomplete="off">
+            <span id="explosionDragFreqValue">10</span>
+        </div>
+        <div id="options">    
+            <div class="stat">
+                <input type="checkbox" class="stat-checkbox" id="autoStartCheckbox">
+                <label for="autoStartCheckbox">Auto Start Reaction</label>
+            </div>
+            <div class="stat">
+                <input type="checkbox" class="stat-checkbox" id="ballAfterExplosionCheckbox" checked>
+                <label for="ballAfterExplosionCheckbox">Ball After Explosion</label>
+            </div>
+        </div>
+        <div id="info">
+            <div class="stat">
+                <input type="checkbox" class="stat-checkbox" id="activeExplosionsCheckbox">
+                <label for="activeExplosionsCheckbox">Active Explosions:</label>
+                <span id="activeExplosions">0</span>
+            </div>
+            <div class="stat">
+                <input type="checkbox" class="stat-checkbox" id="longestChainCheckbox">
+                <label for="longestChainCheckbox">Longest Current Chain:</label>
+                <span id="longestCurrentChain">0</span>
+            </div>
+            <div class="stat">
+                <input type="checkbox" class="stat-checkbox" id="totalExplosionsCheckbox">
+                <label for="totalExplosionsCheckbox">Total Explosions:</label>
+                <span id="totalExplosions">0</span>
+            </div>
+        </div>
+        <div class="button-container">
+            <button id="resetButton">Reset</button>
+            <button id="restoreDefaultsButton">Restore Defaults</button>
+        </div>
+        <div class="slider-container mode-toggle">
+            <label>Mode:</label>
+            <div class="toggle-container">
+                <button class="mode-button active" data-mode="click">Click</button>
+                <button class="mode-button" data-mode="drag">Drag</button>
+            </div>
+        </div>
+        <div class="music-credits">
+            Music by StarStabbedMoon:<br>
+            <a href="mailto:StarStabbedMoon@gmail.com">Email</a> 
+            <a href="https://starstabbedmoon.bandcamp.com">Bandcamp</a><br>
+            <a href="https://www.youtube.com/starstabbedmoon">YouTube</a>
+            <a href="https://open.spotify.com/artist/71cCMapE4464Npz4TnTAT8">Spotify</a> 
+            <a href="https://www.soundclick.com/starstabbedmoon">SoundClick</a>
+        </div>
+    </div>
+
+    <!-- Button to show or hide the UI -->
+    <button id="toggleUIButton">Show Controls</button>
+    <button id="fullscreenButton">Full Screen</button>
+    
+    <audio id="bgMusic" loop>
+        <source src="Celestial Assault.mp3" type="audio/mpeg">
+        Your browser does not support the audio element.
+    </audio>
+
+    <script>
+        /*************************************************************
+         *  GLOBAL VARIABLES & INITIAL SETUP
+         *************************************************************/
+        const canvas = document.getElementById('gameCanvas');
+        const ctx = canvas.getContext('2d');
+
+        // Arrays to hold balls and explosions
+        let balls = [];
+        let expandingCircles = [];
+
+        // Default values for game parameters
+        let maxCircleSize = 60;         // Explosion radius
+        let ballCount = 60;             // Number of balls
+        let ballRadius = 6;             // Radius of each ball
+        let ballSpeed = 2;              // Speed of each ball (base value)
+        let explosionSpeed = 1.0;       // Expansion speed of explosion
+        let explosionLingerTime = 0;    // Seconds to linger after reaching max size
+        let explosionDragFreq = 10;    // Milliseconds between explosions during drag
+        let isDragging = false;
+        let lastDragExplosionTime = 0;
+        let currentDragPosition = { x: 0, y: 0 };
+        let mode = 'drag';
+        let muted = false;
+        let totalExplosions = 0;
+
+        // Track the time of the previous frame for consistent animation
+        let lastFrameTime = 0;
+
+        /*************************************************************
+         *  UI ELEMENTS
+         *************************************************************/
+        // Sliders
+        const ballCountSlider = document.getElementById('ballCountSlider');
+        const ballCountValue = document.getElementById('ballCountValue');
+        const ballSpeedSlider = document.getElementById('ballSpeedSlider');
+        const ballSpeedValue = document.getElementById('ballSpeedValue');
+        const ballRadiusSlider = document.getElementById('ballRadiusSlider');
+        const ballRadiusValue = document.getElementById('ballRadiusValue');
+        const explosionRadiusSlider = document.getElementById('explosionRadiusSlider');
+        const explosionRadiusValue = document.getElementById('explosionRadiusValue');
+        const explosionSpeedSlider = document.getElementById('explosionSpeedSlider');
+        const explosionSpeedValue = document.getElementById('explosionSpeedValue');
+        const explosionLingerSlider = document.getElementById('explosionLingerSlider');
+        const explosionLingerValue = document.getElementById('explosionLingerValue');
+        const explosionDragFreqSlider = document.getElementById('explosionDragFreqSlider');
+        const explosionDragFreqValue = document.getElementById('explosionDragFreqValue');
+        
+        // Stats
+        const activeExplosions = document.getElementById('activeExplosions');
+        const longestCurrentChain = document.getElementById('longestCurrentChain');
+        const totalExplosionsElement = document.getElementById('totalExplosions');
+        
+        // Checkboxes
+        const activeExplosionsCheckbox = document.getElementById('activeExplosionsCheckbox');
+        const longestChainCheckbox = document.getElementById('longestChainCheckbox');
+        const totalExplosionsCheckbox = document.getElementById('totalExplosionsCheckbox');
+        const autoStartCheckbox = document.getElementById('autoStartCheckbox');
+        const ballAfterExplosionCheckbox = document.getElementById('ballAfterExplosionCheckbox');
+        
+        // Other UI elements
+        const resetButton = document.getElementById('resetButton');
+        const restoreDefaultsButton = document.getElementById('restoreDefaultsButton');
+        const toggleUIButton = document.getElementById('toggleUIButton');
+        const fullscreenButton = document.getElementById('fullscreenButton');
+        const bgMusic = document.getElementById('bgMusic');
+        const musicButton = document.getElementById('musicButton');
+        const ui = document.getElementById('ui');
+        
+        /*************************************************************
+         *  CLASSES
+         *************************************************************/
+        class Ball {
+            constructor(x, y, dx, dy, radius, color) {
+                this.x = x;
+                this.y = y;
+                this.dx = dx;
+                this.dy = dy;
+                this.radius = radius;
+                this.color = color;
+            }
+
+            draw() {
+                ctx.beginPath();
+                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
+                ctx.fillStyle = this.color;
+                ctx.fill();
+                ctx.closePath();
+                
+                ctx.beginPath();
+                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
+                ctx.strokeStyle = 'black';
+                ctx.lineWidth = 2;
+                ctx.stroke();
+                ctx.closePath();
+            }
+
+            update(frameFactor) {
+                // Handle boundary collisions
+                if (this.x + this.radius > canvas.width) {
+                    this.x = canvas.width - this.radius;
+                    this.dx = -Math.abs(this.dx);
+                }
+                if (this.x - this.radius < 0) {
+                    this.x = this.radius;
+                    this.dx = Math.abs(this.dx);
+                }
+                if (this.y + this.radius > canvas.height) {
+                    this.y = canvas.height - this.radius;
+                    this.dy = -Math.abs(this.dy);
+                }
+                if (this.y - this.radius < 0) {
+                    this.y = this.radius;
+                    this.dy = Math.abs(this.dy);
+                }
+                
+                // Update position
+                this.x += this.dx * frameFactor;
+                this.y += this.dy * frameFactor;
+                this.draw();
+            }
+        }
+
+        class ExpandingCircle {
+            constructor(x, y, chainReactionCount = 1, isMouseClickExplosion = false, parentIndices = { r: 100, g: 200, b: 300 }) {
+                this.x = x;
+                this.y = y;
+                this.radius = 0;
+                this.growing = true;
+                this.lingerStartTime = null;
+                this.chainReactionCount = chainReactionCount;
+                this.isMouseClickExplosion = isMouseClickExplosion;
+                this.indices = {
+                    r: parentIndices.r + 18,
+                    g: parentIndices.g + 16,
+                    b: parentIndices.b + 14,
+                };
+                this.rgb = this.calculateRGB();
+                totalExplosions++;
+            }
+
+            calculateRGB() {
+                const r = 126 * (Math.sin(0.02 * (this.chainReactionCount + 150) * 15) + 1);
+                const g = 126 * (Math.sin(0.03 * (this.chainReactionCount + 150) * 15) + 1);
+                const b = 126 * (Math.sin(0.01 * (this.chainReactionCount + 150) * 15) + 1);
+                return { r, g, b };
+            }
+
+            draw() {
+                ctx.beginPath();
+                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
+                ctx.fillStyle = `rgba(${this.rgb.r}, ${this.rgb.g}, ${this.rgb.b}, 255)`;
+                ctx.fill();
+                ctx.closePath();
+
+                ctx.beginPath();
+                ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
+                ctx.strokeStyle = 'black';
+                ctx.lineWidth = 4;
+                ctx.stroke();
+                ctx.closePath();
+            }
+
+            update(frameFactor) {
+                if (this.growing) {
+                    this.radius += explosionSpeed * frameFactor;
+                    if (this.radius >= maxCircleSize) {
+                        this.growing = false;
+                        this.lingerStartTime = Date.now();
+                    }
+                }
+                this.draw();
+            }
+
+            isColliding(ball) {
+                const dx = this.x - ball.x;
+                const dy = this.y - ball.y;
+                const distance = Math.sqrt(dx * dx + dy * dy);
+                return distance < this.radius + ball.radius;
+            }
+
+            shouldDisappear() {
+                if (!this.lingerStartTime) return false;
+                const elapsedTime = (Date.now() - this.lingerStartTime) / 1000;
+                return elapsedTime >= explosionLingerTime;
+            }
+        }
+        
+        /*************************************************************
+         *  HELPER FUNCTIONS
+         *************************************************************/
+        function getProportionalBallCount() {
+            const screenArea = window.innerWidth * window.innerHeight;
+            const baseArea = 1920 * 1080; // Reference area for default 60 balls
+            let proportionalBallCount = (screenArea / baseArea) * 350;
+            proportionalBallCount = Math.round(proportionalBallCount / 10) * 10; // Round to nearest 10
+            proportionalBallCount = Math.min(proportionalBallCount, 500); // Clamp to slider max
+            proportionalBallCount = Math.max(proportionalBallCount, 10); // Minimum 10 balls
+            return proportionalBallCount;
+        }
+        
+        function getRandomColor() {
+            const r = Math.floor(Math.random() * 256);
+            const g = Math.floor(Math.random() * 256);
+            const b = Math.floor(Math.random() * 256);
+            return `rgb(${r}, ${g}, ${b})`;
+        }
+        
+        function spawnBall() {
+            const radius = ballRadius;
+            const x = Math.random() * (canvas.width - (2 * radius)) + radius;
+            const y = Math.random() * (canvas.height - (2 * radius)) + radius;
+            const angle = Math.random() * 2 * Math.PI;
+            const dx = Math.cos(angle) * ballSpeed;
+            const dy = Math.sin(angle) * ballSpeed;
+            const color = getRandomColor();
+            balls.push(new Ball(x, y, dx, dy, radius, color));
+        }
+        
+        function createExplosion(x, y, chainReactionCount = 1, isMouseClickExplosion = false) {
+            const initialIndices = {
+                r: 300,
+                g: 600,
+                b: 900,
+            };
+            expandingCircles.push(new ExpandingCircle(
+                x,
+                y,
+                chainReactionCount,
+                isMouseClickExplosion,
+                initialIndices
+            ));
+        }
+
+        /*************************************************************
+         *  SETTINGS MANAGEMENT
+         *************************************************************/
+        function loadSettings() {
+            // Sliders
+            const sliders = [
+                { element: ballCountSlider, key: 'ballCount', defaultValue: getProportionalBallCount() },
+                { element: ballSpeedSlider, key: 'ballSpeed', defaultValue: 2 },
+                { element: ballRadiusSlider, key: 'ballRadius', defaultValue: 6 },
+                { element: explosionRadiusSlider, key: 'explosionRadius', defaultValue: 60 },
+                { element: explosionSpeedSlider, key: 'explosionSpeed', defaultValue: 1.0 },
+                { element: explosionLingerSlider, key: 'explosionLinger', defaultValue: 0 },
+                { element: explosionDragFreqSlider, key: 'explosionDragFreq', defaultValue: 10 }
+            ];
+            
+            sliders.forEach(({ element, key, defaultValue }) => {
+                const savedValue = localStorage.getItem(key);
+                element.value = savedValue != null ? savedValue : defaultValue;
+                element.dispatchEvent(new Event('input'));
+            });
+            
+            // Checkboxes
+            const checkboxes = [
+                { element: autoStartCheckbox, key: 'autoStart', defaultValue: false },
+                { element: ballAfterExplosionCheckbox, key: 'ballAfterExplosion', defaultValue: true },
+                { element: activeExplosionsCheckbox, key: 'activeExplosionsCheckbox', defaultValue: false },
+                { element: longestChainCheckbox, key: 'longestChainCheckbox', defaultValue: false },
+                { element: totalExplosionsCheckbox, key: 'totalExplosionsCheckbox', defaultValue: false }
+            ];
+            
+            checkboxes.forEach(({ element, key, defaultValue }) => {
+                const savedValue = localStorage.getItem(key);
+                element.checked = savedValue != null ? savedValue === 'true' : defaultValue;
+                element.dispatchEvent(new Event('change'));
+            });
+
+            // Mode
+            const savedMode = localStorage.getItem('mode');
+            if (savedMode) {
+                mode = savedMode;
+            }
+            document.querySelectorAll('.mode-button').forEach(btn => {
+                btn.classList.toggle('active', btn.dataset.mode === mode);
+            });
+            
+            // UI Visibility
+            const uiVisible = localStorage.getItem('uiVisible') === 'true';
+            ui.classList.toggle('visible', uiVisible);
+            toggleUIButton.textContent = uiVisible ? 'Hide Controls' : 'Show Controls';
+
+            // Music Mute State
+            muted = localStorage.getItem('muted') === 'true';
+            musicButton.textContent = muted ? '🔇' : '🔊';
+            
+            // Set parameters from UI elements
+            updateGameParameters();
+        }
+
+        function saveSetting(key, value) {
+            localStorage.setItem(key, value);
+        }
+        
+        function updateGameParameters() {
+            maxCircleSize = parseInt(explosionRadiusSlider.value);
+            ballCount = parseInt(ballCountSlider.value);
+            ballRadius = parseInt(ballRadiusSlider.value);
+            ballSpeed = parseFloat(ballSpeedSlider.value);
+            explosionSpeed = parseFloat(explosionSpeedSlider.value);
+            explosionLingerTime = parseFloat(explosionLingerSlider.value);
+            explosionDragFreq = parseInt(explosionDragFreqSlider.value);
+            
+            // Update displayed values
+            ballCountValue.textContent = ballCount;
+            ballSpeedValue.textContent = ballSpeed;
+            ballRadiusValue.textContent = ballRadius;
+            explosionRadiusValue.textContent = maxCircleSize;
+            explosionSpeedValue.textContent = explosionSpeed;
+            explosionLingerValue.textContent = explosionLingerTime;
+            explosionDragFreqValue.textContent = explosionDragFreq;
+        }
+        
+        function restoreDefaultSettings() {
+            // Sliders
+            const sliders = [
+                { element: ballCountSlider, value: getProportionalBallCount() },
+                { element: ballSpeedSlider, value: 2 },
+                { element: ballRadiusSlider, value: 6 },
+                { element: explosionRadiusSlider, value: 60 },
+                { element: explosionSpeedSlider, value: 1.0 },
+                { element: explosionLingerSlider, value: 0 },
+                { element: explosionDragFreqSlider, value: 10 }
+            ];
+            
+            sliders.forEach(({ element, value }) => {
+                element.value = value;
+                element.dispatchEvent(new Event('input'));
+            });
+
+            // Checkboxes
+            const checkboxes = [
+                { element: autoStartCheckbox, value: false },
+                { element: ballAfterExplosionCheckbox, value: true },
+                { element: activeExplosionsCheckbox, value: false },
+                { element: longestChainCheckbox, value: false },
+                { element: totalExplosionsCheckbox, value: false }
+            ];
+            
+            checkboxes.forEach(({ element, value }) => {
+                element.checked = value;
+                element.dispatchEvent(new Event('change'));
+            });
+
+            // Mode
+            mode = 'drag';
+            document.querySelectorAll('.mode-button').forEach(btn => {
+                btn.classList.toggle('active', btn.dataset.mode === 'drag');
+            });
+            saveSetting('mode', 'drag');
+
+            resetGame();
+        }
+
+        /*************************************************************
+         *  GAME MANAGEMENT FUNCTIONS
+         *************************************************************/
+        function resetBalls() {
+            balls = [];
+            for (let i = 0; i < ballCount; i++) {
+                spawnBall();
+            }
+        }
+
+        function updateBallSpeeds() {
+            balls.forEach(ball => {
+                const speedCurrent = Math.sqrt(ball.dx * ball.dx + ball.dy * ball.dy);
+                if (speedCurrent === 0) {
+                    // If speed was zero but now set to non-zero, give random direction
+                    if (ballSpeed === 0) return;
+                    const angle = Math.random() * 2 * Math.PI;
+                    ball.dx = Math.cos(angle) * ballSpeed;
+                    ball.dy = Math.sin(angle) * ballSpeed;
+                } else {
+                    const scale = ballSpeed / speedCurrent; 
+                    ball.dx *= scale;
+                    ball.dy *= scale;
+                }
+            });
+        }
+
+        function resetGame() {
+            expandingCircles = [];
+            totalExplosions = 0;
+            totalExplosionsElement.textContent = '0';
+            longestCurrentChain.textContent = '0';
+            resetBalls();
+        }
+
+        function resizeCanvas() {
+            canvas.width = window.innerWidth;
+            canvas.height = window.innerHeight;
+            
+            // relocate all balls to be within the screen bounds
+            balls.forEach(ball => {
+                if(ball.x-ball.radius < 0) {
+                    ball.x = Math.min(ball.radius, canvas.width);
+                }
+                if(ball.y-ball.radius < 0) {
+                    ball.y = Math.min(ball.radius, canvas.height);
+                }
+                if(ball.x+ball.radius >= canvas.width) {
+                    ball.x = Math.max(canvas.width - ball.radius, 0);
+                }
+                if(ball.y+ball.radius >= canvas.height) {
+                    ball.y = Math.max(canvas.height - ball.radius, 0);
+                }
+            });
+        }
+
+        function toggleFullScreen() {
+            if (!document.fullscreenElement) {
+                if (canvas.requestFullscreen) {
+                    canvas.requestFullscreen();
+                } else if (canvas.webkitRequestFullscreen) {
+                    canvas.webkitRequestFullscreen();
+                } else if (canvas.msRequestFullscreen) {
+                    canvas.msRequestFullscreen();
+                }
+                fullscreenButton.textContent = 'Exit Full Screen';
+            } else {
+                if (document.exitFullscreen) {
+                    document.exitFullscreen();
+                } else if (document.webkitExitFullscreen) {
+                    document.webkitExitFullscreen();
+                } else if (document.msExitFullscreen) {
+                    document.msExitFullscreen();
+                }
+                fullscreenButton.textContent = 'Full Screen';
+            }
+        }
+        
+        /*************************************************************
+         *  INTERACTION FUNCTIONS
+         *************************************************************/
+        function handleFirstClick(event) {
+            if (event.target === musicButton) {
+                return;
+            }
+            
+            if (!muted) {
+                bgMusic.play();
+            }
+            
+            canvas.removeEventListener('click', handleFirstClick);
+            canvas.removeEventListener('touchstart', handleFirstClick);
+        }
+        
+        function startDrag(event) {
+            if (mode !== 'drag') return;
+            isDragging = true;
+            updateDragPosition(event);
+            triggerDragExplosion();  // Trigger immediately on click
+        }
+
+        function handleDrag(event) {
+            if (mode !== 'drag' || !isDragging) return;
+            updateDragPosition(event);
+            
+            const now = Date.now();
+            if (now - lastDragExplosionTime >= explosionDragFreq) {
+                triggerDragExplosion();
+                lastDragExplosionTime = now;
+            }
+        }
+
+        function endDrag() {
+            isDragging = false;
+        }
+
+        function updateDragPosition(event) {
+            const rect = canvas.getBoundingClientRect();
+            const scaleX = canvas.width / rect.width;
+            const scaleY = canvas.height / rect.height;
+            currentDragPosition.x = (event.clientX - rect.left) * scaleX;
+            currentDragPosition.y = (event.clientY - rect.top) * scaleY;
+        }
+
+        function triggerDragExplosion() {
+            createExplosion(currentDragPosition.x, currentDragPosition.y, 1, true);
+        }
+        
+        function handleTouchStart(event) {
+            event.preventDefault();
+            const touches = event.touches;
+            for (let i = 0; i < touches.length; i++) {
+                const touch = touches[i];
+                const rect = canvas.getBoundingClientRect();
+                const scaleX = canvas.width / rect.width;
+                const scaleY = canvas.height / rect.height;
+                const x = (touch.clientX - rect.left) * scaleX;
+                const y = (touch.clientY - rect.top) * scaleY;
+
+                createExplosion(x, y, 1, true);
+            }
+        }
+
+        function handleTouchMove(event) {
+            event.preventDefault();
+            if (mode !== 'drag') return;
+
+            const touches = event.touches;
+            for (let i = 0; i < touches.length; i++) {
+                const touch = touches[i];
+                const rect = canvas.getBoundingClientRect();
+                const scaleX = canvas.width / rect.width;
+                const scaleY = canvas.height / rect.height;
+                const x = (touch.clientX - rect.left) * scaleX;
+                const y = (touch.clientY - rect.top) * scaleY;
+
+                createExplosion(x, y, 1, true);
+            }
+        }
+
+        function handleTouchEnd() {
+            // Placeholder for future touch end handling
+        }
+        
+        /*************************************************************
+         *  GAME LOOP FUNCTIONS
+         *************************************************************/
+        function updateGame(frameFactor) {
+            // Update all balls
+            balls.forEach(ball => {
+                ball.update(frameFactor);
+            });
+            
+            // Auto-start reaction check
+            if (autoStartCheckbox.checked && expandingCircles.length === 0) {
+                const x = Math.random() * canvas.width;
+                const y = Math.random() * canvas.height;
+                createExplosion(x, y, 1, true);
+            }
+
+            const explosionsToRemove = [];
+            let longestCurrentChainCount = 0;
+
+            expandingCircles.forEach((circle, circleIndex) => {
+                circle.update(frameFactor);
+
+                // Check for collision with balls
+                balls.forEach((ball, ballIndex) => {
+                    if (circle.isColliding(ball)) {
+                        // Create new explosion at ball position
+                        const newIndices = {
+                            r: circle.indices.r + 9,
+                            g: circle.indices.g + 8,
+                            b: circle.indices.b + 7,
+                        };
+                        expandingCircles.push(
+                            new ExpandingCircle(
+                                ball.x,
+                                ball.y,
+                                circle.chainReactionCount + 1,
+                                false,
+                                newIndices
+                            )
+                        );
+                        // Remove the ball
+                        balls.splice(ballIndex, 1);
+                    }
+                });
+
+                // Track longest chain
+                if (circle.chainReactionCount > longestCurrentChainCount) {
+                    longestCurrentChainCount = circle.chainReactionCount;
+                }
+
+                // Check if explosion should be removed
+                if (!circle.growing && circle.shouldDisappear()) {
+                    explosionsToRemove.push(circleIndex);
+                }
+            });
+
+            // Remove finished explosions and spawn new balls if needed
+            for (let i = explosionsToRemove.length - 1; i >= 0; i--) {
+                const circleIndex = explosionsToRemove[i];
+                const circle = expandingCircles[circleIndex];
+                if (!circle.isMouseClickExplosion && ballAfterExplosionCheckbox.checked) {
+                    spawnBall();
+                }
+                expandingCircles.splice(circleIndex, 1);
+            }
+            
+            // Update UI stats
+            totalExplosionsElement.textContent = totalExplosions;
+            activeExplosions.textContent = expandingCircles.length;
+            longestCurrentChain.textContent = longestCurrentChainCount;
+        }
+
+        function renderGame() {
+            // Clear canvas
+            ctx.clearRect(0, 0, canvas.width, canvas.height);
+            
+            // Draw balls and explosions
+            balls.forEach(ball => ball.draw());
+            expandingCircles.forEach(circle => circle.draw());
+            
+            // Draw stats on canvas if checkboxes are checked
+            ctx.fillStyle = 'white';
+            ctx.font = '16px Arial';
+            const padding = 84;
+            let yPos = 24;
+
+            if (activeExplosionsCheckbox.checked) {
+                ctx.fillText(`Active Explosions: ${activeExplosions.textContent}`, padding, yPos);
+                yPos += 24;
+            }
+            if (longestChainCheckbox.checked) {
+                ctx.fillText(`Longest Current Chain: ${longestCurrentChain.textContent}`, padding, yPos);
+                yPos += 24;
+            }
+            if (totalExplosionsCheckbox.checked) {
+                ctx.fillText(`Total Explosions: ${totalExplosions}`, padding, yPos);
+            }
+        }
+
+        function animate(timestamp) {
+            requestAnimationFrame(animate);
+
+            if (!lastFrameTime) {
+                lastFrameTime = timestamp;
+            }
+
+            const dt = timestamp - lastFrameTime;
+            lastFrameTime = timestamp;
+            const frameFactor = dt / (1000 / 60); // Normalize to 60fps
+
+            updateGame(frameFactor);
+            renderGame();
+        }
+
+        /*************************************************************
+         *  EVENT LISTENERS
+         *************************************************************/
+        function setupEventListeners() {
+            // Slider event listeners
+            ballCountSlider.addEventListener('input', () => {
+                ballCount = parseInt(ballCountSlider.value);
+                ballCountValue.textContent = ballCount;
+                saveSetting('ballCount', ballCount);
+                resetGame();
+            });
+
+            ballSpeedSlider.addEventListener('input', () => {
+                ballSpeed = parseFloat(ballSpeedSlider.value);
+                ballSpeedValue.textContent = ballSpeed;
+                saveSetting('ballSpeed', ballSpeed);
+                updateBallSpeeds();
+            });
+
+            ballRadiusSlider.addEventListener('input', () => {
+                ballRadius = parseInt(ballRadiusSlider.value);
+                ballRadiusValue.textContent = ballRadius;
+                saveSetting('ballRadius', ballRadius);
+                resetBalls();
+            });
+
+            explosionRadiusSlider.addEventListener('input', () => {
+                maxCircleSize = parseInt(explosionRadiusSlider.value);
+                explosionRadiusValue.textContent = maxCircleSize;
+                saveSetting('explosionRadius', maxCircleSize);
+            });
+
+            explosionSpeedSlider.addEventListener('input', () => {
+                explosionSpeed = parseFloat(explosionSpeedSlider.value);
+                explosionSpeedValue.textContent = explosionSpeed.toFixed(2);
+                saveSetting('explosionSpeed', explosionSpeed);
+            });
+
+            explosionLingerSlider.addEventListener('input', () => {
+                explosionLingerTime = parseFloat(explosionLingerSlider.value);
+                explosionLingerValue.textContent = explosionLingerTime;
+                saveSetting('explosionLinger', explosionLingerTime);
+            });
+            
+            explosionDragFreqSlider.addEventListener('input', () => {
+                explosionDragFreq = parseInt(explosionDragFreqSlider.value);
+                explosionDragFreqValue.textContent = explosionDragFreq;
+                saveSetting('explosionDragFreq', explosionDragFreq);
+            });
+            
+            // Checkbox event listeners
+            autoStartCheckbox.addEventListener('change', () => {
+                saveSetting('autoStart', autoStartCheckbox.checked);
+            });
+            
+            ballAfterExplosionCheckbox.addEventListener('change', () => {
+                saveSetting('ballAfterExplosion', ballAfterExplosionCheckbox.checked);
+            });
+            
+            activeExplosionsCheckbox.addEventListener('change', function() {
+                saveSetting('activeExplosionsCheckbox', this.checked);
+            });
+            
+            longestChainCheckbox.addEventListener('change', function() {
+                saveSetting('longestChainCheckbox', this.checked);
+            });
+            
+            totalExplosionsCheckbox.addEventListener('change', function() {
+                saveSetting('totalExplosionsCheckbox', this.checked);
+            });
+            
+            // Button event listeners
+            resetButton.addEventListener('click', resetGame);
+            restoreDefaultsButton.addEventListener('click', restoreDefaultSettings);
+            toggleUIButton.addEventListener('click', () => {
+                ui.classList.toggle('visible');
+                saveSetting('uiVisible', ui.classList.contains('visible'));
+                toggleUIButton.textContent = ui.classList.contains('visible') ? 'Hide Controls' : 'Show Controls';
+            });
+            fullscreenButton.addEventListener('click', toggleFullScreen);
+            
+            // Mode button event listeners
+            document.querySelectorAll('.mode-button').forEach(button => {
+                button.addEventListener('click', function() {
+                    // Remove active class from all buttons
+                    document.querySelectorAll('.mode-button').forEach(b => b.classList.remove('active'));
+                    // Add active class to clicked button
+                    this.classList.add('active');
+                    // Update mode
+                    mode = this.dataset.mode;
+                    saveSetting('mode', mode);
+                    endDrag(); // Cancel any ongoing drag operations
+                });
+            });
+            
+            // Music button event listener
+            musicButton.addEventListener('click', () => {
+                muted = !muted;
+                saveSetting('muted', muted);
+                if (!muted) {
+                    bgMusic.play();
+                    musicButton.textContent = '🔊';
+                } else {
+                    bgMusic.pause();
+                    musicButton.textContent = '🔇';
+                }
+            });
+            
+            // Canvas event listeners
+            canvas.addEventListener('click', (event) => {
+                if (mode !== 'click') return;
+                
+                const rect = canvas.getBoundingClientRect();
+                const scaleX = canvas.width / rect.width;
+                const scaleY = canvas.height / rect.height;
+                const x = (event.clientX - rect.left) * scaleX;
+                const y = (event.clientY - rect.top) * scaleY;
+
+                if (y < canvas.height) {
+                    createExplosion(x, y, 1, true);
+                }
+            });
+            
+            canvas.addEventListener('mousedown', startDrag);
+            canvas.addEventListener('mousemove', handleDrag);
+            canvas.addEventListener('mouseup', endDrag);
+            canvas.addEventListener('mouseleave', endDrag);
+            
+            // Touch event listeners
+            canvas.addEventListener('touchstart', handleTouchStart);
+            canvas.addEventListener('touchmove', handleTouchMove);
+            canvas.addEventListener('touchend', handleTouchEnd);
+            canvas.addEventListener('touchcancel', handleTouchEnd);
+            
+            // Handle touch events on the document body
+            document.body.addEventListener('touchstart', function(event) {
+                if (event.target === canvas) {
+                    event.preventDefault();
+                }
+            }, { passive: false });
+
+            document.body.addEventListener('touchmove', function(event) {
+                if (event.target === canvas) {
+                    event.preventDefault();
+                }
+            }, { passive: false });
+            
+            // Fullscreen change event listener
+            document.addEventListener('fullscreenchange', () => {
+                if (!document.fullscreenElement) {
+                    fullscreenButton.textContent = 'Full Screen';
+                }
+            });
+            
+            // Resize event listener
+            window.addEventListener('resize', resizeCanvas);
+            
+            // First interaction handlers for audio
+            canvas.addEventListener('click', handleFirstClick);
+            canvas.addEventListener('touchstart', handleFirstClick);
+        }
+        
+        /*************************************************************
+         *  INITIALIZATION AND STARTUP
+         *************************************************************/
+        function init() {
+            loadSettings();
+            setupEventListeners();
+            resetGame();
+        }
+
+        // Start the application
+        resizeCanvas();
+        init();
+        requestAnimationFrame(animate);
+    </script>
+</body>
+</html>