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,359
Folders
427
Scanned Size
3.85 GB
PHP Files
948
Editable Text Files
12,615
File viewer
guarded to /htdocs
/si/operations/sphere-bg.js
(() => { 'use strict'; // ═══════════════════════════════════════════════════════ // UTILITY // ═══════════════════════════════════════════════════════ const clamp = (v,lo,hi) => v<lo?lo:v>hi?hi:v; const lerp = (a,b,t) => a+(b-a)*t; const PI2 = Math.PI*2; // ═══════════════════════════════════════════════════════ // CANVAS // ═══════════════════════════════════════════════════════ const c0=document.getElementById('c0'); const c1=document.getElementById('c1'); const c2=document.getElementById('c2'); const ctx=c0.getContext('2d'); const g1 =c1.getContext('2d'); // lighter — particles/nodes const g2 =c2.getContext('2d'); // screen — glow FX let W,H,cx,cy,DPR=Math.min(devicePixelRatio||1,2); function fitCanvas(c){ c.width =Math.floor(innerWidth *DPR); c.height=Math.floor(innerHeight*DPR); c.style.width =innerWidth +'px'; c.style.height=innerHeight+'px'; c.getContext('2d').setTransform(DPR,0,0,DPR,0,0); } function resize(){ DPR=Math.min(devicePixelRatio||1,2); W=innerWidth; H=innerHeight; cx=W/2; cy=H/2; [c0,c1,c2].forEach(fitCanvas); buildStars(); } window.addEventListener('resize',resize); // ═══════════════════════════════════════════════════════ // MOUSE / INPUT // ═══════════════════════════════════════════════════════ const M={x:0,y:0,nx:0,ny:0,down:false,lx:0,ly:0,vx:0,vy:0}; let rotX=.28, rotY=0, tZoom=1, zoom=1; let pulseAmt=0, novaAmt=0, shellP=0; let gT=0; // Figure-8 Lissajous auto-rotation let autoAngle=0; window.addEventListener('mousemove',e=>{ M.x=e.clientX; M.y=e.clientY; M.nx=(e.clientX/W-.5)*2; M.ny=(e.clientY/H-.5)*2; if(M.down){ M.vx=(e.clientX-M.lx)*.013; M.vy=(e.clientY-M.ly)*.013; rotY+=M.vx; rotX+=M.vy; } M.lx=e.clientX; M.ly=e.clientY; document.getElementById('hint').style.opacity='0'; }); window.addEventListener('mousedown',e=>{ M.down=true; M.lx=e.clientX; M.ly=e.clientY; }); window.addEventListener('mouseup', ()=>M.down=false); window.addEventListener('click', ()=>{ pulseAmt=1; shellP=1; spawnSparks(90); }); window.addEventListener('dblclick', ()=>{ novaAmt=1; shellP=1.5; spawnSparks(240); }); window.addEventListener('wheel', e=>{ tZoom=clamp(tZoom-e.deltaY*.0012,.3,2.8); },{passive:true}); // ═══════════════════════════════════════════════════════ // 3D MATH // ═══════════════════════════════════════════════════════ function rX(y,z,a){return{y:y*Math.cos(a)-z*Math.sin(a),z:y*Math.sin(a)+z*Math.cos(a)};} function rY(x,z,a){return{x:x*Math.cos(a)+z*Math.sin(a),z:-x*Math.sin(a)+z*Math.cos(a)};} const FOV=480; function proj(x,y,z){ const sc=FOV/(FOV+z+320); return{sx:cx+x*sc, sy:cy+y*sc, sc, z}; } // ═══════════════════════════════════════════════════════ // SPHERE NODES (Fibonacci distribution) // ═══════════════════════════════════════════════════════ const N=innerWidth<720?650:2000; const GOLD=Math.PI*(1+Math.sqrt(5)); const nodes=[]; const DIG='0123456789'; for(let i=0;i<N;i++){ const t=Math.acos(1-2*(i+.5)/N); const f=GOLD*i; const ox=Math.sin(t)*Math.cos(f); const oy=Math.sin(t)*Math.sin(f); const oz=Math.cos(t); const nd=Math.random()<.55?1:Math.random()<.72?2:3; let num=''; for(let d=0;d<nd;d++) num+=DIG[(Math.random()*10)|0]; nodes.push({ ox,oy,oz,num, hue: 182+Math.random()*60, spLen: .10+Math.random()*.28, fs: 7 +Math.random()*11, ph: Math.random()*PI2, drift: (Math.random()-.5)*.0045, w: .6+Math.random()*1.4, // weight/brightness // color wave phase (distance from north pole) lat: Math.acos(oz) // 0=north, PI=south }); } // ═══════════════════════════════════════════════════════ // PLEXUS CONNECTIONS // ═══════════════════════════════════════════════════════ const links=[]; const THRESH=.22; for(let i=0;i<N&&links.length<(innerWidth<720?1800:7500);i++) for(let j=i+1;j<N&&links.length<(innerWidth<720?1800:7500);j++){ const d=nodes[i].ox*nodes[j].ox+nodes[i].oy*nodes[j].oy+nodes[i].oz*nodes[j].oz; if(d>1-THRESH*.44) links.push([i,j]); } // ═══════════════════════════════════════════════════════ // ENERGY RIPPLES (click spawned rings on sphere surface) // ═══════════════════════════════════════════════════════ const ripples=[]; function spawnRipple(){ ripples.push({lat:Math.random()*Math.PI, t:0, life:2.2, hue:185+Math.random()*50}); } // ═══════════════════════════════════════════════════════ // SPARKS // ═══════════════════════════════════════════════════════ const sparks=[]; function spawnSparks(n){ spawnRipple(); for(let i=0;i<n;i++){ const a=Math.random()*PI2, b=Math.acos(2*Math.random()-1); const spd=1.5+Math.random()*8; sparks.push({ x:cx, y:cy, vx:Math.sin(b)*Math.cos(a)*spd, vy:Math.sin(b)*Math.sin(a)*spd, life:1+Math.random()*.6, decay:.010+Math.random()*.022, hue:182+Math.random()*60, sz:.7+Math.random()*2.4, trail:[] }); } } // ═══════════════════════════════════════════════════════ // STAR FIELD // ═══════════════════════════════════════════════════════ const stars=[]; function buildStars(){ stars.length=0; for(let i=0;i<280;i++) stars.push({ x:Math.random()*W, y:Math.random()*H, r:.2+Math.random()*1.4, a:.04+Math.random()*.3, ph:Math.random()*PI2, sp:.004+Math.random()*.02 }); } // ═══════════════════════════════════════════════════════ // COLOR WAVE ENGINE // Sweeping latitude bands of hue shift across sphere // ═══════════════════════════════════════════════════════ function waveHue(lat, t){ // three overlapping sine waves sweeping pole-to-pole const w1=Math.sin(lat*2.5 - t*1.1)*30; const w2=Math.sin(lat*1.2 + t*.7) *20; const w3=Math.sin(lat*4 - t*1.8)*12; return w1+w2+w3; } // ═══════════════════════════════════════════════════════ // SHOOTING METEORS around sphere // ═══════════════════════════════════════════════════════ const meteors=[]; function spawnMeteor(){ const ang=Math.random()*PI2; const R0=Math.min(W,H)*.48; meteors.push({ x:cx+Math.cos(ang)*R0, y:cy+Math.sin(ang)*R0*.72, vx:(Math.random()-.5)*6, vy:(Math.random()-.5)*4, life:1, decay:.008+Math.random()*.012, hue:185+Math.random()*55, len:40+Math.random()*80 }); } let meteorTimer=0; // ═══════════════════════════════════════════════════════ // MAIN LOOP // ═══════════════════════════════════════════════════════ function loop(ts){ gT=ts*.001; // ── auto figure-8 rotation ── autoAngle+=.0042; if(!M.down){ const asx=Math.sin(autoAngle*.7)*.0025; const asy=Math.sin(autoAngle)* .0058; rotY += asy + M.vx*.88; rotX += asx + M.vy*.88; M.vx*=.93; M.vy*=.93; } // magnetic mouse tilt (gentle lean toward cursor when not dragging) if(!M.down){ rotY=lerp(rotY, rotY+M.nx*.012, .08); rotX=lerp(rotX, rotX+M.ny*.008, .06); } rotX=clamp(rotX,-.95,.95); zoom=lerp(zoom,tZoom,.08); pulseAmt*=.93; novaAmt *=.92; if(novaAmt<.01) novaAmt=0; shellP *=.91; const R=Math.min(W,H)*.38*zoom; const breathe=1+.022*Math.sin(gT*1.35)+pulseAmt*.055; // ── clear layers ── ctx.fillStyle='rgba(0,1,8,.18)'; ctx.fillRect(0,0,W,H); g1.clearRect(0,0,W,H); g2.clearRect(0,0,W,H); g1.globalCompositeOperation='lighter'; g2.globalCompositeOperation='screen'; // ── deep BG glow ── const bg=ctx.createRadialGradient(cx,cy,0,cx,cy,R*2.2); bg.addColorStop(0,'rgba(0,20,60,.08)'); bg.addColorStop(.5,'rgba(0,10,40,.05)'); bg.addColorStop(1,'rgba(0,0,0,0)'); ctx.fillStyle=bg; ctx.fillRect(0,0,W,H); // ── stars ── for(const s of stars){ s.ph+=s.sp; const a=s.a+Math.sin(s.ph)*.06; ctx.beginPath(); ctx.arc(s.x,s.y,s.r,0,PI2); ctx.fillStyle=`rgba(255,255,255,${clamp(a,0,.4)})`; ctx.fill(); } // ── atmospheric rim ── const rp=1+shellP*.18+.04*Math.sin(gT*2.1); const rim=g2.createRadialGradient(cx,cy,R*.76,cx,cy,R*1.24*rp); rim.addColorStop(0,'rgba(0,160,255,0)'); rim.addColorStop(.42,'rgba(0,210,255,.20)'); rim.addColorStop(.70,'rgba(80,235,255,.52)'); rim.addColorStop(.88,'rgba(60,100,255,.15)'); rim.addColorStop(1,'rgba(0,0,0,0)'); g2.fillStyle=rim; g2.beginPath(); g2.arc(cx,cy,R*1.26*rp,0,PI2); g2.fill(); // secondary shimmer ring for(let k=0;k<3;k++){ const kr=R*(.92+k*.055+Math.sin(gT*.85+k)*.018); g2.beginPath(); g2.arc(cx,cy,kr,0,PI2); g2.strokeStyle=`rgba(100,230,255,${.07-k*.018})`; g2.lineWidth=1.2-k*.3; g2.stroke(); } // ── horizontal scan bands ── for(let b=0;b<4;b++){ const by=cy+Math.sin(gT*.7+b*1.4)*R*.5; const bh=12+b*5; const bl=g2.createLinearGradient(cx-R*1.2,by,cx+R*1.2,by); bl.addColorStop(0,'rgba(0,0,0,0)'); bl.addColorStop(.5,`rgba(0,200,255,${.04+.02*Math.sin(gT+b)})`); bl.addColorStop(1,'rgba(0,0,0,0)'); g2.fillStyle=bl; g2.fillRect(cx-R*1.2,by-bh*.5,R*2.4,bh); } // ── rotate & project all nodes ── const pj=new Array(N); for(let i=0;i<N;i++){ const nd=nodes[i]; nd.ph+=nd.drift; const nova=1+novaAmt*1.9; const wb=breathe*nova; const px=nd.ox*wb, py=nd.oy*wb, pz=nd.oz*wb; const ry=rY(px,pz,rotY); const rx=rX(py,ry.z,rotX); const fx=ry.x*R, fy=rx.y*R, fz=rx.z*R; pj[i]={...proj(fx,fy,fz), fx,fy,fz,nd,i}; } pj.sort((a,b)=>a.z-b.z); const idxMap=new Array(N); pj.forEach(p=>idxMap[p.i]=p); // ── plexus links with color wave ── ctx.globalCompositeOperation='source-over'; ctx.lineCap='round'; for(const [ai,bi] of links){ const a=idxMap[ai], b=idxMap[bi]; if(!a||!b) continue; if(a.z<-R*.7&&b.z<-R*.7) continue; const depth=clamp(((a.z+b.z)*.5/R+1)*.5,0,1); const al=depth*.20+pulseAmt*.06; if(al<.01) continue; const wh=waveHue(a.nd.lat,gT)*.5+waveHue(b.nd.lat,gT)*.5; const hue=clamp(190+wh,140,280); ctx.beginPath(); ctx.moveTo(a.sx,a.sy); ctx.lineTo(b.sx,b.sy); ctx.strokeStyle=`hsla(${hue},100%,${55+depth*30}%,${al})`; ctx.lineWidth=.3+depth*.55; ctx.stroke(); } // ── energy ripples (latitude rings sweeping across sphere) ── for(let ri=ripples.length-1;ri>=0;ri--){ const rp2=ripples[ri]; rp2.t+=.016; if(rp2.t>rp2.life){ripples.splice(ri,1);continue;} const prog=rp2.t/rp2.life; // sweep latitude from 0→PI over lifetime const lat=prog*Math.PI; const sinLat=Math.sin(lat); // ring radius in 3D const rRad=sinLat*R*breathe; const rY2 =Math.cos(lat)*R*breathe; // project ring as ellipse const ry2=rX(rY2,0,rotX); const prY=proj(0,ry2.y,ry2.z); const ellA=rRad*proj(rRad,0,0).sc; const ellB=Math.abs(rRad*Math.cos(rotX)*.45)*proj(0,0,0).sc+1; const al2=(1-prog)*.55; ctx.beginPath(); ctx.ellipse(prY.sx,prY.sy,Math.max(1,ellA),Math.max(1,ellB),0,0,PI2); ctx.strokeStyle=`hsla(${rp2.hue},100%,75%,${al2})`; ctx.lineWidth=1.5*(1-prog)+.5; ctx.stroke(); // glow on g2 g2.beginPath(); g2.ellipse(prY.sx,prY.sy,Math.max(1,ellA),Math.max(1,ellB),0,0,PI2); g2.strokeStyle=`hsla(${rp2.hue},100%,80%,${al2*.5})`; g2.lineWidth=8*(1-prog); g2.stroke(); } // ── nodes + spines + numbers ── for(const {sx,sy,sc,z,fx,fy,fz,nd} of pj){ const depth=clamp((z/R+1)*.5,0,1); if(depth<.04) continue; nd.ph+=nd.drift*.3; const pulse=pulseAmt*Math.sin(gT*13+nd.ph); const wh=waveHue(nd.lat,gT); const hue=clamp(nd.hue+wh+pulse*22+gT*9,100,310); const al=clamp(.15+depth*.85,0,1)*(1-novaAmt*.3); // spine const nx=fx/(R*breathe), ny=fy/(R*breathe), nz=fz/(R*breathe); const sp=nd.spLen*R*(1+pulse*.45+novaAmt*.65)*breathe; const tp=proj(fx+nx*sp, fy+ny*sp, fz+nz*sp); const sg=ctx.createLinearGradient(sx,sy,tp.sx,tp.sy); sg.addColorStop(0,`hsla(${hue},100%,55%,${al*.38})`); sg.addColorStop(.6,`hsla(${hue},100%,78%,${al*.75})`); sg.addColorStop(1,`hsla(${hue+12},100%,96%,${al})`); ctx.beginPath(); ctx.moveTo(sx,sy); ctx.lineTo(tp.sx,tp.sy); ctx.strokeStyle=sg; ctx.lineWidth=Math.max(.2,sc*.7*(1+pulse*.4)*nd.w); ctx.stroke(); // node dot const nr=Math.max(.5,sc*(2.5+pulse*.7)*nd.w); ctx.beginPath(); ctx.arc(sx,sy,nr,0,PI2); ctx.fillStyle=`hsla(${hue},100%,88%,${al})`; ctx.fill(); // node glow (g1 lighter) if(depth>.32){ const gr2=sc*8*(1+pulse*.5); const ng=g1.createRadialGradient(sx,sy,0,sx,sy,gr2); ng.addColorStop(0,`hsla(${hue},100%,80%,${depth*.22})`); ng.addColorStop(1,'rgba(0,0,0,0)'); g1.fillStyle=ng; g1.beginPath(); g1.arc(sx,sy,gr2,0,PI2); g1.fill(); } // number label if(depth>.20&&sc>.12){ const fs=clamp(nd.fs*sc*zoom*(1+pulse*.2),5.5,28); ctx.font=`700 ${fs.toFixed(1)}px "Courier New"`; const ta=(.22+depth*.78)*al; ctx.fillStyle=`hsla(${hue},90%,88%,${ta})`; ctx.fillText(nd.num, tp.sx-(fs*.28), tp.sy+(fs*.35)); } } // ── core multi-ring glow ── const cp=1+pulseAmt*1.3+novaAmt*2.8; [[R*.055*cp,'rgba(220,255,255,.95)'],[R*.14*cp,'rgba(0,240,255,.5)'], [R*.32*cp,'rgba(0,160,255,.18)'],[R*.6*cp,'rgba(0,80,200,.06)']].forEach(([r,col])=>{ const cg=g2.createRadialGradient(cx,cy,0,cx,cy,r); cg.addColorStop(0,col); cg.addColorStop(1,'rgba(0,0,0,0)'); g2.fillStyle=cg; g2.beginPath(); g2.arc(cx,cy,r,0,PI2); g2.fill(); }); // ── meteors ── meteorTimer++; if(meteorTimer>90){ meteorTimer=0; spawnMeteor(); } for(let i=meteors.length-1;i>=0;i--){ const m=meteors[i]; m.life-=m.decay; if(m.life<=0){meteors.splice(i,1);continue;} const tail=ctx.createLinearGradient(m.x,m.y,m.x-m.vx*m.len*.2,m.y-m.vy*m.len*.2); tail.addColorStop(0,`hsla(${m.hue},100%,90%,${m.life*.7})`); tail.addColorStop(1,'rgba(0,0,0,0)'); ctx.beginPath(); ctx.moveTo(m.x,m.y); ctx.lineTo(m.x-m.vx*m.len*.2, m.y-m.vy*m.len*.2); ctx.strokeStyle=tail; ctx.lineWidth=m.life*2; ctx.stroke(); m.x+=m.vx; m.y+=m.vy; } // ── sparks with trails ── for(let i=sparks.length-1;i>=0;i--){ const s=sparks[i]; s.trail.push({x:s.x,y:s.y}); if(s.trail.length>10) s.trail.shift(); s.x+=s.vx*(R*.014); s.y+=s.vy*(R*.014); s.vx*=.97; s.vy*=.97; s.life-=s.decay; if(s.life<=0){sparks.splice(i,1);continue;} for(let ti=1;ti<s.trail.length;ti++){ const ta=(ti/s.trail.length)*s.life*.5; ctx.beginPath(); ctx.moveTo(s.trail[ti-1].x,s.trail[ti-1].y); ctx.lineTo(s.trail[ti].x,s.trail[ti].y); ctx.strokeStyle=`hsla(${s.hue},100%,82%,${ta})`; ctx.lineWidth=s.sz*ti/s.trail.length; ctx.stroke(); } ctx.beginPath(); ctx.arc(s.x,s.y,s.sz*clamp(s.life,0,1),0,PI2); ctx.fillStyle=`hsla(${s.hue},100%,92%,${clamp(s.life,0,1)*.85})`; ctx.fill(); } // ── composite all layers ── ctx.save(); ctx.globalCompositeOperation='screen'; ctx.drawImage(c1,0,0); ctx.drawImage(c2,0,0); ctx.restore(); // ── custom cursor ── const mx=M.x||cx, my=M.y||cy; const ch=(192+gT*25)%360; const cr=9+shellP*5; ctx.globalCompositeOperation='source-over'; // rotating ring ctx.save(); ctx.translate(mx,my); ctx.rotate(gT*.8); ctx.beginPath(); ctx.arc(0,0,cr,0,PI2); ctx.strokeStyle=`hsla(${ch},100%,72%,.82)`; ctx.lineWidth=1.1; ctx.stroke(); [0,.5,1,1.5].forEach(f=>{ const a=f*Math.PI; ctx.beginPath(); ctx.moveTo(Math.cos(a)*(cr+3),Math.sin(a)*(cr+3)); ctx.lineTo(Math.cos(a)*(cr+8),Math.sin(a)*(cr+8)); ctx.strokeStyle=`hsla(${ch},100%,82%,.6)`; ctx.lineWidth=1; ctx.stroke(); }); ctx.restore(); ctx.beginPath(); ctx.arc(mx,my,1.8,0,PI2); ctx.fillStyle=`hsla(${ch},100%,98%,1)`; ctx.fill(); // ── HUD ── ctx.font='700 9px "Courier New"'; ctx.letterSpacing='1px'; ctx.fillStyle='rgba(0,190,255,.24)'; ctx.textAlign='left'; ctx.fillText('SIMON // COGNITIVE SPHERE 8K',22,24); ctx.fillText(`NODES ${N} LINKS ${links.length} ZOOM ${zoom.toFixed(2)}x`,22,H-20); ctx.textAlign='right'; const n=new Date(),p=v=>String(v).padStart(2,'0'); ctx.fillText(`${n.getFullYear()}.${p(n.getMonth()+1)}.${p(n.getDate())} ${p(n.getHours())}:${p(n.getMinutes())}:${p(n.getSeconds())}`,W-22,H-20); ctx.textAlign='left'; requestAnimationFrame(loop); } // ═══════════════════════════════════════════════════════ // BOOT // ═══════════════════════════════════════════════════════ resize(); M.x=cx; M.y=cy; setTimeout(()=>spawnSparks(40),600); // intro burst requestAnimationFrame(loop); })();
Save file
Quick jump
open a path
Open