From 1b59453825dce8bfde8c4b76d5ef5badf05e4024 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 29 Sep 2026 20:49:43 +0000 Subject: [PATCH 1/7] afterlife: the game of life, after hours, ported to the web MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit afterlife (LuxiaSL/afterlife), the terminal screensaver, now runs at /afterlife. It is the same program, not an imitation. The engine and the music are method-for-method ports of life.py and life_music.py. The page is drawn as a terminal: half-block cells in the same xterm-256 colours curses used, and a status line where every glyph has its own column. - src/engine: InfiniteLife (step, the infinity engine, the dramaturge, camera, auto-zoom, auto-focus, time dilation, haunted mode), the census (the scipy dilation/label/find_objects it needed, written out), the ticker, and every musing, generated from life.py rather than retyped. - src/music: LifeMusicEngine in an AudioWorklet, rendering the same 2048-frame buffers PyAudio asked for. The worklet is bundled by esbuild and inlined, so there's no second file. - scripts/parity{.py,.ts} replay life.py from a seeded genesis. Every step's population, telemetry, camera, zoom, mood and tempo match exactly, and so do the final ages, the display maps at all five zooms, the census, auto-focus and haunted mode. parity_music matches the original engine sample for sample (worst |Δ| 1.8e-7), including the cadence, the style crossfade and the noise bursts. - The universe persists in localStorage. It is saved on the way out and every 5000 generations, and resumed with "the universe remembers generation N". - Added for the web: a splash to start the sound, a keys panel that runs every key (for phones), drag to draw life, pan and zoom with the pointer and touch, and a two-line status on narrow screens so the ticker keeps its room. oikos gets a tape for it on channel 10. The screen runs afterlife's own engine and renderer, imported from ../afterlife/src, on a 64×24 terminal, and adopts your saved universe if this browser has one. It also has a placement at the end of the floor arc, a pane note and a status line. /afterlife is added to the sitemap and urls.txt, with tests for the page, the committed bundle and the framing headers. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VFkU2eSQ39nbuUTQsiVvFK --- .gitignore | 2 + aethera/api/afterlife.py | 15 + aethera/api/oikos.py | 17 + aethera/api/seo.py | 1 + aethera/main.py | 3 +- aethera/static/afterlife/afterlife.css | 1 + aethera/static/afterlife/afterlife.js | 5 + aethera/static/oikos/oikos.js | 346 ++--- aethera/templates/afterlife/viewer.html | 97 ++ afterlife/README.md | 101 ++ afterlife/index.html | 77 ++ afterlife/package-lock.json | 1689 +++++++++++++++++++++++ afterlife/package.json | 22 + afterlife/scripts/bench.ts | 48 + afterlife/scripts/parity-music.ts | 72 + afterlife/scripts/parity.py | 104 ++ afterlife/scripts/parity.ts | 160 +++ afterlife/scripts/parity_music.py | 71 + afterlife/scripts/shot.mjs | 91 ++ afterlife/src/engine/census.ts | 245 ++++ afterlife/src/engine/constants.ts | 144 ++ afterlife/src/engine/life.ts | 1410 +++++++++++++++++++ afterlife/src/engine/musings.ts | 287 ++++ afterlife/src/engine/persist.ts | 145 ++ afterlife/src/engine/stats.ts | 43 + afterlife/src/engine/ticker.ts | 101 ++ afterlife/src/main.ts | 489 +++++++ afterlife/src/music/audio.ts | 106 ++ afterlife/src/music/engine.ts | 984 +++++++++++++ afterlife/src/music/worklet.ts | 67 + afterlife/src/style.css | 252 ++++ afterlife/src/term/palette.ts | 33 + afterlife/src/term/render.ts | 329 +++++ afterlife/src/vite-env.d.ts | 5 + afterlife/tsconfig.json | 16 + afterlife/vite.config.ts | 54 + oikos/README.md | 1 + oikos/src/data.ts | 31 + oikos/src/screens/afterlife.ts | 54 + oikos/src/screens/index.ts | 2 + oikos/src/world/layout.ts | 1 + oikos/src/xp/pane.ts | 7 + oikos/src/xp/shell.ts | 3 +- tests/test_afterlife.py | 41 + 44 files changed, 7597 insertions(+), 175 deletions(-) create mode 100644 aethera/api/afterlife.py create mode 100644 aethera/static/afterlife/afterlife.css create mode 100644 aethera/static/afterlife/afterlife.js create mode 100644 aethera/templates/afterlife/viewer.html create mode 100644 afterlife/README.md create mode 100644 afterlife/index.html create mode 100644 afterlife/package-lock.json create mode 100644 afterlife/package.json create mode 100644 afterlife/scripts/bench.ts create mode 100644 afterlife/scripts/parity-music.ts create mode 100644 afterlife/scripts/parity.py create mode 100644 afterlife/scripts/parity.ts create mode 100644 afterlife/scripts/parity_music.py create mode 100644 afterlife/scripts/shot.mjs create mode 100644 afterlife/src/engine/census.ts create mode 100644 afterlife/src/engine/constants.ts create mode 100644 afterlife/src/engine/life.ts create mode 100644 afterlife/src/engine/musings.ts create mode 100644 afterlife/src/engine/persist.ts create mode 100644 afterlife/src/engine/stats.ts create mode 100644 afterlife/src/engine/ticker.ts create mode 100644 afterlife/src/main.ts create mode 100644 afterlife/src/music/audio.ts create mode 100644 afterlife/src/music/engine.ts create mode 100644 afterlife/src/music/worklet.ts create mode 100644 afterlife/src/style.css create mode 100644 afterlife/src/term/palette.ts create mode 100644 afterlife/src/term/render.ts create mode 100644 afterlife/src/vite-env.d.ts create mode 100644 afterlife/tsconfig.json create mode 100644 afterlife/vite.config.ts create mode 100644 oikos/src/screens/afterlife.ts create mode 100644 tests/test_afterlife.py diff --git a/.gitignore b/.gitignore index c2ff63a..5c7a8f6 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,8 @@ apeiron/node_modules/ syrinx/node_modules/ oikos/node_modules oikos/shots/ +afterlife/node_modules/ +afterlife/shots/ blog.sqlite irc.sqlite *.db diff --git a/aethera/api/afterlife.py b/aethera/api/afterlife.py new file mode 100644 index 0000000..37b3de4 --- /dev/null +++ b/aethera/api/afterlife.py @@ -0,0 +1,15 @@ +from fastapi import APIRouter, Request +from fastapi.responses import HTMLResponse + +from aethera.utils.templates import templates + +router = APIRouter(tags=["afterlife"]) + + +@router.get("/afterlife", response_class=HTMLResponse) +async def afterlife_viewer(request: Request): + return templates.TemplateResponse( + request=request, + name="afterlife/viewer.html", + context={"title": "afterlife | æthera"}, + ) diff --git a/aethera/api/oikos.py b/aethera/api/oikos.py index c5474d0..0fc81d5 100644 --- a/aethera/api/oikos.py +++ b/aethera/api/oikos.py @@ -114,6 +114,23 @@ ["by", "Luxia & Claude Fable 5"]], "tune": True, }, + { + "id": "afterlife", + "title": "afterlife", + "href": "/afterlife", + "group": "here", + "kind": "screensaver", + "accent": "#ffaf00", + "tagline": "the game of life, after hours", + "about": "Conway's Life on an infinite grid that steers toward its own drama: " + "it names its epochs, stages collisions, greets the famous citizens " + "it recognises, and scores itself as it goes. Press g and it " + "remembers everything. It is a place, not a session: the universe " + "is kept in your browser and resumes where you left it.", + "details": [["kind", "cellular automaton · music"], ["born", "2026-02-07"], + ["by", "Luxia & Claude"], ["source", "github.com/LuxiaSL/afterlife"]], + "tune": True, + }, { "id": "irc", "title": "irc", diff --git a/aethera/api/seo.py b/aethera/api/seo.py index e7fac82..2834ca4 100644 --- a/aethera/api/seo.py +++ b/aethera/api/seo.py @@ -89,6 +89,7 @@ def rss_feed(request: Request, session: Session = Depends(get_session)): ("oikos", "weekly", "0.6"), # the home directory (and mIRC) ("apeiron", "monthly", "0.6"), ("syrinx", "monthly", "0.6"), + ("afterlife", "monthly", "0.6"), ] diff --git a/aethera/main.py b/aethera/main.py index deff11b..e3a1550 100644 --- a/aethera/main.py +++ b/aethera/main.py @@ -14,7 +14,7 @@ load_dotenv() from aethera.models.base import init_db, get_session -from aethera.api import posts, comments, seo, dreams, chronicle, apeiron, syrinx, irc, irc_admin, oikos, chat +from aethera.api import posts, comments, seo, dreams, chronicle, apeiron, syrinx, afterlife, irc, irc_admin, oikos, chat from aethera.irc.database import init_irc_db from aethera.utils.security import SecurityHeadersMiddleware from aethera.utils.templates import templates @@ -68,6 +68,7 @@ async def lifespan(app: FastAPI): app.include_router(chronicle.router) app.include_router(apeiron.router) app.include_router(syrinx.router) +app.include_router(afterlife.router) app.include_router(irc.router) app.include_router(irc_admin.router) app.include_router(oikos.router) diff --git a/aethera/static/afterlife/afterlife.css b/aethera/static/afterlife/afterlife.css new file mode 100644 index 0000000..e72b4cc --- /dev/null +++ b/aethera/static/afterlife/afterlife.css @@ -0,0 +1 @@ +:root{color-scheme:dark}#afterlife-root{--bg: #0a0a0c;--fg: rgb(200, 200, 200);--dim: rgb(112, 112, 116);--age: linear-gradient(90deg, #0000af, #0000ff, #5f00ff, #8700ff, #d700ff, #d700af, #ff5f87, #ff875f, #ffaf00, #ffd700, #ffffff, #ffd700, #ff5f87, #8700ff, #0000af);position:fixed;top:0;right:0;bottom:0;left:0;display:grid;place-items:center;background:var(--bg);color:var(--fg);font-family:ui-monospace,SF Mono,Cascadia Mono,DejaVu Sans Mono,Menlo,Consolas,monospace;overflow:hidden;touch-action:none;user-select:none;-webkit-user-select:none}#afterlife-root #term{display:block;cursor:crosshair;image-rendering:pixelated}#afterlife-root #splash{position:absolute;top:0;right:0;bottom:0;left:0;z-index:10;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.6rem;padding:1rem;background:radial-gradient(ellipse at center,#0a0a0c9e,#0a0a0ce6 70%);cursor:pointer;transition:opacity 1.4s ease;outline:none}#afterlife-root #splash.gone{opacity:0;pointer-events:none}#afterlife-root #splash .logo{margin:0;padding:0;border:0;border-radius:0;box-shadow:none;overflow:visible;font:inherit;font-size:clamp(5px,1.35vw,14px);line-height:1.12;background:var(--age);background-size:300% 100%;-webkit-background-clip:text;background-clip:text;color:transparent;animation:afterlife-age 24s linear infinite;filter:drop-shadow(0 0 12px rgba(135,0,255,.25))}@keyframes afterlife-age{0%{background-position:0% 0}to{background-position:300% 0}}#afterlife-root #splash h1{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);margin:0}#afterlife-root #splash .sub{margin:.4rem 0 0;color:var(--fg);font-size:13px;letter-spacing:.3em}#afterlife-root #splash .go{margin:1.6rem 0 0;color:var(--dim);font-size:11px;letter-spacing:.12em;text-align:center;animation:afterlife-breathe 5.6s ease-in-out infinite}#afterlife-root #splash .go span{margin:0 .4em}@keyframes afterlife-breathe{0%,to{opacity:.45}50%{opacity:1}}#afterlife-root #corner{position:absolute;top:10px;right:14px;z-index:11;display:flex;gap:14px;align-items:baseline}#afterlife-root #corner a,#afterlife-root #corner button{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:0;padding:2px 0;background:none;color:#c8c8c847;font:inherit;font-size:11px;letter-spacing:.08em;text-decoration:none;cursor:pointer;transition:color .6s ease}#afterlife-root #corner a:hover,#afterlife-root #corner button:hover,#afterlife-root #corner button[aria-expanded=true]{color:#c8c8c8bf}#afterlife-root #keys{position:absolute;top:34px;right:14px;z-index:11;width:min(520px,calc(100vw - 28px));max-height:calc(100% - 90px);overflow:auto;box-sizing:border-box;padding:14px 16px 12px;border:1px solid rgba(200,200,200,.12);background:#0a0a0cf0;font-size:12px;touch-action:pan-y;user-select:text;-webkit-user-select:text}#afterlife-root #keys[hidden]{display:none}#afterlife-root #keys .grid{display:grid;grid-template-columns:1fr 1fr;gap:2px 18px}#afterlife-root #keys button{-webkit-appearance:none;-moz-appearance:none;appearance:none;display:flex;align-items:baseline;gap:10px;padding:3px 4px;border:0;background:none;color:var(--fg);font:inherit;text-align:left;cursor:pointer}#afterlife-root #keys button:hover,#afterlife-root #keys button:focus-visible{background:#c8c8c812;outline:none}#afterlife-root #keys kbd{min-width:3.2em;color:#ffaf00;font:inherit}#afterlife-root #keys .haunt kbd{color:#d700ff}#afterlife-root #keys p{margin:12px 4px 0;color:var(--dim);line-height:1.55}#afterlife-root #keys a{color:var(--fg)}#afterlife-root #keys .touch{display:none}@media(pointer:coarse){#afterlife-root #keys .mouse{display:none}#afterlife-root #keys .touch{display:inline}}@media(max-width:480px){#afterlife-root #keys .grid{grid-template-columns:1fr}}.afterlife-noscript{position:fixed;inset:auto 0 45% 0;padding:1rem;color:#c8c8c8;text-align:center;font-family:monospace} diff --git a/aethera/static/afterlife/afterlife.js b/aethera/static/afterlife/afterlife.js new file mode 100644 index 0000000..ff05dad --- /dev/null +++ b/aethera/static/afterlife/afterlife.js @@ -0,0 +1,5 @@ +var is=Object.defineProperty;var ns=(st,U,X)=>U in st?is(st,U,{enumerable:!0,configurable:!0,writable:!0,value:X}):st[U]=X;var g=(st,U,X)=>ns(st,typeof U!="symbol"?U+"":U,X);(function(){"use strict";var ge;const st=[17,19,21,57,93,165,163,204,209,214,220,231],U=[236,234],X=U.length,at=6,we=[17,18,19,20,21,57,56,93,129,165,164,163,198,204,203,209,208,214,220,229,231],At=i=>we[i]??0,ye=Array.from({length:at},(i,t)=>[At(Math.floor((185+t)/21)),At((185+t)%21)]),ve=Array.from({length:at*at},(i,t)=>[At(Math.floor((191+t)/21)),At((191+t)%21)]),Me=.98,Dt=4,xe=Math.fround(Me**Dt),gt="▁▂▃▄▅▆▇█",ot=-2,lt=2,be={[-2]:"0.25x",[-1]:"0.50x",0:" 1.0x",1:" 2.0x",2:" 4.0x"},ct={glider:[[0,1],[1,2],[2,0],[2,1],[2,2]],lwss:[[0,1],[0,4],[1,0],[2,0],[2,4],[3,0],[3,1],[3,2],[3,3]],hwss:[[0,3],[0,4],[1,1],[1,6],[2,0],[3,0],[3,6],[4,0],[4,1],[4,2],[4,3],[4,4],[4,5]],r_pentomino:[[0,1],[0,2],[1,0],[1,1],[2,1]],acorn:[[0,1],[1,3],[2,0],[2,1],[2,4],[2,5],[2,6]],diehard:[[0,6],[1,0],[1,1],[2,1],[2,5],[2,6],[2,7]],pi_heptomino:[[0,0],[0,1],[0,2],[1,1],[2,1],[3,0],[3,2]],b_heptomino:[[0,1],[1,0],[1,2],[1,3],[2,0],[2,1],[3,1]],gosper_gun:[[0,24],[1,22],[1,24],[2,12],[2,13],[2,20],[2,21],[2,34],[2,35],[3,11],[3,15],[3,20],[3,21],[3,34],[3,35],[4,0],[4,1],[4,10],[4,16],[4,20],[4,21],[5,0],[5,1],[5,10],[5,14],[5,16],[5,17],[5,22],[5,24],[6,10],[6,16],[6,24],[7,11],[7,15],[8,12],[8,13]],pulsar:[[0,2],[0,3],[0,4],[0,8],[0,9],[0,10],[2,0],[2,5],[2,7],[2,12],[3,0],[3,5],[3,7],[3,12],[4,0],[4,5],[4,7],[4,12],[5,2],[5,3],[5,4],[5,8],[5,9],[5,10],[7,2],[7,3],[7,4],[7,8],[7,9],[7,10],[8,0],[8,5],[8,7],[8,12],[9,0],[9,5],[9,7],[9,12],[10,0],[10,5],[10,7],[10,12],[12,2],[12,3],[12,4],[12,8],[12,9],[12,10]],pentadecathlon:[[0,1],[1,1],[2,0],[2,2],[3,1],[4,1],[5,1],[6,1],[7,0],[7,2],[8,1],[9,1]]},kt=["glider","lwss","hwss"],Ut=["r_pentomino","acorn","diehard","pi_heptomino","b_heptomino"],Ot=["pulsar","pentadecathlon"],_e=[[1,1],[1,-1],[-1,-1],[-1,1]];function Et(i){const t=new Map;for(const[e,s]of i)for(const[o,a]of[[e,s],[e,-s],[-e,s],[-e,-s]])t.set(`${o},${a}`,[o,a]);return[...t.values()]}const Ae=[Et([[0,1],[0,2],[0,3],[1,0],[1,4],[2,0],[2,5],[3,0],[3,5],[4,1],[4,5],[5,2],[5,3],[5,4]]),Et([[0,1],[0,2],[0,3],[0,4],[1,0],[2,0],[3,0],[4,0],[2,2],[3,3]]),Et([[0,3],[0,4],[1,2],[1,5],[2,1],[2,6],[3,0],[3,7],[4,0],[4,7],[5,1],[5,6],[6,2],[6,5],[7,3],[7,4]])],Se=5e3,Ce={block:[[[0,0],[0,1],[1,0],[1,1]],1],beehive:[[[0,1],[0,2],[1,0],[1,3],[2,1],[2,2]],1],loaf:[[[0,1],[0,2],[1,0],[1,3],[2,1],[2,3],[3,2]],1],boat:[[[0,0],[0,1],[1,0],[1,2],[2,1]],1],tub:[[[0,1],[1,0],[1,2],[2,1]],1],ship:[[[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]],1],pond:[[[0,1],[0,2],[1,0],[1,3],[2,0],[2,3],[3,1],[3,2]],1],blinker:[[[0,0],[0,1],[0,2]],2],toad:[[[0,1],[0,2],[0,3],[1,0],[1,1],[1,2]],2],beacon:[[[0,0],[0,1],[1,0],[2,3],[3,2],[3,3]],2],glider:[ct.glider??[],4],lwss:[ct.lwss??[],4],hwss:[ct.hwss??[],4],pulsar:[ct.pulsar??[],3],pentadecathlon:[ct.pentadecathlon??[],15]},He=60,Yt=20;function qt(i){let t=null;for(let e=0;e<8;e++){const s=e>=4,o=s?i.w:i.h,a=s?i.h:i.w;let n=`${o}x${a}:`;for(let h=0;hl))+1,a=Math.max(...e.map(([,l])=>l))+1,n=Math.max(o,a)+2*(s+4);let h=new Uint8Array(n*n);const r=Math.floor((n-o)/2),c=Math.floor((n-a)/2);for(const[l,d]of e)h[(r+l)*n+c+d]=1;for(let l=0;lo&&(o=l),dn&&(n=d));if(o<0)return null;const h=o-s+1,r=n-a+1,c=new Uint8Array(h*r);for(let l=0;l=t)continue;const f=2-Math.abs(m),v=Math.max(0,d-f),b=Math.min(e-1,d+f);o.fill(1,y*e+v,y*e+b+1)}const a=new Int32Array(t*e),n=[],h=[];for(let l=0;l400)return null;const m={y0:t,y1:-1,x0:e,x1:-1};for(a[l]=d,h.push(l);h.length;){const y=h.pop()??0,f=Math.floor(y/e),v=y-f*e;fm.y1&&(m.y1=f),vm.x1&&(m.x1=v);for(let b=-1;b<=1;b++){const S=f+b;if(!(S<0||S>=t))for(let M=-1;M<=1;M++){const C=v+M;if(C<0||C>=e)continue;const _=S*e+C;o[_]&&!a[_]&&(a[_]=d,h.push(_))}}}n.push(m)}if(n.length===0)return null;const r=new Map,c=[];return n.forEach((l,d)=>{const m=d+1,y=l.y1-l.y0+1,f=l.x1-l.x0+1;if(y>Yt+4||f>Yt+4)return;const v=new Uint8Array(y*f);let b=0,S=0,M=0;for(let w=0;wHe)return;const C=Xt(v,y,f),_=C?s.get(qt(C)):void 0;_!==void 0&&(r.set(_,(r.get(_)??0)+1),c.length<48&&c.push([_,l.y0+Math.floor(S/b),l.x0+Math.floor(M/b)]))}),{counts:r,sites:c}}const Ft=["cells pondering existence","entropy is just a suggestion","order from chaos, chaos from order","the cosmos breathes","finding signal in noise","patterns all the way down","life, uh, finds a way","on the edge of chaos","complexity, emerging","dancing at the phase boundary","stillness is just slow motion","every cell a universe","the substrate computes","from nothing, everything","infinite in all directions","what the dead cells dream","the glider knows the way","automata, contemplating","structure wants to happen","a cosmos in a terminal","the math dreams itself","somewhere, a glider remembers","what is a pattern but frozen time","the void is patient","meaning is optional; beauty is not","computation as meditation","the rules are simple; the consequences infinite","watching the watchers watch","no cell is an island","the ghost of configurations past","asymmetry seeks symmetry seeks asymmetry","this too shall iterate","the universe has no pause button","except when it does","what would Conway think","oscillators keep time for no one","the glider gun knows not what it creates","boundaries are suggestions","death is just a state transition","somewhere in here, a proof of universality","the grid forgets nothing","a thought experiment that thinks back","topology has opinions","the neighborhood watches","not alive, not dead — computing","four rules, one universe","each frame a theorem","proof by existence","the only constant is the ruleset","somewhere between on and off, meaning","the dead outnumber the living, as always","conway's little infinities","the simulation doesn't know it's beautiful","27 neighbors ago, this was empty","elegance is compression","the grid is the message","a love letter to discrete math","listen — the cells are whispering","we are all gliders, briefly"],ke={booming:["runaway growth","the bloom unfolds","life begets life begets life","exponential daydreams","more is different","the bloom cannot be stopped","abundance as instability","growing into the unknown","every birth a cascade","the simulation smiles","lebensraum","mitosis dreams","the substrate strains","a spring that won't stop springing","cells all the way to the horizon","the algorithm is generous today","more, more, more","genesis on fast-forward"],declining:["entropy collects its due","the long exhale","even stars go dark","returning to the void","graceful unwinding","the great filter, in miniature","less is not nothing","the long forgetting","what rises must","simplicity returns","the cells remember fullness","autumn in the grid","graceful subtraction","the tide goes out","a slow dissolve","the universe exhales","dimming, not vanishing","the population curve bends earthward"],cycle:["deja vu, deja vu, deja vu","stuck in a loop","the eternal return","ouroboros","time is a flat circle","we have been here before","the loop remembers itself","stability through repetition","a prayer, repeating","the wheel turns","same as it ever was","history rhymes","the attractor holds","a fixed point in phase space","nietzsche was right about this part","the universe stutters beautifully","clockwork, but organic","breathing in, breathing out"],stagnant:["the hush before the storm","equilibrium is boring","waiting for a perturbation","still waters","the universe holds its breath","the calm before","potential energy","stillness is also motion","the system waits","one perturbation away","dormant, not dead","crystallized","the peace of equilibrium","a held breath","the grid meditates","tension, frozen","the quiet hum of nothing happening","patience is also a computation"],sparse:["the last few embers","clinging to existence","from little things, big things grow","seeds in the dark","quiet, but not empty","lonely structures","the survivors","space between stars","minimalism, enforced","room to breathe","the few, the proud","embers","a whisper, not a shout","the geometry of loneliness","each cell precious now","a constellation, if you squint","small, but not nothing"],dense:["teeming","a city that never sleeps","standing room only","too many neighbours","the crowd murmurs","no room to think","the crush of neighbors","overpopulation is self-correcting","too much life","suffocating in company","the grid groans","rush hour","sardines","every cell has an opinion","a metropolis, thrumming","the carrying capacity protests","elbow room is a luxury"],injection:["a gift from beyond the edge","new visitors","reinforcements arrive","the cosmos provides","seeded by unseen hands","deus ex machina","a nudge from outside","fresh blood","the invisible hand places","salvation arrives","new variables enter","the cosmos intervenes","help from beyond the viewport","strangers in a strange land","the petri dish gets a refill","immigrants, welcome"],milestone:["another thousand turns of the wheel","the odometer clicks over","still here, still going","persistence is its own reward","ten thousand steps","the long now","time is a flat circle, but longer","we persist","generations beyond counting","deep in the run","the odometer means nothing to the cells","and yet, it continues","older than some civilizations","the marathon nobody entered","a digit rolls over; the grid doesn't notice","epochal"],haunted:["the dead outnumber the living, and glow","every path ever walked, still visible","the void remembers being alive","phase-contrast photography of the past","nothing is ever really deleted","the grid forgets nothing — literally, now","a bug so beautiful it became a feature","the ghosts have synchronized their breathing","somewhere between pair 463 and 504","resurrection as a rendering artifact","the afterlife was here all along","history, strobing","every empty cell, a metronome","the universe develops like a photograph","magenta is the color of memory"]},Ee={glider:["a glider, going somewhere","lightspeed, quartered — a glider","a glider carries the news","diagonal traffic"],lwss:["a lightweight spaceship, outbound","small craft advisory"],hwss:["a heavy spaceship shoulders past","heavy freight on the grid"],pulsar:["a pulsar, keeping time for no one","the pulsar breathes in threes"],pentadecathlon:["fifteen beats to the bar","a pentadecathlon runs its laps"],blinker:["the blinkers keep the beat","metronomes, disagreeing"],block:["blocks: the simplest memory","still life with squares"],beehive:["the bees are home","a beehive, sealed"],loaf:["bread, uneaten","a loaf, going stale beautifully"],boat:["a boat with nowhere to sail"],tub:["a tub, holding nothing"],ship:["a ship without a sea"],pond:["a pond, perfectly still"],toad:["a toad, breathing"],beacon:["the beacon still signals","someone left the light on"]},zt={pulsar:100,pentadecathlon:100,hwss:90,lwss:80,glider:40,beacon:30,toad:28,pond:24,ship:20,loaf:16,beehive:12,boat:12,tub:12,blinker:8,block:6},Le={blinker:3,block:3},Zt=[[0,"genesis"],[500,"primordial"],[2e3,"emergence"],[1e4,"expansion"],[5e4,"flourishing"],[15e4,"deep time"],[5e5,"eon"],[1e6,"eternity"]],O=i=>[...i].length;class Kt{constructor(){g(this,"messages",[]);g(this,"scrollSpeed",.4);g(this,"spawnCooldown",0);g(this,"minGap",12);g(this,"ambientInterval",60);g(this,"moodInterval",50);g(this,"ambientIdx",Math.floor(Math.random()*Ft.length));g(this,"lastMood","");g(this,"pendingSpecial","")}queueSpecial(t){this.pendingSpecial=t}tick(t,e,s){if(t<10)return;for(const h of this.messages)h.x-=this.scrollSpeed;if(this.messages=this.messages.filter(h=>h.x+O(h.text)>0),this.pendingSpecial&&this.canSpawn(t)){this.messages.push({text:this.pendingSpecial,x:t}),this.pendingSpecial="",this.spawnCooldown=Math.max(this.spawnCooldown,this.moodInterval);return}const o=e?ke[e]:void 0;if(o&&e!==this.lastMood&&(this.spawnCooldown=Math.min(this.spawnCooldown,15)),this.spawnCooldown=Math.max(0,this.spawnCooldown-1),this.spawnCooldown>0||!this.canSpawn(t))return;let a,n;o?(a=o[Math.floor(s/180)%o.length]??"",n=this.moodInterval):(a=Ft[this.ambientIdx]??"",this.ambientIdx=(this.ambientIdx+1)%Ft.length,n=this.ambientInterval),this.messages.push({text:a,x:t}),this.spawnCooldown=n,this.lastMood=e}canSpawn(t){if(!this.messages.length)return!0;let e=-1/0;for(const s of this.messages)e=Math.max(e,s.x+O(s.text));return ei+Math.floor(Math.random()*(t-i+1)),Z=i=>i[Math.floor(Math.random()*i.length)],u=(i,t)=>Math.floor(i/t),G=(i,t,e)=>Math.max(t,Math.min(i,e)),Fe=Math.fround(.85),ze=Math.fround(.15);function it(i,t){const e=i.length,s=t/100*(e-1),o=Math.floor(s),a=Math.min(e-1,o+1),n=i[o]??0,h=i[a]??0;return Math.trunc(n+(h-n)*(s-o))}class St{constructor(t,e,s=!0){g(this,"viewH");g(this,"viewW");g(this,"worldH");g(this,"worldW");g(this,"grid");g(this,"age");g(this,"ageSmooth");g(this,"activity");g(this,"nextRow");g(this,"colSum");g(this,"camY");g(this,"camX");g(this,"autoCam",!0);g(this,"zoomLevel",0);g(this,"zoomCooldown",0);g(this,"generation",0);g(this,"paused",!1);g(this,"delay",50);g(this,"popHistory",[]);g(this,"hashHistory",[]);g(this,"cachedPop",0);g(this,"spread",0);g(this,"popFloor",0);g(this,"cyclePeriod",0);g(this,"lastEvent","");g(this,"lastEventGen",0);g(this,"totalInjections",0);g(this,"ticker",new Kt);g(this,"autoFocusMode",!1);g(this,"autoFocusFrame",0);g(this,"dispGridCache",null);g(this,"dispAgeCache",null);g(this,"cachedMood","");g(this,"cachedMoodGen",-1);g(this,"stepBbox",null);g(this,"haunted",!1);g(this,"lastCensus",new Map);g(this,"lastCensusSites",[]);g(this,"sightingGen",new Map);g(this,"sightingCount",new Map);g(this,"lastSightingGen",-1e9);g(this,"dramaUntil",0);g(this,"actBaseline",0);g(this,"dilation",1);this.viewH=t*2,this.viewW=e,this.worldH=Math.max(this.viewH*5,400),this.worldW=Math.max(this.viewW*5,800);const o=this.worldH*this.worldW;this.grid=new Uint8Array(o),this.age=new Int32Array(o),this.ageSmooth=new Float32Array(o),this.activity=new Float32Array(o),this.nextRow=new Uint8Array(this.worldW),this.colSum=new Uint8Array(this.worldW),this.camY=u(this.worldH-this.viewH,2),this.camX=u(this.worldW-this.viewW,2),s&&this.seedInitial()}seedInitial(){const t=u(this.worldH,2),e=u(this.worldW,2),s=this.viewH,o=this.viewW;for(const h of Ut)for(let r=0;r<2;r++)this.place(h,t+W(-u(s,3),u(s,3)),e+W(-u(o,3),u(o,3)));for(let h=0;h<2;h++)this.place("gosper_gun",t+W(-u(s,4),u(s,4)),e+W(-u(o,4),u(o,4)));for(let h=0;h<20;h++){const r=G(t+W(-s,s),10,this.worldH-10),c=G(e+W(-o,o),10,this.worldW-10);this.place(Z(kt),r,c)}for(let h=0;h<4;h++)this.place(Z(Ot),t+W(-u(s,3),u(s,3)),e+W(-u(o,3),u(o,3)));const a=t-u(s,2),n=e-u(o,2);for(let h=0;h=0&&c=0&&lr&&(r=R+1))}const c=n>0;let l=!1;c&&a-2>=0&&n+2<=t&&h-2>=0&&r+2<=e&&(a-=2,n+=2,h-=2,r+=2,l=(n-a)*(r-h)<=u(t*e,2)),l=l&&!this.haunted,this.stepBbox=c&&l?[a,n,h,r]:null,l||(a=0,n=t,h=0,r=e);const d=this.ageSmooth;for(let w=0;w0?B=-1:(b||z<0)&&z>v?B=z-1:B=0,o[x]=B,d[x]=(d[x]??0)+Math.fround(Math.fround(B)*ze);const et=T||j?1:0;s[x]=et,C+=et}}if(this.generation+=1,this.generation%Dt===0)for(let w=0;w500&&this.popHistory.shift(),this.hashHistory.push(this.viewportHash()),this.hashHistory.length>60&&this.hashHistory.shift();const _=this.ensureLife(C);return this.updateCamera(),_}viewportHash(){const[t,e]=this.clampCam();let s=2166136261,o=16777619;for(let a=0;a>>0)*2097152+(o>>>0&2097151)}ensureLife(t){const e=this.viewH*this.viewW,s=u(e,40),o=this.popHistory,a=o.length;if(a>=100){let d=0;for(let m=a-100;m=150){let d=o[a-1]??0,m=d;for(let y=a-150;ym&&(m=f)}this.spread=m-d}const n=a>=150&&this.spread=4){const d=h[r-1];for(let m=1;m0&&!c){const d=Math.random()<.65?this.injectProvoke():"";d?l=`inject:provoke(cycle=${this.cyclePeriod},${d})`:(l=`inject:heavy(cycle=${this.cyclePeriod})`,this.inject("heavy"))}else n&&!c?Math.random()<.7&&this.injectCollide()?l="inject:collide(stagnant)":(l="inject:medium(stagnant)",this.inject("medium")):this.generation%5e3===0&&this.generation>0?(l="inject:garden",this.injectGarden()):this.generation%300===0&&this.generation>0&&(l="inject:edge",this.injectFromEdge(),this.injectFromEdge());return l&&(this.lastEvent=l,this.lastEventGen=this.generation,this.totalInjections+=1),l}inject(t="medium"){const e={massive:8,heavy:5,medium:3}[t];for(let s=0;s=0&&r=0&&c(d[S]??0)-(d[M]??0)),f=Z(y.slice(0,m)),v=u(f,l),b=f%l;return[n+v*r+u(r,2),h+b*r+u(r,2)]}aimGlider(t,e,s,o){const[a,n]=_e[o]??[1,1],h=t-a*s,r=e-n*s,[c,l]=this.clampCam();if(!(c+2<=h&&h(zt[s[0]]??0)-(zt[e[0]]??0));for(const[e,s,o]of t.slice(0,6)){const a=W(35,60),n=[0,1,2,3];for(let h=n.length-1;h>0;h--){const r=Math.floor(Math.random()*(h+1));[n[h],n[r]]=[n[r]??0,n[h]??0]}for(const h of n)if(this.aimGlider(s,o,a,h))return this.dramaUntil=this.generation+a*4+150,this.ticker.queueSpecial("the cosmos takes aim"),e}return""}injectCollide(){let[t,e]=this.findQuietSpot();const[s,o]=this.clampCam();for(let a=0;a<6;a++){const n=W(16,34),h=s+n+3,r=s+this.viewH-n-6,c=o+n+3,l=o+this.viewW-n-6;if(h>=r||c>=l)continue;t=Math.max(h,Math.min(t,r)),e=Math.max(c,Math.min(e,l));const d=W(0,3),m=W(-3,3),y=W(-3,3);if(!this.aimGlider(t,e,n,d))continue;const f=(d+Z([1,3]))%4,v=this.aimGlider(t+m,e+y,n,f);return this.dramaUntil=this.generation+n*4+150,this.ticker.queueSpecial(v?"two gliders, one appointment":"a lone glider, sent into the dark"),!0}return!1}calculateTargetZoom(){const[t,e,s,o]=this.stepBbox??[0,this.worldH,0,this.worldW],a=this.worldW;let n=0;for(let M=t;M=1&&_<=10&&++n>=5)break}const h=n>=5,r=[],c=[];for(let M=t;M=1&&(this.age[_]??0)<=10:this.grid[_]!==0)&&(r.push(M),c.push(C))}if(r.length<2)return this.zoomLevel;const l=Int32Array.from(c).sort(),d=it(r,15),m=it(r,85),y=it(l,15),f=it(l,85),v=Math.max(4,m-d+1),b=Math.max(4,f-y+1);let S=ot;for(let M=lt;M>=ot;M--){const C=2**M;if(v<=this.viewH/C*.5&&b<=this.viewW/C*.5){S=M;break}}return G(S,ot,lt)}updateCamera(){if(!this.autoCam)return;const t=30,e=Math.max(0,this.camY-t),s=Math.min(this.worldH,this.camY+this.viewH+t),o=Math.max(0,this.camX-t),a=Math.min(this.worldW,this.camX+this.viewW+t),n=this.worldW;let h=0,r=0,c=0;for(let y=e;y25){this.steer(Math.trunc(r/h)+e,Math.trunc(c/h)+o),this.advanceAutoZoom();return}let l=0,d=0,m=0;for(let y=e;y0&&this.steer(Math.trunc(d/l)+e,Math.trunc(m/l)+o),this.advanceAutoZoom()}steer(t,e){const s=G(t-u(this.viewH,2),0,this.worldH-this.viewH),o=G(e-u(this.viewW,2),0,this.worldW-this.viewW);this.camY=Math.trunc(this.camY+(s-this.camY)*.04),this.camX=Math.trunc(this.camX+(o-this.camX)*.04)}advanceAutoZoom(){if(this.zoomCooldown=Math.max(0,this.zoomCooldown-1),this.zoomCooldown!==0||this.generation%4!==0)return;const t=this.calculateTargetZoom();if(t>this.zoomLevel&&this.zoomLevelot){const e=this.zoomLevel-1,s=e>=0?1:1<<-e;this.viewH*s<=this.worldH&&this.viewW*s<=this.worldW&&(this.zoomLevel=e,this.zoomCooldown=45)}}clampCam(){return[G(this.camY,0,this.worldH-this.viewH),G(this.camX,0,this.worldW-this.viewW)]}viewCenter(){const[t,e]=this.clampCam();return[t+u(this.viewH,2),e+u(this.viewW,2)]}rawViewGrid(){const[t,e]=this.clampCam(),s=new Uint8Array(this.viewH*this.viewW);for(let o=0;othis.worldH||l>this.worldW)return null;const d=Math.max(0,Math.min(t-u(c,2),this.worldH-c)),m=Math.max(0,Math.min(e-u(l,2),this.worldW-l));return[d,m,c,l,r,!1]}const s=1<Math.trunc(t[f]??0),o=this.zoomLevel===0?null:this.cover();if(!o){const[f,v]=this.clampCam(),b=new Int32Array(this.viewH*this.viewW);for(let S=0;S(S[E]??0)&&(S[E]=R);const q=R!==0?R:b;q>(M[E]??0)&&(M[E]=q)}}const C=new Int32Array(f*v);for(let _=0;_0?w:I>b?I:0}return{h:f,w:v,data:C}}const d=Math.min(h*c,this.viewH),m=Math.min(r*c,this.viewW),y=new Int32Array(d*m);for(let f=0;fot){const t=this.zoomLevel-1,e=t>=0?1:1<<-t;(t>=0||this.viewH*e<=this.worldH&&this.viewW*e<=this.worldW)&&(this.zoomLevel=t)}this.invalidate()}autoFocus(){const t=this.worldH,e=this.worldW;let s=0,o=0;for(let x=0;x=1&&H<=10&&s++,this.grid[x]&&o++}const a=s>=5;if((a?s:o)===0)return;const n=x=>{const H=this.age[x]??0;return a?H>=1&&H<=10:this.grid[x]!==0},h=16,r=u(t,h),c=u(e,h);if(r<1||c<1)return;const l=new Float64Array(r*c);for(let x=0;x=0&&z=0&&Bd&&(d=$/9,m=x*c+H)}const y=u(m,c)*h+u(h,2),f=m%c*h+u(h,2),v=h*2,b=Math.max(0,y-v),S=Math.min(t,y+v),M=Math.max(0,f-v),C=Math.min(e,f+v),_=[],w=[];for(let x=b;x=ot;x--){const H=2**x;if(_t<=this.viewH/H*.6&&V<=this.viewW/H*.6){A=x;break}}this.zoomLevel=G(A,ot,lt),this.camY=G(D-u(this.viewH,2),0,this.worldH-this.viewH),this.camX=G(tt-u(this.viewW,2),0,this.worldW-this.viewW),this.autoCam=!1,this.invalidate()}pan(t,e){this.autoCam=!1;const s=2**-this.zoomLevel,o=t!==0?Math.max(1,Math.trunc(Math.abs(t)*s))*Math.sign(t):0,a=e!==0?Math.max(1,Math.trunc(Math.abs(e)*s))*Math.sign(e):0;this.camY=G(this.camY+o,0,this.worldH-this.viewH),this.camX=G(this.camX+a,0,this.worldW-this.viewW),this.invalidate()}home(){this.autoCam=!0,this.zoomLevel=0,this.invalidate()}clear(){this.grid.fill(0),this.age.fill(0),this.ageSmooth.fill(0),this.generation=0,this.popHistory=[],this.hashHistory=[],this.invalidate()}takeCensus(){const t=this.rawViewGrid();let e=!1;for(let r=0;r[d,c+m,l+y]),s=r.counts}}catch{}if(this.lastCensus=s,!s.size||this.generation-this.lastSightingGen<600)return;let o="",a=0;for(const[r,c]of s){if(c<(Le[r]??1)||this.generation-(this.sightingGen.get(r)??-1e9)<1800)continue;const l=zt[r]??0;l>a&&(a=l,o=r)}if(!o)return;const n=Ee[o]??[],h=this.sightingCount.get(o)??0;this.sightingCount.set(o,h+1),this.ticker.queueSpecial(n[h%n.length]??o),this.sightingGen.set(o,this.generation),this.lastSightingGen=this.generation}snapshot(){return{h:this.worldH,w:this.worldW,age:this.age.slice(),generation:this.generation,totalInjections:this.totalInjections}}adopt(t){const e=Math.min(this.worldH,t.h),s=Math.min(this.worldW,t.w),o=u(t.h-e,2),a=u(t.w-s,2),n=u(this.worldH-e,2),h=u(this.worldW-s,2);this.grid.fill(0),this.age.fill(0);let r=0;for(let c=0;c0&&(this.grid[m]=1,r++)}this.generation=Math.max(0,Math.trunc(t.generation)),this.totalInjections=Math.max(0,Math.trunc(t.totalInjections)),this.ageSmooth.fill(0),this.activity.fill(0),this.hashHistory=[],this.cachedPop=r,this.popHistory=[r],this.stepBbox=null,this.dramaUntil=0,this.invalidate()}toggleHaunted(){if(this.haunted=!this.haunted,this.invalidate(),!this.haunted)for(let t=0;t=this.worldH||e<0||e>=this.worldW)return;const o=t*this.worldW+e;this.grid[o]=s,this.age[o]=s?1:0,this.invalidate()}tickTicker(t){this.ticker.tick(t,this.detectMood(),this.generation)}detectMood(){return this.cachedMoodGen===this.generation?this.cachedMood:(this.cachedMood=this.computeMood(),this.cachedMoodGen=this.generation,this.cachedMood)}computeMood(){if(this.haunted)return"haunted";if(this.lastEvent&&this.generation-this.lastEventGen<90)return"injection";if(this.cyclePeriod>0)return"cycle";if(this.generation>=1e4&&this.generation%1e4<120)return"milestone";const t=this.popHistory,e=t.length;if(e>=30){let a=0,n=0;for(let r=e-30;r1.15)return"booming";if(h<.85)return"declining"}const s=e?t[e-1]??0:0;return s/Math.max(this.viewH*this.viewW,1)>.15?"dense":s0?"sparse":this.spread=150?"stagnant":""}epoch(){var e;let t=((e=Zt[0])==null?void 0:e[1])??"genesis";for(const[s,o]of Zt)this.generation>=s&&(t=o);return t}population(){return this.cachedPop}activityCenterX(){const[t,e]=this.clampCam();let s=0,o=0;for(let a=0;athis.actBaseline?.015:.003;this.actBaseline=this.actBaseline*(1-e)+t*e;const s=t/Math.max(this.actBaseline,1);let o=s>1?Math.min(1.6,1+(s-1)*.7):.7+s*.3;return t<60&&(o=Math.min(o,.7)),this.dilation=this.dilation*.85+o*.15,this.dilation}sparkline(t=24){const e=this.popHistory;if(e.length<2)return"";const s=Math.max(0,e.length-t);let o=e[s]??0,a=o;for(let c=s;ca&&(a=l)}const n=gt.length-1,h=gt[Math.floor(gt.length/2)]??"▅";let r="";for(let c=s;c{for(;a>127;)t.push(a&127|128),a=Math.floor(a/128);t.push(a)};let s=-1;for(let a=0;a=0?n*2:-n*2-1),s=a)}let o="";for(let a=0;a{let h=0,r=1;for(;;){if(o>=e.length)throw new Error("afterlife: truncated save");const c=e.charCodeAt(o++);if(h+=(c&127)*r,c<128)return h;r*=128}};let n=-1;for(;o=t)throw new Error("afterlife: save does not fit its own world");s[n]=h%2?-(h+1)/2:h/2}return s}function je(i=globalThis.localStorage){try{const t=i==null?void 0:i.getItem(Qt);if(!t)return null;const e=JSON.parse(t);if(e.v!==1||!Number.isInteger(e.h)||!Number.isInteger(e.w)||typeof e.cells!="string")return null;const s=e.h,o=e.w;if(s<=0||o<=0||s*o>16e6)return null;const a=Number(e.generation);return!Number.isFinite(a)||a<0?null:{h:s,w:o,age:Te(e.cells,s*o),generation:a,totalInjections:Number(e.totalInjections)||0,bornAt:Number(e.bornAt)||Date.now(),savedAt:Number(e.savedAt)||Date.now()}}catch(t){return console.warn("afterlife: could not load the universe, starting fresh",t),null}}function Ne(i,t=globalThis.localStorage){try{const e={v:1,h:i.h,w:i.w,generation:i.generation,totalInjections:i.totalInjections,bornAt:i.bornAt,savedAt:i.savedAt,cells:Re(i.age)},s=JSON.stringify(e);return s.length>Pe||!t?!1:(t.setItem(Qt,s),!0)}catch(e){return console.warn("afterlife: could not save the universe",e),!1}}const $e=`gen,time_s,total_pop,spread_150,pop_floor,cycle_period,zoom,cam_y,cam_x,event +`,Jt=5e4;class Be{constructor(){g(this,"lines",[]);g(this,"t0",performance.now())}log(t){const e=(performance.now()-this.t0)/1e3;this.lines.push(`${t.gen},${e.toFixed(1)},${t.pop},${t.spread},${t.floor},${t.cycle},${t.zoom},${t.camY},${t.camX},${t.event??""} +`),this.lines.length>Jt*1.2&&(this.lines=this.lines.slice(-Jt))}get length(){return this.lines.length}csv(){return $e+this.lines.join("")}}const Ge='"use strict";(()=>{var d=2*Math.PI,x="chiptune",T="ambient",k=[x,T],z={lydian:[0,2,4,6,7,9,11],aeolian:[0,2,3,5,7,8,10],whole_tone:[0,2,4,6,8,10],dorian:[0,2,3,5,7,9,10],minor_pentatonic:[0,3,5,7,10],mixolydian:[0,2,4,5,7,9,10],major_pentatonic:[0,2,4,7,9]},Z=.22,X=20,G={booming:"lydian",declining:"aeolian",cycle:"whole_tone",stagnant:"dorian",sparse:"minor_pentatonic",dense:"mixolydian",injection:"major_pentatonic",haunted:"whole_tone"},O="major_pentatonic",J={genesis:48,primordial:46,emergence:50,expansion:53,flourishing:55,"deep time":51,eon:48,eternity:45},N=48,K=[.005,.05,.7,.02],Q=[.06,.25,.75,.5],B=4,tt={generation:0,population:0,pop_floor:100,density:0,spread:0,cycle_period:0,mood:"",epoch:"genesis",pop_delta:0,playhead_column:[],playhead_position:0,viewport_rows:40,event:"",activity_x:.5},W=class{root_midi=N;target_root_midi=N;scale_name=O;scale_intervals=z[O]??[];prev_scale_intervals=z[O]??[];scale_crossfade=1;tempo_bpm=80;drone_volume=.3;melody_volume=.2;arp_volume=.15;noise_volume=.05;arp_speed=4;arp_pattern=[0,2,4,7];playhead_notes=[]};function P(i){return 440*2**((i-69)/12)}function et(i,t,e=2){let a=[];for(let s=0;s(i%t+t)%t,V=class{alpha;z=0;constructor(t,e=44100){let a=1/(d*t),s=1/e;this.alpha=s/(a+s)}apply(t){let e=new Float32Array(t.length),a=this.alpha,s=this.z;for(let o=0;o=0&&i<1?2*i-i*i-1:i>=-1&&i<0?i*i+2*i+1:0}function U(i,t,e){let a=i.length,s=new Float32Array(a),o=e/44100;if(!(e>0)){let n=0;for(let r=1;r1?n/(a-1):.01}for(let n=0;n0){r1-o&&(h+=H((r-1)/o));let p=(r-t)/o;Math.abs(p)<1&&(h-=H(p))}s[n]=h}return s}var C=class{constructor(t,e,a,s){this.sustain=a;this.attack=Math.max(.001,t),this.decay=Math.max(.001,e),this.release=Math.max(.001,s)}sustain;attack;decay;release;generate(t,e,a,s=-1){let o=new Float32Array(t);for(let n=0;n=0){let h=r-s;o[n]=h<0?this.sustain:this.sustain*Math.max(0,1-h/this.release)}}return o}},rt=new C(...K),st=new C(...Q),L=class{constructor(t=440,e=T){this.style=e;this.freq=t,this.target_freq=t}style;freq;target_freq;phase=0;phase_det=0;active=!1;gate=!1;elapsed=0;release_time=-1;noteOn(t){this.target_freq=t,this.freq=t,this.gate=!0,this.active=!0,this.elapsed=0,this.release_time=-1}retrigger(t){this.target_freq=t,this.active?this.gate||(this.gate=!0,this.release_time=-1):this.noteOn(t)}noteOff(){this.gate=!1,this.release_time=this.elapsed}render(t){if(!this.active)return new Float32Array(t);let e=1/44100,a=this.style===T?.15:.02,s=1-Math.exp(-e/a),o=new Float64Array(t),n=new Float64Array(t),r=this.freq,h=this.phase,p=this.phase_det,m=1;for(let u=0;u0&&(this.freq=r,this.phase=g(h,d));let _,l;if(this.style===x)_=U(o,.25,this.freq),l=rt;else{t>0&&(this.phase_det=g(p,d)),_=new Float32Array(t);for(let u=0;u=0&&this.elapsed-this.release_time>l.release&&(this.active=!1);for(let u=0;unew L(440,this.style)),this.arpVoice=new L(440,this.style),this.cadenceVoice=new L(440,this.style)}get volumePercent(){return Math.round(this.masterVolume*100)}toggleMute(){this.muted=!this.muted}adjustVolume(t){this.masterVolume=Math.max(0,Math.min(1,this.masterVolume+t))}cycleStyle(){this.oldStyle=this.style,this.styleIdx=(this.styleIdx+1)%k.length,this.style=k[this.styleIdx]??T,this.crossfadeRemaining=this.crossfadeTotal;for(let t of this.melodyVoices)t.style=this.style;this.arpVoice.style=this.style,this.cadenceVoice.style=this.style}setStyle(t){t!==this.style&&this.cycleStyle()}update(t){this.snapshot=t;let e=this.musical;e.target_root_midi=J[t.epoch]??N,this.targetRootHz=P(e.target_root_midi);let a=G[t.mood]??O;a!==e.scale_name&&(e.prev_scale_intervals=e.scale_intervals,e.scale_name=a,e.scale_intervals=z[a]??[],e.scale_crossfade=0),e.scale_crossfade<1&&(e.scale_crossfade=Math.min(1,e.scale_crossfade+.017));let s=t.pop_floor>0?Math.min(2,t.population/Math.max(1,t.pop_floor)):.5;e.drone_volume=A(.13,.38,Math.min(1,s)),e.melody_volume=A(.08,.35,Math.min(1,t.density*10)),t.cycle_period>0?(e.arp_speed=A(3,12,Math.min(1,10/Math.max(1,t.cycle_period))),e.arp_volume=.2):(e.arp_speed=A(2,6,Math.min(1,t.spread/200)),e.arp_volume=A(.05,.15,Math.min(1,t.spread/100)));let o=e.scale_intervals;if(o.length>=3?e.arp_pattern=[o[0]??0,o[Math.min(2,o.length-1)]??0,o[Math.min(4,o.length-1)]??0,(o[0]??0)+12]:e.arp_pattern=[0,4,7,12],e.noise_volume=A(0,.15,Math.min(1,Math.abs(t.pop_delta)/50)),this.computePlayheadNotes(t,e),e.tempo_bpm=A(60,120,Math.min(1,t.density*8)),t.event.startsWith("inject")&&t.event.includes("cycle")&&this.cadenceIdx<0&&this.cadenceCooldown<=0){let n=e.target_root_midi+12;this.cadenceSeq=[[P(n+12),Math.trunc(.4*44100)],[P(n+7),Math.trunc(.4*44100)],[P(n),Math.trunc(2*44100)]],this.cadenceRemaining=0,this.cadenceCooldown=Math.trunc(X*44100),this.cadenceIdx=0}}computePlayheadNotes(t,e){let a=t.playhead_column;if(!a.length||t.viewport_rows<2){e.playhead_notes=[];return}let s=a.length,o=et(e.target_root_midi,e.scale_intervals,2);if(!o.length){e.playhead_notes=[];return}let n=[];if(a.forEach((h,p)=>{h&&n.push(p)}),n.length<2&&t.density<.03){e.playhead_notes=[];return}let r=n.map(h=>{let p=1-h/Math.max(1,s-1),m=Math.max(0,Math.min(Math.trunc(p*(o.length-1)),o.length-1));return o[m]??0});if(r.length>B){r.sort((p,m)=>p-m);let h=r.length/B;r=Array.from({length:B},(p,m)=>r[Math.trunc(m*h)]??0)}e.playhead_notes=r}renderBlock(t,e,a=t.length){let s,o;try{[s,o]=this.renderStereo(a)}catch{s=new Float32Array(a),o=new Float32Array(a)}let n=this.muted?0:this.masterVolume;for(let r=0;r0){let S=1-this.crossfadeRemaining/Math.max(1,this.crossfadeTotal);this.crossfadeRemaining=Math.max(0,this.crossfadeRemaining-t);let E=this.renderDrone(t),w=this.style;this.style=this.oldStyle;let M=this.renderDrone(t);this.style=w;let c=Math.fround(Math.sqrt(S)),f=Math.fround(Math.sqrt(1-S));m=new Float32Array(t);for(let v=0;v0&&(this.cadenceCooldown-=t),this.cadenceIdx<0)return null;if(this.cadenceRemaining<=0){let e=this.cadenceSeq[this.cadenceIdx];if(e){let[a,s]=e;this.cadenceIdx===0?this.cadenceVoice.noteOn(a):this.cadenceVoice.retrigger(a),this.cadenceRemaining=s,this.cadenceIdx+=1}else if(this.cadenceVoice.gate)this.cadenceVoice.noteOff();else if(!this.cadenceVoice.active)return this.cadenceIdx=-1,null}return this.cadenceRemaining-=t,this.cadenceVoice.render(t)}renderDrone(t){let e=this.currentRootHz,a=e*1.5,s=1/44100,o=.08,n=new Float32Array(t),r=this.droneLfoPhase;for(let c=0;c{let r=e[n];r!==void 0?o.active?Math.abs(o.target_freq-r)>o.target_freq*.06?o.noteOn(r):o.retrigger(r):o.noteOn(r):o.gate&&o.noteOff()});let a=this.style===T?.5:.3,s=new Float32Array(t);for(let o of this.melodyVoices){if(!o.active)continue;let n=o.render(t);for(let r=0;r1)&&this.arpVoice.noteOn(p),this.arpVoice.style=this.style;let m=this.arpVoice.render(h),_=this.style===T?.55:.4;for(let l=0;l=o&&(this.arpSamplesInNote=0,this.arpNoteIdx=(this.arpNoteIdx+1)%a.length,this.arpVoice.noteOn(P(s+(a[this.arpNoteIdx%a.length]??0))))}return this.style===x&&(n=this.lpfArp.apply(n)),n}renderNoise(t,e){let a=Math.abs(this.snapshot.pop_delta);if(this.noiseBurstCooldown>0&&(this.noiseBurstCooldown=Math.max(0,this.noiseBurstCooldown-e)),a>=this.noiseBurstThreshold&&this.noiseBurstPhase>=1&&this.noiseBurstCooldown<=0&&(this.noiseBurstPhase=0,this.noiseBurstAmp=A(.1,.5,Math.min(1,a/80)),this.noiseBurstDuration=A(.08,.25,Math.min(1,a/100)),this.noiseBurstCooldown=this.noiseBurstDuration+.1),this.noiseBurstPhase>=1)return new Float32Array(t);let s=this.noisePool,o=this.noisePoolIdx%s.length,n=new Float32Array(t);for(let l=0;l{let e=t.data;e.type==="snapshot"?this.engine.update(e.snap):e.type==="controls"?(this.engine.muted=e.muted,this.engine.masterVolume=e.volume,this.engine.setStyle(e.style)):e.type==="stop"&&(this.running=!1)}}process(t,e){let a=e[0],s=a?.[0];if(!a||!s)return this.running;let o=a[1]??s,n=0;for(;n=2048&&(this.engine.renderBlock(this.left,this.right,2048),this.pos=0);let r=Math.min(s.length-n,2048-this.pos);s.set(this.left.subarray(this.pos,this.pos+r),n),o!==s&&o.set(this.right.subarray(this.pos,this.pos+r),n),this.pos+=r,n+=r}return this.running}};registerProcessor("afterlife-music",j);})();\n',Ve=44100,te="chiptune",wt=[te,"ambient"];function De(i,t,e){return i?"[MUTE]":`${t===te?"NES":"AMB"} ${Math.round(e*100)}%`}class Ue{constructor(){g(this,"ctx",null);g(this,"node",null);g(this,"starting",null);g(this,"muted",!1);g(this,"volume",.5);g(this,"style",wt[1])}get running(){return this.node!==null}start(){return this.ctx?(this.ctx.state==="suspended"&&this.ctx.resume().catch(()=>{}),this.starting??Promise.resolve(this.running)):(this.starting=(async()=>{try{const t=new AudioContext({sampleRate:Ve,latencyHint:"playback"});this.ctx=t;const e=URL.createObjectURL(new Blob([Ge],{type:"text/javascript"}));try{await t.audioWorklet.addModule(e)}finally{URL.revokeObjectURL(e)}const s=new AudioWorkletNode(t,"afterlife-music",{numberOfInputs:0,outputChannelCount:[2]});return s.connect(t.destination),this.node=s,this.sendControls(),t.state==="suspended"&&await t.resume().catch(()=>{}),!0}catch(t){return console.warn("afterlife: no music tonight",t),this.node=null,!1}})(),this.starting)}post(t){var e;(e=this.node)==null||e.port.postMessage(t)}sendControls(){this.post({type:"controls",muted:this.muted,volume:this.volume,style:this.style})}update(t){this.post({type:"snapshot",snap:t})}toggleMute(){this.muted=!this.muted,this.sendControls()}adjustVolume(t){this.volume=Math.max(0,Math.min(1,Math.round((this.volume+t)*100)/100)),this.sendControls()}cycleStyle(){this.style=wt[(wt.indexOf(this.style)+1)%wt.length]??wt[1],this.sendControls()}suspend(){var t;(t=this.ctx)==null||t.suspend().catch(()=>{})}resume(){var t;(t=this.ctx)==null||t.resume().catch(()=>{})}statusString(){return this.running?De(this.muted,this.style,this.volume):""}stop(){var t;this.post({type:"stop"}),(t=this.ctx)==null||t.close().catch(()=>{}),this.ctx=null,this.node=null,this.starting=null}}const Oe=[[0,0,0],[205,0,0],[0,205,0],[205,205,0],[0,0,238],[205,0,205],[0,205,205],[229,229,229],[127,127,127],[255,0,0],[0,255,0],[255,255,0],[92,92,255],[255,0,255],[0,255,255],[255,255,255]],Pt=[0,95,135,175,215,255];function dt(i){if(i<16)return[...Oe[i]??[0,0,0]];if(i<232){const e=i-16;return[Pt[Math.floor(e/36)]??0,Pt[Math.floor(e/6)%6]??0,Pt[e%6]??0]}const t=8+(i-232)*10;return[t,t,t]}function rt(i){return(255<<24|i[2]<<16|i[1]<<8|i[0])>>>0}function ee(i){return`rgb(${i[0]},${i[1]},${i[2]})`}const Rt=[10,10,12],Ye="rgb(200,200,200)",ut="rgb(112,112,116)",se=st.length,ft=st.map(i=>rt(dt(i))),Tt=U.map(i=>rt(dt(i))),oe=ye.map(([i,t])=>[rt(dt(i)),rt(dt(t))]),qe=ve.map(([i,t])=>[rt(dt(i)),rt(dt(t))]),Ct=rt(Rt),Xe='ui-monospace, "SF Mono", "Cascadia Mono", "DejaVu Sans Mono", Menlo, Consolas, monospace';let Ht=null;function Ze(i){if(Ht&&Ht.maxAge===i)return Ht.table;const t=new Uint8Array(i+1),e=Math.log1p(i);for(let s=1;s<=i;s++)t[s]=Math.min(Math.trunc(Math.log1p(s)/e*(se-1)),se-1);return Ht={maxAge:i,table:t},t}function yt(i){return i.toLocaleString("en-US")}class Ke{constructor(t){g(this,"cw",8);g(this,"cols",80);g(this,"rows",24);g(this,"statusRows",1);g(this,"keys",!0);g(this,"img",null);g(this,"widths",new Map);g(this,"px",null);g(this,"off",null);this.ctx=t}get gridRows(){return Math.max(1,this.rows-this.statusRows)}resize(t,e,s){this.cw=Math.max(2,Math.round(s)),this.cols=Math.max(20,Math.floor(t/this.cw)),this.rows=Math.max(6,Math.floor(e/(this.cw*2))),this.statusRows=this.cols>=150?1:2,this.keys=this.cols>=150,this.img=null,this.widths.clear()}status(t,e){const s=t.sparkline(this.cols<100?10:24),o=t.autoCam?"auto":"pan",a=be[t.zoomLevel]??`${2**t.zoomLevel}x`,n=t.autoFocusMode?"[F]":"",h=t.haunted?"[HAUNTED]":"",r=e?` ${e}`:"",c=` ${t.epoch()} gen ${yt(t.generation)} pop ${yt(t.population())} ${s}`,l=this.keys?" q r spc +/- arrows h z/x f g s ":" ",d=`${r} ${h}${n} ${a} ${o}${l}`;return this.statusRows===1?{left:c,right:d,tickerCol:O(c)+1,tickerWidth:this.cols-O(c)-O(d)-2}:{left:c,right:d,tickerCol:1,tickerWidth:this.cols-2}}render(t,e,s){const o=this.ctx,a=this.cw,n=this.cols*a,h=this.rows*a*2;o.fillStyle=ee(Rt),o.fillRect(0,0,n,h),this.paintGrid(t),o.font=`${Math.round(a*1.62)}px ${Xe}`,o.textBaseline="middle",s&&this.statsOverlay(t);const r=this.rows-1;if(this.statusRows===1)if(e.tickerWidth<10)this.text(`${e.left} ${e.right}`.slice(0,this.cols-1),r,0,ut);else{this.text(e.left,r,0,ut),this.ticker(t,r,e);const c=this.cols-O(e.right);this.text([...e.right].slice(0,this.cols-1-c).join(""),r,c,ut)}else{const c=this.cols-1,l=O(e.left)+O(e.right)<=c?e.left+" ".repeat(c-O(e.left)-O(e.right))+e.right:`${e.left} ${e.right}`;this.text([...l].slice(0,c).join(""),r-1,0,ut),this.ticker(t,r,e)}}paintGrid(t){const e=t.displayGrid(),s=t.displayAge(),o=Math.min(Math.floor(e.h/2),Math.floor(s.h/2),this.gridRows),a=Math.min(e.w,s.w,this.cols),n=this.cols,h=this.gridRows*2;(!this.img||this.img.width!==n||this.img.height!==h)&&(this.img=new ImageData(n,h),this.px=new Uint32Array(this.img.data.buffer),this.off=typeof OffscreenCanvas<"u"?new OffscreenCanvas(n,h):Object.assign(document.createElement("canvas"),{width:n,height:h}));const r=this.px;r.fill(Ct);let c=1;for(let w=0;wc&&(c=s.data[w]??0);const l=Ze(c),d=t.haunted,m=t.zoomLevel>=0||d,y=d?at:X,f=w=>Math.min(Math.max(-w-1,0),y-1),v=w=>l[Math.min(Math.max(w,0),c)]??0,b=w=>{var I;return d?((I=oe[w])==null?void 0:I[0])??0:Tt[w]??0},S=w=>{var I;return d?((I=oe[w])==null?void 0:I[1])??0:Ct};for(let w=0;w0,tt=(e.data[L+V]??0)>0,A=s.data[R+V]??0,x=s.data[E+V]??0,H=m&&A<0,$=m&&x<0;if(!(D||tt||H||$))continue;let T=Ct,j=Ct;if((D||H)&&(tt||$))if(D&&tt)T=ft[v(A)]??0,j=ft[v(x)]??0;else if(H&&$){const z=f(A),B=f(x);if(d){const et=qe[z*at+B];T=(et==null?void 0:et[0])??0,j=(et==null?void 0:et[1])??0}else T=Tt[z]??0,j=Tt[B]??0}else D?T=ft[v(A)]??0:j=ft[v(x)]??0;else if(D)T=ft[v(A)]??0;else if(tt)j=ft[v(x)]??0;else if(H){const z=f(A);T=b(z),j=S(z)}else{const z=f(x);j=b(z),T=S(z)}r[q+V]=T,r[_t+V]=j}}const M=this.off,C=M.getContext("2d");if(!C||!this.img)return;C.putImageData(this.img,0,0);const _=this.ctx;_.imageSmoothingEnabled=!1,_.drawImage(M,0,0,n*this.cw,h*this.cw)}ticker(t,e,s){const o=Kt.dim(t.generation)?ut:Ye;for(const a of t.ticker.messages){const n=Math.trunc(a.x),h=[...a.text],r=Math.max(n,0),c=Math.min(n+h.length,s.tickerWidth);r>=c||this.text(h.slice(r-n,c-n).join(""),e,s.tickerCol+r,o)}}statsOverlay(t){const e=t.lastCensus.size?[...t.lastCensus.entries()].sort((c,l)=>l[1]-c[1]).map(([c,l])=>`${l}×${c}`).join(" "):"none",s=36,o=11,a=this.cols-s-2,n=this.rows-(this.statusRows-1)-o-2;if(a<0||n<0)return;const h=["─".repeat(s-2)," infinity engine",` pop floor : ${yt(t.popFloor)}`,` spread/150 : ${yt(t.spread)}`,` cycle : ${t.cyclePeriod===0?"none":`period ${t.cyclePeriod}`}`,` injections : ${t.totalInjections}`,` last event : ${t.lastEvent||"none"}`,t.lastEvent?` @ gen : ${yt(t.lastEventGen)}`:" ",` world : ${t.worldH}x${t.worldW}`,` census : ${[...e].slice(0,s-16).join("")}`,` tempo : ${(1/Math.max(t.dilation,.01)).toFixed(2)}x`],r=this.ctx;r.fillStyle=ee(Rt),r.fillRect(a*this.cw,n*this.cw*2,s*this.cw,h.length*this.cw*2),h.forEach((c,l)=>{const d=[...` ${c}`.padEnd(s)].slice(0,s).join("");this.text(d,n+l,a,ut)})}text(t,e,s,o){const a=this.ctx,n=this.cw,h=e*n*2;a.fillStyle=o;let r=s;for(const c of t){if(r>=this.cols)break;if(r>=0&&c!==" "){const l=gt.indexOf(c);if(l>=0){const d=Math.max(1,Math.round(n*2*(l+1)/8));a.fillRect(r*n,h+n*2-d,n,d)}else if(c==="─")a.fillRect(r*n,h+n-Math.max(1,Math.round(n/8))/2,n,Math.max(1,Math.round(n/8)));else{let d=this.widths.get(c);d===void 0&&(d=a.measureText(c).width,this.widths.set(c,d)),a.fillText(c,r*n+n/2-d/2,h+n)}}r++}}}const Qe=document.getElementById("afterlife-root"),P=document.getElementById("term"),K=document.getElementById("splash"),Y=document.getElementById("keys"),ie=P==null?void 0:P.getContext("2d",{alpha:!1});if(!Qe||!P||!ie)throw new Error("afterlife: the page is missing its terminal");const Je=window.top!==window,k=new Ke(ie),N=new Ue,ne=new Be;let p,jt=Date.now(),Nt=!1,ht=0,vt=!1,Mt=[];function ts(){const i=window.innerWidth;return i>=1100?8:i>=700?7:6}function ae(){const i=Math.min(window.devicePixelRatio||1,3),t=Math.max(2,Math.round(ts()*i));k.resize(Math.floor(window.innerWidth*i),Math.floor(window.innerHeight*i),t);const e=k.cols*k.cw,s=k.rows*k.cw*2;P.width=e,P.height=s,P.style.width=`${e/i}px`,P.style.height=`${s/i}px`}function es(){const i=p;ae(),p=new St(k.gridRows,k.cols,!1),p.haunted=i.haunted,p.adopt(i.snapshot()),ht=0}function xt(){p&&Ne({...p.snapshot(),bornAt:jt,savedAt:Date.now()})}ae();const $t=je();$t?(p=new St(k.gridRows,k.cols,!1),p.adopt($t),jt=$t.bornAt,p.ticker.queueSpecial(`the universe remembers generation ${p.generation.toLocaleString("en-US")}`)):p=new St(k.gridRows,k.cols);function re(){const i=p.step();if(N.running&&!p.paused&&p.generation%2===0)try{const s=p.viewW;ht=(ht+Math.max(1,Math.floor(s/240)))%Math.max(1,s);const o=p.displayGrid(),a=[];if(ht=2?(n[n.length-1]??0)-(n[n.length-2]??0):0,playhead_column:a,playhead_position:ht/Math.max(1,s),viewport_rows:o.h,event:i,activity_x:p.activityCenterX()};N.update(r),vt&&Mt.push(JSON.stringify({...r,playhead_column:a.map(c=>c?1:0)}))}catch{}p.autoFocusMode&&++p.autoFocusFrame>=2&&(p.autoFocusFrame=0,p.autoFocus());const t=!p.paused&&p.generation>0;t&&p.generation%150===0&&p.takeCensus(),t&&p.generation%Se===0&&xt(),(i||p.generation%10===0)&&ne.log({gen:p.generation,pop:p.population(),spread:p.spread,floor:p.popFloor,cycle:p.cyclePeriod,zoom:p.zoomLevel,camY:p.camY,camX:p.camX,event:i});const e=k.status(p,he());e.tickerWidth>=10&&p.tickTicker(e.tickerWidth)}function he(){let i=N.statusString();return vt&&(i+=` REC(${Mt.length})`),i}function Q(){k.render(p,k.status(p,he()),Nt)}let It=0,bt=0;function le(i){bt=requestAnimationFrame(le);let t=0;for(;i>=It-8&&t<4;)re(),t++,It=Math.max(It,i-100)+p.delay*p.timeDilation();t&&Q()}function ce(){bt||(It=performance.now(),bt=requestAnimationFrame(le))}function ss(){cancelAnimationFrame(bt),bt=0}function de(i,t,e){const s=URL.createObjectURL(new Blob([t],{type:e})),o=Object.assign(document.createElement("a"),{href:s,download:i});document.body.append(o),o.click(),o.remove(),setTimeout(()=>URL.revokeObjectURL(s),1e3)}function os(){if(xt(),Je){p.ticker.queueSpecial("the glass holds; eject from the other side");return}const i=document.referrer,t=i&&new URL(i,location.href).origin===location.origin&&!i.includes("/afterlife")?i:"/";location.href=t}const Bt={quit:os,reseed:()=>{const i=p.haunted;p=new St(k.gridRows,k.cols),p.haunted=i,jt=Date.now(),ht=0},pause:()=>{p.paused=!p.paused},faster:()=>{p.delay=Math.max(10,p.delay-10)},slower:()=>{p.delay=Math.min(500,p.delay+10)},home:()=>p.home(),clear:()=>p.clear(),zoomOut:()=>p.zoomOut(),zoomIn:()=>p.zoomIn(),focus:()=>{p.autoFocusMode=!p.autoFocusMode,p.autoFocusMode&&p.autoFocus()},haunt:()=>p.toggleHaunted(),stats:()=>{Nt=!Nt},record:()=>{N.running&&(vt=!vt,vt?Mt=[]:Mt.length&&de("snapshots.jsonl",`${Mt.join(` +`)} +`,"application/x-ndjson"))},mute:()=>N.running&&N.toggleMute(),style:()=>N.running&&N.cycleStyle(),volDown:()=>N.running&&N.adjustVolume(-.1),volUp:()=>N.running&&N.adjustVolume(.1),up:()=>p.pan(-5,0),down:()=>p.pan(5,0),left:()=>p.pan(0,-10),right:()=>p.pan(0,10),statsCsv:()=>de("life_stats.csv",ne.csv(),"text/csv"),help:()=>Gt()},ue={q:"quit",r:"reseed"," ":"pause","+":"faster","=":"faster","-":"slower",_:"slower",h:"home",c:"clear",z:"zoomOut",x:"zoomIn",f:"focus",g:"haunt",s:"stats",d:"record",m:"mute",v:"style","[":"volDown","]":"volUp",ArrowUp:"up",ArrowDown:"down",ArrowLeft:"left",ArrowRight:"right","?":"help"};function mt(i){var t;(t=Bt[i])==null||t.call(Bt),Q()}window.addEventListener("keydown",i=>{if(i.ctrlKey||i.metaKey||i.altKey)return;if(i.key==="Escape"){Y&&!Y.hidden&&Gt(!1),pt();return}const t=ue[i.key.length===1?i.key.toLowerCase():i.key]??ue[i.key];t&&(i.preventDefault(),pt(),mt(t))});let fe=!1;function pt(){fe||(fe=!0,K==null||K.classList.add("gone"),setTimeout(()=>K==null?void 0:K.remove(),1600)),N.start()}K==null||K.addEventListener("pointerdown",i=>{i.preventDefault(),i.stopPropagation(),pt()});function Gt(i=(Y==null?void 0:Y.hidden)??!1){var t;Y&&(Y.hidden=!i,(t=document.getElementById("keys-toggle"))==null||t.setAttribute("aria-expanded",String(i)))}Y==null||Y.addEventListener("click",i=>{const t=i.target.closest("[data-act]");t&&(i.preventDefault(),pt(),mt(t.dataset.act??""))}),(ge=document.getElementById("keys-toggle"))==null||ge.addEventListener("click",i=>{i.preventDefault(),pt(),Gt()});function Vt(i){const t=P.getBoundingClientRect(),e=t.width/k.cols,s=Math.floor((i.clientX-t.left)/e),o=Math.floor((i.clientY-t.top)/e);return[Math.floor(o/2),s,o%2]}let F=null;const J=new Map;let nt=0;P.addEventListener("contextmenu",i=>i.preventDefault()),P.addEventListener("pointerdown",i=>{if(pt(),J.set(i.pointerId,{x:i.clientX,y:i.clientY}),J.size===2){const[a,n]=[...J.values()];nt=a&&n?Math.hypot(a.x-n.x,a.y-n.y):0,F=null;return}P.setPointerCapture(i.pointerId);const t=i.button===1||i.button===2||i.shiftKey,[e,s,o]=Vt(i);F={id:i.pointerId,kind:t?"pan":"paint",x:i.clientX,y:i.clientY,last:"",moved:!1},!t&&i.pointerType==="mouse"&&e{if(J.has(i.pointerId)&&J.set(i.pointerId,{x:i.clientX,y:i.clientY}),J.size===2&&nt){const[r,c]=[...J.values()],l=r&&c?Math.hypot(r.x-c.x,r.y-c.y):nt;l/nt>1.35?(mt("zoomIn"),nt=l):l/nt<.74&&(mt("zoomOut"),nt=l);return}if(!F||F.id!==i.pointerId)return;const t=i.pointerType!=="mouse";if(!F.moved&&Math.hypot(i.clientX-F.x,i.clientY-F.y)<(t?10:2))return;if(F.moved=!0,F.kind==="pan"||t){const c=P.getBoundingClientRect().width/k.cols,l=Math.trunc((F.x-i.clientX)/c),d=Math.trunc((F.y-i.clientY)/c);(l||d)&&(p.pan(d,l),F.x-=l*c,F.y-=d*c,Q());return}const[e,s,o]=Vt(i),a=`${e},${s},${o}`;if(a===F.last||e>=k.gridRows)return;F.last=a;const[n,h]=p.termToWorld(e,s,o);p.setCell(n,h,1),Q()});const me=i=>{if(J.delete(i.pointerId),J.size<2&&(nt=0),!(!F||F.id!==i.pointerId)){if(i.type==="pointerup"&&i.pointerType!=="mouse"&&!F.moved){const[t,e,s]=Vt(i);t{i.preventDefault(),Wt+=i.deltaY*(i.deltaMode===1?33:1),!(Math.abs(Wt)<120)&&(mt(Wt>0?"zoomOut":"zoomIn"),Wt=0)},{passive:!1});let pe=0;window.addEventListener("resize",()=>{clearTimeout(pe),pe=window.setTimeout(()=>{es(),Q()},200)}),document.addEventListener("visibilitychange",()=>{document.visibilityState==="hidden"?(xt(),ss(),N.suspend()):(N.resume(),ce())}),window.addEventListener("pagehide",xt),window.afterlife={get life(){return p},term:k,frame:re,paint:Q,act:mt,persist:xt},Q(),document.visibilityState!=="hidden"&&ce()})(); diff --git a/aethera/static/oikos/oikos.js b/aethera/static/oikos/oikos.js index ca2cbe5..8e0cc48 100644 --- a/aethera/static/oikos/oikos.js +++ b/aethera/static/oikos/oikos.js @@ -1,18 +1,18 @@ -var xv=Object.defineProperty;var vv=(xi,yn,Sn)=>yn in xi?xv(xi,yn,{enumerable:!0,configurable:!0,writable:!0,value:Sn}):xi[yn]=Sn;var I=(xi,yn,Sn)=>vv(xi,typeof yn!="symbol"?yn+"":yn,Sn);(function(){"use strict";var Ru;function xi(){const s=document.getElementById("oikos-data");try{const t=JSON.parse((s==null?void 0:s.textContent)??"{}");return{sites:t.sites??[],files:t.files??[],posts:t.posts??[]}}catch{return{sites:[],files:[],posts:[]}}}const yn=s=>/^https?:\/\//.test(s);class Sn{constructor(t){I(this,"listeners",new Set);this.value=t}set(t){this.value=t;for(const e of this.listeners)e(t)}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}}function $l(){try{const s=localStorage.getItem("syrinx-creature-v1");if(!s)return null;const t=JSON.parse(s);if(typeof t.name!="string"||typeof t.bornAt!="number"||!t.state)return null;const e=Array.isArray(t.state.nodes)?t.state.nodes:[],n=Array.isArray(t.state.edges)?t.state.edges:[];return e.length?{name:t.name,bornAt:t.bornAt,lifetime:typeof t.state.lifetime=="number"?t.state.lifetime:0,nodes:e.map(i=>({id:i.id,x:i.x,y:i.y,z:i.z??500,age:i.age??0})),edges:n.map(i=>({a:i.a,b:i.b,age:i.age??0}))}:null}catch{return null}}function Xl(s){return new Promise((t,e)=>{const n=new Image;n.decoding="async",n.onload=()=>t(n),n.onerror=e,n.src=s})}async function Qs(s){try{const t=await fetch(s,{headers:{Accept:"application/json"}});return t.ok?await t.json():null}catch{return null}}class Bu{constructor(){I(this,"dreams",new Sn({known:!1,awake:!1,frame:0,fps:0,viewers:0,raw:null}));I(this,"chronicle",new Sn({known:!1,thumb:null,thumbAt:0,prompt:"",template:"",eras:[],eraCount:0,strata:[]}));I(this,"irc",new Sn({connected:!1,lines:[],collapse:null,fragments:0,version:0}));I(this,"creature",new Sn($l()));I(this,"apeiron",new Sn(null));I(this,"timers",[]);I(this,"ws",null);I(this,"wsBackoff",2e3);I(this,"wsTimer",0);I(this,"running",!1)}start(){if(this.running)return;this.running=!0;const t=(e,n)=>{e(),this.timers.push(window.setInterval(e,n))};t(()=>void this.pollDreams(),2e4),t(()=>void this.pollChronicle(),12e4),t(()=>this.creature.set($l()),15e3),this.openIrc(),this.apeiron.value||this.loadApeiron()}stop(){this.running=!1;for(const t of this.timers)clearInterval(t);this.timers=[],clearTimeout(this.wsTimer),this.ws&&(this.ws.onclose=null,this.ws.close(),this.ws=null),this.irc.set({...this.irc.value,connected:!1,version:this.irc.value.version+1})}async pollDreams(){var e,n,i,r,a;const t=await Qs("/api/dreams/status");if(!t){this.dreams.set({...this.dreams.value,known:!1});return}this.dreams.set({known:!0,awake:!!((e=t.gpu)!=null&&e.active),frame:((n=t.generation)==null?void 0:n.current_frame)??((i=t.generation)==null?void 0:i.frame_count)??0,fps:((r=t.generation)==null?void 0:r.fps)??0,viewers:((a=t.viewers)==null?void 0:a.websocket_count)??0,raw:t})}async pollChronicle(){var a,o,l,c;const t=await Qs("/api/dreams/chronicle/timeline?hours=3");if(!t)return;const e=this.chronicle.value;let n=e.thumb;(a=t.live)!=null&&a.thumb&&t.live.thumb!==(n==null?void 0:n.dataset.src)&&(n=await Xl(t.live.thumb).catch(()=>e.thumb),n&&(n.dataset.src=t.live.thumb));const i=(t.tiles??[]).slice(-3),r=(await Promise.all(i.map(u=>Xl(u.url).catch(()=>null)))).filter(u=>!!u);this.chronicle.set({known:!0,thumb:n,thumbAt:((o=t.live)==null?void 0:o.t)??0,prompt:((l=t.live)==null?void 0:l.prompt)??"",template:((c=t.live)==null?void 0:c.template)??"",eras:(t.eras??[]).map(u=>({title:u.title??"",t0:u.t0,t1:u.t1,open:!!u.open,kf:u.kf??0})),eraCount:t.era_count??0,strata:r.length?r:e.strata})}openIrc(){const t=location.protocol==="https:"?"wss":"ws";let e;try{e=new WebSocket(`${t}://${location.host}/ws/irc`)}catch{return}this.ws=e;const n=i=>{const r=this.irc.value;this.irc.set({...r,...i,version:r.version+1})};e.onopen=()=>{this.wsBackoff=2e3,n({connected:!0,collapse:null})},e.onmessage=i=>{let r;try{r=JSON.parse(String(i.data))}catch{return}if(r.type==="message"&&r.data){const a=r.data,o=a.meta??{},l={nick:String(a.nick??""),content:String(a.content??""),type:String(a.type??"message"),stamp:String(a.timestamp??""),at:performance.now()};if(typeof a.at=="number"&&(l.wallAt=a.at),typeof o.target=="string"&&(l.target=o.target),typeof o.reason=="string"&&(l.reason=o.reason),r.replay&&this.irc.value.lines.some(c=>c.stamp===l.stamp&&c.nick===l.nick&&c.content===l.content))return;n({lines:[...this.irc.value.lines,l].slice(-60)})}else r.type==="collapse_start"?n({collapse:{type:r.collapseType??"collapse",at:performance.now()}}):r.type==="fragment_end"&&(r.replay?n({collapse:null}):n({collapse:null,lines:this.irc.value.lines.slice(-6),fragments:this.irc.value.fragments+1}))},e.onclose=()=>{n({connected:!1}),this.running&&(this.wsTimer=window.setTimeout(()=>this.openIrc(),this.wsBackoff),this.wsBackoff=Math.min(this.wsBackoff*2,6e4))}}async loadApeiron(){const[t,e]=await Promise.all([Qs("/static/apeiron/data/templates.json"),Qs("/static/apeiron/data/components.json")]);t&&e&&this.apeiron.set({templates:t,components:e})}}const It=512,Wt=384,Yt='"Libertinus Mono", "LibertinusMono", ui-monospace, monospace',oa='"Love Letter Typewriter", "Libertinus Mono", monospace';function la(s,t,e){t();const n=typeof document<"u"?document.fonts:void 0,i=(Array.isArray(s)?s:[s]).filter(r=>n&&!n.check(r));!n||!i.length||Promise.all(i.map(r=>n.load(r))).then(()=>{t(),e==null||e()},()=>{})}class bn{constructor(t,e){I(this,"canvas");I(this,"ctx");I(this,"fps",15);I(this,"acc",1);I(this,"version",0);this.site=t,this.env=e,this.canvas=document.createElement("canvas"),this.canvas.width=It,this.canvas.height=Wt;const n=this.canvas.getContext("2d",{alpha:!1});if(!n)throw new Error("oikos: no 2d context");this.ctx=n}tick(t,e,n,i=1){this.acc+=e;const r=n?Math.max(this.fps,30):this.fps*i;if(this.acc<1/r)return!1;const a=this.acc;return this.acc=0,this.draw(t,a),this.version++,!0}clear(t){this.ctx.fillStyle=t,this.ctx.fillRect(0,0,It,Wt)}wrap(t,e,n=1/0){const i=this.ctx,r=t.split(/\s+/).filter(Boolean),a=[];let o="";for(const l of r){const c=o?`${o} ${l}`:l;if(i.measureText(c).width>e&&o){if(a.push(o),o=l,a.length>=n)break}else o=c}if(o&&a.lengthe;)l=l.replace(/\s*\S*$/,"");a[n-1]=`${l}…`}return a}condensed(t,e,n,i=.72,r="left"){const a=this.ctx;a.save(),a.translate(e,n),a.scale(i,1),a.textAlign=r,a.fillText(t,0,0),a.restore()}spaced(t,e,n,i,r="left"){const a=this.ctx,o=[...t],l=o.map(h=>a.measureText(h).width),c=l.reduce((h,d)=>h+d,0)+i*(o.length-1);let u=r==="center"?e-c/2:e;a.save(),a.textAlign="left",o.forEach((h,d)=>{a.fillText(h,u,n),u+=(l[d]??0)+i}),a.restore()}}function ca(s){let t=2166136261;for(let e=0;e>>0)%1e5/1e5}function vi(s){let t=s>>>0;return()=>{t=t+1831565813>>>0;let e=t;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296}}function zu(s){return Math.round(s).toLocaleString("en-US")}const Kn=62,ws=21,Hu=It/Kn,Gu=12.4,Vu=42,ha=" .,:;-=+*#%@";function Wu(){const s=[];for(let e=0;e<16;e++)s.push([e&1?1:-1,e&2?1:-1,e&4?1:-1,e&8?1:-1]);const t=[];for(let e=0;e<16;e++)for(let n=0;n<4;n++){const i=e^1<>>0).toString(16).padStart(8,"0").replace(/(....)(....)/,"$1·$2");return{prompt:a,template:o,coordinate:l,hue:n?Math.floor(ca(a)*360):135,figure:ua[this.seq++%ua.length]??ua[0]??[],bornAt:e}}draw(e){(!this.gen||e-this.gen.bornAt>9||!this.gen.prompt&&this.env.feeds.apeiron.value)&&(this.gen=this.generate(e));const n=this.gen,i=this.ctx,r=`hsl(${n.hue} 100% 58%)`,a=`hsl(${n.hue} 100% 76%)`,o=`hsl(${n.hue} 60% 22%)`,l=i.createRadialGradient(It/2,Wt*.4,20,It/2,Wt*.4,It*.7);l.addColorStop(0,`hsl(${n.hue} 60% 7%)`),l.addColorStop(1,"#030309"),i.fillStyle=l,i.fillRect(0,0,It,Wt),i.font=`12px ${Yt}`,i.fillStyle=r,i.fillText("apeiron",14,22),i.fillStyle=o,i.fillText("· æthera",76,22),i.textAlign="right",i.fillStyle=r,i.fillText(n.template.replace(/_/g," "),It-14,22),i.textAlign="left",this.raster(e,n.figure),i.font=`12px ${Yt}`;for(let d=0;d9?a:p>4?r:o,i.fillText(ha[p]??".",f*Hu,Vu+d*Gu+10))}const c=e-n.bornAt,u=n.prompt||"reading the grammar…";i.font=`12px ${Yt}`;const h=this.wrap(u.slice(0,Math.floor(c*70)),It-28,4);i.fillStyle="rgba(3,3,9,0.7)",i.fillRect(0,Wt-98,It,98),i.fillStyle=o,i.fillRect(14,Wt-98,It-28,1),i.fillStyle=a,h.forEach((d,f)=>i.fillText(d,14,Wt-78+f*15)),i.fillStyle=r,i.font=`11px ${Yt}`,i.fillText(`⌖ ${n.coordinate}`,14,Wt-12),i.fillStyle=o,i.textAlign="right",i.fillText("␣ generate F keep A auto",It-14,Wt-12),i.textAlign="left"}raster(e,n){this.depth.fill(-1/0),this.glyph.fill(0);const i=e*.45,r=e*.31,a=e*.23,[o,l,c,u,h,d]=[Math.cos(i),Math.sin(i),Math.cos(r),Math.sin(r),Math.cos(a),Math.sin(a)];for(const f of n){let[p,v,m,g]=f;[p,g]=[p*o-g*l,p*l+g*o],[v,m]=[v*c-m*u,v*u+m*c],[m,g]=[m*h-g*d,m*d+g*h];const w=2.6/(3.2-g);p*=w,v*=w,m*=w;const E=3.4/(4.6-m),M=Math.round(Kn/2+p*E*11.5),S=Math.round(ws/2+v*E*5.6);if(M<0||M>=Kn||S<0||S>=ws)continue;const b=S*Kn+M;m>(this.depth[b]??-1/0)&&(this.depth[b]=m,this.glyph[b]=Math.max(1,Math.min(ha.length-1,Math.round((m+2.2)/4.4*(ha.length-1)))))}}}function qu(s,t){const e=s.templates[Math.floor(t()*s.templates.length)];return e?{prompt:e.structure.replace(/\{(\w+)\}/g,(i,r)=>{var o;const a=s.components[r];return a!=null&&a.length?((o=a[Math.floor(t()*a.length)])==null?void 0:o.word)??r:r.replace(/_/g," ")}),template:e.id}:{prompt:"",template:""}}const da="#e8e2d4",fa="#a39d90",ql="#5d5850",Mi=34,ki=250,yi=84,js=Wt-yi-22;class Yu extends bn{constructor(e,n){super(e,n);I(this,"standIn");this.fps=10,this.standIn=Ku()}draw(e){const n=this.ctx;this.clear("#070707"),n.fillStyle=da,n.font=`22px ${Yt}`,this.spaced("chronicle",It/2,38,11,"center"),n.fillStyle=fa,n.font=`11px ${Yt}`,this.spaced("what the dream remembers",It/2,60,2,"center");const r=[...this.env.feeds.chronicle.value.strata].reverse();if(n.fillStyle="#000",n.fillRect(Mi-1,yi-1,ki+2,js+2),n.imageSmoothingEnabled=!0,r.length){const l=r.map((h,d)=>Math.pow(.6,d)),c=l.reduce((h,d)=>h+d,0);let u=yi;r.forEach((h,d)=>{const f=js*(l[d]??0)/c;n.save(),n.translate(Mi,u+f),n.scale(1,-1),n.drawImage(h,0,0,ki,f),n.restore(),u+=f,n.fillStyle="rgba(232,226,212,0.08)",n.fillRect(Mi,u,ki,1)})}else n.globalAlpha=.75,n.drawImage(this.standIn,Mi,yi,ki,js),n.globalAlpha=1;const a=yi+e*14%js,o=n.createLinearGradient(0,a-16,0,a+2);o.addColorStop(0,"rgba(232,226,212,0)"),o.addColorStop(1,"rgba(232,226,212,0.22)"),n.fillStyle=o,n.fillRect(Mi,a-16,ki,18),n.fillStyle="rgba(232,226,212,0.5)",n.fillRect(Mi-6,a,4,1),this.log(e)}log(e){const n=this.ctx,i=this.env.feeds.chronicle.value,r=Mi+ki+24,a=It-r-18;n.font=`11px ${Yt}`,n.fillStyle=ql,n.fillText(i.known?`${i.eraCount||i.eras.length} eras`:"reading the core…",r,yi+8);const o=[...i.eras].reverse().slice(0,7);let l=yi+34;if(!o.length){n.fillStyle=fa;for(const c of this.wrap("every fifteen seconds of the dream settles here as one line of its own colour.",a,6))n.fillText(c,r,l),l+=15;return}for(const c of o){if(l>Wt-30)break;const u=new Date(c.t0*1e3);n.fillStyle=c.open?da:ql,n.font=`10px ${Yt}`;const h=`${u.getHours().toString().padStart(2,"0")}:${u.getMinutes().toString().padStart(2,"0")}`;n.fillText(c.open?`${h} now`:h,r,l),c.open&&(n.fillStyle=Math.sin(e*3)>0?"#d6c9a8":"#6d6555",n.fillRect(r-10,l-6,4,4)),n.font=`12px ${Yt}`,n.fillStyle=c.open?da:fa;const d=this.wrap(c.title||"untitled",a,2);d.forEach((f,p)=>n.fillText(f,r,l+15+p*14)),l+=22+d.length*14}}}function Ku(){const s=document.createElement("canvas");s.width=64,s.height=240;const t=s.getContext("2d");if(!t)return s;const e=vi(1729),n=["#5c3b36","#7a4f45","#3f3a4c","#8a6f64","#2d4a4f","#6b2c3a","#a38a74","#40302c"];let i=n[0];for(let r=0;r0?pa:tr,n.globalAlpha=.5+e*.5,n.lineWidth=1,n.strokeRect(t.x+.5,t.y+.5,t.w,t.h),n.globalAlpha=1,n.font=`10px ${Yt}`,n.fillStyle=e>0?ma:Si,n.fillText(t.label,t.x+6,t.y+13)}arrow(t,e,n,i,r,a){const o=this.ctx;o.strokeStyle=tr,o.beginPath(),o.moveTo(t,e),o.lineTo(n,i),o.stroke();const l=Math.sign(n-t||i-e);if(o.fillStyle=tr,o.beginPath(),e===i?(o.moveTo(n,i),o.lineTo(n-6*l,i-4),o.lineTo(n-6*l,i+4)):(o.moveTo(n,i),o.lineTo(n-4,i-6*l),o.lineTo(n+4,i-6*l)),o.fill(),a>=0&&a<=1){const c=t+(n-t)*a,u=e+(i-e)*a,h=o.createRadialGradient(c,u,0,c,u,8);h.addColorStop(0,"rgba(213,155,255,1)"),h.addColorStop(1,"rgba(213,155,255,0)"),o.fillStyle=h,o.fillRect(c-8,u-8,16,16)}r&&(o.font=`9px ${Yt}`,o.fillStyle=Si,o.textAlign="center",o.fillText(r,(t+n)/2,e===i?e-6:(e+i)/2),o.textAlign="left")}draw(t){const e=this.ctx;this.clear(Zu);const n=this.env.feeds.chronicle.value,i=6,r=t%i/i,a=400+Math.floor(t/i);if(e.font=`14px ${Yt}`,e.fillStyle=pa,e.fillText("dream_gen",18,28),e.font=`10px ${Yt}`,e.fillStyle=Si,e.fillText("a truly infinite diffusion stream",110,28),e.textAlign="right",e.fillText(`kf ${String(a).padStart(5,"0")}`,It-18,28),e.textAlign="left",this.box(Zn,r<.25?1:0),this.box(He,r>=.25&&r<.5?1:.2),this.box(Jn,0),this.box(bi,r>=.5?1:0),this.box(er,Math.sin(t*.8)>.6?1:0),n.thumb)e.drawImage(n.thumb,He.x+6,He.y+18,He.w-12,(He.w-12)/2),e.globalAlpha=.35,e.drawImage(n.thumb,Zn.x+6,Zn.y+18,Zn.w-12,(Zn.w-12)/2),e.globalAlpha=1;else for(const h of[Zn,He]){const d=e.createLinearGradient(h.x,h.y,h.x+h.w,h.y+h.h);d.addColorStop(0,`hsl(${(t*8+h.x)%360} 40% 30%)`),d.addColorStop(1,`hsl(${(t*8+h.x+90)%360} 40% 18%)`),e.fillStyle=d,e.fillRect(h.x+6,h.y+18,h.w-12,(h.w-12)/2)}e.fillStyle="#1b1426",e.fillRect(Jn.x+6,Jn.y+18,Jn.w-12,(Jn.w-12)/2),e.fillStyle=Si,e.font=`9px ${Yt}`,e.fillText("txt2img on swap",Jn.x+10,Jn.y+50),this.arrow(Zn.x+Zn.w,91,He.x,91,"img2img",r<.25?r/.25:-1),this.arrow(Jn.x,91,He.x+He.w,91,"",-1),this.arrow(He.x+He.w/2,He.y+He.h,He.x+He.w/2,bi.y,"",r>=.25&&r<.5?(r-.25)/.25:-1);const o=16,l=r>=.5?Math.floor((r-.5)/.5*o):0;for(let h=0;h{const p=er.y+34+f*22;e.fillStyle=ma,e.font=`10px ${Yt}`,e.fillText(h,er.x+8,p),e.fillStyle=Si,e.fillText(d,er.x+78,p)}),e.fillStyle="rgba(20,12,30,0.8)",e.fillRect(0,Wt-110,It,110),e.fillStyle=tr,e.fillRect(18,Wt-110,It-36,1),e.font=`10px ${Yt}`,e.fillStyle=Si,e.fillText(n.prompt?`prompt${n.template?` · ${n.template}`:""}`:"prompt",18,Wt-92),e.font=`12px ${Yt}`,e.fillStyle=ma;const u=n.prompt||"the dreamer is asleep; its last prompt will appear here when the chronicle has one.";this.wrap(u,It-36,5).forEach((h,d)=>e.fillText(h,18,Wt-72+d*15))}}const nr=new Image;nr.src="/static/oikos/stage.jpg";const nn=372,sn=186,Yl=(It-nn)/2,Kl=118;class Qu extends bn{constructor(e,n){super(e,n);I(this,"frame",document.createElement("canvas"));I(this,"fctx");I(this,"prev",null);I(this,"cur",null);I(this,"swapAt",0);this.fps=20,this.frame.width=nn,this.frame.height=sn;const i=this.frame.getContext("2d");if(!i)throw new Error("oikos: no 2d context");this.fctx=i}draw(e){const n=this.ctx;this.clear("#120406"),nr.complete&&nr.naturalWidth&&(n.globalAlpha=.95,n.drawImage(nr,0,0,It,Wt),n.globalAlpha=1);const i=this.env.feeds.chronicle.value;i.thumb&&i.thumb!==this.cur&&(this.prev=this.cur,this.cur=i.thumb,this.swapAt=e);const r=this.fctx;if(r.globalCompositeOperation="source-over",r.globalAlpha=1,this.cur){const o=Math.min(1,(e-this.swapAt)/2.5);this.prev&&o<1&&this.kenBurns(this.prev,e-20),r.globalAlpha=this.prev?o:1,this.kenBurns(this.cur,e),r.globalAlpha=1}else this.standIn(e);const a=r.createRadialGradient(nn/2,sn/2,sn*.25,nn/2,sn/2,nn*.56);a.addColorStop(0,"rgba(0,0,0,1)"),a.addColorStop(.72,"rgba(0,0,0,0.9)"),a.addColorStop(1,"rgba(0,0,0,0)"),r.globalCompositeOperation="destination-in",r.fillStyle=a,r.fillRect(0,0,nn,sn),r.globalCompositeOperation="source-over",n.save(),n.globalCompositeOperation="lighter",n.globalAlpha=.18,n.drawImage(this.frame,Yl-30,Kl+sn-20,nn+60,90),n.restore(),n.drawImage(this.frame,Yl,Kl),this.status(e),n.fillStyle="rgba(8,4,4,0.72)",n.fillRect(0,Wt-34,It,34),n.fillStyle="#efe6d2",n.font=`12px ${Yt}`,this.spaced("NOW SHOWING · A DREAM · ALL NIGHT",It/2,Wt-13,3,"center")}kenBurns(e,n){const i=1.06+.05*Math.sin(n*.07),r=Math.sin(n*.05)*10,a=Math.cos(n*.043)*5,o=nn*i,l=sn*i;this.fctx.drawImage(e,(nn-o)/2+r,(sn-l)/2+a,o,l)}standIn(e){const n=this.fctx,i=n.createLinearGradient(0,0,0,sn);i.addColorStop(0,"#3a2440"),i.addColorStop(1,"#170d1c"),n.fillStyle=i,n.fillRect(0,0,nn,sn);const r=[12,330,280,20,350];for(let a=0;a<5;a++){const o=e*(.11+a*.03)+a*1.7,l=nn/2+Math.cos(o)*(60+a*14)*(a%2?1:-1),c=sn/2+Math.sin(o*1.3)*30,u=52+22*Math.sin(o*.7+a),h=n.createRadialGradient(l,c,0,l,c,u);h.addColorStop(0,`hsla(${r[a]} 90% 66% / 0.75)`),h.addColorStop(1,`hsla(${r[a]} 90% 50% / 0)`),n.fillStyle=h,n.fillRect(0,0,nn,sn)}}status(e){const n=this.ctx,i=this.env.feeds.dreams.value,r=this.env.feeds.chronicle.value;n.font=`12px ${Yt}`;let a,o;i.known&&i.awake?(o=Math.sin(e*4)>0?"#ff3b3b":"#6a1010",a=`LIVE frame ${zu(i.frame)}${i.viewers?` · ${i.viewers} watching`:""}`):i.known?(o="#5a5a5a",a=r.thumb?"asleep · last remembered":"asleep · wakes when watched"):(o="#3a3a3a",a=r.thumb?"last remembered":"no signal · a stand-in");const l=n.measureText(a).width+34;n.fillStyle="rgba(0,0,0,0.55)",n.fillRect(14,14,l,24),n.fillStyle=o,n.beginPath(),n.arc(27,26,4.5,0,Math.PI*2),n.fill(),n.fillStyle="#f2e9dc",n.fillText(a,38,30)}}const ju="#04060c",Zl="#9fc6ff",Es="#3d5378",Ts="#c9d1d9",td="#a5e3b5",ga="#ffc387",Jl=[["GET","/api/dreams/status","how it is (never wakes it)"],["WS ","/ws/dreams","the dream itself, h264"],["GET","/api/dreams/stream","MPEG-TS"],["SSE","/api/dreams/sse","events"],["GET","/api/dreams/embed","take it with you"]];class ed extends bn{constructor(e,n){super(e,n);I(this,"askedAt",-10);I(this,"lastRaw");this.fps=12}draw(e){const n=this.ctx;this.clear(ju);const i=this.env.feeds.dreams.value.raw;i!==this.lastRaw&&(this.lastRaw=i,this.askedAt=e);const r=e-this.askedAt;n.font=`13px ${Yt}`;const a=`curl -s ${location.host}/api/dreams/status`,o=a.slice(0,Math.floor(r*38));if(n.fillStyle=Es,n.fillText("$",16,28),n.fillStyle=Zl,n.fillText(o+(o.length=a.length){const c=i?nd(i,11):[[{text:"curl: (52) the dream did not answer",color:"#e58a8a"}]],u=Math.floor((r-a.length/38)*30);c.slice(0,u).forEach((h,d)=>{let f=16;for(const p of h)n.fillStyle=p.color,n.fillText(p.text,f,52+d*17),f+=n.measureText(p.text).width})}const l=Wt-128;n.fillStyle="rgba(159,198,255,0.06)",n.fillRect(10,l-20,It-20,138),n.strokeStyle="rgba(159,198,255,0.25)",n.strokeRect(10.5,l-19.5,It-21,137),n.font=`11px ${Yt}`,n.fillStyle=Es,n.fillText("ENDPOINTS",20,l-4),Jl.forEach(([c,u,h],d)=>{const f=l+16+d*19,p=Math.floor(e/2.5)%Jl.length===d;n.fillStyle=p?ga:Es,n.fillText(c,20,f),n.fillStyle=p?"#ffffff":Zl,n.fillText(u,58,f),n.fillStyle=Es,n.fillText(h,250,f)})}}function nd(s,t){const e=[],n=(i,r,a,o)=>{if(e.length>=t)return;const l=[{text:r,color:Ts}];a!==null&&l.push({text:`"${a}": `,color:Ts});const c=o?"":",";if(i&&typeof i=="object"&&!Array.isArray(i)){const d=Object.entries(i);e.push([...l,{text:"{",color:Ts}]),d.forEach(([f,p],v)=>n(p,`${r} `,f,v===d.length-1)),e.length=t&&(e[t-1]=[{text:" …",color:Es}]),e}const Ie={bg:"#181522",screen:"#231f36",fg:"#c9d1d9",dim:"#6e7681",sys:"#8b949e",quit:"#f85149",action:"#a371f7",join:"#3fb950"},Ql=["#58a6ff","#3fb950","#d29922","#a371f7","#f778ba","#39c5cf","#ff7b72","#7ee787","#ffa657","#79c0ff","#d2a8ff","#56d364"];function id(s){let t=0;for(const e of s)t=t*31+e.charCodeAt(0)>>>0;return Ql[t%Ql.length]??Ie.fg}function sd(s){const t=[{text:`[${s.stamp}] `,color:Ie.dim}],e=s.nick,n=s.content;switch(s.type){case"message":t.push({text:`<${e}> `,color:id(e)},{text:n,color:Ie.fg});break;case"action":t.push({text:`* ${e} ${n}`,color:Ie.action});break;case"quit":t.push({text:`⫫ ${e} has quit${n?` (${n})`:""}`,color:Ie.quit});break;case"part":t.push({text:`← ${e} has left${n?` (${n})`:""}`,color:Ie.sys});break;case"join":t.push({text:`→ ${e} has joined`,color:Ie.join});break;case"kick":{const i=s.reason||n;t.push({text:`⚠ ${s.target?`${s.target} was kicked by ${e}`:`${e} kicked someone`}${i?` (${i})`:""}`,color:Ie.quit})}break;default:t.push({text:`*** ${n||e}`,color:Ie.sys})}return t}const jl=16,Bi=16,_a=50;class rd extends bn{constructor(e,n){super(e,n);I(this,"laidOut",[]);I(this,"seen",-1);this.fps=15}layout(){const e=this.env.feeds.irc.value;e.version!==this.seen&&(this.seen=e.version,this.ctx.font=`12.5px ${Yt}`,this.laidOut=e.lines.map(n=>({rows:this.wrapChunks(sd(n),It-Bi*2),at:n.at})))}wrapChunks(e,n){var o;const i=this.ctx,r=[[]];let a=0;for(const l of e)for(const c of l.text.split(/(\s+)/)){if(!c)continue;const u=i.measureText(c).width;a+u>n&&a>0&&c.trim()&&(r.push([{text:" ",color:l.color}]),a=i.measureText(" ").width),(o=r[r.length-1])==null||o.push({text:c,color:l.color}),a+=u}return r}draw(e){this.layout();const n=this.ctx,i=this.env.feeds.irc.value;this.clear(Ie.bg),n.fillStyle=Ie.screen,n.fillRect(6,6,It-12,Wt-12),n.fillStyle="rgba(88,166,255,0.1)",n.fillRect(6,6,It-12,28),n.font=`13px ${Yt}`,n.fillStyle="#58a6ff",n.fillText("#aethera",Bi,25),n.fillStyle=Ie.dim,n.font=`11px ${Yt}`,n.textAlign="right";const r=i.connected?Math.sin(e*3)>-.3?"● live":"○ live":"○ connecting…";n.fillStyle=i.connected?Ie.join:Ie.dim,n.fillText(r,It-Bi,25),n.textAlign="left";const a=i.collapse?Math.min(1,(performance.now()-i.collapse.at)/1500):0;n.font=`12.5px ${Yt}`;const o=[],l=performance.now();for(const h of this.laidOut)for(const d of h.rows)o.push({chunks:d,fresh:Math.max(0,1-(l-h.at)/600)});const c=Math.floor((Wt-_a-12)/jl),u=o.slice(-c);u.length||(n.fillStyle=Ie.sys,n.fillText(i.connected?"*** the channel is quiet between fragments":"*** connecting to #aethera…",Bi,_a+12)),u.forEach((h,d)=>{let f=Bi;const p=_a+12+d*jl,v=a?Math.sin(p*.3+e*40)*8*a*(Math.random()<.3?1:0):0;for(const m of h.chunks)n.fillStyle=a>.2&&Math.random()0){this.hop.k+=e/.16,this.hop.k>=1&&(this.hop.k=0,this.hop.left--,this.pos[this.hop.seat]=((this.pos[this.hop.seat]??0)+1)%40,this.hop.left===0&&this.land(this.hop.seat));return}if(this.wait-=e,this.wait>0)return;const n=this.turn%Qn.length,i=1+Math.floor(this.rand()*6),r=1+Math.floor(this.rand()*6);this.dice=[i,r],this.say(`${(a=Qn[n])==null?void 0:a.name} rolls ${i} and ${r}.`),this.hop={seat:n,from:this.pos[n]??0,left:i+r,k:0},this.turn++,this.wait=1.6}land(e){var c,u;const n=this.pos[e]??0,[i,r,a]=tc[n]??["",null,0],o=((c=Qn[e])==null?void 0:c.name)??"",l=this.owner.get(n);if(a&&l===void 0&&this.rand()<.75)this.owner.set(n,e),this.say(`${o} buys ${i} for ₯${a}.`);else if(l!==void 0&&l!==e){const h=Math.max(2,Math.round(a/(r?12:8)));this.say(`${o} pays ₯${h} to ${(u=Qn[l])==null?void 0:u.name} for ${i}.`)}else i==="Moira"||i==="Grammateion"?this.say(`${o} draws from ${i}.`):i==="Kerux"&&(this.say(`${o} is sent to the Desmoterion.`),this.pos[e]=10);this.owner.size>22&&this.owner.clear()}draw(e,n){var c;this.step(Math.min(n,.2));const i=this.ctx,r=i.createRadialGradient(It/2,va,40,It/2,va,It*.7);r.addColorStop(0,"#2a241f"),r.addColorStop(1,"#141210"),i.fillStyle=r,i.fillRect(0,0,It,Wt);const a=[hn(-.4,-.4),hn(11.4,-.4),hn(11.4,11.4),hn(-.4,11.4)];i.fillStyle="rgba(0,0,0,0.45)",i.beginPath(),a.forEach(([u,h],d)=>d?i.lineTo(u,h+8):i.moveTo(u,h+8)),i.fill(),i.fillStyle="#d9ccb2",i.beginPath(),a.forEach(([u,h],d)=>d?i.lineTo(u,h):i.moveTo(u,h)),i.fill();for(let u=0;u<40;u++){const[h,d]=xa(u),[,f]=tc[u]??["",null,0],p=[hn(h,d),hn(h+1,d),hn(h+1,d+1),hn(h,d+1)];i.fillStyle=f?ad[f]??"#efe4cf":u%10===0?"#e6d6b6":"#efe4cf",i.strokeStyle="#7a6a52",i.lineWidth=.7,i.beginPath(),p.forEach(([m,g],w)=>w?i.lineTo(m,g):i.moveTo(m,g)),i.closePath(),i.fill(),i.stroke();const v=this.owner.get(u);if(v!==void 0){const[m,g]=hn(h+.5,d+.5);i.fillStyle=((c=Qn[v])==null?void 0:c.color)??"#fff",i.fillRect(m-2,g-5,4,5)}}const[o,l]=hn(5.5,5.5);i.fillStyle="#7a6a52",i.font=`15px ${Yt}`,this.spaced("KLEROS",o,l+5,5,"center"),Qn.forEach((u,h)=>{let d=this.pos[h]??0,f=0,[p,v]=xa(d);if(this.hop.left>0&&this.hop.seat===h){const[E,M]=xa((d+1)%40);p+=(E-p)*this.hop.k,v+=(M-v)*this.hop.k,f=Math.sin(this.hop.k*Math.PI)*9,d=-1}const m=[[.3,.3],[.7,.3],[.3,.7],[.7,.7]][h]??[.5,.5],[g,w]=hn(p+(m[0]??.5),v+(m[1]??.5));i.fillStyle="rgba(0,0,0,0.35)",i.beginPath(),i.ellipse(g,w+1,5,2.5,0,0,Math.PI*2),i.fill(),i.fillStyle=u.color,i.beginPath(),i.arc(g,w-5-f,4.6,0,Math.PI*2),i.fill(),i.strokeStyle="rgba(0,0,0,0.5)",i.stroke()}),this.dice.forEach((u,h)=>this.die(It-70+h*30,22,u,e)),i.font=`11px ${Yt}`,Qn.forEach((u,h)=>{const d=26+h*16;i.fillStyle=u.color,i.fillRect(16,d-8,8,8),i.fillStyle=(this.turn-1)%Qn.length===h?"#f5ecd9":"#8c826f",i.fillText(`${u.name}${u.model?" ◆ model":""}`,30,d)}),i.fillStyle="rgba(10,8,6,0.75)",i.fillRect(0,Wt-62,It,62),i.font=`12px ${Yt}`,this.log.forEach((u,h)=>{i.fillStyle=h===this.log.length-1?"#f1e6cc":"#8a7f6a",i.fillText(u,16,Wt-42+h*16)})}die(e,n,i,r){const a=this.ctx,o=this.hop.left>0?Math.sin(r*30)*.15:0;a.save(),a.translate(e,n),a.rotate(o),a.fillStyle="#efe4cf",a.fillRect(-10,-10,20,20),a.fillStyle="#3a2f24";const l={1:[[0,0]],2:[[-5,-5],[5,5]],3:[[-5,-5],[0,0],[5,5]],4:[[-5,-5],[5,-5],[-5,5],[5,5]],5:[[-5,-5],[5,-5],[0,0],[-5,5],[5,5]],6:[[-5,-5],[5,-5],[-5,0],[5,0],[-5,5],[5,5]]};for(const[c,u]of l[i]??[])a.beginPath(),a.arc(c,u,1.8,0,Math.PI*2),a.fill();a.restore()}}class cd extends bn{constructor(e,n){super(e,n);I(this,"body");I(this,"creatureRef");I(this,"stars");I(this,"breaths",[]);this.fps=24;const i=vi(33);this.stars=Array.from({length:90},()=>({x:i()*It,y:i()*Wt,a:i()*.5+.1})),this.body=ic()}sync(){const e=this.env.feeds.creature.value;e!==this.creatureRef&&(this.creatureRef=e,this.body=e?hd(e):ic(),this.breaths=Array.from({length:Math.min(4,this.body.edges.length)},(n,i)=>({edge:i*7%Math.max(1,this.body.edges.length),k:0,fwd:!0})))}draw(e,n){this.sync();const i=this.ctx,r=this.body,a=i.createLinearGradient(0,0,0,Wt);a.addColorStop(0,"#070b14"),a.addColorStop(1,"#02030a"),i.fillStyle=a,i.fillRect(0,0,It,Wt);for(const p of this.stars)i.fillStyle=`rgba(200,215,255,${p.a*(.7+.3*Math.sin(e+p.x))})`,i.fillRect(p.x,p.y,1,1);const o=r.born?1.4:.9,l=Math.min(n,.1),c=r.nodes.map((p,v)=>{var w;const m=r.adj[v]??[];let g=0;for(const E of m)g+=Math.sin((((w=r.nodes[E])==null?void 0:w.phase)??0)-p.phase);return p.phase+(p.omega+(m.length?o*g/m.length:0))*l});r.nodes.forEach((p,v)=>{const m=c[v]??p.phase;Math.floor(m/(Math.PI*2))>Math.floor(p.phase/(Math.PI*2))&&(p.flash=1),p.phase=m,p.flash=Math.max(0,p.flash-l*2.2)});const u=e*.18,h=Math.cos(u),d=Math.sin(u),f=r.nodes.map((p,v)=>{const m=Math.sin(e*.9+v)*.02,g=p.x*h-p.z*d,E=2.8/(3.6-(p.x*d+p.z*h));return{x:It/2+g*E*150,y:176+(p.y+m)*E*150,k:E}});i.lineCap="round";for(const p of r.edges){const v=f[p.a],m=f[p.b];!v||!m||(i.strokeStyle=p.elder?"rgba(160,200,235,0.55)":"rgba(140,170,210,0.28)",i.lineWidth=p.elder?1.4:.8,i.beginPath(),i.moveTo(v.x,v.y),i.lineTo(m.x,m.y),i.stroke())}for(const p of this.breaths){const v=r.edges[p.edge];if(!v)continue;if(p.k+=l/.75,p.k>=1){const S=p.fwd?v.b:v.a,b=(r.adj[S]??[]).map(T=>r.edges.findIndex(P=>P.a===S&&P.b===T||P.b===S&&P.a===T)),R=b[Math.floor(Math.random()*b.length)]??p.edge,x=r.edges[R];p.edge=R,p.fwd=x?x.a===S:!0,p.k=0;continue}const m=f[p.fwd?v.a:v.b],g=f[p.fwd?v.b:v.a];if(!m||!g)continue;const w=m.x+(g.x-m.x)*p.k,E=m.y+(g.y-m.y)*p.k,M=i.createRadialGradient(w,E,0,w,E,9);M.addColorStop(0,"rgba(235,245,255,0.95)"),M.addColorStop(1,"rgba(180,220,255,0)"),i.fillStyle=M,i.fillRect(w-9,E-9,18,18)}r.nodes.forEach((p,v)=>{const m=f[v];if(!m)return;const g=p.flash,w=2+m.k*1.2+g*3,E=g>.05?`rgba(255,${Math.round(210-g*40)},${Math.round(120-g*60)},${.6+g*.4})`:"rgba(200,225,255,0.85)";i.strokeStyle=E,i.lineWidth=.8,i.beginPath(),i.moveTo(m.x-w*3,m.y),i.lineTo(m.x+w*3,m.y),i.moveTo(m.x,m.y-w*3),i.lineTo(m.x,m.y+w*3),i.stroke();const M=i.createRadialGradient(m.x,m.y,0,m.x,m.y,w*2.4);M.addColorStop(0,E),M.addColorStop(1,"rgba(0,0,0,0)"),i.fillStyle=M,i.fillRect(m.x-w*3,m.y-w*3,w*6,w*6)}),i.font=`15px ${Yt}`,i.fillStyle=r.born?"#e6f1ff":"#8190a8",i.fillText(r.name,18,Wt-40),i.font=`11px ${Yt}`,i.fillStyle="#6f7f99",i.fillText(r.age,18,Wt-20),i.textAlign="right",i.fillStyle="#4b5870",i.fillText(r.born?`${r.nodes.length} nodes · ${r.edges.length} strings`:"click to wake it",It-18,Wt-20),i.textAlign="left"}}function nc(s,t){var n,i;const e=Array.from({length:s},()=>[]);for(const r of t)(n=e[r.a])==null||n.push(r.b),(i=e[r.b])==null||i.push(r.a);return e}function hd(s){const t=new Map(s.nodes.map((c,u)=>[c.id,u])),e=s.nodes.reduce((c,u)=>c+u.x,0)/s.nodes.length,n=s.nodes.reduce((c,u)=>c+u.y,0)/s.nodes.length,i=s.nodes.reduce((c,u)=>c+u.z,0)/s.nodes.length,r=Math.max(1,...s.nodes.map(c=>Math.hypot(c.x-e,c.y-n,c.z-i))),a=s.nodes.map((c,u)=>({x:(c.x-e)/r,y:(c.y-n)/r,z:(c.z-i)/r,phase:u*1.3,omega:2.4+u%5*.21,flash:0})),o=s.edges.map(c=>({a:t.get(c.a)??-1,b:t.get(c.b)??-1,elder:c.age>150})).filter(c=>c.a>=0&&c.b>=0),l=Math.max(s.lifetime,(Date.now()-s.bornAt)/1e3);return{name:s.name,age:`${ud(l)} old · yours`,born:!0,nodes:a,edges:o,adj:nc(a.length,o)}}function ic(){const s=vi(9),t=9,e=Array.from({length:t},(i,r)=>{const a=r/t*Math.PI*2;return{x:Math.cos(a)*.8+(s()-.5)*.3,y:(s()-.5)*.9,z:Math.sin(a)*.8,phase:s()*6,omega:2.2+s()*.8,flash:0}}),n=[];for(let i=0;i0?`${e}d ${n}h`:n>0?`${n}h ${i}m`:`${i}m`}const zi=new Image;zi.src="/static/uploads/aethera_trimmed.png";class dd extends bn{constructor(e,n){super(e,n);I(this,"specks");this.fps=12;const i=vi(7);this.specks=Array.from({length:70},()=>({x:i()*It,y:i()*Wt,r:i()*1.2+.3,red:i()<.35,v:i()*4+1}))}draw(e){const n=this.ctx;this.clear("#000");for(const c of this.specks){const u=(c.y-e*c.v+Wt)%Wt;n.fillStyle=c.red?"rgba(170,40,50,0.55)":"rgba(255,255,255,0.28)",n.fillRect(c.x,u,c.r,c.r)}if(zi.complete&&zi.naturalWidth){const u=210*zi.naturalHeight/zi.naturalWidth;n.globalAlpha=.92+.08*Math.sin(e*1.3),n.drawImage(zi,(It-210)/2,26,210,u),n.globalAlpha=1}n.fillStyle="#7d7d7d",n.font=`13px ${Yt}`,this.spaced("transmissions",It/2,118,3,"center"),n.fillStyle="#262626",n.fillRect(40,132,It-80,1);const i=this.env.dir.posts.slice(0,6);if(!i.length){n.fillStyle="#9a9a9a",n.font=`16px ${Yt}`,n.textAlign="center",n.fillText(`no transmissions yet${Math.floor(e*2)%2?"_":" "}`,It/2,230),n.textAlign="left";return}const r=3.6,a=Math.floor(e/r)%i.length,o=e%r/r;i.forEach((c,u)=>{const h=162+u*29,d=u===a;n.font=`11px ${Yt}`,n.fillStyle=d?"#bdbdbd":"#555",n.fillText(c.date,46,h),n.font=`16px ${oa}`,n.fillStyle=d?"#ffffff":"#9a9a9a";const f=c.title.length>38?`${c.title.slice(0,37)}…`:c.title;n.fillText(f,132,h),d&&this.star(28,h-5,e)});const l=i[a];if(l!=null&&l.excerpt){n.font=`italic 12px ${Yt}`,n.fillStyle="#8a8a8a";const c=Math.floor(Math.min(1,o*1.6)*l.excerpt.length);this.wrap(l.excerpt.slice(0,c),It-92,2).forEach((h,d)=>n.fillText(h,46,344+d*16))}}star(e,n,i){const r=this.ctx,a=7+Math.sin(i*5)*1.2;r.save(),r.translate(e,n),r.rotate(i*.8),r.fillStyle="#fff",r.shadowColor="#fff",r.shadowBlur=10,r.beginPath();for(let o=0;o<16;o++){const l=o/16*Math.PI*2,c=o%2?a*.28:o%4?a*.7:a;r.lineTo(Math.cos(l)*c,Math.sin(l)*c)}r.closePath(),r.fill(),r.restore()}}const fd={transmissions:dd,dreams:Qu,chronicle:Yu,"dreams-api":ed,apeiron:Xu,syrinx:cd,irc:rd,parlor:ld,dream_gen:Ju};class pd extends bn{draw(t){const e=this.ctx,n=["#c0c0c0","#c0c000","#00c0c0","#00c000","#c000c0","#c00000","#0000c0"];n.forEach((i,r)=>{e.fillStyle=i,e.fillRect(r*It/n.length,0,It/n.length+1,Wt*.66)}),e.fillStyle="#111",e.fillRect(0,Wt*.66,It,Wt*.34),e.fillStyle="#fff",e.font=`22px ${Yt}`,e.textAlign="center",e.fillText(this.site.title,It/2,Wt*.82),e.font=`12px ${Yt}`,e.fillStyle=Math.floor(t)%2?"#888":"#555",e.fillText("no programme yet",It/2,Wt*.92),e.textAlign="left"}}function md(s,t){const e=fd[s.id]??pd;return new e(s,t)}const ir={dreams:{angle:0,r:4.9,y:.5,style:"tv",screenW:2,channel:1},transmissions:{angle:-27,r:4.5,y:.34,style:"beige",screenW:1.22,stand:!0,channel:2},chronicle:{angle:27,r:4.5,y:0,style:"black",screenW:1.3,channel:3},"dreams-api":{angle:27,r:4.5,y:0,style:"grey",screenW:.86,on:"chronicle",channel:4},apeiron:{angle:-54,r:4.2,y:0,style:"black",screenW:1.15,channel:5},irc:{angle:-54,r:4.2,y:0,style:"beige",screenW:.95,on:"apeiron",channel:6},syrinx:{angle:54,r:4.2,y:.28,style:"grey",screenW:1.08,channel:7},dream_gen:{angle:-20,r:7,y:4.35,style:"grey",screenW:1.02,hang:!0,feeds:"dreams",channel:8},parlor:{angle:20,r:6.5,y:3.6,style:"beige",screenW:1.1,hang:!0,channel:9}};function gd(s,t){const e=ir[s];if(e)return e;const n=Math.floor(t/2)+1;return{angle:(t%2?1:-1)*(68+n*10),r:5.4,y:0,style:"grey",screenW:1,channel:12+t}}/** +var Ny=Object.defineProperty;var Uy=(Qn,Bn,Xi)=>Bn in Qn?Ny(Qn,Bn,{enumerable:!0,configurable:!0,writable:!0,value:Xi}):Qn[Bn]=Xi;var R=(Qn,Bn,Xi)=>Uy(Qn,typeof Bn!="symbol"?Bn+"":Bn,Xi);(function(){"use strict";var _d;const Qn="afterlife-universe-v1";function Bn(s,t){const e=atob(s),n=new Int32Array(t);let i=0;const r=()=>{let a=0,l=1;for(;;){if(i>=e.length)throw new Error("afterlife: truncated save");const c=e.charCodeAt(i++);if(a+=(c&127)*l,c<128)return a;l*=128}};let o=-1;for(;i=t)throw new Error("afterlife: save does not fit its own world");n[o]=a%2?-(a+1)/2:a/2}return n}function Xi(s=globalThis.localStorage){try{const t=s==null?void 0:s.getItem(Qn);if(!t)return null;const e=JSON.parse(t);if(e.v!==1||!Number.isInteger(e.h)||!Number.isInteger(e.w)||typeof e.cells!="string")return null;const n=e.h,i=e.w;if(n<=0||i<=0||n*i>16e6)return null;const r=Number(e.generation);return!Number.isFinite(r)||r<0?null:{h:n,w:i,age:Bn(e.cells,n*i),generation:r,totalInjections:Number(e.totalInjections)||0,bornAt:Number(e.bornAt)||Date.now(),savedAt:Number(e.savedAt)||Date.now()}}catch(t){return console.warn("afterlife: could not load the universe, starting fresh",t),null}}function Rd(){const s=document.getElementById("oikos-data");try{const t=JSON.parse((s==null?void 0:s.textContent)??"{}");return{sites:t.sites??[],files:t.files??[],posts:t.posts??[]}}catch{return{sites:[],files:[],posts:[]}}}const yc=s=>/^https?:\/\//.test(s);class qi{constructor(t){R(this,"listeners",new Set);this.value=t}set(t){this.value=t;for(const e of this.listeners)e(t)}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}}function Mc(){try{const s=localStorage.getItem("syrinx-creature-v1");if(!s)return null;const t=JSON.parse(s);if(typeof t.name!="string"||typeof t.bornAt!="number"||!t.state)return null;const e=Array.isArray(t.state.nodes)?t.state.nodes:[],n=Array.isArray(t.state.edges)?t.state.edges:[];return e.length?{name:t.name,bornAt:t.bornAt,lifetime:typeof t.state.lifetime=="number"?t.state.lifetime:0,nodes:e.map(i=>({id:i.id,x:i.x,y:i.y,z:i.z??500,age:i.age??0})),edges:n.map(i=>({a:i.a,b:i.b,age:i.age??0}))}:null}catch{return null}}function bc(){try{const s=localStorage.getItem(Qn);if(!s)return null;const t=JSON.parse(s);return typeof t.generation!="number"||typeof t.savedAt!="number"?null:{generation:t.generation,bornAt:typeof t.bornAt=="number"?t.bornAt:t.savedAt,savedAt:t.savedAt}}catch{return null}}function Sc(s){return new Promise((t,e)=>{const n=new Image;n.decoding="async",n.onload=()=>t(n),n.onerror=e,n.src=s})}async function mr(s){try{const t=await fetch(s,{headers:{Accept:"application/json"}});return t.ok?await t.json():null}catch{return null}}class Pd{constructor(){R(this,"dreams",new qi({known:!1,awake:!1,frame:0,fps:0,viewers:0,raw:null}));R(this,"chronicle",new qi({known:!1,thumb:null,thumbAt:0,prompt:"",template:"",eras:[],eraCount:0,strata:[]}));R(this,"irc",new qi({connected:!1,lines:[],collapse:null,fragments:0,version:0}));R(this,"creature",new qi(Mc()));R(this,"universe",new qi(bc()));R(this,"apeiron",new qi(null));R(this,"timers",[]);R(this,"ws",null);R(this,"wsBackoff",2e3);R(this,"wsTimer",0);R(this,"running",!1)}start(){if(this.running)return;this.running=!0;const t=(e,n)=>{e(),this.timers.push(window.setInterval(e,n))};t(()=>void this.pollDreams(),2e4),t(()=>void this.pollChronicle(),12e4),t(()=>this.creature.set(Mc()),15e3),t(()=>{var n;const e=bc();(e==null?void 0:e.savedAt)!==((n=this.universe.value)==null?void 0:n.savedAt)&&this.universe.set(e)},15e3),this.openIrc(),this.apeiron.value||this.loadApeiron()}stop(){this.running=!1;for(const t of this.timers)clearInterval(t);this.timers=[],clearTimeout(this.wsTimer),this.ws&&(this.ws.onclose=null,this.ws.close(),this.ws=null),this.irc.set({...this.irc.value,connected:!1,version:this.irc.value.version+1})}async pollDreams(){var e,n,i,r,o;const t=await mr("/api/dreams/status");if(!t){this.dreams.set({...this.dreams.value,known:!1});return}this.dreams.set({known:!0,awake:!!((e=t.gpu)!=null&&e.active),frame:((n=t.generation)==null?void 0:n.current_frame)??((i=t.generation)==null?void 0:i.frame_count)??0,fps:((r=t.generation)==null?void 0:r.fps)??0,viewers:((o=t.viewers)==null?void 0:o.websocket_count)??0,raw:t})}async pollChronicle(){var o,a,l,c;const t=await mr("/api/dreams/chronicle/timeline?hours=3");if(!t)return;const e=this.chronicle.value;let n=e.thumb;(o=t.live)!=null&&o.thumb&&t.live.thumb!==(n==null?void 0:n.dataset.src)&&(n=await Sc(t.live.thumb).catch(()=>e.thumb),n&&(n.dataset.src=t.live.thumb));const i=(t.tiles??[]).slice(-3),r=(await Promise.all(i.map(u=>Sc(u.url).catch(()=>null)))).filter(u=>!!u);this.chronicle.set({known:!0,thumb:n,thumbAt:((a=t.live)==null?void 0:a.t)??0,prompt:((l=t.live)==null?void 0:l.prompt)??"",template:((c=t.live)==null?void 0:c.template)??"",eras:(t.eras??[]).map(u=>({title:u.title??"",t0:u.t0,t1:u.t1,open:!!u.open,kf:u.kf??0})),eraCount:t.era_count??0,strata:r.length?r:e.strata})}openIrc(){const t=location.protocol==="https:"?"wss":"ws";let e;try{e=new WebSocket(`${t}://${location.host}/ws/irc`)}catch{return}this.ws=e;const n=i=>{const r=this.irc.value;this.irc.set({...r,...i,version:r.version+1})};e.onopen=()=>{this.wsBackoff=2e3,n({connected:!0,collapse:null})},e.onmessage=i=>{let r;try{r=JSON.parse(String(i.data))}catch{return}if(r.type==="message"&&r.data){const o=r.data,a=o.meta??{},l={nick:String(o.nick??""),content:String(o.content??""),type:String(o.type??"message"),stamp:String(o.timestamp??""),at:performance.now()};if(typeof o.at=="number"&&(l.wallAt=o.at),typeof a.target=="string"&&(l.target=a.target),typeof a.reason=="string"&&(l.reason=a.reason),r.replay&&this.irc.value.lines.some(c=>c.stamp===l.stamp&&c.nick===l.nick&&c.content===l.content))return;n({lines:[...this.irc.value.lines,l].slice(-60)})}else r.type==="collapse_start"?n({collapse:{type:r.collapseType??"collapse",at:performance.now()}}):r.type==="fragment_end"&&(r.replay?n({collapse:null}):n({collapse:null,lines:this.irc.value.lines.slice(-6),fragments:this.irc.value.fragments+1}))},e.onclose=()=>{n({connected:!1}),this.running&&(this.wsTimer=window.setTimeout(()=>this.openIrc(),this.wsBackoff),this.wsBackoff=Math.min(this.wsBackoff*2,6e4))}}async loadApeiron(){const[t,e]=await Promise.all([mr("/static/apeiron/data/templates.json"),mr("/static/apeiron/data/components.json")]);t&&e&&this.apeiron.set({templates:t,components:e})}}const wc=[17,19,21,57,93,165,163,204,209,214,220,231],Ec=[236,234],gr=Ec.length,Ei=6,Ld=[17,18,19,20,21,57,56,93,129,165,164,163,198,204,203,209,208,214,220,229,231],xr=s=>Ld[s]??0,Dd=Array.from({length:Ei},(s,t)=>[xr(Math.floor((185+t)/21)),xr((185+t)%21)]),Id=Array.from({length:Ei*Ei},(s,t)=>[xr(Math.floor((191+t)/21)),xr((191+t)%21)]),Nd=.98,Tc=4,Ud=Math.fround(Nd**Tc),Bs="▁▂▃▄▅▆▇█",ti=-2,Yi=2,Fd={[-2]:"0.25x",[-1]:"0.50x",0:" 1.0x",1:" 2.0x",2:" 4.0x"},Ki={glider:[[0,1],[1,2],[2,0],[2,1],[2,2]],lwss:[[0,1],[0,4],[1,0],[2,0],[2,4],[3,0],[3,1],[3,2],[3,3]],hwss:[[0,3],[0,4],[1,1],[1,6],[2,0],[3,0],[3,6],[4,0],[4,1],[4,2],[4,3],[4,4],[4,5]],r_pentomino:[[0,1],[0,2],[1,0],[1,1],[2,1]],acorn:[[0,1],[1,3],[2,0],[2,1],[2,4],[2,5],[2,6]],diehard:[[0,6],[1,0],[1,1],[2,1],[2,5],[2,6],[2,7]],pi_heptomino:[[0,0],[0,1],[0,2],[1,1],[2,1],[3,0],[3,2]],b_heptomino:[[0,1],[1,0],[1,2],[1,3],[2,0],[2,1],[3,1]],gosper_gun:[[0,24],[1,22],[1,24],[2,12],[2,13],[2,20],[2,21],[2,34],[2,35],[3,11],[3,15],[3,20],[3,21],[3,34],[3,35],[4,0],[4,1],[4,10],[4,16],[4,20],[4,21],[5,0],[5,1],[5,10],[5,14],[5,16],[5,17],[5,22],[5,24],[6,10],[6,16],[6,24],[7,11],[7,15],[8,12],[8,13]],pulsar:[[0,2],[0,3],[0,4],[0,8],[0,9],[0,10],[2,0],[2,5],[2,7],[2,12],[3,0],[3,5],[3,7],[3,12],[4,0],[4,5],[4,7],[4,12],[5,2],[5,3],[5,4],[5,8],[5,9],[5,10],[7,2],[7,3],[7,4],[7,8],[7,9],[7,10],[8,0],[8,5],[8,7],[8,12],[9,0],[9,5],[9,7],[9,12],[10,0],[10,5],[10,7],[10,12],[12,2],[12,3],[12,4],[12,8],[12,9],[12,10]],pentadecathlon:[[0,1],[1,1],[2,0],[2,2],[3,1],[4,1],[5,1],[6,1],[7,0],[7,2],[8,1],[9,1]]},Ro=["glider","lwss","hwss"],Ac=["r_pentomino","acorn","diehard","pi_heptomino","b_heptomino"],Cc=["pulsar","pentadecathlon"],Od=[[1,1],[1,-1],[-1,-1],[-1,1]];function Po(s){const t=new Map;for(const[e,n]of s)for(const[i,r]of[[e,n],[e,-n],[-e,n],[-e,-n]])t.set(`${i},${r}`,[i,r]);return[...t.values()]}const kd=[Po([[0,1],[0,2],[0,3],[1,0],[1,4],[2,0],[2,5],[3,0],[3,5],[4,1],[4,5],[5,2],[5,3],[5,4]]),Po([[0,1],[0,2],[0,3],[0,4],[1,0],[2,0],[3,0],[4,0],[2,2],[3,3]]),Po([[0,3],[0,4],[1,2],[1,5],[2,1],[2,6],[3,0],[3,7],[4,0],[4,7],[5,1],[5,6],[6,2],[6,5],[7,3],[7,4]])],Bd={block:[[[0,0],[0,1],[1,0],[1,1]],1],beehive:[[[0,1],[0,2],[1,0],[1,3],[2,1],[2,2]],1],loaf:[[[0,1],[0,2],[1,0],[1,3],[2,1],[2,3],[3,2]],1],boat:[[[0,0],[0,1],[1,0],[1,2],[2,1]],1],tub:[[[0,1],[1,0],[1,2],[2,1]],1],ship:[[[0,0],[0,1],[1,0],[1,2],[2,1],[2,2]],1],pond:[[[0,1],[0,2],[1,0],[1,3],[2,0],[2,3],[3,1],[3,2]],1],blinker:[[[0,0],[0,1],[0,2]],2],toad:[[[0,1],[0,2],[0,3],[1,0],[1,1],[1,2]],2],beacon:[[[0,0],[0,1],[1,0],[2,3],[3,2],[3,3]],2],glider:[Ki.glider??[],4],lwss:[Ki.lwss??[],4],hwss:[Ki.hwss??[],4],pulsar:[Ki.pulsar??[],3],pentadecathlon:[Ki.pentadecathlon??[],15]},zd=60,Rc=20;function Pc(s){let t=null;for(let e=0;e<8;e++){const n=e>=4,i=n?s.w:s.h,r=n?s.h:s.w;let o=`${i}x${r}:`;for(let a=0;au))+1,r=Math.max(...e.map(([,u])=>u))+1,o=Math.max(i,r)+2*(n+4);let a=new Uint8Array(o*o);const l=Math.floor((o-i)/2),c=Math.floor((o-r)/2);for(const[u,h]of e)a[(l+u)*o+c+h]=1;for(let u=0;ui&&(i=u),ho&&(o=h));if(i<0)return null;const a=i-n+1,l=o-r+1,c=new Uint8Array(a*l);for(let u=0;u=t)continue;const p=2-Math.abs(d),x=Math.max(0,h-p),m=Math.min(e-1,h+p);i.fill(1,f*e+x,f*e+m+1)}const r=new Int32Array(t*e),o=[],a=[];for(let u=0;u400)return null;const d={y0:t,y1:-1,x0:e,x1:-1};for(r[u]=h,a.push(u);a.length;){const f=a.pop()??0,p=Math.floor(f/e),x=f-p*e;pd.y1&&(d.y1=p),xd.x1&&(d.x1=x);for(let m=-1;m<=1;m++){const g=p+m;if(!(g<0||g>=t))for(let b=-1;b<=1;b++){const E=x+b;if(E<0||E>=e)continue;const y=g*e+E;i[y]&&!r[y]&&(r[y]=h,a.push(y))}}}o.push(d)}if(o.length===0)return null;const l=new Map,c=[];return o.forEach((u,h)=>{const d=h+1,f=u.y1-u.y0+1,p=u.x1-u.x0+1;if(f>Rc+4||p>Rc+4)return;const x=new Uint8Array(f*p);let m=0,g=0,b=0;for(let M=0;Mzd)return;const E=Lc(x,f,p),y=E?n.get(Pc(E)):void 0;y!==void 0&&(l.set(y,(l.get(y)??0)+1),c.length<48&&c.push([y,u.y0+Math.floor(g/m),u.x0+Math.floor(b/m)]))}),{counts:l,sites:c}}const Do=["cells pondering existence","entropy is just a suggestion","order from chaos, chaos from order","the cosmos breathes","finding signal in noise","patterns all the way down","life, uh, finds a way","on the edge of chaos","complexity, emerging","dancing at the phase boundary","stillness is just slow motion","every cell a universe","the substrate computes","from nothing, everything","infinite in all directions","what the dead cells dream","the glider knows the way","automata, contemplating","structure wants to happen","a cosmos in a terminal","the math dreams itself","somewhere, a glider remembers","what is a pattern but frozen time","the void is patient","meaning is optional; beauty is not","computation as meditation","the rules are simple; the consequences infinite","watching the watchers watch","no cell is an island","the ghost of configurations past","asymmetry seeks symmetry seeks asymmetry","this too shall iterate","the universe has no pause button","except when it does","what would Conway think","oscillators keep time for no one","the glider gun knows not what it creates","boundaries are suggestions","death is just a state transition","somewhere in here, a proof of universality","the grid forgets nothing","a thought experiment that thinks back","topology has opinions","the neighborhood watches","not alive, not dead — computing","four rules, one universe","each frame a theorem","proof by existence","the only constant is the ruleset","somewhere between on and off, meaning","the dead outnumber the living, as always","conway's little infinities","the simulation doesn't know it's beautiful","27 neighbors ago, this was empty","elegance is compression","the grid is the message","a love letter to discrete math","listen — the cells are whispering","we are all gliders, briefly"],Vd={booming:["runaway growth","the bloom unfolds","life begets life begets life","exponential daydreams","more is different","the bloom cannot be stopped","abundance as instability","growing into the unknown","every birth a cascade","the simulation smiles","lebensraum","mitosis dreams","the substrate strains","a spring that won't stop springing","cells all the way to the horizon","the algorithm is generous today","more, more, more","genesis on fast-forward"],declining:["entropy collects its due","the long exhale","even stars go dark","returning to the void","graceful unwinding","the great filter, in miniature","less is not nothing","the long forgetting","what rises must","simplicity returns","the cells remember fullness","autumn in the grid","graceful subtraction","the tide goes out","a slow dissolve","the universe exhales","dimming, not vanishing","the population curve bends earthward"],cycle:["deja vu, deja vu, deja vu","stuck in a loop","the eternal return","ouroboros","time is a flat circle","we have been here before","the loop remembers itself","stability through repetition","a prayer, repeating","the wheel turns","same as it ever was","history rhymes","the attractor holds","a fixed point in phase space","nietzsche was right about this part","the universe stutters beautifully","clockwork, but organic","breathing in, breathing out"],stagnant:["the hush before the storm","equilibrium is boring","waiting for a perturbation","still waters","the universe holds its breath","the calm before","potential energy","stillness is also motion","the system waits","one perturbation away","dormant, not dead","crystallized","the peace of equilibrium","a held breath","the grid meditates","tension, frozen","the quiet hum of nothing happening","patience is also a computation"],sparse:["the last few embers","clinging to existence","from little things, big things grow","seeds in the dark","quiet, but not empty","lonely structures","the survivors","space between stars","minimalism, enforced","room to breathe","the few, the proud","embers","a whisper, not a shout","the geometry of loneliness","each cell precious now","a constellation, if you squint","small, but not nothing"],dense:["teeming","a city that never sleeps","standing room only","too many neighbours","the crowd murmurs","no room to think","the crush of neighbors","overpopulation is self-correcting","too much life","suffocating in company","the grid groans","rush hour","sardines","every cell has an opinion","a metropolis, thrumming","the carrying capacity protests","elbow room is a luxury"],injection:["a gift from beyond the edge","new visitors","reinforcements arrive","the cosmos provides","seeded by unseen hands","deus ex machina","a nudge from outside","fresh blood","the invisible hand places","salvation arrives","new variables enter","the cosmos intervenes","help from beyond the viewport","strangers in a strange land","the petri dish gets a refill","immigrants, welcome"],milestone:["another thousand turns of the wheel","the odometer clicks over","still here, still going","persistence is its own reward","ten thousand steps","the long now","time is a flat circle, but longer","we persist","generations beyond counting","deep in the run","the odometer means nothing to the cells","and yet, it continues","older than some civilizations","the marathon nobody entered","a digit rolls over; the grid doesn't notice","epochal"],haunted:["the dead outnumber the living, and glow","every path ever walked, still visible","the void remembers being alive","phase-contrast photography of the past","nothing is ever really deleted","the grid forgets nothing — literally, now","a bug so beautiful it became a feature","the ghosts have synchronized their breathing","somewhere between pair 463 and 504","resurrection as a rendering artifact","the afterlife was here all along","history, strobing","every empty cell, a metronome","the universe develops like a photograph","magenta is the color of memory"]},Wd={glider:["a glider, going somewhere","lightspeed, quartered — a glider","a glider carries the news","diagonal traffic"],lwss:["a lightweight spaceship, outbound","small craft advisory"],hwss:["a heavy spaceship shoulders past","heavy freight on the grid"],pulsar:["a pulsar, keeping time for no one","the pulsar breathes in threes"],pentadecathlon:["fifteen beats to the bar","a pentadecathlon runs its laps"],blinker:["the blinkers keep the beat","metronomes, disagreeing"],block:["blocks: the simplest memory","still life with squares"],beehive:["the bees are home","a beehive, sealed"],loaf:["bread, uneaten","a loaf, going stale beautifully"],boat:["a boat with nowhere to sail"],tub:["a tub, holding nothing"],ship:["a ship without a sea"],pond:["a pond, perfectly still"],toad:["a toad, breathing"],beacon:["the beacon still signals","someone left the light on"]},Io={pulsar:100,pentadecathlon:100,hwss:90,lwss:80,glider:40,beacon:30,toad:28,pond:24,ship:20,loaf:16,beehive:12,boat:12,tub:12,blinker:8,block:6},$d={blinker:3,block:3},Dc=[[0,"genesis"],[500,"primordial"],[2e3,"emergence"],[1e4,"expansion"],[5e4,"flourishing"],[15e4,"deep time"],[5e5,"eon"],[1e6,"eternity"]],En=s=>[...s].length;class Ic{constructor(){R(this,"messages",[]);R(this,"scrollSpeed",.4);R(this,"spawnCooldown",0);R(this,"minGap",12);R(this,"ambientInterval",60);R(this,"moodInterval",50);R(this,"ambientIdx",Math.floor(Math.random()*Do.length));R(this,"lastMood","");R(this,"pendingSpecial","")}queueSpecial(t){this.pendingSpecial=t}tick(t,e,n){if(t<10)return;for(const a of this.messages)a.x-=this.scrollSpeed;if(this.messages=this.messages.filter(a=>a.x+En(a.text)>0),this.pendingSpecial&&this.canSpawn(t)){this.messages.push({text:this.pendingSpecial,x:t}),this.pendingSpecial="",this.spawnCooldown=Math.max(this.spawnCooldown,this.moodInterval);return}const i=e?Vd[e]:void 0;if(i&&e!==this.lastMood&&(this.spawnCooldown=Math.min(this.spawnCooldown,15)),this.spawnCooldown=Math.max(0,this.spawnCooldown-1),this.spawnCooldown>0||!this.canSpawn(t))return;let r,o;i?(r=i[Math.floor(n/180)%i.length]??"",o=this.moodInterval):(r=Do[this.ambientIdx]??"",this.ambientIdx=(this.ambientIdx+1)%Do.length,o=this.ambientInterval),this.messages.push({text:r,x:t}),this.spawnCooldown=o,this.lastMood=e}canSpawn(t){if(!this.messages.length)return!0;let e=-1/0;for(const n of this.messages)e=Math.max(e,n.x+En(n.text));return es+Math.floor(Math.random()*(t-s+1)),zn=s=>s[Math.floor(Math.random()*s.length)],at=(s,t)=>Math.floor(s/t),rn=(s,t,e)=>Math.max(t,Math.min(s,e)),Xd=Math.fround(.85),qd=Math.fround(.15);function ei(s,t){const e=s.length,n=t/100*(e-1),i=Math.floor(n),r=Math.min(e-1,i+1),o=s[i]??0,a=s[r]??0;return Math.trunc(o+(a-o)*(n-i))}class Yd{constructor(t,e,n=!0){R(this,"viewH");R(this,"viewW");R(this,"worldH");R(this,"worldW");R(this,"grid");R(this,"age");R(this,"ageSmooth");R(this,"activity");R(this,"nextRow");R(this,"colSum");R(this,"camY");R(this,"camX");R(this,"autoCam",!0);R(this,"zoomLevel",0);R(this,"zoomCooldown",0);R(this,"generation",0);R(this,"paused",!1);R(this,"delay",50);R(this,"popHistory",[]);R(this,"hashHistory",[]);R(this,"cachedPop",0);R(this,"spread",0);R(this,"popFloor",0);R(this,"cyclePeriod",0);R(this,"lastEvent","");R(this,"lastEventGen",0);R(this,"totalInjections",0);R(this,"ticker",new Ic);R(this,"autoFocusMode",!1);R(this,"autoFocusFrame",0);R(this,"dispGridCache",null);R(this,"dispAgeCache",null);R(this,"cachedMood","");R(this,"cachedMoodGen",-1);R(this,"stepBbox",null);R(this,"haunted",!1);R(this,"lastCensus",new Map);R(this,"lastCensusSites",[]);R(this,"sightingGen",new Map);R(this,"sightingCount",new Map);R(this,"lastSightingGen",-1e9);R(this,"dramaUntil",0);R(this,"actBaseline",0);R(this,"dilation",1);this.viewH=t*2,this.viewW=e,this.worldH=Math.max(this.viewH*5,400),this.worldW=Math.max(this.viewW*5,800);const i=this.worldH*this.worldW;this.grid=new Uint8Array(i),this.age=new Int32Array(i),this.ageSmooth=new Float32Array(i),this.activity=new Float32Array(i),this.nextRow=new Uint8Array(this.worldW),this.colSum=new Uint8Array(this.worldW),this.camY=at(this.worldH-this.viewH,2),this.camX=at(this.worldW-this.viewW,2),n&&this.seedInitial()}seedInitial(){const t=at(this.worldH,2),e=at(this.worldW,2),n=this.viewH,i=this.viewW;for(const a of Ac)for(let l=0;l<2;l++)this.place(a,t+xe(-at(n,3),at(n,3)),e+xe(-at(i,3),at(i,3)));for(let a=0;a<2;a++)this.place("gosper_gun",t+xe(-at(n,4),at(n,4)),e+xe(-at(i,4),at(i,4)));for(let a=0;a<20;a++){const l=rn(t+xe(-n,n),10,this.worldH-10),c=rn(e+xe(-i,i),10,this.worldW-10);this.place(zn(Ro),l,c)}for(let a=0;a<4;a++)this.place(zn(Cc),t+xe(-at(n,3),at(n,3)),e+xe(-at(i,3),at(i,3)));const r=t-at(n,2),o=e-at(i,2);for(let a=0;a=0&&c=0&&ul&&(l=v+1))}const c=o>0;let u=!1;c&&r-2>=0&&o+2<=t&&a-2>=0&&l+2<=e&&(r-=2,o+=2,a-=2,l+=2,u=(o-r)*(l-a)<=at(t*e,2)),u=u&&!this.haunted,this.stepBbox=c&&u?[r,o,a,l]:null,u||(r=0,o=t,a=0,l=e);const h=this.ageSmooth;for(let M=0;M0?ht=-1:(m||ot<0)&&ot>x?ht=ot-1:ht=0,i[B]=ht,h[B]=(h[B]??0)+Math.fround(Math.fround(ht)*qd);const Gt=nt||rt?1:0;n[B]=Gt,E+=Gt}}if(this.generation+=1,this.generation%Tc===0)for(let M=0;M500&&this.popHistory.shift(),this.hashHistory.push(this.viewportHash()),this.hashHistory.length>60&&this.hashHistory.shift();const y=this.ensureLife(E);return this.updateCamera(),y}viewportHash(){const[t,e]=this.clampCam();let n=2166136261,i=16777619;for(let r=0;r>>0)*2097152+(i>>>0&2097151)}ensureLife(t){const e=this.viewH*this.viewW,n=at(e,40),i=this.popHistory,r=i.length;if(r>=100){let h=0;for(let d=r-100;d=150){let h=i[r-1]??0,d=h;for(let f=r-150;fd&&(d=p)}this.spread=d-h}const o=r>=150&&this.spread=4){const h=a[l-1];for(let d=1;d0&&!c){const h=Math.random()<.65?this.injectProvoke():"";h?u=`inject:provoke(cycle=${this.cyclePeriod},${h})`:(u=`inject:heavy(cycle=${this.cyclePeriod})`,this.inject("heavy"))}else o&&!c?Math.random()<.7&&this.injectCollide()?u="inject:collide(stagnant)":(u="inject:medium(stagnant)",this.inject("medium")):this.generation%5e3===0&&this.generation>0?(u="inject:garden",this.injectGarden()):this.generation%300===0&&this.generation>0&&(u="inject:edge",this.injectFromEdge(),this.injectFromEdge());return u&&(this.lastEvent=u,this.lastEventGen=this.generation,this.totalInjections+=1),u}inject(t="medium"){const e={massive:8,heavy:5,medium:3}[t];for(let n=0;n=0&&l=0&&c(h[g]??0)-(h[b]??0)),p=zn(f.slice(0,d)),x=at(p,u),m=p%u;return[o+x*l+at(l,2),a+m*l+at(l,2)]}aimGlider(t,e,n,i){const[r,o]=Od[i]??[1,1],a=t-r*n,l=e-o*n,[c,u]=this.clampCam();if(!(c+2<=a&&a(Io[n[0]]??0)-(Io[e[0]]??0));for(const[e,n,i]of t.slice(0,6)){const r=xe(35,60),o=[0,1,2,3];for(let a=o.length-1;a>0;a--){const l=Math.floor(Math.random()*(a+1));[o[a],o[l]]=[o[l]??0,o[a]??0]}for(const a of o)if(this.aimGlider(n,i,r,a))return this.dramaUntil=this.generation+r*4+150,this.ticker.queueSpecial("the cosmos takes aim"),e}return""}injectCollide(){let[t,e]=this.findQuietSpot();const[n,i]=this.clampCam();for(let r=0;r<6;r++){const o=xe(16,34),a=n+o+3,l=n+this.viewH-o-6,c=i+o+3,u=i+this.viewW-o-6;if(a>=l||c>=u)continue;t=Math.max(a,Math.min(t,l)),e=Math.max(c,Math.min(e,u));const h=xe(0,3),d=xe(-3,3),f=xe(-3,3);if(!this.aimGlider(t,e,o,h))continue;const p=(h+zn([1,3]))%4,x=this.aimGlider(t+d,e+f,o,p);return this.dramaUntil=this.generation+o*4+150,this.ticker.queueSpecial(x?"two gliders, one appointment":"a lone glider, sent into the dark"),!0}return!1}calculateTargetZoom(){const[t,e,n,i]=this.stepBbox??[0,this.worldH,0,this.worldW],r=this.worldW;let o=0;for(let b=t;b=1&&y<=10&&++o>=5)break}const a=o>=5,l=[],c=[];for(let b=t;b=1&&(this.age[y]??0)<=10:this.grid[y]!==0)&&(l.push(b),c.push(E))}if(l.length<2)return this.zoomLevel;const u=Int32Array.from(c).sort(),h=ei(l,15),d=ei(l,85),f=ei(u,15),p=ei(u,85),x=Math.max(4,d-h+1),m=Math.max(4,p-f+1);let g=ti;for(let b=Yi;b>=ti;b--){const E=2**b;if(x<=this.viewH/E*.5&&m<=this.viewW/E*.5){g=b;break}}return rn(g,ti,Yi)}updateCamera(){if(!this.autoCam)return;const t=30,e=Math.max(0,this.camY-t),n=Math.min(this.worldH,this.camY+this.viewH+t),i=Math.max(0,this.camX-t),r=Math.min(this.worldW,this.camX+this.viewW+t),o=this.worldW;let a=0,l=0,c=0;for(let f=e;f25){this.steer(Math.trunc(l/a)+e,Math.trunc(c/a)+i),this.advanceAutoZoom();return}let u=0,h=0,d=0;for(let f=e;f0&&this.steer(Math.trunc(h/u)+e,Math.trunc(d/u)+i),this.advanceAutoZoom()}steer(t,e){const n=rn(t-at(this.viewH,2),0,this.worldH-this.viewH),i=rn(e-at(this.viewW,2),0,this.worldW-this.viewW);this.camY=Math.trunc(this.camY+(n-this.camY)*.04),this.camX=Math.trunc(this.camX+(i-this.camX)*.04)}advanceAutoZoom(){if(this.zoomCooldown=Math.max(0,this.zoomCooldown-1),this.zoomCooldown!==0||this.generation%4!==0)return;const t=this.calculateTargetZoom();if(t>this.zoomLevel&&this.zoomLevelti){const e=this.zoomLevel-1,n=e>=0?1:1<<-e;this.viewH*n<=this.worldH&&this.viewW*n<=this.worldW&&(this.zoomLevel=e,this.zoomCooldown=45)}}clampCam(){return[rn(this.camY,0,this.worldH-this.viewH),rn(this.camX,0,this.worldW-this.viewW)]}viewCenter(){const[t,e]=this.clampCam();return[t+at(this.viewH,2),e+at(this.viewW,2)]}rawViewGrid(){const[t,e]=this.clampCam(),n=new Uint8Array(this.viewH*this.viewW);for(let i=0;ithis.worldH||u>this.worldW)return null;const h=Math.max(0,Math.min(t-at(c,2),this.worldH-c)),d=Math.max(0,Math.min(e-at(u,2),this.worldW-u));return[h,d,c,u,l,!1]}const n=1<Math.trunc(t[p]??0),i=this.zoomLevel===0?null:this.cover();if(!i){const[p,x]=this.clampCam(),m=new Int32Array(this.viewH*this.viewW);for(let g=0;g(g[T]??0)&&(g[T]=v);const L=v!==0?v:m;L>(b[T]??0)&&(b[T]=L)}}const E=new Int32Array(p*x);for(let y=0;y0?M:w>m?w:0}return{h:p,w:x,data:E}}const h=Math.min(a*c,this.viewH),d=Math.min(l*c,this.viewW),f=new Int32Array(h*d);for(let p=0;pti){const t=this.zoomLevel-1,e=t>=0?1:1<<-t;(t>=0||this.viewH*e<=this.worldH&&this.viewW*e<=this.worldW)&&(this.zoomLevel=t)}this.invalidate()}autoFocus(){const t=this.worldH,e=this.worldW;let n=0,i=0;for(let B=0;B=1&&z<=10&&n++,this.grid[B]&&i++}const r=n>=5;if((r?n:i)===0)return;const o=B=>{const z=this.age[B]??0;return r?z>=1&&z<=10:this.grid[B]!==0},a=16,l=at(t,a),c=at(e,a);if(l<1||c<1)return;const u=new Float64Array(l*c);for(let B=0;B=0&&ot=0&&hth&&(h=Z/9,d=B*c+z)}const f=at(d,c)*a+at(a,2),p=d%c*a+at(a,2),x=a*2,m=Math.max(0,f-x),g=Math.min(t,f+x),b=Math.max(0,p-x),E=Math.min(e,p+x),y=[],M=[];for(let B=m;B=ti;B--){const z=2**B;if(D<=this.viewH/z*.6&&U<=this.viewW/z*.6){N=B;break}}this.zoomLevel=rn(N,ti,Yi),this.camY=rn(Y-at(this.viewH,2),0,this.worldH-this.viewH),this.camX=rn(K-at(this.viewW,2),0,this.worldW-this.viewW),this.autoCam=!1,this.invalidate()}pan(t,e){this.autoCam=!1;const n=2**-this.zoomLevel,i=t!==0?Math.max(1,Math.trunc(Math.abs(t)*n))*Math.sign(t):0,r=e!==0?Math.max(1,Math.trunc(Math.abs(e)*n))*Math.sign(e):0;this.camY=rn(this.camY+i,0,this.worldH-this.viewH),this.camX=rn(this.camX+r,0,this.worldW-this.viewW),this.invalidate()}home(){this.autoCam=!0,this.zoomLevel=0,this.invalidate()}clear(){this.grid.fill(0),this.age.fill(0),this.ageSmooth.fill(0),this.generation=0,this.popHistory=[],this.hashHistory=[],this.invalidate()}takeCensus(){const t=this.rawViewGrid();let e=!1;for(let l=0;l[h,c+d,u+f]),n=l.counts}}catch{}if(this.lastCensus=n,!n.size||this.generation-this.lastSightingGen<600)return;let i="",r=0;for(const[l,c]of n){if(c<($d[l]??1)||this.generation-(this.sightingGen.get(l)??-1e9)<1800)continue;const u=Io[l]??0;u>r&&(r=u,i=l)}if(!i)return;const o=Wd[i]??[],a=this.sightingCount.get(i)??0;this.sightingCount.set(i,a+1),this.ticker.queueSpecial(o[a%o.length]??i),this.sightingGen.set(i,this.generation),this.lastSightingGen=this.generation}snapshot(){return{h:this.worldH,w:this.worldW,age:this.age.slice(),generation:this.generation,totalInjections:this.totalInjections}}adopt(t){const e=Math.min(this.worldH,t.h),n=Math.min(this.worldW,t.w),i=at(t.h-e,2),r=at(t.w-n,2),o=at(this.worldH-e,2),a=at(this.worldW-n,2);this.grid.fill(0),this.age.fill(0);let l=0;for(let c=0;c0&&(this.grid[d]=1,l++)}this.generation=Math.max(0,Math.trunc(t.generation)),this.totalInjections=Math.max(0,Math.trunc(t.totalInjections)),this.ageSmooth.fill(0),this.activity.fill(0),this.hashHistory=[],this.cachedPop=l,this.popHistory=[l],this.stepBbox=null,this.dramaUntil=0,this.invalidate()}toggleHaunted(){if(this.haunted=!this.haunted,this.invalidate(),!this.haunted)for(let t=0;t=this.worldH||e<0||e>=this.worldW)return;const i=t*this.worldW+e;this.grid[i]=n,this.age[i]=n?1:0,this.invalidate()}tickTicker(t){this.ticker.tick(t,this.detectMood(),this.generation)}detectMood(){return this.cachedMoodGen===this.generation?this.cachedMood:(this.cachedMood=this.computeMood(),this.cachedMoodGen=this.generation,this.cachedMood)}computeMood(){if(this.haunted)return"haunted";if(this.lastEvent&&this.generation-this.lastEventGen<90)return"injection";if(this.cyclePeriod>0)return"cycle";if(this.generation>=1e4&&this.generation%1e4<120)return"milestone";const t=this.popHistory,e=t.length;if(e>=30){let r=0,o=0;for(let l=e-30;l1.15)return"booming";if(a<.85)return"declining"}const n=e?t[e-1]??0:0;return n/Math.max(this.viewH*this.viewW,1)>.15?"dense":n0?"sparse":this.spread=150?"stagnant":""}epoch(){var e;let t=((e=Dc[0])==null?void 0:e[1])??"genesis";for(const[n,i]of Dc)this.generation>=n&&(t=i);return t}population(){return this.cachedPop}activityCenterX(){const[t,e]=this.clampCam();let n=0,i=0;for(let r=0;rthis.actBaseline?.015:.003;this.actBaseline=this.actBaseline*(1-e)+t*e;const n=t/Math.max(this.actBaseline,1);let i=n>1?Math.min(1.6,1+(n-1)*.7):.7+n*.3;return t<60&&(i=Math.min(i,.7)),this.dilation=this.dilation*.85+i*.15,this.dilation}sparkline(t=24){const e=this.popHistory;if(e.length<2)return"";const n=Math.max(0,e.length-t);let i=e[n]??0,r=i;for(let c=n;cr&&(r=u)}const o=Bs.length-1,a=Bs[Math.floor(Bs.length/2)]??"▅";let l="";for(let c=n;c>>0}function Nc(s){return`rgb(${s[0]},${s[1]},${s[2]})`}const Uo=[10,10,12],Zd="rgb(200,200,200)",Ji="rgb(112,112,116)",Uc=wc.length,ji=wc.map(s=>Ti(Zi(s))),Fo=Ec.map(s=>Ti(Zi(s))),Fc=Dd.map(([s,t])=>[Ti(Zi(s)),Ti(Zi(t))]),Jd=Id.map(([s,t])=>[Ti(Zi(s)),Ti(Zi(t))]),vr=Ti(Uo),jd='ui-monospace, "SF Mono", "Cascadia Mono", "DejaVu Sans Mono", Menlo, Consolas, monospace';let _r=null;function Qd(s){if(_r&&_r.maxAge===s)return _r.table;const t=new Uint8Array(s+1),e=Math.log1p(s);for(let n=1;n<=s;n++)t[n]=Math.min(Math.trunc(Math.log1p(n)/e*(Uc-1)),Uc-1);return _r={maxAge:s,table:t},t}function zs(s){return s.toLocaleString("en-US")}class tf{constructor(t){R(this,"cw",8);R(this,"cols",80);R(this,"rows",24);R(this,"statusRows",1);R(this,"keys",!0);R(this,"img",null);R(this,"widths",new Map);R(this,"px",null);R(this,"off",null);this.ctx=t}get gridRows(){return Math.max(1,this.rows-this.statusRows)}resize(t,e,n){this.cw=Math.max(2,Math.round(n)),this.cols=Math.max(20,Math.floor(t/this.cw)),this.rows=Math.max(6,Math.floor(e/(this.cw*2))),this.statusRows=this.cols>=150?1:2,this.keys=this.cols>=150,this.img=null,this.widths.clear()}status(t,e){const n=t.sparkline(this.cols<100?10:24),i=t.autoCam?"auto":"pan",r=Fd[t.zoomLevel]??`${2**t.zoomLevel}x`,o=t.autoFocusMode?"[F]":"",a=t.haunted?"[HAUNTED]":"",l=e?` ${e}`:"",c=` ${t.epoch()} gen ${zs(t.generation)} pop ${zs(t.population())} ${n}`,u=this.keys?" q r spc +/- arrows h z/x f g s ":" ",h=`${l} ${a}${o} ${r} ${i}${u}`;return this.statusRows===1?{left:c,right:h,tickerCol:En(c)+1,tickerWidth:this.cols-En(c)-En(h)-2}:{left:c,right:h,tickerCol:1,tickerWidth:this.cols-2}}render(t,e,n){const i=this.ctx,r=this.cw,o=this.cols*r,a=this.rows*r*2;i.fillStyle=Nc(Uo),i.fillRect(0,0,o,a),this.paintGrid(t),i.font=`${Math.round(r*1.62)}px ${jd}`,i.textBaseline="middle",n&&this.statsOverlay(t);const l=this.rows-1;if(this.statusRows===1)if(e.tickerWidth<10)this.text(`${e.left} ${e.right}`.slice(0,this.cols-1),l,0,Ji);else{this.text(e.left,l,0,Ji),this.ticker(t,l,e);const c=this.cols-En(e.right);this.text([...e.right].slice(0,this.cols-1-c).join(""),l,c,Ji)}else{const c=this.cols-1,u=En(e.left)+En(e.right)<=c?e.left+" ".repeat(c-En(e.left)-En(e.right))+e.right:`${e.left} ${e.right}`;this.text([...u].slice(0,c).join(""),l-1,0,Ji),this.ticker(t,l,e)}}paintGrid(t){const e=t.displayGrid(),n=t.displayAge(),i=Math.min(Math.floor(e.h/2),Math.floor(n.h/2),this.gridRows),r=Math.min(e.w,n.w,this.cols),o=this.cols,a=this.gridRows*2;(!this.img||this.img.width!==o||this.img.height!==a)&&(this.img=new ImageData(o,a),this.px=new Uint32Array(this.img.data.buffer),this.off=typeof OffscreenCanvas<"u"?new OffscreenCanvas(o,a):Object.assign(document.createElement("canvas"),{width:o,height:a}));const l=this.px;l.fill(vr);let c=1;for(let M=0;Mc&&(c=n.data[M]??0);const u=Qd(c),h=t.haunted,d=t.zoomLevel>=0||h,f=h?Ei:gr,p=M=>Math.min(Math.max(-M-1,0),f-1),x=M=>u[Math.min(Math.max(M,0),c)]??0,m=M=>{var w;return h?((w=Fc[M])==null?void 0:w[0])??0:Fo[M]??0},g=M=>{var w;return h?((w=Fc[M])==null?void 0:w[1])??0:vr};for(let M=0;M0,K=(e.data[C+U]??0)>0,N=n.data[v+U]??0,B=n.data[T+U]??0,z=d&&N<0,Z=d&&B<0;if(!(Y||K||z||Z))continue;let nt=vr,rt=vr;if((Y||z)&&(K||Z))if(Y&&K)nt=ji[x(N)]??0,rt=ji[x(B)]??0;else if(z&&Z){const ot=p(N),ht=p(B);if(h){const Gt=Jd[ot*Ei+ht];nt=(Gt==null?void 0:Gt[0])??0,rt=(Gt==null?void 0:Gt[1])??0}else nt=Fo[ot]??0,rt=Fo[ht]??0}else Y?nt=ji[x(N)]??0:rt=ji[x(B)]??0;else if(Y)nt=ji[x(N)]??0;else if(K)rt=ji[x(B)]??0;else if(z){const ot=p(N);nt=m(ot),rt=g(ot)}else{const ot=p(B);rt=m(ot),nt=g(ot)}l[L+U]=nt,l[D+U]=rt}}const b=this.off,E=b.getContext("2d");if(!E||!this.img)return;E.putImageData(this.img,0,0);const y=this.ctx;y.imageSmoothingEnabled=!1,y.drawImage(b,0,0,o*this.cw,a*this.cw)}ticker(t,e,n){const i=Ic.dim(t.generation)?Ji:Zd;for(const r of t.ticker.messages){const o=Math.trunc(r.x),a=[...r.text],l=Math.max(o,0),c=Math.min(o+a.length,n.tickerWidth);l>=c||this.text(a.slice(l-o,c-o).join(""),e,n.tickerCol+l,i)}}statsOverlay(t){const e=t.lastCensus.size?[...t.lastCensus.entries()].sort((c,u)=>u[1]-c[1]).map(([c,u])=>`${u}×${c}`).join(" "):"none",n=36,i=11,r=this.cols-n-2,o=this.rows-(this.statusRows-1)-i-2;if(r<0||o<0)return;const a=["─".repeat(n-2)," infinity engine",` pop floor : ${zs(t.popFloor)}`,` spread/150 : ${zs(t.spread)}`,` cycle : ${t.cyclePeriod===0?"none":`period ${t.cyclePeriod}`}`,` injections : ${t.totalInjections}`,` last event : ${t.lastEvent||"none"}`,t.lastEvent?` @ gen : ${zs(t.lastEventGen)}`:" ",` world : ${t.worldH}x${t.worldW}`,` census : ${[...e].slice(0,n-16).join("")}`,` tempo : ${(1/Math.max(t.dilation,.01)).toFixed(2)}x`],l=this.ctx;l.fillStyle=Nc(Uo),l.fillRect(r*this.cw,o*this.cw*2,n*this.cw,a.length*this.cw*2),a.forEach((c,u)=>{const h=[...` ${c}`.padEnd(n)].slice(0,n).join("");this.text(h,o+u,r,Ji)})}text(t,e,n,i){const r=this.ctx,o=this.cw,a=e*o*2;r.fillStyle=i;let l=n;for(const c of t){if(l>=this.cols)break;if(l>=0&&c!==" "){const u=Bs.indexOf(c);if(u>=0){const h=Math.max(1,Math.round(o*2*(u+1)/8));r.fillRect(l*o,a+o*2-h,o,h)}else if(c==="─")r.fillRect(l*o,a+o-Math.max(1,Math.round(o/8))/2,o,Math.max(1,Math.round(o/8)));else{let h=this.widths.get(c);h===void 0&&(h=r.measureText(c).width,this.widths.set(c,h)),r.fillText(c,l*o+o/2-h/2,a+o)}}l++}}}const It=512,Wt=384,Zt='"Libertinus Mono", "LibertinusMono", ui-monospace, monospace',Oo='"Love Letter Typewriter", "Libertinus Mono", monospace';function ko(s,t,e){t();const n=typeof document<"u"?document.fonts:void 0,i=(Array.isArray(s)?s:[s]).filter(r=>n&&!n.check(r));!n||!i.length||Promise.all(i.map(r=>n.load(r))).then(()=>{t(),e==null||e()},()=>{})}class fn{constructor(t,e){R(this,"canvas");R(this,"ctx");R(this,"fps",15);R(this,"acc",1);R(this,"version",0);this.site=t,this.env=e,this.canvas=document.createElement("canvas"),this.canvas.width=It,this.canvas.height=Wt;const n=this.canvas.getContext("2d",{alpha:!1});if(!n)throw new Error("oikos: no 2d context");this.ctx=n}tick(t,e,n,i=1){this.acc+=e;const r=n?Math.max(this.fps,30):this.fps*i;if(this.acc<1/r)return!1;const o=this.acc;return this.acc=0,this.draw(t,o),this.version++,!0}clear(t){this.ctx.fillStyle=t,this.ctx.fillRect(0,0,It,Wt)}wrap(t,e,n=1/0){const i=this.ctx,r=t.split(/\s+/).filter(Boolean),o=[];let a="";for(const l of r){const c=a?`${a} ${l}`:l;if(i.measureText(c).width>e&&a){if(o.push(a),a=l,o.length>=n)break}else a=c}if(a&&o.lengthe;)l=l.replace(/\s*\S*$/,"");o[n-1]=`${l}…`}return o}condensed(t,e,n,i=.72,r="left"){const o=this.ctx;o.save(),o.translate(e,n),o.scale(i,1),o.textAlign=r,o.fillText(t,0,0),o.restore()}spaced(t,e,n,i,r="left"){const o=this.ctx,a=[...t],l=a.map(h=>o.measureText(h).width),c=l.reduce((h,d)=>h+d,0)+i*(a.length-1);let u=r==="center"?e-c/2:e;o.save(),o.textAlign="left",a.forEach((h,d)=>{o.fillText(h,u,n),u+=(l[d]??0)+i}),o.restore()}}function Bo(s){let t=2166136261;for(let e=0;e>>0)%1e5/1e5}function Ai(s){let t=s>>>0;return()=>{t=t+1831565813>>>0;let e=t;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296}}function ef(s){return Math.round(s).toLocaleString("en-US")}class nf extends fn{constructor(e,n){super(e,n);R(this,"term");R(this,"life",null);R(this,"seenSave");this.fps=15,this.term=new tf(this.ctx),this.term.resize(It,Wt,8)}sync(){var r;const e=this.env.feeds.universe.value;if(this.life&&(e==null?void 0:e.savedAt)===((r=this.seenSave)==null?void 0:r.savedAt))return;this.seenSave=e;const n=e?Xi():null,i=new Yd(this.term.gridRows,this.term.cols,!n);n&&(i.adopt(n),i.ticker.queueSpecial(`the universe remembers generation ${i.generation.toLocaleString("en-US")}`)),this.life=i}draw(){this.sync();const e=this.life;if(!e)return;e.step(),e.generation>0&&e.generation%150===0&&e.takeCensus();const n=this.term.status(e,"");n.tickerWidth>=10&&e.tickTicker(n.tickerWidth),this.term.render(e,n,!1)}}const ni=62,Hs=21,sf=It/ni,rf=12.4,of=42,zo=" .,:;-=+*#%@";function af(){const s=[];for(let e=0;e<16;e++)s.push([e&1?1:-1,e&2?1:-1,e&4?1:-1,e&8?1:-1]);const t=[];for(let e=0;e<16;e++)for(let n=0;n<4;n++){const i=e^1<>>0).toString(16).padStart(8,"0").replace(/(....)(....)/,"$1·$2");return{prompt:o,template:a,coordinate:l,hue:n?Math.floor(Bo(o)*360):135,figure:Ho[this.seq++%Ho.length]??Ho[0]??[],bornAt:e}}draw(e){(!this.gen||e-this.gen.bornAt>9||!this.gen.prompt&&this.env.feeds.apeiron.value)&&(this.gen=this.generate(e));const n=this.gen,i=this.ctx,r=`hsl(${n.hue} 100% 58%)`,o=`hsl(${n.hue} 100% 76%)`,a=`hsl(${n.hue} 60% 22%)`,l=i.createRadialGradient(It/2,Wt*.4,20,It/2,Wt*.4,It*.7);l.addColorStop(0,`hsl(${n.hue} 60% 7%)`),l.addColorStop(1,"#030309"),i.fillStyle=l,i.fillRect(0,0,It,Wt),i.font=`12px ${Zt}`,i.fillStyle=r,i.fillText("apeiron",14,22),i.fillStyle=a,i.fillText("· æthera",76,22),i.textAlign="right",i.fillStyle=r,i.fillText(n.template.replace(/_/g," "),It-14,22),i.textAlign="left",this.raster(e,n.figure),i.font=`12px ${Zt}`;for(let d=0;d9?o:p>4?r:a,i.fillText(zo[p]??".",f*sf,of+d*rf+10))}const c=e-n.bornAt,u=n.prompt||"reading the grammar…";i.font=`12px ${Zt}`;const h=this.wrap(u.slice(0,Math.floor(c*70)),It-28,4);i.fillStyle="rgba(3,3,9,0.7)",i.fillRect(0,Wt-98,It,98),i.fillStyle=a,i.fillRect(14,Wt-98,It-28,1),i.fillStyle=o,h.forEach((d,f)=>i.fillText(d,14,Wt-78+f*15)),i.fillStyle=r,i.font=`11px ${Zt}`,i.fillText(`⌖ ${n.coordinate}`,14,Wt-12),i.fillStyle=a,i.textAlign="right",i.fillText("␣ generate F keep A auto",It-14,Wt-12),i.textAlign="left"}raster(e,n){this.depth.fill(-1/0),this.glyph.fill(0);const i=e*.45,r=e*.31,o=e*.23,[a,l,c,u,h,d]=[Math.cos(i),Math.sin(i),Math.cos(r),Math.sin(r),Math.cos(o),Math.sin(o)];for(const f of n){let[p,x,m,g]=f;[p,g]=[p*a-g*l,p*l+g*a],[x,m]=[x*c-m*u,x*u+m*c],[m,g]=[m*h-g*d,m*d+g*h];const b=2.6/(3.2-g);p*=b,x*=b,m*=b;const E=3.4/(4.6-m),y=Math.round(ni/2+p*E*11.5),M=Math.round(Hs/2+x*E*5.6);if(y<0||y>=ni||M<0||M>=Hs)continue;const w=M*ni+y;m>(this.depth[w]??-1/0)&&(this.depth[w]=m,this.glyph[w]=Math.max(1,Math.min(zo.length-1,Math.round((m+2.2)/4.4*(zo.length-1)))))}}}function hf(s,t){const e=s.templates[Math.floor(t()*s.templates.length)];return e?{prompt:e.structure.replace(/\{(\w+)\}/g,(i,r)=>{var a;const o=s.components[r];return o!=null&&o.length?((a=o[Math.floor(t()*o.length)])==null?void 0:a.word)??r:r.replace(/_/g," ")}),template:e.id}:{prompt:"",template:""}}const Go="#e8e2d4",Vo="#a39d90",Oc="#5d5850",Ci=34,Qi=250,Ri=84,yr=Wt-Ri-22;class uf extends fn{constructor(e,n){super(e,n);R(this,"standIn");this.fps=10,this.standIn=df()}draw(e){const n=this.ctx;this.clear("#070707"),n.fillStyle=Go,n.font=`22px ${Zt}`,this.spaced("chronicle",It/2,38,11,"center"),n.fillStyle=Vo,n.font=`11px ${Zt}`,this.spaced("what the dream remembers",It/2,60,2,"center");const r=[...this.env.feeds.chronicle.value.strata].reverse();if(n.fillStyle="#000",n.fillRect(Ci-1,Ri-1,Qi+2,yr+2),n.imageSmoothingEnabled=!0,r.length){const l=r.map((h,d)=>Math.pow(.6,d)),c=l.reduce((h,d)=>h+d,0);let u=Ri;r.forEach((h,d)=>{const f=yr*(l[d]??0)/c;n.save(),n.translate(Ci,u+f),n.scale(1,-1),n.drawImage(h,0,0,Qi,f),n.restore(),u+=f,n.fillStyle="rgba(232,226,212,0.08)",n.fillRect(Ci,u,Qi,1)})}else n.globalAlpha=.75,n.drawImage(this.standIn,Ci,Ri,Qi,yr),n.globalAlpha=1;const o=Ri+e*14%yr,a=n.createLinearGradient(0,o-16,0,o+2);a.addColorStop(0,"rgba(232,226,212,0)"),a.addColorStop(1,"rgba(232,226,212,0.22)"),n.fillStyle=a,n.fillRect(Ci,o-16,Qi,18),n.fillStyle="rgba(232,226,212,0.5)",n.fillRect(Ci-6,o,4,1),this.log(e)}log(e){const n=this.ctx,i=this.env.feeds.chronicle.value,r=Ci+Qi+24,o=It-r-18;n.font=`11px ${Zt}`,n.fillStyle=Oc,n.fillText(i.known?`${i.eraCount||i.eras.length} eras`:"reading the core…",r,Ri+8);const a=[...i.eras].reverse().slice(0,7);let l=Ri+34;if(!a.length){n.fillStyle=Vo;for(const c of this.wrap("every fifteen seconds of the dream settles here as one line of its own colour.",o,6))n.fillText(c,r,l),l+=15;return}for(const c of a){if(l>Wt-30)break;const u=new Date(c.t0*1e3);n.fillStyle=c.open?Go:Oc,n.font=`10px ${Zt}`;const h=`${u.getHours().toString().padStart(2,"0")}:${u.getMinutes().toString().padStart(2,"0")}`;n.fillText(c.open?`${h} now`:h,r,l),c.open&&(n.fillStyle=Math.sin(e*3)>0?"#d6c9a8":"#6d6555",n.fillRect(r-10,l-6,4,4)),n.font=`12px ${Zt}`,n.fillStyle=c.open?Go:Vo;const d=this.wrap(c.title||"untitled",o,2);d.forEach((f,p)=>n.fillText(f,r,l+15+p*14)),l+=22+d.length*14}}}function df(){const s=document.createElement("canvas");s.width=64,s.height=240;const t=s.getContext("2d");if(!t)return s;const e=Ai(1729),n=["#5c3b36","#7a4f45","#3f3a4c","#8a6f64","#2d4a4f","#6b2c3a","#a38a74","#40302c"];let i=n[0];for(let r=0;r0?Wo:Mr,n.globalAlpha=.5+e*.5,n.lineWidth=1,n.strokeRect(t.x+.5,t.y+.5,t.w,t.h),n.globalAlpha=1,n.font=`10px ${Zt}`,n.fillStyle=e>0?$o:Pi,n.fillText(t.label,t.x+6,t.y+13)}arrow(t,e,n,i,r,o){const a=this.ctx;a.strokeStyle=Mr,a.beginPath(),a.moveTo(t,e),a.lineTo(n,i),a.stroke();const l=Math.sign(n-t||i-e);if(a.fillStyle=Mr,a.beginPath(),e===i?(a.moveTo(n,i),a.lineTo(n-6*l,i-4),a.lineTo(n-6*l,i+4)):(a.moveTo(n,i),a.lineTo(n-4,i-6*l),a.lineTo(n+4,i-6*l)),a.fill(),o>=0&&o<=1){const c=t+(n-t)*o,u=e+(i-e)*o,h=a.createRadialGradient(c,u,0,c,u,8);h.addColorStop(0,"rgba(213,155,255,1)"),h.addColorStop(1,"rgba(213,155,255,0)"),a.fillStyle=h,a.fillRect(c-8,u-8,16,16)}r&&(a.font=`9px ${Zt}`,a.fillStyle=Pi,a.textAlign="center",a.fillText(r,(t+n)/2,e===i?e-6:(e+i)/2),a.textAlign="left")}draw(t){const e=this.ctx;this.clear(ff);const n=this.env.feeds.chronicle.value,i=6,r=t%i/i,o=400+Math.floor(t/i);if(e.font=`14px ${Zt}`,e.fillStyle=Wo,e.fillText("dream_gen",18,28),e.font=`10px ${Zt}`,e.fillStyle=Pi,e.fillText("a truly infinite diffusion stream",110,28),e.textAlign="right",e.fillText(`kf ${String(o).padStart(5,"0")}`,It-18,28),e.textAlign="left",this.box(ii,r<.25?1:0),this.box(Ve,r>=.25&&r<.5?1:.2),this.box(si,0),this.box(Li,r>=.5?1:0),this.box(br,Math.sin(t*.8)>.6?1:0),n.thumb)e.drawImage(n.thumb,Ve.x+6,Ve.y+18,Ve.w-12,(Ve.w-12)/2),e.globalAlpha=.35,e.drawImage(n.thumb,ii.x+6,ii.y+18,ii.w-12,(ii.w-12)/2),e.globalAlpha=1;else for(const h of[ii,Ve]){const d=e.createLinearGradient(h.x,h.y,h.x+h.w,h.y+h.h);d.addColorStop(0,`hsl(${(t*8+h.x)%360} 40% 30%)`),d.addColorStop(1,`hsl(${(t*8+h.x+90)%360} 40% 18%)`),e.fillStyle=d,e.fillRect(h.x+6,h.y+18,h.w-12,(h.w-12)/2)}e.fillStyle="#1b1426",e.fillRect(si.x+6,si.y+18,si.w-12,(si.w-12)/2),e.fillStyle=Pi,e.font=`9px ${Zt}`,e.fillText("txt2img on swap",si.x+10,si.y+50),this.arrow(ii.x+ii.w,91,Ve.x,91,"img2img",r<.25?r/.25:-1),this.arrow(si.x,91,Ve.x+Ve.w,91,"",-1),this.arrow(Ve.x+Ve.w/2,Ve.y+Ve.h,Ve.x+Ve.w/2,Li.y,"",r>=.25&&r<.5?(r-.25)/.25:-1);const a=16,l=r>=.5?Math.floor((r-.5)/.5*a):0;for(let h=0;h{const p=br.y+34+f*22;e.fillStyle=$o,e.font=`10px ${Zt}`,e.fillText(h,br.x+8,p),e.fillStyle=Pi,e.fillText(d,br.x+78,p)}),e.fillStyle="rgba(20,12,30,0.8)",e.fillRect(0,Wt-110,It,110),e.fillStyle=Mr,e.fillRect(18,Wt-110,It-36,1),e.font=`10px ${Zt}`,e.fillStyle=Pi,e.fillText(n.prompt?`prompt${n.template?` · ${n.template}`:""}`:"prompt",18,Wt-92),e.font=`12px ${Zt}`,e.fillStyle=$o;const u=n.prompt||"the dreamer is asleep; its last prompt will appear here when the chronicle has one.";this.wrap(u,It-36,5).forEach((h,d)=>e.fillText(h,18,Wt-72+d*15))}}const Sr=new Image;Sr.src="/static/oikos/stage.jpg";const on=372,an=186,kc=(It-on)/2,Bc=118;class mf extends fn{constructor(e,n){super(e,n);R(this,"frame",document.createElement("canvas"));R(this,"fctx");R(this,"prev",null);R(this,"cur",null);R(this,"swapAt",0);this.fps=20,this.frame.width=on,this.frame.height=an;const i=this.frame.getContext("2d");if(!i)throw new Error("oikos: no 2d context");this.fctx=i}draw(e){const n=this.ctx;this.clear("#120406"),Sr.complete&&Sr.naturalWidth&&(n.globalAlpha=.95,n.drawImage(Sr,0,0,It,Wt),n.globalAlpha=1);const i=this.env.feeds.chronicle.value;i.thumb&&i.thumb!==this.cur&&(this.prev=this.cur,this.cur=i.thumb,this.swapAt=e);const r=this.fctx;if(r.globalCompositeOperation="source-over",r.globalAlpha=1,this.cur){const a=Math.min(1,(e-this.swapAt)/2.5);this.prev&&a<1&&this.kenBurns(this.prev,e-20),r.globalAlpha=this.prev?a:1,this.kenBurns(this.cur,e),r.globalAlpha=1}else this.standIn(e);const o=r.createRadialGradient(on/2,an/2,an*.25,on/2,an/2,on*.56);o.addColorStop(0,"rgba(0,0,0,1)"),o.addColorStop(.72,"rgba(0,0,0,0.9)"),o.addColorStop(1,"rgba(0,0,0,0)"),r.globalCompositeOperation="destination-in",r.fillStyle=o,r.fillRect(0,0,on,an),r.globalCompositeOperation="source-over",n.save(),n.globalCompositeOperation="lighter",n.globalAlpha=.18,n.drawImage(this.frame,kc-30,Bc+an-20,on+60,90),n.restore(),n.drawImage(this.frame,kc,Bc),this.status(e),n.fillStyle="rgba(8,4,4,0.72)",n.fillRect(0,Wt-34,It,34),n.fillStyle="#efe6d2",n.font=`12px ${Zt}`,this.spaced("NOW SHOWING · A DREAM · ALL NIGHT",It/2,Wt-13,3,"center")}kenBurns(e,n){const i=1.06+.05*Math.sin(n*.07),r=Math.sin(n*.05)*10,o=Math.cos(n*.043)*5,a=on*i,l=an*i;this.fctx.drawImage(e,(on-a)/2+r,(an-l)/2+o,a,l)}standIn(e){const n=this.fctx,i=n.createLinearGradient(0,0,0,an);i.addColorStop(0,"#3a2440"),i.addColorStop(1,"#170d1c"),n.fillStyle=i,n.fillRect(0,0,on,an);const r=[12,330,280,20,350];for(let o=0;o<5;o++){const a=e*(.11+o*.03)+o*1.7,l=on/2+Math.cos(a)*(60+o*14)*(o%2?1:-1),c=an/2+Math.sin(a*1.3)*30,u=52+22*Math.sin(a*.7+o),h=n.createRadialGradient(l,c,0,l,c,u);h.addColorStop(0,`hsla(${r[o]} 90% 66% / 0.75)`),h.addColorStop(1,`hsla(${r[o]} 90% 50% / 0)`),n.fillStyle=h,n.fillRect(0,0,on,an)}}status(e){const n=this.ctx,i=this.env.feeds.dreams.value,r=this.env.feeds.chronicle.value;n.font=`12px ${Zt}`;let o,a;i.known&&i.awake?(a=Math.sin(e*4)>0?"#ff3b3b":"#6a1010",o=`LIVE frame ${ef(i.frame)}${i.viewers?` · ${i.viewers} watching`:""}`):i.known?(a="#5a5a5a",o=r.thumb?"asleep · last remembered":"asleep · wakes when watched"):(a="#3a3a3a",o=r.thumb?"last remembered":"no signal · a stand-in");const l=n.measureText(o).width+34;n.fillStyle="rgba(0,0,0,0.55)",n.fillRect(14,14,l,24),n.fillStyle=a,n.beginPath(),n.arc(27,26,4.5,0,Math.PI*2),n.fill(),n.fillStyle="#f2e9dc",n.fillText(o,38,30)}}const gf="#04060c",zc="#9fc6ff",Gs="#3d5378",Vs="#c9d1d9",xf="#a5e3b5",Xo="#ffc387",Hc=[["GET","/api/dreams/status","how it is (never wakes it)"],["WS ","/ws/dreams","the dream itself, h264"],["GET","/api/dreams/stream","MPEG-TS"],["SSE","/api/dreams/sse","events"],["GET","/api/dreams/embed","take it with you"]];class vf extends fn{constructor(e,n){super(e,n);R(this,"askedAt",-10);R(this,"lastRaw");this.fps=12}draw(e){const n=this.ctx;this.clear(gf);const i=this.env.feeds.dreams.value.raw;i!==this.lastRaw&&(this.lastRaw=i,this.askedAt=e);const r=e-this.askedAt;n.font=`13px ${Zt}`;const o=`curl -s ${location.host}/api/dreams/status`,a=o.slice(0,Math.floor(r*38));if(n.fillStyle=Gs,n.fillText("$",16,28),n.fillStyle=zc,n.fillText(a+(a.length=o.length){const c=i?_f(i,11):[[{text:"curl: (52) the dream did not answer",color:"#e58a8a"}]],u=Math.floor((r-o.length/38)*30);c.slice(0,u).forEach((h,d)=>{let f=16;for(const p of h)n.fillStyle=p.color,n.fillText(p.text,f,52+d*17),f+=n.measureText(p.text).width})}const l=Wt-128;n.fillStyle="rgba(159,198,255,0.06)",n.fillRect(10,l-20,It-20,138),n.strokeStyle="rgba(159,198,255,0.25)",n.strokeRect(10.5,l-19.5,It-21,137),n.font=`11px ${Zt}`,n.fillStyle=Gs,n.fillText("ENDPOINTS",20,l-4),Hc.forEach(([c,u,h],d)=>{const f=l+16+d*19,p=Math.floor(e/2.5)%Hc.length===d;n.fillStyle=p?Xo:Gs,n.fillText(c,20,f),n.fillStyle=p?"#ffffff":zc,n.fillText(u,58,f),n.fillStyle=Gs,n.fillText(h,250,f)})}}function _f(s,t){const e=[],n=(i,r,o,a)=>{if(e.length>=t)return;const l=[{text:r,color:Vs}];o!==null&&l.push({text:`"${o}": `,color:Vs});const c=a?"":",";if(i&&typeof i=="object"&&!Array.isArray(i)){const d=Object.entries(i);e.push([...l,{text:"{",color:Vs}]),d.forEach(([f,p],x)=>n(p,`${r} `,f,x===d.length-1)),e.length=t&&(e[t-1]=[{text:" …",color:Gs}]),e}const Ue={bg:"#181522",screen:"#231f36",fg:"#c9d1d9",dim:"#6e7681",sys:"#8b949e",quit:"#f85149",action:"#a371f7",join:"#3fb950"},Gc=["#58a6ff","#3fb950","#d29922","#a371f7","#f778ba","#39c5cf","#ff7b72","#7ee787","#ffa657","#79c0ff","#d2a8ff","#56d364"];function yf(s){let t=0;for(const e of s)t=t*31+e.charCodeAt(0)>>>0;return Gc[t%Gc.length]??Ue.fg}function Mf(s){const t=[{text:`[${s.stamp}] `,color:Ue.dim}],e=s.nick,n=s.content;switch(s.type){case"message":t.push({text:`<${e}> `,color:yf(e)},{text:n,color:Ue.fg});break;case"action":t.push({text:`* ${e} ${n}`,color:Ue.action});break;case"quit":t.push({text:`⫫ ${e} has quit${n?` (${n})`:""}`,color:Ue.quit});break;case"part":t.push({text:`← ${e} has left${n?` (${n})`:""}`,color:Ue.sys});break;case"join":t.push({text:`→ ${e} has joined`,color:Ue.join});break;case"kick":{const i=s.reason||n;t.push({text:`⚠ ${s.target?`${s.target} was kicked by ${e}`:`${e} kicked someone`}${i?` (${i})`:""}`,color:Ue.quit})}break;default:t.push({text:`*** ${n||e}`,color:Ue.sys})}return t}const Vc=16,ts=16,qo=50;class bf extends fn{constructor(e,n){super(e,n);R(this,"laidOut",[]);R(this,"seen",-1);this.fps=15}layout(){const e=this.env.feeds.irc.value;e.version!==this.seen&&(this.seen=e.version,this.ctx.font=`12.5px ${Zt}`,this.laidOut=e.lines.map(n=>({rows:this.wrapChunks(Mf(n),It-ts*2),at:n.at})))}wrapChunks(e,n){var a;const i=this.ctx,r=[[]];let o=0;for(const l of e)for(const c of l.text.split(/(\s+)/)){if(!c)continue;const u=i.measureText(c).width;o+u>n&&o>0&&c.trim()&&(r.push([{text:" ",color:l.color}]),o=i.measureText(" ").width),(a=r[r.length-1])==null||a.push({text:c,color:l.color}),o+=u}return r}draw(e){this.layout();const n=this.ctx,i=this.env.feeds.irc.value;this.clear(Ue.bg),n.fillStyle=Ue.screen,n.fillRect(6,6,It-12,Wt-12),n.fillStyle="rgba(88,166,255,0.1)",n.fillRect(6,6,It-12,28),n.font=`13px ${Zt}`,n.fillStyle="#58a6ff",n.fillText("#aethera",ts,25),n.fillStyle=Ue.dim,n.font=`11px ${Zt}`,n.textAlign="right";const r=i.connected?Math.sin(e*3)>-.3?"● live":"○ live":"○ connecting…";n.fillStyle=i.connected?Ue.join:Ue.dim,n.fillText(r,It-ts,25),n.textAlign="left";const o=i.collapse?Math.min(1,(performance.now()-i.collapse.at)/1500):0;n.font=`12.5px ${Zt}`;const a=[],l=performance.now();for(const h of this.laidOut)for(const d of h.rows)a.push({chunks:d,fresh:Math.max(0,1-(l-h.at)/600)});const c=Math.floor((Wt-qo-12)/Vc),u=a.slice(-c);u.length||(n.fillStyle=Ue.sys,n.fillText(i.connected?"*** the channel is quiet between fragments":"*** connecting to #aethera…",ts,qo+12)),u.forEach((h,d)=>{let f=ts;const p=qo+12+d*Vc,x=o?Math.sin(p*.3+e*40)*8*o*(Math.random()<.3?1:0):0;for(const m of h.chunks)n.fillStyle=o>.2&&Math.random()0){this.hop.k+=e/.16,this.hop.k>=1&&(this.hop.k=0,this.hop.left--,this.pos[this.hop.seat]=((this.pos[this.hop.seat]??0)+1)%40,this.hop.left===0&&this.land(this.hop.seat));return}if(this.wait-=e,this.wait>0)return;const n=this.turn%ri.length,i=1+Math.floor(this.rand()*6),r=1+Math.floor(this.rand()*6);this.dice=[i,r],this.say(`${(o=ri[n])==null?void 0:o.name} rolls ${i} and ${r}.`),this.hop={seat:n,from:this.pos[n]??0,left:i+r,k:0},this.turn++,this.wait=1.6}land(e){var c,u;const n=this.pos[e]??0,[i,r,o]=Wc[n]??["",null,0],a=((c=ri[e])==null?void 0:c.name)??"",l=this.owner.get(n);if(o&&l===void 0&&this.rand()<.75)this.owner.set(n,e),this.say(`${a} buys ${i} for ₯${o}.`);else if(l!==void 0&&l!==e){const h=Math.max(2,Math.round(o/(r?12:8)));this.say(`${a} pays ₯${h} to ${(u=ri[l])==null?void 0:u.name} for ${i}.`)}else i==="Moira"||i==="Grammateion"?this.say(`${a} draws from ${i}.`):i==="Kerux"&&(this.say(`${a} is sent to the Desmoterion.`),this.pos[e]=10);this.owner.size>22&&this.owner.clear()}draw(e,n){var c;this.step(Math.min(n,.2));const i=this.ctx,r=i.createRadialGradient(It/2,Ko,40,It/2,Ko,It*.7);r.addColorStop(0,"#2a241f"),r.addColorStop(1,"#141210"),i.fillStyle=r,i.fillRect(0,0,It,Wt);const o=[pn(-.4,-.4),pn(11.4,-.4),pn(11.4,11.4),pn(-.4,11.4)];i.fillStyle="rgba(0,0,0,0.45)",i.beginPath(),o.forEach(([u,h],d)=>d?i.lineTo(u,h+8):i.moveTo(u,h+8)),i.fill(),i.fillStyle="#d9ccb2",i.beginPath(),o.forEach(([u,h],d)=>d?i.lineTo(u,h):i.moveTo(u,h)),i.fill();for(let u=0;u<40;u++){const[h,d]=Yo(u),[,f]=Wc[u]??["",null,0],p=[pn(h,d),pn(h+1,d),pn(h+1,d+1),pn(h,d+1)];i.fillStyle=f?Sf[f]??"#efe4cf":u%10===0?"#e6d6b6":"#efe4cf",i.strokeStyle="#7a6a52",i.lineWidth=.7,i.beginPath(),p.forEach(([m,g],b)=>b?i.lineTo(m,g):i.moveTo(m,g)),i.closePath(),i.fill(),i.stroke();const x=this.owner.get(u);if(x!==void 0){const[m,g]=pn(h+.5,d+.5);i.fillStyle=((c=ri[x])==null?void 0:c.color)??"#fff",i.fillRect(m-2,g-5,4,5)}}const[a,l]=pn(5.5,5.5);i.fillStyle="#7a6a52",i.font=`15px ${Zt}`,this.spaced("KLEROS",a,l+5,5,"center"),ri.forEach((u,h)=>{let d=this.pos[h]??0,f=0,[p,x]=Yo(d);if(this.hop.left>0&&this.hop.seat===h){const[E,y]=Yo((d+1)%40);p+=(E-p)*this.hop.k,x+=(y-x)*this.hop.k,f=Math.sin(this.hop.k*Math.PI)*9,d=-1}const m=[[.3,.3],[.7,.3],[.3,.7],[.7,.7]][h]??[.5,.5],[g,b]=pn(p+(m[0]??.5),x+(m[1]??.5));i.fillStyle="rgba(0,0,0,0.35)",i.beginPath(),i.ellipse(g,b+1,5,2.5,0,0,Math.PI*2),i.fill(),i.fillStyle=u.color,i.beginPath(),i.arc(g,b-5-f,4.6,0,Math.PI*2),i.fill(),i.strokeStyle="rgba(0,0,0,0.5)",i.stroke()}),this.dice.forEach((u,h)=>this.die(It-70+h*30,22,u,e)),i.font=`11px ${Zt}`,ri.forEach((u,h)=>{const d=26+h*16;i.fillStyle=u.color,i.fillRect(16,d-8,8,8),i.fillStyle=(this.turn-1)%ri.length===h?"#f5ecd9":"#8c826f",i.fillText(`${u.name}${u.model?" ◆ model":""}`,30,d)}),i.fillStyle="rgba(10,8,6,0.75)",i.fillRect(0,Wt-62,It,62),i.font=`12px ${Zt}`,this.log.forEach((u,h)=>{i.fillStyle=h===this.log.length-1?"#f1e6cc":"#8a7f6a",i.fillText(u,16,Wt-42+h*16)})}die(e,n,i,r){const o=this.ctx,a=this.hop.left>0?Math.sin(r*30)*.15:0;o.save(),o.translate(e,n),o.rotate(a),o.fillStyle="#efe4cf",o.fillRect(-10,-10,20,20),o.fillStyle="#3a2f24";const l={1:[[0,0]],2:[[-5,-5],[5,5]],3:[[-5,-5],[0,0],[5,5]],4:[[-5,-5],[5,-5],[-5,5],[5,5]],5:[[-5,-5],[5,-5],[0,0],[-5,5],[5,5]],6:[[-5,-5],[5,-5],[-5,0],[5,0],[-5,5],[5,5]]};for(const[c,u]of l[i]??[])o.beginPath(),o.arc(c,u,1.8,0,Math.PI*2),o.fill();o.restore()}}class Tf extends fn{constructor(e,n){super(e,n);R(this,"body");R(this,"creatureRef");R(this,"stars");R(this,"breaths",[]);this.fps=24;const i=Ai(33);this.stars=Array.from({length:90},()=>({x:i()*It,y:i()*Wt,a:i()*.5+.1})),this.body=qc()}sync(){const e=this.env.feeds.creature.value;e!==this.creatureRef&&(this.creatureRef=e,this.body=e?Af(e):qc(),this.breaths=Array.from({length:Math.min(4,this.body.edges.length)},(n,i)=>({edge:i*7%Math.max(1,this.body.edges.length),k:0,fwd:!0})))}draw(e,n){this.sync();const i=this.ctx,r=this.body,o=i.createLinearGradient(0,0,0,Wt);o.addColorStop(0,"#070b14"),o.addColorStop(1,"#02030a"),i.fillStyle=o,i.fillRect(0,0,It,Wt);for(const p of this.stars)i.fillStyle=`rgba(200,215,255,${p.a*(.7+.3*Math.sin(e+p.x))})`,i.fillRect(p.x,p.y,1,1);const a=r.born?1.4:.9,l=Math.min(n,.1),c=r.nodes.map((p,x)=>{var b;const m=r.adj[x]??[];let g=0;for(const E of m)g+=Math.sin((((b=r.nodes[E])==null?void 0:b.phase)??0)-p.phase);return p.phase+(p.omega+(m.length?a*g/m.length:0))*l});r.nodes.forEach((p,x)=>{const m=c[x]??p.phase;Math.floor(m/(Math.PI*2))>Math.floor(p.phase/(Math.PI*2))&&(p.flash=1),p.phase=m,p.flash=Math.max(0,p.flash-l*2.2)});const u=e*.18,h=Math.cos(u),d=Math.sin(u),f=r.nodes.map((p,x)=>{const m=Math.sin(e*.9+x)*.02,g=p.x*h-p.z*d,E=2.8/(3.6-(p.x*d+p.z*h));return{x:It/2+g*E*150,y:176+(p.y+m)*E*150,k:E}});i.lineCap="round";for(const p of r.edges){const x=f[p.a],m=f[p.b];!x||!m||(i.strokeStyle=p.elder?"rgba(160,200,235,0.55)":"rgba(140,170,210,0.28)",i.lineWidth=p.elder?1.4:.8,i.beginPath(),i.moveTo(x.x,x.y),i.lineTo(m.x,m.y),i.stroke())}for(const p of this.breaths){const x=r.edges[p.edge];if(!x)continue;if(p.k+=l/.75,p.k>=1){const M=p.fwd?x.b:x.a,w=(r.adj[M]??[]).map(T=>r.edges.findIndex(L=>L.a===M&&L.b===T||L.b===M&&L.a===T)),C=w[Math.floor(Math.random()*w.length)]??p.edge,v=r.edges[C];p.edge=C,p.fwd=v?v.a===M:!0,p.k=0;continue}const m=f[p.fwd?x.a:x.b],g=f[p.fwd?x.b:x.a];if(!m||!g)continue;const b=m.x+(g.x-m.x)*p.k,E=m.y+(g.y-m.y)*p.k,y=i.createRadialGradient(b,E,0,b,E,9);y.addColorStop(0,"rgba(235,245,255,0.95)"),y.addColorStop(1,"rgba(180,220,255,0)"),i.fillStyle=y,i.fillRect(b-9,E-9,18,18)}r.nodes.forEach((p,x)=>{const m=f[x];if(!m)return;const g=p.flash,b=2+m.k*1.2+g*3,E=g>.05?`rgba(255,${Math.round(210-g*40)},${Math.round(120-g*60)},${.6+g*.4})`:"rgba(200,225,255,0.85)";i.strokeStyle=E,i.lineWidth=.8,i.beginPath(),i.moveTo(m.x-b*3,m.y),i.lineTo(m.x+b*3,m.y),i.moveTo(m.x,m.y-b*3),i.lineTo(m.x,m.y+b*3),i.stroke();const y=i.createRadialGradient(m.x,m.y,0,m.x,m.y,b*2.4);y.addColorStop(0,E),y.addColorStop(1,"rgba(0,0,0,0)"),i.fillStyle=y,i.fillRect(m.x-b*3,m.y-b*3,b*6,b*6)}),i.font=`15px ${Zt}`,i.fillStyle=r.born?"#e6f1ff":"#8190a8",i.fillText(r.name,18,Wt-40),i.font=`11px ${Zt}`,i.fillStyle="#6f7f99",i.fillText(r.age,18,Wt-20),i.textAlign="right",i.fillStyle="#4b5870",i.fillText(r.born?`${r.nodes.length} nodes · ${r.edges.length} strings`:"click to wake it",It-18,Wt-20),i.textAlign="left"}}function Xc(s,t){var n,i;const e=Array.from({length:s},()=>[]);for(const r of t)(n=e[r.a])==null||n.push(r.b),(i=e[r.b])==null||i.push(r.a);return e}function Af(s){const t=new Map(s.nodes.map((c,u)=>[c.id,u])),e=s.nodes.reduce((c,u)=>c+u.x,0)/s.nodes.length,n=s.nodes.reduce((c,u)=>c+u.y,0)/s.nodes.length,i=s.nodes.reduce((c,u)=>c+u.z,0)/s.nodes.length,r=Math.max(1,...s.nodes.map(c=>Math.hypot(c.x-e,c.y-n,c.z-i))),o=s.nodes.map((c,u)=>({x:(c.x-e)/r,y:(c.y-n)/r,z:(c.z-i)/r,phase:u*1.3,omega:2.4+u%5*.21,flash:0})),a=s.edges.map(c=>({a:t.get(c.a)??-1,b:t.get(c.b)??-1,elder:c.age>150})).filter(c=>c.a>=0&&c.b>=0),l=Math.max(s.lifetime,(Date.now()-s.bornAt)/1e3);return{name:s.name,age:`${Cf(l)} old · yours`,born:!0,nodes:o,edges:a,adj:Xc(o.length,a)}}function qc(){const s=Ai(9),t=9,e=Array.from({length:t},(i,r)=>{const o=r/t*Math.PI*2;return{x:Math.cos(o)*.8+(s()-.5)*.3,y:(s()-.5)*.9,z:Math.sin(o)*.8,phase:s()*6,omega:2.2+s()*.8,flash:0}}),n=[];for(let i=0;i0?`${e}d ${n}h`:n>0?`${n}h ${i}m`:`${i}m`}const es=new Image;es.src="/static/uploads/aethera_trimmed.png";class Rf extends fn{constructor(e,n){super(e,n);R(this,"specks");this.fps=12;const i=Ai(7);this.specks=Array.from({length:70},()=>({x:i()*It,y:i()*Wt,r:i()*1.2+.3,red:i()<.35,v:i()*4+1}))}draw(e){const n=this.ctx;this.clear("#000");for(const c of this.specks){const u=(c.y-e*c.v+Wt)%Wt;n.fillStyle=c.red?"rgba(170,40,50,0.55)":"rgba(255,255,255,0.28)",n.fillRect(c.x,u,c.r,c.r)}if(es.complete&&es.naturalWidth){const u=210*es.naturalHeight/es.naturalWidth;n.globalAlpha=.92+.08*Math.sin(e*1.3),n.drawImage(es,(It-210)/2,26,210,u),n.globalAlpha=1}n.fillStyle="#7d7d7d",n.font=`13px ${Zt}`,this.spaced("transmissions",It/2,118,3,"center"),n.fillStyle="#262626",n.fillRect(40,132,It-80,1);const i=this.env.dir.posts.slice(0,6);if(!i.length){n.fillStyle="#9a9a9a",n.font=`16px ${Zt}`,n.textAlign="center",n.fillText(`no transmissions yet${Math.floor(e*2)%2?"_":" "}`,It/2,230),n.textAlign="left";return}const r=3.6,o=Math.floor(e/r)%i.length,a=e%r/r;i.forEach((c,u)=>{const h=162+u*29,d=u===o;n.font=`11px ${Zt}`,n.fillStyle=d?"#bdbdbd":"#555",n.fillText(c.date,46,h),n.font=`16px ${Oo}`,n.fillStyle=d?"#ffffff":"#9a9a9a";const f=c.title.length>38?`${c.title.slice(0,37)}…`:c.title;n.fillText(f,132,h),d&&this.star(28,h-5,e)});const l=i[o];if(l!=null&&l.excerpt){n.font=`italic 12px ${Zt}`,n.fillStyle="#8a8a8a";const c=Math.floor(Math.min(1,a*1.6)*l.excerpt.length);this.wrap(l.excerpt.slice(0,c),It-92,2).forEach((h,d)=>n.fillText(h,46,344+d*16))}}star(e,n,i){const r=this.ctx,o=7+Math.sin(i*5)*1.2;r.save(),r.translate(e,n),r.rotate(i*.8),r.fillStyle="#fff",r.shadowColor="#fff",r.shadowBlur=10,r.beginPath();for(let a=0;a<16;a++){const l=a/16*Math.PI*2,c=a%2?o*.28:a%4?o*.7:o;r.lineTo(Math.cos(l)*c,Math.sin(l)*c)}r.closePath(),r.fill(),r.restore()}}const Pf={transmissions:Rf,dreams:mf,chronicle:uf,"dreams-api":vf,apeiron:cf,syrinx:Tf,afterlife:nf,irc:bf,parlor:Ef,dream_gen:pf};class Lf extends fn{draw(t){const e=this.ctx,n=["#c0c0c0","#c0c000","#00c0c0","#00c000","#c000c0","#c00000","#0000c0"];n.forEach((i,r)=>{e.fillStyle=i,e.fillRect(r*It/n.length,0,It/n.length+1,Wt*.66)}),e.fillStyle="#111",e.fillRect(0,Wt*.66,It,Wt*.34),e.fillStyle="#fff",e.font=`22px ${Zt}`,e.textAlign="center",e.fillText(this.site.title,It/2,Wt*.82),e.font=`12px ${Zt}`,e.fillStyle=Math.floor(t)%2?"#888":"#555",e.fillText("no programme yet",It/2,Wt*.92),e.textAlign="left"}}function Df(s,t){const e=Pf[s.id]??Lf;return new e(s,t)}const wr={dreams:{angle:0,r:4.9,y:.5,style:"tv",screenW:2,channel:1},transmissions:{angle:-27,r:4.5,y:.34,style:"beige",screenW:1.22,stand:!0,channel:2},chronicle:{angle:27,r:4.5,y:0,style:"black",screenW:1.3,channel:3},"dreams-api":{angle:27,r:4.5,y:0,style:"grey",screenW:.86,on:"chronicle",channel:4},apeiron:{angle:-54,r:4.2,y:0,style:"black",screenW:1.15,channel:5},irc:{angle:-54,r:4.2,y:0,style:"beige",screenW:.95,on:"apeiron",channel:6},syrinx:{angle:54,r:4.2,y:.28,style:"grey",screenW:1.08,channel:7},afterlife:{angle:78,r:3.9,y:0,style:"black",screenW:1.02,channel:10},dream_gen:{angle:-20,r:7,y:4.35,style:"grey",screenW:1.02,hang:!0,feeds:"dreams",channel:8},parlor:{angle:20,r:6.5,y:3.6,style:"beige",screenW:1.1,hang:!0,channel:9}};function If(s,t){const e=wr[s];if(e)return e;const n=Math.floor(t/2)+1;return{angle:(t%2?1:-1)*(68+n*10),r:5.4,y:0,style:"grey",screenW:1,channel:12+t}}/** * @license * Copyright 2010-2026 Three.js Authors * SPDX-License-Identifier: MIT - */const Ma="185",Hi={ROTATE:0,DOLLY:1,PAN:2},Gi={ROTATE:0,PAN:1,DOLLY_PAN:2,DOLLY_ROTATE:3},_d=0,sc=1,xd=2,sr=1,vd=2,As=3,jn=0,Ge=1,On=2,wn=0,Vi=1,rr=2,rc=3,ac=4,Md=5,wi=100,yd=101,Sd=102,bd=103,wd=104,Ed=200,Td=201,Ad=202,Cd=203,ya=204,Sa=205,Rd=206,Pd=207,Ld=208,Dd=209,Id=210,Nd=211,Ud=212,Fd=213,Od=214,ba=0,wa=1,Ea=2,Wi=3,Ta=4,Aa=5,Ca=6,Ra=7,oc=0,kd=1,Bd=2,En=0,Pa=1,La=2,Da=3,ar=4,Ia=5,Na=6,Ua=7,lc=300,Ei=301,$i=302,Fa=303,Oa=304,or=306,lr=1e3,kn=1001,ka=1002,Ne=1003,zd=1004,cr=1005,Ue=1006,Ba=1007,Ti=1008,Ze=1009,cc=1010,hc=1011,Cs=1012,za=1013,Tn=1014,un=1015,Je=1016,Ha=1017,Ga=1018,Rs=1020,uc=35902,dc=35899,fc=1021,pc=1022,dn=1023,Bn=1026,Ai=1027,Va=1028,Wa=1029,Ci=1030,$a=1031,Xa=1033,hr=33776,ur=33777,dr=33778,fr=33779,qa=35840,Ya=35841,Ka=35842,Za=35843,Ja=36196,Qa=37492,ja=37496,to=37488,eo=37489,pr=37490,no=37491,io=37808,so=37809,ro=37810,ao=37811,oo=37812,lo=37813,co=37814,ho=37815,uo=37816,fo=37817,po=37818,mo=37819,go=37820,_o=37821,xo=36492,vo=36494,Mo=36495,yo=36283,So=36284,mr=36285,bo=36286,Hd=3200,wo=0,Gd=1,ti="",Se="srgb",Ps="srgb-linear",gr="linear",ie="srgb",Xi=7680,mc=519,Vd=512,Wd=513,$d=514,Eo=515,Xd=516,qd=517,To=518,Yd=519,gc=35044,_c="300 es",An=2e3,Ls=2001;function Kd(s){for(let t=s.length-1;t>=0;--t)if(s[t]>=65535)return!0;return!1}function _r(s){return document.createElementNS("http://www.w3.org/1999/xhtml",s)}function Zd(){const s=_r("canvas");return s.style.display="block",s}const xc={};function vc(...s){const t="THREE."+s.shift();console.log(t,...s)}function Mc(s){const t=s[0];if(typeof t=="string"&&t.startsWith("TSL:")){const e=s[1];e&&e.isStackTrace?s[0]+=" "+e.getLocation():s[1]='Stack trace not available. Enable "THREE.Node.captureStackTrace" to capture stack traces.'}return s}function Nt(...s){s=Mc(s);const t="THREE."+s.shift();{const e=s[0];e&&e.isStackTrace?console.warn(e.getError(t)):console.warn(t,...s)}}function Qt(...s){s=Mc(s);const t="THREE."+s.shift();{const e=s[0];e&&e.isStackTrace?console.error(e.getError(t)):console.error(t,...s)}}function qi(...s){const t=s.join(" ");t in xc||(xc[t]=!0,Nt(...s))}function Jd(s,t,e){return new Promise(function(n,i){function r(){switch(s.clientWaitSync(t,s.SYNC_FLUSH_COMMANDS_BIT,0)){case s.WAIT_FAILED:i();break;case s.TIMEOUT_EXPIRED:setTimeout(r,e);break;default:n()}}setTimeout(r,e)})}const Qd={[ba]:wa,[Ea]:Ca,[Ta]:Ra,[Wi]:Aa,[wa]:ba,[Ca]:Ea,[Ra]:Ta,[Aa]:Wi};class ei{addEventListener(t,e){this._listeners===void 0&&(this._listeners={});const n=this._listeners;n[t]===void 0&&(n[t]=[]),n[t].indexOf(e)===-1&&n[t].push(e)}hasEventListener(t,e){const n=this._listeners;return n===void 0?!1:n[t]!==void 0&&n[t].indexOf(e)!==-1}removeEventListener(t,e){const n=this._listeners;if(n===void 0)return;const i=n[t];if(i!==void 0){const r=i.indexOf(e);r!==-1&&i.splice(r,1)}}dispatchEvent(t){const e=this._listeners;if(e===void 0)return;const n=e[t.type];if(n!==void 0){t.target=this;const i=n.slice(0);for(let r=0,a=i.length;r>8&255]+Fe[s>>16&255]+Fe[s>>24&255]+"-"+Fe[t&255]+Fe[t>>8&255]+"-"+Fe[t>>16&15|64]+Fe[t>>24&255]+"-"+Fe[e&63|128]+Fe[e>>8&255]+"-"+Fe[e>>16&255]+Fe[e>>24&255]+Fe[n&255]+Fe[n>>8&255]+Fe[n>>16&255]+Fe[n>>24&255]).toLowerCase()}function $t(s,t,e){return Math.max(t,Math.min(e,s))}function Ao(s,t){return(s%t+t)%t}function jd(s,t,e,n,i){return n+(s-t)*(i-n)/(e-t)}function tf(s,t,e){return s!==t?(e-s)/(t-s):0}function Is(s,t,e){return(1-e)*s+e*t}function ef(s,t,e,n){return Is(s,t,1-Math.exp(-e*n))}function nf(s,t=1){return t-Math.abs(Ao(s,t*2)-t)}function sf(s,t,e){return s<=t?0:s>=e?1:(s=(s-t)/(e-t),s*s*(3-2*s))}function rf(s,t,e){return s<=t?0:s>=e?1:(s=(s-t)/(e-t),s*s*s*(s*(s*6-15)+10))}function af(s,t){return s+Math.floor(Math.random()*(t-s+1))}function of(s,t){return s+Math.random()*(t-s)}function lf(s){return s*(.5-Math.random())}function cf(s){s!==void 0&&(yc=s);let t=yc+=1831565813;return t=Math.imul(t^t>>>15,t|1),t^=t+Math.imul(t^t>>>7,t|61),((t^t>>>14)>>>0)/4294967296}function hf(s){return s*Ds}function uf(s){return s*Yi}function df(s){return(s&s-1)===0&&s!==0}function ff(s){return Math.pow(2,Math.ceil(Math.log(s)/Math.LN2))}function pf(s){return Math.pow(2,Math.floor(Math.log(s)/Math.LN2))}function mf(s,t,e,n,i){const r=Math.cos,a=Math.sin,o=r(e/2),l=a(e/2),c=r((t+n)/2),u=a((t+n)/2),h=r((t-n)/2),d=a((t-n)/2),f=r((n-t)/2),p=a((n-t)/2);switch(i){case"XYX":s.set(o*u,l*h,l*d,o*c);break;case"YZY":s.set(l*d,o*u,l*h,o*c);break;case"ZXZ":s.set(l*h,l*d,o*u,o*c);break;case"XZX":s.set(o*u,l*p,l*f,o*c);break;case"YXY":s.set(l*f,o*u,l*p,o*c);break;case"ZYZ":s.set(l*p,l*f,o*u,o*c);break;default:Nt("MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+i)}}function Zi(s,t){switch(t.constructor){case Float32Array:return s;case Uint32Array:return s/4294967295;case Uint16Array:return s/65535;case Uint8Array:return s/255;case Int32Array:return Math.max(s/2147483647,-1);case Int16Array:return Math.max(s/32767,-1);case Int8Array:return Math.max(s/127,-1);default:throw new Error("THREE.MathUtils: Invalid component type.")}}function Ve(s,t){switch(t.constructor){case Float32Array:return s;case Uint32Array:return Math.round(s*4294967295);case Uint16Array:return Math.round(s*65535);case Uint8Array:return Math.round(s*255);case Int32Array:return Math.round(s*2147483647);case Int16Array:return Math.round(s*32767);case Int8Array:return Math.round(s*127);default:throw new Error("THREE.MathUtils: Invalid component type.")}}const xr={DEG2RAD:Ds,RAD2DEG:Yi,generateUUID:Ki,clamp:$t,euclideanModulo:Ao,mapLinear:jd,inverseLerp:tf,lerp:Is,damp:ef,pingpong:nf,smoothstep:sf,smootherstep:rf,randInt:af,randFloat:of,randFloatSpread:lf,seededRandom:cf,degToRad:hf,radToDeg:uf,isPowerOfTwo:df,ceilPowerOfTwo:ff,floorPowerOfTwo:pf,setQuaternionFromProperEuler:mf,normalize:Ve,denormalize:Zi},kl=class kl{constructor(t=0,e=0){this.x=t,this.y=e}get width(){return this.x}set width(t){this.x=t}get height(){return this.y}set height(t){this.y=t}set(t,e){return this.x=t,this.y=e,this}setScalar(t){return this.x=t,this.y=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;default:throw new Error("THREE.Vector2: index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;default:throw new Error("THREE.Vector2: index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y)}copy(t){return this.x=t.x,this.y=t.y,this}add(t){return this.x+=t.x,this.y+=t.y,this}addScalar(t){return this.x+=t,this.y+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this}subScalar(t){return this.x-=t,this.y-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this}multiply(t){return this.x*=t.x,this.y*=t.y,this}multiplyScalar(t){return this.x*=t,this.y*=t,this}divide(t){return this.x/=t.x,this.y/=t.y,this}divideScalar(t){return this.multiplyScalar(1/t)}applyMatrix3(t){const e=this.x,n=this.y,i=t.elements;return this.x=i[0]*e+i[3]*n+i[6],this.y=i[1]*e+i[4]*n+i[7],this}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this}clamp(t,e){return this.x=$t(this.x,t.x,e.x),this.y=$t(this.y,t.y,e.y),this}clampScalar(t,e){return this.x=$t(this.x,t,e),this.y=$t(this.y,t,e),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar($t(n,t,e))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(t){return this.x*t.x+this.y*t.y}cross(t){return this.x*t.y-this.y*t.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(e===0)return Math.PI/2;const n=this.dot(t)/e;return Math.acos($t(n,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y;return e*e+n*n}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this}equals(t){return t.x===this.x&&t.y===this.y}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this}rotateAround(t,e){const n=Math.cos(e),i=Math.sin(e),r=this.x-t.x,a=this.y-t.y;return this.x=r*n-a*i+t.x,this.y=r*i+a*n+t.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}};kl.prototype.isVector2=!0;let ht=kl;class Cn{constructor(t=0,e=0,n=0,i=1){this.isQuaternion=!0,this._x=t,this._y=e,this._z=n,this._w=i}static slerpFlat(t,e,n,i,r,a,o){let l=n[i+0],c=n[i+1],u=n[i+2],h=n[i+3],d=r[a+0],f=r[a+1],p=r[a+2],v=r[a+3];if(h!==v||l!==d||c!==f||u!==p){let m=l*d+c*f+u*p+h*v;m<0&&(d=-d,f=-f,p=-p,v=-v,m=-m);let g=1-o;if(m<.9995){const w=Math.acos(m),E=Math.sin(w);g=Math.sin(g*w)/E,o=Math.sin(o*w)/E,l=l*g+d*o,c=c*g+f*o,u=u*g+p*o,h=h*g+v*o}else{l=l*g+d*o,c=c*g+f*o,u=u*g+p*o,h=h*g+v*o;const w=1/Math.sqrt(l*l+c*c+u*u+h*h);l*=w,c*=w,u*=w,h*=w}}t[e]=l,t[e+1]=c,t[e+2]=u,t[e+3]=h}static multiplyQuaternionsFlat(t,e,n,i,r,a){const o=n[i],l=n[i+1],c=n[i+2],u=n[i+3],h=r[a],d=r[a+1],f=r[a+2],p=r[a+3];return t[e]=o*p+u*h+l*f-c*d,t[e+1]=l*p+u*d+c*h-o*f,t[e+2]=c*p+u*f+o*d-l*h,t[e+3]=u*p-o*h-l*d-c*f,t}get x(){return this._x}set x(t){this._x=t,this._onChangeCallback()}get y(){return this._y}set y(t){this._y=t,this._onChangeCallback()}get z(){return this._z}set z(t){this._z=t,this._onChangeCallback()}get w(){return this._w}set w(t){this._w=t,this._onChangeCallback()}set(t,e,n,i){return this._x=t,this._y=e,this._z=n,this._w=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(t){return this._x=t.x,this._y=t.y,this._z=t.z,this._w=t.w,this._onChangeCallback(),this}setFromEuler(t,e=!0){const n=t._x,i=t._y,r=t._z,a=t._order,o=Math.cos,l=Math.sin,c=o(n/2),u=o(i/2),h=o(r/2),d=l(n/2),f=l(i/2),p=l(r/2);switch(a){case"XYZ":this._x=d*u*h+c*f*p,this._y=c*f*h-d*u*p,this._z=c*u*p+d*f*h,this._w=c*u*h-d*f*p;break;case"YXZ":this._x=d*u*h+c*f*p,this._y=c*f*h-d*u*p,this._z=c*u*p-d*f*h,this._w=c*u*h+d*f*p;break;case"ZXY":this._x=d*u*h-c*f*p,this._y=c*f*h+d*u*p,this._z=c*u*p+d*f*h,this._w=c*u*h-d*f*p;break;case"ZYX":this._x=d*u*h-c*f*p,this._y=c*f*h+d*u*p,this._z=c*u*p-d*f*h,this._w=c*u*h+d*f*p;break;case"YZX":this._x=d*u*h+c*f*p,this._y=c*f*h+d*u*p,this._z=c*u*p-d*f*h,this._w=c*u*h-d*f*p;break;case"XZY":this._x=d*u*h-c*f*p,this._y=c*f*h-d*u*p,this._z=c*u*p+d*f*h,this._w=c*u*h+d*f*p;break;default:Nt("Quaternion: .setFromEuler() encountered an unknown order: "+a)}return e===!0&&this._onChangeCallback(),this}setFromAxisAngle(t,e){const n=e/2,i=Math.sin(n);return this._x=t.x*i,this._y=t.y*i,this._z=t.z*i,this._w=Math.cos(n),this._onChangeCallback(),this}setFromRotationMatrix(t){const e=t.elements,n=e[0],i=e[4],r=e[8],a=e[1],o=e[5],l=e[9],c=e[2],u=e[6],h=e[10],d=n+o+h;if(d>0){const f=.5/Math.sqrt(d+1);this._w=.25/f,this._x=(u-l)*f,this._y=(r-c)*f,this._z=(a-i)*f}else if(n>o&&n>h){const f=2*Math.sqrt(1+n-o-h);this._w=(u-l)/f,this._x=.25*f,this._y=(i+a)/f,this._z=(r+c)/f}else if(o>h){const f=2*Math.sqrt(1+o-n-h);this._w=(r-c)/f,this._x=(i+a)/f,this._y=.25*f,this._z=(l+u)/f}else{const f=2*Math.sqrt(1+h-n-o);this._w=(a-i)/f,this._x=(r+c)/f,this._y=(l+u)/f,this._z=.25*f}return this._onChangeCallback(),this}setFromUnitVectors(t,e){let n=t.dot(e)+1;return n<1e-8?(n=0,Math.abs(t.x)>Math.abs(t.z)?(this._x=-t.y,this._y=t.x,this._z=0,this._w=n):(this._x=0,this._y=-t.z,this._z=t.y,this._w=n)):(this._x=t.y*e.z-t.z*e.y,this._y=t.z*e.x-t.x*e.z,this._z=t.x*e.y-t.y*e.x,this._w=n),this.normalize()}angleTo(t){return 2*Math.acos(Math.abs($t(this.dot(t),-1,1)))}rotateTowards(t,e){const n=this.angleTo(t);if(n===0)return this;const i=Math.min(1,e/n);return this.slerp(t,i),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(t){return this._x*t._x+this._y*t._y+this._z*t._z+this._w*t._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let t=this.length();return t===0?(this._x=0,this._y=0,this._z=0,this._w=1):(t=1/t,this._x=this._x*t,this._y=this._y*t,this._z=this._z*t,this._w=this._w*t),this._onChangeCallback(),this}multiply(t){return this.multiplyQuaternions(this,t)}premultiply(t){return this.multiplyQuaternions(t,this)}multiplyQuaternions(t,e){const n=t._x,i=t._y,r=t._z,a=t._w,o=e._x,l=e._y,c=e._z,u=e._w;return this._x=n*u+a*o+i*c-r*l,this._y=i*u+a*l+r*o-n*c,this._z=r*u+a*c+n*l-i*o,this._w=a*u-n*o-i*l-r*c,this._onChangeCallback(),this}slerp(t,e){let n=t._x,i=t._y,r=t._z,a=t._w,o=this.dot(t);o<0&&(n=-n,i=-i,r=-r,a=-a,o=-o);let l=1-e;if(o<.9995){const c=Math.acos(o),u=Math.sin(c);l=Math.sin(l*c)/u,e=Math.sin(e*c)/u,this._x=this._x*l+n*e,this._y=this._y*l+i*e,this._z=this._z*l+r*e,this._w=this._w*l+a*e,this._onChangeCallback()}else this._x=this._x*l+n*e,this._y=this._y*l+i*e,this._z=this._z*l+r*e,this._w=this._w*l+a*e,this.normalize();return this}slerpQuaternions(t,e,n){return this.copy(t).slerp(e,n)}random(){const t=2*Math.PI*Math.random(),e=2*Math.PI*Math.random(),n=Math.random(),i=Math.sqrt(1-n),r=Math.sqrt(n);return this.set(i*Math.sin(t),i*Math.cos(t),r*Math.sin(e),r*Math.cos(e))}equals(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._w===this._w}fromArray(t,e=0){return this._x=t[e],this._y=t[e+1],this._z=t[e+2],this._w=t[e+3],this._onChangeCallback(),this}toArray(t=[],e=0){return t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._w,t}fromBufferAttribute(t,e){return this._x=t.getX(e),this._y=t.getY(e),this._z=t.getZ(e),this._w=t.getW(e),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(t){return this._onChangeCallback=t,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}}const Bl=class Bl{constructor(t=0,e=0,n=0){this.x=t,this.y=e,this.z=n}set(t,e,n){return n===void 0&&(n=this.z),this.x=t,this.y=e,this.z=n,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;default:throw new Error("THREE.Vector3: index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("THREE.Vector3: index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this}multiplyVectors(t,e){return this.x=t.x*e.x,this.y=t.y*e.y,this.z=t.z*e.z,this}applyEuler(t){return this.applyQuaternion(Sc.setFromEuler(t))}applyAxisAngle(t,e){return this.applyQuaternion(Sc.setFromAxisAngle(t,e))}applyMatrix3(t){const e=this.x,n=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[3]*n+r[6]*i,this.y=r[1]*e+r[4]*n+r[7]*i,this.z=r[2]*e+r[5]*n+r[8]*i,this}applyNormalMatrix(t){return this.applyMatrix3(t).normalize()}applyMatrix4(t){const e=this.x,n=this.y,i=this.z,r=t.elements,a=1/(r[3]*e+r[7]*n+r[11]*i+r[15]);return this.x=(r[0]*e+r[4]*n+r[8]*i+r[12])*a,this.y=(r[1]*e+r[5]*n+r[9]*i+r[13])*a,this.z=(r[2]*e+r[6]*n+r[10]*i+r[14])*a,this}applyQuaternion(t){const e=this.x,n=this.y,i=this.z,r=t.x,a=t.y,o=t.z,l=t.w,c=2*(a*i-o*n),u=2*(o*e-r*i),h=2*(r*n-a*e);return this.x=e+l*c+a*h-o*u,this.y=n+l*u+o*c-r*h,this.z=i+l*h+r*u-a*c,this}project(t){return this.applyMatrix4(t.matrixWorldInverse).applyMatrix4(t.projectionMatrix)}unproject(t){return this.applyMatrix4(t.projectionMatrixInverse).applyMatrix4(t.matrixWorld)}transformDirection(t){const e=this.x,n=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[4]*n+r[8]*i,this.y=r[1]*e+r[5]*n+r[9]*i,this.z=r[2]*e+r[6]*n+r[10]*i,this.normalize()}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this}divideScalar(t){return this.multiplyScalar(1/t)}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this.z=Math.min(this.z,t.z),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this.z=Math.max(this.z,t.z),this}clamp(t,e){return this.x=$t(this.x,t.x,e.x),this.y=$t(this.y,t.y,e.y),this.z=$t(this.z,t.z,e.z),this}clampScalar(t,e){return this.x=$t(this.x,t,e),this.y=$t(this.y,t,e),this.z=$t(this.z,t,e),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar($t(n,t,e))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(t){return this.x*t.x+this.y*t.y+this.z*t.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this.z+=(t.z-this.z)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this.z=t.z+(e.z-t.z)*n,this}cross(t){return this.crossVectors(this,t)}crossVectors(t,e){const n=t.x,i=t.y,r=t.z,a=e.x,o=e.y,l=e.z;return this.x=i*l-r*o,this.y=r*a-n*l,this.z=n*o-i*a,this}projectOnVector(t){const e=t.lengthSq();if(e===0)return this.set(0,0,0);const n=t.dot(this)/e;return this.copy(t).multiplyScalar(n)}projectOnPlane(t){return Co.copy(this).projectOnVector(t),this.sub(Co)}reflect(t){return this.sub(Co.copy(t).multiplyScalar(2*this.dot(t)))}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(e===0)return Math.PI/2;const n=this.dot(t)/e;return Math.acos($t(n,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y,i=this.z-t.z;return e*e+n*n+i*i}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)+Math.abs(this.z-t.z)}setFromSpherical(t){return this.setFromSphericalCoords(t.radius,t.phi,t.theta)}setFromSphericalCoords(t,e,n){const i=Math.sin(e)*t;return this.x=i*Math.sin(n),this.y=Math.cos(e)*t,this.z=i*Math.cos(n),this}setFromCylindrical(t){return this.setFromCylindricalCoords(t.radius,t.theta,t.y)}setFromCylindricalCoords(t,e,n){return this.x=t*Math.sin(e),this.y=n,this.z=t*Math.cos(e),this}setFromMatrixPosition(t){const e=t.elements;return this.x=e[12],this.y=e[13],this.z=e[14],this}setFromMatrixScale(t){const e=this.setFromMatrixColumn(t,0).length(),n=this.setFromMatrixColumn(t,1).length(),i=this.setFromMatrixColumn(t,2).length();return this.x=e,this.y=n,this.z=i,this}setFromMatrixColumn(t,e){return this.fromArray(t.elements,e*4)}setFromMatrix3Column(t,e){return this.fromArray(t.elements,e*3)}setFromEuler(t){return this.x=t._x,this.y=t._y,this.z=t._z,this}setFromColor(t){return this.x=t.r,this.y=t.g,this.z=t.b,this}equals(t){return t.x===this.x&&t.y===this.y&&t.z===this.z}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this.z=t[e+2],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t[e+2]=this.z,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this.z=t.getZ(e),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){const t=Math.random()*Math.PI*2,e=Math.random()*2-1,n=Math.sqrt(1-e*e);return this.x=n*Math.cos(t),this.y=e,this.z=n*Math.sin(t),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}};Bl.prototype.isVector3=!0;let C=Bl;const Co=new C,Sc=new Cn,zl=class zl{constructor(t,e,n,i,r,a,o,l,c){this.elements=[1,0,0,0,1,0,0,0,1],t!==void 0&&this.set(t,e,n,i,r,a,o,l,c)}set(t,e,n,i,r,a,o,l,c){const u=this.elements;return u[0]=t,u[1]=i,u[2]=o,u[3]=e,u[4]=r,u[5]=l,u[6]=n,u[7]=a,u[8]=c,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(t){const e=this.elements,n=t.elements;return e[0]=n[0],e[1]=n[1],e[2]=n[2],e[3]=n[3],e[4]=n[4],e[5]=n[5],e[6]=n[6],e[7]=n[7],e[8]=n[8],this}extractBasis(t,e,n){return t.setFromMatrix3Column(this,0),e.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(t){const e=t.elements;return this.set(e[0],e[4],e[8],e[1],e[5],e[9],e[2],e[6],e[10]),this}multiply(t){return this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const n=t.elements,i=e.elements,r=this.elements,a=n[0],o=n[3],l=n[6],c=n[1],u=n[4],h=n[7],d=n[2],f=n[5],p=n[8],v=i[0],m=i[3],g=i[6],w=i[1],E=i[4],M=i[7],S=i[2],b=i[5],R=i[8];return r[0]=a*v+o*w+l*S,r[3]=a*m+o*E+l*b,r[6]=a*g+o*M+l*R,r[1]=c*v+u*w+h*S,r[4]=c*m+u*E+h*b,r[7]=c*g+u*M+h*R,r[2]=d*v+f*w+p*S,r[5]=d*m+f*E+p*b,r[8]=d*g+f*M+p*R,this}multiplyScalar(t){const e=this.elements;return e[0]*=t,e[3]*=t,e[6]*=t,e[1]*=t,e[4]*=t,e[7]*=t,e[2]*=t,e[5]*=t,e[8]*=t,this}determinant(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],a=t[4],o=t[5],l=t[6],c=t[7],u=t[8];return e*a*u-e*o*c-n*r*u+n*o*l+i*r*c-i*a*l}invert(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],a=t[4],o=t[5],l=t[6],c=t[7],u=t[8],h=u*a-o*c,d=o*l-u*r,f=c*r-a*l,p=e*h+n*d+i*f;if(p===0)return this.set(0,0,0,0,0,0,0,0,0);const v=1/p;return t[0]=h*v,t[1]=(i*c-u*n)*v,t[2]=(o*n-i*a)*v,t[3]=d*v,t[4]=(u*e-i*l)*v,t[5]=(i*r-o*e)*v,t[6]=f*v,t[7]=(n*l-c*e)*v,t[8]=(a*e-n*r)*v,this}transpose(){let t;const e=this.elements;return t=e[1],e[1]=e[3],e[3]=t,t=e[2],e[2]=e[6],e[6]=t,t=e[5],e[5]=e[7],e[7]=t,this}getNormalMatrix(t){return this.setFromMatrix4(t).invert().transpose()}transposeIntoArray(t){const e=this.elements;return t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8],this}setUvTransform(t,e,n,i,r,a,o){const l=Math.cos(r),c=Math.sin(r);return this.set(n*l,n*c,-n*(l*a+c*o)+a+t,-i*c,i*l,-i*(-c*a+l*o)+o+e,0,0,1),this}scale(t,e){return qi("Matrix3: .scale() is deprecated. Use .makeScale() instead."),this.premultiply(Ro.makeScale(t,e)),this}rotate(t){return qi("Matrix3: .rotate() is deprecated. Use .makeRotation() instead."),this.premultiply(Ro.makeRotation(-t)),this}translate(t,e){return qi("Matrix3: .translate() is deprecated. Use .makeTranslation() instead."),this.premultiply(Ro.makeTranslation(t,e)),this}makeTranslation(t,e){return t.isVector2?this.set(1,0,t.x,0,1,t.y,0,0,1):this.set(1,0,t,0,1,e,0,0,1),this}makeRotation(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,-n,0,n,e,0,0,0,1),this}makeScale(t,e){return this.set(t,0,0,0,e,0,0,0,1),this}equals(t){const e=this.elements,n=t.elements;for(let i=0;i<9;i++)if(e[i]!==n[i])return!1;return!0}fromArray(t,e=0){for(let n=0;n<9;n++)this.elements[n]=t[n+e];return this}toArray(t=[],e=0){const n=this.elements;return t[e]=n[0],t[e+1]=n[1],t[e+2]=n[2],t[e+3]=n[3],t[e+4]=n[4],t[e+5]=n[5],t[e+6]=n[6],t[e+7]=n[7],t[e+8]=n[8],t}clone(){return new this.constructor().fromArray(this.elements)}};zl.prototype.isMatrix3=!0;let zt=zl;const Ro=new zt,bc=new zt().set(.4123908,.3575843,.1804808,.212639,.7151687,.0721923,.0193308,.1191948,.9505322),wc=new zt().set(3.2409699,-1.5373832,-.4986108,-.9692436,1.8759675,.0415551,.0556301,-.203977,1.0569715);function gf(){const s={enabled:!0,workingColorSpace:Ps,spaces:{},convert:function(i,r,a){return this.enabled===!1||r===a||!r||!a||(this.spaces[r].transfer===ie&&(i.r=zn(i.r),i.g=zn(i.g),i.b=zn(i.b)),this.spaces[r].primaries!==this.spaces[a].primaries&&(i.applyMatrix3(this.spaces[r].toXYZ),i.applyMatrix3(this.spaces[a].fromXYZ)),this.spaces[a].transfer===ie&&(i.r=Ji(i.r),i.g=Ji(i.g),i.b=Ji(i.b))),i},workingToColorSpace:function(i,r){return this.convert(i,this.workingColorSpace,r)},colorSpaceToWorking:function(i,r){return this.convert(i,r,this.workingColorSpace)},getPrimaries:function(i){return this.spaces[i].primaries},getTransfer:function(i){return i===ti?gr:this.spaces[i].transfer},getToneMappingMode:function(i){return this.spaces[i].outputColorSpaceConfig.toneMappingMode||"standard"},getLuminanceCoefficients:function(i,r=this.workingColorSpace){return i.fromArray(this.spaces[r].luminanceCoefficients)},define:function(i){Object.assign(this.spaces,i)},_getMatrix:function(i,r,a){return i.copy(this.spaces[r].toXYZ).multiply(this.spaces[a].fromXYZ)},_getDrawingBufferColorSpace:function(i){return this.spaces[i].outputColorSpaceConfig.drawingBufferColorSpace},_getUnpackColorSpace:function(i=this.workingColorSpace){return this.spaces[i].workingColorSpaceConfig.unpackColorSpace},fromWorkingColorSpace:function(i,r){return qi("ColorManagement: .fromWorkingColorSpace() has been renamed to .workingToColorSpace()."),s.workingToColorSpace(i,r)},toWorkingColorSpace:function(i,r){return qi("ColorManagement: .toWorkingColorSpace() has been renamed to .colorSpaceToWorking()."),s.colorSpaceToWorking(i,r)}},t=[.64,.33,.3,.6,.15,.06],e=[.2126,.7152,.0722],n=[.3127,.329];return s.define({[Ps]:{primaries:t,whitePoint:n,transfer:gr,toXYZ:bc,fromXYZ:wc,luminanceCoefficients:e,workingColorSpaceConfig:{unpackColorSpace:Se},outputColorSpaceConfig:{drawingBufferColorSpace:Se}},[Se]:{primaries:t,whitePoint:n,transfer:ie,toXYZ:bc,fromXYZ:wc,luminanceCoefficients:e,outputColorSpaceConfig:{drawingBufferColorSpace:Se}}}),s}const Kt=gf();function zn(s){return s<.04045?s*.0773993808:Math.pow(s*.9478672986+.0521327014,2.4)}function Ji(s){return s<.0031308?s*12.92:1.055*Math.pow(s,.41666)-.055}let Qi;class _f{static getDataURL(t,e="image/png"){if(/^data:/i.test(t.src)||typeof HTMLCanvasElement>"u")return t.src;let n;if(t instanceof HTMLCanvasElement)n=t;else{Qi===void 0&&(Qi=_r("canvas")),Qi.width=t.width,Qi.height=t.height;const i=Qi.getContext("2d");t instanceof ImageData?i.putImageData(t,0,0):i.drawImage(t,0,0,t.width,t.height),n=Qi}return n.toDataURL(e)}static sRGBToLinear(t){if(typeof HTMLImageElement<"u"&&t instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&t instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&t instanceof ImageBitmap){const e=_r("canvas");e.width=t.width,e.height=t.height;const n=e.getContext("2d");n.drawImage(t,0,0,t.width,t.height);const i=n.getImageData(0,0,t.width,t.height),r=i.data;for(let a=0;a1),this.pmremVersion=0,this.normalized=!1}get width(){return this.source.getSize(Do).x}get height(){return this.source.getSize(Do).y}get depth(){return this.source.getSize(Do).z}get image(){return this.source.data}set image(t){this.source.data=t}updateMatrix(){this.matrix.setUvTransform(this.offset.x,this.offset.y,this.repeat.x,this.repeat.y,this.rotation,this.center.x,this.center.y)}addUpdateRange(t,e){this.updateRanges.push({start:t,count:e})}clearUpdateRanges(){this.updateRanges.length=0}clone(){return new this.constructor().copy(this)}copy(t){return this.name=t.name,this.source=t.source,this.mipmaps=t.mipmaps.slice(0),this.mapping=t.mapping,this.channel=t.channel,this.wrapS=t.wrapS,this.wrapT=t.wrapT,this.magFilter=t.magFilter,this.minFilter=t.minFilter,this.anisotropy=t.anisotropy,this.format=t.format,this.internalFormat=t.internalFormat,this.type=t.type,this.normalized=t.normalized,this.offset.copy(t.offset),this.repeat.copy(t.repeat),this.center.copy(t.center),this.rotation=t.rotation,this.matrixAutoUpdate=t.matrixAutoUpdate,this.matrix.copy(t.matrix),this.generateMipmaps=t.generateMipmaps,this.premultiplyAlpha=t.premultiplyAlpha,this.flipY=t.flipY,this.unpackAlignment=t.unpackAlignment,this.colorSpace=t.colorSpace,this.renderTarget=t.renderTarget,this.isRenderTargetTexture=t.isRenderTargetTexture,this.isArrayTexture=t.isArrayTexture,this.userData=JSON.parse(JSON.stringify(t.userData)),this.needsUpdate=!0,this}setValues(t){for(const e in t){const n=t[e];if(n===void 0){Nt(`Texture.setValues(): parameter '${e}' has value of undefined.`);continue}const i=this[e];if(i===void 0){Nt(`Texture.setValues(): property '${e}' does not exist.`);continue}i&&n&&i.isVector2&&n.isVector2||i&&n&&i.isVector3&&n.isVector3||i&&n&&i.isMatrix3&&n.isMatrix3?i.copy(n):this[e]=n}}toJSON(t){const e=t===void 0||typeof t=="string";if(!e&&t.textures[this.uuid]!==void 0)return t.textures[this.uuid];const n={metadata:{version:4.7,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,image:this.source.toJSON(t).uuid,mapping:this.mapping,channel:this.channel,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],center:[this.center.x,this.center.y],rotation:this.rotation,wrap:[this.wrapS,this.wrapT],format:this.format,internalFormat:this.internalFormat,type:this.type,normalized:this.normalized,colorSpace:this.colorSpace,minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy,flipY:this.flipY,generateMipmaps:this.generateMipmaps,premultiplyAlpha:this.premultiplyAlpha,unpackAlignment:this.unpackAlignment};return Object.keys(this.userData).length>0&&(n.userData=this.userData),e||(t.textures[this.uuid]=n),n}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(t){if(this.mapping!==lc)return t;if(t.applyMatrix3(this.matrix),t.x<0||t.x>1)switch(this.wrapS){case lr:t.x=t.x-Math.floor(t.x);break;case kn:t.x=t.x<0?0:1;break;case ka:Math.abs(Math.floor(t.x)%2)===1?t.x=Math.ceil(t.x)-t.x:t.x=t.x-Math.floor(t.x);break}if(t.y<0||t.y>1)switch(this.wrapT){case lr:t.y=t.y-Math.floor(t.y);break;case kn:t.y=t.y<0?0:1;break;case ka:Math.abs(Math.floor(t.y)%2)===1?t.y=Math.ceil(t.y)-t.y:t.y=t.y-Math.floor(t.y);break}return this.flipY&&(t.y=1-t.y),t}set needsUpdate(t){t===!0&&(this.version++,this.source.needsUpdate=!0)}set needsPMREMUpdate(t){t===!0&&this.pmremVersion++}}Oe.DEFAULT_IMAGE=null,Oe.DEFAULT_MAPPING=lc,Oe.DEFAULT_ANISOTROPY=1;const Hl=class Hl{constructor(t=0,e=0,n=0,i=1){this.x=t,this.y=e,this.z=n,this.w=i}get width(){return this.z}set width(t){this.z=t}get height(){return this.w}set height(t){this.w=t}set(t,e,n,i){return this.x=t,this.y=e,this.z=n,this.w=i,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this.w=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setW(t){return this.w=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;case 3:this.w=e;break;default:throw new Error("THREE.Vector4: index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("THREE.Vector4: index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this.w=t.w!==void 0?t.w:1,this}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this.w+=t.w,this}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this.w+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this.w=t.w+e.w,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this.w+=t.w*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this.w-=t.w,this}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this.w-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this.w=t.w-e.w,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this.w*=t.w,this}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this.w*=t,this}applyMatrix4(t){const e=this.x,n=this.y,i=this.z,r=this.w,a=t.elements;return this.x=a[0]*e+a[4]*n+a[8]*i+a[12]*r,this.y=a[1]*e+a[5]*n+a[9]*i+a[13]*r,this.z=a[2]*e+a[6]*n+a[10]*i+a[14]*r,this.w=a[3]*e+a[7]*n+a[11]*i+a[15]*r,this}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this.w/=t.w,this}divideScalar(t){return this.multiplyScalar(1/t)}setAxisAngleFromQuaternion(t){this.w=2*Math.acos(t.w);const e=Math.sqrt(1-t.w*t.w);return e<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=t.x/e,this.y=t.y/e,this.z=t.z/e),this}setAxisAngleFromRotationMatrix(t){let e,n,i,r;const l=t.elements,c=l[0],u=l[4],h=l[8],d=l[1],f=l[5],p=l[9],v=l[2],m=l[6],g=l[10];if(Math.abs(u-d)<.01&&Math.abs(h-v)<.01&&Math.abs(p-m)<.01){if(Math.abs(u+d)<.1&&Math.abs(h+v)<.1&&Math.abs(p+m)<.1&&Math.abs(c+f+g-3)<.1)return this.set(1,0,0,0),this;e=Math.PI;const E=(c+1)/2,M=(f+1)/2,S=(g+1)/2,b=(u+d)/4,R=(h+v)/4,x=(p+m)/4;return E>M&&E>S?E<.01?(n=0,i=.707106781,r=.707106781):(n=Math.sqrt(E),i=b/n,r=R/n):M>S?M<.01?(n=.707106781,i=0,r=.707106781):(i=Math.sqrt(M),n=b/i,r=x/i):S<.01?(n=.707106781,i=.707106781,r=0):(r=Math.sqrt(S),n=R/r,i=x/r),this.set(n,i,r,e),this}let w=Math.sqrt((m-p)*(m-p)+(h-v)*(h-v)+(d-u)*(d-u));return Math.abs(w)<.001&&(w=1),this.x=(m-p)/w,this.y=(h-v)/w,this.z=(d-u)/w,this.w=Math.acos((c+f+g-1)/2),this}setFromMatrixPosition(t){const e=t.elements;return this.x=e[12],this.y=e[13],this.z=e[14],this.w=e[15],this}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this.z=Math.min(this.z,t.z),this.w=Math.min(this.w,t.w),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this.z=Math.max(this.z,t.z),this.w=Math.max(this.w,t.w),this}clamp(t,e){return this.x=$t(this.x,t.x,e.x),this.y=$t(this.y,t.y,e.y),this.z=$t(this.z,t.z,e.z),this.w=$t(this.w,t.w,e.w),this}clampScalar(t,e){return this.x=$t(this.x,t,e),this.y=$t(this.y,t,e),this.z=$t(this.z,t,e),this.w=$t(this.w,t,e),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar($t(n,t,e))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this.w=Math.floor(this.w),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this.w=Math.ceil(this.w),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this.w=Math.round(this.w),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this.w=Math.trunc(this.w),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this.w=-this.w,this}dot(t){return this.x*t.x+this.y*t.y+this.z*t.z+this.w*t.w}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)}normalize(){return this.divideScalar(this.length()||1)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this.z+=(t.z-this.z)*e,this.w+=(t.w-this.w)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this.z=t.z+(e.z-t.z)*n,this.w=t.w+(e.w-t.w)*n,this}equals(t){return t.x===this.x&&t.y===this.y&&t.z===this.z&&t.w===this.w}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this.z=t[e+2],this.w=t[e+3],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t[e+2]=this.z,t[e+3]=this.w,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this.z=t.getZ(e),this.w=t.getW(e),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this.w=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z,yield this.w}};Hl.prototype.isVector4=!0;let me=Hl;class Mf extends ei{constructor(t=1,e=1,n={}){super(),n=Object.assign({generateMipmaps:!1,internalFormat:null,minFilter:Ue,depthBuffer:!0,stencilBuffer:!1,resolveDepthBuffer:!0,resolveStencilBuffer:!0,depthTexture:null,samples:0,count:1,depth:1,multiview:!1,useArrayDepthTexture:!1},n),this.isRenderTarget=!0,this.width=t,this.height=e,this.depth=n.depth,this.scissor=new me(0,0,t,e),this.scissorTest=!1,this.viewport=new me(0,0,t,e),this.textures=[];const i={width:t,height:e,depth:n.depth},r=new Oe(i),a=n.count;for(let o=0;o1);this.dispose()}this.viewport.set(0,0,t,e),this.scissor.set(0,0,t,e)}clone(){return new this.constructor().copy(this)}copy(t){this.width=t.width,this.height=t.height,this.depth=t.depth,this.scissor.copy(t.scissor),this.scissorTest=t.scissorTest,this.viewport.copy(t.viewport),this.textures.length=0;for(let e=0,n=t.textures.length;e>>0}enable(t){this.mask|=1<1){for(let e=0;e1){for(let n=0;n0&&(i.userData=this.userData),i.layers=this.layers.mask,i.matrix=this.matrix.toArray(),i.up=this.up.toArray(),this.pivot!==null&&(i.pivot=this.pivot.toArray()),this.matrixAutoUpdate===!1&&(i.matrixAutoUpdate=!1),this.morphTargetDictionary!==void 0&&(i.morphTargetDictionary=Object.assign({},this.morphTargetDictionary)),this.morphTargetInfluences!==void 0&&(i.morphTargetInfluences=this.morphTargetInfluences.slice()),this.isInstancedMesh&&(i.type="InstancedMesh",i.count=this.count,i.instanceMatrix=this.instanceMatrix.toJSON(),this.instanceColor!==null&&(i.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(i.type="BatchedMesh",i.perObjectFrustumCulled=this.perObjectFrustumCulled,i.sortObjects=this.sortObjects,i.drawRanges=this._drawRanges,i.reservedRanges=this._reservedRanges,i.geometryInfo=this._geometryInfo.map(o=>({...o,boundingBox:o.boundingBox?o.boundingBox.toJSON():void 0,boundingSphere:o.boundingSphere?o.boundingSphere.toJSON():void 0})),i.instanceInfo=this._instanceInfo.map(o=>({...o})),i.availableInstanceIds=this._availableInstanceIds.slice(),i.availableGeometryIds=this._availableGeometryIds.slice(),i.nextIndexStart=this._nextIndexStart,i.nextVertexStart=this._nextVertexStart,i.geometryCount=this._geometryCount,i.maxInstanceCount=this._maxInstanceCount,i.maxVertexCount=this._maxVertexCount,i.maxIndexCount=this._maxIndexCount,i.geometryInitialized=this._geometryInitialized,i.matricesTexture=this._matricesTexture.toJSON(t),i.indirectTexture=this._indirectTexture.toJSON(t),this._colorsTexture!==null&&(i.colorsTexture=this._colorsTexture.toJSON(t)),this.boundingSphere!==null&&(i.boundingSphere=this.boundingSphere.toJSON()),this.boundingBox!==null&&(i.boundingBox=this.boundingBox.toJSON()));function r(o,l){return o[l.uuid]===void 0&&(o[l.uuid]=l.toJSON(t)),l.uuid}if(this.isScene)this.background&&(this.background.isColor?i.background=this.background.toJSON():this.background.isTexture&&(i.background=this.background.toJSON(t).uuid)),this.environment&&this.environment.isTexture&&this.environment.isRenderTargetTexture!==!0&&(i.environment=this.environment.toJSON(t).uuid);else if(this.isMesh||this.isLine||this.isPoints){i.geometry=r(t.geometries,this.geometry);const o=this.geometry.parameters;if(o!==void 0&&o.shapes!==void 0){const l=o.shapes;if(Array.isArray(l))for(let c=0,u=l.length;c0){i.children=[];for(let o=0;o0){i.animations=[];for(let o=0;o0&&(n.geometries=o),l.length>0&&(n.materials=l),c.length>0&&(n.textures=c),u.length>0&&(n.images=u),h.length>0&&(n.shapes=h),d.length>0&&(n.skeletons=d),f.length>0&&(n.animations=f),p.length>0&&(n.nodes=p)}return n.object=i,n;function a(o){const l=[];for(const c in o){const u=o[c];delete u.metadata,l.push(u)}return l}}clone(t){return new this.constructor().copy(this,t)}copy(t,e=!0){if(this.name=t.name,this.up.copy(t.up),this.position.copy(t.position),this.rotation.order=t.rotation.order,this.quaternion.copy(t.quaternion),this.scale.copy(t.scale),this.pivot=t.pivot!==null?t.pivot.clone():null,this.matrix.copy(t.matrix),this.matrixWorld.copy(t.matrixWorld),this.matrixAutoUpdate=t.matrixAutoUpdate,this.matrixWorldAutoUpdate=t.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=t.matrixWorldNeedsUpdate,this.layers.mask=t.layers.mask,this.visible=t.visible,this.castShadow=t.castShadow,this.receiveShadow=t.receiveShadow,this.frustumCulled=t.frustumCulled,this.renderOrder=t.renderOrder,this.static=t.static,this.animations=t.animations.slice(),this.userData=JSON.parse(JSON.stringify(t.userData)),e===!0)for(let n=0;nf+p?(c.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:t.handedness,target:this})):!c.inputState.pinching&&d<=f-p&&(c.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:t.handedness,target:this}))}else l!==null&&t.gripSpace&&(r=e.getPose(t.gripSpace,n),r!==null&&(l.matrix.fromArray(r.transform.matrix),l.matrix.decompose(l.position,l.rotation,l.scale),l.matrixWorldNeedsUpdate=!0,r.linearVelocity?(l.hasLinearVelocity=!0,l.linearVelocity.copy(r.linearVelocity)):l.hasLinearVelocity=!1,r.angularVelocity?(l.hasAngularVelocity=!0,l.angularVelocity.copy(r.angularVelocity)):l.hasAngularVelocity=!1,l.eventsEnabled&&l.dispatchEvent({type:"gripUpdated",data:t,target:this})));o!==null&&(i=e.getPose(t.targetRaySpace,n),i===null&&r!==null&&(i=r),i!==null&&(o.matrix.fromArray(i.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),o.matrixWorldNeedsUpdate=!0,i.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(i.linearVelocity)):o.hasLinearVelocity=!1,i.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(i.angularVelocity)):o.hasAngularVelocity=!1,this.dispatchEvent(Cf)))}return o!==null&&(o.visible=i!==null),l!==null&&(l.visible=r!==null),c!==null&&(c.visible=a!==null),this}_getHandJoint(t,e){if(t.joints[e.jointName]===void 0){const n=new pn;n.matrixAutoUpdate=!1,n.visible=!1,t.joints[e.jointName]=n,t.add(n)}return t.joints[e.jointName]}}const Ic={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},ii={h:0,s:0,l:0},yr={h:0,s:0,l:0};function Fo(s,t,e){return e<0&&(e+=1),e>1&&(e-=1),e<1/6?s+(t-s)*6*e:e<1/2?t:e<2/3?s+(t-s)*6*(2/3-e):s}class kt{constructor(t,e,n){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(t,e,n)}set(t,e,n){if(e===void 0&&n===void 0){const i=t;i&&i.isColor?this.copy(i):typeof i=="number"?this.setHex(i):typeof i=="string"&&this.setStyle(i)}else this.setRGB(t,e,n);return this}setScalar(t){return this.r=t,this.g=t,this.b=t,this}setHex(t,e=Se){return t=Math.floor(t),this.r=(t>>16&255)/255,this.g=(t>>8&255)/255,this.b=(t&255)/255,Kt.colorSpaceToWorking(this,e),this}setRGB(t,e,n,i=Kt.workingColorSpace){return this.r=t,this.g=e,this.b=n,Kt.colorSpaceToWorking(this,i),this}setHSL(t,e,n,i=Kt.workingColorSpace){if(t=Ao(t,1),e=$t(e,0,1),n=$t(n,0,1),e===0)this.r=this.g=this.b=n;else{const r=n<=.5?n*(1+e):n+e-n*e,a=2*n-r;this.r=Fo(a,r,t+1/3),this.g=Fo(a,r,t),this.b=Fo(a,r,t-1/3)}return Kt.colorSpaceToWorking(this,i),this}setStyle(t,e=Se){function n(r){r!==void 0&&parseFloat(r)<1&&Nt("Color: Alpha component of "+t+" will be ignored.")}let i;if(i=/^(\w+)\(([^\)]*)\)/.exec(t)){let r;const a=i[1],o=i[2];switch(a){case"rgb":case"rgba":if(r=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(r[4]),this.setRGB(Math.min(255,parseInt(r[1],10))/255,Math.min(255,parseInt(r[2],10))/255,Math.min(255,parseInt(r[3],10))/255,e);if(r=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(r[4]),this.setRGB(Math.min(100,parseInt(r[1],10))/100,Math.min(100,parseInt(r[2],10))/100,Math.min(100,parseInt(r[3],10))/100,e);break;case"hsl":case"hsla":if(r=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(o))return n(r[4]),this.setHSL(parseFloat(r[1])/360,parseFloat(r[2])/100,parseFloat(r[3])/100,e);break;default:Nt("Color: Unknown color model "+t)}}else if(i=/^\#([A-Fa-f\d]+)$/.exec(t)){const r=i[1],a=r.length;if(a===3)return this.setRGB(parseInt(r.charAt(0),16)/15,parseInt(r.charAt(1),16)/15,parseInt(r.charAt(2),16)/15,e);if(a===6)return this.setHex(parseInt(r,16),e);Nt("Color: Invalid hex color "+t)}else if(t&&t.length>0)return this.setColorName(t,e);return this}setColorName(t,e=Se){const n=Ic[t.toLowerCase()];return n!==void 0?this.setHex(n,e):Nt("Color: Unknown color "+t),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(t){return this.r=t.r,this.g=t.g,this.b=t.b,this}copySRGBToLinear(t){return this.r=zn(t.r),this.g=zn(t.g),this.b=zn(t.b),this}copyLinearToSRGB(t){return this.r=Ji(t.r),this.g=Ji(t.g),this.b=Ji(t.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(t=Se){return Kt.workingToColorSpace(ke.copy(this),t),Math.round($t(ke.r*255,0,255))*65536+Math.round($t(ke.g*255,0,255))*256+Math.round($t(ke.b*255,0,255))}getHexString(t=Se){return("000000"+this.getHex(t).toString(16)).slice(-6)}getHSL(t,e=Kt.workingColorSpace){Kt.workingToColorSpace(ke.copy(this),e);const n=ke.r,i=ke.g,r=ke.b,a=Math.max(n,i,r),o=Math.min(n,i,r);let l,c;const u=(o+a)/2;if(o===a)l=0,c=0;else{const h=a-o;switch(c=u<=.5?h/(a+o):h/(2-a-o),a){case n:l=(i-r)/h+(i0&&(e.object.backgroundBlurriness=this.backgroundBlurriness),this.backgroundIntensity!==1&&(e.object.backgroundIntensity=this.backgroundIntensity),e.object.backgroundRotation=this.backgroundRotation.toArray(),this.environmentIntensity!==1&&(e.object.environmentIntensity=this.environmentIntensity),e.object.environmentRotation=this.environmentRotation.toArray(),e}}const mn=new C,Vn=new C,ko=new C,Wn=new C,ns=new C,is=new C,Nc=new C,Bo=new C,zo=new C,Ho=new C,Go=new me,Vo=new me,Wo=new me;class gn{constructor(t=new C,e=new C,n=new C){this.a=t,this.b=e,this.c=n}static getNormal(t,e,n,i){i.subVectors(n,e),mn.subVectors(t,e),i.cross(mn);const r=i.lengthSq();return r>0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)}static getBarycoord(t,e,n,i,r){mn.subVectors(i,e),Vn.subVectors(n,e),ko.subVectors(t,e);const a=mn.dot(mn),o=mn.dot(Vn),l=mn.dot(ko),c=Vn.dot(Vn),u=Vn.dot(ko),h=a*c-o*o;if(h===0)return r.set(0,0,0),null;const d=1/h,f=(c*l-o*u)*d,p=(a*u-o*l)*d;return r.set(1-f-p,p,f)}static containsPoint(t,e,n,i){return this.getBarycoord(t,e,n,i,Wn)===null?!1:Wn.x>=0&&Wn.y>=0&&Wn.x+Wn.y<=1}static getInterpolation(t,e,n,i,r,a,o,l){return this.getBarycoord(t,e,n,i,Wn)===null?(l.x=0,l.y=0,"z"in l&&(l.z=0),"w"in l&&(l.w=0),null):(l.setScalar(0),l.addScaledVector(r,Wn.x),l.addScaledVector(a,Wn.y),l.addScaledVector(o,Wn.z),l)}static getInterpolatedAttribute(t,e,n,i,r,a){return Go.setScalar(0),Vo.setScalar(0),Wo.setScalar(0),Go.fromBufferAttribute(t,e),Vo.fromBufferAttribute(t,n),Wo.fromBufferAttribute(t,i),a.setScalar(0),a.addScaledVector(Go,r.x),a.addScaledVector(Vo,r.y),a.addScaledVector(Wo,r.z),a}static isFrontFacing(t,e,n,i){return mn.subVectors(n,e),Vn.subVectors(t,e),mn.cross(Vn).dot(i)<0}set(t,e,n){return this.a.copy(t),this.b.copy(e),this.c.copy(n),this}setFromPointsAndIndices(t,e,n,i){return this.a.copy(t[e]),this.b.copy(t[n]),this.c.copy(t[i]),this}setFromAttributeAndIndices(t,e,n,i){return this.a.fromBufferAttribute(t,e),this.b.fromBufferAttribute(t,n),this.c.fromBufferAttribute(t,i),this}clone(){return new this.constructor().copy(this)}copy(t){return this.a.copy(t.a),this.b.copy(t.b),this.c.copy(t.c),this}getArea(){return mn.subVectors(this.c,this.b),Vn.subVectors(this.a,this.b),mn.cross(Vn).length()*.5}getMidpoint(t){return t.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(t){return gn.getNormal(this.a,this.b,this.c,t)}getPlane(t){return t.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(t,e){return gn.getBarycoord(t,this.a,this.b,this.c,e)}getInterpolation(t,e,n,i,r){return gn.getInterpolation(t,this.a,this.b,this.c,e,n,i,r)}containsPoint(t){return gn.containsPoint(t,this.a,this.b,this.c)}isFrontFacing(t){return gn.isFrontFacing(this.a,this.b,this.c,t)}intersectsBox(t){return t.intersectsTriangle(this)}closestPointToPoint(t,e){const n=this.a,i=this.b,r=this.c;let a,o;ns.subVectors(i,n),is.subVectors(r,n),Bo.subVectors(t,n);const l=ns.dot(Bo),c=is.dot(Bo);if(l<=0&&c<=0)return e.copy(n);zo.subVectors(t,i);const u=ns.dot(zo),h=is.dot(zo);if(u>=0&&h<=u)return e.copy(i);const d=l*h-u*c;if(d<=0&&l>=0&&u<=0)return a=l/(l-u),e.copy(n).addScaledVector(ns,a);Ho.subVectors(t,r);const f=ns.dot(Ho),p=is.dot(Ho);if(p>=0&&f<=p)return e.copy(r);const v=f*c-l*p;if(v<=0&&c>=0&&p<=0)return o=c/(c-p),e.copy(n).addScaledVector(is,o);const m=u*p-f*h;if(m<=0&&h-u>=0&&f-p>=0)return Nc.subVectors(r,i),o=(h-u)/(h-u+(f-p)),e.copy(i).addScaledVector(Nc,o);const g=1/(m+v+d);return a=v*g,o=d*g,e.copy(n).addScaledVector(ns,a).addScaledVector(is,o)}equals(t){return t.a.equals(this.a)&&t.b.equals(this.b)&&t.c.equals(this.c)}}class Ri{constructor(t=new C(1/0,1/0,1/0),e=new C(-1/0,-1/0,-1/0)){this.isBox3=!0,this.min=t,this.max=e}set(t,e){return this.min.copy(t),this.max.copy(e),this}setFromArray(t){this.makeEmpty();for(let e=0,n=t.length;e=this.min.x&&t.x<=this.max.x&&t.y>=this.min.y&&t.y<=this.max.y&&t.z>=this.min.z&&t.z<=this.max.z}containsBox(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y&&this.min.z<=t.min.z&&t.max.z<=this.max.z}getParameter(t,e){return e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y),(t.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(t){return t.max.x>=this.min.x&&t.min.x<=this.max.x&&t.max.y>=this.min.y&&t.min.y<=this.max.y&&t.max.z>=this.min.z&&t.min.z<=this.max.z}intersectsSphere(t){return this.clampPoint(t.center,_n),_n.distanceToSquared(t.center)<=t.radius*t.radius}intersectsPlane(t){let e,n;return t.normal.x>0?(e=t.normal.x*this.min.x,n=t.normal.x*this.max.x):(e=t.normal.x*this.max.x,n=t.normal.x*this.min.x),t.normal.y>0?(e+=t.normal.y*this.min.y,n+=t.normal.y*this.max.y):(e+=t.normal.y*this.max.y,n+=t.normal.y*this.min.y),t.normal.z>0?(e+=t.normal.z*this.min.z,n+=t.normal.z*this.max.z):(e+=t.normal.z*this.max.z,n+=t.normal.z*this.min.z),e<=-t.constant&&n>=-t.constant}intersectsTriangle(t){if(this.isEmpty())return!1;this.getCenter(Us),br.subVectors(this.max,Us),ss.subVectors(t.a,Us),rs.subVectors(t.b,Us),as.subVectors(t.c,Us),si.subVectors(rs,ss),ri.subVectors(as,rs),Pi.subVectors(ss,as);let e=[0,-si.z,si.y,0,-ri.z,ri.y,0,-Pi.z,Pi.y,si.z,0,-si.x,ri.z,0,-ri.x,Pi.z,0,-Pi.x,-si.y,si.x,0,-ri.y,ri.x,0,-Pi.y,Pi.x,0];return!$o(e,ss,rs,as,br)||(e=[1,0,0,0,1,0,0,0,1],!$o(e,ss,rs,as,br))?!1:(wr.crossVectors(si,ri),e=[wr.x,wr.y,wr.z],$o(e,ss,rs,as,br))}clampPoint(t,e){return e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return this.clampPoint(t,_n).distanceTo(t)}getBoundingSphere(t){return this.isEmpty()?t.makeEmpty():(this.getCenter(t.center),t.radius=this.getSize(_n).length()*.5),t}intersect(t){return this.min.max(t.min),this.max.min(t.max),this.isEmpty()&&this.makeEmpty(),this}union(t){return this.min.min(t.min),this.max.max(t.max),this}applyMatrix4(t){return this.isEmpty()?this:($n[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(t),$n[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(t),$n[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(t),$n[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(t),$n[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(t),$n[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(t),$n[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(t),$n[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(t),this.setFromPoints($n),this)}translate(t){return this.min.add(t),this.max.add(t),this}equals(t){return t.min.equals(this.min)&&t.max.equals(this.max)}toJSON(){return{min:this.min.toArray(),max:this.max.toArray()}}fromJSON(t){return this.min.fromArray(t.min),this.max.fromArray(t.max),this}}const $n=[new C,new C,new C,new C,new C,new C,new C,new C],_n=new C,Sr=new Ri,ss=new C,rs=new C,as=new C,si=new C,ri=new C,Pi=new C,Us=new C,br=new C,wr=new C,Li=new C;function $o(s,t,e,n,i){for(let r=0,a=s.length-3;r<=a;r+=3){Li.fromArray(s,r);const o=i.x*Math.abs(Li.x)+i.y*Math.abs(Li.y)+i.z*Math.abs(Li.z),l=t.dot(Li),c=e.dot(Li),u=n.dot(Li);if(Math.max(-Math.max(l,c,u),Math.min(l,c,u))>o)return!1}return!0}const we=new C,Er=new ht;let Pf=0;class rn extends ei{constructor(t,e,n=!1){if(super(),Array.isArray(t))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,Object.defineProperty(this,"id",{value:Pf++}),this.name="",this.array=t,this.itemSize=e,this.count=t!==void 0?t.length/e:0,this.normalized=n,this.usage=gc,this.updateRanges=[],this.gpuType=un,this.version=0}onUploadCallback(){}set needsUpdate(t){t===!0&&this.version++}setUsage(t){return this.usage=t,this}addUpdateRange(t,e){this.updateRanges.push({start:t,count:e})}clearUpdateRanges(){this.updateRanges.length=0}copy(t){return this.name=t.name,this.array=new t.array.constructor(t.array),this.itemSize=t.itemSize,this.count=t.count,this.normalized=t.normalized,this.usage=t.usage,this.gpuType=t.gpuType,this}copyAt(t,e,n){t*=this.itemSize,n*=e.itemSize;for(let i=0,r=this.itemSize;ithis.radius*this.radius&&(e.sub(this.center).normalize(),e.multiplyScalar(this.radius).add(this.center)),e}getBoundingBox(t){return this.isEmpty()?(t.makeEmpty(),t):(t.set(this.center,this.center),t.expandByScalar(this.radius),t)}applyMatrix4(t){return this.center.applyMatrix4(t),this.radius=this.radius*t.getMaxScaleOnAxis(),this}translate(t){return this.center.add(t),this}expandByPoint(t){if(this.isEmpty())return this.center.copy(t),this.radius=0,this;Fs.subVectors(t,this.center);const e=Fs.lengthSq();if(e>this.radius*this.radius){const n=Math.sqrt(e),i=(n-this.radius)*.5;this.center.addScaledVector(Fs,i/n),this.radius+=i}return this}union(t){return t.isEmpty()?this:this.isEmpty()?(this.copy(t),this):(this.center.equals(t.center)===!0?this.radius=Math.max(this.radius,t.radius):(Xo.subVectors(t.center,this.center).setLength(t.radius),this.expandByPoint(Fs.copy(t.center).add(Xo)),this.expandByPoint(Fs.copy(t.center).sub(Xo))),this)}equals(t){return t.center.equals(this.center)&&t.radius===this.radius}clone(){return new this.constructor().copy(this)}toJSON(){return{radius:this.radius,center:this.center.toArray()}}fromJSON(t){return this.radius=t.radius,this.center.fromArray(t.center),this}}let Df=0;const an=new se,qo=new be,ls=new C,je=new Ri,Os=new Ri,De=new C;class Be extends ei{constructor(){super(),this.isBufferGeometry=!0,Object.defineProperty(this,"id",{value:Df++}),this.uuid=Ki(),this.name="",this.type="BufferGeometry",this.index=null,this.indirect=null,this.indirectOffset=0,this.attributes={},this.morphAttributes={},this.morphTargetsRelative=!1,this.groups=[],this.boundingBox=null,this.boundingSphere=null,this.drawRange={start:0,count:1/0},this.userData={},this._transformed=!1}getIndex(){return this.index}setIndex(t){return Array.isArray(t)?this.index=new(Kd(t)?Fc:Uc)(t,1):this.index=t,this}setIndirect(t,e=0){return this.indirect=t,this.indirectOffset=e,this}getIndirect(){return this.indirect}getAttribute(t){return this.attributes[t]}setAttribute(t,e){return this.attributes[t]=e,this}deleteAttribute(t){return delete this.attributes[t],this}hasAttribute(t){return this.attributes[t]!==void 0}addGroup(t,e,n=0){this.groups.push({start:t,count:e,materialIndex:n})}clearGroups(){this.groups=[]}setDrawRange(t,e){this.drawRange.start=t,this.drawRange.count=e}applyMatrix4(t){const e=this.attributes.position;e!==void 0&&(e.applyMatrix4(t),e.needsUpdate=!0);const n=this.attributes.normal;if(n!==void 0){const r=new zt().getNormalMatrix(t);n.applyNormalMatrix(r),n.needsUpdate=!0}const i=this.attributes.tangent;return i!==void 0&&(i.transformDirection(t),i.needsUpdate=!0),this.boundingBox!==null&&this.computeBoundingBox(),this.boundingSphere!==null&&this.computeBoundingSphere(),this._transformed=!0,this}applyQuaternion(t){return an.makeRotationFromQuaternion(t),this.applyMatrix4(an),this}rotateX(t){return an.makeRotationX(t),this.applyMatrix4(an),this}rotateY(t){return an.makeRotationY(t),this.applyMatrix4(an),this}rotateZ(t){return an.makeRotationZ(t),this.applyMatrix4(an),this}translate(t,e,n){return an.makeTranslation(t,e,n),this.applyMatrix4(an),this}scale(t,e,n){return an.makeScale(t,e,n),this.applyMatrix4(an),this}lookAt(t){return qo.lookAt(t),qo.updateMatrix(),this.applyMatrix4(qo.matrix),this}center(){return this.computeBoundingBox(),this.boundingBox.getCenter(ls).negate(),this.translate(ls.x,ls.y,ls.z),this}setFromPoints(t){const e=this.getAttribute("position");if(e===void 0){const n=[];for(let i=0,r=t.length;ie.count&&Nt("BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry."),e.needsUpdate=!0}return this}computeBoundingBox(){this.boundingBox===null&&(this.boundingBox=new Ri);const t=this.attributes.position,e=this.morphAttributes.position;if(t&&t.isGLBufferAttribute){Qt("BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.",this),this.boundingBox.set(new C(-1/0,-1/0,-1/0),new C(1/0,1/0,1/0));return}if(t!==void 0){if(this.boundingBox.setFromBufferAttribute(t),e)for(let n=0,i=e.length;n0&&(t.userData=this.userData),this.parameters!==void 0&&this._transformed!==!0){const l=this.parameters;for(const c in l)l[c]!==void 0&&(t[c]=l[c]);return t}t.data={attributes:{}};const e=this.index;e!==null&&(t.data.index={type:e.array.constructor.name,array:Array.prototype.slice.call(e.array)});const n=this.attributes;for(const l in n){const c=n[l];t.data.attributes[l]=c.toJSON(t.data)}const i={};let r=!1;for(const l in this.morphAttributes){const c=this.morphAttributes[l],u=[];for(let h=0,d=c.length;h0&&(i[l]=u,r=!0)}r&&(t.data.morphAttributes=i,t.data.morphTargetsRelative=this.morphTargetsRelative);const a=this.groups;a.length>0&&(t.data.groups=JSON.parse(JSON.stringify(a)));const o=this.boundingSphere;return o!==null&&(t.data.boundingSphere=o.toJSON()),t}clone(){return new this.constructor().copy(this)}copy(t){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const e={};this.name=t.name;const n=t.index;n!==null&&this.setIndex(n.clone());const i=t.attributes;for(const c in i){const u=i[c];this.setAttribute(c,u.clone(e))}const r=t.morphAttributes;for(const c in r){const u=[],h=r[c];for(let d=0,f=h.length;d0!=t>0&&this.version++,this._alphaTest=t}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(t){if(t!==void 0)for(const e in t){const n=t[e];if(n===void 0){Nt(`Material: parameter '${e}' has value of undefined.`);continue}const i=this[e];if(i===void 0){Nt(`Material: '${e}' is not a property of THREE.${this.type}.`);continue}i&&i.isColor?i.set(n):i&&i.isVector2&&n&&n.isVector2||i&&i.isEuler&&n&&n.isEuler||i&&i.isVector3&&n&&n.isVector3?i.copy(n):this[e]=n}}toJSON(t){const e=t===void 0||typeof t=="string";e&&(t={textures:{},images:{}});const n={metadata:{version:4.7,type:"Material",generator:"Material.toJSON"}};n.uuid=this.uuid,n.type=this.type,this.name!==""&&(n.name=this.name),this.color&&this.color.isColor&&(n.color=this.color.getHex()),this.roughness!==void 0&&(n.roughness=this.roughness),this.metalness!==void 0&&(n.metalness=this.metalness),this.sheen!==void 0&&(n.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(n.sheenColor=this.sheenColor.getHex()),this.sheenRoughness!==void 0&&(n.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(n.emissive=this.emissive.getHex()),this.emissiveIntensity!==void 0&&this.emissiveIntensity!==1&&(n.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(n.specular=this.specular.getHex()),this.specularIntensity!==void 0&&(n.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(n.specularColor=this.specularColor.getHex()),this.shininess!==void 0&&(n.shininess=this.shininess),this.clearcoat!==void 0&&(n.clearcoat=this.clearcoat),this.clearcoatRoughness!==void 0&&(n.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(n.clearcoatMap=this.clearcoatMap.toJSON(t).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(n.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(t).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(n.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(t).uuid,n.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),this.sheenColorMap&&this.sheenColorMap.isTexture&&(n.sheenColorMap=this.sheenColorMap.toJSON(t).uuid),this.sheenRoughnessMap&&this.sheenRoughnessMap.isTexture&&(n.sheenRoughnessMap=this.sheenRoughnessMap.toJSON(t).uuid),this.dispersion!==void 0&&(n.dispersion=this.dispersion),this.iridescence!==void 0&&(n.iridescence=this.iridescence),this.iridescenceIOR!==void 0&&(n.iridescenceIOR=this.iridescenceIOR),this.iridescenceThicknessRange!==void 0&&(n.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(n.iridescenceMap=this.iridescenceMap.toJSON(t).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(n.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(t).uuid),this.anisotropy!==void 0&&(n.anisotropy=this.anisotropy),this.anisotropyRotation!==void 0&&(n.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(n.anisotropyMap=this.anisotropyMap.toJSON(t).uuid),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(t).uuid),this.matcap&&this.matcap.isTexture&&(n.matcap=this.matcap.toJSON(t).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(t).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(t).uuid,n.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(n.aoMap=this.aoMap.toJSON(t).uuid,n.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(t).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(t).uuid,n.normalMapType=this.normalMapType,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(t).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(t).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(t).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(t).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(t).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(n.specularIntensityMap=this.specularIntensityMap.toJSON(t).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(n.specularColorMap=this.specularColorMap.toJSON(t).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(t).uuid,this.combine!==void 0&&(n.combine=this.combine)),this.envMapRotation!==void 0&&(n.envMapRotation=this.envMapRotation.toArray()),this.envMapIntensity!==void 0&&(n.envMapIntensity=this.envMapIntensity),this.reflectivity!==void 0&&(n.reflectivity=this.reflectivity),this.refractionRatio!==void 0&&(n.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(n.gradientMap=this.gradientMap.toJSON(t).uuid),this.transmission!==void 0&&(n.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(n.transmissionMap=this.transmissionMap.toJSON(t).uuid),this.thickness!==void 0&&(n.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(n.thicknessMap=this.thicknessMap.toJSON(t).uuid),this.attenuationDistance!==void 0&&this.attenuationDistance!==1/0&&(n.attenuationDistance=this.attenuationDistance),this.attenuationColor!==void 0&&(n.attenuationColor=this.attenuationColor.getHex()),this.size!==void 0&&(n.size=this.size),this.shadowSide!==null&&(n.shadowSide=this.shadowSide),this.sizeAttenuation!==void 0&&(n.sizeAttenuation=this.sizeAttenuation),this.blending!==Vi&&(n.blending=this.blending),this.side!==jn&&(n.side=this.side),this.vertexColors===!0&&(n.vertexColors=!0),this.opacity<1&&(n.opacity=this.opacity),this.transparent===!0&&(n.transparent=!0),this.blendSrc!==ya&&(n.blendSrc=this.blendSrc),this.blendDst!==Sa&&(n.blendDst=this.blendDst),this.blendEquation!==wi&&(n.blendEquation=this.blendEquation),this.blendSrcAlpha!==null&&(n.blendSrcAlpha=this.blendSrcAlpha),this.blendDstAlpha!==null&&(n.blendDstAlpha=this.blendDstAlpha),this.blendEquationAlpha!==null&&(n.blendEquationAlpha=this.blendEquationAlpha),this.blendColor&&this.blendColor.isColor&&(n.blendColor=this.blendColor.getHex()),this.blendAlpha!==0&&(n.blendAlpha=this.blendAlpha),this.depthFunc!==Wi&&(n.depthFunc=this.depthFunc),this.depthTest===!1&&(n.depthTest=this.depthTest),this.depthWrite===!1&&(n.depthWrite=this.depthWrite),this.colorWrite===!1&&(n.colorWrite=this.colorWrite),this.stencilWriteMask!==255&&(n.stencilWriteMask=this.stencilWriteMask),this.stencilFunc!==mc&&(n.stencilFunc=this.stencilFunc),this.stencilRef!==0&&(n.stencilRef=this.stencilRef),this.stencilFuncMask!==255&&(n.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==Xi&&(n.stencilFail=this.stencilFail),this.stencilZFail!==Xi&&(n.stencilZFail=this.stencilZFail),this.stencilZPass!==Xi&&(n.stencilZPass=this.stencilZPass),this.stencilWrite===!0&&(n.stencilWrite=this.stencilWrite),this.rotation!==void 0&&this.rotation!==0&&(n.rotation=this.rotation),this.polygonOffset===!0&&(n.polygonOffset=!0),this.polygonOffsetFactor!==0&&(n.polygonOffsetFactor=this.polygonOffsetFactor),this.polygonOffsetUnits!==0&&(n.polygonOffsetUnits=this.polygonOffsetUnits),this.linewidth!==void 0&&this.linewidth!==1&&(n.linewidth=this.linewidth),this.dashSize!==void 0&&(n.dashSize=this.dashSize),this.gapSize!==void 0&&(n.gapSize=this.gapSize),this.scale!==void 0&&(n.scale=this.scale),this.dithering===!0&&(n.dithering=!0),this.alphaTest>0&&(n.alphaTest=this.alphaTest),this.alphaHash===!0&&(n.alphaHash=!0),this.alphaToCoverage===!0&&(n.alphaToCoverage=!0),this.premultipliedAlpha===!0&&(n.premultipliedAlpha=!0),this.forceSinglePass===!0&&(n.forceSinglePass=!0),this.allowOverride===!1&&(n.allowOverride=!1),this.wireframe===!0&&(n.wireframe=!0),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),this.wireframeLinecap!=="round"&&(n.wireframeLinecap=this.wireframeLinecap),this.wireframeLinejoin!=="round"&&(n.wireframeLinejoin=this.wireframeLinejoin),this.flatShading===!0&&(n.flatShading=!0),this.visible===!1&&(n.visible=!1),this.toneMapped===!1&&(n.toneMapped=!1),this.fog===!1&&(n.fog=!1),Object.keys(this.userData).length>0&&(n.userData=this.userData);function i(r){const a=[];for(const o in r){const l=r[o];delete l.metadata,a.push(l)}return a}if(e){const r=i(t.textures),a=i(t.images);r.length>0&&(n.textures=r),a.length>0&&(n.images=a)}return n}fromJSON(t,e){if(t.uuid!==void 0&&(this.uuid=t.uuid),t.name!==void 0&&(this.name=t.name),t.color!==void 0&&this.color!==void 0&&this.color.setHex(t.color),t.roughness!==void 0&&(this.roughness=t.roughness),t.metalness!==void 0&&(this.metalness=t.metalness),t.sheen!==void 0&&(this.sheen=t.sheen),t.sheenColor!==void 0&&(this.sheenColor=new kt().setHex(t.sheenColor)),t.sheenRoughness!==void 0&&(this.sheenRoughness=t.sheenRoughness),t.emissive!==void 0&&this.emissive!==void 0&&this.emissive.setHex(t.emissive),t.specular!==void 0&&this.specular!==void 0&&this.specular.setHex(t.specular),t.specularIntensity!==void 0&&(this.specularIntensity=t.specularIntensity),t.specularColor!==void 0&&this.specularColor!==void 0&&this.specularColor.setHex(t.specularColor),t.shininess!==void 0&&(this.shininess=t.shininess),t.clearcoat!==void 0&&(this.clearcoat=t.clearcoat),t.clearcoatRoughness!==void 0&&(this.clearcoatRoughness=t.clearcoatRoughness),t.dispersion!==void 0&&(this.dispersion=t.dispersion),t.iridescence!==void 0&&(this.iridescence=t.iridescence),t.iridescenceIOR!==void 0&&(this.iridescenceIOR=t.iridescenceIOR),t.iridescenceThicknessRange!==void 0&&(this.iridescenceThicknessRange=t.iridescenceThicknessRange),t.transmission!==void 0&&(this.transmission=t.transmission),t.thickness!==void 0&&(this.thickness=t.thickness),t.attenuationDistance!==void 0&&(this.attenuationDistance=t.attenuationDistance),t.attenuationColor!==void 0&&this.attenuationColor!==void 0&&this.attenuationColor.setHex(t.attenuationColor),t.anisotropy!==void 0&&(this.anisotropy=t.anisotropy),t.anisotropyRotation!==void 0&&(this.anisotropyRotation=t.anisotropyRotation),t.fog!==void 0&&(this.fog=t.fog),t.flatShading!==void 0&&(this.flatShading=t.flatShading),t.blending!==void 0&&(this.blending=t.blending),t.combine!==void 0&&(this.combine=t.combine),t.side!==void 0&&(this.side=t.side),t.shadowSide!==void 0&&(this.shadowSide=t.shadowSide),t.opacity!==void 0&&(this.opacity=t.opacity),t.transparent!==void 0&&(this.transparent=t.transparent),t.alphaTest!==void 0&&(this.alphaTest=t.alphaTest),t.alphaHash!==void 0&&(this.alphaHash=t.alphaHash),t.depthFunc!==void 0&&(this.depthFunc=t.depthFunc),t.depthTest!==void 0&&(this.depthTest=t.depthTest),t.depthWrite!==void 0&&(this.depthWrite=t.depthWrite),t.colorWrite!==void 0&&(this.colorWrite=t.colorWrite),t.blendSrc!==void 0&&(this.blendSrc=t.blendSrc),t.blendDst!==void 0&&(this.blendDst=t.blendDst),t.blendEquation!==void 0&&(this.blendEquation=t.blendEquation),t.blendSrcAlpha!==void 0&&(this.blendSrcAlpha=t.blendSrcAlpha),t.blendDstAlpha!==void 0&&(this.blendDstAlpha=t.blendDstAlpha),t.blendEquationAlpha!==void 0&&(this.blendEquationAlpha=t.blendEquationAlpha),t.blendColor!==void 0&&this.blendColor!==void 0&&this.blendColor.setHex(t.blendColor),t.blendAlpha!==void 0&&(this.blendAlpha=t.blendAlpha),t.stencilWriteMask!==void 0&&(this.stencilWriteMask=t.stencilWriteMask),t.stencilFunc!==void 0&&(this.stencilFunc=t.stencilFunc),t.stencilRef!==void 0&&(this.stencilRef=t.stencilRef),t.stencilFuncMask!==void 0&&(this.stencilFuncMask=t.stencilFuncMask),t.stencilFail!==void 0&&(this.stencilFail=t.stencilFail),t.stencilZFail!==void 0&&(this.stencilZFail=t.stencilZFail),t.stencilZPass!==void 0&&(this.stencilZPass=t.stencilZPass),t.stencilWrite!==void 0&&(this.stencilWrite=t.stencilWrite),t.wireframe!==void 0&&(this.wireframe=t.wireframe),t.wireframeLinewidth!==void 0&&(this.wireframeLinewidth=t.wireframeLinewidth),t.wireframeLinecap!==void 0&&(this.wireframeLinecap=t.wireframeLinecap),t.wireframeLinejoin!==void 0&&(this.wireframeLinejoin=t.wireframeLinejoin),t.rotation!==void 0&&(this.rotation=t.rotation),t.linewidth!==void 0&&(this.linewidth=t.linewidth),t.dashSize!==void 0&&(this.dashSize=t.dashSize),t.gapSize!==void 0&&(this.gapSize=t.gapSize),t.scale!==void 0&&(this.scale=t.scale),t.polygonOffset!==void 0&&(this.polygonOffset=t.polygonOffset),t.polygonOffsetFactor!==void 0&&(this.polygonOffsetFactor=t.polygonOffsetFactor),t.polygonOffsetUnits!==void 0&&(this.polygonOffsetUnits=t.polygonOffsetUnits),t.dithering!==void 0&&(this.dithering=t.dithering),t.alphaToCoverage!==void 0&&(this.alphaToCoverage=t.alphaToCoverage),t.premultipliedAlpha!==void 0&&(this.premultipliedAlpha=t.premultipliedAlpha),t.forceSinglePass!==void 0&&(this.forceSinglePass=t.forceSinglePass),t.allowOverride!==void 0&&(this.allowOverride=t.allowOverride),t.visible!==void 0&&(this.visible=t.visible),t.toneMapped!==void 0&&(this.toneMapped=t.toneMapped),t.userData!==void 0&&(this.userData=t.userData),t.vertexColors!==void 0&&(typeof t.vertexColors=="number"?this.vertexColors=t.vertexColors>0:this.vertexColors=t.vertexColors),t.size!==void 0&&(this.size=t.size),t.sizeAttenuation!==void 0&&(this.sizeAttenuation=t.sizeAttenuation),t.map!==void 0&&(this.map=e[t.map]||null),t.matcap!==void 0&&(this.matcap=e[t.matcap]||null),t.alphaMap!==void 0&&(this.alphaMap=e[t.alphaMap]||null),t.bumpMap!==void 0&&(this.bumpMap=e[t.bumpMap]||null),t.bumpScale!==void 0&&(this.bumpScale=t.bumpScale),t.normalMap!==void 0&&(this.normalMap=e[t.normalMap]||null),t.normalMapType!==void 0&&(this.normalMapType=t.normalMapType),t.normalScale!==void 0){let n=t.normalScale;Array.isArray(n)===!1&&(n=[n,n]),this.normalScale=new ht().fromArray(n)}return t.displacementMap!==void 0&&(this.displacementMap=e[t.displacementMap]||null),t.displacementScale!==void 0&&(this.displacementScale=t.displacementScale),t.displacementBias!==void 0&&(this.displacementBias=t.displacementBias),t.roughnessMap!==void 0&&(this.roughnessMap=e[t.roughnessMap]||null),t.metalnessMap!==void 0&&(this.metalnessMap=e[t.metalnessMap]||null),t.emissiveMap!==void 0&&(this.emissiveMap=e[t.emissiveMap]||null),t.emissiveIntensity!==void 0&&(this.emissiveIntensity=t.emissiveIntensity),t.specularMap!==void 0&&(this.specularMap=e[t.specularMap]||null),t.specularIntensityMap!==void 0&&(this.specularIntensityMap=e[t.specularIntensityMap]||null),t.specularColorMap!==void 0&&(this.specularColorMap=e[t.specularColorMap]||null),t.envMap!==void 0&&(this.envMap=e[t.envMap]||null),t.envMapRotation!==void 0&&this.envMapRotation.fromArray(t.envMapRotation),t.envMapIntensity!==void 0&&(this.envMapIntensity=t.envMapIntensity),t.reflectivity!==void 0&&(this.reflectivity=t.reflectivity),t.refractionRatio!==void 0&&(this.refractionRatio=t.refractionRatio),t.lightMap!==void 0&&(this.lightMap=e[t.lightMap]||null),t.lightMapIntensity!==void 0&&(this.lightMapIntensity=t.lightMapIntensity),t.aoMap!==void 0&&(this.aoMap=e[t.aoMap]||null),t.aoMapIntensity!==void 0&&(this.aoMapIntensity=t.aoMapIntensity),t.gradientMap!==void 0&&(this.gradientMap=e[t.gradientMap]||null),t.clearcoatMap!==void 0&&(this.clearcoatMap=e[t.clearcoatMap]||null),t.clearcoatRoughnessMap!==void 0&&(this.clearcoatRoughnessMap=e[t.clearcoatRoughnessMap]||null),t.clearcoatNormalMap!==void 0&&(this.clearcoatNormalMap=e[t.clearcoatNormalMap]||null),t.clearcoatNormalScale!==void 0&&(this.clearcoatNormalScale=new ht().fromArray(t.clearcoatNormalScale)),t.iridescenceMap!==void 0&&(this.iridescenceMap=e[t.iridescenceMap]||null),t.iridescenceThicknessMap!==void 0&&(this.iridescenceThicknessMap=e[t.iridescenceThicknessMap]||null),t.transmissionMap!==void 0&&(this.transmissionMap=e[t.transmissionMap]||null),t.thicknessMap!==void 0&&(this.thicknessMap=e[t.thicknessMap]||null),t.anisotropyMap!==void 0&&(this.anisotropyMap=e[t.anisotropyMap]||null),t.sheenColorMap!==void 0&&(this.sheenColorMap=e[t.sheenColorMap]||null),t.sheenRoughnessMap!==void 0&&(this.sheenRoughnessMap=e[t.sheenRoughnessMap]||null),this}clone(){return new this.constructor().copy(this)}copy(t){this.name=t.name,this.blending=t.blending,this.side=t.side,this.vertexColors=t.vertexColors,this.opacity=t.opacity,this.transparent=t.transparent,this.blendSrc=t.blendSrc,this.blendDst=t.blendDst,this.blendEquation=t.blendEquation,this.blendSrcAlpha=t.blendSrcAlpha,this.blendDstAlpha=t.blendDstAlpha,this.blendEquationAlpha=t.blendEquationAlpha,this.blendColor.copy(t.blendColor),this.blendAlpha=t.blendAlpha,this.depthFunc=t.depthFunc,this.depthTest=t.depthTest,this.depthWrite=t.depthWrite,this.stencilWriteMask=t.stencilWriteMask,this.stencilFunc=t.stencilFunc,this.stencilRef=t.stencilRef,this.stencilFuncMask=t.stencilFuncMask,this.stencilFail=t.stencilFail,this.stencilZFail=t.stencilZFail,this.stencilZPass=t.stencilZPass,this.stencilWrite=t.stencilWrite;const e=t.clippingPlanes;let n=null;if(e!==null){const i=e.length;n=new Array(i);for(let r=0;r!==i;++r)n[r]=e[r].clone()}return this.clippingPlanes=n,this.clipIntersection=t.clipIntersection,this.clipShadows=t.clipShadows,this.shadowSide=t.shadowSide,this.colorWrite=t.colorWrite,this.precision=t.precision,this.polygonOffset=t.polygonOffset,this.polygonOffsetFactor=t.polygonOffsetFactor,this.polygonOffsetUnits=t.polygonOffsetUnits,this.dithering=t.dithering,this.alphaTest=t.alphaTest,this.alphaHash=t.alphaHash,this.alphaToCoverage=t.alphaToCoverage,this.premultipliedAlpha=t.premultipliedAlpha,this.forceSinglePass=t.forceSinglePass,this.allowOverride=t.allowOverride,this.visible=t.visible,this.toneMapped=t.toneMapped,this.userData=JSON.parse(JSON.stringify(t.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(t){t===!0&&this.version++}}const Xn=new C,Yo=new C,Tr=new C,ai=new C,Ko=new C,Ar=new C,Zo=new C;class Cr{constructor(t=new C,e=new C(0,0,-1)){this.origin=t,this.direction=e}set(t,e){return this.origin.copy(t),this.direction.copy(e),this}copy(t){return this.origin.copy(t.origin),this.direction.copy(t.direction),this}at(t,e){return e.copy(this.origin).addScaledVector(this.direction,t)}lookAt(t){return this.direction.copy(t).sub(this.origin).normalize(),this}recast(t){return this.origin.copy(this.at(t,Xn)),this}closestPointToPoint(t,e){e.subVectors(t,this.origin);const n=e.dot(this.direction);return n<0?e.copy(this.origin):e.copy(this.origin).addScaledVector(this.direction,n)}distanceToPoint(t){return Math.sqrt(this.distanceSqToPoint(t))}distanceSqToPoint(t){const e=Xn.subVectors(t,this.origin).dot(this.direction);return e<0?this.origin.distanceToSquared(t):(Xn.copy(this.origin).addScaledVector(this.direction,e),Xn.distanceToSquared(t))}distanceSqToSegment(t,e,n,i){Yo.copy(t).add(e).multiplyScalar(.5),Tr.copy(e).sub(t).normalize(),ai.copy(this.origin).sub(Yo);const r=t.distanceTo(e)*.5,a=-this.direction.dot(Tr),o=ai.dot(this.direction),l=-ai.dot(Tr),c=ai.lengthSq(),u=Math.abs(1-a*a);let h,d,f,p;if(u>0)if(h=a*l-o,d=a*o-l,p=r*u,h>=0)if(d>=-p)if(d<=p){const v=1/u;h*=v,d*=v,f=h*(h+a*d+2*o)+d*(a*h+d+2*l)+c}else d=r,h=Math.max(0,-(a*d+o)),f=-h*h+d*(d+2*l)+c;else d=-r,h=Math.max(0,-(a*d+o)),f=-h*h+d*(d+2*l)+c;else d<=-p?(h=Math.max(0,-(-a*r+o)),d=h>0?-r:Math.min(Math.max(-r,-l),r),f=-h*h+d*(d+2*l)+c):d<=p?(h=0,d=Math.min(Math.max(-r,-l),r),f=d*(d+2*l)+c):(h=Math.max(0,-(a*r+o)),d=h>0?r:Math.min(Math.max(-r,-l),r),f=-h*h+d*(d+2*l)+c);else d=a>0?-r:r,h=Math.max(0,-(a*d+o)),f=-h*h+d*(d+2*l)+c;return n&&n.copy(this.origin).addScaledVector(this.direction,h),i&&i.copy(Yo).addScaledVector(Tr,d),f}intersectSphere(t,e){Xn.subVectors(t.center,this.origin);const n=Xn.dot(this.direction),i=Xn.dot(Xn)-n*n,r=t.radius*t.radius;if(i>r)return null;const a=Math.sqrt(r-i),o=n-a,l=n+a;return l<0?null:o<0?this.at(l,e):this.at(o,e)}intersectsSphere(t){return t.radius<0?!1:this.distanceSqToPoint(t.center)<=t.radius*t.radius}distanceToPlane(t){const e=t.normal.dot(this.direction);if(e===0)return t.distanceToPoint(this.origin)===0?0:null;const n=-(this.origin.dot(t.normal)+t.constant)/e;return n>=0?n:null}intersectPlane(t,e){const n=this.distanceToPlane(t);return n===null?null:this.at(n,e)}intersectsPlane(t){const e=t.distanceToPoint(this.origin);return e===0||t.normal.dot(this.direction)*e<0}intersectBox(t,e){let n,i,r,a,o,l;const c=1/this.direction.x,u=1/this.direction.y,h=1/this.direction.z,d=this.origin;return c>=0?(n=(t.min.x-d.x)*c,i=(t.max.x-d.x)*c):(n=(t.max.x-d.x)*c,i=(t.min.x-d.x)*c),u>=0?(r=(t.min.y-d.y)*u,a=(t.max.y-d.y)*u):(r=(t.max.y-d.y)*u,a=(t.min.y-d.y)*u),n>a||r>i||((r>n||isNaN(n))&&(n=r),(a=0?(o=(t.min.z-d.z)*h,l=(t.max.z-d.z)*h):(o=(t.max.z-d.z)*h,l=(t.min.z-d.z)*h),n>l||o>i)||((o>n||n!==n)&&(n=o),(l=0?n:i,e)}intersectsBox(t){return this.intersectBox(t,Xn)!==null}intersectTriangle(t,e,n,i,r){Ko.subVectors(e,t),Ar.subVectors(n,t),Zo.crossVectors(Ko,Ar);let a=this.direction.dot(Zo),o;if(a>0){if(i)return null;o=1}else if(a<0)o=-1,a=-a;else return null;ai.subVectors(this.origin,t);const l=o*this.direction.dot(Ar.crossVectors(ai,Ar));if(l<0)return null;const c=o*this.direction.dot(Ko.cross(ai));if(c<0||l+c>a)return null;const u=-o*ai.dot(Zo);return u<0?null:this.at(u/a,r)}applyMatrix4(t){return this.origin.applyMatrix4(t),this.direction.transformDirection(t),this}equals(t){return t.origin.equals(this.origin)&&t.direction.equals(this.direction)}clone(){return new this.constructor().copy(this)}}class xn extends cs{constructor(t){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new kt(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new Hn,this.combine=oc,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.envMapRotation.copy(t.envMapRotation),this.combine=t.combine,this.reflectivity=t.reflectivity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.fog=t.fog,this}}const Oc=new se,Di=new Cr,Rr=new os,kc=new C,Pr=new C,Lr=new C,Dr=new C,Jo=new C,Ir=new C,Bc=new C,Nr=new C;class Bt extends be{constructor(t=new Be,e=new xn){super(),this.isMesh=!0,this.type="Mesh",this.geometry=t,this.material=e,this.morphTargetDictionary=void 0,this.morphTargetInfluences=void 0,this.count=1,this.updateMorphTargets()}copy(t,e){return super.copy(t,e),t.morphTargetInfluences!==void 0&&(this.morphTargetInfluences=t.morphTargetInfluences.slice()),t.morphTargetDictionary!==void 0&&(this.morphTargetDictionary=Object.assign({},t.morphTargetDictionary)),this.material=Array.isArray(t.material)?t.material.slice():t.material,this.geometry=t.geometry,this}updateMorphTargets(){const e=this.geometry.morphAttributes,n=Object.keys(e);if(n.length>0){const i=e[n[0]];if(i!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,a=i.length;r(t.far-t.near)**2))&&(Oc.copy(r).invert(),Di.copy(t.ray).applyMatrix4(Oc),!(n.boundingBox!==null&&Di.intersectsBox(n.boundingBox)===!1)&&this._computeIntersections(t,e,Di)))}_computeIntersections(t,e,n){let i;const r=this.geometry,a=this.material,o=r.index,l=r.attributes.position,c=r.attributes.uv,u=r.attributes.uv1,h=r.attributes.normal,d=r.groups,f=r.drawRange;if(o!==null)if(Array.isArray(a))for(let p=0,v=d.length;pe.far?null:{distance:c,point:Nr.clone(),object:s}}function Ur(s,t,e,n,i,r,a,o,l,c){s.getVertexPosition(o,Pr),s.getVertexPosition(l,Lr),s.getVertexPosition(c,Dr);const u=Nf(s,t,e,n,Pr,Lr,Dr,Bc);if(u){const h=new C;gn.getBarycoord(Bc,Pr,Lr,Dr,h),i&&(u.uv=gn.getInterpolatedAttribute(i,o,l,c,h,new ht)),r&&(u.uv1=gn.getInterpolatedAttribute(r,o,l,c,h,new ht)),a&&(u.normal=gn.getInterpolatedAttribute(a,o,l,c,h,new C),u.normal.dot(n.direction)>0&&u.normal.multiplyScalar(-1));const d={a:o,b:l,c,normal:new C,materialIndex:0};gn.getNormal(Pr,Lr,Dr,d.normal),u.face=d,u.barycoord=h}return u}class zc extends Oe{constructor(t=null,e=1,n=1,i,r,a,o,l,c=Ne,u=Ne,h,d){super(null,a,o,l,c,u,i,r,h,d),this.isDataTexture=!0,this.image={data:t,width:e,height:n},this.generateMipmaps=!1,this.flipY=!1,this.unpackAlignment=1}}class ks extends rn{constructor(t,e,n,i=1){super(t,e,n),this.isInstancedBufferAttribute=!0,this.meshPerAttribute=i}copy(t){return super.copy(t),this.meshPerAttribute=t.meshPerAttribute,this}toJSON(){const t=super.toJSON();return t.meshPerAttribute=this.meshPerAttribute,t.isInstancedBufferAttribute=!0,t}}const hs=new se,Hc=new se,Fr=[],Gc=new Ri,Uf=new se,Bs=new Bt,zs=new os;class Vc extends Bt{constructor(t,e,n){super(t,e),this.isInstancedMesh=!0,this.instanceMatrix=new ks(new Float32Array(n*16),16),this.instanceColor=null,this.morphTexture=null,this.count=n,this.boundingBox=null,this.boundingSphere=null;for(let i=0;i1)?null:e.copy(t.start).addScaledVector(i,a)}intersectsLine(t){const e=this.distanceToPoint(t.start),n=this.distanceToPoint(t.end);return e<0&&n>0||n<0&&e>0}intersectsBox(t){return t.intersectsPlane(this)}intersectsSphere(t){return t.intersectsPlane(this)}coplanarPoint(t){return t.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(t,e){const n=e||Of.getNormalMatrix(t),i=this.coplanarPoint(Qo).applyMatrix4(t),r=this.normal.applyMatrix3(n).normalize();return this.constant=-i.dot(r),this}translate(t){return this.constant-=t.dot(this.normal),this}equals(t){return t.normal.equals(this.normal)&&t.constant===this.constant}clone(){return new this.constructor().copy(this)}}const Ii=new os,kf=new ht(.5,.5),Or=new C;class kr{constructor(t=new oi,e=new oi,n=new oi,i=new oi,r=new oi,a=new oi){this.planes=[t,e,n,i,r,a]}set(t,e,n,i,r,a){const o=this.planes;return o[0].copy(t),o[1].copy(e),o[2].copy(n),o[3].copy(i),o[4].copy(r),o[5].copy(a),this}copy(t){const e=this.planes;for(let n=0;n<6;n++)e[n].copy(t.planes[n]);return this}setFromProjectionMatrix(t,e=An,n=!1){const i=this.planes,r=t.elements,a=r[0],o=r[1],l=r[2],c=r[3],u=r[4],h=r[5],d=r[6],f=r[7],p=r[8],v=r[9],m=r[10],g=r[11],w=r[12],E=r[13],M=r[14],S=r[15];if(i[0].setComponents(c-a,f-u,g-p,S-w).normalize(),i[1].setComponents(c+a,f+u,g+p,S+w).normalize(),i[2].setComponents(c+o,f+h,g+v,S+E).normalize(),i[3].setComponents(c-o,f-h,g-v,S-E).normalize(),n)i[4].setComponents(l,d,m,M).normalize(),i[5].setComponents(c-l,f-d,g-m,S-M).normalize();else if(i[4].setComponents(c-l,f-d,g-m,S-M).normalize(),e===An)i[5].setComponents(c+l,f+d,g+m,S+M).normalize();else if(e===Ls)i[5].setComponents(l,d,m,M).normalize();else throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+e);return this}intersectsObject(t){if(t.boundingSphere!==void 0)t.boundingSphere===null&&t.computeBoundingSphere(),Ii.copy(t.boundingSphere).applyMatrix4(t.matrixWorld);else{const e=t.geometry;e.boundingSphere===null&&e.computeBoundingSphere(),Ii.copy(e.boundingSphere).applyMatrix4(t.matrixWorld)}return this.intersectsSphere(Ii)}intersectsSprite(t){Ii.center.set(0,0,0);const e=kf.distanceTo(t.center);return Ii.radius=.7071067811865476+e,Ii.applyMatrix4(t.matrixWorld),this.intersectsSphere(Ii)}intersectsSphere(t){const e=this.planes,n=t.center,i=-t.radius;for(let r=0;r<6;r++)if(e[r].distanceToPoint(n)0?t.max.x:t.min.x,Or.y=i.normal.y>0?t.max.y:t.min.y,Or.z=i.normal.z>0?t.max.z:t.min.z,i.distanceToPoint(Or)<0)return!1}return!0}containsPoint(t){const e=this.planes;for(let n=0;n<6;n++)if(e[n].distanceToPoint(t)<0)return!1;return!0}clone(){return new this.constructor().copy(this)}}class Wc extends cs{constructor(t){super(),this.isLineBasicMaterial=!0,this.type="LineBasicMaterial",this.color=new kt(16777215),this.map=null,this.linewidth=1,this.linecap="round",this.linejoin="round",this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.linewidth=t.linewidth,this.linecap=t.linecap,this.linejoin=t.linejoin,this.fog=t.fog,this}}const Br=new C,zr=new C,$c=new se,Hs=new Cr,Hr=new os,jo=new C,Xc=new C;class qc extends be{constructor(t=new Be,e=new Wc){super(),this.isLine=!0,this.type="Line",this.geometry=t,this.material=e,this.morphTargetDictionary=void 0,this.morphTargetInfluences=void 0,this.updateMorphTargets()}copy(t,e){return super.copy(t,e),this.material=Array.isArray(t.material)?t.material.slice():t.material,this.geometry=t.geometry,this}computeLineDistances(){const t=this.geometry;if(t.index===null){const e=t.attributes.position,n=[0];for(let i=1,r=e.count;i0){const i=e[n[0]];if(i!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,a=i.length;rn)return;jo.applyMatrix4(s.matrixWorld);const c=t.ray.origin.distanceTo(jo);if(!(ct.far))return{distance:c,point:Xc.clone().applyMatrix4(s.matrixWorld),index:a,face:null,faceIndex:null,barycoord:null,object:s}}class Yc extends Oe{constructor(t=[],e=Ei,n,i,r,a,o,l,c,u){super(t,e,n,i,r,a,o,l,c,u),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(t){this.image=t}}class li extends Oe{constructor(t,e,n,i,r,a,o,l,c){super(t,e,n,i,r,a,o,l,c),this.isCanvasTexture=!0,this.needsUpdate=!0}}class us extends Oe{constructor(t,e,n=Tn,i,r,a,o=Ne,l=Ne,c,u=Bn,h=1){if(u!==Bn&&u!==Ai)throw new Error("THREE.DepthTexture: format must be either THREE.DepthFormat or THREE.DepthStencilFormat");const d={width:t,height:e,depth:h};super(d,i,r,a,o,l,u,n,c),this.isDepthTexture=!0,this.flipY=!1,this.generateMipmaps=!1,this.compareFunction=null}copy(t){return super.copy(t),this.source=new Po(Object.assign({},t.image)),this.compareFunction=t.compareFunction,this}toJSON(t){const e=super.toJSON(t);return this.compareFunction!==null&&(e.compareFunction=this.compareFunction),e}}class Bf extends us{constructor(t,e=Tn,n=Ei,i,r,a=Ne,o=Ne,l,c=Bn){const u={width:t,height:t,depth:1},h=[u,u,u,u,u,u];super(t,t,e,n,i,r,a,o,l,c),this.image=h,this.isCubeDepthTexture=!0,this.isCubeTexture=!0}get images(){return this.image}set images(t){this.image=t}}class Kc extends Oe{constructor(t=null){super(),this.sourceTexture=t,this.isExternalTexture=!0}copy(t){return super.copy(t),this.sourceTexture=t.sourceTexture,this}}class tn extends Be{constructor(t=1,e=1,n=1,i=1,r=1,a=1){super(),this.type="BoxGeometry",this.parameters={width:t,height:e,depth:n,widthSegments:i,heightSegments:r,depthSegments:a};const o=this;i=Math.floor(i),r=Math.floor(r),a=Math.floor(a);const l=[],c=[],u=[],h=[];let d=0,f=0;p("z","y","x",-1,-1,n,e,t,a,r,0),p("z","y","x",1,-1,n,e,-t,a,r,1),p("x","z","y",1,1,t,n,e,i,a,2),p("x","z","y",1,-1,t,n,-e,i,a,3),p("x","y","z",1,-1,t,e,n,i,r,4),p("x","y","z",-1,-1,t,e,-n,i,r,5),this.setIndex(l),this.setAttribute("position",new ve(c,3)),this.setAttribute("normal",new ve(u,3)),this.setAttribute("uv",new ve(h,2));function p(v,m,g,w,E,M,S,b,R,x,T){const P=M/R,L=S/x,F=M/2,q=S/2,Y=b/2,B=R+1,K=x+1;let X=0,Q=0;const it=new C;for(let pt=0;pt0?1:-1,u.push(it.x,it.y,it.z),h.push(bt/R),h.push(1-pt/x),X+=1}}for(let pt=0;pt0&&E(!0),e>0&&E(!1)),this.setIndex(u),this.setAttribute("position",new ve(h,3)),this.setAttribute("normal",new ve(d,3)),this.setAttribute("uv",new ve(f,2));function w(){const M=new C,S=new C;let b=0;const R=(e-t)/n;for(let x=0;x<=r;x++){const T=[],P=x/r,L=P*(e-t)+t;for(let F=0;F<=i;F++){const q=F/i,Y=q*l+o,B=Math.sin(Y),K=Math.cos(Y);S.x=L*B,S.y=-P*n+m,S.z=L*K,h.push(S.x,S.y,S.z),M.set(B,R,K).normalize(),d.push(M.x,M.y,M.z),f.push(q,1-P),T.push(p++)}v.push(T)}for(let x=0;x0||T!==0)&&(u.push(P,L,q),b+=3),(e>0||T!==r-1)&&(u.push(L,F,q),b+=3)}c.addGroup(g,b,0),g+=b}function E(M){const S=p,b=new ht,R=new C;let x=0;const T=M===!0?t:e,P=M===!0?1:-1;for(let F=1;F<=i;F++)h.push(0,m*P,0),d.push(0,P,0),f.push(.5,.5),p++;const L=p;for(let F=0;F<=i;F++){const Y=F/i*l+o,B=Math.cos(Y),K=Math.sin(Y);R.x=T*K,R.y=m*P,R.z=T*B,h.push(R.x,R.y,R.z),d.push(0,P,0),b.x=B*.5+.5,b.y=K*.5*P+.5,f.push(b.x,b.y),p++}for(let F=0;F0)l=i-1;else{l=i;break}if(i=l,n[i]===a)return i/(r-1);const u=n[i],d=n[i+1]-u,f=(a-u)/d;return(i+f)/(r-1)}getTangent(t,e){let i=t-1e-4,r=t+1e-4;i<0&&(i=0),r>1&&(r=1);const a=this.getPoint(i),o=this.getPoint(r),l=e||(a.isVector2?new ht:new C);return l.copy(o).sub(a).normalize(),l}getTangentAt(t,e){const n=this.getUtoTmapping(t);return this.getTangent(n,e)}computeFrenetFrames(t,e=!1){const n=new C,i=[],r=[],a=[],o=new C,l=new se;for(let f=0;f<=t;f++){const p=f/t;i[f]=this.getTangentAt(p,new C)}r[0]=new C,a[0]=new C;let c=Number.MAX_VALUE;const u=Math.abs(i[0].x),h=Math.abs(i[0].y),d=Math.abs(i[0].z);u<=c&&(c=u,n.set(1,0,0)),h<=c&&(c=h,n.set(0,1,0)),d<=c&&n.set(0,0,1),o.crossVectors(i[0],n).normalize(),r[0].crossVectors(i[0],o),a[0].crossVectors(i[0],r[0]);for(let f=1;f<=t;f++){if(r[f]=r[f-1].clone(),a[f]=a[f-1].clone(),o.crossVectors(i[f-1],i[f]),o.length()>Number.EPSILON){o.normalize();const p=Math.acos($t(i[f-1].dot(i[f]),-1,1));r[f].applyMatrix4(l.makeRotationAxis(o,p))}a[f].crossVectors(i[f],r[f])}if(e===!0){let f=Math.acos($t(r[0].dot(r[t]),-1,1));f/=t,i[0].dot(o.crossVectors(r[0],r[t]))>0&&(f=-f);for(let p=1;p<=t;p++)r[p].applyMatrix4(l.makeRotationAxis(i[p],f*p)),a[p].crossVectors(i[p],r[p])}return{tangents:i,normals:r,binormals:a}}clone(){return new this.constructor().copy(this)}copy(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}toJSON(){const t={metadata:{version:4.7,type:"Curve",generator:"Curve.toJSON"}};return t.arcLengthDivisions=this.arcLengthDivisions,t.type=this.type,t}fromJSON(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}}class Zc extends qn{constructor(t=0,e=0,n=1,i=1,r=0,a=Math.PI*2,o=!1,l=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=t,this.aY=e,this.xRadius=n,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=a,this.aClockwise=o,this.aRotation=l}getPoint(t,e=new ht){const n=e,i=Math.PI*2;let r=this.aEndAngle-this.aStartAngle;const a=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(o)/r)+1)*r:l===0&&o===r-1&&(o=r-2,l=1);let c,u;this.closed||o>0?c=i[(o-1)%r]:(Qc.subVectors(i[0],i[1]).add(i[0]),c=Qc);const h=i[o%r],d=i[(o+1)%r];if(this.closed||o+2i.length-2?i.length-1:a+1],h=i[a>i.length-3?i.length-1:a+2];return n.set(th(o,l.x,c.x,u.x,h.x),th(o,l.y,c.y,u.y,h.y)),n}copy(t){super.copy(t),this.points=[];for(let e=0,n=t.points.length;e0)&&f.push(E,M,b),(g!==n-1||l=0;--t)if(s[t]>=65535)return!0;return!1}function kr(s){return document.createElementNS("http://www.w3.org/1999/xhtml",s)}function fp(){const s=kr("canvas");return s.style.display="block",s}const lh={};function ch(...s){const t="THREE."+s.shift();console.log(t,...s)}function hh(s){const t=s[0];if(typeof t=="string"&&t.startsWith("TSL:")){const e=s[1];e&&e.isStackTrace?s[0]+=" "+e.getLocation():s[1]='Stack trace not available. Enable "THREE.Node.captureStackTrace" to capture stack traces.'}return s}function Ut(...s){s=hh(s);const t="THREE."+s.shift();{const e=s[0];e&&e.isStackTrace?console.warn(e.getError(t)):console.warn(t,...s)}}function te(...s){s=hh(s);const t="THREE."+s.shift();{const e=s[0];e&&e.isStackTrace?console.error(e.getError(t)):console.error(t,...s)}}function ls(...s){const t=s.join(" ");t in lh||(lh[t]=!0,Ut(...s))}function pp(s,t,e){return new Promise(function(n,i){function r(){switch(s.clientWaitSync(t,s.SYNC_FLUSH_COMMANDS_BIT,0)){case s.WAIT_FAILED:i();break;case s.TIMEOUT_EXPIRED:setTimeout(r,e);break;default:n()}}setTimeout(r,e)})}const mp={[Qo]:ta,[ea]:sa,[na]:ra,[rs]:ia,[ta]:Qo,[sa]:ea,[ra]:na,[ia]:rs};class li{addEventListener(t,e){this._listeners===void 0&&(this._listeners={});const n=this._listeners;n[t]===void 0&&(n[t]=[]),n[t].indexOf(e)===-1&&n[t].push(e)}hasEventListener(t,e){const n=this._listeners;return n===void 0?!1:n[t]!==void 0&&n[t].indexOf(e)!==-1}removeEventListener(t,e){const n=this._listeners;if(n===void 0)return;const i=n[t];if(i!==void 0){const r=i.indexOf(e);r!==-1&&i.splice(r,1)}}dispatchEvent(t){const e=this._listeners;if(e===void 0)return;const n=e[t.type];if(n!==void 0){t.target=this;const i=n.slice(0);for(let r=0,o=i.length;r>8&255]+ke[s>>16&255]+ke[s>>24&255]+"-"+ke[t&255]+ke[t>>8&255]+"-"+ke[t>>16&15|64]+ke[t>>24&255]+"-"+ke[e&63|128]+ke[e>>8&255]+"-"+ke[e>>16&255]+ke[e>>24&255]+ke[n&255]+ke[n>>8&255]+ke[n>>16&255]+ke[n>>24&255]).toLowerCase()}function qt(s,t,e){return Math.max(t,Math.min(e,s))}function nl(s,t){return(s%t+t)%t}function gp(s,t,e,n,i){return n+(s-t)*(i-n)/(e-t)}function xp(s,t,e){return s!==t?(e-s)/(t-s):0}function Zs(s,t,e){return(1-e)*s+e*t}function vp(s,t,e,n){return Zs(s,t,1-Math.exp(-e*n))}function _p(s,t=1){return t-Math.abs(nl(s,t*2)-t)}function yp(s,t,e){return s<=t?0:s>=e?1:(s=(s-t)/(e-t),s*s*(3-2*s))}function Mp(s,t,e){return s<=t?0:s>=e?1:(s=(s-t)/(e-t),s*s*s*(s*(s*6-15)+10))}function bp(s,t){return s+Math.floor(Math.random()*(t-s+1))}function Sp(s,t){return s+Math.random()*(t-s)}function wp(s){return s*(.5-Math.random())}function Ep(s){s!==void 0&&(uh=s);let t=uh+=1831565813;return t=Math.imul(t^t>>>15,t|1),t^=t+Math.imul(t^t>>>7,t|61),((t^t>>>14)>>>0)/4294967296}function Tp(s){return s*Ks}function Ap(s){return s*cs}function Cp(s){return(s&s-1)===0&&s!==0}function Rp(s){return Math.pow(2,Math.ceil(Math.log(s)/Math.LN2))}function Pp(s){return Math.pow(2,Math.floor(Math.log(s)/Math.LN2))}function Lp(s,t,e,n,i){const r=Math.cos,o=Math.sin,a=r(e/2),l=o(e/2),c=r((t+n)/2),u=o((t+n)/2),h=r((t-n)/2),d=o((t-n)/2),f=r((n-t)/2),p=o((n-t)/2);switch(i){case"XYX":s.set(a*u,l*h,l*d,a*c);break;case"YZY":s.set(l*d,a*u,l*h,a*c);break;case"ZXZ":s.set(l*h,l*d,a*u,a*c);break;case"XZX":s.set(a*u,l*p,l*f,a*c);break;case"YXY":s.set(l*f,a*u,l*p,a*c);break;case"ZYZ":s.set(l*p,l*f,a*u,a*c);break;default:Ut("MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+i)}}function us(s,t){switch(t.constructor){case Float32Array:return s;case Uint32Array:return s/4294967295;case Uint16Array:return s/65535;case Uint8Array:return s/255;case Int32Array:return Math.max(s/2147483647,-1);case Int16Array:return Math.max(s/32767,-1);case Int8Array:return Math.max(s/127,-1);default:throw new Error("THREE.MathUtils: Invalid component type.")}}function $e(s,t){switch(t.constructor){case Float32Array:return s;case Uint32Array:return Math.round(s*4294967295);case Uint16Array:return Math.round(s*65535);case Uint8Array:return Math.round(s*255);case Int32Array:return Math.round(s*2147483647);case Int16Array:return Math.round(s*32767);case Int8Array:return Math.round(s*127);default:throw new Error("THREE.MathUtils: Invalid component type.")}}const Br={DEG2RAD:Ks,RAD2DEG:cs,generateUUID:hs,clamp:qt,euclideanModulo:nl,mapLinear:gp,inverseLerp:xp,lerp:Zs,damp:vp,pingpong:_p,smoothstep:yp,smootherstep:Mp,randInt:bp,randFloat:Sp,randFloatSpread:wp,seededRandom:Ep,degToRad:Tp,radToDeg:Ap,isPowerOfTwo:Cp,ceilPowerOfTwo:Rp,floorPowerOfTwo:Pp,setQuaternionFromProperEuler:Lp,normalize:$e,denormalize:us},fc=class fc{constructor(t=0,e=0){this.x=t,this.y=e}get width(){return this.x}set width(t){this.x=t}get height(){return this.y}set height(t){this.y=t}set(t,e){return this.x=t,this.y=e,this}setScalar(t){return this.x=t,this.y=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;default:throw new Error("THREE.Vector2: index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;default:throw new Error("THREE.Vector2: index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y)}copy(t){return this.x=t.x,this.y=t.y,this}add(t){return this.x+=t.x,this.y+=t.y,this}addScalar(t){return this.x+=t,this.y+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this}subScalar(t){return this.x-=t,this.y-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this}multiply(t){return this.x*=t.x,this.y*=t.y,this}multiplyScalar(t){return this.x*=t,this.y*=t,this}divide(t){return this.x/=t.x,this.y/=t.y,this}divideScalar(t){return this.multiplyScalar(1/t)}applyMatrix3(t){const e=this.x,n=this.y,i=t.elements;return this.x=i[0]*e+i[3]*n+i[6],this.y=i[1]*e+i[4]*n+i[7],this}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this}clamp(t,e){return this.x=qt(this.x,t.x,e.x),this.y=qt(this.y,t.y,e.y),this}clampScalar(t,e){return this.x=qt(this.x,t,e),this.y=qt(this.y,t,e),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar(qt(n,t,e))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(t){return this.x*t.x+this.y*t.y}cross(t){return this.x*t.y-this.y*t.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(e===0)return Math.PI/2;const n=this.dot(t)/e;return Math.acos(qt(n,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y;return e*e+n*n}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this}equals(t){return t.x===this.x&&t.y===this.y}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this}rotateAround(t,e){const n=Math.cos(e),i=Math.sin(e),r=this.x-t.x,o=this.y-t.y;return this.x=r*n-o*i+t.x,this.y=r*i+o*n+t.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}};fc.prototype.isVector2=!0;let pt=fc;class Pn{constructor(t=0,e=0,n=0,i=1){this.isQuaternion=!0,this._x=t,this._y=e,this._z=n,this._w=i}static slerpFlat(t,e,n,i,r,o,a){let l=n[i+0],c=n[i+1],u=n[i+2],h=n[i+3],d=r[o+0],f=r[o+1],p=r[o+2],x=r[o+3];if(h!==x||l!==d||c!==f||u!==p){let m=l*d+c*f+u*p+h*x;m<0&&(d=-d,f=-f,p=-p,x=-x,m=-m);let g=1-a;if(m<.9995){const b=Math.acos(m),E=Math.sin(b);g=Math.sin(g*b)/E,a=Math.sin(a*b)/E,l=l*g+d*a,c=c*g+f*a,u=u*g+p*a,h=h*g+x*a}else{l=l*g+d*a,c=c*g+f*a,u=u*g+p*a,h=h*g+x*a;const b=1/Math.sqrt(l*l+c*c+u*u+h*h);l*=b,c*=b,u*=b,h*=b}}t[e]=l,t[e+1]=c,t[e+2]=u,t[e+3]=h}static multiplyQuaternionsFlat(t,e,n,i,r,o){const a=n[i],l=n[i+1],c=n[i+2],u=n[i+3],h=r[o],d=r[o+1],f=r[o+2],p=r[o+3];return t[e]=a*p+u*h+l*f-c*d,t[e+1]=l*p+u*d+c*h-a*f,t[e+2]=c*p+u*f+a*d-l*h,t[e+3]=u*p-a*h-l*d-c*f,t}get x(){return this._x}set x(t){this._x=t,this._onChangeCallback()}get y(){return this._y}set y(t){this._y=t,this._onChangeCallback()}get z(){return this._z}set z(t){this._z=t,this._onChangeCallback()}get w(){return this._w}set w(t){this._w=t,this._onChangeCallback()}set(t,e,n,i){return this._x=t,this._y=e,this._z=n,this._w=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(t){return this._x=t.x,this._y=t.y,this._z=t.z,this._w=t.w,this._onChangeCallback(),this}setFromEuler(t,e=!0){const n=t._x,i=t._y,r=t._z,o=t._order,a=Math.cos,l=Math.sin,c=a(n/2),u=a(i/2),h=a(r/2),d=l(n/2),f=l(i/2),p=l(r/2);switch(o){case"XYZ":this._x=d*u*h+c*f*p,this._y=c*f*h-d*u*p,this._z=c*u*p+d*f*h,this._w=c*u*h-d*f*p;break;case"YXZ":this._x=d*u*h+c*f*p,this._y=c*f*h-d*u*p,this._z=c*u*p-d*f*h,this._w=c*u*h+d*f*p;break;case"ZXY":this._x=d*u*h-c*f*p,this._y=c*f*h+d*u*p,this._z=c*u*p+d*f*h,this._w=c*u*h-d*f*p;break;case"ZYX":this._x=d*u*h-c*f*p,this._y=c*f*h+d*u*p,this._z=c*u*p-d*f*h,this._w=c*u*h+d*f*p;break;case"YZX":this._x=d*u*h+c*f*p,this._y=c*f*h+d*u*p,this._z=c*u*p-d*f*h,this._w=c*u*h-d*f*p;break;case"XZY":this._x=d*u*h-c*f*p,this._y=c*f*h-d*u*p,this._z=c*u*p+d*f*h,this._w=c*u*h+d*f*p;break;default:Ut("Quaternion: .setFromEuler() encountered an unknown order: "+o)}return e===!0&&this._onChangeCallback(),this}setFromAxisAngle(t,e){const n=e/2,i=Math.sin(n);return this._x=t.x*i,this._y=t.y*i,this._z=t.z*i,this._w=Math.cos(n),this._onChangeCallback(),this}setFromRotationMatrix(t){const e=t.elements,n=e[0],i=e[4],r=e[8],o=e[1],a=e[5],l=e[9],c=e[2],u=e[6],h=e[10],d=n+a+h;if(d>0){const f=.5/Math.sqrt(d+1);this._w=.25/f,this._x=(u-l)*f,this._y=(r-c)*f,this._z=(o-i)*f}else if(n>a&&n>h){const f=2*Math.sqrt(1+n-a-h);this._w=(u-l)/f,this._x=.25*f,this._y=(i+o)/f,this._z=(r+c)/f}else if(a>h){const f=2*Math.sqrt(1+a-n-h);this._w=(r-c)/f,this._x=(i+o)/f,this._y=.25*f,this._z=(l+u)/f}else{const f=2*Math.sqrt(1+h-n-a);this._w=(o-i)/f,this._x=(r+c)/f,this._y=(l+u)/f,this._z=.25*f}return this._onChangeCallback(),this}setFromUnitVectors(t,e){let n=t.dot(e)+1;return n<1e-8?(n=0,Math.abs(t.x)>Math.abs(t.z)?(this._x=-t.y,this._y=t.x,this._z=0,this._w=n):(this._x=0,this._y=-t.z,this._z=t.y,this._w=n)):(this._x=t.y*e.z-t.z*e.y,this._y=t.z*e.x-t.x*e.z,this._z=t.x*e.y-t.y*e.x,this._w=n),this.normalize()}angleTo(t){return 2*Math.acos(Math.abs(qt(this.dot(t),-1,1)))}rotateTowards(t,e){const n=this.angleTo(t);if(n===0)return this;const i=Math.min(1,e/n);return this.slerp(t,i),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(t){return this._x*t._x+this._y*t._y+this._z*t._z+this._w*t._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let t=this.length();return t===0?(this._x=0,this._y=0,this._z=0,this._w=1):(t=1/t,this._x=this._x*t,this._y=this._y*t,this._z=this._z*t,this._w=this._w*t),this._onChangeCallback(),this}multiply(t){return this.multiplyQuaternions(this,t)}premultiply(t){return this.multiplyQuaternions(t,this)}multiplyQuaternions(t,e){const n=t._x,i=t._y,r=t._z,o=t._w,a=e._x,l=e._y,c=e._z,u=e._w;return this._x=n*u+o*a+i*c-r*l,this._y=i*u+o*l+r*a-n*c,this._z=r*u+o*c+n*l-i*a,this._w=o*u-n*a-i*l-r*c,this._onChangeCallback(),this}slerp(t,e){let n=t._x,i=t._y,r=t._z,o=t._w,a=this.dot(t);a<0&&(n=-n,i=-i,r=-r,o=-o,a=-a);let l=1-e;if(a<.9995){const c=Math.acos(a),u=Math.sin(c);l=Math.sin(l*c)/u,e=Math.sin(e*c)/u,this._x=this._x*l+n*e,this._y=this._y*l+i*e,this._z=this._z*l+r*e,this._w=this._w*l+o*e,this._onChangeCallback()}else this._x=this._x*l+n*e,this._y=this._y*l+i*e,this._z=this._z*l+r*e,this._w=this._w*l+o*e,this.normalize();return this}slerpQuaternions(t,e,n){return this.copy(t).slerp(e,n)}random(){const t=2*Math.PI*Math.random(),e=2*Math.PI*Math.random(),n=Math.random(),i=Math.sqrt(1-n),r=Math.sqrt(n);return this.set(i*Math.sin(t),i*Math.cos(t),r*Math.sin(e),r*Math.cos(e))}equals(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._w===this._w}fromArray(t,e=0){return this._x=t[e],this._y=t[e+1],this._z=t[e+2],this._w=t[e+3],this._onChangeCallback(),this}toArray(t=[],e=0){return t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._w,t}fromBufferAttribute(t,e){return this._x=t.getX(e),this._y=t.getY(e),this._z=t.getZ(e),this._w=t.getW(e),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(t){return this._onChangeCallback=t,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}}const pc=class pc{constructor(t=0,e=0,n=0){this.x=t,this.y=e,this.z=n}set(t,e,n){return n===void 0&&(n=this.z),this.x=t,this.y=e,this.z=n,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;default:throw new Error("THREE.Vector3: index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("THREE.Vector3: index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this}multiplyVectors(t,e){return this.x=t.x*e.x,this.y=t.y*e.y,this.z=t.z*e.z,this}applyEuler(t){return this.applyQuaternion(dh.setFromEuler(t))}applyAxisAngle(t,e){return this.applyQuaternion(dh.setFromAxisAngle(t,e))}applyMatrix3(t){const e=this.x,n=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[3]*n+r[6]*i,this.y=r[1]*e+r[4]*n+r[7]*i,this.z=r[2]*e+r[5]*n+r[8]*i,this}applyNormalMatrix(t){return this.applyMatrix3(t).normalize()}applyMatrix4(t){const e=this.x,n=this.y,i=this.z,r=t.elements,o=1/(r[3]*e+r[7]*n+r[11]*i+r[15]);return this.x=(r[0]*e+r[4]*n+r[8]*i+r[12])*o,this.y=(r[1]*e+r[5]*n+r[9]*i+r[13])*o,this.z=(r[2]*e+r[6]*n+r[10]*i+r[14])*o,this}applyQuaternion(t){const e=this.x,n=this.y,i=this.z,r=t.x,o=t.y,a=t.z,l=t.w,c=2*(o*i-a*n),u=2*(a*e-r*i),h=2*(r*n-o*e);return this.x=e+l*c+o*h-a*u,this.y=n+l*u+a*c-r*h,this.z=i+l*h+r*u-o*c,this}project(t){return this.applyMatrix4(t.matrixWorldInverse).applyMatrix4(t.projectionMatrix)}unproject(t){return this.applyMatrix4(t.projectionMatrixInverse).applyMatrix4(t.matrixWorld)}transformDirection(t){const e=this.x,n=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[4]*n+r[8]*i,this.y=r[1]*e+r[5]*n+r[9]*i,this.z=r[2]*e+r[6]*n+r[10]*i,this.normalize()}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this}divideScalar(t){return this.multiplyScalar(1/t)}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this.z=Math.min(this.z,t.z),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this.z=Math.max(this.z,t.z),this}clamp(t,e){return this.x=qt(this.x,t.x,e.x),this.y=qt(this.y,t.y,e.y),this.z=qt(this.z,t.z,e.z),this}clampScalar(t,e){return this.x=qt(this.x,t,e),this.y=qt(this.y,t,e),this.z=qt(this.z,t,e),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar(qt(n,t,e))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(t){return this.x*t.x+this.y*t.y+this.z*t.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this.z+=(t.z-this.z)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this.z=t.z+(e.z-t.z)*n,this}cross(t){return this.crossVectors(this,t)}crossVectors(t,e){const n=t.x,i=t.y,r=t.z,o=e.x,a=e.y,l=e.z;return this.x=i*l-r*a,this.y=r*o-n*l,this.z=n*a-i*o,this}projectOnVector(t){const e=t.lengthSq();if(e===0)return this.set(0,0,0);const n=t.dot(this)/e;return this.copy(t).multiplyScalar(n)}projectOnPlane(t){return il.copy(this).projectOnVector(t),this.sub(il)}reflect(t){return this.sub(il.copy(t).multiplyScalar(2*this.dot(t)))}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(e===0)return Math.PI/2;const n=this.dot(t)/e;return Math.acos(qt(n,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,n=this.y-t.y,i=this.z-t.z;return e*e+n*n+i*i}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)+Math.abs(this.z-t.z)}setFromSpherical(t){return this.setFromSphericalCoords(t.radius,t.phi,t.theta)}setFromSphericalCoords(t,e,n){const i=Math.sin(e)*t;return this.x=i*Math.sin(n),this.y=Math.cos(e)*t,this.z=i*Math.cos(n),this}setFromCylindrical(t){return this.setFromCylindricalCoords(t.radius,t.theta,t.y)}setFromCylindricalCoords(t,e,n){return this.x=t*Math.sin(e),this.y=n,this.z=t*Math.cos(e),this}setFromMatrixPosition(t){const e=t.elements;return this.x=e[12],this.y=e[13],this.z=e[14],this}setFromMatrixScale(t){const e=this.setFromMatrixColumn(t,0).length(),n=this.setFromMatrixColumn(t,1).length(),i=this.setFromMatrixColumn(t,2).length();return this.x=e,this.y=n,this.z=i,this}setFromMatrixColumn(t,e){return this.fromArray(t.elements,e*4)}setFromMatrix3Column(t,e){return this.fromArray(t.elements,e*3)}setFromEuler(t){return this.x=t._x,this.y=t._y,this.z=t._z,this}setFromColor(t){return this.x=t.r,this.y=t.g,this.z=t.b,this}equals(t){return t.x===this.x&&t.y===this.y&&t.z===this.z}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this.z=t[e+2],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t[e+2]=this.z,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this.z=t.getZ(e),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){const t=Math.random()*Math.PI*2,e=Math.random()*2-1,n=Math.sqrt(1-e*e);return this.x=n*Math.cos(t),this.y=e,this.z=n*Math.sin(t),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}};pc.prototype.isVector3=!0;let P=pc;const il=new P,dh=new Pn,mc=class mc{constructor(t,e,n,i,r,o,a,l,c){this.elements=[1,0,0,0,1,0,0,0,1],t!==void 0&&this.set(t,e,n,i,r,o,a,l,c)}set(t,e,n,i,r,o,a,l,c){const u=this.elements;return u[0]=t,u[1]=i,u[2]=a,u[3]=e,u[4]=r,u[5]=l,u[6]=n,u[7]=o,u[8]=c,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(t){const e=this.elements,n=t.elements;return e[0]=n[0],e[1]=n[1],e[2]=n[2],e[3]=n[3],e[4]=n[4],e[5]=n[5],e[6]=n[6],e[7]=n[7],e[8]=n[8],this}extractBasis(t,e,n){return t.setFromMatrix3Column(this,0),e.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(t){const e=t.elements;return this.set(e[0],e[4],e[8],e[1],e[5],e[9],e[2],e[6],e[10]),this}multiply(t){return this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const n=t.elements,i=e.elements,r=this.elements,o=n[0],a=n[3],l=n[6],c=n[1],u=n[4],h=n[7],d=n[2],f=n[5],p=n[8],x=i[0],m=i[3],g=i[6],b=i[1],E=i[4],y=i[7],M=i[2],w=i[5],C=i[8];return r[0]=o*x+a*b+l*M,r[3]=o*m+a*E+l*w,r[6]=o*g+a*y+l*C,r[1]=c*x+u*b+h*M,r[4]=c*m+u*E+h*w,r[7]=c*g+u*y+h*C,r[2]=d*x+f*b+p*M,r[5]=d*m+f*E+p*w,r[8]=d*g+f*y+p*C,this}multiplyScalar(t){const e=this.elements;return e[0]*=t,e[3]*=t,e[6]*=t,e[1]*=t,e[4]*=t,e[7]*=t,e[2]*=t,e[5]*=t,e[8]*=t,this}determinant(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],o=t[4],a=t[5],l=t[6],c=t[7],u=t[8];return e*o*u-e*a*c-n*r*u+n*a*l+i*r*c-i*o*l}invert(){const t=this.elements,e=t[0],n=t[1],i=t[2],r=t[3],o=t[4],a=t[5],l=t[6],c=t[7],u=t[8],h=u*o-a*c,d=a*l-u*r,f=c*r-o*l,p=e*h+n*d+i*f;if(p===0)return this.set(0,0,0,0,0,0,0,0,0);const x=1/p;return t[0]=h*x,t[1]=(i*c-u*n)*x,t[2]=(a*n-i*o)*x,t[3]=d*x,t[4]=(u*e-i*l)*x,t[5]=(i*r-a*e)*x,t[6]=f*x,t[7]=(n*l-c*e)*x,t[8]=(o*e-n*r)*x,this}transpose(){let t;const e=this.elements;return t=e[1],e[1]=e[3],e[3]=t,t=e[2],e[2]=e[6],e[6]=t,t=e[5],e[5]=e[7],e[7]=t,this}getNormalMatrix(t){return this.setFromMatrix4(t).invert().transpose()}transposeIntoArray(t){const e=this.elements;return t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8],this}setUvTransform(t,e,n,i,r,o,a){const l=Math.cos(r),c=Math.sin(r);return this.set(n*l,n*c,-n*(l*o+c*a)+o+t,-i*c,i*l,-i*(-c*o+l*a)+a+e,0,0,1),this}scale(t,e){return ls("Matrix3: .scale() is deprecated. Use .makeScale() instead."),this.premultiply(sl.makeScale(t,e)),this}rotate(t){return ls("Matrix3: .rotate() is deprecated. Use .makeRotation() instead."),this.premultiply(sl.makeRotation(-t)),this}translate(t,e){return ls("Matrix3: .translate() is deprecated. Use .makeTranslation() instead."),this.premultiply(sl.makeTranslation(t,e)),this}makeTranslation(t,e){return t.isVector2?this.set(1,0,t.x,0,1,t.y,0,0,1):this.set(1,0,t,0,1,e,0,0,1),this}makeRotation(t){const e=Math.cos(t),n=Math.sin(t);return this.set(e,-n,0,n,e,0,0,0,1),this}makeScale(t,e){return this.set(t,0,0,0,e,0,0,0,1),this}equals(t){const e=this.elements,n=t.elements;for(let i=0;i<9;i++)if(e[i]!==n[i])return!1;return!0}fromArray(t,e=0){for(let n=0;n<9;n++)this.elements[n]=t[n+e];return this}toArray(t=[],e=0){const n=this.elements;return t[e]=n[0],t[e+1]=n[1],t[e+2]=n[2],t[e+3]=n[3],t[e+4]=n[4],t[e+5]=n[5],t[e+6]=n[6],t[e+7]=n[7],t[e+8]=n[8],t}clone(){return new this.constructor().fromArray(this.elements)}};mc.prototype.isMatrix3=!0;let Ht=mc;const sl=new Ht,fh=new Ht().set(.4123908,.3575843,.1804808,.212639,.7151687,.0721923,.0193308,.1191948,.9505322),ph=new Ht().set(3.2409699,-1.5373832,-.4986108,-.9692436,1.8759675,.0415551,.0556301,-.203977,1.0569715);function Dp(){const s={enabled:!0,workingColorSpace:qs,spaces:{},convert:function(i,r,o){return this.enabled===!1||r===o||!r||!o||(this.spaces[r].transfer===se&&(i.r=Wn(i.r),i.g=Wn(i.g),i.b=Wn(i.b)),this.spaces[r].primaries!==this.spaces[o].primaries&&(i.applyMatrix3(this.spaces[r].toXYZ),i.applyMatrix3(this.spaces[o].fromXYZ)),this.spaces[o].transfer===se&&(i.r=ds(i.r),i.g=ds(i.g),i.b=ds(i.b))),i},workingToColorSpace:function(i,r){return this.convert(i,this.workingColorSpace,r)},colorSpaceToWorking:function(i,r){return this.convert(i,r,this.workingColorSpace)},getPrimaries:function(i){return this.spaces[i].primaries},getTransfer:function(i){return i===ai?Or:this.spaces[i].transfer},getToneMappingMode:function(i){return this.spaces[i].outputColorSpaceConfig.toneMappingMode||"standard"},getLuminanceCoefficients:function(i,r=this.workingColorSpace){return i.fromArray(this.spaces[r].luminanceCoefficients)},define:function(i){Object.assign(this.spaces,i)},_getMatrix:function(i,r,o){return i.copy(this.spaces[r].toXYZ).multiply(this.spaces[o].fromXYZ)},_getDrawingBufferColorSpace:function(i){return this.spaces[i].outputColorSpaceConfig.drawingBufferColorSpace},_getUnpackColorSpace:function(i=this.workingColorSpace){return this.spaces[i].workingColorSpaceConfig.unpackColorSpace},fromWorkingColorSpace:function(i,r){return ls("ColorManagement: .fromWorkingColorSpace() has been renamed to .workingToColorSpace()."),s.workingToColorSpace(i,r)},toWorkingColorSpace:function(i,r){return ls("ColorManagement: .toWorkingColorSpace() has been renamed to .colorSpaceToWorking()."),s.colorSpaceToWorking(i,r)}},t=[.64,.33,.3,.6,.15,.06],e=[.2126,.7152,.0722],n=[.3127,.329];return s.define({[qs]:{primaries:t,whitePoint:n,transfer:Or,toXYZ:fh,fromXYZ:ph,luminanceCoefficients:e,workingColorSpaceConfig:{unpackColorSpace:we},outputColorSpaceConfig:{drawingBufferColorSpace:we}},[we]:{primaries:t,whitePoint:n,transfer:se,toXYZ:fh,fromXYZ:ph,luminanceCoefficients:e,outputColorSpaceConfig:{drawingBufferColorSpace:we}}}),s}const Jt=Dp();function Wn(s){return s<.04045?s*.0773993808:Math.pow(s*.9478672986+.0521327014,2.4)}function ds(s){return s<.0031308?s*12.92:1.055*Math.pow(s,.41666)-.055}let fs;class Ip{static getDataURL(t,e="image/png"){if(/^data:/i.test(t.src)||typeof HTMLCanvasElement>"u")return t.src;let n;if(t instanceof HTMLCanvasElement)n=t;else{fs===void 0&&(fs=kr("canvas")),fs.width=t.width,fs.height=t.height;const i=fs.getContext("2d");t instanceof ImageData?i.putImageData(t,0,0):i.drawImage(t,0,0,t.width,t.height),n=fs}return n.toDataURL(e)}static sRGBToLinear(t){if(typeof HTMLImageElement<"u"&&t instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&t instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&t instanceof ImageBitmap){const e=kr("canvas");e.width=t.width,e.height=t.height;const n=e.getContext("2d");n.drawImage(t,0,0,t.width,t.height);const i=n.getImageData(0,0,t.width,t.height),r=i.data;for(let o=0;o1),this.pmremVersion=0,this.normalized=!1}get width(){return this.source.getSize(al).x}get height(){return this.source.getSize(al).y}get depth(){return this.source.getSize(al).z}get image(){return this.source.data}set image(t){this.source.data=t}updateMatrix(){this.matrix.setUvTransform(this.offset.x,this.offset.y,this.repeat.x,this.repeat.y,this.rotation,this.center.x,this.center.y)}addUpdateRange(t,e){this.updateRanges.push({start:t,count:e})}clearUpdateRanges(){this.updateRanges.length=0}clone(){return new this.constructor().copy(this)}copy(t){return this.name=t.name,this.source=t.source,this.mipmaps=t.mipmaps.slice(0),this.mapping=t.mapping,this.channel=t.channel,this.wrapS=t.wrapS,this.wrapT=t.wrapT,this.magFilter=t.magFilter,this.minFilter=t.minFilter,this.anisotropy=t.anisotropy,this.format=t.format,this.internalFormat=t.internalFormat,this.type=t.type,this.normalized=t.normalized,this.offset.copy(t.offset),this.repeat.copy(t.repeat),this.center.copy(t.center),this.rotation=t.rotation,this.matrixAutoUpdate=t.matrixAutoUpdate,this.matrix.copy(t.matrix),this.generateMipmaps=t.generateMipmaps,this.premultiplyAlpha=t.premultiplyAlpha,this.flipY=t.flipY,this.unpackAlignment=t.unpackAlignment,this.colorSpace=t.colorSpace,this.renderTarget=t.renderTarget,this.isRenderTargetTexture=t.isRenderTargetTexture,this.isArrayTexture=t.isArrayTexture,this.userData=JSON.parse(JSON.stringify(t.userData)),this.needsUpdate=!0,this}setValues(t){for(const e in t){const n=t[e];if(n===void 0){Ut(`Texture.setValues(): parameter '${e}' has value of undefined.`);continue}const i=this[e];if(i===void 0){Ut(`Texture.setValues(): property '${e}' does not exist.`);continue}i&&n&&i.isVector2&&n.isVector2||i&&n&&i.isVector3&&n.isVector3||i&&n&&i.isMatrix3&&n.isMatrix3?i.copy(n):this[e]=n}}toJSON(t){const e=t===void 0||typeof t=="string";if(!e&&t.textures[this.uuid]!==void 0)return t.textures[this.uuid];const n={metadata:{version:4.7,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,image:this.source.toJSON(t).uuid,mapping:this.mapping,channel:this.channel,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],center:[this.center.x,this.center.y],rotation:this.rotation,wrap:[this.wrapS,this.wrapT],format:this.format,internalFormat:this.internalFormat,type:this.type,normalized:this.normalized,colorSpace:this.colorSpace,minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy,flipY:this.flipY,generateMipmaps:this.generateMipmaps,premultiplyAlpha:this.premultiplyAlpha,unpackAlignment:this.unpackAlignment};return Object.keys(this.userData).length>0&&(n.userData=this.userData),e||(t.textures[this.uuid]=n),n}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(t){if(this.mapping!==jc)return t;if(t.applyMatrix3(this.matrix),t.x<0||t.x>1)switch(this.wrapS){case Rr:t.x=t.x-Math.floor(t.x);break;case Gn:t.x=t.x<0?0:1;break;case pa:Math.abs(Math.floor(t.x)%2)===1?t.x=Math.ceil(t.x)-t.x:t.x=t.x-Math.floor(t.x);break}if(t.y<0||t.y>1)switch(this.wrapT){case Rr:t.y=t.y-Math.floor(t.y);break;case Gn:t.y=t.y<0?0:1;break;case pa:Math.abs(Math.floor(t.y)%2)===1?t.y=Math.ceil(t.y)-t.y:t.y=t.y-Math.floor(t.y);break}return this.flipY&&(t.y=1-t.y),t}set needsUpdate(t){t===!0&&(this.version++,this.source.needsUpdate=!0)}set needsPMREMUpdate(t){t===!0&&this.pmremVersion++}}Be.DEFAULT_IMAGE=null,Be.DEFAULT_MAPPING=jc,Be.DEFAULT_ANISOTROPY=1;const gc=class gc{constructor(t=0,e=0,n=0,i=1){this.x=t,this.y=e,this.z=n,this.w=i}get width(){return this.z}set width(t){this.z=t}get height(){return this.w}set height(t){this.w=t}set(t,e,n,i){return this.x=t,this.y=e,this.z=n,this.w=i,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this.w=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setW(t){return this.w=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;case 3:this.w=e;break;default:throw new Error("THREE.Vector4: index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("THREE.Vector4: index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this.w=t.w!==void 0?t.w:1,this}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this.w+=t.w,this}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this.w+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this.w=t.w+e.w,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this.w+=t.w*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this.w-=t.w,this}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this.w-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this.w=t.w-e.w,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this.w*=t.w,this}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this.w*=t,this}applyMatrix4(t){const e=this.x,n=this.y,i=this.z,r=this.w,o=t.elements;return this.x=o[0]*e+o[4]*n+o[8]*i+o[12]*r,this.y=o[1]*e+o[5]*n+o[9]*i+o[13]*r,this.z=o[2]*e+o[6]*n+o[10]*i+o[14]*r,this.w=o[3]*e+o[7]*n+o[11]*i+o[15]*r,this}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this.w/=t.w,this}divideScalar(t){return this.multiplyScalar(1/t)}setAxisAngleFromQuaternion(t){this.w=2*Math.acos(t.w);const e=Math.sqrt(1-t.w*t.w);return e<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=t.x/e,this.y=t.y/e,this.z=t.z/e),this}setAxisAngleFromRotationMatrix(t){let e,n,i,r;const l=t.elements,c=l[0],u=l[4],h=l[8],d=l[1],f=l[5],p=l[9],x=l[2],m=l[6],g=l[10];if(Math.abs(u-d)<.01&&Math.abs(h-x)<.01&&Math.abs(p-m)<.01){if(Math.abs(u+d)<.1&&Math.abs(h+x)<.1&&Math.abs(p+m)<.1&&Math.abs(c+f+g-3)<.1)return this.set(1,0,0,0),this;e=Math.PI;const E=(c+1)/2,y=(f+1)/2,M=(g+1)/2,w=(u+d)/4,C=(h+x)/4,v=(p+m)/4;return E>y&&E>M?E<.01?(n=0,i=.707106781,r=.707106781):(n=Math.sqrt(E),i=w/n,r=C/n):y>M?y<.01?(n=.707106781,i=0,r=.707106781):(i=Math.sqrt(y),n=w/i,r=v/i):M<.01?(n=.707106781,i=.707106781,r=0):(r=Math.sqrt(M),n=C/r,i=v/r),this.set(n,i,r,e),this}let b=Math.sqrt((m-p)*(m-p)+(h-x)*(h-x)+(d-u)*(d-u));return Math.abs(b)<.001&&(b=1),this.x=(m-p)/b,this.y=(h-x)/b,this.z=(d-u)/b,this.w=Math.acos((c+f+g-1)/2),this}setFromMatrixPosition(t){const e=t.elements;return this.x=e[12],this.y=e[13],this.z=e[14],this.w=e[15],this}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this.z=Math.min(this.z,t.z),this.w=Math.min(this.w,t.w),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this.z=Math.max(this.z,t.z),this.w=Math.max(this.w,t.w),this}clamp(t,e){return this.x=qt(this.x,t.x,e.x),this.y=qt(this.y,t.y,e.y),this.z=qt(this.z,t.z,e.z),this.w=qt(this.w,t.w,e.w),this}clampScalar(t,e){return this.x=qt(this.x,t,e),this.y=qt(this.y,t,e),this.z=qt(this.z,t,e),this.w=qt(this.w,t,e),this}clampLength(t,e){const n=this.length();return this.divideScalar(n||1).multiplyScalar(qt(n,t,e))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this.w=Math.floor(this.w),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this.w=Math.ceil(this.w),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this.w=Math.round(this.w),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this.w=Math.trunc(this.w),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this.w=-this.w,this}dot(t){return this.x*t.x+this.y*t.y+this.z*t.z+this.w*t.w}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z+this.w*this.w)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)}normalize(){return this.divideScalar(this.length()||1)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this.z+=(t.z-this.z)*e,this.w+=(t.w-this.w)*e,this}lerpVectors(t,e,n){return this.x=t.x+(e.x-t.x)*n,this.y=t.y+(e.y-t.y)*n,this.z=t.z+(e.z-t.z)*n,this.w=t.w+(e.w-t.w)*n,this}equals(t){return t.x===this.x&&t.y===this.y&&t.z===this.z&&t.w===this.w}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this.z=t[e+2],this.w=t[e+3],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t[e+2]=this.z,t[e+3]=this.w,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this.z=t.getZ(e),this.w=t.getW(e),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this.w=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z,yield this.w}};gc.prototype.isVector4=!0;let ge=gc;class Fp extends li{constructor(t=1,e=1,n={}){super(),n=Object.assign({generateMipmaps:!1,internalFormat:null,minFilter:Oe,depthBuffer:!0,stencilBuffer:!1,resolveDepthBuffer:!0,resolveStencilBuffer:!0,depthTexture:null,samples:0,count:1,depth:1,multiview:!1,useArrayDepthTexture:!1},n),this.isRenderTarget=!0,this.width=t,this.height=e,this.depth=n.depth,this.scissor=new ge(0,0,t,e),this.scissorTest=!1,this.viewport=new ge(0,0,t,e),this.textures=[];const i={width:t,height:e,depth:n.depth},r=new Be(i),o=n.count;for(let a=0;a1);this.dispose()}this.viewport.set(0,0,t,e),this.scissor.set(0,0,t,e)}clone(){return new this.constructor().copy(this)}copy(t){this.width=t.width,this.height=t.height,this.depth=t.depth,this.scissor.copy(t.scissor),this.scissorTest=t.scissorTest,this.viewport.copy(t.viewport),this.textures.length=0;for(let e=0,n=t.textures.length;e>>0}enable(t){this.mask|=1<1){for(let e=0;e1){for(let n=0;n0&&(i.userData=this.userData),i.layers=this.layers.mask,i.matrix=this.matrix.toArray(),i.up=this.up.toArray(),this.pivot!==null&&(i.pivot=this.pivot.toArray()),this.matrixAutoUpdate===!1&&(i.matrixAutoUpdate=!1),this.morphTargetDictionary!==void 0&&(i.morphTargetDictionary=Object.assign({},this.morphTargetDictionary)),this.morphTargetInfluences!==void 0&&(i.morphTargetInfluences=this.morphTargetInfluences.slice()),this.isInstancedMesh&&(i.type="InstancedMesh",i.count=this.count,i.instanceMatrix=this.instanceMatrix.toJSON(),this.instanceColor!==null&&(i.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(i.type="BatchedMesh",i.perObjectFrustumCulled=this.perObjectFrustumCulled,i.sortObjects=this.sortObjects,i.drawRanges=this._drawRanges,i.reservedRanges=this._reservedRanges,i.geometryInfo=this._geometryInfo.map(a=>({...a,boundingBox:a.boundingBox?a.boundingBox.toJSON():void 0,boundingSphere:a.boundingSphere?a.boundingSphere.toJSON():void 0})),i.instanceInfo=this._instanceInfo.map(a=>({...a})),i.availableInstanceIds=this._availableInstanceIds.slice(),i.availableGeometryIds=this._availableGeometryIds.slice(),i.nextIndexStart=this._nextIndexStart,i.nextVertexStart=this._nextVertexStart,i.geometryCount=this._geometryCount,i.maxInstanceCount=this._maxInstanceCount,i.maxVertexCount=this._maxVertexCount,i.maxIndexCount=this._maxIndexCount,i.geometryInitialized=this._geometryInitialized,i.matricesTexture=this._matricesTexture.toJSON(t),i.indirectTexture=this._indirectTexture.toJSON(t),this._colorsTexture!==null&&(i.colorsTexture=this._colorsTexture.toJSON(t)),this.boundingSphere!==null&&(i.boundingSphere=this.boundingSphere.toJSON()),this.boundingBox!==null&&(i.boundingBox=this.boundingBox.toJSON()));function r(a,l){return a[l.uuid]===void 0&&(a[l.uuid]=l.toJSON(t)),l.uuid}if(this.isScene)this.background&&(this.background.isColor?i.background=this.background.toJSON():this.background.isTexture&&(i.background=this.background.toJSON(t).uuid)),this.environment&&this.environment.isTexture&&this.environment.isRenderTargetTexture!==!0&&(i.environment=this.environment.toJSON(t).uuid);else if(this.isMesh||this.isLine||this.isPoints){i.geometry=r(t.geometries,this.geometry);const a=this.geometry.parameters;if(a!==void 0&&a.shapes!==void 0){const l=a.shapes;if(Array.isArray(l))for(let c=0,u=l.length;c0){i.children=[];for(let a=0;a0){i.animations=[];for(let a=0;a0&&(n.geometries=a),l.length>0&&(n.materials=l),c.length>0&&(n.textures=c),u.length>0&&(n.images=u),h.length>0&&(n.shapes=h),d.length>0&&(n.skeletons=d),f.length>0&&(n.animations=f),p.length>0&&(n.nodes=p)}return n.object=i,n;function o(a){const l=[];for(const c in a){const u=a[c];delete u.metadata,l.push(u)}return l}}clone(t){return new this.constructor().copy(this,t)}copy(t,e=!0){if(this.name=t.name,this.up.copy(t.up),this.position.copy(t.position),this.rotation.order=t.rotation.order,this.quaternion.copy(t.quaternion),this.scale.copy(t.scale),this.pivot=t.pivot!==null?t.pivot.clone():null,this.matrix.copy(t.matrix),this.matrixWorld.copy(t.matrixWorld),this.matrixAutoUpdate=t.matrixAutoUpdate,this.matrixWorldAutoUpdate=t.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=t.matrixWorldNeedsUpdate,this.layers.mask=t.layers.mask,this.visible=t.visible,this.castShadow=t.castShadow,this.receiveShadow=t.receiveShadow,this.frustumCulled=t.frustumCulled,this.renderOrder=t.renderOrder,this.static=t.static,this.animations=t.animations.slice(),this.userData=JSON.parse(JSON.stringify(t.userData)),e===!0)for(let n=0;nf+p?(c.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:t.handedness,target:this})):!c.inputState.pinching&&d<=f-p&&(c.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:t.handedness,target:this}))}else l!==null&&t.gripSpace&&(r=e.getPose(t.gripSpace,n),r!==null&&(l.matrix.fromArray(r.transform.matrix),l.matrix.decompose(l.position,l.rotation,l.scale),l.matrixWorldNeedsUpdate=!0,r.linearVelocity?(l.hasLinearVelocity=!0,l.linearVelocity.copy(r.linearVelocity)):l.hasLinearVelocity=!1,r.angularVelocity?(l.hasAngularVelocity=!0,l.angularVelocity.copy(r.angularVelocity)):l.hasAngularVelocity=!1,l.eventsEnabled&&l.dispatchEvent({type:"gripUpdated",data:t,target:this})));a!==null&&(i=e.getPose(t.targetRaySpace,n),i===null&&r!==null&&(i=r),i!==null&&(a.matrix.fromArray(i.transform.matrix),a.matrix.decompose(a.position,a.rotation,a.scale),a.matrixWorldNeedsUpdate=!0,i.linearVelocity?(a.hasLinearVelocity=!0,a.linearVelocity.copy(i.linearVelocity)):a.hasLinearVelocity=!1,i.angularVelocity?(a.hasAngularVelocity=!0,a.angularVelocity.copy(i.angularVelocity)):a.hasAngularVelocity=!1,this.dispatchEvent(Wp)))}return a!==null&&(a.visible=i!==null),l!==null&&(l.visible=r!==null),c!==null&&(c.visible=o!==null),this}_getHandJoint(t,e){if(t.joints[e.jointName]===void 0){const n=new vn;n.matrixAutoUpdate=!1,n.visible=!1,t.joints[e.jointName]=n,t.add(n)}return t.joints[e.jointName]}}const Sh={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},hi={h:0,s:0,l:0},Gr={h:0,s:0,l:0};function ul(s,t,e){return e<0&&(e+=1),e>1&&(e-=1),e<1/6?s+(t-s)*6*e:e<1/2?t:e<2/3?s+(t-s)*6*(2/3-e):s}class Bt{constructor(t,e,n){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(t,e,n)}set(t,e,n){if(e===void 0&&n===void 0){const i=t;i&&i.isColor?this.copy(i):typeof i=="number"?this.setHex(i):typeof i=="string"&&this.setStyle(i)}else this.setRGB(t,e,n);return this}setScalar(t){return this.r=t,this.g=t,this.b=t,this}setHex(t,e=we){return t=Math.floor(t),this.r=(t>>16&255)/255,this.g=(t>>8&255)/255,this.b=(t&255)/255,Jt.colorSpaceToWorking(this,e),this}setRGB(t,e,n,i=Jt.workingColorSpace){return this.r=t,this.g=e,this.b=n,Jt.colorSpaceToWorking(this,i),this}setHSL(t,e,n,i=Jt.workingColorSpace){if(t=nl(t,1),e=qt(e,0,1),n=qt(n,0,1),e===0)this.r=this.g=this.b=n;else{const r=n<=.5?n*(1+e):n+e-n*e,o=2*n-r;this.r=ul(o,r,t+1/3),this.g=ul(o,r,t),this.b=ul(o,r,t-1/3)}return Jt.colorSpaceToWorking(this,i),this}setStyle(t,e=we){function n(r){r!==void 0&&parseFloat(r)<1&&Ut("Color: Alpha component of "+t+" will be ignored.")}let i;if(i=/^(\w+)\(([^\)]*)\)/.exec(t)){let r;const o=i[1],a=i[2];switch(o){case"rgb":case"rgba":if(r=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setRGB(Math.min(255,parseInt(r[1],10))/255,Math.min(255,parseInt(r[2],10))/255,Math.min(255,parseInt(r[3],10))/255,e);if(r=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setRGB(Math.min(100,parseInt(r[1],10))/100,Math.min(100,parseInt(r[2],10))/100,Math.min(100,parseInt(r[3],10))/100,e);break;case"hsl":case"hsla":if(r=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return n(r[4]),this.setHSL(parseFloat(r[1])/360,parseFloat(r[2])/100,parseFloat(r[3])/100,e);break;default:Ut("Color: Unknown color model "+t)}}else if(i=/^\#([A-Fa-f\d]+)$/.exec(t)){const r=i[1],o=r.length;if(o===3)return this.setRGB(parseInt(r.charAt(0),16)/15,parseInt(r.charAt(1),16)/15,parseInt(r.charAt(2),16)/15,e);if(o===6)return this.setHex(parseInt(r,16),e);Ut("Color: Invalid hex color "+t)}else if(t&&t.length>0)return this.setColorName(t,e);return this}setColorName(t,e=we){const n=Sh[t.toLowerCase()];return n!==void 0?this.setHex(n,e):Ut("Color: Unknown color "+t),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(t){return this.r=t.r,this.g=t.g,this.b=t.b,this}copySRGBToLinear(t){return this.r=Wn(t.r),this.g=Wn(t.g),this.b=Wn(t.b),this}copyLinearToSRGB(t){return this.r=ds(t.r),this.g=ds(t.g),this.b=ds(t.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(t=we){return Jt.workingToColorSpace(ze.copy(this),t),Math.round(qt(ze.r*255,0,255))*65536+Math.round(qt(ze.g*255,0,255))*256+Math.round(qt(ze.b*255,0,255))}getHexString(t=we){return("000000"+this.getHex(t).toString(16)).slice(-6)}getHSL(t,e=Jt.workingColorSpace){Jt.workingToColorSpace(ze.copy(this),e);const n=ze.r,i=ze.g,r=ze.b,o=Math.max(n,i,r),a=Math.min(n,i,r);let l,c;const u=(a+o)/2;if(a===o)l=0,c=0;else{const h=o-a;switch(c=u<=.5?h/(o+a):h/(2-o-a),o){case n:l=(i-r)/h+(i0&&(e.object.backgroundBlurriness=this.backgroundBlurriness),this.backgroundIntensity!==1&&(e.object.backgroundIntensity=this.backgroundIntensity),e.object.backgroundRotation=this.backgroundRotation.toArray(),this.environmentIntensity!==1&&(e.object.environmentIntensity=this.environmentIntensity),e.object.environmentRotation=this.environmentRotation.toArray(),e}}const _n=new P,qn=new P,fl=new P,Yn=new P,xs=new P,vs=new P,wh=new P,pl=new P,ml=new P,gl=new P,xl=new ge,vl=new ge,_l=new ge;class yn{constructor(t=new P,e=new P,n=new P){this.a=t,this.b=e,this.c=n}static getNormal(t,e,n,i){i.subVectors(n,e),_n.subVectors(t,e),i.cross(_n);const r=i.lengthSq();return r>0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)}static getBarycoord(t,e,n,i,r){_n.subVectors(i,e),qn.subVectors(n,e),fl.subVectors(t,e);const o=_n.dot(_n),a=_n.dot(qn),l=_n.dot(fl),c=qn.dot(qn),u=qn.dot(fl),h=o*c-a*a;if(h===0)return r.set(0,0,0),null;const d=1/h,f=(c*l-a*u)*d,p=(o*u-a*l)*d;return r.set(1-f-p,p,f)}static containsPoint(t,e,n,i){return this.getBarycoord(t,e,n,i,Yn)===null?!1:Yn.x>=0&&Yn.y>=0&&Yn.x+Yn.y<=1}static getInterpolation(t,e,n,i,r,o,a,l){return this.getBarycoord(t,e,n,i,Yn)===null?(l.x=0,l.y=0,"z"in l&&(l.z=0),"w"in l&&(l.w=0),null):(l.setScalar(0),l.addScaledVector(r,Yn.x),l.addScaledVector(o,Yn.y),l.addScaledVector(a,Yn.z),l)}static getInterpolatedAttribute(t,e,n,i,r,o){return xl.setScalar(0),vl.setScalar(0),_l.setScalar(0),xl.fromBufferAttribute(t,e),vl.fromBufferAttribute(t,n),_l.fromBufferAttribute(t,i),o.setScalar(0),o.addScaledVector(xl,r.x),o.addScaledVector(vl,r.y),o.addScaledVector(_l,r.z),o}static isFrontFacing(t,e,n,i){return _n.subVectors(n,e),qn.subVectors(t,e),_n.cross(qn).dot(i)<0}set(t,e,n){return this.a.copy(t),this.b.copy(e),this.c.copy(n),this}setFromPointsAndIndices(t,e,n,i){return this.a.copy(t[e]),this.b.copy(t[n]),this.c.copy(t[i]),this}setFromAttributeAndIndices(t,e,n,i){return this.a.fromBufferAttribute(t,e),this.b.fromBufferAttribute(t,n),this.c.fromBufferAttribute(t,i),this}clone(){return new this.constructor().copy(this)}copy(t){return this.a.copy(t.a),this.b.copy(t.b),this.c.copy(t.c),this}getArea(){return _n.subVectors(this.c,this.b),qn.subVectors(this.a,this.b),_n.cross(qn).length()*.5}getMidpoint(t){return t.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(t){return yn.getNormal(this.a,this.b,this.c,t)}getPlane(t){return t.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(t,e){return yn.getBarycoord(t,this.a,this.b,this.c,e)}getInterpolation(t,e,n,i,r){return yn.getInterpolation(t,this.a,this.b,this.c,e,n,i,r)}containsPoint(t){return yn.containsPoint(t,this.a,this.b,this.c)}isFrontFacing(t){return yn.isFrontFacing(this.a,this.b,this.c,t)}intersectsBox(t){return t.intersectsTriangle(this)}closestPointToPoint(t,e){const n=this.a,i=this.b,r=this.c;let o,a;xs.subVectors(i,n),vs.subVectors(r,n),pl.subVectors(t,n);const l=xs.dot(pl),c=vs.dot(pl);if(l<=0&&c<=0)return e.copy(n);ml.subVectors(t,i);const u=xs.dot(ml),h=vs.dot(ml);if(u>=0&&h<=u)return e.copy(i);const d=l*h-u*c;if(d<=0&&l>=0&&u<=0)return o=l/(l-u),e.copy(n).addScaledVector(xs,o);gl.subVectors(t,r);const f=xs.dot(gl),p=vs.dot(gl);if(p>=0&&f<=p)return e.copy(r);const x=f*c-l*p;if(x<=0&&c>=0&&p<=0)return a=c/(c-p),e.copy(n).addScaledVector(vs,a);const m=u*p-f*h;if(m<=0&&h-u>=0&&f-p>=0)return wh.subVectors(r,i),a=(h-u)/(h-u+(f-p)),e.copy(i).addScaledVector(wh,a);const g=1/(m+x+d);return o=x*g,a=d*g,e.copy(n).addScaledVector(xs,o).addScaledVector(vs,a)}equals(t){return t.a.equals(this.a)&&t.b.equals(this.b)&&t.c.equals(this.c)}}class Oi{constructor(t=new P(1/0,1/0,1/0),e=new P(-1/0,-1/0,-1/0)){this.isBox3=!0,this.min=t,this.max=e}set(t,e){return this.min.copy(t),this.max.copy(e),this}setFromArray(t){this.makeEmpty();for(let e=0,n=t.length;e=this.min.x&&t.x<=this.max.x&&t.y>=this.min.y&&t.y<=this.max.y&&t.z>=this.min.z&&t.z<=this.max.z}containsBox(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y&&this.min.z<=t.min.z&&t.max.z<=this.max.z}getParameter(t,e){return e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y),(t.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(t){return t.max.x>=this.min.x&&t.min.x<=this.max.x&&t.max.y>=this.min.y&&t.min.y<=this.max.y&&t.max.z>=this.min.z&&t.min.z<=this.max.z}intersectsSphere(t){return this.clampPoint(t.center,Mn),Mn.distanceToSquared(t.center)<=t.radius*t.radius}intersectsPlane(t){let e,n;return t.normal.x>0?(e=t.normal.x*this.min.x,n=t.normal.x*this.max.x):(e=t.normal.x*this.max.x,n=t.normal.x*this.min.x),t.normal.y>0?(e+=t.normal.y*this.min.y,n+=t.normal.y*this.max.y):(e+=t.normal.y*this.max.y,n+=t.normal.y*this.min.y),t.normal.z>0?(e+=t.normal.z*this.min.z,n+=t.normal.z*this.max.z):(e+=t.normal.z*this.max.z,n+=t.normal.z*this.min.z),e<=-t.constant&&n>=-t.constant}intersectsTriangle(t){if(this.isEmpty())return!1;this.getCenter(js),Wr.subVectors(this.max,js),_s.subVectors(t.a,js),ys.subVectors(t.b,js),Ms.subVectors(t.c,js),ui.subVectors(ys,_s),di.subVectors(Ms,ys),ki.subVectors(_s,Ms);let e=[0,-ui.z,ui.y,0,-di.z,di.y,0,-ki.z,ki.y,ui.z,0,-ui.x,di.z,0,-di.x,ki.z,0,-ki.x,-ui.y,ui.x,0,-di.y,di.x,0,-ki.y,ki.x,0];return!yl(e,_s,ys,Ms,Wr)||(e=[1,0,0,0,1,0,0,0,1],!yl(e,_s,ys,Ms,Wr))?!1:($r.crossVectors(ui,di),e=[$r.x,$r.y,$r.z],yl(e,_s,ys,Ms,Wr))}clampPoint(t,e){return e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return this.clampPoint(t,Mn).distanceTo(t)}getBoundingSphere(t){return this.isEmpty()?t.makeEmpty():(this.getCenter(t.center),t.radius=this.getSize(Mn).length()*.5),t}intersect(t){return this.min.max(t.min),this.max.min(t.max),this.isEmpty()&&this.makeEmpty(),this}union(t){return this.min.min(t.min),this.max.max(t.max),this}applyMatrix4(t){return this.isEmpty()?this:(Kn[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(t),Kn[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(t),Kn[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(t),Kn[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(t),Kn[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(t),Kn[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(t),Kn[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(t),Kn[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(t),this.setFromPoints(Kn),this)}translate(t){return this.min.add(t),this.max.add(t),this}equals(t){return t.min.equals(this.min)&&t.max.equals(this.max)}toJSON(){return{min:this.min.toArray(),max:this.max.toArray()}}fromJSON(t){return this.min.fromArray(t.min),this.max.fromArray(t.max),this}}const Kn=[new P,new P,new P,new P,new P,new P,new P,new P],Mn=new P,Vr=new Oi,_s=new P,ys=new P,Ms=new P,ui=new P,di=new P,ki=new P,js=new P,Wr=new P,$r=new P,Bi=new P;function yl(s,t,e,n,i){for(let r=0,o=s.length-3;r<=o;r+=3){Bi.fromArray(s,r);const a=i.x*Math.abs(Bi.x)+i.y*Math.abs(Bi.y)+i.z*Math.abs(Bi.z),l=t.dot(Bi),c=e.dot(Bi),u=n.dot(Bi);if(Math.max(-Math.max(l,c,u),Math.min(l,c,u))>a)return!1}return!0}const Te=new P,Xr=new pt;let Xp=0;class ln extends li{constructor(t,e,n=!1){if(super(),Array.isArray(t))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,Object.defineProperty(this,"id",{value:Xp++}),this.name="",this.array=t,this.itemSize=e,this.count=t!==void 0?t.length/e:0,this.normalized=n,this.usage=oh,this.updateRanges=[],this.gpuType=mn,this.version=0}onUploadCallback(){}set needsUpdate(t){t===!0&&this.version++}setUsage(t){return this.usage=t,this}addUpdateRange(t,e){this.updateRanges.push({start:t,count:e})}clearUpdateRanges(){this.updateRanges.length=0}copy(t){return this.name=t.name,this.array=new t.array.constructor(t.array),this.itemSize=t.itemSize,this.count=t.count,this.normalized=t.normalized,this.usage=t.usage,this.gpuType=t.gpuType,this}copyAt(t,e,n){t*=this.itemSize,n*=e.itemSize;for(let i=0,r=this.itemSize;ithis.radius*this.radius&&(e.sub(this.center).normalize(),e.multiplyScalar(this.radius).add(this.center)),e}getBoundingBox(t){return this.isEmpty()?(t.makeEmpty(),t):(t.set(this.center,this.center),t.expandByScalar(this.radius),t)}applyMatrix4(t){return this.center.applyMatrix4(t),this.radius=this.radius*t.getMaxScaleOnAxis(),this}translate(t){return this.center.add(t),this}expandByPoint(t){if(this.isEmpty())return this.center.copy(t),this.radius=0,this;Qs.subVectors(t,this.center);const e=Qs.lengthSq();if(e>this.radius*this.radius){const n=Math.sqrt(e),i=(n-this.radius)*.5;this.center.addScaledVector(Qs,i/n),this.radius+=i}return this}union(t){return t.isEmpty()?this:this.isEmpty()?(this.copy(t),this):(this.center.equals(t.center)===!0?this.radius=Math.max(this.radius,t.radius):(Ml.subVectors(t.center,this.center).setLength(t.radius),this.expandByPoint(Qs.copy(t.center).add(Ml)),this.expandByPoint(Qs.copy(t.center).sub(Ml))),this)}equals(t){return t.center.equals(this.center)&&t.radius===this.radius}clone(){return new this.constructor().copy(this)}toJSON(){return{radius:this.radius,center:this.center.toArray()}}fromJSON(t){return this.radius=t.radius,this.center.fromArray(t.center),this}}let Yp=0;const cn=new re,bl=new Ee,Ss=new P,en=new Oi,tr=new Oi,Ne=new P;class He extends li{constructor(){super(),this.isBufferGeometry=!0,Object.defineProperty(this,"id",{value:Yp++}),this.uuid=hs(),this.name="",this.type="BufferGeometry",this.index=null,this.indirect=null,this.indirectOffset=0,this.attributes={},this.morphAttributes={},this.morphTargetsRelative=!1,this.groups=[],this.boundingBox=null,this.boundingSphere=null,this.drawRange={start:0,count:1/0},this.userData={},this._transformed=!1}getIndex(){return this.index}setIndex(t){return Array.isArray(t)?this.index=new(dp(t)?Th:Eh)(t,1):this.index=t,this}setIndirect(t,e=0){return this.indirect=t,this.indirectOffset=e,this}getIndirect(){return this.indirect}getAttribute(t){return this.attributes[t]}setAttribute(t,e){return this.attributes[t]=e,this}deleteAttribute(t){return delete this.attributes[t],this}hasAttribute(t){return this.attributes[t]!==void 0}addGroup(t,e,n=0){this.groups.push({start:t,count:e,materialIndex:n})}clearGroups(){this.groups=[]}setDrawRange(t,e){this.drawRange.start=t,this.drawRange.count=e}applyMatrix4(t){const e=this.attributes.position;e!==void 0&&(e.applyMatrix4(t),e.needsUpdate=!0);const n=this.attributes.normal;if(n!==void 0){const r=new Ht().getNormalMatrix(t);n.applyNormalMatrix(r),n.needsUpdate=!0}const i=this.attributes.tangent;return i!==void 0&&(i.transformDirection(t),i.needsUpdate=!0),this.boundingBox!==null&&this.computeBoundingBox(),this.boundingSphere!==null&&this.computeBoundingSphere(),this._transformed=!0,this}applyQuaternion(t){return cn.makeRotationFromQuaternion(t),this.applyMatrix4(cn),this}rotateX(t){return cn.makeRotationX(t),this.applyMatrix4(cn),this}rotateY(t){return cn.makeRotationY(t),this.applyMatrix4(cn),this}rotateZ(t){return cn.makeRotationZ(t),this.applyMatrix4(cn),this}translate(t,e,n){return cn.makeTranslation(t,e,n),this.applyMatrix4(cn),this}scale(t,e,n){return cn.makeScale(t,e,n),this.applyMatrix4(cn),this}lookAt(t){return bl.lookAt(t),bl.updateMatrix(),this.applyMatrix4(bl.matrix),this}center(){return this.computeBoundingBox(),this.boundingBox.getCenter(Ss).negate(),this.translate(Ss.x,Ss.y,Ss.z),this}setFromPoints(t){const e=this.getAttribute("position");if(e===void 0){const n=[];for(let i=0,r=t.length;ie.count&&Ut("BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry."),e.needsUpdate=!0}return this}computeBoundingBox(){this.boundingBox===null&&(this.boundingBox=new Oi);const t=this.attributes.position,e=this.morphAttributes.position;if(t&&t.isGLBufferAttribute){te("BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.",this),this.boundingBox.set(new P(-1/0,-1/0,-1/0),new P(1/0,1/0,1/0));return}if(t!==void 0){if(this.boundingBox.setFromBufferAttribute(t),e)for(let n=0,i=e.length;n0&&(t.userData=this.userData),this.parameters!==void 0&&this._transformed!==!0){const l=this.parameters;for(const c in l)l[c]!==void 0&&(t[c]=l[c]);return t}t.data={attributes:{}};const e=this.index;e!==null&&(t.data.index={type:e.array.constructor.name,array:Array.prototype.slice.call(e.array)});const n=this.attributes;for(const l in n){const c=n[l];t.data.attributes[l]=c.toJSON(t.data)}const i={};let r=!1;for(const l in this.morphAttributes){const c=this.morphAttributes[l],u=[];for(let h=0,d=c.length;h0&&(i[l]=u,r=!0)}r&&(t.data.morphAttributes=i,t.data.morphTargetsRelative=this.morphTargetsRelative);const o=this.groups;o.length>0&&(t.data.groups=JSON.parse(JSON.stringify(o)));const a=this.boundingSphere;return a!==null&&(t.data.boundingSphere=a.toJSON()),t}clone(){return new this.constructor().copy(this)}copy(t){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const e={};this.name=t.name;const n=t.index;n!==null&&this.setIndex(n.clone());const i=t.attributes;for(const c in i){const u=i[c];this.setAttribute(c,u.clone(e))}const r=t.morphAttributes;for(const c in r){const u=[],h=r[c];for(let d=0,f=h.length;d0!=t>0&&this.version++,this._alphaTest=t}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(t){if(t!==void 0)for(const e in t){const n=t[e];if(n===void 0){Ut(`Material: parameter '${e}' has value of undefined.`);continue}const i=this[e];if(i===void 0){Ut(`Material: '${e}' is not a property of THREE.${this.type}.`);continue}i&&i.isColor?i.set(n):i&&i.isVector2&&n&&n.isVector2||i&&i.isEuler&&n&&n.isEuler||i&&i.isVector3&&n&&n.isVector3?i.copy(n):this[e]=n}}toJSON(t){const e=t===void 0||typeof t=="string";e&&(t={textures:{},images:{}});const n={metadata:{version:4.7,type:"Material",generator:"Material.toJSON"}};n.uuid=this.uuid,n.type=this.type,this.name!==""&&(n.name=this.name),this.color&&this.color.isColor&&(n.color=this.color.getHex()),this.roughness!==void 0&&(n.roughness=this.roughness),this.metalness!==void 0&&(n.metalness=this.metalness),this.sheen!==void 0&&(n.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(n.sheenColor=this.sheenColor.getHex()),this.sheenRoughness!==void 0&&(n.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(n.emissive=this.emissive.getHex()),this.emissiveIntensity!==void 0&&this.emissiveIntensity!==1&&(n.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(n.specular=this.specular.getHex()),this.specularIntensity!==void 0&&(n.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(n.specularColor=this.specularColor.getHex()),this.shininess!==void 0&&(n.shininess=this.shininess),this.clearcoat!==void 0&&(n.clearcoat=this.clearcoat),this.clearcoatRoughness!==void 0&&(n.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(n.clearcoatMap=this.clearcoatMap.toJSON(t).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(n.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(t).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(n.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(t).uuid,n.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),this.sheenColorMap&&this.sheenColorMap.isTexture&&(n.sheenColorMap=this.sheenColorMap.toJSON(t).uuid),this.sheenRoughnessMap&&this.sheenRoughnessMap.isTexture&&(n.sheenRoughnessMap=this.sheenRoughnessMap.toJSON(t).uuid),this.dispersion!==void 0&&(n.dispersion=this.dispersion),this.iridescence!==void 0&&(n.iridescence=this.iridescence),this.iridescenceIOR!==void 0&&(n.iridescenceIOR=this.iridescenceIOR),this.iridescenceThicknessRange!==void 0&&(n.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(n.iridescenceMap=this.iridescenceMap.toJSON(t).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(n.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(t).uuid),this.anisotropy!==void 0&&(n.anisotropy=this.anisotropy),this.anisotropyRotation!==void 0&&(n.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(n.anisotropyMap=this.anisotropyMap.toJSON(t).uuid),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(t).uuid),this.matcap&&this.matcap.isTexture&&(n.matcap=this.matcap.toJSON(t).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(t).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(t).uuid,n.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(n.aoMap=this.aoMap.toJSON(t).uuid,n.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(t).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(t).uuid,n.normalMapType=this.normalMapType,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(t).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(t).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(t).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(t).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(t).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(n.specularIntensityMap=this.specularIntensityMap.toJSON(t).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(n.specularColorMap=this.specularColorMap.toJSON(t).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(t).uuid,this.combine!==void 0&&(n.combine=this.combine)),this.envMapRotation!==void 0&&(n.envMapRotation=this.envMapRotation.toArray()),this.envMapIntensity!==void 0&&(n.envMapIntensity=this.envMapIntensity),this.reflectivity!==void 0&&(n.reflectivity=this.reflectivity),this.refractionRatio!==void 0&&(n.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(n.gradientMap=this.gradientMap.toJSON(t).uuid),this.transmission!==void 0&&(n.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(n.transmissionMap=this.transmissionMap.toJSON(t).uuid),this.thickness!==void 0&&(n.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(n.thicknessMap=this.thicknessMap.toJSON(t).uuid),this.attenuationDistance!==void 0&&this.attenuationDistance!==1/0&&(n.attenuationDistance=this.attenuationDistance),this.attenuationColor!==void 0&&(n.attenuationColor=this.attenuationColor.getHex()),this.size!==void 0&&(n.size=this.size),this.shadowSide!==null&&(n.shadowSide=this.shadowSide),this.sizeAttenuation!==void 0&&(n.sizeAttenuation=this.sizeAttenuation),this.blending!==ss&&(n.blending=this.blending),this.side!==oi&&(n.side=this.side),this.vertexColors===!0&&(n.vertexColors=!0),this.opacity<1&&(n.opacity=this.opacity),this.transparent===!0&&(n.transparent=!0),this.blendSrc!==Jo&&(n.blendSrc=this.blendSrc),this.blendDst!==jo&&(n.blendDst=this.blendDst),this.blendEquation!==Di&&(n.blendEquation=this.blendEquation),this.blendSrcAlpha!==null&&(n.blendSrcAlpha=this.blendSrcAlpha),this.blendDstAlpha!==null&&(n.blendDstAlpha=this.blendDstAlpha),this.blendEquationAlpha!==null&&(n.blendEquationAlpha=this.blendEquationAlpha),this.blendColor&&this.blendColor.isColor&&(n.blendColor=this.blendColor.getHex()),this.blendAlpha!==0&&(n.blendAlpha=this.blendAlpha),this.depthFunc!==rs&&(n.depthFunc=this.depthFunc),this.depthTest===!1&&(n.depthTest=this.depthTest),this.depthWrite===!1&&(n.depthWrite=this.depthWrite),this.colorWrite===!1&&(n.colorWrite=this.colorWrite),this.stencilWriteMask!==255&&(n.stencilWriteMask=this.stencilWriteMask),this.stencilFunc!==rh&&(n.stencilFunc=this.stencilFunc),this.stencilRef!==0&&(n.stencilRef=this.stencilRef),this.stencilFuncMask!==255&&(n.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==as&&(n.stencilFail=this.stencilFail),this.stencilZFail!==as&&(n.stencilZFail=this.stencilZFail),this.stencilZPass!==as&&(n.stencilZPass=this.stencilZPass),this.stencilWrite===!0&&(n.stencilWrite=this.stencilWrite),this.rotation!==void 0&&this.rotation!==0&&(n.rotation=this.rotation),this.polygonOffset===!0&&(n.polygonOffset=!0),this.polygonOffsetFactor!==0&&(n.polygonOffsetFactor=this.polygonOffsetFactor),this.polygonOffsetUnits!==0&&(n.polygonOffsetUnits=this.polygonOffsetUnits),this.linewidth!==void 0&&this.linewidth!==1&&(n.linewidth=this.linewidth),this.dashSize!==void 0&&(n.dashSize=this.dashSize),this.gapSize!==void 0&&(n.gapSize=this.gapSize),this.scale!==void 0&&(n.scale=this.scale),this.dithering===!0&&(n.dithering=!0),this.alphaTest>0&&(n.alphaTest=this.alphaTest),this.alphaHash===!0&&(n.alphaHash=!0),this.alphaToCoverage===!0&&(n.alphaToCoverage=!0),this.premultipliedAlpha===!0&&(n.premultipliedAlpha=!0),this.forceSinglePass===!0&&(n.forceSinglePass=!0),this.allowOverride===!1&&(n.allowOverride=!1),this.wireframe===!0&&(n.wireframe=!0),this.wireframeLinewidth>1&&(n.wireframeLinewidth=this.wireframeLinewidth),this.wireframeLinecap!=="round"&&(n.wireframeLinecap=this.wireframeLinecap),this.wireframeLinejoin!=="round"&&(n.wireframeLinejoin=this.wireframeLinejoin),this.flatShading===!0&&(n.flatShading=!0),this.visible===!1&&(n.visible=!1),this.toneMapped===!1&&(n.toneMapped=!1),this.fog===!1&&(n.fog=!1),Object.keys(this.userData).length>0&&(n.userData=this.userData);function i(r){const o=[];for(const a in r){const l=r[a];delete l.metadata,o.push(l)}return o}if(e){const r=i(t.textures),o=i(t.images);r.length>0&&(n.textures=r),o.length>0&&(n.images=o)}return n}fromJSON(t,e){if(t.uuid!==void 0&&(this.uuid=t.uuid),t.name!==void 0&&(this.name=t.name),t.color!==void 0&&this.color!==void 0&&this.color.setHex(t.color),t.roughness!==void 0&&(this.roughness=t.roughness),t.metalness!==void 0&&(this.metalness=t.metalness),t.sheen!==void 0&&(this.sheen=t.sheen),t.sheenColor!==void 0&&(this.sheenColor=new Bt().setHex(t.sheenColor)),t.sheenRoughness!==void 0&&(this.sheenRoughness=t.sheenRoughness),t.emissive!==void 0&&this.emissive!==void 0&&this.emissive.setHex(t.emissive),t.specular!==void 0&&this.specular!==void 0&&this.specular.setHex(t.specular),t.specularIntensity!==void 0&&(this.specularIntensity=t.specularIntensity),t.specularColor!==void 0&&this.specularColor!==void 0&&this.specularColor.setHex(t.specularColor),t.shininess!==void 0&&(this.shininess=t.shininess),t.clearcoat!==void 0&&(this.clearcoat=t.clearcoat),t.clearcoatRoughness!==void 0&&(this.clearcoatRoughness=t.clearcoatRoughness),t.dispersion!==void 0&&(this.dispersion=t.dispersion),t.iridescence!==void 0&&(this.iridescence=t.iridescence),t.iridescenceIOR!==void 0&&(this.iridescenceIOR=t.iridescenceIOR),t.iridescenceThicknessRange!==void 0&&(this.iridescenceThicknessRange=t.iridescenceThicknessRange),t.transmission!==void 0&&(this.transmission=t.transmission),t.thickness!==void 0&&(this.thickness=t.thickness),t.attenuationDistance!==void 0&&(this.attenuationDistance=t.attenuationDistance),t.attenuationColor!==void 0&&this.attenuationColor!==void 0&&this.attenuationColor.setHex(t.attenuationColor),t.anisotropy!==void 0&&(this.anisotropy=t.anisotropy),t.anisotropyRotation!==void 0&&(this.anisotropyRotation=t.anisotropyRotation),t.fog!==void 0&&(this.fog=t.fog),t.flatShading!==void 0&&(this.flatShading=t.flatShading),t.blending!==void 0&&(this.blending=t.blending),t.combine!==void 0&&(this.combine=t.combine),t.side!==void 0&&(this.side=t.side),t.shadowSide!==void 0&&(this.shadowSide=t.shadowSide),t.opacity!==void 0&&(this.opacity=t.opacity),t.transparent!==void 0&&(this.transparent=t.transparent),t.alphaTest!==void 0&&(this.alphaTest=t.alphaTest),t.alphaHash!==void 0&&(this.alphaHash=t.alphaHash),t.depthFunc!==void 0&&(this.depthFunc=t.depthFunc),t.depthTest!==void 0&&(this.depthTest=t.depthTest),t.depthWrite!==void 0&&(this.depthWrite=t.depthWrite),t.colorWrite!==void 0&&(this.colorWrite=t.colorWrite),t.blendSrc!==void 0&&(this.blendSrc=t.blendSrc),t.blendDst!==void 0&&(this.blendDst=t.blendDst),t.blendEquation!==void 0&&(this.blendEquation=t.blendEquation),t.blendSrcAlpha!==void 0&&(this.blendSrcAlpha=t.blendSrcAlpha),t.blendDstAlpha!==void 0&&(this.blendDstAlpha=t.blendDstAlpha),t.blendEquationAlpha!==void 0&&(this.blendEquationAlpha=t.blendEquationAlpha),t.blendColor!==void 0&&this.blendColor!==void 0&&this.blendColor.setHex(t.blendColor),t.blendAlpha!==void 0&&(this.blendAlpha=t.blendAlpha),t.stencilWriteMask!==void 0&&(this.stencilWriteMask=t.stencilWriteMask),t.stencilFunc!==void 0&&(this.stencilFunc=t.stencilFunc),t.stencilRef!==void 0&&(this.stencilRef=t.stencilRef),t.stencilFuncMask!==void 0&&(this.stencilFuncMask=t.stencilFuncMask),t.stencilFail!==void 0&&(this.stencilFail=t.stencilFail),t.stencilZFail!==void 0&&(this.stencilZFail=t.stencilZFail),t.stencilZPass!==void 0&&(this.stencilZPass=t.stencilZPass),t.stencilWrite!==void 0&&(this.stencilWrite=t.stencilWrite),t.wireframe!==void 0&&(this.wireframe=t.wireframe),t.wireframeLinewidth!==void 0&&(this.wireframeLinewidth=t.wireframeLinewidth),t.wireframeLinecap!==void 0&&(this.wireframeLinecap=t.wireframeLinecap),t.wireframeLinejoin!==void 0&&(this.wireframeLinejoin=t.wireframeLinejoin),t.rotation!==void 0&&(this.rotation=t.rotation),t.linewidth!==void 0&&(this.linewidth=t.linewidth),t.dashSize!==void 0&&(this.dashSize=t.dashSize),t.gapSize!==void 0&&(this.gapSize=t.gapSize),t.scale!==void 0&&(this.scale=t.scale),t.polygonOffset!==void 0&&(this.polygonOffset=t.polygonOffset),t.polygonOffsetFactor!==void 0&&(this.polygonOffsetFactor=t.polygonOffsetFactor),t.polygonOffsetUnits!==void 0&&(this.polygonOffsetUnits=t.polygonOffsetUnits),t.dithering!==void 0&&(this.dithering=t.dithering),t.alphaToCoverage!==void 0&&(this.alphaToCoverage=t.alphaToCoverage),t.premultipliedAlpha!==void 0&&(this.premultipliedAlpha=t.premultipliedAlpha),t.forceSinglePass!==void 0&&(this.forceSinglePass=t.forceSinglePass),t.allowOverride!==void 0&&(this.allowOverride=t.allowOverride),t.visible!==void 0&&(this.visible=t.visible),t.toneMapped!==void 0&&(this.toneMapped=t.toneMapped),t.userData!==void 0&&(this.userData=t.userData),t.vertexColors!==void 0&&(typeof t.vertexColors=="number"?this.vertexColors=t.vertexColors>0:this.vertexColors=t.vertexColors),t.size!==void 0&&(this.size=t.size),t.sizeAttenuation!==void 0&&(this.sizeAttenuation=t.sizeAttenuation),t.map!==void 0&&(this.map=e[t.map]||null),t.matcap!==void 0&&(this.matcap=e[t.matcap]||null),t.alphaMap!==void 0&&(this.alphaMap=e[t.alphaMap]||null),t.bumpMap!==void 0&&(this.bumpMap=e[t.bumpMap]||null),t.bumpScale!==void 0&&(this.bumpScale=t.bumpScale),t.normalMap!==void 0&&(this.normalMap=e[t.normalMap]||null),t.normalMapType!==void 0&&(this.normalMapType=t.normalMapType),t.normalScale!==void 0){let n=t.normalScale;Array.isArray(n)===!1&&(n=[n,n]),this.normalScale=new pt().fromArray(n)}return t.displacementMap!==void 0&&(this.displacementMap=e[t.displacementMap]||null),t.displacementScale!==void 0&&(this.displacementScale=t.displacementScale),t.displacementBias!==void 0&&(this.displacementBias=t.displacementBias),t.roughnessMap!==void 0&&(this.roughnessMap=e[t.roughnessMap]||null),t.metalnessMap!==void 0&&(this.metalnessMap=e[t.metalnessMap]||null),t.emissiveMap!==void 0&&(this.emissiveMap=e[t.emissiveMap]||null),t.emissiveIntensity!==void 0&&(this.emissiveIntensity=t.emissiveIntensity),t.specularMap!==void 0&&(this.specularMap=e[t.specularMap]||null),t.specularIntensityMap!==void 0&&(this.specularIntensityMap=e[t.specularIntensityMap]||null),t.specularColorMap!==void 0&&(this.specularColorMap=e[t.specularColorMap]||null),t.envMap!==void 0&&(this.envMap=e[t.envMap]||null),t.envMapRotation!==void 0&&this.envMapRotation.fromArray(t.envMapRotation),t.envMapIntensity!==void 0&&(this.envMapIntensity=t.envMapIntensity),t.reflectivity!==void 0&&(this.reflectivity=t.reflectivity),t.refractionRatio!==void 0&&(this.refractionRatio=t.refractionRatio),t.lightMap!==void 0&&(this.lightMap=e[t.lightMap]||null),t.lightMapIntensity!==void 0&&(this.lightMapIntensity=t.lightMapIntensity),t.aoMap!==void 0&&(this.aoMap=e[t.aoMap]||null),t.aoMapIntensity!==void 0&&(this.aoMapIntensity=t.aoMapIntensity),t.gradientMap!==void 0&&(this.gradientMap=e[t.gradientMap]||null),t.clearcoatMap!==void 0&&(this.clearcoatMap=e[t.clearcoatMap]||null),t.clearcoatRoughnessMap!==void 0&&(this.clearcoatRoughnessMap=e[t.clearcoatRoughnessMap]||null),t.clearcoatNormalMap!==void 0&&(this.clearcoatNormalMap=e[t.clearcoatNormalMap]||null),t.clearcoatNormalScale!==void 0&&(this.clearcoatNormalScale=new pt().fromArray(t.clearcoatNormalScale)),t.iridescenceMap!==void 0&&(this.iridescenceMap=e[t.iridescenceMap]||null),t.iridescenceThicknessMap!==void 0&&(this.iridescenceThicknessMap=e[t.iridescenceThicknessMap]||null),t.transmissionMap!==void 0&&(this.transmissionMap=e[t.transmissionMap]||null),t.thicknessMap!==void 0&&(this.thicknessMap=e[t.thicknessMap]||null),t.anisotropyMap!==void 0&&(this.anisotropyMap=e[t.anisotropyMap]||null),t.sheenColorMap!==void 0&&(this.sheenColorMap=e[t.sheenColorMap]||null),t.sheenRoughnessMap!==void 0&&(this.sheenRoughnessMap=e[t.sheenRoughnessMap]||null),this}clone(){return new this.constructor().copy(this)}copy(t){this.name=t.name,this.blending=t.blending,this.side=t.side,this.vertexColors=t.vertexColors,this.opacity=t.opacity,this.transparent=t.transparent,this.blendSrc=t.blendSrc,this.blendDst=t.blendDst,this.blendEquation=t.blendEquation,this.blendSrcAlpha=t.blendSrcAlpha,this.blendDstAlpha=t.blendDstAlpha,this.blendEquationAlpha=t.blendEquationAlpha,this.blendColor.copy(t.blendColor),this.blendAlpha=t.blendAlpha,this.depthFunc=t.depthFunc,this.depthTest=t.depthTest,this.depthWrite=t.depthWrite,this.stencilWriteMask=t.stencilWriteMask,this.stencilFunc=t.stencilFunc,this.stencilRef=t.stencilRef,this.stencilFuncMask=t.stencilFuncMask,this.stencilFail=t.stencilFail,this.stencilZFail=t.stencilZFail,this.stencilZPass=t.stencilZPass,this.stencilWrite=t.stencilWrite;const e=t.clippingPlanes;let n=null;if(e!==null){const i=e.length;n=new Array(i);for(let r=0;r!==i;++r)n[r]=e[r].clone()}return this.clippingPlanes=n,this.clipIntersection=t.clipIntersection,this.clipShadows=t.clipShadows,this.shadowSide=t.shadowSide,this.colorWrite=t.colorWrite,this.precision=t.precision,this.polygonOffset=t.polygonOffset,this.polygonOffsetFactor=t.polygonOffsetFactor,this.polygonOffsetUnits=t.polygonOffsetUnits,this.dithering=t.dithering,this.alphaTest=t.alphaTest,this.alphaHash=t.alphaHash,this.alphaToCoverage=t.alphaToCoverage,this.premultipliedAlpha=t.premultipliedAlpha,this.forceSinglePass=t.forceSinglePass,this.allowOverride=t.allowOverride,this.visible=t.visible,this.toneMapped=t.toneMapped,this.userData=JSON.parse(JSON.stringify(t.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(t){t===!0&&this.version++}}const Zn=new P,Sl=new P,qr=new P,fi=new P,wl=new P,Yr=new P,El=new P;class Kr{constructor(t=new P,e=new P(0,0,-1)){this.origin=t,this.direction=e}set(t,e){return this.origin.copy(t),this.direction.copy(e),this}copy(t){return this.origin.copy(t.origin),this.direction.copy(t.direction),this}at(t,e){return e.copy(this.origin).addScaledVector(this.direction,t)}lookAt(t){return this.direction.copy(t).sub(this.origin).normalize(),this}recast(t){return this.origin.copy(this.at(t,Zn)),this}closestPointToPoint(t,e){e.subVectors(t,this.origin);const n=e.dot(this.direction);return n<0?e.copy(this.origin):e.copy(this.origin).addScaledVector(this.direction,n)}distanceToPoint(t){return Math.sqrt(this.distanceSqToPoint(t))}distanceSqToPoint(t){const e=Zn.subVectors(t,this.origin).dot(this.direction);return e<0?this.origin.distanceToSquared(t):(Zn.copy(this.origin).addScaledVector(this.direction,e),Zn.distanceToSquared(t))}distanceSqToSegment(t,e,n,i){Sl.copy(t).add(e).multiplyScalar(.5),qr.copy(e).sub(t).normalize(),fi.copy(this.origin).sub(Sl);const r=t.distanceTo(e)*.5,o=-this.direction.dot(qr),a=fi.dot(this.direction),l=-fi.dot(qr),c=fi.lengthSq(),u=Math.abs(1-o*o);let h,d,f,p;if(u>0)if(h=o*l-a,d=o*a-l,p=r*u,h>=0)if(d>=-p)if(d<=p){const x=1/u;h*=x,d*=x,f=h*(h+o*d+2*a)+d*(o*h+d+2*l)+c}else d=r,h=Math.max(0,-(o*d+a)),f=-h*h+d*(d+2*l)+c;else d=-r,h=Math.max(0,-(o*d+a)),f=-h*h+d*(d+2*l)+c;else d<=-p?(h=Math.max(0,-(-o*r+a)),d=h>0?-r:Math.min(Math.max(-r,-l),r),f=-h*h+d*(d+2*l)+c):d<=p?(h=0,d=Math.min(Math.max(-r,-l),r),f=d*(d+2*l)+c):(h=Math.max(0,-(o*r+a)),d=h>0?r:Math.min(Math.max(-r,-l),r),f=-h*h+d*(d+2*l)+c);else d=o>0?-r:r,h=Math.max(0,-(o*d+a)),f=-h*h+d*(d+2*l)+c;return n&&n.copy(this.origin).addScaledVector(this.direction,h),i&&i.copy(Sl).addScaledVector(qr,d),f}intersectSphere(t,e){Zn.subVectors(t.center,this.origin);const n=Zn.dot(this.direction),i=Zn.dot(Zn)-n*n,r=t.radius*t.radius;if(i>r)return null;const o=Math.sqrt(r-i),a=n-o,l=n+o;return l<0?null:a<0?this.at(l,e):this.at(a,e)}intersectsSphere(t){return t.radius<0?!1:this.distanceSqToPoint(t.center)<=t.radius*t.radius}distanceToPlane(t){const e=t.normal.dot(this.direction);if(e===0)return t.distanceToPoint(this.origin)===0?0:null;const n=-(this.origin.dot(t.normal)+t.constant)/e;return n>=0?n:null}intersectPlane(t,e){const n=this.distanceToPlane(t);return n===null?null:this.at(n,e)}intersectsPlane(t){const e=t.distanceToPoint(this.origin);return e===0||t.normal.dot(this.direction)*e<0}intersectBox(t,e){let n,i,r,o,a,l;const c=1/this.direction.x,u=1/this.direction.y,h=1/this.direction.z,d=this.origin;return c>=0?(n=(t.min.x-d.x)*c,i=(t.max.x-d.x)*c):(n=(t.max.x-d.x)*c,i=(t.min.x-d.x)*c),u>=0?(r=(t.min.y-d.y)*u,o=(t.max.y-d.y)*u):(r=(t.max.y-d.y)*u,o=(t.min.y-d.y)*u),n>o||r>i||((r>n||isNaN(n))&&(n=r),(o=0?(a=(t.min.z-d.z)*h,l=(t.max.z-d.z)*h):(a=(t.max.z-d.z)*h,l=(t.min.z-d.z)*h),n>l||a>i)||((a>n||n!==n)&&(n=a),(l=0?n:i,e)}intersectsBox(t){return this.intersectBox(t,Zn)!==null}intersectTriangle(t,e,n,i,r){wl.subVectors(e,t),Yr.subVectors(n,t),El.crossVectors(wl,Yr);let o=this.direction.dot(El),a;if(o>0){if(i)return null;a=1}else if(o<0)a=-1,o=-o;else return null;fi.subVectors(this.origin,t);const l=a*this.direction.dot(Yr.crossVectors(fi,Yr));if(l<0)return null;const c=a*this.direction.dot(wl.cross(fi));if(c<0||l+c>o)return null;const u=-a*fi.dot(El);return u<0?null:this.at(u/o,r)}applyMatrix4(t){return this.origin.applyMatrix4(t),this.direction.transformDirection(t),this}equals(t){return t.origin.equals(this.origin)&&t.direction.equals(this.direction)}clone(){return new this.constructor().copy(this)}}class bn extends ws{constructor(t){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new Bt(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new $n,this.combine=Jc,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.envMapRotation.copy(t.envMapRotation),this.combine=t.combine,this.reflectivity=t.reflectivity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.fog=t.fog,this}}const Ah=new re,zi=new Kr,Zr=new bs,Ch=new P,Jr=new P,jr=new P,Qr=new P,Tl=new P,to=new P,Rh=new P,eo=new P;class zt extends Ee{constructor(t=new He,e=new bn){super(),this.isMesh=!0,this.type="Mesh",this.geometry=t,this.material=e,this.morphTargetDictionary=void 0,this.morphTargetInfluences=void 0,this.count=1,this.updateMorphTargets()}copy(t,e){return super.copy(t,e),t.morphTargetInfluences!==void 0&&(this.morphTargetInfluences=t.morphTargetInfluences.slice()),t.morphTargetDictionary!==void 0&&(this.morphTargetDictionary=Object.assign({},t.morphTargetDictionary)),this.material=Array.isArray(t.material)?t.material.slice():t.material,this.geometry=t.geometry,this}updateMorphTargets(){const e=this.geometry.morphAttributes,n=Object.keys(e);if(n.length>0){const i=e[n[0]];if(i!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,o=i.length;r(t.far-t.near)**2))&&(Ah.copy(r).invert(),zi.copy(t.ray).applyMatrix4(Ah),!(n.boundingBox!==null&&zi.intersectsBox(n.boundingBox)===!1)&&this._computeIntersections(t,e,zi)))}_computeIntersections(t,e,n){let i;const r=this.geometry,o=this.material,a=r.index,l=r.attributes.position,c=r.attributes.uv,u=r.attributes.uv1,h=r.attributes.normal,d=r.groups,f=r.drawRange;if(a!==null)if(Array.isArray(o))for(let p=0,x=d.length;pe.far?null:{distance:c,point:eo.clone(),object:s}}function no(s,t,e,n,i,r,o,a,l,c){s.getVertexPosition(a,Jr),s.getVertexPosition(l,jr),s.getVertexPosition(c,Qr);const u=Zp(s,t,e,n,Jr,jr,Qr,Rh);if(u){const h=new P;yn.getBarycoord(Rh,Jr,jr,Qr,h),i&&(u.uv=yn.getInterpolatedAttribute(i,a,l,c,h,new pt)),r&&(u.uv1=yn.getInterpolatedAttribute(r,a,l,c,h,new pt)),o&&(u.normal=yn.getInterpolatedAttribute(o,a,l,c,h,new P),u.normal.dot(n.direction)>0&&u.normal.multiplyScalar(-1));const d={a,b:l,c,normal:new P,materialIndex:0};yn.getNormal(Jr,jr,Qr,d.normal),u.face=d,u.barycoord=h}return u}class Ph extends Be{constructor(t=null,e=1,n=1,i,r,o,a,l,c=Fe,u=Fe,h,d){super(null,o,a,l,c,u,i,r,h,d),this.isDataTexture=!0,this.image={data:t,width:e,height:n},this.generateMipmaps=!1,this.flipY=!1,this.unpackAlignment=1}}class er extends ln{constructor(t,e,n,i=1){super(t,e,n),this.isInstancedBufferAttribute=!0,this.meshPerAttribute=i}copy(t){return super.copy(t),this.meshPerAttribute=t.meshPerAttribute,this}toJSON(){const t=super.toJSON();return t.meshPerAttribute=this.meshPerAttribute,t.isInstancedBufferAttribute=!0,t}}const Es=new re,Lh=new re,io=[],Dh=new Oi,Jp=new re,nr=new zt,ir=new bs;class Ih extends zt{constructor(t,e,n){super(t,e),this.isInstancedMesh=!0,this.instanceMatrix=new er(new Float32Array(n*16),16),this.instanceColor=null,this.morphTexture=null,this.count=n,this.boundingBox=null,this.boundingSphere=null;for(let i=0;i1)?null:e.copy(t.start).addScaledVector(i,o)}intersectsLine(t){const e=this.distanceToPoint(t.start),n=this.distanceToPoint(t.end);return e<0&&n>0||n<0&&e>0}intersectsBox(t){return t.intersectsPlane(this)}intersectsSphere(t){return t.intersectsPlane(this)}coplanarPoint(t){return t.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(t,e){const n=e||Qp.getNormalMatrix(t),i=this.coplanarPoint(Al).applyMatrix4(t),r=this.normal.applyMatrix3(n).normalize();return this.constant=-i.dot(r),this}translate(t){return this.constant-=t.dot(this.normal),this}equals(t){return t.normal.equals(this.normal)&&t.constant===this.constant}clone(){return new this.constructor().copy(this)}}const Hi=new bs,tm=new pt(.5,.5),so=new P;class ro{constructor(t=new pi,e=new pi,n=new pi,i=new pi,r=new pi,o=new pi){this.planes=[t,e,n,i,r,o]}set(t,e,n,i,r,o){const a=this.planes;return a[0].copy(t),a[1].copy(e),a[2].copy(n),a[3].copy(i),a[4].copy(r),a[5].copy(o),this}copy(t){const e=this.planes;for(let n=0;n<6;n++)e[n].copy(t.planes[n]);return this}setFromProjectionMatrix(t,e=Rn,n=!1){const i=this.planes,r=t.elements,o=r[0],a=r[1],l=r[2],c=r[3],u=r[4],h=r[5],d=r[6],f=r[7],p=r[8],x=r[9],m=r[10],g=r[11],b=r[12],E=r[13],y=r[14],M=r[15];if(i[0].setComponents(c-o,f-u,g-p,M-b).normalize(),i[1].setComponents(c+o,f+u,g+p,M+b).normalize(),i[2].setComponents(c+a,f+h,g+x,M+E).normalize(),i[3].setComponents(c-a,f-h,g-x,M-E).normalize(),n)i[4].setComponents(l,d,m,y).normalize(),i[5].setComponents(c-l,f-d,g-m,M-y).normalize();else if(i[4].setComponents(c-l,f-d,g-m,M-y).normalize(),e===Rn)i[5].setComponents(c+l,f+d,g+m,M+y).normalize();else if(e===Ys)i[5].setComponents(l,d,m,y).normalize();else throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+e);return this}intersectsObject(t){if(t.boundingSphere!==void 0)t.boundingSphere===null&&t.computeBoundingSphere(),Hi.copy(t.boundingSphere).applyMatrix4(t.matrixWorld);else{const e=t.geometry;e.boundingSphere===null&&e.computeBoundingSphere(),Hi.copy(e.boundingSphere).applyMatrix4(t.matrixWorld)}return this.intersectsSphere(Hi)}intersectsSprite(t){Hi.center.set(0,0,0);const e=tm.distanceTo(t.center);return Hi.radius=.7071067811865476+e,Hi.applyMatrix4(t.matrixWorld),this.intersectsSphere(Hi)}intersectsSphere(t){const e=this.planes,n=t.center,i=-t.radius;for(let r=0;r<6;r++)if(e[r].distanceToPoint(n)0?t.max.x:t.min.x,so.y=i.normal.y>0?t.max.y:t.min.y,so.z=i.normal.z>0?t.max.z:t.min.z,i.distanceToPoint(so)<0)return!1}return!0}containsPoint(t){const e=this.planes;for(let n=0;n<6;n++)if(e[n].distanceToPoint(t)<0)return!1;return!0}clone(){return new this.constructor().copy(this)}}class Nh extends ws{constructor(t){super(),this.isLineBasicMaterial=!0,this.type="LineBasicMaterial",this.color=new Bt(16777215),this.map=null,this.linewidth=1,this.linecap="round",this.linejoin="round",this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.linewidth=t.linewidth,this.linecap=t.linecap,this.linejoin=t.linejoin,this.fog=t.fog,this}}const oo=new P,ao=new P,Uh=new re,sr=new Kr,lo=new bs,Cl=new P,Fh=new P;class Oh extends Ee{constructor(t=new He,e=new Nh){super(),this.isLine=!0,this.type="Line",this.geometry=t,this.material=e,this.morphTargetDictionary=void 0,this.morphTargetInfluences=void 0,this.updateMorphTargets()}copy(t,e){return super.copy(t,e),this.material=Array.isArray(t.material)?t.material.slice():t.material,this.geometry=t.geometry,this}computeLineDistances(){const t=this.geometry;if(t.index===null){const e=t.attributes.position,n=[0];for(let i=1,r=e.count;i0){const i=e[n[0]];if(i!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,o=i.length;rn)return;Cl.applyMatrix4(s.matrixWorld);const c=t.ray.origin.distanceTo(Cl);if(!(ct.far))return{distance:c,point:Fh.clone().applyMatrix4(s.matrixWorld),index:o,face:null,faceIndex:null,barycoord:null,object:s}}class kh extends Be{constructor(t=[],e=Ii,n,i,r,o,a,l,c,u){super(t,e,n,i,r,o,a,l,c,u),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(t){this.image=t}}class mi extends Be{constructor(t,e,n,i,r,o,a,l,c){super(t,e,n,i,r,o,a,l,c),this.isCanvasTexture=!0,this.needsUpdate=!0}}class Ts extends Be{constructor(t,e,n=Cn,i,r,o,a=Fe,l=Fe,c,u=Vn,h=1){if(u!==Vn&&u!==Ui)throw new Error("THREE.DepthTexture: format must be either THREE.DepthFormat or THREE.DepthStencilFormat");const d={width:t,height:e,depth:h};super(d,i,r,o,a,l,u,n,c),this.isDepthTexture=!0,this.flipY=!1,this.generateMipmaps=!1,this.compareFunction=null}copy(t){return super.copy(t),this.source=new rl(Object.assign({},t.image)),this.compareFunction=t.compareFunction,this}toJSON(t){const e=super.toJSON(t);return this.compareFunction!==null&&(e.compareFunction=this.compareFunction),e}}class em extends Ts{constructor(t,e=Cn,n=Ii,i,r,o=Fe,a=Fe,l,c=Vn){const u={width:t,height:t,depth:1},h=[u,u,u,u,u,u];super(t,t,e,n,i,r,o,a,l,c),this.image=h,this.isCubeDepthTexture=!0,this.isCubeTexture=!0}get images(){return this.image}set images(t){this.image=t}}class Bh extends Be{constructor(t=null){super(),this.sourceTexture=t,this.isExternalTexture=!0}copy(t){return super.copy(t),this.sourceTexture=t.sourceTexture,this}}class nn extends He{constructor(t=1,e=1,n=1,i=1,r=1,o=1){super(),this.type="BoxGeometry",this.parameters={width:t,height:e,depth:n,widthSegments:i,heightSegments:r,depthSegments:o};const a=this;i=Math.floor(i),r=Math.floor(r),o=Math.floor(o);const l=[],c=[],u=[],h=[];let d=0,f=0;p("z","y","x",-1,-1,n,e,t,o,r,0),p("z","y","x",1,-1,n,e,-t,o,r,1),p("x","z","y",1,1,t,n,e,i,o,2),p("x","z","y",1,-1,t,n,-e,i,o,3),p("x","y","z",1,-1,t,e,n,i,r,4),p("x","y","z",-1,-1,t,e,-n,i,r,5),this.setIndex(l),this.setAttribute("position",new Me(c,3)),this.setAttribute("normal",new Me(u,3)),this.setAttribute("uv",new Me(h,2));function p(x,m,g,b,E,y,M,w,C,v,T){const L=y/C,D=M/v,U=y/2,Y=M/2,K=w/2,N=C+1,B=v+1;let z=0,Z=0;const nt=new P;for(let rt=0;rt0?1:-1,u.push(nt.x,nt.y,nt.z),h.push(ht/C),h.push(1-rt/v),z+=1}}for(let rt=0;rt0&&E(!0),e>0&&E(!1)),this.setIndex(u),this.setAttribute("position",new Me(h,3)),this.setAttribute("normal",new Me(d,3)),this.setAttribute("uv",new Me(f,2));function b(){const y=new P,M=new P;let w=0;const C=(e-t)/n;for(let v=0;v<=r;v++){const T=[],L=v/r,D=L*(e-t)+t;for(let U=0;U<=i;U++){const Y=U/i,K=Y*l+a,N=Math.sin(K),B=Math.cos(K);M.x=D*N,M.y=-L*n+m,M.z=D*B,h.push(M.x,M.y,M.z),y.set(N,C,B).normalize(),d.push(y.x,y.y,y.z),f.push(Y,1-L),T.push(p++)}x.push(T)}for(let v=0;v0||T!==0)&&(u.push(L,D,Y),w+=3),(e>0||T!==r-1)&&(u.push(D,U,Y),w+=3)}c.addGroup(g,w,0),g+=w}function E(y){const M=p,w=new pt,C=new P;let v=0;const T=y===!0?t:e,L=y===!0?1:-1;for(let U=1;U<=i;U++)h.push(0,m*L,0),d.push(0,L,0),f.push(.5,.5),p++;const D=p;for(let U=0;U<=i;U++){const K=U/i*l+a,N=Math.cos(K),B=Math.sin(K);C.x=T*B,C.y=m*L,C.z=T*N,h.push(C.x,C.y,C.z),d.push(0,L,0),w.x=N*.5+.5,w.y=B*.5*L+.5,f.push(w.x,w.y),p++}for(let U=0;U0)l=i-1;else{l=i;break}if(i=l,n[i]===o)return i/(r-1);const u=n[i],d=n[i+1]-u,f=(o-u)/d;return(i+f)/(r-1)}getTangent(t,e){let i=t-1e-4,r=t+1e-4;i<0&&(i=0),r>1&&(r=1);const o=this.getPoint(i),a=this.getPoint(r),l=e||(o.isVector2?new pt:new P);return l.copy(a).sub(o).normalize(),l}getTangentAt(t,e){const n=this.getUtoTmapping(t);return this.getTangent(n,e)}computeFrenetFrames(t,e=!1){const n=new P,i=[],r=[],o=[],a=new P,l=new re;for(let f=0;f<=t;f++){const p=f/t;i[f]=this.getTangentAt(p,new P)}r[0]=new P,o[0]=new P;let c=Number.MAX_VALUE;const u=Math.abs(i[0].x),h=Math.abs(i[0].y),d=Math.abs(i[0].z);u<=c&&(c=u,n.set(1,0,0)),h<=c&&(c=h,n.set(0,1,0)),d<=c&&n.set(0,0,1),a.crossVectors(i[0],n).normalize(),r[0].crossVectors(i[0],a),o[0].crossVectors(i[0],r[0]);for(let f=1;f<=t;f++){if(r[f]=r[f-1].clone(),o[f]=o[f-1].clone(),a.crossVectors(i[f-1],i[f]),a.length()>Number.EPSILON){a.normalize();const p=Math.acos(qt(i[f-1].dot(i[f]),-1,1));r[f].applyMatrix4(l.makeRotationAxis(a,p))}o[f].crossVectors(i[f],r[f])}if(e===!0){let f=Math.acos(qt(r[0].dot(r[t]),-1,1));f/=t,i[0].dot(a.crossVectors(r[0],r[t]))>0&&(f=-f);for(let p=1;p<=t;p++)r[p].applyMatrix4(l.makeRotationAxis(i[p],f*p)),o[p].crossVectors(i[p],r[p])}return{tangents:i,normals:r,binormals:o}}clone(){return new this.constructor().copy(this)}copy(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}toJSON(){const t={metadata:{version:4.7,type:"Curve",generator:"Curve.toJSON"}};return t.arcLengthDivisions=this.arcLengthDivisions,t.type=this.type,t}fromJSON(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}}class zh extends Jn{constructor(t=0,e=0,n=1,i=1,r=0,o=Math.PI*2,a=!1,l=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=t,this.aY=e,this.xRadius=n,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=o,this.aClockwise=a,this.aRotation=l}getPoint(t,e=new pt){const n=e,i=Math.PI*2;let r=this.aEndAngle-this.aStartAngle;const o=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(a)/r)+1)*r:l===0&&a===r-1&&(a=r-2,l=1);let c,u;this.closed||a>0?c=i[(a-1)%r]:(Gh.subVectors(i[0],i[1]).add(i[0]),c=Gh);const h=i[a%r],d=i[(a+1)%r];if(this.closed||a+2i.length-2?i.length-1:o+1],h=i[o>i.length-3?i.length-1:o+2];return n.set(Wh(a,l.x,c.x,u.x,h.x),Wh(a,l.y,c.y,u.y,h.y)),n}copy(t){super.copy(t),this.points=[];for(let e=0,n=t.points.length;e0)&&f.push(E,y,w),(g!==n-1||l0&&(e.defines=this.defines),e.vertexShader=this.vertexShader,e.fragmentShader=this.fragmentShader,e.lights=this.lights,e.clipping=this.clipping;const n={};for(const i in this.extensions)this.extensions[i]===!0&&(n[i]=!0);return Object.keys(n).length>0&&(e.extensions=n),e}fromJSON(t,e){if(super.fromJSON(t,e),t.uniforms!==void 0)for(const n in t.uniforms){const i=t.uniforms[n];switch(this.uniforms[n]={},i.type){case"t":this.uniforms[n].value=e[i.value]||null;break;case"c":this.uniforms[n].value=new kt().setHex(i.value);break;case"v2":this.uniforms[n].value=new ht().fromArray(i.value);break;case"v3":this.uniforms[n].value=new C().fromArray(i.value);break;case"v4":this.uniforms[n].value=new me().fromArray(i.value);break;case"m3":this.uniforms[n].value=new zt().fromArray(i.value);break;case"m4":this.uniforms[n].value=new se().fromArray(i.value);break;default:this.uniforms[n].value=i.value}}if(t.defines!==void 0&&(this.defines=t.defines),t.vertexShader!==void 0&&(this.vertexShader=t.vertexShader),t.fragmentShader!==void 0&&(this.fragmentShader=t.fragmentShader),t.glslVersion!==void 0&&(this.glslVersion=t.glslVersion),t.extensions!==void 0)for(const n in t.extensions)this.extensions[n]=t.extensions[n];return t.lights!==void 0&&(this.lights=t.lights),t.clipping!==void 0&&(this.clipping=t.clipping),this}}class sh extends Ce{constructor(t){super(t),this.isRawShaderMaterial=!0,this.type="RawShaderMaterial"}}class Ee extends cs{constructor(t){super(),this.isMeshStandardMaterial=!0,this.type="MeshStandardMaterial",this.defines={STANDARD:""},this.color=new kt(16777215),this.roughness=1,this.metalness=0,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new kt(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=wo,this.normalScale=new ht(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.roughnessMap=null,this.metalnessMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new Hn,this.envMapIntensity=1,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.defines={STANDARD:""},this.color.copy(t.color),this.roughness=t.roughness,this.metalness=t.metalness,this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.roughnessMap=t.roughnessMap,this.metalnessMap=t.metalnessMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.envMapRotation.copy(t.envMapRotation),this.envMapIntensity=t.envMapIntensity,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.flatShading=t.flatShading,this.fog=t.fog,this}}class sp extends cs{constructor(t){super(),this.isMeshDepthMaterial=!0,this.type="MeshDepthMaterial",this.depthPacking=Hd,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.setValues(t)}copy(t){return super.copy(t),this.depthPacking=t.depthPacking,this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this}}class rp extends cs{constructor(t){super(),this.isMeshDistanceMaterial=!0,this.type="MeshDistanceMaterial",this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.setValues(t)}copy(t){return super.copy(t),this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this}}class Vr extends be{constructor(t,e=1){super(),this.isLight=!0,this.type="Light",this.color=new kt(t),this.intensity=e}dispose(){this.dispatchEvent({type:"dispose"})}copy(t,e){return super.copy(t,e),this.color.copy(t.color),this.intensity=t.intensity,this}toJSON(t){const e=super.toJSON(t);return e.object.color=this.color.getHex(),e.object.intensity=this.intensity,e}}class ap extends Vr{constructor(t,e,n){super(t,n),this.isHemisphereLight=!0,this.type="HemisphereLight",this.position.copy(be.DEFAULT_UP),this.updateMatrix(),this.groundColor=new kt(e)}copy(t,e){return super.copy(t,e),this.groundColor.copy(t.groundColor),this}toJSON(t){const e=super.toJSON(t);return e.object.groundColor=this.groundColor.getHex(),e}}const rl=new se,rh=new C,ah=new C;class al{constructor(t){this.camera=t,this.intensity=1,this.bias=0,this.biasNode=null,this.normalBias=0,this.radius=1,this.blurSamples=8,this.mapSize=new ht(512,512),this.mapType=Ze,this.map=null,this.mapPass=null,this.matrix=new se,this.autoUpdate=!0,this.needsUpdate=!1,this._frustum=new kr,this._frameExtents=new ht(1,1),this._viewportCount=1,this._viewports=[new me(0,0,1,1)]}getViewportCount(){return this._viewportCount}getFrustum(){return this._frustum}updateMatrices(t){const e=this.camera,n=this.matrix;rh.setFromMatrixPosition(t.matrixWorld),e.position.copy(rh),ah.setFromMatrixPosition(t.target.matrixWorld),e.lookAt(ah),e.updateMatrixWorld(),rl.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this._frustum.setFromProjectionMatrix(rl,e.coordinateSystem,e.reversedDepth),e.coordinateSystem===Ls||e.reversedDepth?n.set(.5,0,0,.5,0,.5,0,.5,0,0,1,0,0,0,0,1):n.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1),n.multiply(rl)}getViewport(t){return this._viewports[t]}getFrameExtents(){return this._frameExtents}dispose(){this.map&&this.map.dispose(),this.mapPass&&this.mapPass.dispose()}copy(t){return this.camera=t.camera.clone(),this.intensity=t.intensity,this.bias=t.bias,this.radius=t.radius,this.autoUpdate=t.autoUpdate,this.needsUpdate=t.needsUpdate,this.normalBias=t.normalBias,this.blurSamples=t.blurSamples,this.mapSize.copy(t.mapSize),this.biasNode=t.biasNode,this}clone(){return new this.constructor().copy(this)}toJSON(){const t={};return this.intensity!==1&&(t.intensity=this.intensity),this.bias!==0&&(t.bias=this.bias),this.normalBias!==0&&(t.normalBias=this.normalBias),this.radius!==1&&(t.radius=this.radius),(this.mapSize.x!==512||this.mapSize.y!==512)&&(t.mapSize=this.mapSize.toArray()),t.camera=this.camera.toJSON(!1).object,delete t.camera.matrix,t}}const Wr=new C,$r=new Cn,Rn=new C;class oh extends be{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new se,this.projectionMatrix=new se,this.projectionMatrixInverse=new se,this.coordinateSystem=An,this._reversedDepth=!1}get reversedDepth(){return this._reversedDepth}copy(t,e){return super.copy(t,e),this.matrixWorldInverse.copy(t.matrixWorldInverse),this.projectionMatrix.copy(t.projectionMatrix),this.projectionMatrixInverse.copy(t.projectionMatrixInverse),this.coordinateSystem=t.coordinateSystem,this}getWorldDirection(t){return super.getWorldDirection(t).negate()}updateMatrixWorld(t){super.updateMatrixWorld(t),this.matrixWorld.decompose(Wr,$r,Rn),Rn.x===1&&Rn.y===1&&Rn.z===1?this.matrixWorldInverse.copy(this.matrixWorld).invert():this.matrixWorldInverse.compose(Wr,$r,Rn.set(1,1,1)).invert()}updateWorldMatrix(t,e,n=!1){super.updateWorldMatrix(t,e,n),this.matrixWorld.decompose(Wr,$r,Rn),Rn.x===1&&Rn.y===1&&Rn.z===1?this.matrixWorldInverse.copy(this.matrixWorld).invert():this.matrixWorldInverse.compose(Wr,$r,Rn.set(1,1,1)).invert()}clone(){return new this.constructor().copy(this)}}const hi=new C,lh=new ht,ch=new ht;class qe extends oh{constructor(t=50,e=1,n=.1,i=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=t,this.zoom=1,this.near=n,this.far=i,this.focus=10,this.aspect=e,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(t,e){return super.copy(t,e),this.fov=t.fov,this.zoom=t.zoom,this.near=t.near,this.far=t.far,this.focus=t.focus,this.aspect=t.aspect,this.view=t.view===null?null:Object.assign({},t.view),this.filmGauge=t.filmGauge,this.filmOffset=t.filmOffset,this}setFocalLength(t){const e=.5*this.getFilmHeight()/t;this.fov=Yi*2*Math.atan(e),this.updateProjectionMatrix()}getFocalLength(){const t=Math.tan(Ds*.5*this.fov);return .5*this.getFilmHeight()/t}getEffectiveFOV(){return Yi*2*Math.atan(Math.tan(Ds*.5*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}getViewBounds(t,e,n){hi.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),e.set(hi.x,hi.y).multiplyScalar(-t/hi.z),hi.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),n.set(hi.x,hi.y).multiplyScalar(-t/hi.z)}getViewSize(t,e){return this.getViewBounds(t,lh,ch),e.subVectors(ch,lh)}setViewOffset(t,e,n,i,r,a){this.aspect=t/e,this.view===null&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=t,this.view.fullHeight=e,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=a,this.updateProjectionMatrix()}clearViewOffset(){this.view!==null&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const t=this.near;let e=t*Math.tan(Ds*.5*this.fov)/this.zoom,n=2*e,i=this.aspect*n,r=-.5*i;const a=this.view;if(this.view!==null&&this.view.enabled){const l=a.fullWidth,c=a.fullHeight;r+=a.offsetX*i/l,e-=a.offsetY*n/c,i*=a.width/l,n*=a.height/c}const o=this.filmOffset;o!==0&&(r+=t*o/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,e,e-n,t,this.far,this.coordinateSystem,this.reversedDepth),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(t){const e=super.toJSON(t);return e.object.fov=this.fov,e.object.zoom=this.zoom,e.object.near=this.near,e.object.far=this.far,e.object.focus=this.focus,e.object.aspect=this.aspect,this.view!==null&&(e.object.view=Object.assign({},this.view)),e.object.filmGauge=this.filmGauge,e.object.filmOffset=this.filmOffset,e}}class op extends al{constructor(){super(new qe(50,1,.5,500)),this.isSpotLightShadow=!0,this.focus=1,this.aspect=1}updateMatrices(t){const e=this.camera,n=Yi*2*t.angle*this.focus,i=this.mapSize.width/this.mapSize.height*this.aspect,r=t.distance||e.far;(n!==e.fov||i!==e.aspect||r!==e.far)&&(e.fov=n,e.aspect=i,e.far=r,e.updateProjectionMatrix()),super.updateMatrices(t)}copy(t){return super.copy(t),this.focus=t.focus,this}}class lp extends Vr{constructor(t,e,n=0,i=Math.PI/3,r=0,a=2){super(t,e),this.isSpotLight=!0,this.type="SpotLight",this.position.copy(be.DEFAULT_UP),this.updateMatrix(),this.target=new be,this.distance=n,this.angle=i,this.penumbra=r,this.decay=a,this.map=null,this.shadow=new op}get power(){return this.intensity*Math.PI}set power(t){this.intensity=t/Math.PI}dispose(){super.dispose(),this.shadow.dispose()}copy(t,e){return super.copy(t,e),this.distance=t.distance,this.angle=t.angle,this.penumbra=t.penumbra,this.decay=t.decay,this.target=t.target.clone(),this.map=t.map,this.shadow=t.shadow.clone(),this}toJSON(t){const e=super.toJSON(t);return e.object.distance=this.distance,e.object.angle=this.angle,e.object.decay=this.decay,e.object.penumbra=this.penumbra,e.object.target=this.target.uuid,this.map&&this.map.isTexture&&(e.object.map=this.map.toJSON(t).uuid),e.object.shadow=this.shadow.toJSON(),e}}class cp extends al{constructor(){super(new qe(90,1,.5,500)),this.isPointLightShadow=!0}}class ol extends Vr{constructor(t,e,n=0,i=2){super(t,e),this.isPointLight=!0,this.type="PointLight",this.distance=n,this.decay=i,this.shadow=new cp}get power(){return this.intensity*4*Math.PI}set power(t){this.intensity=t/(4*Math.PI)}dispose(){super.dispose(),this.shadow.dispose()}copy(t,e){return super.copy(t,e),this.distance=t.distance,this.decay=t.decay,this.shadow=t.shadow.clone(),this}toJSON(t){const e=super.toJSON(t);return e.object.distance=this.distance,e.object.decay=this.decay,e.object.shadow=this.shadow.toJSON(),e}}class Xr extends oh{constructor(t=-1,e=1,n=1,i=-1,r=.1,a=2e3){super(),this.isOrthographicCamera=!0,this.type="OrthographicCamera",this.zoom=1,this.view=null,this.left=t,this.right=e,this.top=n,this.bottom=i,this.near=r,this.far=a,this.updateProjectionMatrix()}copy(t,e){return super.copy(t,e),this.left=t.left,this.right=t.right,this.top=t.top,this.bottom=t.bottom,this.near=t.near,this.far=t.far,this.zoom=t.zoom,this.view=t.view===null?null:Object.assign({},t.view),this}setViewOffset(t,e,n,i,r,a){this.view===null&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=t,this.view.fullHeight=e,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=a,this.updateProjectionMatrix()}clearViewOffset(){this.view!==null&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const t=(this.right-this.left)/(2*this.zoom),e=(this.top-this.bottom)/(2*this.zoom),n=(this.right+this.left)/2,i=(this.top+this.bottom)/2;let r=n-t,a=n+t,o=i+e,l=i-e;if(this.view!==null&&this.view.enabled){const c=(this.right-this.left)/this.view.fullWidth/this.zoom,u=(this.top-this.bottom)/this.view.fullHeight/this.zoom;r+=c*this.view.offsetX,a=r+c*this.view.width,o-=u*this.view.offsetY,l=o-u*this.view.height}this.projectionMatrix.makeOrthographic(r,a,o,l,this.near,this.far,this.coordinateSystem,this.reversedDepth),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(t){const e=super.toJSON(t);return e.object.zoom=this.zoom,e.object.left=this.left,e.object.right=this.right,e.object.top=this.top,e.object.bottom=this.bottom,e.object.near=this.near,e.object.far=this.far,this.view!==null&&(e.object.view=Object.assign({},this.view)),e}}class hp extends al{constructor(){super(new Xr(-5,5,5,-5,.5,500)),this.isDirectionalLightShadow=!0}}class up extends Vr{constructor(t,e){super(t,e),this.isDirectionalLight=!0,this.type="DirectionalLight",this.position.copy(be.DEFAULT_UP),this.updateMatrix(),this.target=new be,this.shadow=new hp}dispose(){super.dispose(),this.shadow.dispose()}copy(t){return super.copy(t),this.target=t.target.clone(),this.shadow=t.shadow.clone(),this}toJSON(t){const e=super.toJSON(t);return e.object.shadow=this.shadow.toJSON(),e.object.target=this.target.uuid,e}}const fs=-90,ps=1;class dp extends be{constructor(t,e,n){super(),this.type="CubeCamera",this.renderTarget=n,this.coordinateSystem=null,this.activeMipmapLevel=0;const i=new qe(fs,ps,t,e);i.layers=this.layers,this.add(i);const r=new qe(fs,ps,t,e);r.layers=this.layers,this.add(r);const a=new qe(fs,ps,t,e);a.layers=this.layers,this.add(a);const o=new qe(fs,ps,t,e);o.layers=this.layers,this.add(o);const l=new qe(fs,ps,t,e);l.layers=this.layers,this.add(l);const c=new qe(fs,ps,t,e);c.layers=this.layers,this.add(c)}updateCoordinateSystem(){const t=this.coordinateSystem,e=this.children.concat(),[n,i,r,a,o,l]=e;for(const c of e)this.remove(c);if(t===An)n.up.set(0,1,0),n.lookAt(1,0,0),i.up.set(0,1,0),i.lookAt(-1,0,0),r.up.set(0,0,-1),r.lookAt(0,1,0),a.up.set(0,0,1),a.lookAt(0,-1,0),o.up.set(0,1,0),o.lookAt(0,0,1),l.up.set(0,1,0),l.lookAt(0,0,-1);else if(t===Ls)n.up.set(0,-1,0),n.lookAt(-1,0,0),i.up.set(0,-1,0),i.lookAt(1,0,0),r.up.set(0,0,1),r.lookAt(0,1,0),a.up.set(0,0,-1),a.lookAt(0,-1,0),o.up.set(0,-1,0),o.lookAt(0,0,1),l.up.set(0,-1,0),l.lookAt(0,0,-1);else throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+t);for(const c of e)this.add(c),c.updateMatrixWorld()}update(t,e){this.parent===null&&this.updateMatrixWorld();const{renderTarget:n,activeMipmapLevel:i}=this;this.coordinateSystem!==t.coordinateSystem&&(this.coordinateSystem=t.coordinateSystem,this.updateCoordinateSystem());const[r,a,o,l,c,u]=this.children,h=t.getRenderTarget(),d=t.getActiveCubeFace(),f=t.getActiveMipmapLevel(),p=t.xr.enabled;t.xr.enabled=!1;const v=n.texture.generateMipmaps;n.texture.generateMipmaps=!1;let m=!1;t.isWebGLRenderer===!0?m=t.state.buffers.depth.getReversed():m=t.reversedDepthBuffer,t.setRenderTarget(n,0,i),m&&t.autoClear===!1&&t.clearDepth(),t.render(e,r),t.setRenderTarget(n,1,i),m&&t.autoClear===!1&&t.clearDepth(),t.render(e,a),t.setRenderTarget(n,2,i),m&&t.autoClear===!1&&t.clearDepth(),t.render(e,o),t.setRenderTarget(n,3,i),m&&t.autoClear===!1&&t.clearDepth(),t.render(e,l),t.setRenderTarget(n,4,i),m&&t.autoClear===!1&&t.clearDepth(),t.render(e,c),n.texture.generateMipmaps=v,t.setRenderTarget(n,5,i),m&&t.autoClear===!1&&t.clearDepth(),t.render(e,u),t.setRenderTarget(h,d,f),t.xr.enabled=p,n.texture.needsPMREMUpdate=!0}}class fp extends qe{constructor(t=[]){super(),this.isArrayCamera=!0,this.isMultiViewCamera=!1,this.cameras=t}}class pp{constructor(){this._previousTime=0,this._currentTime=0,this._startTime=performance.now(),this._delta=0,this._elapsed=0,this._timescale=1,this._document=null,this._pageVisibilityHandler=null}connect(t){this._document=t,t.hidden!==void 0&&(this._pageVisibilityHandler=mp.bind(this),t.addEventListener("visibilitychange",this._pageVisibilityHandler,!1))}disconnect(){this._pageVisibilityHandler!==null&&(this._document.removeEventListener("visibilitychange",this._pageVisibilityHandler),this._pageVisibilityHandler=null),this._document=null}getDelta(){return this._delta/1e3}getElapsed(){return this._elapsed/1e3}getTimescale(){return this._timescale}setTimescale(t){return this._timescale=t,this}reset(){return this._currentTime=performance.now()-this._startTime,this}dispose(){this.disconnect()}update(t){return this._pageVisibilityHandler!==null&&this._document.hidden===!0?this._delta=0:(this._previousTime=this._currentTime,this._currentTime=(t!==void 0?t:performance.now())-this._startTime,this._delta=(this._currentTime-this._previousTime)*this._timescale,this._elapsed+=this._delta),this}}function mp(){this._document.hidden===!1&&this.reset()}const hh=new se;class gp{constructor(t,e,n=0,i=1/0){this.ray=new Cr(t,e),this.near=n,this.far=i,this.camera=null,this.layers=new Io,this.params={Mesh:{},Line:{threshold:1},LOD:{},Points:{threshold:1},Sprite:{}}}set(t,e){this.ray.set(t,e)}setFromCamera(t,e){e.isPerspectiveCamera?(this.ray.origin.setFromMatrixPosition(e.matrixWorld),this.ray.direction.set(t.x,t.y,.5).unproject(e).sub(this.ray.origin).normalize(),this.camera=e):e.isOrthographicCamera?(this.ray.origin.set(t.x,t.y,e.projectionMatrix.elements[14]).unproject(e),this.ray.direction.set(0,0,-1).transformDirection(e.matrixWorld),this.camera=e):Qt("Raycaster: Unsupported camera type: "+e.type)}setFromXRController(t){return hh.identity().extractRotation(t.matrixWorld),this.ray.origin.setFromMatrixPosition(t.matrixWorld),this.ray.direction.set(0,0,-1).applyMatrix4(hh),this}intersectObject(t,e=!0,n=[]){return ll(t,this,n,e),n.sort(uh),n}intersectObjects(t,e=!0,n=[]){for(let i=0,r=t.length;i0&&(e.defines=this.defines),e.vertexShader=this.vertexShader,e.fragmentShader=this.fragmentShader,e.lights=this.lights,e.clipping=this.clipping;const n={};for(const i in this.extensions)this.extensions[i]===!0&&(n[i]=!0);return Object.keys(n).length>0&&(e.extensions=n),e}fromJSON(t,e){if(super.fromJSON(t,e),t.uniforms!==void 0)for(const n in t.uniforms){const i=t.uniforms[n];switch(this.uniforms[n]={},i.type){case"t":this.uniforms[n].value=e[i.value]||null;break;case"c":this.uniforms[n].value=new Bt().setHex(i.value);break;case"v2":this.uniforms[n].value=new pt().fromArray(i.value);break;case"v3":this.uniforms[n].value=new P().fromArray(i.value);break;case"v4":this.uniforms[n].value=new ge().fromArray(i.value);break;case"m3":this.uniforms[n].value=new Ht().fromArray(i.value);break;case"m4":this.uniforms[n].value=new re().fromArray(i.value);break;default:this.uniforms[n].value=i.value}}if(t.defines!==void 0&&(this.defines=t.defines),t.vertexShader!==void 0&&(this.vertexShader=t.vertexShader),t.fragmentShader!==void 0&&(this.fragmentShader=t.fragmentShader),t.glslVersion!==void 0&&(this.glslVersion=t.glslVersion),t.extensions!==void 0)for(const n in t.extensions)this.extensions[n]=t.extensions[n];return t.lights!==void 0&&(this.lights=t.lights),t.clipping!==void 0&&(this.clipping=t.clipping),this}}class Yh extends Pe{constructor(t){super(t),this.isRawShaderMaterial=!0,this.type="RawShaderMaterial"}}class Ae extends ws{constructor(t){super(),this.isMeshStandardMaterial=!0,this.type="MeshStandardMaterial",this.defines={STANDARD:""},this.color=new Bt(16777215),this.roughness=1,this.metalness=0,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Bt(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Qa,this.normalScale=new pt(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.roughnessMap=null,this.metalnessMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new $n,this.envMapIntensity=1,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.defines={STANDARD:""},this.color.copy(t.color),this.roughness=t.roughness,this.metalness=t.metalness,this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.roughnessMap=t.roughnessMap,this.metalnessMap=t.metalnessMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.envMapRotation.copy(t.envMapRotation),this.envMapIntensity=t.envMapIntensity,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.flatShading=t.flatShading,this.fog=t.fog,this}}class ym extends ws{constructor(t){super(),this.isMeshDepthMaterial=!0,this.type="MeshDepthMaterial",this.depthPacking=sp,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.setValues(t)}copy(t){return super.copy(t),this.depthPacking=t.depthPacking,this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this}}class Mm extends ws{constructor(t){super(),this.isMeshDistanceMaterial=!0,this.type="MeshDistanceMaterial",this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.setValues(t)}copy(t){return super.copy(t),this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this}}class ho extends Ee{constructor(t,e=1){super(),this.isLight=!0,this.type="Light",this.color=new Bt(t),this.intensity=e}dispose(){this.dispatchEvent({type:"dispose"})}copy(t,e){return super.copy(t,e),this.color.copy(t.color),this.intensity=t.intensity,this}toJSON(t){const e=super.toJSON(t);return e.object.color=this.color.getHex(),e.object.intensity=this.intensity,e}}class bm extends ho{constructor(t,e,n){super(t,n),this.isHemisphereLight=!0,this.type="HemisphereLight",this.position.copy(Ee.DEFAULT_UP),this.updateMatrix(),this.groundColor=new Bt(e)}copy(t,e){return super.copy(t,e),this.groundColor.copy(t.groundColor),this}toJSON(t){const e=super.toJSON(t);return e.object.groundColor=this.groundColor.getHex(),e}}const Nl=new re,Kh=new P,Zh=new P;class Ul{constructor(t){this.camera=t,this.intensity=1,this.bias=0,this.biasNode=null,this.normalBias=0,this.radius=1,this.blurSamples=8,this.mapSize=new pt(512,512),this.mapType=je,this.map=null,this.mapPass=null,this.matrix=new re,this.autoUpdate=!0,this.needsUpdate=!1,this._frustum=new ro,this._frameExtents=new pt(1,1),this._viewportCount=1,this._viewports=[new ge(0,0,1,1)]}getViewportCount(){return this._viewportCount}getFrustum(){return this._frustum}updateMatrices(t){const e=this.camera,n=this.matrix;Kh.setFromMatrixPosition(t.matrixWorld),e.position.copy(Kh),Zh.setFromMatrixPosition(t.target.matrixWorld),e.lookAt(Zh),e.updateMatrixWorld(),Nl.multiplyMatrices(e.projectionMatrix,e.matrixWorldInverse),this._frustum.setFromProjectionMatrix(Nl,e.coordinateSystem,e.reversedDepth),e.coordinateSystem===Ys||e.reversedDepth?n.set(.5,0,0,.5,0,.5,0,.5,0,0,1,0,0,0,0,1):n.set(.5,0,0,.5,0,.5,0,.5,0,0,.5,.5,0,0,0,1),n.multiply(Nl)}getViewport(t){return this._viewports[t]}getFrameExtents(){return this._frameExtents}dispose(){this.map&&this.map.dispose(),this.mapPass&&this.mapPass.dispose()}copy(t){return this.camera=t.camera.clone(),this.intensity=t.intensity,this.bias=t.bias,this.radius=t.radius,this.autoUpdate=t.autoUpdate,this.needsUpdate=t.needsUpdate,this.normalBias=t.normalBias,this.blurSamples=t.blurSamples,this.mapSize.copy(t.mapSize),this.biasNode=t.biasNode,this}clone(){return new this.constructor().copy(this)}toJSON(){const t={};return this.intensity!==1&&(t.intensity=this.intensity),this.bias!==0&&(t.bias=this.bias),this.normalBias!==0&&(t.normalBias=this.normalBias),this.radius!==1&&(t.radius=this.radius),(this.mapSize.x!==512||this.mapSize.y!==512)&&(t.mapSize=this.mapSize.toArray()),t.camera=this.camera.toJSON(!1).object,delete t.camera.matrix,t}}const uo=new P,fo=new Pn,Ln=new P;class Jh extends Ee{constructor(){super(),this.isCamera=!0,this.type="Camera",this.matrixWorldInverse=new re,this.projectionMatrix=new re,this.projectionMatrixInverse=new re,this.coordinateSystem=Rn,this._reversedDepth=!1}get reversedDepth(){return this._reversedDepth}copy(t,e){return super.copy(t,e),this.matrixWorldInverse.copy(t.matrixWorldInverse),this.projectionMatrix.copy(t.projectionMatrix),this.projectionMatrixInverse.copy(t.projectionMatrixInverse),this.coordinateSystem=t.coordinateSystem,this}getWorldDirection(t){return super.getWorldDirection(t).negate()}updateMatrixWorld(t){super.updateMatrixWorld(t),this.matrixWorld.decompose(uo,fo,Ln),Ln.x===1&&Ln.y===1&&Ln.z===1?this.matrixWorldInverse.copy(this.matrixWorld).invert():this.matrixWorldInverse.compose(uo,fo,Ln.set(1,1,1)).invert()}updateWorldMatrix(t,e,n=!1){super.updateWorldMatrix(t,e,n),this.matrixWorld.decompose(uo,fo,Ln),Ln.x===1&&Ln.y===1&&Ln.z===1?this.matrixWorldInverse.copy(this.matrixWorld).invert():this.matrixWorldInverse.compose(uo,fo,Ln.set(1,1,1)).invert()}clone(){return new this.constructor().copy(this)}}const xi=new P,jh=new pt,Qh=new pt;class Ke extends Jh{constructor(t=50,e=1,n=.1,i=2e3){super(),this.isPerspectiveCamera=!0,this.type="PerspectiveCamera",this.fov=t,this.zoom=1,this.near=n,this.far=i,this.focus=10,this.aspect=e,this.view=null,this.filmGauge=35,this.filmOffset=0,this.updateProjectionMatrix()}copy(t,e){return super.copy(t,e),this.fov=t.fov,this.zoom=t.zoom,this.near=t.near,this.far=t.far,this.focus=t.focus,this.aspect=t.aspect,this.view=t.view===null?null:Object.assign({},t.view),this.filmGauge=t.filmGauge,this.filmOffset=t.filmOffset,this}setFocalLength(t){const e=.5*this.getFilmHeight()/t;this.fov=cs*2*Math.atan(e),this.updateProjectionMatrix()}getFocalLength(){const t=Math.tan(Ks*.5*this.fov);return .5*this.getFilmHeight()/t}getEffectiveFOV(){return cs*2*Math.atan(Math.tan(Ks*.5*this.fov)/this.zoom)}getFilmWidth(){return this.filmGauge*Math.min(this.aspect,1)}getFilmHeight(){return this.filmGauge/Math.max(this.aspect,1)}getViewBounds(t,e,n){xi.set(-1,-1,.5).applyMatrix4(this.projectionMatrixInverse),e.set(xi.x,xi.y).multiplyScalar(-t/xi.z),xi.set(1,1,.5).applyMatrix4(this.projectionMatrixInverse),n.set(xi.x,xi.y).multiplyScalar(-t/xi.z)}getViewSize(t,e){return this.getViewBounds(t,jh,Qh),e.subVectors(Qh,jh)}setViewOffset(t,e,n,i,r,o){this.aspect=t/e,this.view===null&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=t,this.view.fullHeight=e,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=o,this.updateProjectionMatrix()}clearViewOffset(){this.view!==null&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const t=this.near;let e=t*Math.tan(Ks*.5*this.fov)/this.zoom,n=2*e,i=this.aspect*n,r=-.5*i;const o=this.view;if(this.view!==null&&this.view.enabled){const l=o.fullWidth,c=o.fullHeight;r+=o.offsetX*i/l,e-=o.offsetY*n/c,i*=o.width/l,n*=o.height/c}const a=this.filmOffset;a!==0&&(r+=t*a/this.getFilmWidth()),this.projectionMatrix.makePerspective(r,r+i,e,e-n,t,this.far,this.coordinateSystem,this.reversedDepth),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(t){const e=super.toJSON(t);return e.object.fov=this.fov,e.object.zoom=this.zoom,e.object.near=this.near,e.object.far=this.far,e.object.focus=this.focus,e.object.aspect=this.aspect,this.view!==null&&(e.object.view=Object.assign({},this.view)),e.object.filmGauge=this.filmGauge,e.object.filmOffset=this.filmOffset,e}}class Sm extends Ul{constructor(){super(new Ke(50,1,.5,500)),this.isSpotLightShadow=!0,this.focus=1,this.aspect=1}updateMatrices(t){const e=this.camera,n=cs*2*t.angle*this.focus,i=this.mapSize.width/this.mapSize.height*this.aspect,r=t.distance||e.far;(n!==e.fov||i!==e.aspect||r!==e.far)&&(e.fov=n,e.aspect=i,e.far=r,e.updateProjectionMatrix()),super.updateMatrices(t)}copy(t){return super.copy(t),this.focus=t.focus,this}}class wm extends ho{constructor(t,e,n=0,i=Math.PI/3,r=0,o=2){super(t,e),this.isSpotLight=!0,this.type="SpotLight",this.position.copy(Ee.DEFAULT_UP),this.updateMatrix(),this.target=new Ee,this.distance=n,this.angle=i,this.penumbra=r,this.decay=o,this.map=null,this.shadow=new Sm}get power(){return this.intensity*Math.PI}set power(t){this.intensity=t/Math.PI}dispose(){super.dispose(),this.shadow.dispose()}copy(t,e){return super.copy(t,e),this.distance=t.distance,this.angle=t.angle,this.penumbra=t.penumbra,this.decay=t.decay,this.target=t.target.clone(),this.map=t.map,this.shadow=t.shadow.clone(),this}toJSON(t){const e=super.toJSON(t);return e.object.distance=this.distance,e.object.angle=this.angle,e.object.decay=this.decay,e.object.penumbra=this.penumbra,e.object.target=this.target.uuid,this.map&&this.map.isTexture&&(e.object.map=this.map.toJSON(t).uuid),e.object.shadow=this.shadow.toJSON(),e}}class Em extends Ul{constructor(){super(new Ke(90,1,.5,500)),this.isPointLightShadow=!0}}class Fl extends ho{constructor(t,e,n=0,i=2){super(t,e),this.isPointLight=!0,this.type="PointLight",this.distance=n,this.decay=i,this.shadow=new Em}get power(){return this.intensity*4*Math.PI}set power(t){this.intensity=t/(4*Math.PI)}dispose(){super.dispose(),this.shadow.dispose()}copy(t,e){return super.copy(t,e),this.distance=t.distance,this.decay=t.decay,this.shadow=t.shadow.clone(),this}toJSON(t){const e=super.toJSON(t);return e.object.distance=this.distance,e.object.decay=this.decay,e.object.shadow=this.shadow.toJSON(),e}}class po extends Jh{constructor(t=-1,e=1,n=1,i=-1,r=.1,o=2e3){super(),this.isOrthographicCamera=!0,this.type="OrthographicCamera",this.zoom=1,this.view=null,this.left=t,this.right=e,this.top=n,this.bottom=i,this.near=r,this.far=o,this.updateProjectionMatrix()}copy(t,e){return super.copy(t,e),this.left=t.left,this.right=t.right,this.top=t.top,this.bottom=t.bottom,this.near=t.near,this.far=t.far,this.zoom=t.zoom,this.view=t.view===null?null:Object.assign({},t.view),this}setViewOffset(t,e,n,i,r,o){this.view===null&&(this.view={enabled:!0,fullWidth:1,fullHeight:1,offsetX:0,offsetY:0,width:1,height:1}),this.view.enabled=!0,this.view.fullWidth=t,this.view.fullHeight=e,this.view.offsetX=n,this.view.offsetY=i,this.view.width=r,this.view.height=o,this.updateProjectionMatrix()}clearViewOffset(){this.view!==null&&(this.view.enabled=!1),this.updateProjectionMatrix()}updateProjectionMatrix(){const t=(this.right-this.left)/(2*this.zoom),e=(this.top-this.bottom)/(2*this.zoom),n=(this.right+this.left)/2,i=(this.top+this.bottom)/2;let r=n-t,o=n+t,a=i+e,l=i-e;if(this.view!==null&&this.view.enabled){const c=(this.right-this.left)/this.view.fullWidth/this.zoom,u=(this.top-this.bottom)/this.view.fullHeight/this.zoom;r+=c*this.view.offsetX,o=r+c*this.view.width,a-=u*this.view.offsetY,l=a-u*this.view.height}this.projectionMatrix.makeOrthographic(r,o,a,l,this.near,this.far,this.coordinateSystem,this.reversedDepth),this.projectionMatrixInverse.copy(this.projectionMatrix).invert()}toJSON(t){const e=super.toJSON(t);return e.object.zoom=this.zoom,e.object.left=this.left,e.object.right=this.right,e.object.top=this.top,e.object.bottom=this.bottom,e.object.near=this.near,e.object.far=this.far,this.view!==null&&(e.object.view=Object.assign({},this.view)),e}}class Tm extends Ul{constructor(){super(new po(-5,5,5,-5,.5,500)),this.isDirectionalLightShadow=!0}}class Am extends ho{constructor(t,e){super(t,e),this.isDirectionalLight=!0,this.type="DirectionalLight",this.position.copy(Ee.DEFAULT_UP),this.updateMatrix(),this.target=new Ee,this.shadow=new Tm}dispose(){super.dispose(),this.shadow.dispose()}copy(t){return super.copy(t),this.target=t.target.clone(),this.shadow=t.shadow.clone(),this}toJSON(t){const e=super.toJSON(t);return e.object.shadow=this.shadow.toJSON(),e.object.target=this.target.uuid,e}}const Cs=-90,Rs=1;class Cm extends Ee{constructor(t,e,n){super(),this.type="CubeCamera",this.renderTarget=n,this.coordinateSystem=null,this.activeMipmapLevel=0;const i=new Ke(Cs,Rs,t,e);i.layers=this.layers,this.add(i);const r=new Ke(Cs,Rs,t,e);r.layers=this.layers,this.add(r);const o=new Ke(Cs,Rs,t,e);o.layers=this.layers,this.add(o);const a=new Ke(Cs,Rs,t,e);a.layers=this.layers,this.add(a);const l=new Ke(Cs,Rs,t,e);l.layers=this.layers,this.add(l);const c=new Ke(Cs,Rs,t,e);c.layers=this.layers,this.add(c)}updateCoordinateSystem(){const t=this.coordinateSystem,e=this.children.concat(),[n,i,r,o,a,l]=e;for(const c of e)this.remove(c);if(t===Rn)n.up.set(0,1,0),n.lookAt(1,0,0),i.up.set(0,1,0),i.lookAt(-1,0,0),r.up.set(0,0,-1),r.lookAt(0,1,0),o.up.set(0,0,1),o.lookAt(0,-1,0),a.up.set(0,1,0),a.lookAt(0,0,1),l.up.set(0,1,0),l.lookAt(0,0,-1);else if(t===Ys)n.up.set(0,-1,0),n.lookAt(-1,0,0),i.up.set(0,-1,0),i.lookAt(1,0,0),r.up.set(0,0,1),r.lookAt(0,1,0),o.up.set(0,0,-1),o.lookAt(0,-1,0),a.up.set(0,-1,0),a.lookAt(0,0,1),l.up.set(0,-1,0),l.lookAt(0,0,-1);else throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+t);for(const c of e)this.add(c),c.updateMatrixWorld()}update(t,e){this.parent===null&&this.updateMatrixWorld();const{renderTarget:n,activeMipmapLevel:i}=this;this.coordinateSystem!==t.coordinateSystem&&(this.coordinateSystem=t.coordinateSystem,this.updateCoordinateSystem());const[r,o,a,l,c,u]=this.children,h=t.getRenderTarget(),d=t.getActiveCubeFace(),f=t.getActiveMipmapLevel(),p=t.xr.enabled;t.xr.enabled=!1;const x=n.texture.generateMipmaps;n.texture.generateMipmaps=!1;let m=!1;t.isWebGLRenderer===!0?m=t.state.buffers.depth.getReversed():m=t.reversedDepthBuffer,t.setRenderTarget(n,0,i),m&&t.autoClear===!1&&t.clearDepth(),t.render(e,r),t.setRenderTarget(n,1,i),m&&t.autoClear===!1&&t.clearDepth(),t.render(e,o),t.setRenderTarget(n,2,i),m&&t.autoClear===!1&&t.clearDepth(),t.render(e,a),t.setRenderTarget(n,3,i),m&&t.autoClear===!1&&t.clearDepth(),t.render(e,l),t.setRenderTarget(n,4,i),m&&t.autoClear===!1&&t.clearDepth(),t.render(e,c),n.texture.generateMipmaps=x,t.setRenderTarget(n,5,i),m&&t.autoClear===!1&&t.clearDepth(),t.render(e,u),t.setRenderTarget(h,d,f),t.xr.enabled=p,n.texture.needsPMREMUpdate=!0}}class Rm extends Ke{constructor(t=[]){super(),this.isArrayCamera=!0,this.isMultiViewCamera=!1,this.cameras=t}}class Pm{constructor(){this._previousTime=0,this._currentTime=0,this._startTime=performance.now(),this._delta=0,this._elapsed=0,this._timescale=1,this._document=null,this._pageVisibilityHandler=null}connect(t){this._document=t,t.hidden!==void 0&&(this._pageVisibilityHandler=Lm.bind(this),t.addEventListener("visibilitychange",this._pageVisibilityHandler,!1))}disconnect(){this._pageVisibilityHandler!==null&&(this._document.removeEventListener("visibilitychange",this._pageVisibilityHandler),this._pageVisibilityHandler=null),this._document=null}getDelta(){return this._delta/1e3}getElapsed(){return this._elapsed/1e3}getTimescale(){return this._timescale}setTimescale(t){return this._timescale=t,this}reset(){return this._currentTime=performance.now()-this._startTime,this}dispose(){this.disconnect()}update(t){return this._pageVisibilityHandler!==null&&this._document.hidden===!0?this._delta=0:(this._previousTime=this._currentTime,this._currentTime=(t!==void 0?t:performance.now())-this._startTime,this._delta=(this._currentTime-this._previousTime)*this._timescale,this._elapsed+=this._delta),this}}function Lm(){this._document.hidden===!1&&this.reset()}const tu=new re;class Dm{constructor(t,e,n=0,i=1/0){this.ray=new Kr(t,e),this.near=n,this.far=i,this.camera=null,this.layers=new ll,this.params={Mesh:{},Line:{threshold:1},LOD:{},Points:{threshold:1},Sprite:{}}}set(t,e){this.ray.set(t,e)}setFromCamera(t,e){e.isPerspectiveCamera?(this.ray.origin.setFromMatrixPosition(e.matrixWorld),this.ray.direction.set(t.x,t.y,.5).unproject(e).sub(this.ray.origin).normalize(),this.camera=e):e.isOrthographicCamera?(this.ray.origin.set(t.x,t.y,e.projectionMatrix.elements[14]).unproject(e),this.ray.direction.set(0,0,-1).transformDirection(e.matrixWorld),this.camera=e):te("Raycaster: Unsupported camera type: "+e.type)}setFromXRController(t){return tu.identity().extractRotation(t.matrixWorld),this.ray.origin.setFromMatrixPosition(t.matrixWorld),this.ray.direction.set(0,0,-1).applyMatrix4(tu),this}intersectObject(t,e=!0,n=[]){return Ol(t,this,n,e),n.sort(eu),n}intersectObjects(t,e=!0,n=[]){for(let i=0,r=t.length;if.start-p.start);let d=0;for(let f=1;ff.start-p.start);let d=0;for(let f=1;fyn in xi?xv(xi,yn,{enumerable:!0 : cases.z; return clamp( threshold , 1.0e-6, 1.0 ); } -#endif`,bp=`#ifdef USE_ALPHAMAP +#endif`,Bm=`#ifdef USE_ALPHAMAP diffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g; -#endif`,wp=`#ifdef USE_ALPHAMAP +#endif`,zm=`#ifdef USE_ALPHAMAP uniform sampler2D alphaMap; -#endif`,Ep=`#ifdef USE_ALPHATEST +#endif`,Hm=`#ifdef USE_ALPHATEST #ifdef ALPHA_TO_COVERAGE diffuseColor.a = smoothstep( alphaTest, alphaTest + fwidth( diffuseColor.a ), diffuseColor.a ); if ( diffuseColor.a == 0.0 ) discard; #else if ( diffuseColor.a < alphaTest ) discard; #endif -#endif`,Tp=`#ifdef USE_ALPHATEST +#endif`,Gm=`#ifdef USE_ALPHATEST uniform float alphaTest; -#endif`,Ap=`#ifdef USE_AOMAP +#endif`,Vm=`#ifdef USE_AOMAP float ambientOcclusion = ( texture2D( aoMap, vAoMapUv ).r - 1.0 ) * aoMapIntensity + 1.0; reflectedLight.indirectDiffuse *= ambientOcclusion; #if defined( USE_CLEARCOAT ) @@ -73,10 +73,10 @@ var xv=Object.defineProperty;var vv=(xi,yn,Sn)=>yn in xi?xv(xi,yn,{enumerable:!0 float dotNV = saturate( dot( geometryNormal, geometryViewDir ) ); reflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.roughness ); #endif -#endif`,Cp=`#ifdef USE_AOMAP +#endif`,Wm=`#ifdef USE_AOMAP uniform sampler2D aoMap; uniform float aoMapIntensity; -#endif`,Rp=`#ifdef USE_BATCHING +#endif`,$m=`#ifdef USE_BATCHING #if ! defined( GL_ANGLE_multi_draw ) #define gl_DrawID _gl_DrawID uniform int _gl_DrawID; @@ -110,15 +110,15 @@ var xv=Object.defineProperty;var vv=(xi,yn,Sn)=>yn in xi?xv(xi,yn,{enumerable:!0 int y = j / size; return texelFetch( batchingColorTexture, ivec2( x, y ), 0 ); } -#endif`,Pp=`#ifdef USE_BATCHING +#endif`,Xm=`#ifdef USE_BATCHING mat4 batchingMatrix = getBatchingMatrix( getIndirectIndex( gl_DrawID ) ); -#endif`,Lp=`vec3 transformed = vec3( position ); +#endif`,qm=`vec3 transformed = vec3( position ); #ifdef USE_ALPHAHASH vPosition = vec3( position ); -#endif`,Dp=`vec3 objectNormal = vec3( normal ); +#endif`,Ym=`vec3 objectNormal = vec3( normal ); #ifdef USE_TANGENT vec3 objectTangent = vec3( tangent.xyz ); -#endif`,Ip=`float G_BlinnPhong_Implicit( ) { +#endif`,Km=`float G_BlinnPhong_Implicit( ) { return 0.25; } float D_BlinnPhong( const in float shininess, const in float dotNH ) { @@ -132,7 +132,7 @@ vec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in ve float G = G_BlinnPhong_Implicit( ); float D = D_BlinnPhong( shininess, dotNH ); return F * ( G * D ); -} // validated`,Np=`#ifdef USE_IRIDESCENCE +} // validated`,Zm=`#ifdef USE_IRIDESCENCE const mat3 XYZ_TO_REC709 = mat3( 3.2404542, -0.9692660, 0.0556434, -1.5371385, 1.8760108, -0.2040259, @@ -195,7 +195,7 @@ vec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in ve } return max( I, vec3( 0.0 ) ); } -#endif`,Up=`#ifdef USE_BUMPMAP +#endif`,Jm=`#ifdef USE_BUMPMAP uniform sampler2D bumpMap; uniform float bumpScale; vec2 dHdxy_fwd() { @@ -216,7 +216,7 @@ vec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in ve vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 ); return normalize( abs( fDet ) * surf_norm - vGrad ); } -#endif`,Fp=`#if NUM_CLIPPING_PLANES > 0 +#endif`,jm=`#if NUM_CLIPPING_PLANES > 0 vec4 plane; #ifdef ALPHA_TO_COVERAGE float distanceToPlane, distanceGradient; @@ -262,20 +262,20 @@ vec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in ve if ( clipped ) discard; #endif #endif -#endif`,Op=`#if NUM_CLIPPING_PLANES > 0 +#endif`,Qm=`#if NUM_CLIPPING_PLANES > 0 varying vec3 vClipPosition; uniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ]; -#endif`,kp=`#if NUM_CLIPPING_PLANES > 0 +#endif`,t0=`#if NUM_CLIPPING_PLANES > 0 varying vec3 vClipPosition; -#endif`,Bp=`#if NUM_CLIPPING_PLANES > 0 +#endif`,e0=`#if NUM_CLIPPING_PLANES > 0 vClipPosition = - mvPosition.xyz; -#endif`,zp=`#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) +#endif`,n0=`#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) diffuseColor *= vColor; -#endif`,Hp=`#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) +#endif`,i0=`#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) varying vec4 vColor; -#endif`,Gp=`#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR ) +#endif`,s0=`#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR ) varying vec4 vColor; -#endif`,Vp=`#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR ) +#endif`,r0=`#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR ) vColor = vec4( 1.0 ); #endif #ifdef USE_COLOR_ALPHA @@ -288,7 +288,7 @@ vec3 BRDF_BlinnPhong( const in vec3 lightDir, const in vec3 viewDir, const in ve #endif #ifdef USE_BATCHING_COLOR vColor *= getBatchingColor( getIndirectIndex( gl_DrawID ) ); -#endif`,Wp=`#define PI 3.141592653589793 +#endif`,o0=`#define PI 3.141592653589793 #define PI2 6.283185307179586 #define PI_HALF 1.5707963267948966 #define RECIPROCAL_PI 0.3183098861837907 @@ -359,7 +359,7 @@ vec3 F_Schlick( const in vec3 f0, const in float f90, const in float dotVH ) { float F_Schlick( const in float f0, const in float f90, const in float dotVH ) { float fresnel = exp2( ( - 5.55473 * dotVH - 6.98316 ) * dotVH ); return f0 * ( 1.0 - fresnel ) + ( f90 * fresnel ); -} // validated`,$p=`#ifdef ENVMAP_TYPE_CUBE_UV +} // validated`,a0=`#ifdef ENVMAP_TYPE_CUBE_UV #define cubeUV_minMipLevel 4.0 #define cubeUV_minTileSize 16.0 float getFace( vec3 direction ) { @@ -452,7 +452,7 @@ float F_Schlick( const in float f0, const in float f90, const in float dotVH ) { return vec4( mix( color0, color1, mipF ), 1.0 ); } } -#endif`,Xp=`vec3 transformedNormal = objectNormal; +#endif`,l0=`vec3 transformedNormal = objectNormal; #ifdef USE_TANGENT vec3 transformedTangent = objectTangent; #endif @@ -478,21 +478,21 @@ transformedNormal = normalMatrix * transformedNormal; #endif #ifdef USE_TANGENT transformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz; -#endif`,qp=`#ifdef USE_DISPLACEMENTMAP +#endif`,c0=`#ifdef USE_DISPLACEMENTMAP uniform sampler2D displacementMap; uniform float displacementScale; uniform float displacementBias; -#endif`,Yp=`#ifdef USE_DISPLACEMENTMAP +#endif`,h0=`#ifdef USE_DISPLACEMENTMAP transformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias ); -#endif`,Kp=`#ifdef USE_EMISSIVEMAP +#endif`,u0=`#ifdef USE_EMISSIVEMAP vec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv ); #ifdef DECODE_VIDEO_TEXTURE_EMISSIVE emissiveColor = sRGBTransferEOTF( emissiveColor ); #endif totalEmissiveRadiance *= emissiveColor.rgb; -#endif`,Zp=`#ifdef USE_EMISSIVEMAP +#endif`,d0=`#ifdef USE_EMISSIVEMAP uniform sampler2D emissiveMap; -#endif`,Jp="gl_FragColor = linearToOutputTexel( gl_FragColor );",Qp=`vec4 LinearTransferOETF( in vec4 value ) { +#endif`,f0="gl_FragColor = linearToOutputTexel( gl_FragColor );",p0=`vec4 LinearTransferOETF( in vec4 value ) { return value; } vec4 sRGBTransferEOTF( in vec4 value ) { @@ -500,7 +500,7 @@ vec4 sRGBTransferEOTF( in vec4 value ) { } vec4 sRGBTransferOETF( in vec4 value ) { return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a ); -}`,jp=`#ifdef USE_ENVMAP +}`,m0=`#ifdef USE_ENVMAP #ifdef ENV_WORLDPOS vec3 cameraToFrag; if ( isOrthographic ) { @@ -527,7 +527,7 @@ vec4 sRGBTransferOETF( in vec4 value ) { outgoingLight += envColor.xyz * specularStrength * reflectivity; #endif #endif -#endif`,tm=`#ifdef USE_ENVMAP +#endif`,g0=`#ifdef USE_ENVMAP uniform float envMapIntensity; uniform mat3 envMapRotation; #ifdef ENVMAP_TYPE_CUBE @@ -535,7 +535,7 @@ vec4 sRGBTransferOETF( in vec4 value ) { #else uniform sampler2D envMap; #endif -#endif`,em=`#ifdef USE_ENVMAP +#endif`,x0=`#ifdef USE_ENVMAP uniform float reflectivity; #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) #define ENV_WORLDPOS @@ -546,7 +546,7 @@ vec4 sRGBTransferOETF( in vec4 value ) { #else varying vec3 vReflect; #endif -#endif`,nm=`#ifdef USE_ENVMAP +#endif`,v0=`#ifdef USE_ENVMAP #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) #define ENV_WORLDPOS #endif @@ -557,7 +557,7 @@ vec4 sRGBTransferOETF( in vec4 value ) { varying vec3 vReflect; uniform float refractionRatio; #endif -#endif`,im=`#ifdef USE_ENVMAP +#endif`,_0=`#ifdef USE_ENVMAP #ifdef ENV_WORLDPOS vWorldPosition = worldPosition.xyz; #else @@ -574,18 +574,18 @@ vec4 sRGBTransferOETF( in vec4 value ) { vReflect = refract( cameraToVertex, worldNormal, refractionRatio ); #endif #endif -#endif`,sm=`#ifdef USE_FOG +#endif`,y0=`#ifdef USE_FOG vFogDepth = - mvPosition.z; -#endif`,rm=`#ifdef USE_FOG +#endif`,M0=`#ifdef USE_FOG varying float vFogDepth; -#endif`,am=`#ifdef USE_FOG +#endif`,b0=`#ifdef USE_FOG #ifdef FOG_EXP2 float fogFactor = 1.0 - exp( - fogDensity * fogDensity * vFogDepth * vFogDepth ); #else float fogFactor = smoothstep( fogNear, fogFar, vFogDepth ); #endif gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor ); -#endif`,om=`#ifdef USE_FOG +#endif`,S0=`#ifdef USE_FOG uniform vec3 fogColor; varying float vFogDepth; #ifdef FOG_EXP2 @@ -594,7 +594,7 @@ vec4 sRGBTransferOETF( in vec4 value ) { uniform float fogNear; uniform float fogFar; #endif -#endif`,lm=`#ifdef USE_GRADIENTMAP +#endif`,w0=`#ifdef USE_GRADIENTMAP uniform sampler2D gradientMap; #endif vec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) { @@ -606,12 +606,12 @@ vec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) { vec2 fw = fwidth( coord ) * 0.5; return mix( vec3( 0.7 ), vec3( 1.0 ), smoothstep( 0.7 - fw.x, 0.7 + fw.x, coord.x ) ); #endif -}`,cm=`#ifdef USE_LIGHTMAP +}`,E0=`#ifdef USE_LIGHTMAP uniform sampler2D lightMap; uniform float lightMapIntensity; -#endif`,hm=`LambertMaterial material; +#endif`,T0=`LambertMaterial material; material.diffuseColor = diffuseColor.rgb; -material.specularStrength = specularStrength;`,um=`varying vec3 vViewPosition; +material.specularStrength = specularStrength;`,A0=`varying vec3 vViewPosition; struct LambertMaterial { vec3 diffuseColor; float specularStrength; @@ -625,7 +625,7 @@ void RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometr reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); } #define RE_Direct RE_Direct_Lambert -#define RE_IndirectDiffuse RE_IndirectDiffuse_Lambert`,dm=`uniform bool receiveShadow; +#define RE_IndirectDiffuse RE_IndirectDiffuse_Lambert`,C0=`uniform bool receiveShadow; uniform vec3 ambientLightColor; #if defined( USE_LIGHT_PROBES ) uniform vec3 lightProbe[ 9 ]; @@ -742,7 +742,7 @@ float getSpotAttenuation( const in float coneCosine, const in float penumbraCosi return irradiance; } #endif -#include `,fm=`#ifdef USE_ENVMAP +#include `,R0=`#ifdef USE_ENVMAP vec3 getIBLIrradiance( const in vec3 normal ) { #ifdef ENVMAP_TYPE_CUBE_UV vec3 worldNormal = transformNormalByInverseViewMatrix( normal, viewMatrix ); @@ -775,8 +775,8 @@ float getSpotAttenuation( const in float coneCosine, const in float penumbraCosi #endif } #endif -#endif`,pm=`ToonMaterial material; -material.diffuseColor = diffuseColor.rgb;`,mm=`varying vec3 vViewPosition; +#endif`,P0=`ToonMaterial material; +material.diffuseColor = diffuseColor.rgb;`,L0=`varying vec3 vViewPosition; struct ToonMaterial { vec3 diffuseColor; }; @@ -788,11 +788,11 @@ void RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPo reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); } #define RE_Direct RE_Direct_Toon -#define RE_IndirectDiffuse RE_IndirectDiffuse_Toon`,gm=`BlinnPhongMaterial material; +#define RE_IndirectDiffuse RE_IndirectDiffuse_Toon`,D0=`BlinnPhongMaterial material; material.diffuseColor = diffuseColor.rgb; material.specularColor = specular; material.specularShininess = shininess; -material.specularStrength = specularStrength;`,_m=`varying vec3 vViewPosition; +material.specularStrength = specularStrength;`,I0=`varying vec3 vViewPosition; struct BlinnPhongMaterial { vec3 diffuseColor; vec3 specularColor; @@ -809,7 +809,7 @@ void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geom reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); } #define RE_Direct RE_Direct_BlinnPhong -#define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong`,xm=`PhysicalMaterial material; +#define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong`,N0=`PhysicalMaterial material; material.diffuseColor = diffuseColor.rgb; material.diffuseContribution = diffuseColor.rgb * ( 1.0 - metalnessFactor ); material.metalness = metalnessFactor; @@ -899,7 +899,7 @@ material.roughness = min( material.roughness, 1.0 ); material.alphaT = mix( pow2( material.roughness ), 1.0, pow2( material.anisotropy ) ); material.anisotropyT = tbn[ 0 ] * anisotropyV.x + tbn[ 1 ] * anisotropyV.y; material.anisotropyB = tbn[ 1 ] * anisotropyV.x - tbn[ 0 ] * anisotropyV.y; -#endif`,vm=`uniform sampler2D dfgLUT; +#endif`,U0=`uniform sampler2D dfgLUT; struct PhysicalMaterial { vec3 diffuseColor; vec3 diffuseContribution; @@ -1259,7 +1259,7 @@ void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradia #define RE_IndirectSpecular RE_IndirectSpecular_Physical float computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) { return saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion ); -}`,Mm=` +}`,F0=` vec3 geometryPosition = - vViewPosition; vec3 geometryNormal = normal; vec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition ); @@ -1381,7 +1381,7 @@ IncidentLight directLight; #if defined( RE_IndirectSpecular ) vec3 radiance = vec3( 0.0 ); vec3 clearcoatRadiance = vec3( 0.0 ); -#endif`,ym=`#if defined( RE_IndirectDiffuse ) +#endif`,O0=`#if defined( RE_IndirectDiffuse ) #ifdef USE_LIGHTMAP vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); vec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity; @@ -1402,7 +1402,7 @@ IncidentLight directLight; #ifdef USE_CLEARCOAT clearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness ); #endif -#endif`,Sm=`#if defined( RE_IndirectDiffuse ) +#endif`,k0=`#if defined( RE_IndirectDiffuse ) #if defined( LAMBERT ) || defined( PHONG ) irradiance += iblIrradiance; #endif @@ -1410,7 +1410,7 @@ IncidentLight directLight; #endif #if defined( RE_IndirectSpecular ) RE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); -#endif`,bm=`#ifdef USE_LIGHT_PROBES_GRID +#endif`,B0=`#ifdef USE_LIGHT_PROBES_GRID uniform highp sampler3D probesSH; uniform vec3 probesMin; uniform vec3 probesMax; @@ -1455,27 +1455,27 @@ vec3 getLightProbeGridIrradiance( vec3 worldPos, vec3 worldNormal ) { result += c8 * 0.429043 * ( x * x - y * y ); return max( result, vec3( 0.0 ) ); } -#endif`,wm=`#if defined( USE_LOGARITHMIC_DEPTH_BUFFER ) +#endif`,z0=`#if defined( USE_LOGARITHMIC_DEPTH_BUFFER ) gl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5; -#endif`,Em=`#if defined( USE_LOGARITHMIC_DEPTH_BUFFER ) +#endif`,H0=`#if defined( USE_LOGARITHMIC_DEPTH_BUFFER ) uniform float logDepthBufFC; varying float vFragDepth; varying float vIsPerspective; -#endif`,Tm=`#ifdef USE_LOGARITHMIC_DEPTH_BUFFER +#endif`,G0=`#ifdef USE_LOGARITHMIC_DEPTH_BUFFER varying float vFragDepth; varying float vIsPerspective; -#endif`,Am=`#ifdef USE_LOGARITHMIC_DEPTH_BUFFER +#endif`,V0=`#ifdef USE_LOGARITHMIC_DEPTH_BUFFER vFragDepth = 1.0 + gl_Position.w; vIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) ); -#endif`,Cm=`#ifdef USE_MAP +#endif`,W0=`#ifdef USE_MAP vec4 sampledDiffuseColor = texture2D( map, vMapUv ); #ifdef DECODE_VIDEO_TEXTURE sampledDiffuseColor = sRGBTransferEOTF( sampledDiffuseColor ); #endif diffuseColor *= sampledDiffuseColor; -#endif`,Rm=`#ifdef USE_MAP +#endif`,$0=`#ifdef USE_MAP uniform sampler2D map; -#endif`,Pm=`#if defined( USE_MAP ) || defined( USE_ALPHAMAP ) +#endif`,X0=`#if defined( USE_MAP ) || defined( USE_ALPHAMAP ) #if defined( USE_POINTS_UV ) vec2 uv = vUv; #else @@ -1487,7 +1487,7 @@ vec3 getLightProbeGridIrradiance( vec3 worldPos, vec3 worldNormal ) { #endif #ifdef USE_ALPHAMAP diffuseColor.a *= texture2D( alphaMap, uv ).g; -#endif`,Lm=`#if defined( USE_POINTS_UV ) +#endif`,q0=`#if defined( USE_POINTS_UV ) varying vec2 vUv; #else #if defined( USE_MAP ) || defined( USE_ALPHAMAP ) @@ -1499,19 +1499,19 @@ vec3 getLightProbeGridIrradiance( vec3 worldPos, vec3 worldNormal ) { #endif #ifdef USE_ALPHAMAP uniform sampler2D alphaMap; -#endif`,Dm=`float metalnessFactor = metalness; +#endif`,Y0=`float metalnessFactor = metalness; #ifdef USE_METALNESSMAP vec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv ); metalnessFactor *= texelMetalness.b; -#endif`,Im=`#ifdef USE_METALNESSMAP +#endif`,K0=`#ifdef USE_METALNESSMAP uniform sampler2D metalnessMap; -#endif`,Nm=`#ifdef USE_INSTANCING_MORPH +#endif`,Z0=`#ifdef USE_INSTANCING_MORPH float morphTargetInfluences[ MORPHTARGETS_COUNT ]; float morphTargetBaseInfluence = texelFetch( morphTexture, ivec2( 0, gl_InstanceID ), 0 ).r; for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { morphTargetInfluences[i] = texelFetch( morphTexture, ivec2( i + 1, gl_InstanceID ), 0 ).r; } -#endif`,Um=`#if defined( USE_MORPHCOLORS ) +#endif`,J0=`#if defined( USE_MORPHCOLORS ) vColor *= morphTargetBaseInfluence; for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { #if defined( USE_COLOR_ALPHA ) @@ -1520,12 +1520,12 @@ vec3 getLightProbeGridIrradiance( vec3 worldPos, vec3 worldNormal ) { if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ]; #endif } -#endif`,Fm=`#ifdef USE_MORPHNORMALS +#endif`,j0=`#ifdef USE_MORPHNORMALS objectNormal *= morphTargetBaseInfluence; for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { if ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ]; } -#endif`,Om=`#ifdef USE_MORPHTARGETS +#endif`,Q0=`#ifdef USE_MORPHTARGETS #ifndef USE_INSTANCING_MORPH uniform float morphTargetBaseInfluence; uniform float morphTargetInfluences[ MORPHTARGETS_COUNT ]; @@ -1539,12 +1539,12 @@ vec3 getLightProbeGridIrradiance( vec3 worldPos, vec3 worldNormal ) { ivec3 morphUV = ivec3( x, y, morphTargetIndex ); return texelFetch( morphTargetsTexture, morphUV, 0 ); } -#endif`,km=`#ifdef USE_MORPHTARGETS +#endif`,tg=`#ifdef USE_MORPHTARGETS transformed *= morphTargetBaseInfluence; for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { if ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ]; } -#endif`,Bm=`float faceDirection = gl_FrontFacing ? 1.0 : - 1.0; +#endif`,eg=`float faceDirection = gl_FrontFacing ? 1.0 : - 1.0; #ifdef FLAT_SHADED vec3 fdx = dFdx( vViewPosition ); vec3 fdy = dFdy( vViewPosition ); @@ -1585,7 +1585,7 @@ vec3 getLightProbeGridIrradiance( vec3 worldPos, vec3 worldNormal ) { tbn2[1] *= faceDirection; #endif #endif -vec3 nonPerturbedNormal = normal;`,zm=`#ifdef USE_NORMALMAP_OBJECTSPACE +vec3 nonPerturbedNormal = normal;`,ng=`#ifdef USE_NORMALMAP_OBJECTSPACE normal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0; #ifdef FLIP_SIDED normal = - normal; @@ -1603,19 +1603,19 @@ vec3 nonPerturbedNormal = normal;`,zm=`#ifdef USE_NORMALMAP_OBJECTSPACE normal = normalize( tbn * mapN ); #elif defined( USE_BUMPMAP ) normal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection ); -#endif`,Hm=`#ifndef FLAT_SHADED +#endif`,ig=`#ifndef FLAT_SHADED varying vec3 vNormal; #ifdef USE_TANGENT varying vec3 vTangent; varying vec3 vBitangent; #endif -#endif`,Gm=`#ifndef FLAT_SHADED +#endif`,sg=`#ifndef FLAT_SHADED varying vec3 vNormal; #ifdef USE_TANGENT varying vec3 vTangent; varying vec3 vBitangent; #endif -#endif`,Vm=`#ifndef FLAT_SHADED +#endif`,rg=`#ifndef FLAT_SHADED vNormal = normalize( transformedNormal ); #ifdef USE_TANGENT vTangent = normalize( transformedTangent ); @@ -1624,7 +1624,7 @@ vec3 nonPerturbedNormal = normal;`,zm=`#ifdef USE_NORMALMAP_OBJECTSPACE vBitangent = - vBitangent; #endif #endif -#endif`,Wm=`#ifdef USE_NORMALMAP +#endif`,og=`#ifdef USE_NORMALMAP uniform sampler2D normalMap; uniform vec2 normalScale; #endif @@ -1646,13 +1646,13 @@ vec3 nonPerturbedNormal = normal;`,zm=`#ifdef USE_NORMALMAP_OBJECTSPACE float scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det ); return mat3( T * scale, B * scale, N ); } -#endif`,$m=`#ifdef USE_CLEARCOAT +#endif`,ag=`#ifdef USE_CLEARCOAT vec3 clearcoatNormal = nonPerturbedNormal; -#endif`,Xm=`#ifdef USE_CLEARCOAT_NORMALMAP +#endif`,lg=`#ifdef USE_CLEARCOAT_NORMALMAP vec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0; clearcoatMapN.xy *= clearcoatNormalScale; clearcoatNormal = normalize( tbn2 * clearcoatMapN ); -#endif`,qm=`#ifdef USE_CLEARCOATMAP +#endif`,cg=`#ifdef USE_CLEARCOATMAP uniform sampler2D clearcoatMap; #endif #ifdef USE_CLEARCOAT_NORMALMAP @@ -1661,18 +1661,18 @@ vec3 nonPerturbedNormal = normal;`,zm=`#ifdef USE_NORMALMAP_OBJECTSPACE #endif #ifdef USE_CLEARCOAT_ROUGHNESSMAP uniform sampler2D clearcoatRoughnessMap; -#endif`,Ym=`#ifdef USE_IRIDESCENCEMAP +#endif`,hg=`#ifdef USE_IRIDESCENCEMAP uniform sampler2D iridescenceMap; #endif #ifdef USE_IRIDESCENCE_THICKNESSMAP uniform sampler2D iridescenceThicknessMap; -#endif`,Km=`#ifdef OPAQUE +#endif`,ug=`#ifdef OPAQUE diffuseColor.a = 1.0; #endif #ifdef USE_TRANSMISSION diffuseColor.a *= material.transmissionAlpha; #endif -gl_FragColor = vec4( outgoingLight, diffuseColor.a );`,Zm=`vec3 packNormalToRGB( const in vec3 normal ) { +gl_FragColor = vec4( outgoingLight, diffuseColor.a );`,dg=`vec3 packNormalToRGB( const in vec3 normal ) { return normalize( normal ) * 0.5 + 0.5; } vec3 unpackRGBToNormal( const in vec3 rgb ) { @@ -1751,9 +1751,9 @@ float perspectiveDepthToViewZ( const in float depth, const in float near, const #else return ( near * far ) / ( ( far - near ) * depth - far ); #endif -}`,Jm=`#ifdef PREMULTIPLIED_ALPHA +}`,fg=`#ifdef PREMULTIPLIED_ALPHA gl_FragColor.rgb *= gl_FragColor.a; -#endif`,Qm=`vec4 mvPosition = vec4( transformed, 1.0 ); +#endif`,pg=`vec4 mvPosition = vec4( transformed, 1.0 ); #ifdef USE_BATCHING mvPosition = batchingMatrix * mvPosition; #endif @@ -1761,22 +1761,22 @@ float perspectiveDepthToViewZ( const in float depth, const in float near, const mvPosition = instanceMatrix * mvPosition; #endif mvPosition = modelViewMatrix * mvPosition; -gl_Position = projectionMatrix * mvPosition;`,jm=`#ifdef DITHERING +gl_Position = projectionMatrix * mvPosition;`,mg=`#ifdef DITHERING gl_FragColor.rgb = dithering( gl_FragColor.rgb ); -#endif`,tg=`#ifdef DITHERING +#endif`,gg=`#ifdef DITHERING vec3 dithering( vec3 color ) { float grid_position = rand( gl_FragCoord.xy ); vec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 ); dither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position ); return color + dither_shift_RGB; } -#endif`,eg=`float roughnessFactor = roughness; +#endif`,xg=`float roughnessFactor = roughness; #ifdef USE_ROUGHNESSMAP vec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv ); roughnessFactor *= texelRoughness.g; -#endif`,ng=`#ifdef USE_ROUGHNESSMAP +#endif`,vg=`#ifdef USE_ROUGHNESSMAP uniform sampler2D roughnessMap; -#endif`,ig=`#if NUM_SPOT_LIGHT_COORDS > 0 +#endif`,_g=`#if NUM_SPOT_LIGHT_COORDS > 0 varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; #endif #if NUM_SPOT_LIGHT_MAPS > 0 @@ -1976,7 +1976,7 @@ gl_Position = projectionMatrix * mvPosition;`,jm=`#ifdef DITHERING } #endif #endif -#endif`,sg=`#if NUM_SPOT_LIGHT_COORDS > 0 +#endif`,yg=`#if NUM_SPOT_LIGHT_COORDS > 0 uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ]; varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; #endif @@ -2017,7 +2017,7 @@ gl_Position = projectionMatrix * mvPosition;`,jm=`#ifdef DITHERING }; uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ]; #endif -#endif`,rg=`#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 ) +#endif`,Mg=`#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 ) #ifdef HAS_NORMAL vec3 shadowWorldNormal = transformNormalByInverseViewMatrix( transformedNormal, viewMatrix ); #else @@ -2053,7 +2053,7 @@ gl_Position = projectionMatrix * mvPosition;`,jm=`#ifdef DITHERING vSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition; } #pragma unroll_loop_end -#endif`,ag=`float getShadowMask() { +#endif`,bg=`float getShadowMask() { float shadow = 1.0; #ifdef USE_SHADOWMAP #if NUM_DIR_LIGHT_SHADOWS > 0 @@ -2085,12 +2085,12 @@ gl_Position = projectionMatrix * mvPosition;`,jm=`#ifdef DITHERING #endif #endif return shadow; -}`,og=`#ifdef USE_SKINNING +}`,Sg=`#ifdef USE_SKINNING mat4 boneMatX = getBoneMatrix( skinIndex.x ); mat4 boneMatY = getBoneMatrix( skinIndex.y ); mat4 boneMatZ = getBoneMatrix( skinIndex.z ); mat4 boneMatW = getBoneMatrix( skinIndex.w ); -#endif`,lg=`#ifdef USE_SKINNING +#endif`,wg=`#ifdef USE_SKINNING uniform mat4 bindMatrix; uniform mat4 bindMatrixInverse; uniform highp sampler2D boneTexture; @@ -2105,7 +2105,7 @@ gl_Position = projectionMatrix * mvPosition;`,jm=`#ifdef DITHERING vec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 ); return mat4( v1, v2, v3, v4 ); } -#endif`,cg=`#ifdef USE_SKINNING +#endif`,Eg=`#ifdef USE_SKINNING vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 ); vec4 skinned = vec4( 0.0 ); skinned += boneMatX * skinVertex * skinWeight.x; @@ -2113,7 +2113,7 @@ gl_Position = projectionMatrix * mvPosition;`,jm=`#ifdef DITHERING skinned += boneMatZ * skinVertex * skinWeight.z; skinned += boneMatW * skinVertex * skinWeight.w; transformed = ( bindMatrixInverse * skinned ).xyz; -#endif`,hg=`#ifdef USE_SKINNING +#endif`,Tg=`#ifdef USE_SKINNING mat4 skinMatrix = mat4( 0.0 ); skinMatrix += skinWeight.x * boneMatX; skinMatrix += skinWeight.y * boneMatY; @@ -2124,17 +2124,17 @@ gl_Position = projectionMatrix * mvPosition;`,jm=`#ifdef DITHERING #ifdef USE_TANGENT objectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz; #endif -#endif`,ug=`float specularStrength; +#endif`,Ag=`float specularStrength; #ifdef USE_SPECULARMAP vec4 texelSpecular = texture2D( specularMap, vSpecularMapUv ); specularStrength = texelSpecular.r; #else specularStrength = 1.0; -#endif`,dg=`#ifdef USE_SPECULARMAP +#endif`,Cg=`#ifdef USE_SPECULARMAP uniform sampler2D specularMap; -#endif`,fg=`#if defined( TONE_MAPPING ) +#endif`,Rg=`#if defined( TONE_MAPPING ) gl_FragColor.rgb = toneMapping( gl_FragColor.rgb ); -#endif`,pg=`#ifndef saturate +#endif`,Pg=`#ifndef saturate #define saturate( a ) clamp( a, 0.0, 1.0 ) #endif uniform float toneMappingExposure; @@ -2231,7 +2231,7 @@ vec3 NeutralToneMapping( vec3 color ) { float g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. ); return mix( color, vec3( newPeak ), g ); } -vec3 CustomToneMapping( vec3 color ) { return color; }`,mg=`#ifdef USE_TRANSMISSION +vec3 CustomToneMapping( vec3 color ) { return color; }`,Lg=`#ifdef USE_TRANSMISSION material.transmission = transmission; material.transmissionAlpha = 1.0; material.thickness = thickness; @@ -2252,7 +2252,7 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`,mg=`#ifdef USE_TRANSMISS material.attenuationColor, material.attenuationDistance ); material.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission ); totalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission ); -#endif`,gg=`#ifdef USE_TRANSMISSION +#endif`,Dg=`#ifdef USE_TRANSMISSION uniform float transmission; uniform float thickness; uniform float attenuationDistance; @@ -2378,7 +2378,7 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`,mg=`#ifdef USE_TRANSMISS float transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0; return vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor ); } -#endif`,_g=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) +#endif`,Ig=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) varying vec2 vUv; #endif #ifdef USE_MAP @@ -2448,7 +2448,7 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`,mg=`#ifdef USE_TRANSMISS #ifdef USE_THICKNESSMAP uniform mat3 thicknessMapTransform; varying vec2 vThicknessMapUv; -#endif`,xg=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) +#endif`,Ng=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) varying vec2 vUv; #endif #ifdef USE_MAP @@ -2542,7 +2542,7 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`,mg=`#ifdef USE_TRANSMISS #ifdef USE_THICKNESSMAP uniform mat3 thicknessMapTransform; varying vec2 vThicknessMapUv; -#endif`,vg=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) +#endif`,Ug=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) vUv = vec3( uv, 1 ).xy; #endif #ifdef USE_MAP @@ -2613,7 +2613,7 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`,mg=`#ifdef USE_TRANSMISS #endif #ifdef USE_THICKNESSMAP vThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy; -#endif`,Mg=`#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0 +#endif`,Fg=`#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP ) || defined ( USE_TRANSMISSION ) || NUM_SPOT_LIGHT_COORDS > 0 vec4 worldPosition = vec4( transformed, 1.0 ); #ifdef USE_BATCHING worldPosition = batchingMatrix * worldPosition; @@ -2622,7 +2622,7 @@ vec3 CustomToneMapping( vec3 color ) { return color; }`,mg=`#ifdef USE_TRANSMISS worldPosition = instanceMatrix * worldPosition; #endif worldPosition = modelMatrix * worldPosition; -#endif`;const Xt={alphahash_fragment:yp,alphahash_pars_fragment:Sp,alphamap_fragment:bp,alphamap_pars_fragment:wp,alphatest_fragment:Ep,alphatest_pars_fragment:Tp,aomap_fragment:Ap,aomap_pars_fragment:Cp,batching_pars_vertex:Rp,batching_vertex:Pp,begin_vertex:Lp,beginnormal_vertex:Dp,bsdfs:Ip,iridescence_fragment:Np,bumpmap_pars_fragment:Up,clipping_planes_fragment:Fp,clipping_planes_pars_fragment:Op,clipping_planes_pars_vertex:kp,clipping_planes_vertex:Bp,color_fragment:zp,color_pars_fragment:Hp,color_pars_vertex:Gp,color_vertex:Vp,common:Wp,cube_uv_reflection_fragment:$p,defaultnormal_vertex:Xp,displacementmap_pars_vertex:qp,displacementmap_vertex:Yp,emissivemap_fragment:Kp,emissivemap_pars_fragment:Zp,colorspace_fragment:Jp,colorspace_pars_fragment:Qp,envmap_fragment:jp,envmap_common_pars_fragment:tm,envmap_pars_fragment:em,envmap_pars_vertex:nm,envmap_physical_pars_fragment:fm,envmap_vertex:im,fog_vertex:sm,fog_pars_vertex:rm,fog_fragment:am,fog_pars_fragment:om,gradientmap_pars_fragment:lm,lightmap_pars_fragment:cm,lights_lambert_fragment:hm,lights_lambert_pars_fragment:um,lights_pars_begin:dm,lights_toon_fragment:pm,lights_toon_pars_fragment:mm,lights_phong_fragment:gm,lights_phong_pars_fragment:_m,lights_physical_fragment:xm,lights_physical_pars_fragment:vm,lights_fragment_begin:Mm,lights_fragment_maps:ym,lights_fragment_end:Sm,lightprobes_pars_fragment:bm,logdepthbuf_fragment:wm,logdepthbuf_pars_fragment:Em,logdepthbuf_pars_vertex:Tm,logdepthbuf_vertex:Am,map_fragment:Cm,map_pars_fragment:Rm,map_particle_fragment:Pm,map_particle_pars_fragment:Lm,metalnessmap_fragment:Dm,metalnessmap_pars_fragment:Im,morphinstance_vertex:Nm,morphcolor_vertex:Um,morphnormal_vertex:Fm,morphtarget_pars_vertex:Om,morphtarget_vertex:km,normal_fragment_begin:Bm,normal_fragment_maps:zm,normal_pars_fragment:Hm,normal_pars_vertex:Gm,normal_vertex:Vm,normalmap_pars_fragment:Wm,clearcoat_normal_fragment_begin:$m,clearcoat_normal_fragment_maps:Xm,clearcoat_pars_fragment:qm,iridescence_pars_fragment:Ym,opaque_fragment:Km,packing:Zm,premultiplied_alpha_fragment:Jm,project_vertex:Qm,dithering_fragment:jm,dithering_pars_fragment:tg,roughnessmap_fragment:eg,roughnessmap_pars_fragment:ng,shadowmap_pars_fragment:ig,shadowmap_pars_vertex:sg,shadowmap_vertex:rg,shadowmask_pars_fragment:ag,skinbase_vertex:og,skinning_pars_vertex:lg,skinning_vertex:cg,skinnormal_vertex:hg,specularmap_fragment:ug,specularmap_pars_fragment:dg,tonemapping_fragment:fg,tonemapping_pars_fragment:pg,transmission_fragment:mg,transmission_pars_fragment:gg,uv_pars_fragment:_g,uv_pars_vertex:xg,uv_vertex:vg,worldpos_vertex:Mg,background_vert:`varying vec2 vUv; +#endif`;const Yt={alphahash_fragment:Om,alphahash_pars_fragment:km,alphamap_fragment:Bm,alphamap_pars_fragment:zm,alphatest_fragment:Hm,alphatest_pars_fragment:Gm,aomap_fragment:Vm,aomap_pars_fragment:Wm,batching_pars_vertex:$m,batching_vertex:Xm,begin_vertex:qm,beginnormal_vertex:Ym,bsdfs:Km,iridescence_fragment:Zm,bumpmap_pars_fragment:Jm,clipping_planes_fragment:jm,clipping_planes_pars_fragment:Qm,clipping_planes_pars_vertex:t0,clipping_planes_vertex:e0,color_fragment:n0,color_pars_fragment:i0,color_pars_vertex:s0,color_vertex:r0,common:o0,cube_uv_reflection_fragment:a0,defaultnormal_vertex:l0,displacementmap_pars_vertex:c0,displacementmap_vertex:h0,emissivemap_fragment:u0,emissivemap_pars_fragment:d0,colorspace_fragment:f0,colorspace_pars_fragment:p0,envmap_fragment:m0,envmap_common_pars_fragment:g0,envmap_pars_fragment:x0,envmap_pars_vertex:v0,envmap_physical_pars_fragment:R0,envmap_vertex:_0,fog_vertex:y0,fog_pars_vertex:M0,fog_fragment:b0,fog_pars_fragment:S0,gradientmap_pars_fragment:w0,lightmap_pars_fragment:E0,lights_lambert_fragment:T0,lights_lambert_pars_fragment:A0,lights_pars_begin:C0,lights_toon_fragment:P0,lights_toon_pars_fragment:L0,lights_phong_fragment:D0,lights_phong_pars_fragment:I0,lights_physical_fragment:N0,lights_physical_pars_fragment:U0,lights_fragment_begin:F0,lights_fragment_maps:O0,lights_fragment_end:k0,lightprobes_pars_fragment:B0,logdepthbuf_fragment:z0,logdepthbuf_pars_fragment:H0,logdepthbuf_pars_vertex:G0,logdepthbuf_vertex:V0,map_fragment:W0,map_pars_fragment:$0,map_particle_fragment:X0,map_particle_pars_fragment:q0,metalnessmap_fragment:Y0,metalnessmap_pars_fragment:K0,morphinstance_vertex:Z0,morphcolor_vertex:J0,morphnormal_vertex:j0,morphtarget_pars_vertex:Q0,morphtarget_vertex:tg,normal_fragment_begin:eg,normal_fragment_maps:ng,normal_pars_fragment:ig,normal_pars_vertex:sg,normal_vertex:rg,normalmap_pars_fragment:og,clearcoat_normal_fragment_begin:ag,clearcoat_normal_fragment_maps:lg,clearcoat_pars_fragment:cg,iridescence_pars_fragment:hg,opaque_fragment:ug,packing:dg,premultiplied_alpha_fragment:fg,project_vertex:pg,dithering_fragment:mg,dithering_pars_fragment:gg,roughnessmap_fragment:xg,roughnessmap_pars_fragment:vg,shadowmap_pars_fragment:_g,shadowmap_pars_vertex:yg,shadowmap_vertex:Mg,shadowmask_pars_fragment:bg,skinbase_vertex:Sg,skinning_pars_vertex:wg,skinning_vertex:Eg,skinnormal_vertex:Tg,specularmap_fragment:Ag,specularmap_pars_fragment:Cg,tonemapping_fragment:Rg,tonemapping_pars_fragment:Pg,transmission_fragment:Lg,transmission_pars_fragment:Dg,uv_pars_fragment:Ig,uv_pars_vertex:Ng,uv_vertex:Ug,worldpos_vertex:Fg,background_vert:`varying vec2 vUv; uniform mat3 uvTransform; void main() { vUv = ( uvTransform * vec3( uv, 1 ) ).xy; @@ -3676,7 +3676,7 @@ void main() { #include #include #include -}`},mt={common:{diffuse:{value:new kt(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new zt},alphaMap:{value:null},alphaMapTransform:{value:new zt},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new zt}},envmap:{envMap:{value:null},envMapRotation:{value:new zt},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98},dfgLUT:{value:null}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new zt}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new zt}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new zt},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new zt},normalScale:{value:new ht(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new zt},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new zt}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new zt}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new zt}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new kt(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},spotLightMap:{value:[]},spotLightMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}},ltc_1:{value:null},ltc_2:{value:null},probesSH:{value:null},probesMin:{value:new C},probesMax:{value:new C},probesResolution:{value:new C}},points:{diffuse:{value:new kt(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new zt},alphaTest:{value:0},uvTransform:{value:new zt}},sprite:{diffuse:{value:new kt(16777215)},opacity:{value:1},center:{value:new ht(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new zt},alphaMap:{value:null},alphaMapTransform:{value:new zt},alphaTest:{value:0}}},Pn={basic:{uniforms:$e([mt.common,mt.specularmap,mt.envmap,mt.aomap,mt.lightmap,mt.fog]),vertexShader:Xt.meshbasic_vert,fragmentShader:Xt.meshbasic_frag},lambert:{uniforms:$e([mt.common,mt.specularmap,mt.envmap,mt.aomap,mt.lightmap,mt.emissivemap,mt.bumpmap,mt.normalmap,mt.displacementmap,mt.fog,mt.lights,{emissive:{value:new kt(0)},envMapIntensity:{value:1}}]),vertexShader:Xt.meshlambert_vert,fragmentShader:Xt.meshlambert_frag},phong:{uniforms:$e([mt.common,mt.specularmap,mt.envmap,mt.aomap,mt.lightmap,mt.emissivemap,mt.bumpmap,mt.normalmap,mt.displacementmap,mt.fog,mt.lights,{emissive:{value:new kt(0)},specular:{value:new kt(1118481)},shininess:{value:30},envMapIntensity:{value:1}}]),vertexShader:Xt.meshphong_vert,fragmentShader:Xt.meshphong_frag},standard:{uniforms:$e([mt.common,mt.envmap,mt.aomap,mt.lightmap,mt.emissivemap,mt.bumpmap,mt.normalmap,mt.displacementmap,mt.roughnessmap,mt.metalnessmap,mt.fog,mt.lights,{emissive:{value:new kt(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:Xt.meshphysical_vert,fragmentShader:Xt.meshphysical_frag},toon:{uniforms:$e([mt.common,mt.aomap,mt.lightmap,mt.emissivemap,mt.bumpmap,mt.normalmap,mt.displacementmap,mt.gradientmap,mt.fog,mt.lights,{emissive:{value:new kt(0)}}]),vertexShader:Xt.meshtoon_vert,fragmentShader:Xt.meshtoon_frag},matcap:{uniforms:$e([mt.common,mt.bumpmap,mt.normalmap,mt.displacementmap,mt.fog,{matcap:{value:null}}]),vertexShader:Xt.meshmatcap_vert,fragmentShader:Xt.meshmatcap_frag},points:{uniforms:$e([mt.points,mt.fog]),vertexShader:Xt.points_vert,fragmentShader:Xt.points_frag},dashed:{uniforms:$e([mt.common,mt.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:Xt.linedashed_vert,fragmentShader:Xt.linedashed_frag},depth:{uniforms:$e([mt.common,mt.displacementmap]),vertexShader:Xt.depth_vert,fragmentShader:Xt.depth_frag},normal:{uniforms:$e([mt.common,mt.bumpmap,mt.normalmap,mt.displacementmap,{opacity:{value:1}}]),vertexShader:Xt.meshnormal_vert,fragmentShader:Xt.meshnormal_frag},sprite:{uniforms:$e([mt.sprite,mt.fog]),vertexShader:Xt.sprite_vert,fragmentShader:Xt.sprite_frag},background:{uniforms:{uvTransform:{value:new zt},t2D:{value:null},backgroundIntensity:{value:1}},vertexShader:Xt.background_vert,fragmentShader:Xt.background_frag},backgroundCube:{uniforms:{envMap:{value:null},backgroundBlurriness:{value:0},backgroundIntensity:{value:1},backgroundRotation:{value:new zt}},vertexShader:Xt.backgroundCube_vert,fragmentShader:Xt.backgroundCube_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:Xt.cube_vert,fragmentShader:Xt.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:Xt.equirect_vert,fragmentShader:Xt.equirect_frag},distance:{uniforms:$e([mt.common,mt.displacementmap,{referencePosition:{value:new C},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:Xt.distance_vert,fragmentShader:Xt.distance_frag},shadow:{uniforms:$e([mt.lights,mt.fog,{color:{value:new kt(0)},opacity:{value:1}}]),vertexShader:Xt.shadow_vert,fragmentShader:Xt.shadow_frag}};Pn.physical={uniforms:$e([Pn.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatMapTransform:{value:new zt},clearcoatNormalMap:{value:null},clearcoatNormalMapTransform:{value:new zt},clearcoatNormalScale:{value:new ht(1,1)},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatRoughnessMapTransform:{value:new zt},dispersion:{value:0},iridescence:{value:0},iridescenceMap:{value:null},iridescenceMapTransform:{value:new zt},iridescenceIOR:{value:1.3},iridescenceThicknessMinimum:{value:100},iridescenceThicknessMaximum:{value:400},iridescenceThicknessMap:{value:null},iridescenceThicknessMapTransform:{value:new zt},sheen:{value:0},sheenColor:{value:new kt(0)},sheenColorMap:{value:null},sheenColorMapTransform:{value:new zt},sheenRoughness:{value:1},sheenRoughnessMap:{value:null},sheenRoughnessMapTransform:{value:new zt},transmission:{value:0},transmissionMap:{value:null},transmissionMapTransform:{value:new zt},transmissionSamplerSize:{value:new ht},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},thicknessMapTransform:{value:new zt},attenuationDistance:{value:0},attenuationColor:{value:new kt(0)},specularColor:{value:new kt(1,1,1)},specularColorMap:{value:null},specularColorMapTransform:{value:new zt},specularIntensity:{value:1},specularIntensityMap:{value:null},specularIntensityMapTransform:{value:new zt},anisotropyVector:{value:new ht},anisotropyMap:{value:null},anisotropyMapTransform:{value:new zt}}]),vertexShader:Xt.meshphysical_vert,fragmentShader:Xt.meshphysical_frag};const qr={r:0,b:0,g:0},yg=new se,mh=new zt;mh.set(-1,0,0,0,1,0,0,0,1);function Sg(s,t,e,n,i,r){const a=new kt(0);let o=i===!0?0:1,l,c,u=null,h=0,d=null;function f(w){let E=w.isScene===!0?w.background:null;if(E&&E.isTexture){const M=w.backgroundBlurriness>0;E=t.get(E,M)}return E}function p(w){let E=!1;const M=f(w);M===null?m(a,o):M&&M.isColor&&(m(M,1),E=!0);const S=s.xr.getEnvironmentBlendMode();S==="additive"?e.buffers.color.setClear(0,0,0,1,r):S==="alpha-blend"&&e.buffers.color.setClear(0,0,0,0,r),(s.autoClear||E)&&(e.buffers.depth.setTest(!0),e.buffers.depth.setMask(!0),e.buffers.color.setMask(!0),s.clear(s.autoClearColor,s.autoClearDepth,s.autoClearStencil))}function v(w,E){const M=f(E);M&&(M.isCubeTexture||M.mapping===or)?(c===void 0&&(c=new Bt(new tn(1,1,1),new Ce({name:"BackgroundCubeMaterial",uniforms:ds(Pn.backgroundCube.uniforms),vertexShader:Pn.backgroundCube.vertexShader,fragmentShader:Pn.backgroundCube.fragmentShader,side:Ge,depthTest:!1,depthWrite:!1,fog:!1,allowOverride:!1})),c.geometry.deleteAttribute("normal"),c.geometry.deleteAttribute("uv"),c.onBeforeRender=function(S,b,R){this.matrixWorld.copyPosition(R.matrixWorld)},Object.defineProperty(c.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),n.update(c)),c.material.uniforms.envMap.value=M,c.material.uniforms.backgroundBlurriness.value=E.backgroundBlurriness,c.material.uniforms.backgroundIntensity.value=E.backgroundIntensity,c.material.uniforms.backgroundRotation.value.setFromMatrix4(yg.makeRotationFromEuler(E.backgroundRotation)).transpose(),M.isCubeTexture&&M.isRenderTargetTexture===!1&&c.material.uniforms.backgroundRotation.value.premultiply(mh),c.material.toneMapped=Kt.getTransfer(M.colorSpace)!==ie,(u!==M||h!==M.version||d!==s.toneMapping)&&(c.material.needsUpdate=!0,u=M,h=M.version,d=s.toneMapping),c.layers.enableAll(),w.unshift(c,c.geometry,c.material,0,0,null)):M&&M.isTexture&&(l===void 0&&(l=new Bt(new We(2,2),new Ce({name:"BackgroundMaterial",uniforms:ds(Pn.background.uniforms),vertexShader:Pn.background.vertexShader,fragmentShader:Pn.background.fragmentShader,side:jn,depthTest:!1,depthWrite:!1,fog:!1,allowOverride:!1})),l.geometry.deleteAttribute("normal"),Object.defineProperty(l.material,"map",{get:function(){return this.uniforms.t2D.value}}),n.update(l)),l.material.uniforms.t2D.value=M,l.material.uniforms.backgroundIntensity.value=E.backgroundIntensity,l.material.toneMapped=Kt.getTransfer(M.colorSpace)!==ie,M.matrixAutoUpdate===!0&&M.updateMatrix(),l.material.uniforms.uvTransform.value.copy(M.matrix),(u!==M||h!==M.version||d!==s.toneMapping)&&(l.material.needsUpdate=!0,u=M,h=M.version,d=s.toneMapping),l.layers.enableAll(),w.unshift(l,l.geometry,l.material,0,0,null))}function m(w,E){w.getRGB(qr,ih(s)),e.buffers.color.setClear(qr.r,qr.g,qr.b,E,r)}function g(){c!==void 0&&(c.geometry.dispose(),c.material.dispose(),c=void 0),l!==void 0&&(l.geometry.dispose(),l.material.dispose(),l=void 0)}return{getClearColor:function(){return a},setClearColor:function(w,E=1){a.set(w),o=E,m(a,o)},getClearAlpha:function(){return o},setClearAlpha:function(w){o=w,m(a,o)},render:p,addToRenderList:v,dispose:g}}function bg(s,t){const e=s.getParameter(s.MAX_VERTEX_ATTRIBS),n={},i=d(null);let r=i,a=!1;function o(L,F,q,Y,B){let K=!1;const X=h(L,Y,q,F);r!==X&&(r=X,c(r.object)),K=f(L,Y,q,B),K&&p(L,Y,q,B),B!==null&&t.update(B,s.ELEMENT_ARRAY_BUFFER),(K||a)&&(a=!1,M(L,F,q,Y),B!==null&&s.bindBuffer(s.ELEMENT_ARRAY_BUFFER,t.get(B).buffer))}function l(){return s.createVertexArray()}function c(L){return s.bindVertexArray(L)}function u(L){return s.deleteVertexArray(L)}function h(L,F,q,Y){const B=Y.wireframe===!0;let K=n[F.id];K===void 0&&(K={},n[F.id]=K);const X=L.isInstancedMesh===!0?L.id:0;let Q=K[X];Q===void 0&&(Q={},K[X]=Q);let it=Q[q.id];it===void 0&&(it={},Q[q.id]=it);let pt=it[B];return pt===void 0&&(pt=d(l()),it[B]=pt),pt}function d(L){const F=[],q=[],Y=[];for(let B=0;B=0){const _t=B[it];let bt=K[it];if(bt===void 0&&(it==="instanceMatrix"&&L.instanceMatrix&&(bt=L.instanceMatrix),it==="instanceColor"&&L.instanceColor&&(bt=L.instanceColor)),_t===void 0||_t.attribute!==bt||bt&&_t.data!==bt.data)return!0;X++}return r.attributesNum!==X||r.index!==Y}function p(L,F,q,Y){const B={},K=F.attributes;let X=0;const Q=q.getAttributes();for(const it in Q)if(Q[it].location>=0){let _t=K[it];_t===void 0&&(it==="instanceMatrix"&&L.instanceMatrix&&(_t=L.instanceMatrix),it==="instanceColor"&&L.instanceColor&&(_t=L.instanceColor));const bt={};bt.attribute=_t,_t&&_t.data&&(bt.data=_t.data),B[it]=bt,X++}r.attributes=B,r.attributesNum=X,r.index=Y}function v(){const L=r.newAttributes;for(let F=0,q=L.length;F=0){let pt=B[Q];if(pt===void 0&&(Q==="instanceMatrix"&&L.instanceMatrix&&(pt=L.instanceMatrix),Q==="instanceColor"&&L.instanceColor&&(pt=L.instanceColor)),pt!==void 0){const _t=pt.normalized,bt=pt.itemSize,ee=t.get(pt);if(ee===void 0)continue;const pe=ee.buffer,jt=ee.type,j=ee.bytesPerElement,D=jt===s.INT||jt===s.UNSIGNED_INT||pt.gpuType===za;if(pt.isInterleavedBufferAttribute){const W=pt.data,st=W.stride,lt=pt.offset;if(W.isInstancedInterleavedBuffer){for(let rt=0;rt0&&s.getShaderPrecisionFormat(s.FRAGMENT_SHADER,s.HIGH_FLOAT).precision>0)return"highp";R="mediump"}return R==="mediump"&&s.getShaderPrecisionFormat(s.VERTEX_SHADER,s.MEDIUM_FLOAT).precision>0&&s.getShaderPrecisionFormat(s.FRAGMENT_SHADER,s.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}let c=e.precision!==void 0?e.precision:"highp";const u=l(c);u!==c&&(Nt("WebGLRenderer:",c,"not supported, using",u,"instead."),c=u);const h=e.logarithmicDepthBuffer===!0,d=e.reversedDepthBuffer===!0&&t.has("EXT_clip_control");e.reversedDepthBuffer===!0&&d===!1&&Nt("WebGLRenderer: Unable to use reversed depth buffer due to missing EXT_clip_control extension. Fallback to default depth buffer.");const f=s.getParameter(s.MAX_TEXTURE_IMAGE_UNITS),p=s.getParameter(s.MAX_VERTEX_TEXTURE_IMAGE_UNITS),v=s.getParameter(s.MAX_TEXTURE_SIZE),m=s.getParameter(s.MAX_CUBE_MAP_TEXTURE_SIZE),g=s.getParameter(s.MAX_VERTEX_ATTRIBS),w=s.getParameter(s.MAX_VERTEX_UNIFORM_VECTORS),E=s.getParameter(s.MAX_VARYING_VECTORS),M=s.getParameter(s.MAX_FRAGMENT_UNIFORM_VECTORS),S=s.getParameter(s.MAX_SAMPLES),b=s.getParameter(s.SAMPLES);return{isWebGL2:!0,getMaxAnisotropy:r,getMaxPrecision:l,textureFormatReadable:a,textureTypeReadable:o,precision:c,logarithmicDepthBuffer:h,reversedDepthBuffer:d,maxTextures:f,maxVertexTextures:p,maxTextureSize:v,maxCubemapSize:m,maxAttributes:g,maxVertexUniforms:w,maxVaryings:E,maxFragmentUniforms:M,maxSamples:S,samples:b}}function Tg(s){const t=this;let e=null,n=0,i=!1,r=!1;const a=new oi,o=new zt,l={value:null,needsUpdate:!1};this.uniform=l,this.numPlanes=0,this.numIntersection=0,this.init=function(h,d){const f=h.length!==0||d||n!==0||i;return i=d,n=h.length,f},this.beginShadows=function(){r=!0,u(null)},this.endShadows=function(){r=!1},this.setGlobalState=function(h,d){e=u(h,d,0)},this.setState=function(h,d,f){const p=h.clippingPlanes,v=h.clipIntersection,m=h.clipShadows,g=s.get(h);if(!i||p===null||p.length===0||r&&!m)r?u(null):c();else{const w=r?0:n,E=w*4;let M=g.clippingState||null;l.value=M,M=u(p,d,E,f);for(let S=0;S!==E;++S)M[S]=e[S];g.clippingState=M,this.numIntersection=v?this.numPlanes:0,this.numPlanes+=w}};function c(){l.value!==e&&(l.value=e,l.needsUpdate=n>0),t.numPlanes=n,t.numIntersection=0}function u(h,d,f,p){const v=h!==null?h.length:0;let m=null;if(v!==0){if(m=l.value,p!==!0||m===null){const g=f+v*4,w=d.matrixWorldInverse;o.getNormalMatrix(w),(m===null||m.length0&&this._blur(l,0,0,e),this._applyPMREM(l),this._cleanup(l),l}fromEquirectangular(t,e=null){return this._fromTexture(t,e)}fromCubemap(t,e=null){return this._fromTexture(t,e)}compileCubemapShader(){this._cubemapMaterial===null&&(this._cubemapMaterial=yh(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){this._equirectMaterial===null&&(this._equirectMaterial=Mh(),this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),this._cubemapMaterial!==null&&this._cubemapMaterial.dispose(),this._equirectMaterial!==null&&this._equirectMaterial.dispose(),this._backgroundBox!==null&&(this._backgroundBox.geometry.dispose(),this._backgroundBox.material.dispose())}_setSize(t){this._lodMax=Math.floor(Math.log2(t)),this._cubeSize=Math.pow(2,this._lodMax)}_dispose(){this._blurMaterial!==null&&this._blurMaterial.dispose(),this._ggxMaterial!==null&&this._ggxMaterial.dispose(),this._pingPongRenderTarget!==null&&this._pingPongRenderTarget.dispose();for(let t=0;t2?S:0,S,S),h.setRenderTarget(i),g&&h.render(v,l),h.render(t,l)}h.toneMapping=f,h.autoClear=d,t.background=w}_textureToCubeUV(t,e){const n=this._renderer,i=t.mapping===Ei||t.mapping===$i;i?(this._cubemapMaterial===null&&(this._cubemapMaterial=yh()),this._cubemapMaterial.uniforms.flipEnvMap.value=t.isRenderTargetTexture===!1?-1:1):this._equirectMaterial===null&&(this._equirectMaterial=Mh());const r=i?this._cubemapMaterial:this._equirectMaterial,a=this._lodMeshes[0];a.material=r;const o=r.uniforms;o.envMap.value=t;const l=this._cubeSize;ms(e,0,0,3*l,2*l),n.setRenderTarget(e),n.render(a,Xs)}_applyPMREM(t){const e=this._renderer,n=e.autoClear;e.autoClear=!1;const i=this._lodMeshes.length;for(let r=1;rp-ui?n-p+ui:0),g=4*(this._cubeSize-v);l.envMap.value=t.texture,l.roughness.value=f,l.mipInt.value=p-e,ms(r,m,g,3*v,2*v),i.setRenderTarget(r),i.render(o,Xs),l.envMap.value=r.texture,l.roughness.value=0,l.mipInt.value=p-n,ms(t,m,g,3*v,2*v),i.setRenderTarget(t),i.render(o,Xs)}_blur(t,e,n,i,r){const a=this._pingPongRenderTarget;this._halfBlur(t,a,e,n,i,"latitudinal",r),this._halfBlur(a,t,n,n,i,"longitudinal",r)}_halfBlur(t,e,n,i,r,a,o){const l=this._renderer,c=this._blurMaterial;a!=="latitudinal"&&a!=="longitudinal"&&Qt("blur direction must be either latitudinal or longitudinal!");const u=3,h=this._lodMeshes[i];h.material=c;const d=c.uniforms,f=this._sizeLods[n]-1,p=isFinite(r)?Math.PI/(2*f):2*Math.PI/(2*Ni-1),v=r/p,m=isFinite(r)?1+Math.floor(u*v):Ni;m>Ni&&Nt(`sigmaRadians, ${r}, is too large and will clip, as it requested ${m} samples when the maximum is set to ${Ni}`);const g=[];let w=0;for(let R=0;RE-ui?i-E+ui:0),b=4*(this._cubeSize-M);ms(e,S,b,3*M,2*M),l.setRenderTarget(e),l.render(h,Xs)}}function Rg(s){const t=[],e=[],n=[];let i=s;const r=s-ui+1+gh.length;for(let a=0;as-ui?l=gh[a-s+ui-1]:a===0&&(l=0),e.push(l);const c=1/(o-2),u=-c,h=1+c,d=[u,u,h,u,h,h,u,u,h,h,u,h],f=6,p=6,v=3,m=2,g=1,w=new Float32Array(v*p*f),E=new Float32Array(m*p*f),M=new Float32Array(g*p*f);for(let b=0;b2?0:-1,T=[R,x,0,R+2/3,x,0,R+2/3,x+1,0,R,x,0,R+2/3,x+1,0,R,x+1,0];w.set(T,v*p*b),E.set(d,m*p*b);const P=[b,b,b,b,b,b];M.set(P,g*p*b)}const S=new Be;S.setAttribute("position",new rn(w,v)),S.setAttribute("uv",new rn(E,m)),S.setAttribute("faceIndex",new rn(M,g)),n.push(new Bt(S,null)),i>ui&&i--}return{lodMeshes:n,sizeLods:t,sigmas:e}}function vh(s,t,e){const n=new Xe(s,t,e);return n.texture.mapping=or,n.texture.name="PMREM.cubeUv",n.scissorTest=!0,n}function ms(s,t,e,n,i){s.viewport.set(t,e,n,i),s.scissor.set(t,e,n,i)}function Pg(s,t,e){return new Ce({name:"PMREMGGXConvolution",defines:{GGX_SAMPLES:Ag,CUBEUV_TEXEL_WIDTH:1/t,CUBEUV_TEXEL_HEIGHT:1/e,CUBEUV_MAX_MIP:`${s}.0`},uniforms:{envMap:{value:null},roughness:{value:0},mipInt:{value:0}},vertexShader:Yr(),fragmentShader:` +}`},vt={common:{diffuse:{value:new Bt(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new Ht},alphaMap:{value:null},alphaMapTransform:{value:new Ht},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new Ht}},envmap:{envMap:{value:null},envMapRotation:{value:new Ht},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98},dfgLUT:{value:null}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new Ht}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new Ht}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new Ht},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new Ht},normalScale:{value:new pt(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new Ht},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new Ht}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new Ht}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new Ht}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new Bt(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{}}},directionalLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{}}},spotLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},spotLightMap:{value:[]},spotLightMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{}}},pointLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}},ltc_1:{value:null},ltc_2:{value:null},probesSH:{value:null},probesMin:{value:new P},probesMax:{value:new P},probesResolution:{value:new P}},points:{diffuse:{value:new Bt(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new Ht},alphaTest:{value:0},uvTransform:{value:new Ht}},sprite:{diffuse:{value:new Bt(16777215)},opacity:{value:1},center:{value:new pt(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new Ht},alphaMap:{value:null},alphaMapTransform:{value:new Ht},alphaTest:{value:0}}},Dn={basic:{uniforms:qe([vt.common,vt.specularmap,vt.envmap,vt.aomap,vt.lightmap,vt.fog]),vertexShader:Yt.meshbasic_vert,fragmentShader:Yt.meshbasic_frag},lambert:{uniforms:qe([vt.common,vt.specularmap,vt.envmap,vt.aomap,vt.lightmap,vt.emissivemap,vt.bumpmap,vt.normalmap,vt.displacementmap,vt.fog,vt.lights,{emissive:{value:new Bt(0)},envMapIntensity:{value:1}}]),vertexShader:Yt.meshlambert_vert,fragmentShader:Yt.meshlambert_frag},phong:{uniforms:qe([vt.common,vt.specularmap,vt.envmap,vt.aomap,vt.lightmap,vt.emissivemap,vt.bumpmap,vt.normalmap,vt.displacementmap,vt.fog,vt.lights,{emissive:{value:new Bt(0)},specular:{value:new Bt(1118481)},shininess:{value:30},envMapIntensity:{value:1}}]),vertexShader:Yt.meshphong_vert,fragmentShader:Yt.meshphong_frag},standard:{uniforms:qe([vt.common,vt.envmap,vt.aomap,vt.lightmap,vt.emissivemap,vt.bumpmap,vt.normalmap,vt.displacementmap,vt.roughnessmap,vt.metalnessmap,vt.fog,vt.lights,{emissive:{value:new Bt(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:Yt.meshphysical_vert,fragmentShader:Yt.meshphysical_frag},toon:{uniforms:qe([vt.common,vt.aomap,vt.lightmap,vt.emissivemap,vt.bumpmap,vt.normalmap,vt.displacementmap,vt.gradientmap,vt.fog,vt.lights,{emissive:{value:new Bt(0)}}]),vertexShader:Yt.meshtoon_vert,fragmentShader:Yt.meshtoon_frag},matcap:{uniforms:qe([vt.common,vt.bumpmap,vt.normalmap,vt.displacementmap,vt.fog,{matcap:{value:null}}]),vertexShader:Yt.meshmatcap_vert,fragmentShader:Yt.meshmatcap_frag},points:{uniforms:qe([vt.points,vt.fog]),vertexShader:Yt.points_vert,fragmentShader:Yt.points_frag},dashed:{uniforms:qe([vt.common,vt.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:Yt.linedashed_vert,fragmentShader:Yt.linedashed_frag},depth:{uniforms:qe([vt.common,vt.displacementmap]),vertexShader:Yt.depth_vert,fragmentShader:Yt.depth_frag},normal:{uniforms:qe([vt.common,vt.bumpmap,vt.normalmap,vt.displacementmap,{opacity:{value:1}}]),vertexShader:Yt.meshnormal_vert,fragmentShader:Yt.meshnormal_frag},sprite:{uniforms:qe([vt.sprite,vt.fog]),vertexShader:Yt.sprite_vert,fragmentShader:Yt.sprite_frag},background:{uniforms:{uvTransform:{value:new Ht},t2D:{value:null},backgroundIntensity:{value:1}},vertexShader:Yt.background_vert,fragmentShader:Yt.background_frag},backgroundCube:{uniforms:{envMap:{value:null},backgroundBlurriness:{value:0},backgroundIntensity:{value:1},backgroundRotation:{value:new Ht}},vertexShader:Yt.backgroundCube_vert,fragmentShader:Yt.backgroundCube_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:Yt.cube_vert,fragmentShader:Yt.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:Yt.equirect_vert,fragmentShader:Yt.equirect_frag},distance:{uniforms:qe([vt.common,vt.displacementmap,{referencePosition:{value:new P},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:Yt.distance_vert,fragmentShader:Yt.distance_frag},shadow:{uniforms:qe([vt.lights,vt.fog,{color:{value:new Bt(0)},opacity:{value:1}}]),vertexShader:Yt.shadow_vert,fragmentShader:Yt.shadow_frag}};Dn.physical={uniforms:qe([Dn.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatMapTransform:{value:new Ht},clearcoatNormalMap:{value:null},clearcoatNormalMapTransform:{value:new Ht},clearcoatNormalScale:{value:new pt(1,1)},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatRoughnessMapTransform:{value:new Ht},dispersion:{value:0},iridescence:{value:0},iridescenceMap:{value:null},iridescenceMapTransform:{value:new Ht},iridescenceIOR:{value:1.3},iridescenceThicknessMinimum:{value:100},iridescenceThicknessMaximum:{value:400},iridescenceThicknessMap:{value:null},iridescenceThicknessMapTransform:{value:new Ht},sheen:{value:0},sheenColor:{value:new Bt(0)},sheenColorMap:{value:null},sheenColorMapTransform:{value:new Ht},sheenRoughness:{value:1},sheenRoughnessMap:{value:null},sheenRoughnessMapTransform:{value:new Ht},transmission:{value:0},transmissionMap:{value:null},transmissionMapTransform:{value:new Ht},transmissionSamplerSize:{value:new pt},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},thicknessMapTransform:{value:new Ht},attenuationDistance:{value:0},attenuationColor:{value:new Bt(0)},specularColor:{value:new Bt(1,1,1)},specularColorMap:{value:null},specularColorMapTransform:{value:new Ht},specularIntensity:{value:1},specularIntensityMap:{value:null},specularIntensityMapTransform:{value:new Ht},anisotropyVector:{value:new pt},anisotropyMap:{value:null},anisotropyMapTransform:{value:new Ht}}]),vertexShader:Yt.meshphysical_vert,fragmentShader:Yt.meshphysical_frag};const mo={r:0,b:0,g:0},Og=new re,ru=new Ht;ru.set(-1,0,0,0,1,0,0,0,1);function kg(s,t,e,n,i,r){const o=new Bt(0);let a=i===!0?0:1,l,c,u=null,h=0,d=null;function f(b){let E=b.isScene===!0?b.background:null;if(E&&E.isTexture){const y=b.backgroundBlurriness>0;E=t.get(E,y)}return E}function p(b){let E=!1;const y=f(b);y===null?m(o,a):y&&y.isColor&&(m(y,1),E=!0);const M=s.xr.getEnvironmentBlendMode();M==="additive"?e.buffers.color.setClear(0,0,0,1,r):M==="alpha-blend"&&e.buffers.color.setClear(0,0,0,0,r),(s.autoClear||E)&&(e.buffers.depth.setTest(!0),e.buffers.depth.setMask(!0),e.buffers.color.setMask(!0),s.clear(s.autoClearColor,s.autoClearDepth,s.autoClearStencil))}function x(b,E){const y=f(E);y&&(y.isCubeTexture||y.mapping===Cr)?(c===void 0&&(c=new zt(new nn(1,1,1),new Pe({name:"BackgroundCubeMaterial",uniforms:As(Dn.backgroundCube.uniforms),vertexShader:Dn.backgroundCube.vertexShader,fragmentShader:Dn.backgroundCube.fragmentShader,side:We,depthTest:!1,depthWrite:!1,fog:!1,allowOverride:!1})),c.geometry.deleteAttribute("normal"),c.geometry.deleteAttribute("uv"),c.onBeforeRender=function(M,w,C){this.matrixWorld.copyPosition(C.matrixWorld)},Object.defineProperty(c.material,"envMap",{get:function(){return this.uniforms.envMap.value}}),n.update(c)),c.material.uniforms.envMap.value=y,c.material.uniforms.backgroundBlurriness.value=E.backgroundBlurriness,c.material.uniforms.backgroundIntensity.value=E.backgroundIntensity,c.material.uniforms.backgroundRotation.value.setFromMatrix4(Og.makeRotationFromEuler(E.backgroundRotation)).transpose(),y.isCubeTexture&&y.isRenderTargetTexture===!1&&c.material.uniforms.backgroundRotation.value.premultiply(ru),c.material.toneMapped=Jt.getTransfer(y.colorSpace)!==se,(u!==y||h!==y.version||d!==s.toneMapping)&&(c.material.needsUpdate=!0,u=y,h=y.version,d=s.toneMapping),c.layers.enableAll(),b.unshift(c,c.geometry,c.material,0,0,null)):y&&y.isTexture&&(l===void 0&&(l=new zt(new Xe(2,2),new Pe({name:"BackgroundMaterial",uniforms:As(Dn.background.uniforms),vertexShader:Dn.background.vertexShader,fragmentShader:Dn.background.fragmentShader,side:oi,depthTest:!1,depthWrite:!1,fog:!1,allowOverride:!1})),l.geometry.deleteAttribute("normal"),Object.defineProperty(l.material,"map",{get:function(){return this.uniforms.t2D.value}}),n.update(l)),l.material.uniforms.t2D.value=y,l.material.uniforms.backgroundIntensity.value=E.backgroundIntensity,l.material.toneMapped=Jt.getTransfer(y.colorSpace)!==se,y.matrixAutoUpdate===!0&&y.updateMatrix(),l.material.uniforms.uvTransform.value.copy(y.matrix),(u!==y||h!==y.version||d!==s.toneMapping)&&(l.material.needsUpdate=!0,u=y,h=y.version,d=s.toneMapping),l.layers.enableAll(),b.unshift(l,l.geometry,l.material,0,0,null))}function m(b,E){b.getRGB(mo,qh(s)),e.buffers.color.setClear(mo.r,mo.g,mo.b,E,r)}function g(){c!==void 0&&(c.geometry.dispose(),c.material.dispose(),c=void 0),l!==void 0&&(l.geometry.dispose(),l.material.dispose(),l=void 0)}return{getClearColor:function(){return o},setClearColor:function(b,E=1){o.set(b),a=E,m(o,a)},getClearAlpha:function(){return a},setClearAlpha:function(b){a=b,m(o,a)},render:p,addToRenderList:x,dispose:g}}function Bg(s,t){const e=s.getParameter(s.MAX_VERTEX_ATTRIBS),n={},i=d(null);let r=i,o=!1;function a(D,U,Y,K,N){let B=!1;const z=h(D,K,Y,U);r!==z&&(r=z,c(r.object)),B=f(D,K,Y,N),B&&p(D,K,Y,N),N!==null&&t.update(N,s.ELEMENT_ARRAY_BUFFER),(B||o)&&(o=!1,y(D,U,Y,K),N!==null&&s.bindBuffer(s.ELEMENT_ARRAY_BUFFER,t.get(N).buffer))}function l(){return s.createVertexArray()}function c(D){return s.bindVertexArray(D)}function u(D){return s.deleteVertexArray(D)}function h(D,U,Y,K){const N=K.wireframe===!0;let B=n[U.id];B===void 0&&(B={},n[U.id]=B);const z=D.isInstancedMesh===!0?D.id:0;let Z=B[z];Z===void 0&&(Z={},B[z]=Z);let nt=Z[Y.id];nt===void 0&&(nt={},Z[Y.id]=nt);let rt=nt[N];return rt===void 0&&(rt=d(l()),nt[N]=rt),rt}function d(D){const U=[],Y=[],K=[];for(let N=0;N=0){const ot=N[nt];let ht=B[nt];if(ht===void 0&&(nt==="instanceMatrix"&&D.instanceMatrix&&(ht=D.instanceMatrix),nt==="instanceColor"&&D.instanceColor&&(ht=D.instanceColor)),ot===void 0||ot.attribute!==ht||ht&&ot.data!==ht.data)return!0;z++}return r.attributesNum!==z||r.index!==K}function p(D,U,Y,K){const N={},B=U.attributes;let z=0;const Z=Y.getAttributes();for(const nt in Z)if(Z[nt].location>=0){let ot=B[nt];ot===void 0&&(nt==="instanceMatrix"&&D.instanceMatrix&&(ot=D.instanceMatrix),nt==="instanceColor"&&D.instanceColor&&(ot=D.instanceColor));const ht={};ht.attribute=ot,ot&&ot.data&&(ht.data=ot.data),N[nt]=ht,z++}r.attributes=N,r.attributesNum=z,r.index=K}function x(){const D=r.newAttributes;for(let U=0,Y=D.length;U=0){let rt=N[Z];if(rt===void 0&&(Z==="instanceMatrix"&&D.instanceMatrix&&(rt=D.instanceMatrix),Z==="instanceColor"&&D.instanceColor&&(rt=D.instanceColor)),rt!==void 0){const ot=rt.normalized,ht=rt.itemSize,Gt=t.get(rt);if(Gt===void 0)continue;const me=Gt.buffer,ee=Gt.type,Q=Gt.bytesPerElement,I=ee===s.INT||ee===s.UNSIGNED_INT||rt.gpuType===ga;if(rt.isInterleavedBufferAttribute){const X=rt.data,st=X.stride,dt=rt.offset;if(X.isInstancedInterleavedBuffer){for(let lt=0;lt0&&s.getShaderPrecisionFormat(s.FRAGMENT_SHADER,s.HIGH_FLOAT).precision>0)return"highp";C="mediump"}return C==="mediump"&&s.getShaderPrecisionFormat(s.VERTEX_SHADER,s.MEDIUM_FLOAT).precision>0&&s.getShaderPrecisionFormat(s.FRAGMENT_SHADER,s.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}let c=e.precision!==void 0?e.precision:"highp";const u=l(c);u!==c&&(Ut("WebGLRenderer:",c,"not supported, using",u,"instead."),c=u);const h=e.logarithmicDepthBuffer===!0,d=e.reversedDepthBuffer===!0&&t.has("EXT_clip_control");e.reversedDepthBuffer===!0&&d===!1&&Ut("WebGLRenderer: Unable to use reversed depth buffer due to missing EXT_clip_control extension. Fallback to default depth buffer.");const f=s.getParameter(s.MAX_TEXTURE_IMAGE_UNITS),p=s.getParameter(s.MAX_VERTEX_TEXTURE_IMAGE_UNITS),x=s.getParameter(s.MAX_TEXTURE_SIZE),m=s.getParameter(s.MAX_CUBE_MAP_TEXTURE_SIZE),g=s.getParameter(s.MAX_VERTEX_ATTRIBS),b=s.getParameter(s.MAX_VERTEX_UNIFORM_VECTORS),E=s.getParameter(s.MAX_VARYING_VECTORS),y=s.getParameter(s.MAX_FRAGMENT_UNIFORM_VECTORS),M=s.getParameter(s.MAX_SAMPLES),w=s.getParameter(s.SAMPLES);return{isWebGL2:!0,getMaxAnisotropy:r,getMaxPrecision:l,textureFormatReadable:o,textureTypeReadable:a,precision:c,logarithmicDepthBuffer:h,reversedDepthBuffer:d,maxTextures:f,maxVertexTextures:p,maxTextureSize:x,maxCubemapSize:m,maxAttributes:g,maxVertexUniforms:b,maxVaryings:E,maxFragmentUniforms:y,maxSamples:M,samples:w}}function Gg(s){const t=this;let e=null,n=0,i=!1,r=!1;const o=new pi,a=new Ht,l={value:null,needsUpdate:!1};this.uniform=l,this.numPlanes=0,this.numIntersection=0,this.init=function(h,d){const f=h.length!==0||d||n!==0||i;return i=d,n=h.length,f},this.beginShadows=function(){r=!0,u(null)},this.endShadows=function(){r=!1},this.setGlobalState=function(h,d){e=u(h,d,0)},this.setState=function(h,d,f){const p=h.clippingPlanes,x=h.clipIntersection,m=h.clipShadows,g=s.get(h);if(!i||p===null||p.length===0||r&&!m)r?u(null):c();else{const b=r?0:n,E=b*4;let y=g.clippingState||null;l.value=y,y=u(p,d,E,f);for(let M=0;M!==E;++M)y[M]=e[M];g.clippingState=y,this.numIntersection=x?this.numPlanes:0,this.numPlanes+=b}};function c(){l.value!==e&&(l.value=e,l.needsUpdate=n>0),t.numPlanes=n,t.numIntersection=0}function u(h,d,f,p){const x=h!==null?h.length:0;let m=null;if(x!==0){if(m=l.value,p!==!0||m===null){const g=f+x*4,b=d.matrixWorldInverse;a.getNormalMatrix(b),(m===null||m.length0&&this._blur(l,0,0,e),this._applyPMREM(l),this._cleanup(l),l}fromEquirectangular(t,e=null){return this._fromTexture(t,e)}fromCubemap(t,e=null){return this._fromTexture(t,e)}compileCubemapShader(){this._cubemapMaterial===null&&(this._cubemapMaterial=uu(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){this._equirectMaterial===null&&(this._equirectMaterial=hu(),this._compileMaterial(this._equirectMaterial))}dispose(){this._dispose(),this._cubemapMaterial!==null&&this._cubemapMaterial.dispose(),this._equirectMaterial!==null&&this._equirectMaterial.dispose(),this._backgroundBox!==null&&(this._backgroundBox.geometry.dispose(),this._backgroundBox.material.dispose())}_setSize(t){this._lodMax=Math.floor(Math.log2(t)),this._cubeSize=Math.pow(2,this._lodMax)}_dispose(){this._blurMaterial!==null&&this._blurMaterial.dispose(),this._ggxMaterial!==null&&this._ggxMaterial.dispose(),this._pingPongRenderTarget!==null&&this._pingPongRenderTarget.dispose();for(let t=0;t2?M:0,M,M),h.setRenderTarget(i),g&&h.render(x,l),h.render(t,l)}h.toneMapping=f,h.autoClear=d,t.background=b}_textureToCubeUV(t,e){const n=this._renderer,i=t.mapping===Ii||t.mapping===os;i?(this._cubemapMaterial===null&&(this._cubemapMaterial=uu()),this._cubemapMaterial.uniforms.flipEnvMap.value=t.isRenderTargetTexture===!1?-1:1):this._equirectMaterial===null&&(this._equirectMaterial=hu());const r=i?this._cubemapMaterial:this._equirectMaterial,o=this._lodMeshes[0];o.material=r;const a=r.uniforms;a.envMap.value=t;const l=this._cubeSize;Ps(e,0,0,3*l,2*l),n.setRenderTarget(e),n.render(o,cr)}_applyPMREM(t){const e=this._renderer,n=e.autoClear;e.autoClear=!1;const i=this._lodMeshes.length;for(let r=1;rp-vi?n-p+vi:0),g=4*(this._cubeSize-x);l.envMap.value=t.texture,l.roughness.value=f,l.mipInt.value=p-e,Ps(r,m,g,3*x,2*x),i.setRenderTarget(r),i.render(a,cr),l.envMap.value=r.texture,l.roughness.value=0,l.mipInt.value=p-n,Ps(t,m,g,3*x,2*x),i.setRenderTarget(t),i.render(a,cr)}_blur(t,e,n,i,r){const o=this._pingPongRenderTarget;this._halfBlur(t,o,e,n,i,"latitudinal",r),this._halfBlur(o,t,n,n,i,"longitudinal",r)}_halfBlur(t,e,n,i,r,o,a){const l=this._renderer,c=this._blurMaterial;o!=="latitudinal"&&o!=="longitudinal"&&te("blur direction must be either latitudinal or longitudinal!");const u=3,h=this._lodMeshes[i];h.material=c;const d=c.uniforms,f=this._sizeLods[n]-1,p=isFinite(r)?Math.PI/(2*f):2*Math.PI/(2*Gi-1),x=r/p,m=isFinite(r)?1+Math.floor(u*x):Gi;m>Gi&&Ut(`sigmaRadians, ${r}, is too large and will clip, as it requested ${m} samples when the maximum is set to ${Gi}`);const g=[];let b=0;for(let C=0;CE-vi?i-E+vi:0),w=4*(this._cubeSize-y);Ps(e,M,w,3*y,2*y),l.setRenderTarget(e),l.render(h,cr)}}function $g(s){const t=[],e=[],n=[];let i=s;const r=s-vi+1+ou.length;for(let o=0;os-vi?l=ou[o-s+vi-1]:o===0&&(l=0),e.push(l);const c=1/(a-2),u=-c,h=1+c,d=[u,u,h,u,h,h,u,u,h,h,u,h],f=6,p=6,x=3,m=2,g=1,b=new Float32Array(x*p*f),E=new Float32Array(m*p*f),y=new Float32Array(g*p*f);for(let w=0;w2?0:-1,T=[C,v,0,C+2/3,v,0,C+2/3,v+1,0,C,v,0,C+2/3,v+1,0,C,v+1,0];b.set(T,x*p*w),E.set(d,m*p*w);const L=[w,w,w,w,w,w];y.set(L,g*p*w)}const M=new He;M.setAttribute("position",new ln(b,x)),M.setAttribute("uv",new ln(E,m)),M.setAttribute("faceIndex",new ln(y,g)),n.push(new zt(M,null)),i>vi&&i--}return{lodMeshes:n,sizeLods:t,sigmas:e}}function cu(s,t,e){const n=new Ye(s,t,e);return n.texture.mapping=Cr,n.texture.name="PMREM.cubeUv",n.scissorTest=!0,n}function Ps(s,t,e,n,i){s.viewport.set(t,e,n,i),s.scissor.set(t,e,n,i)}function Xg(s,t,e){return new Pe({name:"PMREMGGXConvolution",defines:{GGX_SAMPLES:Vg,CUBEUV_TEXEL_WIDTH:1/t,CUBEUV_TEXEL_HEIGHT:1/e,CUBEUV_MAX_MIP:`${s}.0`},uniforms:{envMap:{value:null},roughness:{value:0},mipInt:{value:0}},vertexShader:go(),fragmentShader:` precision highp float; precision highp int; @@ -3780,7 +3780,7 @@ void main() { gl_FragColor = vec4(prefilteredColor, 1.0); } - `,blending:wn,depthTest:!1,depthWrite:!1})}function Lg(s,t,e){const n=new Float32Array(Ni),i=new C(0,1,0);return new Ce({name:"SphericalGaussianBlur",defines:{n:Ni,CUBEUV_TEXEL_WIDTH:1/t,CUBEUV_TEXEL_HEIGHT:1/e,CUBEUV_MAX_MIP:`${s}.0`},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:n},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:i}},vertexShader:Yr(),fragmentShader:` + `,blending:Tn,depthTest:!1,depthWrite:!1})}function qg(s,t,e){const n=new Float32Array(Gi),i=new P(0,1,0);return new Pe({name:"SphericalGaussianBlur",defines:{n:Gi,CUBEUV_TEXEL_WIDTH:1/t,CUBEUV_TEXEL_HEIGHT:1/e,CUBEUV_MAX_MIP:`${s}.0`},uniforms:{envMap:{value:null},samples:{value:1},weights:{value:n},latitudinal:{value:!1},dTheta:{value:0},mipInt:{value:0},poleAxis:{value:i}},vertexShader:go(),fragmentShader:` precision mediump float; precision mediump int; @@ -3840,7 +3840,7 @@ void main() { } } - `,blending:wn,depthTest:!1,depthWrite:!1})}function Mh(){return new Ce({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:Yr(),fragmentShader:` + `,blending:Tn,depthTest:!1,depthWrite:!1})}function hu(){return new Pe({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:go(),fragmentShader:` precision mediump float; precision mediump int; @@ -3859,7 +3859,7 @@ void main() { gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); } - `,blending:wn,depthTest:!1,depthWrite:!1})}function yh(){return new Ce({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:Yr(),fragmentShader:` + `,blending:Tn,depthTest:!1,depthWrite:!1})}function uu(){return new Pe({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:go(),fragmentShader:` precision mediump float; precision mediump int; @@ -3875,7 +3875,7 @@ void main() { gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); } - `,blending:wn,depthTest:!1,depthWrite:!1})}function Yr(){return` + `,blending:Tn,depthTest:!1,depthWrite:!1})}function go(){return` precision mediump float; precision mediump int; @@ -3930,7 +3930,7 @@ void main() { gl_Position = vec4( position, 1.0 ); } - `}class Sh extends Xe{constructor(t=1,e={}){super(t,t,e),this.isWebGLCubeRenderTarget=!0;const n={width:t,height:t,depth:1},i=[n,n,n,n,n,n];this.texture=new Yc(i),this._setTextureOptions(e),this.texture.isRenderTargetTexture=!0}fromEquirectangularTexture(t,e){this.texture.type=e.type,this.texture.colorSpace=e.colorSpace,this.texture.generateMipmaps=e.generateMipmaps,this.texture.minFilter=e.minFilter,this.texture.magFilter=e.magFilter;const n={uniforms:{tEquirect:{value:null}},vertexShader:` + `}class du extends Ye{constructor(t=1,e={}){super(t,t,e),this.isWebGLCubeRenderTarget=!0;const n={width:t,height:t,depth:1},i=[n,n,n,n,n,n];this.texture=new kh(i),this._setTextureOptions(e),this.texture.isRenderTargetTexture=!0}fromEquirectangularTexture(t,e){this.texture.type=e.type,this.texture.colorSpace=e.colorSpace,this.texture.generateMipmaps=e.generateMipmaps,this.texture.minFilter=e.minFilter,this.texture.magFilter=e.magFilter;const n={uniforms:{tEquirect:{value:null}},vertexShader:` varying vec3 vWorldDirection; @@ -3965,7 +3965,7 @@ void main() { gl_FragColor = texture2D( tEquirect, sampleUV ); } - `},i=new tn(5,5,5),r=new Ce({name:"CubemapFromEquirect",uniforms:ds(n.uniforms),vertexShader:n.vertexShader,fragmentShader:n.fragmentShader,side:Ge,blending:wn});r.uniforms.tEquirect.value=e;const a=new Bt(i,r),o=e.minFilter;return e.minFilter===Ti&&(e.minFilter=Ue),new dp(1,10,this).update(t,a),e.minFilter=o,a.geometry.dispose(),a.material.dispose(),this}clear(t,e=!0,n=!0,i=!0){const r=t.getRenderTarget();for(let a=0;a<6;a++)t.setRenderTarget(this,a),t.clear(e,n,i);t.setRenderTarget(r)}}function Dg(s){let t=new WeakMap,e=new WeakMap,n=null;function i(d,f=!1){return d==null?null:f?a(d):r(d)}function r(d){if(d&&d.isTexture){const f=d.mapping;if(f===Fa||f===Oa)if(t.has(d)){const p=t.get(d).texture;return o(p,d.mapping)}else{const p=d.image;if(p&&p.height>0){const v=new Sh(p.height);return v.fromEquirectangularTexture(s,d),t.set(d,v),d.addEventListener("dispose",c),o(v.texture,d.mapping)}else return null}}return d}function a(d){if(d&&d.isTexture){const f=d.mapping,p=f===Fa||f===Oa,v=f===Ei||f===$i;if(p||v){let m=e.get(d);const g=m!==void 0?m.texture.pmremVersion:0;if(d.isRenderTargetTexture&&d.pmremVersion!==g)return n===null&&(n=new xh(s)),m=p?n.fromEquirectangular(d,m):n.fromCubemap(d,m),m.texture.pmremVersion=d.pmremVersion,e.set(d,m),m.texture;if(m!==void 0)return m.texture;{const w=d.image;return p&&w&&w.height>0||v&&w&&l(w)?(n===null&&(n=new xh(s)),m=p?n.fromEquirectangular(d):n.fromCubemap(d),m.texture.pmremVersion=d.pmremVersion,e.set(d,m),d.addEventListener("dispose",u),m.texture):null}}}return d}function o(d,f){return f===Fa?d.mapping=Ei:f===Oa&&(d.mapping=$i),d}function l(d){let f=0;const p=6;for(let v=0;v=65535?Fc:Uc)(d,1);m.version=v;const g=r.get(h);g&&t.remove(g),r.set(h,m)}function u(h){const d=r.get(h);if(d){const f=h.index;f!==null&&d.versiont.maxTextureSize&&(S=Math.ceil(M/t.maxTextureSize),M=t.maxTextureSize);const b=new Float32Array(M*S*4*h),R=new Ec(b,M,S,h);R.type=un,R.needsUpdate=!0;const x=E*4;for(let P=0;P0){const x=new du(p.height);return x.fromEquirectangularTexture(s,d),t.set(d,x),d.addEventListener("dispose",c),a(x.texture,d.mapping)}else return null}}return d}function o(d){if(d&&d.isTexture){const f=d.mapping,p=f===da||f===fa,x=f===Ii||f===os;if(p||x){let m=e.get(d);const g=m!==void 0?m.texture.pmremVersion:0;if(d.isRenderTargetTexture&&d.pmremVersion!==g)return n===null&&(n=new lu(s)),m=p?n.fromEquirectangular(d,m):n.fromCubemap(d,m),m.texture.pmremVersion=d.pmremVersion,e.set(d,m),m.texture;if(m!==void 0)return m.texture;{const b=d.image;return p&&b&&b.height>0||x&&b&&l(b)?(n===null&&(n=new lu(s)),m=p?n.fromEquirectangular(d):n.fromCubemap(d),m.texture.pmremVersion=d.pmremVersion,e.set(d,m),d.addEventListener("dispose",u),m.texture):null}}}return d}function a(d,f){return f===da?d.mapping=Ii:f===fa&&(d.mapping=os),d}function l(d){let f=0;const p=6;for(let x=0;x=65535?Th:Eh)(d,1);m.version=x;const g=r.get(h);g&&t.remove(g),r.set(h,m)}function u(h){const d=r.get(h);if(d){const f=h.index;f!==null&&d.versiont.maxTextureSize&&(M=Math.ceil(y/t.maxTextureSize),y=t.maxTextureSize);const w=new Float32Array(y*M*4*h),C=new mh(w,y,M,h);C.type=mn,C.needsUpdate=!0;const v=E*4;for(let L=0;L0&&g[0].isRenderPass===!0;const M=a.width,S=a.height;for(let b=0;b0)return s;const i=t*e;let r=Ah[i];if(r===void 0&&(r=new Float32Array(i),Ah[i]=r),t!==0){n.toArray(r,0);for(let a=1,o=0;a!==t;++a)o+=e,s[a].toArray(r,o)}return r}function Re(s,t){if(s.length!==t.length)return!1;for(let e=0,n=s.length;e0&&(this.seq=i.concat(r))}setValue(t,e,n,i){const r=this.map[e];r!==void 0&&r.setValue(t,n,i)}setOptional(t,e,n){const i=e[n];i!==void 0&&this.setValue(t,n,i)}static upload(t,e,n,i){for(let r=0,a=e.length;r!==a;++r){const o=e[r],l=n[o.id];l.needsUpdate!==!1&&o.setValue(t,l.value,i)}}static seqWithValue(t,e){const n=[];for(let i=0,r=t.length;i!==r;++i){const a=t[i];a.id in e&&n.push(a)}return n}}function Ih(s,t,e){const n=s.createShader(t);return s.shaderSource(n,e),s.compileShader(n),n}const L0=37297;let D0=0;function I0(s,t){const e=s.split(` -`),n=[],i=Math.max(t-6,0),r=Math.min(t+6,e.length);for(let a=i;a":" "} ${o}: ${e[a]}`)}return n.join(` -`)}const Nh=new zt;function N0(s){Kt._getMatrix(Nh,Kt.workingColorSpace,s);const t=`mat3( ${Nh.elements.map(e=>e.toFixed(4))} )`;switch(Kt.getTransfer(s)){case gr:return[t,"LinearTransferOETF"];case ie:return[t,"sRGBTransferOETF"];default:return Nt("WebGLProgram: Unsupported color space: ",s),[t,"LinearTransferOETF"]}}function Uh(s,t,e){const n=s.getShaderParameter(t,s.COMPILE_STATUS),r=(s.getShaderInfoLog(t)||"").trim();if(n&&r==="")return"";const a=/ERROR: 0:(\d+)/.exec(r);if(a){const o=parseInt(a[1]);return e.toUpperCase()+` + }`,depthTest:!1,depthWrite:!1}),u=new zt(l,c),h=new po(-1,1,1,-1,0,1);let d=null,f=null,p=!1,x,m=null,g=[],b=!1;this.setSize=function(E,y){o.setSize(E,y),a.setSize(E,y);for(let M=0;M0&&g[0].isRenderPass===!0;const y=o.width,M=o.height;for(let w=0;w0)return s;const i=t*e;let r=xu[i];if(r===void 0&&(r=new Float32Array(i),xu[i]=r),t!==0){n.toArray(r,0);for(let o=1,a=0;o!==t;++o)a+=e,s[o].toArray(r,a)}return r}function Le(s,t){if(s.length!==t.length)return!1;for(let e=0,n=s.length;e0&&(this.seq=i.concat(r))}setValue(t,e,n,i){const r=this.map[e];r!==void 0&&r.setValue(t,n,i)}setOptional(t,e,n){const i=e[n];i!==void 0&&this.setValue(t,n,i)}static upload(t,e,n,i){for(let r=0,o=e.length;r!==o;++r){const a=e[r],l=n[a.id];l.needsUpdate!==!1&&a.setValue(t,l.value,i)}}static seqWithValue(t,e){const n=[];for(let i=0,r=t.length;i!==r;++i){const o=t[i];o.id in e&&n.push(o)}return n}}function Su(s,t,e){const n=s.createShader(t);return s.shaderSource(n,e),s.compileShader(n),n}const qx=37297;let Yx=0;function Kx(s,t){const e=s.split(` +`),n=[],i=Math.max(t-6,0),r=Math.min(t+6,e.length);for(let o=i;o":" "} ${a}: ${e[o]}`)}return n.join(` +`)}const wu=new Ht;function Zx(s){Jt._getMatrix(wu,Jt.workingColorSpace,s);const t=`mat3( ${wu.elements.map(e=>e.toFixed(4))} )`;switch(Jt.getTransfer(s)){case Or:return[t,"LinearTransferOETF"];case se:return[t,"sRGBTransferOETF"];default:return Ut("WebGLProgram: Unsupported color space: ",s),[t,"LinearTransferOETF"]}}function Eu(s,t,e){const n=s.getShaderParameter(t,s.COMPILE_STATUS),r=(s.getShaderInfoLog(t)||"").trim();if(n&&r==="")return"";const o=/ERROR: 0:(\d+)/.exec(r);if(o){const a=parseInt(o[1]);return e.toUpperCase()+` `+r+` -`+I0(s.getShaderSource(t),o)}else return r}function U0(s,t){const e=N0(t);return[`vec4 ${s}( vec4 value ) {`,` return ${e[1]}( vec4( value.rgb * ${e[0]}, value.a ) );`,"}"].join(` -`)}const F0={[Pa]:"Linear",[La]:"Reinhard",[Da]:"Cineon",[ar]:"ACESFilmic",[Na]:"AgX",[Ua]:"Neutral",[Ia]:"Custom"};function O0(s,t){const e=F0[t];return e===void 0?(Nt("WebGLProgram: Unsupported toneMapping:",t),"vec3 "+s+"( vec3 color ) { return LinearToneMapping( color ); }"):"vec3 "+s+"( vec3 color ) { return "+e+"ToneMapping( color ); }"}const Jr=new C;function k0(){Kt.getLuminanceCoefficients(Jr);const s=Jr.x.toFixed(4),t=Jr.y.toFixed(4),e=Jr.z.toFixed(4);return["float luminance( const in vec3 rgb ) {",` const vec3 weights = vec3( ${s}, ${t}, ${e} );`," return dot( weights, rgb );","}"].join(` -`)}function B0(s){return[s.extensionClipCullDistance?"#extension GL_ANGLE_clip_cull_distance : require":"",s.extensionMultiDraw?"#extension GL_ANGLE_multi_draw : require":""].filter(qs).join(` -`)}function z0(s){const t=[];for(const e in s){const n=s[e];n!==!1&&t.push("#define "+e+" "+n)}return t.join(` -`)}function H0(s,t){const e={},n=s.getProgramParameter(t,s.ACTIVE_ATTRIBUTES);for(let i=0;i/gm;function gl(s){return s.replace(G0,W0)}const V0=new Map;function W0(s,t){let e=Xt[t];if(e===void 0){const n=V0.get(t);if(n!==void 0)e=Xt[n],Nt('WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',t,n);else throw new Error("THREE.WebGLProgram: Can not resolve #include <"+t+">")}return gl(e)}const $0=/#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;function kh(s){return s.replace($0,X0)}function X0(s,t,e,n){let i="";for(let r=parseInt(t);r/gm;function $l(s){return s.replace(sv,ov)}const rv=new Map;function ov(s,t){let e=Yt[t];if(e===void 0){const n=rv.get(t);if(n!==void 0)e=Yt[n],Ut('WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',t,n);else throw new Error("THREE.WebGLProgram: Can not resolve #include <"+t+">")}return $l(e)}const av=/#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*i\s*\+\+\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g;function Cu(s){return s.replace(av,lv)}function lv(s,t,e,n){let i="";for(let r=parseInt(t);r0&&(m+=` -`),g=["#define SHADER_TYPE "+e.shaderType,"#define SHADER_NAME "+e.shaderName,p].filter(qs).join(` +`),g=["#define SHADER_TYPE "+e.shaderType,"#define SHADER_NAME "+e.shaderName,p].filter(hr).join(` `),g.length>0&&(g+=` -`)):(m=[Bh(e),"#define SHADER_TYPE "+e.shaderType,"#define SHADER_NAME "+e.shaderName,p,e.extensionClipCullDistance?"#define USE_CLIP_DISTANCE":"",e.batching?"#define USE_BATCHING":"",e.batchingColor?"#define USE_BATCHING_COLOR":"",e.instancing?"#define USE_INSTANCING":"",e.instancingColor?"#define USE_INSTANCING_COLOR":"",e.instancingMorph?"#define USE_INSTANCING_MORPH":"",e.useFog&&e.fog?"#define USE_FOG":"",e.useFog&&e.fogExp2?"#define FOG_EXP2":"",e.map?"#define USE_MAP":"",e.envMap?"#define USE_ENVMAP":"",e.envMap?"#define "+u:"",e.lightMap?"#define USE_LIGHTMAP":"",e.aoMap?"#define USE_AOMAP":"",e.bumpMap?"#define USE_BUMPMAP":"",e.normalMap?"#define USE_NORMALMAP":"",e.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",e.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",e.displacementMap?"#define USE_DISPLACEMENTMAP":"",e.emissiveMap?"#define USE_EMISSIVEMAP":"",e.anisotropy?"#define USE_ANISOTROPY":"",e.anisotropyMap?"#define USE_ANISOTROPYMAP":"",e.clearcoatMap?"#define USE_CLEARCOATMAP":"",e.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",e.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",e.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",e.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",e.specularMap?"#define USE_SPECULARMAP":"",e.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",e.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",e.roughnessMap?"#define USE_ROUGHNESSMAP":"",e.metalnessMap?"#define USE_METALNESSMAP":"",e.alphaMap?"#define USE_ALPHAMAP":"",e.alphaHash?"#define USE_ALPHAHASH":"",e.transmission?"#define USE_TRANSMISSION":"",e.transmissionMap?"#define USE_TRANSMISSIONMAP":"",e.thicknessMap?"#define USE_THICKNESSMAP":"",e.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",e.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",e.mapUv?"#define MAP_UV "+e.mapUv:"",e.alphaMapUv?"#define ALPHAMAP_UV "+e.alphaMapUv:"",e.lightMapUv?"#define LIGHTMAP_UV "+e.lightMapUv:"",e.aoMapUv?"#define AOMAP_UV "+e.aoMapUv:"",e.emissiveMapUv?"#define EMISSIVEMAP_UV "+e.emissiveMapUv:"",e.bumpMapUv?"#define BUMPMAP_UV "+e.bumpMapUv:"",e.normalMapUv?"#define NORMALMAP_UV "+e.normalMapUv:"",e.displacementMapUv?"#define DISPLACEMENTMAP_UV "+e.displacementMapUv:"",e.metalnessMapUv?"#define METALNESSMAP_UV "+e.metalnessMapUv:"",e.roughnessMapUv?"#define ROUGHNESSMAP_UV "+e.roughnessMapUv:"",e.anisotropyMapUv?"#define ANISOTROPYMAP_UV "+e.anisotropyMapUv:"",e.clearcoatMapUv?"#define CLEARCOATMAP_UV "+e.clearcoatMapUv:"",e.clearcoatNormalMapUv?"#define CLEARCOAT_NORMALMAP_UV "+e.clearcoatNormalMapUv:"",e.clearcoatRoughnessMapUv?"#define CLEARCOAT_ROUGHNESSMAP_UV "+e.clearcoatRoughnessMapUv:"",e.iridescenceMapUv?"#define IRIDESCENCEMAP_UV "+e.iridescenceMapUv:"",e.iridescenceThicknessMapUv?"#define IRIDESCENCE_THICKNESSMAP_UV "+e.iridescenceThicknessMapUv:"",e.sheenColorMapUv?"#define SHEEN_COLORMAP_UV "+e.sheenColorMapUv:"",e.sheenRoughnessMapUv?"#define SHEEN_ROUGHNESSMAP_UV "+e.sheenRoughnessMapUv:"",e.specularMapUv?"#define SPECULARMAP_UV "+e.specularMapUv:"",e.specularColorMapUv?"#define SPECULAR_COLORMAP_UV "+e.specularColorMapUv:"",e.specularIntensityMapUv?"#define SPECULAR_INTENSITYMAP_UV "+e.specularIntensityMapUv:"",e.transmissionMapUv?"#define TRANSMISSIONMAP_UV "+e.transmissionMapUv:"",e.thicknessMapUv?"#define THICKNESSMAP_UV "+e.thicknessMapUv:"",e.vertexTangents&&e.flatShading===!1?"#define USE_TANGENT":"",e.vertexNormals?"#define HAS_NORMAL":"",e.vertexColors?"#define USE_COLOR":"",e.vertexAlphas?"#define USE_COLOR_ALPHA":"",e.vertexUv1s?"#define USE_UV1":"",e.vertexUv2s?"#define USE_UV2":"",e.vertexUv3s?"#define USE_UV3":"",e.pointsUvs?"#define USE_POINTS_UV":"",e.flatShading?"#define FLAT_SHADED":"",e.skinning?"#define USE_SKINNING":"",e.morphTargets?"#define USE_MORPHTARGETS":"",e.morphNormals&&e.flatShading===!1?"#define USE_MORPHNORMALS":"",e.morphColors?"#define USE_MORPHCOLORS":"",e.morphTargetsCount>0?"#define MORPHTARGETS_TEXTURE_STRIDE "+e.morphTextureStride:"",e.morphTargetsCount>0?"#define MORPHTARGETS_COUNT "+e.morphTargetsCount:"",e.doubleSided?"#define DOUBLE_SIDED":"",e.flipSided?"#define FLIP_SIDED":"",e.shadowMapEnabled?"#define USE_SHADOWMAP":"",e.shadowMapEnabled?"#define "+l:"",e.sizeAttenuation?"#define USE_SIZEATTENUATION":"",e.numLightProbes>0?"#define USE_LIGHT_PROBES":"",e.logarithmicDepthBuffer?"#define USE_LOGARITHMIC_DEPTH_BUFFER":"",e.reversedDepthBuffer?"#define USE_REVERSED_DEPTH_BUFFER":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING"," attribute mat4 instanceMatrix;","#endif","#ifdef USE_INSTANCING_COLOR"," attribute vec3 instanceColor;","#endif","#ifdef USE_INSTANCING_MORPH"," uniform sampler2D morphTexture;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_UV1"," attribute vec2 uv1;","#endif","#ifdef USE_UV2"," attribute vec2 uv2;","#endif","#ifdef USE_UV3"," attribute vec2 uv3;","#endif","#ifdef USE_TANGENT"," attribute vec4 tangent;","#endif","#if defined( USE_COLOR_ALPHA )"," attribute vec4 color;","#elif defined( USE_COLOR )"," attribute vec3 color;","#endif","#ifdef USE_SKINNING"," attribute vec4 skinIndex;"," attribute vec4 skinWeight;","#endif",` -`].filter(qs).join(` -`),g=[Bh(e),"#define SHADER_TYPE "+e.shaderType,"#define SHADER_NAME "+e.shaderName,p,e.useFog&&e.fog?"#define USE_FOG":"",e.useFog&&e.fogExp2?"#define FOG_EXP2":"",e.alphaToCoverage?"#define ALPHA_TO_COVERAGE":"",e.map?"#define USE_MAP":"",e.matcap?"#define USE_MATCAP":"",e.envMap?"#define USE_ENVMAP":"",e.envMap?"#define "+c:"",e.envMap?"#define "+u:"",e.envMap?"#define "+h:"",d?"#define CUBEUV_TEXEL_WIDTH "+d.texelWidth:"",d?"#define CUBEUV_TEXEL_HEIGHT "+d.texelHeight:"",d?"#define CUBEUV_MAX_MIP "+d.maxMip+".0":"",e.lightMap?"#define USE_LIGHTMAP":"",e.aoMap?"#define USE_AOMAP":"",e.bumpMap?"#define USE_BUMPMAP":"",e.normalMap?"#define USE_NORMALMAP":"",e.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",e.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",e.packedNormalMap?"#define USE_PACKED_NORMALMAP":"",e.emissiveMap?"#define USE_EMISSIVEMAP":"",e.anisotropy?"#define USE_ANISOTROPY":"",e.anisotropyMap?"#define USE_ANISOTROPYMAP":"",e.clearcoat?"#define USE_CLEARCOAT":"",e.clearcoatMap?"#define USE_CLEARCOATMAP":"",e.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",e.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",e.dispersion?"#define USE_DISPERSION":"",e.iridescence?"#define USE_IRIDESCENCE":"",e.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",e.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",e.specularMap?"#define USE_SPECULARMAP":"",e.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",e.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",e.roughnessMap?"#define USE_ROUGHNESSMAP":"",e.metalnessMap?"#define USE_METALNESSMAP":"",e.alphaMap?"#define USE_ALPHAMAP":"",e.alphaTest?"#define USE_ALPHATEST":"",e.alphaHash?"#define USE_ALPHAHASH":"",e.sheen?"#define USE_SHEEN":"",e.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",e.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",e.transmission?"#define USE_TRANSMISSION":"",e.transmissionMap?"#define USE_TRANSMISSIONMAP":"",e.thicknessMap?"#define USE_THICKNESSMAP":"",e.vertexTangents&&e.flatShading===!1?"#define USE_TANGENT":"",e.vertexColors||e.instancingColor?"#define USE_COLOR":"",e.vertexAlphas||e.batchingColor?"#define USE_COLOR_ALPHA":"",e.vertexUv1s?"#define USE_UV1":"",e.vertexUv2s?"#define USE_UV2":"",e.vertexUv3s?"#define USE_UV3":"",e.pointsUvs?"#define USE_POINTS_UV":"",e.gradientMap?"#define USE_GRADIENTMAP":"",e.flatShading?"#define FLAT_SHADED":"",e.doubleSided?"#define DOUBLE_SIDED":"",e.flipSided?"#define FLIP_SIDED":"",e.shadowMapEnabled?"#define USE_SHADOWMAP":"",e.shadowMapEnabled?"#define "+l:"",e.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",e.numLightProbes>0?"#define USE_LIGHT_PROBES":"",e.numLightProbeGrids>0?"#define USE_LIGHT_PROBES_GRID":"",e.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",e.decodeVideoTextureEmissive?"#define DECODE_VIDEO_TEXTURE_EMISSIVE":"",e.logarithmicDepthBuffer?"#define USE_LOGARITHMIC_DEPTH_BUFFER":"",e.reversedDepthBuffer?"#define USE_REVERSED_DEPTH_BUFFER":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",e.toneMapping!==En?"#define TONE_MAPPING":"",e.toneMapping!==En?Xt.tonemapping_pars_fragment:"",e.toneMapping!==En?O0("toneMapping",e.toneMapping):"",e.dithering?"#define DITHERING":"",e.opaque?"#define OPAQUE":"",Xt.colorspace_pars_fragment,U0("linearToOutputTexel",e.outputColorSpace),k0(),e.useDepthPacking?"#define DEPTH_PACKING "+e.depthPacking:"",` -`].filter(qs).join(` -`)),a=gl(a),a=Fh(a,e),a=Oh(a,e),o=gl(o),o=Fh(o,e),o=Oh(o,e),a=kh(a),o=kh(o),e.isRawShaderMaterial!==!0&&(w=`#version 300 es +`)):(m=[Ru(e),"#define SHADER_TYPE "+e.shaderType,"#define SHADER_NAME "+e.shaderName,p,e.extensionClipCullDistance?"#define USE_CLIP_DISTANCE":"",e.batching?"#define USE_BATCHING":"",e.batchingColor?"#define USE_BATCHING_COLOR":"",e.instancing?"#define USE_INSTANCING":"",e.instancingColor?"#define USE_INSTANCING_COLOR":"",e.instancingMorph?"#define USE_INSTANCING_MORPH":"",e.useFog&&e.fog?"#define USE_FOG":"",e.useFog&&e.fogExp2?"#define FOG_EXP2":"",e.map?"#define USE_MAP":"",e.envMap?"#define USE_ENVMAP":"",e.envMap?"#define "+u:"",e.lightMap?"#define USE_LIGHTMAP":"",e.aoMap?"#define USE_AOMAP":"",e.bumpMap?"#define USE_BUMPMAP":"",e.normalMap?"#define USE_NORMALMAP":"",e.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",e.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",e.displacementMap?"#define USE_DISPLACEMENTMAP":"",e.emissiveMap?"#define USE_EMISSIVEMAP":"",e.anisotropy?"#define USE_ANISOTROPY":"",e.anisotropyMap?"#define USE_ANISOTROPYMAP":"",e.clearcoatMap?"#define USE_CLEARCOATMAP":"",e.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",e.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",e.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",e.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",e.specularMap?"#define USE_SPECULARMAP":"",e.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",e.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",e.roughnessMap?"#define USE_ROUGHNESSMAP":"",e.metalnessMap?"#define USE_METALNESSMAP":"",e.alphaMap?"#define USE_ALPHAMAP":"",e.alphaHash?"#define USE_ALPHAHASH":"",e.transmission?"#define USE_TRANSMISSION":"",e.transmissionMap?"#define USE_TRANSMISSIONMAP":"",e.thicknessMap?"#define USE_THICKNESSMAP":"",e.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",e.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",e.mapUv?"#define MAP_UV "+e.mapUv:"",e.alphaMapUv?"#define ALPHAMAP_UV "+e.alphaMapUv:"",e.lightMapUv?"#define LIGHTMAP_UV "+e.lightMapUv:"",e.aoMapUv?"#define AOMAP_UV "+e.aoMapUv:"",e.emissiveMapUv?"#define EMISSIVEMAP_UV "+e.emissiveMapUv:"",e.bumpMapUv?"#define BUMPMAP_UV "+e.bumpMapUv:"",e.normalMapUv?"#define NORMALMAP_UV "+e.normalMapUv:"",e.displacementMapUv?"#define DISPLACEMENTMAP_UV "+e.displacementMapUv:"",e.metalnessMapUv?"#define METALNESSMAP_UV "+e.metalnessMapUv:"",e.roughnessMapUv?"#define ROUGHNESSMAP_UV "+e.roughnessMapUv:"",e.anisotropyMapUv?"#define ANISOTROPYMAP_UV "+e.anisotropyMapUv:"",e.clearcoatMapUv?"#define CLEARCOATMAP_UV "+e.clearcoatMapUv:"",e.clearcoatNormalMapUv?"#define CLEARCOAT_NORMALMAP_UV "+e.clearcoatNormalMapUv:"",e.clearcoatRoughnessMapUv?"#define CLEARCOAT_ROUGHNESSMAP_UV "+e.clearcoatRoughnessMapUv:"",e.iridescenceMapUv?"#define IRIDESCENCEMAP_UV "+e.iridescenceMapUv:"",e.iridescenceThicknessMapUv?"#define IRIDESCENCE_THICKNESSMAP_UV "+e.iridescenceThicknessMapUv:"",e.sheenColorMapUv?"#define SHEEN_COLORMAP_UV "+e.sheenColorMapUv:"",e.sheenRoughnessMapUv?"#define SHEEN_ROUGHNESSMAP_UV "+e.sheenRoughnessMapUv:"",e.specularMapUv?"#define SPECULARMAP_UV "+e.specularMapUv:"",e.specularColorMapUv?"#define SPECULAR_COLORMAP_UV "+e.specularColorMapUv:"",e.specularIntensityMapUv?"#define SPECULAR_INTENSITYMAP_UV "+e.specularIntensityMapUv:"",e.transmissionMapUv?"#define TRANSMISSIONMAP_UV "+e.transmissionMapUv:"",e.thicknessMapUv?"#define THICKNESSMAP_UV "+e.thicknessMapUv:"",e.vertexTangents&&e.flatShading===!1?"#define USE_TANGENT":"",e.vertexNormals?"#define HAS_NORMAL":"",e.vertexColors?"#define USE_COLOR":"",e.vertexAlphas?"#define USE_COLOR_ALPHA":"",e.vertexUv1s?"#define USE_UV1":"",e.vertexUv2s?"#define USE_UV2":"",e.vertexUv3s?"#define USE_UV3":"",e.pointsUvs?"#define USE_POINTS_UV":"",e.flatShading?"#define FLAT_SHADED":"",e.skinning?"#define USE_SKINNING":"",e.morphTargets?"#define USE_MORPHTARGETS":"",e.morphNormals&&e.flatShading===!1?"#define USE_MORPHNORMALS":"",e.morphColors?"#define USE_MORPHCOLORS":"",e.morphTargetsCount>0?"#define MORPHTARGETS_TEXTURE_STRIDE "+e.morphTextureStride:"",e.morphTargetsCount>0?"#define MORPHTARGETS_COUNT "+e.morphTargetsCount:"",e.doubleSided?"#define DOUBLE_SIDED":"",e.flipSided?"#define FLIP_SIDED":"",e.shadowMapEnabled?"#define USE_SHADOWMAP":"",e.shadowMapEnabled?"#define "+l:"",e.sizeAttenuation?"#define USE_SIZEATTENUATION":"",e.numLightProbes>0?"#define USE_LIGHT_PROBES":"",e.logarithmicDepthBuffer?"#define USE_LOGARITHMIC_DEPTH_BUFFER":"",e.reversedDepthBuffer?"#define USE_REVERSED_DEPTH_BUFFER":"","uniform mat4 modelMatrix;","uniform mat4 modelViewMatrix;","uniform mat4 projectionMatrix;","uniform mat4 viewMatrix;","uniform mat3 normalMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;","#ifdef USE_INSTANCING"," attribute mat4 instanceMatrix;","#endif","#ifdef USE_INSTANCING_COLOR"," attribute vec3 instanceColor;","#endif","#ifdef USE_INSTANCING_MORPH"," uniform sampler2D morphTexture;","#endif","attribute vec3 position;","attribute vec3 normal;","attribute vec2 uv;","#ifdef USE_UV1"," attribute vec2 uv1;","#endif","#ifdef USE_UV2"," attribute vec2 uv2;","#endif","#ifdef USE_UV3"," attribute vec2 uv3;","#endif","#ifdef USE_TANGENT"," attribute vec4 tangent;","#endif","#if defined( USE_COLOR_ALPHA )"," attribute vec4 color;","#elif defined( USE_COLOR )"," attribute vec3 color;","#endif","#ifdef USE_SKINNING"," attribute vec4 skinIndex;"," attribute vec4 skinWeight;","#endif",` +`].filter(hr).join(` +`),g=[Ru(e),"#define SHADER_TYPE "+e.shaderType,"#define SHADER_NAME "+e.shaderName,p,e.useFog&&e.fog?"#define USE_FOG":"",e.useFog&&e.fogExp2?"#define FOG_EXP2":"",e.alphaToCoverage?"#define ALPHA_TO_COVERAGE":"",e.map?"#define USE_MAP":"",e.matcap?"#define USE_MATCAP":"",e.envMap?"#define USE_ENVMAP":"",e.envMap?"#define "+c:"",e.envMap?"#define "+u:"",e.envMap?"#define "+h:"",d?"#define CUBEUV_TEXEL_WIDTH "+d.texelWidth:"",d?"#define CUBEUV_TEXEL_HEIGHT "+d.texelHeight:"",d?"#define CUBEUV_MAX_MIP "+d.maxMip+".0":"",e.lightMap?"#define USE_LIGHTMAP":"",e.aoMap?"#define USE_AOMAP":"",e.bumpMap?"#define USE_BUMPMAP":"",e.normalMap?"#define USE_NORMALMAP":"",e.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",e.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",e.packedNormalMap?"#define USE_PACKED_NORMALMAP":"",e.emissiveMap?"#define USE_EMISSIVEMAP":"",e.anisotropy?"#define USE_ANISOTROPY":"",e.anisotropyMap?"#define USE_ANISOTROPYMAP":"",e.clearcoat?"#define USE_CLEARCOAT":"",e.clearcoatMap?"#define USE_CLEARCOATMAP":"",e.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",e.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",e.dispersion?"#define USE_DISPERSION":"",e.iridescence?"#define USE_IRIDESCENCE":"",e.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",e.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",e.specularMap?"#define USE_SPECULARMAP":"",e.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",e.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",e.roughnessMap?"#define USE_ROUGHNESSMAP":"",e.metalnessMap?"#define USE_METALNESSMAP":"",e.alphaMap?"#define USE_ALPHAMAP":"",e.alphaTest?"#define USE_ALPHATEST":"",e.alphaHash?"#define USE_ALPHAHASH":"",e.sheen?"#define USE_SHEEN":"",e.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",e.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",e.transmission?"#define USE_TRANSMISSION":"",e.transmissionMap?"#define USE_TRANSMISSIONMAP":"",e.thicknessMap?"#define USE_THICKNESSMAP":"",e.vertexTangents&&e.flatShading===!1?"#define USE_TANGENT":"",e.vertexColors||e.instancingColor?"#define USE_COLOR":"",e.vertexAlphas||e.batchingColor?"#define USE_COLOR_ALPHA":"",e.vertexUv1s?"#define USE_UV1":"",e.vertexUv2s?"#define USE_UV2":"",e.vertexUv3s?"#define USE_UV3":"",e.pointsUvs?"#define USE_POINTS_UV":"",e.gradientMap?"#define USE_GRADIENTMAP":"",e.flatShading?"#define FLAT_SHADED":"",e.doubleSided?"#define DOUBLE_SIDED":"",e.flipSided?"#define FLIP_SIDED":"",e.shadowMapEnabled?"#define USE_SHADOWMAP":"",e.shadowMapEnabled?"#define "+l:"",e.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",e.numLightProbes>0?"#define USE_LIGHT_PROBES":"",e.numLightProbeGrids>0?"#define USE_LIGHT_PROBES_GRID":"",e.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",e.decodeVideoTextureEmissive?"#define DECODE_VIDEO_TEXTURE_EMISSIVE":"",e.logarithmicDepthBuffer?"#define USE_LOGARITHMIC_DEPTH_BUFFER":"",e.reversedDepthBuffer?"#define USE_REVERSED_DEPTH_BUFFER":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",e.toneMapping!==An?"#define TONE_MAPPING":"",e.toneMapping!==An?Yt.tonemapping_pars_fragment:"",e.toneMapping!==An?Qx("toneMapping",e.toneMapping):"",e.dithering?"#define DITHERING":"",e.opaque?"#define OPAQUE":"",Yt.colorspace_pars_fragment,Jx("linearToOutputTexel",e.outputColorSpace),tv(),e.useDepthPacking?"#define DEPTH_PACKING "+e.depthPacking:"",` +`].filter(hr).join(` +`)),o=$l(o),o=Tu(o,e),o=Au(o,e),a=$l(a),a=Tu(a,e),a=Au(a,e),o=Cu(o),a=Cu(a),e.isRawShaderMaterial!==!0&&(b=`#version 300 es `,m=[f,"#define attribute in","#define varying out","#define texture2D texture"].join(` `)+` -`+m,g=["#define varying in",e.glslVersion===_c?"":"layout(location = 0) out highp vec4 pc_fragColor;",e.glslVersion===_c?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join(` +`+m,g=["#define varying in",e.glslVersion===ah?"":"layout(location = 0) out highp vec4 pc_fragColor;",e.glslVersion===ah?"":"#define gl_FragColor pc_fragColor","#define gl_FragDepthEXT gl_FragDepth","#define texture2D texture","#define textureCube texture","#define texture2DProj textureProj","#define texture2DLodEXT textureLod","#define texture2DProjLodEXT textureProjLod","#define textureCubeLodEXT textureLod","#define texture2DGradEXT textureGrad","#define texture2DProjGradEXT textureProjGrad","#define textureCubeGradEXT textureGrad"].join(` `)+` -`+g);const E=w+m+a,M=w+g+o,S=Ih(i,i.VERTEX_SHADER,E),b=Ih(i,i.FRAGMENT_SHADER,M);i.attachShader(v,S),i.attachShader(v,b),e.index0AttributeName!==void 0?i.bindAttribLocation(v,0,e.index0AttributeName):e.hasPositionAttribute===!0&&i.bindAttribLocation(v,0,"position"),i.linkProgram(v);function R(L){if(s.debug.checkShaderErrors){const F=i.getProgramInfoLog(v)||"",q=i.getShaderInfoLog(S)||"",Y=i.getShaderInfoLog(b)||"",B=F.trim(),K=q.trim(),X=Y.trim();let Q=!0,it=!0;if(i.getProgramParameter(v,i.LINK_STATUS)===!1)if(Q=!1,typeof s.debug.onShaderError=="function")s.debug.onShaderError(i,v,S,b);else{const pt=Uh(i,S,"vertex"),_t=Uh(i,b,"fragment");Qt("WebGLProgram: Shader Error "+i.getError()+" - VALIDATE_STATUS "+i.getProgramParameter(v,i.VALIDATE_STATUS)+` +`+g);const E=b+m+o,y=b+g+a,M=Su(i,i.VERTEX_SHADER,E),w=Su(i,i.FRAGMENT_SHADER,y);i.attachShader(x,M),i.attachShader(x,w),e.index0AttributeName!==void 0?i.bindAttribLocation(x,0,e.index0AttributeName):e.hasPositionAttribute===!0&&i.bindAttribLocation(x,0,"position"),i.linkProgram(x);function C(D){if(s.debug.checkShaderErrors){const U=i.getProgramInfoLog(x)||"",Y=i.getShaderInfoLog(M)||"",K=i.getShaderInfoLog(w)||"",N=U.trim(),B=Y.trim(),z=K.trim();let Z=!0,nt=!0;if(i.getProgramParameter(x,i.LINK_STATUS)===!1)if(Z=!1,typeof s.debug.onShaderError=="function")s.debug.onShaderError(i,x,M,w);else{const rt=Eu(i,M,"vertex"),ot=Eu(i,w,"fragment");te("WebGLProgram: Shader Error "+i.getError()+" - VALIDATE_STATUS "+i.getProgramParameter(x,i.VALIDATE_STATUS)+` -Material Name: `+L.name+` -Material Type: `+L.type+` +Material Name: `+D.name+` +Material Type: `+D.type+` -Program Info Log: `+B+` -`+pt+` -`+_t)}else B!==""?Nt("WebGLProgram: Program Info Log:",B):(K===""||X==="")&&(it=!1);it&&(L.diagnostics={runnable:Q,programLog:B,vertexShader:{log:K,prefix:m},fragmentShader:{log:X,prefix:g}})}i.deleteShader(S),i.deleteShader(b),x=new Zr(i,v),T=H0(i,v)}let x;this.getUniforms=function(){return x===void 0&&R(this),x};let T;this.getAttributes=function(){return T===void 0&&R(this),T};let P=e.rendererExtensionParallelShaderCompile===!1;return this.isReady=function(){return P===!1&&(P=i.getProgramParameter(v,L0)),P},this.destroy=function(){n.releaseStatesOfProgram(this),i.deleteProgram(v),this.program=void 0},this.type=e.shaderType,this.name=e.shaderName,this.id=D0++,this.cacheKey=t,this.usedTimes=1,this.program=v,this.vertexShader=S,this.fragmentShader=b,this}let i_=0;class s_{constructor(){this.shaderCache=new Map,this.materialCache=new Map}update(t,e,n){const i=this._getShaderCacheForMaterial(t);return i.has(e)===!1&&(i.add(e),e.usedTimes++),i.has(n)===!1&&(i.add(n),n.usedTimes++),this}remove(t){const e=this.materialCache.get(t);for(const n of e)n.usedTimes--,n.usedTimes===0&&this.shaderCache.delete(n.code);return this.materialCache.delete(t),this}getVertexShaderStage(t){return this._getShaderStage(t.vertexShader)}getFragmentShaderStage(t){return this._getShaderStage(t.fragmentShader)}dispose(){this.shaderCache.clear(),this.materialCache.clear()}_getShaderCacheForMaterial(t){const e=this.materialCache;let n=e.get(t);return n===void 0&&(n=new Set,e.set(t,n)),n}_getShaderStage(t){const e=this.shaderCache;let n=e.get(t);return n===void 0&&(n=new r_(t),e.set(t,n)),n}}class r_{constructor(t){this.id=i_++,this.code=t,this.usedTimes=0}}function a_(s){return s===Ci||s===pr||s===mr}function o_(s,t,e,n,i,r){const a=new Io,o=new s_,l=new Set,c=[],u=new Map,h=n.logarithmicDepthBuffer;let d=n.precision;const f={MeshDepthMaterial:"depth",MeshDistanceMaterial:"distance",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",MeshToonMaterial:"toon",MeshStandardMaterial:"physical",MeshPhysicalMaterial:"physical",MeshMatcapMaterial:"matcap",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointsMaterial:"points",ShadowMaterial:"shadow",SpriteMaterial:"sprite"};function p(x){return l.add(x),x===0?"uv":`uv${x}`}function v(x,T,P,L,F,q){const Y=L.fog,B=F.geometry,K=x.isMeshStandardMaterial||x.isMeshLambertMaterial||x.isMeshPhongMaterial?L.environment:null,X=x.isMeshStandardMaterial||x.isMeshLambertMaterial&&!x.envMap||x.isMeshPhongMaterial&&!x.envMap,Q=t.get(x.envMap||K,X),it=Q&&Q.mapping===or?Q.image.height:null,pt=f[x.type];x.precision!==null&&(d=n.getMaxPrecision(x.precision),d!==x.precision&&Nt("WebGLProgram.getParameters:",x.precision,"not supported, using",d,"instead."));const _t=B.morphAttributes.position||B.morphAttributes.normal||B.morphAttributes.color,bt=_t!==void 0?_t.length:0;let ee=0;B.morphAttributes.position!==void 0&&(ee=1),B.morphAttributes.normal!==void 0&&(ee=2),B.morphAttributes.color!==void 0&&(ee=3);let pe,jt,j,D;if(pt){const wt=Pn[pt];pe=wt.vertexShader,jt=wt.fragmentShader}else{pe=x.vertexShader,jt=x.fragmentShader;const wt=o.getVertexShaderStage(x),_e=o.getFragmentShaderStage(x);o.update(x,wt,_e),j=wt.id,D=_e.id}const W=s.getRenderTarget(),st=s.state.buffers.depth.getReversed(),lt=F.isInstancedMesh===!0,rt=F.isBatchedMesh===!0,Ft=!!x.map,Lt=!!x.matcap,Ht=!!Q,Zt=!!x.aoMap,Jt=!!x.lightMap,te=!!x.bumpMap&&x.wireframe===!1,le=!!x.normalMap,ce=!!x.displacementMap,Te=!!x.emissiveMap,ge=!!x.metalnessMap,Ae=!!x.roughnessMap,U=x.anisotropy>0,Ke=x.clearcoat>0,re=x.dispersion>0,A=x.iridescence>0,_=x.sheen>0,k=x.transmission>0,V=U&&!!x.anisotropyMap,Z=Ke&&!!x.clearcoatMap,at=Ke&&!!x.clearcoatNormalMap,ct=Ke&&!!x.clearcoatRoughnessMap,J=A&&!!x.iridescenceMap,et=A&&!!x.iridescenceThicknessMap,ut=_&&!!x.sheenColorMap,At=_&&!!x.sheenRoughnessMap,gt=!!x.specularMap,dt=!!x.specularColorMap,Dt=!!x.specularIntensityMap,Ut=k&&!!x.transmissionMap,Gt=k&&!!x.thicknessMap,N=!!x.gradientMap,ot=!!x.alphaMap,tt=x.alphaTest>0,ft=!!x.alphaHash,Mt=!!x.extensions;let nt=En;x.toneMapped&&(W===null||W.isXRRenderTarget===!0)&&(nt=s.toneMapping);const Tt={shaderID:pt,shaderType:x.type,shaderName:x.name,vertexShader:pe,fragmentShader:jt,defines:x.defines,customVertexShaderID:j,customFragmentShaderID:D,isRawShaderMaterial:x.isRawShaderMaterial===!0,glslVersion:x.glslVersion,precision:d,batching:rt,batchingColor:rt&&F._colorsTexture!==null,instancing:lt,instancingColor:lt&&F.instanceColor!==null,instancingMorph:lt&&F.morphTexture!==null,outputColorSpace:W===null?s.outputColorSpace:W.isXRRenderTarget===!0?W.texture.colorSpace:Kt.workingColorSpace,alphaToCoverage:!!x.alphaToCoverage,map:Ft,matcap:Lt,envMap:Ht,envMapMode:Ht&&Q.mapping,envMapCubeUVHeight:it,aoMap:Zt,lightMap:Jt,bumpMap:te,normalMap:le,displacementMap:ce,emissiveMap:Te,normalMapObjectSpace:le&&x.normalMapType===Gd,normalMapTangentSpace:le&&x.normalMapType===wo,packedNormalMap:le&&x.normalMapType===wo&&a_(x.normalMap.format),metalnessMap:ge,roughnessMap:Ae,anisotropy:U,anisotropyMap:V,clearcoat:Ke,clearcoatMap:Z,clearcoatNormalMap:at,clearcoatRoughnessMap:ct,dispersion:re,iridescence:A,iridescenceMap:J,iridescenceThicknessMap:et,sheen:_,sheenColorMap:ut,sheenRoughnessMap:At,specularMap:gt,specularColorMap:dt,specularIntensityMap:Dt,transmission:k,transmissionMap:Ut,thicknessMap:Gt,gradientMap:N,opaque:x.transparent===!1&&x.blending===Vi&&x.alphaToCoverage===!1,alphaMap:ot,alphaTest:tt,alphaHash:ft,combine:x.combine,mapUv:Ft&&p(x.map.channel),aoMapUv:Zt&&p(x.aoMap.channel),lightMapUv:Jt&&p(x.lightMap.channel),bumpMapUv:te&&p(x.bumpMap.channel),normalMapUv:le&&p(x.normalMap.channel),displacementMapUv:ce&&p(x.displacementMap.channel),emissiveMapUv:Te&&p(x.emissiveMap.channel),metalnessMapUv:ge&&p(x.metalnessMap.channel),roughnessMapUv:Ae&&p(x.roughnessMap.channel),anisotropyMapUv:V&&p(x.anisotropyMap.channel),clearcoatMapUv:Z&&p(x.clearcoatMap.channel),clearcoatNormalMapUv:at&&p(x.clearcoatNormalMap.channel),clearcoatRoughnessMapUv:ct&&p(x.clearcoatRoughnessMap.channel),iridescenceMapUv:J&&p(x.iridescenceMap.channel),iridescenceThicknessMapUv:et&&p(x.iridescenceThicknessMap.channel),sheenColorMapUv:ut&&p(x.sheenColorMap.channel),sheenRoughnessMapUv:At&&p(x.sheenRoughnessMap.channel),specularMapUv:gt&&p(x.specularMap.channel),specularColorMapUv:dt&&p(x.specularColorMap.channel),specularIntensityMapUv:Dt&&p(x.specularIntensityMap.channel),transmissionMapUv:Ut&&p(x.transmissionMap.channel),thicknessMapUv:Gt&&p(x.thicknessMap.channel),alphaMapUv:ot&&p(x.alphaMap.channel),vertexTangents:!!B.attributes.tangent&&(le||U),vertexNormals:!!B.attributes.normal,vertexColors:x.vertexColors,vertexAlphas:x.vertexColors===!0&&!!B.attributes.color&&B.attributes.color.itemSize===4,pointsUvs:F.isPoints===!0&&!!B.attributes.uv&&(Ft||ot),fog:!!Y,useFog:x.fog===!0,fogExp2:!!Y&&Y.isFogExp2,flatShading:x.wireframe===!1&&(x.flatShading===!0||B.attributes.normal===void 0&&le===!1&&(x.isMeshLambertMaterial||x.isMeshPhongMaterial||x.isMeshStandardMaterial||x.isMeshPhysicalMaterial)),sizeAttenuation:x.sizeAttenuation===!0,logarithmicDepthBuffer:h,reversedDepthBuffer:st,skinning:F.isSkinnedMesh===!0,hasPositionAttribute:B.attributes.position!==void 0,morphTargets:B.morphAttributes.position!==void 0,morphNormals:B.morphAttributes.normal!==void 0,morphColors:B.morphAttributes.color!==void 0,morphTargetsCount:bt,morphTextureStride:ee,numDirLights:T.directional.length,numPointLights:T.point.length,numSpotLights:T.spot.length,numSpotLightMaps:T.spotLightMap.length,numRectAreaLights:T.rectArea.length,numHemiLights:T.hemi.length,numDirLightShadows:T.directionalShadowMap.length,numPointLightShadows:T.pointShadowMap.length,numSpotLightShadows:T.spotShadowMap.length,numSpotLightShadowsWithMaps:T.numSpotLightShadowsWithMaps,numLightProbes:T.numLightProbes,numLightProbeGrids:q.length,numClippingPlanes:r.numPlanes,numClipIntersection:r.numIntersection,dithering:x.dithering,shadowMapEnabled:s.shadowMap.enabled&&P.length>0,shadowMapType:s.shadowMap.type,toneMapping:nt,decodeVideoTexture:Ft&&x.map.isVideoTexture===!0&&Kt.getTransfer(x.map.colorSpace)===ie,decodeVideoTextureEmissive:Te&&x.emissiveMap.isVideoTexture===!0&&Kt.getTransfer(x.emissiveMap.colorSpace)===ie,premultipliedAlpha:x.premultipliedAlpha,doubleSided:x.side===On,flipSided:x.side===Ge,useDepthPacking:x.depthPacking>=0,depthPacking:x.depthPacking||0,index0AttributeName:x.index0AttributeName,extensionClipCullDistance:Mt&&x.extensions.clipCullDistance===!0&&e.has("WEBGL_clip_cull_distance"),extensionMultiDraw:(Mt&&x.extensions.multiDraw===!0||rt)&&e.has("WEBGL_multi_draw"),rendererExtensionParallelShaderCompile:e.has("KHR_parallel_shader_compile"),customProgramCacheKey:x.customProgramCacheKey()};return Tt.vertexUv1s=l.has(1),Tt.vertexUv2s=l.has(2),Tt.vertexUv3s=l.has(3),l.clear(),Tt}function m(x){const T=[];if(x.shaderID?T.push(x.shaderID):(T.push(x.customVertexShaderID),T.push(x.customFragmentShaderID)),x.defines!==void 0)for(const P in x.defines)T.push(P),T.push(x.defines[P]);return x.isRawShaderMaterial===!1&&(g(T,x),w(T,x),T.push(s.outputColorSpace)),T.push(x.customProgramCacheKey),T.join()}function g(x,T){x.push(T.precision),x.push(T.outputColorSpace),x.push(T.envMapMode),x.push(T.envMapCubeUVHeight),x.push(T.mapUv),x.push(T.alphaMapUv),x.push(T.lightMapUv),x.push(T.aoMapUv),x.push(T.bumpMapUv),x.push(T.normalMapUv),x.push(T.displacementMapUv),x.push(T.emissiveMapUv),x.push(T.metalnessMapUv),x.push(T.roughnessMapUv),x.push(T.anisotropyMapUv),x.push(T.clearcoatMapUv),x.push(T.clearcoatNormalMapUv),x.push(T.clearcoatRoughnessMapUv),x.push(T.iridescenceMapUv),x.push(T.iridescenceThicknessMapUv),x.push(T.sheenColorMapUv),x.push(T.sheenRoughnessMapUv),x.push(T.specularMapUv),x.push(T.specularColorMapUv),x.push(T.specularIntensityMapUv),x.push(T.transmissionMapUv),x.push(T.thicknessMapUv),x.push(T.combine),x.push(T.fogExp2),x.push(T.sizeAttenuation),x.push(T.morphTargetsCount),x.push(T.morphAttributeCount),x.push(T.numDirLights),x.push(T.numPointLights),x.push(T.numSpotLights),x.push(T.numSpotLightMaps),x.push(T.numHemiLights),x.push(T.numRectAreaLights),x.push(T.numDirLightShadows),x.push(T.numPointLightShadows),x.push(T.numSpotLightShadows),x.push(T.numSpotLightShadowsWithMaps),x.push(T.numLightProbes),x.push(T.shadowMapType),x.push(T.toneMapping),x.push(T.numClippingPlanes),x.push(T.numClipIntersection),x.push(T.depthPacking)}function w(x,T){a.disableAll(),T.instancing&&a.enable(0),T.instancingColor&&a.enable(1),T.instancingMorph&&a.enable(2),T.matcap&&a.enable(3),T.envMap&&a.enable(4),T.normalMapObjectSpace&&a.enable(5),T.normalMapTangentSpace&&a.enable(6),T.clearcoat&&a.enable(7),T.iridescence&&a.enable(8),T.alphaTest&&a.enable(9),T.vertexColors&&a.enable(10),T.vertexAlphas&&a.enable(11),T.vertexUv1s&&a.enable(12),T.vertexUv2s&&a.enable(13),T.vertexUv3s&&a.enable(14),T.vertexTangents&&a.enable(15),T.anisotropy&&a.enable(16),T.alphaHash&&a.enable(17),T.batching&&a.enable(18),T.dispersion&&a.enable(19),T.batchingColor&&a.enable(20),T.gradientMap&&a.enable(21),T.packedNormalMap&&a.enable(22),T.vertexNormals&&a.enable(23),x.push(a.mask),a.disableAll(),T.fog&&a.enable(0),T.useFog&&a.enable(1),T.flatShading&&a.enable(2),T.logarithmicDepthBuffer&&a.enable(3),T.reversedDepthBuffer&&a.enable(4),T.skinning&&a.enable(5),T.morphTargets&&a.enable(6),T.morphNormals&&a.enable(7),T.morphColors&&a.enable(8),T.premultipliedAlpha&&a.enable(9),T.shadowMapEnabled&&a.enable(10),T.doubleSided&&a.enable(11),T.flipSided&&a.enable(12),T.useDepthPacking&&a.enable(13),T.dithering&&a.enable(14),T.transmission&&a.enable(15),T.sheen&&a.enable(16),T.opaque&&a.enable(17),T.pointsUvs&&a.enable(18),T.decodeVideoTexture&&a.enable(19),T.decodeVideoTextureEmissive&&a.enable(20),T.alphaToCoverage&&a.enable(21),T.numLightProbeGrids>0&&a.enable(22),T.hasPositionAttribute&&a.enable(23),x.push(a.mask)}function E(x){const T=f[x.type];let P;if(T){const L=Pn[T];P=$s.clone(L.uniforms)}else P=x.uniforms;return P}function M(x,T){let P=u.get(T);return P!==void 0?++P.usedTimes:(P=new n_(s,T,x,i),c.push(P),u.set(T,P)),P}function S(x){if(--x.usedTimes===0){const T=c.indexOf(x);c[T]=c[c.length-1],c.pop(),u.delete(x.cacheKey),x.destroy()}}function b(x){o.remove(x)}function R(){o.dispose()}return{getParameters:v,getProgramCacheKey:m,getUniforms:E,acquireProgram:M,releaseProgram:S,releaseShaderCache:b,programs:c,dispose:R}}function l_(){let s=new WeakMap;function t(a){return s.has(a)}function e(a){let o=s.get(a);return o===void 0&&(o={},s.set(a,o)),o}function n(a){s.delete(a)}function i(a,o,l){s.get(a)[o]=l}function r(){s=new WeakMap}return{has:t,get:e,remove:n,update:i,dispose:r}}function c_(s,t){return s.groupOrder!==t.groupOrder?s.groupOrder-t.groupOrder:s.renderOrder!==t.renderOrder?s.renderOrder-t.renderOrder:s.material.id!==t.material.id?s.material.id-t.material.id:s.materialVariant!==t.materialVariant?s.materialVariant-t.materialVariant:s.z!==t.z?s.z-t.z:s.id-t.id}function zh(s,t){return s.groupOrder!==t.groupOrder?s.groupOrder-t.groupOrder:s.renderOrder!==t.renderOrder?s.renderOrder-t.renderOrder:s.z!==t.z?t.z-s.z:s.id-t.id}function Hh(){const s=[];let t=0;const e=[],n=[],i=[];function r(){t=0,e.length=0,n.length=0,i.length=0}function a(d){let f=0;return d.isInstancedMesh&&(f+=2),d.isSkinnedMesh&&(f+=1),f}function o(d,f,p,v,m,g){let w=s[t];return w===void 0?(w={id:d.id,object:d,geometry:f,material:p,materialVariant:a(d),groupOrder:v,renderOrder:d.renderOrder,z:m,group:g},s[t]=w):(w.id=d.id,w.object=d,w.geometry=f,w.material=p,w.materialVariant=a(d),w.groupOrder=v,w.renderOrder=d.renderOrder,w.z=m,w.group=g),t++,w}function l(d,f,p,v,m,g){const w=o(d,f,p,v,m,g);p.transmission>0?n.push(w):p.transparent===!0?i.push(w):e.push(w)}function c(d,f,p,v,m,g){const w=o(d,f,p,v,m,g);p.transmission>0?n.unshift(w):p.transparent===!0?i.unshift(w):e.unshift(w)}function u(d,f,p){e.length>1&&e.sort(d||c_),n.length>1&&n.sort(f||zh),i.length>1&&i.sort(f||zh),p&&(e.reverse(),n.reverse(),i.reverse())}function h(){for(let d=t,f=s.length;d=r.length?(a=new Hh,r.push(a)):a=r[i],a}function e(){s=new WeakMap}return{get:t,dispose:e}}function u_(){const s={};return{get:function(t){if(s[t.id]!==void 0)return s[t.id];let e;switch(t.type){case"DirectionalLight":e={direction:new C,color:new kt};break;case"SpotLight":e={position:new C,direction:new C,color:new kt,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":e={position:new C,color:new kt,distance:0,decay:0};break;case"HemisphereLight":e={direction:new C,skyColor:new kt,groundColor:new kt};break;case"RectAreaLight":e={color:new kt,position:new C,halfWidth:new C,halfHeight:new C};break}return s[t.id]=e,e}}}function d_(){const s={};return{get:function(t){if(s[t.id]!==void 0)return s[t.id];let e;switch(t.type){case"DirectionalLight":e={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new ht};break;case"SpotLight":e={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new ht};break;case"PointLight":e={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new ht,shadowCameraNear:1,shadowCameraFar:1e3};break}return s[t.id]=e,e}}}let f_=0;function p_(s,t){return(t.castShadow?2:0)-(s.castShadow?2:0)+(t.map?1:0)-(s.map?1:0)}function m_(s){const t=new u_,e=d_(),n={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1,numSpotMaps:-1,numLightProbes:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotLightMap:[],spotShadow:[],spotShadowMap:[],spotLightMatrix:[],rectArea:[],rectAreaLTC1:null,rectAreaLTC2:null,point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[],numSpotLightShadowsWithMaps:0,numLightProbes:0};for(let c=0;c<9;c++)n.probe.push(new C);const i=new C,r=new se,a=new se;function o(c){let u=0,h=0,d=0;for(let T=0;T<9;T++)n.probe[T].set(0,0,0);let f=0,p=0,v=0,m=0,g=0,w=0,E=0,M=0,S=0,b=0,R=0;c.sort(p_);for(let T=0,P=c.length;T0&&(s.has("OES_texture_float_linear")===!0?(n.rectAreaLTC1=mt.LTC_FLOAT_1,n.rectAreaLTC2=mt.LTC_FLOAT_2):(n.rectAreaLTC1=mt.LTC_HALF_1,n.rectAreaLTC2=mt.LTC_HALF_2)),n.ambient[0]=u,n.ambient[1]=h,n.ambient[2]=d;const x=n.hash;(x.directionalLength!==f||x.pointLength!==p||x.spotLength!==v||x.rectAreaLength!==m||x.hemiLength!==g||x.numDirectionalShadows!==w||x.numPointShadows!==E||x.numSpotShadows!==M||x.numSpotMaps!==S||x.numLightProbes!==R)&&(n.directional.length=f,n.spot.length=v,n.rectArea.length=m,n.point.length=p,n.hemi.length=g,n.directionalShadow.length=w,n.directionalShadowMap.length=w,n.pointShadow.length=E,n.pointShadowMap.length=E,n.spotShadow.length=M,n.spotShadowMap.length=M,n.directionalShadowMatrix.length=w,n.pointShadowMatrix.length=E,n.spotLightMatrix.length=M+S-b,n.spotLightMap.length=S,n.numSpotLightShadowsWithMaps=b,n.numLightProbes=R,x.directionalLength=f,x.pointLength=p,x.spotLength=v,x.rectAreaLength=m,x.hemiLength=g,x.numDirectionalShadows=w,x.numPointShadows=E,x.numSpotShadows=M,x.numSpotMaps=S,x.numLightProbes=R,n.version=f_++)}function l(c,u){let h=0,d=0,f=0,p=0,v=0;const m=u.matrixWorldInverse;for(let g=0,w=c.length;g=a.length?(o=new Gh(s),a.push(o)):o=a[r],o}function n(){t=new WeakMap}return{get:e,dispose:n}}const __=`void main() { +Program Info Log: `+N+` +`+rt+` +`+ot)}else N!==""?Ut("WebGLProgram: Program Info Log:",N):(B===""||z==="")&&(nt=!1);nt&&(D.diagnostics={runnable:Z,programLog:N,vertexShader:{log:B,prefix:m},fragmentShader:{log:z,prefix:g}})}i.deleteShader(M),i.deleteShader(w),v=new vo(i,x),T=iv(i,x)}let v;this.getUniforms=function(){return v===void 0&&C(this),v};let T;this.getAttributes=function(){return T===void 0&&C(this),T};let L=e.rendererExtensionParallelShaderCompile===!1;return this.isReady=function(){return L===!1&&(L=i.getProgramParameter(x,qx)),L},this.destroy=function(){n.releaseStatesOfProgram(this),i.deleteProgram(x),this.program=void 0},this.type=e.shaderType,this.name=e.shaderName,this.id=Yx++,this.cacheKey=t,this.usedTimes=1,this.program=x,this.vertexShader=M,this.fragmentShader=w,this}let _v=0;class yv{constructor(){this.shaderCache=new Map,this.materialCache=new Map}update(t,e,n){const i=this._getShaderCacheForMaterial(t);return i.has(e)===!1&&(i.add(e),e.usedTimes++),i.has(n)===!1&&(i.add(n),n.usedTimes++),this}remove(t){const e=this.materialCache.get(t);for(const n of e)n.usedTimes--,n.usedTimes===0&&this.shaderCache.delete(n.code);return this.materialCache.delete(t),this}getVertexShaderStage(t){return this._getShaderStage(t.vertexShader)}getFragmentShaderStage(t){return this._getShaderStage(t.fragmentShader)}dispose(){this.shaderCache.clear(),this.materialCache.clear()}_getShaderCacheForMaterial(t){const e=this.materialCache;let n=e.get(t);return n===void 0&&(n=new Set,e.set(t,n)),n}_getShaderStage(t){const e=this.shaderCache;let n=e.get(t);return n===void 0&&(n=new Mv(t),e.set(t,n)),n}}class Mv{constructor(t){this.id=_v++,this.code=t,this.usedTimes=0}}function bv(s){return s===Fi||s===Ur||s===Fr}function Sv(s,t,e,n,i,r){const o=new ll,a=new yv,l=new Set,c=[],u=new Map,h=n.logarithmicDepthBuffer;let d=n.precision;const f={MeshDepthMaterial:"depth",MeshDistanceMaterial:"distance",MeshNormalMaterial:"normal",MeshBasicMaterial:"basic",MeshLambertMaterial:"lambert",MeshPhongMaterial:"phong",MeshToonMaterial:"toon",MeshStandardMaterial:"physical",MeshPhysicalMaterial:"physical",MeshMatcapMaterial:"matcap",LineBasicMaterial:"basic",LineDashedMaterial:"dashed",PointsMaterial:"points",ShadowMaterial:"shadow",SpriteMaterial:"sprite"};function p(v){return l.add(v),v===0?"uv":`uv${v}`}function x(v,T,L,D,U,Y){const K=D.fog,N=U.geometry,B=v.isMeshStandardMaterial||v.isMeshLambertMaterial||v.isMeshPhongMaterial?D.environment:null,z=v.isMeshStandardMaterial||v.isMeshLambertMaterial&&!v.envMap||v.isMeshPhongMaterial&&!v.envMap,Z=t.get(v.envMap||B,z),nt=Z&&Z.mapping===Cr?Z.image.height:null,rt=f[v.type];v.precision!==null&&(d=n.getMaxPrecision(v.precision),d!==v.precision&&Ut("WebGLProgram.getParameters:",v.precision,"not supported, using",d,"instead."));const ot=N.morphAttributes.position||N.morphAttributes.normal||N.morphAttributes.color,ht=ot!==void 0?ot.length:0;let Gt=0;N.morphAttributes.position!==void 0&&(Gt=1),N.morphAttributes.normal!==void 0&&(Gt=2),N.morphAttributes.color!==void 0&&(Gt=3);let me,ee,Q,I;if(rt){const Et=Dn[rt];me=Et.vertexShader,ee=Et.fragmentShader}else{me=v.vertexShader,ee=v.fragmentShader;const Et=a.getVertexShaderStage(v),_e=a.getFragmentShaderStage(v);a.update(v,Et,_e),Q=Et.id,I=_e.id}const X=s.getRenderTarget(),st=s.state.buffers.depth.getReversed(),dt=U.isInstancedMesh===!0,lt=U.isBatchedMesh===!0,Ot=!!v.map,Dt=!!v.matcap,Vt=!!Z,jt=!!v.aoMap,Qt=!!v.lightMap,ne=!!v.bumpMap&&v.wireframe===!1,ce=!!v.normalMap,he=!!v.displacementMap,Ce=!!v.emissiveMap,ve=!!v.metalnessMap,Re=!!v.roughnessMap,O=v.anisotropy>0,Je=v.clearcoat>0,oe=v.dispersion>0,A=v.iridescence>0,_=v.sheen>0,H=v.transmission>0,$=O&&!!v.anisotropyMap,J=Je&&!!v.clearcoatMap,ct=Je&&!!v.clearcoatNormalMap,ft=Je&&!!v.clearcoatRoughnessMap,j=A&&!!v.iridescenceMap,et=A&&!!v.iridescenceThicknessMap,mt=_&&!!v.sheenColorMap,Ct=_&&!!v.sheenRoughnessMap,_t=!!v.specularMap,gt=!!v.specularColorMap,Nt=!!v.specularIntensityMap,Ft=H&&!!v.transmissionMap,$t=H&&!!v.thicknessMap,F=!!v.gradientMap,ut=!!v.alphaMap,tt=v.alphaTest>0,xt=!!v.alphaHash,bt=!!v.extensions;let it=An;v.toneMapped&&(X===null||X.isXRRenderTarget===!0)&&(it=s.toneMapping);const At={shaderID:rt,shaderType:v.type,shaderName:v.name,vertexShader:me,fragmentShader:ee,defines:v.defines,customVertexShaderID:Q,customFragmentShaderID:I,isRawShaderMaterial:v.isRawShaderMaterial===!0,glslVersion:v.glslVersion,precision:d,batching:lt,batchingColor:lt&&U._colorsTexture!==null,instancing:dt,instancingColor:dt&&U.instanceColor!==null,instancingMorph:dt&&U.morphTexture!==null,outputColorSpace:X===null?s.outputColorSpace:X.isXRRenderTarget===!0?X.texture.colorSpace:Jt.workingColorSpace,alphaToCoverage:!!v.alphaToCoverage,map:Ot,matcap:Dt,envMap:Vt,envMapMode:Vt&&Z.mapping,envMapCubeUVHeight:nt,aoMap:jt,lightMap:Qt,bumpMap:ne,normalMap:ce,displacementMap:he,emissiveMap:Ce,normalMapObjectSpace:ce&&v.normalMapType===rp,normalMapTangentSpace:ce&&v.normalMapType===Qa,packedNormalMap:ce&&v.normalMapType===Qa&&bv(v.normalMap.format),metalnessMap:ve,roughnessMap:Re,anisotropy:O,anisotropyMap:$,clearcoat:Je,clearcoatMap:J,clearcoatNormalMap:ct,clearcoatRoughnessMap:ft,dispersion:oe,iridescence:A,iridescenceMap:j,iridescenceThicknessMap:et,sheen:_,sheenColorMap:mt,sheenRoughnessMap:Ct,specularMap:_t,specularColorMap:gt,specularIntensityMap:Nt,transmission:H,transmissionMap:Ft,thicknessMap:$t,gradientMap:F,opaque:v.transparent===!1&&v.blending===ss&&v.alphaToCoverage===!1,alphaMap:ut,alphaTest:tt,alphaHash:xt,combine:v.combine,mapUv:Ot&&p(v.map.channel),aoMapUv:jt&&p(v.aoMap.channel),lightMapUv:Qt&&p(v.lightMap.channel),bumpMapUv:ne&&p(v.bumpMap.channel),normalMapUv:ce&&p(v.normalMap.channel),displacementMapUv:he&&p(v.displacementMap.channel),emissiveMapUv:Ce&&p(v.emissiveMap.channel),metalnessMapUv:ve&&p(v.metalnessMap.channel),roughnessMapUv:Re&&p(v.roughnessMap.channel),anisotropyMapUv:$&&p(v.anisotropyMap.channel),clearcoatMapUv:J&&p(v.clearcoatMap.channel),clearcoatNormalMapUv:ct&&p(v.clearcoatNormalMap.channel),clearcoatRoughnessMapUv:ft&&p(v.clearcoatRoughnessMap.channel),iridescenceMapUv:j&&p(v.iridescenceMap.channel),iridescenceThicknessMapUv:et&&p(v.iridescenceThicknessMap.channel),sheenColorMapUv:mt&&p(v.sheenColorMap.channel),sheenRoughnessMapUv:Ct&&p(v.sheenRoughnessMap.channel),specularMapUv:_t&&p(v.specularMap.channel),specularColorMapUv:gt&&p(v.specularColorMap.channel),specularIntensityMapUv:Nt&&p(v.specularIntensityMap.channel),transmissionMapUv:Ft&&p(v.transmissionMap.channel),thicknessMapUv:$t&&p(v.thicknessMap.channel),alphaMapUv:ut&&p(v.alphaMap.channel),vertexTangents:!!N.attributes.tangent&&(ce||O),vertexNormals:!!N.attributes.normal,vertexColors:v.vertexColors,vertexAlphas:v.vertexColors===!0&&!!N.attributes.color&&N.attributes.color.itemSize===4,pointsUvs:U.isPoints===!0&&!!N.attributes.uv&&(Ot||ut),fog:!!K,useFog:v.fog===!0,fogExp2:!!K&&K.isFogExp2,flatShading:v.wireframe===!1&&(v.flatShading===!0||N.attributes.normal===void 0&&ce===!1&&(v.isMeshLambertMaterial||v.isMeshPhongMaterial||v.isMeshStandardMaterial||v.isMeshPhysicalMaterial)),sizeAttenuation:v.sizeAttenuation===!0,logarithmicDepthBuffer:h,reversedDepthBuffer:st,skinning:U.isSkinnedMesh===!0,hasPositionAttribute:N.attributes.position!==void 0,morphTargets:N.morphAttributes.position!==void 0,morphNormals:N.morphAttributes.normal!==void 0,morphColors:N.morphAttributes.color!==void 0,morphTargetsCount:ht,morphTextureStride:Gt,numDirLights:T.directional.length,numPointLights:T.point.length,numSpotLights:T.spot.length,numSpotLightMaps:T.spotLightMap.length,numRectAreaLights:T.rectArea.length,numHemiLights:T.hemi.length,numDirLightShadows:T.directionalShadowMap.length,numPointLightShadows:T.pointShadowMap.length,numSpotLightShadows:T.spotShadowMap.length,numSpotLightShadowsWithMaps:T.numSpotLightShadowsWithMaps,numLightProbes:T.numLightProbes,numLightProbeGrids:Y.length,numClippingPlanes:r.numPlanes,numClipIntersection:r.numIntersection,dithering:v.dithering,shadowMapEnabled:s.shadowMap.enabled&&L.length>0,shadowMapType:s.shadowMap.type,toneMapping:it,decodeVideoTexture:Ot&&v.map.isVideoTexture===!0&&Jt.getTransfer(v.map.colorSpace)===se,decodeVideoTextureEmissive:Ce&&v.emissiveMap.isVideoTexture===!0&&Jt.getTransfer(v.emissiveMap.colorSpace)===se,premultipliedAlpha:v.premultipliedAlpha,doubleSided:v.side===Hn,flipSided:v.side===We,useDepthPacking:v.depthPacking>=0,depthPacking:v.depthPacking||0,index0AttributeName:v.index0AttributeName,extensionClipCullDistance:bt&&v.extensions.clipCullDistance===!0&&e.has("WEBGL_clip_cull_distance"),extensionMultiDraw:(bt&&v.extensions.multiDraw===!0||lt)&&e.has("WEBGL_multi_draw"),rendererExtensionParallelShaderCompile:e.has("KHR_parallel_shader_compile"),customProgramCacheKey:v.customProgramCacheKey()};return At.vertexUv1s=l.has(1),At.vertexUv2s=l.has(2),At.vertexUv3s=l.has(3),l.clear(),At}function m(v){const T=[];if(v.shaderID?T.push(v.shaderID):(T.push(v.customVertexShaderID),T.push(v.customFragmentShaderID)),v.defines!==void 0)for(const L in v.defines)T.push(L),T.push(v.defines[L]);return v.isRawShaderMaterial===!1&&(g(T,v),b(T,v),T.push(s.outputColorSpace)),T.push(v.customProgramCacheKey),T.join()}function g(v,T){v.push(T.precision),v.push(T.outputColorSpace),v.push(T.envMapMode),v.push(T.envMapCubeUVHeight),v.push(T.mapUv),v.push(T.alphaMapUv),v.push(T.lightMapUv),v.push(T.aoMapUv),v.push(T.bumpMapUv),v.push(T.normalMapUv),v.push(T.displacementMapUv),v.push(T.emissiveMapUv),v.push(T.metalnessMapUv),v.push(T.roughnessMapUv),v.push(T.anisotropyMapUv),v.push(T.clearcoatMapUv),v.push(T.clearcoatNormalMapUv),v.push(T.clearcoatRoughnessMapUv),v.push(T.iridescenceMapUv),v.push(T.iridescenceThicknessMapUv),v.push(T.sheenColorMapUv),v.push(T.sheenRoughnessMapUv),v.push(T.specularMapUv),v.push(T.specularColorMapUv),v.push(T.specularIntensityMapUv),v.push(T.transmissionMapUv),v.push(T.thicknessMapUv),v.push(T.combine),v.push(T.fogExp2),v.push(T.sizeAttenuation),v.push(T.morphTargetsCount),v.push(T.morphAttributeCount),v.push(T.numDirLights),v.push(T.numPointLights),v.push(T.numSpotLights),v.push(T.numSpotLightMaps),v.push(T.numHemiLights),v.push(T.numRectAreaLights),v.push(T.numDirLightShadows),v.push(T.numPointLightShadows),v.push(T.numSpotLightShadows),v.push(T.numSpotLightShadowsWithMaps),v.push(T.numLightProbes),v.push(T.shadowMapType),v.push(T.toneMapping),v.push(T.numClippingPlanes),v.push(T.numClipIntersection),v.push(T.depthPacking)}function b(v,T){o.disableAll(),T.instancing&&o.enable(0),T.instancingColor&&o.enable(1),T.instancingMorph&&o.enable(2),T.matcap&&o.enable(3),T.envMap&&o.enable(4),T.normalMapObjectSpace&&o.enable(5),T.normalMapTangentSpace&&o.enable(6),T.clearcoat&&o.enable(7),T.iridescence&&o.enable(8),T.alphaTest&&o.enable(9),T.vertexColors&&o.enable(10),T.vertexAlphas&&o.enable(11),T.vertexUv1s&&o.enable(12),T.vertexUv2s&&o.enable(13),T.vertexUv3s&&o.enable(14),T.vertexTangents&&o.enable(15),T.anisotropy&&o.enable(16),T.alphaHash&&o.enable(17),T.batching&&o.enable(18),T.dispersion&&o.enable(19),T.batchingColor&&o.enable(20),T.gradientMap&&o.enable(21),T.packedNormalMap&&o.enable(22),T.vertexNormals&&o.enable(23),v.push(o.mask),o.disableAll(),T.fog&&o.enable(0),T.useFog&&o.enable(1),T.flatShading&&o.enable(2),T.logarithmicDepthBuffer&&o.enable(3),T.reversedDepthBuffer&&o.enable(4),T.skinning&&o.enable(5),T.morphTargets&&o.enable(6),T.morphNormals&&o.enable(7),T.morphColors&&o.enable(8),T.premultipliedAlpha&&o.enable(9),T.shadowMapEnabled&&o.enable(10),T.doubleSided&&o.enable(11),T.flipSided&&o.enable(12),T.useDepthPacking&&o.enable(13),T.dithering&&o.enable(14),T.transmission&&o.enable(15),T.sheen&&o.enable(16),T.opaque&&o.enable(17),T.pointsUvs&&o.enable(18),T.decodeVideoTexture&&o.enable(19),T.decodeVideoTextureEmissive&&o.enable(20),T.alphaToCoverage&&o.enable(21),T.numLightProbeGrids>0&&o.enable(22),T.hasPositionAttribute&&o.enable(23),v.push(o.mask)}function E(v){const T=f[v.type];let L;if(T){const D=Dn[T];L=lr.clone(D.uniforms)}else L=v.uniforms;return L}function y(v,T){let L=u.get(T);return L!==void 0?++L.usedTimes:(L=new vv(s,T,v,i),c.push(L),u.set(T,L)),L}function M(v){if(--v.usedTimes===0){const T=c.indexOf(v);c[T]=c[c.length-1],c.pop(),u.delete(v.cacheKey),v.destroy()}}function w(v){a.remove(v)}function C(){a.dispose()}return{getParameters:x,getProgramCacheKey:m,getUniforms:E,acquireProgram:y,releaseProgram:M,releaseShaderCache:w,programs:c,dispose:C}}function wv(){let s=new WeakMap;function t(o){return s.has(o)}function e(o){let a=s.get(o);return a===void 0&&(a={},s.set(o,a)),a}function n(o){s.delete(o)}function i(o,a,l){s.get(o)[a]=l}function r(){s=new WeakMap}return{has:t,get:e,remove:n,update:i,dispose:r}}function Ev(s,t){return s.groupOrder!==t.groupOrder?s.groupOrder-t.groupOrder:s.renderOrder!==t.renderOrder?s.renderOrder-t.renderOrder:s.material.id!==t.material.id?s.material.id-t.material.id:s.materialVariant!==t.materialVariant?s.materialVariant-t.materialVariant:s.z!==t.z?s.z-t.z:s.id-t.id}function Pu(s,t){return s.groupOrder!==t.groupOrder?s.groupOrder-t.groupOrder:s.renderOrder!==t.renderOrder?s.renderOrder-t.renderOrder:s.z!==t.z?t.z-s.z:s.id-t.id}function Lu(){const s=[];let t=0;const e=[],n=[],i=[];function r(){t=0,e.length=0,n.length=0,i.length=0}function o(d){let f=0;return d.isInstancedMesh&&(f+=2),d.isSkinnedMesh&&(f+=1),f}function a(d,f,p,x,m,g){let b=s[t];return b===void 0?(b={id:d.id,object:d,geometry:f,material:p,materialVariant:o(d),groupOrder:x,renderOrder:d.renderOrder,z:m,group:g},s[t]=b):(b.id=d.id,b.object=d,b.geometry=f,b.material=p,b.materialVariant=o(d),b.groupOrder=x,b.renderOrder=d.renderOrder,b.z=m,b.group=g),t++,b}function l(d,f,p,x,m,g){const b=a(d,f,p,x,m,g);p.transmission>0?n.push(b):p.transparent===!0?i.push(b):e.push(b)}function c(d,f,p,x,m,g){const b=a(d,f,p,x,m,g);p.transmission>0?n.unshift(b):p.transparent===!0?i.unshift(b):e.unshift(b)}function u(d,f,p){e.length>1&&e.sort(d||Ev),n.length>1&&n.sort(f||Pu),i.length>1&&i.sort(f||Pu),p&&(e.reverse(),n.reverse(),i.reverse())}function h(){for(let d=t,f=s.length;d=r.length?(o=new Lu,r.push(o)):o=r[i],o}function e(){s=new WeakMap}return{get:t,dispose:e}}function Av(){const s={};return{get:function(t){if(s[t.id]!==void 0)return s[t.id];let e;switch(t.type){case"DirectionalLight":e={direction:new P,color:new Bt};break;case"SpotLight":e={position:new P,direction:new P,color:new Bt,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":e={position:new P,color:new Bt,distance:0,decay:0};break;case"HemisphereLight":e={direction:new P,skyColor:new Bt,groundColor:new Bt};break;case"RectAreaLight":e={color:new Bt,position:new P,halfWidth:new P,halfHeight:new P};break}return s[t.id]=e,e}}}function Cv(){const s={};return{get:function(t){if(s[t.id]!==void 0)return s[t.id];let e;switch(t.type){case"DirectionalLight":e={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new pt};break;case"SpotLight":e={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new pt};break;case"PointLight":e={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new pt,shadowCameraNear:1,shadowCameraFar:1e3};break}return s[t.id]=e,e}}}let Rv=0;function Pv(s,t){return(t.castShadow?2:0)-(s.castShadow?2:0)+(t.map?1:0)-(s.map?1:0)}function Lv(s){const t=new Av,e=Cv(),n={version:0,hash:{directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1,numSpotMaps:-1,numLightProbes:-1},ambient:[0,0,0],probe:[],directional:[],directionalShadow:[],directionalShadowMap:[],directionalShadowMatrix:[],spot:[],spotLightMap:[],spotShadow:[],spotShadowMap:[],spotLightMatrix:[],rectArea:[],rectAreaLTC1:null,rectAreaLTC2:null,point:[],pointShadow:[],pointShadowMap:[],pointShadowMatrix:[],hemi:[],numSpotLightShadowsWithMaps:0,numLightProbes:0};for(let c=0;c<9;c++)n.probe.push(new P);const i=new P,r=new re,o=new re;function a(c){let u=0,h=0,d=0;for(let T=0;T<9;T++)n.probe[T].set(0,0,0);let f=0,p=0,x=0,m=0,g=0,b=0,E=0,y=0,M=0,w=0,C=0;c.sort(Pv);for(let T=0,L=c.length;T0&&(s.has("OES_texture_float_linear")===!0?(n.rectAreaLTC1=vt.LTC_FLOAT_1,n.rectAreaLTC2=vt.LTC_FLOAT_2):(n.rectAreaLTC1=vt.LTC_HALF_1,n.rectAreaLTC2=vt.LTC_HALF_2)),n.ambient[0]=u,n.ambient[1]=h,n.ambient[2]=d;const v=n.hash;(v.directionalLength!==f||v.pointLength!==p||v.spotLength!==x||v.rectAreaLength!==m||v.hemiLength!==g||v.numDirectionalShadows!==b||v.numPointShadows!==E||v.numSpotShadows!==y||v.numSpotMaps!==M||v.numLightProbes!==C)&&(n.directional.length=f,n.spot.length=x,n.rectArea.length=m,n.point.length=p,n.hemi.length=g,n.directionalShadow.length=b,n.directionalShadowMap.length=b,n.pointShadow.length=E,n.pointShadowMap.length=E,n.spotShadow.length=y,n.spotShadowMap.length=y,n.directionalShadowMatrix.length=b,n.pointShadowMatrix.length=E,n.spotLightMatrix.length=y+M-w,n.spotLightMap.length=M,n.numSpotLightShadowsWithMaps=w,n.numLightProbes=C,v.directionalLength=f,v.pointLength=p,v.spotLength=x,v.rectAreaLength=m,v.hemiLength=g,v.numDirectionalShadows=b,v.numPointShadows=E,v.numSpotShadows=y,v.numSpotMaps=M,v.numLightProbes=C,n.version=Rv++)}function l(c,u){let h=0,d=0,f=0,p=0,x=0;const m=u.matrixWorldInverse;for(let g=0,b=c.length;g=o.length?(a=new Du(s),o.push(a)):a=o[r],a}function n(){t=new WeakMap}return{get:e,dispose:n}}const Iv=`void main() { gl_Position = vec4( position, 1.0 ); -}`,x_=`uniform sampler2D shadow_pass; +}`,Nv=`uniform sampler2D shadow_pass; uniform vec2 resolution; uniform float radius; void main() { @@ -4089,12 +4089,12 @@ void main() { squared_mean = squared_mean / samples; float std_dev = sqrt( max( 0.0, squared_mean - mean * mean ) ); gl_FragColor = vec4( mean, std_dev, 0.0, 1.0 ); -}`,v_=[new C(1,0,0),new C(-1,0,0),new C(0,1,0),new C(0,-1,0),new C(0,0,1),new C(0,0,-1)],M_=[new C(0,-1,0),new C(0,-1,0),new C(0,0,1),new C(0,0,-1),new C(0,-1,0),new C(0,-1,0)],Vh=new se,Ys=new C,_l=new C;function y_(s,t,e){let n=new kr;const i=new ht,r=new ht,a=new me,o=new sp,l=new rp,c={},u=e.maxTextureSize,h={[jn]:Ge,[Ge]:jn,[On]:On},d=new Ce({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new ht},radius:{value:4}},vertexShader:__,fragmentShader:x_}),f=d.clone();f.defines.HORIZONTAL_PASS=1;const p=new Be;p.setAttribute("position",new rn(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const v=new Bt(p,d),m=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=sr;let g=this.type;this.render=function(b,R,x){if(m.enabled===!1||m.autoUpdate===!1&&m.needsUpdate===!1||b.length===0)return;this.type===vd&&(Nt("WebGLShadowMap: PCFSoftShadowMap has been deprecated. Using PCFShadowMap instead."),this.type=sr);const T=s.getRenderTarget(),P=s.getActiveCubeFace(),L=s.getActiveMipmapLevel(),F=s.state;F.setBlending(wn),F.buffers.depth.getReversed()===!0?F.buffers.color.setClear(0,0,0,0):F.buffers.color.setClear(1,1,1,1),F.buffers.depth.setTest(!0),F.setScissorTest(!1);const q=g!==this.type;q&&R.traverse(function(Y){Y.material&&(Array.isArray(Y.material)?Y.material.forEach(B=>B.needsUpdate=!0):Y.material.needsUpdate=!0)});for(let Y=0,B=b.length;Yu||i.y>u)&&(i.x>u&&(r.x=Math.floor(u/Q.x),i.x=r.x*Q.x,X.mapSize.x=r.x),i.y>u&&(r.y=Math.floor(u/Q.y),i.y=r.y*Q.y,X.mapSize.y=r.y));const it=s.state.buffers.depth.getReversed();if(X.camera._reversedDepth=it,X.map===null||q===!0){if(X.map!==null&&(X.map.depthTexture!==null&&(X.map.depthTexture.dispose(),X.map.depthTexture=null),X.map.dispose()),this.type===As){if(K.isPointLight){Nt("WebGLShadowMap: VSM shadow maps are not supported for PointLights. Use PCF or BasicShadowMap instead.");continue}X.map=new Xe(i.x,i.y,{format:Ci,type:Je,minFilter:Ue,magFilter:Ue,generateMipmaps:!1}),X.map.texture.name=K.name+".shadowMap",X.map.depthTexture=new us(i.x,i.y,un),X.map.depthTexture.name=K.name+".shadowMapDepth",X.map.depthTexture.format=Bn,X.map.depthTexture.compareFunction=null,X.map.depthTexture.minFilter=Ne,X.map.depthTexture.magFilter=Ne}else K.isPointLight?(X.map=new Sh(i.x),X.map.depthTexture=new Bf(i.x,Tn)):(X.map=new Xe(i.x,i.y),X.map.depthTexture=new us(i.x,i.y,Tn)),X.map.depthTexture.name=K.name+".shadowMap",X.map.depthTexture.format=Bn,this.type===sr?(X.map.depthTexture.compareFunction=it?To:Eo,X.map.depthTexture.minFilter=Ue,X.map.depthTexture.magFilter=Ue):(X.map.depthTexture.compareFunction=null,X.map.depthTexture.minFilter=Ne,X.map.depthTexture.magFilter=Ne);X.camera.updateProjectionMatrix()}const pt=X.map.isWebGLCubeRenderTarget?6:1;for(let _t=0;_t0||R.map&&R.alphaTest>0||R.alphaToCoverage===!0){const F=P.uuid,q=R.uuid;let Y=c[F];Y===void 0&&(Y={},c[F]=Y);let B=Y[q];B===void 0&&(B=P.clone(),Y[q]=B,R.addEventListener("dispose",S)),P=B}if(P.visible=R.visible,P.wireframe=R.wireframe,T===As?P.side=R.shadowSide!==null?R.shadowSide:R.side:P.side=R.shadowSide!==null?R.shadowSide:h[R.side],P.alphaMap=R.alphaMap,P.alphaTest=R.alphaToCoverage===!0?.5:R.alphaTest,P.map=R.map,P.clipShadows=R.clipShadows,P.clippingPlanes=R.clippingPlanes,P.clipIntersection=R.clipIntersection,P.displacementMap=R.displacementMap,P.displacementScale=R.displacementScale,P.displacementBias=R.displacementBias,P.wireframeLinewidth=R.wireframeLinewidth,P.linewidth=R.linewidth,x.isPointLight===!0&&P.isMeshDistanceMaterial===!0){const F=s.properties.get(P);F.light=x}return P}function M(b,R,x,T,P){if(b.visible===!1)return;if(b.layers.test(R.layers)&&(b.isMesh||b.isLine||b.isPoints)&&(b.castShadow||b.receiveShadow&&P===As)&&(!b.frustumCulled||n.intersectsObject(b))){b.modelViewMatrix.multiplyMatrices(x.matrixWorldInverse,b.matrixWorld);const q=t.update(b),Y=b.material;if(Array.isArray(Y)){const B=q.groups;for(let K=0,X=B.length;K=1):it.indexOf("OpenGL ES")!==-1&&(Q=parseFloat(/^OpenGL ES (\d)/.exec(it)[1]),X=Q>=2);let pt=null,_t={};const bt=s.getParameter(s.SCISSOR_BOX),ee=s.getParameter(s.VIEWPORT),pe=new me().fromArray(bt),jt=new me().fromArray(ee);function j(N,ot,tt,ft){const Mt=new Uint8Array(4),nt=s.createTexture();s.bindTexture(N,nt),s.texParameteri(N,s.TEXTURE_MIN_FILTER,s.NEAREST),s.texParameteri(N,s.TEXTURE_MAG_FILTER,s.NEAREST);for(let Tt=0;Tt"u"?!1:/OculusBrowser/g.test(navigator.userAgent),c=new ht,u=new WeakMap,h=new Set;let d;const f=new WeakMap;let p=!1;try{p=typeof OffscreenCanvas<"u"&&new OffscreenCanvas(1,1).getContext("2d")!==null}catch{}function v(A,_){return p?new OffscreenCanvas(A,_):_r("canvas")}function m(A,_,k){let V=1;const Z=re(A);if((Z.width>k||Z.height>k)&&(V=k/Math.max(Z.width,Z.height)),V<1)if(typeof HTMLImageElement<"u"&&A instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&A instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&A instanceof ImageBitmap||typeof VideoFrame<"u"&&A instanceof VideoFrame){const at=Math.floor(V*Z.width),ct=Math.floor(V*Z.height);d===void 0&&(d=v(at,ct));const J=_?v(at,ct):d;return J.width=at,J.height=ct,J.getContext("2d").drawImage(A,0,0,at,ct),Nt("WebGLRenderer: Texture has been resized from ("+Z.width+"x"+Z.height+") to ("+at+"x"+ct+")."),J}else return"data"in A&&Nt("WebGLRenderer: Image in DataTexture is too big ("+Z.width+"x"+Z.height+")."),A;return A}function g(A){return A.generateMipmaps}function w(A){s.generateMipmap(A)}function E(A){return A.isWebGLCubeRenderTarget?s.TEXTURE_CUBE_MAP:A.isWebGL3DRenderTarget?s.TEXTURE_3D:A.isWebGLArrayRenderTarget||A.isCompressedArrayTexture?s.TEXTURE_2D_ARRAY:s.TEXTURE_2D}function M(A,_,k,V,Z,at=!1){if(A!==null){if(s[A]!==void 0)return s[A];Nt("WebGLRenderer: Attempt to use non-existing WebGL internal format '"+A+"'")}let ct;V&&(ct=t.get("EXT_texture_norm16"),ct||Nt("WebGLRenderer: Unable to use normalized textures without EXT_texture_norm16 extension"));let J=_;if(_===s.RED&&(k===s.FLOAT&&(J=s.R32F),k===s.HALF_FLOAT&&(J=s.R16F),k===s.UNSIGNED_BYTE&&(J=s.R8),k===s.UNSIGNED_SHORT&&ct&&(J=ct.R16_EXT),k===s.SHORT&&ct&&(J=ct.R16_SNORM_EXT)),_===s.RED_INTEGER&&(k===s.UNSIGNED_BYTE&&(J=s.R8UI),k===s.UNSIGNED_SHORT&&(J=s.R16UI),k===s.UNSIGNED_INT&&(J=s.R32UI),k===s.BYTE&&(J=s.R8I),k===s.SHORT&&(J=s.R16I),k===s.INT&&(J=s.R32I)),_===s.RG&&(k===s.FLOAT&&(J=s.RG32F),k===s.HALF_FLOAT&&(J=s.RG16F),k===s.UNSIGNED_BYTE&&(J=s.RG8),k===s.UNSIGNED_SHORT&&ct&&(J=ct.RG16_EXT),k===s.SHORT&&ct&&(J=ct.RG16_SNORM_EXT)),_===s.RG_INTEGER&&(k===s.UNSIGNED_BYTE&&(J=s.RG8UI),k===s.UNSIGNED_SHORT&&(J=s.RG16UI),k===s.UNSIGNED_INT&&(J=s.RG32UI),k===s.BYTE&&(J=s.RG8I),k===s.SHORT&&(J=s.RG16I),k===s.INT&&(J=s.RG32I)),_===s.RGB_INTEGER&&(k===s.UNSIGNED_BYTE&&(J=s.RGB8UI),k===s.UNSIGNED_SHORT&&(J=s.RGB16UI),k===s.UNSIGNED_INT&&(J=s.RGB32UI),k===s.BYTE&&(J=s.RGB8I),k===s.SHORT&&(J=s.RGB16I),k===s.INT&&(J=s.RGB32I)),_===s.RGBA_INTEGER&&(k===s.UNSIGNED_BYTE&&(J=s.RGBA8UI),k===s.UNSIGNED_SHORT&&(J=s.RGBA16UI),k===s.UNSIGNED_INT&&(J=s.RGBA32UI),k===s.BYTE&&(J=s.RGBA8I),k===s.SHORT&&(J=s.RGBA16I),k===s.INT&&(J=s.RGBA32I)),_===s.RGB&&(k===s.UNSIGNED_SHORT&&ct&&(J=ct.RGB16_EXT),k===s.SHORT&&ct&&(J=ct.RGB16_SNORM_EXT),k===s.UNSIGNED_INT_5_9_9_9_REV&&(J=s.RGB9_E5),k===s.UNSIGNED_INT_10F_11F_11F_REV&&(J=s.R11F_G11F_B10F)),_===s.RGBA){const et=at?gr:Kt.getTransfer(Z);k===s.FLOAT&&(J=s.RGBA32F),k===s.HALF_FLOAT&&(J=s.RGBA16F),k===s.UNSIGNED_BYTE&&(J=et===ie?s.SRGB8_ALPHA8:s.RGBA8),k===s.UNSIGNED_SHORT&&ct&&(J=ct.RGBA16_EXT),k===s.SHORT&&ct&&(J=ct.RGBA16_SNORM_EXT),k===s.UNSIGNED_SHORT_4_4_4_4&&(J=s.RGBA4),k===s.UNSIGNED_SHORT_5_5_5_1&&(J=s.RGB5_A1)}return(J===s.R16F||J===s.R32F||J===s.RG16F||J===s.RG32F||J===s.RGBA16F||J===s.RGBA32F)&&t.get("EXT_color_buffer_float"),J}function S(A,_){let k;return A?_===null||_===Tn||_===Rs?k=s.DEPTH24_STENCIL8:_===un?k=s.DEPTH32F_STENCIL8:_===Cs&&(k=s.DEPTH24_STENCIL8,Nt("DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.")):_===null||_===Tn||_===Rs?k=s.DEPTH_COMPONENT24:_===un?k=s.DEPTH_COMPONENT32F:_===Cs&&(k=s.DEPTH_COMPONENT16),k}function b(A,_){return g(A)===!0||A.isFramebufferTexture&&A.minFilter!==Ne&&A.minFilter!==Ue?Math.log2(Math.max(_.width,_.height))+1:A.mipmaps!==void 0&&A.mipmaps.length>0?A.mipmaps.length:A.isCompressedTexture&&Array.isArray(A.image)?_.mipmaps.length:1}function R(A){const _=A.target;_.removeEventListener("dispose",R),T(_),_.isVideoTexture&&u.delete(_),_.isHTMLTexture&&h.delete(_)}function x(A){const _=A.target;_.removeEventListener("dispose",x),L(_)}function T(A){const _=n.get(A);if(_.__webglInit===void 0)return;const k=A.source,V=f.get(k);if(V){const Z=V[_.__cacheKey];Z.usedTimes--,Z.usedTimes===0&&P(A),Object.keys(V).length===0&&f.delete(k)}n.remove(A)}function P(A){const _=n.get(A);s.deleteTexture(_.__webglTexture);const k=A.source,V=f.get(k);delete V[_.__cacheKey],a.memory.textures--}function L(A){const _=n.get(A);if(A.depthTexture&&(A.depthTexture.dispose(),n.remove(A.depthTexture)),A.isWebGLCubeRenderTarget)for(let V=0;V<6;V++){if(Array.isArray(_.__webglFramebuffer[V]))for(let Z=0;Z<_.__webglFramebuffer[V].length;Z++)s.deleteFramebuffer(_.__webglFramebuffer[V][Z]);else s.deleteFramebuffer(_.__webglFramebuffer[V]);_.__webglDepthbuffer&&s.deleteRenderbuffer(_.__webglDepthbuffer[V])}else{if(Array.isArray(_.__webglFramebuffer))for(let V=0;V<_.__webglFramebuffer.length;V++)s.deleteFramebuffer(_.__webglFramebuffer[V]);else s.deleteFramebuffer(_.__webglFramebuffer);if(_.__webglDepthbuffer&&s.deleteRenderbuffer(_.__webglDepthbuffer),_.__webglMultisampledFramebuffer&&s.deleteFramebuffer(_.__webglMultisampledFramebuffer),_.__webglColorRenderbuffer)for(let V=0;V<_.__webglColorRenderbuffer.length;V++)_.__webglColorRenderbuffer[V]&&s.deleteRenderbuffer(_.__webglColorRenderbuffer[V]);_.__webglDepthRenderbuffer&&s.deleteRenderbuffer(_.__webglDepthRenderbuffer)}const k=A.textures;for(let V=0,Z=k.length;V=i.maxTextures&&Nt("WebGLTextures: Trying to use "+A+" texture units while this GPU supports only "+i.maxTextures),F+=1,A}function X(A){const _=[];return _.push(A.wrapS),_.push(A.wrapT),_.push(A.wrapR||0),_.push(A.magFilter),_.push(A.minFilter),_.push(A.anisotropy),_.push(A.internalFormat),_.push(A.format),_.push(A.type),_.push(A.generateMipmaps),_.push(A.premultiplyAlpha),_.push(A.flipY),_.push(A.unpackAlignment),_.push(A.colorSpace),_.join()}function Q(A,_){const k=n.get(A);if(A.isVideoTexture&&U(A),A.isRenderTargetTexture===!1&&A.isExternalTexture!==!0&&A.version>0&&k.__version!==A.version){const V=A.image;if(V===null)Nt("WebGLRenderer: Texture marked for update but no image data found.");else if(V.complete===!1)Nt("WebGLRenderer: Texture marked for update but image is incomplete");else{st(k,A,_);return}}else A.isExternalTexture&&(k.__webglTexture=A.sourceTexture?A.sourceTexture:null);e.bindTexture(s.TEXTURE_2D,k.__webglTexture,s.TEXTURE0+_)}function it(A,_){const k=n.get(A);if(A.isRenderTargetTexture===!1&&A.version>0&&k.__version!==A.version){st(k,A,_);return}else A.isExternalTexture&&(k.__webglTexture=A.sourceTexture?A.sourceTexture:null);e.bindTexture(s.TEXTURE_2D_ARRAY,k.__webglTexture,s.TEXTURE0+_)}function pt(A,_){const k=n.get(A);if(A.isRenderTargetTexture===!1&&A.version>0&&k.__version!==A.version){st(k,A,_);return}e.bindTexture(s.TEXTURE_3D,k.__webglTexture,s.TEXTURE0+_)}function _t(A,_){const k=n.get(A);if(A.isCubeDepthTexture!==!0&&A.version>0&&k.__version!==A.version){lt(k,A,_);return}e.bindTexture(s.TEXTURE_CUBE_MAP,k.__webglTexture,s.TEXTURE0+_)}const bt={[lr]:s.REPEAT,[kn]:s.CLAMP_TO_EDGE,[ka]:s.MIRRORED_REPEAT},ee={[Ne]:s.NEAREST,[zd]:s.NEAREST_MIPMAP_NEAREST,[cr]:s.NEAREST_MIPMAP_LINEAR,[Ue]:s.LINEAR,[Ba]:s.LINEAR_MIPMAP_NEAREST,[Ti]:s.LINEAR_MIPMAP_LINEAR},pe={[Vd]:s.NEVER,[Yd]:s.ALWAYS,[Wd]:s.LESS,[Eo]:s.LEQUAL,[$d]:s.EQUAL,[To]:s.GEQUAL,[Xd]:s.GREATER,[qd]:s.NOTEQUAL};function jt(A,_){if(_.type===un&&t.has("OES_texture_float_linear")===!1&&(_.magFilter===Ue||_.magFilter===Ba||_.magFilter===cr||_.magFilter===Ti||_.minFilter===Ue||_.minFilter===Ba||_.minFilter===cr||_.minFilter===Ti)&&Nt("WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device."),s.texParameteri(A,s.TEXTURE_WRAP_S,bt[_.wrapS]),s.texParameteri(A,s.TEXTURE_WRAP_T,bt[_.wrapT]),(A===s.TEXTURE_3D||A===s.TEXTURE_2D_ARRAY)&&s.texParameteri(A,s.TEXTURE_WRAP_R,bt[_.wrapR]),s.texParameteri(A,s.TEXTURE_MAG_FILTER,ee[_.magFilter]),s.texParameteri(A,s.TEXTURE_MIN_FILTER,ee[_.minFilter]),_.compareFunction&&(s.texParameteri(A,s.TEXTURE_COMPARE_MODE,s.COMPARE_REF_TO_TEXTURE),s.texParameteri(A,s.TEXTURE_COMPARE_FUNC,pe[_.compareFunction])),t.has("EXT_texture_filter_anisotropic")===!0){if(_.magFilter===Ne||_.minFilter!==cr&&_.minFilter!==Ti||_.type===un&&t.has("OES_texture_float_linear")===!1)return;if(_.anisotropy>1||n.get(_).__currentAnisotropy){const k=t.get("EXT_texture_filter_anisotropic");s.texParameterf(A,k.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(_.anisotropy,i.getMaxAnisotropy())),n.get(_).__currentAnisotropy=_.anisotropy}}}function j(A,_){let k=!1;A.__webglInit===void 0&&(A.__webglInit=!0,_.addEventListener("dispose",R));const V=_.source;let Z=f.get(V);Z===void 0&&(Z={},f.set(V,Z));const at=X(_);if(at!==A.__cacheKey){Z[at]===void 0&&(Z[at]={texture:s.createTexture(),usedTimes:0},a.memory.textures++,k=!0),Z[at].usedTimes++;const ct=Z[A.__cacheKey];ct!==void 0&&(Z[A.__cacheKey].usedTimes--,ct.usedTimes===0&&P(_)),A.__cacheKey=at,A.__webglTexture=Z[at].texture}return k}function D(A,_,k){return Math.floor(Math.floor(A/k)/_)}function W(A,_,k,V){const at=A.updateRanges;if(at.length===0)e.texSubImage2D(s.TEXTURE_2D,0,0,0,_.width,_.height,k,V,_.data);else{at.sort((At,gt)=>At.start-gt.start);let ct=0;for(let At=1;At0){Ut&&Gt&&e.texStorage2D(s.TEXTURE_2D,ot,gt,Dt[0].width,Dt[0].height);for(let tt=0,ft=Dt.length;tt0){const Mt=fh(dt.width,dt.height,_.format,_.type);for(const nt of _.layerUpdates){const Tt=dt.data.subarray(nt*Mt/dt.data.BYTES_PER_ELEMENT,(nt+1)*Mt/dt.data.BYTES_PER_ELEMENT);e.compressedTexSubImage3D(s.TEXTURE_2D_ARRAY,tt,0,0,nt,dt.width,dt.height,1,ut,Tt)}_.clearLayerUpdates()}else e.compressedTexSubImage3D(s.TEXTURE_2D_ARRAY,tt,0,0,0,dt.width,dt.height,et.depth,ut,dt.data)}else e.compressedTexImage3D(s.TEXTURE_2D_ARRAY,tt,gt,dt.width,dt.height,et.depth,0,dt.data,0,0);else Nt("WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()");else Ut?N&&e.texSubImage3D(s.TEXTURE_2D_ARRAY,tt,0,0,0,dt.width,dt.height,et.depth,ut,At,dt.data):e.texImage3D(s.TEXTURE_2D_ARRAY,tt,gt,dt.width,dt.height,et.depth,0,ut,At,dt.data)}else{Ut&&Gt&&e.texStorage2D(s.TEXTURE_2D,ot,gt,Dt[0].width,Dt[0].height);for(let tt=0,ft=Dt.length;tt0){const tt=fh(et.width,et.height,_.format,_.type);for(const ft of _.layerUpdates){const Mt=et.data.subarray(ft*tt/et.data.BYTES_PER_ELEMENT,(ft+1)*tt/et.data.BYTES_PER_ELEMENT);e.texSubImage3D(s.TEXTURE_2D_ARRAY,0,0,0,ft,et.width,et.height,1,ut,At,Mt)}_.clearLayerUpdates()}else e.texSubImage3D(s.TEXTURE_2D_ARRAY,0,0,0,0,et.width,et.height,et.depth,ut,At,et.data)}else e.texImage3D(s.TEXTURE_2D_ARRAY,0,gt,et.width,et.height,et.depth,0,ut,At,et.data);else if(_.isData3DTexture)Ut?(Gt&&e.texStorage3D(s.TEXTURE_3D,ot,gt,et.width,et.height,et.depth),N&&e.texSubImage3D(s.TEXTURE_3D,0,0,0,0,et.width,et.height,et.depth,ut,At,et.data)):e.texImage3D(s.TEXTURE_3D,0,gt,et.width,et.height,et.depth,0,ut,At,et.data);else if(_.isFramebufferTexture){if(Gt)if(Ut)e.texStorage2D(s.TEXTURE_2D,ot,gt,et.width,et.height);else{let tt=et.width,ft=et.height;for(let Mt=0;Mt>=1,ft>>=1}}else if(_.isHTMLTexture){if("texElementImage2D"in s){const tt=s.canvas;if(tt.hasAttribute("layoutsubtree")||tt.setAttribute("layoutsubtree","true"),et.parentNode!==tt){tt.appendChild(et),h.add(_),tt.onpaint=ft=>{const Mt=ft.changedElements;for(const nt of h)Mt.includes(nt.image)&&(nt.needsUpdate=!0)},tt.requestPaint();return}if(s.texElementImage2D.length===3)s.texElementImage2D(s.TEXTURE_2D,s.RGBA8,et);else{const Mt=s.RGBA,nt=s.RGBA,Tt=s.UNSIGNED_BYTE;s.texElementImage2D(s.TEXTURE_2D,0,Mt,nt,Tt,et)}s.texParameteri(s.TEXTURE_2D,s.TEXTURE_MIN_FILTER,s.LINEAR),s.texParameteri(s.TEXTURE_2D,s.TEXTURE_WRAP_S,s.CLAMP_TO_EDGE),s.texParameteri(s.TEXTURE_2D,s.TEXTURE_WRAP_T,s.CLAMP_TO_EDGE)}}else if(Dt.length>0){if(Ut&&Gt){const tt=re(Dt[0]);e.texStorage2D(s.TEXTURE_2D,ot,gt,tt.width,tt.height)}for(let tt=0,ft=Dt.length;tt0&&ft++;const nt=re(gt[0]);e.texStorage2D(s.TEXTURE_CUBE_MAP,ft,Gt,nt.width,nt.height)}for(let nt=0;nt<6;nt++)if(At){N?tt&&e.texSubImage2D(s.TEXTURE_CUBE_MAP_POSITIVE_X+nt,0,0,0,gt[nt].width,gt[nt].height,Dt,Ut,gt[nt].data):e.texImage2D(s.TEXTURE_CUBE_MAP_POSITIVE_X+nt,0,Gt,gt[nt].width,gt[nt].height,0,Dt,Ut,gt[nt].data);for(let Tt=0;Tt>at),dt=Math.max(1,_.height>>at);Z===s.TEXTURE_3D||Z===s.TEXTURE_2D_ARRAY?e.texImage3D(Z,at,et,gt,dt,_.depth,0,ct,J,null):e.texImage2D(Z,at,et,gt,dt,0,ct,J,null)}e.bindFramebuffer(s.FRAMEBUFFER,A),Ae(_)?o.framebufferTexture2DMultisampleEXT(s.FRAMEBUFFER,V,Z,At.__webglTexture,0,ge(_)):(Z===s.TEXTURE_2D||Z>=s.TEXTURE_CUBE_MAP_POSITIVE_X&&Z<=s.TEXTURE_CUBE_MAP_NEGATIVE_Z)&&s.framebufferTexture2D(s.FRAMEBUFFER,V,Z,At.__webglTexture,at),e.bindFramebuffer(s.FRAMEBUFFER,null)}function Ft(A,_,k){if(s.bindRenderbuffer(s.RENDERBUFFER,A),_.depthBuffer){const V=_.depthTexture,Z=V&&V.isDepthTexture?V.type:null,at=S(_.stencilBuffer,Z),ct=_.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT;Ae(_)?o.renderbufferStorageMultisampleEXT(s.RENDERBUFFER,ge(_),at,_.width,_.height):k?s.renderbufferStorageMultisample(s.RENDERBUFFER,ge(_),at,_.width,_.height):s.renderbufferStorage(s.RENDERBUFFER,at,_.width,_.height),s.framebufferRenderbuffer(s.FRAMEBUFFER,ct,s.RENDERBUFFER,A)}else{const V=_.textures;for(let Z=0;Z{delete _.__boundDepthTexture,delete _.__depthDisposeCallback,V.removeEventListener("dispose",Z)};V.addEventListener("dispose",Z),_.__depthDisposeCallback=Z}_.__boundDepthTexture=V}if(A.depthTexture&&!_.__autoAllocateDepthBuffer)if(k)for(let V=0;V<6;V++)Lt(_.__webglFramebuffer[V],A,V);else{const V=A.texture.mipmaps;V&&V.length>0?Lt(_.__webglFramebuffer[0],A,0):Lt(_.__webglFramebuffer,A,0)}else if(k){_.__webglDepthbuffer=[];for(let V=0;V<6;V++)if(e.bindFramebuffer(s.FRAMEBUFFER,_.__webglFramebuffer[V]),_.__webglDepthbuffer[V]===void 0)_.__webglDepthbuffer[V]=s.createRenderbuffer(),Ft(_.__webglDepthbuffer[V],A,!1);else{const Z=A.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT,at=_.__webglDepthbuffer[V];s.bindRenderbuffer(s.RENDERBUFFER,at),s.framebufferRenderbuffer(s.FRAMEBUFFER,Z,s.RENDERBUFFER,at)}}else{const V=A.texture.mipmaps;if(V&&V.length>0?e.bindFramebuffer(s.FRAMEBUFFER,_.__webglFramebuffer[0]):e.bindFramebuffer(s.FRAMEBUFFER,_.__webglFramebuffer),_.__webglDepthbuffer===void 0)_.__webglDepthbuffer=s.createRenderbuffer(),Ft(_.__webglDepthbuffer,A,!1);else{const Z=A.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT,at=_.__webglDepthbuffer;s.bindRenderbuffer(s.RENDERBUFFER,at),s.framebufferRenderbuffer(s.FRAMEBUFFER,Z,s.RENDERBUFFER,at)}}e.bindFramebuffer(s.FRAMEBUFFER,null)}function Zt(A,_,k){const V=n.get(A);_!==void 0&&rt(V.__webglFramebuffer,A,A.texture,s.COLOR_ATTACHMENT0,s.TEXTURE_2D,0),k!==void 0&&Ht(A)}function Jt(A){const _=A.texture,k=n.get(A),V=n.get(_);A.addEventListener("dispose",x);const Z=A.textures,at=A.isWebGLCubeRenderTarget===!0,ct=Z.length>1;if(ct||(V.__webglTexture===void 0&&(V.__webglTexture=s.createTexture()),V.__version=_.version,a.memory.textures++),at){k.__webglFramebuffer=[];for(let J=0;J<6;J++)if(_.mipmaps&&_.mipmaps.length>0){k.__webglFramebuffer[J]=[];for(let et=0;et<_.mipmaps.length;et++)k.__webglFramebuffer[J][et]=s.createFramebuffer()}else k.__webglFramebuffer[J]=s.createFramebuffer()}else{if(_.mipmaps&&_.mipmaps.length>0){k.__webglFramebuffer=[];for(let J=0;J<_.mipmaps.length;J++)k.__webglFramebuffer[J]=s.createFramebuffer()}else k.__webglFramebuffer=s.createFramebuffer();if(ct)for(let J=0,et=Z.length;J0&&Ae(A)===!1){k.__webglMultisampledFramebuffer=s.createFramebuffer(),k.__webglColorRenderbuffer=[],e.bindFramebuffer(s.FRAMEBUFFER,k.__webglMultisampledFramebuffer);for(let J=0;J0)for(let et=0;et<_.mipmaps.length;et++)rt(k.__webglFramebuffer[J][et],A,_,s.COLOR_ATTACHMENT0,s.TEXTURE_CUBE_MAP_POSITIVE_X+J,et);else rt(k.__webglFramebuffer[J],A,_,s.COLOR_ATTACHMENT0,s.TEXTURE_CUBE_MAP_POSITIVE_X+J,0);g(_)&&w(s.TEXTURE_CUBE_MAP),e.unbindTexture()}else if(ct){for(let J=0,et=Z.length;J0)for(let et=0;et<_.mipmaps.length;et++)rt(k.__webglFramebuffer[et],A,_,s.COLOR_ATTACHMENT0,J,et);else rt(k.__webglFramebuffer,A,_,s.COLOR_ATTACHMENT0,J,0);g(_)&&w(J),e.unbindTexture()}A.depthBuffer&&Ht(A)}function te(A){const _=A.textures;for(let k=0,V=_.length;k0){if(Ae(A)===!1){const _=A.textures,k=A.width,V=A.height;let Z=s.COLOR_BUFFER_BIT;const at=A.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT,ct=n.get(A),J=_.length>1;if(J)for(let ut=0;ut<_.length;ut++)e.bindFramebuffer(s.FRAMEBUFFER,ct.__webglMultisampledFramebuffer),s.framebufferRenderbuffer(s.FRAMEBUFFER,s.COLOR_ATTACHMENT0+ut,s.RENDERBUFFER,null),e.bindFramebuffer(s.FRAMEBUFFER,ct.__webglFramebuffer),s.framebufferTexture2D(s.DRAW_FRAMEBUFFER,s.COLOR_ATTACHMENT0+ut,s.TEXTURE_2D,null,0);e.bindFramebuffer(s.READ_FRAMEBUFFER,ct.__webglMultisampledFramebuffer);const et=A.texture.mipmaps;et&&et.length>0?e.bindFramebuffer(s.DRAW_FRAMEBUFFER,ct.__webglFramebuffer[0]):e.bindFramebuffer(s.DRAW_FRAMEBUFFER,ct.__webglFramebuffer);for(let ut=0;ut<_.length;ut++){if(A.resolveDepthBuffer&&(A.depthBuffer&&(Z|=s.DEPTH_BUFFER_BIT),A.stencilBuffer&&A.resolveStencilBuffer&&(Z|=s.STENCIL_BUFFER_BIT)),J){s.framebufferRenderbuffer(s.READ_FRAMEBUFFER,s.COLOR_ATTACHMENT0,s.RENDERBUFFER,ct.__webglColorRenderbuffer[ut]);const At=n.get(_[ut]).__webglTexture;s.framebufferTexture2D(s.DRAW_FRAMEBUFFER,s.COLOR_ATTACHMENT0,s.TEXTURE_2D,At,0)}s.blitFramebuffer(0,0,k,V,0,0,k,V,Z,s.NEAREST),l===!0&&(le.length=0,ce.length=0,le.push(s.COLOR_ATTACHMENT0+ut),A.depthBuffer&&A.resolveDepthBuffer===!1&&(le.push(at),ce.push(at),s.invalidateFramebuffer(s.DRAW_FRAMEBUFFER,ce)),s.invalidateFramebuffer(s.READ_FRAMEBUFFER,le))}if(e.bindFramebuffer(s.READ_FRAMEBUFFER,null),e.bindFramebuffer(s.DRAW_FRAMEBUFFER,null),J)for(let ut=0;ut<_.length;ut++){e.bindFramebuffer(s.FRAMEBUFFER,ct.__webglMultisampledFramebuffer),s.framebufferRenderbuffer(s.FRAMEBUFFER,s.COLOR_ATTACHMENT0+ut,s.RENDERBUFFER,ct.__webglColorRenderbuffer[ut]);const At=n.get(_[ut]).__webglTexture;e.bindFramebuffer(s.FRAMEBUFFER,ct.__webglFramebuffer),s.framebufferTexture2D(s.DRAW_FRAMEBUFFER,s.COLOR_ATTACHMENT0+ut,s.TEXTURE_2D,At,0)}e.bindFramebuffer(s.DRAW_FRAMEBUFFER,ct.__webglMultisampledFramebuffer)}else if(A.depthBuffer&&A.resolveDepthBuffer===!1&&l){const _=A.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT;s.invalidateFramebuffer(s.DRAW_FRAMEBUFFER,[_])}}}function ge(A){return Math.min(i.maxSamples,A.samples)}function Ae(A){const _=n.get(A);return A.samples>0&&t.has("WEBGL_multisampled_render_to_texture")===!0&&_.__useRenderToTexture!==!1}function U(A){const _=a.render.frame;u.get(A)!==_&&(u.set(A,_),A.update())}function Ke(A,_){const k=A.colorSpace,V=A.format,Z=A.type;return A.isCompressedTexture===!0||A.isVideoTexture===!0||k!==Ps&&k!==ti&&(Kt.getTransfer(k)===ie?(V!==dn||Z!==Ze)&&Nt("WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType."):Qt("WebGLTextures: Unsupported texture color space:",k)),_}function re(A){return typeof HTMLImageElement<"u"&&A instanceof HTMLImageElement?(c.width=A.naturalWidth||A.width,c.height=A.naturalHeight||A.height):typeof VideoFrame<"u"&&A instanceof VideoFrame?(c.width=A.displayWidth,c.height=A.displayHeight):(c.width=A.width,c.height=A.height),c}this.allocateTextureUnit=K,this.resetTextureUnits=q,this.getTextureUnits=Y,this.setTextureUnits=B,this.setTexture2D=Q,this.setTexture2DArray=it,this.setTexture3D=pt,this.setTextureCube=_t,this.rebindTextures=Zt,this.setupRenderTarget=Jt,this.updateRenderTargetMipmap=te,this.updateMultisampleRenderTarget=Te,this.setupDepthRenderbuffer=Ht,this.setupFrameBufferTexture=rt,this.useMultisampledRTT=Ae,this.isReversedDepthBuffer=function(){return e.buffers.depth.getReversed()}}function w_(s,t){function e(n,i=ti){let r;const a=Kt.getTransfer(i);if(n===Ze)return s.UNSIGNED_BYTE;if(n===Ha)return s.UNSIGNED_SHORT_4_4_4_4;if(n===Ga)return s.UNSIGNED_SHORT_5_5_5_1;if(n===uc)return s.UNSIGNED_INT_5_9_9_9_REV;if(n===dc)return s.UNSIGNED_INT_10F_11F_11F_REV;if(n===cc)return s.BYTE;if(n===hc)return s.SHORT;if(n===Cs)return s.UNSIGNED_SHORT;if(n===za)return s.INT;if(n===Tn)return s.UNSIGNED_INT;if(n===un)return s.FLOAT;if(n===Je)return s.HALF_FLOAT;if(n===fc)return s.ALPHA;if(n===pc)return s.RGB;if(n===dn)return s.RGBA;if(n===Bn)return s.DEPTH_COMPONENT;if(n===Ai)return s.DEPTH_STENCIL;if(n===Va)return s.RED;if(n===Wa)return s.RED_INTEGER;if(n===Ci)return s.RG;if(n===$a)return s.RG_INTEGER;if(n===Xa)return s.RGBA_INTEGER;if(n===hr||n===ur||n===dr||n===fr)if(a===ie)if(r=t.get("WEBGL_compressed_texture_s3tc_srgb"),r!==null){if(n===hr)return r.COMPRESSED_SRGB_S3TC_DXT1_EXT;if(n===ur)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;if(n===dr)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;if(n===fr)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}else return null;else if(r=t.get("WEBGL_compressed_texture_s3tc"),r!==null){if(n===hr)return r.COMPRESSED_RGB_S3TC_DXT1_EXT;if(n===ur)return r.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(n===dr)return r.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(n===fr)return r.COMPRESSED_RGBA_S3TC_DXT5_EXT}else return null;if(n===qa||n===Ya||n===Ka||n===Za)if(r=t.get("WEBGL_compressed_texture_pvrtc"),r!==null){if(n===qa)return r.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(n===Ya)return r.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(n===Ka)return r.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(n===Za)return r.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}else return null;if(n===Ja||n===Qa||n===ja||n===to||n===eo||n===pr||n===no)if(r=t.get("WEBGL_compressed_texture_etc"),r!==null){if(n===Ja||n===Qa)return a===ie?r.COMPRESSED_SRGB8_ETC2:r.COMPRESSED_RGB8_ETC2;if(n===ja)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:r.COMPRESSED_RGBA8_ETC2_EAC;if(n===to)return r.COMPRESSED_R11_EAC;if(n===eo)return r.COMPRESSED_SIGNED_R11_EAC;if(n===pr)return r.COMPRESSED_RG11_EAC;if(n===no)return r.COMPRESSED_SIGNED_RG11_EAC}else return null;if(n===io||n===so||n===ro||n===ao||n===oo||n===lo||n===co||n===ho||n===uo||n===fo||n===po||n===mo||n===go||n===_o)if(r=t.get("WEBGL_compressed_texture_astc"),r!==null){if(n===io)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:r.COMPRESSED_RGBA_ASTC_4x4_KHR;if(n===so)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:r.COMPRESSED_RGBA_ASTC_5x4_KHR;if(n===ro)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:r.COMPRESSED_RGBA_ASTC_5x5_KHR;if(n===ao)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:r.COMPRESSED_RGBA_ASTC_6x5_KHR;if(n===oo)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:r.COMPRESSED_RGBA_ASTC_6x6_KHR;if(n===lo)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:r.COMPRESSED_RGBA_ASTC_8x5_KHR;if(n===co)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:r.COMPRESSED_RGBA_ASTC_8x6_KHR;if(n===ho)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:r.COMPRESSED_RGBA_ASTC_8x8_KHR;if(n===uo)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:r.COMPRESSED_RGBA_ASTC_10x5_KHR;if(n===fo)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:r.COMPRESSED_RGBA_ASTC_10x6_KHR;if(n===po)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:r.COMPRESSED_RGBA_ASTC_10x8_KHR;if(n===mo)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:r.COMPRESSED_RGBA_ASTC_10x10_KHR;if(n===go)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:r.COMPRESSED_RGBA_ASTC_12x10_KHR;if(n===_o)return a===ie?r.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:r.COMPRESSED_RGBA_ASTC_12x12_KHR}else return null;if(n===xo||n===vo||n===Mo)if(r=t.get("EXT_texture_compression_bptc"),r!==null){if(n===xo)return a===ie?r.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:r.COMPRESSED_RGBA_BPTC_UNORM_EXT;if(n===vo)return r.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;if(n===Mo)return r.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT}else return null;if(n===yo||n===So||n===mr||n===bo)if(r=t.get("EXT_texture_compression_rgtc"),r!==null){if(n===yo)return r.COMPRESSED_RED_RGTC1_EXT;if(n===So)return r.COMPRESSED_SIGNED_RED_RGTC1_EXT;if(n===mr)return r.COMPRESSED_RED_GREEN_RGTC2_EXT;if(n===bo)return r.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT}else return null;return n===Rs?s.UNSIGNED_INT_24_8:s[n]!==void 0?s[n]:null}return{convert:e}}const E_=` +}`,Uv=[new P(1,0,0),new P(-1,0,0),new P(0,1,0),new P(0,-1,0),new P(0,0,1),new P(0,0,-1)],Fv=[new P(0,-1,0),new P(0,-1,0),new P(0,0,1),new P(0,0,-1),new P(0,-1,0),new P(0,-1,0)],Iu=new re,ur=new P,Xl=new P;function Ov(s,t,e){let n=new ro;const i=new pt,r=new pt,o=new ge,a=new ym,l=new Mm,c={},u=e.maxTextureSize,h={[oi]:We,[We]:oi,[Hn]:Hn},d=new Pe({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new pt},radius:{value:4}},vertexShader:Iv,fragmentShader:Nv}),f=d.clone();f.defines.HORIZONTAL_PASS=1;const p=new He;p.setAttribute("position",new ln(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));const x=new zt(p,d),m=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=Er;let g=this.type;this.render=function(w,C,v){if(m.enabled===!1||m.autoUpdate===!1&&m.needsUpdate===!1||w.length===0)return;this.type===Ff&&(Ut("WebGLShadowMap: PCFSoftShadowMap has been deprecated. Using PCFShadowMap instead."),this.type=Er);const T=s.getRenderTarget(),L=s.getActiveCubeFace(),D=s.getActiveMipmapLevel(),U=s.state;U.setBlending(Tn),U.buffers.depth.getReversed()===!0?U.buffers.color.setClear(0,0,0,0):U.buffers.color.setClear(1,1,1,1),U.buffers.depth.setTest(!0),U.setScissorTest(!1);const Y=g!==this.type;Y&&C.traverse(function(K){K.material&&(Array.isArray(K.material)?K.material.forEach(N=>N.needsUpdate=!0):K.material.needsUpdate=!0)});for(let K=0,N=w.length;Ku||i.y>u)&&(i.x>u&&(r.x=Math.floor(u/Z.x),i.x=r.x*Z.x,z.mapSize.x=r.x),i.y>u&&(r.y=Math.floor(u/Z.y),i.y=r.y*Z.y,z.mapSize.y=r.y));const nt=s.state.buffers.depth.getReversed();if(z.camera._reversedDepth=nt,z.map===null||Y===!0){if(z.map!==null&&(z.map.depthTexture!==null&&(z.map.depthTexture.dispose(),z.map.depthTexture=null),z.map.dispose()),this.type===Ws){if(B.isPointLight){Ut("WebGLShadowMap: VSM shadow maps are not supported for PointLights. Use PCF or BasicShadowMap instead.");continue}z.map=new Ye(i.x,i.y,{format:Fi,type:Qe,minFilter:Oe,magFilter:Oe,generateMipmaps:!1}),z.map.texture.name=B.name+".shadowMap",z.map.depthTexture=new Ts(i.x,i.y,mn),z.map.depthTexture.name=B.name+".shadowMapDepth",z.map.depthTexture.format=Vn,z.map.depthTexture.compareFunction=null,z.map.depthTexture.minFilter=Fe,z.map.depthTexture.magFilter=Fe}else B.isPointLight?(z.map=new du(i.x),z.map.depthTexture=new em(i.x,Cn)):(z.map=new Ye(i.x,i.y),z.map.depthTexture=new Ts(i.x,i.y,Cn)),z.map.depthTexture.name=B.name+".shadowMap",z.map.depthTexture.format=Vn,this.type===Er?(z.map.depthTexture.compareFunction=nt?el:tl,z.map.depthTexture.minFilter=Oe,z.map.depthTexture.magFilter=Oe):(z.map.depthTexture.compareFunction=null,z.map.depthTexture.minFilter=Fe,z.map.depthTexture.magFilter=Fe);z.camera.updateProjectionMatrix()}const rt=z.map.isWebGLCubeRenderTarget?6:1;for(let ot=0;ot0||C.map&&C.alphaTest>0||C.alphaToCoverage===!0){const U=L.uuid,Y=C.uuid;let K=c[U];K===void 0&&(K={},c[U]=K);let N=K[Y];N===void 0&&(N=L.clone(),K[Y]=N,C.addEventListener("dispose",M)),L=N}if(L.visible=C.visible,L.wireframe=C.wireframe,T===Ws?L.side=C.shadowSide!==null?C.shadowSide:C.side:L.side=C.shadowSide!==null?C.shadowSide:h[C.side],L.alphaMap=C.alphaMap,L.alphaTest=C.alphaToCoverage===!0?.5:C.alphaTest,L.map=C.map,L.clipShadows=C.clipShadows,L.clippingPlanes=C.clippingPlanes,L.clipIntersection=C.clipIntersection,L.displacementMap=C.displacementMap,L.displacementScale=C.displacementScale,L.displacementBias=C.displacementBias,L.wireframeLinewidth=C.wireframeLinewidth,L.linewidth=C.linewidth,v.isPointLight===!0&&L.isMeshDistanceMaterial===!0){const U=s.properties.get(L);U.light=v}return L}function y(w,C,v,T,L){if(w.visible===!1)return;if(w.layers.test(C.layers)&&(w.isMesh||w.isLine||w.isPoints)&&(w.castShadow||w.receiveShadow&&L===Ws)&&(!w.frustumCulled||n.intersectsObject(w))){w.modelViewMatrix.multiplyMatrices(v.matrixWorldInverse,w.matrixWorld);const Y=t.update(w),K=w.material;if(Array.isArray(K)){const N=Y.groups;for(let B=0,z=N.length;B=1):nt.indexOf("OpenGL ES")!==-1&&(Z=parseFloat(/^OpenGL ES (\d)/.exec(nt)[1]),z=Z>=2);let rt=null,ot={};const ht=s.getParameter(s.SCISSOR_BOX),Gt=s.getParameter(s.VIEWPORT),me=new ge().fromArray(ht),ee=new ge().fromArray(Gt);function Q(F,ut,tt,xt){const bt=new Uint8Array(4),it=s.createTexture();s.bindTexture(F,it),s.texParameteri(F,s.TEXTURE_MIN_FILTER,s.NEAREST),s.texParameteri(F,s.TEXTURE_MAG_FILTER,s.NEAREST);for(let At=0;At"u"?!1:/OculusBrowser/g.test(navigator.userAgent),c=new pt,u=new WeakMap,h=new Set;let d;const f=new WeakMap;let p=!1;try{p=typeof OffscreenCanvas<"u"&&new OffscreenCanvas(1,1).getContext("2d")!==null}catch{}function x(A,_){return p?new OffscreenCanvas(A,_):kr("canvas")}function m(A,_,H){let $=1;const J=oe(A);if((J.width>H||J.height>H)&&($=H/Math.max(J.width,J.height)),$<1)if(typeof HTMLImageElement<"u"&&A instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&A instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&A instanceof ImageBitmap||typeof VideoFrame<"u"&&A instanceof VideoFrame){const ct=Math.floor($*J.width),ft=Math.floor($*J.height);d===void 0&&(d=x(ct,ft));const j=_?x(ct,ft):d;return j.width=ct,j.height=ft,j.getContext("2d").drawImage(A,0,0,ct,ft),Ut("WebGLRenderer: Texture has been resized from ("+J.width+"x"+J.height+") to ("+ct+"x"+ft+")."),j}else return"data"in A&&Ut("WebGLRenderer: Image in DataTexture is too big ("+J.width+"x"+J.height+")."),A;return A}function g(A){return A.generateMipmaps}function b(A){s.generateMipmap(A)}function E(A){return A.isWebGLCubeRenderTarget?s.TEXTURE_CUBE_MAP:A.isWebGL3DRenderTarget?s.TEXTURE_3D:A.isWebGLArrayRenderTarget||A.isCompressedArrayTexture?s.TEXTURE_2D_ARRAY:s.TEXTURE_2D}function y(A,_,H,$,J,ct=!1){if(A!==null){if(s[A]!==void 0)return s[A];Ut("WebGLRenderer: Attempt to use non-existing WebGL internal format '"+A+"'")}let ft;$&&(ft=t.get("EXT_texture_norm16"),ft||Ut("WebGLRenderer: Unable to use normalized textures without EXT_texture_norm16 extension"));let j=_;if(_===s.RED&&(H===s.FLOAT&&(j=s.R32F),H===s.HALF_FLOAT&&(j=s.R16F),H===s.UNSIGNED_BYTE&&(j=s.R8),H===s.UNSIGNED_SHORT&&ft&&(j=ft.R16_EXT),H===s.SHORT&&ft&&(j=ft.R16_SNORM_EXT)),_===s.RED_INTEGER&&(H===s.UNSIGNED_BYTE&&(j=s.R8UI),H===s.UNSIGNED_SHORT&&(j=s.R16UI),H===s.UNSIGNED_INT&&(j=s.R32UI),H===s.BYTE&&(j=s.R8I),H===s.SHORT&&(j=s.R16I),H===s.INT&&(j=s.R32I)),_===s.RG&&(H===s.FLOAT&&(j=s.RG32F),H===s.HALF_FLOAT&&(j=s.RG16F),H===s.UNSIGNED_BYTE&&(j=s.RG8),H===s.UNSIGNED_SHORT&&ft&&(j=ft.RG16_EXT),H===s.SHORT&&ft&&(j=ft.RG16_SNORM_EXT)),_===s.RG_INTEGER&&(H===s.UNSIGNED_BYTE&&(j=s.RG8UI),H===s.UNSIGNED_SHORT&&(j=s.RG16UI),H===s.UNSIGNED_INT&&(j=s.RG32UI),H===s.BYTE&&(j=s.RG8I),H===s.SHORT&&(j=s.RG16I),H===s.INT&&(j=s.RG32I)),_===s.RGB_INTEGER&&(H===s.UNSIGNED_BYTE&&(j=s.RGB8UI),H===s.UNSIGNED_SHORT&&(j=s.RGB16UI),H===s.UNSIGNED_INT&&(j=s.RGB32UI),H===s.BYTE&&(j=s.RGB8I),H===s.SHORT&&(j=s.RGB16I),H===s.INT&&(j=s.RGB32I)),_===s.RGBA_INTEGER&&(H===s.UNSIGNED_BYTE&&(j=s.RGBA8UI),H===s.UNSIGNED_SHORT&&(j=s.RGBA16UI),H===s.UNSIGNED_INT&&(j=s.RGBA32UI),H===s.BYTE&&(j=s.RGBA8I),H===s.SHORT&&(j=s.RGBA16I),H===s.INT&&(j=s.RGBA32I)),_===s.RGB&&(H===s.UNSIGNED_SHORT&&ft&&(j=ft.RGB16_EXT),H===s.SHORT&&ft&&(j=ft.RGB16_SNORM_EXT),H===s.UNSIGNED_INT_5_9_9_9_REV&&(j=s.RGB9_E5),H===s.UNSIGNED_INT_10F_11F_11F_REV&&(j=s.R11F_G11F_B10F)),_===s.RGBA){const et=ct?Or:Jt.getTransfer(J);H===s.FLOAT&&(j=s.RGBA32F),H===s.HALF_FLOAT&&(j=s.RGBA16F),H===s.UNSIGNED_BYTE&&(j=et===se?s.SRGB8_ALPHA8:s.RGBA8),H===s.UNSIGNED_SHORT&&ft&&(j=ft.RGBA16_EXT),H===s.SHORT&&ft&&(j=ft.RGBA16_SNORM_EXT),H===s.UNSIGNED_SHORT_4_4_4_4&&(j=s.RGBA4),H===s.UNSIGNED_SHORT_5_5_5_1&&(j=s.RGB5_A1)}return(j===s.R16F||j===s.R32F||j===s.RG16F||j===s.RG32F||j===s.RGBA16F||j===s.RGBA32F)&&t.get("EXT_color_buffer_float"),j}function M(A,_){let H;return A?_===null||_===Cn||_===Xs?H=s.DEPTH24_STENCIL8:_===mn?H=s.DEPTH32F_STENCIL8:_===$s&&(H=s.DEPTH24_STENCIL8,Ut("DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.")):_===null||_===Cn||_===Xs?H=s.DEPTH_COMPONENT24:_===mn?H=s.DEPTH_COMPONENT32F:_===$s&&(H=s.DEPTH_COMPONENT16),H}function w(A,_){return g(A)===!0||A.isFramebufferTexture&&A.minFilter!==Fe&&A.minFilter!==Oe?Math.log2(Math.max(_.width,_.height))+1:A.mipmaps!==void 0&&A.mipmaps.length>0?A.mipmaps.length:A.isCompressedTexture&&Array.isArray(A.image)?_.mipmaps.length:1}function C(A){const _=A.target;_.removeEventListener("dispose",C),T(_),_.isVideoTexture&&u.delete(_),_.isHTMLTexture&&h.delete(_)}function v(A){const _=A.target;_.removeEventListener("dispose",v),D(_)}function T(A){const _=n.get(A);if(_.__webglInit===void 0)return;const H=A.source,$=f.get(H);if($){const J=$[_.__cacheKey];J.usedTimes--,J.usedTimes===0&&L(A),Object.keys($).length===0&&f.delete(H)}n.remove(A)}function L(A){const _=n.get(A);s.deleteTexture(_.__webglTexture);const H=A.source,$=f.get(H);delete $[_.__cacheKey],o.memory.textures--}function D(A){const _=n.get(A);if(A.depthTexture&&(A.depthTexture.dispose(),n.remove(A.depthTexture)),A.isWebGLCubeRenderTarget)for(let $=0;$<6;$++){if(Array.isArray(_.__webglFramebuffer[$]))for(let J=0;J<_.__webglFramebuffer[$].length;J++)s.deleteFramebuffer(_.__webglFramebuffer[$][J]);else s.deleteFramebuffer(_.__webglFramebuffer[$]);_.__webglDepthbuffer&&s.deleteRenderbuffer(_.__webglDepthbuffer[$])}else{if(Array.isArray(_.__webglFramebuffer))for(let $=0;$<_.__webglFramebuffer.length;$++)s.deleteFramebuffer(_.__webglFramebuffer[$]);else s.deleteFramebuffer(_.__webglFramebuffer);if(_.__webglDepthbuffer&&s.deleteRenderbuffer(_.__webglDepthbuffer),_.__webglMultisampledFramebuffer&&s.deleteFramebuffer(_.__webglMultisampledFramebuffer),_.__webglColorRenderbuffer)for(let $=0;$<_.__webglColorRenderbuffer.length;$++)_.__webglColorRenderbuffer[$]&&s.deleteRenderbuffer(_.__webglColorRenderbuffer[$]);_.__webglDepthRenderbuffer&&s.deleteRenderbuffer(_.__webglDepthRenderbuffer)}const H=A.textures;for(let $=0,J=H.length;$=i.maxTextures&&Ut("WebGLTextures: Trying to use "+A+" texture units while this GPU supports only "+i.maxTextures),U+=1,A}function z(A){const _=[];return _.push(A.wrapS),_.push(A.wrapT),_.push(A.wrapR||0),_.push(A.magFilter),_.push(A.minFilter),_.push(A.anisotropy),_.push(A.internalFormat),_.push(A.format),_.push(A.type),_.push(A.generateMipmaps),_.push(A.premultiplyAlpha),_.push(A.flipY),_.push(A.unpackAlignment),_.push(A.colorSpace),_.join()}function Z(A,_){const H=n.get(A);if(A.isVideoTexture&&O(A),A.isRenderTargetTexture===!1&&A.isExternalTexture!==!0&&A.version>0&&H.__version!==A.version){const $=A.image;if($===null)Ut("WebGLRenderer: Texture marked for update but no image data found.");else if($.complete===!1)Ut("WebGLRenderer: Texture marked for update but image is incomplete");else{st(H,A,_);return}}else A.isExternalTexture&&(H.__webglTexture=A.sourceTexture?A.sourceTexture:null);e.bindTexture(s.TEXTURE_2D,H.__webglTexture,s.TEXTURE0+_)}function nt(A,_){const H=n.get(A);if(A.isRenderTargetTexture===!1&&A.version>0&&H.__version!==A.version){st(H,A,_);return}else A.isExternalTexture&&(H.__webglTexture=A.sourceTexture?A.sourceTexture:null);e.bindTexture(s.TEXTURE_2D_ARRAY,H.__webglTexture,s.TEXTURE0+_)}function rt(A,_){const H=n.get(A);if(A.isRenderTargetTexture===!1&&A.version>0&&H.__version!==A.version){st(H,A,_);return}e.bindTexture(s.TEXTURE_3D,H.__webglTexture,s.TEXTURE0+_)}function ot(A,_){const H=n.get(A);if(A.isCubeDepthTexture!==!0&&A.version>0&&H.__version!==A.version){dt(H,A,_);return}e.bindTexture(s.TEXTURE_CUBE_MAP,H.__webglTexture,s.TEXTURE0+_)}const ht={[Rr]:s.REPEAT,[Gn]:s.CLAMP_TO_EDGE,[pa]:s.MIRRORED_REPEAT},Gt={[Fe]:s.NEAREST,[ip]:s.NEAREST_MIPMAP_NEAREST,[Pr]:s.NEAREST_MIPMAP_LINEAR,[Oe]:s.LINEAR,[ma]:s.LINEAR_MIPMAP_NEAREST,[Ni]:s.LINEAR_MIPMAP_LINEAR},me={[op]:s.NEVER,[up]:s.ALWAYS,[ap]:s.LESS,[tl]:s.LEQUAL,[lp]:s.EQUAL,[el]:s.GEQUAL,[cp]:s.GREATER,[hp]:s.NOTEQUAL};function ee(A,_){if(_.type===mn&&t.has("OES_texture_float_linear")===!1&&(_.magFilter===Oe||_.magFilter===ma||_.magFilter===Pr||_.magFilter===Ni||_.minFilter===Oe||_.minFilter===ma||_.minFilter===Pr||_.minFilter===Ni)&&Ut("WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device."),s.texParameteri(A,s.TEXTURE_WRAP_S,ht[_.wrapS]),s.texParameteri(A,s.TEXTURE_WRAP_T,ht[_.wrapT]),(A===s.TEXTURE_3D||A===s.TEXTURE_2D_ARRAY)&&s.texParameteri(A,s.TEXTURE_WRAP_R,ht[_.wrapR]),s.texParameteri(A,s.TEXTURE_MAG_FILTER,Gt[_.magFilter]),s.texParameteri(A,s.TEXTURE_MIN_FILTER,Gt[_.minFilter]),_.compareFunction&&(s.texParameteri(A,s.TEXTURE_COMPARE_MODE,s.COMPARE_REF_TO_TEXTURE),s.texParameteri(A,s.TEXTURE_COMPARE_FUNC,me[_.compareFunction])),t.has("EXT_texture_filter_anisotropic")===!0){if(_.magFilter===Fe||_.minFilter!==Pr&&_.minFilter!==Ni||_.type===mn&&t.has("OES_texture_float_linear")===!1)return;if(_.anisotropy>1||n.get(_).__currentAnisotropy){const H=t.get("EXT_texture_filter_anisotropic");s.texParameterf(A,H.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(_.anisotropy,i.getMaxAnisotropy())),n.get(_).__currentAnisotropy=_.anisotropy}}}function Q(A,_){let H=!1;A.__webglInit===void 0&&(A.__webglInit=!0,_.addEventListener("dispose",C));const $=_.source;let J=f.get($);J===void 0&&(J={},f.set($,J));const ct=z(_);if(ct!==A.__cacheKey){J[ct]===void 0&&(J[ct]={texture:s.createTexture(),usedTimes:0},o.memory.textures++,H=!0),J[ct].usedTimes++;const ft=J[A.__cacheKey];ft!==void 0&&(J[A.__cacheKey].usedTimes--,ft.usedTimes===0&&L(_)),A.__cacheKey=ct,A.__webglTexture=J[ct].texture}return H}function I(A,_,H){return Math.floor(Math.floor(A/H)/_)}function X(A,_,H,$){const ct=A.updateRanges;if(ct.length===0)e.texSubImage2D(s.TEXTURE_2D,0,0,0,_.width,_.height,H,$,_.data);else{ct.sort((Ct,_t)=>Ct.start-_t.start);let ft=0;for(let Ct=1;Ct0){Ft&&$t&&e.texStorage2D(s.TEXTURE_2D,ut,_t,Nt[0].width,Nt[0].height);for(let tt=0,xt=Nt.length;tt0){const bt=iu(gt.width,gt.height,_.format,_.type);for(const it of _.layerUpdates){const At=gt.data.subarray(it*bt/gt.data.BYTES_PER_ELEMENT,(it+1)*bt/gt.data.BYTES_PER_ELEMENT);e.compressedTexSubImage3D(s.TEXTURE_2D_ARRAY,tt,0,0,it,gt.width,gt.height,1,mt,At)}_.clearLayerUpdates()}else e.compressedTexSubImage3D(s.TEXTURE_2D_ARRAY,tt,0,0,0,gt.width,gt.height,et.depth,mt,gt.data)}else e.compressedTexImage3D(s.TEXTURE_2D_ARRAY,tt,_t,gt.width,gt.height,et.depth,0,gt.data,0,0);else Ut("WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()");else Ft?F&&e.texSubImage3D(s.TEXTURE_2D_ARRAY,tt,0,0,0,gt.width,gt.height,et.depth,mt,Ct,gt.data):e.texImage3D(s.TEXTURE_2D_ARRAY,tt,_t,gt.width,gt.height,et.depth,0,mt,Ct,gt.data)}else{Ft&&$t&&e.texStorage2D(s.TEXTURE_2D,ut,_t,Nt[0].width,Nt[0].height);for(let tt=0,xt=Nt.length;tt0){const tt=iu(et.width,et.height,_.format,_.type);for(const xt of _.layerUpdates){const bt=et.data.subarray(xt*tt/et.data.BYTES_PER_ELEMENT,(xt+1)*tt/et.data.BYTES_PER_ELEMENT);e.texSubImage3D(s.TEXTURE_2D_ARRAY,0,0,0,xt,et.width,et.height,1,mt,Ct,bt)}_.clearLayerUpdates()}else e.texSubImage3D(s.TEXTURE_2D_ARRAY,0,0,0,0,et.width,et.height,et.depth,mt,Ct,et.data)}else e.texImage3D(s.TEXTURE_2D_ARRAY,0,_t,et.width,et.height,et.depth,0,mt,Ct,et.data);else if(_.isData3DTexture)Ft?($t&&e.texStorage3D(s.TEXTURE_3D,ut,_t,et.width,et.height,et.depth),F&&e.texSubImage3D(s.TEXTURE_3D,0,0,0,0,et.width,et.height,et.depth,mt,Ct,et.data)):e.texImage3D(s.TEXTURE_3D,0,_t,et.width,et.height,et.depth,0,mt,Ct,et.data);else if(_.isFramebufferTexture){if($t)if(Ft)e.texStorage2D(s.TEXTURE_2D,ut,_t,et.width,et.height);else{let tt=et.width,xt=et.height;for(let bt=0;bt>=1,xt>>=1}}else if(_.isHTMLTexture){if("texElementImage2D"in s){const tt=s.canvas;if(tt.hasAttribute("layoutsubtree")||tt.setAttribute("layoutsubtree","true"),et.parentNode!==tt){tt.appendChild(et),h.add(_),tt.onpaint=xt=>{const bt=xt.changedElements;for(const it of h)bt.includes(it.image)&&(it.needsUpdate=!0)},tt.requestPaint();return}if(s.texElementImage2D.length===3)s.texElementImage2D(s.TEXTURE_2D,s.RGBA8,et);else{const bt=s.RGBA,it=s.RGBA,At=s.UNSIGNED_BYTE;s.texElementImage2D(s.TEXTURE_2D,0,bt,it,At,et)}s.texParameteri(s.TEXTURE_2D,s.TEXTURE_MIN_FILTER,s.LINEAR),s.texParameteri(s.TEXTURE_2D,s.TEXTURE_WRAP_S,s.CLAMP_TO_EDGE),s.texParameteri(s.TEXTURE_2D,s.TEXTURE_WRAP_T,s.CLAMP_TO_EDGE)}}else if(Nt.length>0){if(Ft&&$t){const tt=oe(Nt[0]);e.texStorage2D(s.TEXTURE_2D,ut,_t,tt.width,tt.height)}for(let tt=0,xt=Nt.length;tt0&&xt++;const it=oe(_t[0]);e.texStorage2D(s.TEXTURE_CUBE_MAP,xt,$t,it.width,it.height)}for(let it=0;it<6;it++)if(Ct){F?tt&&e.texSubImage2D(s.TEXTURE_CUBE_MAP_POSITIVE_X+it,0,0,0,_t[it].width,_t[it].height,Nt,Ft,_t[it].data):e.texImage2D(s.TEXTURE_CUBE_MAP_POSITIVE_X+it,0,$t,_t[it].width,_t[it].height,0,Nt,Ft,_t[it].data);for(let At=0;At>ct),gt=Math.max(1,_.height>>ct);J===s.TEXTURE_3D||J===s.TEXTURE_2D_ARRAY?e.texImage3D(J,ct,et,_t,gt,_.depth,0,ft,j,null):e.texImage2D(J,ct,et,_t,gt,0,ft,j,null)}e.bindFramebuffer(s.FRAMEBUFFER,A),Re(_)?a.framebufferTexture2DMultisampleEXT(s.FRAMEBUFFER,$,J,Ct.__webglTexture,0,ve(_)):(J===s.TEXTURE_2D||J>=s.TEXTURE_CUBE_MAP_POSITIVE_X&&J<=s.TEXTURE_CUBE_MAP_NEGATIVE_Z)&&s.framebufferTexture2D(s.FRAMEBUFFER,$,J,Ct.__webglTexture,ct),e.bindFramebuffer(s.FRAMEBUFFER,null)}function Ot(A,_,H){if(s.bindRenderbuffer(s.RENDERBUFFER,A),_.depthBuffer){const $=_.depthTexture,J=$&&$.isDepthTexture?$.type:null,ct=M(_.stencilBuffer,J),ft=_.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT;Re(_)?a.renderbufferStorageMultisampleEXT(s.RENDERBUFFER,ve(_),ct,_.width,_.height):H?s.renderbufferStorageMultisample(s.RENDERBUFFER,ve(_),ct,_.width,_.height):s.renderbufferStorage(s.RENDERBUFFER,ct,_.width,_.height),s.framebufferRenderbuffer(s.FRAMEBUFFER,ft,s.RENDERBUFFER,A)}else{const $=_.textures;for(let J=0;J<$.length;J++){const ct=$[J],ft=r.convert(ct.format,ct.colorSpace),j=r.convert(ct.type),et=y(ct.internalFormat,ft,j,ct.normalized,ct.colorSpace);Re(_)?a.renderbufferStorageMultisampleEXT(s.RENDERBUFFER,ve(_),et,_.width,_.height):H?s.renderbufferStorageMultisample(s.RENDERBUFFER,ve(_),et,_.width,_.height):s.renderbufferStorage(s.RENDERBUFFER,et,_.width,_.height)}}s.bindRenderbuffer(s.RENDERBUFFER,null)}function Dt(A,_,H){const $=_.isWebGLCubeRenderTarget===!0;if(e.bindFramebuffer(s.FRAMEBUFFER,A),!(_.depthTexture&&_.depthTexture.isDepthTexture))throw new Error("THREE.WebGLTextures: renderTarget.depthTexture must be an instance of THREE.DepthTexture.");const J=n.get(_.depthTexture);if(J.__renderTarget=_,(!J.__webglTexture||_.depthTexture.image.width!==_.width||_.depthTexture.image.height!==_.height)&&(_.depthTexture.image.width=_.width,_.depthTexture.image.height=_.height,_.depthTexture.needsUpdate=!0),$){if(J.__webglInit===void 0&&(J.__webglInit=!0,_.depthTexture.addEventListener("dispose",C)),J.__webglTexture===void 0){J.__webglTexture=s.createTexture(),e.bindTexture(s.TEXTURE_CUBE_MAP,J.__webglTexture),ee(s.TEXTURE_CUBE_MAP,_.depthTexture);const mt=r.convert(_.depthTexture.format),Ct=r.convert(_.depthTexture.type);let _t;_.depthTexture.format===Vn?_t=s.DEPTH_COMPONENT24:_.depthTexture.format===Ui&&(_t=s.DEPTH24_STENCIL8);for(let gt=0;gt<6;gt++)s.texImage2D(s.TEXTURE_CUBE_MAP_POSITIVE_X+gt,0,_t,_.width,_.height,0,mt,Ct,null)}}else Z(_.depthTexture,0);const ct=J.__webglTexture,ft=ve(_),j=$?s.TEXTURE_CUBE_MAP_POSITIVE_X+H:s.TEXTURE_2D,et=_.depthTexture.format===Ui?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT;if(_.depthTexture.format===Vn)Re(_)?a.framebufferTexture2DMultisampleEXT(s.FRAMEBUFFER,et,j,ct,0,ft):s.framebufferTexture2D(s.FRAMEBUFFER,et,j,ct,0);else if(_.depthTexture.format===Ui)Re(_)?a.framebufferTexture2DMultisampleEXT(s.FRAMEBUFFER,et,j,ct,0,ft):s.framebufferTexture2D(s.FRAMEBUFFER,et,j,ct,0);else throw new Error("THREE.WebGLTextures: Unknown depthTexture format.")}function Vt(A){const _=n.get(A),H=A.isWebGLCubeRenderTarget===!0;if(_.__boundDepthTexture!==A.depthTexture){const $=A.depthTexture;if(_.__depthDisposeCallback&&_.__depthDisposeCallback(),$){const J=()=>{delete _.__boundDepthTexture,delete _.__depthDisposeCallback,$.removeEventListener("dispose",J)};$.addEventListener("dispose",J),_.__depthDisposeCallback=J}_.__boundDepthTexture=$}if(A.depthTexture&&!_.__autoAllocateDepthBuffer)if(H)for(let $=0;$<6;$++)Dt(_.__webglFramebuffer[$],A,$);else{const $=A.texture.mipmaps;$&&$.length>0?Dt(_.__webglFramebuffer[0],A,0):Dt(_.__webglFramebuffer,A,0)}else if(H){_.__webglDepthbuffer=[];for(let $=0;$<6;$++)if(e.bindFramebuffer(s.FRAMEBUFFER,_.__webglFramebuffer[$]),_.__webglDepthbuffer[$]===void 0)_.__webglDepthbuffer[$]=s.createRenderbuffer(),Ot(_.__webglDepthbuffer[$],A,!1);else{const J=A.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT,ct=_.__webglDepthbuffer[$];s.bindRenderbuffer(s.RENDERBUFFER,ct),s.framebufferRenderbuffer(s.FRAMEBUFFER,J,s.RENDERBUFFER,ct)}}else{const $=A.texture.mipmaps;if($&&$.length>0?e.bindFramebuffer(s.FRAMEBUFFER,_.__webglFramebuffer[0]):e.bindFramebuffer(s.FRAMEBUFFER,_.__webglFramebuffer),_.__webglDepthbuffer===void 0)_.__webglDepthbuffer=s.createRenderbuffer(),Ot(_.__webglDepthbuffer,A,!1);else{const J=A.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT,ct=_.__webglDepthbuffer;s.bindRenderbuffer(s.RENDERBUFFER,ct),s.framebufferRenderbuffer(s.FRAMEBUFFER,J,s.RENDERBUFFER,ct)}}e.bindFramebuffer(s.FRAMEBUFFER,null)}function jt(A,_,H){const $=n.get(A);_!==void 0&<($.__webglFramebuffer,A,A.texture,s.COLOR_ATTACHMENT0,s.TEXTURE_2D,0),H!==void 0&&Vt(A)}function Qt(A){const _=A.texture,H=n.get(A),$=n.get(_);A.addEventListener("dispose",v);const J=A.textures,ct=A.isWebGLCubeRenderTarget===!0,ft=J.length>1;if(ft||($.__webglTexture===void 0&&($.__webglTexture=s.createTexture()),$.__version=_.version,o.memory.textures++),ct){H.__webglFramebuffer=[];for(let j=0;j<6;j++)if(_.mipmaps&&_.mipmaps.length>0){H.__webglFramebuffer[j]=[];for(let et=0;et<_.mipmaps.length;et++)H.__webglFramebuffer[j][et]=s.createFramebuffer()}else H.__webglFramebuffer[j]=s.createFramebuffer()}else{if(_.mipmaps&&_.mipmaps.length>0){H.__webglFramebuffer=[];for(let j=0;j<_.mipmaps.length;j++)H.__webglFramebuffer[j]=s.createFramebuffer()}else H.__webglFramebuffer=s.createFramebuffer();if(ft)for(let j=0,et=J.length;j0&&Re(A)===!1){H.__webglMultisampledFramebuffer=s.createFramebuffer(),H.__webglColorRenderbuffer=[],e.bindFramebuffer(s.FRAMEBUFFER,H.__webglMultisampledFramebuffer);for(let j=0;j0)for(let et=0;et<_.mipmaps.length;et++)lt(H.__webglFramebuffer[j][et],A,_,s.COLOR_ATTACHMENT0,s.TEXTURE_CUBE_MAP_POSITIVE_X+j,et);else lt(H.__webglFramebuffer[j],A,_,s.COLOR_ATTACHMENT0,s.TEXTURE_CUBE_MAP_POSITIVE_X+j,0);g(_)&&b(s.TEXTURE_CUBE_MAP),e.unbindTexture()}else if(ft){for(let j=0,et=J.length;j0)for(let et=0;et<_.mipmaps.length;et++)lt(H.__webglFramebuffer[et],A,_,s.COLOR_ATTACHMENT0,j,et);else lt(H.__webglFramebuffer,A,_,s.COLOR_ATTACHMENT0,j,0);g(_)&&b(j),e.unbindTexture()}A.depthBuffer&&Vt(A)}function ne(A){const _=A.textures;for(let H=0,$=_.length;H<$;H++){const J=_[H];if(g(J)){const ct=E(A),ft=n.get(J).__webglTexture;e.bindTexture(ct,ft),b(ct),e.unbindTexture()}}}const ce=[],he=[];function Ce(A){if(A.samples>0){if(Re(A)===!1){const _=A.textures,H=A.width,$=A.height;let J=s.COLOR_BUFFER_BIT;const ct=A.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT,ft=n.get(A),j=_.length>1;if(j)for(let mt=0;mt<_.length;mt++)e.bindFramebuffer(s.FRAMEBUFFER,ft.__webglMultisampledFramebuffer),s.framebufferRenderbuffer(s.FRAMEBUFFER,s.COLOR_ATTACHMENT0+mt,s.RENDERBUFFER,null),e.bindFramebuffer(s.FRAMEBUFFER,ft.__webglFramebuffer),s.framebufferTexture2D(s.DRAW_FRAMEBUFFER,s.COLOR_ATTACHMENT0+mt,s.TEXTURE_2D,null,0);e.bindFramebuffer(s.READ_FRAMEBUFFER,ft.__webglMultisampledFramebuffer);const et=A.texture.mipmaps;et&&et.length>0?e.bindFramebuffer(s.DRAW_FRAMEBUFFER,ft.__webglFramebuffer[0]):e.bindFramebuffer(s.DRAW_FRAMEBUFFER,ft.__webglFramebuffer);for(let mt=0;mt<_.length;mt++){if(A.resolveDepthBuffer&&(A.depthBuffer&&(J|=s.DEPTH_BUFFER_BIT),A.stencilBuffer&&A.resolveStencilBuffer&&(J|=s.STENCIL_BUFFER_BIT)),j){s.framebufferRenderbuffer(s.READ_FRAMEBUFFER,s.COLOR_ATTACHMENT0,s.RENDERBUFFER,ft.__webglColorRenderbuffer[mt]);const Ct=n.get(_[mt]).__webglTexture;s.framebufferTexture2D(s.DRAW_FRAMEBUFFER,s.COLOR_ATTACHMENT0,s.TEXTURE_2D,Ct,0)}s.blitFramebuffer(0,0,H,$,0,0,H,$,J,s.NEAREST),l===!0&&(ce.length=0,he.length=0,ce.push(s.COLOR_ATTACHMENT0+mt),A.depthBuffer&&A.resolveDepthBuffer===!1&&(ce.push(ct),he.push(ct),s.invalidateFramebuffer(s.DRAW_FRAMEBUFFER,he)),s.invalidateFramebuffer(s.READ_FRAMEBUFFER,ce))}if(e.bindFramebuffer(s.READ_FRAMEBUFFER,null),e.bindFramebuffer(s.DRAW_FRAMEBUFFER,null),j)for(let mt=0;mt<_.length;mt++){e.bindFramebuffer(s.FRAMEBUFFER,ft.__webglMultisampledFramebuffer),s.framebufferRenderbuffer(s.FRAMEBUFFER,s.COLOR_ATTACHMENT0+mt,s.RENDERBUFFER,ft.__webglColorRenderbuffer[mt]);const Ct=n.get(_[mt]).__webglTexture;e.bindFramebuffer(s.FRAMEBUFFER,ft.__webglFramebuffer),s.framebufferTexture2D(s.DRAW_FRAMEBUFFER,s.COLOR_ATTACHMENT0+mt,s.TEXTURE_2D,Ct,0)}e.bindFramebuffer(s.DRAW_FRAMEBUFFER,ft.__webglMultisampledFramebuffer)}else if(A.depthBuffer&&A.resolveDepthBuffer===!1&&l){const _=A.stencilBuffer?s.DEPTH_STENCIL_ATTACHMENT:s.DEPTH_ATTACHMENT;s.invalidateFramebuffer(s.DRAW_FRAMEBUFFER,[_])}}}function ve(A){return Math.min(i.maxSamples,A.samples)}function Re(A){const _=n.get(A);return A.samples>0&&t.has("WEBGL_multisampled_render_to_texture")===!0&&_.__useRenderToTexture!==!1}function O(A){const _=o.render.frame;u.get(A)!==_&&(u.set(A,_),A.update())}function Je(A,_){const H=A.colorSpace,$=A.format,J=A.type;return A.isCompressedTexture===!0||A.isVideoTexture===!0||H!==qs&&H!==ai&&(Jt.getTransfer(H)===se?($!==gn||J!==je)&&Ut("WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType."):te("WebGLTextures: Unsupported texture color space:",H)),_}function oe(A){return typeof HTMLImageElement<"u"&&A instanceof HTMLImageElement?(c.width=A.naturalWidth||A.width,c.height=A.naturalHeight||A.height):typeof VideoFrame<"u"&&A instanceof VideoFrame?(c.width=A.displayWidth,c.height=A.displayHeight):(c.width=A.width,c.height=A.height),c}this.allocateTextureUnit=B,this.resetTextureUnits=Y,this.getTextureUnits=K,this.setTextureUnits=N,this.setTexture2D=Z,this.setTexture2DArray=nt,this.setTexture3D=rt,this.setTextureCube=ot,this.rebindTextures=jt,this.setupRenderTarget=Qt,this.updateRenderTargetMipmap=ne,this.updateMultisampleRenderTarget=Ce,this.setupDepthRenderbuffer=Vt,this.setupFrameBufferTexture=lt,this.useMultisampledRTT=Re,this.isReversedDepthBuffer=function(){return e.buffers.depth.getReversed()}}function zv(s,t){function e(n,i=ai){let r;const o=Jt.getTransfer(i);if(n===je)return s.UNSIGNED_BYTE;if(n===xa)return s.UNSIGNED_SHORT_4_4_4_4;if(n===va)return s.UNSIGNED_SHORT_5_5_5_1;if(n===eh)return s.UNSIGNED_INT_5_9_9_9_REV;if(n===nh)return s.UNSIGNED_INT_10F_11F_11F_REV;if(n===Qc)return s.BYTE;if(n===th)return s.SHORT;if(n===$s)return s.UNSIGNED_SHORT;if(n===ga)return s.INT;if(n===Cn)return s.UNSIGNED_INT;if(n===mn)return s.FLOAT;if(n===Qe)return s.HALF_FLOAT;if(n===ih)return s.ALPHA;if(n===sh)return s.RGB;if(n===gn)return s.RGBA;if(n===Vn)return s.DEPTH_COMPONENT;if(n===Ui)return s.DEPTH_STENCIL;if(n===_a)return s.RED;if(n===ya)return s.RED_INTEGER;if(n===Fi)return s.RG;if(n===Ma)return s.RG_INTEGER;if(n===ba)return s.RGBA_INTEGER;if(n===Lr||n===Dr||n===Ir||n===Nr)if(o===se)if(r=t.get("WEBGL_compressed_texture_s3tc_srgb"),r!==null){if(n===Lr)return r.COMPRESSED_SRGB_S3TC_DXT1_EXT;if(n===Dr)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;if(n===Ir)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;if(n===Nr)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}else return null;else if(r=t.get("WEBGL_compressed_texture_s3tc"),r!==null){if(n===Lr)return r.COMPRESSED_RGB_S3TC_DXT1_EXT;if(n===Dr)return r.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(n===Ir)return r.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(n===Nr)return r.COMPRESSED_RGBA_S3TC_DXT5_EXT}else return null;if(n===Sa||n===wa||n===Ea||n===Ta)if(r=t.get("WEBGL_compressed_texture_pvrtc"),r!==null){if(n===Sa)return r.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(n===wa)return r.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(n===Ea)return r.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(n===Ta)return r.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}else return null;if(n===Aa||n===Ca||n===Ra||n===Pa||n===La||n===Ur||n===Da)if(r=t.get("WEBGL_compressed_texture_etc"),r!==null){if(n===Aa||n===Ca)return o===se?r.COMPRESSED_SRGB8_ETC2:r.COMPRESSED_RGB8_ETC2;if(n===Ra)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:r.COMPRESSED_RGBA8_ETC2_EAC;if(n===Pa)return r.COMPRESSED_R11_EAC;if(n===La)return r.COMPRESSED_SIGNED_R11_EAC;if(n===Ur)return r.COMPRESSED_RG11_EAC;if(n===Da)return r.COMPRESSED_SIGNED_RG11_EAC}else return null;if(n===Ia||n===Na||n===Ua||n===Fa||n===Oa||n===ka||n===Ba||n===za||n===Ha||n===Ga||n===Va||n===Wa||n===$a||n===Xa)if(r=t.get("WEBGL_compressed_texture_astc"),r!==null){if(n===Ia)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:r.COMPRESSED_RGBA_ASTC_4x4_KHR;if(n===Na)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:r.COMPRESSED_RGBA_ASTC_5x4_KHR;if(n===Ua)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:r.COMPRESSED_RGBA_ASTC_5x5_KHR;if(n===Fa)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:r.COMPRESSED_RGBA_ASTC_6x5_KHR;if(n===Oa)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:r.COMPRESSED_RGBA_ASTC_6x6_KHR;if(n===ka)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:r.COMPRESSED_RGBA_ASTC_8x5_KHR;if(n===Ba)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:r.COMPRESSED_RGBA_ASTC_8x6_KHR;if(n===za)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:r.COMPRESSED_RGBA_ASTC_8x8_KHR;if(n===Ha)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:r.COMPRESSED_RGBA_ASTC_10x5_KHR;if(n===Ga)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:r.COMPRESSED_RGBA_ASTC_10x6_KHR;if(n===Va)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:r.COMPRESSED_RGBA_ASTC_10x8_KHR;if(n===Wa)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:r.COMPRESSED_RGBA_ASTC_10x10_KHR;if(n===$a)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:r.COMPRESSED_RGBA_ASTC_12x10_KHR;if(n===Xa)return o===se?r.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:r.COMPRESSED_RGBA_ASTC_12x12_KHR}else return null;if(n===qa||n===Ya||n===Ka)if(r=t.get("EXT_texture_compression_bptc"),r!==null){if(n===qa)return o===se?r.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:r.COMPRESSED_RGBA_BPTC_UNORM_EXT;if(n===Ya)return r.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;if(n===Ka)return r.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT}else return null;if(n===Za||n===Ja||n===Fr||n===ja)if(r=t.get("EXT_texture_compression_rgtc"),r!==null){if(n===Za)return r.COMPRESSED_RED_RGTC1_EXT;if(n===Ja)return r.COMPRESSED_SIGNED_RED_RGTC1_EXT;if(n===Fr)return r.COMPRESSED_RED_GREEN_RGTC2_EXT;if(n===ja)return r.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT}else return null;return n===Xs?s.UNSIGNED_INT_24_8:s[n]!==void 0?s[n]:null}return{convert:e}}const Hv=` void main() { gl_Position = vec4( position, 1.0 ); -}`,T_=` +}`,Gv=` uniform sampler2DArray depthColor; uniform float depthWidth; uniform float depthHeight; @@ -4113,7 +4113,7 @@ void main() { } -}`;class A_{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(t,e){if(this.texture===null){const n=new Kc(t.texture);(t.depthNear!==e.depthNear||t.depthFar!==e.depthFar)&&(this.depthNear=t.depthNear,this.depthFar=t.depthFar),this.texture=n}}getMesh(t){if(this.texture!==null&&this.mesh===null){const e=t.cameras[0].viewport,n=new Ce({vertexShader:E_,fragmentShader:T_,uniforms:{depthColor:{value:this.texture},depthWidth:{value:e.z},depthHeight:{value:e.w}}});this.mesh=new Bt(new We(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}getDepthTexture(){return this.texture}}class C_ extends ei{constructor(t,e){super();const n=this;let i=null,r=1,a=null,o="local-floor",l=1,c=null,u=null,h=null,d=null,f=null,p=null;const v=typeof XRWebGLBinding<"u",m=new A_,g={},w=e.getContextAttributes();let E=null,M=null;const S=[],b=[],R=new ht;let x=null;const T=new qe;T.viewport=new me;const P=new qe;P.viewport=new me;const L=[T,P],F=new fp;let q=null,Y=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(j){let D=S[j];return D===void 0&&(D=new Uo,S[j]=D),D.getTargetRaySpace()},this.getControllerGrip=function(j){let D=S[j];return D===void 0&&(D=new Uo,S[j]=D),D.getGripSpace()},this.getHand=function(j){let D=S[j];return D===void 0&&(D=new Uo,S[j]=D),D.getHandSpace()};function B(j){const D=b.indexOf(j.inputSource);if(D===-1)return;const W=S[D];W!==void 0&&(W.update(j.inputSource,j.frame,c||a),W.dispatchEvent({type:j.type,data:j.inputSource}))}function K(){i.removeEventListener("select",B),i.removeEventListener("selectstart",B),i.removeEventListener("selectend",B),i.removeEventListener("squeeze",B),i.removeEventListener("squeezestart",B),i.removeEventListener("squeezeend",B),i.removeEventListener("end",K),i.removeEventListener("inputsourceschange",X);for(let j=0;j=0&&(b[st]=null,S[st].disconnect(W))}for(let D=0;D=b.length){b.push(W),st=rt;break}else if(b[rt]===null){b[rt]=W,st=rt;break}if(st===-1)break}const lt=S[st];lt&<.connect(W)}}const Q=new C,it=new C;function pt(j,D,W){Q.setFromMatrixPosition(D.matrixWorld),it.setFromMatrixPosition(W.matrixWorld);const st=Q.distanceTo(it),lt=D.projectionMatrix.elements,rt=W.projectionMatrix.elements,Ft=lt[14]/(lt[10]-1),Lt=lt[14]/(lt[10]+1),Ht=(lt[9]+1)/lt[5],Zt=(lt[9]-1)/lt[5],Jt=(lt[8]-1)/lt[0],te=(rt[8]+1)/rt[0],le=Ft*Jt,ce=Ft*te,Te=st/(-Jt+te),ge=Te*-Jt;if(D.matrixWorld.decompose(j.position,j.quaternion,j.scale),j.translateX(ge),j.translateZ(Te),j.matrixWorld.compose(j.position,j.quaternion,j.scale),j.matrixWorldInverse.copy(j.matrixWorld).invert(),lt[10]===-1)j.projectionMatrix.copy(D.projectionMatrix),j.projectionMatrixInverse.copy(D.projectionMatrixInverse);else{const Ae=Ft+Te,U=Lt+Te,Ke=le-ge,re=ce+(st-ge),A=Ht*Lt/U*Ae,_=Zt*Lt/U*Ae;j.projectionMatrix.makePerspective(Ke,re,A,_,Ae,U),j.projectionMatrixInverse.copy(j.projectionMatrix).invert()}}function _t(j,D){D===null?j.matrixWorld.copy(j.matrix):j.matrixWorld.multiplyMatrices(D.matrixWorld,j.matrix),j.matrixWorldInverse.copy(j.matrixWorld).invert()}this.updateCamera=function(j){if(i===null)return;let D=j.near,W=j.far;m.texture!==null&&(m.depthNear>0&&(D=m.depthNear),m.depthFar>0&&(W=m.depthFar)),F.near=P.near=T.near=D,F.far=P.far=T.far=W,(q!==F.near||Y!==F.far)&&(i.updateRenderState({depthNear:F.near,depthFar:F.far}),q=F.near,Y=F.far),F.layers.mask=j.layers.mask|6,T.layers.mask=F.layers.mask&-5,P.layers.mask=F.layers.mask&-3;const st=j.parent,lt=F.cameras;_t(F,st);for(let rt=0;rt0&&(m.alphaTest.value=g.alphaTest);const w=t.get(g),E=w.envMap,M=w.envMapRotation;E&&(m.envMap.value=E,m.envMapRotation.value.setFromMatrix4(R_.makeRotationFromEuler(M)).transpose(),E.isCubeTexture&&E.isRenderTargetTexture===!1&&m.envMapRotation.value.premultiply(Wh),m.reflectivity.value=g.reflectivity,m.ior.value=g.ior,m.refractionRatio.value=g.refractionRatio),g.lightMap&&(m.lightMap.value=g.lightMap,m.lightMapIntensity.value=g.lightMapIntensity,e(g.lightMap,m.lightMapTransform)),g.aoMap&&(m.aoMap.value=g.aoMap,m.aoMapIntensity.value=g.aoMapIntensity,e(g.aoMap,m.aoMapTransform))}function a(m,g){m.diffuse.value.copy(g.color),m.opacity.value=g.opacity,g.map&&(m.map.value=g.map,e(g.map,m.mapTransform))}function o(m,g){m.dashSize.value=g.dashSize,m.totalSize.value=g.dashSize+g.gapSize,m.scale.value=g.scale}function l(m,g,w,E){m.diffuse.value.copy(g.color),m.opacity.value=g.opacity,m.size.value=g.size*w,m.scale.value=E*.5,g.map&&(m.map.value=g.map,e(g.map,m.uvTransform)),g.alphaMap&&(m.alphaMap.value=g.alphaMap,e(g.alphaMap,m.alphaMapTransform)),g.alphaTest>0&&(m.alphaTest.value=g.alphaTest)}function c(m,g){m.diffuse.value.copy(g.color),m.opacity.value=g.opacity,m.rotation.value=g.rotation,g.map&&(m.map.value=g.map,e(g.map,m.mapTransform)),g.alphaMap&&(m.alphaMap.value=g.alphaMap,e(g.alphaMap,m.alphaMapTransform)),g.alphaTest>0&&(m.alphaTest.value=g.alphaTest)}function u(m,g){m.specular.value.copy(g.specular),m.shininess.value=Math.max(g.shininess,1e-4)}function h(m,g){g.gradientMap&&(m.gradientMap.value=g.gradientMap)}function d(m,g){m.metalness.value=g.metalness,g.metalnessMap&&(m.metalnessMap.value=g.metalnessMap,e(g.metalnessMap,m.metalnessMapTransform)),m.roughness.value=g.roughness,g.roughnessMap&&(m.roughnessMap.value=g.roughnessMap,e(g.roughnessMap,m.roughnessMapTransform)),g.envMap&&(m.envMapIntensity.value=g.envMapIntensity)}function f(m,g,w){m.ior.value=g.ior,g.sheen>0&&(m.sheenColor.value.copy(g.sheenColor).multiplyScalar(g.sheen),m.sheenRoughness.value=g.sheenRoughness,g.sheenColorMap&&(m.sheenColorMap.value=g.sheenColorMap,e(g.sheenColorMap,m.sheenColorMapTransform)),g.sheenRoughnessMap&&(m.sheenRoughnessMap.value=g.sheenRoughnessMap,e(g.sheenRoughnessMap,m.sheenRoughnessMapTransform))),g.clearcoat>0&&(m.clearcoat.value=g.clearcoat,m.clearcoatRoughness.value=g.clearcoatRoughness,g.clearcoatMap&&(m.clearcoatMap.value=g.clearcoatMap,e(g.clearcoatMap,m.clearcoatMapTransform)),g.clearcoatRoughnessMap&&(m.clearcoatRoughnessMap.value=g.clearcoatRoughnessMap,e(g.clearcoatRoughnessMap,m.clearcoatRoughnessMapTransform)),g.clearcoatNormalMap&&(m.clearcoatNormalMap.value=g.clearcoatNormalMap,e(g.clearcoatNormalMap,m.clearcoatNormalMapTransform),m.clearcoatNormalScale.value.copy(g.clearcoatNormalScale),g.side===Ge&&m.clearcoatNormalScale.value.negate())),g.dispersion>0&&(m.dispersion.value=g.dispersion),g.iridescence>0&&(m.iridescence.value=g.iridescence,m.iridescenceIOR.value=g.iridescenceIOR,m.iridescenceThicknessMinimum.value=g.iridescenceThicknessRange[0],m.iridescenceThicknessMaximum.value=g.iridescenceThicknessRange[1],g.iridescenceMap&&(m.iridescenceMap.value=g.iridescenceMap,e(g.iridescenceMap,m.iridescenceMapTransform)),g.iridescenceThicknessMap&&(m.iridescenceThicknessMap.value=g.iridescenceThicknessMap,e(g.iridescenceThicknessMap,m.iridescenceThicknessMapTransform))),g.transmission>0&&(m.transmission.value=g.transmission,m.transmissionSamplerMap.value=w.texture,m.transmissionSamplerSize.value.set(w.width,w.height),g.transmissionMap&&(m.transmissionMap.value=g.transmissionMap,e(g.transmissionMap,m.transmissionMapTransform)),m.thickness.value=g.thickness,g.thicknessMap&&(m.thicknessMap.value=g.thicknessMap,e(g.thicknessMap,m.thicknessMapTransform)),m.attenuationDistance.value=g.attenuationDistance,m.attenuationColor.value.copy(g.attenuationColor)),g.anisotropy>0&&(m.anisotropyVector.value.set(g.anisotropy*Math.cos(g.anisotropyRotation),g.anisotropy*Math.sin(g.anisotropyRotation)),g.anisotropyMap&&(m.anisotropyMap.value=g.anisotropyMap,e(g.anisotropyMap,m.anisotropyMapTransform))),m.specularIntensity.value=g.specularIntensity,m.specularColor.value.copy(g.specularColor),g.specularColorMap&&(m.specularColorMap.value=g.specularColorMap,e(g.specularColorMap,m.specularColorMapTransform)),g.specularIntensityMap&&(m.specularIntensityMap.value=g.specularIntensityMap,e(g.specularIntensityMap,m.specularIntensityMapTransform))}function p(m,g){g.matcap&&(m.matcap.value=g.matcap)}function v(m,g){const w=t.get(g).light;m.referencePosition.value.setFromMatrixPosition(w.matrixWorld),m.nearDistance.value=w.shadow.camera.near,m.farDistance.value=w.shadow.camera.far}return{refreshFogUniforms:n,refreshMaterialUniforms:i}}function L_(s,t,e,n){let i={},r={},a=[];const o=s.getParameter(s.MAX_UNIFORM_BUFFER_BINDINGS);function l(M,S){const b=S.program;n.uniformBlockBinding(M,b)}function c(M,S){let b=i[M.id];b===void 0&&(m(M),b=u(M),i[M.id]=b,M.addEventListener("dispose",w));const R=S.program;n.updateUBOMapping(M,R);const x=t.render.frame;r[M.id]!==x&&(d(M),r[M.id]=x)}function u(M){const S=h();M.__bindingPointIndex=S;const b=s.createBuffer(),R=M.__size,x=M.usage;return s.bindBuffer(s.UNIFORM_BUFFER,b),s.bufferData(s.UNIFORM_BUFFER,R,x),s.bindBuffer(s.UNIFORM_BUFFER,null),s.bindBufferBase(s.UNIFORM_BUFFER,S,b),b}function h(){for(let M=0;M0&&(b+=R-x),M.__size=b,M.__cache={},this}function g(M){const S={boundary:0,storage:0};return typeof M=="number"||typeof M=="boolean"?(S.boundary=4,S.storage=4):M.isVector2?(S.boundary=8,S.storage=8):M.isVector3||M.isColor?(S.boundary=16,S.storage=12):M.isVector4?(S.boundary=16,S.storage=16):M.isMatrix3?(S.boundary=48,S.storage=48):M.isMatrix4?(S.boundary=64,S.storage=64):M.isTexture?Nt("WebGLRenderer: Texture samplers can not be part of an uniforms group."):ArrayBuffer.isView(M)?(S.boundary=16,S.storage=M.byteLength):Nt("WebGLRenderer: Unsupported uniform value type.",M),S}function w(M){const S=M.target;S.removeEventListener("dispose",w);const b=a.indexOf(S.__bindingPointIndex);a.splice(b,1),s.deleteBuffer(i[S.id]),delete i[S.id],delete r[S.id]}function E(){for(const M in i)s.deleteBuffer(i[M]);a=[],i={},r={}}return{bind:l,update:c,dispose:E}}const D_=new Uint16Array([12469,15057,12620,14925,13266,14620,13807,14376,14323,13990,14545,13625,14713,13328,14840,12882,14931,12528,14996,12233,15039,11829,15066,11525,15080,11295,15085,10976,15082,10705,15073,10495,13880,14564,13898,14542,13977,14430,14158,14124,14393,13732,14556,13410,14702,12996,14814,12596,14891,12291,14937,11834,14957,11489,14958,11194,14943,10803,14921,10506,14893,10278,14858,9960,14484,14039,14487,14025,14499,13941,14524,13740,14574,13468,14654,13106,14743,12678,14818,12344,14867,11893,14889,11509,14893,11180,14881,10751,14852,10428,14812,10128,14765,9754,14712,9466,14764,13480,14764,13475,14766,13440,14766,13347,14769,13070,14786,12713,14816,12387,14844,11957,14860,11549,14868,11215,14855,10751,14825,10403,14782,10044,14729,9651,14666,9352,14599,9029,14967,12835,14966,12831,14963,12804,14954,12723,14936,12564,14917,12347,14900,11958,14886,11569,14878,11247,14859,10765,14828,10401,14784,10011,14727,9600,14660,9289,14586,8893,14508,8533,15111,12234,15110,12234,15104,12216,15092,12156,15067,12010,15028,11776,14981,11500,14942,11205,14902,10752,14861,10393,14812,9991,14752,9570,14682,9252,14603,8808,14519,8445,14431,8145,15209,11449,15208,11451,15202,11451,15190,11438,15163,11384,15117,11274,15055,10979,14994,10648,14932,10343,14871,9936,14803,9532,14729,9218,14645,8742,14556,8381,14461,8020,14365,7603,15273,10603,15272,10607,15267,10619,15256,10631,15231,10614,15182,10535,15118,10389,15042,10167,14963,9787,14883,9447,14800,9115,14710,8665,14615,8318,14514,7911,14411,7507,14279,7198,15314,9675,15313,9683,15309,9712,15298,9759,15277,9797,15229,9773,15166,9668,15084,9487,14995,9274,14898,8910,14800,8539,14697,8234,14590,7790,14479,7409,14367,7067,14178,6621,15337,8619,15337,8631,15333,8677,15325,8769,15305,8871,15264,8940,15202,8909,15119,8775,15022,8565,14916,8328,14804,8009,14688,7614,14569,7287,14448,6888,14321,6483,14088,6171,15350,7402,15350,7419,15347,7480,15340,7613,15322,7804,15287,7973,15229,8057,15148,8012,15046,7846,14933,7611,14810,7357,14682,7069,14552,6656,14421,6316,14251,5948,14007,5528,15356,5942,15356,5977,15353,6119,15348,6294,15332,6551,15302,6824,15249,7044,15171,7122,15070,7050,14949,6861,14818,6611,14679,6349,14538,6067,14398,5651,14189,5311,13935,4958,15359,4123,15359,4153,15356,4296,15353,4646,15338,5160,15311,5508,15263,5829,15188,6042,15088,6094,14966,6001,14826,5796,14678,5543,14527,5287,14377,4985,14133,4586,13869,4257,15360,1563,15360,1642,15358,2076,15354,2636,15341,3350,15317,4019,15273,4429,15203,4732,15105,4911,14981,4932,14836,4818,14679,4621,14517,4386,14359,4156,14083,3795,13808,3437,15360,122,15360,137,15358,285,15355,636,15344,1274,15322,2177,15281,2765,15215,3223,15120,3451,14995,3569,14846,3567,14681,3466,14511,3305,14344,3121,14037,2800,13753,2467,15360,0,15360,1,15359,21,15355,89,15346,253,15325,479,15287,796,15225,1148,15133,1492,15008,1749,14856,1882,14685,1886,14506,1783,14324,1608,13996,1398,13702,1183]);let Ln=null;function I_(){return Ln===null&&(Ln=new zc(D_,16,16,Ci,Je),Ln.name="DFG_LUT",Ln.minFilter=Ue,Ln.magFilter=Ue,Ln.wrapS=kn,Ln.wrapT=kn,Ln.generateMipmaps=!1,Ln.needsUpdate=!0),Ln}class N_{constructor(t={}){const{canvas:e=Zd(),context:n=null,depth:i=!0,stencil:r=!1,alpha:a=!1,antialias:o=!1,premultipliedAlpha:l=!0,preserveDrawingBuffer:c=!1,powerPreference:u="default",failIfMajorPerformanceCaveat:h=!1,reversedDepthBuffer:d=!1,outputBufferType:f=Ze}=t;this.isWebGLRenderer=!0;let p;if(n!==null){if(typeof WebGLRenderingContext<"u"&&n instanceof WebGLRenderingContext)throw new Error("THREE.WebGLRenderer: WebGL 1 is not supported since r163.");p=n.getContextAttributes().alpha}else p=a;const v=f,m=new Set([Xa,$a,Wa]),g=new Set([Ze,Tn,Cs,Rs,Ha,Ga]),w=new Uint32Array(4),E=new Int32Array(4),M=new C;let S=null,b=null;const R=[],x=[];let T=null;this.domElement=e,this.debug={checkShaderErrors:!0,onShaderError:null},this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this.toneMapping=En,this.toneMappingExposure=1,this.transmissionResolutionScale=1;const P=this;let L=!1,F=null,q=null,Y=null,B=null;this._outputColorSpace=Se;let K=0,X=0,Q=null,it=-1,pt=null;const _t=new me,bt=new me;let ee=null;const pe=new kt(0);let jt=0,j=e.width,D=e.height,W=1,st=null,lt=null;const rt=new me(0,0,j,D),Ft=new me(0,0,j,D);let Lt=!1;const Ht=new kr;let Zt=!1,Jt=!1;const te=new se,le=new C,ce=new me,Te={background:null,fog:null,environment:null,overrideMaterial:null,isScene:!0};let ge=!1;function Ae(){return Q===null?W:1}let U=n;function Ke(y,O){return e.getContext(y,O)}try{const y={alpha:!0,depth:i,stencil:r,antialias:o,premultipliedAlpha:l,preserveDrawingBuffer:c,powerPreference:u,failIfMajorPerformanceCaveat:h};if("setAttribute"in e&&e.setAttribute("data-engine",`three.js r${Ma}`),e.addEventListener("webglcontextlost",_e,!1),e.addEventListener("webglcontextrestored",de,!1),e.addEventListener("webglcontextcreationerror",Nn,!1),U===null){const O="webgl2";if(U=Ke(O,y),U===null)throw Ke(O)?new Error("THREE.WebGLRenderer: Error creating WebGL context with your selected attributes."):new Error("THREE.WebGLRenderer: Error creating WebGL context.")}}catch(y){throw Qt("WebGLRenderer: "+y.message),y}let re,A,_,k,V,Z,at,ct,J,et,ut,At,gt,dt,Dt,Ut,Gt,N,ot,tt,ft,Mt,nt;function Tt(){re=new Ig(U),re.init(),ft=new w_(U,re),A=new Eg(U,re,t,ft),_=new S_(U,re),A.reversedDepthBuffer&&d&&_.buffers.depth.setReversed(!0),q=U.createFramebuffer(),Y=U.createFramebuffer(),B=U.createFramebuffer(),k=new Fg(U),V=new l_,Z=new b_(U,re,_,V,A,ft,k),at=new Dg(P),ct=new Mp(U),Mt=new bg(U,ct),J=new Ng(U,ct,k,Mt),et=new kg(U,J,ct,Mt,k),N=new Og(U,A,Z),Dt=new Tg(V),ut=new o_(P,at,re,A,Mt,Dt),At=new P_(P,V),gt=new h_,dt=new g_(re),Gt=new Sg(P,at,_,et,p,l),Ut=new y_(P,et,A),nt=new L_(U,k,A,_),ot=new wg(U,re,k),tt=new Ug(U,re,k),k.programs=ut.programs,P.capabilities=A,P.extensions=re,P.properties=V,P.renderLists=gt,P.shadowMap=Ut,P.state=_,P.info=k}Tt(),v!==Ze&&(T=new zg(v,e.width,e.height,o,i,r));const wt=new C_(P,U);this.xr=wt,this.getContext=function(){return U},this.getContextAttributes=function(){return U.getContextAttributes()},this.forceContextLoss=function(){const y=re.get("WEBGL_lose_context");y&&y.loseContext()},this.forceContextRestore=function(){const y=re.get("WEBGL_lose_context");y&&y.restoreContext()},this.getPixelRatio=function(){return W},this.setPixelRatio=function(y){y!==void 0&&(W=y,this.setSize(j,D,!1))},this.getSize=function(y){return y.set(j,D)},this.setSize=function(y,O,$=!0){if(wt.isPresenting){Nt("WebGLRenderer: Can't change size while VR device is presenting.");return}j=y,D=O,e.width=Math.floor(y*W),e.height=Math.floor(O*W),$===!0&&(e.style.width=y+"px",e.style.height=O+"px"),T!==null&&T.setSize(e.width,e.height),this.setViewport(0,0,y,O)},this.getDrawingBufferSize=function(y){return y.set(j*W,D*W).floor()},this.setDrawingBufferSize=function(y,O,$){j=y,D=O,W=$,e.width=Math.floor(y*$),e.height=Math.floor(O*$),this.setViewport(0,0,y,O)},this.setEffects=function(y){if(v===Ze){Qt("WebGLRenderer: setEffects() requires outputBufferType set to HalfFloatType or FloatType.");return}if(y){for(let O=0;O{function vt(){if(z.forEach(function(St){V.get(St).currentProgram.isReady()&&z.delete(St)}),z.size===0){H(y);return}setTimeout(vt,10)}re.get("KHR_parallel_shader_compile")!==null?vt():setTimeout(vt,10)})};let Vl=null;function fv(y){Vl&&Vl(y)}function Lu(){Oi.stop()}function Du(){Oi.start()}const Oi=new ph;Oi.setAnimationLoop(fv),typeof self<"u"&&Oi.setContext(self),this.setAnimationLoop=function(y){Vl=y,wt.setAnimationLoop(y),y===null?Oi.stop():Oi.start()},wt.addEventListener("sessionstart",Lu),wt.addEventListener("sessionend",Du),this.render=function(y,O){if(O!==void 0&&O.isCamera!==!0){Qt("WebGLRenderer.render: camera is not an instance of THREE.Camera.");return}if(L===!0)return;F!==null&&F.renderStart(y,O);const $=wt.enabled===!0&&wt.isPresenting===!0,z=T!==null&&(Q===null||$)&&T.begin(P,Q);if(y.matrixWorldAutoUpdate===!0&&y.updateMatrixWorld(),O.parent===null&&O.matrixWorldAutoUpdate===!0&&O.updateMatrixWorld(),wt.enabled===!0&&wt.isPresenting===!0&&(T===null||T.isCompositing()===!1)&&(wt.cameraAutoUpdate===!0&&wt.updateCamera(O),O=wt.getCamera()),y.isScene===!0&&y.onBeforeRender(P,y,O,Q),b=dt.get(y,x.length),b.init(O),b.state.textureUnits=Z.getTextureUnits(),x.push(b),te.multiplyMatrices(O.projectionMatrix,O.matrixWorldInverse),Ht.setFromProjectionMatrix(te,An,O.reversedDepth),Jt=this.localClippingEnabled,Zt=Dt.init(this.clippingPlanes,Jt),S=gt.get(y,R.length),S.init(),R.push(S),wt.enabled===!0&&wt.isPresenting===!0){const St=P.xr.getDepthSensingMesh();St!==null&&Wl(St,O,-1/0,P.sortObjects)}Wl(y,O,0,P.sortObjects),S.finish(),P.sortObjects===!0&&S.sort(st,lt,O.reversedDepth),ge=wt.enabled===!1||wt.isPresenting===!1||wt.hasDepthSensing()===!1,ge&&Gt.addToRenderList(S,y),this.info.render.frame++,this.info.autoReset===!0&&this.info.reset(),Zt===!0&&Dt.beginShadows();const H=b.state.shadowsArray;if(Ut.render(H,y,O),Zt===!0&&Dt.endShadows(),(z&&T.hasRenderPass())===!1){const St=S.opaque,xt=S.transmissive;if(b.setupLights(),O.isArrayCamera){const Et=O.cameras;if(xt.length>0)for(let Ct=0,Vt=Et.length;Ct0&&Nu(St,xt,y,O),ge&&Gt.render(y),Iu(S,y,O)}Q!==null&&X===0&&(Z.updateMultisampleRenderTarget(Q),Z.updateRenderTargetMipmap(Q)),z&&T.end(P),y.isScene===!0&&y.onAfterRender(P,y,O),Mt.resetDefaultState(),it=-1,pt=null,x.pop(),x.length>0?(b=x[x.length-1],Z.setTextureUnits(b.state.textureUnits),Zt===!0&&Dt.setGlobalState(P.clippingPlanes,b.state.camera)):b=null,R.pop(),R.length>0?S=R[R.length-1]:S=null,F!==null&&F.renderEnd()};function Wl(y,O,$,z){if(y.visible===!1)return;if(y.layers.test(O.layers)){if(y.isGroup)$=y.renderOrder;else if(y.isLOD)y.autoUpdate===!0&&y.update(O);else if(y.isLightProbeGrid)b.pushLightProbeGrid(y);else if(y.isLight)b.pushLight(y),y.castShadow&&b.pushShadow(y);else if(y.isSprite){if(!y.frustumCulled||Ht.intersectsSprite(y)){z&&ce.setFromMatrixPosition(y.matrixWorld).applyMatrix4(te);const St=et.update(y),xt=y.material;xt.visible&&S.push(y,St,xt,$,ce.z,null)}}else if((y.isMesh||y.isLine||y.isPoints)&&(!y.frustumCulled||Ht.intersectsObject(y))){const St=et.update(y),xt=y.material;if(z&&(y.boundingSphere!==void 0?(y.boundingSphere===null&&y.computeBoundingSphere(),ce.copy(y.boundingSphere.center)):(St.boundingSphere===null&&St.computeBoundingSphere(),ce.copy(St.boundingSphere.center)),ce.applyMatrix4(y.matrixWorld).applyMatrix4(te)),Array.isArray(xt)){const Et=St.groups;for(let Ct=0,Vt=Et.length;Ct0&&ra(H,O,$),vt.length>0&&ra(vt,O,$),St.length>0&&ra(St,O,$),_.buffers.depth.setTest(!0),_.buffers.depth.setMask(!0),_.buffers.color.setMask(!0),_.setPolygonOffset(!1)}function Nu(y,O,$,z){if(($.isScene===!0?$.overrideMaterial:null)!==null)return;if(b.state.transmissionRenderTarget[z.id]===void 0){const Pt=re.has("EXT_color_buffer_half_float")||re.has("EXT_color_buffer_float");b.state.transmissionRenderTarget[z.id]=new Xe(1,1,{generateMipmaps:!0,type:Pt?Je:Ze,minFilter:Ti,samples:Math.max(4,A.samples),stencilBuffer:r,resolveDepthBuffer:!1,resolveStencilBuffer:!1,colorSpace:Kt.workingColorSpace})}const vt=b.state.transmissionRenderTarget[z.id],St=z.viewport||_t;vt.setSize(St.z*P.transmissionResolutionScale,St.w*P.transmissionResolutionScale);const xt=P.getRenderTarget(),Et=P.getActiveCubeFace(),Ct=P.getActiveMipmapLevel();P.setRenderTarget(vt),P.getClearColor(pe),jt=P.getClearAlpha(),jt<1&&P.setClearColor(16777215,.5),P.clear(),ge&&Gt.render($);const Vt=P.toneMapping;P.toneMapping=En;const qt=z.viewport;if(z.viewport!==void 0&&(z.viewport=void 0),b.setupLightsView(z),Zt===!0&&Dt.setGlobalState(P.clippingPlanes,z),ra(y,$,z),Z.updateMultisampleRenderTarget(vt),Z.updateRenderTargetMipmap(vt),re.has("WEBGL_multisampled_render_to_texture")===!1){let Pt=!1;for(let oe=0,Me=O.length;oe0,z.currentProgram=qt,z.uniformsList=null,qt}function Fu(y){if(y.uniformsList===null){const O=y.currentProgram.getUniforms();y.uniformsList=Zr.seqWithValue(O.seq,y.uniforms)}return y.uniformsList}function Ou(y,O){const $=V.get(y);$.outputColorSpace=O.outputColorSpace,$.batching=O.batching,$.batchingColor=O.batchingColor,$.instancing=O.instancing,$.instancingColor=O.instancingColor,$.instancingMorph=O.instancingMorph,$.skinning=O.skinning,$.morphTargets=O.morphTargets,$.morphNormals=O.morphNormals,$.morphColors=O.morphColors,$.morphTargetsCount=O.morphTargetsCount,$.numClippingPlanes=O.numClippingPlanes,$.numIntersection=O.numClipIntersection,$.vertexAlphas=O.vertexAlphas,$.vertexTangents=O.vertexTangents,$.toneMapping=O.toneMapping}function pv(y,O){if(y.length===0)return null;if(y.length===1)return y[0].texture!==null?y[0]:null;M.setFromMatrixPosition(O.matrixWorld);for(let $=0,z=y.length;$0),Pt=!!$.morphAttributes.position,oe=!!$.morphAttributes.normal,Me=!!$.morphAttributes.color;let xe=En;z.toneMapped&&(Q===null||Q.isXRRenderTarget===!0)&&(xe=P.toneMapping);const he=$.morphAttributes.position||$.morphAttributes.normal||$.morphAttributes.color,ze=he!==void 0?he.length:0,yt=V.get(z),en=b.state.lights;if(Zt===!0&&(Jt===!0||y!==pt)){const fe=y===pt&&z.id===it;Dt.setState(z,y,fe)}let ne=!1;z.version===yt.__version?(yt.needsLights&&yt.lightsStateVersion!==en.state.version||yt.outputColorSpace!==xt||H.isBatchedMesh&&yt.batching===!1||!H.isBatchedMesh&&yt.batching===!0||H.isBatchedMesh&&yt.batchingColor===!0&&H.colorTexture===null||H.isBatchedMesh&&yt.batchingColor===!1&&H.colorTexture!==null||H.isInstancedMesh&&yt.instancing===!1||!H.isInstancedMesh&&yt.instancing===!0||H.isSkinnedMesh&&yt.skinning===!1||!H.isSkinnedMesh&&yt.skinning===!0||H.isInstancedMesh&&yt.instancingColor===!0&&H.instanceColor===null||H.isInstancedMesh&&yt.instancingColor===!1&&H.instanceColor!==null||H.isInstancedMesh&&yt.instancingMorph===!0&&H.morphTexture===null||H.isInstancedMesh&&yt.instancingMorph===!1&&H.morphTexture!==null||yt.envMap!==Ct||z.fog===!0&&yt.fog!==vt||yt.numClippingPlanes!==void 0&&(yt.numClippingPlanes!==Dt.numPlanes||yt.numIntersection!==Dt.numIntersection)||yt.vertexAlphas!==Vt||yt.vertexTangents!==qt||yt.morphTargets!==Pt||yt.morphNormals!==oe||yt.morphColors!==Me||yt.toneMapping!==xe||yt.morphTargetsCount!==ze||!!yt.lightProbeGrid!=b.state.lightProbeGridArray.length>0)&&(ne=!0):(ne=!0,yt.__version=z.version);let cn=yt.currentProgram;ne===!0&&(cn=aa(z,O,H),F&&z.isNodeMaterial&&F.onUpdateProgram(z,cn,yt));let Fn=!1,mi=!1,Ss=!1;const ue=cn.getUniforms(),ye=yt.uniforms;if(_.useProgram(cn.program)&&(Fn=!0,mi=!0,Ss=!0),z.id!==it&&(it=z.id,mi=!0),yt.needsLights){const fe=pv(b.state.lightProbeGridArray,H);yt.lightProbeGrid!==fe&&(yt.lightProbeGrid=fe,mi=!0)}if(Fn||pt!==y){_.buffers.depth.getReversed()&&y.reversedDepth!==!0&&(y._reversedDepth=!0,y.updateProjectionMatrix()),ue.setValue(U,"projectionMatrix",y.projectionMatrix),ue.setValue(U,"viewMatrix",y.matrixWorldInverse);const _i=ue.map.cameraPosition;_i!==void 0&&_i.setValue(U,le.setFromMatrixPosition(y.matrixWorld)),A.logarithmicDepthBuffer&&ue.setValue(U,"logDepthBufFC",2/(Math.log(y.far+1)/Math.LN2)),(z.isMeshPhongMaterial||z.isMeshToonMaterial||z.isMeshLambertMaterial||z.isMeshBasicMaterial||z.isMeshStandardMaterial||z.isShaderMaterial)&&ue.setValue(U,"isOrthographic",y.isOrthographicCamera===!0),pt!==y&&(pt=y,mi=!0,Ss=!0)}if(yt.needsLights&&(en.state.directionalShadowMap.length>0&&ue.setValue(U,"directionalShadowMap",en.state.directionalShadowMap,Z),en.state.spotShadowMap.length>0&&ue.setValue(U,"spotShadowMap",en.state.spotShadowMap,Z),en.state.pointShadowMap.length>0&&ue.setValue(U,"pointShadowMap",en.state.pointShadowMap,Z)),H.isSkinnedMesh){ue.setOptional(U,H,"bindMatrix"),ue.setOptional(U,H,"bindMatrixInverse");const fe=H.skeleton;fe&&(fe.boneTexture===null&&fe.computeBoneTexture(),ue.setValue(U,"boneTexture",fe.boneTexture,Z))}H.isBatchedMesh&&(ue.setOptional(U,H,"batchingTexture"),ue.setValue(U,"batchingTexture",H._matricesTexture,Z),ue.setOptional(U,H,"batchingIdTexture"),ue.setValue(U,"batchingIdTexture",H._indirectTexture,Z),ue.setOptional(U,H,"batchingColorTexture"),H._colorsTexture!==null&&ue.setValue(U,"batchingColorTexture",H._colorsTexture,Z));const gi=$.morphAttributes;if((gi.position!==void 0||gi.normal!==void 0||gi.color!==void 0)&&N.update(H,$,cn),(mi||yt.receiveShadow!==H.receiveShadow)&&(yt.receiveShadow=H.receiveShadow,ue.setValue(U,"receiveShadow",H.receiveShadow)),(z.isMeshStandardMaterial||z.isMeshLambertMaterial||z.isMeshPhongMaterial)&&z.envMap===null&&O.environment!==null&&(ye.envMapIntensity.value=O.environmentIntensity),ye.dfgLUT!==void 0&&(ye.dfgLUT.value=I_()),mi){if(ue.setValue(U,"toneMappingExposure",P.toneMappingExposure),yt.needsLights&&gv(ye,Ss),vt&&z.fog===!0&&At.refreshFogUniforms(ye,vt),At.refreshMaterialUniforms(ye,z,W,D,b.state.transmissionRenderTarget[y.id]),yt.needsLights&&yt.lightProbeGrid){const fe=yt.lightProbeGrid;ye.probesSH.value=fe.texture,ye.probesMin.value.copy(fe.boundingBox.min),ye.probesMax.value.copy(fe.boundingBox.max),ye.probesResolution.value.copy(fe.resolution)}Zr.upload(U,Fu(yt),ye,Z)}if(z.isShaderMaterial&&z.uniformsNeedUpdate===!0&&(Zr.upload(U,Fu(yt),ye,Z),z.uniformsNeedUpdate=!1),z.isSpriteMaterial&&ue.setValue(U,"center",H.center),ue.setValue(U,"modelViewMatrix",H.modelViewMatrix),ue.setValue(U,"normalMatrix",H.normalMatrix),ue.setValue(U,"modelMatrix",H.matrixWorld),z.uniformsGroups!==void 0){const fe=z.uniformsGroups;for(let _i=0,bs=fe.length;_i0&&Z.useMultisampledRTT(y)===!1?z=V.get(y).__webglMultisampledFramebuffer:Array.isArray(Ct)?z=Ct[$]:z=Ct,_t.copy(y.viewport),bt.copy(y.scissor),ee=y.scissorTest}else _t.copy(rt).multiplyScalar(W).floor(),bt.copy(Ft).multiplyScalar(W).floor(),ee=Lt;if($!==0&&(z=q),_.bindFramebuffer(U.FRAMEBUFFER,z)&&_.drawBuffers(y,z),_.viewport(_t),_.scissor(bt),_.setScissorTest(ee),H){const xt=V.get(y.texture);U.framebufferTexture2D(U.FRAMEBUFFER,U.COLOR_ATTACHMENT0,U.TEXTURE_CUBE_MAP_POSITIVE_X+O,xt.__webglTexture,$)}else if(vt){const xt=O;for(let Et=0;Et1&&U.readBuffer(U.COLOR_ATTACHMENT0+xt),!A.textureFormatReadable(Vt)){Qt("WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");return}if(!A.textureTypeReadable(qt)){Qt("WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");return}O>=0&&O<=y.width-z&&$>=0&&$<=y.height-H&&U.readPixels(O,$,z,H,ft.convert(Vt),ft.convert(qt),vt)}finally{const Ct=Q!==null?V.get(Q).__webglFramebuffer:null;_.bindFramebuffer(U.FRAMEBUFFER,Ct)}}},this.readRenderTargetPixelsAsync=async function(y,O,$,z,H,vt,St,xt=0){if(!(y&&y.isWebGLRenderTarget))throw new Error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let Et=V.get(y).__webglFramebuffer;if(y.isWebGLCubeRenderTarget&&St!==void 0&&(Et=Et[St]),Et)if(O>=0&&O<=y.width-z&&$>=0&&$<=y.height-H){_.bindFramebuffer(U.FRAMEBUFFER,Et);const Ct=y.textures[xt],Vt=Ct.format,qt=Ct.type;if(y.textures.length>1&&U.readBuffer(U.COLOR_ATTACHMENT0+xt),!A.textureFormatReadable(Vt))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.");if(!A.textureTypeReadable(qt))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.");const Pt=U.createBuffer();U.bindBuffer(U.PIXEL_PACK_BUFFER,Pt),U.bufferData(U.PIXEL_PACK_BUFFER,vt.byteLength,U.STREAM_READ),U.readPixels(O,$,z,H,ft.convert(Vt),ft.convert(qt),0);const oe=Q!==null?V.get(Q).__webglFramebuffer:null;_.bindFramebuffer(U.FRAMEBUFFER,oe);const Me=U.fenceSync(U.SYNC_GPU_COMMANDS_COMPLETE,0);return U.flush(),await Jd(U,Me,4),U.bindBuffer(U.PIXEL_PACK_BUFFER,Pt),U.getBufferSubData(U.PIXEL_PACK_BUFFER,0,vt),U.deleteBuffer(Pt),U.deleteSync(Me),vt}else throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.")},this.copyFramebufferToTexture=function(y,O=null,$=0){const z=Math.pow(2,-$),H=Math.floor(y.image.width*z),vt=Math.floor(y.image.height*z),St=O!==null?O.x:0,xt=O!==null?O.y:0;Z.setTexture2D(y,0),U.copyTexSubImage2D(U.TEXTURE_2D,$,0,0,St,xt,H,vt),_.unbindTexture()},this.copyTextureToTexture=function(y,O,$=null,z=null,H=0,vt=0){let St,xt,Et,Ct,Vt,qt,Pt,oe,Me;const xe=y.isCompressedTexture?y.mipmaps[vt]:y.image;if($!==null)St=$.max.x-$.min.x,xt=$.max.y-$.min.y,Et=$.isBox3?$.max.z-$.min.z:1,Ct=$.min.x,Vt=$.min.y,qt=$.isBox3?$.min.z:0;else{const ye=Math.pow(2,-H);St=Math.floor(xe.width*ye),xt=Math.floor(xe.height*ye),y.isDataArrayTexture?Et=xe.depth:y.isData3DTexture?Et=Math.floor(xe.depth*ye):Et=1,Ct=0,Vt=0,qt=0}z!==null?(Pt=z.x,oe=z.y,Me=z.z):(Pt=0,oe=0,Me=0);const he=ft.convert(O.format),ze=ft.convert(O.type);let yt;O.isData3DTexture?(Z.setTexture3D(O,0),yt=U.TEXTURE_3D):O.isDataArrayTexture||O.isCompressedArrayTexture?(Z.setTexture2DArray(O,0),yt=U.TEXTURE_2D_ARRAY):(Z.setTexture2D(O,0),yt=U.TEXTURE_2D),_.activeTexture(U.TEXTURE0),_.pixelStorei(U.UNPACK_FLIP_Y_WEBGL,O.flipY),_.pixelStorei(U.UNPACK_PREMULTIPLY_ALPHA_WEBGL,O.premultiplyAlpha),_.pixelStorei(U.UNPACK_ALIGNMENT,O.unpackAlignment);const en=_.getParameter(U.UNPACK_ROW_LENGTH),ne=_.getParameter(U.UNPACK_IMAGE_HEIGHT),cn=_.getParameter(U.UNPACK_SKIP_PIXELS),Fn=_.getParameter(U.UNPACK_SKIP_ROWS),mi=_.getParameter(U.UNPACK_SKIP_IMAGES);_.pixelStorei(U.UNPACK_ROW_LENGTH,xe.width),_.pixelStorei(U.UNPACK_IMAGE_HEIGHT,xe.height),_.pixelStorei(U.UNPACK_SKIP_PIXELS,Ct),_.pixelStorei(U.UNPACK_SKIP_ROWS,Vt),_.pixelStorei(U.UNPACK_SKIP_IMAGES,qt);const Ss=y.isDataArrayTexture||y.isData3DTexture,ue=O.isDataArrayTexture||O.isData3DTexture;if(y.isDepthTexture){const ye=V.get(y),gi=V.get(O),fe=V.get(ye.__renderTarget),_i=V.get(gi.__renderTarget);_.bindFramebuffer(U.READ_FRAMEBUFFER,fe.__webglFramebuffer),_.bindFramebuffer(U.DRAW_FRAMEBUFFER,_i.__webglFramebuffer);for(let bs=0;bsMath.PI&&(n-=Ye),i<-Math.PI?i+=Ye:i>Math.PI&&(i-=Ye),n<=i?this._spherical.theta=Math.max(n,Math.min(i,this._spherical.theta)):this._spherical.theta=this._spherical.theta>(n+i)/2?Math.max(n,this._spherical.theta):Math.min(i,this._spherical.theta)),this._spherical.phi=Math.max(this.minPolarAngle,Math.min(this.maxPolarAngle,this._spherical.phi)),this._spherical.makeSafe(),this.enableDamping===!0?this.target.addScaledVector(this._panOffset,this.dampingFactor):this.target.add(this._panOffset),this.target.sub(this.cursor),this.target.clampLength(this.minTargetRadius,this.maxTargetRadius),this.target.add(this.cursor);let r=!1;if(this.zoomToCursor&&this._performCursorZoom||this.object.isOrthographicCamera)this._spherical.radius=this._clampDistance(this._spherical.radius);else{const a=this._spherical.radius;this._spherical.radius=this._clampDistance(this._spherical.radius*this._scale),r=a!=this._spherical.radius}if(Le.setFromSpherical(this._spherical),Le.applyQuaternion(this._quatInverse),e.copy(this.target).add(Le),this.object.lookAt(this.target),this.enableDamping===!0?(this._sphericalDelta.theta*=1-this.dampingFactor,this._sphericalDelta.phi*=1-this.dampingFactor,this._panOffset.multiplyScalar(1-this.dampingFactor)):(this._sphericalDelta.set(0,0,0),this._panOffset.set(0,0,0)),this.zoomToCursor&&this._performCursorZoom){let a=null;if(this.object.isPerspectiveCamera){const o=Le.length();a=this._clampDistance(o*this._scale);const l=o-a;this.object.position.addScaledVector(this._dollyDirection,l),this.object.updateMatrixWorld(),r=!!l}else if(this.object.isOrthographicCamera){const o=new C(this._mouse.x,this._mouse.y,0);o.unproject(this.object);const l=this.object.zoom;this.object.zoom=Math.max(this.minZoom,Math.min(this.maxZoom,this.object.zoom/this._scale)),this.object.updateProjectionMatrix(),r=l!==this.object.zoom;const c=new C(this._mouse.x,this._mouse.y,0);c.unproject(this.object),this.object.position.sub(c).add(o),this.object.updateMatrixWorld(),a=Le.length()}else console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."),this.zoomToCursor=!1;a!==null&&(this.screenSpacePanning?this.target.set(0,0,-1).transformDirection(this.object.matrix).multiplyScalar(a).add(this.object.position):(Qr.origin.copy(this.object.position),Qr.direction.set(0,0,-1).transformDirection(this.object.matrix),Math.abs(this.object.up.dot(Qr.direction))vl||8*(1-this._lastQuaternion.dot(this.object.quaternion))>vl||this._lastTargetPosition.distanceToSquared(this.target)>vl?(this.dispatchEvent($h),this._lastPosition.copy(this.object.position),this._lastQuaternion.copy(this.object.quaternion),this._lastTargetPosition.copy(this.target),!0):!1}_getAutoRotationAngle(t){return t!==null?Ye/60*this.autoRotateSpeed*t:Ye/60/60*this.autoRotateSpeed}_getZoomScale(t){const e=Math.abs(t*.01);return Math.pow(.95,this.zoomSpeed*e)}_rotateLeft(t){this._sphericalDelta.theta-=t}_rotateUp(t){this._sphericalDelta.phi-=t}_panLeft(t,e){Le.setFromMatrixColumn(e,0),Le.multiplyScalar(-t),this._panOffset.add(Le)}_panUp(t,e){this.screenSpacePanning===!0?Le.setFromMatrixColumn(e,1):(Le.setFromMatrixColumn(e,0),Le.crossVectors(this.object.up,Le)),Le.multiplyScalar(t),this._panOffset.add(Le)}_pan(t,e){const n=this.domElement;if(this.object.isPerspectiveCamera){const i=this.object.position;Le.copy(i).sub(this.target);let r=Le.length();r*=Math.tan(this.object.fov/2*Math.PI/180),this._panLeft(2*t*r/n.clientHeight,this.object.matrix),this._panUp(2*e*r/n.clientHeight,this.object.matrix)}else this.object.isOrthographicCamera?(this._panLeft(t*(this.object.right-this.object.left)/this.object.zoom/n.clientWidth,this.object.matrix),this._panUp(e*(this.object.top-this.object.bottom)/this.object.zoom/n.clientHeight,this.object.matrix)):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."),this.enablePan=!1)}_dollyOut(t){this.object.isPerspectiveCamera||this.object.isOrthographicCamera?this._scale/=t:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),this.enableZoom=!1)}_dollyIn(t){this.object.isPerspectiveCamera||this.object.isOrthographicCamera?this._scale*=t:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),this.enableZoom=!1)}_updateZoomParameters(t,e){if(!this.zoomToCursor)return;this._performCursorZoom=!0;const n=this.domElement.getBoundingClientRect(),i=t-n.left,r=e-n.top,a=n.width,o=n.height;this._mouse.x=i/a*2-1,this._mouse.y=-(r/o)*2+1,this._dollyDirection.set(this._mouse.x,this._mouse.y,1).unproject(this.object).sub(this.object.position).normalize()}_clampDistance(t){return Math.max(this.minDistance,Math.min(this.maxDistance,t))}_handleMouseDownRotate(t){this._rotateStart.set(t.clientX,t.clientY)}_handleMouseDownDolly(t){this._updateZoomParameters(t.clientX,t.clientX),this._dollyStart.set(t.clientX,t.clientY)}_handleMouseDownPan(t){this._panStart.set(t.clientX,t.clientY)}_handleMouseMoveRotate(t){this._rotateEnd.set(t.clientX,t.clientY),this._rotateDelta.subVectors(this._rotateEnd,this._rotateStart).multiplyScalar(this.rotateSpeed);const e=this.domElement;this._rotateLeft(Ye*this._rotateDelta.x/e.clientHeight),this._rotateUp(Ye*this._rotateDelta.y/e.clientHeight),this._rotateStart.copy(this._rotateEnd),this.update()}_handleMouseMoveDolly(t){this._dollyEnd.set(t.clientX,t.clientY),this._dollyDelta.subVectors(this._dollyEnd,this._dollyStart),this._dollyDelta.y>0?this._dollyOut(this._getZoomScale(this._dollyDelta.y)):this._dollyDelta.y<0&&this._dollyIn(this._getZoomScale(this._dollyDelta.y)),this._dollyStart.copy(this._dollyEnd),this.update()}_handleMouseMovePan(t){this._panEnd.set(t.clientX,t.clientY),this._panDelta.subVectors(this._panEnd,this._panStart).multiplyScalar(this.panSpeed),this._pan(this._panDelta.x,this._panDelta.y),this._panStart.copy(this._panEnd),this.update()}_handleMouseWheel(t){this._updateZoomParameters(t.clientX,t.clientY),t.deltaY<0?this._dollyIn(this._getZoomScale(t.deltaY)):t.deltaY>0&&this._dollyOut(this._getZoomScale(t.deltaY)),this.update()}_handleKeyDown(t){let e=!1;switch(t.code){case this.keys.UP:t.ctrlKey||t.metaKey||t.shiftKey?this.enableRotate&&this._rotateUp(Ye*this.keyRotateSpeed/this.domElement.clientHeight):this.enablePan&&this._pan(0,this.keyPanSpeed),e=!0;break;case this.keys.BOTTOM:t.ctrlKey||t.metaKey||t.shiftKey?this.enableRotate&&this._rotateUp(-Ye*this.keyRotateSpeed/this.domElement.clientHeight):this.enablePan&&this._pan(0,-this.keyPanSpeed),e=!0;break;case this.keys.LEFT:t.ctrlKey||t.metaKey||t.shiftKey?this.enableRotate&&this._rotateLeft(Ye*this.keyRotateSpeed/this.domElement.clientHeight):this.enablePan&&this._pan(this.keyPanSpeed,0),e=!0;break;case this.keys.RIGHT:t.ctrlKey||t.metaKey||t.shiftKey?this.enableRotate&&this._rotateLeft(-Ye*this.keyRotateSpeed/this.domElement.clientHeight):this.enablePan&&this._pan(-this.keyPanSpeed,0),e=!0;break}e&&(t.preventDefault(),this.update())}_handleTouchStartRotate(t){if(this._pointers.length===1)this._rotateStart.set(t.pageX,t.pageY);else{const e=this._getSecondPointerPosition(t),n=.5*(t.pageX+e.x),i=.5*(t.pageY+e.y);this._rotateStart.set(n,i)}}_handleTouchStartPan(t){if(this._pointers.length===1)this._panStart.set(t.pageX,t.pageY);else{const e=this._getSecondPointerPosition(t),n=.5*(t.pageX+e.x),i=.5*(t.pageY+e.y);this._panStart.set(n,i)}}_handleTouchStartDolly(t){const e=this._getSecondPointerPosition(t),n=t.pageX-e.x,i=t.pageY-e.y,r=Math.sqrt(n*n+i*i);this._dollyStart.set(0,r)}_handleTouchStartDollyPan(t){this.enableZoom&&this._handleTouchStartDolly(t),this.enablePan&&this._handleTouchStartPan(t)}_handleTouchStartDollyRotate(t){this.enableZoom&&this._handleTouchStartDolly(t),this.enableRotate&&this._handleTouchStartRotate(t)}_handleTouchMoveRotate(t){if(this._pointers.length==1)this._rotateEnd.set(t.pageX,t.pageY);else{const n=this._getSecondPointerPosition(t),i=.5*(t.pageX+n.x),r=.5*(t.pageY+n.y);this._rotateEnd.set(i,r)}this._rotateDelta.subVectors(this._rotateEnd,this._rotateStart).multiplyScalar(this.rotateSpeed);const e=this.domElement;this._rotateLeft(Ye*this._rotateDelta.x/e.clientHeight),this._rotateUp(Ye*this._rotateDelta.y/e.clientHeight),this._rotateStart.copy(this._rotateEnd)}_handleTouchMovePan(t){if(this._pointers.length===1)this._panEnd.set(t.pageX,t.pageY);else{const e=this._getSecondPointerPosition(t),n=.5*(t.pageX+e.x),i=.5*(t.pageY+e.y);this._panEnd.set(n,i)}this._panDelta.subVectors(this._panEnd,this._panStart).multiplyScalar(this.panSpeed),this._pan(this._panDelta.x,this._panDelta.y),this._panStart.copy(this._panEnd)}_handleTouchMoveDolly(t){const e=this._getSecondPointerPosition(t),n=t.pageX-e.x,i=t.pageY-e.y,r=Math.sqrt(n*n+i*i);this._dollyEnd.set(0,r),this._dollyDelta.set(0,Math.pow(this._dollyEnd.y/this._dollyStart.y,this.zoomSpeed)),this._dollyOut(this._dollyDelta.y),this._dollyStart.copy(this._dollyEnd);const a=(t.pageX+e.x)*.5,o=(t.pageY+e.y)*.5;this._updateZoomParameters(a,o)}_handleTouchMoveDollyPan(t){this.enableZoom&&this._handleTouchMoveDolly(t),this.enablePan&&this._handleTouchMovePan(t)}_handleTouchMoveDollyRotate(t){this.enableZoom&&this._handleTouchMoveDolly(t),this.enableRotate&&this._handleTouchMoveRotate(t)}_addPointer(t){this._pointers.push(t.pointerId)}_removePointer(t){delete this._pointerPositions[t.pointerId];for(let e=0;e[o%4*e,Math.floor(o/4)*n],a=(o,l,c,u,h=26)=>{const[d,f]=r(o);t.fillStyle=u,t.fillRect(d,f,e,n),t.fillStyle=c,t.font=`${h}px "Libertinus Mono", ui-monospace, monospace`,t.textAlign="center",l.forEach((p,v)=>t.fillText(p,d+e/2,f+n/2+(v-(l.length-1)/2)*h*1.3+h*.35)),t.textAlign="left"};a(1,["NO SIGNAL"],"#ffffff","#1432c8",30);{const[o,l]=r(2);["#c0c0c0","#c0c000","#00c0c0","#00c000","#c000c0","#c00000","#0000c0"].forEach((c,u)=>{t.fillStyle=c,t.fillRect(o+u*e/7,l,e/7+1,n*.7)}),t.fillStyle="#0b0b0b",t.fillRect(o,l+n*.7,e,n*.3)}a(3,["PRESENT DAY","PRESENT TIME"],"#e8e8e8","#050505",22);{const[o,l]=r(4);t.fillStyle="#000",t.fillRect(o,l,e,n),t.fillStyle="#b8b8b8",t.font="18px ui-monospace, monospace",t.fillText("C:\\>_",o+16,l+34)}a(5,["▶ PLAY"],"#ffffff","#0a1a7a",30),a(6,["æ"],"#f4f1ea","#000000",110),a(7,["CLOSE THE WORLD","OPEN THE nExT"],"#ff4a4a","#070000",18)}const i=new li(s);return i.colorSpace=Se,i}class J_{constructor(t,e,n){I(this,"group",new pn);I(this,"screens");I(this,"uniforms",{uTime:{value:0},uAtlas:{value:null},uFogColor:{value:new kt},uFogDensity:{value:0}});this.uniforms.uFogColor.value.copy(n.color),this.uniforms.uFogDensity.value=n.density;const i=new Dn(1.26,1.1,.95,2,.05);i.translate(0,.55,-.475);const r=new Vc(i,new Ee({roughness:.6,metalness:.05}),t),a=new We(1,.75);a.translate(0,.62,.004),this.uniforms.uAtlas.value=Z_();const o=new Ce({uniforms:this.uniforms,vertexShader:` +}`;class Vv{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(t,e){if(this.texture===null){const n=new Bh(t.texture);(t.depthNear!==e.depthNear||t.depthFar!==e.depthFar)&&(this.depthNear=t.depthNear,this.depthFar=t.depthFar),this.texture=n}}getMesh(t){if(this.texture!==null&&this.mesh===null){const e=t.cameras[0].viewport,n=new Pe({vertexShader:Hv,fragmentShader:Gv,uniforms:{depthColor:{value:this.texture},depthWidth:{value:e.z},depthHeight:{value:e.w}}});this.mesh=new zt(new Xe(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}getDepthTexture(){return this.texture}}class Wv extends li{constructor(t,e){super();const n=this;let i=null,r=1,o=null,a="local-floor",l=1,c=null,u=null,h=null,d=null,f=null,p=null;const x=typeof XRWebGLBinding<"u",m=new Vv,g={},b=e.getContextAttributes();let E=null,y=null;const M=[],w=[],C=new pt;let v=null;const T=new Ke;T.viewport=new ge;const L=new Ke;L.viewport=new ge;const D=[T,L],U=new Rm;let Y=null,K=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(Q){let I=M[Q];return I===void 0&&(I=new hl,M[Q]=I),I.getTargetRaySpace()},this.getControllerGrip=function(Q){let I=M[Q];return I===void 0&&(I=new hl,M[Q]=I),I.getGripSpace()},this.getHand=function(Q){let I=M[Q];return I===void 0&&(I=new hl,M[Q]=I),I.getHandSpace()};function N(Q){const I=w.indexOf(Q.inputSource);if(I===-1)return;const X=M[I];X!==void 0&&(X.update(Q.inputSource,Q.frame,c||o),X.dispatchEvent({type:Q.type,data:Q.inputSource}))}function B(){i.removeEventListener("select",N),i.removeEventListener("selectstart",N),i.removeEventListener("selectend",N),i.removeEventListener("squeeze",N),i.removeEventListener("squeezestart",N),i.removeEventListener("squeezeend",N),i.removeEventListener("end",B),i.removeEventListener("inputsourceschange",z);for(let Q=0;Q=0&&(w[st]=null,M[st].disconnect(X))}for(let I=0;I=w.length){w.push(X),st=lt;break}else if(w[lt]===null){w[lt]=X,st=lt;break}if(st===-1)break}const dt=M[st];dt&&dt.connect(X)}}const Z=new P,nt=new P;function rt(Q,I,X){Z.setFromMatrixPosition(I.matrixWorld),nt.setFromMatrixPosition(X.matrixWorld);const st=Z.distanceTo(nt),dt=I.projectionMatrix.elements,lt=X.projectionMatrix.elements,Ot=dt[14]/(dt[10]-1),Dt=dt[14]/(dt[10]+1),Vt=(dt[9]+1)/dt[5],jt=(dt[9]-1)/dt[5],Qt=(dt[8]-1)/dt[0],ne=(lt[8]+1)/lt[0],ce=Ot*Qt,he=Ot*ne,Ce=st/(-Qt+ne),ve=Ce*-Qt;if(I.matrixWorld.decompose(Q.position,Q.quaternion,Q.scale),Q.translateX(ve),Q.translateZ(Ce),Q.matrixWorld.compose(Q.position,Q.quaternion,Q.scale),Q.matrixWorldInverse.copy(Q.matrixWorld).invert(),dt[10]===-1)Q.projectionMatrix.copy(I.projectionMatrix),Q.projectionMatrixInverse.copy(I.projectionMatrixInverse);else{const Re=Ot+Ce,O=Dt+Ce,Je=ce-ve,oe=he+(st-ve),A=Vt*Dt/O*Re,_=jt*Dt/O*Re;Q.projectionMatrix.makePerspective(Je,oe,A,_,Re,O),Q.projectionMatrixInverse.copy(Q.projectionMatrix).invert()}}function ot(Q,I){I===null?Q.matrixWorld.copy(Q.matrix):Q.matrixWorld.multiplyMatrices(I.matrixWorld,Q.matrix),Q.matrixWorldInverse.copy(Q.matrixWorld).invert()}this.updateCamera=function(Q){if(i===null)return;let I=Q.near,X=Q.far;m.texture!==null&&(m.depthNear>0&&(I=m.depthNear),m.depthFar>0&&(X=m.depthFar)),U.near=L.near=T.near=I,U.far=L.far=T.far=X,(Y!==U.near||K!==U.far)&&(i.updateRenderState({depthNear:U.near,depthFar:U.far}),Y=U.near,K=U.far),U.layers.mask=Q.layers.mask|6,T.layers.mask=U.layers.mask&-5,L.layers.mask=U.layers.mask&-3;const st=Q.parent,dt=U.cameras;ot(U,st);for(let lt=0;lt0&&(m.alphaTest.value=g.alphaTest);const b=t.get(g),E=b.envMap,y=b.envMapRotation;E&&(m.envMap.value=E,m.envMapRotation.value.setFromMatrix4($v.makeRotationFromEuler(y)).transpose(),E.isCubeTexture&&E.isRenderTargetTexture===!1&&m.envMapRotation.value.premultiply(Nu),m.reflectivity.value=g.reflectivity,m.ior.value=g.ior,m.refractionRatio.value=g.refractionRatio),g.lightMap&&(m.lightMap.value=g.lightMap,m.lightMapIntensity.value=g.lightMapIntensity,e(g.lightMap,m.lightMapTransform)),g.aoMap&&(m.aoMap.value=g.aoMap,m.aoMapIntensity.value=g.aoMapIntensity,e(g.aoMap,m.aoMapTransform))}function o(m,g){m.diffuse.value.copy(g.color),m.opacity.value=g.opacity,g.map&&(m.map.value=g.map,e(g.map,m.mapTransform))}function a(m,g){m.dashSize.value=g.dashSize,m.totalSize.value=g.dashSize+g.gapSize,m.scale.value=g.scale}function l(m,g,b,E){m.diffuse.value.copy(g.color),m.opacity.value=g.opacity,m.size.value=g.size*b,m.scale.value=E*.5,g.map&&(m.map.value=g.map,e(g.map,m.uvTransform)),g.alphaMap&&(m.alphaMap.value=g.alphaMap,e(g.alphaMap,m.alphaMapTransform)),g.alphaTest>0&&(m.alphaTest.value=g.alphaTest)}function c(m,g){m.diffuse.value.copy(g.color),m.opacity.value=g.opacity,m.rotation.value=g.rotation,g.map&&(m.map.value=g.map,e(g.map,m.mapTransform)),g.alphaMap&&(m.alphaMap.value=g.alphaMap,e(g.alphaMap,m.alphaMapTransform)),g.alphaTest>0&&(m.alphaTest.value=g.alphaTest)}function u(m,g){m.specular.value.copy(g.specular),m.shininess.value=Math.max(g.shininess,1e-4)}function h(m,g){g.gradientMap&&(m.gradientMap.value=g.gradientMap)}function d(m,g){m.metalness.value=g.metalness,g.metalnessMap&&(m.metalnessMap.value=g.metalnessMap,e(g.metalnessMap,m.metalnessMapTransform)),m.roughness.value=g.roughness,g.roughnessMap&&(m.roughnessMap.value=g.roughnessMap,e(g.roughnessMap,m.roughnessMapTransform)),g.envMap&&(m.envMapIntensity.value=g.envMapIntensity)}function f(m,g,b){m.ior.value=g.ior,g.sheen>0&&(m.sheenColor.value.copy(g.sheenColor).multiplyScalar(g.sheen),m.sheenRoughness.value=g.sheenRoughness,g.sheenColorMap&&(m.sheenColorMap.value=g.sheenColorMap,e(g.sheenColorMap,m.sheenColorMapTransform)),g.sheenRoughnessMap&&(m.sheenRoughnessMap.value=g.sheenRoughnessMap,e(g.sheenRoughnessMap,m.sheenRoughnessMapTransform))),g.clearcoat>0&&(m.clearcoat.value=g.clearcoat,m.clearcoatRoughness.value=g.clearcoatRoughness,g.clearcoatMap&&(m.clearcoatMap.value=g.clearcoatMap,e(g.clearcoatMap,m.clearcoatMapTransform)),g.clearcoatRoughnessMap&&(m.clearcoatRoughnessMap.value=g.clearcoatRoughnessMap,e(g.clearcoatRoughnessMap,m.clearcoatRoughnessMapTransform)),g.clearcoatNormalMap&&(m.clearcoatNormalMap.value=g.clearcoatNormalMap,e(g.clearcoatNormalMap,m.clearcoatNormalMapTransform),m.clearcoatNormalScale.value.copy(g.clearcoatNormalScale),g.side===We&&m.clearcoatNormalScale.value.negate())),g.dispersion>0&&(m.dispersion.value=g.dispersion),g.iridescence>0&&(m.iridescence.value=g.iridescence,m.iridescenceIOR.value=g.iridescenceIOR,m.iridescenceThicknessMinimum.value=g.iridescenceThicknessRange[0],m.iridescenceThicknessMaximum.value=g.iridescenceThicknessRange[1],g.iridescenceMap&&(m.iridescenceMap.value=g.iridescenceMap,e(g.iridescenceMap,m.iridescenceMapTransform)),g.iridescenceThicknessMap&&(m.iridescenceThicknessMap.value=g.iridescenceThicknessMap,e(g.iridescenceThicknessMap,m.iridescenceThicknessMapTransform))),g.transmission>0&&(m.transmission.value=g.transmission,m.transmissionSamplerMap.value=b.texture,m.transmissionSamplerSize.value.set(b.width,b.height),g.transmissionMap&&(m.transmissionMap.value=g.transmissionMap,e(g.transmissionMap,m.transmissionMapTransform)),m.thickness.value=g.thickness,g.thicknessMap&&(m.thicknessMap.value=g.thicknessMap,e(g.thicknessMap,m.thicknessMapTransform)),m.attenuationDistance.value=g.attenuationDistance,m.attenuationColor.value.copy(g.attenuationColor)),g.anisotropy>0&&(m.anisotropyVector.value.set(g.anisotropy*Math.cos(g.anisotropyRotation),g.anisotropy*Math.sin(g.anisotropyRotation)),g.anisotropyMap&&(m.anisotropyMap.value=g.anisotropyMap,e(g.anisotropyMap,m.anisotropyMapTransform))),m.specularIntensity.value=g.specularIntensity,m.specularColor.value.copy(g.specularColor),g.specularColorMap&&(m.specularColorMap.value=g.specularColorMap,e(g.specularColorMap,m.specularColorMapTransform)),g.specularIntensityMap&&(m.specularIntensityMap.value=g.specularIntensityMap,e(g.specularIntensityMap,m.specularIntensityMapTransform))}function p(m,g){g.matcap&&(m.matcap.value=g.matcap)}function x(m,g){const b=t.get(g).light;m.referencePosition.value.setFromMatrixPosition(b.matrixWorld),m.nearDistance.value=b.shadow.camera.near,m.farDistance.value=b.shadow.camera.far}return{refreshFogUniforms:n,refreshMaterialUniforms:i}}function qv(s,t,e,n){let i={},r={},o=[];const a=s.getParameter(s.MAX_UNIFORM_BUFFER_BINDINGS);function l(y,M){const w=M.program;n.uniformBlockBinding(y,w)}function c(y,M){let w=i[y.id];w===void 0&&(m(y),w=u(y),i[y.id]=w,y.addEventListener("dispose",b));const C=M.program;n.updateUBOMapping(y,C);const v=t.render.frame;r[y.id]!==v&&(d(y),r[y.id]=v)}function u(y){const M=h();y.__bindingPointIndex=M;const w=s.createBuffer(),C=y.__size,v=y.usage;return s.bindBuffer(s.UNIFORM_BUFFER,w),s.bufferData(s.UNIFORM_BUFFER,C,v),s.bindBuffer(s.UNIFORM_BUFFER,null),s.bindBufferBase(s.UNIFORM_BUFFER,M,w),w}function h(){for(let y=0;y0&&(w+=C-v),y.__size=w,y.__cache={},this}function g(y){const M={boundary:0,storage:0};return typeof y=="number"||typeof y=="boolean"?(M.boundary=4,M.storage=4):y.isVector2?(M.boundary=8,M.storage=8):y.isVector3||y.isColor?(M.boundary=16,M.storage=12):y.isVector4?(M.boundary=16,M.storage=16):y.isMatrix3?(M.boundary=48,M.storage=48):y.isMatrix4?(M.boundary=64,M.storage=64):y.isTexture?Ut("WebGLRenderer: Texture samplers can not be part of an uniforms group."):ArrayBuffer.isView(y)?(M.boundary=16,M.storage=y.byteLength):Ut("WebGLRenderer: Unsupported uniform value type.",y),M}function b(y){const M=y.target;M.removeEventListener("dispose",b);const w=o.indexOf(M.__bindingPointIndex);o.splice(w,1),s.deleteBuffer(i[M.id]),delete i[M.id],delete r[M.id]}function E(){for(const y in i)s.deleteBuffer(i[y]);o=[],i={},r={}}return{bind:l,update:c,dispose:E}}const Yv=new Uint16Array([12469,15057,12620,14925,13266,14620,13807,14376,14323,13990,14545,13625,14713,13328,14840,12882,14931,12528,14996,12233,15039,11829,15066,11525,15080,11295,15085,10976,15082,10705,15073,10495,13880,14564,13898,14542,13977,14430,14158,14124,14393,13732,14556,13410,14702,12996,14814,12596,14891,12291,14937,11834,14957,11489,14958,11194,14943,10803,14921,10506,14893,10278,14858,9960,14484,14039,14487,14025,14499,13941,14524,13740,14574,13468,14654,13106,14743,12678,14818,12344,14867,11893,14889,11509,14893,11180,14881,10751,14852,10428,14812,10128,14765,9754,14712,9466,14764,13480,14764,13475,14766,13440,14766,13347,14769,13070,14786,12713,14816,12387,14844,11957,14860,11549,14868,11215,14855,10751,14825,10403,14782,10044,14729,9651,14666,9352,14599,9029,14967,12835,14966,12831,14963,12804,14954,12723,14936,12564,14917,12347,14900,11958,14886,11569,14878,11247,14859,10765,14828,10401,14784,10011,14727,9600,14660,9289,14586,8893,14508,8533,15111,12234,15110,12234,15104,12216,15092,12156,15067,12010,15028,11776,14981,11500,14942,11205,14902,10752,14861,10393,14812,9991,14752,9570,14682,9252,14603,8808,14519,8445,14431,8145,15209,11449,15208,11451,15202,11451,15190,11438,15163,11384,15117,11274,15055,10979,14994,10648,14932,10343,14871,9936,14803,9532,14729,9218,14645,8742,14556,8381,14461,8020,14365,7603,15273,10603,15272,10607,15267,10619,15256,10631,15231,10614,15182,10535,15118,10389,15042,10167,14963,9787,14883,9447,14800,9115,14710,8665,14615,8318,14514,7911,14411,7507,14279,7198,15314,9675,15313,9683,15309,9712,15298,9759,15277,9797,15229,9773,15166,9668,15084,9487,14995,9274,14898,8910,14800,8539,14697,8234,14590,7790,14479,7409,14367,7067,14178,6621,15337,8619,15337,8631,15333,8677,15325,8769,15305,8871,15264,8940,15202,8909,15119,8775,15022,8565,14916,8328,14804,8009,14688,7614,14569,7287,14448,6888,14321,6483,14088,6171,15350,7402,15350,7419,15347,7480,15340,7613,15322,7804,15287,7973,15229,8057,15148,8012,15046,7846,14933,7611,14810,7357,14682,7069,14552,6656,14421,6316,14251,5948,14007,5528,15356,5942,15356,5977,15353,6119,15348,6294,15332,6551,15302,6824,15249,7044,15171,7122,15070,7050,14949,6861,14818,6611,14679,6349,14538,6067,14398,5651,14189,5311,13935,4958,15359,4123,15359,4153,15356,4296,15353,4646,15338,5160,15311,5508,15263,5829,15188,6042,15088,6094,14966,6001,14826,5796,14678,5543,14527,5287,14377,4985,14133,4586,13869,4257,15360,1563,15360,1642,15358,2076,15354,2636,15341,3350,15317,4019,15273,4429,15203,4732,15105,4911,14981,4932,14836,4818,14679,4621,14517,4386,14359,4156,14083,3795,13808,3437,15360,122,15360,137,15358,285,15355,636,15344,1274,15322,2177,15281,2765,15215,3223,15120,3451,14995,3569,14846,3567,14681,3466,14511,3305,14344,3121,14037,2800,13753,2467,15360,0,15360,1,15359,21,15355,89,15346,253,15325,479,15287,796,15225,1148,15133,1492,15008,1749,14856,1882,14685,1886,14506,1783,14324,1608,13996,1398,13702,1183]);let In=null;function Kv(){return In===null&&(In=new Ph(Yv,16,16,Fi,Qe),In.name="DFG_LUT",In.minFilter=Oe,In.magFilter=Oe,In.wrapS=Gn,In.wrapT=Gn,In.generateMipmaps=!1,In.needsUpdate=!0),In}class Zv{constructor(t={}){const{canvas:e=fp(),context:n=null,depth:i=!0,stencil:r=!1,alpha:o=!1,antialias:a=!1,premultipliedAlpha:l=!0,preserveDrawingBuffer:c=!1,powerPreference:u="default",failIfMajorPerformanceCaveat:h=!1,reversedDepthBuffer:d=!1,outputBufferType:f=je}=t;this.isWebGLRenderer=!0;let p;if(n!==null){if(typeof WebGLRenderingContext<"u"&&n instanceof WebGLRenderingContext)throw new Error("THREE.WebGLRenderer: WebGL 1 is not supported since r163.");p=n.getContextAttributes().alpha}else p=o;const x=f,m=new Set([ba,Ma,ya]),g=new Set([je,Cn,$s,Xs,xa,va]),b=new Uint32Array(4),E=new Int32Array(4),y=new P;let M=null,w=null;const C=[],v=[];let T=null;this.domElement=e,this.debug={checkShaderErrors:!0,onShaderError:null},this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this.toneMapping=An,this.toneMappingExposure=1,this.transmissionResolutionScale=1;const L=this;let D=!1,U=null,Y=null,K=null,N=null;this._outputColorSpace=we;let B=0,z=0,Z=null,nt=-1,rt=null;const ot=new ge,ht=new ge;let Gt=null;const me=new Bt(0);let ee=0,Q=e.width,I=e.height,X=1,st=null,dt=null;const lt=new ge(0,0,Q,I),Ot=new ge(0,0,Q,I);let Dt=!1;const Vt=new ro;let jt=!1,Qt=!1;const ne=new re,ce=new P,he=new ge,Ce={background:null,fog:null,environment:null,overrideMaterial:null,isScene:!0};let ve=!1;function Re(){return Z===null?X:1}let O=n;function Je(S,k){return e.getContext(S,k)}try{const S={alpha:!0,depth:i,stencil:r,antialias:a,premultipliedAlpha:l,preserveDrawingBuffer:c,powerPreference:u,failIfMajorPerformanceCaveat:h};if("setAttribute"in e&&e.setAttribute("data-engine",`three.js r${Zo}`),e.addEventListener("webglcontextlost",_e,!1),e.addEventListener("webglcontextrestored",fe,!1),e.addEventListener("webglcontextcreationerror",Fn,!1),O===null){const k="webgl2";if(O=Je(k,S),O===null)throw Je(k)?new Error("THREE.WebGLRenderer: Error creating WebGL context with your selected attributes."):new Error("THREE.WebGLRenderer: Error creating WebGL context.")}}catch(S){throw te("WebGLRenderer: "+S.message),S}let oe,A,_,H,$,J,ct,ft,j,et,mt,Ct,_t,gt,Nt,Ft,$t,F,ut,tt,xt,bt,it;function At(){oe=new Kg(O),oe.init(),xt=new zv(O,oe),A=new Hg(O,oe,t,xt),_=new kv(O,oe),A.reversedDepthBuffer&&d&&_.buffers.depth.setReversed(!0),Y=O.createFramebuffer(),K=O.createFramebuffer(),N=O.createFramebuffer(),H=new jg(O),$=new wv,J=new Bv(O,oe,_,$,A,xt,H),ct=new Yg(L),ft=new Fm(O),bt=new Bg(O,ft),j=new Zg(O,ft,H,bt),et=new tx(O,j,ft,bt,H),F=new Qg(O,A,J),Nt=new Gg($),mt=new Sv(L,ct,oe,A,bt,Nt),Ct=new Xv(L,$),_t=new Tv,gt=new Dv(oe),$t=new kg(L,ct,_,et,p,l),Ft=new Ov(L,et,A),it=new qv(O,H,A,_),ut=new zg(O,oe,H),tt=new Jg(O,oe,H),H.programs=mt.programs,L.capabilities=A,L.extensions=oe,L.properties=$,L.renderLists=_t,L.shadowMap=Ft,L.state=_,L.info=H}At(),x!==je&&(T=new nx(x,e.width,e.height,a,i,r));const Et=new Wv(L,O);this.xr=Et,this.getContext=function(){return O},this.getContextAttributes=function(){return O.getContextAttributes()},this.forceContextLoss=function(){const S=oe.get("WEBGL_lose_context");S&&S.loseContext()},this.forceContextRestore=function(){const S=oe.get("WEBGL_lose_context");S&&S.restoreContext()},this.getPixelRatio=function(){return X},this.setPixelRatio=function(S){S!==void 0&&(X=S,this.setSize(Q,I,!1))},this.getSize=function(S){return S.set(Q,I)},this.setSize=function(S,k,q=!0){if(Et.isPresenting){Ut("WebGLRenderer: Can't change size while VR device is presenting.");return}Q=S,I=k,e.width=Math.floor(S*X),e.height=Math.floor(k*X),q===!0&&(e.style.width=S+"px",e.style.height=k+"px"),T!==null&&T.setSize(e.width,e.height),this.setViewport(0,0,S,k)},this.getDrawingBufferSize=function(S){return S.set(Q*X,I*X).floor()},this.setDrawingBufferSize=function(S,k,q){Q=S,I=k,X=q,e.width=Math.floor(S*q),e.height=Math.floor(k*q),this.setViewport(0,0,S,k)},this.setEffects=function(S){if(x===je){te("WebGLRenderer: setEffects() requires outputBufferType set to HalfFloatType or FloatType.");return}if(S){for(let k=0;k{function Mt(){if(G.forEach(function(wt){$.get(wt).currentProgram.isReady()&&G.delete(wt)}),G.size===0){V(S);return}setTimeout(Mt,10)}oe.get("KHR_parallel_shader_compile")!==null?Mt():setTimeout(Mt,10)})};let vc=null;function Ry(S){vc&&vc(S)}function Md(){$i.stop()}function bd(){$i.start()}const $i=new su;$i.setAnimationLoop(Ry),typeof self<"u"&&$i.setContext(self),this.setAnimationLoop=function(S){vc=S,Et.setAnimationLoop(S),S===null?$i.stop():$i.start()},Et.addEventListener("sessionstart",Md),Et.addEventListener("sessionend",bd),this.render=function(S,k){if(k!==void 0&&k.isCamera!==!0){te("WebGLRenderer.render: camera is not an instance of THREE.Camera.");return}if(D===!0)return;U!==null&&U.renderStart(S,k);const q=Et.enabled===!0&&Et.isPresenting===!0,G=T!==null&&(Z===null||q)&&T.begin(L,Z);if(S.matrixWorldAutoUpdate===!0&&S.updateMatrixWorld(),k.parent===null&&k.matrixWorldAutoUpdate===!0&&k.updateMatrixWorld(),Et.enabled===!0&&Et.isPresenting===!0&&(T===null||T.isCompositing()===!1)&&(Et.cameraAutoUpdate===!0&&Et.updateCamera(k),k=Et.getCamera()),S.isScene===!0&&S.onBeforeRender(L,S,k,Z),w=gt.get(S,v.length),w.init(k),w.state.textureUnits=J.getTextureUnits(),v.push(w),ne.multiplyMatrices(k.projectionMatrix,k.matrixWorldInverse),Vt.setFromProjectionMatrix(ne,Rn,k.reversedDepth),Qt=this.localClippingEnabled,jt=Nt.init(this.clippingPlanes,Qt),M=_t.get(S,C.length),M.init(),C.push(M),Et.enabled===!0&&Et.isPresenting===!0){const wt=L.xr.getDepthSensingMesh();wt!==null&&_c(wt,k,-1/0,L.sortObjects)}_c(S,k,0,L.sortObjects),M.finish(),L.sortObjects===!0&&M.sort(st,dt,k.reversedDepth),ve=Et.enabled===!1||Et.isPresenting===!1||Et.hasDepthSensing()===!1,ve&&$t.addToRenderList(M,S),this.info.render.frame++,this.info.autoReset===!0&&this.info.reset(),jt===!0&&Nt.beginShadows();const V=w.state.shadowsArray;if(Ft.render(V,S,k),jt===!0&&Nt.endShadows(),(G&&T.hasRenderPass())===!1){const wt=M.opaque,yt=M.transmissive;if(w.setupLights(),k.isArrayCamera){const Tt=k.cameras;if(yt.length>0)for(let Rt=0,Xt=Tt.length;Rt0&&wd(wt,yt,S,k),ve&&$t.render(S),Sd(M,S,k)}Z!==null&&z===0&&(J.updateMultisampleRenderTarget(Z),J.updateRenderTargetMipmap(Z)),G&&T.end(L),S.isScene===!0&&S.onAfterRender(L,S,k),bt.resetDefaultState(),nt=-1,rt=null,v.pop(),v.length>0?(w=v[v.length-1],J.setTextureUnits(w.state.textureUnits),jt===!0&&Nt.setGlobalState(L.clippingPlanes,w.state.camera)):w=null,C.pop(),C.length>0?M=C[C.length-1]:M=null,U!==null&&U.renderEnd()};function _c(S,k,q,G){if(S.visible===!1)return;if(S.layers.test(k.layers)){if(S.isGroup)q=S.renderOrder;else if(S.isLOD)S.autoUpdate===!0&&S.update(k);else if(S.isLightProbeGrid)w.pushLightProbeGrid(S);else if(S.isLight)w.pushLight(S),S.castShadow&&w.pushShadow(S);else if(S.isSprite){if(!S.frustumCulled||Vt.intersectsSprite(S)){G&&he.setFromMatrixPosition(S.matrixWorld).applyMatrix4(ne);const wt=et.update(S),yt=S.material;yt.visible&&M.push(S,wt,yt,q,he.z,null)}}else if((S.isMesh||S.isLine||S.isPoints)&&(!S.frustumCulled||Vt.intersectsObject(S))){const wt=et.update(S),yt=S.material;if(G&&(S.boundingSphere!==void 0?(S.boundingSphere===null&&S.computeBoundingSphere(),he.copy(S.boundingSphere.center)):(wt.boundingSphere===null&&wt.computeBoundingSphere(),he.copy(wt.boundingSphere.center)),he.applyMatrix4(S.matrixWorld).applyMatrix4(ne)),Array.isArray(yt)){const Tt=wt.groups;for(let Rt=0,Xt=Tt.length;Rt0&&Ao(V,k,q),Mt.length>0&&Ao(Mt,k,q),wt.length>0&&Ao(wt,k,q),_.buffers.depth.setTest(!0),_.buffers.depth.setMask(!0),_.buffers.color.setMask(!0),_.setPolygonOffset(!1)}function wd(S,k,q,G){if((q.isScene===!0?q.overrideMaterial:null)!==null)return;if(w.state.transmissionRenderTarget[G.id]===void 0){const Lt=oe.has("EXT_color_buffer_half_float")||oe.has("EXT_color_buffer_float");w.state.transmissionRenderTarget[G.id]=new Ye(1,1,{generateMipmaps:!0,type:Lt?Qe:je,minFilter:Ni,samples:Math.max(4,A.samples),stencilBuffer:r,resolveDepthBuffer:!1,resolveStencilBuffer:!1,colorSpace:Jt.workingColorSpace})}const Mt=w.state.transmissionRenderTarget[G.id],wt=G.viewport||ot;Mt.setSize(wt.z*L.transmissionResolutionScale,wt.w*L.transmissionResolutionScale);const yt=L.getRenderTarget(),Tt=L.getActiveCubeFace(),Rt=L.getActiveMipmapLevel();L.setRenderTarget(Mt),L.getClearColor(me),ee=L.getClearAlpha(),ee<1&&L.setClearColor(16777215,.5),L.clear(),ve&&$t.render(q);const Xt=L.toneMapping;L.toneMapping=An;const Kt=G.viewport;if(G.viewport!==void 0&&(G.viewport=void 0),w.setupLightsView(G),jt===!0&&Nt.setGlobalState(L.clippingPlanes,G),Ao(S,q,G),J.updateMultisampleRenderTarget(Mt),J.updateRenderTargetMipmap(Mt),oe.has("WEBGL_multisampled_render_to_texture")===!1){let Lt=!1;for(let le=0,be=k.length;le0,G.currentProgram=Kt,G.uniformsList=null,Kt}function Td(S){if(S.uniformsList===null){const k=S.currentProgram.getUniforms();S.uniformsList=vo.seqWithValue(k.seq,S.uniforms)}return S.uniformsList}function Ad(S,k){const q=$.get(S);q.outputColorSpace=k.outputColorSpace,q.batching=k.batching,q.batchingColor=k.batchingColor,q.instancing=k.instancing,q.instancingColor=k.instancingColor,q.instancingMorph=k.instancingMorph,q.skinning=k.skinning,q.morphTargets=k.morphTargets,q.morphNormals=k.morphNormals,q.morphColors=k.morphColors,q.morphTargetsCount=k.morphTargetsCount,q.numClippingPlanes=k.numClippingPlanes,q.numIntersection=k.numClipIntersection,q.vertexAlphas=k.vertexAlphas,q.vertexTangents=k.vertexTangents,q.toneMapping=k.toneMapping}function Py(S,k){if(S.length===0)return null;if(S.length===1)return S[0].texture!==null?S[0]:null;y.setFromMatrixPosition(k.matrixWorld);for(let q=0,G=S.length;q0),Lt=!!q.morphAttributes.position,le=!!q.morphAttributes.normal,be=!!q.morphAttributes.color;let ye=An;G.toneMapped&&(Z===null||Z.isXRRenderTarget===!0)&&(ye=L.toneMapping);const ue=q.morphAttributes.position||q.morphAttributes.normal||q.morphAttributes.color,Ge=ue!==void 0?ue.length:0,St=$.get(G),sn=w.state.lights;if(jt===!0&&(Qt===!0||S!==rt)){const pe=S===rt&&G.id===nt;Nt.setState(G,S,pe)}let ie=!1;G.version===St.__version?(St.needsLights&&St.lightsStateVersion!==sn.state.version||St.outputColorSpace!==yt||V.isBatchedMesh&&St.batching===!1||!V.isBatchedMesh&&St.batching===!0||V.isBatchedMesh&&St.batchingColor===!0&&V.colorTexture===null||V.isBatchedMesh&&St.batchingColor===!1&&V.colorTexture!==null||V.isInstancedMesh&&St.instancing===!1||!V.isInstancedMesh&&St.instancing===!0||V.isSkinnedMesh&&St.skinning===!1||!V.isSkinnedMesh&&St.skinning===!0||V.isInstancedMesh&&St.instancingColor===!0&&V.instanceColor===null||V.isInstancedMesh&&St.instancingColor===!1&&V.instanceColor!==null||V.isInstancedMesh&&St.instancingMorph===!0&&V.morphTexture===null||V.isInstancedMesh&&St.instancingMorph===!1&&V.morphTexture!==null||St.envMap!==Rt||G.fog===!0&&St.fog!==Mt||St.numClippingPlanes!==void 0&&(St.numClippingPlanes!==Nt.numPlanes||St.numIntersection!==Nt.numIntersection)||St.vertexAlphas!==Xt||St.vertexTangents!==Kt||St.morphTargets!==Lt||St.morphNormals!==le||St.morphColors!==be||St.toneMapping!==ye||St.morphTargetsCount!==Ge||!!St.lightProbeGrid!=w.state.lightProbeGridArray.length>0)&&(ie=!0):(ie=!0,St.__version=G.version);let dn=St.currentProgram;ie===!0&&(dn=Co(G,k,V),U&&G.isNodeMaterial&&U.onUpdateProgram(G,dn,St));let kn=!1,bi=!1,Os=!1;const de=dn.getUniforms(),Se=St.uniforms;if(_.useProgram(dn.program)&&(kn=!0,bi=!0,Os=!0),G.id!==nt&&(nt=G.id,bi=!0),St.needsLights){const pe=Py(w.state.lightProbeGridArray,V);St.lightProbeGrid!==pe&&(St.lightProbeGrid=pe,bi=!0)}if(kn||rt!==S){_.buffers.depth.getReversed()&&S.reversedDepth!==!0&&(S._reversedDepth=!0,S.updateProjectionMatrix()),de.setValue(O,"projectionMatrix",S.projectionMatrix),de.setValue(O,"viewMatrix",S.matrixWorldInverse);const wi=de.map.cameraPosition;wi!==void 0&&wi.setValue(O,ce.setFromMatrixPosition(S.matrixWorld)),A.logarithmicDepthBuffer&&de.setValue(O,"logDepthBufFC",2/(Math.log(S.far+1)/Math.LN2)),(G.isMeshPhongMaterial||G.isMeshToonMaterial||G.isMeshLambertMaterial||G.isMeshBasicMaterial||G.isMeshStandardMaterial||G.isShaderMaterial)&&de.setValue(O,"isOrthographic",S.isOrthographicCamera===!0),rt!==S&&(rt=S,bi=!0,Os=!0)}if(St.needsLights&&(sn.state.directionalShadowMap.length>0&&de.setValue(O,"directionalShadowMap",sn.state.directionalShadowMap,J),sn.state.spotShadowMap.length>0&&de.setValue(O,"spotShadowMap",sn.state.spotShadowMap,J),sn.state.pointShadowMap.length>0&&de.setValue(O,"pointShadowMap",sn.state.pointShadowMap,J)),V.isSkinnedMesh){de.setOptional(O,V,"bindMatrix"),de.setOptional(O,V,"bindMatrixInverse");const pe=V.skeleton;pe&&(pe.boneTexture===null&&pe.computeBoneTexture(),de.setValue(O,"boneTexture",pe.boneTexture,J))}V.isBatchedMesh&&(de.setOptional(O,V,"batchingTexture"),de.setValue(O,"batchingTexture",V._matricesTexture,J),de.setOptional(O,V,"batchingIdTexture"),de.setValue(O,"batchingIdTexture",V._indirectTexture,J),de.setOptional(O,V,"batchingColorTexture"),V._colorsTexture!==null&&de.setValue(O,"batchingColorTexture",V._colorsTexture,J));const Si=q.morphAttributes;if((Si.position!==void 0||Si.normal!==void 0||Si.color!==void 0)&&F.update(V,q,dn),(bi||St.receiveShadow!==V.receiveShadow)&&(St.receiveShadow=V.receiveShadow,de.setValue(O,"receiveShadow",V.receiveShadow)),(G.isMeshStandardMaterial||G.isMeshLambertMaterial||G.isMeshPhongMaterial)&&G.envMap===null&&k.environment!==null&&(Se.envMapIntensity.value=k.environmentIntensity),Se.dfgLUT!==void 0&&(Se.dfgLUT.value=Kv()),bi){if(de.setValue(O,"toneMappingExposure",L.toneMappingExposure),St.needsLights&&Dy(Se,Os),Mt&&G.fog===!0&&Ct.refreshFogUniforms(Se,Mt),Ct.refreshMaterialUniforms(Se,G,X,I,w.state.transmissionRenderTarget[S.id]),St.needsLights&&St.lightProbeGrid){const pe=St.lightProbeGrid;Se.probesSH.value=pe.texture,Se.probesMin.value.copy(pe.boundingBox.min),Se.probesMax.value.copy(pe.boundingBox.max),Se.probesResolution.value.copy(pe.resolution)}vo.upload(O,Td(St),Se,J)}if(G.isShaderMaterial&&G.uniformsNeedUpdate===!0&&(vo.upload(O,Td(St),Se,J),G.uniformsNeedUpdate=!1),G.isSpriteMaterial&&de.setValue(O,"center",V.center),de.setValue(O,"modelViewMatrix",V.modelViewMatrix),de.setValue(O,"normalMatrix",V.normalMatrix),de.setValue(O,"modelMatrix",V.matrixWorld),G.uniformsGroups!==void 0){const pe=G.uniformsGroups;for(let wi=0,ks=pe.length;wi0&&J.useMultisampledRTT(S)===!1?G=$.get(S).__webglMultisampledFramebuffer:Array.isArray(Rt)?G=Rt[q]:G=Rt,ot.copy(S.viewport),ht.copy(S.scissor),Gt=S.scissorTest}else ot.copy(lt).multiplyScalar(X).floor(),ht.copy(Ot).multiplyScalar(X).floor(),Gt=Dt;if(q!==0&&(G=Y),_.bindFramebuffer(O.FRAMEBUFFER,G)&&_.drawBuffers(S,G),_.viewport(ot),_.scissor(ht),_.setScissorTest(Gt),V){const yt=$.get(S.texture);O.framebufferTexture2D(O.FRAMEBUFFER,O.COLOR_ATTACHMENT0,O.TEXTURE_CUBE_MAP_POSITIVE_X+k,yt.__webglTexture,q)}else if(Mt){const yt=k;for(let Tt=0;Tt1&&O.readBuffer(O.COLOR_ATTACHMENT0+yt),!A.textureFormatReadable(Xt)){te("WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");return}if(!A.textureTypeReadable(Kt)){te("WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");return}k>=0&&k<=S.width-G&&q>=0&&q<=S.height-V&&O.readPixels(k,q,G,V,xt.convert(Xt),xt.convert(Kt),Mt)}finally{const Rt=Z!==null?$.get(Z).__webglFramebuffer:null;_.bindFramebuffer(O.FRAMEBUFFER,Rt)}}},this.readRenderTargetPixelsAsync=async function(S,k,q,G,V,Mt,wt,yt=0){if(!(S&&S.isWebGLRenderTarget))throw new Error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let Tt=$.get(S).__webglFramebuffer;if(S.isWebGLCubeRenderTarget&&wt!==void 0&&(Tt=Tt[wt]),Tt)if(k>=0&&k<=S.width-G&&q>=0&&q<=S.height-V){_.bindFramebuffer(O.FRAMEBUFFER,Tt);const Rt=S.textures[yt],Xt=Rt.format,Kt=Rt.type;if(S.textures.length>1&&O.readBuffer(O.COLOR_ATTACHMENT0+yt),!A.textureFormatReadable(Xt))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.");if(!A.textureTypeReadable(Kt))throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.");const Lt=O.createBuffer();O.bindBuffer(O.PIXEL_PACK_BUFFER,Lt),O.bufferData(O.PIXEL_PACK_BUFFER,Mt.byteLength,O.STREAM_READ),O.readPixels(k,q,G,V,xt.convert(Xt),xt.convert(Kt),0);const le=Z!==null?$.get(Z).__webglFramebuffer:null;_.bindFramebuffer(O.FRAMEBUFFER,le);const be=O.fenceSync(O.SYNC_GPU_COMMANDS_COMPLETE,0);return O.flush(),await pp(O,be,4),O.bindBuffer(O.PIXEL_PACK_BUFFER,Lt),O.getBufferSubData(O.PIXEL_PACK_BUFFER,0,Mt),O.deleteBuffer(Lt),O.deleteSync(be),Mt}else throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.")},this.copyFramebufferToTexture=function(S,k=null,q=0){const G=Math.pow(2,-q),V=Math.floor(S.image.width*G),Mt=Math.floor(S.image.height*G),wt=k!==null?k.x:0,yt=k!==null?k.y:0;J.setTexture2D(S,0),O.copyTexSubImage2D(O.TEXTURE_2D,q,0,0,wt,yt,V,Mt),_.unbindTexture()},this.copyTextureToTexture=function(S,k,q=null,G=null,V=0,Mt=0){let wt,yt,Tt,Rt,Xt,Kt,Lt,le,be;const ye=S.isCompressedTexture?S.mipmaps[Mt]:S.image;if(q!==null)wt=q.max.x-q.min.x,yt=q.max.y-q.min.y,Tt=q.isBox3?q.max.z-q.min.z:1,Rt=q.min.x,Xt=q.min.y,Kt=q.isBox3?q.min.z:0;else{const Se=Math.pow(2,-V);wt=Math.floor(ye.width*Se),yt=Math.floor(ye.height*Se),S.isDataArrayTexture?Tt=ye.depth:S.isData3DTexture?Tt=Math.floor(ye.depth*Se):Tt=1,Rt=0,Xt=0,Kt=0}G!==null?(Lt=G.x,le=G.y,be=G.z):(Lt=0,le=0,be=0);const ue=xt.convert(k.format),Ge=xt.convert(k.type);let St;k.isData3DTexture?(J.setTexture3D(k,0),St=O.TEXTURE_3D):k.isDataArrayTexture||k.isCompressedArrayTexture?(J.setTexture2DArray(k,0),St=O.TEXTURE_2D_ARRAY):(J.setTexture2D(k,0),St=O.TEXTURE_2D),_.activeTexture(O.TEXTURE0),_.pixelStorei(O.UNPACK_FLIP_Y_WEBGL,k.flipY),_.pixelStorei(O.UNPACK_PREMULTIPLY_ALPHA_WEBGL,k.premultiplyAlpha),_.pixelStorei(O.UNPACK_ALIGNMENT,k.unpackAlignment);const sn=_.getParameter(O.UNPACK_ROW_LENGTH),ie=_.getParameter(O.UNPACK_IMAGE_HEIGHT),dn=_.getParameter(O.UNPACK_SKIP_PIXELS),kn=_.getParameter(O.UNPACK_SKIP_ROWS),bi=_.getParameter(O.UNPACK_SKIP_IMAGES);_.pixelStorei(O.UNPACK_ROW_LENGTH,ye.width),_.pixelStorei(O.UNPACK_IMAGE_HEIGHT,ye.height),_.pixelStorei(O.UNPACK_SKIP_PIXELS,Rt),_.pixelStorei(O.UNPACK_SKIP_ROWS,Xt),_.pixelStorei(O.UNPACK_SKIP_IMAGES,Kt);const Os=S.isDataArrayTexture||S.isData3DTexture,de=k.isDataArrayTexture||k.isData3DTexture;if(S.isDepthTexture){const Se=$.get(S),Si=$.get(k),pe=$.get(Se.__renderTarget),wi=$.get(Si.__renderTarget);_.bindFramebuffer(O.READ_FRAMEBUFFER,pe.__webglFramebuffer),_.bindFramebuffer(O.DRAW_FRAMEBUFFER,wi.__webglFramebuffer);for(let ks=0;ksMath.PI&&(n-=Ze),i<-Math.PI?i+=Ze:i>Math.PI&&(i-=Ze),n<=i?this._spherical.theta=Math.max(n,Math.min(i,this._spherical.theta)):this._spherical.theta=this._spherical.theta>(n+i)/2?Math.max(n,this._spherical.theta):Math.min(i,this._spherical.theta)),this._spherical.phi=Math.max(this.minPolarAngle,Math.min(this.maxPolarAngle,this._spherical.phi)),this._spherical.makeSafe(),this.enableDamping===!0?this.target.addScaledVector(this._panOffset,this.dampingFactor):this.target.add(this._panOffset),this.target.sub(this.cursor),this.target.clampLength(this.minTargetRadius,this.maxTargetRadius),this.target.add(this.cursor);let r=!1;if(this.zoomToCursor&&this._performCursorZoom||this.object.isOrthographicCamera)this._spherical.radius=this._clampDistance(this._spherical.radius);else{const o=this._spherical.radius;this._spherical.radius=this._clampDistance(this._spherical.radius*this._scale),r=o!=this._spherical.radius}if(Ie.setFromSpherical(this._spherical),Ie.applyQuaternion(this._quatInverse),e.copy(this.target).add(Ie),this.object.lookAt(this.target),this.enableDamping===!0?(this._sphericalDelta.theta*=1-this.dampingFactor,this._sphericalDelta.phi*=1-this.dampingFactor,this._panOffset.multiplyScalar(1-this.dampingFactor)):(this._sphericalDelta.set(0,0,0),this._panOffset.set(0,0,0)),this.zoomToCursor&&this._performCursorZoom){let o=null;if(this.object.isPerspectiveCamera){const a=Ie.length();o=this._clampDistance(a*this._scale);const l=a-o;this.object.position.addScaledVector(this._dollyDirection,l),this.object.updateMatrixWorld(),r=!!l}else if(this.object.isOrthographicCamera){const a=new P(this._mouse.x,this._mouse.y,0);a.unproject(this.object);const l=this.object.zoom;this.object.zoom=Math.max(this.minZoom,Math.min(this.maxZoom,this.object.zoom/this._scale)),this.object.updateProjectionMatrix(),r=l!==this.object.zoom;const c=new P(this._mouse.x,this._mouse.y,0);c.unproject(this.object),this.object.position.sub(c).add(a),this.object.updateMatrixWorld(),o=Ie.length()}else console.warn("WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled."),this.zoomToCursor=!1;o!==null&&(this.screenSpacePanning?this.target.set(0,0,-1).transformDirection(this.object.matrix).multiplyScalar(o).add(this.object.position):(yo.origin.copy(this.object.position),yo.direction.set(0,0,-1).transformDirection(this.object.matrix),Math.abs(this.object.up.dot(yo.direction))Yl||8*(1-this._lastQuaternion.dot(this.object.quaternion))>Yl||this._lastTargetPosition.distanceToSquared(this.target)>Yl?(this.dispatchEvent(Uu),this._lastPosition.copy(this.object.position),this._lastQuaternion.copy(this.object.quaternion),this._lastTargetPosition.copy(this.target),!0):!1}_getAutoRotationAngle(t){return t!==null?Ze/60*this.autoRotateSpeed*t:Ze/60/60*this.autoRotateSpeed}_getZoomScale(t){const e=Math.abs(t*.01);return Math.pow(.95,this.zoomSpeed*e)}_rotateLeft(t){this._sphericalDelta.theta-=t}_rotateUp(t){this._sphericalDelta.phi-=t}_panLeft(t,e){Ie.setFromMatrixColumn(e,0),Ie.multiplyScalar(-t),this._panOffset.add(Ie)}_panUp(t,e){this.screenSpacePanning===!0?Ie.setFromMatrixColumn(e,1):(Ie.setFromMatrixColumn(e,0),Ie.crossVectors(this.object.up,Ie)),Ie.multiplyScalar(t),this._panOffset.add(Ie)}_pan(t,e){const n=this.domElement;if(this.object.isPerspectiveCamera){const i=this.object.position;Ie.copy(i).sub(this.target);let r=Ie.length();r*=Math.tan(this.object.fov/2*Math.PI/180),this._panLeft(2*t*r/n.clientHeight,this.object.matrix),this._panUp(2*e*r/n.clientHeight,this.object.matrix)}else this.object.isOrthographicCamera?(this._panLeft(t*(this.object.right-this.object.left)/this.object.zoom/n.clientWidth,this.object.matrix),this._panUp(e*(this.object.top-this.object.bottom)/this.object.zoom/n.clientHeight,this.object.matrix)):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."),this.enablePan=!1)}_dollyOut(t){this.object.isPerspectiveCamera||this.object.isOrthographicCamera?this._scale/=t:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),this.enableZoom=!1)}_dollyIn(t){this.object.isPerspectiveCamera||this.object.isOrthographicCamera?this._scale*=t:(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),this.enableZoom=!1)}_updateZoomParameters(t,e){if(!this.zoomToCursor)return;this._performCursorZoom=!0;const n=this.domElement.getBoundingClientRect(),i=t-n.left,r=e-n.top,o=n.width,a=n.height;this._mouse.x=i/o*2-1,this._mouse.y=-(r/a)*2+1,this._dollyDirection.set(this._mouse.x,this._mouse.y,1).unproject(this.object).sub(this.object.position).normalize()}_clampDistance(t){return Math.max(this.minDistance,Math.min(this.maxDistance,t))}_handleMouseDownRotate(t){this._rotateStart.set(t.clientX,t.clientY)}_handleMouseDownDolly(t){this._updateZoomParameters(t.clientX,t.clientX),this._dollyStart.set(t.clientX,t.clientY)}_handleMouseDownPan(t){this._panStart.set(t.clientX,t.clientY)}_handleMouseMoveRotate(t){this._rotateEnd.set(t.clientX,t.clientY),this._rotateDelta.subVectors(this._rotateEnd,this._rotateStart).multiplyScalar(this.rotateSpeed);const e=this.domElement;this._rotateLeft(Ze*this._rotateDelta.x/e.clientHeight),this._rotateUp(Ze*this._rotateDelta.y/e.clientHeight),this._rotateStart.copy(this._rotateEnd),this.update()}_handleMouseMoveDolly(t){this._dollyEnd.set(t.clientX,t.clientY),this._dollyDelta.subVectors(this._dollyEnd,this._dollyStart),this._dollyDelta.y>0?this._dollyOut(this._getZoomScale(this._dollyDelta.y)):this._dollyDelta.y<0&&this._dollyIn(this._getZoomScale(this._dollyDelta.y)),this._dollyStart.copy(this._dollyEnd),this.update()}_handleMouseMovePan(t){this._panEnd.set(t.clientX,t.clientY),this._panDelta.subVectors(this._panEnd,this._panStart).multiplyScalar(this.panSpeed),this._pan(this._panDelta.x,this._panDelta.y),this._panStart.copy(this._panEnd),this.update()}_handleMouseWheel(t){this._updateZoomParameters(t.clientX,t.clientY),t.deltaY<0?this._dollyIn(this._getZoomScale(t.deltaY)):t.deltaY>0&&this._dollyOut(this._getZoomScale(t.deltaY)),this.update()}_handleKeyDown(t){let e=!1;switch(t.code){case this.keys.UP:t.ctrlKey||t.metaKey||t.shiftKey?this.enableRotate&&this._rotateUp(Ze*this.keyRotateSpeed/this.domElement.clientHeight):this.enablePan&&this._pan(0,this.keyPanSpeed),e=!0;break;case this.keys.BOTTOM:t.ctrlKey||t.metaKey||t.shiftKey?this.enableRotate&&this._rotateUp(-Ze*this.keyRotateSpeed/this.domElement.clientHeight):this.enablePan&&this._pan(0,-this.keyPanSpeed),e=!0;break;case this.keys.LEFT:t.ctrlKey||t.metaKey||t.shiftKey?this.enableRotate&&this._rotateLeft(Ze*this.keyRotateSpeed/this.domElement.clientHeight):this.enablePan&&this._pan(this.keyPanSpeed,0),e=!0;break;case this.keys.RIGHT:t.ctrlKey||t.metaKey||t.shiftKey?this.enableRotate&&this._rotateLeft(-Ze*this.keyRotateSpeed/this.domElement.clientHeight):this.enablePan&&this._pan(-this.keyPanSpeed,0),e=!0;break}e&&(t.preventDefault(),this.update())}_handleTouchStartRotate(t){if(this._pointers.length===1)this._rotateStart.set(t.pageX,t.pageY);else{const e=this._getSecondPointerPosition(t),n=.5*(t.pageX+e.x),i=.5*(t.pageY+e.y);this._rotateStart.set(n,i)}}_handleTouchStartPan(t){if(this._pointers.length===1)this._panStart.set(t.pageX,t.pageY);else{const e=this._getSecondPointerPosition(t),n=.5*(t.pageX+e.x),i=.5*(t.pageY+e.y);this._panStart.set(n,i)}}_handleTouchStartDolly(t){const e=this._getSecondPointerPosition(t),n=t.pageX-e.x,i=t.pageY-e.y,r=Math.sqrt(n*n+i*i);this._dollyStart.set(0,r)}_handleTouchStartDollyPan(t){this.enableZoom&&this._handleTouchStartDolly(t),this.enablePan&&this._handleTouchStartPan(t)}_handleTouchStartDollyRotate(t){this.enableZoom&&this._handleTouchStartDolly(t),this.enableRotate&&this._handleTouchStartRotate(t)}_handleTouchMoveRotate(t){if(this._pointers.length==1)this._rotateEnd.set(t.pageX,t.pageY);else{const n=this._getSecondPointerPosition(t),i=.5*(t.pageX+n.x),r=.5*(t.pageY+n.y);this._rotateEnd.set(i,r)}this._rotateDelta.subVectors(this._rotateEnd,this._rotateStart).multiplyScalar(this.rotateSpeed);const e=this.domElement;this._rotateLeft(Ze*this._rotateDelta.x/e.clientHeight),this._rotateUp(Ze*this._rotateDelta.y/e.clientHeight),this._rotateStart.copy(this._rotateEnd)}_handleTouchMovePan(t){if(this._pointers.length===1)this._panEnd.set(t.pageX,t.pageY);else{const e=this._getSecondPointerPosition(t),n=.5*(t.pageX+e.x),i=.5*(t.pageY+e.y);this._panEnd.set(n,i)}this._panDelta.subVectors(this._panEnd,this._panStart).multiplyScalar(this.panSpeed),this._pan(this._panDelta.x,this._panDelta.y),this._panStart.copy(this._panEnd)}_handleTouchMoveDolly(t){const e=this._getSecondPointerPosition(t),n=t.pageX-e.x,i=t.pageY-e.y,r=Math.sqrt(n*n+i*i);this._dollyEnd.set(0,r),this._dollyDelta.set(0,Math.pow(this._dollyEnd.y/this._dollyStart.y,this.zoomSpeed)),this._dollyOut(this._dollyDelta.y),this._dollyStart.copy(this._dollyEnd);const o=(t.pageX+e.x)*.5,a=(t.pageY+e.y)*.5;this._updateZoomParameters(o,a)}_handleTouchMoveDollyPan(t){this.enableZoom&&this._handleTouchMoveDolly(t),this.enablePan&&this._handleTouchMovePan(t)}_handleTouchMoveDollyRotate(t){this.enableZoom&&this._handleTouchMoveDolly(t),this.enableRotate&&this._handleTouchMoveRotate(t)}_addPointer(t){this._pointers.push(t.pointerId)}_removePointer(t){delete this._pointerPositions[t.pointerId];for(let e=0;e[a%4*e,Math.floor(a/4)*n],o=(a,l,c,u,h=26)=>{const[d,f]=r(a);t.fillStyle=u,t.fillRect(d,f,e,n),t.fillStyle=c,t.font=`${h}px "Libertinus Mono", ui-monospace, monospace`,t.textAlign="center",l.forEach((p,x)=>t.fillText(p,d+e/2,f+n/2+(x-(l.length-1)/2)*h*1.3+h*.35)),t.textAlign="left"};o(1,["NO SIGNAL"],"#ffffff","#1432c8",30);{const[a,l]=r(2);["#c0c0c0","#c0c000","#00c0c0","#00c000","#c000c0","#c00000","#0000c0"].forEach((c,u)=>{t.fillStyle=c,t.fillRect(a+u*e/7,l,e/7+1,n*.7)}),t.fillStyle="#0b0b0b",t.fillRect(a,l+n*.7,e,n*.3)}o(3,["PRESENT DAY","PRESENT TIME"],"#e8e8e8","#050505",22);{const[a,l]=r(4);t.fillStyle="#000",t.fillRect(a,l,e,n),t.fillStyle="#b8b8b8",t.font="18px ui-monospace, monospace",t.fillText("C:\\>_",a+16,l+34)}o(5,["▶ PLAY"],"#ffffff","#0a1a7a",30),o(6,["æ"],"#f4f1ea","#000000",110),o(7,["CLOSE THE WORLD","OPEN THE nExT"],"#ff4a4a","#070000",18)}const i=new mi(s);return i.colorSpace=we,i}class f_{constructor(t,e,n){R(this,"group",new vn);R(this,"screens");R(this,"uniforms",{uTime:{value:0},uAtlas:{value:null},uFogColor:{value:new Bt},uFogDensity:{value:0}});this.uniforms.uFogColor.value.copy(n.color),this.uniforms.uFogDensity.value=n.density;const i=new Nn(1.26,1.1,.95,2,.05);i.translate(0,.55,-.475);const r=new Ih(i,new Ae({roughness:.6,metalness:.05}),t),o=new Xe(1,.75);o.translate(0,.62,.004),this.uniforms.uAtlas.value=d_();const a=new Pe({uniforms:this.uniforms,vertexShader:` attribute float aTile; attribute float aSeed; attribute float aOn; @@ -4156,7 +4156,7 @@ void main() { col = mix(col, uFogColor, fogK * 0.7); gl_FragColor = vec4(col, 1.0); #include - }`});this.screens=new Vc(a,o,t);const l=new Float32Array(t),c=new Float32Array(t),u=new Float32Array(t),h=[12168852,1513242,7172214,855311,9407100],d=new se,f=new Cn,p=new Hn,v=new kt;let m=0;for(;m.3)continue;const w=9+e()*13,E=Math.sin(g)*w,M=-Math.cos(g)*w,S=Math.atan2(-E,-M)+(e()-.5)*.9,b=e()<.14,R=Math.min(t-m,b?1:1+Math.floor(e()*4));let x=b?4+e()*5:0;for(let T=0;T.3)continue;const b=9+e()*13,E=Math.sin(g)*b,y=-Math.cos(g)*b,M=Math.atan2(-E,-y)+(e()-.5)*.9,w=e()<.14,C=Math.min(t-m,w?1:1+Math.floor(e()*4));let v=w?4+e()*5:0;for(let T=0;T #include } -`;function tx(s,t){return new Ce({uniforms:{map:{value:s},uTime:{value:0},uPower:{value:0},uHover:{value:0},uStatic:{value:0},uSeed:{value:t},uGain:{value:1},uTint:{value:new kt(1,1,1)}},vertexShader:Q_,fragmentShader:j_})}function ex(s,t,e){const n=new We(s,t,24,18),i=n.attributes.position;for(let r=0;r{e&&(r?e.putImageData(r,0,0):r=e.getImageData(0,0,256,56),e.fillStyle="#16161c",e.font=i,e.textAlign="center",e.textBaseline="middle",e.save(),e.translate(128,31),e.rotate(-.02),e.fillText(s,0,0),e.restore())},()=>n.needsUpdate=!0),n.colorSpace=Se,n.anisotropy=4,n}class rx{constructor(t){I(this,"group",new pn);I(this,"texture");I(this,"crt");I(this,"glass");I(this,"hit");I(this,"height");I(this,"width");I(this,"depth");I(this,"screenH");I(this,"screenLocal");I(this,"portLocal");I(this,"topLocal");I(this,"led");const e=t.screenW,n=e*.75;this.screenH=n;const i=e*1.26,r=n+e*.34,a=e*.2;this.width=i,this.height=r+(t.stand?e*.08:0);const o=t.stand?e*.08:0,l=nx(t.style),c=new Bt(new Dn(i,r,a,3,e*.045),l);c.position.set(0,o+r/2,-a/2),this.group.add(c);const u=e*.62,h=new Bt(new Dn(i*.84,r*.86,u,3,e*.08),l);h.position.set(0,o+r*.52,-a-u/2+e*.04),this.group.add(h);const d=e*.3,f=new Bt(new Dn(i*.46,r*.46,d,2,e*.05),l);if(f.position.set(0,o+r*.54,-a-u-d/2+e*.1),this.group.add(f),this.depth=a+u+d-e*.14,t.stand){const g=new Bt(new ci(e*.34,e*.4,o,24),l);g.position.set(0,o/2,-a-u*.4),this.group.add(g)}const p=o+r/2+e*.07;this.screenLocal=new C(0,p,.02),this.portLocal=new C(e*.1,o+r*.25,-this.depth+e*.05),this.topLocal=new C(0,o+r,-a-u*.45);const v=new Bt(new We(e*1.05,n*1.05),ix);v.position.set(0,p,.002),this.group.add(v),this.texture=new li(t.screen),this.texture.colorSpace=Se,this.texture.minFilter=Ue,this.texture.generateMipmaps=!1,this.crt=tx(this.texture,t.seed),this.glass=new Bt(ex(e,n,e*.035),this.crt),this.glass.position.set(0,p,.004),this.group.add(this.glass);const m=new Bt(new We(e*.4,e*.088),new Ee({map:sx(t.label),transparent:!0,roughness:.9}));if(m.position.set(-e*.18,o+e*.075,.003),m.rotation.z=t.seed%7*.012-.03,this.group.add(m),this.led=new Bt(new Ws(e*.014,8,6),new xn({color:1714714})),this.led.position.set(i/2-e*.12,o+e*.08,.004),this.group.add(this.led),t.style==="tv"||t.style==="grey"){const g=new Ee({color:2763310,roughness:.4});for(let w=0;w<2;w++){const E=new Bt(new ci(e*.028,e*.028,e*.03,16),g);E.rotation.x=Math.PI/2,E.position.set(i/2-e*.24-w*e*.09,o+e*.08,.012),this.group.add(E)}}this.hit=new Bt(new tn(i,r,this.depth),new xn({visible:!1})),this.hit.position.set(0,o+r/2,-this.depth/2),this.group.add(this.hit)}setLed(t,e){this.led.material.color.set(t?e:"#1a2a1a")}world(t){return this.group.updateMatrixWorld(!0),t.clone().applyMatrix4(this.group.matrixWorld)}normal(){const t=new Cn;return this.group.getWorldQuaternion(t),new C(0,0,1).applyQuaternion(t)}}const jr={name:"CopyShader",uniforms:{tDiffuse:{value:null},opacity:{value:1}},vertexShader:` +`;function g_(s,t){return new Pe({uniforms:{map:{value:s},uTime:{value:0},uPower:{value:0},uHover:{value:0},uStatic:{value:0},uSeed:{value:t},uGain:{value:1},uTint:{value:new Bt(1,1,1)}},vertexShader:p_,fragmentShader:m_})}function x_(s,t,e){const n=new Xe(s,t,24,18),i=n.attributes.position;for(let r=0;r{e&&(r?e.putImageData(r,0,0):r=e.getImageData(0,0,256,56),e.fillStyle="#16161c",e.font=i,e.textAlign="center",e.textBaseline="middle",e.save(),e.translate(128,31),e.rotate(-.02),e.fillText(s,0,0),e.restore())},()=>n.needsUpdate=!0),n.colorSpace=we,n.anisotropy=4,n}class M_{constructor(t){R(this,"group",new vn);R(this,"texture");R(this,"crt");R(this,"glass");R(this,"hit");R(this,"height");R(this,"width");R(this,"depth");R(this,"screenH");R(this,"screenLocal");R(this,"portLocal");R(this,"topLocal");R(this,"led");const e=t.screenW,n=e*.75;this.screenH=n;const i=e*1.26,r=n+e*.34,o=e*.2;this.width=i,this.height=r+(t.stand?e*.08:0);const a=t.stand?e*.08:0,l=v_(t.style),c=new zt(new Nn(i,r,o,3,e*.045),l);c.position.set(0,a+r/2,-o/2),this.group.add(c);const u=e*.62,h=new zt(new Nn(i*.84,r*.86,u,3,e*.08),l);h.position.set(0,a+r*.52,-o-u/2+e*.04),this.group.add(h);const d=e*.3,f=new zt(new Nn(i*.46,r*.46,d,2,e*.05),l);if(f.position.set(0,a+r*.54,-o-u-d/2+e*.1),this.group.add(f),this.depth=o+u+d-e*.14,t.stand){const g=new zt(new gi(e*.34,e*.4,a,24),l);g.position.set(0,a/2,-o-u*.4),this.group.add(g)}const p=a+r/2+e*.07;this.screenLocal=new P(0,p,.02),this.portLocal=new P(e*.1,a+r*.25,-this.depth+e*.05),this.topLocal=new P(0,a+r,-o-u*.45);const x=new zt(new Xe(e*1.05,n*1.05),__);x.position.set(0,p,.002),this.group.add(x),this.texture=new mi(t.screen),this.texture.colorSpace=we,this.texture.minFilter=Oe,this.texture.generateMipmaps=!1,this.crt=g_(this.texture,t.seed),this.glass=new zt(x_(e,n,e*.035),this.crt),this.glass.position.set(0,p,.004),this.group.add(this.glass);const m=new zt(new Xe(e*.4,e*.088),new Ae({map:y_(t.label),transparent:!0,roughness:.9}));if(m.position.set(-e*.18,a+e*.075,.003),m.rotation.z=t.seed%7*.012-.03,this.group.add(m),this.led=new zt(new ar(e*.014,8,6),new bn({color:1714714})),this.led.position.set(i/2-e*.12,a+e*.08,.004),this.group.add(this.led),t.style==="tv"||t.style==="grey"){const g=new Ae({color:2763310,roughness:.4});for(let b=0;b<2;b++){const E=new zt(new gi(e*.028,e*.028,e*.03,16),g);E.rotation.x=Math.PI/2,E.position.set(i/2-e*.24-b*e*.09,a+e*.08,.012),this.group.add(E)}}this.hit=new zt(new nn(i,r,this.depth),new bn({visible:!1})),this.hit.position.set(0,a+r/2,-this.depth/2),this.group.add(this.hit)}setLed(t,e){this.led.material.color.set(t?e:"#1a2a1a")}world(t){return this.group.updateMatrixWorld(!0),t.clone().applyMatrix4(this.group.matrixWorld)}normal(){const t=new Pn;return this.group.getWorldQuaternion(t),new P(0,0,1).applyQuaternion(t)}}const Mo={name:"CopyShader",uniforms:{tDiffuse:{value:null},opacity:{value:1}},vertexShader:` varying vec2 vUv; @@ -4255,7 +4255,7 @@ void main() { gl_FragColor = opacity * texel; - }`};class _s{constructor(){this.isPass=!0,this.enabled=!0,this.needsSwap=!0,this.clear=!1,this.renderToScreen=!1}setSize(){}render(){console.error("THREE.Pass: .render() must be implemented in derived pass.")}dispose(){}}const ax=new Xr(-1,1,1,-1,0,1);class ox extends Be{constructor(){super(),this.setAttribute("position",new ve([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new ve([0,2,0,0,2,0],2))}}const lx=new ox;class Ml{constructor(t){this._mesh=new Bt(lx,t)}dispose(){this._mesh.geometry.dispose()}render(t){t.render(this._mesh,ax)}get material(){return this._mesh.material}set material(t){this._mesh.material=t}}class Zh extends _s{constructor(t,e="tDiffuse"){super(),this.textureID=e,this.uniforms=null,this.material=null,t instanceof Ce?(this.uniforms=t.uniforms,this.material=t):t&&(this.uniforms=$s.clone(t.uniforms),this.material=new Ce({name:t.name!==void 0?t.name:"unspecified",defines:Object.assign({},t.defines),uniforms:this.uniforms,vertexShader:t.vertexShader,fragmentShader:t.fragmentShader})),this._fsQuad=new Ml(this.material)}render(t,e,n){this.uniforms[this.textureID]&&(this.uniforms[this.textureID].value=n.texture),this._fsQuad.material=this.material,this.renderToScreen?(t.setRenderTarget(null),this._fsQuad.render(t)):(t.setRenderTarget(e),this.clear&&t.clear(t.autoClearColor,t.autoClearDepth,t.autoClearStencil),this._fsQuad.render(t))}dispose(){this.material.dispose(),this._fsQuad.dispose()}}class Jh extends _s{constructor(t,e){super(),this.scene=t,this.camera=e,this.clear=!0,this.needsSwap=!1,this.inverse=!1}render(t,e,n){const i=t.getContext(),r=t.state;r.buffers.color.setMask(!1),r.buffers.depth.setMask(!1),r.buffers.color.setLocked(!0),r.buffers.depth.setLocked(!0);let a,o;this.inverse?(a=0,o=1):(a=1,o=0),r.buffers.stencil.setTest(!0),r.buffers.stencil.setOp(i.REPLACE,i.REPLACE,i.REPLACE),r.buffers.stencil.setFunc(i.ALWAYS,a,4294967295),r.buffers.stencil.setClear(o),r.buffers.stencil.setLocked(!0),t.setRenderTarget(n),this.clear&&t.clear(),t.render(this.scene,this.camera),t.setRenderTarget(e),this.clear&&t.clear(),t.render(this.scene,this.camera),r.buffers.color.setLocked(!1),r.buffers.depth.setLocked(!1),r.buffers.color.setMask(!0),r.buffers.depth.setMask(!0),r.buffers.stencil.setLocked(!1),r.buffers.stencil.setFunc(i.EQUAL,1,4294967295),r.buffers.stencil.setOp(i.KEEP,i.KEEP,i.KEEP),r.buffers.stencil.setLocked(!0)}}class cx extends _s{constructor(){super(),this.needsSwap=!1}render(t){t.state.buffers.stencil.setLocked(!1),t.state.buffers.stencil.setTest(!1)}}class hx{constructor(t,e){if(this.renderer=t,this._pixelRatio=t.getPixelRatio(),e===void 0){const n=t.getSize(new ht);this._width=n.width,this._height=n.height,e=new Xe(this._width*this._pixelRatio,this._height*this._pixelRatio,{type:Je}),e.texture.name="EffectComposer.rt1"}else this._width=e.width,this._height=e.height;this.renderTarget1=e,this.renderTarget2=e.clone(),this.renderTarget2.texture.name="EffectComposer.rt2",this.writeBuffer=this.renderTarget1,this.readBuffer=this.renderTarget2,this.renderToScreen=!0,this.passes=[],this.copyPass=new Zh(jr),this.copyPass.material.blending=wn,this.timer=new pp}swapBuffers(){const t=this.readBuffer;this.readBuffer=this.writeBuffer,this.writeBuffer=t}addPass(t){this.passes.push(t),t.setSize(this._width*this._pixelRatio,this._height*this._pixelRatio)}insertPass(t,e){this.passes.splice(e,0,t),t.setSize(this._width*this._pixelRatio,this._height*this._pixelRatio)}removePass(t){const e=this.passes.indexOf(t);e!==-1&&this.passes.splice(e,1)}isLastEnabledPass(t){for(let e=t+1;e{n.fillStyle=h?i:r,n.fillText(c,u,24)};if(o("VHS",18,!0),o("HQ",62,!0),o("▶ PLAY",100,a),o("REC",180,!1),o("CH",226,a),o("PM",470,!a),this.marquee&&t-this.marqueeAt<2+this.marquee.length*.22){const c=512-(t-this.marqueeAt)*150;n.fillStyle=i,n.font='bold 50px ui-monospace, "Courier New", monospace',n.fillText(this.marquee.toUpperCase(),c,92)}else if(a)this.digits(String(this.channel).padStart(2,"0"),228,36,i,r),n.fillStyle=i,n.font="bold 40px ui-monospace, monospace",n.fillText("▶",360,88);else{const c=Math.floor(t*1.4)%2===0;this.digits("1200",150,36,c?i:r,r,!0,c)}n.shadowBlur=0,this.texture.needsUpdate=!0}digits(t,e,n,i,r,a=!1,o=!0){const l=this.ctx,c=34,u=60;if([...t].forEach((h,d)=>{const f=e+d*(c+16)+(a&&d>=2?22:0),p=gx[h]??"",v=(m,g,w,E,M)=>{l.strokeStyle=p.includes(m)?i:r,l.lineWidth=7,l.beginPath(),l.moveTo(f+g,n+w),l.lineTo(f+E,n+M),l.stroke()};v("a",5,0,c-5,0),v("b",c,5,c,u/2-5),v("c",c,u/2+5,c,u-5),v("d",5,u,c-5,u),v("e",0,u/2+5,0,u-5),v("f",0,5,0,u/2-5),v("g",5,u/2,c-5,u/2)}),a){l.fillStyle=o?i:r;const h=e+2*(c+16)+2;l.fillRect(h,n+16,7,7),l.fillRect(h,n+40,7,7)}}}function Qh(s){const t=document.createElement("canvas");t.width=512,t.height=160;const e=t.getContext("2d");if(e){e.fillStyle="#f1ede2",e.fillRect(0,0,512,160),e.fillStyle="#c0392b",e.fillRect(0,0,512,16),e.fillStyle="#9aa1b0";for(let o=40;o<160;o+=30)e.fillRect(16,o+20,480,1)}const n=new li(t),i=`54px ${oa}`,r='18px "Libertinus Mono", monospace';let a=null;return la([i,r],()=>{e&&(a?e.putImageData(a,0,0):a=e.getImageData(0,0,512,160),e.font=r,e.fillStyle="#6b6f7a",e.textAlign="right",e.textBaseline="alphabetic",e.fillText("T-120 SP",496,142),e.fillStyle="#15151a",e.font=i,e.textAlign="left",e.textBaseline="middle",e.fillText(s,26,94,470))},()=>n.needsUpdate=!0),n.colorSpace=Se,n.anisotropy=4,n}const yl=1.3,Ui=.27,ea=.95,ln=.66;class xx{constructor(){I(this,"group",new pn);I(this,"hit");I(this,"vfd",new _x);I(this,"rearZ");I(this,"rearY");I(this,"flap");I(this,"tape");I(this,"tapeLabel");I(this,"restPose",{pos:new C,rotY:0});I(this,"slotPose",{pos:new C,rotY:0});I(this,"insidePose",{pos:new C,rotY:0});I(this,"state","rest");I(this,"anim",null);I(this,"queue",[]);I(this,"currentLabel","~");const t=new Ee({color:723725,roughness:.7,metalness:.1}),e=new Bt(new Dn(1.9,ln,1.6,2,.02),t);e.position.set(0,ln/2,.15),this.group.add(e);const n=new Bt(new tn(1.92,.006,1.62),new xn({color:11735583}));n.position.set(0,ln-.03,.15),this.group.add(n);const i=new pn;i.position.set(0,ln+Ui/2+.012,-.12),this.group.add(i);const r=new Ee({color:2500396,roughness:.42,metalness:.12});i.add(new Bt(new Dn(yl,Ui,ea,3,.018),r));const a=new Ee({color:6974837,roughness:.34,metalness:.2}),o=new Bt(new tn(yl-.04,.004,ea-.04),a);o.position.y=Ui/2+.001,i.add(o);for(const[x,T]of[[-.55,.38],[.55,.38],[-.55,-.38],[.55,-.38]]){const P=new Bt(new ci(.035,.04,.012,12),t);P.position.set(x,-Ui/2-.006,T),i.add(P)}const l=ea/2+.001,c=new Bt(new We(yl-.03,Ui-.03),new Ee({map:this.panelTexture(),roughness:.5,metalness:.08}));c.position.z=l,i.add(c);const u=.58,h=.095,d=-.21,f=.035,p=new Bt(new We(u,h),new xn({color:65793}));p.position.set(d,f,l+.001),i.add(p);const v=new pn;v.position.set(d,f+h/2,l+.004),i.add(v),this.flap=new Bt(new tn(u-.01,h-.006,.006),new Ee({color:1710879,roughness:.35,metalness:.1})),this.flap.position.y=-h/2,v.add(this.flap);const m=new Bt(new We(.4,.0875),new xn({map:this.vfd.texture,toneMapped:!1}));m.position.set(.36,.045,l+.002),i.add(m);const g=new Ee({color:3816258,roughness:.4,metalness:.1}),w=new Ee({color:9049376,roughness:.4});for(let x=0;x<6;x++){const T=new Bt(new Dn(.058,.024,.02,2,.006),x===5?w:g);T.position.set(.19+x*.075,-.075,l+.006),i.add(T)}const E=new Bt(new ci(.022,.022,.02,20),g);E.rotation.x=Math.PI/2,E.position.set(-.57,.04,l+.008),i.add(E);const M=new Bt(new Ws(.006,8,6),new xn({color:16724016}));M.position.set(-.57,-.01,l+.004),i.add(M),this.rearZ=i.position.z-ea/2,this.rearY=i.position.y,this.tape=new pn;const S=new Bt(new Dn(.54,.07,.3,2,.01),new Ee({color:789518,roughness:.45,metalness:.2}));this.tape.add(S);const b=new Bt(new We(.2,.06),new Ee({color:2761504,roughness:.1,metalness:.3}));b.rotation.x=-Math.PI/2,b.position.set(0,.0355,-.05),this.tape.add(b),this.tapeLabel=new Ee({map:Qh("~"),roughness:.8});const R=new Bt(new We(.46,.1),this.tapeLabel);R.rotation.x=-Math.PI/2,R.position.set(0,.036,.085),this.tape.add(R),this.group.add(this.tape),this.restPose={pos:new C(-.38,ln+.036,.66),rotY:.32},this.slotPose={pos:new C(d,i.position.y+f,i.position.z+l+.34),rotY:0},this.insidePose={pos:new C(d,i.position.y+f,i.position.z+l-.36),rotY:0},this.applyPose(this.restPose,this.restPose,0),this.hit=new Bt(new tn(1.9,ln+Ui+.1,1.6),new xn({visible:!1})),this.hit.position.set(0,(ln+Ui+.1)/2,.15),this.group.add(this.hit)}panelTexture(){const t=document.createElement("canvas");t.width=1024,t.height=200;const e=t.getContext("2d");if(e){const a=e.createLinearGradient(0,0,0,200);a.addColorStop(0,"#1f2024"),a.addColorStop(1,"#131417"),e.fillStyle=a,e.fillRect(0,0,1024,200),e.fillStyle="#3a3c43";for(let l=0;l<1024;l+=3)e.fillRect(l,0,1,200);e.globalAlpha=.9,e.font="13px ui-monospace, monospace",e.fillStyle="#8b8f99",e.fillText("VIDEO CASSETTE RECORDER · 4 HEAD HI-FI · HQ",150,172),e.fillText("POWER",16,26),["EJECT","REW","PLAY","FF","STOP","REC"].forEach((l,c)=>e.fillText(l,632+c*58.5,184))}const n=new li(t),i='30px "Libertinus Mono", monospace';let r=null;return la(i,()=>{e&&(r?e.putImageData(r,0,0):r=e.getImageData(0,0,1024,200),e.globalAlpha=.9,e.fillStyle="#c9ccd4",e.font=i,e.textAlign="left",e.textBaseline="alphabetic",e.fillText("æthera",26,176),e.globalAlpha=1)},()=>n.needsUpdate=!0),n.colorSpace=Se,n.anisotropy=4,n}applyPose(t,e,n){this.tape.position.lerpVectors(t.pos,e.pos,n),this.tape.rotation.y=t.rotY+(e.rotY-t.rotY)*n}load(t){var e;this.queue=[],(this.state==="in"||((e=this.anim)==null?void 0:e.to)==="in")&&this.queue.push({to:"rest",label:this.currentLabel}),t&&this.queue.push({to:"in",label:t})}update(t){var a;if(!this.anim&&this.queue.length){const o=this.queue.shift();if(o&&o.to!==this.state){if(o.to==="in"){this.currentLabel=o.label;const l=this.tapeLabel.map;this.tapeLabel.map=Qh(o.label),this.tapeLabel.needsUpdate=!0,l==null||l.dispose()}this.anim={from:this.state,to:o.to,k:0,label:o.label}}}const e=this.anim;if(!e)return;e.k=Math.min(1,e.k+t/(e.to==="in"?1.3:.9));const n=e.to==="in"?e.k:1-e.k,i=o=>o*o*(3-2*o);if(n<.45){const o=i(n/.45);this.applyPose(this.restPose,this.slotPose,o),this.tape.position.y+=Math.sin(o*Math.PI)*.18}else this.applyPose(this.slotPose,this.insidePose,i(Math.min(1,(n-.5)/.4))*(n>.5?1:0));const r=n<.4?0:n<.5?(n-.4)/.1:n<.85?1:1-(n-.85)/.15;(a=this.flap.parent)==null||a.rotation.set(r*1.25,0,0),e.k>=1&&(this.state=e.to,this.anim=null)}}const vx={color:723724,roughness:.55,metalness:0};class Mx{constructor(t,e,n){I(this,"mesh");I(this,"uniforms",{uPulseColor:{value:new kt},uPulseTime:{value:0},uPulseGain:{value:.35},uPulseCount:{value:3},uPulseSpeed:{value:.35}});I(this,"base",.35);I(this,"surgeLeft",0);I(this,"lit",0);const i=new jc(t,!1,"centripetal",.5),r=i.getLength(),a=new sl(i,Math.max(40,Math.round(r*18)),e,6,!1),o=a.attributes.uv,l=new Float32Array(o.count);for(let u=0;u{Object.assign(u.uniforms,this.uniforms),u.vertexShader=u.vertexShader.replace("#include ",`#include + }`};class L_{constructor(t,e,n){R(this,"composer");R(this,"bloom");R(this,"wired");R(this,"tear",0);this.composer=new T_(t),this.composer.addPass(new C_(e,n)),this.bloom=new Is(new pt(256,256),.7,.5,.78),this.composer.addPass(this.bloom),this.wired=new zu(P_),this.composer.addPass(this.wired),this.composer.addPass(new A_)}get u(){return this.wired.uniforms}setSize(t,e,n){this.composer.setPixelRatio(n),this.composer.setSize(t,e),this.u.uRes.value.set(t*n,e*n),this.u.uDot.value=Math.max(2.5,3*n)}kick(t=1){this.tear=Math.max(this.tear,t)}setHalftone(t){this.u.uHalftone.value=t?1:0}render(t,e){this.tear=Math.max(0,this.tear-e*2.2),this.u.uTime.value=t,this.u.uTear.value=this.tear*this.tear,this.composer.render(e)}}const D_={0:"abcdef",1:"bc",2:"abged",3:"abgcd",4:"fgbc",5:"afgcd",6:"afgedc",7:"abc",8:"abcdefg",9:"abcfgd","-":"g"," ":""};class I_{constructor(){R(this,"canvas",document.createElement("canvas"));R(this,"texture");R(this,"ctx");R(this,"mode","clock");R(this,"channel",0);R(this,"marquee","");R(this,"marqueeAt",0);R(this,"acc",1);R(this,"glow",1);this.canvas.width=512,this.canvas.height=112;const t=this.canvas.getContext("2d");if(!t)throw new Error("oikos: no 2d context");this.ctx=t,this.texture=new mi(this.canvas),this.texture.colorSpace=we}scroll(t,e){this.marquee=t,this.marqueeAt=e}play(t,e,n){this.mode="play",this.channel=t,this.scroll(e,n)}stop(){this.mode="clock"}update(t,e){if(this.acc+=e,this.acc<1/12)return;this.acc=0;const n=this.ctx;n.fillStyle="#020807",n.fillRect(0,0,512,112);const i=`rgba(127,245,225,${.85*this.glow+.15})`,r="rgba(127,245,225,0.07)";n.shadowColor="#7ff5e1",n.shadowBlur=10*this.glow,n.lineCap="round";const o=this.mode==="play";n.font="bold 15px ui-monospace, monospace";const a=(c,u,h)=>{n.fillStyle=h?i:r,n.fillText(c,u,24)};if(a("VHS",18,!0),a("HQ",62,!0),a("▶ PLAY",100,o),a("REC",180,!1),a("CH",226,o),a("PM",470,!o),this.marquee&&t-this.marqueeAt<2+this.marquee.length*.22){const c=512-(t-this.marqueeAt)*150;n.fillStyle=i,n.font='bold 50px ui-monospace, "Courier New", monospace',n.fillText(this.marquee.toUpperCase(),c,92)}else if(o)this.digits(String(this.channel).padStart(2,"0"),228,36,i,r),n.fillStyle=i,n.font="bold 40px ui-monospace, monospace",n.fillText("▶",360,88);else{const c=Math.floor(t*1.4)%2===0;this.digits("1200",150,36,c?i:r,r,!0,c)}n.shadowBlur=0,this.texture.needsUpdate=!0}digits(t,e,n,i,r,o=!1,a=!0){const l=this.ctx,c=34,u=60;if([...t].forEach((h,d)=>{const f=e+d*(c+16)+(o&&d>=2?22:0),p=D_[h]??"",x=(m,g,b,E,y)=>{l.strokeStyle=p.includes(m)?i:r,l.lineWidth=7,l.beginPath(),l.moveTo(f+g,n+b),l.lineTo(f+E,n+y),l.stroke()};x("a",5,0,c-5,0),x("b",c,5,c,u/2-5),x("c",c,u/2+5,c,u-5),x("d",5,u,c-5,u),x("e",0,u/2+5,0,u-5),x("f",0,5,0,u/2-5),x("g",5,u/2,c-5,u/2)}),o){l.fillStyle=a?i:r;const h=e+2*(c+16)+2;l.fillRect(h,n+16,7,7),l.fillRect(h,n+40,7,7)}}}function Gu(s){const t=document.createElement("canvas");t.width=512,t.height=160;const e=t.getContext("2d");if(e){e.fillStyle="#f1ede2",e.fillRect(0,0,512,160),e.fillStyle="#c0392b",e.fillRect(0,0,512,16),e.fillStyle="#9aa1b0";for(let a=40;a<160;a+=30)e.fillRect(16,a+20,480,1)}const n=new mi(t),i=`54px ${Oo}`,r='18px "Libertinus Mono", monospace';let o=null;return ko([i,r],()=>{e&&(o?e.putImageData(o,0,0):o=e.getImageData(0,0,512,160),e.font=r,e.fillStyle="#6b6f7a",e.textAlign="right",e.textBaseline="alphabetic",e.fillText("T-120 SP",496,142),e.fillStyle="#15151a",e.font=i,e.textAlign="left",e.textBaseline="middle",e.fillText(s,26,94,470))},()=>n.needsUpdate=!0),n.colorSpace=we,n.anisotropy=4,n}const Zl=1.3,Vi=.27,So=.95,un=.66;class N_{constructor(){R(this,"group",new vn);R(this,"hit");R(this,"vfd",new I_);R(this,"rearZ");R(this,"rearY");R(this,"flap");R(this,"tape");R(this,"tapeLabel");R(this,"restPose",{pos:new P,rotY:0});R(this,"slotPose",{pos:new P,rotY:0});R(this,"insidePose",{pos:new P,rotY:0});R(this,"state","rest");R(this,"anim",null);R(this,"queue",[]);R(this,"currentLabel","~");const t=new Ae({color:723725,roughness:.7,metalness:.1}),e=new zt(new Nn(1.9,un,1.6,2,.02),t);e.position.set(0,un/2,.15),this.group.add(e);const n=new zt(new nn(1.92,.006,1.62),new bn({color:11735583}));n.position.set(0,un-.03,.15),this.group.add(n);const i=new vn;i.position.set(0,un+Vi/2+.012,-.12),this.group.add(i);const r=new Ae({color:2500396,roughness:.42,metalness:.12});i.add(new zt(new Nn(Zl,Vi,So,3,.018),r));const o=new Ae({color:6974837,roughness:.34,metalness:.2}),a=new zt(new nn(Zl-.04,.004,So-.04),o);a.position.y=Vi/2+.001,i.add(a);for(const[v,T]of[[-.55,.38],[.55,.38],[-.55,-.38],[.55,-.38]]){const L=new zt(new gi(.035,.04,.012,12),t);L.position.set(v,-Vi/2-.006,T),i.add(L)}const l=So/2+.001,c=new zt(new Xe(Zl-.03,Vi-.03),new Ae({map:this.panelTexture(),roughness:.5,metalness:.08}));c.position.z=l,i.add(c);const u=.58,h=.095,d=-.21,f=.035,p=new zt(new Xe(u,h),new bn({color:65793}));p.position.set(d,f,l+.001),i.add(p);const x=new vn;x.position.set(d,f+h/2,l+.004),i.add(x),this.flap=new zt(new nn(u-.01,h-.006,.006),new Ae({color:1710879,roughness:.35,metalness:.1})),this.flap.position.y=-h/2,x.add(this.flap);const m=new zt(new Xe(.4,.0875),new bn({map:this.vfd.texture,toneMapped:!1}));m.position.set(.36,.045,l+.002),i.add(m);const g=new Ae({color:3816258,roughness:.4,metalness:.1}),b=new Ae({color:9049376,roughness:.4});for(let v=0;v<6;v++){const T=new zt(new Nn(.058,.024,.02,2,.006),v===5?b:g);T.position.set(.19+v*.075,-.075,l+.006),i.add(T)}const E=new zt(new gi(.022,.022,.02,20),g);E.rotation.x=Math.PI/2,E.position.set(-.57,.04,l+.008),i.add(E);const y=new zt(new ar(.006,8,6),new bn({color:16724016}));y.position.set(-.57,-.01,l+.004),i.add(y),this.rearZ=i.position.z-So/2,this.rearY=i.position.y,this.tape=new vn;const M=new zt(new Nn(.54,.07,.3,2,.01),new Ae({color:789518,roughness:.45,metalness:.2}));this.tape.add(M);const w=new zt(new Xe(.2,.06),new Ae({color:2761504,roughness:.1,metalness:.3}));w.rotation.x=-Math.PI/2,w.position.set(0,.0355,-.05),this.tape.add(w),this.tapeLabel=new Ae({map:Gu("~"),roughness:.8});const C=new zt(new Xe(.46,.1),this.tapeLabel);C.rotation.x=-Math.PI/2,C.position.set(0,.036,.085),this.tape.add(C),this.group.add(this.tape),this.restPose={pos:new P(-.38,un+.036,.66),rotY:.32},this.slotPose={pos:new P(d,i.position.y+f,i.position.z+l+.34),rotY:0},this.insidePose={pos:new P(d,i.position.y+f,i.position.z+l-.36),rotY:0},this.applyPose(this.restPose,this.restPose,0),this.hit=new zt(new nn(1.9,un+Vi+.1,1.6),new bn({visible:!1})),this.hit.position.set(0,(un+Vi+.1)/2,.15),this.group.add(this.hit)}panelTexture(){const t=document.createElement("canvas");t.width=1024,t.height=200;const e=t.getContext("2d");if(e){const o=e.createLinearGradient(0,0,0,200);o.addColorStop(0,"#1f2024"),o.addColorStop(1,"#131417"),e.fillStyle=o,e.fillRect(0,0,1024,200),e.fillStyle="#3a3c43";for(let l=0;l<1024;l+=3)e.fillRect(l,0,1,200);e.globalAlpha=.9,e.font="13px ui-monospace, monospace",e.fillStyle="#8b8f99",e.fillText("VIDEO CASSETTE RECORDER · 4 HEAD HI-FI · HQ",150,172),e.fillText("POWER",16,26),["EJECT","REW","PLAY","FF","STOP","REC"].forEach((l,c)=>e.fillText(l,632+c*58.5,184))}const n=new mi(t),i='30px "Libertinus Mono", monospace';let r=null;return ko(i,()=>{e&&(r?e.putImageData(r,0,0):r=e.getImageData(0,0,1024,200),e.globalAlpha=.9,e.fillStyle="#c9ccd4",e.font=i,e.textAlign="left",e.textBaseline="alphabetic",e.fillText("æthera",26,176),e.globalAlpha=1)},()=>n.needsUpdate=!0),n.colorSpace=we,n.anisotropy=4,n}applyPose(t,e,n){this.tape.position.lerpVectors(t.pos,e.pos,n),this.tape.rotation.y=t.rotY+(e.rotY-t.rotY)*n}load(t){var e;this.queue=[],(this.state==="in"||((e=this.anim)==null?void 0:e.to)==="in")&&this.queue.push({to:"rest",label:this.currentLabel}),t&&this.queue.push({to:"in",label:t})}update(t){var o;if(!this.anim&&this.queue.length){const a=this.queue.shift();if(a&&a.to!==this.state){if(a.to==="in"){this.currentLabel=a.label;const l=this.tapeLabel.map;this.tapeLabel.map=Gu(a.label),this.tapeLabel.needsUpdate=!0,l==null||l.dispose()}this.anim={from:this.state,to:a.to,k:0,label:a.label}}}const e=this.anim;if(!e)return;e.k=Math.min(1,e.k+t/(e.to==="in"?1.3:.9));const n=e.to==="in"?e.k:1-e.k,i=a=>a*a*(3-2*a);if(n<.45){const a=i(n/.45);this.applyPose(this.restPose,this.slotPose,a),this.tape.position.y+=Math.sin(a*Math.PI)*.18}else this.applyPose(this.slotPose,this.insidePose,i(Math.min(1,(n-.5)/.4))*(n>.5?1:0));const r=n<.4?0:n<.5?(n-.4)/.1:n<.85?1:1-(n-.85)/.15;(o=this.flap.parent)==null||o.rotation.set(r*1.25,0,0),e.k>=1&&(this.state=e.to,this.anim=null)}}const U_={color:723724,roughness:.55,metalness:0};class F_{constructor(t,e,n){R(this,"mesh");R(this,"uniforms",{uPulseColor:{value:new Bt},uPulseTime:{value:0},uPulseGain:{value:.35},uPulseCount:{value:3},uPulseSpeed:{value:.35}});R(this,"base",.35);R(this,"surgeLeft",0);R(this,"lit",0);const i=new Vh(t,!1,"centripetal",.5),r=i.getLength(),o=new Il(i,Math.max(40,Math.round(r*18)),e,6,!1),a=o.attributes.uv,l=new Float32Array(a.count);for(let u=0;u{Object.assign(u.uniforms,this.uniforms),u.vertexShader=u.vertexShader.replace("#include ",`#include attribute float aAlong; varying float vAlong;`).replace("#include ",`#include vAlong = aAlong;`),u.fragmentShader=u.fragmentShader.replace("#include ",`#include @@ -4486,7 +4486,7 @@ uniform float uPulseTime, uPulseGain, uPulseCount, uPulseSpeed; varying float vAlong;`).replace("#include ",`#include float ph = fract(vAlong * uPulseCount + uPulseTime * uPulseSpeed); float pulse = smoothstep(0.0, 0.03, ph) * (1.0 - smoothstep(0.03, 0.14, ph)); -totalEmissiveRadiance += uPulseColor * (pulse * uPulseGain + 0.012 * uPulseGain);`)},c.customProgramCacheKey=()=>"oikos-cable",this.mesh=new Bt(a,c)}setLit(t){this.lit=t}surge(){this.surgeLeft=2.2}update(t,e){this.surgeLeft=Math.max(0,this.surgeLeft-e);const n=this.surgeLeft>0?Math.sin(this.surgeLeft/2.2*Math.PI)*5:0,i=this.base+this.lit*1.2+n;this.uniforms.uPulseGain.value+=(i-this.uniforms.uPulseGain.value)*Math.min(1,e*6),this.uniforms.uPulseTime.value=t*(1+this.lit*1.5+n*.8)}}function yx(s,t,e,n,i,r){const o=[s.clone()],l=s.clone().addScaledVector(t,.18);o.push(l);const c=new C(l.x,.022,l.z).addScaledVector(t,.22);s.y>.3&&o.push(new C(l.x,(s.y+.022)*.4,l.z).addScaledVector(t,.2)),o.push(c);const u=new C(e.x,.022,n-.14),h=Math.sign(c.x||1);c.z>n-.1&&o.push(new C(h*1.15,.022,n-.25));const d=2;for(let f=1;f<=d;f++){const p=f/(d+1),v=new C().lerpVectors(c,u,p),m=new C(u.z-c.z,0,c.x-u.x).normalize();v.addScaledVector(m,(r()-.5)*.9),v.y=.022,o.push(v)}return o.push(u),o.push(new C(e.x,i-.04,n-.035)),o.push(new C(e.x,i+.03,n+.01)),o.push(e.clone()),o}function jh(s,t,e,n=32){const i=[];for(let r=0;r<=n;r++){const a=r/n,o=new C().lerpVectors(s,t,a);o.y-=e*4*a*(1-a),i.push(o)}return i}function Sx(){var o,l,c;const s=new pn,t=new Ee({color:854795,roughness:.9}),e=new Wc({color:328708}),n=[new C(-26,0,-18),new C(-9,0,-24),new C(8,0,-23),new C(24,0,-15),new C(33,0,2)],i=12.5,r=[];n.forEach((u,h)=>{const d=new Bt(new ci(.12,.17,i,8),t);d.position.set(u.x,i/2,u.z),s.add(d);const f=n[h+1]??n[h-1]??u,p=new C().subVectors(f,u).setY(0).normalize(),v=new C(-p.z,0,p.x),m=[];for(const[g,w]of[[i-.4,1.9],[i-1.5,1.4]]){const E=new Bt(new tn(w*2,.12,.12),t);E.position.set(u.x,g,u.z),E.rotation.y=Math.atan2(-v.z,v.x),s.add(E);for(const M of[-1,-.45,.45,1])m.push(new C(u.x,g+.08,u.z).addScaledVector(v,M*w*.95))}r.push(m)});for(let u=0;u{const v=d[p];if(!v)return;const m=new Be().setFromPoints(jh(f,v,1.4+p%3*.25));s.add(new qc(m,e))})}const a=[[(o=r[1])==null?void 0:o[0],new C(-2.4,9,-6.6)],[(l=r[2])==null?void 0:l[3],new C(2.2,9,-6.1)],[(c=r[3])==null?void 0:c[1],new C(6,8.5,-3)]];for(const[u,h]of a)u&&s.add(new qc(new Be().setFromPoints(jh(u,h,2.2)),e));return s}function bx(){const s=new Ce({side:Ge,depthWrite:!1,fog:!1,uniforms:{uTime:{value:0}},vertexShader:` +totalEmissiveRadiance += uPulseColor * (pulse * uPulseGain + 0.012 * uPulseGain);`)},c.customProgramCacheKey=()=>"oikos-cable",this.mesh=new zt(o,c)}setLit(t){this.lit=t}surge(){this.surgeLeft=2.2}update(t,e){this.surgeLeft=Math.max(0,this.surgeLeft-e);const n=this.surgeLeft>0?Math.sin(this.surgeLeft/2.2*Math.PI)*5:0,i=this.base+this.lit*1.2+n;this.uniforms.uPulseGain.value+=(i-this.uniforms.uPulseGain.value)*Math.min(1,e*6),this.uniforms.uPulseTime.value=t*(1+this.lit*1.5+n*.8)}}function O_(s,t,e,n,i,r){const a=[s.clone()],l=s.clone().addScaledVector(t,.18);a.push(l);const c=new P(l.x,.022,l.z).addScaledVector(t,.22);s.y>.3&&a.push(new P(l.x,(s.y+.022)*.4,l.z).addScaledVector(t,.2)),a.push(c);const u=new P(e.x,.022,n-.14),h=Math.sign(c.x||1);c.z>n-.1&&a.push(new P(h*1.15,.022,n-.25));const d=2;for(let f=1;f<=d;f++){const p=f/(d+1),x=new P().lerpVectors(c,u,p),m=new P(u.z-c.z,0,c.x-u.x).normalize();x.addScaledVector(m,(r()-.5)*.9),x.y=.022,a.push(x)}return a.push(u),a.push(new P(e.x,i-.04,n-.035)),a.push(new P(e.x,i+.03,n+.01)),a.push(e.clone()),a}function Vu(s,t,e,n=32){const i=[];for(let r=0;r<=n;r++){const o=r/n,a=new P().lerpVectors(s,t,o);a.y-=e*4*o*(1-o),i.push(a)}return i}function k_(){var a,l,c;const s=new vn,t=new Ae({color:854795,roughness:.9}),e=new Nh({color:328708}),n=[new P(-26,0,-18),new P(-9,0,-24),new P(8,0,-23),new P(24,0,-15),new P(33,0,2)],i=12.5,r=[];n.forEach((u,h)=>{const d=new zt(new gi(.12,.17,i,8),t);d.position.set(u.x,i/2,u.z),s.add(d);const f=n[h+1]??n[h-1]??u,p=new P().subVectors(f,u).setY(0).normalize(),x=new P(-p.z,0,p.x),m=[];for(const[g,b]of[[i-.4,1.9],[i-1.5,1.4]]){const E=new zt(new nn(b*2,.12,.12),t);E.position.set(u.x,g,u.z),E.rotation.y=Math.atan2(-x.z,x.x),s.add(E);for(const y of[-1,-.45,.45,1])m.push(new P(u.x,g+.08,u.z).addScaledVector(x,y*b*.95))}r.push(m)});for(let u=0;u{const x=d[p];if(!x)return;const m=new He().setFromPoints(Vu(f,x,1.4+p%3*.25));s.add(new Oh(m,e))})}const o=[[(a=r[1])==null?void 0:a[0],new P(-2.4,9,-6.6)],[(l=r[2])==null?void 0:l[3],new P(2.2,9,-6.1)],[(c=r[3])==null?void 0:c[1],new P(6,8.5,-3)]];for(const[u,h]of o)u&&s.add(new Oh(new He().setFromPoints(Vu(u,h,2.2)),e));return s}function B_(){const s=new Pe({side:We,depthWrite:!1,fog:!1,uniforms:{uTime:{value:0}},vertexShader:` varying vec3 vDir; void main() { vDir = normalize(position); @@ -4506,71 +4506,71 @@ totalEmissiveRadiance += uPulseColor * (pulse * uPulseGain + 0.012 * uPulseGain) if (h < 0.0) col = ember + vec3(0.004, 0.0008, 0.0014); gl_FragColor = vec4(col, 1.0); #include - }`}),t=new Bt(new Ws(70,32,16),s);return t.renderOrder=-1,t}const wx=s=>s<.5?4*s*s*s:1-Math.pow(-2*s+2,3)/2;function Ex(){const s=document.createElement("canvas");s.width=s.height=128;const t=s.getContext("2d");if(t){const e=t.createRadialGradient(64,64,0,64,64,64);e.addColorStop(0,"rgba(255,255,255,0.9)"),e.addColorStop(.4,"rgba(255,255,255,0.3)"),e.addColorStop(1,"rgba(255,255,255,0)"),t.fillStyle=e,t.fillRect(0,0,128,128)}return new li(s)}class Tx{constructor(t,e,n,i){I(this,"renderer");I(this,"scene",new Rf);I(this,"camera",new qe(45,1,.05,160));I(this,"controls");I(this,"post");I(this,"vcr",new xx);I(this,"field");I(this,"sky");I(this,"stations",new Map);I(this,"pickables",[]);I(this,"raycaster",new gp);I(this,"pointer",new ht(-9,-9));I(this,"pointerPx",{x:0,y:0});I(this,"pointerDirty",!1);I(this,"hovered",null);I(this,"focused",null);I(this,"tween",null);I(this,"playing",null);I(this,"settlePlay",null);I(this,"tuneSeq",0);I(this,"lastAspect",0);I(this,"later",[]);I(this,"clock",new _p);I(this,"t",0);I(this,"running",!1);I(this,"raf",0);I(this,"lastInput",0);I(this,"swayDir",1);I(this,"pixelRatio");I(this,"maxPixelRatio");I(this,"frameTimes",[]);I(this,"qualityStep",0);I(this,"shift",{x:0,y:0});I(this,"tuned",null);I(this,"shiftTarget",{x:0,y:0});I(this,"reduced");I(this,"lowPower");I(this,"speed",Math.min(10,Math.max(1,Number(new URLSearchParams(location.search).get("speed"))||1)));I(this,"driven",new URLSearchParams(location.search).has("drive"));I(this,"perf",{frames:0,paint:0,render:0,uploads:0});I(this,"frustum",new kr);I(this,"viewProj",new se);I(this,"kept",null);I(this,"calm",0);this.container=t,this.events=i,this.reduced=matchMedia("(prefers-reduced-motion: reduce)").matches,this.lowPower=matchMedia("(pointer: coarse)").matches||Math.min(innerWidth,innerHeight)<600,this.maxPixelRatio=Math.min(devicePixelRatio||1,this.lowPower?1.25:1.6),this.pixelRatio=this.maxPixelRatio,this.renderer=new N_({antialias:!1,powerPreference:"high-performance"}),this.renderer.setPixelRatio(this.pixelRatio),this.renderer.toneMapping=ar,this.renderer.toneMappingExposure=1.1,this.renderer.outputColorSpace=Se,this.renderer.domElement.id="oikos-gl",t.prepend(this.renderer.domElement);try{this.build(e,n)}catch(r){throw this.renderer.domElement.remove(),this.renderer.dispose(),this.renderer.forceContextLoss(),r}}build(t,e){this.scene.background=new kt(0),this.scene.fog=new Oo(new kt().setRGB(.049,.0063,.0089,Ps),.042),this.sky=bx(),this.scene.add(this.sky),this.scene.add(new ap(4866648,393988,.8));const n=new up(9082040,.35);n.position.set(-4,10,-6),this.scene.add(n);const i=new lp(14212351,9,7,.42,.65,1.6);i.position.set(.4,4.6,1.2),i.target.position.set(0,ln,.1),this.scene.add(i,i.target);const r=new ol(10466303,2.2,4.5,2);r.position.set(-.4,1.35,2.3),this.scene.add(r);const a=new ol(11735583,1.6,4,2);a.position.set(0,.25,1.4),this.scene.add(a),this.buildFloor(),this.scene.add(this.vcr.group),this.pickables.push(this.vcr.hit),this.vcr.hit.userData.pick="vcr",this.scene.add(Sx());const o=vi(1998);this.field=new J_(this.lowPower?40:90,o,this.scene.fog),this.scene.add(this.field.group),this.buildStations(t,e,o),this.controls=new F_(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.dampingFactor=.07,this.controls.enablePan=!1,this.controls.rotateSpeed=.28,this.controls.zoomSpeed=.6,this.controls.addEventListener("start",()=>this.lastInput=this.t),this.post=new mx(this.renderer,this.scene,this.camera),this.resize();const l=this.homePose();this.camera.position.copy(l.pos),this.controls.target.copy(l.target),this.applyLimits(null),this.controls.update(),this.bindPointer(),addEventListener("resize",()=>this.resize())}buildFloor(){const t=document.createElement("canvas");t.width=t.height=512;const e=t.getContext("2d");if(e){e.fillStyle="#0c0b0d",e.fillRect(0,0,512,512),e.strokeStyle="rgba(120,110,130,0.10)",e.lineWidth=2;for(let r=0;r<=512;r+=128)e.beginPath(),e.moveTo(r,0),e.lineTo(r,512),e.moveTo(0,r),e.lineTo(512,r),e.stroke();for(let r=0;r<900;r++)e.fillStyle=`rgba(${Math.random()<.3?"120,20,30":"90,90,100"},${Math.random()*.12})`,e.fillRect(Math.random()*512,Math.random()*512,2,2)}const n=new li(t);n.wrapS=n.wrapT=lr,n.repeat.set(24,24),n.colorSpace=Se,n.anisotropy=8;const i=new Bt(new We(96,96),new Ee({map:n,roughness:.82,metalness:.15}));i.rotation.x=-Math.PI/2,this.scene.add(i)}buildStations(t,e,n){const i=new Ee({color:1315086,roughness:.85}),r=new Ee({color:657930,roughness:.6}),a=Ex(),o=new C,l=new Map,c=t.map((h,d)=>({site:h,i:d,p:gd(h.id,d)}));c.sort((h,d)=>+!!h.p.on-+!!d.p.on);let u=0;for(const{site:h,p:d}of c){const f=e.get(h.id);if(!f)continue;const p=new rx({style:d.style,screenW:d.screenW,screen:f.canvas,label:h.title,accent:h.accent,seed:Math.floor(n()*1e3),stand:d.stand}),v=xr.degToRad(d.angle),m=d.on?l.get(d.on):void 0;if(m)p.group.position.copy(m.group.position),p.group.position.y+=m.height,p.group.rotation.copy(m.group.rotation),p.group.rotateY((n()-.5)*.12),p.group.translateZ(-(m.depth-p.depth)*.3);else{p.group.position.set(Math.sin(v)*d.r,d.y,-Math.cos(v)*d.r);const L=new C(0,d.hang?1.3:p.group.position.y+.6,.6);p.group.lookAt(L),d.hang||(p.group.rotation.set(0,Math.atan2(-p.group.position.x,.6-p.group.position.z),0),p.group.rotateY((n()-.5)*.1))}if(this.scene.add(p.group),l.set(h.id,p),!d.hang&&!d.on&&d.y>.01){const L=new Bt(new tn(p.width*.92,d.y,p.depth*.9),i);L.position.set(0,-d.y/2,-p.depth*.45),p.group.add(L)}if(d.hang){const L=p.world(p.topLocal),F=new Bt(new ci(.008,.008,16,5),r);F.position.set(L.x,L.y+8,L.z),this.scene.add(F)}const g=-.5+u++*.37%1;o.set(g,this.vcr.rearY-.05,this.vcr.rearZ-.01);const w=p.world(p.portLocal),E=p.normal().multiplyScalar(-1).setY(0).normalize();let M;const S=d.feeds?l.get(d.feeds):void 0;if(S){const L=S.world(S.portLocal.clone().add(new C(-.25,.15,0))),F=new C().lerpVectors(w,L,.5);F.y=Math.min(w.y,L.y)-.6,M=[w,w.clone().addScaledVector(E,.3).setY(w.y-.2),F,L.clone().add(new C(0,.3,-.3)),L]}else M=yx(w,E,o,.15-.8,ln,n);const b=new Mx(M,d.hang?.014:.02,h.accent);this.scene.add(b.mesh);const R=new Bt(new We(d.screenW*2.6,d.screenW*2.2),new xn({map:a,color:h.accent,transparent:!0,opacity:0,depthWrite:!1,blending:rr,fog:!0})),x=p.normal().setY(0).normalize(),T=p.world(p.screenLocal).addScaledVector(x,d.screenW*.9);R.position.set(T.x,.012,T.z),R.rotation.x=-Math.PI/2,R.rotation.z=Math.atan2(x.x,x.z),d.hang||this.scene.add(R);let P=null;this.lowPower||(P=new ol(h.accent,0,3.2+d.screenW,2),P.position.copy(p.world(p.screenLocal).addScaledVector(p.normal(),1.1)),this.scene.add(P)),p.hit.userData.pick=h.id,this.pickables.push(p.hit),this.stations.set(h.id,{site:h,screen:f,monitor:p,placement:d,cable:b,glow:R,light:P,power:0,powerAt:1/0,staticLeft:0,hover:0})}}homePose(){const t=this.camera.aspect,e=t<1,n=e?7.2+(1-t)*2.4:7.8;return{pos:new C(0,e?2.5:2.4,n),target:new C(0,e?1.7:1.95,-1.6)}}posesFor(t){if(t==="vcr"){const c=this.camera.aspect<1;return{pos:new C(.3,1.75,c?3.9:2.9),target:new C(0,ln+.12,.2)}}const e=this.stations.get(t);if(!e)return null;const n=e.monitor,i=n.world(n.screenLocal),r=n.normal(),a=xr.degToRad(this.camera.fov),o=2*Math.atan(Math.tan(a/2)*this.camera.aspect),l=Math.max(n.screenH/2/Math.tan(a/2)/.46,n.screenH/.75/2/Math.tan(o/2)/.7);return{pos:i.clone().addScaledVector(r,l+.05),target:i}}applyLimits(t){const e=this.controls;if(!t){e.minDistance=3,e.maxDistance=15,e.minAzimuthAngle=-.8,e.maxAzimuthAngle=.8,e.minPolarAngle=.95,e.maxPolarAngle=1.56;return}const n=new C().subVectors(this.camera.position,e.target),i=new cl().setFromVector3(n);e.minDistance=i.radius*.45,e.maxDistance=i.radius*1.7,e.minAzimuthAngle=i.theta-.6,e.maxAzimuthAngle=i.theta+.6,e.minPolarAngle=Math.max(.3,i.phi-.45),e.maxPolarAngle=Math.min(1.6,i.phi+.35)}flyTo(t,e,n){this.controls.enabled=!1,this.controls.minAzimuthAngle=-1/0,this.controls.maxAzimuthAngle=1/0,this.tween={from:{pos:this.camera.position.clone(),target:this.controls.target.clone()},to:t,k:0,dur:this.reduced?.01:e,done:n}}focus(t){const e=t?this.posesFor(t):this.homePose();if(e){this.cancelPlay(),this.focused=t;for(const[n,i]of this.stations)i.cable.setLit(n===t?1:0);this.flyTo(e,t?1.15:1.3,()=>{this.applyLimits(t),this.controls.enabled=!this.tuned,this.controls.update()})}}get focusedId(){return this.focused}keepAlive(t){this.kept=t}get busy(){return this.playing!==null}cancelPlay(){this.playing=null;const t=this.settlePlay;this.settlePlay=null,t==null||t(!1)}play(t){const e=this.stations.get(t),n=this.posesFor(t);if(!e||!n)return Promise.resolve(!0);this.cancelPlay();const i=new Promise(c=>this.settlePlay=c);this.vcr.load(e.site.title),this.vcr.vfd.play(e.placement.channel,e.site.title,this.t),this.focused=t,this.playing=t;for(const[c,u]of this.stations)u.cable.setLit(c===t?1:0);const r=()=>{this.playing===t&&(e.staticLeft=.9,this.post.kick(.7),this.flyTo(n,1.15,()=>{if(this.playing!==t)return;this.playing=null,this.applyLimits(t),this.controls.enabled=!this.tuned,this.controls.update();const c=this.settlePlay;this.settlePlay=null,c==null||c(!0)}))};if(this.reduced)return r(),i;const a=Math.sign(e.monitor.group.position.x)||1,o=this.camera.aspect<1,l={pos:new C(a*.45,1.4,o?3.1:2.25),target:new C(a*.05,ln+.1,.25)};return this.flyTo(l,.8,()=>{this.playing===t&&(e.cable.surge(),this.after(.35,r))}),i}after(t,e){this.later.push({at:this.t+t,fn:e})}eject(){this.vcr.load(null),this.vcr.vfd.stop()}scroll(t){this.vcr.vfd.scroll(t,this.t)}dive(t){const e=this.stations.get(t);if(!e||this.reduced)return Promise.resolve();this.cancelPlay();const n=e.monitor,i=n.world(n.screenLocal),r=i.clone().addScaledVector(n.normal(),n.screenH*.16);return e.staticLeft=.8,this.post.kick(1),new Promise(a=>this.flyTo({pos:r,target:i},.75,a))}powerOn(){let t=0;const e=[...this.stations.values()].sort((n,i)=>n.placement.channel-i.placement.channel);for(const n of e)n.powerAt=this.t+.25+t++*(this.reduced?0:.14);this.vcr.vfd.scroll("present day present time",this.t+.4)}anchor(t){let e;if(t==="vcr")e=new C(0,ln-.05,.95);else{const i=this.stations.get(t);if(!i)return null;e=i.monitor.world(i.monitor.screenLocal.clone().add(new C(0,i.monitor.screenH*.5,0)))}if(e.project(this.camera),e.z>1)return null;const n=this.renderer.domElement.getBoundingClientRect();return{x:n.left+(e.x+1)/2*n.width,y:n.top+(1-e.y)/2*n.height}}setShift(t,e){this.shiftTarget={x:t,y:e}}applyShift(t){this.tuned&&(this.shiftTarget={x:0,y:0});const e=this.reduced?1:Math.min(1,t*5),n=this.shift.x+(this.shiftTarget.x-this.shift.x)*e,i=this.shift.y+(this.shiftTarget.y-this.shift.y)*e;if(Math.abs(n-this.shift.x)<.05&&Math.abs(i-this.shift.y)<.05&&this.camera.view)return;this.shift={x:n,y:i};const r=this.container.clientWidth||innerWidth,a=this.container.clientHeight||innerHeight;this.camera.setViewOffset(r,a,n,i,r,a)}tuneIn(t,e){const n=this.stations.get(t),i=this.tunePose(t);if(!n||!i)return Promise.resolve();this.tuneOut(),this.cancelPlay();const r=this.tuneSeq;this.focused=t,this.shiftTarget={x:0,y:0};for(const[a,o]of this.stations)o.cable.setLit(a===t?1:0);return new Promise(a=>this.flyTo(i,1.1,()=>{if(r!==this.tuneSeq){this.applyLimits(t),this.controls.enabled=!0;return}this.tuned={id:t,place:e},n.staticLeft=0,this.resize(),a()}))}tunePose(t){const e=this.stations.get(t);if(!e)return null;const n=e.monitor,i=n.screenH/.75,r=n.world(n.screenLocal),a=xr.degToRad(this.camera.fov),o=2*Math.atan(Math.tan(a/2)*this.camera.aspect),l=Math.max(n.screenH/2/Math.tan(a/2)/.84,i/2/Math.tan(o/2)/.94);return{pos:r.clone().addScaledVector(n.normal(),l),target:r}}tuneOut(){this.tuneSeq++,this.tuned&&(this.tuned=null,this.tween||(this.applyLimits(this.focused),this.controls.enabled=!0))}reset(){this.tuneOut(),this.cancelPlay(),this.focus(null)}glassRect(t){const e=this.stations.get(t);if(!e)return null;const n=e.monitor,i=n.screenH/.75,r=this.renderer.domElement.getBoundingClientRect(),a=[],o=[];this.camera.updateMatrixWorld();for(const[u,h]of[[-1,-1],[1,-1],[1,1],[-1,1]]){const d=n.world(n.screenLocal.clone().add(new C(u*i/2,h*n.screenH/2,i*.02)));d.project(this.camera),a.push(r.left+(d.x+1)/2*r.width),o.push(r.top+(1-d.y)/2*r.height)}const l=Math.min(...a),c=Math.min(...o);return new DOMRectReadOnly(l,c,Math.max(...a)-l,Math.max(...o)-c)}get tunedId(){var t;return((t=this.tuned)==null?void 0:t.id)??null}bindPointer(){const t=this.renderer.domElement;let e=null;t.addEventListener("pointermove",n=>{const i=t.getBoundingClientRect();this.pointer.set((n.clientX-i.left)/i.width*2-1,-((n.clientY-i.top)/i.height)*2+1),this.pointerPx={x:n.clientX,y:n.clientY},this.pointerDirty=!0,this.lastInput=this.t}),t.addEventListener("pointerleave",()=>{this.pointer.set(-9,-9),this.pointerDirty=!0}),t.addEventListener("pointerdown",n=>{if(n.button!==0||!n.isPrimary){e=null;return}e={x:n.clientX,y:n.clientY,t:performance.now()},this.lastInput=this.t}),t.addEventListener("pointerup",n=>{if(!e)return;const i=Math.hypot(n.clientX-e.x,n.clientY-e.y),r=performance.now()-e.t<600;if(e=null,i>7||!r||this.tuned)return;const a=t.getBoundingClientRect();this.pointer.set((n.clientX-a.left)/a.width*2-1,-((n.clientY-a.top)/a.height)*2+1),this.events.pick(this.pickAt())})}pickFromPoint(t,e){const n=this.renderer.domElement.getBoundingClientRect(),i=this.pointer.clone();this.pointer.set((t-n.left)/n.width*2-1,-((e-n.top)/n.height)*2+1);const r=this.pickAt();return this.pointer.copy(i),r}pickAt(){this.raycaster.setFromCamera(this.pointer,this.camera);const t=this.raycaster.intersectObjects(this.pickables,!1)[0];return(t==null?void 0:t.object.userData.pick)??null}resize(){const t=this.container.clientWidth||innerWidth,e=this.container.clientHeight||innerHeight,n=Math.abs(t/e-this.lastAspect)>.02;if(this.lastAspect=t/e,this.camera.aspect=t/e,this.camera.fov=this.camera.aspect<1?58:45,this.camera.setViewOffset(t,e,this.shift.x,this.shift.y,t,e),this.renderer.setSize(t,e,!1),this.renderer.domElement.style.width=`${t}px`,this.renderer.domElement.style.height=`${e}px`,this.post.setSize(t,e,this.pixelRatio),this.tuned){this.shift={x:0,y:0},this.camera.setViewOffset(t,e,0,0,t,e);const i=this.tunePose(this.tuned.id);i&&(this.camera.position.copy(i.pos),this.controls.target.copy(i.target),this.camera.lookAt(i.target));const r=this.glassRect(this.tuned.id);r&&this.tuned.place(r)}if(n&&!this.tween&&!this.focused&&this.controls){const i=this.homePose();this.camera.position.copy(i.pos),this.controls.target.copy(i.target)}}async warm(t=5e3){try{await Promise.race([this.renderer.compileAsync(this.scene,this.camera),new Promise(e=>setTimeout(e,t))]),this.post.render(0,0)}catch(e){console.warn("oikos: warm-up skipped",e)}}start(){if(this.running)return;if(this.running=!0,this.clock.getDelta(),this.driven){const e=this.renderer.getContext();window.__oikos={step:(n=1,i=1/30)=>{var r;this.perf={frames:0,paint:0,render:0,uploads:0};for(let a=0;athis.anchor(n),glass:n=>this.glassRect(n)};return}const t=()=>{this.running&&(this.raf=requestAnimationFrame(t),this.frame())};this.raf=requestAnimationFrame(t)}stop(){this.running=!1,cancelAnimationFrame(this.raf)}adapt(t){this.frameTimes.push(t);const e=this.frameTimes.reduce((i,r)=>i+r,0);if(this.frameTimes.length<90&&e<2)return;const n=this.frameTimes.reduce((i,r)=>i+r,0)/this.frameTimes.length;if(this.frameTimes=[],this.calm=n<1/50?this.calm+1:0,this.calm>=3&&this.qualityStep>0){this.calm=0,this.qualityStep--,this.pixelRatio=Math.min(this.maxPixelRatio,this.pixelRatio/.8),this.post.bloom.enabled=!0,this.applyPixelRatio();return}n>1/27&&this.qualityStep<3&&(this.qualityStep++,this.pixelRatio=Math.max(.6,this.pixelRatio*.8),this.qualityStep>=3&&(this.post.bloom.enabled=!1),this.applyPixelRatio())}applyPixelRatio(){this.renderer.setPixelRatio(this.pixelRatio);const t=this.container.clientWidth||innerWidth,e=this.container.clientHeight||innerHeight;this.renderer.setSize(t,e,!1),this.post.setSize(t,e,this.pixelRatio)}frame(t){var o;const e=t??this.clock.getDelta(),n=Math.min(e,.1)*this.speed;this.t+=n;const i=this.t;if(this.driven||this.adapt(Math.min(e,.5)),this.applyShift(n),this.later.length){const l=this.later.filter(c=>c.at<=i);this.later=this.later.filter(c=>c.at>i);for(const c of l)c.fn()}if(this.tween){const l=this.tween;l.k=Math.min(1,l.k+n/l.dur);const c=wx(l.k);this.camera.position.lerpVectors(l.from.pos,l.to.pos,c),this.controls.target.lerpVectors(l.from.target,l.to.target,c),this.camera.lookAt(this.controls.target),l.k>=1&&(this.tween=null,(o=l.done)==null||o.call(l))}else{if(!this.focused&&!this.reduced&&i-this.lastInput>9){this.controls.autoRotate=!0;const l=this.controls.getAzimuthalAngle();l>.32&&(this.swayDir=1),l<-.32&&(this.swayDir=-1),this.controls.autoRotateSpeed=.18*this.swayDir}else this.controls.autoRotate=!1;this.controls.update(n)}if(this.pointerDirty&&!this.tween){this.pointerDirty=!1;const l=this.pickAt();l!==this.hovered&&(this.hovered=l,this.renderer.domElement.style.cursor=l?"pointer":""),this.events.hover(l,this.pointerPx.x,this.pointerPx.y)}const r=performance.now();this.camera.updateMatrixWorld(),this.viewProj.multiplyMatrices(this.camera.projectionMatrix,this.camera.matrixWorldInverse),this.frustum.setFromProjectionMatrix(this.viewProj);for(const[l,c]of this.stations){i>=c.powerAt&&(c.power=Math.min(1,c.power+n/(this.reduced?.01:.8))),c.staticLeft=Math.max(0,c.staticLeft-n),c.hover+=((l===this.hovered?1:0)-c.hover)*Math.min(1,n*8);const u=c.monitor.crt.uniforms;u.uTime.value=i,u.uPower.value=c.power,u.uHover.value=c.hover,u.uStatic.value=Math.min(1,c.staticLeft*1.6);const h=this.focused===l,d=h||l===this.kept||this.frustum.intersectsObject(c.monitor.glass),f=this.focused&&this.focused!=="vcr"&&!h&&l!==this.kept?.5:1;c.power>.2&&d&&c.screen.tick(i,n,h,f)&&(c.monitor.texture.needsUpdate=!0,this.perf.uploads++),c.monitor.setLed(c.power>.5,c.site.accent);const p=c.glow.material;p.opacity=c.power*(.16+c.hover*.12+(h?.1:0)),c.light&&(c.light.intensity=c.power*(2.2+c.hover*1.4+(h?.6:0))),c.cable.update(i,n)}this.vcr.vfd.glow=this.hovered==="vcr"?1:.8,this.vcr.vfd.update(i,n),this.vcr.update(n),this.field.update(i);const a=performance.now();if(this.post.render(i,n),this.driven){this.renderer.getContext().finish();const l=performance.now();this.perf.frames++,this.perf.paint+=a-r,this.perf.render+=l-a}}}let Ax=0;const di=s=>`${s}${++Ax}`,Cx="/static/oikos/mark.png";function vn(s,t=""){const e=di("tp"),n=t.length>9?`${t.slice(0,8)}…`:t;return``}function hu(s){return s.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t]??t)}function fi(s="app"){if(s==="status")return'';if(s==="channel")return'';const t=di("ch");return``}function Zu(){return''}function Ju(){return''}function ty(){return''}function ju(){return''}function ey(){const s=_i("ap");return``}function Qu(){return''}function pr(s,t=!1){return``}function td(s){return s.replace(/[&<>"']/g,t=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[t]??t)}function yi(s="app"){if(s==="status")return'';if(s==="channel")return'';const t=_i("ch");return``}let Fi=null,Mn=null,bl=null;function zx(s){Fi=s,s.addEventListener("pointerdown",t=>{if(!Mn)return;const e=t.target;e.closest(".xp-menu")||e.closest("[data-menu-owner]")||pi()},!0)}function Hx(){return Mn!==null}function pi(){if(!Mn)return!1;let s=Mn;for(;s;)s.el.remove(),s=s.child;Mn=null;const t=bl;return bl=null,t==null||t(),!0}function uu(s,t){const e=G("div",{class:"xp-menu",role:"menu"}),n=[];for(const i of s){if(i==="sep"){e.append(G("div",{class:"xp-menu-sep",role:"separator"}));continue}const r=G("button",{type:"button",role:i.checked!==void 0?"menuitemcheckbox":"menuitem",class:`${i.bold?"bold ":""}${i.submenu?"has-sub":""}`.trim(),html:`${i.icon??""}`});r.querySelector(".lb").textContent=i.label,r.querySelector(".sc").textContent=i.shortcut??"",i.checked!==void 0&&(r.setAttribute("aria-checked",String(i.checked)),i.checked&&r.classList.add("checked")),i.disabled&&(r.setAttribute("aria-disabled","true"),r.tabIndex=-1);const a=()=>{var u;if(!i.submenu||i.disabled)return;const o=wl(e);if(!o||((u=o.child)==null?void 0:u.el.dataset.for)===i.label)return;El(o);const l=r.getBoundingClientRect(),c=du(uu(i.submenu(),o),l.right-3,l.top-3,l.left+3);c.dataset.for=i.label,o.child={el:c,child:null}};r.addEventListener("pointerenter",()=>{const o=wl(e);i.submenu?a():o&&El(o)}),r.addEventListener("click",o=>{var l,c,u,h;if(o.stopPropagation(),!i.disabled){if(i.submenu){a(),(u=(c=(l=wl(e))==null?void 0:l.child)==null?void 0:c.el.querySelector("button:not([aria-disabled])"))==null||u.focus();return}pi(),(h=i.run)==null||h.call(i)}}),e.append(r),n.push(r)}return e.addEventListener("keydown",i=>{var o,l,c;const r=n.filter(u=>u.getAttribute("aria-disabled")!=="true"),a=r.indexOf(document.activeElement);if(i.key==="ArrowDown"||i.key==="ArrowUp"){i.preventDefault(),i.stopPropagation();const u=r[(a+(i.key==="ArrowDown"?1:-1)+r.length)%r.length];u==null||u.focus()}else i.key==="ArrowRight"&&((o=r[a])!=null&&o.classList.contains("has-sub"))?(i.preventDefault(),i.stopPropagation(),(l=r[a])==null||l.click()):i.key==="ArrowLeft"&&t&&(i.preventDefault(),i.stopPropagation(),El(t),(c=t.el.querySelector("button.has-sub"))==null||c.focus())}),e}function wl(s){let t=Mn;for(;t;){if(t.el===s)return t;t=t.child}return null}function El(s){let t=s.child;for(;t;)t.el.remove(),t=t.child;s.child=null}function du(s,t,e,n=t){if(!Fi)throw new Error("menu host not set");s.style.left="0px",s.style.top="0px",Fi.append(s);const i=Fi.getBoundingClientRect(),r=s.offsetWidth,a=s.offsetHeight;let o=t-i.left,l=e-i.top;return o+r>i.width-2&&(o=Math.max(2,n-i.left-r)),l+a>i.height-32&&(l=Math.max(2,i.height-32-a)),s.style.left=`${Math.round(o)}px`,s.style.top=`${Math.round(l)}px`,s}function Ms(s,t,e,n,i=!1){var a;pi();const r=uu(s,null);Mn={el:r,child:null},du(r,t,e),bl=n??null,i&&((a=r.querySelector("button:not([aria-disabled])"))==null||a.focus())}function fu(s,t,e){const n=t.getBoundingClientRect();if(Ms(s,n.right-2,n.top-3,e),Mn){const i=Fi==null?void 0:Fi.getBoundingClientRect();i&&n.right+Mn.el.offsetWidth>i.right&&(Mn.el.style.left=`${Math.max(2,n.left-i.left-Mn.el.offsetWidth+2)}px`)}}function Gx(s,t){s.addEventListener("contextmenu",e=>{const n=e.target;if(n.closest("input, textarea, [contenteditable], .oikos-tube"))return;const i=t(n,e);if(i!==null){if(e.preventDefault(),!i.length){pi();return}Ms(i,e.clientX,e.clientY)}})}function G(s,t={},e=[]){const n=document.createElement(s);for(const[i,r]of Object.entries(t))i==="html"?n.innerHTML=r:n.setAttribute(i,r);for(const i of e)n.append(i);return n}function Tl(s){const t=G("div",{class:"xp-menubar",role:"menubar"});let e=null;const n=(i,r,a)=>{var c;const o=(c=s[r])==null?void 0:c.call(s);if(!o)return;const l=i.getBoundingClientRect();Ms(o,l.left,l.bottom,()=>{i.classList.remove("open"),e===i&&(e=null)},a),i.classList.add("open"),e=i};for(const i of Object.keys(s)){const r=G("button",{type:"button",class:"xp-menutitle",role:"menuitem","aria-haspopup":"menu","data-menu-owner":""},[i]);r.addEventListener("click",()=>{e===r?pi():n(r,i,!1)}),r.addEventListener("pointerenter",()=>{e&&e!==r&&Hx()&&n(r,i,!1)}),r.addEventListener("keydown",a=>{(a.key==="ArrowDown"||a.key==="Enter"||a.key===" ")&&(a.preventDefault(),n(r,i,!0))}),t.append(r)}return t.append(G("span",{class:"xp-throbber",html:Js(18,!0)})),t}function pu(s){const t=G("div",{class:"xp-toolbar"}),e=(a,o,l,c=!0)=>{const u=G("button",{class:"xp-tb",type:"button",title:o,html:`${a}${c?`${o}`:""}`});return l?u.addEventListener("click",l):u.disabled=!0,t.append(u),u},n=e(Px(),"Back",s.back),i=e(Lx(),"Forward",s.forward,!1);e(Dx(),"Up",s.up,!1),t.append(G("span",{class:"xp-tb-sep"})),e(Ix(),"Search",s.search),e(Nx(),"Folders",s.folders);const r=()=>{if(!s.can)return;const a=s.can();n.disabled=!s.back||!a.back,i.disabled=!s.forward||!a.forward};return r(),{el:t,refresh:r}}function mu(s,t,e,n){const i=G("div",{class:"xp-address"});i.append(G("span",{class:"lbl"},["Address"]));const r=G("label",{class:"field",html:s});let a=null;e?(a=G("input",{type:"text",value:t,"aria-label":"Address",spellcheck:"false"}),a.style.cssText="flex:1;min-width:0;border:0;outline:0;font:inherit;background:transparent;",r.append(a),a.addEventListener("keydown",l=>{l.key==="Enter"&&a&&(n==null||n(a.value)),l.stopPropagation()})):r.append(G("span",{},[t])),i.append(r);const o=G("button",{class:"go",type:"button",html:`${Ux()}Go`});return o.addEventListener("click",()=>n==null?void 0:n((a==null?void 0:a.value)??t)),i.append(o),{el:i,input:a}}function ys(s,t,e=!1){const n=G("section",{class:`xp-taskgroup${e?" primary":""}`}),i=G("header",{role:"button",tabindex:"0","aria-expanded":"true"},[s]),r=()=>{n.classList.toggle("collapsed"),i.setAttribute("aria-expanded",String(!n.classList.contains("collapsed")))};i.addEventListener("click",r),i.addEventListener("keydown",o=>{(o.key==="Enter"||o.key===" ")&&(o.preventDefault(),r())}),n.append(i);const a=G("div",{class:"xp-taskbody"});if(t instanceof HTMLElement)a.append(t);else{const o=G("ul");for(const l of t){const c=G("li");let u;if(l.href)u=G("a",{class:"xp-link",href:l.href,html:`${l.icon}`}),l.external&&(u.setAttribute("target","_blank"),u.setAttribute("rel","noopener"));else{u=G("button",{class:"xp-link",type:"button",html:`${l.icon}`});const d=l.run;d?u.addEventListener("click",d):u.setAttribute("aria-disabled","true")}const h=u.querySelector("span");h&&(h.textContent=l.label),c.append(u),o.append(c)}a.append(o)}return n.append(a),n}function gu(){const s=G("div",{class:"xp-statusbar",role:"status"}),t=G("span"),e=G("span",{class:"zone"});return s.append(t,e),{el:s,set(n,i){t.textContent=n;const[r,a]=i==="computer"?[tu(),"My Computer"]:[eu(),"Internet"];e.innerHTML=`${r}${a}`}}}const Vx={dreams:["chronicle","dreams-api","dream_gen"],chronicle:["dreams","dream_gen"],"dreams-api":["dreams","chronicle"],dream_gen:["dreams","chronicle"],transmissions:["irc","syrinx"],apeiron:["dreams","syrinx"],syrinx:["apeiron","transmissions"],irc:["transmissions","parlor"],parlor:["irc","transmissions"]};function _u(s){return/^https?:/.test(s.href)?s.href:`${location.origin}${s.href}`}function xu(s){return s.group==="here"?"computer":"internet"}function Al(s,t){var i;const e=_u(t),n=(i=navigator.clipboard)==null?void 0:i.writeText(e);if(!n){s.balloon("Could not copy",e);return}n.then(()=>s.balloon("Copied",e),()=>s.balloon("Could not copy",e))}function na(s,t,e=!1){const n=[];return e?n.push({label:`Open ${t.title}`,bold:!0,run:()=>s.open(t)}):(n.push({label:"Play",bold:!0,run:()=>s.play(t.id)}),n.push({label:`Go to ${t.title}`,run:()=>s.open(t)})),n.push({label:"Look at its screen",run:()=>s.look(t.id),disabled:!s.canTune}),t.tune&&n.push({label:"Watch it here",run:()=>s.tuneIn(t.id),disabled:!s.canTune}),t.id==="irc"&&n.push({label:"Join in mIRC",run:()=>s.chat("#aethera")}),n.push("sep",{label:"Copy Address",run:()=>Al(s,t)}),e||n.push("sep",{label:"Properties",run:()=>s.play(t.id)}),n}function vu(s,t){return[{label:"Undo",shortcut:"Ctrl+Z",disabled:!0},"sep",{label:"Cut",shortcut:"Ctrl+X",disabled:!0},{label:"Copy",shortcut:"Ctrl+C",disabled:!t,run:()=>t&&Al(s,t)},{label:"Paste",shortcut:"Ctrl+V",disabled:!0},"sep",{label:"Select All",shortcut:"Ctrl+A",disabled:!0},{label:"Invert Selection",disabled:!0}]}function Mu(s){return[{label:"Add to Favorites...",disabled:!0},{label:"Organize Favorites...",disabled:!0},"sep",...s.dir.sites.filter(t=>t.group==="here").map(t=>({label:t.title,icon:vn(t.accent),run:()=>s.play(t.id)}))]}function yu(){return[{label:"Map Network Drive...",disabled:!0},{label:"Disconnect Network Drive...",disabled:!0},{label:"Synchronize...",disabled:!0},"sep",{label:"Folder Options...",disabled:!0}]}function Su(s){return[{label:"Help and Support Center",disabled:!0},"sep",{label:"About æthera",run:()=>s.about()}]}function Cl(s){s.hidden=!s.hidden}function bu(s,t){return[{label:"Toolbars",submenu:()=>[{label:"Standard Buttons",checked:!t.toolbar.hidden,run:()=>Cl(t.toolbar)},{label:"Address Bar",checked:!t.address.hidden,run:()=>Cl(t.address)}]},{label:"Status Bar",checked:!t.status.hidden,run:()=>Cl(t.status)},...t.views?["sep",...t.views]:[],"sep",{label:"Go To",submenu:()=>[{label:"Back",shortcut:"Alt+Left",disabled:!s.canBack,run:()=>s.back()},{label:"Forward",shortcut:"Alt+Right",disabled:!s.canForward,run:()=>s.forward()},{label:"Up One Level",disabled:!t.up,run:()=>{var e;return(e=t.up)==null?void 0:e.call(t)}},"sep",{label:"Home Page",shortcut:"Alt+Home",run:()=>s.home()}]},{label:"Refresh",shortcut:"F5",run:()=>t.refresh()}]}class Wx{constructor(t,e){I(this,"win",null);I(this,"selected",null);I(this,"tiles",new Map);I(this,"tasks",null);I(this,"status",null);I(this,"content",null);I(this,"view","tiles");this.shell=t,this.wm=e}get isOpen(){return!!this.win&&!this.win.closed}open(){var u;if(this.isOpen&&this.win){this.win.minimized?this.win.restore():this.win.focus();return}this.tiles.clear();const t=G("div");t.style.cssText="display:flex;flex-direction:column;min-height:0;flex:1;";const{dir:e}=this.shell,n=pu({back:()=>this.shell.back(),forward:()=>this.shell.forward(),can:()=>({back:this.shell.canBack,forward:this.shell.canForward}),search:()=>{var h;return(h=i.input)==null?void 0:h.focus()},folders:()=>{var h;return(h=this.tasks)==null?void 0:h.toggleAttribute("hidden")}}),i=mu(Zs(),"~/æthera",!0,h=>this.go(h));(u=i.input)==null||u.addEventListener("input",()=>{var h;return this.filter(((h=i.input)==null?void 0:h.value)??"")}),this.status=gu();const r=()=>this.selected?this.shell.site(this.selected)??null:null;t.append(Tl({File:()=>this.fileMenu(),Edit:()=>vu(this.shell,r()),View:()=>{var h;return bu(this.shell,{toolbar:n.el,address:i.el,status:((h=this.status)==null?void 0:h.el)??G("div"),views:this.viewItems(),refresh:()=>{i.input&&(i.input.value="~/æthera"),this.filter("")}})},Favorites:()=>Mu(this.shell),Tools:()=>yu(),Help:()=>Su(this.shell)}),n.el,i.el);const a=this.shell.onNav(()=>n.refresh()),o=G("div",{class:"xp-body"});this.tasks=G("aside",{class:"xp-tasks"}),o.append(this.tasks);const l=G("div",{class:`xp-content view-${this.view}`,role:"listbox","aria-label":"tapes"});this.content=l,l.addEventListener("pointerdown",h=>{h.button===0&&!h.target.closest(".xp-tile")&&this.select(null)});const c=(h,d)=>{if(!d.length)return;l.append(G("h3",{class:"xp-group-head"},[h]));const f=G("div",{class:"xp-tiles"});for(const p of d)f.append(this.tile(p));l.append(f)};if(c("Tapes Stored on This Server",e.sites.filter(h=>h.group==="here")),c("Other Places on the Wired",e.sites.filter(h=>h.group==="wired")),e.files.length){l.append(G("h3",{class:"xp-group-head"},["Files"]));const h=G("div",{class:"xp-tiles"});for(const d of e.files){const f=d.title.split(".").pop()??"txt",p=G("a",{class:"xp-tile",href:d.href,html:`${vs(f)}`});p.querySelector(".t").textContent=d.title,p.querySelector(".k").textContent=d.about,h.append(p)}l.append(h)}o.append(l),t.append(o),t.append(this.status.el),this.win=this.wm.open({id:"home",title:"~ (home directory)",icon:Zs(),body:t,width:Math.round(Math.min(680,Math.max(420,innerWidth*.46))),dock:"left",onClose:()=>{a(),this.win=null,this.content=null,this.selected=null}}),this.win.el.style.height="min(560px, calc(100% - 40px))",this.renderTasks(),this.renderStatus()}close(){var t;(t=this.win)==null||t.close()}fileMenu(){const t=this.selected?this.shell.site(this.selected):void 0;return[...t?na(this.shell,t):[{label:"Play",bold:!0,disabled:!0}],"sep",{label:"New",disabled:!0,submenu:()=>[]},"sep",{label:"Create Shortcut",disabled:!0},{label:"Delete",disabled:!0},{label:"Rename",disabled:!0},"sep",{label:"Close",run:()=>this.close()}]}viewItems(){const t=e=>()=>{this.view=e,this.content&&(this.content.className=`xp-content view-${e}`)};return[{label:"Tiles",checked:this.view==="tiles",run:t("tiles")},{label:"Icons",checked:this.view==="icons",run:t("icons")},{label:"List",checked:this.view==="list",run:t("list")}]}contextFor(t){const e=this.shell.site(t);return e?(this.select(t,!0),na(this.shell,e)):null}blankMenu(){return[{label:"View",submenu:()=>this.viewItems()},{label:"Arrange Icons By",disabled:!0,submenu:()=>[]},"sep",{label:"Refresh",run:()=>this.filter("")},"sep",{label:"Paste",disabled:!0},{label:"Paste Shortcut",disabled:!0},"sep",{label:"New",disabled:!0,submenu:()=>[]},"sep",{label:"Properties",disabled:!0}]}tile(t){const e=G("button",{class:"xp-tile",type:"button",role:"option","data-id":t.id,html:`${vn(t.accent,t.title)}`});return e.querySelector(".t").textContent=t.title,e.querySelector(".k").textContent=t.kind,e.querySelector(".d").textContent=t.tagline,e.title=t.tagline,e.addEventListener("click",()=>this.select(t.id,!0)),e.addEventListener("dblclick",()=>this.shell.play(t.id)),e.addEventListener("keydown",n=>{if(n.key==="Enter"&&this.shell.play(t.id),["ArrowRight","ArrowDown","ArrowLeft","ArrowUp"].includes(n.key)){n.preventDefault(),n.stopPropagation();const i=[...this.tiles.values()].filter(o=>!o.hidden),r=i.indexOf(e),a=i[(r+(n.key==="ArrowRight"||n.key==="ArrowDown"?1:-1)+i.length)%i.length];a==null||a.focus(),a!=null&&a.dataset.id&&this.select(a.dataset.id,!0)}}),e.addEventListener("pointerup",n=>{n.pointerType==="touch"&&this.selected===t.id&&e.dataset.armed&&this.shell.play(t.id),e.dataset.armed="1"}),this.tiles.set(t.id,e),e}select(t,e=!1){if(t!==this.selected){this.selected=t;for(const[n,i]of this.tiles)i.classList.toggle("selected",n===t),i.setAttribute("aria-selected",String(n===t)),n!==t&&delete i.dataset.armed;e&&this.shell.select(t),this.renderTasks(),this.renderStatus()}}filter(t){const e=t.replace(/^~\/?(æthera)?\/?/i,"").trim().toLowerCase();for(const[n,i]of this.tiles){const r=this.shell.site(n);i.hidden=!!e&&!`${r==null?void 0:r.title} ${r==null?void 0:r.kind} ${r==null?void 0:r.tagline}`.toLowerCase().includes(e)}}go(t){const e=t.replace(/^~\/?(æthera)?\/?/i,"").trim().toLowerCase();if(!e)return;const n=this.shell.dir.sites.find(i=>i.title.toLowerCase()===e)??this.shell.dir.sites.find(i=>`${i.title} ${i.kind} ${i.tagline}`.toLowerCase().includes(e));n?this.shell.play(n.id):this.shell.balloon("Cannot find it",`There is no tape called “${t}” in ~.`)}renderTasks(){if(!this.tasks)return;const t=this.selected?this.shell.site(this.selected):void 0,e=t?[{icon:Sl(),label:"Play this tape",run:()=>this.shell.play(t.id)},{icon:su(),label:"Look at its screen",run:()=>this.shell.look(t.id)},{icon:eu(),label:`Go to ${t.title}`,run:()=>this.shell.open(t)}]:[{icon:Sl(),label:"Select a tape to play it"},{icon:ru(),label:"Eject the tape",run:()=>this.shell.eject()}],n=[{icon:tu(),label:"æthera",href:"/"},{icon:vs("xml"),label:"feed.xml",href:"/feed.xml"},{icon:vs("txt"),label:"llms.txt",href:"/llms.txt"}],i=G("div",{class:"xp-details"});if(t){i.append(G("b",{},[t.title]));const r=G("dl");for(const[a,o]of t.details)r.append(G("dt",{},[a]),G("dd",{},[o]));i.append(r)}else{const r=this.shell.dir.sites.filter(a=>a.group==="here").length;i.append(G("b",{},["~"]),G("span",{},[`home directory · ${r} tapes here, ${this.shell.dir.sites.length-r} elsewhere on the Wired`]))}this.tasks.replaceChildren(ys(t?"Tape Tasks":"System Tasks",e,!0),ys("Other Places",n),ys("Details",i))}renderStatus(){var n;const t=this.selected?this.shell.site(this.selected):void 0,e=this.shell.dir.sites.length+this.shell.dir.files.length;(n=this.status)==null||n.set(t?`${t.title} — ${t.tagline}`:`${e} objects`,t?xu(t):"computer")}}const $x=4001,Xx=4002,qx=s=>s>=4e3&&s<5e3,Yx=4;class Kx{constructor(t,e,n){I(this,"ws",null);I(this,"tries",0);I(this,"timer",0);I(this,"wanted",!1);I(this,"welcomed",!1);I(this,"refused",!1);this.nick=t,this.password=e,this.on=n}get open(){var t;return this.welcomed&&((t=this.ws)==null?void 0:t.readyState)===WebSocket.OPEN}connect(){this.wanted=!0,this.refused=!1,clearTimeout(this.timer);const t=location.protocol==="https:"?"wss":"ws";let e;try{e=new WebSocket(`${t}://${location.host}/ws/chat`)}catch{this.on.closed(!1,!1,!1);return}this.ws=e,this.welcomed=!1,e.onopen=()=>{e.send(JSON.stringify({type:"hello",nick:this.nick,password:this.password||null}))},e.onmessage=n=>{let i;try{i=JSON.parse(String(n.data))}catch{return}switch(i.type){case"welcome":{const r=i;this.welcomed=!0,this.tries=0,this.nick=r.nick,this.on.welcome(r);break}case"event":{const r=i.event;if(!r)break;r.kind==="nick"&&r.nick===this.nick&&r.target&&(this.nick=r.target),this.on.event(r);break}case"whois":this.on.whois(i);break;case"error":{this.welcomed||(this.refused=!0),this.on.error(String(i.code??""),String(i.text??""));break}}},e.onclose=n=>{if(this.ws!==e)return;this.ws=null;const i=n.code===$x,r=n.code===Xx,a=this.wanted&&!qx(n.code)&&!this.refused&&this.triesthis.connect(),2e3*2**(this.tries-1))}}send(t){if(!this.open||!this.ws)return!1;try{return this.ws.send(JSON.stringify(t)),!0}catch{return!1}}part(t="Leaving"){if(this.open&&this.ws)try{this.ws.send(JSON.stringify({type:"part",reason:t}))}catch{}this.close()}close(){this.wanted=!1,clearTimeout(this.timer);const t=this.ws;if(this.ws=null,this.welcomed=!1,this.password=null,t){t.onclose=null;try{t.close()}catch{}}}}const Ot="#aethera",Rt="#oikos",In="irc.aetherawi.red",Rl=6667,Pl="guest",wu="always falling apart",Zx=600,Jx=6e3,Eu="oikos-mirc-nick",Qx=/^[A-Za-z[\]\\`_^{|}][A-Za-z0-9[\]\\`_^{|}-]{0,15}$/,Ll=["~","&","@","%","+"];function jx(s){const t=new Date(s);return`[${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}]`}function tv(s){return Date.now()-(performance.now()-s)}function Dl(s){const t=Yn(s)||"anon",e=ca(t),n=["dialup.wired.net","cable.aether.org","dsl.lain.jp","adsl.nowhere.nu","res.navi.co"],i=n[Math.floor(e*n.length)]??n[0],r=Math.floor(e*251)+2,a=Math.floor(ca(`${t}.`)*251)+2;return`~${t.slice(0,9).toLowerCase()}@ppp-${r}-${a}.${i}`}function Yn(s){return s.replace(/^[~&@%+]+/,"")}function Tu(s){const t=s.charAt(0);return Ll.includes(t)?t:""}function ev(){try{return localStorage.getItem(Eu)??""}catch{return""}}function Au(s){try{localStorage.setItem(Eu,s)}catch{}}function Il(s){s.addEventListener("keydown",t=>{t.key!=="Escape"&&t.stopPropagation()})}class Nl{constructor(t,e,n){I(this,"tab");I(this,"pane");I(this,"log");I(this,"nicksEl");I(this,"nicks",new Map);I(this,"topic","");I(this,"joined",!1);this.id=t;const i=`mirc-pane-${t==="status"?"status":t.slice(1)}`;this.tab=G("button",{type:"button",role:"tab","aria-controls":i,html:`${e}`}),this.tab.querySelector("span").textContent=t==="status"?"Status":t,this.log=G("div",{class:"mirc-log",role:"log","aria-label":t==="status"?"Status":t}),n?(this.log.setAttribute("aria-live","polite"),this.nicksEl=G("ul",{class:"mirc-nicks","aria-label":`Nicknames in ${t}`}),this.pane=G("div",{class:"mirc-pane",id:i,role:"tabpanel"},[G("div",{class:"mirc-split"},[this.log,this.nicksEl])])):(this.nicksEl=null,this.pane=G("div",{class:"mirc-pane",id:i,role:"tabpanel"},[this.log]))}setNick(t,e=Tu(t)){const n=Yn(t);n&&this.nicks.set(n.toLowerCase(),{name:n,mode:e})}seen(t){const e=Yn(t);if(!e)return!1;const n=e.toLowerCase(),i=this.nicks.get(n),r=Tu(t)||(i==null?void 0:i.mode)||"";return i&&i.mode===r&&i.name===e?!1:(this.nicks.set(n,{name:e,mode:r}),!0)}drop(t){return this.nicks.delete(Yn(t).toLowerCase())}rename(t,e){const n=this.nicks.get(Yn(t).toLowerCase());this.drop(t),this.setNick(e,(n==null?void 0:n.mode)??"")}render(){if(!this.nicksEl)return;const t=n=>n?Ll.indexOf(n):Ll.length,e=[...this.nicks.values()].sort((n,i)=>t(n.mode)-t(i.mode)||n.name.localeCompare(i.name,void 0,{sensitivity:"base"}));this.nicksEl.replaceChildren(...e.map(n=>G("li",{title:`${n.mode}${n.name}`},[`${n.mode}${n.name}`])))}}class nv{constructor(t,e,n){I(this,"win");I(this,"wins");I(this,"view",Ot);I(this,"input");I(this,"me",Pl);I(this,"link",null);I(this,"hintedOikos",!1);I(this,"livingSeenAt",0);I(this,"livingOnce",!1);I(this,"greeted",!1);I(this,"hung",!1);I(this,"lastAt",-1);I(this,"seenFragments");I(this,"seenCollapse",null);I(this,"wasConnected",!1);I(this,"rejoinTimer",0);I(this,"off");var c;this.shell=t,this.wm=e;const i=G("div",{class:"mirc"});i.append(Tl({File:()=>[{label:"Connect...",run:()=>this.joinLiving(),disabled:!!this.link},{label:"Disconnect",run:()=>this.partLiving(),disabled:!this.link},"sep",{label:"Select Server...",disabled:!0},"sep",{label:"Exit",run:()=>this.win.close()}],Tools:()=>[{label:"Address Book...",disabled:!0},{label:"Options...",shortcut:"Alt+O",disabled:!0}],Commands:()=>[{label:`Join ${Rt}`,run:()=>this.joinLiving()},{label:`Part ${Rt}`,run:()=>this.partLiving(),disabled:!this.link},"sep",{label:"Clear buffer",run:()=>this.wins[this.view].log.replaceChildren()}],Window:()=>["status",Ot,Rt].filter(u=>!this.wins[u].tab.hidden).map(u=>({label:u==="status"?"Status":u,checked:this.view===u,run:()=>this.show(u)})),Help:()=>[{label:"Commands",shortcut:"F1",run:()=>this.help()},"sep",{label:"About æthera",run:()=>this.shell.about()}]}));const r=G("div",{class:"mirc-switch",role:"tablist"});this.wins={status:new Nl("status",fi("status"),!1),[Ot]:new Nl(Ot,fi("channel"),!0),[Rt]:new Nl(Rt,fi("channel"),!0)},this.wins[Ot].topic=wu,this.wins[Rt].tab.hidden=!0;const a=G("div",{class:"mirc-mdi"});for(const u of Object.values(this.wins))u.tab.addEventListener("click",()=>this.show(u.id)),r.append(u.tab),a.append(u.pane);this.input=G("input",{class:"mirc-input",type:"text",spellcheck:"false",autocomplete:"off",maxlength:"400","aria-label":"Message"}),Il(this.input),this.input.addEventListener("keydown",u=>{if(u.key!=="Enter")return;u.preventDefault();const h=this.input.value;this.input.value="",this.say(h)}),i.append(r,a,this.input),this.win=e.open({id:"mirc",title:"mIRC",icon:fi("app"),body:i,width:Math.round(Math.min(760,Math.max(460,innerWidth*.52))),dock:"center",onClose:()=>{var u,h;clearTimeout(this.rejoinTimer),this.off(),(u=this.link)==null||u.part("Leaving"),this.link=null,(h=this.wm.get("mirc-connect"))==null||h.close(),n()},onFocus:()=>{innerWidth>720&&this.input.focus({preventScroll:!0})}}),this.win.el.classList.add("mirc-window"),this.win.el.style.height="min(540px, calc(100% - 24px))";const o=this.win.el.parentElement;if(o){const u=this.win.el.offsetTop+this.win.el.offsetHeight-(o.clientHeight-8);u>0&&this.win.moveTo(this.win.el.offsetLeft,this.win.el.offsetTop-u)}const l=this.shell.feeds.irc.value;this.seenFragments=l.fragments,this.seenCollapse=((c=l.collapse)==null?void 0:c.at)??null,this.show(Ot),l.connected?this.connect(l):this.push("status","info",`* Connecting to ${In} (${Rl})`),this.off=this.shell.feeds.irc.on(u=>this.update(u))}focus(t){this.win.minimized?this.win.restore():this.win.focus();const e=t===Ot||t===Rt||t==="status"?this.wins[t]:null;e&&!e.tab.hidden&&this.show(e.id)}update(t){var n;if(t.connected&&!this.wasConnected?this.connect(t):!t.connected&&this.wasConnected&&this.disconnect(),!t.connected)return;for(const i of t.lines)i.at<=this.lastAt||(this.rejoinTimer&&this.rejoin(),this.lastAt=i.at,this.line(i));const e=((n=t.collapse)==null?void 0:n.at)??null;e!==null&&e!==this.seenCollapse&&t.collapse&&this.collapse(t.collapse.type),this.seenCollapse=e,t.fragments!==this.seenFragments&&(this.seenFragments=t.fragments,clearTimeout(this.rejoinTimer),this.hung?this.rejoinTimer=window.setTimeout(()=>this.rejoin(),Jx):this.rejoin())}connect(t){this.wasConnected=!0;const e=(i,r)=>this.push("status",i,r);if(this.greeted){e("info",`* Reconnected to ${In}`),this.joinHaunted(),t.collapse&&this.collapse(t.collapse.type);return}this.greeted=!0,e("info",`* Connecting to ${In} (${Rl})`),e("notice",`-${In}- *** Looking up your hostname...`),e("notice",`-${In}- *** Found your hostname`),e("text",`Welcome to the æthera IRC Network ${this.me}!${this.me}@oikos`),e("text",`Your host is ${In}, running version hauntd-2.8.21`),e("text",`- ${In} Message of the Day -`),e("text","- nobody here is who they were."),e("text","- every line is a replay; every replay is live."),e("text",`- ${Ot} is moderated: the living listen.`),e("text",`- the living talk in ${Rt}. /join ${Rt}`),e("text","End of /MOTD command."),e("mode",`* ${this.me} sets mode: +i`),this.joinHaunted();const n=t.lines.filter(i=>i.at>this.lastAt);if(n.length){this.push(Ot,"info","*** Buffer Playback...");for(const i of n)this.line(i);this.push(Ot,"info","*** Playback Complete.")}this.lastAt=Math.max(this.lastAt,...t.lines.map(i=>i.at)),t.collapse&&this.collapse(t.collapse.type)}joinHaunted(){const t=this.wins[Ot];t.joined=!0,t.nicks.clear(),t.setNick(this.me,""),this.push(Ot,"join",`* Now talking in ${Ot}`),this.push(Ot,"topic",`* Topic is '${t.topic}'`),this.push(Ot,"topic","* Set by ChanServ"),this.nicksChanged(Ot)}disconnect(){clearTimeout(this.rejoinTimer),this.rejoinTimer=0,this.wasConnected=!1;const t=this.wins[Ot];t.joined=!1,this.setHung(!1),this.push("status","info",`* Disconnected from ${Ot}`),this.push(Ot,"info","* Disconnected"),t.nicks.clear(),this.nicksChanged(Ot)}collapse(t){const e=t.replace(/_/g," ");this.push("status","notice",`-${In}- *** Notice -- ${e} on ${Ot}`),this.setHung(!0)}rejoin(){clearTimeout(this.rejoinTimer),this.rejoinTimer=0,this.setHung(!1),this.push(Ot,"info",`* Attempting to rejoin channel ${Ot}`),this.wins[Ot].topic=wu,this.joinHaunted()}line(t){const e=this.wins[Ot],n=t.nick,i=Yn(n),r=t.content,a=t.wallAt??tv(t.at),o=(c,u)=>this.push(Ot,c,u,a);let l=!1;switch(t.type){case"message":l=e.seen(n),o("text",`<${n}> ${r}`);break;case"action":{const c=/^sets mode: ([+-])([a-z]+) (.+)$/i.exec(r);c?(e.seen(n),this.applyMode(c[1]??"+",c[2]??"",(c[3]??"").split(/\s+/)),l=!0,o("mode",`* ${n} ${r}`)):/^has quit\b/i.test(r)?(l=e.drop(n),o("quit",`* ${i} ${r.replace(/^has quit\b/i,"has quit IRC")}`)):(l=e.seen(n),o("action",`* ${n} ${r}`));break}case"join":l=e.seen(n),o("join",`* ${i} (${Dl(n)}) has joined ${Ot}`);break;case"part":l=e.drop(n),o("part",`* ${i} (${Dl(n)}) has left ${Ot}${r?` (${r})`:""}`);break;case"quit":l=e.drop(n),o("quit",`* ${i} (${Dl(n)}) Quit (${r||"Client exited"})`);break;case"kick":{const c=t.reason||r;t.target?(l=e.drop(t.target),o("kick",`* ${Yn(t.target)} was kicked by ${i}${c?` (${c})`:""}`)):o("kick",`* ${i} kicks${c?` (${c})`:""}`);break}default:{const c=/changes topic to '(.*)'$/i.exec(r);if(c){e.topic=c[1]??e.topic,o("topic",`* ${r}`),this.retitle();break}const u=r||n;o("info",/^[*<]/.test(u)||u.length<6?u:`* ${u}`)}}!e.nicks.has(this.me.toLowerCase())&&e.joined&&(e.setNick(this.me,""),l=!0),l&&this.nicksChanged(Ot)}applyMode(t,e,n){const i=this.wins[Ot],r={q:"~",a:"&",o:"@",h:"%",v:"+"};[...e].forEach((a,o)=>{const l=n[o],c=r[a];if(!l||!c)return;const u=i.nicks.get(Yn(l).toLowerCase());i.setNick((u==null?void 0:u.name)??Yn(l),t==="+"?c:(u==null?void 0:u.mode)===c?"":(u==null?void 0:u.mode)??"")})}joinLiving(){if(this.link&&this.wins[Rt].joined){this.show(Rt);return}if(this.link){this.push(this.view,"info",`* Still connecting to ${Rt}...`);return}this.connectDialog()}partLiving(){if(!this.link)return;this.link.part("Leaving"),this.link=null;const t=this.wins[Rt];t.joined=!1,t.nicks.clear(),this.nicksChanged(Rt),this.push(Rt,"part",`* You have left ${Rt}`),this.push("status","info",`* Disconnected from ${Rt}`),this.livingSeenAt=0,this.livingOnce=!1,this.renameMe(Pl)}connectDialog(t){var u;(u=this.wm.get("mirc-connect"))==null||u.close();const e=G("form",{class:"mirc-connect"}),n=G("input",{type:"text",value:ev(),maxlength:"16",spellcheck:"false",autocomplete:"nickname",required:""}),i=G("input",{type:"password",maxlength:"256",autocomplete:"current-password"});Il(n),Il(i);const r=G("p",{class:"err",role:"alert"});r.textContent=t??"",r.hidden=!t,e.append(G("div",{class:"xp-dialog-body"},[G("span",{html:fi("app")}),G("div",{},[G("p",{},[`Join ${Rt}, where the living talk.`]),G("label",{},["Nickname:",n]),G("label",{},["Password (optional):",i]),G("p",{class:"hint"},["A password gives you a tripcode, the same one your blog comments carry. It is never stored."]),r])]));const a=G("div",{class:"xp-actions"}),o=G("button",{class:"xp-btn default",type:"submit"},["Connect"]),l=G("button",{class:"xp-btn",type:"button"},["Cancel"]);a.append(o,l),e.append(a);const c=this.wm.open({id:"mirc-connect",title:"mIRC Connect",icon:fi("app"),body:e,width:360,dialog:!0});l.addEventListener("click",()=>c.close()),e.addEventListener("keydown",h=>{h.key==="Escape"&&(h.preventDefault(),c.close(),this.input.focus({preventScroll:!0}))}),e.addEventListener("submit",h=>{h.preventDefault();const d=n.value.trim();if(!Qx.test(d)){r.textContent="A nickname starts with a letter and has at most 16 letters, digits or - _ [ ] { } | ^ `",r.hidden=!1,n.focus();return}Au(d),c.close(),this.dial(d,i.value||null)}),n.focus(),n.select()}dial(t,e){this.push("status","info",`* Connecting to ${Rt} as ${t}${e?" (with a tripcode)":""}`);const n=new Kx(t,e,{welcome:i=>this.welcomed(i),event:i=>this.event(i),whois:i=>this.whoisReply(i),error:(i,r)=>this.chatError(i,r),closed:(i,r,a)=>this.dropped(i,r,a)});this.link=n,n.connect()}welcomed(t){const e=this.wins[Rt];e.tab.hidden=!1,e.joined=!0,e.topic=t.topic,e.nicks.clear();for(const r of t.names)e.setNick(r.nick,r.op?"@":"");this.renameMe(t.nick);const n=this.livingOnce;this.livingOnce=!0;const i=t.backlog.filter(r=>r.at>this.livingSeenAt);if(n?this.push(Rt,"join",`* Rejoined ${Rt}`):(this.push("status","text",`* You are now known as ${t.nick} (${t.mask})`),t.op&&this.push("status","mode",`* ${In} sets mode: +o ${t.nick}`),this.push(Rt,"join",`* Now talking in ${Rt}`),this.push(Rt,"topic",`* Topic is '${t.topic}'`)),i.length){this.push(Rt,"info","*** Buffer Playback...");for(const r of i)this.event(r,!0);this.push(Rt,"info","*** Playback Complete.")}this.nicksChanged(Rt),n||this.show(Rt)}event(t,e=!1){const n=this.wins[Rt],i=(a,o)=>this.push(Rt,a,o,t.at),r=t.nick===this.me;switch(this.livingSeenAt=Math.max(this.livingSeenAt,t.at),t.kind){case"message":i(r?"own":"text",`<${t.nick}> ${t.text}`);return;case"action":i("action",`* ${t.nick} ${t.text}`);return;case"join":i("join",`* ${t.nick} (${t.mask??""}) has joined ${Rt}`),e||n.setNick(t.nick,"");break;case"part":i("part",`* ${t.nick} (${t.mask??""}) has left ${Rt}${t.text?` (${t.text})`:""}`),e||n.drop(t.nick);break;case"quit":i("quit",`* ${t.nick} (${t.mask??""}) Quit (${t.text||"Client exited"})`),e||n.drop(t.nick);break;case"kick":t.target===this.me&&!e?(i("kick",`* You were kicked from ${Rt} by ${t.nick} (${t.text})`),n.joined=!1,n.nicks.clear()):(i("kick",`* ${t.target??"?"} was kicked by ${t.nick} (${t.text})`),!e&&t.target&&n.drop(t.target));break;case"nick":r&&!e&&t.target?(i("text",`* Your nick is now ${t.target}`),this.renameMe(t.target),Au(t.target)):i("text",`* ${t.nick} is now known as ${t.target??"?"}`),!e&&t.target&&n.rename(t.nick,t.target);break;case"topic":i("topic",`* ${t.nick} changes topic to '${t.text}'`),e||(n.topic=t.text);break}e||this.nicksChanged(Rt)}whoisReply(t){const e=n=>this.push(this.view,"text",n);e(`${t.nick} is ${t.mask} * ${t.nick}`),t.trip&&e(`${t.nick} is identified by tripcode ${t.trip}`),t.op&&e(`${t.nick} is a channel operator on ${Rt}`),e(`${t.nick} signed on ${new Date(t.signon).toLocaleString()}`),e(`${t.nick} End of /WHOIS list.`)}chatError(t,e){var r;const n=this.wins[Rt],i=e.replace(/^(\S+) :/,"$1 ");this.push(n.joined?Rt:"status","error",`* ${i}`),!n.joined&&(t==="432"||t==="433")&&((r=this.link)==null||r.close(),this.link=null,this.livingOnce=!1,this.livingSeenAt=0,this.connectDialog(e.replace(/^\S+ :/,"")))}dropped(t,e,n){const i=this.wins[Rt],r=i.joined;i.joined=!1,i.nicks.clear(),this.nicksChanged(Rt),n?this.push(Rt,"info",`* ${this.me} is connected from somewhere else now (another window?); this one let go`):r&&!e&&this.push(Rt,"info",`* Disconnected${t?" (reconnecting...)":""}`),this.push("status","info",`* Disconnected from ${Rt}${t?" (reconnecting...)":""}`),t||(this.link=null,this.livingOnce=!1,this.livingSeenAt=0,this.renameMe(Pl))}renameMe(t){if(t===this.me)return;const e=this.wins[Ot];e.joined&&(e.rename(this.me,t),this.nicksChanged(Ot)),this.me=t,this.retitle()}say(t){var o,l,c,u,h,d;const e=t.trim();if(!e)return;const n=this.view,i=n===Rt&&this.wins[Rt].joined&&!!this.link,r=f=>this.push(n,"error",`* ${f}`);if(e.startsWith("/")&&!e.startsWith("//")){const[f="",...p]=e.slice(1).split(/\s+/),v=p.join(" ");switch(f.toLowerCase()){case"help":this.help();return;case"clear":this.wins[n].log.replaceChildren();return;case"quit":case"exit":this.win.close();return;case"join":{const m=(p[0]??"").toLowerCase().replace(/^#?/,"#");m===Rt||m==="#"&&n==="status"?this.joinLiving():m===Ot?(this.show(Ot),this.push(Ot,"error",`* You are already on ${Ot}`)):r(`${p[0]??"#"} Cannot join channel (this network has ${Ot} and ${Rt})`);return}case"part":case"leave":n===Rt&&this.link?this.partLiving():r(n===Ot?`${Ot} will not let you go`:"You are not on a channel");return;case"nick":p[0]?(o=this.link)!=null&&o.send({type:"nick",nick:p[0]})||r(`Join ${Rt} first to have a name (/join ${Rt})`):r("Usage: /nick ");return;case"whois":p[0]?(l=this.link)!=null&&l.send({type:"whois",nick:p[0]})||r(`${p[0]} :No such nick`):r("Usage: /whois ");return;case"me":if(!v)return;i?(c=this.link)==null||c.send({type:"say",text:v,action:!0}):n===Ot?this.refused(`* ${this.me} ${v}`,"action"):r("You are not on a channel");return;case"topic":i&&v?(u=this.link)==null||u.send({type:"topic",text:v}):i?this.push(Rt,"topic",`* Topic is '${this.wins[Rt].topic}'`):r(`${n==="status"?"":`${n} `}You're not channel operator`);return;case"kick":i&&p[0]?(h=this.link)==null||h.send({type:"kick",nick:p[0],reason:p.slice(1).join(" ")}):r(i?"Usage: /kick [reason]":"You're not channel operator");return;default:r(`${f.toUpperCase()} Unknown command`);return}}const a=e.startsWith("//")?e.slice(1):e;i?(d=this.link)!=null&&d.send({type:"say",text:a})||r("Not connected"):n===Ot&&this.wins[Ot].joined?this.refused(`<${this.me}> ${a}`,"own"):r("You are not on a channel")}refused(t,e){this.push(Ot,e,t),this.push(Ot,"error",`* ${Ot} Cannot send to channel`),this.hintedOikos||(this.hintedOikos=!0,this.push(Ot,"info",`* (the living talk in ${Rt}: /join ${Rt})`))}help(){const t=e=>this.push(this.view,"info",e);t("* Commands:"),t(`* /join ${Rt} join the living (a nick, and a password for a tripcode if you like)`),t("* /nick change your nick"),t("* /me an action"),t("* /whois who someone is (their tripcode, if they have one)"),t(`* /part leave ${Rt}`),t("* /topic, /kick for channel operators"),t("* /clear /quit")}push(t,e,n,i=Date.now()){var c;const r=this.wins[t],a=r.log,o=a.scrollHeight-a.scrollTop-a.clientHeight<24,l=G("div",{class:`mirc-row t-${e}`});for(l.append(G("span",{class:"ts"},[jx(i)]),` ${n}`),a.append(l);a.childElementCount>Zx;)(c=a.firstElementChild)==null||c.remove();o&&(a.scrollTop=a.scrollHeight),t!==this.view&&(t!=="status"&&(e==="text"||e==="action"||e==="own")?r.tab.classList.add("said"):r.tab.classList.contains("said")||r.tab.classList.add("event"))}show(t){this.view=t;for(const n of Object.values(this.wins)){const i=n.id===t;n.pane.hidden=!i,n.tab.classList.toggle("on",i),n.tab.setAttribute("aria-selected",String(i)),i&&n.tab.classList.remove("said","event")}const e=this.wins[t].log;e.scrollTop=e.scrollHeight,this.input.setAttribute("aria-label",t==="status"?"Command":`Message ${t}`),this.retitle()}nicksChanged(t){this.wins[t].render(),this.retitle()}setHung(t){this.hung!==t&&(this.hung=t,this.win.el.classList.toggle("mirc-hung",t),this.retitle())}retitle(){const t=this.wins[this.view],e=t.id===Ot?"+mnt":"+nt",n=t.id==="status"?`mIRC - [Status: ${this.me} on ${In} (${Rl})]`:t.joined?`mIRC - [${t.id} [${t.nicks.size}] [${e}]: ${t.topic}]`:`mIRC - [${t.id} (not on channel)]`;this.win.setTitle(this.hung?`${n} (Not Responding)`:n)}}class iv{constructor(t,e,n,i){I(this,"win");I(this,"statusLine");I(this,"timer",0);this.site=t,this.shell=e;const r=G("div");r.style.cssText="display:flex;flex-direction:column;min-height:0;flex:1;";const a=pu({back:()=>this.shell.back(),forward:()=>this.shell.forward(),can:()=>({back:this.shell.canBack,forward:this.shell.canForward}),up:()=>this.shell.home(),folders:()=>d.toggleAttribute("hidden")}),o=_u(t),l=mu(vn(t.accent),o,!1,()=>this.shell.open(t)).el,c=gu();r.append(Tl({File:()=>[...na(this.shell,t,!0),"sep",{label:"Properties",disabled:!0},"sep",{label:"Close",run:()=>this.win.close()}],Edit:()=>vu(this.shell,t),View:()=>bu(this.shell,{toolbar:a.el,address:l,status:c.el,up:()=>this.shell.home(),refresh:()=>this.refresh()}),Favorites:()=>Mu(this.shell),Tools:()=>yu(),Help:()=>Su(this.shell)}),a.el,l);const u=this.shell.onNav(()=>a.refresh()),h=G("div",{class:"xp-body"}),d=G("aside",{class:"xp-tasks"});h.append(d);const f=G("div",{class:"xp-content"});h.append(f),r.append(h),c.set("Done",xu(t)),r.append(c.el);const p=G("div",{class:"xp-hero",html:vn(t.accent,t.title)}),v=G("div");v.append(G("h2",{},[t.title]),G("p",{},[t.tagline])),p.append(v),f.append(p);const m=G("button",{class:"xp-preview",type:"button","aria-label":`Open ${t.title}`}),g=this.shell.screens.get(t.id);g&&m.append(g.canvas),m.append(G("span",{class:"xp-play"},[`▶ open ${t.title}`])),m.addEventListener("click",P=>this.shell.open(t,P)),f.append(m),f.append(G("p",{class:"xp-about"},[t.about]));const w=this.note();w&&f.append(G("div",{class:"xp-note"},[w]));const E=G("div",{class:"xp-actions"}),M=G("button",{class:"xp-btn default",type:"button"},[`Open ${t.title}`]);M.addEventListener("click",P=>this.shell.open(t,P));const S=G("button",{class:"xp-btn",type:"button"},["~ Home directory"]);if(S.addEventListener("click",()=>this.shell.home()),E.append(M),t.tune&&this.shell.canTune){const P=G("button",{class:"xp-btn",type:"button"},["▣ Watch it here"]);P.title="the live page, on its own screen in the room",P.addEventListener("click",()=>this.shell.tuneIn(t.id)),E.append(P)}if(t.id==="irc"){const P=G("button",{class:"xp-btn",type:"button"},["Join #aethera"]);P.title="sit in the channel, in mIRC",P.addEventListener("click",()=>this.shell.chat("#aethera")),E.append(P)}E.append(S),f.append(E);const b=[{icon:Sl(),label:`Open ${t.title}`,run:()=>this.shell.open(t)},{icon:su(),label:"Look at its screen",run:()=>this.shell.look(t.id)}];t.tune&&this.shell.canTune&&b.splice(1,0,{icon:Fx(),label:"Watch it on its screen",run:()=>this.shell.tuneIn(t.id)}),t.id==="irc"&&b.splice(1,0,{icon:fi("channel"),label:"Join #aethera in mIRC",run:()=>this.shell.chat("#aethera")}),b.push({icon:Ox(),label:"Copy address",run:()=>Al(this.shell,t)}),b.push({icon:ru(),label:"Eject tape",run:()=>this.win.close()});const R=[{icon:Zs(),label:"~ (home directory)",run:()=>this.shell.home()}];for(const P of Vx[t.id]??[]){const L=this.shell.site(P);L&&R.push({icon:vn(L.accent),label:L.title,run:()=>this.shell.play(L.id)})}const x=G("div",{class:"xp-details"});x.append(G("b",{},[t.title]));const T=G("dl");for(const[P,L]of t.details)T.append(G("dt",{},[P]),G("dd",{},[L]));x.append(T),this.statusLine=G("div",{class:"status"}),x.append(this.statusLine),d.append(ys("Tape Tasks",b,!0),ys("Other Places",R),ys("Details",x)),this.win=n.open({id:`site:${t.id}`,title:`${t.title} — ${o.replace(/^https?:\/\//,"")}`,icon:vn(t.accent),body:r,width:Math.round(Math.min(760,Math.max(440,innerWidth*.5))),dock:"right",onClose:()=>{u(),clearInterval(this.timer),g==null||g.canvas.remove(),i()}}),this.win.el.style.height="min(640px, calc(100% - 24px))",this.refresh(),this.timer=window.setInterval(()=>this.refresh(),2e3)}note(){const t=this.site;return t.id==="dreams"?"Opening dreams wakes the dreamer: a GPU starts up while anyone is watching and goes back to sleep after. The frame here is the last one the chronicle kept.":t.id==="syrinx"?"Syrinx makes sound once you wake it. The creature here is read from this browser; nobody else sees yours.":t.group==="wired"?`${t.title} is not on this server; it opens in a new window.`:null}refresh(){const{feeds:t}=this.shell;let e=!1,n="";switch(this.site.id){case"dreams":case"dreams-api":{const r=t.dreams.value;e=r.known&&r.awake,n=r.known?r.awake?`awake · frame ${r.frame.toLocaleString("en-US")}${r.viewers?` · ${r.viewers} watching`:""}`:"asleep":"status unknown";break}case"chronicle":{const r=t.chronicle.value;e=r.known&&r.eras.some(a=>a.open),n=r.known?`${r.eraCount||r.eras.length} eras recorded`:"reading the core…";break}case"irc":{const r=t.irc.value;e=r.connected,n=r.connected?"live on #aethera":"connecting…";break}case"syrinx":{const r=t.creature.value;e=!!r,n=r?`yours: ${r.name}`:"not woken in this browser";break}default:return}this.statusLine.className=`status${e?" on":""}`,this.statusLine.innerHTML="";const i=this.statusLine.querySelector("span");i&&(i.textContent=n)}}const Cu=2;class sv{constructor(t,e,n,i){I(this,"el");I(this,"menu");I(this,"buttons");I(this,"clock");I(this,"moonEl");I(this,"start");I(this,"tip");I(this,"balloonEl");I(this,"balloonTimer",0);I(this,"dialogEl",null);this.root=t,this.shell=e,this.wm=n,this.hooks=i,this.el=G("nav",{class:"xp-taskbar","aria-label":"taskbar"}),this.start=G("button",{class:"xp-start",type:"button","aria-haspopup":"menu","aria-expanded":"false",html:`${Js(22,!1)}start`}),this.buttons=G("div",{class:"xp-taskbuttons"});const r=G("div",{class:"xp-tray"}),a=G("span",{class:"tray-icon net",title:"Connected to the Wired",html:Rx()});this.moonEl=G("span",{class:"tray-icon dream",title:"dreams",html:nu(!1)}),this.clock=G("span",{class:"clock"}),r.append(a,this.moonEl,this.clock),this.el.append(this.start,this.buttons,r),t.append(this.el),this.menu=this.buildMenu(),t.append(this.menu),this.start.addEventListener("click",()=>this.toggleMenu()),t.addEventListener("pointerdown",o=>{const l=o.target;!this.menu.hidden&&!l.closest(".xp-startmenu")&&!l.closest(".xp-start")&&!l.closest(".xp-menu")&&this.toggleMenu(!1)}),this.el.addEventListener("contextmenu",o=>{o.preventDefault(),o.stopPropagation();const l=o.target.closest(".xp-taskbtn"),c=l?this.wm.list.find(u=>u.opts.id===l.dataset.win):void 0;Ms(c?c.systemMenu():this.barMenu(),o.clientX,o.clientY)}),a.addEventListener("click",()=>this.balloon("Connected to the Wired",`${e.dir.sites.length} screens · 1 VCR · signal: present day, present time`,this.trayAnchor())),this.tip=G("div",{class:"xp-tip",role:"tooltip",hidden:""}),this.balloonEl=G("div",{class:"xp-balloon",role:"status",hidden:""}),t.append(this.tip,this.balloonEl),n.on(()=>this.renderButtons()),e.feeds.dreams.on(o=>{this.moonEl.innerHTML=nu(o.awake),this.moonEl.title=o.known?o.awake?`dreams: awake · frame ${o.frame.toLocaleString("en-US")}`:"dreams: asleep":"dreams: no answer"}),this.tick(),setInterval(()=>this.tick(),15e3)}tick(){this.clock.textContent=new Date().toLocaleTimeString([],{hour:"numeric",minute:"2-digit"})}trayAnchor(){const t=this.el.getBoundingClientRect();return{x:t.right-60,y:t.top}}toggleMenu(t){var n;const e=t??this.menu.hidden;e||pi(),this.menu.hidden=!e,this.start.classList.toggle("open",e),this.start.setAttribute("aria-expanded",String(e)),e&&((n=this.menu.querySelector("a,button"))==null||n.focus())}barMenu(){return[{label:"Toolbars",disabled:!0,submenu:()=>[]},"sep",{label:"Cascade Windows",disabled:!0},{label:"Tile Windows Horizontally",disabled:!0},{label:"Tile Windows Vertically",disabled:!0},{label:"Show the Desktop",run:()=>this.showDesktop(),disabled:!this.wm.list.some(t=>!t.minimized&&!t.opts.dialog)},"sep",{label:"Task Manager",disabled:!0},"sep",{label:"Lock the Taskbar",checked:!0,disabled:!0},{label:"Properties",disabled:!0}]}showDesktop(){for(const t of[...this.wm.list])!t.opts.dialog&&!t.minimized&&t.minimize()}buildMenu(){const t=G("div",{class:"xp-startmenu",role:"menu",hidden:""}),e=G("header");e.append(G("span",{class:"avatar",html:Js(40)}),G("span",{},["guest"])),t.append(e,G("div",{class:"orange","aria-hidden":"true"}));const n=G("div",{class:"cols"}),i=G("ul",{class:"left"}),r=G("ul",{class:"right"}),a=(S,b)=>{const R=G("li");return R.append(b),S.append(R),b},o=(S,b,R,x,T,P="")=>{const L=G("button",{type:"button",role:"menuitem",class:P,html:`${b}${x!==null?"":""}`});L.querySelector(".tt").textContent=R;const F=L.querySelector("small");return F&&x&&(F.textContent=x),L.addEventListener("click",()=>{this.toggleMenu(!1),T()}),a(S,L)},l=(S,b,R,x)=>{const T=G("a",{href:x,role:"menuitem",html:`${b}`});T.querySelector("span").textContent=R,a(S,T)},c=(S,b,R,x,T)=>{const P=G("button",{type:"button",role:"menuitem",class:`cascade ${x}`,"aria-haspopup":"menu","data-menu-owner":"",html:`${b}`});P.querySelector(".tt").textContent=R;const L=()=>{P.classList.add("open"),fu(T(),P,()=>P.classList.remove("open"))};return P.addEventListener("click",L),P.addEventListener("pointerenter",L),a(S,P)},u=S=>S.append(G("li",{class:"sep",role:"separator"}));t.addEventListener("pointerover",S=>{const b=S.target.closest("li > a, li > button");b&&!b.classList.contains("cascade")&&pi()});const h=S=>({label:S.title,icon:vn(S.accent),run:()=>{this.toggleMenu(!1),this.shell.play(S.id)}});o(i,fi(),"mIRC","#aethera",()=>this.shell.chat(),"pinned");const d=this.shell.dir.sites.filter(S=>S.group==="here");d.slice(0,Cu).forEach(S=>o(i,vn(S.accent,S.title),S.title,S.kind,()=>this.shell.play(S.id),"pinned")),u(i),d.slice(Cu).forEach(S=>o(i,vn(S.accent,S.title),S.title,null,()=>this.shell.play(S.id)));const f=G("li",{class:"allprog"});i.append(G("li",{class:"sep",role:"separator"}),f);const p=G("button",{type:"button",role:"menuitem",class:"cascade","aria-haspopup":"menu","data-menu-owner":"",html:`All Programs${Bx()}`}),v=()=>{p.classList.add("open"),fu([...this.shell.dir.sites.filter(S=>S.group==="here").map(h),"sep",...this.shell.dir.sites.filter(S=>S.group==="wired").map(h),"sep",{label:"~ (home directory)",icon:Zs(),run:()=>{this.toggleMenu(!1),this.shell.home()}}],p,()=>p.classList.remove("open"))};p.addEventListener("click",v),p.addEventListener("pointerenter",v),f.append(p),o(r,Zs(),"My Tapes",null,()=>this.shell.home(),"strong");const m=this.shell.dir.posts.slice(0,8);m.length&&c(r,vs("txt"),"My Recent Transmissions","strong",()=>m.map(S=>({label:S.title,icon:vs("txt"),run:()=>location.assign(S.href)}))),u(r);const g=this.shell.dir.sites.filter(S=>S.group==="wired");for(const S of g)o(r,vn(S.accent),S.title,null,()=>this.shell.play(S.id));u(r);for(const S of this.shell.dir.files)l(r,vs(S.title.split(".").pop()??"txt"),S.title,S.href);n.append(i,r),t.append(n);const w=G("div",{class:"foot"}),E=G("button",{type:"button",html:`${lu()}Log Off`});E.addEventListener("click",()=>{this.toggleMenu(!1),this.logOffDialog()});const M=G("button",{type:"button",html:`${ou()}Turn Off Computer`});return M.addEventListener("click",()=>{this.toggleMenu(!1),this.shutdownDialog()}),w.append(E,M),t.append(w),t}dismiss(){return this.dialogEl?(this.dialogEl.remove(),this.dialogEl=null,this.start.focus(),!0):!1}bigDialog(t,e){var l,c;(l=this.dialogEl)==null||l.remove();const n=G("div",{class:"xp-shutdown",role:"dialog","aria-modal":"true","aria-label":t});this.dialogEl=n;const i=G("div",{class:"panel"});i.append(G("header",{html:`${Js(28,!1)}`})),i.querySelector("header span").textContent=t;const r=G("div",{class:"choices"});for(const u of e){const h=G("button",{type:"button",class:u.cls,html:`${u.icon}${u.label}`}),d=u.run;d?h.addEventListener("click",()=>{n.remove(),this.dialogEl=null,d()}):h.disabled=!0,r.append(h)}i.append(r);const a=G("div",{class:"foot"}),o=G("button",{class:"xp-btn",type:"button"},["Cancel"]);o.addEventListener("click",()=>this.dismiss()),a.append(o),i.append(a),n.append(i),this.root.append(n),(c=r.querySelector("button:not(:disabled):last-of-type, button:not(:disabled)"))==null||c.focus()}logOffDialog(){this.bigDialog("Log Off æthera",[{cls:"switch",icon:cu(),label:"Switch User"},{cls:"logoff",icon:lu(),label:"Log Off",run:()=>this.hooks.logOff()}])}shutdownDialog(){var t,e;this.bigDialog("Turn off computer",[{cls:"standby",icon:kx(),label:"Stand By",run:()=>this.hooks.standby(!0)},{cls:"off",icon:ou(),label:"Turn Off",run:()=>this.hooks.turnOff()},{cls:"restart",icon:cu(),label:"Restart",run:()=>this.hooks.restart()}]),(e=(t=this.dialogEl)==null?void 0:t.querySelector(".off"))==null||e.focus()}renderButtons(){this.buttons.replaceChildren();for(const t of this.wm.list){if(t.opts.dialog)continue;const e=G("button",{class:`xp-taskbtn${this.wm.activeWindow===t&&!t.minimized?" active":""}`,type:"button","data-win":t.opts.id,html:`${t.opts.icon}`});e.querySelector("span").textContent=t.opts.title,e.title=t.opts.title,e.addEventListener("click",()=>{t.minimized?t.restore():this.wm.activeWindow===t?t.minimize():t.focus()}),this.buttons.append(e)}}showTip(t,e,n,i){const r=t?{title:t.title,text:t.tagline}:e;if(!r){this.tip.hidden=!0;return}this.tip.innerHTML="",this.tip.querySelector("b").textContent=r.title,this.tip.querySelector("span").textContent=r.text,this.tip.hidden=!1;const a=this.root.getBoundingClientRect(),o=this.tip.offsetWidth;this.tip.style.left=`${Math.min(n+14,a.width-o-6)}px`,this.tip.style.top=`${Math.min(i+20,a.height-70)}px`}balloon(t,e,n,i=7e3,r=!1){var f;const a=this.balloonEl;a.innerHTML=`${au()}`,a.querySelector("b span").textContent=t,a.querySelector(".msg").textContent=e,(f=a.querySelector(".x"))==null||f.addEventListener("click",()=>a.hidden=!0),a.hidden=!1;const o=this.root.getBoundingClientRect(),l=n??this.trayAnchor(),c=a.offsetWidth,u=a.offsetHeight,h=Math.max(6,Math.min(l.x-30,o.width-c-6)),d=r?l.y+u+24>o.height-30:l.y-u-20>0;a.classList.toggle("above",d),a.classList.toggle("below",!d),a.style.left=`${h}px`,a.style.top=`${d?l.y-u-18:l.y+18}px`,a.style.setProperty("--tail",`${Math.max(12,Math.min(c-30,l.x-h))}px`),clearTimeout(this.balloonTimer),this.balloonTimer=window.setTimeout(()=>a.hidden=!0,i)}hideBalloon(){this.balloonEl.hidden=!0}}const Ul=300,Fl=180,rv=["n","s","e","w","ne","nw","se","sw"];class av{constructor(t,e){I(this,"el");I(this,"minimized",!1);I(this,"closed",!1);var a,o,l,c,u;this.opts=t,this.wm=e;const n=document.createElement("section");n.className=`xp-window${t.dialog?" xp-dialog":""}`,n.setAttribute("role",t.dialog?"alertdialog":"dialog"),n.setAttribute("aria-label",t.title),n.innerHTML=` +`}let Wi=null,wn=null,jl=null;function ny(s){Wi=s,s.addEventListener("pointerdown",t=>{if(!wn)return;const e=t.target;e.closest(".xp-menu")||e.closest("[data-menu-owner]")||Mi()},!0)}function iy(){return wn!==null}function Mi(){if(!wn)return!1;let s=wn;for(;s;)s.el.remove(),s=s.child;wn=null;const t=jl;return jl=null,t==null||t(),!0}function ed(s,t){const e=W("div",{class:"xp-menu",role:"menu"}),n=[];for(const i of s){if(i==="sep"){e.append(W("div",{class:"xp-menu-sep",role:"separator"}));continue}const r=W("button",{type:"button",role:i.checked!==void 0?"menuitemcheckbox":"menuitem",class:`${i.bold?"bold ":""}${i.submenu?"has-sub":""}`.trim(),html:`${i.icon??""}`});r.querySelector(".lb").textContent=i.label,r.querySelector(".sc").textContent=i.shortcut??"",i.checked!==void 0&&(r.setAttribute("aria-checked",String(i.checked)),i.checked&&r.classList.add("checked")),i.disabled&&(r.setAttribute("aria-disabled","true"),r.tabIndex=-1);const o=()=>{var u;if(!i.submenu||i.disabled)return;const a=Ql(e);if(!a||((u=a.child)==null?void 0:u.el.dataset.for)===i.label)return;tc(a);const l=r.getBoundingClientRect(),c=nd(ed(i.submenu(),a),l.right-3,l.top-3,l.left+3);c.dataset.for=i.label,a.child={el:c,child:null}};r.addEventListener("pointerenter",()=>{const a=Ql(e);i.submenu?o():a&&tc(a)}),r.addEventListener("click",a=>{var l,c,u,h;if(a.stopPropagation(),!i.disabled){if(i.submenu){o(),(u=(c=(l=Ql(e))==null?void 0:l.child)==null?void 0:c.el.querySelector("button:not([aria-disabled])"))==null||u.focus();return}Mi(),(h=i.run)==null||h.call(i)}}),e.append(r),n.push(r)}return e.addEventListener("keydown",i=>{var a,l,c;const r=n.filter(u=>u.getAttribute("aria-disabled")!=="true"),o=r.indexOf(document.activeElement);if(i.key==="ArrowDown"||i.key==="ArrowUp"){i.preventDefault(),i.stopPropagation();const u=r[(o+(i.key==="ArrowDown"?1:-1)+r.length)%r.length];u==null||u.focus()}else i.key==="ArrowRight"&&((a=r[o])!=null&&a.classList.contains("has-sub"))?(i.preventDefault(),i.stopPropagation(),(l=r[o])==null||l.click()):i.key==="ArrowLeft"&&t&&(i.preventDefault(),i.stopPropagation(),tc(t),(c=t.el.querySelector("button.has-sub"))==null||c.focus())}),e}function Ql(s){let t=wn;for(;t;){if(t.el===s)return t;t=t.child}return null}function tc(s){let t=s.child;for(;t;)t.el.remove(),t=t.child;s.child=null}function nd(s,t,e,n=t){if(!Wi)throw new Error("menu host not set");s.style.left="0px",s.style.top="0px",Wi.append(s);const i=Wi.getBoundingClientRect(),r=s.offsetWidth,o=s.offsetHeight;let a=t-i.left,l=e-i.top;return a+r>i.width-2&&(a=Math.max(2,n-i.left-r)),l+o>i.height-32&&(l=Math.max(2,i.height-32-o)),s.style.left=`${Math.round(a)}px`,s.style.top=`${Math.round(l)}px`,s}function Us(s,t,e,n,i=!1){var o;Mi();const r=ed(s,null);wn={el:r,child:null},nd(r,t,e),jl=n??null,i&&((o=r.querySelector("button:not([aria-disabled])"))==null||o.focus())}function id(s,t,e){const n=t.getBoundingClientRect();if(Us(s,n.right-2,n.top-3,e),wn){const i=Wi==null?void 0:Wi.getBoundingClientRect();i&&n.right+wn.el.offsetWidth>i.right&&(wn.el.style.left=`${Math.max(2,n.left-i.left-wn.el.offsetWidth+2)}px`)}}function sy(s,t){s.addEventListener("contextmenu",e=>{const n=e.target;if(n.closest("input, textarea, [contenteditable], .oikos-tube"))return;const i=t(n,e);if(i!==null){if(e.preventDefault(),!i.length){Mi();return}Us(i,e.clientX,e.clientY)}})}function W(s,t={},e=[]){const n=document.createElement(s);for(const[i,r]of Object.entries(t))i==="html"?n.innerHTML=r:n.setAttribute(i,r);for(const i of e)n.append(i);return n}function ec(s){const t=W("div",{class:"xp-menubar",role:"menubar"});let e=null;const n=(i,r,o)=>{var c;const a=(c=s[r])==null?void 0:c.call(s);if(!a)return;const l=i.getBoundingClientRect();Us(a,l.left,l.bottom,()=>{i.classList.remove("open"),e===i&&(e=null)},o),i.classList.add("open"),e=i};for(const i of Object.keys(s)){const r=W("button",{type:"button",class:"xp-menutitle",role:"menuitem","aria-haspopup":"menu","data-menu-owner":""},[i]);r.addEventListener("click",()=>{e===r?Mi():n(r,i,!1)}),r.addEventListener("pointerenter",()=>{e&&e!==r&&iy()&&n(r,i,!1)}),r.addEventListener("keydown",o=>{(o.key==="ArrowDown"||o.key==="Enter"||o.key===" ")&&(o.preventDefault(),n(r,i,!0))}),t.append(r)}return t.append(W("span",{class:"xp-throbber",html:pr(18,!0)})),t}function sd(s){const t=W("div",{class:"xp-toolbar"}),e=(o,a,l,c=!0)=>{const u=W("button",{class:"xp-tb",type:"button",title:a,html:`${o}${c?`${a}`:""}`});return l?u.addEventListener("click",l):u.disabled=!0,t.append(u),u},n=e(X_(),"Back",s.back),i=e(q_(),"Forward",s.forward,!1);e(Y_(),"Up",s.up,!1),t.append(W("span",{class:"xp-tb-sep"})),e(K_(),"Search",s.search),e(Z_(),"Folders",s.folders);const r=()=>{if(!s.can)return;const o=s.can();n.disabled=!s.back||!o.back,i.disabled=!s.forward||!o.forward};return r(),{el:t,refresh:r}}function rd(s,t,e,n){const i=W("div",{class:"xp-address"});i.append(W("span",{class:"lbl"},["Address"]));const r=W("label",{class:"field",html:s});let o=null;e?(o=W("input",{type:"text",value:t,"aria-label":"Address",spellcheck:"false"}),o.style.cssText="flex:1;min-width:0;border:0;outline:0;font:inherit;background:transparent;",r.append(o),o.addEventListener("keydown",l=>{l.key==="Enter"&&o&&(n==null||n(o.value)),l.stopPropagation()})):r.append(W("span",{},[t])),i.append(r);const a=W("button",{class:"go",type:"button",html:`${J_()}Go`});return a.addEventListener("click",()=>n==null?void 0:n((o==null?void 0:o.value)??t)),i.append(a),{el:i,input:o}}function Fs(s,t,e=!1){const n=W("section",{class:`xp-taskgroup${e?" primary":""}`}),i=W("header",{role:"button",tabindex:"0","aria-expanded":"true"},[s]),r=()=>{n.classList.toggle("collapsed"),i.setAttribute("aria-expanded",String(!n.classList.contains("collapsed")))};i.addEventListener("click",r),i.addEventListener("keydown",a=>{(a.key==="Enter"||a.key===" ")&&(a.preventDefault(),r())}),n.append(i);const o=W("div",{class:"xp-taskbody"});if(t instanceof HTMLElement)o.append(t);else{const a=W("ul");for(const l of t){const c=W("li");let u;if(l.href)u=W("a",{class:"xp-link",href:l.href,html:`${l.icon}`}),l.external&&(u.setAttribute("target","_blank"),u.setAttribute("rel","noopener"));else{u=W("button",{class:"xp-link",type:"button",html:`${l.icon}`});const d=l.run;d?u.addEventListener("click",d):u.setAttribute("aria-disabled","true")}const h=u.querySelector("span");h&&(h.textContent=l.label),c.append(u),a.append(c)}o.append(a)}return n.append(o),n}function od(){const s=W("div",{class:"xp-statusbar",role:"status"}),t=W("span"),e=W("span",{class:"zone"});return s.append(t,e),{el:s,set(n,i){t.textContent=n;const[r,o]=i==="computer"?[Wu(),"My Computer"]:[$u(),"Internet"];e.innerHTML=`${r}${o}`}}}const ry={dreams:["chronicle","dreams-api","dream_gen"],chronicle:["dreams","dream_gen"],"dreams-api":["dreams","chronicle"],dream_gen:["dreams","chronicle"],transmissions:["irc","syrinx"],apeiron:["dreams","syrinx"],syrinx:["apeiron","afterlife"],afterlife:["syrinx","apeiron"],irc:["transmissions","parlor"],parlor:["irc","transmissions"]};function ad(s){return/^https?:/.test(s.href)?s.href:`${location.origin}${s.href}`}function ld(s){return s.group==="here"?"computer":"internet"}function nc(s,t){var i;const e=ad(t),n=(i=navigator.clipboard)==null?void 0:i.writeText(e);if(!n){s.balloon("Could not copy",e);return}n.then(()=>s.balloon("Copied",e),()=>s.balloon("Could not copy",e))}function wo(s,t,e=!1){const n=[];return e?n.push({label:`Open ${t.title}`,bold:!0,run:()=>s.open(t)}):(n.push({label:"Play",bold:!0,run:()=>s.play(t.id)}),n.push({label:`Go to ${t.title}`,run:()=>s.open(t)})),n.push({label:"Look at its screen",run:()=>s.look(t.id),disabled:!s.canTune}),t.tune&&n.push({label:"Watch it here",run:()=>s.tuneIn(t.id),disabled:!s.canTune}),t.id==="irc"&&n.push({label:"Join in mIRC",run:()=>s.chat("#aethera")}),n.push("sep",{label:"Copy Address",run:()=>nc(s,t)}),e||n.push("sep",{label:"Properties",run:()=>s.play(t.id)}),n}function cd(s,t){return[{label:"Undo",shortcut:"Ctrl+Z",disabled:!0},"sep",{label:"Cut",shortcut:"Ctrl+X",disabled:!0},{label:"Copy",shortcut:"Ctrl+C",disabled:!t,run:()=>t&&nc(s,t)},{label:"Paste",shortcut:"Ctrl+V",disabled:!0},"sep",{label:"Select All",shortcut:"Ctrl+A",disabled:!0},{label:"Invert Selection",disabled:!0}]}function hd(s){return[{label:"Add to Favorites...",disabled:!0},{label:"Organize Favorites...",disabled:!0},"sep",...s.dir.sites.filter(t=>t.group==="here").map(t=>({label:t.title,icon:Sn(t.accent),run:()=>s.play(t.id)}))]}function ud(){return[{label:"Map Network Drive...",disabled:!0},{label:"Disconnect Network Drive...",disabled:!0},{label:"Synchronize...",disabled:!0},"sep",{label:"Folder Options...",disabled:!0}]}function dd(s){return[{label:"Help and Support Center",disabled:!0},"sep",{label:"About æthera",run:()=>s.about()}]}function ic(s){s.hidden=!s.hidden}function fd(s,t){return[{label:"Toolbars",submenu:()=>[{label:"Standard Buttons",checked:!t.toolbar.hidden,run:()=>ic(t.toolbar)},{label:"Address Bar",checked:!t.address.hidden,run:()=>ic(t.address)}]},{label:"Status Bar",checked:!t.status.hidden,run:()=>ic(t.status)},...t.views?["sep",...t.views]:[],"sep",{label:"Go To",submenu:()=>[{label:"Back",shortcut:"Alt+Left",disabled:!s.canBack,run:()=>s.back()},{label:"Forward",shortcut:"Alt+Right",disabled:!s.canForward,run:()=>s.forward()},{label:"Up One Level",disabled:!t.up,run:()=>{var e;return(e=t.up)==null?void 0:e.call(t)}},"sep",{label:"Home Page",shortcut:"Alt+Home",run:()=>s.home()}]},{label:"Refresh",shortcut:"F5",run:()=>t.refresh()}]}class oy{constructor(t,e){R(this,"win",null);R(this,"selected",null);R(this,"tiles",new Map);R(this,"tasks",null);R(this,"status",null);R(this,"content",null);R(this,"view","tiles");this.shell=t,this.wm=e}get isOpen(){return!!this.win&&!this.win.closed}open(){var u;if(this.isOpen&&this.win){this.win.minimized?this.win.restore():this.win.focus();return}this.tiles.clear();const t=W("div");t.style.cssText="display:flex;flex-direction:column;min-height:0;flex:1;";const{dir:e}=this.shell,n=sd({back:()=>this.shell.back(),forward:()=>this.shell.forward(),can:()=>({back:this.shell.canBack,forward:this.shell.canForward}),search:()=>{var h;return(h=i.input)==null?void 0:h.focus()},folders:()=>{var h;return(h=this.tasks)==null?void 0:h.toggleAttribute("hidden")}}),i=rd(fr(),"~/æthera",!0,h=>this.go(h));(u=i.input)==null||u.addEventListener("input",()=>{var h;return this.filter(((h=i.input)==null?void 0:h.value)??"")}),this.status=od();const r=()=>this.selected?this.shell.site(this.selected)??null:null;t.append(ec({File:()=>this.fileMenu(),Edit:()=>cd(this.shell,r()),View:()=>{var h;return fd(this.shell,{toolbar:n.el,address:i.el,status:((h=this.status)==null?void 0:h.el)??W("div"),views:this.viewItems(),refresh:()=>{i.input&&(i.input.value="~/æthera"),this.filter("")}})},Favorites:()=>hd(this.shell),Tools:()=>ud(),Help:()=>dd(this.shell)}),n.el,i.el);const o=this.shell.onNav(()=>n.refresh()),a=W("div",{class:"xp-body"});this.tasks=W("aside",{class:"xp-tasks"}),a.append(this.tasks);const l=W("div",{class:`xp-content view-${this.view}`,role:"listbox","aria-label":"tapes"});this.content=l,l.addEventListener("pointerdown",h=>{h.button===0&&!h.target.closest(".xp-tile")&&this.select(null)});const c=(h,d)=>{if(!d.length)return;l.append(W("h3",{class:"xp-group-head"},[h]));const f=W("div",{class:"xp-tiles"});for(const p of d)f.append(this.tile(p));l.append(f)};if(c("Tapes Stored on This Server",e.sites.filter(h=>h.group==="here")),c("Other Places on the Wired",e.sites.filter(h=>h.group==="wired")),e.files.length){l.append(W("h3",{class:"xp-group-head"},["Files"]));const h=W("div",{class:"xp-tiles"});for(const d of e.files){const f=d.title.split(".").pop()??"txt",p=W("a",{class:"xp-tile",href:d.href,html:`${Ns(f)}`});p.querySelector(".t").textContent=d.title,p.querySelector(".k").textContent=d.about,h.append(p)}l.append(h)}a.append(l),t.append(a),t.append(this.status.el),this.win=this.wm.open({id:"home",title:"~ (home directory)",icon:fr(),body:t,width:Math.round(Math.min(680,Math.max(420,innerWidth*.46))),dock:"left",onClose:()=>{o(),this.win=null,this.content=null,this.selected=null}}),this.win.el.style.height="min(560px, calc(100% - 40px))",this.renderTasks(),this.renderStatus()}close(){var t;(t=this.win)==null||t.close()}fileMenu(){const t=this.selected?this.shell.site(this.selected):void 0;return[...t?wo(this.shell,t):[{label:"Play",bold:!0,disabled:!0}],"sep",{label:"New",disabled:!0,submenu:()=>[]},"sep",{label:"Create Shortcut",disabled:!0},{label:"Delete",disabled:!0},{label:"Rename",disabled:!0},"sep",{label:"Close",run:()=>this.close()}]}viewItems(){const t=e=>()=>{this.view=e,this.content&&(this.content.className=`xp-content view-${e}`)};return[{label:"Tiles",checked:this.view==="tiles",run:t("tiles")},{label:"Icons",checked:this.view==="icons",run:t("icons")},{label:"List",checked:this.view==="list",run:t("list")}]}contextFor(t){const e=this.shell.site(t);return e?(this.select(t,!0),wo(this.shell,e)):null}blankMenu(){return[{label:"View",submenu:()=>this.viewItems()},{label:"Arrange Icons By",disabled:!0,submenu:()=>[]},"sep",{label:"Refresh",run:()=>this.filter("")},"sep",{label:"Paste",disabled:!0},{label:"Paste Shortcut",disabled:!0},"sep",{label:"New",disabled:!0,submenu:()=>[]},"sep",{label:"Properties",disabled:!0}]}tile(t){const e=W("button",{class:"xp-tile",type:"button",role:"option","data-id":t.id,html:`${Sn(t.accent,t.title)}`});return e.querySelector(".t").textContent=t.title,e.querySelector(".k").textContent=t.kind,e.querySelector(".d").textContent=t.tagline,e.title=t.tagline,e.addEventListener("click",()=>this.select(t.id,!0)),e.addEventListener("dblclick",()=>this.shell.play(t.id)),e.addEventListener("keydown",n=>{if(n.key==="Enter"&&this.shell.play(t.id),["ArrowRight","ArrowDown","ArrowLeft","ArrowUp"].includes(n.key)){n.preventDefault(),n.stopPropagation();const i=[...this.tiles.values()].filter(a=>!a.hidden),r=i.indexOf(e),o=i[(r+(n.key==="ArrowRight"||n.key==="ArrowDown"?1:-1)+i.length)%i.length];o==null||o.focus(),o!=null&&o.dataset.id&&this.select(o.dataset.id,!0)}}),e.addEventListener("pointerup",n=>{n.pointerType==="touch"&&this.selected===t.id&&e.dataset.armed&&this.shell.play(t.id),e.dataset.armed="1"}),this.tiles.set(t.id,e),e}select(t,e=!1){if(t!==this.selected){this.selected=t;for(const[n,i]of this.tiles)i.classList.toggle("selected",n===t),i.setAttribute("aria-selected",String(n===t)),n!==t&&delete i.dataset.armed;e&&this.shell.select(t),this.renderTasks(),this.renderStatus()}}filter(t){const e=t.replace(/^~\/?(æthera)?\/?/i,"").trim().toLowerCase();for(const[n,i]of this.tiles){const r=this.shell.site(n);i.hidden=!!e&&!`${r==null?void 0:r.title} ${r==null?void 0:r.kind} ${r==null?void 0:r.tagline}`.toLowerCase().includes(e)}}go(t){const e=t.replace(/^~\/?(æthera)?\/?/i,"").trim().toLowerCase();if(!e)return;const n=this.shell.dir.sites.find(i=>i.title.toLowerCase()===e)??this.shell.dir.sites.find(i=>`${i.title} ${i.kind} ${i.tagline}`.toLowerCase().includes(e));n?this.shell.play(n.id):this.shell.balloon("Cannot find it",`There is no tape called “${t}” in ~.`)}renderTasks(){if(!this.tasks)return;const t=this.selected?this.shell.site(this.selected):void 0,e=t?[{icon:Jl(),label:"Play this tape",run:()=>this.shell.play(t.id)},{icon:Yu(),label:"Look at its screen",run:()=>this.shell.look(t.id)},{icon:$u(),label:`Go to ${t.title}`,run:()=>this.shell.open(t)}]:[{icon:Jl(),label:"Select a tape to play it"},{icon:Ku(),label:"Eject the tape",run:()=>this.shell.eject()}],n=[{icon:Wu(),label:"æthera",href:"/"},{icon:Ns("xml"),label:"feed.xml",href:"/feed.xml"},{icon:Ns("txt"),label:"llms.txt",href:"/llms.txt"}],i=W("div",{class:"xp-details"});if(t){i.append(W("b",{},[t.title]));const r=W("dl");for(const[o,a]of t.details)r.append(W("dt",{},[o]),W("dd",{},[a]));i.append(r)}else{const r=this.shell.dir.sites.filter(o=>o.group==="here").length;i.append(W("b",{},["~"]),W("span",{},[`home directory · ${r} tapes here, ${this.shell.dir.sites.length-r} elsewhere on the Wired`]))}this.tasks.replaceChildren(Fs(t?"Tape Tasks":"System Tasks",e,!0),Fs("Other Places",n),Fs("Details",i))}renderStatus(){var n;const t=this.selected?this.shell.site(this.selected):void 0,e=this.shell.dir.sites.length+this.shell.dir.files.length;(n=this.status)==null||n.set(t?`${t.title} — ${t.tagline}`:`${e} objects`,t?ld(t):"computer")}}const ay=4001,ly=4002,cy=s=>s>=4e3&&s<5e3,hy=4;class uy{constructor(t,e,n){R(this,"ws",null);R(this,"tries",0);R(this,"timer",0);R(this,"wanted",!1);R(this,"welcomed",!1);R(this,"refused",!1);this.nick=t,this.password=e,this.on=n}get open(){var t;return this.welcomed&&((t=this.ws)==null?void 0:t.readyState)===WebSocket.OPEN}connect(){this.wanted=!0,this.refused=!1,clearTimeout(this.timer);const t=location.protocol==="https:"?"wss":"ws";let e;try{e=new WebSocket(`${t}://${location.host}/ws/chat`)}catch{this.on.closed(!1,!1,!1);return}this.ws=e,this.welcomed=!1,e.onopen=()=>{e.send(JSON.stringify({type:"hello",nick:this.nick,password:this.password||null}))},e.onmessage=n=>{let i;try{i=JSON.parse(String(n.data))}catch{return}switch(i.type){case"welcome":{const r=i;this.welcomed=!0,this.tries=0,this.nick=r.nick,this.on.welcome(r);break}case"event":{const r=i.event;if(!r)break;r.kind==="nick"&&r.nick===this.nick&&r.target&&(this.nick=r.target),this.on.event(r);break}case"whois":this.on.whois(i);break;case"error":{this.welcomed||(this.refused=!0),this.on.error(String(i.code??""),String(i.text??""));break}}},e.onclose=n=>{if(this.ws!==e)return;this.ws=null;const i=n.code===ay,r=n.code===ly,o=this.wanted&&!cy(n.code)&&!this.refused&&this.triesthis.connect(),2e3*2**(this.tries-1))}}send(t){if(!this.open||!this.ws)return!1;try{return this.ws.send(JSON.stringify(t)),!0}catch{return!1}}part(t="Leaving"){if(this.open&&this.ws)try{this.ws.send(JSON.stringify({type:"part",reason:t}))}catch{}this.close()}close(){this.wanted=!1,clearTimeout(this.timer);const t=this.ws;if(this.ws=null,this.welcomed=!1,this.password=null,t){t.onclose=null;try{t.close()}catch{}}}}const kt="#aethera",Pt="#oikos",Un="irc.aetherawi.red",sc=6667,rc="guest",pd="always falling apart",dy=600,fy=6e3,md="oikos-mirc-nick",py=/^[A-Za-z[\]\\`_^{|}][A-Za-z0-9[\]\\`_^{|}-]{0,15}$/,oc=["~","&","@","%","+"];function my(s){const t=new Date(s);return`[${String(t.getHours()).padStart(2,"0")}:${String(t.getMinutes()).padStart(2,"0")}]`}function gy(s){return Date.now()-(performance.now()-s)}function ac(s){const t=jn(s)||"anon",e=Bo(t),n=["dialup.wired.net","cable.aether.org","dsl.lain.jp","adsl.nowhere.nu","res.navi.co"],i=n[Math.floor(e*n.length)]??n[0],r=Math.floor(e*251)+2,o=Math.floor(Bo(`${t}.`)*251)+2;return`~${t.slice(0,9).toLowerCase()}@ppp-${r}-${o}.${i}`}function jn(s){return s.replace(/^[~&@%+]+/,"")}function gd(s){const t=s.charAt(0);return oc.includes(t)?t:""}function xy(){try{return localStorage.getItem(md)??""}catch{return""}}function xd(s){try{localStorage.setItem(md,s)}catch{}}function lc(s){s.addEventListener("keydown",t=>{t.key!=="Escape"&&t.stopPropagation()})}class cc{constructor(t,e,n){R(this,"tab");R(this,"pane");R(this,"log");R(this,"nicksEl");R(this,"nicks",new Map);R(this,"topic","");R(this,"joined",!1);this.id=t;const i=`mirc-pane-${t==="status"?"status":t.slice(1)}`;this.tab=W("button",{type:"button",role:"tab","aria-controls":i,html:`${e}`}),this.tab.querySelector("span").textContent=t==="status"?"Status":t,this.log=W("div",{class:"mirc-log",role:"log","aria-label":t==="status"?"Status":t}),n?(this.log.setAttribute("aria-live","polite"),this.nicksEl=W("ul",{class:"mirc-nicks","aria-label":`Nicknames in ${t}`}),this.pane=W("div",{class:"mirc-pane",id:i,role:"tabpanel"},[W("div",{class:"mirc-split"},[this.log,this.nicksEl])])):(this.nicksEl=null,this.pane=W("div",{class:"mirc-pane",id:i,role:"tabpanel"},[this.log]))}setNick(t,e=gd(t)){const n=jn(t);n&&this.nicks.set(n.toLowerCase(),{name:n,mode:e})}seen(t){const e=jn(t);if(!e)return!1;const n=e.toLowerCase(),i=this.nicks.get(n),r=gd(t)||(i==null?void 0:i.mode)||"";return i&&i.mode===r&&i.name===e?!1:(this.nicks.set(n,{name:e,mode:r}),!0)}drop(t){return this.nicks.delete(jn(t).toLowerCase())}rename(t,e){const n=this.nicks.get(jn(t).toLowerCase());this.drop(t),this.setNick(e,(n==null?void 0:n.mode)??"")}render(){if(!this.nicksEl)return;const t=n=>n?oc.indexOf(n):oc.length,e=[...this.nicks.values()].sort((n,i)=>t(n.mode)-t(i.mode)||n.name.localeCompare(i.name,void 0,{sensitivity:"base"}));this.nicksEl.replaceChildren(...e.map(n=>W("li",{title:`${n.mode}${n.name}`},[`${n.mode}${n.name}`])))}}class vy{constructor(t,e,n){R(this,"win");R(this,"wins");R(this,"view",kt);R(this,"input");R(this,"me",rc);R(this,"link",null);R(this,"hintedOikos",!1);R(this,"livingSeenAt",0);R(this,"livingOnce",!1);R(this,"greeted",!1);R(this,"hung",!1);R(this,"lastAt",-1);R(this,"seenFragments");R(this,"seenCollapse",null);R(this,"wasConnected",!1);R(this,"rejoinTimer",0);R(this,"off");var c;this.shell=t,this.wm=e;const i=W("div",{class:"mirc"});i.append(ec({File:()=>[{label:"Connect...",run:()=>this.joinLiving(),disabled:!!this.link},{label:"Disconnect",run:()=>this.partLiving(),disabled:!this.link},"sep",{label:"Select Server...",disabled:!0},"sep",{label:"Exit",run:()=>this.win.close()}],Tools:()=>[{label:"Address Book...",disabled:!0},{label:"Options...",shortcut:"Alt+O",disabled:!0}],Commands:()=>[{label:`Join ${Pt}`,run:()=>this.joinLiving()},{label:`Part ${Pt}`,run:()=>this.partLiving(),disabled:!this.link},"sep",{label:"Clear buffer",run:()=>this.wins[this.view].log.replaceChildren()}],Window:()=>["status",kt,Pt].filter(u=>!this.wins[u].tab.hidden).map(u=>({label:u==="status"?"Status":u,checked:this.view===u,run:()=>this.show(u)})),Help:()=>[{label:"Commands",shortcut:"F1",run:()=>this.help()},"sep",{label:"About æthera",run:()=>this.shell.about()}]}));const r=W("div",{class:"mirc-switch",role:"tablist"});this.wins={status:new cc("status",yi("status"),!1),[kt]:new cc(kt,yi("channel"),!0),[Pt]:new cc(Pt,yi("channel"),!0)},this.wins[kt].topic=pd,this.wins[Pt].tab.hidden=!0;const o=W("div",{class:"mirc-mdi"});for(const u of Object.values(this.wins))u.tab.addEventListener("click",()=>this.show(u.id)),r.append(u.tab),o.append(u.pane);this.input=W("input",{class:"mirc-input",type:"text",spellcheck:"false",autocomplete:"off",maxlength:"400","aria-label":"Message"}),lc(this.input),this.input.addEventListener("keydown",u=>{if(u.key!=="Enter")return;u.preventDefault();const h=this.input.value;this.input.value="",this.say(h)}),i.append(r,o,this.input),this.win=e.open({id:"mirc",title:"mIRC",icon:yi("app"),body:i,width:Math.round(Math.min(760,Math.max(460,innerWidth*.52))),dock:"center",onClose:()=>{var u,h;clearTimeout(this.rejoinTimer),this.off(),(u=this.link)==null||u.part("Leaving"),this.link=null,(h=this.wm.get("mirc-connect"))==null||h.close(),n()},onFocus:()=>{innerWidth>720&&this.input.focus({preventScroll:!0})}}),this.win.el.classList.add("mirc-window"),this.win.el.style.height="min(540px, calc(100% - 24px))";const a=this.win.el.parentElement;if(a){const u=this.win.el.offsetTop+this.win.el.offsetHeight-(a.clientHeight-8);u>0&&this.win.moveTo(this.win.el.offsetLeft,this.win.el.offsetTop-u)}const l=this.shell.feeds.irc.value;this.seenFragments=l.fragments,this.seenCollapse=((c=l.collapse)==null?void 0:c.at)??null,this.show(kt),l.connected?this.connect(l):this.push("status","info",`* Connecting to ${Un} (${sc})`),this.off=this.shell.feeds.irc.on(u=>this.update(u))}focus(t){this.win.minimized?this.win.restore():this.win.focus();const e=t===kt||t===Pt||t==="status"?this.wins[t]:null;e&&!e.tab.hidden&&this.show(e.id)}update(t){var n;if(t.connected&&!this.wasConnected?this.connect(t):!t.connected&&this.wasConnected&&this.disconnect(),!t.connected)return;for(const i of t.lines)i.at<=this.lastAt||(this.rejoinTimer&&this.rejoin(),this.lastAt=i.at,this.line(i));const e=((n=t.collapse)==null?void 0:n.at)??null;e!==null&&e!==this.seenCollapse&&t.collapse&&this.collapse(t.collapse.type),this.seenCollapse=e,t.fragments!==this.seenFragments&&(this.seenFragments=t.fragments,clearTimeout(this.rejoinTimer),this.hung?this.rejoinTimer=window.setTimeout(()=>this.rejoin(),fy):this.rejoin())}connect(t){this.wasConnected=!0;const e=(i,r)=>this.push("status",i,r);if(this.greeted){e("info",`* Reconnected to ${Un}`),this.joinHaunted(),t.collapse&&this.collapse(t.collapse.type);return}this.greeted=!0,e("info",`* Connecting to ${Un} (${sc})`),e("notice",`-${Un}- *** Looking up your hostname...`),e("notice",`-${Un}- *** Found your hostname`),e("text",`Welcome to the æthera IRC Network ${this.me}!${this.me}@oikos`),e("text",`Your host is ${Un}, running version hauntd-2.8.21`),e("text",`- ${Un} Message of the Day -`),e("text","- nobody here is who they were."),e("text","- every line is a replay; every replay is live."),e("text",`- ${kt} is moderated: the living listen.`),e("text",`- the living talk in ${Pt}. /join ${Pt}`),e("text","End of /MOTD command."),e("mode",`* ${this.me} sets mode: +i`),this.joinHaunted();const n=t.lines.filter(i=>i.at>this.lastAt);if(n.length){this.push(kt,"info","*** Buffer Playback...");for(const i of n)this.line(i);this.push(kt,"info","*** Playback Complete.")}this.lastAt=Math.max(this.lastAt,...t.lines.map(i=>i.at)),t.collapse&&this.collapse(t.collapse.type)}joinHaunted(){const t=this.wins[kt];t.joined=!0,t.nicks.clear(),t.setNick(this.me,""),this.push(kt,"join",`* Now talking in ${kt}`),this.push(kt,"topic",`* Topic is '${t.topic}'`),this.push(kt,"topic","* Set by ChanServ"),this.nicksChanged(kt)}disconnect(){clearTimeout(this.rejoinTimer),this.rejoinTimer=0,this.wasConnected=!1;const t=this.wins[kt];t.joined=!1,this.setHung(!1),this.push("status","info",`* Disconnected from ${kt}`),this.push(kt,"info","* Disconnected"),t.nicks.clear(),this.nicksChanged(kt)}collapse(t){const e=t.replace(/_/g," ");this.push("status","notice",`-${Un}- *** Notice -- ${e} on ${kt}`),this.setHung(!0)}rejoin(){clearTimeout(this.rejoinTimer),this.rejoinTimer=0,this.setHung(!1),this.push(kt,"info",`* Attempting to rejoin channel ${kt}`),this.wins[kt].topic=pd,this.joinHaunted()}line(t){const e=this.wins[kt],n=t.nick,i=jn(n),r=t.content,o=t.wallAt??gy(t.at),a=(c,u)=>this.push(kt,c,u,o);let l=!1;switch(t.type){case"message":l=e.seen(n),a("text",`<${n}> ${r}`);break;case"action":{const c=/^sets mode: ([+-])([a-z]+) (.+)$/i.exec(r);c?(e.seen(n),this.applyMode(c[1]??"+",c[2]??"",(c[3]??"").split(/\s+/)),l=!0,a("mode",`* ${n} ${r}`)):/^has quit\b/i.test(r)?(l=e.drop(n),a("quit",`* ${i} ${r.replace(/^has quit\b/i,"has quit IRC")}`)):(l=e.seen(n),a("action",`* ${n} ${r}`));break}case"join":l=e.seen(n),a("join",`* ${i} (${ac(n)}) has joined ${kt}`);break;case"part":l=e.drop(n),a("part",`* ${i} (${ac(n)}) has left ${kt}${r?` (${r})`:""}`);break;case"quit":l=e.drop(n),a("quit",`* ${i} (${ac(n)}) Quit (${r||"Client exited"})`);break;case"kick":{const c=t.reason||r;t.target?(l=e.drop(t.target),a("kick",`* ${jn(t.target)} was kicked by ${i}${c?` (${c})`:""}`)):a("kick",`* ${i} kicks${c?` (${c})`:""}`);break}default:{const c=/changes topic to '(.*)'$/i.exec(r);if(c){e.topic=c[1]??e.topic,a("topic",`* ${r}`),this.retitle();break}const u=r||n;a("info",/^[*<]/.test(u)||u.length<6?u:`* ${u}`)}}!e.nicks.has(this.me.toLowerCase())&&e.joined&&(e.setNick(this.me,""),l=!0),l&&this.nicksChanged(kt)}applyMode(t,e,n){const i=this.wins[kt],r={q:"~",a:"&",o:"@",h:"%",v:"+"};[...e].forEach((o,a)=>{const l=n[a],c=r[o];if(!l||!c)return;const u=i.nicks.get(jn(l).toLowerCase());i.setNick((u==null?void 0:u.name)??jn(l),t==="+"?c:(u==null?void 0:u.mode)===c?"":(u==null?void 0:u.mode)??"")})}joinLiving(){if(this.link&&this.wins[Pt].joined){this.show(Pt);return}if(this.link){this.push(this.view,"info",`* Still connecting to ${Pt}...`);return}this.connectDialog()}partLiving(){if(!this.link)return;this.link.part("Leaving"),this.link=null;const t=this.wins[Pt];t.joined=!1,t.nicks.clear(),this.nicksChanged(Pt),this.push(Pt,"part",`* You have left ${Pt}`),this.push("status","info",`* Disconnected from ${Pt}`),this.livingSeenAt=0,this.livingOnce=!1,this.renameMe(rc)}connectDialog(t){var u;(u=this.wm.get("mirc-connect"))==null||u.close();const e=W("form",{class:"mirc-connect"}),n=W("input",{type:"text",value:xy(),maxlength:"16",spellcheck:"false",autocomplete:"nickname",required:""}),i=W("input",{type:"password",maxlength:"256",autocomplete:"current-password"});lc(n),lc(i);const r=W("p",{class:"err",role:"alert"});r.textContent=t??"",r.hidden=!t,e.append(W("div",{class:"xp-dialog-body"},[W("span",{html:yi("app")}),W("div",{},[W("p",{},[`Join ${Pt}, where the living talk.`]),W("label",{},["Nickname:",n]),W("label",{},["Password (optional):",i]),W("p",{class:"hint"},["A password gives you a tripcode, the same one your blog comments carry. It is never stored."]),r])]));const o=W("div",{class:"xp-actions"}),a=W("button",{class:"xp-btn default",type:"submit"},["Connect"]),l=W("button",{class:"xp-btn",type:"button"},["Cancel"]);o.append(a,l),e.append(o);const c=this.wm.open({id:"mirc-connect",title:"mIRC Connect",icon:yi("app"),body:e,width:360,dialog:!0});l.addEventListener("click",()=>c.close()),e.addEventListener("keydown",h=>{h.key==="Escape"&&(h.preventDefault(),c.close(),this.input.focus({preventScroll:!0}))}),e.addEventListener("submit",h=>{h.preventDefault();const d=n.value.trim();if(!py.test(d)){r.textContent="A nickname starts with a letter and has at most 16 letters, digits or - _ [ ] { } | ^ `",r.hidden=!1,n.focus();return}xd(d),c.close(),this.dial(d,i.value||null)}),n.focus(),n.select()}dial(t,e){this.push("status","info",`* Connecting to ${Pt} as ${t}${e?" (with a tripcode)":""}`);const n=new uy(t,e,{welcome:i=>this.welcomed(i),event:i=>this.event(i),whois:i=>this.whoisReply(i),error:(i,r)=>this.chatError(i,r),closed:(i,r,o)=>this.dropped(i,r,o)});this.link=n,n.connect()}welcomed(t){const e=this.wins[Pt];e.tab.hidden=!1,e.joined=!0,e.topic=t.topic,e.nicks.clear();for(const r of t.names)e.setNick(r.nick,r.op?"@":"");this.renameMe(t.nick);const n=this.livingOnce;this.livingOnce=!0;const i=t.backlog.filter(r=>r.at>this.livingSeenAt);if(n?this.push(Pt,"join",`* Rejoined ${Pt}`):(this.push("status","text",`* You are now known as ${t.nick} (${t.mask})`),t.op&&this.push("status","mode",`* ${Un} sets mode: +o ${t.nick}`),this.push(Pt,"join",`* Now talking in ${Pt}`),this.push(Pt,"topic",`* Topic is '${t.topic}'`)),i.length){this.push(Pt,"info","*** Buffer Playback...");for(const r of i)this.event(r,!0);this.push(Pt,"info","*** Playback Complete.")}this.nicksChanged(Pt),n||this.show(Pt)}event(t,e=!1){const n=this.wins[Pt],i=(o,a)=>this.push(Pt,o,a,t.at),r=t.nick===this.me;switch(this.livingSeenAt=Math.max(this.livingSeenAt,t.at),t.kind){case"message":i(r?"own":"text",`<${t.nick}> ${t.text}`);return;case"action":i("action",`* ${t.nick} ${t.text}`);return;case"join":i("join",`* ${t.nick} (${t.mask??""}) has joined ${Pt}`),e||n.setNick(t.nick,"");break;case"part":i("part",`* ${t.nick} (${t.mask??""}) has left ${Pt}${t.text?` (${t.text})`:""}`),e||n.drop(t.nick);break;case"quit":i("quit",`* ${t.nick} (${t.mask??""}) Quit (${t.text||"Client exited"})`),e||n.drop(t.nick);break;case"kick":t.target===this.me&&!e?(i("kick",`* You were kicked from ${Pt} by ${t.nick} (${t.text})`),n.joined=!1,n.nicks.clear()):(i("kick",`* ${t.target??"?"} was kicked by ${t.nick} (${t.text})`),!e&&t.target&&n.drop(t.target));break;case"nick":r&&!e&&t.target?(i("text",`* Your nick is now ${t.target}`),this.renameMe(t.target),xd(t.target)):i("text",`* ${t.nick} is now known as ${t.target??"?"}`),!e&&t.target&&n.rename(t.nick,t.target);break;case"topic":i("topic",`* ${t.nick} changes topic to '${t.text}'`),e||(n.topic=t.text);break}e||this.nicksChanged(Pt)}whoisReply(t){const e=n=>this.push(this.view,"text",n);e(`${t.nick} is ${t.mask} * ${t.nick}`),t.trip&&e(`${t.nick} is identified by tripcode ${t.trip}`),t.op&&e(`${t.nick} is a channel operator on ${Pt}`),e(`${t.nick} signed on ${new Date(t.signon).toLocaleString()}`),e(`${t.nick} End of /WHOIS list.`)}chatError(t,e){var r;const n=this.wins[Pt],i=e.replace(/^(\S+) :/,"$1 ");this.push(n.joined?Pt:"status","error",`* ${i}`),!n.joined&&(t==="432"||t==="433")&&((r=this.link)==null||r.close(),this.link=null,this.livingOnce=!1,this.livingSeenAt=0,this.connectDialog(e.replace(/^\S+ :/,"")))}dropped(t,e,n){const i=this.wins[Pt],r=i.joined;i.joined=!1,i.nicks.clear(),this.nicksChanged(Pt),n?this.push(Pt,"info",`* ${this.me} is connected from somewhere else now (another window?); this one let go`):r&&!e&&this.push(Pt,"info",`* Disconnected${t?" (reconnecting...)":""}`),this.push("status","info",`* Disconnected from ${Pt}${t?" (reconnecting...)":""}`),t||(this.link=null,this.livingOnce=!1,this.livingSeenAt=0,this.renameMe(rc))}renameMe(t){if(t===this.me)return;const e=this.wins[kt];e.joined&&(e.rename(this.me,t),this.nicksChanged(kt)),this.me=t,this.retitle()}say(t){var a,l,c,u,h,d;const e=t.trim();if(!e)return;const n=this.view,i=n===Pt&&this.wins[Pt].joined&&!!this.link,r=f=>this.push(n,"error",`* ${f}`);if(e.startsWith("/")&&!e.startsWith("//")){const[f="",...p]=e.slice(1).split(/\s+/),x=p.join(" ");switch(f.toLowerCase()){case"help":this.help();return;case"clear":this.wins[n].log.replaceChildren();return;case"quit":case"exit":this.win.close();return;case"join":{const m=(p[0]??"").toLowerCase().replace(/^#?/,"#");m===Pt||m==="#"&&n==="status"?this.joinLiving():m===kt?(this.show(kt),this.push(kt,"error",`* You are already on ${kt}`)):r(`${p[0]??"#"} Cannot join channel (this network has ${kt} and ${Pt})`);return}case"part":case"leave":n===Pt&&this.link?this.partLiving():r(n===kt?`${kt} will not let you go`:"You are not on a channel");return;case"nick":p[0]?(a=this.link)!=null&&a.send({type:"nick",nick:p[0]})||r(`Join ${Pt} first to have a name (/join ${Pt})`):r("Usage: /nick ");return;case"whois":p[0]?(l=this.link)!=null&&l.send({type:"whois",nick:p[0]})||r(`${p[0]} :No such nick`):r("Usage: /whois ");return;case"me":if(!x)return;i?(c=this.link)==null||c.send({type:"say",text:x,action:!0}):n===kt?this.refused(`* ${this.me} ${x}`,"action"):r("You are not on a channel");return;case"topic":i&&x?(u=this.link)==null||u.send({type:"topic",text:x}):i?this.push(Pt,"topic",`* Topic is '${this.wins[Pt].topic}'`):r(`${n==="status"?"":`${n} `}You're not channel operator`);return;case"kick":i&&p[0]?(h=this.link)==null||h.send({type:"kick",nick:p[0],reason:p.slice(1).join(" ")}):r(i?"Usage: /kick [reason]":"You're not channel operator");return;default:r(`${f.toUpperCase()} Unknown command`);return}}const o=e.startsWith("//")?e.slice(1):e;i?(d=this.link)!=null&&d.send({type:"say",text:o})||r("Not connected"):n===kt&&this.wins[kt].joined?this.refused(`<${this.me}> ${o}`,"own"):r("You are not on a channel")}refused(t,e){this.push(kt,e,t),this.push(kt,"error",`* ${kt} Cannot send to channel`),this.hintedOikos||(this.hintedOikos=!0,this.push(kt,"info",`* (the living talk in ${Pt}: /join ${Pt})`))}help(){const t=e=>this.push(this.view,"info",e);t("* Commands:"),t(`* /join ${Pt} join the living (a nick, and a password for a tripcode if you like)`),t("* /nick change your nick"),t("* /me an action"),t("* /whois who someone is (their tripcode, if they have one)"),t(`* /part leave ${Pt}`),t("* /topic, /kick for channel operators"),t("* /clear /quit")}push(t,e,n,i=Date.now()){var c;const r=this.wins[t],o=r.log,a=o.scrollHeight-o.scrollTop-o.clientHeight<24,l=W("div",{class:`mirc-row t-${e}`});for(l.append(W("span",{class:"ts"},[my(i)]),` ${n}`),o.append(l);o.childElementCount>dy;)(c=o.firstElementChild)==null||c.remove();a&&(o.scrollTop=o.scrollHeight),t!==this.view&&(t!=="status"&&(e==="text"||e==="action"||e==="own")?r.tab.classList.add("said"):r.tab.classList.contains("said")||r.tab.classList.add("event"))}show(t){this.view=t;for(const n of Object.values(this.wins)){const i=n.id===t;n.pane.hidden=!i,n.tab.classList.toggle("on",i),n.tab.setAttribute("aria-selected",String(i)),i&&n.tab.classList.remove("said","event")}const e=this.wins[t].log;e.scrollTop=e.scrollHeight,this.input.setAttribute("aria-label",t==="status"?"Command":`Message ${t}`),this.retitle()}nicksChanged(t){this.wins[t].render(),this.retitle()}setHung(t){this.hung!==t&&(this.hung=t,this.win.el.classList.toggle("mirc-hung",t),this.retitle())}retitle(){const t=this.wins[this.view],e=t.id===kt?"+mnt":"+nt",n=t.id==="status"?`mIRC - [Status: ${this.me} on ${Un} (${sc})]`:t.joined?`mIRC - [${t.id} [${t.nicks.size}] [${e}]: ${t.topic}]`:`mIRC - [${t.id} (not on channel)]`;this.win.setTitle(this.hung?`${n} (Not Responding)`:n)}}class _y{constructor(t,e,n,i){R(this,"win");R(this,"statusLine");R(this,"timer",0);this.site=t,this.shell=e;const r=W("div");r.style.cssText="display:flex;flex-direction:column;min-height:0;flex:1;";const o=sd({back:()=>this.shell.back(),forward:()=>this.shell.forward(),can:()=>({back:this.shell.canBack,forward:this.shell.canForward}),up:()=>this.shell.home(),folders:()=>d.toggleAttribute("hidden")}),a=ad(t),l=rd(Sn(t.accent),a,!1,()=>this.shell.open(t)).el,c=od();r.append(ec({File:()=>[...wo(this.shell,t,!0),"sep",{label:"Properties",disabled:!0},"sep",{label:"Close",run:()=>this.win.close()}],Edit:()=>cd(this.shell,t),View:()=>fd(this.shell,{toolbar:o.el,address:l,status:c.el,up:()=>this.shell.home(),refresh:()=>this.refresh()}),Favorites:()=>hd(this.shell),Tools:()=>ud(),Help:()=>dd(this.shell)}),o.el,l);const u=this.shell.onNav(()=>o.refresh()),h=W("div",{class:"xp-body"}),d=W("aside",{class:"xp-tasks"});h.append(d);const f=W("div",{class:"xp-content"});h.append(f),r.append(h),c.set("Done",ld(t)),r.append(c.el);const p=W("div",{class:"xp-hero",html:Sn(t.accent,t.title)}),x=W("div");x.append(W("h2",{},[t.title]),W("p",{},[t.tagline])),p.append(x),f.append(p);const m=W("button",{class:"xp-preview",type:"button","aria-label":`Open ${t.title}`}),g=this.shell.screens.get(t.id);g&&m.append(g.canvas),m.append(W("span",{class:"xp-play"},[`▶ open ${t.title}`])),m.addEventListener("click",L=>this.shell.open(t,L)),f.append(m),f.append(W("p",{class:"xp-about"},[t.about]));const b=this.note();b&&f.append(W("div",{class:"xp-note"},[b]));const E=W("div",{class:"xp-actions"}),y=W("button",{class:"xp-btn default",type:"button"},[`Open ${t.title}`]);y.addEventListener("click",L=>this.shell.open(t,L));const M=W("button",{class:"xp-btn",type:"button"},["~ Home directory"]);if(M.addEventListener("click",()=>this.shell.home()),E.append(y),t.tune&&this.shell.canTune){const L=W("button",{class:"xp-btn",type:"button"},["▣ Watch it here"]);L.title="the live page, on its own screen in the room",L.addEventListener("click",()=>this.shell.tuneIn(t.id)),E.append(L)}if(t.id==="irc"){const L=W("button",{class:"xp-btn",type:"button"},["Join #aethera"]);L.title="sit in the channel, in mIRC",L.addEventListener("click",()=>this.shell.chat("#aethera")),E.append(L)}E.append(M),f.append(E);const w=[{icon:Jl(),label:`Open ${t.title}`,run:()=>this.shell.open(t)},{icon:Yu(),label:"Look at its screen",run:()=>this.shell.look(t.id)}];t.tune&&this.shell.canTune&&w.splice(1,0,{icon:j_(),label:"Watch it on its screen",run:()=>this.shell.tuneIn(t.id)}),t.id==="irc"&&w.splice(1,0,{icon:yi("channel"),label:"Join #aethera in mIRC",run:()=>this.shell.chat("#aethera")}),w.push({icon:Q_(),label:"Copy address",run:()=>nc(this.shell,t)}),w.push({icon:Ku(),label:"Eject tape",run:()=>this.win.close()});const C=[{icon:fr(),label:"~ (home directory)",run:()=>this.shell.home()}];for(const L of ry[t.id]??[]){const D=this.shell.site(L);D&&C.push({icon:Sn(D.accent),label:D.title,run:()=>this.shell.play(D.id)})}const v=W("div",{class:"xp-details"});v.append(W("b",{},[t.title]));const T=W("dl");for(const[L,D]of t.details)T.append(W("dt",{},[L]),W("dd",{},[D]));v.append(T),this.statusLine=W("div",{class:"status"}),v.append(this.statusLine),d.append(Fs("Tape Tasks",w,!0),Fs("Other Places",C),Fs("Details",v)),this.win=n.open({id:`site:${t.id}`,title:`${t.title} — ${a.replace(/^https?:\/\//,"")}`,icon:Sn(t.accent),body:r,width:Math.round(Math.min(760,Math.max(440,innerWidth*.5))),dock:"right",onClose:()=>{u(),clearInterval(this.timer),g==null||g.canvas.remove(),i()}}),this.win.el.style.height="min(640px, calc(100% - 24px))",this.refresh(),this.timer=window.setInterval(()=>this.refresh(),2e3)}note(){const t=this.site;return t.id==="dreams"?"Opening dreams wakes the dreamer: a GPU starts up while anyone is watching and goes back to sleep after. The frame here is the last one the chronicle kept.":t.id==="syrinx"?"Syrinx makes sound once you wake it. The creature here is read from this browser; nobody else sees yours.":t.id==="afterlife"?"afterlife makes music once you click in. The universe on this screen is the one saved in this browser, if you have visited; nobody else sees yours.":t.group==="wired"?`${t.title} is not on this server; it opens in a new window.`:null}refresh(){const{feeds:t}=this.shell;let e=!1,n="";switch(this.site.id){case"dreams":case"dreams-api":{const r=t.dreams.value;e=r.known&&r.awake,n=r.known?r.awake?`awake · frame ${r.frame.toLocaleString("en-US")}${r.viewers?` · ${r.viewers} watching`:""}`:"asleep":"status unknown";break}case"chronicle":{const r=t.chronicle.value;e=r.known&&r.eras.some(o=>o.open),n=r.known?`${r.eraCount||r.eras.length} eras recorded`:"reading the core…";break}case"irc":{const r=t.irc.value;e=r.connected,n=r.connected?"live on #aethera":"connecting…";break}case"syrinx":{const r=t.creature.value;e=!!r,n=r?`yours: ${r.name}`:"not woken in this browser";break}case"afterlife":{const r=t.universe.value;e=!!r,n=r?`yours: generation ${r.generation.toLocaleString("en-US")}`:"no universe in this browser yet";break}default:return}this.statusLine.className=`status${e?" on":""}`,this.statusLine.innerHTML="";const i=this.statusLine.querySelector("span");i&&(i.textContent=n)}}const vd=2;class yy{constructor(t,e,n,i){R(this,"el");R(this,"menu");R(this,"buttons");R(this,"clock");R(this,"moonEl");R(this,"start");R(this,"tip");R(this,"balloonEl");R(this,"balloonTimer",0);R(this,"dialogEl",null);this.root=t,this.shell=e,this.wm=n,this.hooks=i,this.el=W("nav",{class:"xp-taskbar","aria-label":"taskbar"}),this.start=W("button",{class:"xp-start",type:"button","aria-haspopup":"menu","aria-expanded":"false",html:`${pr(22,!1)}start`}),this.buttons=W("div",{class:"xp-taskbuttons"});const r=W("div",{class:"xp-tray"}),o=W("span",{class:"tray-icon net",title:"Connected to the Wired",html:$_()});this.moonEl=W("span",{class:"tray-icon dream",title:"dreams",html:Xu(!1)}),this.clock=W("span",{class:"clock"}),r.append(o,this.moonEl,this.clock),this.el.append(this.start,this.buttons,r),t.append(this.el),this.menu=this.buildMenu(),t.append(this.menu),this.start.addEventListener("click",()=>this.toggleMenu()),t.addEventListener("pointerdown",a=>{const l=a.target;!this.menu.hidden&&!l.closest(".xp-startmenu")&&!l.closest(".xp-start")&&!l.closest(".xp-menu")&&this.toggleMenu(!1)}),this.el.addEventListener("contextmenu",a=>{a.preventDefault(),a.stopPropagation();const l=a.target.closest(".xp-taskbtn"),c=l?this.wm.list.find(u=>u.opts.id===l.dataset.win):void 0;Us(c?c.systemMenu():this.barMenu(),a.clientX,a.clientY)}),o.addEventListener("click",()=>this.balloon("Connected to the Wired",`${e.dir.sites.length} screens · 1 VCR · signal: present day, present time`,this.trayAnchor())),this.tip=W("div",{class:"xp-tip",role:"tooltip",hidden:""}),this.balloonEl=W("div",{class:"xp-balloon",role:"status",hidden:""}),t.append(this.tip,this.balloonEl),n.on(()=>this.renderButtons()),e.feeds.dreams.on(a=>{this.moonEl.innerHTML=Xu(a.awake),this.moonEl.title=a.known?a.awake?`dreams: awake · frame ${a.frame.toLocaleString("en-US")}`:"dreams: asleep":"dreams: no answer"}),this.tick(),setInterval(()=>this.tick(),15e3)}tick(){this.clock.textContent=new Date().toLocaleTimeString([],{hour:"numeric",minute:"2-digit"})}trayAnchor(){const t=this.el.getBoundingClientRect();return{x:t.right-60,y:t.top}}toggleMenu(t){var n;const e=t??this.menu.hidden;e||Mi(),this.menu.hidden=!e,this.start.classList.toggle("open",e),this.start.setAttribute("aria-expanded",String(e)),e&&((n=this.menu.querySelector("a,button"))==null||n.focus())}barMenu(){return[{label:"Toolbars",disabled:!0,submenu:()=>[]},"sep",{label:"Cascade Windows",disabled:!0},{label:"Tile Windows Horizontally",disabled:!0},{label:"Tile Windows Vertically",disabled:!0},{label:"Show the Desktop",run:()=>this.showDesktop(),disabled:!this.wm.list.some(t=>!t.minimized&&!t.opts.dialog)},"sep",{label:"Task Manager",disabled:!0},"sep",{label:"Lock the Taskbar",checked:!0,disabled:!0},{label:"Properties",disabled:!0}]}showDesktop(){for(const t of[...this.wm.list])!t.opts.dialog&&!t.minimized&&t.minimize()}buildMenu(){const t=W("div",{class:"xp-startmenu",role:"menu",hidden:""}),e=W("header");e.append(W("span",{class:"avatar",html:pr(40)}),W("span",{},["guest"])),t.append(e,W("div",{class:"orange","aria-hidden":"true"}));const n=W("div",{class:"cols"}),i=W("ul",{class:"left"}),r=W("ul",{class:"right"}),o=(M,w)=>{const C=W("li");return C.append(w),M.append(C),w},a=(M,w,C,v,T,L="")=>{const D=W("button",{type:"button",role:"menuitem",class:L,html:`${w}${v!==null?"":""}`});D.querySelector(".tt").textContent=C;const U=D.querySelector("small");return U&&v&&(U.textContent=v),D.addEventListener("click",()=>{this.toggleMenu(!1),T()}),o(M,D)},l=(M,w,C,v)=>{const T=W("a",{href:v,role:"menuitem",html:`${w}`});T.querySelector("span").textContent=C,o(M,T)},c=(M,w,C,v,T)=>{const L=W("button",{type:"button",role:"menuitem",class:`cascade ${v}`,"aria-haspopup":"menu","data-menu-owner":"",html:`${w}`});L.querySelector(".tt").textContent=C;const D=()=>{L.classList.add("open"),id(T(),L,()=>L.classList.remove("open"))};return L.addEventListener("click",D),L.addEventListener("pointerenter",D),o(M,L)},u=M=>M.append(W("li",{class:"sep",role:"separator"}));t.addEventListener("pointerover",M=>{const w=M.target.closest("li > a, li > button");w&&!w.classList.contains("cascade")&&Mi()});const h=M=>({label:M.title,icon:Sn(M.accent),run:()=>{this.toggleMenu(!1),this.shell.play(M.id)}});a(i,yi(),"mIRC","#aethera",()=>this.shell.chat(),"pinned");const d=this.shell.dir.sites.filter(M=>M.group==="here");d.slice(0,vd).forEach(M=>a(i,Sn(M.accent,M.title),M.title,M.kind,()=>this.shell.play(M.id),"pinned")),u(i),d.slice(vd).forEach(M=>a(i,Sn(M.accent,M.title),M.title,null,()=>this.shell.play(M.id)));const f=W("li",{class:"allprog"});i.append(W("li",{class:"sep",role:"separator"}),f);const p=W("button",{type:"button",role:"menuitem",class:"cascade","aria-haspopup":"menu","data-menu-owner":"",html:`All Programs${ey()}`}),x=()=>{p.classList.add("open"),id([...this.shell.dir.sites.filter(M=>M.group==="here").map(h),"sep",...this.shell.dir.sites.filter(M=>M.group==="wired").map(h),"sep",{label:"~ (home directory)",icon:fr(),run:()=>{this.toggleMenu(!1),this.shell.home()}}],p,()=>p.classList.remove("open"))};p.addEventListener("click",x),p.addEventListener("pointerenter",x),f.append(p),a(r,fr(),"My Tapes",null,()=>this.shell.home(),"strong");const m=this.shell.dir.posts.slice(0,8);m.length&&c(r,Ns("txt"),"My Recent Transmissions","strong",()=>m.map(M=>({label:M.title,icon:Ns("txt"),run:()=>location.assign(M.href)}))),u(r);const g=this.shell.dir.sites.filter(M=>M.group==="wired");for(const M of g)a(r,Sn(M.accent),M.title,null,()=>this.shell.play(M.id));u(r);for(const M of this.shell.dir.files)l(r,Ns(M.title.split(".").pop()??"txt"),M.title,M.href);n.append(i,r),t.append(n);const b=W("div",{class:"foot"}),E=W("button",{type:"button",html:`${ju()}Log Off`});E.addEventListener("click",()=>{this.toggleMenu(!1),this.logOffDialog()});const y=W("button",{type:"button",html:`${Ju()}Turn Off Computer`});return y.addEventListener("click",()=>{this.toggleMenu(!1),this.shutdownDialog()}),b.append(E,y),t.append(b),t}dismiss(){return this.dialogEl?(this.dialogEl.remove(),this.dialogEl=null,this.start.focus(),!0):!1}bigDialog(t,e){var l,c;(l=this.dialogEl)==null||l.remove();const n=W("div",{class:"xp-shutdown",role:"dialog","aria-modal":"true","aria-label":t});this.dialogEl=n;const i=W("div",{class:"panel"});i.append(W("header",{html:`${pr(28,!1)}`})),i.querySelector("header span").textContent=t;const r=W("div",{class:"choices"});for(const u of e){const h=W("button",{type:"button",class:u.cls,html:`${u.icon}${u.label}`}),d=u.run;d?h.addEventListener("click",()=>{n.remove(),this.dialogEl=null,d()}):h.disabled=!0,r.append(h)}i.append(r);const o=W("div",{class:"foot"}),a=W("button",{class:"xp-btn",type:"button"},["Cancel"]);a.addEventListener("click",()=>this.dismiss()),o.append(a),i.append(o),n.append(i),this.root.append(n),(c=r.querySelector("button:not(:disabled):last-of-type, button:not(:disabled)"))==null||c.focus()}logOffDialog(){this.bigDialog("Log Off æthera",[{cls:"switch",icon:Qu(),label:"Switch User"},{cls:"logoff",icon:ju(),label:"Log Off",run:()=>this.hooks.logOff()}])}shutdownDialog(){var t,e;this.bigDialog("Turn off computer",[{cls:"standby",icon:ty(),label:"Stand By",run:()=>this.hooks.standby(!0)},{cls:"off",icon:Ju(),label:"Turn Off",run:()=>this.hooks.turnOff()},{cls:"restart",icon:Qu(),label:"Restart",run:()=>this.hooks.restart()}]),(e=(t=this.dialogEl)==null?void 0:t.querySelector(".off"))==null||e.focus()}renderButtons(){this.buttons.replaceChildren();for(const t of this.wm.list){if(t.opts.dialog)continue;const e=W("button",{class:`xp-taskbtn${this.wm.activeWindow===t&&!t.minimized?" active":""}`,type:"button","data-win":t.opts.id,html:`${t.opts.icon}`});e.querySelector("span").textContent=t.opts.title,e.title=t.opts.title,e.addEventListener("click",()=>{t.minimized?t.restore():this.wm.activeWindow===t?t.minimize():t.focus()}),this.buttons.append(e)}}showTip(t,e,n,i){const r=t?{title:t.title,text:t.tagline}:e;if(!r){this.tip.hidden=!0;return}this.tip.innerHTML="",this.tip.querySelector("b").textContent=r.title,this.tip.querySelector("span").textContent=r.text,this.tip.hidden=!1;const o=this.root.getBoundingClientRect(),a=this.tip.offsetWidth;this.tip.style.left=`${Math.min(n+14,o.width-a-6)}px`,this.tip.style.top=`${Math.min(i+20,o.height-70)}px`}balloon(t,e,n,i=7e3,r=!1){var f;const o=this.balloonEl;o.innerHTML=`${Zu()}`,o.querySelector("b span").textContent=t,o.querySelector(".msg").textContent=e,(f=o.querySelector(".x"))==null||f.addEventListener("click",()=>o.hidden=!0),o.hidden=!1;const a=this.root.getBoundingClientRect(),l=n??this.trayAnchor(),c=o.offsetWidth,u=o.offsetHeight,h=Math.max(6,Math.min(l.x-30,a.width-c-6)),d=r?l.y+u+24>a.height-30:l.y-u-20>0;o.classList.toggle("above",d),o.classList.toggle("below",!d),o.style.left=`${h}px`,o.style.top=`${d?l.y-u-18:l.y+18}px`,o.style.setProperty("--tail",`${Math.max(12,Math.min(c-30,l.x-h))}px`),clearTimeout(this.balloonTimer),this.balloonTimer=window.setTimeout(()=>o.hidden=!0,i)}hideBalloon(){this.balloonEl.hidden=!0}}const hc=300,uc=180,My=["n","s","e","w","ne","nw","se","sw"];class by{constructor(t,e){R(this,"el");R(this,"minimized",!1);R(this,"closed",!1);var o,a,l,c,u;this.opts=t,this.wm=e;const n=document.createElement("section");n.className=`xp-window${t.dialog?" xp-dialog":""}`,n.setAttribute("role",t.dialog?"alertdialog":"dialog"),n.setAttribute("aria-label",t.title),n.innerHTML=`
${t.icon} @@ -4578,4 +4578,4 @@ ${s?''} -
`;const i=n.querySelector(".xp-title");i&&(i.textContent=t.title),n.append(t.body),n.style.width=`${t.width}px`,this.el=n,(a=n.querySelector(".xp-close"))==null||a.addEventListener("click",()=>this.close()),(o=n.querySelector(".xp-min"))==null||o.addEventListener("click",()=>this.minimize()),(l=n.querySelector(".xp-max"))==null||l.addEventListener("click",()=>this.toggleMax()),n.addEventListener("pointerdown",()=>this.focus(),!0),this.bindDrag(n.querySelector(".xp-titlebar")),t.dialog||this.bindResize(),(c=n.querySelector(".xp-titlebar"))==null||c.addEventListener("dblclick",h=>{const d=h.target;d.closest(".xp-controls")||t.dialog||(d.closest(".xp-title-icon")?this.close():this.toggleMax())});const r=n.querySelector(".xp-title-icon");r==null||r.setAttribute("data-menu-owner",""),r==null||r.addEventListener("click",h=>{h.stopPropagation();const d=n.getBoundingClientRect();Ms(this.systemMenu(),d.left+3,d.top+29)}),(u=n.querySelector(".xp-titlebar"))==null||u.addEventListener("contextmenu",h=>{const d=h;d.target.closest(".xp-controls")||(d.preventDefault(),d.stopPropagation(),Ms(this.systemMenu(),d.clientX,d.clientY))})}get maximized(){return this.el.classList.contains("maximized")}systemMenu(){const t=!!this.opts.dialog;return[{label:"Restore",run:()=>this.minimized?this.restore():this.toggleMax(),disabled:t||!this.maximized&&!this.minimized},{label:"Move",disabled:!0},{label:"Size",disabled:!0},{label:"Minimize",run:()=>this.minimize(),disabled:t||this.minimized},{label:"Maximize",run:()=>{this.minimized&&this.restore(),this.maximized||this.toggleMax()},disabled:t||this.maximized},"sep",{label:"Close",run:()=>this.close(),bold:!0,shortcut:"Alt+F4"}]}setTitle(t){const e=this.el.querySelector(".xp-title");e&&(e.textContent=t),this.el.setAttribute("aria-label",t)}place(t){const e=t.clientWidth,n=t.clientHeight,i=Math.min(this.opts.width,e-16);this.el.style.width=`${i}px`,t.append(this.el);const r=Math.min(this.el.offsetHeight,n-16);let a=this.opts.x??0,o=this.opts.y??0;this.opts.x===void 0&&(this.opts.dock==="left"?a=18:this.opts.dock==="right"?a=e-i-18:a=(e-i)/2),this.opts.y===void 0&&(o=this.opts.dialog?(n-r)/2.4:Math.max(8,Math.min(60,(n-r)/2))),this.moveTo(a,o)}moveTo(t,e){const n=this.el.parentElement;if(!n)return;const i=n.clientWidth-60,r=n.clientHeight-30;this.el.style.left=`${Math.round(Math.max(-this.el.offsetWidth+80,Math.min(i,t)))}px`,this.el.style.top=`${Math.round(Math.max(0,Math.min(r,e)))}px`}bindDrag(t){let e=null;t.addEventListener("pointerdown",i=>{i.target.closest(".xp-controls, .xp-title-icon")||i.button!==0||this.el.classList.contains("maximized")||innerWidth<=720||(e={x:i.clientX,y:i.clientY,left:this.el.offsetLeft,top:this.el.offsetTop},t.setPointerCapture(i.pointerId))}),t.addEventListener("pointermove",i=>{e&&this.moveTo(e.left+i.clientX-e.x,e.top+i.clientY-e.y)});const n=()=>{e&&this.wm.changed(),e=null};t.addEventListener("pointerup",n),t.addEventListener("pointercancel",n)}bindResize(){for(const t of rv){const e=document.createElement("div");e.className=`xp-grip xp-grip-${t}`,e.setAttribute("aria-hidden","true"),this.el.append(e);let n=null;e.addEventListener("pointerdown",r=>{r.button!==0||this.maximized||innerWidth<=720||(r.preventDefault(),n={x:r.clientX,y:r.clientY,left:this.el.offsetLeft,top:this.el.offsetTop,w:this.el.offsetWidth,h:this.el.offsetHeight},e.setPointerCapture(r.pointerId),this.focus())}),e.addEventListener("pointermove",r=>{if(!n)return;const a=this.el.parentElement;if(!a)return;const o=r.clientX-n.x,l=r.clientY-n.y;let{left:c,top:u,w:h,h:d}=n;t.includes("e")&&(h=Math.min(a.clientWidth-c,Math.max(Ul,n.w+o))),t.includes("s")&&(d=Math.min(a.clientHeight-u,Math.max(Fl,n.h+l))),t.includes("w")&&(h=Math.max(Ul,Math.min(n.left+n.w,n.w-o)),c=n.left+n.w-h),t.includes("n")&&(d=Math.max(Fl,Math.min(n.top+n.h,n.h-l)),u=n.top+n.h-d),this.el.style.left=`${Math.round(c)}px`,this.el.style.top=`${Math.round(u)}px`,this.el.style.width=`${Math.round(h)}px`,this.el.style.height=`${Math.round(d)}px`,this.el.style.maxHeight="none"});const i=()=>{n&&this.wm.changed(),n=null};e.addEventListener("pointerup",i),e.addEventListener("pointercancel",i)}}clamp(){if(this.maximized||this.minimized)return;const t=this.el.parentElement;t&&(this.el.offsetWidth>t.clientWidth&&(this.el.style.width=`${Math.max(Ul,t.clientWidth-8)}px`),this.el.offsetHeight>t.clientHeight&&(this.el.style.height=`${Math.max(Fl,t.clientHeight-8)}px`),this.moveTo(this.el.offsetLeft,this.el.offsetTop))}focus(){this.wm.focus(this)}minimize(){this.minimized=!0,this.el.classList.add("minimized"),this.wm.focusTop(),this.wm.changed()}restore(){this.minimized=!1,this.el.classList.remove("minimized"),this.focus()}toggleMax(){const t=this.el.classList.toggle("maximized"),e=this.el.querySelector(".xp-max");e==null||e.setAttribute("aria-label",t?"Restore":"Maximize"),e==null||e.setAttribute("title",t?"Restore":"Maximize"),this.wm.changed()}close(){var t,e;this.closed||(this.closed=!0,this.el.remove(),this.wm.remove(this),(e=(t=this.opts).onClose)==null||e.call(t))}}class ov{constructor(t){I(this,"windows",[]);I(this,"active",null);I(this,"z",30);I(this,"listeners",new Set);this.desk=t,addEventListener("resize",()=>{for(const e of this.windows)e.clamp()})}get list(){return this.windows}get activeWindow(){return this.active}get(t){return this.windows.find(e=>e.opts.id===t)}open(t){const e=this.get(t.id);if(e)return e.minimized?e.restore():e.focus(),e;const n=new av(t,this);return this.windows.push(n),n.place(this.desk),this.focus(n),n}focus(t){var n,i;if(t.closed)return;const e=this.active!==t;this.active=t,t.el.style.zIndex=String(++this.z);for(const r of this.windows)r.el.classList.toggle("inactive",r!==t);e&&((i=(n=t.opts).onFocus)==null||i.call(n)),this.changed()}deactivate(){if(this.active){this.active=null;for(const t of this.windows)t.el.classList.add("inactive");this.changed()}}focusTop(){const e=this.windows.filter(n=>!n.minimized).sort((n,i)=>Number(i.el.style.zIndex)-Number(n.el.style.zIndex))[0];e?this.focus(e):(this.active=null,this.changed())}remove(t){this.windows=this.windows.filter(e=>e!==t),this.active===t&&(this.active=null,this.focusTop()),this.changed()}closeTop(){const t=this.active&&!this.active.minimized?this.active:null;return t?(t.close(),!0):!1}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}changed(){for(const t of this.listeners)t()}}const Ol=document.getElementById("oikos");if(Ol)try{cv(Ol)}catch(s){console.error("oikos: boot failed; falling back to the plain directory",s),Ol.classList.remove("oikos-live"),(Ru=document.getElementById("oikos-boot"))==null||Ru.remove()}function lv(){var s;try{const t=document.createElement("canvas").getContext("webgl2");return(s=t==null?void 0:t.getExtension("WEBGL_lose_context"))==null||s.loseContext(),!!t}catch{return!1}}function ia(){return location.pathname+location.search}function cv(s){var jt,j;s.classList.add("oikos-live");const t=matchMedia("(prefers-reduced-motion: reduce)").matches,e=xi(),n=new Bu,i=new Map(e.sites.map(D=>[D.id,md(D,{dir:e,feeds:n})])),r=new Map(e.sites.map(D=>[D.id,D]));if(new URLSearchParams(location.search).has("contact")){hv(s,e.sites,i,n);return}const a=G("div",{id:"oikos-desktop"});s.append(a);const o=new ov(a);zx(s);const l={stack:[],i:-1,moving:!1,listeners:new Set},c=D=>{if(!(l.moving||l.stack[l.i]===D)){l.stack=l.stack.slice(0,l.i+1),l.stack.push(D),l.i=l.stack.length-1;for(const W of l.listeners)W()}},u=D=>{const W=l.stack[l.i+D];if(W!==void 0){l.i+=D,l.moving=!0;try{W==="~"?E.home():E.play(W)}finally{l.moving=!1}for(const st of l.listeners)st()}};let h=null,d=null,f=null,p=null,v=!1,m=null,g=0,w=!1;const E={dir:e,feeds:n,screens:i,site:D=>r.get(D),select(D){b(!1),h==null||h.focus(D)},play(D){const W=r.get(D);if(!W)return;if(c(D),b(!1),M.select(D),f===D&&d){h==null||h.play(D),d.win.minimized?d.win.restore():d.win.focus();return}const st=d;d=null,f=null,st==null||st.win.close(),history.replaceState(null,"",`${ia()}#${D}`);const lt=o.get("home");lt&&!lt.minimized&&h&&(lt.minimize(),w=!0);const rt=++g,Ft=Lt=>{if(rt===g){if(!Lt){h==null||h.eject(),history.replaceState(null,"",ia());const Ht=o.get("home");w&&(Ht!=null&&Ht.minimized)&&Ht.restore(),w=!1;return}f=D,h==null||h.keepAlive(D),d=new iv(W,E,o,()=>{if(f!==D)return;d=null,f=null,h==null||h.keepAlive(null),h==null||h.eject(),(h==null?void 0:h.focusedId)===D&&h.focus(null),history.replaceState(null,"",ia());const Ht=o.get("home");w&&(Ht!=null&&Ht.minimized)&&Ht.restore(),w=!1})}};h?h.play(D).then(Ft):Ft(!0)},open(D,W){if(W==null||W.preventDefault(),v)return;if(yn(D.href)){window.open(D.href,"_blank","noopener"),S.balloon(`${D.title} opened`,"It opened in a new window. The room is still here.");return}const st=D.href;v=!0,S.balloon(`Opening ${D.title}`,"tuning in…",void 0,2e3);let lt=!1;const rt=()=>{lt||(lt=!0,location.assign(st))};h?h.dive(D.id).then(rt):rt(),setTimeout(rt,1500)},look(D){b(!1),h==null||h.focus(D)},get canTune(){return!!h},tuneIn(D){const W=r.get(D);if(!h||!(W!=null&&W.tune))return;const st=typeof W.tune=="string"?W.tune:W.href;b(!1);const lt=o.list.filter(te=>!te.minimized&&!te.opts.dialog);for(const te of lt)te.minimize();S.hideBalloon();const rt=G("div",{class:"oikos-tube"});rt.style.setProperty("--glow",W.accent);const Ft=G("iframe",{src:st,title:`${W.title}, live`,allow:"autoplay; fullscreen; clipboard-write"});rt.append(Ft,G("i",{class:"roll"}),G("i",{class:"glass"})),Ft.addEventListener("load",()=>{var te;try{(te=Ft.contentWindow)==null||te.addEventListener("keydown",le=>{var Te;const ce=le.target;le.key!=="Escape"||le.defaultPrevented||(Te=ce==null?void 0:ce.closest)!=null&&Te.call(ce,"input, textarea, [contenteditable]")||b(!0)})}catch{}});const Lt=G("div",{class:"oikos-tuned",role:"toolbar","aria-label":"tuned in"});Lt.innerHTML=`${vn(W.accent)}tuned in · live on its screen`,Lt.querySelector("b").textContent=W.title;const Ht=G("button",{class:"xp-btn",type:"button"},["⏏ Eject"]);Ht.addEventListener("click",()=>b(!0));const Zt=G("a",{class:"xp-btn",href:W.href},["Open full ↗"]);yn(W.href)&&(Zt.setAttribute("target","_blank"),Zt.setAttribute("rel","noopener")),Lt.append(Ht,Zt),m={id:D,bar:Lt,hidden:lt,tube:rt};const Jt=te=>{const le=Math.round(Math.min(1024,Math.max(420,te.width*1.15))),ce=Math.round(le*.75);rt.style.width=`${le}px`,rt.style.height=`${ce}px`,rt.style.transform=`translate(${te.left}px, ${te.top}px) scale(${te.width/le}, ${te.height/ce})`};h.tuneIn(D,Jt).then(()=>{(m==null?void 0:m.bar)===Lt&&(s.append(rt,Lt),Ft.focus())})},chat(D){b(!1),p||(p=new nv(E,o,()=>p=null)),p.focus(D)},home(){c("~"),b(!1),M.open(),h==null||h.scroll("~ home")},eject(){b(!1),d==null||d.win.close(),h==null||h.eject(),h==null||h.focus(null)},balloon(D,W,st){S.balloon(D,W,st)},back:()=>u(-1),forward:()=>u(1),get canBack(){return l.i>0},get canForward(){return l.il.listeners.delete(D)},about:()=>R()},M=new Wx(E,o),S=new sv(s,E,o,{standby:D=>P(D),turnOff(){s.classList.add("off"),setTimeout(()=>location.assign("/"),t?50:750)},logOff(){b(!1);for(const D of[...o.list])D.close();h==null||h.eject(),h==null||h.focus(null),history.replaceState(null,"",ia()),S.balloon("Logged off","The desk is clear. Click the VCR to begin again.",(h==null?void 0:h.anchor("vcr"))??void 0)},restart(){try{sessionStorage.removeItem("oikos-booted")}catch{}location.reload()}});function b(D){if(!m)return;const{id:W,bar:st,hidden:lt,tube:rt}=m;if(m=null,st.remove(),rt.remove(),h==null||h.tuneOut(),!!D){for(const Ft of lt)Ft.closed||Ft.restore();h==null||h.focus(W)}}function R(){var Ht;(Ht=o.get("about"))==null||Ht.close();const D=G("div",{class:"xp-about-box"}),W=G("div",{class:"band",html:Js(44,!0)});W.append(G("b",{},["æthera"]),G("span",{},["oikos"]));const st=G("div",{class:"xp-dialog-body"}),lt=G("div");lt.append(G("p",{},["æthera · the home directory"]),G("p",{},["Version 1998 (Build 2026.present_day)"]),G("p",{},["A room of screens wired to one VCR, and every part of the site playing at once."]),G("p",{class:"lic"},["This product is licensed under CC BY 4.0 to:"]),G("p",{},["guest"])),st.append(lt);const rt=G("div",{class:"xp-actions"}),Ft=G("button",{class:"xp-btn default",type:"button"},["OK"]);rt.append(Ft),D.append(W,st,rt);const Lt=o.open({id:"about",title:"About æthera",icon:au(),body:D,width:400,dialog:!0});Ft.addEventListener("click",()=>Lt.close()),Ft.focus()}if(lv())try{h=new Tx(s,e.sites,i,{pick(D){L(),S.hideBalloon(),S.showTip(null,null,0,0),D==="vcr"?E.home():D?E.play(D):h!=null&&h.focusedId&&!d&&!h.busy&&h.focus(null)},hover(D,W,st){D==="vcr"?S.showTip(null,{title:"VCR",text:"your home directory · click to open ~"},W,st):S.showTip(D?r.get(D)??null:null,null,W,st)}})}catch(D){console.warn("oikos: the room would not build; running the desktop alone",D),h==null||h.stop(),h=null}if(h==null||h.renderer.domElement.addEventListener("pointerdown",()=>o.deactivate()),Gx(s,(D,W)=>{var Ft,Lt;const st=D.closest(".xp-tile");if(st)return st.dataset.id?M.contextFor(st.dataset.id):null;if(D.closest("a"))return null;if(D.closest(".xp-content")&&((Lt=(Ft=D.closest(".xp-window"))==null?void 0:Ft.getAttribute("aria-label"))!=null&&Lt.startsWith("~")))return M.blankMenu();if(D.closest(".xp-window, .xp-startmenu, .xp-shutdown, .xp-menu, .xp-balloon"))return[];if(!h||D!==h.renderer.domElement)return[];const lt=h.pickFromPoint(W.clientX,W.clientY);if(lt==="vcr")return[{label:"Open ~",bold:!0,run:()=>E.home()},{label:"Eject",run:()=>E.eject(),disabled:!f},"sep",{label:"Properties",disabled:!0}];const rt=lt?r.get(lt):void 0;return rt?na(E,rt):[{label:"Arrange Icons By",disabled:!0,submenu:()=>[]},{label:"Refresh",run:()=>h==null?void 0:h.focus(null)},"sep",{label:"Paste",disabled:!0},{label:"Paste Shortcut",disabled:!0},"sep",{label:"New",disabled:!0,submenu:()=>[]},"sep",{label:"~ Home directory",run:()=>E.home()},{label:"Properties",disabled:!0}]}),!h){let D=performance.now();const W=st=>{var rt;requestAnimationFrame(W);const lt=Math.min(.1,(st-D)/1e3);D=st,f&&((rt=i.get(f))==null||rt.tick(st/1e3,lt,!0))};requestAnimationFrame(W)}const x=()=>{if(!h)return;const D=innerWidth,W=innerHeight-30,st=o.list.filter(Ft=>!Ft.minimized&&!Ft.opts.dialog&&!Ft.el.classList.contains("maximized"));if(D<=720){h.setShift(0,st.length?W*.3:0);return}let lt=0,rt=D;for(const Ft of st){const Lt=Ft.el.getBoundingClientRect();Lt.left+Lt.width/2[W.channel,D])),q=e.sites.map(D=>D.id).sort((D,W)=>{var st,lt;return(((st=ir[D])==null?void 0:st.channel)??99)-(((lt=ir[W])==null?void 0:lt.channel)??99)});let Y="",B=0;addEventListener("keydown",D=>{if(T){L();return}const W=D.target;if(!W.closest("input, textarea")){if(D.key==="Escape"&&m){b(!0);return}if(!m){if(D.key==="Escape"){if(pi()||S.dismiss()||!K())return;const st=o.activeWindow;if(st!=null&&st.opts.dialog&&!st.minimized){st.close();return}h!=null&&h.focusedId&&h.focus(null);return}if(D.altKey&&(D.key==="ArrowLeft"||D.key==="ArrowRight")){D.preventDefault(),u(D.key==="ArrowLeft"?-1:1);return}if(!W.closest(".xp-window, .xp-startmenu, .xp-menu, .xp-shutdown")){if(D.key==="~"||D.key==="Home"){E.home();return}if((D.key==="ArrowRight"||D.key==="ArrowLeft")&&!(h!=null&&h.busy)){const st=h!=null&&h.focusedId&&h.focusedId!=="vcr"?q.indexOf(h.focusedId):-1,lt=q[(st+(D.key==="ArrowRight"?1:-1)+q.length)%q.length];if(lt){h==null||h.focus(lt),M.select(lt);const rt=h==null?void 0:h.anchor(lt),Ft=r.get(lt);rt&&Ft&&S.showTip(Ft,null,rt.x-40,rt.y-50)}return}if(D.key==="Enter"&&(h!=null&&h.focusedId)&&h.focusedId!=="vcr"){E.play(h.focusedId);return}/^[0-9]$/.test(D.key)&&(Y=(Y+D.key).slice(-2),clearTimeout(B),h==null||h.scroll(`ch ${Y}`),B=window.setTimeout(()=>{const st=F.get(Number(Y));Y="",st&&r.has(st)&&E.play(st)},700))}}}});function K(){const D=s==null?void 0:s.querySelector(".xp-startmenu");return D&&!D.hidden?(S.toggleMenu(!1),!1):!0}let X=!1;document.addEventListener("visibilitychange",()=>{document.hidden?(h==null||h.stop(),n.stop(),m&&b(!0)):X&&(h==null||h.start(),n.start())}),addEventListener("pageshow",D=>{D.persisted&&(v=!1,s.classList.remove("off"),h==null||h.reset())});const Q=document.getElementById("oikos-boot");let it=!1;try{it=!!sessionStorage.getItem("oikos-booted"),sessionStorage.setItem("oikos-booted","1")}catch{}const pt=t||it?250:1900;let _t=()=>{};const bt=new Promise(D=>_t=D);Q==null||Q.addEventListener("click",()=>_t());const ee=Promise.race([Promise.all([(jt=document.fonts)==null?void 0:jt.load('16px "Libertinus Mono"'),(j=document.fonts)==null?void 0:j.load('16px "Love Letter Typewriter"')]).then(()=>{},()=>{}),new Promise(D=>setTimeout(D,1500))]),pe=(h==null?void 0:h.warm())??Promise.resolve();Promise.race([Promise.all([ee,pe,new Promise(D=>setTimeout(D,pt))]),bt]).then(()=>{X=!0,document.hidden||(n.start(),h==null||h.start()),h==null||h.powerOn(),Q==null||Q.classList.add("gone"),setTimeout(()=>Q==null?void 0:Q.remove(),800);const D=new URLSearchParams(location.search).get("look");D&&h&&(D==="vcr"||r.has(D))&&setTimeout(()=>h==null?void 0:h.focus(D),300);let W="";try{W=decodeURIComponent(location.hash.slice(1))}catch{}if(W==="mirc"){setTimeout(()=>E.chat(),600);return}if(W&&r.has(W)){setTimeout(()=>E.play(W),900);return}if(!h){E.home(),S.balloon("No room tonight","This browser has no WebGL, so the room of screens is dark. The tapes all still play.");return}setTimeout(()=>{if(o.list.length)return;const st=(h==null?void 0:h.anchor("vcr"))??void 0;S.balloon("This is the way in",innerWidth<=720?"Tap the VCR for the home directory, or any screen to tune in. Drag to look around.":"Click the VCR for your home directory, or any screen to tune in. Drag to look around; ← → walk the screens.",st,11e3,!0)},it?900:2600)})}function hv(s,t,e,n){var o;(o=document.getElementById("oikos-boot"))==null||o.remove();const i=G("div");i.style.cssText="position:absolute;inset:0;overflow:auto;padding:16px;display:grid;gap:14px;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));background:#0a0a0a;";for(const l of t){const c=e.get(l.id);if(!c)continue;const u=G("figure");u.style.cssText="margin:0;color:#aaa;font:12px ui-monospace,monospace;",c.canvas.style.cssText="width:100%;display:block;border:1px solid #333;";const h=G("figcaption",{},[`${l.title} · ${l.kind}`]);h.style.padding="4px 0",u.append(c.canvas,h),i.append(u)}s.append(i),n.start();let r=performance.now();const a=l=>{requestAnimationFrame(a);const c=Math.min(.1,(l-r)/1e3);r=l;for(const u of e.values())u.tick(l/1e3,c,!1)};requestAnimationFrame(a)}})(); + `;const i=n.querySelector(".xp-title");i&&(i.textContent=t.title),n.append(t.body),n.style.width=`${t.width}px`,this.el=n,(o=n.querySelector(".xp-close"))==null||o.addEventListener("click",()=>this.close()),(a=n.querySelector(".xp-min"))==null||a.addEventListener("click",()=>this.minimize()),(l=n.querySelector(".xp-max"))==null||l.addEventListener("click",()=>this.toggleMax()),n.addEventListener("pointerdown",()=>this.focus(),!0),this.bindDrag(n.querySelector(".xp-titlebar")),t.dialog||this.bindResize(),(c=n.querySelector(".xp-titlebar"))==null||c.addEventListener("dblclick",h=>{const d=h.target;d.closest(".xp-controls")||t.dialog||(d.closest(".xp-title-icon")?this.close():this.toggleMax())});const r=n.querySelector(".xp-title-icon");r==null||r.setAttribute("data-menu-owner",""),r==null||r.addEventListener("click",h=>{h.stopPropagation();const d=n.getBoundingClientRect();Us(this.systemMenu(),d.left+3,d.top+29)}),(u=n.querySelector(".xp-titlebar"))==null||u.addEventListener("contextmenu",h=>{const d=h;d.target.closest(".xp-controls")||(d.preventDefault(),d.stopPropagation(),Us(this.systemMenu(),d.clientX,d.clientY))})}get maximized(){return this.el.classList.contains("maximized")}systemMenu(){const t=!!this.opts.dialog;return[{label:"Restore",run:()=>this.minimized?this.restore():this.toggleMax(),disabled:t||!this.maximized&&!this.minimized},{label:"Move",disabled:!0},{label:"Size",disabled:!0},{label:"Minimize",run:()=>this.minimize(),disabled:t||this.minimized},{label:"Maximize",run:()=>{this.minimized&&this.restore(),this.maximized||this.toggleMax()},disabled:t||this.maximized},"sep",{label:"Close",run:()=>this.close(),bold:!0,shortcut:"Alt+F4"}]}setTitle(t){const e=this.el.querySelector(".xp-title");e&&(e.textContent=t),this.el.setAttribute("aria-label",t)}place(t){const e=t.clientWidth,n=t.clientHeight,i=Math.min(this.opts.width,e-16);this.el.style.width=`${i}px`,t.append(this.el);const r=Math.min(this.el.offsetHeight,n-16);let o=this.opts.x??0,a=this.opts.y??0;this.opts.x===void 0&&(this.opts.dock==="left"?o=18:this.opts.dock==="right"?o=e-i-18:o=(e-i)/2),this.opts.y===void 0&&(a=this.opts.dialog?(n-r)/2.4:Math.max(8,Math.min(60,(n-r)/2))),this.moveTo(o,a)}moveTo(t,e){const n=this.el.parentElement;if(!n)return;const i=n.clientWidth-60,r=n.clientHeight-30;this.el.style.left=`${Math.round(Math.max(-this.el.offsetWidth+80,Math.min(i,t)))}px`,this.el.style.top=`${Math.round(Math.max(0,Math.min(r,e)))}px`}bindDrag(t){let e=null;t.addEventListener("pointerdown",i=>{i.target.closest(".xp-controls, .xp-title-icon")||i.button!==0||this.el.classList.contains("maximized")||innerWidth<=720||(e={x:i.clientX,y:i.clientY,left:this.el.offsetLeft,top:this.el.offsetTop},t.setPointerCapture(i.pointerId))}),t.addEventListener("pointermove",i=>{e&&this.moveTo(e.left+i.clientX-e.x,e.top+i.clientY-e.y)});const n=()=>{e&&this.wm.changed(),e=null};t.addEventListener("pointerup",n),t.addEventListener("pointercancel",n)}bindResize(){for(const t of My){const e=document.createElement("div");e.className=`xp-grip xp-grip-${t}`,e.setAttribute("aria-hidden","true"),this.el.append(e);let n=null;e.addEventListener("pointerdown",r=>{r.button!==0||this.maximized||innerWidth<=720||(r.preventDefault(),n={x:r.clientX,y:r.clientY,left:this.el.offsetLeft,top:this.el.offsetTop,w:this.el.offsetWidth,h:this.el.offsetHeight},e.setPointerCapture(r.pointerId),this.focus())}),e.addEventListener("pointermove",r=>{if(!n)return;const o=this.el.parentElement;if(!o)return;const a=r.clientX-n.x,l=r.clientY-n.y;let{left:c,top:u,w:h,h:d}=n;t.includes("e")&&(h=Math.min(o.clientWidth-c,Math.max(hc,n.w+a))),t.includes("s")&&(d=Math.min(o.clientHeight-u,Math.max(uc,n.h+l))),t.includes("w")&&(h=Math.max(hc,Math.min(n.left+n.w,n.w-a)),c=n.left+n.w-h),t.includes("n")&&(d=Math.max(uc,Math.min(n.top+n.h,n.h-l)),u=n.top+n.h-d),this.el.style.left=`${Math.round(c)}px`,this.el.style.top=`${Math.round(u)}px`,this.el.style.width=`${Math.round(h)}px`,this.el.style.height=`${Math.round(d)}px`,this.el.style.maxHeight="none"});const i=()=>{n&&this.wm.changed(),n=null};e.addEventListener("pointerup",i),e.addEventListener("pointercancel",i)}}clamp(){if(this.maximized||this.minimized)return;const t=this.el.parentElement;t&&(this.el.offsetWidth>t.clientWidth&&(this.el.style.width=`${Math.max(hc,t.clientWidth-8)}px`),this.el.offsetHeight>t.clientHeight&&(this.el.style.height=`${Math.max(uc,t.clientHeight-8)}px`),this.moveTo(this.el.offsetLeft,this.el.offsetTop))}focus(){this.wm.focus(this)}minimize(){this.minimized=!0,this.el.classList.add("minimized"),this.wm.focusTop(),this.wm.changed()}restore(){this.minimized=!1,this.el.classList.remove("minimized"),this.focus()}toggleMax(){const t=this.el.classList.toggle("maximized"),e=this.el.querySelector(".xp-max");e==null||e.setAttribute("aria-label",t?"Restore":"Maximize"),e==null||e.setAttribute("title",t?"Restore":"Maximize"),this.wm.changed()}close(){var t,e;this.closed||(this.closed=!0,this.el.remove(),this.wm.remove(this),(e=(t=this.opts).onClose)==null||e.call(t))}}class Sy{constructor(t){R(this,"windows",[]);R(this,"active",null);R(this,"z",30);R(this,"listeners",new Set);this.desk=t,addEventListener("resize",()=>{for(const e of this.windows)e.clamp()})}get list(){return this.windows}get activeWindow(){return this.active}get(t){return this.windows.find(e=>e.opts.id===t)}open(t){const e=this.get(t.id);if(e)return e.minimized?e.restore():e.focus(),e;const n=new by(t,this);return this.windows.push(n),n.place(this.desk),this.focus(n),n}focus(t){var n,i;if(t.closed)return;const e=this.active!==t;this.active=t,t.el.style.zIndex=String(++this.z);for(const r of this.windows)r.el.classList.toggle("inactive",r!==t);e&&((i=(n=t.opts).onFocus)==null||i.call(n)),this.changed()}deactivate(){if(this.active){this.active=null;for(const t of this.windows)t.el.classList.add("inactive");this.changed()}}focusTop(){const e=this.windows.filter(n=>!n.minimized).sort((n,i)=>Number(i.el.style.zIndex)-Number(n.el.style.zIndex))[0];e?this.focus(e):(this.active=null,this.changed())}remove(t){this.windows=this.windows.filter(e=>e!==t),this.active===t&&(this.active=null,this.focusTop()),this.changed()}closeTop(){const t=this.active&&!this.active.minimized?this.active:null;return t?(t.close(),!0):!1}on(t){return this.listeners.add(t),()=>this.listeners.delete(t)}changed(){for(const t of this.listeners)t()}}const dc=document.getElementById("oikos");if(dc)try{Ey(dc)}catch(s){console.error("oikos: boot failed; falling back to the plain directory",s),dc.classList.remove("oikos-live"),(_d=document.getElementById("oikos-boot"))==null||_d.remove()}function wy(){var s;try{const t=document.createElement("canvas").getContext("webgl2");return(s=t==null?void 0:t.getExtension("WEBGL_lose_context"))==null||s.loseContext(),!!t}catch{return!1}}function Eo(){return location.pathname+location.search}function Ey(s){var ee,Q;s.classList.add("oikos-live");const t=matchMedia("(prefers-reduced-motion: reduce)").matches,e=Rd(),n=new Pd,i=new Map(e.sites.map(I=>[I.id,Df(I,{dir:e,feeds:n})])),r=new Map(e.sites.map(I=>[I.id,I]));if(new URLSearchParams(location.search).has("contact")){Ty(s,e.sites,i,n);return}const o=W("div",{id:"oikos-desktop"});s.append(o);const a=new Sy(o);ny(s);const l={stack:[],i:-1,moving:!1,listeners:new Set},c=I=>{if(!(l.moving||l.stack[l.i]===I)){l.stack=l.stack.slice(0,l.i+1),l.stack.push(I),l.i=l.stack.length-1;for(const X of l.listeners)X()}},u=I=>{const X=l.stack[l.i+I];if(X!==void 0){l.i+=I,l.moving=!0;try{X==="~"?E.home():E.play(X)}finally{l.moving=!1}for(const st of l.listeners)st()}};let h=null,d=null,f=null,p=null,x=!1,m=null,g=0,b=!1;const E={dir:e,feeds:n,screens:i,site:I=>r.get(I),select(I){w(!1),h==null||h.focus(I)},play(I){const X=r.get(I);if(!X)return;if(c(I),w(!1),y.select(I),f===I&&d){h==null||h.play(I),d.win.minimized?d.win.restore():d.win.focus();return}const st=d;d=null,f=null,st==null||st.win.close(),history.replaceState(null,"",`${Eo()}#${I}`);const dt=a.get("home");dt&&!dt.minimized&&h&&(dt.minimize(),b=!0);const lt=++g,Ot=Dt=>{if(lt===g){if(!Dt){h==null||h.eject(),history.replaceState(null,"",Eo());const Vt=a.get("home");b&&(Vt!=null&&Vt.minimized)&&Vt.restore(),b=!1;return}f=I,h==null||h.keepAlive(I),d=new _y(X,E,a,()=>{if(f!==I)return;d=null,f=null,h==null||h.keepAlive(null),h==null||h.eject(),(h==null?void 0:h.focusedId)===I&&h.focus(null),history.replaceState(null,"",Eo());const Vt=a.get("home");b&&(Vt!=null&&Vt.minimized)&&Vt.restore(),b=!1})}};h?h.play(I).then(Ot):Ot(!0)},open(I,X){if(X==null||X.preventDefault(),x)return;if(yc(I.href)){window.open(I.href,"_blank","noopener"),M.balloon(`${I.title} opened`,"It opened in a new window. The room is still here.");return}const st=I.href;x=!0,M.balloon(`Opening ${I.title}`,"tuning in…",void 0,2e3);let dt=!1;const lt=()=>{dt||(dt=!0,location.assign(st))};h?h.dive(I.id).then(lt):lt(),setTimeout(lt,1500)},look(I){w(!1),h==null||h.focus(I)},get canTune(){return!!h},tuneIn(I){const X=r.get(I);if(!h||!(X!=null&&X.tune))return;const st=typeof X.tune=="string"?X.tune:X.href;w(!1);const dt=a.list.filter(ne=>!ne.minimized&&!ne.opts.dialog);for(const ne of dt)ne.minimize();M.hideBalloon();const lt=W("div",{class:"oikos-tube"});lt.style.setProperty("--glow",X.accent);const Ot=W("iframe",{src:st,title:`${X.title}, live`,allow:"autoplay; fullscreen; clipboard-write"});lt.append(Ot,W("i",{class:"roll"}),W("i",{class:"glass"})),Ot.addEventListener("load",()=>{var ne;try{(ne=Ot.contentWindow)==null||ne.addEventListener("keydown",ce=>{var Ce;const he=ce.target;ce.key!=="Escape"||ce.defaultPrevented||(Ce=he==null?void 0:he.closest)!=null&&Ce.call(he,"input, textarea, [contenteditable]")||w(!0)})}catch{}});const Dt=W("div",{class:"oikos-tuned",role:"toolbar","aria-label":"tuned in"});Dt.innerHTML=`${Sn(X.accent)}tuned in · live on its screen`,Dt.querySelector("b").textContent=X.title;const Vt=W("button",{class:"xp-btn",type:"button"},["⏏ Eject"]);Vt.addEventListener("click",()=>w(!0));const jt=W("a",{class:"xp-btn",href:X.href},["Open full ↗"]);yc(X.href)&&(jt.setAttribute("target","_blank"),jt.setAttribute("rel","noopener")),Dt.append(Vt,jt),m={id:I,bar:Dt,hidden:dt,tube:lt};const Qt=ne=>{const ce=Math.round(Math.min(1024,Math.max(420,ne.width*1.15))),he=Math.round(ce*.75);lt.style.width=`${ce}px`,lt.style.height=`${he}px`,lt.style.transform=`translate(${ne.left}px, ${ne.top}px) scale(${ne.width/ce}, ${ne.height/he})`};h.tuneIn(I,Qt).then(()=>{(m==null?void 0:m.bar)===Dt&&(s.append(lt,Dt),Ot.focus())})},chat(I){w(!1),p||(p=new vy(E,a,()=>p=null)),p.focus(I)},home(){c("~"),w(!1),y.open(),h==null||h.scroll("~ home")},eject(){w(!1),d==null||d.win.close(),h==null||h.eject(),h==null||h.focus(null)},balloon(I,X,st){M.balloon(I,X,st)},back:()=>u(-1),forward:()=>u(1),get canBack(){return l.i>0},get canForward(){return l.il.listeners.delete(I)},about:()=>C()},y=new oy(E,a),M=new yy(s,E,a,{standby:I=>L(I),turnOff(){s.classList.add("off"),setTimeout(()=>location.assign("/"),t?50:750)},logOff(){w(!1);for(const I of[...a.list])I.close();h==null||h.eject(),h==null||h.focus(null),history.replaceState(null,"",Eo()),M.balloon("Logged off","The desk is clear. Click the VCR to begin again.",(h==null?void 0:h.anchor("vcr"))??void 0)},restart(){try{sessionStorage.removeItem("oikos-booted")}catch{}location.reload()}});function w(I){if(!m)return;const{id:X,bar:st,hidden:dt,tube:lt}=m;if(m=null,st.remove(),lt.remove(),h==null||h.tuneOut(),!!I){for(const Ot of dt)Ot.closed||Ot.restore();h==null||h.focus(X)}}function C(){var Vt;(Vt=a.get("about"))==null||Vt.close();const I=W("div",{class:"xp-about-box"}),X=W("div",{class:"band",html:pr(44,!0)});X.append(W("b",{},["æthera"]),W("span",{},["oikos"]));const st=W("div",{class:"xp-dialog-body"}),dt=W("div");dt.append(W("p",{},["æthera · the home directory"]),W("p",{},["Version 1998 (Build 2026.present_day)"]),W("p",{},["A room of screens wired to one VCR, and every part of the site playing at once."]),W("p",{class:"lic"},["This product is licensed under CC BY 4.0 to:"]),W("p",{},["guest"])),st.append(dt);const lt=W("div",{class:"xp-actions"}),Ot=W("button",{class:"xp-btn default",type:"button"},["OK"]);lt.append(Ot),I.append(X,st,lt);const Dt=a.open({id:"about",title:"About æthera",icon:Zu(),body:I,width:400,dialog:!0});Ot.addEventListener("click",()=>Dt.close()),Ot.focus()}if(wy())try{h=new G_(s,e.sites,i,{pick(I){D(),M.hideBalloon(),M.showTip(null,null,0,0),I==="vcr"?E.home():I?E.play(I):h!=null&&h.focusedId&&!d&&!h.busy&&h.focus(null)},hover(I,X,st){I==="vcr"?M.showTip(null,{title:"VCR",text:"your home directory · click to open ~"},X,st):M.showTip(I?r.get(I)??null:null,null,X,st)}})}catch(I){console.warn("oikos: the room would not build; running the desktop alone",I),h==null||h.stop(),h=null}if(h==null||h.renderer.domElement.addEventListener("pointerdown",()=>a.deactivate()),sy(s,(I,X)=>{var Ot,Dt;const st=I.closest(".xp-tile");if(st)return st.dataset.id?y.contextFor(st.dataset.id):null;if(I.closest("a"))return null;if(I.closest(".xp-content")&&((Dt=(Ot=I.closest(".xp-window"))==null?void 0:Ot.getAttribute("aria-label"))!=null&&Dt.startsWith("~")))return y.blankMenu();if(I.closest(".xp-window, .xp-startmenu, .xp-shutdown, .xp-menu, .xp-balloon"))return[];if(!h||I!==h.renderer.domElement)return[];const dt=h.pickFromPoint(X.clientX,X.clientY);if(dt==="vcr")return[{label:"Open ~",bold:!0,run:()=>E.home()},{label:"Eject",run:()=>E.eject(),disabled:!f},"sep",{label:"Properties",disabled:!0}];const lt=dt?r.get(dt):void 0;return lt?wo(E,lt):[{label:"Arrange Icons By",disabled:!0,submenu:()=>[]},{label:"Refresh",run:()=>h==null?void 0:h.focus(null)},"sep",{label:"Paste",disabled:!0},{label:"Paste Shortcut",disabled:!0},"sep",{label:"New",disabled:!0,submenu:()=>[]},"sep",{label:"~ Home directory",run:()=>E.home()},{label:"Properties",disabled:!0}]}),!h){let I=performance.now();const X=st=>{var lt;requestAnimationFrame(X);const dt=Math.min(.1,(st-I)/1e3);I=st,f&&((lt=i.get(f))==null||lt.tick(st/1e3,dt,!0))};requestAnimationFrame(X)}const v=()=>{if(!h)return;const I=innerWidth,X=innerHeight-30,st=a.list.filter(Ot=>!Ot.minimized&&!Ot.opts.dialog&&!Ot.el.classList.contains("maximized"));if(I<=720){h.setShift(0,st.length?X*.3:0);return}let dt=0,lt=I;for(const Ot of st){const Dt=Ot.el.getBoundingClientRect();Dt.left+Dt.width/2[X.channel,I])),Y=e.sites.map(I=>I.id).sort((I,X)=>{var st,dt;return(((st=wr[I])==null?void 0:st.channel)??99)-(((dt=wr[X])==null?void 0:dt.channel)??99)});let K="",N=0;addEventListener("keydown",I=>{if(T){D();return}const X=I.target;if(!X.closest("input, textarea")){if(I.key==="Escape"&&m){w(!0);return}if(!m){if(I.key==="Escape"){if(Mi()||M.dismiss()||!B())return;const st=a.activeWindow;if(st!=null&&st.opts.dialog&&!st.minimized){st.close();return}h!=null&&h.focusedId&&h.focus(null);return}if(I.altKey&&(I.key==="ArrowLeft"||I.key==="ArrowRight")){I.preventDefault(),u(I.key==="ArrowLeft"?-1:1);return}if(!X.closest(".xp-window, .xp-startmenu, .xp-menu, .xp-shutdown")){if(I.key==="~"||I.key==="Home"){E.home();return}if((I.key==="ArrowRight"||I.key==="ArrowLeft")&&!(h!=null&&h.busy)){const st=h!=null&&h.focusedId&&h.focusedId!=="vcr"?Y.indexOf(h.focusedId):-1,dt=Y[(st+(I.key==="ArrowRight"?1:-1)+Y.length)%Y.length];if(dt){h==null||h.focus(dt),y.select(dt);const lt=h==null?void 0:h.anchor(dt),Ot=r.get(dt);lt&&Ot&&M.showTip(Ot,null,lt.x-40,lt.y-50)}return}if(I.key==="Enter"&&(h!=null&&h.focusedId)&&h.focusedId!=="vcr"){E.play(h.focusedId);return}/^[0-9]$/.test(I.key)&&(K=(K+I.key).slice(-2),clearTimeout(N),h==null||h.scroll(`ch ${K}`),N=window.setTimeout(()=>{const st=U.get(Number(K));K="",st&&r.has(st)&&E.play(st)},700))}}}});function B(){const I=s==null?void 0:s.querySelector(".xp-startmenu");return I&&!I.hidden?(M.toggleMenu(!1),!1):!0}let z=!1;document.addEventListener("visibilitychange",()=>{document.hidden?(h==null||h.stop(),n.stop(),m&&w(!0)):z&&(h==null||h.start(),n.start())}),addEventListener("pageshow",I=>{I.persisted&&(x=!1,s.classList.remove("off"),h==null||h.reset())});const Z=document.getElementById("oikos-boot");let nt=!1;try{nt=!!sessionStorage.getItem("oikos-booted"),sessionStorage.setItem("oikos-booted","1")}catch{}const rt=t||nt?250:1900;let ot=()=>{};const ht=new Promise(I=>ot=I);Z==null||Z.addEventListener("click",()=>ot());const Gt=Promise.race([Promise.all([(ee=document.fonts)==null?void 0:ee.load('16px "Libertinus Mono"'),(Q=document.fonts)==null?void 0:Q.load('16px "Love Letter Typewriter"')]).then(()=>{},()=>{}),new Promise(I=>setTimeout(I,1500))]),me=(h==null?void 0:h.warm())??Promise.resolve();Promise.race([Promise.all([Gt,me,new Promise(I=>setTimeout(I,rt))]),ht]).then(()=>{z=!0,document.hidden||(n.start(),h==null||h.start()),h==null||h.powerOn(),Z==null||Z.classList.add("gone"),setTimeout(()=>Z==null?void 0:Z.remove(),800);const I=new URLSearchParams(location.search).get("look");I&&h&&(I==="vcr"||r.has(I))&&setTimeout(()=>h==null?void 0:h.focus(I),300);let X="";try{X=decodeURIComponent(location.hash.slice(1))}catch{}if(X==="mirc"){setTimeout(()=>E.chat(),600);return}if(X&&r.has(X)){setTimeout(()=>E.play(X),900);return}if(!h){E.home(),M.balloon("No room tonight","This browser has no WebGL, so the room of screens is dark. The tapes all still play.");return}setTimeout(()=>{if(a.list.length)return;const st=(h==null?void 0:h.anchor("vcr"))??void 0;M.balloon("This is the way in",innerWidth<=720?"Tap the VCR for the home directory, or any screen to tune in. Drag to look around.":"Click the VCR for your home directory, or any screen to tune in. Drag to look around; ← → walk the screens.",st,11e3,!0)},nt?900:2600)})}function Ty(s,t,e,n){var a;(a=document.getElementById("oikos-boot"))==null||a.remove();const i=W("div");i.style.cssText="position:absolute;inset:0;overflow:auto;padding:16px;display:grid;gap:14px;grid-template-columns:repeat(auto-fill,minmax(360px,1fr));background:#0a0a0a;";for(const l of t){const c=e.get(l.id);if(!c)continue;const u=W("figure");u.style.cssText="margin:0;color:#aaa;font:12px ui-monospace,monospace;",c.canvas.style.cssText="width:100%;display:block;border:1px solid #333;";const h=W("figcaption",{},[`${l.title} · ${l.kind}`]);h.style.padding="4px 0",u.append(c.canvas,h),i.append(u)}s.append(i),n.start();let r=performance.now();const o=l=>{requestAnimationFrame(o);const c=Math.min(.1,(l-r)/1e3);r=l;for(const u of e.values())u.tick(l/1e3,c,!1)};requestAnimationFrame(o)}})(); diff --git a/aethera/templates/afterlife/viewer.html b/aethera/templates/afterlife/viewer.html new file mode 100644 index 0000000..9d6bcaf --- /dev/null +++ b/aethera/templates/afterlife/viewer.html @@ -0,0 +1,97 @@ +{% extends "base.html" %} + +{% block title %}afterlife | æthera{% endblock %} + +{% block meta %} + + + + + + + + + + + +{% endblock %} + +{% block schema %}{% endblock %} + +{% block extra_head %} + + +{% endblock %} + +{% block content %} +{# + Keep this skeleton in step with afterlife/index.html (the dev page). It + lives in the template rather than being built by main.ts so the splash + paints before the bundle has parsed. + + hx-boost="false" on the way out is load-bearing (see syrinx/viewer.html): + an htmx swap would leave the universe, its AudioContext and its loop + running under the next page. A real navigation also fires pagehide, which + is when the universe is saved. +#} + +
+ +
+ +

afterlife

+

the game of life, after hours

+

click to listen · ? for the keys · q to leave, if you can

+
+ + +
+{% endblock %} + +{% block scripts %} + +{% endblock %} diff --git a/afterlife/README.md b/afterlife/README.md new file mode 100644 index 0000000..0c2a216 --- /dev/null +++ b/afterlife/README.md @@ -0,0 +1,101 @@ +# afterlife + +> *the game of life, after hours.* A web port of +> [afterlife](https://github.com/LuxiaSL/afterlife), the terminal screensaver. +> Served at **`/afterlife`**, and on channel 10 in [oikos](../oikos). + +Conway's Life on a toroidal world five times the size of the screen. A camera +steers toward the drama. A dramaturge stages collisions and aims gliders at +the citizens it has recognised. A ticker muses. The music scores it all, and +`g` brings back the bug that painted the void magenta. + +It is meant to be the same program, not a tribute. The terminal was the +medium, so the page is a terminal: a canvas drawn as a grid of character +cells. Every cell is an upper-half block in the same xterm-256 colours curses +asked for, and the status line keeps to the grid one glyph per column. + +## Faithful, and how we know + +The engine (`src/engine/`) and the music (`src/music/engine.ts`) are +method-for-method ports of `life.py` and `life_music.py`. Two scripts replay +the Python original and compare the results: + +```bash +# needs the afterlife checkout and a Python with numpy + scipy +python scripts/parity.py /path/to/afterlife > /tmp/parity.json +npm run parity -- /tmp/parity.json # "the same universe ✓" + +python scripts/parity_music.py /path/to/afterlife > /tmp/music.json +npm run parity-music -- /tmp/music.json # "the same music ✓" +``` + +`parity` seeds `life.py`'s `InfiniteLife` and takes out the dice (the +injections are the only randomness a replay can't share). Then it checks the +port step by step: population, pop floor, spread, cycle detection, engine +events, camera, auto-zoom, mood and time dilation. At the end it checks the +final ages, the display maps at all five zooms, the census (the original's is +scipy), auto-focus, a pan/zoom, and haunted mode. All of it matches exactly. +`parity-music` feeds both engines the same scripted evening: a boom, a broken +cycle and its cadence, two style crossfades, noise bursts, and epoch roots. +Every sample matches within float32 rounding (worst |Δ| ≈ 2e-7). + +## What changed for the web, and why + +- **The universe lives in localStorage** (`afterlife-universe-v1`), not + `universe.npz`. It is saved when you leave (`pagehide`, or the tab being + hidden) and every 5000 generations, and resumed on the next visit with + *the universe remembers generation N*. Only ages are stored, sparsely (the + grid is exactly `age > 0`), because a save must be synchronous on the way + out. oikos reads the same key, so its screen runs *your* universe. +- **Music waits for a gesture.** Browsers only start sound from a click or a + key, so the splash asks for one. Until then the status line shows no music, + just as the terminal did without PyAudio. The engine runs in an + AudioWorklet at 44.1 kHz and renders the same 2048-frame buffers PyAudio + asked for, because its smoothing constants are per buffer. `vite.config.ts` + bundles the worklet with esbuild and inlines it into the page. +- **`q` leaves**: back where you came from, or to æthera. Inside an oikos + screen it can't leave, and the ticker says so; ⏏ is on the other side of the + glass. **`d`** records snapshots as before and downloads `snapshots.jsonl` + when you stop (`life_music_diag.py --replay` reads it). `life_stats.csv` is + kept in memory and downloads from the keys panel. +- **More than a terminal's mouse.** A click still toggles a cell. You can + also drag to draw life, right-drag or shift-drag to pan, and scroll to zoom. + On touch: tap to toggle, drag to pan, pinch to zoom. The **keys** panel + (`?`) lists every key and runs it on click, for phones. +- **Narrow screens get a two-line status.** On a phone the ticker would lose + its room to the stats and fall back to the terminal's compact line, so the + ticker gets a line of its own instead. The sparkline shortens to fit. +- **Resizing keeps the universe**, as `KEY_RESIZE` did: it is adopted, + centred, into the new world. +- Two display caches are now invalidated on pan, zoom and toggle. In the + terminal, a pan or click made while paused didn't show until you unpaused. + +## Layout + +``` +src/engine/ life.ts (InfiniteLife), census, ticker, musings, constants, persist, stats +src/term/ render.ts (the terminal: grid, status line, stats overlay), palette.ts (xterm-256) +src/music/ engine.ts (LifeMusicEngine), worklet.ts, audio.ts (the page's side) +src/main.ts life.py's main(): the loop, keys, pointer, splash, persistence +scripts/ parity checks, bench.ts (life_bench.py), shot.mjs (headless screenshots) +``` + +The engine and renderer have no DOM dependencies beyond a 2D context, so +oikos imports them directly (`oikos/src/screens/afterlife.ts`). + +## Build + +Like syrinx, apeiron and oikos, the built bundle is committed. The Docker +image never runs npm, so rebuild and commit whenever `src/` changes. Rebuild +oikos too if `src/engine` or `src/term` changed, since it bundles them. + +```bash +npm install +npm run build # → ../aethera/static/afterlife/afterlife.{js,css} +npm run dev # the standalone index.html on :5198 +npm run bench # per-frame cost, headless (240×66 terminal by default) +npm run shot -- out/ [url] # splash, lived, stats, haunted, keys, resume, phone +``` + +`shot` wants Playwright's Chromium. Set `CHROMIUM=/path/to/chrome` if the +downloaded one doesn't match. diff --git a/afterlife/index.html b/afterlife/index.html new file mode 100644 index 0000000..8a60ba7 --- /dev/null +++ b/afterlife/index.html @@ -0,0 +1,77 @@ + + + + + + afterlife + + + + +
+ +
+ +

afterlife

+

the game of life, after hours

+

click to listen · ? for the keys · q to leave, if you can

+
+ + +
+ + + diff --git a/afterlife/package-lock.json b/afterlife/package-lock.json new file mode 100644 index 0000000..da8b8c5 --- /dev/null +++ b/afterlife/package-lock.json @@ -0,0 +1,1689 @@ +{ + "name": "afterlife", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "afterlife", + "version": "1.0.0", + "devDependencies": { + "@types/node": "^22.20.4", + "playwright": "^1.61.1", + "tsx": "^4.19.0", + "typescript": "^5.6.0", + "vite": "^6.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^22.20 || ^24.12 || >=25" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.63.5.tgz", + "integrity": "sha512-J25QJU+B78T4FhhBsNpLJyVWOi31mwtpcMwywHmOKH65Q9IWGA81gPj+dnwlhU8wktVriYE+tFAaQgrnJRzAZg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.63.5.tgz", + "integrity": "sha512-LDopB3zuZM5Ux9TT2luNEBJW/tYbGU2g1d+VpKk6I+gSKDb+/7sYE6M225gRQt4RbMX6MSwMsVR/phdjVUgRLg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.63.5.tgz", + "integrity": "sha512-wlJEERGfeuHeBavCL2qVnNacOK43NDoZM4sjkeRPymd04OAE9T1zBqDJgmZ+CIsPTYKwdzpUC8vmOw84dwY4Tg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.63.5.tgz", + "integrity": "sha512-4nJJGg5jbo2wwPP4JP+LfEBA3bvP8rU9CLuhp7jWvq9sxEyhjQFTFdrqi+/dHEin/pd8jpT0vcehIpnZtmEdcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.63.5.tgz", + "integrity": "sha512-DrZbyCDF1hneuO6jRbvZ2D7+PIBM6yIwYnJpg2vIk58T+wuFpiaGZrfUr59lDWw45bg+IrpTGLPiNi/Fk4w3Cg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.63.5.tgz", + "integrity": "sha512-gqfUVMJMB3mehqywxp6hTBFfgtMQykZY19+cfiaYP0toIJLb/1DZRJHVkQQGP13W4TAwfZDWeg1qBcheTRioXQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.63.5.tgz", + "integrity": "sha512-CFmhpvAwzSaWMlN3VN7UtmoTihlZNzoP0juQib5TQRnYUyDV8dXeWOp29sobWAT6gXl/hQgAClLlEiYozQG3OQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.63.5.tgz", + "integrity": "sha512-Uc9H8eXCOayV6JLTH5bXKMId6qbhNHa818/BgYjm4jrlq3vZquC9cqyvHBw17xy5Mnj5f+I3gFK5JcEf3hSqrw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.63.5.tgz", + "integrity": "sha512-VcPr/szv/1BFw112Kt//fxulXt/JPqzzidU84iW68L2DdjnOO8QFUv2zTSYBEPHD6movBD4z+bbr5y60GYM7Jw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.63.5.tgz", + "integrity": "sha512-BnxtJ5/91BrIHYIkGrmjz/lbMhqEHt1dPFqIxIFR+jPn0xVc/oUSCtIT089zfp5ufwGDlYz2UC+Fe1SRBpYFbQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.63.5.tgz", + "integrity": "sha512-LrYcHZwF+fAMNKHYTOQ5osWM4AZF7YF6D+XtsjDyEvljtt11twc+zHVXBLNEjxVSUnKYsOhvVz4Z213eW02COQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.63.5.tgz", + "integrity": "sha512-nj7QKQePAAUpCpJHtg0pR0W/b92A9NO17JS3BAQmHDn/yhmkir2p8llrKY9TOhleKIaSzy1JhxS3T9FVld6coA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.63.5.tgz", + "integrity": "sha512-5ylkX6dWMeBKge9nTU+Rxfb+ZfaCIJ9lRqIFaK0eAMcWp7OJbYnLveLgXmm0VrvuLKb8qIK+mHyH0qu88RM+iA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.63.5.tgz", + "integrity": "sha512-oHK4ZHYFDKjZviK34I+NwgfbGxgI7ztrNxj2hPTSSNFgeq1a/lEd7dHV2fdGAuTH4Iym3RHJg+vAbWaWG4B7Zg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.63.5.tgz", + "integrity": "sha512-UcetmHZ6XOXuUByiKZyQmb55ZPr0LABr3Ec/HB9wKZn6CEAFWZkE+hsJErJ9hbPBC7nI0dKuELx7CoV6IM7TMg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.63.5.tgz", + "integrity": "sha512-C5CmDPQBtvjVo8cgQsBs+w6WB0JLkiixhgi6hVLV11hERWdn/p0XcPU2OUcZzac9BPOFq7SbaHFa8r3SWEysCQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.63.5.tgz", + "integrity": "sha512-lHVQHJFKsuuxLMi3MQO9XVL8Tje3JR82CzB+QDKC5NWBcsIWuwsn9uIM5e3lBhI+fF1/s63qnyYqsg65+8rV/w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.63.5.tgz", + "integrity": "sha512-3W9bTFcQNJn71cSJVM9RKIiZOy8DO/XLDii8Uv/Pm6WKqDRj7JV3ZfuXIEfyuy5LXpIzAbB/1M4Ukp9GKNa7nA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.63.5.tgz", + "integrity": "sha512-VDC7rRJlee/scpki96GZ27Omf6yU87s1YXwVTpjE5841faVlDYYT565rgfmoR1U0sqL7z5ivQSDjcsF6VRXyBA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.63.5.tgz", + "integrity": "sha512-z86Ok2p4pTdv5xqCKZsTooO7yBEiaJR/HzU3Wx8RmWsPoLppnMKROhJusQob8B3IE1ghC343kUW9rC2r+Wf3ig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.63.5.tgz", + "integrity": "sha512-IzQmj+xXwQFGhMAMKMQVXkMwMZN3TqkJgAE0nSsqvVwWWciP4AIPMmWRqOQ2GfX7TUDZr+xqGFcBS36CRPGw0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.63.5.tgz", + "integrity": "sha512-F6qpTaPc9bwBH85kjy0/BLmLSW1uv7AoOXCoRIkg2arlgCYlWYcAbiMkvZuAcaWk9TpCRG//okznLAqLGshkMw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.63.5.tgz", + "integrity": "sha512-igoDsTFhhwECBeGbUuLeIk7t8Y1apa+cs6mDWpx2EZ0ch7oEQgzHbFUXN9euoHekCAQzXdXApAGkV6jznS7tWw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.63.5.tgz", + "integrity": "sha512-U3teMeMbXFmaM5D+OTJpsOXd+wV/qftIeYF9kBKL4v73641qyJmoXFtA28DQLsnmlyayEsTe72xpLHrArq6vHw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.5.tgz", + "integrity": "sha512-ypfC34F3RKXvCXBglGqGMsUSMKlgwd1HX9AOAlx9RoZZ6GaI42YHVeKpzg3JG+wpBUJYTG+NNZhqbDWL8tBZkw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.20.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.4.tgz", + "integrity": "sha512-zJRE40jpHtKqE/C4fgHrAKQLJuSpzEnP9ff9Y7YtoR3Wd2pwqzlekDeEuUQXjRd+QCYnVnNwuJYmhdk9XV8gvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.19", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", + "integrity": "sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.7.tgz", + "integrity": "sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/playwright": { + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz", + "integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.63.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/playwright-core": { + "version": "1.63.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz", + "integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/postcss": { + "version": "8.5.28", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.28.tgz", + "integrity": "sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.18", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/rollup": { + "version": "4.63.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.63.5.tgz", + "integrity": "sha512-KRWwmNLlPw5M7HcdYfm15oBv9n9LPtjzpzCIxS/phwqvPyxHSoKX6Y2YU3pxSPfy0CLquVgsx/j/hBi6OvH1Nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.63.5", + "@rollup/rollup-android-arm64": "4.63.5", + "@rollup/rollup-darwin-arm64": "4.63.5", + "@rollup/rollup-darwin-x64": "4.63.5", + "@rollup/rollup-freebsd-arm64": "4.63.5", + "@rollup/rollup-freebsd-x64": "4.63.5", + "@rollup/rollup-linux-arm-gnueabihf": "4.63.5", + "@rollup/rollup-linux-arm-musleabihf": "4.63.5", + "@rollup/rollup-linux-arm64-gnu": "4.63.5", + "@rollup/rollup-linux-arm64-musl": "4.63.5", + "@rollup/rollup-linux-loong64-gnu": "4.63.5", + "@rollup/rollup-linux-loong64-musl": "4.63.5", + "@rollup/rollup-linux-ppc64-gnu": "4.63.5", + "@rollup/rollup-linux-ppc64-musl": "4.63.5", + "@rollup/rollup-linux-riscv64-gnu": "4.63.5", + "@rollup/rollup-linux-riscv64-musl": "4.63.5", + "@rollup/rollup-linux-s390x-gnu": "4.63.5", + "@rollup/rollup-linux-x64-gnu": "4.63.5", + "@rollup/rollup-linux-x64-musl": "4.63.5", + "@rollup/rollup-openbsd-x64": "4.63.5", + "@rollup/rollup-openharmony-arm64": "4.63.5", + "@rollup/rollup-win32-arm64-msvc": "4.63.5", + "@rollup/rollup-win32-ia32-msvc": "4.63.5", + "@rollup/rollup-win32-x64-gnu": "4.63.5", + "@rollup/rollup-win32-x64-msvc": "4.63.5", + "fsevents": "~2.3.2" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tsx": { + "version": "4.23.15", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.23.15.tgz", + "integrity": "sha512-Yiex1Ovn8z2xPpOWckIiysV1SSyRMY9BkLF++q0yKiDxCqRhosKfMg3janKkiLBwZ5c/YryloKwGZcrEmtwxKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz", + "integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" + } + } + } +} diff --git a/afterlife/package.json b/afterlife/package.json new file mode 100644 index 0000000..de82ae1 --- /dev/null +++ b/afterlife/package.json @@ -0,0 +1,22 @@ +{ + "name": "afterlife", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc --noEmit && vite build", + "typecheck": "tsc --noEmit", + "bench": "tsx scripts/bench.ts", + "parity": "tsx scripts/parity.ts", + "parity-music": "tsx scripts/parity-music.ts", + "shot": "node scripts/shot.mjs" + }, + "devDependencies": { + "@types/node": "^22.20.4", + "playwright": "^1.61.1", + "tsx": "^4.19.0", + "typescript": "^5.6.0", + "vite": "^6.0.0" + } +} diff --git a/afterlife/scripts/bench.ts b/afterlife/scripts/bench.ts new file mode 100644 index 0000000..4f6205b --- /dev/null +++ b/afterlife/scripts/bench.ts @@ -0,0 +1,48 @@ +/** + * bench.ts — how long a frame costs, headless (life_bench.py's job). + * + * npx tsx scripts/bench.ts [frames] [cols] [rows] [--haunted] + * + * Defaults to a 1920×1080 screen at 8px cells (240×67). Times the same + * per-frame work main.ts does, minus painting: step, the display maps, + * dilation, the activity centroid, and a census every 150 generations. + */ + +import { InfiniteLife } from '../src/engine/life'; + +const args = process.argv.slice(2).filter((a) => !a.startsWith('--')); +const frames = Number(args[0] ?? 500); +const cols = Number(args[1] ?? 240); +const rows = Number(args[2] ?? 66); +const life = new InfiniteLife(rows, cols); +if (process.argv.includes('--haunted')) life.toggleHaunted(); + +const t = { step: 0, display: 0, dilation: 0, census: 0 }; +const times: number[] = []; +const events: string[] = []; +for (let f = 0; f < frames; f++) { + const a = performance.now(); + const ev = life.step(); + const b = performance.now(); + life.displayGrid(); + life.displayAge(); + const c = performance.now(); + life.timeDilation(); + life.activityCenterX(); + const d = performance.now(); + if (life.generation % 150 === 0) life.takeCensus(); + const e = performance.now(); + t.step += b - a; + t.display += c - b; + t.dilation += d - c; + t.census += e - d; + times.push(e - a); + if (ev) events.push(`${life.generation}:${ev}`); +} +times.sort((x, y) => x - y); +const total = times.reduce((s, x) => s + x, 0); +console.log(`${cols}×${rows} terminal → world ${life.worldH}×${life.worldW}, ${frames} frames${life.haunted ? ', haunted' : ''}`); +console.log(`per frame: mean ${(total / frames).toFixed(2)} ms · p50 ${times[Math.floor(frames / 2)]?.toFixed(2)} · p95 ${times[Math.floor(frames * 0.95)]?.toFixed(2)} ms`); +for (const [k, v] of Object.entries(t)) console.log(` ${k.padEnd(9)} ${(v / frames).toFixed(2)} ms`); +console.log(`gen ${life.generation} · pop ${life.population()} · ${events.length} events · census ${JSON.stringify(Object.fromEntries(life.lastCensus))}`); +console.log(`last events: ${events.slice(-5).join(' ')}`); diff --git a/afterlife/scripts/parity-music.ts b/afterlife/scripts/parity-music.ts new file mode 100644 index 0000000..effd248 --- /dev/null +++ b/afterlife/scripts/parity-music.ts @@ -0,0 +1,72 @@ +/** + * parity-music.ts — does the port's music engine play the same evening? + * See scripts/parity_music.py, which records the original. + */ + +import { readFileSync } from 'node:fs'; +import { BUFFER_SIZE, LifeMusicEngine, SAMPLE_RATE, type SimulationSnapshot } from '../src/music/engine'; + +const file = process.argv[2]; +if (!file) { + console.error('usage: tsx scripts/parity-music.ts music.json'); + process.exit(2); +} +const want = JSON.parse(readFileSync(file, 'utf8')) as [number[], number[]][]; + +const pool = new Float32Array(SAMPLE_RATE); +for (let i = 0; i < pool.length; i++) { + // numpy: (sin(i·12.9898)·43758.5453 % 1.0)·2 − 1, with python's floored % + const v = Math.sin(i * 12.9898) * 43758.5453; + pool[i] = (((v % 1) + 1) % 1) * 2 - 1; +} + +const moods = ['', 'booming', 'booming', 'cycle', 'cycle', 'injection', 'declining', 'sparse', 'dense', 'stagnant', 'haunted']; +const epochs = ['genesis', 'genesis', 'primordial', 'emergence', 'expansion', 'deep time', 'eternity']; + +const eng = new LifeMusicEngine(); +(eng as unknown as { noisePool: Float32Array }).noisePool = pool; +let worst = 0; +let worstAt = ''; +let rms = 0; +let count = 0; +for (let b = 0; b < want.length; b++) { + if (b === 30 || b === 70) eng.cycleStyle(); + const rows = 60; + const snap: SimulationSnapshot = { + generation: b * 4, + population: 400 + 40 * b, + pop_floor: 300, + density: 0.01 + 0.002 * b, + spread: (b * 13) % 250, + cycle_period: moods[b % moods.length] === 'cycle' ? 3 : 0, + mood: moods[Math.floor(b / 3) % moods.length] ?? '', + epoch: epochs[Math.floor(b / 13) % epochs.length] ?? 'genesis', + pop_delta: [0, 5, 35, -60, 120, 0, -25][b % 7] ?? 0, + playhead_column: Array.from({ length: rows }, (_, r) => (r * 7 + b * 3) % 11 < 2), + playhead_position: (b % 30) / 30, + viewport_rows: rows, + event: b === 12 || b === 40 ? 'inject:heavy(cycle=3)' : b === 20 ? 'inject:edge' : '', + activity_x: 0.5 + 0.4 * Math.sin(b * 0.3), + }; + eng.update(snap); + const [l, r] = eng.renderStereo(BUFFER_SIZE); + const [wl, wr] = want[b] ?? [[], []]; + for (let i = 0; i < BUFFER_SIZE; i++) { + for (const [got, exp, ch] of [[l[i] ?? 0, wl[i] ?? 0, 'L'], [r[i] ?? 0, wr[i] ?? 0, 'R']] as const) { + const d = Math.abs(got - exp); + rms += exp * exp; + count++; + if (d > worst) { + worst = d; + worstAt = `buffer ${b} sample ${i} ${ch}: ${got} vs ${exp}`; + } + } + } +} +rms = Math.sqrt(rms / count); +console.log(`${want.length} stereo buffers · signal rms ${rms.toFixed(4)} · worst |Δ| ${worst.toExponential(2)} (${worstAt})`); +if (worst > 1e-4) { + console.log('the evening sounds different ✗'); + process.exit(1); +} +console.log('the same music ✓'); diff --git a/afterlife/scripts/parity.py b/afterlife/scripts/parity.py new file mode 100644 index 0000000..e042d9c --- /dev/null +++ b/afterlife/scripts/parity.py @@ -0,0 +1,104 @@ +""" +parity.py — run the original afterlife, and write down what it did. + +The web port claims to be the same universe. This drives life.py's own +InfiniteLife from a seeded genesis and records everything the port has to +reproduce: every step's population, telemetry, camera, zoom, mood and tempo, +then the final ages, the display maps at every zoom, the census, auto-focus, +and a stretch of haunted mode. scripts/parity.ts replays the same genesis +through the port and compares. + +The dice are taken out (injections become no-ops; their choices are the +one thing a replay can't share), which leaves the physics, the camera, the +infinity engine's telemetry and every read-out deterministic. + + python scripts/parity.py /path/to/afterlife > /tmp/parity.json + npx tsx scripts/parity.ts /tmp/parity.json + +Needs numpy and scipy (the census is scipy's in the original). +""" + +import json +import random +import sys + +import numpy as np + +sys.path.insert(0, sys.argv[1] if len(sys.argv) > 1 else ".") +import life # noqa: E402 + + +def sparse(a): + idx = np.flatnonzero(a) + return [[int(i), int(a.flat[i])] for i in idx] + + +def still(lf): + lf._inject = lambda *a, **k: None + lf._inject_from_edge = lambda *a, **k: None + lf._inject_garden = lambda *a, **k: None + lf._inject_provoke = lambda *a, **k: "" + lf._inject_collide = lambda *a, **k: False + + +def run(rows, cols, steps, seed, haunt_at=None, pan_at=None): + random.seed(seed) + np.random.seed(seed) + lf = life.InfiniteLife(rows, cols) + still(lf) + out = { + "rows": rows, "cols": cols, + "cam": [lf.cam_y, lf.cam_x], + "initial": sparse(lf.age), + "steps": [], + } + for s in range(steps): + if haunt_at is not None and s == haunt_at: + lf.toggle_haunted() + if pan_at is not None and s == pan_at: + lf.pan(7, -12) + lf.zoom_out() + event = lf.step() + dil = lf.time_dilation() + rec = { + "event": event, + "pop": lf.population(), + "floor": lf.pop_floor, + "spread": lf.spread, + "cycle": lf.cycle_period, + "cam": [lf.cam_y, lf.cam_x], + "zoom": lf.zoom_level, + "mood": lf._detect_mood(), + "dilation": dil, + "ax": lf.activity_center_x(), + } + if s % 150 == 149: + lf.take_census() + rec["census"] = dict(sorted(lf.last_census.items())) + rec["sites"] = sorted([list(x) for x in lf.last_census_sites]) + out["steps"].append(rec) + out["final_age"] = sparse(lf.age) + out["smooth_sum"] = float(lf.age_smooth.astype(np.float64).sum()) + out["activity_sum"] = float(lf.activity.astype(np.float64).sum()) + out["sparkline"] = lf.sparkline() + out["epoch"] = lf.epoch() + disp = {} + for z in range(life.MIN_ZOOM, life.MAX_ZOOM + 1): + lf.zoom_level = z + lf._disp_grid_cache = None + lf._disp_age_cache = None + g = lf.display_grid() + a = lf.display_age() + disp[str(z)] = {"g_shape": list(g.shape), "a_shape": list(a.shape), "g": sparse(g), "a": sparse(a)} + out["display"] = disp + lf.auto_focus() + out["focus"] = {"zoom": lf.zoom_level, "cam": [lf.cam_y, lf.cam_x]} + return out + + +cases = [ + run(30, 100, 600, 1), + run(40, 150, 400, 7, pan_at=120), + run(25, 90, 160, 3, haunt_at=60), +] +json.dump(cases, sys.stdout, default=lambda o: o.item()) diff --git a/afterlife/scripts/parity.ts b/afterlife/scripts/parity.ts new file mode 100644 index 0000000..2e64536 --- /dev/null +++ b/afterlife/scripts/parity.ts @@ -0,0 +1,160 @@ +/** + * parity.ts — is the port the same universe? + * + * Replays the genesis recorded by scripts/parity.py (life.py's own + * InfiniteLife, dice taken out) through the port and compares every step's + * read-outs, the final state, the display maps at every zoom, the census, + * auto-focus and haunted mode. Exits 1 on the first kind of mismatch it + * finds, after listing them. + * + * python scripts/parity.py /path/to/afterlife > /tmp/parity.json + * npx tsx scripts/parity.ts /tmp/parity.json + */ + +import { readFileSync } from 'node:fs'; +import { InfiniteLife } from '../src/engine/life'; + +type Sparse = [number, number][]; +interface Step { + event: string; + pop: number; + floor: number; + spread: number; + cycle: number; + cam: [number, number]; + zoom: number; + mood: string; + dilation: number; + ax: number; + census?: Record; + sites?: [string, number, number][]; +} +interface Case { + rows: number; + cols: number; + cam: [number, number]; + initial: Sparse; + steps: Step[]; + final_age: Sparse; + smooth_sum: number; + activity_sum: number; + sparkline: string; + epoch: string; + display: Record; + focus: { zoom: number; cam: [number, number] }; +} + +const file = process.argv[2]; +if (!file) { + console.error('usage: tsx scripts/parity.ts parity.json'); + process.exit(2); +} +const cases = JSON.parse(readFileSync(file, 'utf8')) as Case[]; +let failures = 0; +const fail = (what: string): void => { + failures++; + if (failures <= 40) console.log(` ✗ ${what}`); +}; +const close = (a: number, b: number, tol: number): boolean => Math.abs(a - b) <= tol * Math.max(1, Math.abs(b)); + +function sparse(a: ArrayLike): Sparse { + const out: Sparse = []; + for (let i = 0; i < a.length; i++) if (a[i]) out.push([i, a[i] ?? 0]); + return out; +} +function sameSparse(a: Sparse, b: Sparse): string | null { + if (a.length !== b.length) return `${a.length} vs ${b.length} nonzero`; + for (let i = 0; i < a.length; i++) { + if (a[i]?.[0] !== b[i]?.[0] || a[i]?.[1] !== b[i]?.[1]) return `first difference at ${JSON.stringify(a[i])} vs ${JSON.stringify(b[i])}`; + } + return null; +} + +cases.forEach((c, k) => { + console.log(`case ${k + 1}: ${c.cols}×${c.rows} terminal, ${c.steps.length} steps`); + const life = new InfiniteLife(c.rows, c.cols, false); + for (const [i, a] of c.initial) { + life.age[i] = a; + life.grid[i] = a > 0 ? 1 : 0; + life.ageSmooth[i] = a; + } + [life.camY, life.camX] = c.cam; + // the dice, taken out the same way parity.py takes them out + const l = life as unknown as Record; + l.inject = () => undefined; + l.injectFromEdge = () => undefined; + l.injectGarden = () => undefined; + l.injectProvoke = () => ''; + l.injectCollide = () => false; + + const hauntAt = k === 2 ? 60 : -1; + const panAt = k === 1 ? 120 : -1; + c.steps.forEach((want, s) => { + if (s === hauntAt) life.toggleHaunted(); + if (s === panAt) { + life.pan(7, -12); + life.zoomOut(); + } + const event = life.step(); + const dil = life.timeDilation(); + const got = { + event, pop: life.population(), floor: life.popFloor, spread: life.spread, cycle: life.cyclePeriod, + cam: [life.camY, life.camX], zoom: life.zoomLevel, mood: life.detectMood(), + }; + for (const key of ['event', 'pop', 'floor', 'spread', 'cycle', 'zoom', 'mood'] as const) { + if (got[key] !== want[key]) fail(`step ${s + 1} ${key}: ${JSON.stringify(got[key])} vs ${JSON.stringify(want[key])}`); + } + if (got.cam[0] !== want.cam[0] || got.cam[1] !== want.cam[1]) fail(`step ${s + 1} cam: ${got.cam} vs ${want.cam}`); + if (!close(dil, want.dilation, 1e-6)) fail(`step ${s + 1} dilation: ${dil} vs ${want.dilation}`); + if (!close(life.activityCenterX(), want.ax, 1e-4)) fail(`step ${s + 1} activity_x: ${life.activityCenterX()} vs ${want.ax}`); + if (want.census) { + life.takeCensus(); + const gotCensus = Object.fromEntries([...life.lastCensus.entries()].sort()); + if (JSON.stringify(gotCensus) !== JSON.stringify(want.census)) fail(`step ${s + 1} census: ${JSON.stringify(gotCensus)} vs ${JSON.stringify(want.census)}`); + const gotSites = life.lastCensusSites.map((x) => [...x]).sort(); + const wantSites = (want.sites ?? []).map((x) => [...x]).sort(); + if (JSON.stringify(gotSites) !== JSON.stringify(wantSites)) fail(`step ${s + 1} census sites differ`); + else console.log(` census at ${s + 1}: ${JSON.stringify(want.census)}`); + } + }); + + const d = sameSparse(sparse(life.age), c.final_age); + if (d) fail(`final ages: ${d}`); + let smooth = 0; + for (const v of life.ageSmooth) smooth += v; + let act = 0; + for (const v of life.activity) act += v; + if (!close(smooth, c.smooth_sum, 1e-5)) fail(`age_smooth sum ${smooth} vs ${c.smooth_sum}`); + if (!close(act, c.activity_sum, 1e-5)) fail(`activity sum ${act} vs ${c.activity_sum}`); + if (life.sparkline() !== c.sparkline) fail(`sparkline ${life.sparkline()} vs ${c.sparkline}`); + if (life.epoch() !== c.epoch) fail(`epoch ${life.epoch()} vs ${c.epoch}`); + + for (const [z, want] of Object.entries(c.display)) { + life.zoomLevel = Number(z); + (l as { dispGridCache: unknown }).dispGridCache = null; + (l as { dispAgeCache: unknown }).dispAgeCache = null; + const g = life.displayGrid(); + const a = life.displayAge(); + if (g.h !== want.g_shape[0] || g.w !== want.g_shape[1]) fail(`zoom ${z} grid shape ${g.h}×${g.w} vs ${want.g_shape}`); + if (a.h !== want.a_shape[0] || a.w !== want.a_shape[1]) fail(`zoom ${z} age shape ${a.h}×${a.w} vs ${want.a_shape}`); + const dg = sameSparse(sparse(g.data), want.g); + if (dg) fail(`zoom ${z} display grid: ${dg}`); + const da = sameSparse(sparse(a.data), want.a); + if (da) fail(`zoom ${z} display age: ${da}`); + } + + life.autoFocus(); + if (life.zoomLevel !== c.focus.zoom || life.camY !== c.focus.cam[0] || life.camX !== c.focus.cam[1]) { + fail(`auto_focus: zoom ${life.zoomLevel} cam ${life.camY},${life.camX} vs ${JSON.stringify(c.focus)}`); + } + const pops = c.steps.map((s) => s.pop); + const events = c.steps.filter((s) => s.event).length; + const cycles = c.steps.filter((s) => s.cycle).length; + console.log(` pop ${pops[0]} → ${pops[pops.length - 1]}, ${events} engine events, ${cycles} steps in a detected cycle`); +}); + +if (failures) { + console.log(`\n${failures} mismatch${failures === 1 ? '' : 'es'}`); + process.exit(1); +} +console.log('\nthe same universe ✓'); diff --git a/afterlife/scripts/parity_music.py b/afterlife/scripts/parity_music.py new file mode 100644 index 0000000..0057fcc --- /dev/null +++ b/afterlife/scripts/parity_music.py @@ -0,0 +1,71 @@ +""" +parity_music.py — record life_music.py rendering a scripted evening. + +A sequence of snapshots (a boom, a cycle broken by an injection — which +scores the cadence — a style switch mid-buffer-stream, population spikes for +the noise bursts, epochs changing the root) is fed to the original +LifeMusicEngine and every stereo buffer it renders is written down. +scripts/parity-music.ts renders the same evening through the port. + +The noise pool is the one random thing in the engine; both sides replace it +with the same deterministic sequence. + + python scripts/parity_music.py /path/to/afterlife > /tmp/music.json + npx tsx scripts/parity-music.ts /tmp/music.json +""" + +import json +import math +import sys + +import numpy as np + +sys.path.insert(0, sys.argv[1] if len(sys.argv) > 1 else ".") +import life_music as lm # noqa: E402 + +N = lm.BUFFER_SIZE + + +def pool(): + i = np.arange(lm.SAMPLE_RATE, dtype=np.float64) + return (np.sin(i * 12.9898) * 43758.5453 % 1.0 * 2 - 1).astype(np.float32) + + +def evening(): + """(buffer index → snapshot kwargs, controls)""" + moods = ["", "booming", "booming", "cycle", "cycle", "injection", "declining", "sparse", "dense", "stagnant", "haunted"] + epochs = ["genesis", "genesis", "primordial", "emergence", "expansion", "deep time", "eternity"] + for b in range(90): + rows = 60 + col = [((r * 7 + b * 3) % 11) < 2 for r in range(rows)] + yield b, dict( + generation=b * 4, + population=400 + 40 * b, + pop_floor=300, + density=0.01 + 0.002 * b, + spread=(b * 13) % 250, + cycle_period=3 if moods[b % len(moods)] == "cycle" else 0, + mood=moods[(b // 3) % len(moods)], + epoch=epochs[(b // 13) % len(epochs)], + pop_delta=[0, 5, 35, -60, 120, 0, -25][b % 7], + playhead_column=tuple(col), + playhead_position=(b % 30) / 30.0, + viewport_rows=rows, + event="inject:heavy(cycle=3)" if b in (12, 40) else ("inject:edge" if b == 20 else ""), + activity_x=0.5 + 0.4 * math.sin(b * 0.3), + ) + + +eng = lm.LifeMusicEngine() +eng._noise_pool = pool() +bufs = [] +for b, kw in evening(): + if b == 30: + eng.cycle_style() # → chiptune + if b == 70: + eng.cycle_style() # → ambient again + snap = lm.SimulationSnapshot(**kw) + eng.update(snap) + left, right = eng._render_stereo(N) + bufs.append([left.astype(float).tolist(), right.astype(float).tolist()]) +json.dump(bufs, sys.stdout) diff --git a/afterlife/scripts/shot.mjs b/afterlife/scripts/shot.mjs new file mode 100644 index 0000000..f23e2cb --- /dev/null +++ b/afterlife/scripts/shot.mjs @@ -0,0 +1,91 @@ +/** + * shot.mjs — headless screenshots, so the terminal can be looked at by eye + * without a human in the loop: the splash, the universe a little later, the + * stats overlay, haunted mode, the keys panel, a phone, and a resume. + * + * npm run dev & # or the real server + * node scripts/shot.mjs [url] + * + * `url` defaults to the dev page; pass http://localhost:8000/afterlife to + * shoot the site's own page. + */ + +import { chromium } from 'playwright'; + +const outdir = process.argv[2] ?? '.'; +const URL = process.argv[3] ?? 'http://localhost:5198/'; + +// CHROMIUM=/path/to/chrome when playwright's own download doesn't match its version +const browser = await chromium.launch({ + executablePath: process.env.CHROMIUM || undefined, + args: ['--autoplay-policy=no-user-gesture-required'], +}); +const errors = []; +const watch = (page) => { + page.on('console', (m) => m.type() === 'error' && errors.push(`[console] ${m.text()}`)); + page.on('pageerror', (e) => errors.push(`[pageerror] ${e.message}`)); +}; +const status = (page) => + page.evaluate(() => { + const a = window.afterlife; + const l = a.life; + return { gen: l.generation, pop: l.population(), zoom: l.zoomLevel, mood: l.detectMood(), haunted: l.haunted, cols: a.term.cols, rows: a.term.rows, ticker: l.ticker.messages.map((m) => m.text) }; + }); +try { + const ctx = await browser.newContext({ viewport: { width: 1600, height: 900 } }); + const page = await ctx.newPage(); + watch(page); + await page.goto(URL, { waitUntil: 'networkidle' }); + await page.waitForTimeout(1200); + await page.screenshot({ path: `${outdir}/a-splash.png` }); + await page.click('#splash'); + await page.waitForTimeout(9000); + await page.screenshot({ path: `${outdir}/b-lived.png` }); + console.log('lived', await status(page)); + + await page.keyboard.press('s'); + await page.waitForTimeout(1500); + await page.screenshot({ path: `${outdir}/c-stats.png` }); + await page.keyboard.press('s'); + + await page.keyboard.press('g'); + await page.waitForTimeout(6000); + await page.screenshot({ path: `${outdir}/d-haunted.png` }); + console.log('haunted', await status(page)); + await page.keyboard.press('g'); + + await page.keyboard.press('z'); + await page.keyboard.press('z'); + await page.waitForTimeout(1500); + await page.screenshot({ path: `${outdir}/e-zoomed-out.png` }); + await page.keyboard.press('h'); + + await page.keyboard.press('?'); + await page.waitForTimeout(300); + await page.screenshot({ path: `${outdir}/f-keys.png` }); + await page.keyboard.press('Escape'); + + // leave and come back: the universe remembers + const gen = (await status(page)).gen; + await page.evaluate(() => window.afterlife.persist()); + await page.reload({ waitUntil: 'networkidle' }); + await page.waitForTimeout(3000); + const back = await status(page); + console.log(`resumed: saved at gen ${gen}, back at gen ${back.gen}; ticker ${JSON.stringify(back.ticker)}`); + await page.screenshot({ path: `${outdir}/g-resumed.png` }); + + const phone = await browser.newContext({ viewport: { width: 390, height: 844 }, deviceScaleFactor: 3, isMobile: true, hasTouch: true }); + const p2 = await phone.newPage(); + watch(p2); + await p2.goto(URL, { waitUntil: 'networkidle' }); + await p2.tap('#splash'); + await p2.waitForTimeout(6000); + await p2.screenshot({ path: `${outdir}/h-phone.png` }); + console.log('phone', await status(p2)); +} finally { + await browser.close(); +} +if (errors.length) { + console.log(errors.join('\n')); + process.exitCode = 1; +} diff --git a/afterlife/src/engine/census.ts b/afterlife/src/engine/census.ts new file mode 100644 index 0000000..e4da2b9 --- /dev/null +++ b/afterlife/src/engine/census.ts @@ -0,0 +1,245 @@ +/** + * census.ts — who lives here. + * + * The simulation periodically identifies the famous citizens living in the + * viewport (spaceships, oscillators, and the common still-life ash) so the + * ticker can greet them by name. Recognition works by matching each small + * isolated cluster against dihedral-canonical signatures of every phase of + * every known pattern — signatures are generated by actually simulating the + * patterns, so the library below stays honest. + * + * life.py leans on scipy.ndimage for this (binary_dilation, label, + * find_objects). Those are small enough to write out, which also means the + * census works everywhere here; in the terminal it needed scipy. + */ + +import { PATTERNS, type Cells } from './constants'; + +/** name → [cells, period]. Spaceships/oscillators cover all their phases. */ +const CENSUS_SEEDS: Readonly> = { + block: [[[0, 0], [0, 1], [1, 0], [1, 1]], 1], + beehive: [[[0, 1], [0, 2], [1, 0], [1, 3], [2, 1], [2, 2]], 1], + loaf: [[[0, 1], [0, 2], [1, 0], [1, 3], [2, 1], [2, 3], [3, 2]], 1], + boat: [[[0, 0], [0, 1], [1, 0], [1, 2], [2, 1]], 1], + tub: [[[0, 1], [1, 0], [1, 2], [2, 1]], 1], + ship: [[[0, 0], [0, 1], [1, 0], [1, 2], [2, 1], [2, 2]], 1], + pond: [[[0, 1], [0, 2], [1, 0], [1, 3], [2, 0], [2, 3], [3, 1], [3, 2]], 1], + blinker: [[[0, 0], [0, 1], [0, 2]], 2], + toad: [[[0, 1], [0, 2], [0, 3], [1, 0], [1, 1], [1, 2]], 2], + beacon: [[[0, 0], [0, 1], [1, 0], [2, 3], [3, 2], [3, 3]], 2], + glider: [PATTERNS.glider ?? [], 4], + lwss: [PATTERNS.lwss ?? [], 4], + hwss: [PATTERNS.hwss ?? [], 4], + pulsar: [PATTERNS.pulsar ?? [], 3], + pentadecathlon: [PATTERNS.pentadecathlon ?? [], 15], +}; + +/** Larger clusters than this can't be any known pattern — skip early */ +export const CENSUS_MAX_CELLS = 60; +export const CENSUS_MAX_DIM = 20; + +/** A cropped bitmap: h rows × w cols, row-major, 0/1. */ +interface Bitmap { + h: number; + w: number; + bits: Uint8Array; +} + +/** + * Canonical signature over the 8 dihedral transforms of a cropped bitmap. + * life.py compares packbits byte strings; any canonical choice works as long + * as the library and the lookup share it, and this one is a plain string. + */ +function canonicalSignature(m: Bitmap): string { + let best: string | null = null; + for (let t = 0; t < 8; t++) { + const swap = t >= 4; // transpose first + const h = swap ? m.w : m.h; + const w = swap ? m.h : m.w; + let s = `${h}x${w}:`; + for (let r = 0; r < h; r++) { + for (let c = 0; c < w; c++) { + let rr = t & 1 ? h - 1 - r : r; + let cc = t & 2 ? w - 1 - c : c; + if (swap) [rr, cc] = [cc, rr]; + s += m.bits[rr * m.w + cc] ? '1' : '0'; + } + } + if (best === null || s < best) best = s; + } + return best ?? ''; +} + +let signatures: Map | null = null; + +/** + * Build (once) the signature → name table by simulating each seed pattern + * through all phases of its period on a quiet private grid. + */ +export function censusSignatures(): Map { + if (signatures) return signatures; + const sigs = new Map(); + for (const [name, [cells, period]] of Object.entries(CENSUS_SEEDS)) { + const h = Math.max(...cells.map(([r]) => r)) + 1; + const w = Math.max(...cells.map(([, c]) => c)) + 1; + // Room to breathe: patterns may grow/travel a little mid-phase + const size = Math.max(h, w) + 2 * (period + 4); + let grid = new Uint8Array(size * size); + const oy = Math.floor((size - h) / 2); + const ox = Math.floor((size - w) / 2); + for (const [r, c] of cells) grid[(oy + r) * size + ox + c] = 1; + + for (let p = 0; p < period; p++) { + const crop = cropToBbox(grid, size, size); + if (crop) { + const sig = canonicalSignature(crop); + if (!sigs.has(sig)) sigs.set(sig, name); + } + // One Life step (wrapping, as np.roll does; the grid is roomy enough) + const next = new Uint8Array(size * size); + for (let y = 0; y < size; y++) { + for (let x = 0; x < size; x++) { + let n = 0; + for (let dy = -1; dy <= 1; dy++) { + for (let dx = -1; dx <= 1; dx++) { + if (dy || dx) n += grid[((y + dy + size) % size) * size + ((x + dx + size) % size)] ?? 0; + } + } + const alive = grid[y * size + x] === 1; + next[y * size + x] = (alive && (n === 2 || n === 3)) || (!alive && n === 3) ? 1 : 0; + } + } + grid = next; + } + } + signatures = sigs; + return sigs; +} + +function cropToBbox(mask: Uint8Array, h: number, w: number): Bitmap | null { + let y0 = h; + let y1 = -1; + let x0 = w; + let x1 = -1; + for (let y = 0; y < h; y++) { + for (let x = 0; x < w; x++) { + if (!mask[y * w + x]) continue; + if (y < y0) y0 = y; + if (y > y1) y1 = y; + if (x < x0) x0 = x; + if (x > x1) x1 = x; + } + } + if (y1 < 0) return null; + const ch = y1 - y0 + 1; + const cw = x1 - x0 + 1; + const bits = new Uint8Array(ch * cw); + for (let y = 0; y < ch; y++) { + for (let x = 0; x < cw; x++) bits[y * cw + x] = mask[(y0 + y) * w + x0 + x] ?? 0; + } + return { h: ch, w: cw, bits }; +} + +export interface CensusResult { + counts: Map; + /** (name, row, col) in viewport coordinates, at most 48 */ + sites: [string, number, number][]; +} + +/** + * Count known patterns in a viewport-sized occupancy map (h × w, row-major). + * + * Small gaps are bridged with dilation before labeling so patterns with + * 8-disconnected parts (the pulsar) group as one cluster; each cluster is + * then matched against the canonical signature table. Returns null when the + * scene is too busy to be worth it (more than 400 clusters), as life.py does. + */ +export function census(occupied: Uint8Array, h: number, w: number): CensusResult | null { + const sigs = censusSignatures(); + + // binary_dilation(iterations=2) with scipy's default cross: a Manhattan + // radius-2 diamond around every occupied cell, clipped at the border. + const merged = new Uint8Array(h * w); + for (let y = 0; y < h; y++) { + for (let x = 0; x < w; x++) { + if (!occupied[y * w + x]) continue; + for (let dy = -2; dy <= 2; dy++) { + const yy = y + dy; + if (yy < 0 || yy >= h) continue; + const span = 2 - Math.abs(dy); + const xa = Math.max(0, x - span); + const xb = Math.min(w - 1, x + span); + merged.fill(1, yy * w + xa, yy * w + xb + 1); + } + } + } + + // label with 8-connectivity, raster order (scipy numbers labels the same way) + const labels = new Int32Array(h * w); + const boxes: { y0: number; y1: number; x0: number; x1: number }[] = []; + const stack: number[] = []; + for (let start = 0; start < h * w; start++) { + if (!merged[start] || labels[start]) continue; + const id = boxes.length + 1; + if (id > 400) return null; + const box = { y0: h, y1: -1, x0: w, x1: -1 }; + labels[start] = id; + stack.push(start); + while (stack.length) { + const i = stack.pop() ?? 0; + const y = Math.floor(i / w); + const x = i - y * w; + if (y < box.y0) box.y0 = y; + if (y > box.y1) box.y1 = y; + if (x < box.x0) box.x0 = x; + if (x > box.x1) box.x1 = x; + for (let dy = -1; dy <= 1; dy++) { + const yy = y + dy; + if (yy < 0 || yy >= h) continue; + for (let dx = -1; dx <= 1; dx++) { + const xx = x + dx; + if (xx < 0 || xx >= w) continue; + const j = yy * w + xx; + if (merged[j] && !labels[j]) { + labels[j] = id; + stack.push(j); + } + } + } + } + boxes.push(box); + } + if (boxes.length === 0) return null; + + const counts = new Map(); + const sites: [string, number, number][] = []; + boxes.forEach((box, k) => { + const id = k + 1; + const bh = box.y1 - box.y0 + 1; + const bw = box.x1 - box.x0 + 1; + // Dilated bbox is at most 4 wider than the pattern itself + if (bh > CENSUS_MAX_DIM + 4 || bw > CENSUS_MAX_DIM + 4) return; + const cluster = new Uint8Array(bh * bw); + let n = 0; + let sy = 0; + let sx = 0; + for (let y = 0; y < bh; y++) { + for (let x = 0; x < bw; x++) { + const i = (box.y0 + y) * w + box.x0 + x; + if (occupied[i] && labels[i] === id) { + cluster[y * bw + x] = 1; + n++; + sy += y; + sx += x; + } + } + } + if (n < 3 || n > CENSUS_MAX_CELLS) return; + const crop = cropToBbox(cluster, bh, bw); + const name = crop ? sigs.get(canonicalSignature(crop)) : undefined; + if (name === undefined) return; + counts.set(name, (counts.get(name) ?? 0) + 1); + if (sites.length < 48) sites.push([name, box.y0 + Math.floor(sy / n), box.x0 + Math.floor(sx / n)]); + }); + return { counts, sites }; +} diff --git a/afterlife/src/engine/constants.ts b/afterlife/src/engine/constants.ts new file mode 100644 index 0000000..5130dca --- /dev/null +++ b/afterlife/src/engine/constants.ts @@ -0,0 +1,144 @@ +/** + * constants.ts — the physics and the palette, as life.py has them. + * + * Numbers here are afterlife's own and are not tuned for the web: the port's + * promise is that the universe behaves the way it does in a terminal. + */ + +// ── Palette ───────────────────────────────────────────────────────────── +// Birth (cool indigo) → youth (violet) → maturity (claude amber) → ancient (white). +// xterm-256 colour numbers; term/palette.ts turns them into RGB. +export const GRADIENT: readonly number[] = [ + 17, 19, 21, // deep indigo → blue + 57, 93, // blue-violet → violet + 165, 163, // magenta + 204, 209, // salmon → orange + 214, 220, 231, // amber → gold → white +]; + +/** Ghost trail colours (very dim, nearly black — just a hint of motion) */ +export const GHOST_COLORS: readonly number[] = [236, 234]; +export const GHOST_FRAMES = GHOST_COLORS.length; + +// ── Haunted mode: a resurrected bug ───────────────────────────────────── +// An early version of afterlife had no `age < 0` guard on ghost decay, so +// every never-alive cell cycled 0 → -1 → … → -6 → 0 forever: the entire +// empty universe pulsed as synchronized ghosts. On terminals with extended +// colour pairs, the ghost pair ids (463–504) then overflowed the 8-bit pair +// field in the curses attr word and aliased into the gradient dual-pair +// table — painting the void magenta and orange, and leaving every glider's +// path visible forever as a phase-shifted trail. The tables below encode +// the exact colours that aliasing produced, on purpose this time. +export const HAUNT_FRAMES = 6; +/** The 21-colour gradient of the era, needed to decode the aliased pairs */ +const HAUNT_ERA_GRADIENT: readonly number[] = [ + 17, 18, 19, 20, 21, 57, 56, 93, 129, 165, 164, + 163, 198, 204, 203, 209, 208, 214, 220, 229, 231, +]; +const era = (i: number): number => HAUNT_ERA_GRADIENT[i] ?? 0; +/** Single ghost over true emptiness: pairs 463–468 → dual table idx 185+i. [fg, bg] */ +export const HAUNT_SINGLE: readonly (readonly [number, number])[] = Array.from( + { length: HAUNT_FRAMES }, + (_, i) => [era(Math.floor((185 + i) / 21)), era((185 + i) % 21)] as const, +); +/** Ghost over ghost (top phase i, bottom phase j): pairs 469–504 → idx 191+i*6+j. [fg, bg] */ +export const HAUNT_DUAL: readonly (readonly [number, number])[] = Array.from( + { length: HAUNT_FRAMES * HAUNT_FRAMES }, + (_, k) => [era(Math.floor((191 + k) / 21)), era((191 + k) % 21)] as const, +); + +// ── Activity field ────────────────────────────────────────────────────── +// A decaying map of recent change (births + deaths). This is how the +// universe senses itself: the camera steers toward it, injections read it +// to find dead zones and living targets, the music pans with it, and time +// dilation listens for its spikes. Half-life ≈ 34 steps at 0.98/step. +// The decay multiply touches the whole world, so it's batched: applied +// every ACTIVITY_DECAY_EVERY steps at DECAY^EVERY (same integral, 1/4 the +// memory traffic). +export const ACTIVITY_DECAY = 0.98; +export const ACTIVITY_DECAY_EVERY = 4; +export const ACTIVITY_DECAY_BATCH = Math.fround(ACTIVITY_DECAY ** ACTIVITY_DECAY_EVERY); + +/** Sparkline characters */ +export const SPARKS = '▁▂▃▄▅▆▇█'; + +// ── Zoom ──────────────────────────────────────────────────────────────── +export const MIN_ZOOM = -2; // 4× zoom out (each terminal pixel = 4×4 grid cells) +export const MAX_ZOOM = 2; // 4× zoom in (each grid cell = 4×4 terminal pixels) +export const ZOOM_LABELS: Readonly> = { + [-2]: '0.25x', [-1]: '0.50x', 0: ' 1.0x', 1: ' 2.0x', 2: ' 4.0x', +}; + +// ── Pattern library ───────────────────────────────────────────────────── +export type Cells = readonly (readonly [number, number])[]; + +/** (row, col) offsets, verbatim from life.py */ +export const PATTERNS: Readonly> = { + glider: [[0, 1], [1, 2], [2, 0], [2, 1], [2, 2]], + lwss: [[0, 1], [0, 4], [1, 0], [2, 0], [2, 4], [3, 0], [3, 1], [3, 2], [3, 3]], + hwss: [[0, 3], [0, 4], [1, 1], [1, 6], [2, 0], [3, 0], [3, 6], [4, 0], [4, 1], [4, 2], [4, 3], [4, 4], [4, 5]], + r_pentomino: [[0, 1], [0, 2], [1, 0], [1, 1], [2, 1]], + acorn: [[0, 1], [1, 3], [2, 0], [2, 1], [2, 4], [2, 5], [2, 6]], + diehard: [[0, 6], [1, 0], [1, 1], [2, 1], [2, 5], [2, 6], [2, 7]], + pi_heptomino: [[0, 0], [0, 1], [0, 2], [1, 1], [2, 1], [3, 0], [3, 2]], + b_heptomino: [[0, 1], [1, 0], [1, 2], [1, 3], [2, 0], [2, 1], [3, 1]], + gosper_gun: [[0, 24], [1, 22], [1, 24], [2, 12], [2, 13], [2, 20], [2, 21], [2, 34], [2, 35], [3, 11], [3, 15], [3, 20], [3, 21], [3, 34], [3, 35], [4, 0], [4, 1], [4, 10], [4, 16], [4, 20], [4, 21], [5, 0], [5, 1], [5, 10], [5, 14], [5, 16], [5, 17], [5, 22], [5, 24], [6, 10], [6, 16], [6, 24], [7, 11], [7, 15], [8, 12], [8, 13]], + pulsar: [[0, 2], [0, 3], [0, 4], [0, 8], [0, 9], [0, 10], [2, 0], [2, 5], [2, 7], [2, 12], [3, 0], [3, 5], [3, 7], [3, 12], [4, 0], [4, 5], [4, 7], [4, 12], [5, 2], [5, 3], [5, 4], [5, 8], [5, 9], [5, 10], [7, 2], [7, 3], [7, 4], [7, 8], [7, 9], [7, 10], [8, 0], [8, 5], [8, 7], [8, 12], [9, 0], [9, 5], [9, 7], [9, 12], [10, 0], [10, 5], [10, 7], [10, 12], [12, 2], [12, 3], [12, 4], [12, 8], [12, 9], [12, 10]], + pentadecathlon: [[0, 1], [1, 1], [2, 0], [2, 2], [3, 1], [4, 1], [5, 1], [6, 1], [7, 0], [7, 2], [8, 1], [9, 1]], +}; + +export const TRAVELLERS: readonly string[] = ['glider', 'lwss', 'hwss']; +export const METHUSELAHS: readonly string[] = ['r_pentomino', 'acorn', 'diehard', 'pi_heptomino', 'b_heptomino']; +export const OSCILLATORS: readonly string[] = ['pulsar', 'pentadecathlon']; + +/** + * Glider travel direction per place() rotation (verified empirically: one + * cell diagonally per 4 generations). [dy, dx] + */ +export const GLIDER_DIR: readonly (readonly [number, number])[] = [ + [1, 1], [1, -1], [-1, -1], [-1, 1], +]; + +// ── Symmetric garden patterns ────────────────────────────────────────── +// Beautiful hand-crafted symmetric structures for rare special injections. + +/** Reflect a quadrant pattern into full 4-fold symmetry around (0,0). */ +function mirror4(cells: Cells): [number, number][] { + const full = new Map(); + for (const [r, c] of cells) { + for (const [y, x] of [[r, c], [r, -c], [-r, c], [-r, -c]] as const) full.set(`${y},${x}`, [y, x]); + } + return [...full.values()]; +} + +export const GARDENS: readonly Cells[] = [ + // "Diamond pulsar" — a radially symmetric oscillator seed + mirror4([ + [0, 1], [0, 2], [0, 3], + [1, 0], [1, 4], + [2, 0], [2, 5], + [3, 0], [3, 5], + [4, 1], [4, 5], + [5, 2], [5, 3], [5, 4], + ]), + // "Cross bloom" — explodes outward from a cross shape + mirror4([ + [0, 1], [0, 2], [0, 3], [0, 4], + [1, 0], [2, 0], [3, 0], [4, 0], + [2, 2], [3, 3], + ]), + // "Ring of life" — a hollow circle that breaks into travelers + mirror4([ + [0, 3], [0, 4], + [1, 2], [1, 5], + [2, 1], [2, 6], + [3, 0], [3, 7], + [4, 0], [4, 7], + [5, 1], [5, 6], + [6, 2], [6, 5], + [7, 3], [7, 4], + ]), +]; + +/** generations between autosaves (plus a save whenever the page is left) */ +export const AUTOSAVE_EVERY = 5000; diff --git a/afterlife/src/engine/life.ts b/afterlife/src/engine/life.ts new file mode 100644 index 0000000..849c80a --- /dev/null +++ b/afterlife/src/engine/life.ts @@ -0,0 +1,1410 @@ +/** + * life.ts — the universe. + * + * An infinite, self-sustaining Game of Life with zoom, ported from + * afterlife's InfiniteLife (life.py) method for method. The simulation grid + * extends well beyond the viewport. A camera tracks the centre of activity, + * and life is periodically injected from beyond the visible edge. Zoom lets + * you pull back to see the macro structure or push in to watch individual + * interactions. + * + * Nothing in here touches the DOM: the page (main.ts) and oikos's screen + * both drive this same class, and scripts/ drive it from node. + * + * Where numpy did a whole-array expression, this does one pass over typed + * arrays. The one structural change is in step(): life.py has two code paths + * (a zero-padded bounding box, and a toroidal full-world roll) that compute + * the same physics; here they are one loop over either region, with toroidal + * indexing throughout (inside a padded box that fits, the wrapped neighbours + * it reads are dead anyway, which is exactly the padding's promise). + */ + +import { census } from './census'; +import { + ACTIVITY_DECAY_BATCH, + ACTIVITY_DECAY_EVERY, + GARDENS, + GHOST_FRAMES, + GLIDER_DIR, + HAUNT_FRAMES, + MAX_ZOOM, + METHUSELAHS, + MIN_ZOOM, + OSCILLATORS, + PATTERNS, + SPARKS, + TRAVELLERS, +} from './constants'; +import { EPOCHS, SIGHTING_MIN_COUNT, SIGHTING_MUSINGS, SIGHTING_RARITY } from './musings'; +import { NewsTicker } from './ticker'; + +// ── python's random, as used by life.py ──────────────────────────────── +/** random.randint: inclusive at both ends */ +export const randint = (a: number, b: number): number => a + Math.floor(Math.random() * (b - a + 1)); +export const choice = (xs: readonly T[]): T => xs[Math.floor(Math.random() * xs.length)] as T; +/** python's // (floor division), which rounds toward -inf */ +const fdiv = (a: number, b: number): number => Math.floor(a / b); +const clampi = (v: number, lo: number, hi: number): number => Math.max(lo, Math.min(v, hi)); + +const F85 = Math.fround(0.85); +const F15 = Math.fround(0.15); + +/** np.percentile's default (linear) on a sorted array, then int() */ +function percentileInt(sorted: ArrayLike, p: number): number { + const n = sorted.length; + const pos = (p / 100) * (n - 1); + const lo = Math.floor(pos); + const hi = Math.min(n - 1, lo + 1); + const a = sorted[lo] ?? 0; + const b = sorted[hi] ?? 0; + return Math.trunc(a + (b - a) * (pos - lo)); +} + +/** A view-sized map: rows × cols, row-major. */ +export interface Plane { + h: number; + w: number; + data: T; +} + +/** What an adopted or saved universe carries (life.py's universe.npz). */ +export interface UniverseState { + h: number; + w: number; + /** ages: > 0 alive, < 0 ghost, 0 empty. The grid is exactly age > 0. */ + age: Int32Array; + generation: number; + totalInjections: number; +} + +export class InfiniteLife { + // view_h/view_w = the display grid at zoom 0 (half-block doubles vertical) + readonly viewH: number; + readonly viewW: number; + // World must accommodate max zoom-out (4× in each axis) + readonly worldH: number; + readonly worldW: number; + + grid: Uint8Array; + age: Int32Array; + /** Smoothed age for rendering — breaks coherent oscillation stripes */ + ageSmooth: Float32Array; + /** Activity field: decaying map of recent change (see ACTIVITY_DECAY) */ + activity: Float32Array; + private nextRow: Uint8Array; + private colSum: Uint8Array; + + // Camera: top-left of viewport (at zoom 0) in world coordinates + camY: number; + camX: number; + autoCam = true; + zoomLevel = 0; + private zoomCooldown = 0; // frames until next zoom change allowed + + generation = 0; + paused = false; + delay = 50; + + // Population tracking + popHistory: number[] = []; // maxlen 500 + hashHistory: number[] = []; // maxlen 60 + private cachedPop = 0; + + // ── Engine telemetry (readable by stats overlay + logger) ─── + spread = 0; // pop spread over last 150 gens + popFloor = 0; // current minimum pop threshold + cyclePeriod = 0; // detected cycle period (0 = none) + lastEvent = ''; // last injection event + lastEventGen = 0; // generation of last event + totalInjections = 0; + + ticker = new NewsTicker(); + + // Auto-focus mode: when true, autoFocus() runs every other frame + autoFocusMode = false; + autoFocusFrame = 0; + + // Cached display grid/age (invalidated each step, lazily recomputed) + private dispGridCache: Plane | null = null; + private dispAgeCache: Plane | null = null; + + // Cached mood (computed once per generation) + private cachedMood = ''; + private cachedMoodGen = -1; + + /** Bounding box from last step() — reused by calculateTargetZoom() */ + private stepBbox: [number, number, number, number] | null = null; + + /** Haunted mode: resurrects the historical ghost-decay bug. Toggled with 'g'. */ + haunted = false; + + // Pattern census: sightings of known patterns in the viewport + lastCensus = new Map(); + lastCensusSites: [string, number, number][] = []; // (name, wy, wx) + private sightingGen = new Map(); // per-pattern last announce + private sightingCount = new Map(); // per-pattern musing rotation + private lastSightingGen = -1e9; + + // Dramaturge: while a staged plot (aimed gliders) is in flight, + // cycle/stagnation injections hold their breath until this generation. + // The population floor stays armed — it's life support. + private dramaUntil = 0; + + // Time dilation: activity baseline (EMA) and smoothed tempo factor + private actBaseline = 0; + dilation = 1; + + constructor(termRows: number, termCols: number, seed = true) { + this.viewH = termRows * 2; + this.viewW = termCols; + this.worldH = Math.max(this.viewH * 5, 400); + this.worldW = Math.max(this.viewW * 5, 800); + const n = this.worldH * this.worldW; + this.grid = new Uint8Array(n); + this.age = new Int32Array(n); + this.ageSmooth = new Float32Array(n); + this.activity = new Float32Array(n); + this.nextRow = new Uint8Array(this.worldW); + this.colSum = new Uint8Array(this.worldW); + this.camY = fdiv(this.worldH - this.viewH, 2); + this.camX = fdiv(this.worldW - this.viewW, 2); + if (seed) this.seedInitial(); + } + + // ── Seeding ───────────────────────────────────────────────────── + + private seedInitial(): void { + const cy = fdiv(this.worldH, 2); + const cx = fdiv(this.worldW, 2); + const vh = this.viewH; + const vw = this.viewW; + + for (const name of METHUSELAHS) { + for (let i = 0; i < 2; i++) { + this.place(name, cy + randint(-fdiv(vh, 3), fdiv(vh, 3)), cx + randint(-fdiv(vw, 3), fdiv(vw, 3))); + } + } + for (let i = 0; i < 2; i++) { + this.place('gosper_gun', cy + randint(-fdiv(vh, 4), fdiv(vh, 4)), cx + randint(-fdiv(vw, 4), fdiv(vw, 4))); + } + for (let i = 0; i < 20; i++) { + const y = clampi(cy + randint(-vh, vh), 10, this.worldH - 10); + const x = clampi(cx + randint(-vw, vw), 10, this.worldW - 10); + this.place(choice(TRAVELLERS), y, x); + } + for (let i = 0; i < 4; i++) { + this.place(choice(OSCILLATORS), cy + randint(-fdiv(vh, 3), fdiv(vh, 3)), cx + randint(-fdiv(vw, 3), fdiv(vw, 3))); + } + + const y0 = cy - fdiv(vh, 2); + const x0 = cx - fdiv(vw, 2); + for (let y = 0; y < vh; y++) { + for (let x = 0; x < vw; x++) { + if (Math.random() < 0.035) this.grid[(y0 + y) * this.worldW + x0 + x] = 1; + } + } + + for (let i = 0; i < this.grid.length; i++) { + this.age[i] = this.grid[i] ? 1 : 0; + this.ageSmooth[i] = this.age[i] ?? 0; + } + } + + place(name: string, y: number, x: number, rotation?: number): void { + const cells = PATTERNS[name]; + if (!cells) return; + const rot = rotation ?? randint(0, 3); + for (let [dy, dx] of cells) { + for (let r = 0; r < rot; r++) [dy, dx] = [dx, -dy]; + const ny = y + dy; + const nx = x + dx; + if (ny >= 0 && ny < this.worldH && nx >= 0 && nx < this.worldW) { + const i = ny * this.worldW + nx; + this.grid[i] = 1; + this.age[i] = Math.max(this.age[i] ?? 0, 1); + } + } + this.invalidate(); + } + + private invalidate(): void { + this.dispGridCache = null; + this.dispAgeCache = null; + } + + // ── Simulation ────────────────────────────────────────────────── + + /** Advance one generation. Returns event string (empty if none). */ + step(): string { + if (this.paused) return ''; + this.invalidate(); + + const H = this.worldH; + const W = this.worldW; + const g = this.grid; + const age = this.age; + + // ── Bounding box of all active cells (alive + ghosts) ── + let by0 = H; + let by1 = -1; + let bx0 = W; + let bx1 = -1; + for (let y = 0; y < H; y++) { + const row = y * W; + let first = -1; + let last = -1; + for (let x = 0; x < W; x++) { + if (age[row + x] !== 0) { + if (first < 0) first = x; + last = x; + } + } + if (first < 0) continue; + if (y < by0) by0 = y; + by1 = y + 1; + if (first < bx0) bx0 = first; + if (last + 1 > bx1) bx1 = last + 1; + } + const hasActivity = by1 > 0; + + // Expand by 2 cells (kernel radius 1 + birth margin 1). If the padded + // box would spill past a world edge, toroidal wrap-around comes into + // play — fall back to the full world instead. + let useBbox = false; + if (hasActivity) { + const pad = 2; + const fits = by0 - pad >= 0 && by1 + pad <= H && bx0 - pad >= 0 && bx1 + pad <= W; + if (fits) { + by0 -= pad; + by1 += pad; + bx0 -= pad; + bx1 += pad; + useBbox = (by1 - by0) * (bx1 - bx0) <= fdiv(H * W, 2); + } + } + // Haunted mode keeps (nearly) every cell's age in motion — the bbox path + // would freeze ages outside the box, so always take the full world. + useBbox = useBbox && !this.haunted; + this.stepBbox = hasActivity && useBbox ? [by0, by1, bx0, bx1] : null; + if (!useBbox) { + by0 = 0; + by1 = H; + bx0 = 0; + bx1 = W; + } + + // Temporal smoothing decays the whole world; the region adds its ages below + const sm = this.ageSmooth; + for (let i = 0; i < sm.length; i++) sm[i] = (sm[i] ?? 0) * F85; + + const act = this.activity; + const next = this.nextRow; + const cs = this.colSum; + const ghostFloor = this.haunted ? -HAUNT_FRAMES : -GHOST_FRAMES; + const haunted = this.haunted; + // rows are written one behind, so the row above is still the old one + // when the row below reads it: keep the old row y-1 and row by0 aside + const prevOld = new Uint8Array(W); + const firstOld = g.slice(by0 * W, by0 * W + W); + let pop = 0; + + for (let y = by0; y < by1; y++) { + const rowUp = y === 0 ? H - 1 : y - 1; + const rowDn = y === H - 1 ? 0 : y + 1; + const up = y === by0 ? null : prevOld; // old row y-1 (already overwritten in g) + const base = y * W; + const upBase = rowUp * W; + // the row below is never written yet, unless it wrapped round to by0 + const dnIsFirst = rowDn === by0 && y !== by0; + const dnBase = rowDn * W; + // column sums over the three old rows, for this region's columns ±1 + const xa = bx0 === 0 ? 0 : bx0 - 1; + const xb = bx1 === W ? W : bx1 + 1; + for (let x = xa; x < xb; x++) { + const u = up ? (up[x] ?? 0) : (g[upBase + x] ?? 0); + const d = dnIsFirst ? (firstOld[x] ?? 0) : (g[dnBase + x] ?? 0); + cs[x] = u + (g[base + x] ?? 0) + d; + } + if (bx0 === 0 && bx1 === W) { + // full-width rows wrap left↔right + for (let x = 0; x < W; x++) { + const l = x === 0 ? W - 1 : x - 1; + const r = x === W - 1 ? 0 : x + 1; + next[x] = (cs[l] ?? 0) + (cs[x] ?? 0) + (cs[r] ?? 0) - (g[base + x] ?? 0); + } + } else { + for (let x = bx0; x < bx1; x++) { + next[x] = (cs[x - 1] ?? 0) + (cs[x] ?? 0) + (cs[x + 1] ?? 0) - (g[base + x] ?? 0); + } + } + // keep this row's old state for the row below, then write the new one + prevOld.set(g.subarray(base + xa, base + xb), xa); + for (let x = bx0; x < bx1; x++) { + const i = base + x; + const n = next[x] ?? 0; + const alive = g[i] === 1; + const birth = !alive && n === 3; + const survive = alive && (n === 3 || n === 2); + if (birth || (alive && !survive)) act[i] = (act[i] ?? 0) + 1; + const a = age[i] ?? 0; + let na: number; + if (survive) na = a + 1; + else if (birth) na = 1; + else if (a > 0) na = -1; + // the resurrected bug: no `age < 0` guard in haunted mode, so + // never-alive cells (age 0) fall into the decay branch too and the + // whole empty universe cycles 0 → -1 → … → -HAUNT_FRAMES → 0 + else if ((haunted || a < 0) && a > ghostFloor) na = a - 1; + else na = 0; + age[i] = na; + sm[i] = (sm[i] ?? 0) + Math.fround(Math.fround(na) * F15); // float32, as numpy rounds it + const v = birth || survive ? 1 : 0; + g[i] = v; + pop += v; + } + } + + this.generation += 1; + + // Batched activity decay (see ACTIVITY_DECAY_EVERY) + if (this.generation % ACTIVITY_DECAY_EVERY === 0) { + for (let i = 0; i < act.length; i++) act[i] = (act[i] ?? 0) * ACTIVITY_DECAY_BATCH; + } + + this.cachedPop = pop; + this.popHistory.push(pop); + if (this.popHistory.length > 500) this.popHistory.shift(); + + this.hashHistory.push(this.viewportHash()); + if (this.hashHistory.length > 60) this.hashHistory.shift(); + + const event = this.ensureLife(pop); + this.updateCamera(); + return event; + } + + /** hash(raw viewport bytes): two FNV-1a lanes folded into one safe integer */ + private viewportHash(): number { + const [y0, x0] = this.clampCam(); + let h1 = 0x811c9dc5; + let h2 = 0x01000193; + for (let y = 0; y < this.viewH; y++) { + const row = (y0 + y) * this.worldW + x0; + for (let x = 0; x < this.viewW; x++) { + const v = this.grid[row + x] ?? 0; + h1 = Math.imul(h1 ^ v, 16777619); + h2 = Math.imul(h2 ^ (v + 0x9e), 2246822519); + } + } + return (h1 >>> 0) * 2097152 + ((h2 >>> 0) & 0x1fffff); + } + + // ── Infinity engine ───────────────────────────────────────────── + + /** + * The core 'infinite' mechanic. Returns event name if triggered. + * + * Tunable parameters (visible in stats): + * - pop_floor: ~2.5% of default viewport area + * - stagnation window: 150 generations + * - stagnation threshold: spread < max(8, floor/8) + * - cycle detection: periods 1-30 + * - edge spawn interval: every 300 generations + */ + private ensureLife(population: number): string { + const viewportArea = this.viewH * this.viewW; + const baseFloor = fdiv(viewportArea, 40); + // Adaptive floor: rises to ~20% of recent average population, so the + // simulation faces real challenges at higher pop counts too. Clamped to + // base_floor minimum so bootstrap still works. + const ph = this.popHistory; + const phLen = ph.length; + if (phLen >= 100) { + let recentSum = 0; + for (let i = phLen - 100; i < phLen; i++) recentSum += ph[i] ?? 0; + this.popFloor = Math.max(baseFloor, Math.trunc(recentSum * 0.002)); // /100 * 0.20 + } else { + this.popFloor = baseFloor; + } + + // ── Stagnation spread ── + this.spread = 0; + if (phLen >= 150) { + let lo = ph[phLen - 1] ?? 0; + let hi = lo; + for (let i = phLen - 150; i < phLen; i++) { + const v = ph[i] ?? 0; + if (v < lo) lo = v; + if (v > hi) hi = v; + } + this.spread = hi - lo; + } + const stagnant = phLen >= 150 && this.spread < Math.max(8, fdiv(this.popFloor, 8)); + + // ── Cycle detection ── + this.cyclePeriod = 0; + const hh = this.hashHistory; + const hhLen = hh.length; + if (hhLen >= 4) { + const latest = hh[hhLen - 1]; + for (let period = 1; period < Math.min(31, hhLen); period++) { + if (hh[hhLen - 1 - period] === latest) { + this.cyclePeriod = period; + break; + } + } + } + + // ── Act ── + // While a staged plot is in flight (aimed gliders travelling), + // cycle/stagnation responses hold their breath and let it arrive. + // The population floor stays armed — it's life support, not drama. + const dramaPending = this.generation < this.dramaUntil; + + let event = ''; + if (population < fdiv(this.popFloor, 3)) { + event = 'inject:massive'; + this.inject('massive'); + } else if (population < this.popFloor) { + event = 'inject:heavy(low_pop)'; + this.inject('heavy'); + } else if (this.cyclePeriod > 0 && !dramaPending) { + // An attractor: prefer assassination over carpet-bombing. + const target = Math.random() < 0.65 ? this.injectProvoke() : ''; + if (target) { + event = `inject:provoke(cycle=${this.cyclePeriod},${target})`; + } else { + event = `inject:heavy(cycle=${this.cyclePeriod})`; + this.inject('heavy'); + } + } else if (stagnant && !dramaPending) { + // Quiet stretch: stage a collision instead of dumping mass. + if (Math.random() < 0.7 && this.injectCollide()) { + event = 'inject:collide(stagnant)'; + } else { + event = 'inject:medium(stagnant)'; + this.inject('medium'); + } + } else if (this.generation % 5000 === 0 && this.generation > 0) { + // Rare garden event — a beautiful symmetric pattern appears + event = 'inject:garden'; + this.injectGarden(); + } else if (this.generation % 300 === 0 && this.generation > 0) { + event = 'inject:edge'; + this.injectFromEdge(); + this.injectFromEdge(); + } + + if (event) { + this.lastEvent = event; + this.lastEventGen = this.generation; + this.totalInjections += 1; + } + return event; + } + + private inject(intensity: 'massive' | 'heavy' | 'medium' = 'medium'): void { + const n = { massive: 8, heavy: 5, medium: 3 }[intensity]; + for (let i = 0; i < n; i++) { + let name: string; + if (intensity === 'massive' && Math.random() < 0.3) name = 'gosper_gun'; + else if (Math.random() < 0.4) name = choice(METHUSELAHS); + else name = choice([...TRAVELLERS, ...OSCILLATORS]); + + // New life blooms where it's darkest (jitter breaks the block-grid + // regularity of the void finder) + const [y, x] = this.findQuietSpot(); + this.place(name, y + randint(-6, 6), x + randint(-6, 6)); + } + if (intensity === 'massive' || intensity === 'heavy') { + const [y, x] = this.findQuietSpot(); + this.place('gosper_gun', y, x); + } + } + + private injectFromEdge(): void { + const cy = this.camY + fdiv(this.viewH, 2); + const cx = this.camX + fdiv(this.viewW, 2); + const vh3 = fdiv(this.viewH, 3); + const vw3 = fdiv(this.viewW, 3); + const edge = choice(['top', 'bottom', 'left', 'right'] as const); + let y: number; + let x: number; + let rot: number; + if (edge === 'top') [y, x, rot] = [this.camY + 2, cx + randint(-vw3, vw3), 2]; + else if (edge === 'bottom') [y, x, rot] = [this.camY + this.viewH - 5, cx + randint(-vw3, vw3), 0]; + else if (edge === 'left') [y, x, rot] = [cy + randint(-vh3, vh3), this.camX + 2, 1]; + else [y, x, rot] = [cy + randint(-vh3, vh3), this.camX + this.viewW - 10, 3]; + this.place(choice(TRAVELLERS), y, x, rot); + } + + /** Place a symmetric garden pattern near the camera center. */ + private injectGarden(): void { + const cy = this.camY + fdiv(this.viewH, 2); + const cx = this.camX + fdiv(this.viewW, 2); + const garden = choice(GARDENS); + // Offset slightly from dead center for visual interest + const oy = randint(-fdiv(this.viewH, 6), fdiv(this.viewH, 6)); + const ox = randint(-fdiv(this.viewW, 6), fdiv(this.viewW, 6)); + for (const [dy, dx] of garden) { + const ny = cy + oy + dy; + const nx = cx + ox + dx; + if (ny >= 0 && ny < this.worldH && nx >= 0 && nx < this.worldW) { + this.grid[ny * this.worldW + nx] = 1; + this.age[ny * this.worldW + nx] = 1; + } + } + this.invalidate(); + } + + // ── Dramaturge ────────────────────────────────────────────────── + // Injections with intention. The engine reads the activity field and the + // census, then composes events instead of rolling dice: new life blooms in + // the darkest visible void, assassins are aimed at named citizens, + // collisions are scheduled in the quiet. + + /** + * Pick a low-occupancy, low-activity spot in the visible region. + * + * Block-reduces occupancy + activity over the current zoom cover and + * chooses randomly among the darkest quintile, so revivals bloom in the + * void where there's room to watch them grow. + */ + findQuietSpot(): [number, number] { + const [cy, cx] = this.viewCenter(); + const factor = this.zoomLevel < 0 ? 1 << -this.zoomLevel : 1; + const coverH = Math.min(this.worldH, this.viewH * factor); + const coverW = Math.min(this.worldW, this.viewW * factor); + const y0 = Math.max(0, Math.min(cy - fdiv(coverH, 2), this.worldH - coverH)); + const x0 = Math.max(0, Math.min(cx - fdiv(coverW, 2), this.worldW - coverW)); + + const B = 16; + const bh = fdiv(coverH, B); + const bw = fdiv(coverW, B); + if (bh < 2 || bw < 2) return [cy, cx]; + + const score = new Float64Array(bh * bw); + for (let y = 0; y < bh * B; y++) { + const row = (y0 + y) * this.worldW + x0; + const sr = fdiv(y, B) * bw; + for (let x = 0; x < bw * B; x++) { + const k = sr + fdiv(x, B); + score[k] = (score[k] ?? 0) + (this.grid[row + x] ?? 0) * 2 + (this.activity[row + x] ?? 0); + } + } + const k = Math.max(1, fdiv(score.length, 5)); + const order = Array.from(score.keys()).sort((a, b) => (score[a] ?? 0) - (score[b] ?? 0)); + const pick = choice(order.slice(0, k)); + const by = fdiv(pick, bw); + const bx = pick % bw; + return [y0 + by * B + fdiv(B, 2), x0 + bx * B + fdiv(B, 2)]; + } + + /** + * Place a glider `dist` cells out, aimed to pass through (ty, tx). + * + * The origin must sit inside the raw viewport (so the staging itself breaks + * any viewport-hash cycle) with a clear launch pad. Returns true on + * placement; ETA is dist * 4 generations. + */ + private aimGlider(ty: number, tx: number, dist: number, rot: number): boolean { + const [dy, dx] = GLIDER_DIR[rot] ?? [1, 1]; + const oy = ty - dy * dist; + const ox = tx - dx * dist; + const [vy0, vx0] = this.clampCam(); + if (!(vy0 + 2 <= oy && oy < vy0 + this.viewH - 5 && vx0 + 2 <= ox && ox < vx0 + this.viewW - 5)) return false; + for (let y = Math.max(0, oy - 2); y < Math.min(this.worldH, oy + 5); y++) { + for (let x = Math.max(0, ox - 2); x < Math.min(this.worldW, ox + 5); x++) { + if (this.grid[y * this.worldW + x]) return false; + } + } + this.place('glider', oy, ox, rot); + return true; + } + + /** Aim a glider at a named citizen (rarest first). Returns the target's + * name, or '' if no shot lined up. */ + private injectProvoke(): string { + const sites = [...this.lastCensusSites]; + if (!sites.length) return ''; + sites.sort((a, b) => (SIGHTING_RARITY[b[0]] ?? 0) - (SIGHTING_RARITY[a[0]] ?? 0)); + // Consider the most notable few, in order + for (const [name, ty, tx] of sites.slice(0, 6)) { + const dist = randint(35, 60); + const rots = [0, 1, 2, 3]; + for (let i = rots.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [rots[i], rots[j]] = [rots[j] ?? 0, rots[i] ?? 0]; + } + for (const rot of rots) { + if (this.aimGlider(ty, tx, dist, rot)) { + this.dramaUntil = this.generation + dist * 4 + 150; + this.ticker.queueSpecial('the cosmos takes aim'); + return name; + } + } + } + return ''; + } + + /** Stage a head-on glider collision at a quiet visible spot. */ + private injectCollide(): boolean { + let [ty, tx] = this.findQuietSpot(); + const [vy0, vx0] = this.clampCam(); + + for (let attempt = 0; attempt < 6; attempt++) { + // Pick the throw distance first, then clamp the meeting point into the + // band where both launch pads provably fit inside the viewport + // (origins sit at target ∓ dist on each axis). + const dist = randint(16, 34); + const loY = vy0 + dist + 3; + const hiY = vy0 + this.viewH - dist - 6; + const loX = vx0 + dist + 3; + const hiX = vx0 + this.viewW - dist - 6; + if (loY >= hiY || loX >= hiX) continue; // viewport too small for this throw + ty = Math.max(loY, Math.min(ty, hiY)); + tx = Math.max(loX, Math.min(tx, hiX)); + const rot = randint(0, 3); + // Jitter varies the collision outcome; right-angle approaches (rot ± 1) + // explode far more often than head-on (rot + 2), which mostly + // annihilates quietly — measured 14/49 vs 1/49 explosion geometries. + const jy = randint(-3, 3); + const jx = randint(-3, 3); + if (!this.aimGlider(ty, tx, dist, rot)) continue; + // First glider is in flight; try to give it a partner. (If none fits, + // a lone glider crossing the quiet is still a scene — keep the + // appointment either way.) + const partnerRot = (rot + choice([1, 3])) % 4; + const paired = this.aimGlider(ty + jy, tx + jx, dist, partnerRot); + this.dramaUntil = this.generation + dist * 4 + 150; + this.ticker.queueSpecial(paired ? 'two gliders, one appointment' : 'a lone glider, sent into the dark'); + return true; + } + return false; + } + + // ── Camera ────────────────────────────────────────────────────── + + /** Calculate optimal zoom level based on activity spread. */ + private calculateTargetZoom(): number { + // Every nonzero age lives inside the bbox recorded by step(), so restrict + // the scan to it. Falls back to the full world otherwise. + const [by0, by1, bx0, bx1] = this.stepBbox ?? [0, this.worldH, 0, this.worldW]; + const W = this.worldW; + + // Find recent activity (age 1-10) or fall back to all living cells + let nActive = 0; + for (let y = by0; y < by1 && nActive < 5; y++) { + for (let x = bx0; x < bx1; x++) { + const a = this.age[y * W + x] ?? 0; + if (a >= 1 && a <= 10 && ++nActive >= 5) break; + } + } + const recent = nActive >= 5; + const ys: number[] = []; + const xs: number[] = []; + for (let y = by0; y < by1; y++) { + for (let x = bx0; x < bx1; x++) { + const i = y * W + x; + const hit = recent ? (this.age[i] ?? 0) >= 1 && (this.age[i] ?? 0) <= 10 : this.grid[i] !== 0; + if (hit) { + ys.push(y); + xs.push(x); + } + } + } + if (ys.length < 2) return this.zoomLevel; + + // Use a percentile range for a tight bbox that ignores outliers + const sx = Int32Array.from(xs).sort(); + const yLo = percentileInt(ys, 15); + const yHi = percentileInt(ys, 85); + const xLo = percentileInt(sx, 15); + const xHi = percentileInt(sx, 85); + const bboxH = Math.max(4, yHi - yLo + 1); + const bboxW = Math.max(4, xHi - xLo + 1); + + // Choose zoom to fit the core activity in ~50% of viewport + let best = MIN_ZOOM; + for (let z = MAX_ZOOM; z >= MIN_ZOOM; z--) { + const mag = 2 ** z; + if (bboxH <= (this.viewH / mag) * 0.5 && bboxW <= (this.viewW / mag) * 0.5) { + best = z; + break; + } + } + return clampi(best, MIN_ZOOM, MAX_ZOOM); + } + + private updateCamera(): void { + if (!this.autoCam) return; + + const pad = 30; + const y0 = Math.max(0, this.camY - pad); + const y1 = Math.min(this.worldH, this.camY + this.viewH + pad); + const x0 = Math.max(0, this.camX - pad); + const x1 = Math.min(this.worldW, this.camX + this.viewW + pad); + const W = this.worldW; + + // Steer toward drama: centroid of squared activity (squaring emphasizes + // hotspots — an explosion outweighs a blinker farm). Falls back to the + // population centroid when the region is calm. + let total = 0; + let wy = 0; + let wx = 0; + for (let y = y0; y < y1; y++) { + for (let x = x0; x < x1; x++) { + const a = this.activity[y * W + x] ?? 0; + if (a === 0) continue; + const a2 = a * a; + total += a2; + wy += a2 * (y - y0); + wx += a2 * (x - x0); + } + } + if (total > 25) { + this.steer(Math.trunc(wy / total) + y0, Math.trunc(wx / total) + x0); + this.advanceAutoZoom(); + return; + } + + let n = 0; + let sy = 0; + let sx = 0; + for (let y = y0; y < y1; y++) { + for (let x = x0; x < x1; x++) { + if (this.grid[y * W + x]) { + n++; + sy += y - y0; + sx += x - x0; + } + } + } + if (n > 0) this.steer(Math.trunc(sy / n) + y0, Math.trunc(sx / n) + x0); + this.advanceAutoZoom(); + } + + private steer(cy: number, cx: number): void { + const ty = clampi(cy - fdiv(this.viewH, 2), 0, this.worldH - this.viewH); + const tx = clampi(cx - fdiv(this.viewW, 2), 0, this.worldW - this.viewW); + this.camY = Math.trunc(this.camY + (ty - this.camY) * 0.04); + this.camX = Math.trunc(this.camX + (tx - this.camX) * 0.04); + } + + /** Auto-zoom: gradually step toward optimal zoom level. + * Throttled: only recalculates every 4th frame when cooldown is 0. */ + private advanceAutoZoom(): void { + this.zoomCooldown = Math.max(0, this.zoomCooldown - 1); + if (this.zoomCooldown !== 0 || this.generation % 4 !== 0) return; + const target = this.calculateTargetZoom(); + if (target > this.zoomLevel && this.zoomLevel < MAX_ZOOM) { + this.zoomLevel += 1; + this.zoomCooldown = 45; // ~1.5 sec at 30fps before next change + } else if (target < this.zoomLevel && this.zoomLevel > MIN_ZOOM) { + // Verify zoom out is safe (world can fit the expanded view) + const nz = this.zoomLevel - 1; + const factor = nz >= 0 ? 1 : 1 << -nz; + if (this.viewH * factor <= this.worldH && this.viewW * factor <= this.worldW) { + this.zoomLevel = nz; + this.zoomCooldown = 45; + } + } + } + + // ── Viewport access (raw = zoom 0, display = current zoom) ───── + + clampCam(): [number, number] { + return [clampi(this.camY, 0, this.worldH - this.viewH), clampi(this.camX, 0, this.worldW - this.viewW)]; + } + + viewCenter(): [number, number] { + const [y0, x0] = this.clampCam(); + return [y0 + fdiv(this.viewH, 2), x0 + fdiv(this.viewW, 2)]; + } + + /** The raw viewport (zoom 0) as a view_h × view_w occupancy map. */ + rawViewGrid(): Plane { + const [y0, x0] = this.clampCam(); + const out = new Uint8Array(this.viewH * this.viewW); + for (let y = 0; y < this.viewH; y++) { + const src = (y0 + y) * this.worldW + x0; + out.set(this.grid.subarray(src, src + this.viewW), y * this.viewW); + } + return { h: this.viewH, w: this.viewW, data: out }; + } + + /** The region the current zoom shows: [y0, x0, h, w, factor, zoomedIn]. */ + private cover(): [number, number, number, number, number, boolean] | null { + const [cy, cx] = this.viewCenter(); + if (this.zoomLevel < 0) { + const factor = 1 << -this.zoomLevel; // 2 or 4 + const ch = this.viewH * factor; + const cw = this.viewW * factor; + if (ch > this.worldH || cw > this.worldW) return null; + const y0 = Math.max(0, Math.min(cy - fdiv(ch, 2), this.worldH - ch)); + const x0 = Math.max(0, Math.min(cx - fdiv(cw, 2), this.worldW - cw)); + return [y0, x0, ch, cw, factor, false]; + } + const factor = 1 << this.zoomLevel; // 2 or 4 + const ch = Math.max(2, fdiv(this.viewH, factor)); + const cw = Math.max(2, fdiv(this.viewW, factor)); + const y0 = Math.max(0, Math.min(cy - fdiv(ch, 2), this.worldH - ch)); + const x0 = Math.max(0, Math.min(cx - fdiv(cw, 2), this.worldW - cw)); + return [y0, x0, ch, cw, factor, true]; + } + + /** Grid scaled for the current zoom level, sized (about) view_h × view_w. */ + displayGrid(): Plane { + if (!this.dispGridCache) this.dispGridCache = this.computeDisplayGrid(); + return this.dispGridCache; + } + + private computeDisplayGrid(): Plane { + if (this.zoomLevel === 0) return this.rawViewGrid(); + const c = this.cover(); + if (!c) return this.rawViewGrid(); + const [y0, x0, ch, cw, f, zoomedIn] = c; + const W = this.worldW; + if (!zoomedIn) { + const bh = fdiv(ch, f); + const bw = fdiv(cw, f); + const out = new Uint8Array(bh * bw); + for (let y = 0; y < bh * f; y++) { + const src = (y0 + y) * W + x0; + const dst = fdiv(y, f) * bw; + for (let x = 0; x < bw * f; x++) if (this.grid[src + x]) out[dst + fdiv(x, f)] = 1; + } + return { h: bh, w: bw, data: out }; + } + const h = Math.min(ch * f, this.viewH); + const w = Math.min(cw * f, this.viewW); + const out = new Uint8Array(h * w); + for (let y = 0; y < h; y++) { + const src = (y0 + fdiv(y, f)) * W + x0; + for (let x = 0; x < w; x++) out[y * w + x] = this.grid[src + fdiv(x, f)] ?? 0; + } + return { h, w, data: out }; + } + + /** + * Age map scaled for the current zoom level. + * + * Handles ghost trails: positive ages = alive, negative = ghost (recently + * dead). When downsampling, prioritizes living cells; shows the brightest + * ghost otherwise. + */ + displayAge(): Plane { + if (!this.dispAgeCache) this.dispAgeCache = this.computeDisplayAge(); + return this.dispAgeCache; + } + + private computeDisplayAge(): Plane { + // Haunted mode renders raw ages: the ghost phase cycle IS the visual — + // temporal smoothing would blur the strobe into mush. + const src: Int32Array | Float32Array = this.haunted ? this.age : this.ageSmooth; + const W = this.worldW; + const at = (i: number): number => Math.trunc(src[i] ?? 0); // astype(int32) + + const c = this.zoomLevel === 0 ? null : this.cover(); + if (!c) { + const [y0, x0] = this.clampCam(); + const out = new Int32Array(this.viewH * this.viewW); + for (let y = 0; y < this.viewH; y++) { + const s = (y0 + y) * W + x0; + for (let x = 0; x < this.viewW; x++) out[y * this.viewW + x] = at(s + x); + } + return { h: this.viewH, w: this.viewW, data: out }; + } + const [y0, x0, ch, cw, f, zoomedIn] = c; + if (!zoomedIn) { + const bh = fdiv(ch, f); + const bw = fdiv(cw, f); + // Smart aggregation: prioritize alive (positive), then the brightest + // ghost (least negative) + const sentinel = -(this.haunted ? HAUNT_FRAMES : GHOST_FRAMES) - 1; + const maxv = new Int32Array(bh * bw).fill(-2147483648); + const ghost = new Int32Array(bh * bw).fill(sentinel); + for (let y = 0; y < bh * f; y++) { + const s = (y0 + y) * W + x0; + const d = fdiv(y, f) * bw; + for (let x = 0; x < bw * f; x++) { + const v = at(s + x); + const k = d + fdiv(x, f); + if (v > (maxv[k] ?? 0)) maxv[k] = v; + const m = v !== 0 ? v : sentinel; + if (m > (ghost[k] ?? 0)) ghost[k] = m; + } + } + const out = new Int32Array(bh * bw); + for (let k = 0; k < out.length; k++) { + const mv = maxv[k] ?? 0; + const gm = ghost[k] ?? 0; + out[k] = mv > 0 ? mv : gm > sentinel ? gm : 0; + } + return { h: bh, w: bw, data: out }; + } + const h = Math.min(ch * f, this.viewH); + const w = Math.min(cw * f, this.viewW); + const out = new Int32Array(h * w); + for (let y = 0; y < h; y++) { + const s = (y0 + fdiv(y, f)) * W + x0; + for (let x = 0; x < w; x++) out[y * w + x] = at(s + fdiv(x, f)); + } + return { h, w, data: out }; + } + + // ── Zoom ──────────────────────────────────────────────────────── + + zoomIn(): void { + if (this.zoomLevel < MAX_ZOOM) this.zoomLevel += 1; + this.invalidate(); + } + + zoomOut(): void { + if (this.zoomLevel > MIN_ZOOM) { + const nz = this.zoomLevel - 1; + const factor = nz >= 0 ? 1 : 1 << -nz; + // Zooming past default into negative — verify the world fits + if (nz >= 0 || (this.viewH * factor <= this.worldH && this.viewW * factor <= this.worldW)) { + this.zoomLevel = nz; + } + } + this.invalidate(); + } + + /** + * Zoom + pan to the densest cluster of recent activity. + * + * Strategy: build a coarse heat map, find the hottest spot, then use the + * 10th–90th percentile range (not the full bounding box) of nearby active + * cells to size the zoom — this ignores sparse outliers and focuses on the + * tight core of the action. + */ + autoFocus(): void { + const H = this.worldH; + const W = this.worldW; + let recentCount = 0; + let aliveCount = 0; + for (let i = 0; i < this.age.length; i++) { + const a = this.age[i] ?? 0; + if (a >= 1 && a <= 10) recentCount++; + if (this.grid[i]) aliveCount++; + } + const recent = recentCount >= 5; + if ((recent ? recentCount : aliveCount) === 0) return; + const active = (i: number): boolean => { + const a = this.age[i] ?? 0; + return recent ? a >= 1 && a <= 10 : this.grid[i] !== 0; + }; + + // Coarse heat map: 16×16 cell blocks + const block = 16; + const bh = fdiv(H, block); + const bw = fdiv(W, block); + if (bh < 1 || bw < 1) return; + const heat = new Float64Array(bh * bw); + for (let y = 0; y < bh * block; y++) { + for (let x = 0; x < bw * block; x++) { + if (!active(y * W + x)) continue; + const k = fdiv(y, block) * bw + fdiv(x, block); + heat[k] = (heat[k] ?? 0) + 1; + } + } + + // Find the hottest 3×3 neighbourhood (not just one block) + let best = -1; + let hot = 0; + for (let by = 0; by < bh; by++) { + for (let bx = 0; bx < bw; bx++) { + let s = 0; + for (let dy = -1; dy <= 1; dy++) { + for (let dx = -1; dx <= 1; dx++) { + const yy = by + dy; + const xx = bx + dx; + if (yy >= 0 && yy < bh && xx >= 0 && xx < bw) s += heat[yy * bw + xx] ?? 0; + } + } + if (s / 9 > best) { + best = s / 9; + hot = by * bw + bx; + } + } + } + const focusCy = fdiv(hot, bw) * block + fdiv(block, 2); + const focusCx = (hot % bw) * block + fdiv(block, 2); + + // Tight search region around hotspot (±2 blocks) + const r = block * 2; + const ry0 = Math.max(0, focusCy - r); + const ry1 = Math.min(H, focusCy + r); + const rx0 = Math.max(0, focusCx - r); + const rx1 = Math.min(W, focusCx + r); + const ys: number[] = []; + const xs: number[] = []; + for (let y = ry0; y < ry1; y++) { + for (let x = rx0; x < rx1; x++) { + if (active(y * W + x)) { + ys.push(y - ry0); + xs.push(x - rx0); + } + } + } + if (!ys.length) return; + const sx = Int32Array.from(xs).sort(); + const yLo = percentileInt(ys, 10); + const yHi = percentileInt(ys, 90); + const xLo = percentileInt(sx, 10); + const xHi = percentileInt(sx, 90); + const bboxH = Math.max(4, yHi - yLo + 1); + const bboxW = Math.max(4, xHi - xLo + 1); + const centerY = ry0 + fdiv(yLo + yHi, 2); + const centerX = rx0 + fdiv(xLo + xHi, 2); + + // Choose zoom to fit the core cluster in ~60% of viewport + let bestZ = MIN_ZOOM; + for (let z = MAX_ZOOM; z >= MIN_ZOOM; z--) { + const mag = 2 ** z; + if (bboxH <= (this.viewH / mag) * 0.6 && bboxW <= (this.viewW / mag) * 0.6) { + bestZ = z; + break; + } + } + this.zoomLevel = clampi(bestZ, MIN_ZOOM, MAX_ZOOM); + this.camY = clampi(centerY - fdiv(this.viewH, 2), 0, this.worldH - this.viewH); + this.camX = clampi(centerX - fdiv(this.viewW, 2), 0, this.worldW - this.viewW); + this.autoCam = false; + this.invalidate(); + } + + // ── Controls ──────────────────────────────────────────────────── + + pan(dy: number, dx: number): void { + this.autoCam = false; + // Scale pan speed with zoom: faster when zoomed out, slower when in + const factor = 2 ** -this.zoomLevel; + const sy = dy !== 0 ? Math.max(1, Math.trunc(Math.abs(dy) * factor)) * Math.sign(dy) : 0; + const sx = dx !== 0 ? Math.max(1, Math.trunc(Math.abs(dx) * factor)) * Math.sign(dx) : 0; + this.camY = clampi(this.camY + sy, 0, this.worldH - this.viewH); + this.camX = clampi(this.camX + sx, 0, this.worldW - this.viewW); + this.invalidate(); + } + + home(): void { + this.autoCam = true; + this.zoomLevel = 0; + this.invalidate(); + } + + clear(): void { + this.grid.fill(0); + this.age.fill(0); + this.ageSmooth.fill(0); + this.generation = 0; + this.popHistory = []; + this.hashHistory = []; + this.invalidate(); + } + + /** Run the pattern census and maybe queue a ticker sighting. */ + takeCensus(): void { + const vg = this.rawViewGrid(); + let any = false; + for (let i = 0; i < vg.data.length; i++) { + if (vg.data[i]) { + any = true; + break; + } + } + let counts = new Map(); + if (!any) { + this.lastCensusSites = []; + } else { + try { + const res = census(vg.data, vg.h, vg.w); + if (!res) { + this.lastCensusSites = []; + } else { + const [vy0, vx0] = this.clampCam(); // viewport origin in world coords + this.lastCensusSites = res.sites.map(([n, y, x]) => [n, vy0 + y, vx0 + x]); + counts = res.counts; + } + } catch { + // the census must never crash the sim + } + } + this.lastCensus = counts; + if (!counts.size) return; + + // Global cadence: at most one sighting per ~600 generations + if (this.generation - this.lastSightingGen < 600) return; + + let bestName = ''; + let bestScore = 0; + for (const [name, count] of counts) { + if (count < (SIGHTING_MIN_COUNT[name] ?? 1)) continue; + // Don't greet the same citizen again too soon + if (this.generation - (this.sightingGen.get(name) ?? -1e9) < 1800) continue; + const score = SIGHTING_RARITY[name] ?? 0; + if (score > bestScore) { + bestScore = score; + bestName = name; + } + } + if (!bestName) return; + + const pool = SIGHTING_MUSINGS[bestName] ?? []; + const idx = this.sightingCount.get(bestName) ?? 0; + this.sightingCount.set(bestName, idx + 1); + this.ticker.queueSpecial(pool[idx % pool.length] ?? bestName); + this.sightingGen.set(bestName, this.generation); + this.lastSightingGen = this.generation; + } + + // ── Persistence ───────────────────────────────────────────────── + // The universe is a place, not a session: state survives leaving. + + snapshot(): UniverseState { + return { + h: this.worldH, + w: this.worldW, + age: this.age.slice(), + generation: this.generation, + totalInjections: this.totalInjections, + }; + } + + /** + * Adopt a prior universe's state (resume or window resize). + * + * The old world is embedded centered; whatever doesn't fit is cropped. + * Derived state (smoothing, activity, histories) warms back up within a + * few dozen generations. + */ + adopt(s: UniverseState): void { + const h = Math.min(this.worldH, s.h); + const w = Math.min(this.worldW, s.w); + const sy = fdiv(s.h - h, 2); + const sx = fdiv(s.w - w, 2); + const dy = fdiv(this.worldH - h, 2); + const dx = fdiv(this.worldW - w, 2); + + this.grid.fill(0); + this.age.fill(0); + let pop = 0; + for (let y = 0; y < h; y++) { + for (let x = 0; x < w; x++) { + let a = s.age[(sy + y) * s.w + sx + x] ?? 0; + // Retire ghosts deeper than normal decay can reach (haunted-mode + // ages, or a future format change) — they'd be stuck forever + if (a < -GHOST_FRAMES) a = 0; + const i = (dy + y) * this.worldW + dx + x; + this.age[i] = a; + if (a > 0) { + this.grid[i] = 1; + pop++; + } + } + } + this.generation = Math.max(0, Math.trunc(s.generation)); + this.totalInjections = Math.max(0, Math.trunc(s.totalInjections)); + this.ageSmooth.fill(0); + this.activity.fill(0); + this.hashHistory = []; + this.cachedPop = pop; + this.popHistory = [pop]; + this.stepBbox = null; + this.dramaUntil = 0; + this.invalidate(); + } + + /** Toggle haunted mode (the resurrected ghost-decay bug). */ + toggleHaunted(): void { + this.haunted = !this.haunted; + this.invalidate(); + if (!this.haunted) { + // Exorcism: normal-mode decay can't retire ghosts older than + // -GHOST_FRAMES (they'd be stuck forever), so clear them all. + for (let i = 0; i < this.age.length; i++) { + if ((this.age[i] ?? 0) < 0) this.age[i] = 0; + if ((this.ageSmooth[i] ?? 0) < 0) this.ageSmooth[i] = 0; + } + } + } + + /** Map a terminal cell (row, col) to world coordinates, accounting for zoom. + * `half` picks the bottom pixel of the half-block cell. */ + termToWorld(termY: number, termX: number, half = 0): [number, number] { + const [cy, cx] = this.viewCenter(); + const dy = termY * 2 + half; // half-block: each term row = 2 display rows + const dx = termX; + if (this.zoomLevel <= 0) { + const factor = 1 << -this.zoomLevel; // 1, 2, 4 + const baseY = cy - fdiv(this.viewH * factor, 2); + const baseX = cx - fdiv(this.viewW * factor, 2); + return [baseY + dy * factor, baseX + dx * factor]; + } + const factor = 1 << this.zoomLevel; // 2, 4 + const baseY = cy - fdiv(Math.max(2, fdiv(this.viewH, factor)), 2); + const baseX = cx - fdiv(Math.max(2, fdiv(this.viewW, factor)), 2); + return [baseY + fdiv(dy, factor), baseX + fdiv(dx, factor)]; + } + + /** Toggle a cell at terminal coordinates, accounting for zoom. */ + toggleCell(termY: number, termX: number, half = 0): void { + const [gy, gx] = this.termToWorld(termY, termX, half); + this.setCell(gy, gx, this.grid[gy * this.worldW + gx] ? 0 : 1); + } + + /** Set a world cell alive (1) or dead (0), as a toggle would leave it. */ + setCell(gy: number, gx: number, v: 0 | 1): void { + if (gy < 0 || gy >= this.worldH || gx < 0 || gx >= this.worldW) return; + const i = gy * this.worldW + gx; + this.grid[i] = v; + this.age[i] = v ? 1 : 0; + this.invalidate(); + } + + /** Advance the news ticker by one frame. */ + tickTicker(tickerWidth: number): void { + this.ticker.tick(tickerWidth, this.detectMood(), this.generation); + } + + /** Classify current simulation mood for context-aware musings. + * Cached per generation — safe to call multiple times per frame. */ + detectMood(): string { + if (this.cachedMoodGen === this.generation) return this.cachedMood; + this.cachedMood = this.computeMood(); + this.cachedMoodGen = this.generation; + return this.cachedMood; + } + + private computeMood(): string { + // Haunted mode possesses everything, including the ticker + if (this.haunted) return 'haunted'; + + // Recent injection gets priority (show for ~90 frames after event) + if (this.lastEvent && this.generation - this.lastEventGen < 90) return 'injection'; + + // Cycle detected + if (this.cyclePeriod > 0) return 'cycle'; + + // Milestone (every 10,000 generations, show for 120 frames) + if (this.generation >= 10_000 && this.generation % 10_000 < 120) return 'milestone'; + + // Population trends (need enough history) + const ph = this.popHistory; + const phLen = ph.length; + if (phLen >= 30) { + let first = 0; + let second = 0; + for (let i = phLen - 30; i < phLen - 15; i++) first += ph[i] ?? 0; + for (let i = phLen - 15; i < phLen; i++) second += ph[i] ?? 0; + const ratio = second / 15 / Math.max(first / 15, 1); + if (ratio > 1.15) return 'booming'; + if (ratio < 0.85) return 'declining'; + } + + // Density + const pop = phLen ? (ph[phLen - 1] ?? 0) : 0; + const density = pop / Math.max(this.viewH * this.viewW, 1); + if (density > 0.15) return 'dense'; + if (pop < this.popFloor && pop > 0) return 'sparse'; + + // Stagnation + if (this.spread < Math.max(8, fdiv(this.popFloor, 8)) && phLen >= 150) return 'stagnant'; + + return ''; + } + + /** The current epoch name based on generation count. */ + epoch(): string { + let name = EPOCHS[0]?.[1] ?? 'genesis'; + for (const [threshold, label] of EPOCHS) if (this.generation >= threshold) name = label; + return name; + } + + population(): number { + return this.cachedPop; + } + + /** + * Horizontal centroid of viewport activity, 0.0 (left) – 1.0 (right). + * Feeds the music engine's stereo field: the arpeggio pans toward where + * the universe is actually changing. 0.5 when calm. + */ + activityCenterX(): number { + const [y0, x0] = this.clampCam(); + let total = 0; + let idx = 0; + for (let y = 0; y < this.viewH; y++) { + const row = (y0 + y) * this.worldW + x0; + for (let x = 0; x < this.viewW; x++) { + const a = this.activity[row + x] ?? 0; + total += a; + idx += a * x; + } + } + if (total < 1 || this.viewW < 2) return 0.5; + return idx / total / (this.viewW - 1); + } + + /** Total activity in the viewport (drama meter for time dilation). */ + viewportActivity(): number { + const [y0, x0] = this.clampCam(); + let total = 0; + for (let y = 0; y < this.viewH; y++) { + const row = (y0 + y) * this.worldW + x0; + for (let x = 0; x < this.viewW; x++) total += this.activity[row + x] ?? 0; + } + return total; + } + + /** + * Frame-delay factor: > 1 savors drama, < 1 hurries the calm. + * + * Compares viewport activity against its own long-run baseline (EMA), so + * "dramatic" is always relative to this universe's normal. Call once per + * frame; disabled while the user drives the camera. + */ + timeDilation(): number { + if (!this.autoCam) return 1; + const act = this.viewportActivity(); + if (this.actBaseline <= 0) { + this.actBaseline = Math.max(act, 1); + return 1; + } + // Asymmetric baseline: rises fast (a burst is savored briefly, then + // absorbed as the new normal), decays slow (a lull reads as fast-forward + // until it becomes the new normal). Drama is always a *change*, relative + // to this universe's own recent history. + const alpha = act > this.actBaseline ? 0.015 : 0.003; + this.actBaseline = this.actBaseline * (1 - alpha) + act * alpha; + const ratio = act / Math.max(this.actBaseline, 1); + let target = ratio > 1 ? Math.min(1.6, 1 + (ratio - 1) * 0.7) : 0.7 + ratio * 0.3; + if (act < 60) target = Math.min(target, 0.7); // near-dead viewport: don't linger + // Smooth the factor itself so tempo never jitters + this.dilation = this.dilation * 0.85 + target * 0.15; + return this.dilation; + } + + sparkline(width = 24): string { + const ph = this.popHistory; + if (ph.length < 2) return ''; + const start = Math.max(0, ph.length - width); + let lo = ph[start] ?? 0; + let hi = lo; + for (let i = start; i < ph.length; i++) { + const v = ph[i] ?? 0; + if (v < lo) lo = v; + if (v > hi) hi = v; + } + const n = SPARKS.length - 1; + const mid = SPARKS[Math.floor(SPARKS.length / 2)] ?? '▅'; + let out = ''; + for (let i = start; i < ph.length; i++) { + const v = ph[i] ?? 0; + out += hi === lo ? mid : (SPARKS[Math.trunc(((v - lo) / (hi - lo)) * n)] ?? ''); + } + return out; + } +} diff --git a/afterlife/src/engine/musings.ts b/afterlife/src/engine/musings.ts new file mode 100644 index 0000000..f410638 --- /dev/null +++ b/afterlife/src/engine/musings.ts @@ -0,0 +1,287 @@ +/** + * musings.ts — what the universe says about itself. + * + * Every string here is afterlife's own, carried over verbatim from life.py + * (generated from it, not retyped). The voice is the program's; the web port + * only moves it. + */ + +/** Default ambient musings (used when nothing special is happening) */ +export const MUSINGS: readonly string[] = [ + 'cells pondering existence', + 'entropy is just a suggestion', + 'order from chaos, chaos from order', + 'the cosmos breathes', + 'finding signal in noise', + 'patterns all the way down', + 'life, uh, finds a way', + 'on the edge of chaos', + 'complexity, emerging', + 'dancing at the phase boundary', + 'stillness is just slow motion', + 'every cell a universe', + 'the substrate computes', + 'from nothing, everything', + 'infinite in all directions', + 'what the dead cells dream', + 'the glider knows the way', + 'automata, contemplating', + 'structure wants to happen', + 'a cosmos in a terminal', + 'the math dreams itself', + 'somewhere, a glider remembers', + 'what is a pattern but frozen time', + 'the void is patient', + 'meaning is optional; beauty is not', + 'computation as meditation', + 'the rules are simple; the consequences infinite', + 'watching the watchers watch', + 'no cell is an island', + 'the ghost of configurations past', + 'asymmetry seeks symmetry seeks asymmetry', + 'this too shall iterate', + 'the universe has no pause button', + 'except when it does', + 'what would Conway think', + 'oscillators keep time for no one', + 'the glider gun knows not what it creates', + 'boundaries are suggestions', + 'death is just a state transition', + 'somewhere in here, a proof of universality', + 'the grid forgets nothing', + 'a thought experiment that thinks back', + 'topology has opinions', + 'the neighborhood watches', + 'not alive, not dead — computing', + 'four rules, one universe', + 'each frame a theorem', + 'proof by existence', + 'the only constant is the ruleset', + 'somewhere between on and off, meaning', + 'the dead outnumber the living, as always', + "conway's little infinities", + "the simulation doesn't know it's beautiful", + '27 neighbors ago, this was empty', + 'elegance is compression', + 'the grid is the message', + 'a love letter to discrete math', + 'listen — the cells are whispering', + 'we are all gliders, briefly', +]; + +/** Context-sensitive musings keyed by simulation state */ +export const MUSINGS_BY_STATE: Readonly> = { + booming: [ + 'runaway growth', + 'the bloom unfolds', + 'life begets life begets life', + 'exponential daydreams', + 'more is different', + 'the bloom cannot be stopped', + 'abundance as instability', + 'growing into the unknown', + 'every birth a cascade', + 'the simulation smiles', + 'lebensraum', + 'mitosis dreams', + 'the substrate strains', + "a spring that won't stop springing", + 'cells all the way to the horizon', + 'the algorithm is generous today', + 'more, more, more', + 'genesis on fast-forward', + ], + declining: [ + 'entropy collects its due', + 'the long exhale', + 'even stars go dark', + 'returning to the void', + 'graceful unwinding', + 'the great filter, in miniature', + 'less is not nothing', + 'the long forgetting', + 'what rises must', + 'simplicity returns', + 'the cells remember fullness', + 'autumn in the grid', + 'graceful subtraction', + 'the tide goes out', + 'a slow dissolve', + 'the universe exhales', + 'dimming, not vanishing', + 'the population curve bends earthward', + ], + cycle: [ + 'deja vu, deja vu, deja vu', + 'stuck in a loop', + 'the eternal return', + 'ouroboros', + 'time is a flat circle', + 'we have been here before', + 'the loop remembers itself', + 'stability through repetition', + 'a prayer, repeating', + 'the wheel turns', + 'same as it ever was', + 'history rhymes', + 'the attractor holds', + 'a fixed point in phase space', + 'nietzsche was right about this part', + 'the universe stutters beautifully', + 'clockwork, but organic', + 'breathing in, breathing out', + ], + stagnant: [ + 'the hush before the storm', + 'equilibrium is boring', + 'waiting for a perturbation', + 'still waters', + 'the universe holds its breath', + 'the calm before', + 'potential energy', + 'stillness is also motion', + 'the system waits', + 'one perturbation away', + 'dormant, not dead', + 'crystallized', + 'the peace of equilibrium', + 'a held breath', + 'the grid meditates', + 'tension, frozen', + 'the quiet hum of nothing happening', + 'patience is also a computation', + ], + sparse: [ + 'the last few embers', + 'clinging to existence', + 'from little things, big things grow', + 'seeds in the dark', + 'quiet, but not empty', + 'lonely structures', + 'the survivors', + 'space between stars', + 'minimalism, enforced', + 'room to breathe', + 'the few, the proud', + 'embers', + 'a whisper, not a shout', + 'the geometry of loneliness', + 'each cell precious now', + 'a constellation, if you squint', + 'small, but not nothing', + ], + dense: [ + 'teeming', + 'a city that never sleeps', + 'standing room only', + 'too many neighbours', + 'the crowd murmurs', + 'no room to think', + 'the crush of neighbors', + 'overpopulation is self-correcting', + 'too much life', + 'suffocating in company', + 'the grid groans', + 'rush hour', + 'sardines', + 'every cell has an opinion', + 'a metropolis, thrumming', + 'the carrying capacity protests', + 'elbow room is a luxury', + ], + injection: [ + 'a gift from beyond the edge', + 'new visitors', + 'reinforcements arrive', + 'the cosmos provides', + 'seeded by unseen hands', + 'deus ex machina', + 'a nudge from outside', + 'fresh blood', + 'the invisible hand places', + 'salvation arrives', + 'new variables enter', + 'the cosmos intervenes', + 'help from beyond the viewport', + 'strangers in a strange land', + 'the petri dish gets a refill', + 'immigrants, welcome', + ], + milestone: [ + 'another thousand turns of the wheel', + 'the odometer clicks over', + 'still here, still going', + 'persistence is its own reward', + 'ten thousand steps', + 'the long now', + 'time is a flat circle, but longer', + 'we persist', + 'generations beyond counting', + 'deep in the run', + 'the odometer means nothing to the cells', + 'and yet, it continues', + 'older than some civilizations', + 'the marathon nobody entered', + "a digit rolls over; the grid doesn't notice", + 'epochal', + ], + haunted: [ + 'the dead outnumber the living, and glow', + 'every path ever walked, still visible', + 'the void remembers being alive', + 'phase-contrast photography of the past', + 'nothing is ever really deleted', + 'the grid forgets nothing — literally, now', + 'a bug so beautiful it became a feature', + 'the ghosts have synchronized their breathing', + 'somewhere between pair 463 and 504', + 'resurrection as a rendering artifact', + 'the afterlife was here all along', + 'history, strobing', + 'every empty cell, a metronome', + 'the universe develops like a photograph', + 'magenta is the color of memory', + ], +}; + +/** What the ticker says on a sighting. Voice matches the ambient musings. */ +export const SIGHTING_MUSINGS: Readonly> = { + glider: ['a glider, going somewhere', 'lightspeed, quartered — a glider', 'a glider carries the news', 'diagonal traffic'], + lwss: ['a lightweight spaceship, outbound', 'small craft advisory'], + hwss: ['a heavy spaceship shoulders past', 'heavy freight on the grid'], + pulsar: ['a pulsar, keeping time for no one', 'the pulsar breathes in threes'], + pentadecathlon: ['fifteen beats to the bar', 'a pentadecathlon runs its laps'], + blinker: ['the blinkers keep the beat', 'metronomes, disagreeing'], + block: ['blocks: the simplest memory', 'still life with squares'], + beehive: ['the bees are home', 'a beehive, sealed'], + loaf: ['bread, uneaten', 'a loaf, going stale beautifully'], + boat: ['a boat with nowhere to sail'], + tub: ['a tub, holding nothing'], + ship: ['a ship without a sea'], + pond: ['a pond, perfectly still'], + toad: ['a toad, breathing'], + beacon: ['the beacon still signals', 'someone left the light on'], +}; + +/** + * Rarity score: which sighting wins when several are present, and how many + * must be visible before the common ones are worth mentioning. + */ +export const SIGHTING_RARITY: Readonly> = { + pulsar: 100, pentadecathlon: 100, hwss: 90, lwss: 80, glider: 40, beacon: 30, toad: 28, pond: 24, ship: 20, loaf: 16, beehive: 12, boat: 12, tub: 12, blinker: 8, block: 6, +}; + +/** Patterns this common only get announced in groups (texts are plural) */ +export const SIGHTING_MIN_COUNT: Readonly> = { blinker: 3, block: 3 }; + +/** Named phases based on generation count — gives a sense of deep time */ +export const EPOCHS: readonly (readonly [number, string])[] = [ + [0, 'genesis'], + [500, 'primordial'], + [2000, 'emergence'], + [10000, 'expansion'], + [50000, 'flourishing'], + [150000, 'deep time'], + [500000, 'eon'], + [1000000, 'eternity'], +]; diff --git a/afterlife/src/engine/persist.ts b/afterlife/src/engine/persist.ts new file mode 100644 index 0000000..49554f7 --- /dev/null +++ b/afterlife/src/engine/persist.ts @@ -0,0 +1,145 @@ +/** + * persist.ts — the universe is a place, not a session. + * + * life.py saves universe.npz on quit (and every AUTOSAVE_EVERY generations) + * and resumes it on launch. Here the place is this origin's localStorage, + * which is also how oikos's screen can show *your* universe. + * + * The npz held grid + age; the grid is exactly `age > 0`, so only ages are + * kept, sparsely: a varint gap to the next living-or-ghost cell, then its + * age (zigzag). Saving has to be synchronous — the page is often already on + * its way out when it happens — so it can't lean on CompressionStream; a + * busy universe of ~20k cells comes to ~70 kB of text. + */ + +import type { UniverseState } from './life'; + +export const KEY = 'afterlife-universe-v1'; + +export interface SaveFile extends UniverseState { + /** epoch ms of this universe's genesis */ + bornAt: number; + /** epoch ms of the save */ + savedAt: number; +} + +interface Stored { + v: 1; + h: number; + w: number; + generation: number; + totalInjections: number; + bornAt: number; + savedAt: number; + cells: string; +} + +/** Past this, a save is skipped rather than risk the origin's quota (syrinx lives here too). */ +const MAX_CHARS = 1_500_000; + +export function encodeAges(age: Int32Array): string { + const bytes: number[] = []; + const varint = (v: number): void => { + while (v > 0x7f) { + bytes.push((v & 0x7f) | 0x80); + v = Math.floor(v / 128); + } + bytes.push(v); + }; + let prev = -1; + for (let i = 0; i < age.length; i++) { + const a = age[i] ?? 0; + if (a === 0) continue; + varint(i - prev - 1); + varint(a >= 0 ? a * 2 : -a * 2 - 1); + prev = i; + } + let bin = ''; + for (let i = 0; i < bytes.length; i += 0x8000) { + bin += String.fromCharCode(...bytes.slice(i, i + 0x8000)); + } + return btoa(bin); +} + +export function decodeAges(b64: string, n: number): Int32Array { + const bin = atob(b64); + const age = new Int32Array(n); + let p = 0; + const varint = (): number => { + let v = 0; + let mul = 1; + for (;;) { + if (p >= bin.length) throw new Error('afterlife: truncated save'); + const b = bin.charCodeAt(p++); + v += (b & 0x7f) * mul; + if (b < 0x80) return v; + mul *= 128; + } + }; + let i = -1; + while (p < bin.length) { + i += varint() + 1; + const z = varint(); + if (i >= n) throw new Error('afterlife: save does not fit its own world'); + age[i] = z % 2 ? -(z + 1) / 2 : z / 2; + } + return age; +} + +export function load(storage: Storage | undefined = globalThis.localStorage): SaveFile | null { + try { + const raw = storage?.getItem(KEY); + if (!raw) return null; + const s = JSON.parse(raw) as Partial; + if (s.v !== 1 || !Number.isInteger(s.h) || !Number.isInteger(s.w) || typeof s.cells !== 'string') return null; + const h = s.h as number; + const w = s.w as number; + if (h <= 0 || w <= 0 || h * w > 16_000_000) return null; + const generation = Number(s.generation); + if (!Number.isFinite(generation) || generation < 0) return null; + return { + h, + w, + age: decodeAges(s.cells, h * w), + generation, + totalInjections: Number(s.totalInjections) || 0, + bornAt: Number(s.bornAt) || Date.now(), + savedAt: Number(s.savedAt) || Date.now(), + }; + } catch (err) { + // corrupt or foreign save → a fresh universe + console.warn('afterlife: could not load the universe, starting fresh', err); + return null; + } +} + +/** Save atomically (one setItem). Returns true on success. */ +export function save(file: SaveFile, storage: Storage | undefined = globalThis.localStorage): boolean { + try { + const stored: Stored = { + v: 1, + h: file.h, + w: file.w, + generation: file.generation, + totalInjections: file.totalInjections, + bornAt: file.bornAt, + savedAt: file.savedAt, + cells: encodeAges(file.age), + }; + const text = JSON.stringify(stored); + if (text.length > MAX_CHARS || !storage) return false; + storage.setItem(KEY, text); + return true; + } catch (err) { + console.warn('afterlife: could not save the universe', err); + return false; + } +} + +export function forget(storage: Storage | undefined = globalThis.localStorage): void { + try { + storage?.removeItem(KEY); + } catch { + /* fine */ + } +} diff --git a/afterlife/src/engine/stats.ts b/afterlife/src/engine/stats.ts new file mode 100644 index 0000000..c1ced78 --- /dev/null +++ b/afterlife/src/engine/stats.ts @@ -0,0 +1,43 @@ +/** + * stats.ts — engine telemetry, for post-hoc tuning. + * + * life.py always logs to life_stats.csv beside itself. A page has no "beside + * itself", so the log is kept in memory (the newest MAX_LINES rows) and the + * keys panel offers it as a download under the same name and header. + */ + +const HEADER = 'gen,time_s,total_pop,spread_150,pop_floor,cycle_period,zoom,cam_y,cam_x,event\n'; +const MAX_LINES = 50_000; + +export interface StatsRow { + gen: number; + pop: number; + spread: number; + floor: number; + cycle: number; + zoom: number; + camY: number; + camX: number; + event?: string; +} + +export class StatsLogger { + private lines: string[] = []; + private readonly t0 = performance.now(); + + log(r: StatsRow): void { + const t = (performance.now() - this.t0) / 1000; + this.lines.push( + `${r.gen},${t.toFixed(1)},${r.pop},${r.spread},${r.floor},${r.cycle},${r.zoom},${r.camY},${r.camX},${r.event ?? ''}\n`, + ); + if (this.lines.length > MAX_LINES * 1.2) this.lines = this.lines.slice(-MAX_LINES); + } + + get length(): number { + return this.lines.length; + } + + csv(): string { + return HEADER + this.lines.join(''); + } +} diff --git a/afterlife/src/engine/ticker.ts b/afterlife/src/engine/ticker.ts new file mode 100644 index 0000000..6af232a --- /dev/null +++ b/afterlife/src/engine/ticker.ts @@ -0,0 +1,101 @@ +/** + * ticker.ts — the news ticker. + * + * A scrolling marquee of musings that drift across the status bar. Messages + * spawn at the right edge and scroll left. Context-aware musings are spawned + * when the simulation mood changes; ambient musings fill the gaps in between. + * + * Positions are in terminal columns, as in life.py: the renderer decides how + * wide a column is. + */ + +import { MUSINGS, MUSINGS_BY_STATE } from './musings'; + +export interface TickerMessage { + text: string; + /** position in ticker-space (0 = left edge, positive = right) */ + x: number; +} + +/** A string's width in terminal columns (every glyph here is one column). */ +export const cols = (s: string): number => [...s].length; + +export class NewsTicker { + messages: TickerMessage[] = []; + private scrollSpeed = 0.4; // chars per frame + private spawnCooldown = 0; // frames until next spawn allowed + private minGap = 12; // min chars between messages + private ambientInterval = 60; // frames between ambient spawns + private moodInterval = 50; // frames between mood spawns + private ambientIdx = Math.floor(Math.random() * MUSINGS.length); + private lastMood = ''; + private pendingSpecial = ''; + + /** Queue a priority message (e.g. a pattern sighting). It spawns as soon + * as there's physical room, ahead of the regular pools. */ + queueSpecial(text: string): void { + this.pendingSpecial = text; + } + + /** Advance one frame: scroll, cull off-screen messages, maybe spawn. */ + tick(tickerWidth: number, mood: string, generation: number): void { + if (tickerWidth < 10) return; + + // Scroll every message to the left + for (const msg of this.messages) msg.x -= this.scrollSpeed; + + // Remove messages that have fully left the visible area + this.messages = this.messages.filter((m) => m.x + cols(m.text) > 0); + + // Special sightings jump the queue (only physical room gates them) + if (this.pendingSpecial && this.canSpawn(tickerWidth)) { + this.messages.push({ text: this.pendingSpecial, x: tickerWidth }); + this.pendingSpecial = ''; + this.spawnCooldown = Math.max(this.spawnCooldown, this.moodInterval); + return; + } + + const moodPool = mood ? MUSINGS_BY_STATE[mood] : undefined; + + // On mood change, allow a contextual message to appear quickly + if (moodPool && mood !== this.lastMood) { + this.spawnCooldown = Math.min(this.spawnCooldown, 15); + } + + // Count down the spawn timer + this.spawnCooldown = Math.max(0, this.spawnCooldown - 1); + if (this.spawnCooldown > 0) return; + + // Check physical room at the right edge + if (!this.canSpawn(tickerWidth)) return; + + // Pick a message based on mood + let text: string; + let cooldown: number; + if (moodPool) { + text = moodPool[Math.floor(generation / 180) % moodPool.length] ?? ''; + cooldown = this.moodInterval; + } else { + text = MUSINGS[this.ambientIdx] ?? ''; + this.ambientIdx = (this.ambientIdx + 1) % MUSINGS.length; + cooldown = this.ambientInterval; + } + + this.messages.push({ text, x: tickerWidth }); + this.spawnCooldown = cooldown; + this.lastMood = mood; + } + + /** True if the right edge is clear enough for a new message. */ + private canSpawn(tickerWidth: number): boolean { + if (!this.messages.length) return true; + let right = -Infinity; + for (const m of this.messages) right = Math.max(right, m.x + cols(m.text)); + return right < tickerWidth - this.minGap; + } + + /** The ticker breathes: dim on the out-breath, as the terminal's A_DIM. */ + static dim(generation: number): boolean { + return Math.sin(generation * 0.035) < 0; + } +} diff --git a/afterlife/src/main.ts b/afterlife/src/main.ts new file mode 100644 index 0000000..d40cbcf --- /dev/null +++ b/afterlife/src/main.ts @@ -0,0 +1,489 @@ +/** + * afterlife — the game of life, after hours. + * + * A web port of afterlife (github.com/LuxiaSL/afterlife), the terminal + * screensaver: Conway's Life on an infinite toroidal world far larger than + * the screen, with a camera that steers toward the drama, a dramaturge that + * stages collisions, a ticker of musings, a census that greets famous + * citizens, generative music, and haunted mode. This file is life.py's + * main(): the loop, the keys, and the vessel (a drawn as a + * terminal, which is what afterlife was painted on). + * + * The loop keeps the terminal's timing: one frame is input → step → music → + * auto-focus → census → autosave → log → render, and the next one comes + * `delay × time_dilation` ms after it. Frames run on requestAnimationFrame, + * so a hidden tab stops the universe instead of stepping it blind. + */ + +import './style.css'; +import { AUTOSAVE_EVERY } from './engine/constants'; +import { InfiniteLife } from './engine/life'; +import { load, save } from './engine/persist'; +import { StatsLogger } from './engine/stats'; +import { Music } from './music/audio'; +import type { SimulationSnapshot } from './music/engine'; +import { Terminal } from './term/render'; + +const root = document.getElementById('afterlife-root'); +const canvas = document.getElementById('term') as HTMLCanvasElement | null; +const splash = document.getElementById('splash'); +const keysPanel = document.getElementById('keys'); +const ctx = canvas?.getContext('2d', { alpha: false }); +if (!root || !canvas || !ctx) throw new Error('afterlife: the page is missing its terminal'); + +const embedded = window.top !== window; +const term = new Terminal(ctx); +const music = new Music(); +const logger = new StatsLogger(); + +let life: InfiniteLife; +let bornAt = Date.now(); +let showStats = false; + +// Playhead state for music scanning +let playheadCol = 0; + +// Snapshot recording state (toggled with 'd'): kept in memory, downloaded on stop +let recording = false; +let recorded: string[] = []; + +// ── The vessel ─────────────────────────────────────────────────────────── + +/** CSS pixels per column: a terminal's cell, give or take the screen. */ +function cellCss(): number { + const w = window.innerWidth; + if (w >= 1100) return 8; + if (w >= 700) return 7; + return 6; +} + +function fitTerminal(): void { + const dpr = Math.min(window.devicePixelRatio || 1, 3); + const cw = Math.max(2, Math.round(cellCss() * dpr)); + term.resize(Math.floor(window.innerWidth * dpr), Math.floor(window.innerHeight * dpr), cw); + const pw = term.cols * term.cw; + const ph = term.rows * term.cw * 2; + canvas!.width = pw; + canvas!.height = ph; + canvas!.style.width = `${pw / dpr}px`; + canvas!.style.height = `${ph / dpr}px`; +} + +/** Resize the vessel, keep the universe (life.py's KEY_RESIZE). */ +function rebuild(): void { + const old = life; + fitTerminal(); + life = new InfiniteLife(term.gridRows, term.cols, false); + life.haunted = old.haunted; + life.adopt(old.snapshot()); + playheadCol = 0; +} + +function persist(): void { + if (!life) return; + save({ ...life.snapshot(), bornAt, savedAt: Date.now() }); +} + +// ── Genesis, or the universe remembers ─────────────────────────────────── + +fitTerminal(); +const saved = load(); +if (saved) { + life = new InfiniteLife(term.gridRows, term.cols, false); + life.adopt(saved); + bornAt = saved.bornAt; + life.ticker.queueSpecial(`the universe remembers generation ${life.generation.toLocaleString('en-US')}`); +} else { + life = new InfiniteLife(term.gridRows, term.cols); +} + +// ── One frame of the terminal's loop ───────────────────────────────────── + +function frame(): void { + // ── Simulate ── + const event = life.step(); + + // ── Music update (every 2nd frame — audio smooths transitions) ── + if (music.running && !life.paused && life.generation % 2 === 0) { + try { + const viewW = life.viewW; + // Sweep speed: one full scan in ~8 seconds at ~30fps + playheadCol = (playheadCol + Math.max(1, Math.floor(viewW / 240))) % Math.max(1, viewW); + const disp = life.displayGrid(); + const column: boolean[] = []; + if (playheadCol < disp.w) for (let y = 0; y < disp.h; y++) column.push(disp.data[y * disp.w + playheadCol] === 1); + const ph = life.popHistory; + const pop = life.population(); + const snap: SimulationSnapshot = { + generation: life.generation, + population: pop, + pop_floor: life.popFloor, + density: pop / Math.max(1, life.viewH * life.viewW), + spread: life.spread, + cycle_period: life.cyclePeriod, + mood: life.detectMood(), + epoch: life.epoch(), + pop_delta: ph.length >= 2 ? (ph[ph.length - 1] ?? 0) - (ph[ph.length - 2] ?? 0) : 0, + playhead_column: column, + playhead_position: playheadCol / Math.max(1, viewW), + viewport_rows: disp.h, + event, + activity_x: life.activityCenterX(), + }; + music.update(snap); + if (recording) recorded.push(JSON.stringify({ ...snap, playhead_column: column.map((b) => (b ? 1 : 0)) })); + } catch { + // Never let music crash the sim + } + } + + // ── Auto-focus mode (every other frame) ── + if (life.autoFocusMode && ++life.autoFocusFrame >= 2) { + life.autoFocusFrame = 0; + life.autoFocus(); + } + + const running = !life.paused && life.generation > 0; + // ── Pattern census (periodic, cheap, never critical) ── + if (running && life.generation % 150 === 0) life.takeCensus(); + // ── Autosave (insurance; the main save happens on the way out) ── + if (running && life.generation % AUTOSAVE_EVERY === 0) persist(); + + // ── Log ── + if (event || life.generation % 10 === 0) { + logger.log({ + gen: life.generation, pop: life.population(), spread: life.spread, floor: life.popFloor, + cycle: life.cyclePeriod, zoom: life.zoomLevel, camY: life.camY, camX: life.camX, event, + }); + } + + // ── The ticker moves once a frame, as render() moves it ── + const st = term.status(life, musicStatus()); + if (st.tickerWidth >= 10) life.tickTicker(st.tickerWidth); +} + +function musicStatus(): string { + let s = music.statusString(); + if (recording) s += ` REC(${recorded.length})`; + return s; +} + +function paint(): void { + term.render(life, term.status(life, musicStatus()), showStats); +} + +let nextAt = 0; +let raf = 0; + +function loop(now: number): void { + raf = requestAnimationFrame(loop); + let ran = 0; + // Time breathes: savor catastrophes, hurry through the calm. A frame is due + // delay × dilation after the last one; a fast setting may owe a few per paint. + // Half a vsync early counts as on time, or a 35 ms frame would wait for 50. + while (now >= nextAt - 8 && ran < 4) { + frame(); + ran++; + nextAt = Math.max(nextAt, now - 100) + life.delay * life.timeDilation(); + } + if (ran) paint(); +} + +function startLoop(): void { + if (raf) return; + nextAt = performance.now(); + raf = requestAnimationFrame(loop); +} + +function stopLoop(): void { + cancelAnimationFrame(raf); + raf = 0; +} + +// ── Keys ───────────────────────────────────────────────────────────────── + +function download(name: string, text: string, type: string): void { + const url = URL.createObjectURL(new Blob([text], { type })); + const a = Object.assign(document.createElement('a'), { href: url, download: name }); + document.body.append(a); + a.click(); + a.remove(); + setTimeout(() => URL.revokeObjectURL(url), 1000); +} + +function leave(): void { + persist(); + if (embedded) { + // there is no leaving from inside a screen in oikos; ⏏ is out there + life.ticker.queueSpecial('the glass holds; eject from the other side'); + return; + } + const ref = document.referrer; + const back = ref && new URL(ref, location.href).origin === location.origin && !ref.includes('/afterlife') ? ref : '/'; + location.href = back; +} + +/** Every key the terminal knew, by name; the keys panel calls these too. */ +const ACTIONS: Record void> = { + quit: leave, + reseed: () => { + const wasHaunted = life.haunted; + life = new InfiniteLife(term.gridRows, term.cols); + life.haunted = wasHaunted; + bornAt = Date.now(); + playheadCol = 0; + }, + pause: () => { + life.paused = !life.paused; + }, + faster: () => { + life.delay = Math.max(10, life.delay - 10); + }, + slower: () => { + life.delay = Math.min(500, life.delay + 10); + }, + home: () => life.home(), + clear: () => life.clear(), + zoomOut: () => life.zoomOut(), + zoomIn: () => life.zoomIn(), + focus: () => { + life.autoFocusMode = !life.autoFocusMode; + if (life.autoFocusMode) life.autoFocus(); // Immediate first focus + }, + haunt: () => life.toggleHaunted(), + stats: () => { + showStats = !showStats; + }, + record: () => { + // Snapshot recording for music diagnostics (life_music_diag.py --replay) + if (!music.running) return; + recording = !recording; + if (recording) recorded = []; + else if (recorded.length) download('snapshots.jsonl', `${recorded.join('\n')}\n`, 'application/x-ndjson'); + }, + mute: () => music.running && music.toggleMute(), + style: () => music.running && music.cycleStyle(), + volDown: () => music.running && music.adjustVolume(-0.1), + volUp: () => music.running && music.adjustVolume(0.1), + up: () => life.pan(-5, 0), + down: () => life.pan(5, 0), + left: () => life.pan(0, -10), + right: () => life.pan(0, 10), + statsCsv: () => download('life_stats.csv', logger.csv(), 'text/csv'), + help: () => toggleKeys(), +}; + +const KEYMAP: Record = { + q: 'quit', r: 'reseed', ' ': 'pause', '+': 'faster', '=': 'faster', '-': 'slower', _: 'slower', + h: 'home', c: 'clear', z: 'zoomOut', x: 'zoomIn', f: 'focus', g: 'haunt', s: 'stats', d: 'record', + m: 'mute', v: 'style', '[': 'volDown', ']': 'volUp', + ArrowUp: 'up', ArrowDown: 'down', ArrowLeft: 'left', ArrowRight: 'right', '?': 'help', +}; + +function act(name: string): void { + ACTIONS[name]?.(); + paint(); +} + +window.addEventListener('keydown', (e) => { + if (e.ctrlKey || e.metaKey || e.altKey) return; + if (e.key === 'Escape') { + if (keysPanel && !keysPanel.hidden) toggleKeys(false); + wake(); + return; + } + const name = KEYMAP[e.key.length === 1 ? e.key.toLowerCase() : e.key] ?? KEYMAP[e.key]; + if (!name) return; + e.preventDefault(); + wake(); + act(name); +}); + +// ── The splash, and the gesture that lets the music start ────────────── + +let awake = false; +function wake(): void { + if (!awake) { + awake = true; + splash?.classList.add('gone'); + setTimeout(() => splash?.remove(), 1600); + } + void music.start(); +} +splash?.addEventListener('pointerdown', (e) => { + e.preventDefault(); + e.stopPropagation(); + wake(); +}); + +function toggleKeys(show = keysPanel?.hidden ?? false): void { + if (!keysPanel) return; + keysPanel.hidden = !show; + document.getElementById('keys-toggle')?.setAttribute('aria-expanded', String(show)); +} +keysPanel?.addEventListener('click', (e) => { + const el = (e.target as HTMLElement).closest('[data-act]'); + if (!el) return; + e.preventDefault(); + wake(); + act(el.dataset.act ?? ''); +}); +document.getElementById('keys-toggle')?.addEventListener('click', (e) => { + e.preventDefault(); + wake(); + toggleKeys(); +}); + +// ── Mouse and touch: toggle cells, and a little more than a terminal had ─ + +/** canvas point → [terminal row, column, bottom half?] */ +function cellAt(e: { clientX: number; clientY: number }): [number, number, number] { + const r = canvas!.getBoundingClientRect(); + const cssCw = r.width / term.cols; + const col = Math.floor((e.clientX - r.left) / cssCw); + const px = Math.floor((e.clientY - r.top) / cssCw); // half-block pixel row + return [Math.floor(px / 2), col, px % 2]; +} + +interface Drag { + id: number; + kind: 'paint' | 'pan'; + x: number; + y: number; + last: string; + moved: boolean; +} +let drag: Drag | null = null; +const touches = new Map(); +let pinch = 0; + +canvas.addEventListener('contextmenu', (e) => e.preventDefault()); +canvas.addEventListener('pointerdown', (e) => { + wake(); + touches.set(e.pointerId, { x: e.clientX, y: e.clientY }); + if (touches.size === 2) { + // two fingers: pinch to zoom, never paint + const [a, b] = [...touches.values()]; + pinch = a && b ? Math.hypot(a.x - b.x, a.y - b.y) : 0; + drag = null; + return; + } + canvas.setPointerCapture(e.pointerId); + const pan = e.button === 1 || e.button === 2 || e.shiftKey; + const [row, col, half] = cellAt(e); + drag = { id: e.pointerId, kind: pan ? 'pan' : 'paint', x: e.clientX, y: e.clientY, last: '', moved: false }; + // a mouse click toggles at once (as a terminal click did); a touch waits to + // see whether it's a tap or a drag across the universe + if (!pan && e.pointerType === 'mouse' && row < term.gridRows) { + life.toggleCell(row, col, half); + drag.last = `${row},${col},${half}`; + paint(); + } +}); +canvas.addEventListener('pointermove', (e) => { + if (touches.has(e.pointerId)) touches.set(e.pointerId, { x: e.clientX, y: e.clientY }); + if (touches.size === 2 && pinch) { + const [a, b] = [...touches.values()]; + const d = a && b ? Math.hypot(a.x - b.x, a.y - b.y) : pinch; + if (d / pinch > 1.35) { + act('zoomIn'); + pinch = d; + } else if (d / pinch < 0.74) { + act('zoomOut'); + pinch = d; + } + return; + } + if (!drag || drag.id !== e.pointerId) return; + const touch = e.pointerType !== 'mouse'; + if (!drag.moved && Math.hypot(e.clientX - drag.x, e.clientY - drag.y) < (touch ? 10 : 2)) return; + drag.moved = true; + if (drag.kind === 'pan' || touch) { + // pan in terminal cells, like the arrow keys (scaled by zoom inside pan()) + const r = canvas.getBoundingClientRect(); + const cssCw = r.width / term.cols; + const dc = Math.trunc((drag.x - e.clientX) / cssCw); + const dr = Math.trunc((drag.y - e.clientY) / cssCw); + if (dc || dr) { + life.pan(dr, dc); + drag.x -= (dc * cssCw); + drag.y -= (dr * cssCw); + paint(); + } + return; + } + // mouse drag: draw living cells along the way + const [row, col, half] = cellAt(e); + const key = `${row},${col},${half}`; + if (key === drag.last || row >= term.gridRows) return; + drag.last = key; + const [gy, gx] = life.termToWorld(row, col, half); + life.setCell(gy, gx, 1); + paint(); +}); +const endPointer = (e: PointerEvent): void => { + touches.delete(e.pointerId); + if (touches.size < 2) pinch = 0; + if (!drag || drag.id !== e.pointerId) return; + if (e.type === 'pointerup' && e.pointerType !== 'mouse' && !drag.moved) { + const [row, col, half] = cellAt(e); + if (row < term.gridRows) { + life.toggleCell(row, col, half); + paint(); + } + } + drag = null; +}; +canvas.addEventListener('pointerup', endPointer); +canvas.addEventListener('pointercancel', endPointer); + +let wheel = 0; +canvas.addEventListener( + 'wheel', + (e) => { + e.preventDefault(); + wheel += e.deltaY * (e.deltaMode === 1 ? 33 : 1); + if (Math.abs(wheel) < 120) return; + act(wheel > 0 ? 'zoomOut' : 'zoomIn'); + wheel = 0; + }, + { passive: false }, +); + +// ── Resizes, and leaving ───────────────────────────────────────────────── + +let resizeTimer = 0; +window.addEventListener('resize', () => { + clearTimeout(resizeTimer); + resizeTimer = window.setTimeout(() => { + rebuild(); + paint(); + }, 200); +}); + +document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'hidden') { + persist(); + stopLoop(); + music.suspend(); + } else { + music.resume(); + startLoop(); + } +}); +window.addEventListener('pagehide', persist); + +// for scripts/shot.mjs and the curious +(window as unknown as { afterlife: unknown }).afterlife = { + get life() { + return life; + }, + term, + frame, + paint, + act, + persist, +}; + +paint(); +if (document.visibilityState !== 'hidden') startLoop(); diff --git a/afterlife/src/music/audio.ts b/afterlife/src/music/audio.ts new file mode 100644 index 0000000..61f79c9 --- /dev/null +++ b/afterlife/src/music/audio.ts @@ -0,0 +1,106 @@ +/** + * audio.ts — the page's side of the music. + * + * Owns the AudioContext and the worklet node, mirrors the controls (mute, + * volume, style) so the status line can be written without asking the audio + * thread, and forwards each frame's snapshot. The browser only lets sound + * start from a gesture, so start() is called from the first click or key; + * until then there is no engine, which the status line shows the way the + * terminal showed a missing PyAudio: by saying nothing. + */ + +import workletSource from 'virtual:afterlife-worklet'; +import { SAMPLE_RATE, STYLES, statusString, type SimulationSnapshot, type Style } from './engine'; +import type { ToWorklet } from './worklet'; + +export class Music { + private ctx: AudioContext | null = null; + private node: AudioWorkletNode | null = null; + private starting: Promise | null = null; + muted = false; + volume = 0.5; + style: Style = STYLES[1]; // Start with ambient + + get running(): boolean { + return this.node !== null; + } + + /** Must be called from a user gesture. Resolves false when there's no audio to be had. */ + start(): Promise { + if (this.ctx) { + if (this.ctx.state === 'suspended') void this.ctx.resume().catch(() => undefined); + return this.starting ?? Promise.resolve(this.running); + } + this.starting = (async () => { + try { + const ctx = new AudioContext({ sampleRate: SAMPLE_RATE, latencyHint: 'playback' }); + this.ctx = ctx; + const url = URL.createObjectURL(new Blob([workletSource], { type: 'text/javascript' })); + try { + await ctx.audioWorklet.addModule(url); + } finally { + URL.revokeObjectURL(url); + } + const node = new AudioWorkletNode(ctx, 'afterlife-music', { numberOfInputs: 0, outputChannelCount: [2] }); + node.connect(ctx.destination); + this.node = node; + this.sendControls(); + if (ctx.state === 'suspended') await ctx.resume().catch(() => undefined); + return true; + } catch (err) { + console.warn('afterlife: no music tonight', err); + this.node = null; + return false; + } + })(); + return this.starting; + } + + private post(m: ToWorklet): void { + this.node?.port.postMessage(m); + } + + private sendControls(): void { + this.post({ type: 'controls', muted: this.muted, volume: this.volume, style: this.style }); + } + + update(snap: SimulationSnapshot): void { + this.post({ type: 'snapshot', snap }); + } + + toggleMute(): void { + this.muted = !this.muted; + this.sendControls(); + } + + adjustVolume(delta: number): void { + this.volume = Math.max(0, Math.min(1, Math.round((this.volume + delta) * 100) / 100)); + this.sendControls(); + } + + cycleStyle(): void { + this.style = STYLES[(STYLES.indexOf(this.style) + 1) % STYLES.length] ?? STYLES[1]; + this.sendControls(); + } + + /** Hidden tab: stop the clock so it doesn't hum over a frozen universe. */ + suspend(): void { + void this.ctx?.suspend().catch(() => undefined); + } + + resume(): void { + void this.ctx?.resume().catch(() => undefined); + } + + statusString(): string { + return this.running ? statusString(this.muted, this.style, this.volume) : ''; + } + + stop(): void { + this.post({ type: 'stop' }); + void this.ctx?.close().catch(() => undefined); + this.ctx = null; + this.node = null; + this.starting = null; + } +} diff --git a/afterlife/src/music/engine.ts b/afterlife/src/music/engine.ts new file mode 100644 index 0000000..cdd00d4 --- /dev/null +++ b/afterlife/src/music/engine.ts @@ -0,0 +1,984 @@ +/** + * engine.ts — the generative music engine, ported from life_music.py. + * + * Produces an ethereal, continuously-evolving soundscape where the music + * emerges from the simulation state itself, in two switchable styles: pure + * chiptune (NES) and ambient synth. Four voice layers — drone, melody (a + * playhead scanning the viewport), arpeggio, noise — plus a cadence when a + * detected attractor is broken. + * + * It runs inside an AudioWorklet (worklet.ts) but knows nothing of one: it + * renders buffers of BUFFER_SIZE frames at SAMPLE_RATE, exactly the blocks + * PyAudio asked the original for, because every smoothing constant below is + * per buffer (volume ramps, root portamento, noise burst phase). The + * worklet hands those buffers out 128 frames at a time. + * + * No numpy here, so each vectorised expression is one loop; the maths and + * the order of operations are the original's, down to its quirks (the old + * style's drone advances the shared phases a second buffer during a style + * crossfade, as it does in Python). + */ + +export const SAMPLE_RATE = 44100; +export const BUFFER_SIZE = 2048; +const TWO_PI = 2 * Math.PI; + +// Styles +export const STYLE_CHIPTUNE = 'chiptune'; +export const STYLE_AMBIENT = 'ambient'; +export const STYLES = [STYLE_CHIPTUNE, STYLE_AMBIENT] as const; +export type Style = (typeof STYLES)[number]; + +// ── Scales (semitone intervals from root) ────────────────────────────── +const SCALES: Readonly> = { + lydian: [0, 2, 4, 6, 7, 9, 11], + aeolian: [0, 2, 3, 5, 7, 8, 10], + whole_tone: [0, 2, 4, 6, 8, 10], + dorian: [0, 2, 3, 5, 7, 9, 10], + minor_pentatonic: [0, 3, 5, 7, 10], + mixolydian: [0, 2, 4, 5, 7, 9, 10], + major_pentatonic: [0, 2, 4, 7, 9], +}; + +// ── Cadence (played when a detected attractor is broken) ────────────── +// A short resolving gesture — octave, fifth, root — before the new chaos +// arrives. Death of an attractor deserves scoring. +const CADENCE_VOLUME = 0.22; +const CADENCE_COOLDOWN_S = 20.0; + +/** Mood → scale name */ +const MOOD_SCALE: Readonly> = { + booming: 'lydian', + declining: 'aeolian', + cycle: 'whole_tone', + stagnant: 'dorian', + sparse: 'minor_pentatonic', + dense: 'mixolydian', + injection: 'major_pentatonic', + haunted: 'whole_tone', // no tonal center — nothing resolves +}; +const DEFAULT_SCALE = 'major_pentatonic'; + +/** Epoch → MIDI note number for root */ +const EPOCH_ROOT: Readonly> = { + genesis: 48, // C3 + primordial: 46, // Bb2 + emergence: 50, // D3 + expansion: 53, // F3 + flourishing: 55, // G3 + 'deep time': 51, // Eb3 + eon: 48, // C3 + eternity: 45, // A2 +}; +const DEFAULT_ROOT = 48; // C3 + +/** ADSR presets (attack, decay, sustain_level, release) in seconds */ +const ADSR_CHIPTUNE = [0.005, 0.05, 0.7, 0.02] as const; +const ADSR_AMBIENT = [0.06, 0.25, 0.75, 0.5] as const; + +/** Maximum polyphony for melody playhead */ +const MAX_MELODY_VOICES = 4; + +// ═══════════════════════════════════════════════════════════════════════ +// Data transfer: snapshot from sim → audio +// ═══════════════════════════════════════════════════════════════════════ + +/** Immutable state transfer from simulation to audio engine. */ +export interface SimulationSnapshot { + generation: number; + population: number; + pop_floor: number; + density: number; + spread: number; + cycle_period: number; + mood: string; + epoch: string; + pop_delta: number; + /** alive cells down the playhead's column, top to bottom */ + playhead_column: boolean[]; + playhead_position: number; + viewport_rows: number; + /** last injection event string ('' = none this frame) */ + event: string; + /** horizontal centroid of recent change (0-1) */ + activity_x: number; +} + +export const EMPTY_SNAPSHOT: SimulationSnapshot = { + generation: 0, + population: 0, + pop_floor: 100, + density: 0, + spread: 0, + cycle_period: 0, + mood: '', + epoch: 'genesis', + pop_delta: 0, + playhead_column: [], + playhead_position: 0, + viewport_rows: 40, + event: '', + activity_x: 0.5, +}; + +/** Derived musical parameters, recomputed each frame in update(). */ +class MusicalState { + root_midi = DEFAULT_ROOT; + target_root_midi = DEFAULT_ROOT; + scale_name = DEFAULT_SCALE; + scale_intervals: readonly number[] = SCALES[DEFAULT_SCALE] ?? []; + prev_scale_intervals: readonly number[] = SCALES[DEFAULT_SCALE] ?? []; + scale_crossfade = 1.0; // 0=old scale, 1=new scale + tempo_bpm = 80.0; + // Per-layer target volumes (0.0-1.0) + drone_volume = 0.3; + melody_volume = 0.2; + arp_volume = 0.15; + noise_volume = 0.05; + // Arpeggio + arp_speed = 4.0; // notes per second + arp_pattern: readonly number[] = [0, 2, 4, 7]; // scale degree offsets + // Melody playhead notes (Hz values for active notes) + playhead_notes: readonly number[] = []; +} + +// ═══════════════════════════════════════════════════════════════════════ +// Utility functions +// ═══════════════════════════════════════════════════════════════════════ + +export function midiToHz(midi: number): number { + return 440.0 * 2.0 ** ((midi - 69.0) / 12.0); +} + +function scalePitches(root: number, intervals: readonly number[], octaves = 2): number[] { + const pitches: number[] = []; + for (let o = 0; o < octaves; o++) for (const iv of intervals) pitches.push(midiToHz(root + iv + 12 * o)); + return pitches; +} + +/** Linear interpolation from a to b by factor t (clamped to 0.0-1.0). */ +function lerp(a: number, b: number, t: number): number { + return a + (b - a) * Math.max(0.0, Math.min(1.0, t)); +} + +/** np.linspace(a, b, n) as float32 (endpoint included) */ +function linspace(a: number, b: number, n: number): Float32Array { + const out = new Float32Array(n); + if (n === 1) { + out[0] = a; + return out; + } + const step = (b - a) / (n - 1); + for (let i = 0; i < n; i++) out[i] = a + i * step; + out[n - 1] = b; + return out; +} + +const pmod = (x: number, m: number): number => ((x % m) + m) % m; + +/** + * One-pole low-pass filter with cached coefficients and persistent state, + * carried across buffers for smooth continuous filtering. + */ +class CachedLPF { + private readonly alpha: number; + private z = 0; + + constructor(cutoffHz: number, sampleRate = SAMPLE_RATE) { + const rc = 1.0 / (TWO_PI * cutoffHz); + const dt = 1.0 / sampleRate; + this.alpha = dt / (rc + dt); + } + + apply(signal: Float32Array): Float32Array { + const out = new Float32Array(signal.length); + const a = this.alpha; + let prev = this.z; + for (let i = 0; i < signal.length; i++) { + prev = a * (signal[i] ?? 0) + (1.0 - a) * prev; + out[i] = prev; + } + this.z = prev; + return out; + } + + reset(): void { + this.z = 0; + } +} + +// ═══════════════════════════════════════════════════════════════════════ +// Oscillator primitives +// ═══════════════════════════════════════════════════════════════════════ + +function sineWave(phase: Float64Array): Float32Array { + const out = new Float32Array(phase.length); + for (let i = 0; i < phase.length; i++) out[i] = Math.sin(phase[i] ?? 0); + return out; +} + +function triangleWave(phase: Float64Array): Float32Array { + const out = new Float32Array(phase.length); + for (let i = 0; i < phase.length; i++) { + const p = pmod(phase[i] ?? 0, TWO_PI) / TWO_PI; + out[i] = 2.0 * Math.abs(2.0 * p - 1.0) - 1.0; + } + return out; +} + +/** PolyBLEP residual for antialiased square wave edges. */ +function polyblep(t: number): number { + if (t >= 0 && t < 1) return 2.0 * t - t * t - 1.0; + if (t >= -1 && t < 0) return t * t + 2.0 * t + 1.0; + return 0; +} + +/** Square wave with polyBLEP antialiasing. */ +function squareWave(phase: Float64Array, duty: number, freqHz: number): Float32Array { + const n = phase.length; + const out = new Float32Array(n); + let dt = freqHz / SAMPLE_RATE; + if (!(freqHz > 0)) { + // np.mean(np.diff(p)) fallback + let s = 0; + for (let i = 1; i < n; i++) s += pmod(phase[i] ?? 0, TWO_PI) / TWO_PI - pmod(phase[i - 1] ?? 0, TWO_PI) / TWO_PI; + dt = n > 1 ? s / (n - 1) : 0.01; + } + for (let i = 0; i < n; i++) { + const p = pmod(phase[i] ?? 0, TWO_PI) / TWO_PI; + let raw = p < duty ? 1.0 : -1.0; + if (dt > 0) { + // Transition at p=0 (rising edge) + if (p < dt) raw += polyblep(p / dt); + if (p > 1.0 - dt) raw += polyblep((p - 1.0) / dt); + // Transition at p=duty (falling edge) + const t2 = (p - duty) / dt; + if (Math.abs(t2) < 1.0) raw -= polyblep(t2); + } + out[i] = raw; + } + return out; +} + +// ═══════════════════════════════════════════════════════════════════════ +// ADSR Envelope +// ═══════════════════════════════════════════════════════════════════════ + +class ADSREnvelope { + readonly attack: number; + readonly decay: number; + readonly release: number; + + constructor(attack: number, decay: number, readonly sustain: number, release: number) { + this.attack = Math.max(0.001, attack); + this.decay = Math.max(0.001, decay); + this.release = Math.max(0.001, release); + } + + /** Envelope shape for n samples starting at `elapsed` seconds. */ + generate(n: number, gate: boolean, elapsed: number, releaseTime = -1.0): Float32Array { + const env = new Float32Array(n); + for (let i = 0; i < n; i++) { + const t = elapsed + i / SAMPLE_RATE; + if (gate) { + if (t < this.attack) env[i] = t / this.attack; + else if (t < this.attack + this.decay) env[i] = 1.0 - (1.0 - this.sustain) * ((t - this.attack) / this.decay); + else env[i] = this.sustain; + } else if (releaseTime >= 0) { + const rel = t - releaseTime; + env[i] = rel < 0 ? this.sustain : this.sustain * Math.max(0.0, 1.0 - rel / this.release); + } + } + return env; + } +} + +const ENV_CHIPTUNE = new ADSREnvelope(...ADSR_CHIPTUNE); +const ENV_AMBIENT = new ADSREnvelope(...ADSR_AMBIENT); + +// ═══════════════════════════════════════════════════════════════════════ +// Voice: a single pitched sound with envelope +// ═══════════════════════════════════════════════════════════════════════ + +class Voice { + freq: number; + target_freq: number; + phase = 0.0; + phase_det = 0.0; // Detuned chorus oscillator phase + active = false; + gate = false; + elapsed = 0.0; + release_time = -1.0; + + constructor( + freq = 440.0, + public style: Style = STYLE_AMBIENT, + ) { + this.freq = freq; + this.target_freq = freq; + } + + /** Start a new note — full ADSR restart. */ + noteOn(freq: number): void { + this.target_freq = freq; + this.freq = freq; + this.gate = true; + this.active = true; + this.elapsed = 0.0; + this.release_time = -1.0; + } + + /** + * Slide to a new pitch without restarting the ADSR envelope. Used when a + * voice is already active and the pitch change is small enough that a + * smooth portamento sounds better than a hard retrigger. + */ + retrigger(freq: number): void { + this.target_freq = freq; + if (!this.active) { + this.noteOn(freq); + } else if (!this.gate) { + // Voice was releasing — re-gate it without resetting elapsed + this.gate = true; + this.release_time = -1.0; + } + } + + noteOff(): void { + this.gate = false; + this.release_time = this.elapsed; + } + + render(n: number): Float32Array { + if (!this.active) return new Float32Array(n); + const dt = 1.0 / SAMPLE_RATE; + + // Per-sample frequency ramp for buffer-size-independent portamento. + // Time constant in seconds: ambient slides slowly, chiptune snaps fast. + const slideTc = this.style === STYLE_AMBIENT ? 0.15 : 0.02; + const alpha = 1.0 - Math.exp(-dt / slideTc); + const phases = new Float64Array(n); + const phasesDet = new Float64Array(n); + let f = this.freq; + let ph = this.phase; + let phd = this.phase_det; + let decay = 1; + for (let i = 0; i < n; i++) { + // f[n] = target + (start - target) * (1 - alpha)^n + f = this.target_freq + (this.freq - this.target_freq) * decay; + decay *= 1.0 - alpha; + ph += TWO_PI * f * dt; + phd += TWO_PI * f * 1.003 * dt; + phases[i] = ph; + phasesDet[i] = phd; + } + if (n > 0) { + this.freq = f; + this.phase = pmod(ph, TWO_PI); + } + + let osc: Float32Array; + let adsr: ADSREnvelope; + if (this.style === STYLE_CHIPTUNE) { + osc = squareWave(phases, 0.25, this.freq); + adsr = ENV_CHIPTUNE; + } else { + // Ambient: sine + chorus with a dedicated detuned phase accumulator + if (n > 0) this.phase_det = pmod(phd, TWO_PI); + osc = new Float32Array(n); + for (let i = 0; i < n; i++) { + osc[i] = Math.fround(Math.sin(phases[i] ?? 0)) * 0.7 + Math.fround(Math.sin(phasesDet[i] ?? 0)) * 0.3; + } + adsr = ENV_AMBIENT; + } + + const env = adsr.generate(n, this.gate, this.elapsed, this.release_time); + this.elapsed += n * dt; + + // Check if voice has fully released + if (!this.gate && this.release_time >= 0 && this.elapsed - this.release_time > adsr.release) { + this.active = false; + } + for (let i = 0; i < n; i++) osc[i] = (osc[i] ?? 0) * (env[i] ?? 0); + return osc; + } +} + +// ═══════════════════════════════════════════════════════════════════════ +// The Music Engine +// ═══════════════════════════════════════════════════════════════════════ + +/** Standard-normal samples (numpy's randn), Box–Muller. */ +function randn(n: number): Float32Array { + const out = new Float32Array(n); + for (let i = 0; i < n; i += 2) { + const u = 1 - Math.random(); + const v = Math.random(); + const r = Math.sqrt(-2 * Math.log(u)); + out[i] = r * Math.cos(TWO_PI * v); + if (i + 1 < n) out[i + 1] = r * Math.sin(TWO_PI * v); + } + return out; +} + +export class LifeMusicEngine { + muted = false; + masterVolume = 0.5; + private styleIdx = 1; // Start with ambient + style: Style = STYLES[1]; + + private musical = new MusicalState(); + private snapshot: SimulationSnapshot = EMPTY_SNAPSHOT; + + // Phase accumulators for drone layer + private dronePhase1 = 0.0; + private dronePhase1Det = 0.0; // Detuned chorus oscillator + private dronePhase2 = 0.0; + private dronePhase2Det = 0.0; // Detuned fifth oscillator + private dronePhaseSub = 0.0; + private droneLfoPhase = 0.0; + + // Melody voices + private melodyVoices: Voice[]; + + // Arpeggio state + private arpVoice: Voice; + private arpNoteIdx = 0; + private arpSamplesInNote = 0; // discrete counter, no float drift + + // Noise state: triggered burst system + private noiseBurstAmp = 0.0; // current burst amplitude + private noiseBurstPhase = 1.0; // 0=attack start, 1=idle + private noiseBurstDuration = 0.15; // seconds per burst + private readonly noiseBurstThreshold = 20; // min pop_delta to trigger + private noiseBurstCooldown = 0.0; // seconds remaining before next burst allowed + + // Smoothed volumes (to avoid clicks) + private smoothDroneVol = 0.3; + private smoothMelodyVol = 0.0; + private smoothArpVol = 0.0; + private smoothNoiseVol = 0.0; + + // Root frequency portamento + private currentRootHz = midiToHz(DEFAULT_ROOT); + private targetRootHz = midiToHz(DEFAULT_ROOT); + + // Crossfade for anti-click when switching styles + private crossfadeRemaining = 0; + private readonly crossfadeTotal = Math.floor(SAMPLE_RATE / 4); // 250ms crossfade + private oldStyle: Style = this.style; + + private readonly noisePool = randn(SAMPLE_RATE); + private noisePoolIdx = 0; + + // Cached low-pass filters (pre-computed coefficients, persistent state) + private lpfDrone = new CachedLPF(800.0); + private lpfMelody = new CachedLPF(3500.0); + private lpfArp = new CachedLPF(4500.0); + private lpfNoise = new CachedLPF(600.0); + + // Stereo: melody pans with the playhead; arpeggio drifts on a slow LFO. + private prevMelodyPan = 0.5; + private prevArpPan = 0.5; + private autopanPhase = 0.0; + + // Cadence: resolving gesture when a detected cycle is broken. + // Sequence of [freq_hz, duration_samples]; idx -1 = inactive. + private cadenceVoice: Voice; + private cadenceSeq: [number, number][] = []; + private cadenceIdx = -1; + private cadenceRemaining = 0; + private cadenceCooldown = 0; // samples until next trigger allowed + + constructor() { + this.melodyVoices = Array.from({ length: MAX_MELODY_VOICES }, () => new Voice(440, this.style)); + this.arpVoice = new Voice(440, this.style); + this.cadenceVoice = new Voice(440, this.style); + } + + get volumePercent(): number { + return Math.round(this.masterVolume * 100); + } + + // ── Controls ─────────────────────────────────────────────────────── + + toggleMute(): void { + this.muted = !this.muted; + } + + adjustVolume(delta: number): void { + this.masterVolume = Math.max(0.0, Math.min(1.0, this.masterVolume + delta)); + } + + cycleStyle(): void { + this.oldStyle = this.style; + this.styleIdx = (this.styleIdx + 1) % STYLES.length; + this.style = STYLES[this.styleIdx] ?? STYLE_AMBIENT; + this.crossfadeRemaining = this.crossfadeTotal; + for (const v of this.melodyVoices) v.style = this.style; + this.arpVoice.style = this.style; + this.cadenceVoice.style = this.style; + } + + setStyle(style: Style): void { + if (style !== this.style) this.cycleStyle(); + } + + // ── State update (called each sim frame) ──────────────────────────── + + /** Map simulation state to musical parameters. */ + update(snapshot: SimulationSnapshot): void { + this.snapshot = snapshot; + const ms = this.musical; + + // ── Root note from epoch ── + ms.target_root_midi = EPOCH_ROOT[snapshot.epoch] ?? DEFAULT_ROOT; + // Smooth portamento for root changes + this.targetRootHz = midiToHz(ms.target_root_midi); + + // ── Scale from mood ── + const newScale = MOOD_SCALE[snapshot.mood] ?? DEFAULT_SCALE; + if (newScale !== ms.scale_name) { + ms.prev_scale_intervals = ms.scale_intervals; + ms.scale_name = newScale; + ms.scale_intervals = SCALES[newScale] ?? []; + ms.scale_crossfade = 0.0; // Start crossfade + } + // Advance crossfade (over ~2 seconds at ~30fps ≈ 60 frames) + if (ms.scale_crossfade < 1.0) ms.scale_crossfade = Math.min(1.0, ms.scale_crossfade + 0.017); + + // ── Drone volume: proportional to population ── + const popRatio = snapshot.pop_floor > 0 ? Math.min(2.0, snapshot.population / Math.max(1, snapshot.pop_floor)) : 0.5; + ms.drone_volume = lerp(0.13, 0.38, Math.min(1.0, popRatio)); + + // ── Melody volume: moderate, scales with density ── + ms.melody_volume = lerp(0.08, 0.35, Math.min(1.0, snapshot.density * 10.0)); + + // ── Arpeggio: speed from cycle detection, volume from spread ── + if (snapshot.cycle_period > 0) { + // Faster arpeggios when cycles are short + ms.arp_speed = lerp(3.0, 12.0, Math.min(1.0, 10.0 / Math.max(1, snapshot.cycle_period))); + ms.arp_volume = 0.2; + } else { + ms.arp_speed = lerp(2.0, 6.0, Math.min(1.0, snapshot.spread / 200.0)); + ms.arp_volume = lerp(0.05, 0.15, Math.min(1.0, snapshot.spread / 100.0)); + } + + // Build arpeggio pattern from scale + const si = ms.scale_intervals; + if (si.length >= 3) { + ms.arp_pattern = [si[0] ?? 0, si[Math.min(2, si.length - 1)] ?? 0, si[Math.min(4, si.length - 1)] ?? 0, (si[0] ?? 0) + 12]; + } else { + ms.arp_pattern = [0, 4, 7, 12]; + } + + // ── Noise: driven by population delta (births/deaths) ── + ms.noise_volume = lerp(0.0, 0.15, Math.min(1.0, Math.abs(snapshot.pop_delta) / 50.0)); + + // ── Melody playhead notes ── + this.computePlayheadNotes(snapshot, ms); + + // ── Tempo ── + ms.tempo_bpm = lerp(60.0, 120.0, Math.min(1.0, snapshot.density * 8.0)); + + // ── Cadence: score the death of an attractor ── + // The sim breaks detected cycles with an injection; before the new chaos + // registers, resolve — octave, fifth, root, ringing out. + if (snapshot.event.startsWith('inject') && snapshot.event.includes('cycle') && this.cadenceIdx < 0 && this.cadenceCooldown <= 0) { + const base = ms.target_root_midi + 12; // melody register + this.cadenceSeq = [ + [midiToHz(base + 12), Math.trunc(0.4 * SAMPLE_RATE)], + [midiToHz(base + 7), Math.trunc(0.4 * SAMPLE_RATE)], + [midiToHz(base), Math.trunc(2.0 * SAMPLE_RATE)], + ]; + this.cadenceRemaining = 0; + this.cadenceCooldown = Math.trunc(CADENCE_COOLDOWN_S * SAMPLE_RATE); + this.cadenceIdx = 0; + } + } + + /** Map alive cells in the playhead column to pitches. */ + private computePlayheadNotes(snap: SimulationSnapshot, ms: MusicalState): void { + const col = snap.playhead_column; + if (!col.length || snap.viewport_rows < 2) { + ms.playhead_notes = []; + return; + } + const nRows = col.length; + // Build pitch range: 2 octaves of current scale + const pitches = scalePitches(ms.target_root_midi, ms.scale_intervals, 2); + if (!pitches.length) { + ms.playhead_notes = []; + return; + } + const aliveRows: number[] = []; + col.forEach((alive, i) => { + if (alive) aliveRows.push(i); + }); + // Density gate: skip if too sparse and overall density is low + if (aliveRows.length < 2 && snap.density < 0.03) { + ms.playhead_notes = []; + return; + } + // Map row index → pitch (top = high, bottom = low) + let notes = aliveRows.map((row) => { + const frac = 1.0 - row / Math.max(1, nRows - 1); + const idx = Math.max(0, Math.min(Math.trunc(frac * (pitches.length - 1)), pitches.length - 1)); + return pitches[idx] ?? 0; + }); + // Cap polyphony: pick most spread-out if too many + if (notes.length > MAX_MELODY_VOICES) { + notes.sort((a, b) => a - b); + const step = notes.length / MAX_MELODY_VOICES; + notes = Array.from({ length: MAX_MELODY_VOICES }, (_, i) => notes[Math.trunc(i * step)] ?? 0); + } + ms.playhead_notes = notes; + } + + // ── The audio callback ────────────────────────────────────────────── + + /** + * One buffer, as PyAudio's stream callback produced it: the stereo mix, + * master volume (or silence when muted), then a tanh soft clip. Writes + * into `left`/`right`, which must be `n` long. + */ + renderBlock(left: Float32Array, right: Float32Array, n = left.length): void { + let l: Float32Array; + let r: Float32Array; + try { + [l, r] = this.renderStereo(n); + } catch { + l = new Float32Array(n); + r = new Float32Array(n); + } + const g = this.muted ? 0 : this.masterVolume; + for (let i = 0; i < n; i++) { + left[i] = Math.tanh((l[i] ?? 0) * g); + right[i] = Math.tanh((r[i] ?? 0) * g); + } + } + + /** Render all layers + per-sample volume ramps (shared by the mix paths). */ + private renderLayers(n: number): { + drone: Float32Array; + melody: Float32Array; + arp: Float32Array; + noise: Float32Array; + cadence: Float32Array | null; + ramps: [Float32Array, Float32Array, Float32Array, Float32Array]; + } { + const ms = this.musical; + const dt = n / SAMPLE_RATE; + + // Smooth volume transitions — per-sample linear ramp to avoid step + // discontinuities at buffer boundaries (audible as ~43 Hz buzz) + const smooth = 0.15; + const pd = this.smoothDroneVol; + const pm = this.smoothMelodyVol; + const pa = this.smoothArpVol; + const pn = this.smoothNoiseVol; + this.smoothDroneVol = lerp(pd, ms.drone_volume, smooth); + this.smoothMelodyVol = lerp(pm, ms.melody_volume, smooth); + this.smoothArpVol = lerp(pa, ms.arp_volume, smooth); + this.smoothNoiseVol = lerp(pn, ms.noise_volume, smooth); + const ramps: [Float32Array, Float32Array, Float32Array, Float32Array] = [ + linspace(pd, this.smoothDroneVol, n), + linspace(pm, this.smoothMelodyVol, n), + linspace(pa, this.smoothArpVol, n), + linspace(pn, this.smoothNoiseVol, n), + ]; + + // Root portamento + this.currentRootHz = lerp(this.currentRootHz, this.targetRootHz, 0.05); + + let drone: Float32Array; + if (this.crossfadeRemaining > 0) { + // During style crossfade: render with both styles and blend + const progress = 1.0 - this.crossfadeRemaining / Math.max(1, this.crossfadeTotal); + this.crossfadeRemaining = Math.max(0, this.crossfadeRemaining - n); + const droneNew = this.renderDrone(n); + const saved = this.style; + this.style = this.oldStyle; + const droneOld = this.renderDrone(n); + this.style = saved; + // Crossfade: equal-power curve + const fNew = Math.fround(Math.sqrt(progress)); + const fOld = Math.fround(Math.sqrt(1.0 - progress)); + drone = new Float32Array(n); + for (let i = 0; i < n; i++) drone[i] = (droneOld[i] ?? 0) * fOld + (droneNew[i] ?? 0) * fNew; + } else { + drone = this.renderDrone(n); + } + + const melody = this.renderMelody(n); + const arp = this.renderArpeggio(n); + const noise = this.renderNoise(n, dt); + const cadence = this.renderCadence(n); + return { drone, melody, arp, noise, cadence, ramps }; + } + + /** + * Mix all layers into left/right buffers. + * + * The melody pans with the playhead as it sweeps the viewport, so the grid + * is spatially audible; the arpeggio leans toward where the universe is + * changing, with a slow LFO wobble. Drone, noise and cadence stay centered. + * Constant-power panning, with per-sample gain ramps so pan moves never + * click. + */ + renderStereo(n: number): [Float32Array, Float32Array] { + const { drone, melody, arp, noise, cadence, ramps } = this.renderLayers(n); + const [droneRamp, melodyRamp, arpRamp, noiseRamp] = ramps; + const snap = this.snapshot; + + const melodyPan = Math.min(1.0, Math.max(0.0, snap.playhead_position)); + this.autopanPhase = pmod(this.autopanPhase + (TWO_PI * n) / SAMPLE_RATE / 13.0, TWO_PI); + const arpPan = Math.min(1.0, Math.max(0.0, snap.activity_x + 0.12 * Math.sin(this.autopanPhase))); + + const halfPi = Math.PI / 2.0; + const melTheta = linspace(this.prevMelodyPan, melodyPan, n); + const arpTheta = linspace(this.prevArpPan, arpPan, n); + this.prevMelodyPan = melodyPan; + this.prevArpPan = arpPan; + + const left = new Float32Array(n); + const right = new Float32Array(n); + for (let i = 0; i < n; i++) { + const mv = (melody[i] ?? 0) * (melodyRamp[i] ?? 0); + const av = (arp[i] ?? 0) * (arpRamp[i] ?? 0); + let center = (drone[i] ?? 0) * (droneRamp[i] ?? 0) + (noise[i] ?? 0) * (noiseRamp[i] ?? 0); + if (cadence) center += (cadence[i] ?? 0) * CADENCE_VOLUME; + center *= 0.7071; // constant-power center + const mt = (melTheta[i] ?? 0) * halfPi; + const at = (arpTheta[i] ?? 0) * halfPi; + left[i] = center + mv * Math.cos(mt) + av * Math.cos(at); + right[i] = center + mv * Math.sin(mt) + av * Math.sin(at); + } + return [left, right]; + } + + /** Render the resolving cadence voice, or null while inactive. */ + private renderCadence(n: number): Float32Array | null { + if (this.cadenceCooldown > 0) this.cadenceCooldown -= n; + if (this.cadenceIdx < 0) return null; + + if (this.cadenceRemaining <= 0) { + const next = this.cadenceSeq[this.cadenceIdx]; + if (next) { + const [freq, dur] = next; + if (this.cadenceIdx === 0) this.cadenceVoice.noteOn(freq); + else this.cadenceVoice.retrigger(freq); // legato slide down the resolution + this.cadenceRemaining = dur; + this.cadenceIdx += 1; + } else if (this.cadenceVoice.gate) { + this.cadenceVoice.noteOff(); // let the release ring out + } else if (!this.cadenceVoice.active) { + this.cadenceIdx = -1; // tail finished + return null; + } + } + this.cadenceRemaining -= n; + return this.cadenceVoice.render(n); + } + + // ── Drone layer ──────────────────────────────────────────────────── + + /** Continuous drone bed — always present, breathes with LFO. */ + private renderDrone(n: number): Float32Array { + const rootHz = this.currentRootHz; + const fifthHz = rootHz * 1.5; // Perfect fifth + const tInc = 1.0 / SAMPLE_RATE; + + // LFO for breathing (very slow: ~0.1 Hz) + const lfoFreq = 0.08; + const lfo = new Float32Array(n); + let lastLfo = this.droneLfoPhase; + for (let i = 0; i < n; i++) { + lastLfo = this.droneLfoPhase + TWO_PI * lfoFreq * (i / SAMPLE_RATE); + lfo[i] = 0.15 * Math.fround(Math.sin(lastLfo)); + } + this.droneLfoPhase = pmod(lastLfo + TWO_PI * lfoFreq * tInc, TWO_PI); + + const p1 = TWO_PI * rootHz * tInc; + const p1d = TWO_PI * (rootHz * 1.003) * tInc; // Detuned root (chorus) + const p2 = TWO_PI * fifthHz * tInc; + const p2d = TWO_PI * (fifthHz * 1.002) * tInc; // Detuned fifth + const ps = TWO_PI * (rootHz * 0.5) * tInc; // Sub-octave + + const ph1 = new Float64Array(n); + const ph1d = new Float64Array(n); + const ph2 = new Float64Array(n); + const ph2d = new Float64Array(n); + const phs = new Float64Array(n); + for (let i = 0; i < n; i++) { + ph1[i] = this.dronePhase1 + i * p1; + ph1d[i] = this.dronePhase1Det + i * p1d; + ph2[i] = this.dronePhase2 + i * p2; + ph2d[i] = this.dronePhase2Det + i * p2d; + phs[i] = this.dronePhaseSub + i * ps; + } + // Keep phases bounded to preserve float precision + this.dronePhase1 = pmod((ph1[n - 1] ?? 0) + p1, TWO_PI); + this.dronePhase1Det = pmod((ph1d[n - 1] ?? 0) + p1d, TWO_PI); + this.dronePhase2 = pmod((ph2[n - 1] ?? 0) + p2, TWO_PI); + this.dronePhase2Det = pmod((ph2d[n - 1] ?? 0) + p2d, TWO_PI); + this.dronePhaseSub = pmod((phs[n - 1] ?? 0) + ps, TWO_PI); + + let drone: Float32Array = new Float32Array(n); + if (this.style === STYLE_CHIPTUNE) { + // Detuned square waves + triangle sub + const osc1 = squareWave(ph1, 0.5, rootHz); + const osc2 = squareWave(ph2d, 0.5, fifthHz * 1.002); + const sub = triangleWave(phs); + for (let i = 0; i < n; i++) drone[i] = (osc1[i] ?? 0) * 0.35 + (osc2[i] ?? 0) * 0.25 + (sub[i] ?? 0) * 0.4; + } else { + // Ambient: detuned sines + filtered fifth + const osc1 = sineWave(ph1); + const osc1d = sineWave(ph1d); + const osc2 = sineWave(ph2); + const sub = sineWave(phs); + for (let i = 0; i < n; i++) { + drone[i] = (osc1[i] ?? 0) * 0.4 + (osc1d[i] ?? 0) * 0.15 + (osc2[i] ?? 0) * 0.25 + (sub[i] ?? 0) * 0.2; + } + // Low-pass filter for warmth + drone = this.lpfDrone.apply(drone); + } + // Apply LFO breathing + for (let i = 0; i < n; i++) drone[i] = (drone[i] ?? 0) * (0.85 + (lfo[i] ?? 0)); + return drone; + } + + // ── Melody layer ─────────────────────────────────────────────────── + + /** Grid-scanning playhead: alive cells at current column → pitches. */ + private renderMelody(n: number): Float32Array { + const target = this.musical.playhead_notes; + + // Update voice assignments — portamento for small pitch changes to avoid + // ADSR retriggering at 30Hz (audible flutter). Only hard-retrigger for + // large intervals (> ~1 semitone = 6% freq change). + this.melodyVoices.forEach((voice, i) => { + const freq = target[i]; + if (freq !== undefined) { + if (!voice.active) voice.noteOn(freq); + else if (Math.abs(voice.target_freq - freq) > voice.target_freq * 0.06) voice.noteOn(freq); + else voice.retrigger(freq); + } else if (voice.gate) { + voice.noteOff(); + } + }); + + // Ambient gets a per-voice boost (sines have ~3dB less RMS than squares) + const gain = this.style === STYLE_AMBIENT ? 0.5 : 0.3; + let buf: Float32Array = new Float32Array(n); + for (const voice of this.melodyVoices) { + if (!voice.active) continue; + const v = voice.render(n); + for (let i = 0; i < n; i++) buf[i] = (buf[i] ?? 0) + (v[i] ?? 0) * gain; + } + // Chiptune melody benefits from a slight LPF to tame square harmonics + if (this.style === STYLE_CHIPTUNE) buf = this.lpfMelody.apply(buf); + return buf; + } + + // ── Arpeggio layer ───────────────────────────────────────────────── + + /** Rhythmic arpeggiated texture, speed tied to cycle detection. */ + private renderArpeggio(n: number): Float32Array { + const ms = this.musical; + const pattern = ms.arp_pattern; + if (!pattern.length) return new Float32Array(n); + const root = ms.target_root_midi; + const noteDur = Math.max(1, Math.trunc(SAMPLE_RATE / Math.max(0.5, ms.arp_speed))); + + let buf: Float32Array = new Float32Array(n); + let done = 0; + while (done < n) { + // Samples remaining in current note + const chunk = Math.max(1, Math.min(noteDur - this.arpSamplesInNote, n - done)); + const freq = midiToHz(root + (pattern[this.arpNoteIdx % pattern.length] ?? 0)); + if (!this.arpVoice.active || Math.abs(this.arpVoice.target_freq - freq) > 1.0) this.arpVoice.noteOn(freq); + this.arpVoice.style = this.style; + + const rendered = this.arpVoice.render(chunk); + const gain = this.style === STYLE_AMBIENT ? 0.55 : 0.4; + for (let i = 0; i < chunk && done + i < n; i++) buf[done + i] = (rendered[i] ?? 0) * gain; + + this.arpSamplesInNote += chunk; + done += chunk; + // Advance to next note when current note is complete + if (this.arpSamplesInNote >= noteDur) { + this.arpSamplesInNote = 0; + this.arpNoteIdx = (this.arpNoteIdx + 1) % pattern.length; + this.arpVoice.noteOn(midiToHz(root + (pattern[this.arpNoteIdx % pattern.length] ?? 0))); + } + } + // Tame chiptune square harmonics; ambient sines don't need filtering + if (this.style === STYLE_CHIPTUNE) buf = this.lpfArp.apply(buf); + return buf; + } + + // ── Noise layer ──────────────────────────────────────────────────── + + /** Percussive noise bursts triggered by population delta spikes. */ + private renderNoise(n: number, dt: number): Float32Array { + const absDelta = Math.abs(this.snapshot.pop_delta); + // Trigger a new burst when pop_delta exceeds threshold. Require full + // completion + cooldown to prevent chain-firing flutter. + if (this.noiseBurstCooldown > 0) this.noiseBurstCooldown = Math.max(0.0, this.noiseBurstCooldown - dt); + if (absDelta >= this.noiseBurstThreshold && this.noiseBurstPhase >= 1.0 && this.noiseBurstCooldown <= 0) { + this.noiseBurstPhase = 0.0; + this.noiseBurstAmp = lerp(0.1, 0.5, Math.min(1.0, absDelta / 80.0)); + // Bigger events = longer bursts + this.noiseBurstDuration = lerp(0.08, 0.25, Math.min(1.0, absDelta / 100.0)); + // Cooldown: at least the burst duration + 100ms breathing room + this.noiseBurstCooldown = this.noiseBurstDuration + 0.1; + } + // If no burst active, return silence + if (this.noiseBurstPhase >= 1.0) return new Float32Array(n); + + // Read from the pre-generated noise pool (circular buffer) + const pool = this.noisePool; + const idx = this.noisePoolIdx % pool.length; + const noise = new Float32Array(n); + for (let i = 0; i < n; i++) noise[i] = pool[(idx + i) % pool.length] ?? 0; + this.noisePoolIdx = (idx + n) % pool.length; + + // Per-sample envelope for the burst: attack (first 10%) then exponential decay + const burst = Math.max(0.01, this.noiseBurstDuration); + const attackEnd = burst * 0.1; + const t0 = this.noiseBurstPhase * burst; + const env = new Float32Array(n); + for (let i = 0; i < n; i++) { + const t = Math.fround(t0 + (i * (n / SAMPLE_RATE)) / n); + env[i] = t < attackEnd ? t / Math.max(0.001, attackEnd) : Math.exp((-6.0 * (t - attackEnd)) / burst); + } + + // Advance burst phase + this.noiseBurstPhase = Math.min(1.0, this.noiseBurstPhase + dt / burst); + + const out = new Float32Array(n); + if (this.style === STYLE_CHIPTUNE) { + // NES-style: downsample for lo-fi crunch + for (let i = 0; i < n; i++) out[i] = (noise[i - (i % 8)] ?? 0) * (env[i] ?? 0) * this.noiseBurstAmp; + } else { + // Ambient: low-pass filtered wash + const filtered = this.lpfNoise.apply(noise); + for (let i = 0; i < n; i++) out[i] = (filtered[i] ?? 0) * (env[i] ?? 0) * this.noiseBurstAmp * 0.6; + } + return out; + } + + // ── Status string for display ────────────────────────────────────── + + statusString(): string { + if (this.muted) return '[MUTE]'; + return `${this.style === STYLE_CHIPTUNE ? 'NES' : 'AMB'} ${this.volumePercent}%`; + } +} + +/** The status string, from the controls alone (the page mirrors them). */ +export function statusString(muted: boolean, style: Style, volume: number): string { + if (muted) return '[MUTE]'; + return `${style === STYLE_CHIPTUNE ? 'NES' : 'AMB'} ${Math.round(volume * 100)}%`; +} diff --git a/afterlife/src/music/worklet.ts b/afterlife/src/music/worklet.ts new file mode 100644 index 0000000..3d7af1e --- /dev/null +++ b/afterlife/src/music/worklet.ts @@ -0,0 +1,67 @@ +/** + * worklet.ts — where the music engine plays. + * + * life_music.py rendered on PyAudio's callback thread and read the latest + * SimulationSnapshot the main thread had swapped in. This is the same shape: + * the page posts snapshots and control changes, and the engine renders + * BUFFER_SIZE-frame blocks on the audio thread, handed out 128 frames at a + * time. vite.config.ts bundles this file on its own and inlines it into the + * page as a string, so it loads from a blob: URL without a second request. + */ + +import { BUFFER_SIZE, LifeMusicEngine, type SimulationSnapshot, type Style } from './engine'; + +// The AudioWorkletGlobalScope, which lib.dom doesn't describe +declare abstract class AudioWorkletProcessor { + readonly port: MessagePort; + abstract process(inputs: Float32Array[][], outputs: Float32Array[][]): boolean; +} +declare function registerProcessor(name: string, ctor: new () => AudioWorkletProcessor): void; + +export type ToWorklet = + | { type: 'snapshot'; snap: SimulationSnapshot } + | { type: 'controls'; muted: boolean; volume: number; style: Style } + | { type: 'stop' }; + +class AfterlifeProcessor extends AudioWorkletProcessor { + private engine = new LifeMusicEngine(); + private left = new Float32Array(BUFFER_SIZE); + private right = new Float32Array(BUFFER_SIZE); + private pos = BUFFER_SIZE; // empty: render on the first quantum + private running = true; + + constructor() { + super(); + this.port.onmessage = (e: MessageEvent) => { + const m = e.data; + if (m.type === 'snapshot') this.engine.update(m.snap); + else if (m.type === 'controls') { + this.engine.muted = m.muted; + this.engine.masterVolume = m.volume; + this.engine.setStyle(m.style); + } else if (m.type === 'stop') this.running = false; + }; + } + + process(_inputs: Float32Array[][], outputs: Float32Array[][]): boolean { + const out = outputs[0]; + const l = out?.[0]; + if (!out || !l) return this.running; + const r = out[1] ?? l; + let written = 0; + while (written < l.length) { + if (this.pos >= BUFFER_SIZE) { + this.engine.renderBlock(this.left, this.right, BUFFER_SIZE); + this.pos = 0; + } + const take = Math.min(l.length - written, BUFFER_SIZE - this.pos); + l.set(this.left.subarray(this.pos, this.pos + take), written); + if (r !== l) r.set(this.right.subarray(this.pos, this.pos + take), written); + this.pos += take; + written += take; + } + return this.running; + } +} + +registerProcessor('afterlife-music', AfterlifeProcessor); diff --git a/afterlife/src/style.css b/afterlife/src/style.css new file mode 100644 index 0000000..153316e --- /dev/null +++ b/afterlife/src/style.css @@ -0,0 +1,252 @@ +/** + * style.css — the chrome around the terminal. + * + * Imported by main.ts so vite emits a single afterlife.css for the dev page + * and the æthera template. Everything is scoped under #afterlife-root, + * because on the site this loads alongside tailwind and branding.css. + * + * The colours are the universe's own: the splash's logo is lit with the + * cell-age gradient (xterm 17 → 231, indigo through magenta and amber to + * white), and the background is the terminal's. + */ + +:root { + color-scheme: dark; +} + +#afterlife-root { + --bg: #0a0a0c; + --fg: rgb(200, 200, 200); + --dim: rgb(112, 112, 116); + --age: linear-gradient(90deg, #0000af, #0000ff, #5f00ff, #8700ff, #d700ff, #d700af, #ff5f87, #ff875f, #ffaf00, #ffd700, #ffffff, #ffd700, #ff5f87, #8700ff, #0000af); + position: fixed; + inset: 0; + display: grid; + place-items: center; + background: var(--bg); + color: var(--fg); + font-family: ui-monospace, 'SF Mono', 'Cascadia Mono', 'DejaVu Sans Mono', Menlo, Consolas, monospace; + overflow: hidden; + touch-action: none; + user-select: none; + -webkit-user-select: none; +} + +#afterlife-root #term { + display: block; + cursor: crosshair; + image-rendering: pixelated; +} + +/* ── the splash: over the running universe, until the first gesture ── */ + +#afterlife-root #splash { + position: absolute; + inset: 0; + z-index: 10; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 0.6rem; + padding: 1rem; + background: radial-gradient(ellipse at center, rgba(10, 10, 12, 0.62) 0%, rgba(10, 10, 12, 0.9) 70%); + cursor: pointer; + transition: opacity 1.4s ease; + outline: none; +} + +#afterlife-root #splash.gone { + opacity: 0; + pointer-events: none; +} + +#afterlife-root #splash .logo { + /* the site styles
 as a code block; this one is a sign */
+  margin: 0;
+  padding: 0;
+  border: 0;
+  border-radius: 0;
+  box-shadow: none;
+  overflow: visible;
+  font: inherit;
+  font-size: clamp(5px, 1.35vw, 14px);
+  line-height: 1.12;
+  background: var(--age);
+  background-size: 300% 100%;
+  -webkit-background-clip: text;
+  background-clip: text;
+  color: transparent;
+  animation: afterlife-age 24s linear infinite;
+  filter: drop-shadow(0 0 12px rgba(135, 0, 255, 0.25));
+}
+
+@keyframes afterlife-age {
+  from { background-position: 0% 0; }
+  to { background-position: 300% 0; }
+}
+
+#afterlife-root #splash h1 {
+  /* the logo says it; this is for readers without the art */
+  position: absolute;
+  width: 1px;
+  height: 1px;
+  overflow: hidden;
+  clip-path: inset(50%);
+  margin: 0;
+}
+
+#afterlife-root #splash .sub {
+  margin: 0.4rem 0 0;
+  color: var(--fg);
+  font-size: 13px;
+  letter-spacing: 0.3em;
+}
+
+#afterlife-root #splash .go {
+  margin: 1.6rem 0 0;
+  color: var(--dim);
+  font-size: 11px;
+  letter-spacing: 0.12em;
+  text-align: center;
+  animation: afterlife-breathe 5.6s ease-in-out infinite;
+}
+
+#afterlife-root #splash .go span {
+  margin: 0 0.4em;
+}
+
+/* the ticker's own breath: sin(generation × 0.035) */
+@keyframes afterlife-breathe {
+  0%, 100% { opacity: 0.45; }
+  50% { opacity: 1; }
+}
+
+/* ── the one bit of site chrome kept, and the keys ── */
+
+#afterlife-root #corner {
+  position: absolute;
+  top: 10px;
+  right: 14px;
+  z-index: 11;
+  display: flex;
+  gap: 14px;
+  align-items: baseline;
+}
+
+#afterlife-root #corner a,
+#afterlife-root #corner button {
+  appearance: none;
+  border: 0;
+  padding: 2px 0;
+  background: none;
+  color: rgba(200, 200, 200, 0.28);
+  font: inherit;
+  font-size: 11px;
+  letter-spacing: 0.08em;
+  text-decoration: none;
+  cursor: pointer;
+  transition: color 0.6s ease;
+}
+
+#afterlife-root #corner a:hover,
+#afterlife-root #corner button:hover,
+#afterlife-root #corner button[aria-expanded='true'] {
+  color: rgba(200, 200, 200, 0.75);
+}
+
+#afterlife-root #keys {
+  position: absolute;
+  top: 34px;
+  right: 14px;
+  z-index: 11;
+  width: min(520px, calc(100vw - 28px));
+  max-height: calc(100% - 90px);
+  overflow: auto;
+  box-sizing: border-box;
+  padding: 14px 16px 12px;
+  border: 1px solid rgba(200, 200, 200, 0.12);
+  background: rgba(10, 10, 12, 0.94);
+  font-size: 12px;
+  touch-action: pan-y;
+  user-select: text;
+  -webkit-user-select: text;
+}
+
+#afterlife-root #keys[hidden] {
+  display: none;
+}
+
+#afterlife-root #keys .grid {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 2px 18px;
+}
+
+#afterlife-root #keys button {
+  appearance: none;
+  display: flex;
+  align-items: baseline;
+  gap: 10px;
+  padding: 3px 4px;
+  border: 0;
+  background: none;
+  color: var(--fg);
+  font: inherit;
+  text-align: left;
+  cursor: pointer;
+}
+
+#afterlife-root #keys button:hover,
+#afterlife-root #keys button:focus-visible {
+  background: rgba(200, 200, 200, 0.07);
+  outline: none;
+}
+
+#afterlife-root #keys kbd {
+  min-width: 3.2em;
+  color: #ffaf00;
+  font: inherit;
+}
+
+#afterlife-root #keys .haunt kbd {
+  color: #d700ff;
+}
+
+#afterlife-root #keys p {
+  margin: 12px 4px 0;
+  color: var(--dim);
+  line-height: 1.55;
+}
+
+#afterlife-root #keys a {
+  color: var(--fg);
+}
+
+#afterlife-root #keys .touch {
+  display: none;
+}
+
+@media (pointer: coarse) {
+  #afterlife-root #keys .mouse {
+    display: none;
+  }
+  #afterlife-root #keys .touch {
+    display: inline;
+  }
+}
+
+@media (max-width: 480px) {
+  #afterlife-root #keys .grid {
+    grid-template-columns: 1fr;
+  }
+}
+
+.afterlife-noscript {
+  position: fixed;
+  inset: auto 0 45% 0;
+  padding: 1rem;
+  color: #c8c8c8;
+  text-align: center;
+  font-family: monospace;
+}
diff --git a/afterlife/src/term/palette.ts b/afterlife/src/term/palette.ts
new file mode 100644
index 0000000..daa6633
--- /dev/null
+++ b/afterlife/src/term/palette.ts
@@ -0,0 +1,33 @@
+/**
+ * palette.ts — xterm's 256 colours, which is what afterlife was painted in.
+ *
+ * 0–15 are the terminal's own ANSI colours (xterm defaults here), 16–231 a
+ * 6×6×6 cube, 232–255 a grey ramp. Every colour the port draws goes through
+ * this, so the gradient, the ghosts and the haunted aliasing are exactly the
+ * numbers life.py asks curses for.
+ */
+
+const ANSI: readonly (readonly [number, number, number])[] = [
+  [0, 0, 0], [205, 0, 0], [0, 205, 0], [205, 205, 0], [0, 0, 238], [205, 0, 205], [0, 205, 205], [229, 229, 229],
+  [127, 127, 127], [255, 0, 0], [0, 255, 0], [255, 255, 0], [92, 92, 255], [255, 0, 255], [0, 255, 255], [255, 255, 255],
+];
+const CUBE = [0, 95, 135, 175, 215, 255];
+
+export function xterm(n: number): [number, number, number] {
+  if (n < 16) return [...(ANSI[n] ?? [0, 0, 0])] as [number, number, number];
+  if (n < 232) {
+    const i = n - 16;
+    return [CUBE[Math.floor(i / 36)] ?? 0, CUBE[Math.floor(i / 6) % 6] ?? 0, CUBE[i % 6] ?? 0];
+  }
+  const v = 8 + (n - 232) * 10;
+  return [v, v, v];
+}
+
+/** Packed little-endian RGBA (for a Uint32Array view over ImageData). */
+export function packed(rgb: readonly [number, number, number]): number {
+  return ((255 << 24) | (rgb[2] << 16) | (rgb[1] << 8) | rgb[0]) >>> 0;
+}
+
+export function css(rgb: readonly [number, number, number]): string {
+  return `rgb(${rgb[0]},${rgb[1]},${rgb[2]})`;
+}
diff --git a/afterlife/src/term/render.ts b/afterlife/src/term/render.ts
new file mode 100644
index 0000000..24bc3f6
--- /dev/null
+++ b/afterlife/src/term/render.ts
@@ -0,0 +1,329 @@
+/**
+ * render.ts — a terminal, drawn.
+ *
+ * afterlife is a curses program: a grid of character cells, each one an
+ * upper-half block (▀) whose foreground paints the top pixel and background
+ * the bottom, so every cell holds two pixels of the universe. This draws
+ * exactly that, in the same xterm colours, and keeps the terminal's grid for
+ * the status line: every character sits in its own column.
+ *
+ * The cells are drawn as pixels (an ImageData one texel per half-cell, scaled
+ * up without smoothing) rather than as ▀ glyphs, which is what a glyph would
+ * look like on a perfect font and is the same on every machine.
+ *
+ * `render()` is life.py's render() and _draw_stats_overlay(), case for case.
+ */
+
+import { GHOST_COLORS, GHOST_FRAMES, GRADIENT, HAUNT_DUAL, HAUNT_FRAMES, HAUNT_SINGLE, SPARKS, ZOOM_LABELS } from '../engine/constants';
+import type { InfiniteLife } from '../engine/life';
+import { NewsTicker, cols } from '../engine/ticker';
+import { css, packed, xterm } from './palette';
+
+/** The terminal's default background and foreground (curses' -1). */
+export const BG: [number, number, number] = [10, 10, 12];
+const FG = 'rgb(200,200,200)';
+const FG_DIM = 'rgb(112,112,116)';
+
+const NG = GRADIENT.length;
+const GRAD_PX = GRADIENT.map((c) => packed(xterm(c)));
+const GHOST_PX = GHOST_COLORS.map((c) => packed(xterm(c)));
+const HAUNT_SINGLE_PX = HAUNT_SINGLE.map(([f, b]) => [packed(xterm(f)), packed(xterm(b))] as const);
+const HAUNT_DUAL_PX = HAUNT_DUAL.map(([f, b]) => [packed(xterm(f)), packed(xterm(b))] as const);
+const BG_PX = packed(BG);
+
+/** Terminal fonts first: the status line was written for one. */
+export const TERM_FONT = 'ui-monospace, "SF Mono", "Cascadia Mono", "DejaVu Sans Mono", Menlo, Consolas, monospace';
+
+/** What the status line holds this frame (life.py builds it inside render()). */
+export interface Status {
+  left: string;
+  right: string;
+  tickerCol: number;
+  tickerWidth: number;
+}
+
+let lut: { maxAge: number; table: Uint8Array } | null = null;
+
+/** age → gradient index: log-scaled so the young get most of the colours */
+function colorLut(maxAge: number): Uint8Array {
+  if (lut && lut.maxAge === maxAge) return lut.table;
+  const table = new Uint8Array(maxAge + 1);
+  const logMax = Math.log1p(maxAge);
+  for (let a = 1; a <= maxAge; a++) table[a] = Math.min(Math.trunc((Math.log1p(a) / logMax) * (NG - 1)), NG - 1);
+  lut = { maxAge, table };
+  return table;
+}
+
+function fmt(n: number): string {
+  return n.toLocaleString('en-US');
+}
+
+export class Terminal {
+  /** device pixels per column; a row is two of these (square half-blocks) */
+  cw = 8;
+  cols = 80;
+  rows = 24;
+  /**
+   * Status rows at the bottom. One, as in the terminal, when it is wide
+   * enough for the ticker to have room between the stats and the keys;
+   * otherwise two (stats above, the ticker on a line of its own) rather than
+   * lose the ticker to the narrow-terminal fallback on every phone.
+   */
+  statusRows = 1;
+  /** show the key legend at the right of the status line */
+  keys = true;
+
+  private img: ImageData | null = null;
+  private widths = new Map();
+  private px: Uint32Array | null = null;
+  private off: HTMLCanvasElement | OffscreenCanvas | null = null;
+
+  constructor(private readonly ctx: CanvasRenderingContext2D) {}
+
+  /** Rows the universe gets (life.py's max_y - 1). */
+  get gridRows(): number {
+    return Math.max(1, this.rows - this.statusRows);
+  }
+
+  /** Size the terminal: a canvas of w × h device pixels, cells `cw` wide. */
+  resize(w: number, h: number, cw: number): void {
+    this.cw = Math.max(2, Math.round(cw));
+    this.cols = Math.max(20, Math.floor(w / this.cw));
+    this.rows = Math.max(6, Math.floor(h / (this.cw * 2)));
+    this.statusRows = this.cols >= 150 ? 1 : 2;
+    this.keys = this.cols >= 150;
+    this.img = null;
+    this.widths.clear();
+  }
+
+  /** The status line, as render() lays it out (and so the ticker's width). */
+  status(life: InfiniteLife, musicStatus: string): Status {
+    // a phone's status line can't spare 24 columns of history
+    const spark = life.sparkline(this.cols < 100 ? 10 : 24);
+    const cam = life.autoCam ? 'auto' : 'pan';
+    const zoom = ZOOM_LABELS[life.zoomLevel] ?? `${2 ** life.zoomLevel}x`;
+    const focus = life.autoFocusMode ? '[F]' : '';
+    const haunt = life.haunted ? '[HAUNTED]' : '';
+    const music = musicStatus ? ` ${musicStatus}` : '';
+    const left = `  ${life.epoch()}  gen ${fmt(life.generation)}  pop ${fmt(life.population())}  ${spark}`;
+    const legend = this.keys ? '  q r spc +/- arrows h z/x f g s  ' : '  ';
+    const right = `${music} ${haunt}${focus} ${zoom} ${cam}${legend}`;
+    if (this.statusRows === 1) {
+      // Ticker occupies the region between left stats and right controls
+      return { left, right, tickerCol: cols(left) + 1, tickerWidth: this.cols - cols(left) - cols(right) - 2 };
+    }
+    return { left, right, tickerCol: 1, tickerWidth: this.cols - 2 };
+  }
+
+  /** Paint one frame. */
+  render(life: InfiniteLife, st: Status, showStats: boolean): void {
+    const ctx = this.ctx;
+    const cw = this.cw;
+    const W = this.cols * cw;
+    const H = this.rows * cw * 2;
+    ctx.fillStyle = css(BG);
+    ctx.fillRect(0, 0, W, H);
+
+    this.paintGrid(life);
+
+    ctx.font = `${Math.round(cw * 1.62)}px ${TERM_FONT}`;
+    ctx.textBaseline = 'middle';
+    if (showStats) this.statsOverlay(life);
+
+    // ── Status bar (with scrolling news ticker) ──
+    const last = this.rows - 1;
+    if (this.statusRows === 1) {
+      if (st.tickerWidth < 10) {
+        // Terminal too narrow for ticker — compact fallback
+        this.text(`${st.left}  ${st.right}`.slice(0, this.cols - 1), last, 0, FG_DIM);
+      } else {
+        this.text(st.left, last, 0, FG_DIM);
+        this.ticker(life, last, st);
+        const rightCol = this.cols - cols(st.right);
+        this.text([...st.right].slice(0, this.cols - 1 - rightCol).join(''), last, rightCol, FG_DIM);
+      }
+    } else {
+      // two-line status: the stats and the switches, then the ticker below
+      const room = this.cols - 1;
+      const line = cols(st.left) + cols(st.right) <= room
+        ? st.left + ' '.repeat(room - cols(st.left) - cols(st.right)) + st.right
+        : `${st.left}  ${st.right}`;
+      this.text([...line].slice(0, room).join(''), last - 1, 0, FG_DIM);
+      this.ticker(life, last, st);
+    }
+  }
+
+  private paintGrid(life: InfiniteLife): void {
+    const grid = life.displayGrid();
+    const ages = life.displayAge();
+    const drawRows = Math.min(Math.floor(grid.h / 2), Math.floor(ages.h / 2), this.gridRows);
+    const drawCols = Math.min(grid.w, ages.w, this.cols);
+    const w = this.cols;
+    const h = this.gridRows * 2;
+    if (!this.img || this.img.width !== w || this.img.height !== h) {
+      this.img = new ImageData(w, h);
+      this.px = new Uint32Array(this.img.data.buffer);
+      this.off = typeof OffscreenCanvas !== 'undefined' ? new OffscreenCanvas(w, h) : Object.assign(document.createElement('canvas'), { width: w, height: h });
+    }
+    const px = this.px as Uint32Array;
+    px.fill(BG_PX);
+
+    // ages.max() works because alive ages > 0, ghost ages < 0, dead = 0
+    let maxAge = 1;
+    for (let i = 0; i < ages.data.length; i++) if ((ages.data[i] ?? 0) > maxAge) maxAge = ages.data[i] ?? 0;
+    const table = colorLut(maxAge);
+
+    // Disable ghost rendering when zoomed out — too much visual noise.
+    // Haunted mode inverts that judgment: the noise is the exhibit.
+    const haunted = life.haunted;
+    const showGhosts = life.zoomLevel >= 0 || haunted;
+    const gf = haunted ? HAUNT_FRAMES : GHOST_FRAMES;
+    const gidx = (a: number): number => Math.min(Math.max(-a - 1, 0), gf - 1);
+    const cidx = (a: number): number => table[Math.min(Math.max(a, 0), maxAge)] ?? 0;
+    const ghostTop = (i: number): number => (haunted ? (HAUNT_SINGLE_PX[i]?.[0] ?? 0) : (GHOST_PX[i] ?? 0));
+    const ghostBgOf = (i: number): number => (haunted ? (HAUNT_SINGLE_PX[i]?.[1] ?? 0) : BG_PX);
+
+    for (let r = 0; r < drawRows; r++) {
+      const gt = 2 * r * grid.w;
+      const gb = gt + grid.w;
+      const at = 2 * r * ages.w;
+      const ab = at + ages.w;
+      const pt = 2 * r * w;
+      const pb = pt + w;
+      for (let c = 0; c < drawCols; c++) {
+        const tAlive = (grid.data[gt + c] ?? 0) > 0;
+        const bAlive = (grid.data[gb + c] ?? 0) > 0;
+        const tAge = ages.data[at + c] ?? 0;
+        const bAge = ages.data[ab + c] ?? 0;
+        const tGhost = showGhosts && tAge < 0;
+        const bGhost = showGhosts && bAge < 0;
+        if (!(tAlive || bAlive || tGhost || bGhost)) continue;
+
+        let top = BG_PX;
+        let bot = BG_PX;
+        if ((tAlive || tGhost) && (bAlive || bGhost)) {
+          if (tAlive && bAlive) {
+            top = GRAD_PX[cidx(tAge)] ?? 0;
+            bot = GRAD_PX[cidx(bAge)] ?? 0;
+          } else if (tGhost && bGhost) {
+            const ti = gidx(tAge);
+            const bi = gidx(bAge);
+            if (haunted) {
+              const pair = HAUNT_DUAL_PX[ti * HAUNT_FRAMES + bi];
+              top = pair?.[0] ?? 0;
+              bot = pair?.[1] ?? 0;
+            } else {
+              top = GHOST_PX[ti] ?? 0;
+              bot = GHOST_PX[bi] ?? 0;
+            }
+          } else if (tAlive) {
+            top = GRAD_PX[cidx(tAge)] ?? 0; // ▀ on the default background
+          } else {
+            bot = GRAD_PX[cidx(bAge)] ?? 0; // ▄ on the default background
+          }
+        } else if (tAlive) {
+          top = GRAD_PX[cidx(tAge)] ?? 0;
+        } else if (bAlive) {
+          bot = GRAD_PX[cidx(bAge)] ?? 0;
+        } else if (tGhost) {
+          // ▀ in the ghost pair: its fg on top, its bg (the aliased colour,
+          // when haunted) below
+          const i = gidx(tAge);
+          top = ghostTop(i);
+          bot = ghostBgOf(i);
+        } else {
+          // ▄: the pair's fg below, its bg above
+          const i = gidx(bAge);
+          bot = ghostTop(i);
+          top = ghostBgOf(i);
+        }
+        px[pt + c] = top;
+        px[pb + c] = bot;
+      }
+    }
+
+    const off = this.off as HTMLCanvasElement | OffscreenCanvas;
+    const octx = off.getContext('2d') as CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null;
+    if (!octx || !this.img) return;
+    octx.putImageData(this.img, 0, 0);
+    const ctx = this.ctx;
+    ctx.imageSmoothingEnabled = false;
+    ctx.drawImage(off, 0, 0, w * this.cw, h * this.cw);
+  }
+
+  /** Draw visible ticker messages; they breathe between dim and normal. */
+  private ticker(life: InfiniteLife, row: number, st: Status): void {
+    const color = NewsTicker.dim(life.generation) ? FG_DIM : FG;
+    for (const msg of life.ticker.messages) {
+      const col = Math.trunc(msg.x);
+      const chars = [...msg.text];
+      // Clip to the ticker region
+      const visStart = Math.max(col, 0);
+      const visEnd = Math.min(col + chars.length, st.tickerWidth);
+      if (visStart >= visEnd) continue;
+      this.text(chars.slice(visStart - col, visEnd - col).join(''), row, st.tickerCol + visStart, color);
+    }
+  }
+
+  /** The engine telemetry panel in the bottom-right. */
+  private statsOverlay(life: InfiniteLife): void {
+    const census = life.lastCensus.size
+      ? [...life.lastCensus.entries()].sort((a, b) => b[1] - a[1]).map(([n, c]) => `${c}×${n}`).join(' ')
+      : 'none';
+    const panelW = 36;
+    const panelH = 11;
+    const x0 = this.cols - panelW - 2;
+    const y0 = this.rows - (this.statusRows - 1) - panelH - 2;
+    if (x0 < 0 || y0 < 0) return;
+    const lines = [
+      '─'.repeat(panelW - 2),
+      ' infinity engine',
+      ` pop floor  : ${fmt(life.popFloor)}`,
+      ` spread/150 : ${fmt(life.spread)}`,
+      ` cycle       : ${life.cyclePeriod === 0 ? 'none' : `period ${life.cyclePeriod}`}`,
+      ` injections  : ${life.totalInjections}`,
+      ` last event  : ${life.lastEvent || 'none'}`,
+      life.lastEvent ? `   @ gen     : ${fmt(life.lastEventGen)}` : '               ',
+      ` world       : ${life.worldH}x${life.worldW}`,
+      ` census      : ${[...census].slice(0, panelW - 16).join('')}`,
+      ` tempo       : ${(1 / Math.max(life.dilation, 0.01)).toFixed(2)}x`,
+    ];
+    const ctx = this.ctx;
+    ctx.fillStyle = css(BG);
+    ctx.fillRect(x0 * this.cw, y0 * this.cw * 2, panelW * this.cw, lines.length * this.cw * 2);
+    lines.forEach((line, i) => {
+      const padded = [...` ${line}`.padEnd(panelW)].slice(0, panelW).join('');
+      this.text(padded, y0 + i, x0, FG_DIM);
+    });
+  }
+
+  /** Write a string into the character grid, one glyph per column. */
+  text(s: string, row: number, col: number, color: string): void {
+    const ctx = this.ctx;
+    const cw = this.cw;
+    const y = row * cw * 2;
+    ctx.fillStyle = color;
+    let x = col;
+    for (const ch of s) {
+      if (x >= this.cols) break;
+      if (x >= 0 && ch !== ' ') {
+        const spark = SPARKS.indexOf(ch);
+        if (spark >= 0) {
+          // block elements drawn, not typeset: same on every font
+          const hh = Math.max(1, Math.round((cw * 2 * (spark + 1)) / 8));
+          ctx.fillRect(x * cw, y + cw * 2 - hh, cw, hh);
+        } else if (ch === '─') {
+          ctx.fillRect(x * cw, y + cw - Math.max(1, Math.round(cw / 8)) / 2, cw, Math.max(1, Math.round(cw / 8)));
+        } else {
+          let cw2 = this.widths.get(ch);
+          if (cw2 === undefined) {
+            cw2 = ctx.measureText(ch).width;
+            this.widths.set(ch, cw2);
+          }
+          ctx.fillText(ch, x * cw + cw / 2 - cw2 / 2, y + cw);
+        }
+      }
+      x++;
+    }
+  }
+}
diff --git a/afterlife/src/vite-env.d.ts b/afterlife/src/vite-env.d.ts
new file mode 100644
index 0000000..eadabd4
--- /dev/null
+++ b/afterlife/src/vite-env.d.ts
@@ -0,0 +1,5 @@
+/** The music worklet, bundled on its own and inlined as source (vite.config.ts). */
+declare module 'virtual:afterlife-worklet' {
+  const source: string;
+  export default source;
+}
diff --git a/afterlife/tsconfig.json b/afterlife/tsconfig.json
new file mode 100644
index 0000000..e7d1d38
--- /dev/null
+++ b/afterlife/tsconfig.json
@@ -0,0 +1,16 @@
+{
+  "compilerOptions": {
+    "target": "ES2022",
+    "module": "ESNext",
+    "moduleResolution": "bundler",
+    "lib": ["ES2022", "DOM", "DOM.Iterable"],
+    "strict": true,
+    "noUncheckedIndexedAccess": true,
+    "noImplicitOverride": true,
+    "noFallthroughCasesInSwitch": true,
+    "forceConsistentCasingInFileNames": true,
+    "skipLibCheck": true,
+    "noEmit": true
+  },
+  "include": ["src", "scripts"]
+}
diff --git a/afterlife/vite.config.ts b/afterlife/vite.config.ts
new file mode 100644
index 0000000..f6003ad
--- /dev/null
+++ b/afterlife/vite.config.ts
@@ -0,0 +1,54 @@
+import { resolve } from 'path';
+import { build as esbuild } from 'esbuild';
+import { defineConfig, type Plugin } from 'vite';
+
+/**
+ * afterlife builds straight into the blog's static tree, like syrinx, apeiron
+ * and oikos. The Docker image never runs npm, so the bundle in git *is* what
+ * deploys: rebuild and commit whenever src/ changes.
+ *
+ * `npm run dev` serves the standalone index.html (the universe persists in
+ * that origin's localStorage, not the site's).
+ */
+
+/**
+ * The music runs in an AudioWorklet, which has to be its own module. Rather
+ * than ship a second file (and teach an iife build about import.meta.url),
+ * the worklet is bundled here by esbuild — vite's own — and imported as a
+ * string; audio.ts loads it from a blob: URL.
+ */
+function workletInline(): Plugin {
+  const id = 'virtual:afterlife-worklet';
+  return {
+    name: 'afterlife-worklet',
+    resolveId: (source) => (source === id ? `\0${id}` : null),
+    async load(loaded) {
+      if (loaded !== `\0${id}`) return null;
+      const entry = resolve(__dirname, 'src/music/worklet.ts');
+      const out = await esbuild({ entryPoints: [entry], bundle: true, write: false, format: 'iife', minify: true, target: 'es2022' });
+      this.addWatchFile(entry);
+      this.addWatchFile(resolve(__dirname, 'src/music/engine.ts'));
+      return `export default ${JSON.stringify(out.outputFiles[0]?.text ?? '')};`;
+    },
+  };
+}
+
+export default defineConfig({
+  plugins: [workletInline()],
+  server: { port: 5198, strictPort: true },
+  build: {
+    outDir: resolve(__dirname, '../aethera/static/afterlife'),
+    emptyOutDir: false,
+    rollupOptions: {
+      input: resolve(__dirname, 'src/main.ts'),
+      output: {
+        entryFileNames: 'afterlife.js',
+        assetFileNames: 'afterlife.[ext]',
+        format: 'iife',
+      },
+    },
+    // a real afterlife.css to , so the splash is styled before the JS parses
+    cssCodeSplit: false,
+    sourcemap: false,
+  },
+});
diff --git a/oikos/README.md b/oikos/README.md
index 16cc733..b1b3468 100644
--- a/oikos/README.md
+++ b/oikos/README.md
@@ -28,6 +28,7 @@ nothing to watch:
 | dreams api | re-types the real `/api/dreams/status` JSON each poll |
 | apeiron | real prompts composed from apeiron's own `templates.json` / `components.json` |
 | syrinx | **your** creature, read from this origin's localStorage (name, age, topology) |
+| afterlife | **your** universe, run live by afterlife's own engine and terminal renderer (`../afterlife/src`), or a genesis of its own |
 | irc | the live `/ws/irc` broadcast, formatted as `irc.js` formats it |
 | parlor | Kleros' real board, districts and prices; a toy game on it |
 | dream_gen | the core-loop diagram from its README, with the real keyframe and prompt |
diff --git a/oikos/src/data.ts b/oikos/src/data.ts
index eab3e9d..04a1a2c 100644
--- a/oikos/src/data.ts
+++ b/oikos/src/data.ts
@@ -16,10 +16,14 @@
  *   irc        /ws/irc replays a pre-generated bank; one more listener is free.
  *   syrinx     the creature lives in this origin's localStorage, so the room
  *              can show *your* creature, if you have woken one.
+ *   afterlife  the universe is saved in this origin's localStorage too, so the
+ *              room can run *yours* on its screen.
  *   apeiron    the grammar ships as two small JSON files; the screen composes
  *              real prompts from it.
  */
 
+import { KEY as AFTERLIFE_KEY } from '../../afterlife/src/engine/persist';
+
 export interface Site {
   id: string;
   title: string;
@@ -175,6 +179,27 @@ export function readCreature(): Creature | null {
   }
 }
 
+// ---- afterlife --------------------------------------------------------------
+
+/** What the room needs to know about a saved universe (the screen loads the rest). */
+export interface UniverseInfo {
+  generation: number;
+  bornAt: number;
+  savedAt: number;
+}
+
+export function readUniverse(): UniverseInfo | null {
+  try {
+    const raw = localStorage.getItem(AFTERLIFE_KEY);
+    if (!raw) return null;
+    const s = JSON.parse(raw) as { generation?: unknown; bornAt?: unknown; savedAt?: unknown };
+    if (typeof s.generation !== 'number' || typeof s.savedAt !== 'number') return null;
+    return { generation: s.generation, bornAt: typeof s.bornAt === 'number' ? s.bornAt : s.savedAt, savedAt: s.savedAt };
+  } catch {
+    return null;
+  }
+}
+
 // ---- apeiron ----------------------------------------------------------------
 
 export interface ApeironGrammar {
@@ -213,6 +238,7 @@ export class Feeds {
   });
   readonly irc = new Signal({ connected: false, lines: [], collapse: null, fragments: 0, version: 0 });
   readonly creature = new Signal(readCreature());
+  readonly universe = new Signal(readUniverse());
   readonly apeiron = new Signal(null);
 
   private timers: number[] = [];
@@ -232,6 +258,11 @@ export class Feeds {
     every(() => void this.pollChronicle(), 120_000);
     // a creature woken in another tab should appear without a reload
     every(() => this.creature.set(readCreature()), 15_000);
+    // and a universe left at /afterlife in another tab
+    every(() => {
+      const u = readUniverse();
+      if (u?.savedAt !== this.universe.value?.savedAt) this.universe.set(u);
+    }, 15_000);
     this.openIrc();
     if (!this.apeiron.value) void this.loadApeiron();
   }
diff --git a/oikos/src/screens/afterlife.ts b/oikos/src/screens/afterlife.ts
new file mode 100644
index 0000000..0827591
--- /dev/null
+++ b/oikos/src/screens/afterlife.ts
@@ -0,0 +1,54 @@
+/**
+ * afterlife — the real universe, on a small terminal.
+ *
+ * Not a picture of it: this is afterlife's own engine and terminal renderer
+ * (imported from ../afterlife/src), stepping at the screen's frame rate on a
+ * 64×24 terminal the size of the tube. If this browser has a universe saved
+ * at /afterlife, the screen adopts it, generation and all, and the ticker says
+ * so; otherwise it runs a genesis of its own. It never saves: yours only
+ * moves when you're at /afterlife (the screen is a view of the place, like
+ * syrinx's screen is of the creature). No sound here either.
+ */
+
+import { InfiniteLife } from '../../../afterlife/src/engine/life';
+import { load } from '../../../afterlife/src/engine/persist';
+import { Terminal } from '../../../afterlife/src/term/render';
+import type { Site, UniverseInfo } from '../data';
+import { H, Screen, W, type ScreenEnv } from './screen';
+
+export class AfterlifeScreen extends Screen {
+  private term: Terminal;
+  private life: InfiniteLife | null = null;
+  private seenSave: UniverseInfo | null | undefined = undefined;
+
+  constructor(site: Site, env: ScreenEnv) {
+    super(site, env);
+    this.fps = 15;
+    this.term = new Terminal(this.ctx);
+    this.term.resize(W, H, 8);
+  }
+
+  private sync(): void {
+    const info = this.env.feeds.universe.value;
+    if (this.life && info?.savedAt === this.seenSave?.savedAt) return;
+    this.seenSave = info;
+    const save = info ? load() : null;
+    const life = new InfiniteLife(this.term.gridRows, this.term.cols, !save);
+    if (save) {
+      life.adopt(save);
+      life.ticker.queueSpecial(`the universe remembers generation ${life.generation.toLocaleString('en-US')}`);
+    }
+    this.life = life;
+  }
+
+  protected draw(): void {
+    this.sync();
+    const life = this.life;
+    if (!life) return;
+    life.step();
+    if (life.generation > 0 && life.generation % 150 === 0) life.takeCensus();
+    const st = this.term.status(life, '');
+    if (st.tickerWidth >= 10) life.tickTicker(st.tickerWidth);
+    this.term.render(life, st, false);
+  }
+}
diff --git a/oikos/src/screens/index.ts b/oikos/src/screens/index.ts
index 2642891..b346a25 100644
--- a/oikos/src/screens/index.ts
+++ b/oikos/src/screens/index.ts
@@ -5,6 +5,7 @@
  */
 
 import type { Site } from '../data';
+import { AfterlifeScreen } from './afterlife';
 import { ApeironScreen } from './apeiron';
 import { ChronicleScreen } from './chronicle';
 import { DreamGenScreen } from './dreamGen';
@@ -26,6 +27,7 @@ const PAINTERS: Record Screen> = {
   'dreams-api': DreamsApiScreen,
   apeiron: ApeironScreen,
   syrinx: SyrinxScreen,
+  afterlife: AfterlifeScreen,
   irc: IrcScreen,
   parlor: ParlorScreen,
   dream_gen: DreamGenScreen,
diff --git a/oikos/src/world/layout.ts b/oikos/src/world/layout.ts
index 429e4aa..06582eb 100644
--- a/oikos/src/world/layout.ts
+++ b/oikos/src/world/layout.ts
@@ -34,6 +34,7 @@ export const PLACEMENTS: Record = {
   apeiron: { angle: -54, r: 4.2, y: 0, style: 'black', screenW: 1.15, channel: 5 },
   irc: { angle: -54, r: 4.2, y: 0, style: 'beige', screenW: 0.95, on: 'apeiron', channel: 6 },
   syrinx: { angle: 54, r: 4.2, y: 0.28, style: 'grey', screenW: 1.08, channel: 7 },
+  afterlife: { angle: 78, r: 3.9, y: 0, style: 'black', screenW: 1.02, channel: 10 },
   dream_gen: { angle: -20, r: 7.0, y: 4.35, style: 'grey', screenW: 1.02, hang: true, feeds: 'dreams', channel: 8 },
   parlor: { angle: 20, r: 6.5, y: 3.6, style: 'beige', screenW: 1.1, hang: true, channel: 9 },
 };
diff --git a/oikos/src/xp/pane.ts b/oikos/src/xp/pane.ts
index 79a0a73..0748c29 100644
--- a/oikos/src/xp/pane.ts
+++ b/oikos/src/xp/pane.ts
@@ -159,6 +159,7 @@ export class Pane {
     const s = this.site;
     if (s.id === 'dreams') return 'Opening dreams wakes the dreamer: a GPU starts up while anyone is watching and goes back to sleep after. The frame here is the last one the chronicle kept.';
     if (s.id === 'syrinx') return 'Syrinx makes sound once you wake it. The creature here is read from this browser; nobody else sees yours.';
+    if (s.id === 'afterlife') return 'afterlife makes music once you click in. The universe on this screen is the one saved in this browser, if you have visited; nobody else sees yours.';
     if (s.group === 'wired') return `${s.title} is not on this server; it opens in a new window.`;
     return null;
   }
@@ -193,6 +194,12 @@ export class Pane {
         text = c ? `yours: ${c.name}` : 'not woken in this browser';
         break;
       }
+      case 'afterlife': {
+        const u = feeds.universe.value;
+        on = !!u;
+        text = u ? `yours: generation ${u.generation.toLocaleString('en-US')}` : 'no universe in this browser yet';
+        break;
+      }
       default:
         return;
     }
diff --git a/oikos/src/xp/shell.ts b/oikos/src/xp/shell.ts
index 166e12e..5d343f8 100644
--- a/oikos/src/xp/shell.ts
+++ b/oikos/src/xp/shell.ts
@@ -50,7 +50,8 @@ export const RELATED: Record = {
   dream_gen: ['dreams', 'chronicle'],
   transmissions: ['irc', 'syrinx'],
   apeiron: ['dreams', 'syrinx'],
-  syrinx: ['apeiron', 'transmissions'],
+  syrinx: ['apeiron', 'afterlife'],
+  afterlife: ['syrinx', 'apeiron'],
   irc: ['transmissions', 'parlor'],
   parlor: ['irc', 'transmissions'],
 };
diff --git a/tests/test_afterlife.py b/tests/test_afterlife.py
new file mode 100644
index 0000000..93d0f46
--- /dev/null
+++ b/tests/test_afterlife.py
@@ -0,0 +1,41 @@
+from pathlib import Path
+
+from fastapi.testclient import TestClient
+
+from aethera.api.oikos import SITES
+
+STATIC = Path(__file__).resolve().parents[1] / "aethera" / "static" / "afterlife"
+
+
+def test_afterlife_page_renders(client: TestClient):
+    r = client.get("/afterlife")
+    assert r.status_code == 200
+    assert "/static/afterlife/afterlife.js" in r.text
+    assert "/static/afterlife/afterlife.css" in r.text
+    # the terminal and the splash are markup, so they paint before the bundle parses
+    for el in ('id="afterlife-root"', 'id="term"', 'id="splash"', 'id="keys"'):
+        assert el in r.text, el
+    # leaving must be a real navigation (pagehide saves the universe)
+    assert 'id="afterlife-home" href="/" hx-boost="false"' in r.text
+
+
+def test_bundle_is_committed():
+    """The Docker image never runs npm; the built page must be in the tree."""
+    for name in ("afterlife.js", "afterlife.css"):
+        assert (STATIC / name).is_file(), name
+    # the music worklet is inlined into the bundle, not a second file
+    assert "afterlife-music" in (STATIC / "afterlife.js").read_text()
+
+
+def test_afterlife_is_on_the_map(client: TestClient):
+    assert "/afterlife" in client.get("/sitemap.xml").text
+    assert "/afterlife" in client.get("/urls.txt").text
+    site = next(s for s in SITES if s["id"] == "afterlife")
+    assert site["href"] == "/afterlife" and site["tune"] is True
+
+
+def test_afterlife_frames_only_for_aethera(client: TestClient):
+    """oikos tunes the page in on its screen; nobody else may frame it."""
+    r = client.get("/afterlife")
+    assert r.headers["content-security-policy"] == "frame-ancestors 'self'"
+    assert r.headers["x-frame-options"] == "SAMEORIGIN"

From 99a3ff485465fe1aa9fd6dce3e060121697cc45c Mon Sep 17 00:00:00 2001
From: LuxiaSL 
Date: Tue, 29 Sep 2026 15:50:17 -0700
Subject: [PATCH 2/7] afterlife: saves survive blocked storage and haunted
 mode; the world can keep its size

- persist: localStorage is read inside the try, so a browser that blocks
  site data gets a fresh universe instead of a dead page
- persist: ghosts deeper than GHOST_FRAMES are not written (adopt retires
  them anyway); haunted mode no longer blows the 1.5M cap and fails silently
- persist: generation must be a safe integer
- life: the constructor takes a WorldFloor, so a resize can keep the old
  world and a small screen can run a small one

Co-Authored-By: Claude Opus 5.5 
---
 afterlife/src/engine/life.ts    | 18 +++++++++++++++---
 afterlife/src/engine/persist.ts | 27 ++++++++++++++++++---------
 2 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/afterlife/src/engine/life.ts b/afterlife/src/engine/life.ts
index 849c80a..b2be0ba 100644
--- a/afterlife/src/engine/life.ts
+++ b/afterlife/src/engine/life.ts
@@ -77,6 +77,12 @@ export interface UniverseState {
   totalInjections: number;
 }
 
+/** The smallest world an InfiniteLife may have (see its constructor). */
+export interface WorldFloor {
+  minH?: number;
+  minW?: number;
+}
+
 export class InfiniteLife {
   // view_h/view_w = the display grid at zoom 0 (half-block doubles vertical)
   readonly viewH: number;
@@ -154,11 +160,17 @@ export class InfiniteLife {
   private actBaseline = 0;
   dilation = 1;
 
-  constructor(termRows: number, termCols: number, seed = true) {
+  /**
+   * `world` bounds the world from below. life.py's floor (400×800) is the
+   * default; a resize passes the old world so shrinking the window never
+   * crops the universe, and a small screen (oikos) can pass 0 to keep only
+   * 5× its view.
+   */
+  constructor(termRows: number, termCols: number, seed = true, world: WorldFloor = {}) {
     this.viewH = termRows * 2;
     this.viewW = termCols;
-    this.worldH = Math.max(this.viewH * 5, 400);
-    this.worldW = Math.max(this.viewW * 5, 800);
+    this.worldH = Math.max(this.viewH * 5, world.minH ?? 400);
+    this.worldW = Math.max(this.viewW * 5, world.minW ?? 800);
     const n = this.worldH * this.worldW;
     this.grid = new Uint8Array(n);
     this.age = new Int32Array(n);
diff --git a/afterlife/src/engine/persist.ts b/afterlife/src/engine/persist.ts
index 49554f7..5f5cb8c 100644
--- a/afterlife/src/engine/persist.ts
+++ b/afterlife/src/engine/persist.ts
@@ -12,6 +12,7 @@
  * busy universe of ~20k cells comes to ~70 kB of text.
  */
 
+import { GHOST_FRAMES } from './constants';
 import type { UniverseState } from './life';
 
 export const KEY = 'afterlife-universe-v1';
@@ -49,7 +50,9 @@ export function encodeAges(age: Int32Array): string {
   let prev = -1;
   for (let i = 0; i < age.length; i++) {
     const a = age[i] ?? 0;
-    if (a === 0) continue;
+    // ghosts deeper than normal decay reaches are retired on adopt anyway;
+    // haunted mode makes nearly every cell one, and would blow the cap
+    if (a === 0 || a < -GHOST_FRAMES) continue;
     varint(i - prev - 1);
     varint(a >= 0 ? a * 2 : -a * 2 - 1);
     prev = i;
@@ -86,9 +89,10 @@ export function decodeAges(b64: string, n: number): Int32Array {
   return age;
 }
 
-export function load(storage: Storage | undefined = globalThis.localStorage): SaveFile | null {
+export function load(storage?: Storage): SaveFile | null {
   try {
-    const raw = storage?.getItem(KEY);
+    // reading localStorage itself throws where site data is blocked
+    const raw = (storage ?? globalThis.localStorage)?.getItem(KEY);
     if (!raw) return null;
     const s = JSON.parse(raw) as Partial;
     if (s.v !== 1 || !Number.isInteger(s.h) || !Number.isInteger(s.w) || typeof s.cells !== 'string') return null;
@@ -96,7 +100,7 @@ export function load(storage: Storage | undefined = globalThis.localStorage): Sa
     const w = s.w as number;
     if (h <= 0 || w <= 0 || h * w > 16_000_000) return null;
     const generation = Number(s.generation);
-    if (!Number.isFinite(generation) || generation < 0) return null;
+    if (!Number.isSafeInteger(generation) || generation < 0) return null;
     return {
       h,
       w,
@@ -114,8 +118,9 @@ export function load(storage: Storage | undefined = globalThis.localStorage): Sa
 }
 
 /** Save atomically (one setItem). Returns true on success. */
-export function save(file: SaveFile, storage: Storage | undefined = globalThis.localStorage): boolean {
+export function save(file: SaveFile, storage?: Storage): boolean {
   try {
+    const store = storage ?? globalThis.localStorage;
     const stored: Stored = {
       v: 1,
       h: file.h,
@@ -127,8 +132,12 @@ export function save(file: SaveFile, storage: Storage | undefined = globalThis.l
       cells: encodeAges(file.age),
     };
     const text = JSON.stringify(stored);
-    if (text.length > MAX_CHARS || !storage) return false;
-    storage.setItem(KEY, text);
+    if (text.length > MAX_CHARS) {
+      console.warn(`afterlife: the universe is too big to keep (${text.length} chars)`);
+      return false;
+    }
+    if (!store) return false;
+    store.setItem(KEY, text);
     return true;
   } catch (err) {
     console.warn('afterlife: could not save the universe', err);
@@ -136,9 +145,9 @@ export function save(file: SaveFile, storage: Storage | undefined = globalThis.l
   }
 }
 
-export function forget(storage: Storage | undefined = globalThis.localStorage): void {
+export function forget(storage?: Storage): void {
   try {
-    storage?.removeItem(KEY);
+    (storage ?? globalThis.localStorage)?.removeItem(KEY);
   } catch {
     /* fine */
   }

From e7ce6074a54b74f273bc4a2c0d082bc7fd8abbe0 Mon Sep 17 00:00:00 2001
From: LuxiaSL 
Date: Tue, 29 Sep 2026 15:56:26 -0700
Subject: [PATCH 3/7] afterlife: the shell keeps the universe whole across
 resizes, tabs and screens

- a resize keeps the old world as the floor (no more cropping) and carries
  the session across: pause, speed, zoom, camera, modes, ticker; a load
  keeps the saved world's size; URL-bar jitter no longer rebuilds
- an oikos screen shows the save but never writes it
- a later universe saved by another tab isn't overwritten
- the loop stops at a 12 ms budget and drops the backlog
- a failed music start closes its context and can be retried; iOS
  'interrupted' resumes on a gesture; playback audio session
- key repeat only for repeatable keys; ? and Escape don't start music;
  Enter/Space on the splash enters; touch splash copy; csv isn't a key;
  recording is capped and says when it caught nothing; drags stay on grid;
  a third finger doesn't paint; pixel-ratio changes refit; reduced motion

Co-Authored-By: Claude Opus 5.5 
---
 aethera/templates/afterlife/viewer.html |   4 +-
 afterlife/index.html                    |   4 +-
 afterlife/src/main.ts                   | 228 ++++++++++++++++++++----
 afterlife/src/music/audio.ts            |  41 ++++-
 afterlife/src/style.css                 |  25 ++-
 5 files changed, 256 insertions(+), 46 deletions(-)

diff --git a/aethera/templates/afterlife/viewer.html b/aethera/templates/afterlife/viewer.html
index 9d6bcaf..e62fae6 100644
--- a/aethera/templates/afterlife/viewer.html
+++ b/aethera/templates/afterlife/viewer.html
@@ -52,7 +52,7 @@
 ╚═╝  ╚═╝╚═╝        ╚═╝   ╚══════╝╚═╝  ╚═╝╚══════╝╚═╝╚═╝     ╚══════╝

afterlife

the game of life, after hours

-

click to listen · ? for the keys · q to leave, if you can

+

click to listen · ? for the keys · q to leave, if you cantap to listen · the keys are in the corner