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,325
Folders
408
Scanned Size
3.84 GB
PHP Files
885
Editable Text Files
12,586
File viewer
guarded to /htdocs
/arcade/games/SIMON CIRCLE RAINBOW FIELD.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 — Rainbow Energy Orb (Standalone)</title> <style> :root{ --bg:#060a16; --ink:#eaf6ff } html,body{height:100%} body{ margin:0; background:#060a16; overflow:hidden; color:var(--ink); font-family:system-ui,Inter,Segoe UI,Roboto,Arial } /* canvases */ #field,#orb{ position:fixed; inset:0; display:block } /* lockup */ .lock{ position:fixed; inset:0; display:grid; place-items:center; pointer-events:none; z-index:10 } .title{ position:absolute; top:50%; transform:translateY(108%); text-align:center } h1{ margin:0; font-weight:900; font-size:clamp(34px,11vmin,96px); letter-spacing:.06em; text-shadow:0 0 26px rgba(255,255,255,.16) } /* control */ .ctrl{ position:fixed; right:12px; bottom:12px; z-index:20; display:flex; gap:8px; align-items:center; padding:8px 10px; border-radius:12px; border:1px solid rgba(255,255,255,.12); background:linear-gradient(180deg, rgba(255,255,255,.06), rgba(255,255,255,.03)); color:#dff6ff; backdrop-filter:blur(8px) } .ctrl button{ cursor:pointer; border:1px solid rgba(255,255,255,.18); background:rgba(255,255,255,.08); color:inherit; padding:6px 10px; border-radius:8px; font-weight:800; font-size:12px } </style> </head> <body> <canvas id="field"></canvas> <!-- morphing particle field --> <canvas id="orb"></canvas> <!-- rainbow orb + ring + text --> <div class="lock" aria-hidden="true"> <div class="title"><h1>SIMON</h1></div> </div> <div class="ctrl"> <span>Audio-reactive:</span> <button id="audioBtn">Enable</button> </div> <script> /* =========== DPR / sizing =========== */ const DPR_CAP = 2; const CVF = document.getElementById('field'); const CVO = document.getElementById('orb'); const g = CVF.getContext('2d', {alpha:true}); const gx = CVO.getContext('2d', {alpha:true}); let DPR=1, W=0, H=0; function fit(){ DPR = Math.min(DPR_CAP, window.devicePixelRatio||1); W = Math.floor(innerWidth*DPR); H = Math.floor(innerHeight*DPR); [CVF,CVO].forEach(cv=>{ cv.width=W; cv.height=H; cv.style.width=innerWidth+'px'; cv.style.height=innerHeight+'px'; }); g.setTransform(1,0,0,1,0,0); gx.setTransform(1,0,0,1,0,0); g.scale(DPR,DPR); gx.scale(DPR,DPR); } addEventListener('resize', fit, {passive:true}); fit(); /* =========== Curl noise helpers =========== */ const P = new Uint8Array(512); for(let i=0;i<256;i++) P[i]=i; for(let i=255;i>0;i--){ const j=(Math.random()*i)|0; [P[i],P[j]]=[P[j],P[i]]; } for(let i=0;i<256;i++) P[i+256]=P[i]; const fade=s=>s*s*s*(s*(s*6-15)+10); const grad=(h,x,y)=>[x+y,-x+y,x-y,-x-y][h&3]; function n2(x,y){ const X=Math.floor(x)&255, Y=Math.floor(y)&255; x-=Math.floor(x); y-=Math.floor(y); const u=fade(x), v=fade(y), A=P[X]+Y, B=P[X+1]+Y; const n0=grad(P[A],x,y), n1=grad(P[B],x-1,y), n2a=grad(P[A+1],x,y-1), n3=grad(P[B+1],x-1,y-1); return (n0+(n1-n0)*u) + ((n2a+(n3-n2a)*u) - (n0+(n1-n0)*u))*v; } function curl(x,y,t,scale=0.0018,storm=1.0){ const s = scale * (0.9 + 0.3*Math.sin(t*0.25)); const e = 0.0005; const nx = x*s + Math.sin(t*0.13)*2.0; const ny = y*s + Math.cos(t*0.11)*2.0; const a=n2(nx,ny+e), b=n2(nx,ny-e), c=n2(nx+e,ny), d=n2(nx-e,ny); const dx=(a-b)/(2*e), dy=(c-d)/(2*e); return [dy*storm, -dx*storm]; } /* =========== Particle field (color + form morph) =========== */ const mobile = /Mobile|Android|iPhone/i.test(navigator.userAgent); const FSET = { count: mobile?6500:12000, trail:0.075 }; let px=new Float32Array(FSET.count), py=new Float32Array(FSET.count), vx=new Float32Array(FSET.count), vy=new Float32Array(FSET.count); function seedField(){ for(let i=0;i<FSET.count;i++){ const by = Math.random()**0.55; // bias lower px[i]=Math.random()*innerWidth; py[i]=innerHeight*(0.35 + 0.65*by); vx[i]=(Math.random()*2-1)*0.2; vy[i]=(Math.random()*2-1)*0.2; } } seedField(); /* =========== Audio-reactive (optional; no mic) =========== */ let audioOn=false, actx=null, analyser=null, energy=0; document.getElementById('audioBtn').onclick = async ()=>{ if(audioOn) { actx.close(); audioOn=false; event.target.textContent='Enable'; return; } actx = new (window.AudioContext||window.webkitAudioContext)(); const master = actx.createGain(); master.gain.value=0.5; master.connect(actx.destination); const oscA = actx.createOscillator(); oscA.type='sine'; oscA.frequency.value=110; // A2 base const oscB = actx.createOscillator(); oscB.type='sine'; oscB.frequency.value=165; oscB.detune.value=5; const pad = actx.createGain(); pad.gain.value=0.18; oscA.connect(pad); oscB.connect(pad); pad.connect(master); oscA.start(); oscB.start(); // gentle noise for movement const noiseBuf = actx.createBuffer(1, actx.sampleRate*2, actx.sampleRate); const d = noiseBuf.getChannelData(0); for(let i=0;i<d.length;i++) d[i]=(Math.random()*2-1)*0.5; const noise = actx.createBufferSource(); noise.buffer=noiseBuf; noise.loop=true; noise.start(); const bp = actx.createBiquadFilter(); bp.type='bandpass'; bp.frequency.value=700; bp.Q.value=0.8; const whoosh = actx.createGain(); whoosh.gain.value=0.05; noise.connect(bp); bp.connect(whoosh); whoosh.connect(master); analyser = actx.createAnalyser(); analyser.fftSize=512; master.connect(analyser); audioOn=true; event.target.textContent='Disable'; }; /* =========== Draw orb =========== */ function drawOrb(t){ const cx = innerWidth/2, cy = innerHeight*0.36; const R = Math.min(innerWidth,innerHeight)*0.16; const rCore = R*0.28; gx.clearRect(0,0,innerWidth,innerHeight); gx.save(); gx.globalCompositeOperation='lighter'; // Outer neon rainbow ring const seg = Math.PI/36; gx.lineCap='round'; for(let a=0;a<Math.PI*2;a+=seg){ const hue = (a*180/Math.PI + t*60) % 360; gx.strokeStyle = `hsla(${hue}, 100%, 60%, .78)`; gx.lineWidth = 5.5*DPR; gx.beginPath(); gx.arc(cx, cy, R*1.12, a, a+seg*0.92); gx.stroke(); } // Rainbow vortex (3-lobed). Audio energy slightly boosts thickness. const spin = t*0.9, lobes=3, arms=160; const boost = audioOn && analyser ? (()=>{ const arr=new Uint8Array(analyser.frequencyBinCount); analyser.getByteFrequencyData(arr); let s=0; for(const v of arr) s+=v; return Math.min(1,s/(arr.length*255)); })() : 0; energy = boost; gx.translate(cx,cy); gx.rotate(spin); for(let i=0;i<arms;i++){ const a = (i/arms)*Math.PI*2; const hue = (a*180/Math.PI + t*140) % 360; const lobe = Math.sin(a*lobes + t*1.4); const amp = 0.35 + 0.65*(0.5+0.5*lobe); const r1 = rCore + amp*R*0.62; gx.strokeStyle=`hsla(${hue},100%,60%,${0.65+0.25*boost})`; gx.lineWidth = (1.5 + 2.8*amp + 2.0*boost) * DPR; gx.beginPath(); gx.arc(0,0, r1, a-0.18, a+0.08); gx.stroke(); } // Core glow const core = gx.createRadialGradient(0,0,0, 0,0,rCore*1.3); core.addColorStop(0, `rgba(255,255,255,${0.85+0.1*energy})`); core.addColorStop(1, 'rgba(255,255,255,0)'); gx.fillStyle = core; gx.beginPath(); gx.arc(0,0,rCore*1.3,0,Math.PI*2); gx.fill(); // Body soft disk const body = gx.createRadialGradient(0,0,rCore*0.2, 0,0,R); body.addColorStop(0,'rgba(255,255,255,.10)'); body.addColorStop(0.7,'rgba(120,230,255,.08)'); body.addColorStop(1,'rgba(0,0,0,0)'); gx.globalCompositeOperation='lighter'; gx.fillStyle=body; gx.beginPath(); gx.arc(0,0,R,0,Math.PI*2); gx.fill(); gx.restore(); // Title glow under orb gx.save(); gx.globalCompositeOperation='lighter'; const tg=gx.createRadialGradient(cx, cy+R*1.06, 0, cx, cy+R*1.06, R*1.4); tg.addColorStop(0, `rgba(120,220,255,${.15+.2*energy})`); tg.addColorStop(1, 'rgba(0,0,0,0)'); gx.fillStyle=tg; gx.fillRect(0,0,innerWidth,innerHeight); gx.restore(); } /* =========== Animate =========== */ let last=performance.now(); function tick(now){ const dt=Math.min(0.033,(now-last)/1000); last=now; const t=now*0.001; // Field g.globalCompositeOperation='source-over'; g.fillStyle=`rgba(6,10,22,${FSET.trail})`; g.fillRect(0,0,innerWidth,innerHeight); const cx=innerWidth/2, cy=innerHeight*0.64; const basin=g.createRadialGradient(cx,cy,0, cx,cy, Math.max(innerWidth,innerHeight)*0.58); basin.addColorStop(0,'rgba(70,180,255,.12)'); basin.addColorStop(1,'rgba(0,0,0,0)'); g.globalCompositeOperation='lighter'; g.fillStyle=basin; g.fillRect(0,0,innerWidth,innerHeight); // morph palette & flow const hue = (t*30)%360; const scale = 0.0014 + 0.0007*(0.5+0.5*Math.sin(t*0.6)); const storm = 0.9 + 0.5*(0.5+0.5*Math.cos(t*0.4)); g.fillStyle=`hsla(${hue},95%,60%,0.085)`; for(let i=0;i<px.length;i++){ const F = curl(px[i],py[i],t,scale,storm); const w = 0.6 + 0.8*Math.exp(-((py[i]-cy)*(py[i]-cy))/(innerHeight*innerHeight*0.09)); vx[i]=vx[i]*0.985 + F[0]*22*w*dt + (Math.random()*2-1)*0.08*dt; vy[i]=vy[i]*0.985 + F[1]*22*w*dt + (Math.random()*2-1)*0.08*dt; px[i]+=vx[i]; py[i]+=vy[i]; if(px[i]<-2) px[i]+=innerWidth+4; else if(px[i]>innerWidth+2) px[i]-=innerWidth+4; if(py[i]<-2) py[i]+=innerHeight+4; else if(py[i]>innerHeight+2) py[i]-=innerHeight+4; g.fillRect(px[i],py[i],1.2,1.2); } // Orb drawOrb(t); requestAnimationFrame(tick); } requestAnimationFrame(tick); </script> </body> </html>
Save file
Quick jump
open a path
Open