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,311
Folders
409
Scanned Size
3.85 GB
PHP Files
891
Editable Text Files
12,572
File viewer
guarded to /htdocs
/kosmos/kosmos_dimension_forge.php
<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover,user-scalable=no"> <meta name="theme-color" content="#03030a"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <meta name="apple-mobile-web-app-title" content="KOSMOS"> <meta name="mobile-web-app-capable" content="yes"> <meta name="format-detection" content="telephone=no"> <meta name="csrf-token" content="10f9061c1f3d1e12bfd6fab1adb56cef0297856d7b5ddab7"> <!-- KOSMOS · TRACKER CONFIG --> <meta name="impact-site-verification" content="e8ec6683-663c-421a-a30d-f8c0fe517345"> <script> window.KOSMOS_TRACKER_CONFIG = { GA4_ID: 'G-S6MEHB4BEY', WEBHOOK_BASE: '/connlink/test1/ui/webhook_inbox.php', VISIT_STREAM: 'visits', EVENT_STREAM: 'default', SOURCE: 'kosmos-dimension-forge', APP: 'KOSMOS Body Nebula Forge', ADMIN_EMAIL: 'admin@gaylordsinclair.com' }; </script> <title>KOSMOS — Body Nebula Eye Release</title> <style> :root{ --bg:#03030a; --panel:rgba(8,9,27,.92); --panel2:rgba(16,14,40,.94); --line:rgba(144,105,255,.30); --text:#f8f6ff; --muted:#aaa7c6; --cyan:#5be7ff; --violet:#9a6dff; --pink:#ff56d3; --gold:#ffd57e; --green:#67efb5; --red:#ff5d7e; --safe-top:env(safe-area-inset-top,0px); --safe-right:env(safe-area-inset-right,0px); --safe-bottom:env(safe-area-inset-bottom,0px); --safe-left:env(safe-area-inset-left,0px); --app-height:100dvh; } *{box-sizing:border-box} html,body{ margin:0;width:100%;height:100%;overflow:hidden;background:var(--bg);color:var(--text); font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; overscroll-behavior:none;-webkit-text-size-adjust:100% } body{min-height:var(--app-height);touch-action:none;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none} button,input,select{font:inherit} button{ min-height:44px;color:inherit;cursor:pointer;touch-action:manipulation; -webkit-tap-highlight-color:transparent } canvas#world{position:fixed;inset:0;width:100%;height:100%;display:block;touch-action:none} .vignette{ position:fixed;inset:0;pointer-events:none;z-index:1; background: radial-gradient(circle at 50% 47%,transparent 0 35%,rgba(0,0,0,.18) 62%,rgba(0,0,0,.72) 100%), linear-gradient(180deg,rgba(0,0,0,.35),transparent 24%,transparent 72%,rgba(0,0,0,.48)) } .app{position:fixed;inset:0;z-index:2;pointer-events:none} .topbar,.status,.dock,.sheet,.modal,.toast{pointer-events:auto} .topbar{ position:absolute;left:0;right:0;top:0;display:flex;align-items:center;justify-content:space-between; gap:10px;padding:calc(8px + var(--safe-top)) max(10px,var(--safe-right)) 8px max(10px,var(--safe-left)); min-height:calc(58px + var(--safe-top)); background:linear-gradient(180deg,rgba(2,2,9,.97),rgba(2,2,9,.20)); border-bottom:1px solid rgba(255,255,255,.06);backdrop-filter:blur(16px) } .brand{display:flex;align-items:center;gap:9px;min-width:0} .logo{ width:40px;height:40px;flex:0 0 auto;border-radius:13px;display:grid;place-items:center; color:#05050b;font-size:11px;font-weight:950; background:conic-gradient(from 10deg,var(--cyan),var(--violet),var(--pink),var(--gold),var(--cyan)); box-shadow:0 0 30px rgba(154,109,255,.5) } .brandCopy{min-width:0} .brandCopy small{display:block;color:var(--cyan);font-size:7px;letter-spacing:.18em;text-transform:uppercase} .brandCopy strong{display:block;margin-top:2px;font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .topBtns{display:flex;gap:6px} .iconBtn{ width:42px;height:42px;padding:0;border:1px solid rgba(255,255,255,.11); border-radius:13px;background:rgba(255,255,255,.06);font-size:10px;font-weight:900 } .status{ position:absolute;left:8px;right:8px;top:calc(62px + var(--safe-top)); display:grid;grid-template-columns:repeat(4,1fr);gap:5px;padding:6px; border:1px solid rgba(255,255,255,.08);border-radius:16px; background:rgba(4,5,17,.72);backdrop-filter:blur(15px) } .statusCard{min-width:0;padding:7px 5px;border-radius:11px;text-align:center;background:rgba(255,255,255,.045)} .statusCard span{display:block;color:var(--muted);font-size:7px;letter-spacing:.08em;text-transform:uppercase} .statusCard b{display:block;margin-top:2px;font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .statusCard:nth-child(1) b{color:var(--gold)} .statusCard:nth-child(2) b{color:var(--cyan)} .statusCard:nth-child(3) b{color:var(--pink)} .statusCard:nth-child(4) b{color:var(--green)} .bodyMeter{ position:absolute;left:8px;top:calc(128px + var(--safe-top));width:188px; border:1px solid var(--line);border-radius:18px;padding:9px; background:rgba(7,8,23,.70);backdrop-filter:blur(16px);transition:.22s ease } .bodyMeter.compact .bodyDetails{display:none} .bodyHead{display:flex;align-items:center;justify-content:space-between;gap:8px} .bodyHead strong{font-size:10px;letter-spacing:.10em;text-transform:uppercase} .bodyHead button{ min-height:30px;padding:4px 8px;border:1px solid rgba(255,255,255,.09); border-radius:9px;background:rgba(255,255,255,.05);font-size:8px } .bodyPreview{ position:relative;height:122px;margin-top:7px;display:grid;place-items:center;overflow:hidden; border-radius:13px;background: radial-gradient(circle at 50% 36%,rgba(91,231,255,.16),transparent 28%), radial-gradient(circle at 50% 50%,rgba(154,109,255,.14),transparent 52%), rgba(2,3,11,.7) } .bodyPreview canvas{position:absolute;inset:0;width:100%;height:100%} .bodySilhouette{ width:73px;height:108px;filter:drop-shadow(0 0 15px rgba(91,231,255,.35));z-index:2 } .bodySilhouette svg{width:100%;height:100%} .bodyFrequency{text-align:center;margin-top:6px;color:var(--cyan);font-size:10px;font-weight:800} .meterRows{display:grid;gap:6px;margin-top:8px} .meterLabel{display:flex;align-items:center;justify-content:space-between;font-size:8px;color:var(--muted)} .meterTrack{height:6px;border-radius:99px;background:rgba(255,255,255,.08);overflow:hidden} .meterTrack i{display:block;height:100%;width:0;border-radius:inherit;background:linear-gradient(90deg,var(--cyan),var(--violet),var(--pink));transition:width .2s ease} .aimHint{ position:absolute;left:50%;top:calc(130px + var(--safe-top));transform:translateX(-50%); max-width:calc(100vw - 220px);padding:8px 11px;border:1px solid rgba(255,255,255,.08); border-radius:999px;background:rgba(4,5,16,.58);backdrop-filter:blur(12px); color:#dcd9f5;font-size:9px;text-align:center } .dock{ position:absolute;left:0;right:0;bottom:0;display:grid;grid-template-columns:repeat(6,1fr);gap:4px; padding:7px max(7px,var(--safe-right)) calc(7px + var(--safe-bottom)) max(7px,var(--safe-left)); background:linear-gradient(180deg,rgba(8,9,27,.84),rgba(2,2,9,.99)); border-top:1px solid rgba(255,255,255,.10);backdrop-filter:blur(24px) } .dockBtn{ min-width:0;min-height:56px;padding:5px 2px;border:1px solid rgba(255,255,255,.09); border-radius:13px;background:rgba(255,255,255,.045);display:grid;place-items:center;align-content:center;gap:2px } .dockBtn strong{font-size:9px;line-height:1.1} .dockBtn small{font-size:7px;line-height:1;color:var(--muted)} .dockBtn.primary{border-color:rgba(91,231,255,.30);background:linear-gradient(180deg,rgba(91,231,255,.16),rgba(154,109,255,.07))} .dockBtn.release{border-color:rgba(255,86,211,.34);background:linear-gradient(180deg,rgba(255,86,211,.16),rgba(154,109,255,.07))} .dockBtn.active,.dockBtn.holding{box-shadow:0 0 24px rgba(91,231,255,.28);transform:translateY(-2px)} .sheet{ position:absolute;left:8px;right:8px;bottom:calc(72px + var(--safe-bottom)); max-height:min(68dvh,620px);overflow:auto;-webkit-overflow-scrolling:touch; border:1px solid var(--line);border-radius:23px;background:rgba(8,9,27,.98); box-shadow:0 28px 80px rgba(0,0,0,.62);transform:translateY(calc(100% + 110px)); opacity:0;pointer-events:none;transition:.24s ease } .sheet.open{transform:translateY(0);opacity:1;pointer-events:auto} .sheetHandle{width:45px;height:4px;margin:7px auto 3px;border-radius:99px;background:rgba(255,255,255,.24)} .sheetHead{ position:sticky;top:0;z-index:2;display:flex;align-items:center;justify-content:space-between; padding:8px 11px 10px;background:rgba(8,9,27,.98);border-bottom:1px solid rgba(255,255,255,.06) } .sheetHead strong{font-size:11px;letter-spacing:.11em;text-transform:uppercase} .closeBtn{ min-height:34px;padding:4px 10px;border:1px solid rgba(255,255,255,.10); border-radius:10px;background:rgba(255,255,255,.06);font-size:9px } .sheetBody{padding:10px} .section{ padding:10px;border:1px solid rgba(255,255,255,.07);border-radius:15px; background:rgba(255,255,255,.025);margin-bottom:9px } .section:last-child{margin-bottom:0} .section h3{margin:0 0 8px;color:var(--cyan);font-size:9px;letter-spacing:.13em;text-transform:uppercase} .grid2{display:grid;grid-template-columns:1fr 1fr;gap:7px} .grid3{display:grid;grid-template-columns:repeat(3,1fr);gap:7px} .option{ min-height:48px;padding:7px;border:1px solid rgba(255,255,255,.09); border-radius:12px;background:rgba(255,255,255,.04);text-align:center } .option.active{border-color:rgba(255,213,126,.58);background:rgba(255,213,126,.11)} .option strong{display:block;font-size:10px} .option small{display:block;margin-top:2px;color:var(--muted);font-size:8px} .sliderRow{display:grid;grid-template-columns:70px 1fr 36px;gap:8px;align-items:center;margin-top:8px} .sliderRow:first-of-type{margin-top:0} .sliderRow label,.sliderRow span{font-size:9px;color:var(--muted)} .sliderRow input{width:100%} .switchRow{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:10px;margin-top:8px} input[type=checkbox]{width:20px;height:20px;accent-color:var(--cyan)} .frequencyGrid{display:grid;grid-template-columns:1fr 1fr;gap:7px} .frequency{ min-height:52px;padding:8px;border:1px solid rgba(255,255,255,.09); border-radius:13px;background:rgba(255,255,255,.04);text-align:center } .frequency.active{border-color:rgba(255,213,126,.60);background:rgba(255,213,126,.12);box-shadow:0 0 20px rgba(255,213,126,.10)} .frequency strong{display:block;font-size:12px} .frequency small{display:block;margin-top:2px;color:var(--muted);font-size:8px} .ledgerGrid{display:grid;grid-template-columns:repeat(3,1fr);gap:7px} .ledgerCard{padding:9px;border-radius:13px;background:rgba(255,255,255,.04);text-align:center} .ledgerCard span{display:block;color:var(--muted);font-size:7px;text-transform:uppercase} .ledgerCard b{display:block;margin-top:3px;font-size:20px} .log{display:grid;gap:7px;max-height:150px;overflow:auto} .logItem{padding-left:8px;border-left:2px solid rgba(154,109,255,.5);font-size:9px;line-height:1.4;color:#dddaf3} .logItem time{display:block;color:var(--muted);font-size:7px;margin-top:2px} .modalWrap{ position:fixed;inset:0;z-index:50;display:none;align-items:end; background:rgba(1,1,7,.76);backdrop-filter:blur(16px) } .modalWrap.open{display:flex} .modal{ width:100%;max-height:calc(var(--app-height) - var(--safe-top) - 8px);overflow:auto; border-radius:24px 24px 0 0;border:1px solid var(--line);border-bottom:0; background:linear-gradient(180deg,#171530,#080914); padding-bottom:var(--safe-bottom);box-shadow:0 -30px 100px rgba(0,0,0,.7) } .modalHead{ position:sticky;top:0;z-index:3;display:flex;align-items:center;justify-content:space-between; padding:15px 13px 10px;background:rgba(16,15,37,.98);border-bottom:1px solid rgba(255,255,255,.07) } .modalHead::before{ content:"";position:absolute;top:6px;left:50%;transform:translateX(-50%); width:44px;height:4px;border-radius:99px;background:rgba(255,255,255,.25) } .modalHead strong{padding-top:4px;font-size:14px} .modalBody{padding:12px} .modalActions{ position:sticky;bottom:0;z-index:3;display:grid;grid-template-columns:1fr 1fr;gap:8px; padding:9px 12px calc(9px + var(--safe-bottom));background:rgba(8,9,20,.98) } .modalActions button{width:100%;border:1px solid rgba(255,255,255,.11);border-radius:12px;background:rgba(255,255,255,.06)} .cameraStage{ position:relative;min-height:330px;overflow:hidden;border-radius:18px; border:1px solid rgba(255,255,255,.08);background:#03030a;display:grid;place-items:center } .cameraStage video,.cameraStage canvas{ position:absolute;inset:0;width:100%;height:100%;object-fit:cover } .cameraStage video{transform:scaleX(-1)} .cameraStage canvas{display:none} .cameraStage canvas.ready{display:block} .cameraPlaceholder{padding:20px;text-align:center;color:var(--muted);font-size:11px;line-height:1.5} .cameraScan{ position:absolute;inset:10%;border:1px solid rgba(91,231,255,.45);border-radius:40%; box-shadow:0 0 0 999px rgba(0,0,0,.25),0 0 25px rgba(91,231,255,.18);pointer-events:none } .cameraBtns{display:grid;grid-template-columns:1fr 1fr;gap:7px;margin-top:9px} .cameraBtns button,.uploadBtn{ min-height:48px;border:1px solid rgba(255,255,255,.10);border-radius:12px; background:rgba(255,255,255,.06);display:grid;place-items:center;text-align:center;font-size:10px } .uploadBtn input{display:none} .cameraStatus{margin-top:8px;padding:9px;border-radius:12px;background:rgba(255,255,255,.035);color:var(--muted);font-size:9px;line-height:1.45} .photoPreview{display:flex;align-items:center;gap:9px;margin-top:8px} .photoPreview img{width:52px;height:52px;border-radius:13px;object-fit:cover;display:none} .photoPreview img.active{display:block} .photoPreview span{font-size:9px;color:var(--muted)} .helpSteps{display:grid;grid-template-columns:1fr 1fr;gap:8px} .helpStep{padding:10px;border:1px solid rgba(255,255,255,.07);border-radius:13px;background:rgba(255,255,255,.025)} .helpStep b{display:grid;place-items:center;width:25px;height:25px;border-radius:50%;background:rgba(91,231,255,.14);color:var(--cyan)} .helpStep strong{display:block;margin-top:7px;font-size:10px} .helpStep span{display:block;margin-top:3px;color:var(--muted);font-size:9px;line-height:1.4} .helpList{display:grid;gap:7px;margin-top:10px} .helpRow{display:grid;grid-template-columns:76px 1fr;gap:9px;padding:9px;border:1px solid rgba(255,255,255,.06);border-radius:12px;background:rgba(255,255,255,.02)} .helpRow strong{font-size:9px;color:var(--gold)} .helpRow span{font-size:9px;color:#dcd9f3;line-height:1.45} .toast{ position:fixed;z-index:80;left:50%;top:calc(62px + var(--safe-top));transform:translate(-50%,-10px); max-width:calc(100vw - 24px);padding:10px 13px;border:1px solid rgba(255,255,255,.12); border-radius:13px;background:rgba(7,8,23,.96);font-size:10px;text-align:center; opacity:0;pointer-events:none;transition:.2s ease;box-shadow:0 18px 50px rgba(0,0,0,.5) } .toast.show{opacity:1;transform:translate(-50%,0)} /* Full-screen release cinema and creation gallery */ .releaseCinema{ position:fixed;inset:0;z-index:70;display:none;background:#010105; overflow:hidden;isolation:isolate } .releaseCinema.open{display:block} .releaseCinema canvas{position:absolute;inset:0;width:100%;height:100%;display:block} .cinemaShade{ position:absolute;inset:0;pointer-events:none; background: radial-gradient(circle at 50% 48%,transparent 0 38%,rgba(0,0,0,.30) 72%,rgba(0,0,0,.78) 100%), linear-gradient(180deg,rgba(0,0,0,.44),transparent 24%,transparent 72%,rgba(0,0,0,.66)) } .cinemaBrand{ position:absolute;left:max(14px,var(--safe-left));right:max(14px,var(--safe-right)); top:calc(12px + var(--safe-top));text-align:center;pointer-events:none } .cinemaBrand small{ display:block;color:var(--cyan);font-size:8px;letter-spacing:.24em;text-transform:uppercase } .cinemaBrand h2{ margin:4px 0 0;font-size:clamp(24px,7vw,54px);line-height:.95; text-shadow:0 0 18px rgba(91,231,255,.44),0 0 42px rgba(255,86,211,.28) } .cinemaBrand p{margin:6px 0 0;color:#d7d3ed;font-size:10px} .cinemaActions{ position:absolute;left:max(10px,var(--safe-left));right:max(10px,var(--safe-right)); bottom:calc(10px + var(--safe-bottom));display:grid;grid-template-columns:repeat(3,1fr);gap:7px } .cinemaActions button{ min-height:50px;border:1px solid rgba(255,255,255,.14);border-radius:14px; background:rgba(8,9,27,.76);backdrop-filter:blur(18px);font-size:10px;font-weight:850 } .cinemaActions button:first-child{ border-color:rgba(91,231,255,.42); background:linear-gradient(180deg,rgba(91,231,255,.18),rgba(154,109,255,.10)) } .galleryGrid{display:grid;grid-template-columns:1fr 1fr;gap:8px} .galleryCard{ position:relative;min-height:145px;overflow:hidden;padding:10px;border-radius:16px; border:1px solid rgba(255,255,255,.09);background:#09091a } .galleryVisual{ position:absolute;inset:0;opacity:.82; background: radial-gradient(circle at 62% 36%,rgba(var(--gallery-rgb),.90) 0 2%,rgba(var(--gallery-rgb),.30) 8%,transparent 28%), repeating-radial-gradient(ellipse at 55% 45%,rgba(var(--gallery-rgb),.18) 0 2px,transparent 4px 12px), linear-gradient(145deg,#050512,#110a24 55%,#03030a) } .galleryCard[data-type="nebula"] .galleryVisual{ background: radial-gradient(circle at 50% 50%,rgba(255,255,255,.92) 0 1.5%,rgba(255,213,126,.52) 5%,transparent 16%), radial-gradient(ellipse at 62% 40%,rgba(91,231,255,.52),transparent 31%), radial-gradient(ellipse at 37% 62%,rgba(255,86,211,.48),transparent 34%), radial-gradient(ellipse at 50% 52%,rgba(var(--gallery-rgb),.56),transparent 54%), repeating-radial-gradient(ellipse at 50% 50%,rgba(255,255,255,.07) 0 2%,transparent 3% 8%); animation:galleryNebulaColorstorm 5.2s ease-in-out infinite alternate; filter:saturate(1.35) contrast(1.06); } @keyframes galleryNebulaColorstorm{ 0%{transform:scale(1.02) rotate(-4deg);filter:saturate(1.15) hue-rotate(-10deg)} 50%{transform:scale(1.16) rotate(4deg);filter:saturate(1.55) hue-rotate(18deg)} 100%{transform:scale(1.08) rotate(-2deg);filter:saturate(1.35) hue-rotate(42deg)} } .galleryCard[data-type="galaxy"] .galleryVisual{ background: radial-gradient(circle at 54% 45%,#fff 0 1%,rgba(var(--gallery-rgb),.95) 2%,transparent 11%), repeating-conic-gradient(from 20deg at 54% 45%,rgba(var(--gallery-rgb),.32) 0 5deg,transparent 8deg 20deg), radial-gradient(ellipse at 54% 45%,rgba(var(--gallery-rgb),.24),transparent 52%), #03030a } .galleryContent{position:relative;z-index:2;display:flex;min-height:125px;flex-direction:column;justify-content:flex-end} .galleryContent small{font-size:7px;color:var(--cyan);letter-spacing:.12em;text-transform:uppercase} .galleryContent strong{margin-top:3px;font-size:14px;text-shadow:0 0 12px #000} .galleryContent span{margin-top:2px;color:#c9c5df;font-size:8px} .galleryActions{display:grid;grid-template-columns:1fr 1fr;gap:5px;margin-top:8px} .galleryActions button{ min-height:38px;border:1px solid rgba(255,255,255,.11);border-radius:10px; background:rgba(4,5,16,.66);font-size:8px } .galleryEmpty{ grid-column:1/-1;padding:28px 14px;border:1px dashed rgba(255,255,255,.14); border-radius:16px;text-align:center;color:var(--muted);font-size:10px;line-height:1.5 } .bodyPhotoVisible{ opacity:1; } @media (min-width:760px){ .status{left:16px;right:auto;width:430px} .bodyMeter{left:16px;top:138px;width:250px} .aimHint{max-width:480px} .dock{left:50%;right:auto;bottom:15px;transform:translateX(-50%);width:min(800px,calc(100vw - 30px));border:1px solid rgba(255,255,255,.09);border-radius:18px;padding:8px} .sheet{left:auto;right:16px;width:390px;bottom:104px} .modalWrap{align-items:center;justify-content:center;padding:20px} .modal{width:min(720px,100%);border-radius:24px;border:1px solid var(--line);padding-bottom:0} .modalActions{padding-bottom:12px} .cameraStage{min-height:460px} } @media (max-height:680px){ .bodyMeter{top:calc(122px + var(--safe-top))} .bodyPreview{height:90px} .bodySilhouette{height:82px} .aimHint{display:none} } /* ============================================================ KOSMOS · TRACKER + FLOATING I MENU + BODY TELEPORT SYSTEM ============================================================ */ .iOrb{ position:fixed;right:max(14px,var(--safe-right));bottom:calc(82px + var(--safe-bottom)); z-index:86;width:58px;height:58px;border:0;border-radius:50%; display:grid;place-items:center;cursor:pointer;color:#070611; font-weight:950;font-size:22px;letter-spacing:-.02em; background: radial-gradient(circle at 34% 28%,#fff 0 7%,transparent 9%), conic-gradient(from 25deg,var(--cyan),var(--violet),var(--pink),var(--gold),var(--cyan)); box-shadow: 0 0 0 1px rgba(255,255,255,.18), 0 0 28px rgba(91,231,255,.28), 0 0 64px rgba(255,87,211,.20), 0 18px 50px rgba(0,0,0,.44); animation:iOrbPulse 2.8s ease-in-out infinite alternate; } .iOrb:hover{transform:translateY(-2px) scale(1.03)} .iOrb:active{transform:translateY(0) scale(.98)} @keyframes iOrbPulse{ from{filter:saturate(1);box-shadow:0 0 0 1px rgba(255,255,255,.18),0 0 24px rgba(91,231,255,.22),0 16px 48px rgba(0,0,0,.42)} to{filter:saturate(1.55);box-shadow:0 0 0 1px rgba(255,255,255,.24),0 0 42px rgba(255,87,211,.30),0 0 76px rgba(91,231,255,.20),0 20px 58px rgba(0,0,0,.48)} } .menuVeil{ position:fixed;inset:0;z-index:82;display:none; background:rgba(0,0,0,.42);backdrop-filter:blur(7px); pointer-events:auto; } .menuVeil.open{display:block} .iMenu{ position:fixed;z-index:87;right:max(14px,var(--safe-right));bottom:calc(150px + var(--safe-bottom)); width:min(380px,calc(100vw - 28px));max-height:min(78dvh,680px);overflow:auto; border:1px solid rgba(255,255,255,.12);border-radius:24px; background: radial-gradient(circle at 80% 10%,rgba(91,231,255,.16),transparent 28%), radial-gradient(circle at 20% 88%,rgba(255,87,211,.14),transparent 34%), rgba(8,9,28,.97); box-shadow:0 28px 90px rgba(0,0,0,.60); backdrop-filter:blur(22px); opacity:0;pointer-events:none;transform:translateY(18px) scale(.97); transition:opacity .22s ease,transform .22s ease; } .iMenu.open{opacity:1;pointer-events:auto;transform:translateY(0) scale(1)} .iMenuHead{ position:sticky;top:0;z-index:2;display:flex;align-items:center;justify-content:space-between;gap:12px; padding:16px 16px 12px;border-bottom:1px solid rgba(255,255,255,.07); background:rgba(8,9,28,.94);backdrop-filter:blur(18px); } .iMenuHead small{display:block;color:var(--cyan);font-size:8px;letter-spacing:.18em;text-transform:uppercase} .iMenuHead strong{display:block;margin-top:2px;font-size:16px} .iClose{ width:38px;height:38px;border:1px solid rgba(255,255,255,.10);border-radius:13px; background:rgba(255,255,255,.06);color:#fff;font-weight:900;cursor:pointer; } .iMenuBody{padding:13px;display:grid;gap:10px} .iMenuSection{ padding:12px;border:1px solid rgba(255,255,255,.08);border-radius:17px; background:rgba(255,255,255,.035); } .iMenuSection h3{margin:0 0 9px;color:var(--gold);font-size:9px;letter-spacing:.16em;text-transform:uppercase} .iMenuGrid{display:grid;grid-template-columns:1fr 1fr;gap:8px} .iMenuLink,.iMenuAction{ min-height:48px;display:grid;place-items:center;text-align:center; padding:9px;border-radius:13px;text-decoration:none;border:1px solid rgba(255,255,255,.09); background:linear-gradient(180deg,rgba(255,255,255,.065),rgba(255,255,255,.025)); color:#f5f2ff;font-size:10px;font-weight:850;letter-spacing:.05em;cursor:pointer; } .iMenuLink.primaryMenu,.iMenuAction.primaryMenu{ color:#070611;border:0; background:linear-gradient(120deg,var(--cyan),#b68bff 44%,var(--pink) 72%,var(--gold)); } .iMenuLink:hover,.iMenuAction:hover{border-color:rgba(91,231,255,.36);transform:translateY(-1px)} .trackerPanel,.bodySystemPanel{display:grid;gap:7px;color:#cfcbe5;font-size:10px;line-height:1.45} .trackerRow,.bodySystemRow{display:flex;align-items:center;justify-content:space-between;gap:10px} .trackerRow b,.bodySystemRow b{color:#fff} .statusDot{ width:9px;height:9px;border-radius:50%;display:inline-block;margin-right:6px; background:#ffd57d;box-shadow:0 0 16px rgba(255,213,125,.55); } .statusDot.ok{background:#68efb7;box-shadow:0 0 16px rgba(104,239,183,.55)} .statusDot.fail{background:#ff5d7e;box-shadow:0 0 16px rgba(255,93,126,.55)} .iMenuNote{color:var(--muted);font-size:9px;line-height:1.48;margin:0} .instructionsList{margin:0;padding-left:17px;color:#d7d3ed;font-size:10px;line-height:1.55} .instructionsList li{margin:5px 0} .devMessage{ padding:10px;border-radius:14px;border:1px solid rgba(91,231,255,.18); background:linear-gradient(180deg,rgba(91,231,255,.08),rgba(255,86,211,.05)); color:#e8e4ff;font-size:10px;line-height:1.55; } .insideBadge{ position:fixed;z-index:20;left:50%;top:calc(112px + var(--safe-top)); transform:translateX(-50%);display:none;pointer-events:none; padding:8px 12px;border:1px solid rgba(255,213,126,.22);border-radius:999px; color:#fff;background:rgba(8,9,27,.68);backdrop-filter:blur(14px); font-size:9px;font-weight:900;letter-spacing:.12em;text-transform:uppercase; box-shadow:0 0 24px rgba(255,213,126,.10); } .insideBadge.open{display:block} @media(max-width:520px){ .iOrb{right:max(12px,var(--safe-right));bottom:calc(74px + var(--safe-bottom));width:54px;height:54px} .iMenu{ left:10px;right:10px;bottom:calc(138px + var(--safe-bottom));width:auto; border-radius:22px;max-height:70dvh; } .insideBadge{top:calc(112px + var(--safe-top));font-size:8px} } /* ============================================================ KOSMOS · FULL SCREEN I HUB + BODY MECHANICS MENU VISUALS ============================================================ */ .iMenu{ position:fixed!important; z-index:87!important; inset:0!important; width:auto!important; max-height:none!important; overflow:auto!important; border:0!important; border-radius:0!important; background: radial-gradient(circle at 50% 18%,rgba(91,231,255,.18),transparent 30%), radial-gradient(circle at 12% 76%,rgba(255,87,211,.14),transparent 32%), radial-gradient(circle at 88% 70%,rgba(255,213,126,.10),transparent 28%), linear-gradient(180deg,rgba(3,3,14,.98),rgba(6,7,22,.98))!important; box-shadow:none!important; backdrop-filter:blur(24px); opacity:0; pointer-events:none; transform:translateY(18px) scale(.985); transition:opacity .22s ease,transform .22s ease; padding:0 max(14px,var(--safe-right)) calc(22px + var(--safe-bottom)) max(14px,var(--safe-left)); } .iMenu.open{opacity:1;pointer-events:auto;transform:translateY(0) scale(1)} .iMenuHead{ max-width:1180px; margin:0 auto; padding:calc(16px + var(--safe-top)) 4px 14px!important; background:linear-gradient(180deg,rgba(3,3,14,.96),rgba(3,3,14,.72))!important; border-bottom:1px solid rgba(255,255,255,.08)!important; } .iMenuHead strong{font-size:clamp(19px,4vw,34px)!important;letter-spacing:-.035em} .iMenuHead small{font-size:9px!important;color:var(--cyan)!important} .iMenuBody{ width:min(1180px,100%); margin:0 auto; padding:16px 4px 80px!important; display:grid!important; grid-template-columns:1.08fr .92fr; gap:14px!important; } .iMenuSection{ position:relative; overflow:hidden; border-radius:24px!important; padding:16px!important; background: radial-gradient(circle at 85% 0%,rgba(91,231,255,.14),transparent 38%), radial-gradient(circle at 0% 100%,rgba(255,87,211,.10),transparent 38%), rgba(255,255,255,.04)!important; } .iMenuSection::after{ content:""; position:absolute; width:220px;height:220px;right:-90px;bottom:-120px;border-radius:50%; background:conic-gradient(from 0deg,var(--cyan),var(--violet),var(--pink),var(--gold),var(--cyan)); filter:blur(34px); opacity:.10; pointer-events:none; } .iMenuSection.wide{grid-column:1/-1} .iMenuGrid.linksGrid{grid-template-columns:repeat(3,1fr)} .iMenuLink,.iMenuAction{position:relative;z-index:2} .iMenuLink.primaryMenu{ min-height:56px; font-size:11px; box-shadow:0 14px 42px rgba(91,231,255,.14); } .gaylordHero{ position:relative; z-index:2; min-height:230px; display:grid; place-items:center; text-align:center; border-radius:22px; overflow:hidden; background: radial-gradient(circle at 50% 50%,rgba(255,255,255,.16),transparent 8%), radial-gradient(circle at 55% 44%,rgba(91,231,255,.25),transparent 26%), radial-gradient(circle at 42% 58%,rgba(255,87,211,.20),transparent 34%), linear-gradient(145deg,rgba(18,16,52,.72),rgba(7,8,24,.74)); border:1px solid rgba(255,255,255,.08); } .gaylordHero::before, .gaylordHero::after{ content:""; position:absolute; border-radius:50%; border:1px solid rgba(255,255,255,.14); animation:heroOrbit 18s linear infinite; } .gaylordHero::before{width:260px;height:260px} .gaylordHero::after{width:180px;height:180px;animation-duration:11s;animation-direction:reverse} @keyframes heroOrbit{to{transform:rotate(360deg)}} .gaylordHeroContent{position:relative;z-index:2;padding:24px} .gaylordHeroContent small{ display:block; color:var(--gold); font-size:9px; letter-spacing:.22em; text-transform:uppercase; } .gaylordHeroContent h2{ margin:8px 0 0; font-size:clamp(30px,8vw,70px); line-height:.86; letter-spacing:-.07em; } .gaylordHeroContent p{ margin:12px auto 0; max-width:560px; color:#d6d2eb; font-size:12px; line-height:1.55; } .bodyMechanicsHud{ position:absolute; left:8px; right:8px; top:calc(103px + var(--safe-top)); z-index:12; display:grid; grid-template-columns:repeat(3,1fr); gap:5px; pointer-events:none; } .bodyMechanicChip{ padding:7px 6px; border-radius:12px; border:1px solid rgba(255,255,255,.08); background:rgba(4,5,17,.58); backdrop-filter:blur(14px); text-align:center; } .bodyMechanicChip span{ display:block; color:var(--muted); font-size:7px; letter-spacing:.08em; text-transform:uppercase; } .bodyMechanicChip b{ display:block; margin-top:2px; color:#fff; font-size:11px; } .bodyMechanicsGuide{ border-color:rgba(255,213,126,.18)!important; background: radial-gradient(circle at 50% 0%,rgba(255,213,126,.10),transparent 35%), rgba(255,255,255,.03)!important; } .bodyMechanicsRules{ display:grid; gap:7px; } .bodyRule{ display:grid; grid-template-columns:34px 1fr; gap:9px; align-items:start; padding:9px; border:1px solid rgba(255,255,255,.07); border-radius:13px; background:rgba(255,255,255,.028); } .bodyRule b{ display:grid; place-items:center; width:28px; height:28px; border-radius:50%; background:rgba(91,231,255,.13); color:var(--cyan); font-size:12px; } .bodyRule strong{ display:block; font-size:10px; color:#fff; } .bodyRule span{ display:block; margin-top:2px; color:var(--muted); font-size:8px; line-height:1.35; } .bodyActionGrid{ display:grid; grid-template-columns:repeat(2,1fr); gap:7px; margin-top:9px; } .bodyActionGrid .option{ background: linear-gradient(180deg,rgba(91,231,255,.09),rgba(255,86,211,.04)), rgba(255,255,255,.035); } @media(min-width:760px){ .bodyMechanicsHud{ left:16px; right:auto; top:calc(104px + var(--safe-top)); width:430px; } } @media(max-width:760px){ .iMenuBody{grid-template-columns:1fr!important} .iMenuGrid.linksGrid{grid-template-columns:1fr 1fr} } @media(max-width:520px){ .bodyMechanicsHud{top:calc(103px + var(--safe-top))} .bodyMechanicChip span{font-size:6px} .bodyMechanicChip b{font-size:9px} .bodyActionGrid{grid-template-columns:1fr 1fr} } </style> </head> <body> <canvas id="world" aria-label="Animated Kosmos game"></canvas> <div class="vignette"></div> <!-- KOSMOS · FLOATING I MENU --> <div class="menuVeil" id="menuVeil" hidden></div> <button class="iOrb" id="iOrb" type="button" aria-label="Open KOSMOS information menu" aria-expanded="false" aria-controls="iMenu">i</button> <div class="insideBadge" id="insideBadge">Inside Body · Build Mode</div> <aside class="iMenu" id="iMenu" aria-label="Gaylord Sinclair information menu" aria-hidden="true"> <div class="iMenuHead"> <div> <small>Gaylord Sinclair Command Hub</small> <strong>Links · Message · Tracker</strong> </div> <button class="iClose" id="iClose" type="button" aria-label="Close menu">×</button> </div> <div class="iMenuBody"> <section class="iMenuSection wide"> <div class="gaylordHero"> <div class="gaylordHeroContent"> <small>KN Network · Gay Central · KOSMOS</small> <h2>Gaylord Sinclair</h2> <p> This full-screen hub is for site navigation, messages, update notes, flaw reports, admin contact, tracker status, and KOSMOS project links. </p> </div> </div> </section> <section class="iMenuSection"> <h3>Gaylord Sinclair Links</h3> <div class="iMenuGrid linksGrid"> <a class="iMenuLink primaryMenu" href="/" data-track="gs_home">Home</a> <a class="iMenuLink" href="/books/" data-track="gs_books">Books</a> <a class="iMenuLink" href="/art/" data-track="gs_art">Art</a> <a class="iMenuLink" href="/comics/" data-track="gs_comics">Comics</a> <a class="iMenuLink" href="/arcade/" data-track="gs_arcade">Arcade</a> <a class="iMenuLink" href="/kosmos/kosmos_dimension_forge.php" data-track="gs_kosmos_forge">KOSMOS Forge</a> <a class="iMenuLink" href="/sitemap.php" data-track="gs_sitemap">Sitemap</a> <a class="iMenuLink" href="/contact/" data-track="gs_contact">Contact</a> <a class="iMenuLink" href="/message.php" data-track="gs_message_board">Message Board</a> </div> </section> <section class="iMenuSection"> <h3>Message / Developer</h3> <div class="devMessage"> Send update notes, flaws, broken-button reports, animation requests, camera/sound issues, and KOSMOS feature ideas to the admin board. </div> <div class="iMenuGrid" style="margin-top:9px"> <a class="iMenuLink primaryMenu" href="/message.php" data-track="developer_message">Open Message Board</a> <a class="iMenuLink" href="mailto:admin@gaylordsinclair.com?subject=KOSMOS%20Update%20or%20Flaw" data-track="developer_email">Email Admin</a> <button class="iMenuAction" id="infoShareBtn" type="button" data-track="share_latest_from_i">Share Latest</button> <button class="iMenuAction" id="copyPageBtn" type="button" data-track="copy_page_link">Copy Page Link</button> </div> </section> <section class="iMenuSection"> <h3>Tracker</h3> <div class="trackerPanel"> <div class="trackerRow"><span><i class="statusDot" id="trackerDot"></i>Status</span><b id="trackerStatus">Starting</b></div> <div class="trackerRow"><span>Events</span><b id="trackerCount">0</b></div> <div class="trackerRow"><span>GA4</span><b>G-S6MEHB4BEY</b></div> <div class="trackerRow"><span>Webhook</span><b>default</b></div> </div> </section> <section class="iMenuSection"> <h3>KOSMOS Notes</h3> <p class="iMenuNote"> Gameplay controls are now in the bottom Menu button. Use that Menu for Blow Up Body, Teleport Inside, Inner Nebula, Inner Galaxy, and Exit Body. This I hub stays focused on Gaylord Sinclair links, messages, contact, and tracker status. </p> </section> </div> </aside> <div class="app"> <header class="topbar"> <div class="brand"> <div class="logo">KN</div> <div class="brandCopy"> <small>Gaylord Sinclair · Gay Central</small> <strong>KOSMOS Body Nebula Forge</strong> </div> </div> <div class="topBtns"> <button class="iconBtn" id="soundBtn" type="button">SND</button> <button class="iconBtn" id="infoTopBtn" type="button">i</button> <button class="iconBtn" id="helpBtn" type="button">?</button> </div> </header> <section class="status" aria-label="Kosmos status"> <div class="statusCard"><span>Matter</span><b id="matterOut">30</b></div> <div class="statusCard"><span>Energy</span><b id="energyOut">100</b></div> <div class="statusCard"><span>Eye Charge</span><b id="chargeOut">0%</b></div> <div class="statusCard"><span>Release</span><b id="modeOut">Energy</b></div> </section> <section class="bodyMechanicsHud" aria-label="Body mechanics status"> <div class="bodyMechanicChip"><span>Body Size</span><b id="bodySizeOut">100%</b></div> <div class="bodyMechanicChip"><span>Location</span><b id="bodyLocationOut">Outside</b></div> <div class="bodyMechanicChip"><span>Energy Rule</span><b id="bodyRuleOut">Energy = Size</b></div> </section> <section class="bodyMeter compact" id="bodyMeter"> <div class="bodyHead"> <strong>Body Frequency</strong> <button id="bodyToggle" type="button">Open</button> </div> <div class="bodyDetails"> <div class="bodyPreview"> <canvas id="bodyPhotoCanvas" width="340" height="220"></canvas> <div class="bodySilhouette"> <svg viewBox="0 0 120 180" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"> <defs> <linearGradient id="bodyGlow" x1="0" y1="0" x2="1" y2="1"> <stop offset="0%" stop-color="#5be7ff"/> <stop offset="46%" stop-color="#9a6dff"/> <stop offset="78%" stop-color="#ff56d3"/> <stop offset="100%" stop-color="#ffd57e"/> </linearGradient> </defs> <circle cx="60" cy="24" r="16" fill="url(#bodyGlow)" opacity=".92"/> <path d="M41 49c7-8 31-8 38 0l9 32c3 11 1 29-4 40l-8 18c-4 8-8 14-16 14s-12-6-16-14l-8-18c-5-11-7-29-4-40l9-32Z" fill="url(#bodyGlow)" opacity=".85"/> <path d="M30 64c-8 5-17 14-19 23-2 7 5 13 12 9l17-12 3-13-13-7Z" fill="url(#bodyGlow)" opacity=".78"/> <path d="M90 64c8 5 17 14 19 23 2 7-5 13-12 9L80 84l-3-13 13-7Z" fill="url(#bodyGlow)" opacity=".78"/> <path d="M48 138l-13 27c-4 9 9 15 15 7l10-16 10 16c6 8 19 2 15-7l-13-27" fill="url(#bodyGlow)" opacity=".8"/> <circle cx="54" cy="22" r="2.7" fill="#fff"/> <circle cx="66" cy="22" r="2.7" fill="#fff"/> <circle cx="60" cy="77" r="4.6" fill="#fff"/> <circle cx="60" cy="98" r="4.6" fill="#5be7ff"/> <circle cx="60" cy="119" r="4.6" fill="#ff56d3"/> </svg> </div> </div> <div class="bodyFrequency" id="frequencyOut">174 Hz · Foundation</div> <div class="meterRows"> <div class="meterLabel"><span>Energy</span><b id="energyMeterLabel">100</b></div> <div class="meterTrack"><i id="energyMeter"></i></div> <div class="meterLabel"><span>Resonance</span><b id="resonanceMeterLabel">0</b></div> <div class="meterTrack"><i id="resonanceMeter"></i></div> <div class="meterLabel"><span>Eye Charge</span><b id="chargeMeterLabel">0%</b></div> <div class="meterTrack"><i id="chargeMeter"></i></div> </div> </div> </section> <div class="aimHint">Tap the universe to aim. Hold Resonate to collect matter. Hold Charge, then Release from the eyes.</div> <nav class="dock" aria-label="Primary controls"> <button class="dockBtn primary" id="resonateBtn" type="button"><strong>Resonate</strong><small>Hold</small></button> <button class="dockBtn primary" id="chargeBtn" type="button"><strong>Charge</strong><small>Hold</small></button> <button class="dockBtn release" id="releaseBtn" type="button"><strong>Release</strong><small id="releaseModeSmall">Energy</small></button> <button class="dockBtn" id="tuneBtn" type="button"><strong>Tune</strong><small id="tuneSmall">174 Hz</small></button> <button class="dockBtn" id="photoBtn" type="button"><strong>Photo</strong><small>Blend</small></button> <button class="dockBtn" id="menuBtn" type="button"><strong>Menu</strong><small>Maker</small></button> </nav> <section class="sheet" id="tuneSheet" aria-label="Frequency tuning"> <div class="sheetHandle"></div> <div class="sheetHead"><strong>Frequency Tuning</strong><button class="closeBtn" data-close-sheet type="button">Close</button></div> <div class="sheetBody"> <div class="frequencyGrid" id="frequencyGrid"></div> </div> </section> <section class="sheet" id="menuSheet" aria-label="Maker and release menu"> <div class="sheetHandle"></div> <div class="sheetHead"><strong>Spatial Maker Menu</strong><button class="closeBtn" data-close-sheet type="button">Close</button></div> <div class="sheetBody"> <section class="section"> <h3>Eye Release Mode</h3> <div class="grid3"> <button class="option active" data-mode="energy" type="button"><strong>Energy</strong><small>25% charge</small></button> <button class="option" data-mode="nebula" type="button"><strong>Nebula</strong><small>60% charge</small></button> <button class="option" data-mode="galaxy" type="button"><strong>Galaxy</strong><small>100% + 250 M</small></button> </div> </section> <section class="section bodyMechanicsGuide"> <h3>Body Mechanics</h3> <div class="bodyMechanicsRules"> <div class="bodyRule"><b>1</b><div><strong>Blow Up Body</strong><span>Stores energy and makes your body bigger.</span></div></div> <div class="bodyRule"><b>2</b><div><strong>Teleport Inside</strong><span>Enters the inner body universe.</span></div></div> <div class="bodyRule"><b>3</b><div><strong>Build Inner Nebula</strong><span>Builds a nebula inside the body; uses energy and matter, so the body gets smaller.</span></div></div> <div class="bodyRule"><b>4</b><div><strong>Build Inner Galaxy</strong><span>Builds a galaxy inside the body; uses more energy and matter, then opens the full-screen galaxy view.</span></div></div> <div class="bodyRule"><b>5</b><div><strong>Exit Body</strong><span>Returns to the outer universe.</span></div></div> <div class="bodyRule"><b>6</b><div><strong>Energy Rule</strong><span>More energy stored = larger body scale. Building inside drains energy = smaller body afterward.</span></div></div> <div class="bodyRule"><b>7</b><div><strong>Inside Graphics</strong><span>Teleport mode shows animated internal galaxy and nebula fields.</span></div></div> </div> <div class="bodyActionGrid"> <button class="option" id="menuBlowUpBodyBtn" type="button"><strong>Blow Up Body</strong><small>Store energy · grow</small></button> <button class="option" id="menuTeleportBodyBtn" type="button"><strong>Teleport Inside</strong><small>Enter body universe</small></button> <button class="option" id="menuInnerNebulaBtn" type="button"><strong>Build Inner Nebula</strong><small>Spend energy · create</small></button> <button class="option" id="menuInnerGalaxyBtn" type="button"><strong>Build Inner Galaxy</strong><small>Full-screen galaxy</small></button> <button class="option" id="menuExitBodyBtn" type="button"><strong>Exit Body</strong><small>Return outside</small></button> <button class="option" id="menuOpenIHubBtn" type="button"><strong>Open I Hub</strong><small>Links + messages</small></button> </div> </section> <section class="section"> <h3>Maker Options</h3> <div class="grid2"> <button class="option" id="shieldBtn" type="button"><strong>Replicate Shield</strong><small>70 M + 30 E</small></button> <button class="option" id="dimensionBtn" type="button"><strong>Forge Dimension</strong><small>350 M + 3 shields</small></button> <button class="option" id="starBtn" type="button"><strong>Ignite Star</strong><small>160 M + 80 E</small></button> <button class="option" id="matterBurstBtn" type="button"><strong>Matter Burst</strong><small>Spawn matched particles</small></button> <button class="option" id="galleryBtn" type="button"><strong>Kosmos Gallery</strong><small>Show and share creations</small></button> <button class="option" id="shareLatestBtn" type="button"><strong>Share Latest</strong><small>Nebula or galaxy image</small></button> <button class="option" id="blowUpBodyBtn" type="button"><strong>Blow Up Body</strong><small>Store energy · get bigger</small></button> <button class="option" id="teleportBodyBtn" type="button"><strong>Teleport Inside</strong><small>Enter your body galaxy</small></button> <button class="option" id="innerNebulaBtn" type="button"><strong>Build Inner Nebula</strong><small>Costs energy · smaller body</small></button> <button class="option" id="innerGalaxyBtn" type="button"><strong>Build Inner Galaxy</strong><small>High energy forge</small></button> </div> </section> <section class="section"> <h3>Sound</h3> <div class="switchRow"><span>Ambient Hum</span><input id="ambientToggle" type="checkbox"></div> <div class="sliderRow"><label for="masterVolume">Master</label><input id="masterVolume" type="range" min="0" max="100" value="70"><span id="masterVolumeOut">70%</span></div> <div class="sliderRow"><label for="sfxVolume">Effects</label><input id="sfxVolume" type="range" min="0" max="100" value="80"><span id="sfxVolumeOut">80%</span></div> </section> <section class="section"> <h3>Scene</h3> <div class="grid2"> <button class="option active" id="particlesToggle" type="button"><strong>Particles</strong><small>Show / hide</small></button> <button class="option active" id="orbitToggle" type="button"><strong>Auto Orbit</strong><small>On / off</small></button> <button class="option" id="resetAimBtn" type="button"><strong>Reset Aim</strong><small>Center target</small></button> <button class="option" id="saveBtn" type="button"><strong>Save</strong><small>Save PHP state</small></button> </div> </section> </div> </section> <section class="sheet" id="ledgerSheet" aria-label="KN Network ledger"> <div class="sheetHandle"></div> <div class="sheetHead"><strong>KN Network Ledger</strong><button class="closeBtn" data-close-sheet type="button">Close</button></div> <div class="sheetBody"> <section class="section"> <div class="ledgerGrid"> <div class="ledgerCard"><span>Shield</span><b id="shieldOut">0</b></div> <div class="ledgerCard"><span>Dimensions</span><b id="dimensionsOut">0</b></div> <div class="ledgerCard"><span>Nebulae</span><b id="nebulaeOut">0</b></div> <div class="ledgerCard"><span>Stars</span><b id="starsOut">0</b></div> <div class="ledgerCard"><span>Galaxies</span><b id="galaxiesOut">0</b></div> <div class="ledgerCard"><span>Resonance</span><b id="resonanceOut">0</b></div> </div> </section> <section class="section"> <h3>Broadcast Log</h3> <div class="log" id="log"></div> </section> </div> </section> <section class="sheet" id="gallerySheet" aria-label="Kosmos creation gallery"> <div class="sheetHandle"></div> <div class="sheetHead"><strong>Kosmos Creation Gallery</strong><button class="closeBtn" data-close-sheet type="button">Close</button></div> <div class="sheetBody"> <section class="section"> <h3>Your Released Nebulae and Galaxies</h3> <div class="galleryGrid" id="galleryGrid"></div> </section> </div> </section> </div> <div class="releaseCinema" id="releaseCinema" aria-hidden="true"> <canvas id="releaseCanvas"></canvas> <div class="cinemaShade"></div> <div class="cinemaBrand"> <small>Gaylord Sinclair · KN Network · Gay Central</small> <h2 id="cinemaTitle">KOSMOS RELEASE</h2> <p id="cinemaSubtitle">A new creation has entered the network.</p> </div> <div class="cinemaActions"> <button id="cinemaShareBtn" type="button">Share Creation</button> <button id="cinemaSaveBtn" type="button">Save Image</button> <button id="cinemaCloseBtn" type="button">Return to Game</button> </div> </div> <div class="modalWrap" id="photoModal" role="dialog" aria-modal="true" aria-labelledby="photoTitle"> <div class="modal"> <div class="modalHead"><strong id="photoTitle">Kosmos Photo Blend</strong><button class="closeBtn" id="closePhotoBtn" type="button">Close</button></div> <div class="modalBody"> <div class="cameraStage"> <video id="cameraVideo" playsinline muted autoplay></video> <canvas id="captureCanvas" width="640" height="640"></canvas> <div class="cameraPlaceholder" id="cameraPlaceholder">Start Camera on HTTPS, or choose a photo from your iPhone. The image remains on this device.</div> <div class="cameraScan"></div> </div> <div class="cameraBtns"> <button id="startCameraBtn" type="button">Start Camera</button> <button id="takePhotoBtn" type="button" disabled>Take Photo</button> <label class="uploadBtn">Choose Photo<input id="photoInput" type="file" accept="image/*" capture="user"></label> <button id="retakeBtn" type="button">Retake</button> </div> <div class="section" style="margin-top:9px"> <h3>Blend Controls</h3> <div class="sliderRow"><label for="blendRange">Strength</label><input id="blendRange" type="range" min="10" max="100" value="72"><span id="blendOut">72%</span></div> <div class="switchRow"><span>Frequency color infusion</span><input id="tintToggle" type="checkbox" checked></div> </div> <div class="photoPreview"> <img id="photoPreviewImg" alt="Selected photo preview"> <span id="cameraStatus">No photo selected.</span> </div> <div class="cameraStatus">Privacy: no image is uploaded to the PHP server. A resized copy is stored only in this browser.</div> </div> <div class="modalActions"> <button id="removePhotoBtn" type="button">Remove Blend</button> <button id="applyPhotoBtn" type="button" disabled>Blend Into Body</button> </div> </div> </div> <div class="modalWrap" id="helpModal" role="dialog" aria-modal="true"> <div class="modal"> <div class="modalHead"><strong>How KOSMOS Works</strong><button class="closeBtn" id="closeHelpBtn" type="button">Close</button></div> <div class="modalBody"> <div class="helpSteps"> <div class="helpStep"><b>1</b><strong>Tune</strong><span>Select a frequency matching the color of nearby matter.</span></div> <div class="helpStep"><b>2</b><strong>Resonate</strong><span>Hold the button to pull matched matter into the body.</span></div> <div class="helpStep"><b>3</b><strong>Charge</strong><span>Hold to convert body energy into eye-release charge.</span></div> <div class="helpStep"><b>4</b><strong>Release</strong><span>Tap the universe to aim, then fire Energy, Nebula, or Galaxy.</span></div> </div> <div class="helpList"> <div class="helpRow"><strong>Resonate</strong><span>Attracts compatible particles. Incorrect colors move slowly; matched colors produce more matter and resonance.</span></div> <div class="helpRow"><strong>Charge</strong><span>Consumes stored energy and fills the eye-charge meter.</span></div> <div class="helpRow"><strong>Release</strong><span>Energy costs 25%, Nebula costs 60%, and Galaxy costs 100% charge plus 250 matter.</span></div> <div class="helpRow"><strong>Photo</strong><span>Uses the live camera on HTTPS or opens the iPhone photo picker. The photo blends into the animated body.</span></div> <div class="helpRow"><strong>Menu</strong><span>Selects release type, creates shields, dimensions and stars, controls sound, and saves PHP state.</span></div> <div class="helpRow"><strong>Universe</strong><span>Tap to move the target. Drag horizontally to rotate space. The animation uses no external library or CDN.</span></div> <div class="helpRow"><strong>Blow Up</strong><span>Blow Up Body stores energy. More stored energy makes your body physically bigger in the scene.</span></div> <div class="helpRow"><strong>Teleport</strong><span>Teleport Inside puts you inside the body universe so you can build a nebula or galaxy internally.</span></div> <div class="helpRow"><strong>Build Inside</strong><span>Building an inner nebula or galaxy spends stored energy and matter, so the body compresses and gets smaller afterward.</span></div> <div class="helpRow"><strong>I Menu</strong><span>The floating i opens tracker status, instructions, body actions, developer message, and admin contact links.</span></div> </div> </div> <div class="modalActions"> <button id="ledgerBtn" type="button">Open Ledger</button> <button id="resetBtn" type="button">Reset Progress</button> </div> </div> </div> <div class="toast" id="toast" role="status" aria-live="polite"></div> <script> (() => { 'use strict'; const $ = (selector, root = document) => root.querySelector(selector); const $$ = (selector, root = document) => [...root.querySelectorAll(selector)]; const csrf = $('meta[name="csrf-token"]').content; const TRACKER_CFG = window.KOSMOS_TRACKER_CONFIG || {}; const trackerState = { count: 0, online: false, session: (() => { try { const key = 'kosmos_tracker_session'; let value = sessionStorage.getItem(key); if (!value) { value = 'ks-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 9); sessionStorage.setItem(key, value); } return value; } catch (error) { return 'ks-' + Date.now().toString(36); } })() }; function setTrackerStatus(status, ok = null){ const statusEl = $('#trackerStatus'); const dot = $('#trackerDot'); const countEl = $('#trackerCount'); if(statusEl)statusEl.textContent = status; if(countEl)countEl.textContent = String(trackerState.count); if(dot){ dot.classList.remove('ok','fail'); if(ok === true)dot.classList.add('ok'); if(ok === false)dot.classList.add('fail'); } } function trackerPayload(eventName, detail = {}){ return { title: 'KOSMOS · ' + eventName, summary: detail.summary || eventName, event: eventName, app: TRACKER_CFG.APP || 'KOSMOS Body Nebula Forge', source: TRACKER_CFG.SOURCE || 'kosmos-game', url: location.href, path: location.pathname, referrer: document.referrer || '', at: new Date().toISOString(), session: trackerState.session, screen: innerWidth + 'x' + innerHeight, tz: Intl.DateTimeFormat().resolvedOptions().timeZone || 'Local', detail }; } function track(eventName, detail = {}, stream){ const base = TRACKER_CFG.WEBHOOK_BASE || '/connlink/test1/ui/webhook_inbox.php'; const targetStream = stream || TRACKER_CFG.EVENT_STREAM || 'default'; const endpoint = base + '?stream=' + encodeURIComponent(targetStream); const payload = trackerPayload(eventName, detail); const body = JSON.stringify(payload); try{ if(navigator.sendBeacon){ const blob = new Blob([body], {type:'application/json'}); if(navigator.sendBeacon(endpoint, blob)){ trackerState.count++; trackerState.online = true; setTrackerStatus('Online', true); return; } } fetch(endpoint, { method:'POST', headers:{'Content-Type':'application/json'}, keepalive:true, body }).then(()=>{ trackerState.online = true; setTrackerStatus('Online', true); }).catch(()=>{ setTrackerStatus('Local Only', false); }); trackerState.count++; setTrackerStatus('Sending', null); }catch(error){ trackerState.count++; setTrackerStatus('Local Only', false); } } function loadGA4(){ const id = TRACKER_CFG.GA4_ID; if(!id || document.querySelector('script[data-kosmos-ga4]'))return; window.dataLayer = window.dataLayer || []; window.gtag = function(){ window.dataLayer.push(arguments); }; window.gtag('js', new Date()); window.gtag('config', id, { send_page_view:true, page_title:document.title, page_path:location.pathname }); const script = document.createElement('script'); script.async = true; script.dataset.kosmosGa4 = 'true'; script.src = 'https://www.googletagmanager.com/gtag/js?id=' + encodeURIComponent(id); document.head.appendChild(script); } function updateInfoMenuStats(){ const size = Math.round((body?.scale || 1) * 100); const sizeEl = $('#infoBodySize'); const locEl = $('#infoBodyLocation'); const hudSize = $('#bodySizeOut'); const hudLocation = $('#bodyLocationOut'); const hudRule = $('#bodyRuleOut'); if(sizeEl)sizeEl.textContent = size + '%'; if(locEl)locEl.textContent = insideBody ? 'Inside Body' : 'Outside'; if(hudSize)hudSize.textContent = size + '%'; if(hudLocation)hudLocation.textContent = insideBody ? 'Inside' : 'Outside'; if(hudRule)hudRule.textContent = insideBody ? 'Build = Smaller' : 'Energy = Size'; const badge = $('#insideBadge'); if(badge)badge.classList.toggle('open', insideBody); } function openIMenu(){ const menu = $('#iMenu'); const veil = $('#menuVeil'); const orb = $('#iOrb'); if(!menu || !veil || !orb)return; menu.classList.add('open'); veil.classList.add('open'); veil.hidden = false; menu.setAttribute('aria-hidden','false'); orb.setAttribute('aria-expanded','true'); updateInfoMenuStats(); track('menu_open', {summary:'I menu opened'}); } function closeIMenu(){ const menu = $('#iMenu'); const veil = $('#menuVeil'); const orb = $('#iOrb'); if(!menu || !veil || !orb)return; menu.classList.remove('open'); veil.classList.remove('open'); veil.hidden = true; menu.setAttribute('aria-hidden','true'); orb.setAttribute('aria-expanded','false'); track('menu_close', {summary:'I menu closed'}); } const canvas = $('#world'); const ctx = canvas.getContext('2d', { alpha: false }); const FREQS = [ { hz:174, name:'Foundation', color:'#ffd57e', rgb:[255,213,126] }, { hz:285, name:'Repair', color:'#67efb5', rgb:[103,239,181] }, { hz:396, name:'Release', color:'#ff5d7e', rgb:[255,93,126] }, { hz:417, name:'Change', color:'#ff79db', rgb:[255,121,219] }, { hz:528, name:'Creation', color:'#a877ff', rgb:[168,119,255] }, { hz:639, name:'Connection', color:'#5be7ff', rgb:[91,231,255] }, { hz:852, name:'Dimension', color:'#ffffff', rgb:[255,255,255] } ]; const DEFAULT_STATE = { matter:30, energy:100, resonance:0, charge:0, shield:0, dimensions:0, nebulae:0, galaxies:0, stars:0, frequency:174, mode:'energy', playTime:0 }; let state = { ...DEFAULT_STATE }; let width = innerWidth; let height = innerHeight; let dpr = Math.min(devicePixelRatio || 1, 2); let last = performance.now(); let rotation = 0; let autoOrbit = true; let particlesVisible = true; let resonating = false; let charging = false; let soundEnabled = false; let ambientEnabled = false; let masterVolume = .70; let sfxVolume = .80; let audioCtx = null; let resonanceOsc = null; let resonanceGain = null; let ambientOsc = null; let ambientGain = null; let toastTimer = null; let saveTimer = null; let photoStream = null; let pendingPhotoData = ''; let appliedPhotoData = ''; let photoImage = null; let blendStrength = .72; let tintEnabled = true; let pointerDown = false; let dragStartX = 0; let dragRotationStart = 0; let aim = { x: width * .72, y: height * .42 }; let body = { x: width / 2, y: height * .50, scale:1 }; let particles = []; let stars = []; let waves = []; let beams = []; let clouds = []; let galaxies = []; let impacts = []; let logEntries = []; let creationGallery = []; let currentCinemaCreation = null; let cinemaRaf = 0; let cinemaStart = 0; let cinemaStars = []; let audioUnlocked = false; let bodyReleaseFlash = 0; let bodyReleaseMode = ''; let nebulaBuildPhase = 0; let insideBody = false; let bodyBurst = 0; let teleportPulse = 0; let innerBuildPulse = 0; function syncViewport(){ const h = window.visualViewport?.height || window.innerHeight; document.documentElement.style.setProperty('--app-height', `${Math.round(h)}px`); } syncViewport(); function resize(){ width = innerWidth; height = window.visualViewport?.height || innerHeight; dpr = Math.min(devicePixelRatio || 1, 2); canvas.width = Math.round(width * dpr); canvas.height = Math.round(height * dpr); canvas.style.width = width + 'px'; canvas.style.height = height + 'px'; ctx.setTransform(dpr,0,0,dpr,0,0); body.x = width / 2; body.y = height * .50; if (!Number.isFinite(aim.x)) aim.x = width * .72; if (!Number.isFinite(aim.y)) aim.y = height * .42; makeStars(); } window.addEventListener('resize', () => { syncViewport(); resize(); }); window.visualViewport?.addEventListener('resize', () => { syncViewport(); resize(); }); window.visualViewport?.addEventListener('scroll', syncViewport); function rand(min,max){ return Math.random()*(max-min)+min; } function clamp(v,min,max){ return Math.max(min,Math.min(max,v)); } function fmt(v){ if(v>=1e9)return(v/1e9).toFixed(1)+'B'; if(v>=1e6)return(v/1e6).toFixed(1)+'M'; if(v>=1e3)return(v/1e3).toFixed(1)+'K'; return Math.floor(v).toString(); } function currentFreq(){ return FREQS.find(f=>f.hz===Number(state.frequency)) || FREQS[0]; } function frequencyIndex(hz){ return Math.max(0,FREQS.findIndex(f=>f.hz===Number(hz))); } function haptic(pattern=10){ if(navigator.vibrate)navigator.vibrate(pattern); } function toast(message){ const el=$('#toast'); el.textContent=message; el.classList.add('show'); clearTimeout(toastTimer); toastTimer=setTimeout(()=>el.classList.remove('show'),1900); } function addLog(message){ logEntries.unshift({message,time:new Date().toLocaleTimeString([], {hour:'2-digit',minute:'2-digit'})}); logEntries=logEntries.slice(0,14); renderLog(); } function renderLog(){ $('#log').innerHTML=logEntries.map(item=>`<div class="logItem">${item.message}<time>${item.time} · KN Network</time></div>`).join(''); } async function api(action,extra={}){ try{ const response=await fetch(location.href,{ method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({action,csrf,...extra}) }); if(!response.ok)throw new Error('Request failed'); return await response.json(); }catch(error){ return {ok:false,error:error.message}; } } function normalize(input){ const out={...DEFAULT_STATE}; for(const key of Object.keys(DEFAULT_STATE)){ if(key==='mode'){ out.mode=['energy','nebula','galaxy'].includes(input?.mode)?input.mode:'energy'; }else{ const n=Number(input?.[key]); if(Number.isFinite(n))out[key]=Math.max(0,n); } } out.charge=clamp(out.charge,0,100); out.frequency=FREQS.some(f=>f.hz===out.frequency)?out.frequency:174; return out; } function localSave(){ try{ localStorage.setItem('kosmos-standalone-state',JSON.stringify(state)); localStorage.setItem('kosmos-standalone-photo',appliedPhotoData || ''); localStorage.setItem('kosmos-standalone-photo-strength',String(blendStrength)); localStorage.setItem('kosmos-standalone-photo-tint',tintEnabled?'1':'0'); localStorage.setItem('kosmos-standalone-gallery',JSON.stringify(creationGallery)); }catch{} } async function save(show=false){ localSave(); const result=await api('save',{state}); if(show)toast(result.ok?'Saved to PHP session.':'Saved locally.'); } function scheduleSave(){ clearTimeout(saveTimer); saveTimer=setTimeout(()=>save(false),700); } async function load(){ let local=null; try{local=JSON.parse(localStorage.getItem('kosmos-standalone-state')||'null')}catch{} const serverResult=await api('load'); const server=serverResult.ok?serverResult.state:null; const localScore=Number(local?.playTime||0)+Number(local?.resonance||0); const serverScore=Number(server?.playTime||0)+Number(server?.resonance||0); state=normalize(localScore>=serverScore?(local||server):(server||local)); try{ appliedPhotoData=localStorage.getItem('kosmos-standalone-photo')||''; blendStrength=clamp(Number(localStorage.getItem('kosmos-standalone-photo-strength')||.72),.1,1); tintEnabled=localStorage.getItem('kosmos-standalone-photo-tint')!=='0'; const savedGallery=JSON.parse(localStorage.getItem('kosmos-standalone-gallery')||'[]'); creationGallery=Array.isArray(savedGallery)?savedGallery.slice(0,60):[]; }catch{} if(appliedPhotoData)loadAppliedPhoto(appliedPhotoData); renderGallery(); setMode(state.mode,false); setFrequency(state.frequency,false); updateUI(); } function updateUI(){ $('#matterOut').textContent=fmt(state.matter); $('#energyOut').textContent=fmt(state.energy); $('#chargeOut').textContent=Math.round(state.charge)+'%'; $('#modeOut').textContent=capitalize(state.mode); $('#frequencyOut').textContent=`${state.frequency} Hz · ${currentFreq().name}`; $('#energyMeterLabel').textContent=fmt(state.energy); $('#resonanceMeterLabel').textContent=fmt(state.resonance); $('#chargeMeterLabel').textContent=Math.round(state.charge)+'%'; $('#energyMeter').style.width=clamp(state.energy/3,0,100)+'%'; $('#resonanceMeter').style.width=clamp(state.resonance/5,0,100)+'%'; $('#chargeMeter').style.width=state.charge+'%'; $('#releaseModeSmall').textContent=capitalize(state.mode); $('#tuneSmall').textContent=state.frequency+' Hz'; $('#shieldOut').textContent=fmt(state.shield); $('#dimensionsOut').textContent=fmt(state.dimensions); $('#nebulaeOut').textContent=fmt(state.nebulae); $('#starsOut').textContent=fmt(state.stars); $('#galaxiesOut').textContent=fmt(state.galaxies); $('#resonanceOut').textContent=fmt(state.resonance); } function capitalize(s){return s.charAt(0).toUpperCase()+s.slice(1)} function makeStars(){ const count=clamp(Math.floor((width*height)/2300),180,560); stars=Array.from({length:count},()=>({ x:Math.random()*width,y:Math.random()*height,z:rand(.1,1), r:rand(.25,1.6),tw:rand(.6,2.8),phase:rand(0,Math.PI*2) })); } function spawnParticle(forcedHz=null){ const type=forcedHz?FREQS.find(f=>f.hz===forcedHz):FREQS[Math.floor(Math.random()*FREQS.length)]; particles.push({ x:rand(-width*.1,width*1.1), y:rand(height*.12,height*.82), z:rand(.35,1.8), vx:rand(-.25,.25),vy:rand(-.18,.18),vz:rand(-.004,.004), hz:type.hz,color:type.color,rgb:type.rgb,r:rand(2.2,5.4), phase:rand(0,Math.PI*2),life:rand(28,75) }); } function seedParticles(){ particles=[]; const count=clamp(Math.floor((width*height)/7000),70,180); for(let i=0;i<count;i++)spawnParticle(); } function project(x,y,z){ const perspective=1/(.45+z*.55); const dx=x-body.x; const dy=y-body.y; const cos=Math.cos(rotation),sin=Math.sin(rotation); const rx=dx*cos-dy*.08*sin; return { x:body.x+rx*perspective, y:body.y+dy*perspective, scale:perspective }; } function drawBackground(t){ const grad=ctx.createRadialGradient(body.x,body.y,10,body.x,body.y,Math.max(width,height)*.75); grad.addColorStop(0,'#15103b'); grad.addColorStop(.38,'#09091d'); grad.addColorStop(1,'#020207'); ctx.fillStyle=grad; ctx.fillRect(0,0,width,height); for(const s of stars){ const a=.32+s.z*.55+Math.sin(t*.001*s.tw+s.phase)*.18; ctx.fillStyle=`rgba(255,255,255,${clamp(a,0,1)})`; ctx.beginPath(); ctx.arc(s.x,s.y,s.r*s.z,0,Math.PI*2); ctx.fill(); } drawSpaceCloud(width*.18,height*.30,Math.min(width,height)*.32,[154,109,255],.055,t*.00008); drawSpaceCloud(width*.82,height*.64,Math.min(width,height)*.34,[255,86,211],.045,-t*.00006); drawSpaceCloud(width*.72,height*.18,Math.min(width,height)*.22,[91,231,255],.035,t*.0001); } function drawSpaceCloud(x,y,r,rgb,alpha,rot){ ctx.save(); ctx.translate(x,y); ctx.rotate(rot); ctx.strokeStyle=`rgba(${rgb[0]},${rgb[1]},${rgb[2]},${alpha})`; ctx.lineWidth=r*.14; ctx.lineCap='round'; for(let i=0;i<5;i++){ ctx.beginPath(); ctx.ellipse(0,0,r*(.42+i*.13),r*(.08+i*.03),i*.2,0,Math.PI*2); ctx.stroke(); } ctx.restore(); } function drawParticles(t,dt){ if(!particlesVisible)return; const targetCount=clamp(Math.floor((width*height)/6900)+state.shield*3,75,200); while(particles.length<targetCount)spawnParticle(); const attractRadius=150+state.shield*7+state.resonance*.02; const freq=currentFreq(); for(let i=particles.length-1;i>=0;i--){ const p=particles[i]; p.life-=dt; p.phase+=dt*2; p.z+=p.vz; p.x+=p.vx*dt*60; p.y+=p.vy*dt*60; const dx=body.x-p.x; const dy=body.y-p.y; const dist=Math.hypot(dx,dy)||1; const matched=p.hz===state.frequency; if(resonating&&dist<attractRadius*(matched?1.35:.7)){ const pull=(matched?.14:.022)*(1-dist/(attractRadius*(matched?1.35:.7))); p.vx+=(dx/dist)*pull*dt*60; p.vy+=(dy/dist)*pull*dt*60; p.z-=matched?.004:.001; }else{ p.vx+=Math.sin(p.phase)*.0013; p.vy+=Math.cos(p.phase*.8)*.0011; } p.vx*=Math.pow(.992,dt*60); p.vy*=Math.pow(.992,dt*60); if(dist<28+state.shield*.5){ const mult=matched?2.4:.42; state.matter+=1.1*mult*(1+state.shield*.03); state.energy+=.75*mult; state.resonance+=.36*mult; state.charge=clamp(state.charge+(matched?.15:.02),0,100); impacts.push({x:body.x,y:body.y,r:4,life:1,color:p.color}); particles.splice(i,1); spawnParticle(); continue; } if(p.life<=0||p.x<-100||p.x>width+100||p.y<-100||p.y>height+100||p.z<.15||p.z>2.3){ particles.splice(i,1); spawnParticle(); continue; } const q=project(p.x,p.y,p.z); const pulse=1+Math.sin(t*.004+p.phase)*.24; const radius=p.r*q.scale*pulse; const glow=ctx.createRadialGradient(q.x,q.y,0,q.x,q.y,radius*4); glow.addColorStop(0,p.color); glow.addColorStop(.3,`rgba(${p.rgb[0]},${p.rgb[1]},${p.rgb[2]},.72)`); glow.addColorStop(1,'rgba(0,0,0,0)'); ctx.fillStyle=glow; ctx.beginPath();ctx.arc(q.x,q.y,radius*4,0,Math.PI*2);ctx.fill(); ctx.fillStyle=p.color; ctx.beginPath();ctx.arc(q.x,q.y,Math.max(.7,radius*.7),0,Math.PI*2);ctx.fill(); } } function drawShield(t){ const base=58+state.shield*6; ctx.save(); ctx.translate(body.x,body.y); ctx.globalCompositeOperation='lighter'; for(let i=0;i<Math.min(state.shield,10);i++){ ctx.strokeStyle=`rgba(${i%2?'91,231,255':'154,109,255'},${.09+.02*Math.sin(t*.002+i)})`; ctx.lineWidth=1; ctx.setLineDash([4+i,8+i*2]); ctx.lineDashOffset=-t*.01*(i+1); ctx.beginPath(); ctx.ellipse(0,0,base+i*11,(base+i*11)*1.15,rotation*.35+i*.12,0,Math.PI*2); ctx.stroke(); } ctx.setLineDash([]); ctx.restore(); } function nebulaPalette(baseRgb){ const base=Array.isArray(baseRgb)?baseRgb:[154,109,255]; return [ base, [91,231,255], [255,86,211], [255,213,126], [255,255,255], [111,239,181], [118,94,255] ]; } function rgbCss(rgb,alpha=1){ return `rgba(${rgb[0]},${rgb[1]},${rgb[2]},${alpha})`; } function drawInternalNebula(t,intensity,freq){ if(intensity<=.01)return; const palette=nebulaPalette(freq.rgb); const breathing=1+Math.sin(t*.0045)*.08; const coreRadius=34+intensity*24; const spin=t*.00075; ctx.save(); ctx.globalCompositeOperation='lighter'; ctx.globalAlpha=clamp(.20+intensity*.55,0,.92); // Clip the nebula inside the head and expanded torso. ctx.beginPath(); ctx.ellipse(0,-59,17.2,22.4,0,0,Math.PI*2); ctx.moveTo(-24,-35); ctx.bezierCurveTo(-48,-22,-44,15,-33,43); ctx.bezierCurveTo(-24,67,-16,91,0,97); ctx.bezierCurveTo(16,91,24,67,33,43); ctx.bezierCurveTo(44,15,48,-22,24,-35); ctx.closePath(); ctx.clip(); const core=ctx.createRadialGradient(0,5,0,0,5,coreRadius*breathing); core.addColorStop(0,'rgba(255,255,255,.95)'); core.addColorStop(.12,rgbCss(palette[3],.72)); core.addColorStop(.34,rgbCss(palette[2],.48)); core.addColorStop(.62,rgbCss(palette[1],.25)); core.addColorStop(1,'rgba(0,0,0,0)'); ctx.fillStyle=core; ctx.fillRect(-70,-92,140,200); // Layered rotating filaments. // Teleport shock rings. if(teleportPulse > .01){ for(let shock=0;shock<5;shock++){ const sr=Math.min(width,height)*(.09+shock*.07+teleportPulse*.08); const color=palette[shock%palette.length]; ctx.strokeStyle=rgbCss(color,.10+teleportPulse*.10); ctx.lineWidth=8+shock*2; ctx.shadowBlur=28+teleportPulse*30; ctx.shadowColor=rgbCss(color,.9); ctx.beginPath(); ctx.ellipse(0,0,sr,sr*(.22+shock*.018),rotation+shock*.28,0,Math.PI*2); ctx.stroke(); } } for(let layer=0;layer<12;layer++){ const color=palette[layer%palette.length]; const rr=(18+layer*4.7)*(1+intensity*.22); const wobble=Math.sin(t*.0025+layer*1.4)*5; ctx.save(); ctx.rotate(spin*(layer%2?1:-1)+layer*.31); ctx.strokeStyle=rgbCss(color,.11+intensity*.045); ctx.lineWidth=4+layer*.9; ctx.shadowBlur=16+intensity*18; ctx.shadowColor=rgbCss(color,.9); ctx.beginPath(); ctx.ellipse( Math.sin(t*.0017+layer)*4, 8+Math.cos(t*.0013+layer)*5, rr+wobble, rr*(.18+layer*.013), layer*.16, 0, Math.PI*2 ); ctx.stroke(); ctx.restore(); } // Internal star systems and moving particles. for(let i=0;i<42;i++){ const phase=i*.917; const radius=(8+(i%11)*4.4)*(1+intensity*.18); const angle=spin*(i%2?1.8:-1.35)+phase; const px=Math.cos(angle)*radius*.72; const py=10+Math.sin(angle)*radius*.96; const color=palette[i%palette.length]; const spark=1.1+(i%4)*.42+Math.sin(t*.006+phase)*.35; ctx.fillStyle=rgbCss(color,.48+intensity*.35); ctx.shadowBlur=8+intensity*10; ctx.shadowColor=rgbCss(color,.95); ctx.beginPath(); ctx.arc(px,py,Math.max(.5,spark),0,Math.PI*2); ctx.fill(); } // Vertical dimensional current through the body. const current=ctx.createLinearGradient(0,-74,0,94); current.addColorStop(0,'rgba(255,255,255,0)'); current.addColorStop(.22,rgbCss(palette[1],.52)); current.addColorStop(.52,rgbCss(palette[4],.88)); current.addColorStop(.78,rgbCss(palette[2],.52)); current.addColorStop(1,'rgba(255,255,255,0)'); ctx.fillStyle=current; ctx.shadowBlur=20+intensity*24; ctx.shadowColor=freq.color; ctx.fillRect(-2.2,-78,4.4,178); ctx.restore(); // Expanding external nebula aura around the body. ctx.save(); ctx.globalCompositeOperation='lighter'; ctx.globalAlpha=clamp(intensity*.55,0,.76); for(let ring=0;ring<7;ring++){ const color=palette[ring%palette.length]; const radius=(64+ring*14)*(1+intensity*.34+Math.sin(t*.002+ring)*.035); ctx.save(); ctx.rotate(spin*(ring%2?1:-1)+ring*.22); ctx.strokeStyle=rgbCss(color,.10+intensity*.07); ctx.lineWidth=7+ring*2.4; ctx.shadowBlur=20+intensity*24; ctx.shadowColor=rgbCss(color,.9); ctx.beginPath(); ctx.ellipse(0,4,radius,radius*(.23+ring*.012),ring*.11,0,Math.PI*2); ctx.stroke(); ctx.restore(); } ctx.restore(); } function drawBody(t){ const freq=currentFreq(); const nebulaCharge=state.mode==='nebula' ? clamp(state.charge/60,0,1.35) : clamp(state.charge/100,0,.24); const chargeExpansion=state.mode==='nebula'?(nebulaCharge*.18):0; const releaseExpansion=bodyReleaseMode==='nebula'?bodyReleaseFlash*.26:bodyReleaseFlash*.10; const pulse=1+Math.sin(t*.0022)*.025+(resonating?.035:0)+(charging?.025:0); const storedEnergyScale=clamp(state.energy/360,0,.55); const insideShrink=insideBody ? -0.24 : 0; const totalScale=clamp(pulse+chargeExpansion+releaseExpansion+storedEnergyScale+bodyBurst+insideShrink,.46,2.35); body.scale=totalScale; nebulaBuildPhase=nebulaCharge; ctx.save(); ctx.translate(body.x,body.y); ctx.scale(totalScale,totalScale); ctx.globalCompositeOperation='lighter'; const aura=ctx.createRadialGradient(0,0,5,0,0,100+state.shield*4); aura.addColorStop(0,`rgba(${freq.rgb.join(',')},.24)`); aura.addColorStop(.45,'rgba(154,109,255,.10)'); aura.addColorStop(1,'rgba(0,0,0,0)'); ctx.fillStyle=aura; ctx.beginPath();ctx.arc(0,0,100+state.shield*4,0,Math.PI*2);ctx.fill(); // The portrait is painted after the body geometry so it remains visible. const bodyGrad=ctx.createLinearGradient(0,-75,0,85); bodyGrad.addColorStop(0,'rgba(255,224,190,.94)'); bodyGrad.addColorStop(.45,`rgba(${freq.rgb.join(',')},.72)`); bodyGrad.addColorStop(1,'rgba(154,109,255,.45)'); ctx.fillStyle=bodyGrad; ctx.shadowBlur=24;ctx.shadowColor=freq.color; ctx.beginPath(); ctx.ellipse(0,-59,18,23,0,0,Math.PI*2); ctx.fill(); ctx.beginPath(); ctx.moveTo(-23,-35); ctx.bezierCurveTo(-46,-24,-42,12,-31,40); ctx.bezierCurveTo(-23,62,-16,82,0,89); ctx.bezierCurveTo(16,82,23,62,31,40); ctx.bezierCurveTo(42,12,46,-24,23,-35); ctx.closePath(); ctx.fill(); ctx.strokeStyle=`rgba(${freq.rgb.join(',')},.84)`; ctx.lineWidth=10;ctx.lineCap='round'; ctx.beginPath();ctx.moveTo(-25,-25);ctx.lineTo(-52,18);ctx.stroke(); ctx.beginPath();ctx.moveTo(25,-25);ctx.lineTo(52,18);ctx.stroke(); ctx.lineWidth=11; ctx.beginPath();ctx.moveTo(-13,75);ctx.lineTo(-24,111);ctx.stroke(); ctx.beginPath();ctx.moveTo(13,75);ctx.lineTo(24,111);ctx.stroke(); if(photoImage){ const ratio=photoImage.width/photoImage.height; const drawCover=(cx,cy,cw,ch)=>{ let dw=cw,dh=dw/ratio; if(dh<ch){dh=ch;dw=dh*ratio} ctx.drawImage(photoImage,cx-dw/2,cy-dh/2,dw,dh); }; ctx.save(); ctx.globalCompositeOperation='source-over'; ctx.globalAlpha=Math.min(1,blendStrength*.96); ctx.beginPath(); ctx.ellipse(0,-59,16.4,21.5,0,0,Math.PI*2); ctx.clip(); drawCover(0,-59,38,47); if(tintEnabled){ ctx.globalCompositeOperation='screen'; ctx.fillStyle=`rgba(${freq.rgb.join(',')},.24)`; ctx.fillRect(-20,-83,40,49); } ctx.restore(); ctx.save(); ctx.globalCompositeOperation='source-over'; ctx.globalAlpha=blendStrength*.72; ctx.beginPath(); ctx.moveTo(-22,-33); ctx.bezierCurveTo(-39,-19,-36,13,-28,39); ctx.bezierCurveTo(-20,62,-12,79,0,84); ctx.bezierCurveTo(12,79,20,62,28,39); ctx.bezierCurveTo(36,13,39,-19,22,-33); ctx.closePath(); ctx.clip(); drawCover(0,20,62,118); if(tintEnabled){ ctx.globalCompositeOperation='screen'; ctx.fillStyle=`rgba(${freq.rgb.join(',')},.34)`; ctx.fillRect(-36,-40,72,130); } ctx.restore(); ctx.save(); ctx.globalCompositeOperation='lighter'; ctx.strokeStyle=`rgba(${freq.rgb.join(',')},.75)`; ctx.lineWidth=1.2; ctx.shadowBlur=18+Math.sin(t*.004)*8; ctx.shadowColor=freq.color; ctx.beginPath();ctx.ellipse(0,-59,18.5,24.5,0,0,Math.PI*2);ctx.stroke(); ctx.restore(); } const internalNebulaIntensity=clamp( (state.mode==='nebula'?state.charge/60:0)+ (charging&&state.mode==='nebula'?.16:0)+ (bodyReleaseMode==='nebula'?bodyReleaseFlash*.95:0), 0,1.65 ); drawInternalNebula(t,internalNebulaIntensity,freq); const eyeGlow=.45+state.charge/100*.55+ (state.mode==='nebula'?internalNebulaIntensity*.18:0); ctx.shadowBlur=16+state.charge*.12; ctx.shadowColor='#fff'; const eyeRadius=2.1+state.charge*.015+ (state.mode==='nebula'?internalNebulaIntensity*1.8:0); const eyeGradient=ctx.createRadialGradient(0,-61,0,0,-61,14+internalNebulaIntensity*12); eyeGradient.addColorStop(0,'rgba(255,255,255,.98)'); eyeGradient.addColorStop(.18,'rgba(91,231,255,.88)'); eyeGradient.addColorStop(.48,'rgba(255,86,211,.58)'); eyeGradient.addColorStop(1,'rgba(0,0,0,0)'); ctx.fillStyle=eyeGradient; ctx.globalAlpha=clamp(eyeGlow,0,1); ctx.beginPath();ctx.arc(-6,-61,eyeRadius*3.2,0,Math.PI*2);ctx.fill(); ctx.beginPath();ctx.arc(6,-61,eyeRadius*3.2,0,Math.PI*2);ctx.fill(); ctx.globalAlpha=1; ctx.fillStyle='rgba(255,255,255,.98)'; ctx.beginPath();ctx.arc(-6,-61,eyeRadius,0,Math.PI*2);ctx.fill(); ctx.beginPath();ctx.arc(6,-61,eyeRadius,0,Math.PI*2);ctx.fill(); const nodes=[[-0,-27,'#fff'],[0,-5,'#5be7ff'],[0,18,'#ff56d3'],[0,42,'#67efb5']]; for(const [x,y,c] of nodes){ ctx.fillStyle=c;ctx.beginPath();ctx.arc(x,y,3.2,0,Math.PI*2);ctx.fill(); } ctx.save(); ctx.rotate(t*.00042); for(let ring=0;ring<4;ring++){ const rr=48+ring*12+Math.sin(t*.0018+ring)*4; ctx.strokeStyle=`rgba(${ring%2?'91,231,255':'255,86,211'},${.12+ring*.025})`; ctx.lineWidth=1.2; ctx.beginPath(); ctx.ellipse(0,0,rr,rr*(.34+ring*.035),ring*.38,0,Math.PI*2); ctx.stroke(); const orbA=t*.0015*(ring%2?1:-1)+ring; ctx.fillStyle=ring%2?'#5be7ff':'#ff56d3'; ctx.beginPath(); ctx.arc(Math.cos(orbA)*rr,Math.sin(orbA)*rr*.36,2.2+ring*.35,0,Math.PI*2); ctx.fill(); } ctx.restore(); ctx.restore(); } function drawAim(t){ const r=13+Math.sin(t*.006)*3; ctx.save(); ctx.translate(aim.x,aim.y); ctx.strokeStyle=`rgba(${currentFreq().rgb.join(',')},.85)`; ctx.lineWidth=1.4; ctx.setLineDash([4,5]); ctx.rotate(t*.001); ctx.beginPath();ctx.arc(0,0,r,0,Math.PI*2);ctx.stroke(); ctx.setLineDash([]); ctx.beginPath();ctx.moveTo(-r-7,0);ctx.lineTo(r+7,0);ctx.moveTo(0,-r-7);ctx.lineTo(0,r+7);ctx.stroke(); ctx.restore(); } function addWave(color){ waves.push({x:body.x,y:body.y,r:20,life:1,color}); } function updateEffects(dt,t){ ctx.save(); ctx.globalCompositeOperation='lighter'; for(let i=waves.length-1;i>=0;i--){ const w=waves[i];w.r+=dt*150;w.life-=dt*.7; ctx.globalAlpha=clamp(w.life,0,1); ctx.strokeStyle=w.color;ctx.lineWidth=2; ctx.beginPath();ctx.arc(w.x,w.y,w.r,0,Math.PI*2);ctx.stroke(); if(w.life<=0)waves.splice(i,1); } for(let i=beams.length-1;i>=0;i--){ const b=beams[i];b.life-=dt*1.8; ctx.globalAlpha=clamp(b.life,0,1); const grad=ctx.createLinearGradient(b.x1,b.y1,b.x2,b.y2); grad.addColorStop(0,'#fff');grad.addColorStop(.4,b.color);grad.addColorStop(1,'rgba(255,255,255,.1)'); ctx.strokeStyle=grad;ctx.lineWidth=(b.width||4)+b.life*8;ctx.lineCap='round'; ctx.beginPath();ctx.moveTo(b.x1,b.y1);ctx.lineTo(b.x2,b.y2);ctx.stroke(); if(b.life<=0)beams.splice(i,1); } for(let i=impacts.length-1;i>=0;i--){ const p=impacts[i];p.r+=dt*80;p.life-=dt*1.2; ctx.globalAlpha=clamp(p.life,0,1); ctx.strokeStyle=p.color;ctx.lineWidth=2; ctx.beginPath();ctx.arc(p.x,p.y,p.r,0,Math.PI*2);ctx.stroke(); if(p.life<=0)impacts.splice(i,1); } ctx.restore(); ctx.globalAlpha=1; for(const c of clouds){ c.rot+=dt*c.speed; c.life=Math.min(1,c.life+dt*.42); c.phase=(c.phase||0)+dt*.7; const palette=c.palette||nebulaPalette(c.rgb); const depthPulse=1+Math.sin(t*.0018+(c.phase||0))*.09; ctx.save(); ctx.translate(c.x,c.y); ctx.scale(depthPulse,1/depthPulse*.96); ctx.rotate(c.rot); ctx.globalCompositeOperation='lighter'; // Soft colored volume layers. for(let i=0;i<14;i++){ const color=palette[i%palette.length]; const rr=c.r*(.26+i*.055); const wobble=Math.sin(t*.0022+i*1.17+(c.phase||0))*c.r*.035; const alpha=c.life*(.027+i*.0035); ctx.save(); ctx.rotate((i%2?1:-1)*(c.rot*.55+i*.08)); ctx.strokeStyle=rgbCss(color,alpha); ctx.lineWidth=14+i*3.4; ctx.shadowBlur=22+i*1.2; ctx.shadowColor=rgbCss(color,.72); ctx.beginPath(); ctx.ellipse( Math.sin(t*.0014+i)*c.r*.06, Math.cos(t*.0011+i)*c.r*.035, rr+wobble, rr*(.16+i*.011), i*.17, 0,Math.PI*2 ); ctx.stroke(); ctx.restore(); } // Bright breathing core. const coreRadius=c.r*(.18+Math.sin(t*.004+(c.phase||0))*.035); const core=ctx.createRadialGradient(0,0,0,0,0,coreRadius*2.4); core.addColorStop(0,'rgba(255,255,255,.96)'); core.addColorStop(.10,rgbCss(palette[3],.76)); core.addColorStop(.28,rgbCss(palette[2],.48)); core.addColorStop(.55,rgbCss(palette[1],.20)); core.addColorStop(1,'rgba(0,0,0,0)'); ctx.fillStyle=core; ctx.beginPath();ctx.arc(0,0,coreRadius*2.4,0,Math.PI*2);ctx.fill(); // Drifting filaments and internal stars. for(let i=0;i<70;i++){ const phase=(c.phase||0)+i*.781; const radius=(8+(i%17)*c.r*.032); const angle=phase*(i%2?1.4:-1.15)+c.rot*2; const x=Math.cos(angle)*radius; const y=Math.sin(angle)*radius*.43; const color=palette[i%palette.length]; const size=.55+(i%5)*.32+Math.sin(t*.005+phase)*.22; ctx.fillStyle=i%11===0?'rgba(255,255,255,.92)':rgbCss(color,.55); ctx.shadowBlur=6+(i%4)*3; ctx.shadowColor=rgbCss(color,.86); ctx.beginPath();ctx.arc(x,y,Math.max(.4,size),0,Math.PI*2);ctx.fill(); } // Foreground arcs create depth. for(let arc=0;arc<5;arc++){ const color=palette[(arc+2)%palette.length]; ctx.strokeStyle=rgbCss(color,.14+c.life*.05); ctx.lineWidth=1.2+arc*.45; ctx.beginPath(); ctx.ellipse( 0,0, c.r*(.48+arc*.10), c.r*(.12+arc*.018), -c.rot*.7+arc*.38, Math.PI*.10,Math.PI*1.32 ); ctx.stroke(); } ctx.restore(); } for(const g of galaxies){ g.rot+=dt*g.speed; ctx.save(); ctx.translate(g.x,g.y); ctx.rotate(g.rot); ctx.globalCompositeOperation='lighter'; for(let arm=0;arm<3;arm++){ ctx.strokeStyle=arm===1?'rgba(91,231,255,.38)':'rgba(255,86,211,.30)'; ctx.lineWidth=2; ctx.beginPath(); for(let i=0;i<70;i++){ const r=i/70*g.r; const a=arm*Math.PI*2/3+r*.12; const x=Math.cos(a)*r; const y=Math.sin(a)*r*.45; i===0?ctx.moveTo(x,y):ctx.lineTo(x,y); } ctx.stroke(); } ctx.fillStyle='rgba(255,255,255,.8)'; ctx.beginPath();ctx.arc(0,0,3.5,0,Math.PI*2);ctx.fill(); ctx.restore(); } } function drawInsideBodyField(t){ const freq=currentFreq(); const palette=nebulaPalette(freq.rgb); ctx.save(); ctx.globalCompositeOperation='lighter'; const pulse=1+Math.sin(t*.0035)*.12+teleportPulse*.18; const inner=ctx.createRadialGradient(body.x,body.y,8,body.x,body.y,Math.max(width,height)*.62*pulse); inner.addColorStop(0,'rgba(255,255,255,.20)'); inner.addColorStop(.10,`rgba(${freq.rgb.join(',')},.24)`); inner.addColorStop(.32,'rgba(255,86,211,.12)'); inner.addColorStop(.62,'rgba(91,231,255,.08)'); inner.addColorStop(1,'rgba(0,0,0,0)'); ctx.fillStyle=inner; ctx.fillRect(0,0,width,height); ctx.translate(body.x,body.y); for(let layer=0;layer<12;layer++){ const color=palette[layer%palette.length]; const r=Math.min(width,height)*(.12+layer*.035)*(1+innerBuildPulse*.12); ctx.save(); ctx.rotate(t*.00045*(layer%2?1:-1)+layer*.26); ctx.strokeStyle=rgbCss(color,.085+innerBuildPulse*.055); ctx.lineWidth=5+layer*1.2; ctx.shadowBlur=18+innerBuildPulse*22; ctx.shadowColor=rgbCss(color,.8); ctx.beginPath(); ctx.ellipse(0,0,r,r*(.18+layer*.01),layer*.15,0,Math.PI*2); ctx.stroke(); ctx.restore(); } for(let i=0;i<80;i++){ const color=palette[i%palette.length]; const radius=(18+(i%20)*10)*(1+innerBuildPulse*.08); const angle=t*.0009*(i%2?1.35:-1.1)+i*.78; const x=Math.cos(angle)*radius; const y=Math.sin(angle)*radius*.54; ctx.fillStyle=i%13===0?'rgba(255,255,255,.95)':rgbCss(color,.55); ctx.shadowBlur=8; ctx.shadowColor=rgbCss(color,.9); ctx.beginPath(); ctx.arc(x,y,.7+(i%5)*.32,0,Math.PI*2); ctx.fill(); } ctx.restore(); } function loop(t){ const dt=Math.min(.035,(t-last)/1000||.016); last=t; state.playTime+=dt; bodyReleaseFlash=Math.max(0,bodyReleaseFlash-dt*1.15); bodyBurst=Math.max(0,bodyBurst-dt*.55); teleportPulse=Math.max(0,teleportPulse-dt*.72); innerBuildPulse=Math.max(0,innerBuildPulse-dt*.46); if(bodyReleaseFlash<=0&&bodyReleaseMode&&state.mode!=='nebula')bodyReleaseMode=''; if(autoOrbit)rotation+=dt*.06; if(resonating){ state.energy=Math.max(0,state.energy-dt*.45); state.resonance+=dt*(1+state.frequency/700); if(state.energy<=0)stopResonating(); if(Math.floor(t/700)!==Math.floor((t-dt*1000)/700))addWave(currentFreq().color); } if(charging){ const rate=11+state.shield*.5; const needed=dt*2.2; if(state.energy>needed&&state.charge<100){ state.energy-=needed; state.charge=clamp(state.charge+dt*rate,0,100); }else{ stopCharging(); } } drawBackground(t); if(insideBody)drawInsideBodyField(t); drawParticles(t,dt); drawShield(t); updateEffects(dt,t); drawBody(t); drawAim(t); updateUI(); requestAnimationFrame(loop); } function safeAction(fn){ return event=>{ try{ event?.preventDefault?.(); haptic(7); fn(event); }catch(error){ console.error(error); toast('That control could not complete. Try again.'); } }; } function bindHold(button,start,stop){ const begin=e=>{e.preventDefault();button.classList.add('holding');haptic(8);start()}; const end=e=>{e.preventDefault();button.classList.remove('holding');stop()}; button.addEventListener('pointerdown',begin,{passive:false}); ['pointerup','pointercancel','pointerleave'].forEach(name=>button.addEventListener(name,end,{passive:false})); } function startResonating(){ if(resonating)return; resonating=true; startResonanceSound(); addWave(currentFreq().color); } function stopResonating(){ resonating=false; stopResonanceSound(); } function startCharging(){ charging=true; playTone(Math.max(80,state.frequency/2),.12,.04); } function stopCharging(){charging=false} function setFrequency(hz,feedback=true){ state.frequency=Number(hz); $$('.frequency').forEach(b=>b.classList.toggle('active',Number(b.dataset.hz)===state.frequency)); if(feedback){ playTone(state.frequency,.18,.045); haptic(10); toast(`${state.frequency} Hz · ${currentFreq().name}`); } drawBodyMeterPhoto(); updateUI();scheduleSave(); } function setMode(mode,feedback=true){ if(!['energy','nebula','galaxy'].includes(mode))return; state.mode=mode; $$('[data-mode]').forEach(b=>b.classList.toggle('active',b.dataset.mode===mode)); if(feedback){haptic(12);toast(`${capitalize(mode)} eye release selected.`)} updateUI();scheduleSave(); } function makeCreation(type){ const f=currentFreq(); return { id:`${Date.now()}-${Math.random().toString(36).slice(2,8)}`, type, hz:f.hz, frequencyName:f.name, color:f.color, rgb:[...f.rgb], seed:Math.floor(Math.random()*1_000_000), createdAt:new Date().toISOString() }; } function storeCreation(type){ if(!['nebula','galaxy'].includes(type))return null; const creation=makeCreation(type); creationGallery.unshift(creation); creationGallery=creationGallery.slice(0,60); renderGallery(); localSave(); return creation; } function renderGallery(){ const grid=$('#galleryGrid'); if(!grid)return; if(!creationGallery.length){ grid.innerHTML='<div class="galleryEmpty">Release a Nebula or Galaxy from the eyes. Your creations will appear here for full-screen viewing and sharing.</div>'; return; } grid.innerHTML=creationGallery.map(item=>{ const date=new Date(item.createdAt); const safeType=item.type==='galaxy'?'galaxy':'nebula'; const rgb=(item.rgb||[154,109,255]).join(','); return `<article class="galleryCard" data-type="${safeType}" style="--gallery-rgb:${rgb}"> <div class="galleryVisual"></div> <div class="galleryContent"> <small>${safeType} · ${item.hz} Hz</small> <strong>${safeType==='galaxy'?'Released Galaxy':'Released Nebula'}</strong> <span>${date.toLocaleDateString()} · ${item.frequencyName||'Kosmos'}</span> <div class="galleryActions"> <button type="button" data-show-creation="${item.id}">Full Screen</button> <button type="button" data-share-creation="${item.id}">Share</button> </div> </div> </article>`; }).join(''); } function getCreation(id){ return creationGallery.find(item=>item.id===id)||null; } function seedRandom(seed){ let value=(Number(seed)||1)%2147483647; if(value<=0)value+=2147483646; return ()=>((value=value*16807%2147483647)-1)/2147483646; } function resizeCinema(){ const c=$('#releaseCanvas'); const ratio=Math.min(devicePixelRatio||1,2); c.width=Math.round(innerWidth*ratio); c.height=Math.round((window.visualViewport?.height||innerHeight)*ratio); c.style.width=innerWidth+'px'; c.style.height=(window.visualViewport?.height||innerHeight)+'px'; const cctx=c.getContext('2d'); cctx.setTransform(ratio,0,0,ratio,0,0); } function openCinema(creation,requestNativeFullscreen=false){ if(!creation)return; currentCinemaCreation=creation; const overlay=$('#releaseCinema'); overlay.classList.add('open'); overlay.setAttribute('aria-hidden','false'); $('#cinemaTitle').textContent=creation.type==='galaxy'?'GALAXY RELEASED':creation.type==='nebula'?'NEBULA RELEASED':'ENERGY RELEASED'; $('#cinemaSubtitle').textContent=`${creation.hz} Hz · ${creation.frequencyName||'Kosmos'} · KN Network`; closeSheets(); resizeCinema(); cinemaStart=performance.now(); cinemaStars=[]; const random=seedRandom(creation.seed); for(let i=0;i<260;i++){ cinemaStars.push({x:random(),y:random(),z:.2+random()*.8,r:.3+random()*1.8,p:random()*Math.PI*2}); } cancelAnimationFrame(cinemaRaf); drawCinema(performance.now()); if(requestNativeFullscreen&&document.fullscreenEnabled&&!document.fullscreenElement){ document.documentElement.requestFullscreen?.().catch(()=>{}); } } function closeCinema(){ $('#releaseCinema').classList.remove('open'); $('#releaseCinema').setAttribute('aria-hidden','true'); cancelAnimationFrame(cinemaRaf); if(document.fullscreenElement)document.exitFullscreen?.().catch(()=>{}); } function drawCinema(now){ if(!currentCinemaCreation||!$('#releaseCinema').classList.contains('open'))return; const c=$('#releaseCanvas'); const cctx=c.getContext('2d'); const w=innerWidth,h=window.visualViewport?.height||innerHeight; const elapsed=(now-cinemaStart)/1000; const creation=currentCinemaCreation; const rgb=creation.rgb||[154,109,255]; const random=seedRandom(creation.seed); const bg=cctx.createRadialGradient(w*.5,h*.48,1,w*.5,h*.48,Math.max(w,h)*.75); bg.addColorStop(0,`rgba(${rgb.join(',')},.20)`); bg.addColorStop(.32,'#100a26'); bg.addColorStop(1,'#010104'); cctx.fillStyle=bg; cctx.fillRect(0,0,w,h); for(const s of cinemaStars){ const tw=.45+s.z*.5+Math.sin(elapsed*(1+s.z*2)+s.p)*.22; cctx.fillStyle=`rgba(255,255,255,${clamp(tw,0,1)})`; cctx.beginPath(); cctx.arc(s.x*w,s.y*h,s.r*s.z,0,Math.PI*2); cctx.fill(); } cctx.save(); cctx.translate(w/2,h*.49); cctx.globalCompositeOperation='lighter'; if(creation.type==='energy'){ const pulse=1+Math.sin(elapsed*5)*.15; const g=cctx.createRadialGradient(0,0,0,0,0,Math.min(w,h)*.38*pulse); g.addColorStop(0,'rgba(255,255,255,.96)'); g.addColorStop(.10,`rgba(${rgb.join(',')},.72)`); g.addColorStop(.45,`rgba(${rgb.join(',')},.18)`); g.addColorStop(1,'rgba(0,0,0,0)'); cctx.fillStyle=g;cctx.beginPath();cctx.arc(0,0,Math.min(w,h)*.38*pulse,0,Math.PI*2);cctx.fill(); for(let i=0;i<9;i++){ cctx.strokeStyle=`rgba(${rgb.join(',')},${.42-i*.035})`; cctx.lineWidth=2; cctx.beginPath();cctx.arc(0,0,28+i*24+(elapsed*55)%24,0,Math.PI*2);cctx.stroke(); } }else if(creation.type==='nebula'){ const palette=nebulaPalette(rgb); const rot=elapsed*.16; const maxR=Math.min(w,h)*.44; cctx.rotate(rot); // Deep volumetric color shells. for(let i=0;i<22;i++){ const color=palette[i%palette.length]; const rr=maxR*(.18+i*.035); const wobble=Math.sin(elapsed*.8+i*1.4)*maxR*.018; cctx.save(); cctx.rotate((i%2?1:-1)*(elapsed*.08+i*.055)); cctx.strokeStyle=rgbCss(color,.045+i*.0048); cctx.lineWidth=18+i*4.6; cctx.shadowBlur=30+i*1.5; cctx.shadowColor=rgbCss(color,.9); cctx.beginPath(); cctx.ellipse( Math.sin(elapsed*.5+i)*maxR*.045, Math.cos(elapsed*.4+i)*maxR*.025, rr+wobble, rr*(.13+i*.008), i*.17, 0,Math.PI*2 ); cctx.stroke(); cctx.restore(); } // White-gold heart surrounded by cyan and magenta plasma. const pulse=1+Math.sin(elapsed*3.4)*.10; const core=cctx.createRadialGradient(0,0,0,0,0,maxR*.34*pulse); core.addColorStop(0,'rgba(255,255,255,.98)'); core.addColorStop(.08,rgbCss(palette[3],.88)); core.addColorStop(.22,rgbCss(palette[2],.60)); core.addColorStop(.45,rgbCss(palette[1],.32)); core.addColorStop(.72,rgbCss(palette[0],.14)); core.addColorStop(1,'rgba(0,0,0,0)'); cctx.fillStyle=core; cctx.beginPath();cctx.arc(0,0,maxR*.34*pulse,0,Math.PI*2);cctx.fill(); // Animated streams and inner star systems. for(let i=0;i<360;i++){ const base=random(); const arm=i%7; const radius=Math.pow(base,.62)*maxR; const angle=arm*Math.PI*2/7+ radius*.024+ elapsed*(arm%2?.16:-.12)+ (random()-.5)*.36; const depth=.42+random()*.58; const x=Math.cos(angle)*radius; const y=Math.sin(angle)*radius*(.32+depth*.20); const color=palette[i%palette.length]; const size=.45+random()*2.5*depth; cctx.fillStyle=i%17===0?'rgba(255,255,255,.98)':rgbCss(color,.52+depth*.28); cctx.shadowBlur=5+depth*14; cctx.shadowColor=rgbCss(color,.95); cctx.beginPath();cctx.arc(x,y,size,0,Math.PI*2);cctx.fill(); } // Foreground filaments provide a 3D parallax shell. for(let filament=0;filament<8;filament++){ const color=palette[(filament+1)%palette.length]; cctx.save(); cctx.rotate(-rot*1.5+filament*.42); cctx.strokeStyle=rgbCss(color,.18); cctx.lineWidth=1.4+filament*.35; cctx.beginPath(); for(let p=0;p<=90;p++){ const ratio=p/90; const radius=maxR*(.18+ratio*.80); const angle=ratio*Math.PI*2.2+Math.sin(elapsed*.7+filament)*.18; const x=Math.cos(angle)*radius; const y=Math.sin(angle)*radius*(.18+filament*.018); p===0?cctx.moveTo(x,y):cctx.lineTo(x,y); } cctx.stroke(); cctx.restore(); } }else{ cctx.rotate(elapsed*.10); const maxR=Math.min(w,h)*.42; for(let arm=0;arm<4;arm++){ cctx.beginPath(); for(let i=0;i<240;i++){ const r=i/240*maxR; const a=arm*Math.PI/2+r*.033+elapsed*.16; const wobble=Math.sin(i*.22+elapsed*2)*3; const x=Math.cos(a)*(r+wobble); const y=Math.sin(a)*(r+wobble)*.50; i===0?cctx.moveTo(x,y):cctx.lineTo(x,y); } cctx.strokeStyle=arm%2?`rgba(91,231,255,.42)`:`rgba(${rgb.join(',')},.46)`; cctx.lineWidth=2.4; cctx.shadowBlur=22;cctx.shadowColor=arm%2?'#5be7ff':creation.color; cctx.stroke(); } const core=cctx.createRadialGradient(0,0,0,0,0,maxR*.22); core.addColorStop(0,'#fff'); core.addColorStop(.14,creation.color); core.addColorStop(1,'rgba(0,0,0,0)'); cctx.fillStyle=core;cctx.beginPath();cctx.arc(0,0,maxR*.22,0,Math.PI*2);cctx.fill(); for(let i=0;i<340;i++){ const arm=i%4; const r=Math.pow(random(),.62)*maxR; const a=arm*Math.PI/2+r*.033+elapsed*.16+(random()-.5)*.28; const x=Math.cos(a)*r; const y=Math.sin(a)*r*.50+(random()-.5)*10; cctx.fillStyle=i%13===0?'#fff':`rgba(${rgb.join(',')},.78)`; cctx.beginPath();cctx.arc(x,y,.5+random()*1.7,0,Math.PI*2);cctx.fill(); } } cctx.restore(); cinemaRaf=requestAnimationFrame(drawCinema); } function cinemaBlob(){ return new Promise(resolve=>$('#releaseCanvas').toBlob(resolve,'image/png',.94)); } async function shareCurrentCreation(){ if(!currentCinemaCreation){toast('No creation selected.');return} try{ const blob=await cinemaBlob(); if(!blob)throw new Error('Image export failed'); const filename=`kosmos-${currentCinemaCreation.type}-${currentCinemaCreation.hz}hz.png`; const file=new File([blob],filename,{type:'image/png'}); const shareData={ title:`KOSMOS ${capitalize(currentCinemaCreation.type)}`, text:`Created through ${currentCinemaCreation.hz} Hz in Gaylord Sinclair's KN Network.`, files:[file] }; if(navigator.share&&(!navigator.canShare||navigator.canShare({files:[file]}))){ await navigator.share(shareData); return; } downloadCinema(); }catch(error){ if(error?.name!=='AbortError'){ console.error(error); toast('Share unavailable. Use Save Image instead.'); } } } function downloadCinema(){ const c=$('#releaseCanvas'); const link=document.createElement('a'); link.href=c.toDataURL('image/png',.94); link.download=`kosmos-${currentCinemaCreation?.type||'creation'}-${Date.now()}.png`; document.body.appendChild(link); link.click(); link.remove(); } function shareLatestCreation(){ const latest=creationGallery[0]; if(!latest){toast('Release a nebula or galaxy first.');return} openCinema(latest,false); shareCurrentCreation(); } function releaseFromEyes(){ const costs={energy:25,nebula:60,galaxy:100}; const cost=costs[state.mode]; if(state.charge<cost){ toast(`Need ${cost}% eye charge.`); playTone(82,.12,.025); return; } if(state.mode==='galaxy'&&state.matter<250){ toast('Galaxy release also needs 250 matter.'); return; } const eyeY=body.y-60; const releaseColors=state.mode==='nebula' ? nebulaPalette(currentFreq().rgb).map(rgb=>rgbCss(rgb,1)) : [currentFreq().color,'#ffffff']; releaseColors.forEach((color,index)=>{ const spread=(index-(releaseColors.length-1)/2)*2.2; const jitter=(index%2?1:-1)*(2+index*.45); beams.push({ x1:body.x-6,y1:eyeY, x2:aim.x+spread,y2:aim.y+jitter, life:1,color, width:state.mode==='nebula'?5.5:4 }); beams.push({ x1:body.x+6,y1:eyeY, x2:aim.x-spread,y2:aim.y-jitter, life:1,color, width:state.mode==='nebula'?5.5:4 }); }); impacts.push({x:aim.x,y:aim.y,r:8,life:1,color:currentFreq().color}); state.charge-=cost; bodyReleaseFlash=1; bodyReleaseMode=state.mode; let releasedCreation=makeCreation(state.mode); if(state.mode==='energy'){ state.resonance+=18; state.energy+=8; state.matter+=5; addLog('<b>Eye energy released:</b> unstable matter was converted at the target.'); playImpact(state.frequency,.34); }else if(state.mode==='nebula'){ clouds.push({ x:aim.x, y:aim.y, r:rand(90,145), rgb:currentFreq().rgb, palette:nebulaPalette(currentFreq().rgb), rot:0, speed:rand(-.18,.18), phase:rand(0,Math.PI*2), depth:rand(.8,1.25), life:0 }); state.nebulae++; state.resonance+=45; state.matter+=20; addLog('<b>Nebula released:</b> body energy expanded into a persistent cloud.'); releasedCreation=storeCreation('nebula')||releasedCreation; playImpact(state.frequency*.65,.65); }else{ state.matter-=250; galaxies.push({x:aim.x,y:aim.y,r:rand(55,85),rot:0,speed:rand(.08,.18)}); state.galaxies++; state.dimensions++; state.resonance+=120; addLog('<b>Galaxy released:</b> twin-eye projection formed a dimensional system.'); releasedCreation=storeCreation('galaxy')||releasedCreation; playImpact(Math.max(70,state.frequency*.35),1); } haptic([12,30,18]); updateUI();scheduleSave(); setTimeout(()=>{ openCinema(releasedCreation,true); bodyReleaseMode=''; },720); } function replicateShield(){ if(state.matter<70||state.energy<30){toast('Need 70 matter and 30 energy.');return} state.matter-=70;state.energy-=30;state.shield++; state.resonance+=20;addWave('#5be7ff'); addLog(`<b>Shield replicated:</b> layer ${state.shield} is active.`); playImpact(220,.4);updateUI();scheduleSave(); } function forgeDimension(){ if(state.matter<350||state.shield<3){toast('Need 350 matter and 3 shield layers.');return} state.matter-=350;state.dimensions++;state.resonance+=90; galaxies.push({x:width*.5+rand(-80,80),y:height*.35+rand(-50,50),r:rand(35,58),rot:0,speed:.08}); addLog(`<b>Dimension forged:</b> dimensional layer ${state.dimensions} stabilized.`); playImpact(145,.8);updateUI();scheduleSave(); } function igniteStar(){ if(state.matter<160||state.energy<80){toast('Need 160 matter and 80 energy.');return} state.matter-=160;state.energy-=80;state.stars++;state.resonance+=35; for(let i=0;i<24;i++)impacts.push({x:aim.x+rand(-30,30),y:aim.y+rand(-30,30),r:rand(1,8),life:rand(.5,1),color:'#ffd57e'}); addLog(`<b>Star ignited:</b> star ${state.stars} joined the KN Kosmos.`); playImpact(310,.55);updateUI();scheduleSave(); } function matterBurst(){ state.energy=Math.max(0,state.energy-8); for(let i=0;i<22;i++)spawnParticle(state.frequency); addLog(`<b>Matter burst:</b> ${state.frequency} Hz particles entered the field.`); playTone(state.frequency*1.3,.16,.04);toast('Matched matter burst created.'); } function blowUpBody(){ if(state.matter < 25 && state.charge < 10){ toast('Need matter or charge to store body energy.'); return; } const spentMatter=Math.min(state.matter,45); const spentCharge=Math.min(state.charge,25); state.matter-=spentMatter; state.charge-=spentCharge; const energyGain=55+spentMatter*.85+spentCharge*1.4; state.energy+=energyGain; state.resonance+=18+spentCharge*.35; bodyBurst=Math.min(1.15,bodyBurst+.42); innerBuildPulse=1; addWave(currentFreq().color); impacts.push({x:body.x,y:body.y,r:18,life:1,color:'#ffd57e'}); addLog(`<b>Body expanded:</b> stored energy increased body size by ${Math.round(energyGain)} units.`); toast('Body energy stored. You are getting bigger.'); track('body_blow_up', {energyGain, spentMatter, spentCharge, energy:state.energy}); playImpact(180,.45); updateUI();scheduleSave(); } function teleportInsideBody(){ insideBody=!insideBody; teleportPulse=1.45; innerBuildPulse=1.15; aim={x:body.x,y:body.y}; closeSheets(); const msg=insideBody ? '<b>Teleport:</b> you entered the body universe. Build nebulae or galaxies from stored energy.' : '<b>Teleport:</b> you returned outside the body.'; addLog(msg); toast(insideBody?'Teleported inside the body.':'Returned outside the body.'); track(insideBody?'teleport_inside_body':'teleport_exit_body', {energy:state.energy, matter:state.matter}); updateUI(); } function exitInsideBody(){ if(!insideBody){ toast('You are already outside the body.'); return; } insideBody=false; teleportPulse=1; innerBuildPulse=.7; addLog('<b>Exit:</b> body interior closed and the outer universe returned.'); toast('Exited body interior.'); track('teleport_exit_body', {energy:state.energy, matter:state.matter}); updateUI(); } function buildInnerNebula(){ if(!insideBody){ toast('Teleport inside the body first.'); return; } if(state.energy < 55 || state.matter < 40){ toast('Need 55 energy and 40 matter to build an inner nebula.'); return; } state.energy-=55; state.matter-=40; state.nebulae++; state.resonance+=70; state.charge=clamp(state.charge+12,0,100); innerBuildPulse=1.8; bodyBurst=Math.max(bodyBurst,.12); clouds.push({ x:body.x+rand(-55,55), y:body.y+rand(-35,35), r:rand(95,150), rgb:currentFreq().rgb, palette:nebulaPalette(currentFreq().rgb), rot:0, speed:rand(-.18,.18), phase:rand(0,Math.PI*2), depth:rand(.8,1.25), life:0 }); const creation=storeCreation('nebula'); addLog('<b>Inner nebula built:</b> stored energy condensed inside the body. Body size reduced after creation.'); toast('Inner nebula built. Energy spent, body gets smaller.'); track('build_inner_nebula', {energy:state.energy, matter:state.matter, creation:creation?.id||''}); playImpact(state.frequency*.7,.7); updateUI();scheduleSave(); } function buildInnerGalaxy(){ if(!insideBody){ toast('Teleport inside the body first.'); return; } if(state.energy < 130 || state.matter < 160){ toast('Need 130 energy and 160 matter to build an inner galaxy.'); return; } state.energy-=130; state.matter-=160; state.galaxies++; state.dimensions++; state.resonance+=160; state.charge=clamp(state.charge+20,0,100); innerBuildPulse=2.2; bodyBurst=Math.max(bodyBurst,.20); galaxies.push({ x:body.x+rand(-40,40), y:body.y+rand(-35,35), r:rand(65,95), rot:0, speed:rand(.08,.18) }); const creation=storeCreation('galaxy'); addLog('<b>Inner galaxy built:</b> a galaxy formed inside the body. Energy drained and the body compressed smaller.'); toast('Inner galaxy built. Energy spent, body gets smaller.'); track('build_inner_galaxy', {energy:state.energy, matter:state.matter, creation:creation?.id||''}); playImpact(Math.max(70,state.frequency*.35),1); setTimeout(()=>openCinema(creation,true),420); updateUI();scheduleSave(); } function closeSheets(except=null){ $$('.sheet').forEach(s=>{if(s!==except)s.classList.remove('open')}); } function openSheet(sheet){ closeSheets(sheet); sheet.classList.toggle('open'); } $$('[data-close-sheet]').forEach(b=>b.addEventListener('click',()=>b.closest('.sheet')?.classList.remove('open'))); $('#tuneBtn').addEventListener('click',()=>openSheet($('#tuneSheet'))); $('#menuBtn').addEventListener('click',()=>openSheet($('#menuSheet'))); $('#galleryBtn').addEventListener('click',()=>{ renderGallery(); openSheet($('#gallerySheet')); }); $('#shareLatestBtn').addEventListener('click',shareLatestCreation); $('#galleryGrid').addEventListener('click',event=>{ const show=event.target.closest('[data-show-creation]'); const share=event.target.closest('[data-share-creation]'); if(show){ const creation=getCreation(show.dataset.showCreation); if(creation)openCinema(creation,true); }else if(share){ const creation=getCreation(share.dataset.shareCreation); if(creation){ openCinema(creation,false); shareCurrentCreation(); } } }); $('#cinemaShareBtn').addEventListener('click',shareCurrentCreation); $('#cinemaSaveBtn').addEventListener('click',downloadCinema); $('#cinemaCloseBtn').addEventListener('click',closeCinema); window.addEventListener('resize',()=>{if($('#releaseCinema').classList.contains('open'))resizeCinema()}); window.visualViewport?.addEventListener('resize',()=>{if($('#releaseCinema').classList.contains('open'))resizeCinema()}); $('#ledgerBtn').addEventListener('click',()=>{ $('#helpModal').classList.remove('open'); openSheet($('#ledgerSheet')); }); $('#bodyToggle').addEventListener('click',()=>{ const compact=$('#bodyMeter').classList.toggle('compact'); $('#bodyToggle').textContent=compact?'Open':'Close'; }); function bindInfoMenu(){ const openers=[$('#iOrb'),$('#infoTopBtn')].filter(Boolean); openers.forEach(button=>button.addEventListener('click',()=>{ const menu=$('#iMenu'); if(menu?.classList.contains('open'))closeIMenu(); else openIMenu(); })); $('#iClose')?.addEventListener('click',closeIMenu); $('#menuVeil')?.addEventListener('click',closeIMenu); document.addEventListener('keydown',event=>{if(event.key==='Escape')closeIMenu()}); $('#infoBlowUpBtn')?.addEventListener('click',blowUpBody); $('#infoTeleportBtn')?.addEventListener('click',teleportInsideBody); $('#infoNebulaBtn')?.addEventListener('click',buildInnerNebula); $('#infoGalaxyBtn')?.addEventListener('click',buildInnerGalaxy); $('#infoExitBodyBtn')?.addEventListener('click',exitInsideBody); $('#infoShareBtn')?.addEventListener('click',shareLatestCreation); $('#copyPageBtn')?.addEventListener('click', async ()=>{ try{ if(navigator.clipboard){ await navigator.clipboard.writeText(location.href); toast('Page link copied.'); track('page_link_copied', {summary:'KOSMOS page link copied'}); }else{ alert(location.href); } }catch(error){ alert(location.href); track('page_link_copy_failed', {summary:'Clipboard unavailable'}); } }); document.addEventListener('click',event=>{ const target=event.target.closest('a,button'); if(!target)return; const label=target.getAttribute('data-track') || target.id || target.textContent.trim().replace(/\s+/g,'_').toLowerCase().slice(0,80) || target.tagName.toLowerCase(); track('click', { label, href: target.getAttribute('href') || '', text: target.textContent.trim().slice(0,140) }); }, {capture:true}); } function buildFrequencyButtons(){ $('#frequencyGrid').innerHTML=FREQS.map(f=>`<button class="frequency ${f.hz===state.frequency?'active':''}" data-hz="${f.hz}" type="button"><strong>${f.hz} Hz</strong><small>${f.name}</small></button>`).join(''); $$('.frequency').forEach(b=>b.addEventListener('click',()=>setFrequency(Number(b.dataset.hz)))); } buildFrequencyButtons(); bindInfoMenu(); loadGA4(); setTrackerStatus('Starting', null); track('page_view', {summary:'KOSMOS dimension forge viewed'}, TRACKER_CFG.VISIT_STREAM || 'visits'); $$('[data-mode]').forEach(b=>b.addEventListener('click',()=>setMode(b.dataset.mode))); bindHold($('#resonateBtn'),startResonating,stopResonating); bindHold($('#chargeBtn'),startCharging,stopCharging); $('#releaseBtn').addEventListener('click',releaseFromEyes); $('#shieldBtn').addEventListener('click',replicateShield); $('#dimensionBtn').addEventListener('click',forgeDimension); $('#starBtn').addEventListener('click',igniteStar); $('#matterBurstBtn').addEventListener('click',matterBurst); $('#blowUpBodyBtn').addEventListener('click',blowUpBody); $('#teleportBodyBtn').addEventListener('click',teleportInsideBody); $('#innerNebulaBtn').addEventListener('click',buildInnerNebula); $('#innerGalaxyBtn').addEventListener('click',buildInnerGalaxy); $('#menuBlowUpBodyBtn')?.addEventListener('click',blowUpBody); $('#menuTeleportBodyBtn')?.addEventListener('click',teleportInsideBody); $('#menuInnerNebulaBtn')?.addEventListener('click',buildInnerNebula); $('#menuInnerGalaxyBtn')?.addEventListener('click',buildInnerGalaxy); $('#menuExitBodyBtn')?.addEventListener('click',exitInsideBody); $('#menuOpenIHubBtn')?.addEventListener('click',openIMenu); $('#resetAimBtn').addEventListener('click',()=>{aim={x:width*.72,y:height*.42};toast('Aim reset.')}); $('#saveBtn').addEventListener('click',()=>save(true)); $('#particlesToggle').addEventListener('click',()=>{ particlesVisible=!particlesVisible; $('#particlesToggle').classList.toggle('active',particlesVisible); }); $('#orbitToggle').addEventListener('click',()=>{ autoOrbit=!autoOrbit; $('#orbitToggle').classList.toggle('active',autoOrbit); }); canvas.addEventListener('pointerdown',e=>{ pointerDown=true; dragStartX=e.clientX; dragRotationStart=rotation; aim.x=e.clientX;aim.y=e.clientY; }); canvas.addEventListener('pointermove',e=>{ if(!pointerDown)return; const dx=e.clientX-dragStartX; if(Math.abs(dx)>12)rotation=dragRotationStart+dx*.006; aim.x=e.clientX;aim.y=e.clientY; }); canvas.addEventListener('pointerup',e=>{ pointerDown=false; aim.x=e.clientX;aim.y=e.clientY; haptic(6); }); canvas.addEventListener('pointercancel',()=>pointerDown=false); function getAudioContext(){ if(!audioCtx){ const AudioCtor=window.AudioContext||window.webkitAudioContext; if(!AudioCtor)throw new Error('Web Audio is not supported.'); try{ audioCtx=new AudioCtor({latencyHint:'interactive'}); }catch{ audioCtx=new AudioCtor(); } } return audioCtx; } async function unlockAudio(){ try{ const ac=getAudioContext(); if(ac.state!=='running')await ac.resume(); const buffer=ac.createBuffer(1,1,22050); const source=ac.createBufferSource(); source.buffer=buffer; source.connect(ac.destination); source.start(0); const osc=ac.createOscillator(); const gain=ac.createGain(); osc.type='sine'; osc.frequency.value=state.frequency; gain.gain.setValueAtTime(.0001,ac.currentTime); gain.gain.exponentialRampToValueAtTime(.11*masterVolume,ac.currentTime+.02); gain.gain.exponentialRampToValueAtTime(.0001,ac.currentTime+.18); osc.connect(gain).connect(ac.destination); osc.start(); osc.stop(ac.currentTime+.2); audioUnlocked=true; return true; }catch(error){ audioUnlocked=false; console.error('Audio unlock failed',error); return false; } } function withRunningAudio(callback){ if(!soundEnabled)return; let ac; try{ac=getAudioContext()}catch{return} if(ac.state==='running'){ callback(ac); return; } ac.resume().then(()=>{ audioUnlocked=true; callback(ac); }).catch(error=>console.error('Audio resume failed',error)); } function playTone(freq,duration=.12,volume=.07){ withRunningAudio(ac=>{ const osc=ac.createOscillator(); const gain=ac.createGain(); osc.type='sine'; osc.frequency.setValueAtTime(Math.max(40,freq),ac.currentTime); gain.gain.setValueAtTime(Math.max(.0001,volume*masterVolume*sfxVolume),ac.currentTime); gain.gain.exponentialRampToValueAtTime(.0001,ac.currentTime+duration); osc.connect(gain).connect(ac.destination); osc.start(); osc.stop(ac.currentTime+duration+.02); }); } function playImpact(freq,duration=.3){ withRunningAudio(ac=>{ const osc=ac.createOscillator(); const sub=ac.createOscillator(); const gain=ac.createGain(); const subGain=ac.createGain(); osc.type='triangle'; osc.frequency.setValueAtTime(Math.max(50,freq),ac.currentTime); osc.frequency.exponentialRampToValueAtTime(Math.max(40,freq*.34),ac.currentTime+duration); gain.gain.setValueAtTime(.12*masterVolume*sfxVolume,ac.currentTime); gain.gain.exponentialRampToValueAtTime(.0001,ac.currentTime+duration); sub.type='sine'; sub.frequency.setValueAtTime(Math.max(35,freq*.25),ac.currentTime); subGain.gain.setValueAtTime(.08*masterVolume*sfxVolume,ac.currentTime); subGain.gain.exponentialRampToValueAtTime(.0001,ac.currentTime+duration*.85); osc.connect(gain).connect(ac.destination); sub.connect(subGain).connect(ac.destination); osc.start();sub.start(); osc.stop(ac.currentTime+duration+.02); sub.stop(ac.currentTime+duration+.02); }); } function startResonanceSound(){ if(!soundEnabled||resonanceOsc)return; withRunningAudio(ac=>{ if(resonanceOsc)return; resonanceOsc=ac.createOscillator(); resonanceGain=ac.createGain(); resonanceOsc.type='sine'; resonanceOsc.frequency.setValueAtTime(state.frequency,ac.currentTime); resonanceGain.gain.setValueAtTime(.0001,ac.currentTime); resonanceGain.gain.exponentialRampToValueAtTime(.09*masterVolume*sfxVolume,ac.currentTime+.05); resonanceOsc.connect(resonanceGain).connect(ac.destination); resonanceOsc.start(); }); } function stopResonanceSound(){ if(!resonanceOsc||!resonanceGain||!audioCtx)return; try{ resonanceGain.gain.cancelScheduledValues(audioCtx.currentTime); resonanceGain.gain.setValueAtTime(Math.max(.0001,resonanceGain.gain.value),audioCtx.currentTime); resonanceGain.gain.exponentialRampToValueAtTime(.0001,audioCtx.currentTime+.08); resonanceOsc.stop(audioCtx.currentTime+.1); }catch{} resonanceOsc=null;resonanceGain=null; } function startAmbient(){ if(!soundEnabled||!ambientEnabled||ambientOsc)return; withRunningAudio(ac=>{ if(ambientOsc)return; ambientOsc=ac.createOscillator(); ambientGain=ac.createGain(); ambientOsc.type='sine'; ambientOsc.frequency.value=54; ambientGain.gain.setValueAtTime(.018*masterVolume,ac.currentTime); ambientOsc.connect(ambientGain).connect(ac.destination); ambientOsc.start(); }); } function stopAmbient(){ if(!ambientOsc)return; try{ambientOsc.stop()}catch{} ambientOsc=null;ambientGain=null; } $('#soundBtn').addEventListener('click',async()=>{ if(soundEnabled){ soundEnabled=false; $('#soundBtn').textContent='SND'; stopResonanceSound(); stopAmbient(); toast('Sound disabled.'); return; } soundEnabled=true; $('#soundBtn').textContent='...'; const unlocked=await unlockAudio(); if(!unlocked){ soundEnabled=false; $('#soundBtn').textContent='SND'; toast('Sound could not start. Tap SND again and check iPhone volume.'); return; } $('#soundBtn').textContent='ON'; if(ambientEnabled)startAmbient(); toast('Sound enabled. Frequency test played.'); }); $('#ambientToggle').addEventListener('change',e=>{ambientEnabled=e.target.checked;ambientEnabled?startAmbient():stopAmbient()}); $('#masterVolume').addEventListener('input',e=>{masterVolume=Number(e.target.value)/100;$('#masterVolumeOut').textContent=e.target.value+'%'}); $('#sfxVolume').addEventListener('input',e=>{sfxVolume=Number(e.target.value)/100;$('#sfxVolumeOut').textContent=e.target.value+'%'}); function openPhoto(){ closeSheets(); $('#photoModal').classList.add('open'); $('#blendRange').value=String(Math.round(blendStrength*100)); $('#blendOut').textContent=Math.round(blendStrength*100)+'%'; $('#tintToggle').checked=tintEnabled; if(appliedPhotoData){ $('#photoPreviewImg').src=appliedPhotoData; $('#photoPreviewImg').classList.add('active'); $('#cameraStatus').textContent='Current body blend loaded.'; $('#applyPhotoBtn').disabled=false; pendingPhotoData=appliedPhotoData; } } function closePhoto(){ $('#photoModal').classList.remove('open'); stopCamera(); } $('#photoBtn').addEventListener('click',openPhoto); $('#closePhotoBtn').addEventListener('click',closePhoto); async function startCamera(){ stopCamera(); if(!window.isSecureContext){ $('#cameraStatus').textContent='Live camera requires HTTPS. Choose Photo still works.'; toast('Use HTTPS for live camera.'); return; } if(!navigator.mediaDevices?.getUserMedia){ $('#cameraStatus').textContent='This browser does not provide live camera access. Use Choose Photo.'; return; } try{ photoStream=await navigator.mediaDevices.getUserMedia({ video:{facingMode:'user',width:{ideal:1280},height:{ideal:1280}}, audio:false }); const video=$('#cameraVideo'); video.srcObject=photoStream; video.setAttribute('playsinline',''); video.muted=true; await video.play(); $('#cameraPlaceholder').style.display='none'; $('#takePhotoBtn').disabled=false; $('#captureCanvas').classList.remove('ready'); $('#cameraStatus').textContent='Camera ready. Center your face and tap Take Photo.'; }catch(error){ $('#cameraStatus').textContent=`Camera failed: ${error?.name||'permission denied'}. Use Choose Photo.`; toast('Camera permission denied or unavailable.'); } } function stopCamera(){ if(photoStream){ photoStream.getTracks().forEach(track=>track.stop()); photoStream=null; } const video=$('#cameraVideo'); video.pause(); video.srcObject=null; $('#takePhotoBtn').disabled=true; } function squareCrop(sw,sh){ const side=Math.min(sw,sh); return {sx:(sw-side)/2,sy:(sh-side)/2,sw:side,sh:side}; } function drawSource(source,mirror=false){ const c=$('#captureCanvas'); const cctx=c.getContext('2d',{alpha:true}); const sw=source.videoWidth||source.naturalWidth||source.width; const sh=source.videoHeight||source.naturalHeight||source.height; if(!sw||!sh)throw new Error('Photo source not ready'); const crop=squareCrop(sw,sh); cctx.clearRect(0,0,c.width,c.height); cctx.save(); if(mirror){cctx.translate(c.width,0);cctx.scale(-1,1)} cctx.drawImage(source,crop.sx,crop.sy,crop.sw,crop.sh,0,0,c.width,c.height); cctx.restore(); c.classList.add('ready'); $('#cameraPlaceholder').style.display='none'; pendingPhotoData=c.toDataURL('image/jpeg',.86); $('#photoPreviewImg').src=pendingPhotoData; $('#photoPreviewImg').classList.add('active'); $('#cameraStatus').textContent='Photo ready. Adjust the blend and apply.'; $('#applyPhotoBtn').disabled=false; } $('#startCameraBtn').addEventListener('click',startCamera); $('#takePhotoBtn').addEventListener('click',()=>{ const video=$('#cameraVideo'); if(!video.videoWidth){toast('Camera is still loading.');return} try{drawSource(video,true);stopCamera()}catch{toast('Could not capture photo.')} }); $('#retakeBtn').addEventListener('click',()=>{ pendingPhotoData=''; $('#captureCanvas').classList.remove('ready'); $('#applyPhotoBtn').disabled=true; startCamera(); }); $('#photoInput').addEventListener('change',event=>{ const file=event.target.files?.[0]; if(!file)return; if(!file.type.startsWith('image/')){toast('Choose an image file.');return} if(file.size>20*1024*1024){toast('Photo is too large. Choose one under 20 MB.');return} const reader=new FileReader(); reader.onload=()=>{ const image=new Image(); image.onload=()=>{ try{drawSource(image,false)} catch{toast('Could not process the photo.')} }; image.onerror=()=>toast('Could not read the photo.'); image.src=String(reader.result); }; reader.onerror=()=>toast('Could not open the photo.'); reader.readAsDataURL(file); }); $('#blendRange').addEventListener('input',e=>{ blendStrength=Number(e.target.value)/100; $('#blendOut').textContent=e.target.value+'%'; }); $('#tintToggle').addEventListener('change',e=>{tintEnabled=e.target.checked}); function loadAppliedPhoto(data){ const image=new Image(); image.onload=()=>{ photoImage=image; $('#bodyPhotoCanvas').classList.add('bodyPhotoVisible'); drawBodyMeterPhoto(); }; image.onerror=()=>{photoImage=null}; image.src=data; } function drawBodyMeterPhoto(){ const c=$('#bodyPhotoCanvas'); const bctx=c.getContext('2d',{alpha:true}); bctx.clearRect(0,0,c.width,c.height); if(!photoImage)return; const ratio=photoImage.width/photoImage.height; let dw=c.width,dh=dw/ratio; if(dh<c.height){dh=c.height;dw=dh*ratio} bctx.globalAlpha=blendStrength*.65; bctx.drawImage(photoImage,(c.width-dw)/2,(c.height-dh)/2,dw,dh); if(tintEnabled){ bctx.globalCompositeOperation='screen'; const rgb=currentFreq().rgb; bctx.fillStyle=`rgba(${rgb.join(',')},.30)`; bctx.fillRect(0,0,c.width,c.height); } bctx.globalCompositeOperation='source-over'; bctx.globalAlpha=1; } $('#applyPhotoBtn').addEventListener('click',()=>{ if(!pendingPhotoData){toast('Take or choose a photo first.');return} appliedPhotoData=pendingPhotoData; loadAppliedPhoto(appliedPhotoData); $('#bodyPhotoCanvas').classList.add('bodyPhotoVisible'); localSave(); addLog('<b>Photo blend:</b> a local portrait joined the Kosmos body.'); toast('Photo blended into the body.'); closePhoto(); }); $('#removePhotoBtn').addEventListener('click',()=>{ appliedPhotoData='';pendingPhotoData='';photoImage=null; try{localStorage.removeItem('kosmos-standalone-photo')}catch{} $('#photoPreviewImg').classList.remove('active'); $('#captureCanvas').classList.remove('ready'); $('#cameraStatus').textContent='Photo blend removed.'; $('#applyPhotoBtn').disabled=true; drawBodyMeterPhoto(); toast('Photo blend removed.'); }); $('#helpBtn').addEventListener('click',()=>{$('#helpModal').classList.add('open');closeSheets()}); $('#closeHelpBtn').addEventListener('click',()=>$('#helpModal').classList.remove('open')); $('#resetBtn').addEventListener('click',async()=>{ if(!confirm('Reset all KOSMOS progress?'))return; await api('reset'); state={...DEFAULT_STATE}; particles=[];clouds=[];galaxies=[];waves=[];beams=[];impacts=[];logEntries=[];creationGallery=[]; try{ localStorage.removeItem('kosmos-standalone-state'); localStorage.removeItem('kosmos-standalone-gallery'); }catch{} renderGallery(); seedParticles();setMode('energy',false);setFrequency(174,false);updateUI();renderLog(); toast('KOSMOS reset.'); }); document.addEventListener('visibilitychange',()=>{ if(document.hidden){save(false);stopCamera()} track(document.hidden?'page_hidden':'page_visible', {summary:document.hidden?'Page hidden':'Page visible'}); }); window.addEventListener('beforeunload',localSave); setInterval(()=>save(false),15000); resize(); seedParticles(); addLog('<b>Gay Central live:</b> standalone PHP animation engine online.'); addLog('<b>KN Network:</b> photo capture, sound, matter, and eye release ready.'); load().then(()=>{ drawBodyMeterPhoto(); requestAnimationFrame(loop); }); })(); </script> </body> </html>
Save file
Quick jump
open a path
Open