diff --git a/icons/icon-128x128.png b/icons/icon-128x128.png new file mode 100644 index 0000000..77de64d Binary files /dev/null and b/icons/icon-128x128.png differ diff --git a/icons/icon-144x144.png b/icons/icon-144x144.png new file mode 100644 index 0000000..e18d43f Binary files /dev/null and b/icons/icon-144x144.png differ diff --git a/icons/icon-152x152.png b/icons/icon-152x152.png new file mode 100644 index 0000000..9025ac9 Binary files /dev/null and b/icons/icon-152x152.png differ diff --git a/icons/icon-192x192.png b/icons/icon-192x192.png new file mode 100644 index 0000000..d46f62d Binary files /dev/null and b/icons/icon-192x192.png differ diff --git a/icons/icon-384x384.png b/icons/icon-384x384.png new file mode 100644 index 0000000..a1f0412 Binary files /dev/null and b/icons/icon-384x384.png differ diff --git a/icons/icon-512x512.png b/icons/icon-512x512.png new file mode 100644 index 0000000..feb5436 Binary files /dev/null and b/icons/icon-512x512.png differ diff --git a/icons/icon-72x72.png b/icons/icon-72x72.png new file mode 100644 index 0000000..58fccc8 Binary files /dev/null and b/icons/icon-72x72.png differ diff --git a/icons/icon-96x96.png b/icons/icon-96x96.png new file mode 100644 index 0000000..377f9c5 Binary files /dev/null and b/icons/icon-96x96.png differ diff --git a/index.html b/index.html index 1edf5d8..3759652 100644 --- a/index.html +++ b/index.html @@ -1,206 +1,214 @@ - - - - - - FunWebGames - Play & Learn! - - - - - - - - - - - - - - - - - -
- - -
🎨
-
🔵
-

Color Match

-
- - - -
🧩
-
🐱
-

Animal Puzzle

-
- - - -
🫧
-
🔢
-

Bubble Pop

-
- - - -
🔷
-
🏠
-

Shape Builder

-
- - - -
🌸
-
🦋
-

Counting Garden

-
- - - -
🔤
-
🅰️
-

Letter Explorer

-
- - - -
🎵
-
🎹
-

Music Maker

-
- - - -
🗺️
-
🐰
-

Maze Runner

-
- - - -
-
🌙
-

Star Catcher

-
- - - -
👗
-
🎀
-

Dress Up

-
-
- - - - - - - - + + + + + + FunWebGames - Play & Learn! + + + + + + + + + + + + + + + + + +
+ + +
🎨
+
🔵
+

Color Match

+
+ + + +
🧩
+
🐱
+

Animal Puzzle

+
+ + + +
🫧
+
🔢
+

Bubble Pop

+
+ + + +
🔷
+
🏠
+

Shape Builder

+
+ + + +
🌸
+
🦋
+

Counting Garden

+
+ + + +
🔤
+
🅰️
+

Letter Explorer

+
+ + + +
🎵
+
🎹
+

Music Maker

+
+ + + +
🗺️
+
🐰
+

Maze Runner

+
+ + + +
+
🌙
+

Star Catcher

+
+ + + +
👗
+
🎀
+

Dress Up

+
+
+ + + + + + + + + + diff --git a/js/sound-toggle.js b/js/sound-toggle.js index fedcf72..7a279ed 100644 --- a/js/sound-toggle.js +++ b/js/sound-toggle.js @@ -1,171 +1,172 @@ -/** - * Sound Toggle System for FunWebGames - * Global mute/unmute control that persists across all games - * - * Usage: - * SoundToggle.init(); // Call once on page load - * SoundToggle.isMuted(); // Check if muted - * SoundToggle.toggle(); // Toggle mute state - * SoundToggle.setMuted(true); // Set mute state - * - * In game sound functions: - * if (SoundToggle.isMuted()) return; - * // ... play sound - */ - -const SoundToggle = (function() { - const STORAGE_KEY = 'funwebgames-sound-muted'; - let isMutedState = false; - let toggleButton = null; - - // Initialize sound toggle - function init() { - // Load saved preference - try { - isMutedState = localStorage.getItem(STORAGE_KEY) === 'true'; - } catch (e) { - isMutedState = false; - } - - // Check for user preference for reduced motion/sound - const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; - if (prefersReducedMotion) { - isMutedState = true; - } - - // Create toggle button - createToggleButton(); - - // Update all audio contexts - updateAllAudio(); - - return isMutedState; - } - - // Create toggle button in DOM - function createToggleButton() { - toggleButton = document.createElement('button'); - toggleButton.className = 'sound-toggle-btn'; - toggleButton.setAttribute('aria-label', isMutedState ? 'Unmute sound' : 'Mute sound'); - toggleButton.setAttribute('title', isMutedState ? 'Unmute' : 'Mute'); - toggleButton.innerHTML = isMutedState ? '🔇' : '🔊'; - - toggleButton.addEventListener('click', toggle); - - // Add to page (typically in header) - const header = document.querySelector('.game-header'); - if (header) { - const existingBtn = header.querySelector('.sound-toggle-btn'); - if (existingBtn) { - existingBtn.remove(); - } - // Insert after help button if exists, otherwise at end - const helpBtn = header.querySelector('.help-btn'); - if (helpBtn && helpBtn.nextSibling) { - header.insertBefore(toggleButton, helpBtn.nextSibling); - } else { - header.appendChild(toggleButton); - } - } - } - - // Toggle mute state - function toggle() { - isMutedState = !isMutedState; - savePreference(); - updateButton(); - updateAllAudio(); - - // Play feedback sound if unmuting - if (!isMutedState) { - playFeedbackSound(); - } - } - - // Set mute state - function setMuted(muted) { - isMutedState = muted; - savePreference(); - updateButton(); - updateAllAudio(); - } - - // Check if muted - function isMuted() { - return isMutedState; - } - - // Save preference to localStorage - function savePreference() { - try { - localStorage.setItem(STORAGE_KEY, isMutedState.toString()); - } catch (e) { - // localStorage not available, continue silently - } - } - - // Update button appearance - function updateButton() { - if (!toggleButton) return; - - toggleButton.innerHTML = isMutedState ? '🔇' : '🔊'; - toggleButton.setAttribute('aria-label', isMutedState ? 'Unmute sound' : 'Mute sound'); - toggleButton.setAttribute('title', isMutedState ? 'Unmute' : 'Mute'); - - if (isMutedState) { - toggleButton.classList.add('muted'); - } else { - toggleButton.classList.remove('muted'); - } - } - - // Update all audio contexts (suspend/resume) - function updateAllAudio() { - // This will be called by individual games to check mute state - // before playing sounds - dispatchChangeEvent(); - } - - // Dispatch custom event for games to listen to - function dispatchChangeEvent() { - const event = new CustomEvent('soundtoggle-change', { - detail: { muted: isMutedState } - }); - document.dispatchEvent(event); - } - - // Play feedback sound (always plays, even when muted) - function playFeedbackSound() { - try { - const audioContext = new (window.AudioContext || window.webkitAudioContext)(); - const oscillator = audioContext.createOscillator(); - const gainNode = audioContext.createGain(); - - oscillator.connect(gainNode); - gainNode.connect(audioContext.destination); - - oscillator.frequency.value = 800; - oscillator.type = 'sine'; - gainNode.gain.setValueAtTime(0.1, audioContext.currentTime); - gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1); - - oscillator.start(audioContext.currentTime); - oscillator.stop(audioContext.currentTime + 0.1); - } catch (e) { - // Audio not supported - } - } - - // Public API - return { - init, - toggle, - setMuted, - isMuted - }; -})(); - -// Export for use in other files -if (typeof module !== 'undefined' && module.exports) { - module.exports = SoundToggle; -} +/** + * Sound Toggle System for FunWebGames + * Global mute/unmute control that persists across all games + * + * Usage: + * SoundToggle.init(); // Call once on page load + * SoundToggle.isMuted(); // Check if muted + * SoundToggle.toggle(); // Toggle mute state + * SoundToggle.setMuted(true); // Set mute state + * + * In game sound functions: + * if (SoundToggle.isMuted()) return; + * // ... play sound + */ + +const SoundToggle = (function() { + const STORAGE_KEY = 'funwebgames-sound-muted'; + let isMutedState = false; + let toggleButton = null; + + // Initialize sound toggle + function init() { + // Load saved preference + try { + isMutedState = localStorage.getItem(STORAGE_KEY) === 'true'; + } catch (e) { + isMutedState = false; + } + + // Check for user preference for reduced motion/sound + const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; + if (prefersReducedMotion) { + isMutedState = true; + } + + // Create toggle button + createToggleButton(); + + // Update all audio contexts + updateAllAudio(); + + return isMutedState; + } + + // Create toggle button in DOM + function createToggleButton() { + toggleButton = document.createElement('button'); + toggleButton.className = 'sound-toggle-btn'; + toggleButton.setAttribute('aria-label', isMutedState ? 'Unmute sound' : 'Mute sound'); + toggleButton.setAttribute('title', isMutedState ? 'Unmute' : 'Mute'); + toggleButton.textContent = isMutedState ? '🔇' : '🔊'; + + toggleButton.addEventListener('click', toggle); + + // Add to page (typically in header) + // Check for game-header first (individual games), then page-header (landing page) + const header = document.querySelector('.game-header') || document.querySelector('.page-header'); + if (header) { + const existingBtn = header.querySelector('.sound-toggle-btn'); + if (existingBtn) { + existingBtn.remove(); + } + // Insert after help button if exists, otherwise at end + const helpBtn = header.querySelector('.help-btn'); + if (helpBtn && helpBtn.nextSibling) { + header.insertBefore(toggleButton, helpBtn.nextSibling); + } else { + header.appendChild(toggleButton); + } + } + } + + // Toggle mute state + function toggle() { + isMutedState = !isMutedState; + savePreference(); + updateButton(); + updateAllAudio(); + + // Play feedback sound if unmuting + if (!isMutedState) { + playFeedbackSound(); + } + } + + // Set mute state + function setMuted(muted) { + isMutedState = muted; + savePreference(); + updateButton(); + updateAllAudio(); + } + + // Check if muted + function isMuted() { + return isMutedState; + } + + // Save preference to localStorage + function savePreference() { + try { + localStorage.setItem(STORAGE_KEY, isMutedState.toString()); + } catch (e) { + // localStorage not available, continue silently + } + } + + // Update button appearance + function updateButton() { + if (!toggleButton) return; + + toggleButton.textContent = isMutedState ? '🔇' : '🔊'; + toggleButton.setAttribute('aria-label', isMutedState ? 'Unmute sound' : 'Mute sound'); + toggleButton.setAttribute('title', isMutedState ? 'Unmute' : 'Mute'); + + if (isMutedState) { + toggleButton.classList.add('muted'); + } else { + toggleButton.classList.remove('muted'); + } + } + + // Update all audio contexts (suspend/resume) + function updateAllAudio() { + // This will be called by individual games to check mute state + // before playing sounds + dispatchChangeEvent(); + } + + // Dispatch custom event for games to listen to + function dispatchChangeEvent() { + const event = new CustomEvent('soundtoggle-change', { + detail: { muted: isMutedState } + }); + document.dispatchEvent(event); + } + + // Play feedback sound (always plays, even when muted) + function playFeedbackSound() { + try { + const audioContext = new (window.AudioContext || window.webkitAudioContext)(); + const oscillator = audioContext.createOscillator(); + const gainNode = audioContext.createGain(); + + oscillator.connect(gainNode); + gainNode.connect(audioContext.destination); + + oscillator.frequency.value = 800; + oscillator.type = 'sine'; + gainNode.gain.setValueAtTime(0.1, audioContext.currentTime); + gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1); + + oscillator.start(audioContext.currentTime); + oscillator.stop(audioContext.currentTime + 0.1); + } catch (e) { + // Audio not supported + } + } + + // Public API + return { + init, + toggle, + setMuted, + isMuted + }; +})(); + +// Export for use in other files +if (typeof module !== 'undefined' && module.exports) { + module.exports = SoundToggle; +}