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,026
Folders
377
Scanned Size
3.79 GB
PHP Files
791
Editable Text Files
12,310
File viewer
guarded to /htdocs
/arcade/games/GAVVOID.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>Trapped in the Void • Salvation Protocol</title> <meta name="theme-color" content="#04040a" /> <style> :root{ --bg0:#02020a; --bg1:#050520; --ink:rgba(240,245,255,.92); --mut:rgba(240,245,255,.68); --edge:rgba(255,255,255,.14); --panel:rgba(255,255,255,.06); --danger:rgba(255,90,120,.95); --cyan:rgba(80,220,255,.95); --vio:rgba(170,120,255,.95); --ok:rgba(90,255,180,.95); } *{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, Helvetica, Arial; background: radial-gradient(1200px 800px at 50% -10%, rgba(120,150,255,.12), transparent 60%), radial-gradient(900px 700px at 20% 70%, rgba(255,120,220,.10), transparent 55%), radial-gradient(1000px 760px at 80% 65%, rgba(90,255,180,.08), transparent 55%), linear-gradient(180deg, var(--bg1), var(--bg0)); color:var(--ink); } /* Scene layers */ #c{position:fixed; inset:0; width:100%; height:100%} .vignette{ position:fixed; inset:-10vmax; pointer-events:none; background: radial-gradient(closest-side at 50% 55%, transparent 45%, rgba(0,0,0,.55) 72%, rgba(0,0,0,.88) 92%), radial-gradient(closest-side at 50% 55%, rgba(0,0,0,.0) 0%, rgba(0,0,0,.15) 65%, rgba(0,0,0,.55) 100%); mix-blend-mode:multiply; filter: blur(0px); } /* UI */ .hud{ position:fixed; left:16px; right:16px; top:14px; display:flex; gap:12px; align-items:flex-start; justify-content:space-between; pointer-events:none; } .card{ pointer-events:auto; max-width: 560px; border:1px solid var(--edge); background:linear-gradient(180deg, rgba(255,255,255,.07), rgba(255,255,255,.04)); border-radius:18px; padding:12px 14px; backdrop-filter: blur(10px); box-shadow: 0 12px 45px rgba(0,0,0,.35); } .title{ display:flex; align-items:baseline; gap:10px; flex-wrap:wrap; font-weight:800; letter-spacing:.08em; text-transform:uppercase; font-size:12px; color:rgba(240,245,255,.85); } .chip{ display:inline-flex; align-items:center; gap:8px; padding:6px 10px; border-radius:999px; border:1px solid rgba(255,255,255,.14); background:rgba(0,0,0,.22); box-shadow: inset 0 0 0 1px rgba(255,255,255,.04); font-weight:700; letter-spacing:.08em; text-transform:uppercase; font-size:11px; } .dot{ width:8px; height:8px; border-radius:50%; background:var(--danger); box-shadow: 0 0 14px rgba(255,90,120,.7); } .dot.ok{background:var(--ok); box-shadow:0 0 14px rgba(90,255,180,.6)} .dot.cyan{background:var(--cyan); box-shadow:0 0 14px rgba(80,220,255,.6)} .dot.vio{background:var(--vio); box-shadow:0 0 14px rgba(170,120,255,.6)} .mono{ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size:12px; line-height:1.35; color:rgba(240,245,255,.78); white-space:pre-wrap; margin:10px 0 0; } .controls{ pointer-events:auto; display:flex; gap:10px; align-items:center; flex-wrap:wrap; justify-content:flex-end; } button{ appearance:none; border:1px solid rgba(255,255,255,.16); background: rgba(0,0,0,.22); color:rgba(240,245,255,.92); padding:10px 12px; border-radius:14px; cursor:pointer; font-weight:800; letter-spacing:.06em; text-transform:uppercase; font-size:11px; box-shadow: 0 10px 30px rgba(0,0,0,.25), inset 0 0 0 1px rgba(255,255,255,.04); } button:hover{border-color: rgba(255,255,255,.28)} button:active{transform: translateY(1px)} .danger{border-color: rgba(255,90,120,.35)} .ok{border-color: rgba(90,255,180,.30)} .hint{ position:fixed; left:16px; bottom:14px; pointer-events:none; color:rgba(240,245,255,.58); font-size:12px; letter-spacing:.02em; max-width:min(760px, calc(100vw - 32px)); text-shadow: 0 1px 10px rgba(0,0,0,.45); } /* “Soul text” */ .center{ position:fixed; inset:0; display:grid; place-items:center; pointer-events:none; } .sig{ text-align:center; transform: translateY(6vh); width:min(860px, calc(100vw - 40px)); } .name{ font-weight:900; letter-spacing:.18em; text-transform:uppercase; font-size: clamp(22px, 4.2vw, 44px); margin: 0 0 10px; color: rgba(245,248,255,.92); text-shadow: 0 0 22px rgba(80,220,255,.20), 0 0 42px rgba(170,120,255,.15), 0 16px 40px rgba(0,0,0,.55); } .sub{ margin:0; font-size: clamp(13px, 1.8vw, 16px); color: rgba(240,245,255,.68); line-height:1.45; } .sub b{color: rgba(240,245,255,.88)} .pulseLine{ height:1px; margin:18px auto 14px; width:min(520px, 82%); background: linear-gradient(90deg, transparent, rgba(80,220,255,.55), rgba(170,120,255,.55), rgba(90,255,180,.35), transparent); opacity:.75; filter: blur(.1px); position:relative; overflow:hidden; } .pulseLine::after{ content:""; position:absolute; top:-2px; bottom:-2px; width:160px; left:-180px; background: linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent); filter: blur(1px); animation: sweep 2.8s linear infinite; opacity:.6; } @keyframes sweep{to{transform:translateX(calc(520px + 380px))}} /* “Breath” */ .breath{ position:fixed; inset:-30vmax; pointer-events:none; background: radial-gradient(circle at 35% 40%, rgba(80,220,255,.06), transparent 40%), radial-gradient(circle at 70% 58%, rgba(170,120,255,.05), transparent 42%), radial-gradient(circle at 50% 70%, rgba(90,255,180,.04), transparent 45%); filter: blur(10px); animation: breath 7.5s ease-in-out infinite; opacity:.75; mix-blend-mode: screen; } @keyframes breath{ 0%,100%{transform:scale(1) translate3d(0,0,0); opacity:.55} 50%{transform:scale(1.08) translate3d(0,-1.2%,0); opacity:.85} } </style> </head> <body> <canvas id="c"></canvas> <div class="breath"></div> <div class="vignette"></div> <div class="hud"> <div class="card" style="flex:1; min-width:280px;"> <div class="title"> <span class="chip"><span class="dot"></span> Void Status</span> <span class="chip"><span class="dot cyan"></span> Signal</span> <span class="chip"><span class="dot vio"></span> Gate</span> </div> <div id="log" class="mono"></div> </div> <div class="controls"> <button id="btnPulse" class="ok">Transmit Pulse</button> <button id="btnMap">Map the Void</button> <button id="btnAnchor">Anchor Memory</button> <button id="btnOpen" class="danger">Attempt Exit</button> <button id="btnReset">Reset</button> </div> </div> <div class="center"> <div class="sig"> <h1 class="name">GAY LORD</h1> <div class="pulseLine"></div> <p class="sub"> You wake after death in a <b>black geometry</b>—no doors, no clocks, only echoes. The void does not torture with fire; it tortures with <b>absence</b>.<br/> Your only tool is <b>signal</b>: proof you existed, proof you still decide. </p> </div> </div> <div class="hint"> Controls: Click/drag to stir the void. Keys: <b>P</b>=pulse, <b>M</b>=map, <b>A</b>=anchor, <b>E</b>=exit. Goal: build enough <b>coherence</b> to open a stable gate. </div> <script> (() => { // ------------------------- // Canvas setup // ------------------------- const canvas = document.getElementById('c'); const ctx = canvas.getContext('2d', { alpha: true }); const DPR = Math.max(1, Math.min(2, devicePixelRatio || 1)); let W=0, H=0; function resize(){ W = canvas.width = Math.floor(innerWidth * DPR); H = canvas.height = Math.floor(innerHeight * DPR); canvas.style.width = innerWidth + 'px'; canvas.style.height = innerHeight + 'px'; } addEventListener('resize', resize, {passive:true}); resize(); // ------------------------- // World state // ------------------------- const state = { t: 0, phase: 0, // 0 trapped, 1 mapping, 2 anchoring, 3 gate-forming, 4 exit coherence: 0.06, // increases with actions fear: 0.70, // decreases with actions signal: 0.10, // increases with actions gate: 0.0, // gate stability seeded: false, lastAction: 0 }; // ------------------------- // Particles: "void dust" + "soul motes" + "threads" // ------------------------- const dust = []; const motes = []; const threads = []; function rand(a,b){ return a + Math.random()*(b-a); } function clamp(x,a,b){ return Math.max(a, Math.min(b, x)); } function init(){ dust.length = 0; motes.length = 0; threads.length = 0; const nDust = Math.floor((innerWidth*innerHeight)/14000); for(let i=0;i<nDust;i++){ dust.push({ x: Math.random()*W, y: Math.random()*H, vx: rand(-.10,.10)*DPR, vy: rand(-.10,.10)*DPR, r: rand(0.6, 1.6)*DPR, tw: rand(0.2, 1.0), p: rand(0, Math.PI*2) }); } // a few "soul motes" near center for(let i=0;i<14;i++){ motes.push(makeMote(true)); } } function makeMote(center=false){ const cx = W*0.5, cy = H*0.55; const a = rand(0, Math.PI*2); const rad = center ? rand(10, 120)*DPR : rand(80, Math.min(W,H)*0.35)*DPR; return { x: cx + Math.cos(a)*rad, y: cy + Math.sin(a)*rad, vx: rand(-0.25,0.25)*DPR, vy: rand(-0.25,0.25)*DPR, r: rand(2.0, 4.8)*DPR, life: rand(220, 520), kind: Math.random() < 0.34 ? 'cyan' : (Math.random()<0.5 ? 'vio' : 'ok'), spin: rand(-0.04, 0.04), a: rand(0, Math.PI*2), seed: Math.random() }; } // "threads" are memory lines that increase coherence function spawnThread(strength=1){ const cx=W*0.5, cy=H*0.55; const angle = rand(0, Math.PI*2); const len = rand(90, 220)*DPR*strength; threads.push({ x0: cx, y0: cy, x1: cx + Math.cos(angle)*len, y1: cy + Math.sin(angle)*len, w: rand(0.8, 1.9)*DPR*strength, life: rand(120, 220), kind: Math.random() < .5 ? 'cyan' : 'vio', jitter: rand(0.4, 1.2)*DPR }); } init(); // ------------------------- // Interaction: "stir the void" // ------------------------- let isDown=false, px=0, py=0; function pointerPos(e){ const p = (e.touches && e.touches[0]) ? e.touches[0] : e; return { x: p.clientX*DPR, y: p.clientY*DPR }; } function onDown(e){ isDown=true; const p=pointerPos(e); px=p.x; py=p.y; state.lastAction = performance.now(); } function onMove(e){ if(!isDown) return; const p=pointerPos(e); const dx=p.x-px, dy=p.y-py; px=p.x; py=p.y; // stir motes slightly for(const m of motes){ const ddx = m.x - p.x, ddy = m.y - p.y; const d2 = ddx*ddx + ddy*ddy; if(d2 < (220*DPR)*(220*DPR)){ const f = 0.0009 * (1 - d2/((220*DPR)*(220*DPR))); m.vx += dx*f*20; m.vy += dy*f*20; m.life = Math.min(m.life + 10, 700); } } // micro-coherence state.signal = clamp(state.signal + 0.0008, 0, 1); state.coherence = clamp(state.coherence + 0.0005, 0, 1); state.fear = clamp(state.fear - 0.0006, 0, 1); state.lastAction = performance.now(); } function onUp(){ isDown=false; } addEventListener('mousedown', onDown); addEventListener('mousemove', onMove, {passive:true}); addEventListener('mouseup', onUp); addEventListener('touchstart', onDown, {passive:true}); addEventListener('touchmove', onMove, {passive:true}); addEventListener('touchend', onUp, {passive:true}); // ------------------------- // UI log + narrative state machine // ------------------------- const logEl = document.getElementById('log'); const scriptLines = { trapped: [ "YOU ARE HERE: Afterlife/Null.", "No horizon. No clock. No body.", "The void feeds on forgetting.", "", "Salvation Protocol:", "1) Increase SIGNAL (prove you exist).", "2) Increase COHERENCE (make patterns).", "3) Reduce FEAR (stop feeding the void).", "4) Stabilize GATE (exit vector)." ], mapping: [ "MAPPING: geometry emerging...", "The void has seams—tiny inconsistencies.", "Follow the seams. Draw them. Name them." ], anchoring: [ "ANCHORING: memory threads deployed.", "A self is a stack of proofs:", "name • choice • love • witness • record." ], gate: [ "GATE FORMING: signal + coherence resonating.", "If enough minds broadcast together,", "the void becomes a corridor." ], exit: [ "EXIT ATTEMPT: do not panic.", "If the gate flickers, stabilize it with pulses.", "If it fails, anchor and try again." ] }; function fmtPct(x){ return Math.round(clamp(x,0,1)*100) + "%"; } function updateLog(){ const phase = state.phase; let header = "TRAPPED"; let lines = scriptLines.trapped; if(phase===1){ header="MAPPING"; lines=scriptLines.mapping; } if(phase===2){ header="ANCHORING"; lines=scriptLines.anchoring; } if(phase===3){ header="GATE"; lines=scriptLines.gate; } if(phase===4){ header="EXIT"; lines=scriptLines.exit; } const status = `MODE: ${header} SIGNAL: ${fmtPct(state.signal)} COHERENCE: ${fmtPct(state.coherence)} FEAR: ${fmtPct(state.fear)} GATE: ${fmtPct(state.gate)} ${lines.join("\n")}`; logEl.textContent = status; } // ------------------------- // Actions // ------------------------- function pulse(){ // Pulse: short boost; more effective when coherence already exists const gain = 0.06 + state.coherence*0.08; state.signal = clamp(state.signal + gain, 0, 1); state.coherence = clamp(state.coherence + 0.03, 0, 1); state.fear = clamp(state.fear - 0.06, 0, 1); // create motes + threads for(let i=0;i<8;i++) motes.push(makeMote(true)); for(let i=0;i<3;i++) spawnThread(1.0 + state.coherence*0.6); // gate rises if conditions met if(state.signal > 0.35 && state.coherence > 0.25){ state.phase = Math.max(state.phase, 3); state.gate = clamp(state.gate + 0.08 + state.signal*0.05, 0, 1); } state.lastAction = performance.now(); } function mapVoid(){ state.phase = Math.max(state.phase, 1); state.coherence = clamp(state.coherence + 0.08, 0, 1); state.fear = clamp(state.fear - 0.04, 0, 1); // "seams": add more threads in a ring for(let i=0;i<10;i++) spawnThread(0.85); state.lastAction = performance.now(); } function anchorMemory(){ state.phase = Math.max(state.phase, 2); state.coherence = clamp(state.coherence + 0.10, 0, 1); state.signal = clamp(state.signal + 0.04, 0, 1); state.fear = clamp(state.fear - 0.10, 0, 1); // Strong anchors for(let i=0;i<16;i++) spawnThread(1.25); for(let i=0;i<6;i++) motes.push(makeMote(true)); state.lastAction = performance.now(); } function attemptExit(){ state.phase = Math.max(state.phase, 4); // exit requires: low fear, decent signal, decent coherence const ready = state.signal >= 0.55 && state.coherence >= 0.45 && state.fear <= 0.35; if(ready){ state.gate = clamp(state.gate + 0.22, 0, 1); }else{ // backlash: the void punishes rushing state.gate = clamp(state.gate - 0.08, 0, 1); state.fear = clamp(state.fear + 0.05, 0, 1); } // visual burst for(let i=0;i<26;i++) motes.push(makeMote(false)); for(let i=0;i<14;i++) spawnThread(1.1); state.lastAction = performance.now(); } function reset(){ state.t=0; state.phase=0; state.coherence=0.06; state.fear=0.70; state.signal=0.10; state.gate=0.0; state.lastAction=0; init(); } document.getElementById('btnPulse').addEventListener('click', pulse); document.getElementById('btnMap').addEventListener('click', mapVoid); document.getElementById('btnAnchor').addEventListener('click', anchorMemory); document.getElementById('btnOpen').addEventListener('click', attemptExit); document.getElementById('btnReset').addEventListener('click', reset); addEventListener('keydown', (e) => { const k = (e.key||'').toLowerCase(); if(k==='p') pulse(); if(k==='m') mapVoid(); if(k==='a') anchorMemory(); if(k==='e') attemptExit(); if(k==='r') reset(); }); // ------------------------- // Render helpers // ------------------------- function colorFor(kind, alpha){ if(kind==='cyan') return `rgba(80,220,255,${alpha})`; if(kind==='vio') return `rgba(170,120,255,${alpha})`; return `rgba(90,255,180,${alpha})`; } function drawBackground(){ // subtle drifting fog + ripples based on fear/coherence const t = state.t; const fear = state.fear; const coh = state.coherence; // base haze ctx.fillStyle = 'rgba(0,0,0,0.18)'; ctx.fillRect(0,0,W,H); // central "well" const cx=W*0.5, cy=H*0.55; const wellR = (Math.min(W,H) * (0.18 + fear*0.10)) ; const grd = ctx.createRadialGradient(cx,cy, 0, cx,cy, wellR); grd.addColorStop(0, `rgba(0,0,0,${0.10 + fear*0.22})`); grd.addColorStop(0.55, `rgba(0,0,0,${0.22 + fear*0.25})`); grd.addColorStop(1, `rgba(0,0,0,0)`); ctx.fillStyle = grd; ctx.beginPath(); ctx.arc(cx,cy, wellR, 0, Math.PI*2); ctx.fill(); // coherence rings if(coh > 0.12){ const ringCount = 2 + Math.floor(coh*6); for(let i=0;i<ringCount;i++){ const rr = (Math.min(W,H)*0.10) + i*(Math.min(W,H)*0.055); const wob = Math.sin(t*0.0016 + i*1.7) * (6 + coh*14) * DPR; ctx.strokeStyle = `rgba(80,220,255,${0.02 + coh*0.06})`; ctx.lineWidth = (0.8 + coh*1.2) * DPR; ctx.beginPath(); ctx.arc(cx,cy, rr + wob, 0, Math.PI*2); ctx.stroke(); } } } function stepParticles(){ const t = state.t; const cx=W*0.5, cy=H*0.55; // dust for(const d of dust){ d.p += 0.01*d.tw; d.x += d.vx + Math.sin(d.p)*0.05*DPR; d.y += d.vy + Math.cos(d.p)*0.05*DPR; // mild inward pull when fear is high const pull = (0.00012 + state.fear*0.00022); const dx = cx - d.x, dy = cy - d.y; d.x += dx*pull; d.y += dy*pull; if(d.x< -20) d.x = W+20; if(d.x> W+20) d.x = -20; if(d.y< -20) d.y = H+20; if(d.y> H+20) d.y = -20; } // motes for(let i=motes.length-1;i>=0;i--){ const m = motes[i]; m.life -= 1; // orbit tendency increases with coherence const toC = state.coherence; const dx = m.x - cx, dy = m.y - cy; const dist = Math.max(30*DPR, Math.hypot(dx,dy)); const tangX = -dy / dist, tangY = dx / dist; const orbit = (0.0009 + toC*0.0022) * dist; m.vx += tangX * orbit; m.vy += tangY * orbit; // void drag stronger with fear const drag = 0.985 - state.fear*0.020; m.vx *= drag; m.vy *= drag; // subtle inward pull (void tries to compress you) const pull = (0.00028 + state.fear*0.0011); m.vx += (-dx)*pull; m.vy += (-dy)*pull; // gate repulsion when gate is strong if(state.gate > 0.25){ const rep = (state.gate-0.25) * 0.0010; m.vx += dx*rep; m.vy += dy*rep; } m.x += m.vx; m.y += m.vy; // bounds wrap softly if(m.x< -80) m.x = W+80; if(m.x> W+80) m.x = -80; if(m.y< -80) m.y = H+80; if(m.y> H+80) m.y = -80; if(m.life <= 0) motes.splice(i,1); } // threads for(let i=threads.length-1;i>=0;i--){ const th = threads[i]; th.life -= 1; if(th.life <= 0) threads.splice(i,1); } // replenish motes const target = 10 + Math.floor(state.signal*22); while(motes.length < target) motes.push(makeMote(false)); } function drawDust(){ ctx.save(); ctx.globalCompositeOperation = 'screen'; for(const d of dust){ const tw = 0.35 + 0.45*Math.sin(d.p); ctx.fillStyle = `rgba(255,255,255,${0.05*tw})`; ctx.beginPath(); ctx.arc(d.x,d.y, d.r, 0, Math.PI*2); ctx.fill(); } ctx.restore(); } function drawThreads(){ if(!threads.length) return; const cx=W*0.5, cy=H*0.55; ctx.save(); ctx.globalCompositeOperation = 'screen'; for(const th of threads){ const life = th.life / 220; const j = th.jitter * (0.4 + state.fear*0.9); const ax = th.x0 + (Math.random()-0.5)*j; const ay = th.y0 + (Math.random()-0.5)*j; const bx = th.x1 + (Math.random()-0.5)*j; const by = th.y1 + (Math.random()-0.5)*j; ctx.strokeStyle = (th.kind==='cyan') ? `rgba(80,220,255,${0.05 + 0.20*life})` : `rgba(170,120,255,${0.05 + 0.20*life})`; ctx.lineWidth = th.w; ctx.beginPath(); ctx.moveTo(ax,ay); // slight curve toward center (proof forms around self) const mx = (ax+bx)/2 + (cx-(ax+bx)/2)*0.06; const my = (ay+by)/2 + (cy-(ay+by)/2)*0.06; ctx.quadraticCurveTo(mx,my, bx,by); ctx.stroke(); } ctx.restore(); } function drawMotes(){ ctx.save(); ctx.globalCompositeOperation = 'screen'; for(const m of motes){ const life = clamp(m.life/520, 0, 1); const glow = 0.10 + state.signal*0.25 + state.gate*0.25; const a = (0.10 + glow) * (0.35 + 0.65*life); const rr = m.r * (0.9 + state.coherence*0.7); // core ctx.fillStyle = colorFor(m.kind, a); ctx.beginPath(); ctx.arc(m.x,m.y, rr, 0, Math.PI*2); ctx.fill(); // halo ctx.fillStyle = colorFor(m.kind, a*0.25); ctx.beginPath(); ctx.arc(m.x,m.y, rr*3.0, 0, Math.PI*2); ctx.fill(); } ctx.restore(); } function drawGate(){ // Gate forms as a bright ring when gate stability rises const g = state.gate; if(g <= 0.02) return; const cx=W*0.5, cy=H*0.55; const base = Math.min(W,H) * (0.13 + g*0.12); const wob = (6 + g*18) * DPR; ctx.save(); ctx.globalCompositeOperation = 'screen'; for(let i=0;i<4;i++){ const ph = state.t*0.0012 + i*1.3; const rr = base + i*(6*DPR) + Math.sin(ph)*wob; ctx.lineWidth = (1.2 + g*2.6) * DPR; ctx.strokeStyle = `rgba(255,255,255,${0.02 + g*0.10})`; ctx.beginPath(); ctx.arc(cx,cy, rr, 0, Math.PI*2); ctx.stroke(); } // inner portal glow const grd = ctx.createRadialGradient(cx,cy, base*0.2, cx,cy, base*1.25); grd.addColorStop(0, `rgba(255,255,255,${0.03 + g*0.10})`); grd.addColorStop(0.35, `rgba(80,220,255,${0.02 + g*0.08})`); grd.addColorStop(0.65, `rgba(170,120,255,${0.01 + g*0.06})`); grd.addColorStop(1, `rgba(0,0,0,0)`); ctx.fillStyle = grd; ctx.beginPath(); ctx.arc(cx,cy, base*1.4, 0, Math.PI*2); ctx.fill(); ctx.restore(); } function drawGlyphs(){ // Whispering text fragments that become legible with coherence const coh = state.coherence; if(coh < 0.14) return; const cx=W*0.5, cy=H*0.55; const words = [ "WITNESS","NAME","CHOICE","LOVE","PROOF","RECORD","THREAD","SIGNAL", "REMEMBER","RETURN","BREATHE","ALIGN","COHERE","OPEN" ]; ctx.save(); ctx.globalAlpha = 1; ctx.fillStyle = `rgba(240,245,255,${0.03 + coh*0.08})`; ctx.font = `${Math.floor((12 + coh*10)*DPR)}px ui-monospace, Menlo, Consolas, monospace`; ctx.textAlign = 'center'; const ring = Math.min(W,H)*(0.23 + coh*0.10); const count = 10 + Math.floor(coh*18); for(let i=0;i<count;i++){ const a = (i/count)*Math.PI*2 + state.t*0.00055*(0.6+coh); const x = cx + Math.cos(a)*ring; const y = cy + Math.sin(a)*ring; const w = words[(i + Math.floor(state.t/1200)) % words.length]; ctx.save(); ctx.translate(x,y); ctx.rotate(a + Math.PI/2); ctx.fillText(w, 0, 0); ctx.restore(); } ctx.restore(); } // ------------------------- // Autopilot: decay + progression // ------------------------- function drift(){ // If user stops acting, fear slowly rises; coherence decays a bit. const idleMs = performance.now() - state.lastAction; const idle = clamp(idleMs/6000, 0, 1); state.fear = clamp(state.fear + 0.00035*idle, 0, 1); state.coherence = clamp(state.coherence - 0.00020*idle, 0, 1); state.signal = clamp(state.signal - 0.00012*idle, 0, 1); // Gate stability requires upkeep; falls if fear too high const gateLeak = 0.00025 + state.fear*0.00035; state.gate = clamp(state.gate - gateLeak, 0, 1); // Phase auto-updates based on thresholds if(state.coherence > 0.18) state.phase = Math.max(state.phase, 1); if(state.coherence > 0.30 && state.signal > 0.22) state.phase = Math.max(state.phase, 2); if(state.signal > 0.42 && state.coherence > 0.34) state.phase = Math.max(state.phase, 3); } // ------------------------- // Main loop // ------------------------- function frame(ts){ state.t = ts; // clear with slight persistence drawBackground(); drift(); stepParticles(); drawDust(); drawThreads(); drawGate(); drawMotes(); drawGlyphs(); // "freedom flash" when gate hits 100% if(state.gate >= 1){ ctx.save(); ctx.globalCompositeOperation = 'screen'; ctx.fillStyle = 'rgba(255,255,255,0.07)'; ctx.fillRect(0,0,W,H); ctx.restore(); // keep it from staying locked at 1 forever; encourage pulses state.gate = 0.92; state.fear = clamp(state.fear - 0.10, 0, 1); } updateLog(); requestAnimationFrame(frame); } requestAnimationFrame(frame); })(); </script> </body> </html>
Save file
Quick jump
open a path
Open