diff --git a/app.js b/app.js index 3534984..9135074 100644 --- a/app.js +++ b/app.js @@ -37,6 +37,78 @@ document.addEventListener('DOMContentLoaded', function () { const widescreenBgs = document.getElementById('check-widescreen-bgs'); const outroFmv = document.getElementById('check-outro'); const badEnding = document.getElementById('check-ending'); + const logo = document.getElementById('island-logo-img'); + + // --- Debug Mode Activation (5 taps on logo) --- + let debugTapCount = 0; + let debugTapTimeout = null; + let debugEnabled = false; + + // Pizza celebration animation for OGEL mode + function celebratePizza(originElement) { + const rect = originElement.getBoundingClientRect(); + const centerX = rect.left + rect.width / 2; + const centerY = rect.top + rect.height / 2; + const sliceCount = 12; + + for (let i = 0; i < sliceCount; i++) { + const slice = document.createElement('div'); + slice.className = 'pizza-slice'; + slice.textContent = '🍕'; + + // Calculate direction for this slice + const angle = (i / sliceCount) * Math.PI * 2; + const distance = 150 + Math.random() * 100; + const tx = Math.cos(angle) * distance; + const ty = Math.sin(angle) * distance; + const rotation = (Math.random() - 0.5) * 720; + + slice.style.left = centerX + 'px'; + slice.style.top = centerY + 'px'; + slice.style.setProperty('--tx', tx + 'px'); + slice.style.setProperty('--ty', ty + 'px'); + slice.style.setProperty('--rot', rotation + 'deg'); + slice.style.animationDelay = (Math.random() * 0.2) + 's'; + + document.body.appendChild(slice); + + // Remove after animation completes + setTimeout(function() { + slice.remove(); + }, 1700); + } + } + + logo.addEventListener('click', function() { + if (debugEnabled) { + // Replay pizza animation on subsequent clicks + celebratePizza(logo); + return; + } + + debugTapCount++; + clearTimeout(debugTapTimeout); + + if (debugTapCount >= 5) { + // Enable debug mode + debugEnabled = true; + logo.src = 'ogel.webp'; + logo.alt = 'OGEL Mode Enabled'; + + // Celebrate with pizza! + celebratePizza(logo); + + // Dynamically load debug.js + const script = document.createElement('script'); + script.src = 'debug.js'; + document.body.appendChild(script); + } else { + // Reset tap count after 1 second of no taps + debugTapTimeout = setTimeout(function() { + debugTapCount = 0; + }, 1000); + } + }); // --- Sound Toggle --- function updateSoundEmojiState() { @@ -96,11 +168,24 @@ document.addEventListener('DOMContentLoaded', function () { }); let progressUpdates = 0; + const debugUI = document.getElementById('debug-ui'); + let debugUIVisible = false; + + // MutationObserver to prevent Emscripten from hiding the debug UI + const debugUIObserver = new MutationObserver(function(mutations) { + if (debugUIVisible && debugUI.style.display === 'none') { + debugUI.style.setProperty('display', 'block', 'important'); + } + }); + debugUIObserver.observe(debugUI, { attributes: true, attributeFilter: ['style'] }); + emscriptenCanvas.addEventListener('presenterProgress', function (event) { // Intro animation is ready if (event.detail.objectName == 'Lego_Smk' && event.detail.tickleState == 1) { loadingGifOverlay.style.display = 'none'; emscriptenCanvas.style.setProperty('display', 'block', 'important'); + debugUIVisible = true; + debugUI.style.setProperty('display', 'block', 'important'); } else if (progressUpdates < 1003) { progressUpdates++; diff --git a/debug.html b/debug.html new file mode 100644 index 0000000..0f5c100 --- /dev/null +++ b/debug.html @@ -0,0 +1,533 @@ + +
+
Debug Options
+
+
General
+ + + + +
+
+
Debug Mode (OGEL)
+ + + + +
+
+
Camera/View
+ + +
+
+
LOD (Level of Detail)
+ + + +
+
+
Misc
+ +
+
+
Switch Act
+ + + + +
+
+
Locations
+ + +
+
+
Animations
+ + + +
+
diff --git a/debug.js b/debug.js new file mode 100644 index 0000000..0cb3b37 --- /dev/null +++ b/debug.js @@ -0,0 +1,214 @@ +(async function() { + const debugUI = document.getElementById('debug-ui'); + const canvas = document.getElementById('canvas'); + + // Fetch and inject debug panel HTML + try { + const response = await fetch('debug.html'); + const html = await response.text(); + debugUI.innerHTML = html; + } catch (error) { + console.error('Failed to load debug panel:', error); + return; + } + + // Now get references to elements after they've been injected + const debugToggle = document.getElementById('debug-toggle'); + const debugPanel = document.getElementById('debug-panel'); + const debugPasswordBtn = document.querySelector('.debug-password'); + const requiresDebugBtns = document.querySelectorAll('.requires-debug'); + + let debugModeActive = false; + + // Key code mapping for special keys + const keyCodeMap = { + 'Pause': { key: 'Pause', code: 'Pause', keyCode: 19 }, + 'Escape': { key: 'Escape', code: 'Escape', keyCode: 27 }, + ' ': { key: ' ', code: 'Space', keyCode: 32 }, + 'Tab': { key: 'Tab', code: 'Tab', keyCode: 9 }, + 'F11': { key: 'F11', code: 'F11', keyCode: 122 }, + 'F12': { key: 'F12', code: 'F12', keyCode: 123 }, + '+': { key: '+', code: 'NumpadAdd', keyCode: 107 }, + '-kp': { key: '-', code: 'NumpadSubtract', keyCode: 109 }, + '*': { key: '*', code: 'NumpadMultiply', keyCode: 106 }, + '/': { key: '/', code: 'NumpadDivide', keyCode: 111 }, + // Digit keys + '0': { key: '0', code: 'Digit0', keyCode: 48 }, + '1': { key: '1', code: 'Digit1', keyCode: 49 }, + '2': { key: '2', code: 'Digit2', keyCode: 50 }, + '3': { key: '3', code: 'Digit3', keyCode: 51 }, + '4': { key: '4', code: 'Digit4', keyCode: 52 }, + '5': { key: '5', code: 'Digit5', keyCode: 53 }, + '6': { key: '6', code: 'Digit6', keyCode: 54 }, + '7': { key: '7', code: 'Digit7', keyCode: 55 }, + '8': { key: '8', code: 'Digit8', keyCode: 56 }, + '9': { key: '9', code: 'Digit9', keyCode: 57 }, + }; + + // Toggle debug panel + debugToggle.addEventListener('click', function(e) { + e.stopPropagation(); + debugPanel.classList.toggle('open'); + debugToggle.classList.toggle('active'); + }); + + // Dispatch a keyboard event to the canvas + function sendKey(key) { + let keyInfo = keyCodeMap[key]; + + if (!keyInfo) { + // Regular character key (letters) + const char = key.toLowerCase(); + const charCode = char.charCodeAt(0); + keyInfo = { + key: char, + code: 'Key' + char.toUpperCase(), + keyCode: charCode >= 97 && charCode <= 122 ? charCode - 32 : charCode + }; + } + + const eventInit = { + key: keyInfo.key, + code: keyInfo.code, + keyCode: keyInfo.keyCode, + which: keyInfo.keyCode, + bubbles: true, + cancelable: true + }; + + canvas.dispatchEvent(new KeyboardEvent('keydown', eventInit)); + canvas.dispatchEvent(new KeyboardEvent('keyup', eventInit)); + } + + // Send a sequence of keys with delay (longer delay for multi-stage commands) + function sendKeySequence(keys, delay = 100) { + let index = 0; + function sendNext() { + if (index < keys.length) { + sendKey(keys[index]); + index++; + setTimeout(sendNext, delay); + } else { + canvas.focus(); + } + } + sendNext(); + } + + // Update button states based on debug mode + function updateDebugModeUI() { + if (debugModeActive) { + debugPasswordBtn.classList.add('active'); + debugPasswordBtn.textContent = 'Debug Mode Active'; + requiresDebugBtns.forEach(btn => btn.classList.add('enabled')); + } else { + debugPasswordBtn.classList.remove('active'); + debugPasswordBtn.textContent = 'Enter Debug Mode'; + requiresDebugBtns.forEach(btn => btn.classList.remove('enabled')); + } + } + + // Handle button clicks + debugPanel.addEventListener('click', function(e) { + const btn = e.target.closest('button'); + if (!btn || btn === debugToggle) return; + + const keys = btn.dataset.keys; + if (!keys) return; + + e.preventDefault(); + e.stopPropagation(); + + // Handle special cases + if (keys === 'ogel') { + // Enter debug password + sendKeySequence(['o', 'g', 'e', 'l']); + debugModeActive = true; + updateDebugModeUI(); + return; + } + + // For requires-debug buttons, ensure debug mode is active + if (btn.classList.contains('requires-debug') && !debugModeActive) { + // Auto-enter debug mode first + sendKeySequence(['o', 'g', 'e', 'l']); + debugModeActive = true; + updateDebugModeUI(); + // Then send the actual keys after a delay + setTimeout(() => { + sendKeySequence(keys.split('')); + }, 500); + return; + } + + // Handle multi-key sequences (like 'g1' for act switch or 'c00' for locations) + if (keys.length > 1 && !keyCodeMap[keys]) { + sendKeySequence(keys.split('')); + } else { + sendKey(keys); + canvas.focus(); + } + }); + + // Handle location teleport + const locationSelect = document.getElementById('debug-location-select'); + const gotoLocationBtn = document.getElementById('debug-goto-location'); + + gotoLocationBtn.addEventListener('click', function(e) { + e.preventDefault(); + e.stopPropagation(); + + const locationValue = locationSelect.value; + if (!locationValue) return; + + // Ensure debug mode is active + if (!debugModeActive) { + sendKeySequence(['o', 'g', 'e', 'l']); + debugModeActive = true; + updateDebugModeUI(); + // Then send location keys after a delay + setTimeout(() => { + sendKeySequence(locationValue.split('')); + }, 500); + return; + } + + sendKeySequence(locationValue.split('')); + }); + + // Handle animation playback + const animationSelect = document.getElementById('debug-animation-select'); + const playAnimationBtn = document.getElementById('debug-play-animation'); + + playAnimationBtn.addEventListener('click', function(e) { + e.preventDefault(); + e.stopPropagation(); + + const animationId = animationSelect.value; + if (!animationId) return; + + // Ensure debug mode is active + if (!debugModeActive) { + sendKeySequence(['o', 'g', 'e', 'l']); + debugModeActive = true; + updateDebugModeUI(); + // Then send animation keys after a delay + setTimeout(() => { + playAnimation(animationId); + }, 500); + return; + } + + playAnimation(animationId); + }); + + function playAnimation(animationId) { + // Animation command: 'v' + 3 digits (padded with leading zeros) + const paddedId = animationId.toString().padStart(3, '0'); + const keys = ['v', ...paddedId.split('')]; + sendKeySequence(keys); + } + + // Initialize UI + updateDebugModeUI(); +})(); diff --git a/index.html b/index.html index 762ee47..3d3ecc6 100644 --- a/index.html +++ b/index.html @@ -155,6 +155,12 @@

Changelog

+
+ January 2026 + +
December 2025
@@ -751,6 +757,9 @@ + +
+ diff --git a/ogel.webp b/ogel.webp new file mode 100644 index 0000000..db98c8e Binary files /dev/null and b/ogel.webp differ diff --git a/style.css b/style.css index da07b6d..f12dc7b 100644 --- a/style.css +++ b/style.css @@ -909,4 +909,231 @@ select { grid-template-columns: 1fr; gap: 25px; } +} + +/* Debug UI Panel */ +#debug-ui { + display: none; + position: fixed; + top: 10px; + right: 10px; + z-index: 1000; + font-family: Arial, sans-serif; +} + +#debug-toggle { + width: 40px; + height: 40px; + border-radius: 50%; + background-color: rgba(0, 0, 0, 0.7); + border: 2px solid #FFD700; + color: #FFD700; + font-size: 20px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.2s ease; + margin-left: auto; +} + +#debug-toggle:hover { + background-color: rgba(255, 215, 0, 0.2); + transform: rotate(90deg); +} + +#debug-toggle.active { + background-color: #FFD700; + color: #000; +} + +#debug-panel { + display: none; + position: absolute; + top: 50px; + right: 0; + width: 280px; + max-height: calc(100dvh - 70px); + overflow-y: auto; + background-color: rgba(24, 24, 24, 0.95); + border: 1px solid #444; + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); +} + +#debug-panel.open { + display: block; +} + +.debug-header { + padding: 12px 15px; + background-color: #FFD700; + color: #000; + font-weight: bold; + font-size: 14px; + border-radius: 7px 7px 0 0; + position: sticky; + top: 0; + z-index: 1; +} + +.debug-section { + padding: 10px 12px; + border-bottom: 1px solid #333; +} + +.debug-section:last-child { + border-bottom: none; +} + +.debug-section-title { + color: #FFD700; + font-size: 11px; + font-weight: bold; + text-transform: uppercase; + margin-bottom: 8px; + letter-spacing: 0.5px; +} + +#debug-panel button { + display: block; + width: 100%; + padding: 8px 10px; + margin-bottom: 4px; + background-color: #2a2a2a; + border: 1px solid #444; + border-radius: 4px; + color: #e0e0e0; + font-size: 12px; + cursor: pointer; + text-align: left; + transition: all 0.15s ease; +} + +#debug-panel button:last-child { + margin-bottom: 0; +} + +#debug-panel button:hover { + background-color: #3a3a3a; + border-color: #FFD700; +} + +#debug-panel button:active { + background-color: #FFD700; + color: #000; +} + +#debug-panel button.debug-password { + background-color: #3d2a00; + border-color: #FFD700; + color: #FFD700; +} + +#debug-panel button.debug-password:hover { + background-color: #FFD700; + color: #000; +} + +#debug-panel button.debug-password.active { + background-color: #00aa00; + border-color: #00ff00; + color: #fff; +} + +#debug-panel button.requires-debug { + opacity: 0.5; +} + +#debug-panel button.requires-debug.enabled { + opacity: 1; +} + +.debug-location-grid { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 4px; +} + +.debug-location-grid button { + text-align: center; + padding: 6px 4px; + font-size: 11px; + font-family: 'Consolas', 'Menlo', monospace; +} + +/* Scrollbar styling for debug panel */ +#debug-panel::-webkit-scrollbar { + width: 6px; +} + +#debug-panel::-webkit-scrollbar-track { + background: #1a1a1a; +} + +#debug-panel::-webkit-scrollbar-thumb { + background: #555; + border-radius: 3px; +} + +#debug-panel::-webkit-scrollbar-thumb:hover { + background: #FFD700; +} + +#debug-animation-select, +#debug-location-select { + width: 100%; + padding: 8px 10px; + margin-bottom: 8px; + background-color: #2a2a2a; + border: 1px solid #444; + border-radius: 4px; + color: #e0e0e0; + font-size: 12px; + cursor: pointer; +} + +#debug-animation-select:hover, +#debug-location-select:hover { + border-color: #FFD700; +} + +#debug-animation-select:focus, +#debug-location-select:focus { + outline: none; + border-color: #FFD700; +} + +#debug-animation-select optgroup, +#debug-location-select optgroup { + background-color: #1a1a1a; + color: #FFD700; + font-weight: bold; +} + +#debug-animation-select option, +#debug-location-select option { + background-color: #2a2a2a; + color: #e0e0e0; + padding: 4px; +} + +/* Pizza celebration animation for OGEL mode */ +.pizza-slice { + position: fixed; + font-size: 32px; + pointer-events: none; + z-index: 10000; + animation: pizza-fly 1.5s ease-out forwards; +} + +@keyframes pizza-fly { + 0% { + opacity: 1; + transform: translate(0, 0) rotate(0deg) scale(1); + } + 100% { + opacity: 0; + transform: translate(var(--tx), var(--ty)) rotate(var(--rot)) scale(0.5); + } } \ No newline at end of file diff --git a/sw.js b/sw.js index 6216212..068c42d 100644 --- a/sw.js +++ b/sw.js @@ -10,7 +10,7 @@ const { Strategy } = workbox.strategies; const { CacheableResponsePlugin } = workbox.cacheableResponse; const { RangeRequestsPlugin } = workbox.rangeRequests; -precacheAndRoute([{"revision":"1941a2dd1683d34e6503354fa9002d99","url":"index.html"},{"revision":"013ceb7d67293d532e979dde0347f3af","url":"cancel_off.webp"},{"revision":"bfc1563be018d82685716c6130529129","url":"cancel_on.webp"},{"revision":"d282c260fd35522036936bb6faf8ad21","url":"cdspin.gif"},{"revision":"3d820bf72b19bd4e437a61e75f317b83","url":"configure_off.webp"},{"revision":"e2c0c5e6aa1f7703c385a433a2d2a519","url":"configure_on.webp"},{"revision":"88e1e81c930d8e6c24dfdc7af274e812","url":"favicon.png"},{"revision":"d16b293eca457e2fb1e7ef2caca8c904","url":"favicon.svg"},{"revision":"d2b9c2e128ef1e5e4265c603b0bc3305","url":"free_stuff_off.webp"},{"revision":"cbc6a6779897f932c3a3c8dceb329804","url":"free_stuff_on.webp"},{"revision":"05fba4ef1884cbbd6afe09ea3325efc0","url":"install_off.webp"},{"revision":"11247e92082ba3d978a2e3785b0acf51","url":"install_on.webp"},{"revision":"d23ea8243c18eb217ef08fe607097824","url":"island.webp"},{"revision":"92952ef8f080c355aec499e669214840","url":"isle.js"},{"revision":"4fb9dbeadeb5781c3a069b5acb1d5f45","url":"isle.wasm"},{"revision":"6d4248f1a08c218943e582673179b7be","url":"poster.pdf"},{"revision":"a6fcac24a24996545c039a1755af33ea","url":"read_me_off.webp"},{"revision":"aae783d064996b4322e23b092d97ea4a","url":"read_me_on.webp"},{"revision":"766a9e6e6d890f24cef252e81753b29d","url":"run_game_off.webp"},{"revision":"70208e00e9ea641e4c98699f74100db3","url":"run_game_on.webp"},{"revision":"0a65c71d9983c9bb1bc6a5f405fd6fd9","url":"shark.webp"},{"revision":"88c1fd032e6fc16814690712a26c1ede","url":"uninstall_off.webp"},{"revision":"0118a4aca04c5fb0a525bf00b001844e","url":"uninstall_on.webp"},{"revision":"b21ea085712e7a731dd721578b46186b","url":"app.js"},{"revision":"2898f0ebd4847281c7020d48f43812d9","url":"style.css"},{"revision":"060210979e13e305510de6285e085db1","url":"manifest.json"},{"revision":"4f0172bc7007d34cebf681cc233ab57f","url":"install.webp"},{"revision":"6a70d35dadf51d2ec6e38a6202d7fb0b","url":"install.mp3"},{"revision":"eac041a0b8835bfea706d997b0b7b224","url":"downloader.js"}]); +precacheAndRoute([{"revision":"413569e7f8f884133ea6c1d2c9a9cb99","url":"index.html"},{"revision":"013ceb7d67293d532e979dde0347f3af","url":"cancel_off.webp"},{"revision":"bfc1563be018d82685716c6130529129","url":"cancel_on.webp"},{"revision":"d282c260fd35522036936bb6faf8ad21","url":"cdspin.gif"},{"revision":"3d820bf72b19bd4e437a61e75f317b83","url":"configure_off.webp"},{"revision":"e2c0c5e6aa1f7703c385a433a2d2a519","url":"configure_on.webp"},{"revision":"88e1e81c930d8e6c24dfdc7af274e812","url":"favicon.png"},{"revision":"d16b293eca457e2fb1e7ef2caca8c904","url":"favicon.svg"},{"revision":"d2b9c2e128ef1e5e4265c603b0bc3305","url":"free_stuff_off.webp"},{"revision":"cbc6a6779897f932c3a3c8dceb329804","url":"free_stuff_on.webp"},{"revision":"05fba4ef1884cbbd6afe09ea3325efc0","url":"install_off.webp"},{"revision":"11247e92082ba3d978a2e3785b0acf51","url":"install_on.webp"},{"revision":"d23ea8243c18eb217ef08fe607097824","url":"island.webp"},{"revision":"b4754844f694858c2c08307a197c5434","url":"isle.js"},{"revision":"e66ee40529da22100b5f3d55d9aa1850","url":"isle.wasm"},{"revision":"6d4248f1a08c218943e582673179b7be","url":"poster.pdf"},{"revision":"a6fcac24a24996545c039a1755af33ea","url":"read_me_off.webp"},{"revision":"aae783d064996b4322e23b092d97ea4a","url":"read_me_on.webp"},{"revision":"766a9e6e6d890f24cef252e81753b29d","url":"run_game_off.webp"},{"revision":"70208e00e9ea641e4c98699f74100db3","url":"run_game_on.webp"},{"revision":"0a65c71d9983c9bb1bc6a5f405fd6fd9","url":"shark.webp"},{"revision":"88c1fd032e6fc16814690712a26c1ede","url":"uninstall_off.webp"},{"revision":"0118a4aca04c5fb0a525bf00b001844e","url":"uninstall_on.webp"},{"revision":"bc17c7c6ecae6a5258cf2d0d89962e7e","url":"app.js"},{"revision":"ceeab6ec27aba25418c3ded77ebd4517","url":"style.css"},{"revision":"060210979e13e305510de6285e085db1","url":"manifest.json"},{"revision":"4f0172bc7007d34cebf681cc233ab57f","url":"install.webp"},{"revision":"6a70d35dadf51d2ec6e38a6202d7fb0b","url":"install.mp3"},{"revision":"eac041a0b8835bfea706d997b0b7b224","url":"downloader.js"},{"revision":"6899f72755d4e84c707b93ac54a8fb06","url":"debug.js"},{"revision":"7817b36ddda9f07797c05a0ff6cacb21","url":"debug.html"},{"revision":"4ea2aac9446188b8a588811bc593919e","url":"ogel.webp"}]); const gameFiles = [ "/LEGO/Scripts/CREDITS.SI", "/LEGO/Scripts/INTRO.SI", "/LEGO/Scripts/NOCD.SI", "/LEGO/Scripts/SNDANIM.SI", diff --git a/workbox-config.js b/workbox-config.js index 6aa6c54..f31828c 100644 --- a/workbox-config.js +++ b/workbox-config.js @@ -7,7 +7,7 @@ module.exports = { 'island.webp', 'isle.js', 'isle.wasm', 'poster.pdf', 'read_me_off.webp', 'read_me_on.webp', 'run_game_off.webp', 'run_game_on.webp', 'shark.webp', 'uninstall_off.webp', 'uninstall_on.webp', 'app.js', 'style.css', 'manifest.json', - 'install.webp', 'install.mp3', 'downloader.js' + 'install.webp', 'install.mp3', 'downloader.js', 'debug.js', 'debug.html', 'ogel.webp' ], swSrc: 'src/sw.js', swDest: 'sw.js',