SIMON Master Console Rebuild
True command center for SIMON + WEB360
This rebuild gives you a cleaner production spine: interactive tree, live viewer, guarded editor, dynamic graphics, architecture map, and note storage. It is designed to sit beside your existing
console.php
and become the stronger replacement path.
Dashboard
Tree
Viewer
System Map
File Registry
Notes
Files
15,341
Folders
408
Scanned Size
3.84 GB
PHP Files
891
Editable Text Files
12,602
File viewer
guarded to /htdocs
/arcade/games/BUBBLES2.HTML
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"/> <title>SIMON — Bubble Pop Fireworks</title> <meta name="theme-color" content="#070a18"/> <style> :root{ --bg0:#050716; --bg1:#070a22; --glass: rgba(255,255,255,.08); --edge: rgba(255,255,255,.16); --cyan:#00e7ff; --mag:#ff2bd6; --lime:#66ff7a; --vio:#9b7bff; --gold:#ffd166; --shadow: rgba(0,0,0,.55); } *{box-sizing:border-box} html,body{height:100%} body{ margin:0; overflow:hidden; font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Arial; color:#eaf2ff; background: radial-gradient(1200px 900px at 20% 20%, rgba(0,231,255,.11), transparent 60%), radial-gradient(900px 700px at 80% 25%, rgba(255,43,214,.10), transparent 55%), radial-gradient(1000px 900px at 50% 95%, rgba(155,123,255,.10), transparent 60%), linear-gradient(180deg, var(--bg0), var(--bg1)); } canvas{display:block; width:100vw; height:100vh} .hud{ position:fixed; inset:14px 14px auto 14px; display:flex; gap:12px; align-items:center; justify-content:space-between; z-index:10; pointer-events:none; } .pill{ pointer-events:none; padding:10px 12px; border-radius:16px; background: linear-gradient(180deg, rgba(255,255,255,.10), rgba(255,255,255,.06)); border:1px solid var(--edge); box-shadow: 0 12px 35px var(--shadow), inset 0 1px 0 rgba(255,255,255,.10); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); display:flex; gap:12px; align-items:center; flex-wrap:wrap; } .title{ font-weight:800; letter-spacing:.14em; font-size:12px; opacity:.95; } .stat{ font-size:12px; opacity:.9; display:flex; gap:6px; align-items:baseline; } .stat b{font-size:13px} .kbd{font-size:12px; opacity:.9; display:flex; gap:8px; flex-wrap:wrap} .key{ display:inline-flex; align-items:center; justify-content:center; min-width:28px; padding:2px 8px; border-radius:10px; background: rgba(0,0,0,.24); border:1px solid rgba(255,255,255,.18); box-shadow: inset 0 1px 0 rgba(255,255,255,.08); } .right{display:flex; gap:10px; align-items:center; pointer-events:auto} .btn{ cursor:pointer; user-select:none; padding:10px 12px; border-radius:14px; border:1px solid rgba(255,255,255,.18); background: rgba(0,0,0,.22); box-shadow: 0 12px 30px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.08); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); transition: transform .08s ease, border-color .2s ease; font-size:13px; } .btn:hover{transform: translateY(-1px); border-color: rgba(0,231,255,.40)} .btn:active{transform: translateY(0px) scale(.98)} .toastWrap{ position:fixed; inset:auto 0 16px 0; display:flex; justify-content:center; z-index:10; pointer-events:none; } .toast{ padding:10px 14px; border-radius:14px; border:1px solid rgba(255,255,255,.18); background: rgba(0,0,0,.25); box-shadow: 0 14px 35px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.08); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); font-size:12px; opacity:.92; } .vignette{ position:fixed; inset:0; pointer-events:none; background: radial-gradient(1200px 900px at 50% 55%, transparent 55%, rgba(0,0,0,.45) 100%); z-index:5; mix-blend-mode:multiply; } </style> </head> <body> <div class="hud"> <div class="pill"> <span class="title">SIMON — BUBBLE POP FIREWORKS</span> <span class="stat">Score <b id="score">0</b></span> <span class="stat">Combo <b id="combo">x1</b></span> <span class="stat">Time <b id="time">60</b>s</span> <span class="kbd"> <span class="key">Click/Tap</span> pop <span class="key">Space</span> slow-mo <span class="key">M</span> mute <span class="key">R</span> restart </span> </div> <div class="right"> <div class="btn" id="muteBtn">🔊 Sound</div> <div class="btn" id="restartBtn">♻️ Restart</div> </div> </div> <div class="toastWrap"><div class="toast" id="toast">Click once to enable audio. Then pop bubbles for fireworks 🎆</div></div> <canvas id="c"></canvas> <div class="vignette"></div> <script> (() => { 'use strict'; // ---------- Canvas ---------- const canvas = document.getElementById('c'); const ctx = canvas.getContext('2d', { alpha:true }); const DPR = Math.max(1, Math.min(2, window.devicePixelRatio || 1)); function resize(){ canvas.width = Math.floor(innerWidth * DPR); canvas.height = Math.floor(innerHeight * DPR); } addEventListener('resize', resize, {passive:true}); resize(); // ---------- DOM ---------- const scoreEl = document.getElementById('score'); const comboEl = document.getElementById('combo'); const timeEl = document.getElementById('time'); const toastEl = document.getElementById('toast'); const muteBtn = document.getElementById('muteBtn'); const restartBtn = document.getElementById('restartBtn'); function toast(msg, ms=1300){ toastEl.textContent = msg; toastEl.style.opacity = '0.95'; clearTimeout(toast._t); toast._t = setTimeout(()=>toastEl.style.opacity='0.12', ms); } // ---------- Helpers ---------- const rand = (a,b)=>a+Math.random()*(b-a); const clamp = (v,a,b)=>Math.max(a,Math.min(b,v)); const lerp = (a,b,t)=>a+(b-a)*t; const hypot = Math.hypot; const now = ()=>performance.now(); const COLORS = ['#00e7ff','#ff2bd6','#66ff7a','#9b7bff','#ffd166','#ff3b3b']; // ---------- Audio synth ---------- let audioOK=false, muted=false, actx=null; function ensureAudio(){ if (audioOK) return; actx = new (window.AudioContext || window.webkitAudioContext)(); audioOK=true; } function blip({freq=440, dur=0.08, type='sine', gain=0.06, slide=0, noise=0} = {}){ if (!audioOK || muted) return; const t0 = actx.currentTime; const g = actx.createGain(); g.gain.setValueAtTime(0.0001, t0); g.gain.exponentialRampToValueAtTime(gain, t0 + 0.01); g.gain.exponentialRampToValueAtTime(0.0001, t0 + dur); let src; if (noise > 0){ const bufferSize = Math.floor(actx.sampleRate * dur); const buffer = actx.createBuffer(1, bufferSize, actx.sampleRate); const data = buffer.getChannelData(0); for (let i=0;i<bufferSize;i++){ data[i] = (Math.random()*2-1) * Math.pow(1 - i/bufferSize, 2) * noise; } const n = actx.createBufferSource(); n.buffer = buffer; src = n; } else { const o = actx.createOscillator(); o.type = type; o.frequency.setValueAtTime(freq, t0); if (slide !== 0){ o.frequency.exponentialRampToValueAtTime(Math.max(30, freq + slide), t0 + dur); } src = o; } src.connect(g); g.connect(actx.destination); src.start(t0); src.stop(t0 + dur); } const SFX = { popSmall(){ blip({freq:720, dur:0.05, type:'triangle', gain:0.05, slide:200}); }, popBig(){ blip({freq:260, dur:0.12, type:'sawtooth', gain:0.07, slide:-120, noise:0.18}); }, tick(){ blip({freq:520, dur:0.03, type:'sine', gain:0.02}); }, slowmoOn(){ blip({freq:140, dur:0.09, type:'square', gain:0.04, slide:-40, noise:0.10}); }, slowmoOff(){blip({freq:220, dur:0.06, type:'square', gain:0.03, slide:30, noise:0.06}); }, end(){ blip({freq:110, dur:0.22, type:'sine', gain:0.08, slide:-60, noise:0.25}); } }; function toggleMute(){ muted = !muted; muteBtn.textContent = muted ? '🔇 Muted' : '🔊 Sound'; toast(muted ? 'Muted' : 'Sound on'); } muteBtn.addEventListener('click', ()=>{ ensureAudio(); toggleMute(); }); restartBtn.addEventListener('click', ()=>{ reset(); toast('Restarted. Pop pop pop!'); }); // ---------- Game state ---------- let score=0; let combo=1; let comboTimer=0; let timeLeft=60_000; // ms let running=true; let slowmo=false; let slowmoHold=false; // ---------- Background particles ---------- const bg = []; function initBg(n=520){ bg.length=0; for (let i=0;i<n;i++){ bg.push({ x: rand(0, innerWidth), y: rand(0, innerHeight), vx: rand(-0.22,0.22), vy: rand(-0.22,0.22), r: rand(0.7, 2.4), a: rand(0.05, 0.22), c: COLORS[(Math.random()*COLORS.length)|0], t: rand(0,Math.PI*2), s: rand(0.4,1.2) }); } } // ---------- Bubbles ---------- const bubbles = []; function spawnBubble(){ const r = rand(18, 44); const c = COLORS[(Math.random()*COLORS.length)|0]; const speed = rand(0.25, 1.25) * (r < 28 ? 1.3 : 1.0); bubbles.push({ x: rand(r, innerWidth-r), y: innerHeight + r + rand(0, 80), vx: rand(-0.5,0.5) * 0.6, vy: -speed, r, c, wob: rand(0,Math.PI*2), alive:true, born: now() }); } function fillBubbles(){ bubbles.length=0; const n = 16; for (let i=0;i<n;i++){ spawnBubble(); bubbles[bubbles.length-1].y = rand(80, innerHeight-80); } } // ---------- Fireworks particles ---------- const parts = []; const rings = []; function ring(x,y,color, r0=10, r1=170, ms=620){ rings.push({x,y,color,r0,r1,ms, born:now()}); } function firework(x,y,color,power=1){ const count = Math.floor(40 + power*18); for (let i=0;i<count;i++){ const a = rand(0, Math.PI*2); const sp = rand(1.2, 6.6) * power; parts.push({ x,y, vx: Math.cos(a)*sp, vy: Math.sin(a)*sp, r: rand(1.0, 3.2) * power, life: rand(600, 1400), born: now(), c: color, g: rand(0.012, 0.03) }); } ring(x,y,color, 8, 220*power, 700); } // ---------- Input / hit test ---------- const input = { x: innerWidth/2, y: innerHeight/2 }; addEventListener('pointermove', (e)=>{ input.x=e.clientX; input.y=e.clientY; }, {passive:true}); addEventListener('pointerdown', (e)=>{ ensureAudio(); if (!running) return; const x = e.clientX, y = e.clientY; // check topmost bubble (smallest last? we just scan reverse for "front") for (let i=bubbles.length-1;i>=0;i--){ const b = bubbles[i]; if (!b.alive) continue; const d = hypot(x-b.x, y-b.y); if (d <= b.r){ popBubble(b); break; } } }, {passive:true}); addEventListener('keydown', (e)=>{ const k = e.key.toLowerCase(); if (k === 'm'){ ensureAudio(); toggleMute(); } if (k === 'r'){ reset(); toast('Restarted.'); } if (k === ' '){ slowmoHold=true; if (!slowmo){ slowmo=true; if (audioOK) SFX.slowmoOn(); toast('SLOW-MO'); } e.preventDefault(); } }); addEventListener('keyup', (e)=>{ if (e.key === ' '){ slowmoHold=false; if (slowmo){ slowmo=false; if (audioOK) SFX.slowmoOff(); toast('Normal speed'); } } }); function popBubble(b){ b.alive=false; // score: smaller bubbles worth more (harder to click) const base = Math.round(120 / (b.r/18)); const pts = Math.round(base * combo); score += pts; // combo logic comboTimer = 1200; combo = clamp(combo + 0.12, 1, 8); // fireworks power based on bubble size const pwr = clamp(1.0 + (44 - b.r)/22, 0.9, 2.2); firework(b.x, b.y, b.c, pwr); // sound if (audioOK){ if (b.r < 28) SFX.popSmall(); else SFX.popBig(); } toast(`+${pts} ✨`, 700); // respawn replacement quickly spawnBubble(); } // ---------- Rendering ---------- function drawBg(){ ctx.setTransform(1,0,0,1,0,0); ctx.clearRect(0,0,canvas.width,canvas.height); ctx.save(); ctx.scale(DPR,DPR); const t = now()*0.0012; for (const p of bg){ p.t += 0.01 * p.s; p.x += p.vx; p.y += p.vy; if (p.x<0) p.x+=innerWidth; if (p.y<0) p.y+=innerHeight; if (p.x>innerWidth) p.x-=innerWidth; if (p.y>innerHeight) p.y-=innerHeight; const a = p.a + Math.sin(p.t + t)*0.03; ctx.globalAlpha = clamp(a, 0.02, 0.28); ctx.fillStyle = p.c; ctx.beginPath(); ctx.arc(p.x, p.y, p.r*(0.8+0.2*Math.sin(p.t*1.3)), 0, Math.PI*2); ctx.fill(); ctx.globalAlpha *= 0.35; ctx.beginPath(); ctx.arc(p.x, p.y, p.r*4.5, 0, Math.PI*2); ctx.fill(); } ctx.restore(); ctx.globalAlpha = 1; } function bubbleGradient(color, r){ // quick radial gradient with glow const g = ctx.createRadialGradient(0,0, r*0.15, 0,0, r); g.addColorStop(0, 'rgba(255,255,255,.80)'); g.addColorStop(0.10, color); g.addColorStop(0.58, 'rgba(255,255,255,.12)'); g.addColorStop(1, 'rgba(255,255,255,.04)'); return g; } function drawBubbles(dt){ ctx.save(); ctx.scale(DPR,DPR); for (const b of bubbles){ if (!b.alive) continue; b.wob += 0.02; b.x += b.vx * dt; b.y += b.vy * dt + Math.sin(b.wob)*0.12; // wrap-ish + respawn from bottom if (b.x < b.r) { b.x=b.r; b.vx *= -1; } if (b.x > innerWidth-b.r) { b.x=innerWidth-b.r; b.vx *= -1; } if (b.y < -b.r-40){ // recycle b.y = innerHeight + b.r + rand(0, 120); b.x = rand(b.r, innerWidth-b.r); b.vy = -rand(0.25, 1.25) * (b.r < 28 ? 1.3 : 1.0); b.c = COLORS[(Math.random()*COLORS.length)|0]; b.alive = true; } // glow ctx.globalAlpha = 0.18; ctx.fillStyle = b.c; ctx.beginPath(); ctx.arc(b.x, b.y, b.r*1.55, 0, Math.PI*2); ctx.fill(); // body ctx.globalAlpha = 1; ctx.save(); ctx.translate(b.x, b.y); ctx.beginPath(); ctx.arc(0,0, b.r, 0, Math.PI*2); ctx.fillStyle = bubbleGradient(b.c, b.r); ctx.fill(); // rim ctx.globalAlpha = 0.35; ctx.strokeStyle = 'rgba(255,255,255,.35)'; ctx.lineWidth = Math.max(1, b.r*0.08); ctx.beginPath(); ctx.arc(0,0, b.r, 0, Math.PI*2); ctx.stroke(); // specular dot ctx.globalAlpha = 0.22; ctx.fillStyle = 'rgba(255,255,255,.9)'; ctx.beginPath(); ctx.arc(-b.r*0.28, -b.r*0.28, b.r*0.34, 0, Math.PI*2); ctx.fill(); ctx.restore(); } ctx.restore(); ctx.globalAlpha = 1; } function drawFireworks(){ const t = now(); // rings for (let i=rings.length-1;i>=0;i--){ const R = rings[i]; const age = t - R.born; const u = age / R.ms; if (u>=1){ rings.splice(i,1); continue; } const r = lerp(R.r0, R.r1, u); ctx.save(); ctx.scale(DPR,DPR); ctx.globalAlpha = (1-u)*0.65; ctx.strokeStyle = R.color; ctx.lineWidth = 3*(1-u) + 1; ctx.beginPath(); ctx.arc(R.x, R.y, r, 0, Math.PI*2); ctx.stroke(); ctx.globalAlpha *= 0.25; ctx.lineWidth *= 2.2; ctx.beginPath(); ctx.arc(R.x, R.y, r*1.01, 0, Math.PI*2); ctx.stroke(); ctx.restore(); } // particles for (let i=parts.length-1;i>=0;i--){ const p = parts[i]; const age = t - p.born; const u = age / p.life; if (u>=1){ parts.splice(i,1); continue; } p.vy += p.g; p.x += p.vx; p.y += p.vy; p.vx *= 0.986; p.vy *= 0.986; const a = (1-u); ctx.save(); ctx.scale(DPR,DPR); ctx.globalAlpha = a*0.9; ctx.fillStyle = p.c; ctx.beginPath(); ctx.arc(p.x, p.y, p.r*(1-u*0.2), 0, Math.PI*2); ctx.fill(); ctx.globalAlpha *= 0.22; ctx.beginPath(); ctx.arc(p.x, p.y, p.r*5.4, 0, Math.PI*2); ctx.fill(); ctx.restore(); } } // ---------- Timer / UI ---------- function updateUI(){ scoreEl.textContent = String(score|0); comboEl.textContent = 'x' + (combo).toFixed(1); timeEl.textContent = String(Math.max(0, Math.ceil(timeLeft/1000))); } // ---------- Reset ---------- function reset(){ score=0; combo=1; comboTimer=0; timeLeft=60_000; running=true; parts.length=0; rings.length=0; initBg(); fillBubbles(); updateUI(); } reset(); // ---------- Main loop ---------- let last = now(); function loop(){ const t = now(); let dt = Math.min(40, t-last); last = t; // slow motion dt *= slowmo ? 0.35 : 1.0; // countdown if (running){ timeLeft -= (t - (last - dt)); // dt in ms effectively if (timeLeft <= 0){ timeLeft = 0; running = false; toast(`Time! Final score: ${score|0} 🎇`, 2600); if (audioOK) SFX.end(); } } // combo decay if (comboTimer > 0){ comboTimer -= dt; if (comboTimer <= 0){ combo = lerp(combo, 1, 0.6); } } else { combo = lerp(combo, 1, 0.08); } // spawn more bubbles over time while running if (running && bubbles.length < 20 && Math.random() < 0.03){ spawnBubble(); } // draw drawBg(); if (running) drawBubbles(dt); drawFireworks(); updateUI(); requestAnimationFrame(loop); } requestAnimationFrame(loop); // Enable audio on first interaction addEventListener('pointerdown', ()=>{ ensureAudio(); if (audioOK) toast('Audio enabled. Pop bubbles for fireworks! 🎆'); }, {once:true, passive:true}); })(); </script> </body> </html>
Save file
Quick jump
open a path
Open