diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..1e01858 --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,36 @@ +name: Website + +on: + push: + branches: [main] + paths: + - "site/**" + - ".github/workflows/pages.yml" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: pages + cancel-in-progress: false + +jobs: + deploy: + runs-on: ubuntu-latest + timeout-minutes: 10 + permissions: + contents: read + pages: write + id-token: write + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + - uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 + - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 + with: + path: site + - id: deployment + uses: actions/deploy-pages@368f82528645a54fb793d4d04e342629a3f51346 # v5.0.1 diff --git a/.gitignore b/.gitignore index fb81b59..5538f93 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,6 @@ reviews/ # macOS .DS_Store + +# Website build tooling +node_modules/ diff --git a/README.md b/README.md index d6f775f..3e2ce9c 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ A macOS menu bar app that keeps your credentials encrypted on your Mac and lets AI agents use them only after you approve. -English | [Simplified Chinese](README.zh-CN.md) +[Website](https://askkey.sudohg.com/) · English | [Simplified Chinese](README.zh-CN.md) > **[Download the latest release](https://github.com/sudoHG/AskKey/releases/latest/download/AskKey.dmg)** (notarized DMG, macOS 14+). AskKey has no backup or recovery yet, so keep the originals of your credentials somewhere else. diff --git a/README.zh-CN.md b/README.zh-CN.md index 26d4239..db444aa 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -4,7 +4,7 @@ 一个 macOS 菜单栏应用:凭证加密保存在你的 Mac 上,AI Agent 必须经过你的批准才能使用。 -[English](README.md) | 简体中文 +[官网](https://askkey.sudohg.com/zh/) · [English](README.md) | 简体中文 > **[下载最新版本](https://github.com/sudoHG/AskKey/releases/latest/download/AskKey.dmg)**(经过 Apple 公证的 DMG,需要 macOS 14 或更高版本)。请旨目前没有备份和恢复功能,请自行另存一份凭证原件。 diff --git a/scripts/check_hygiene.py b/scripts/check_hygiene.py index 412dee8..11d8576 100644 --- a/scripts/check_hygiene.py +++ b/scripts/check_hygiene.py @@ -20,6 +20,8 @@ "Sources/AskKeyAppKit/Resources/Localizable.xcstrings", # English and Simplified Chinese UI catalog. "Sources/AskKeyHelper/Resources/Localizable.xcstrings", # English and Simplified Chinese helper copy (#83). "README.zh-CN.md", # Simplified Chinese README. + "site/index.html", # Language switcher on the English website (#160). + "site/zh/index.html", # Simplified Chinese website (#160). "docs/glossary.md", # Chinese UI terms alongside English glossary prose (#67). "Sources/AskKeyAppKit/Resources/zh-Hans.lproj/InfoPlist.strings", # Localized product name. "Tests/AskKeyAppTests/AgentClientConnectionPolicyTests.swift", # Chinese client connection errors. diff --git a/site-src/how/README.md b/site-src/how/README.md new file mode 100644 index 0000000..dbfe5a2 --- /dev/null +++ b/site-src/how/README.md @@ -0,0 +1,102 @@ +# Ask Key — "How it works" (morning desk, one unbroken shot) + +## Concept + +A single continuous camera move across an oiled black walnut desk by a window in early morning, where three real-time 3D objects act out the mechanism: the AI is a clear glass block with its live transcript sealed inside (so you can see everything it holds), Ask Key is a frosted vault in the shape of the app icon with vermilion keys inside it, and `./deploy.sh` is a graphite box with a keyhole. The film stops when the request reaches you and shows Ask Key's real approval prompt with a live 5-minute countdown. Whatever you click actually decides the ending: Allow sends a copy of the key out of the frosted glass, around the AI and into the program, which runs, publishes the site and dissolves the key; Deny (or letting it expire) leaves the key untouched and the program never runs. Either way the AI gets back one line and ends holding zero keys. Vermilion is reserved for the secret, so you can watch where it goes and see it never enters the glass. + +The room belongs to the page around it. The stage is the page's own white: the desk fades into white beyond the cast (the white wall of a bright room), the top and bottom of the stage dissolve into the page, the canvas fades up out of white the first time it is seen, and as each ending closes the desk recedes until the cast stands on white paper with its labels, like the slips with seals further down the site. Light is cool morning daylight from a window to the back left: a soft window falls across the desk, the glass and lacquer reflect that window, contact shadows fall away from it, and light through the red keys tints the desk under the vault. Type, ink, vermilion and paper slips are the site's own (#fff, #1a1a1a, #b8281e, Hanken Grotesk, Songti, the site's paper texture and its vermilion "approved" seal). + +## Techniques + +- three.js r186 bundled and minified with esbuild into one ES module (`site/how/how.js`, about 640 KB, about 170 KB gzipped). Its MIT licence ships as `site/how/THREE-LICENSE.txt` and the bundle's first line points to it. No other runtime dependencies and no requests to other hosts. +- One render pass per frame. No transmission pass, no shadow maps, no post-processing. + - Clear glass is a premultiplied layer: what the surface reflects (Fresnel, F0 = 0.04) replaces the light the background no longer sends through, and the slab's body thickens to a dark slate-green toward grazing angles, so its edges read on a white page. Back and front faces are two meshes, so three.js never flips a double-sided material twice a frame. + - The frosted vault is the same layer, rougher, over a milky core (the icon's silhouette, blurred once into a canvas texture) that hides the desk the way ground glass would. The keys inside are their own silhouettes blurred once into a texture and drawn just after the shell, so they stay vermilion instead of turning pink under a white veil. The only sharp key is the copy that is delivered. + - The reflections come from a small white room rendered once into a prefiltered environment map at load: white walls, a pale desk, a tall four-pane window and a few dark shapes (a shelf, a doorway) so glass and lacquer have something dark to reflect. + - The desk is one unlit shader: a seamless black walnut texture in its own colour with a satin sheen where the window falls, a procedural four-pane window patch with soft mullion shadows, a broad falloff from the window, and the fade into the page's white. Contact shadows and the red tint under the vault are decals drawn in the opaque pass, so they need no sorting. +- Text in the scene is drawn into canvas textures from a JSON block in the page, so each language renders its own scene. The transcript is a static sheet plus one thin strip per line: typing a character or turning the spinner re-uploads one 2048×104 strip instead of a 2048×1296 page, and fading a line in changes an opacity rather than redrawing. +- A camera rig of key frames (target, view direction, framing radius) on Catmull-Rom splines with a monotone time warp, so the move never stops between frames. Distance is computed from the viewport, so the same shot recomposes for a phone held upright. +- Every visual is a pure function of the film's time and the reader's decision, which makes chapter seeking, replays and the alternate endings exact. +- The approval prompt is real DOM (buttons, Details disclosure with the app's actual rows, Esc to decide later, a pending pill, a live countdown that really expires at 0:00). Labels pinned to scene objects are projected DOM elements, measured once when they appear and written in one pass, so the browser never lays out mid-frame. Status labels are solid paper pills, so nothing re-blurs the scene behind them; the three names are light text with a soft shadow, shown only while the wood is behind them. + +## Performance + +What it does to stay smooth: + +- Pixel ratio capped at 1.5 (1 on a software renderer; antialiasing off there too). The first three frames are timed with a forced GPU sync and the ratio is lowered (down to 0.5) if a frame would cost more than 7.5 ms; while the film plays, a 40-frame window steps it down by 13% whenever the 75th percentile runs over 20.5 ms. It never steps back up, so it cannot oscillate. +- Every shader program and every texture is compiled and uploaded before the film starts (`compileAsync`, `initTexture`, 1×1 stand-ins for images still loading), so nothing appearing mid-film stalls a frame. Verified: 16 programs before the film, 16 after both endings. +- Frames are drawn only when something moves: every frame while the film plays; 20 fps behind the blurred approval prompt (30 when set aside); otherwise only on pointer movement, resize or a texture arriving. Nothing is drawn while the section is off screen or the tab is hidden. Verified: 0 frames in 2 s while an ending sits still. +- No per-frame allocations in the timeline, camera or labels. + +Measured in headless Google Chrome 1440×900 at device pixel ratio 2, rAF intervals over the whole film (14 s to the prompt, 1.5 s at the prompt, 14 s of the Allow ending), first 5 frames dropped. "Long" counts frames over 50 ms. The test Mac is an M2 Max under heavy load from other work, so the software-renderer rows in particular are noisy. + +| Condition | Before (night, c3) median / p95 / long / fps | After (morning) median / p95 / long / fps | +|---|---|---| +| (a) GPU (ANGLE Metal) | 16.7 ms / 33.3 ms / 9 / 54.8 | 16.7 ms / 16.7 ms / 0 / 60.0 | +| (b) SwiftShader (`--use-angle=swiftshader`) | 4250 ms / 4283 ms / all / 0.3 | 16.7 ms / 33.4 ms / 22–42 / 44–51 (renders at 0.5×; three runs) | +| (c) CPU throttled 4× (`Emulation.setCPUThrottlingRate`) | 16.7 ms / 83.4 ms / 102 / 41.5 | 16.7 ms / 16.7 ms / 0 / 59.9 | + +For a like-for-like software check at device pixel ratio 1 (where the night version starts at its lowest resolution): before 417 ms median, 1050 ms p95, 2.2 fps; after 16.7 ms, 33.4 ms, 50 fps. + +Where the time went before, and what fixed it: + +- CPU: a JS profile of the opening at 4× throttle spent 3.2 s of 10 s in `texSubImage2D`, re-uploading the 2048×1296 transcript texture whenever a character was typed, a line faded or the spinner turned. Now 39 ms (per-line strips). `updateTags` (layout thrash from reading `offsetWidth` per label per frame) went from 420 ms to 31 ms. +- GPU: a synchronous render of a mid-film frame took 11.5 ms at ratio 2, of which the transmission pass was about half (5.6 ms without it); at ratio 1, 7.7 ms. Now 2.6 ms at ratio 1.5 and 2.1 ms at ratio 1, with no transmission pass and no spotlights or point light (one hemisphere and one directional light). + +The targets (60 fps locked on an M1 MacBook Air at 1440×900; at least 40 fps without long frames on an Intel Mac with integrated graphics) were not measured on those machines. The headroom above (a full frame at about 2.6 ms of synchronous GPU work on an M2 Max at ratio 1.5, and a smooth film on a software rasteriser) is the evidence; the benchmark and runtime monitor lower the resolution on anything slower. + +## Accessibility and fallbacks + +- The whole story is real text in an ordered list (`.akhw-steps`); the on-stage caption is a visual copy of it. The prompt is an `alertdialog` with real buttons. +- `prefers-reduced-motion: reduce`: no animation. The stage shows the final composed frame, all six steps are listed in full, and the prompt sits under the scene; choosing Deny re-renders the still for that ending. +- No WebGL2: a pre-rendered poster (`site/how/img/poster-*-wide|tall.webp`, the morning final frame) plus the same still telling. + +## Where it lives + +- Built files: `site/how/` (`how.js`, `how.css`, `img/`, `THREE-LICENSE.txt`). The section markup and its `akhw-i18n` JSON are in `site/index.html` and `site/zh/index.html`; fonts come from `site/fonts/`. +- Source: this folder. It is not deployed. + +## Source and build + +This folder holds the readable source, every file under 600 lines: + +| File | What it holds | +|---|---| +| `how.src.js` | entry: renderer, render loop, sizing, start-up, debug hook, still telling | +| `timing.js` | the film's clock and easings | +| `rig.js` | camera key frames and rails | +| `world.js` | the timeline: what every object does at a given time | +| `ui.js` | labels, captions, chapter rail, the prompt and countdown, endings | +| `quality.js` | GPU probe, benchmark and runtime resolution control | +| `scene.js` | the objects | +| `layout.js` | wide and portrait layouts and the paths between objects | +| `materials.js` | glass, desk, decal and dissolve shaders | +| `room.js` | the room the objects reflect | +| `transcript.js` | the transcript sheet and its per-line strips | +| `textures.js` | canvas drawing for cards, chip, site, program face, shadows, blurred shapes | + +Rebuild (exact versions are pinned in `package.json`): + +```sh +cd site-src/how +npm ci +npm run build # writes site/how/how.js +npm run license # copies three.js's LICENSE to site/how/THREE-LICENSE.txt +``` + +`npm run build` also runs `stamp.mjs`, which adds a content hash (`?v=`) to every script and stylesheet URL in both pages, so a browser never pairs new pages with an old cached file. Run `npm run stamp` after editing `site/style.css` or `site/motion.js` by hand. + + +## Fonts and text in images + +Only open fonts are shipped or rasterised: + +- Shipped web fonts: Hanken Grotesk (OFL) and IBM Plex Mono Regular, Latin-1 split, as published unmodified by IBM in the IBM/plex repository (OFL, reserved font name "Plex"). Licences are in `site/fonts/`. +- System fonts (PingFang SC, Songti SC, SF Mono and similar) are only named in CSS and canvas font stacks; they render on the visitor's own machine and nothing of them is shipped. +- Images that contain text are made only with open fonts: the vermilion seals (`site/assets/seal-*.webp`, `site/how/img/seal-zhun.webp`) are typeset in Source Han Serif CN Heavy, the No-WebGL posters are rendered with every system family name redirected to Source Han Sans CN, and the share images (`site/assets/og-*.jpg`) are set in Source Han Serif CN, Source Han Sans CN and Hanken Grotesk (Adobe's fonts are OFL). Re-render them the same way; never with a system font. + +## Notes + +- All secret values are absent by design: the scene shows names, notes and variable names only, and the value slots are empty. +- The walnut texture (`site/how/img/walnut.webp`) was generated for this piece and made seamless (planks meet at the tile edge; the ends are cross-faded); the paper texture, seal and app icon come from the site's own assets. Fonts are the site's Hanken Grotesk and IBM Plex Mono (OFL, licences in `site/fonts/`). +- Verified in headless Google Chrome (Metal) at 1440×900, 1920×1080 and 390×844, both languages, both endings, Esc/pending, Details, chapter seeking and reduced motion, with no console errors and no requests to other hosts. Safari was not tested directly; the code uses WebGL2, standard CSS with `-webkit-` prefixes where needed, and canvas shadows instead of `ctx.filter` for its blurs. diff --git a/site-src/how/how.src.js b/site-src/how/how.src.js new file mode 100644 index 0000000..91ddafc --- /dev/null +++ b/site-src/how/how.src.js @@ -0,0 +1,278 @@ +// Ask Key — "How it works", told as one unbroken camera move across a desk +// in morning light that stops and waits for the reader to approve (or deny) +// the request. +// +// Rendering budget: one pass, no transmission or shadow maps, pixel ratio +// capped and set from a benchmark, and frames are drawn only when something +// moves: while the film plays, at a reduced rate behind the approval prompt, +// and on demand (pointer, resize) before and after. +import * as THREE from "three"; +import { buildScene, BG } from "./scene.js"; +import { buildRails, placeCamera } from "./rig.js"; +import { createWorld } from "./world.js"; +import { createUI } from "./ui.js"; +import { probeGPU, createQuality } from "./quality.js"; +import { PRE, POST, kindOf, outcomeOf } from "./timing.js"; + +const root = document.querySelector(".akhw"); +if (root) init(root); + +function init(root) { + const I = JSON.parse(root.querySelector(".akhw-i18n").textContent); + const $ = (s) => root.querySelector(s); + const stage = $(".akhw-stage"), canvas = $(".akhw-canvas"); + const params = new URLSearchParams(location.search); + const reduced = matchMedia("(prefers-reduced-motion: reduce)").matches || params.has("still"); + const S = { phase: "idle", T: 0, u: 0, decision: null, started: false, visible: false, later: false, gateAt: 0, ended: false }; + + // ------------------------------------------------------------ renderer + const gpu = probeGPU(); + let renderer = null; + if (gpu) try { + renderer = new THREE.WebGLRenderer({ canvas, antialias: !gpu.software, alpha: false, powerPreference: "high-performance" }); + } catch (e) { + renderer = null; + } + if (!renderer || !renderer.capabilities.isWebGL2) { + root.classList.add("no-gl", "is-still"); + stillTelling(null); + return; + } + renderer.setClearColor(BG, 1); + renderer.outputColorSpace = THREE.SRGBColorSpace; + renderer.toneMapping = THREE.NeutralToneMapping; + renderer.toneMappingExposure = 1.0; + const gl = renderer.getContext(); + const Q = createQuality(gpu, params); + + const asset = (p) => new URL(p, import.meta.url).href; + const paper = new Image(); + paper.src = asset("img/paper.jpg"); + const W = buildScene(renderer, I, paper, { wood: asset("img/walnut.webp"), seal: asset("img/seal-zhun.webp"), onTexture: () => wake(true) }); + const camera = new THREE.PerspectiveCamera(32, 1, 0.1, 100); + let rails = null; + const world = createWorld(W, I, camera); + const ui = createUI({ root, I, S, W, camera, reduced, wake: () => wake(true), renderNow: () => frame(performance.now()) }); + + // ------------------------------------------------------------ one frame + const pointer = { x: 0, y: 0, sx: 0, sy: 0 }; + let clock = 0; // drives the slow drift and idle life; runs only while the film does + const px = new Uint8Array(4); + function frame(now) { + let shot; + if (S.phase === "pre" || S.phase === "idle") shot = rails.pre.at(S.T); + else if (S.phase === "gate") shot = rails.pre.at(PRE); + else shot = rails[kindOf(S.decision)].at(S.u); + placeCamera(camera, shot, clock, pointer, reduced ? 0 : 1); + camera.updateMatrixWorld(); + world.update(S, clock); + world.updateTranscript(S, clock); + const t0 = performance.now(); + renderer.render(W.scene, camera); + if (!Q.benchmarked && !reduced) { + gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, px); + Q.sample(performance.now() - t0); + if (Q.changed) { Q.changed = false; resize(); } + } + ui.updateTags(S); + ui.updateCaptions(S); + // the room fades up out of the page's white the first time it is seen + if (S.visible && !root.classList.contains("is-ready")) requestAnimationFrame(() => root.classList.add("is-ready")); + } + + // --------------------------------------------------------------- loop + let raf = 0, last = 0, lastDraw = 0, dirty = true, frozen = false; + function wake(markDirty) { + if (markDirty) dirty = true; + if (reduced) { if (rails) frame(performance.now()); return; } + if (!raf && rails && S.visible && !document.hidden) { + last = 0; + raf = requestAnimationFrame(tick); + } + } + function tick(now) { + raf = 0; + const dt = last ? Math.min(0.05, (now - last) / 1000) : 0; + last = now; + const playing = S.started && !frozen && (S.phase === "pre" || S.phase === "post"); + if (playing) { + clock += dt; + if (S.phase === "pre") { + S.T += dt; + if (S.T >= PRE) ui.enterGate(); + } else { + S.u += dt; + const k = kindOf(S.decision); + if (S.u >= POST[k]) { + S.u = POST[k]; + S.phase = "end"; + ui.showEnd(); + } + } + } else if (S.phase === "gate" && !frozen) clock += dt; + ui.tickCountdown(now); + pointer.sx += (pointer.x - pointer.sx) * 0.06; + pointer.sy += (pointer.y - pointer.sy) * 0.06; + const easing = Math.abs(pointer.x - pointer.sx) + Math.abs(pointer.y - pointer.sy) > 0.002; + // Behind the prompt the scene is blurred and barely moves: 20 fps is + // plenty, 30 when the prompt is set aside. + const gateDue = S.phase === "gate" && now - lastDraw >= (S.later ? 30 : 46); + if (playing || dirty || easing || gateDue || !Q.benchmarked) { + dirty = false; + lastDraw = now; + frame(now); + if (playing && Q.frame(dt)) resize(); + } + if ((playing || S.phase === "gate" || easing || dirty || !Q.benchmarked) && S.visible && !document.hidden) raf = requestAnimationFrame(tick); + } + function sleep() { + cancelAnimationFrame(raf); + raf = 0; + } + + stage.addEventListener("pointermove", (e) => { + if (e.pointerType !== "mouse" || reduced) return; + const r = stage.getBoundingClientRect(); + pointer.x = ((e.clientX - r.left) / r.width) * 2 - 1; + pointer.y = ((e.clientY - r.top) / r.height) * 2 - 1; + wake(); + }); + stage.addEventListener("pointerleave", () => { pointer.x = 0; pointer.y = 0; wake(); }); + + // ------------------------------------------------------------- sizing + function resize() { + const w = stage.clientWidth, h = stage.clientHeight; + if (!w || !h) return; + renderer.setPixelRatio(Q.dpr); + renderer.setSize(w, h, false); + W.uFloor.uView.value.set(w * Q.dpr, h * Q.dpr); + camera.aspect = w / h; + const kind = w / h >= 1.02 ? "wide" : "tall"; + camera.fov = kind === "wide" ? 32 : 46; + if (kind !== W.L.kind) { + W.setLayout(kind); + rails = buildRails(W.L); + } + // keep the cast clear of the caption in the top-left on wide screens + if (kind === "wide") camera.setViewOffset(w, h, 0, -h * 0.045, w, h); + else camera.clearViewOffset(); + camera.updateProjectionMatrix(); + ui.measure(); + // a resized canvas is blank until drawn again + if (rails && S.phase !== "idle") frame(performance.now()); + } + + // ------------------------------------------------------------- start + W.setLayout(stage.clientWidth / Math.max(1, stage.clientHeight) >= 1.02 ? "wide" : "tall"); + rails = buildRails(W.L); + + const fontsReady = Promise.all([ + document.fonts.load('400 40px "IBM Plex Mono"'), + document.fonts.load('500 40px "Hanken Grotesk"'), + document.fonts.load('600 40px "Hanken Grotesk"'), + new Promise((r) => (paper.complete ? r() : (paper.onload = paper.onerror = r))), + ]).catch(() => {}); + + fontsReady.then(async () => { + W.redrawCards(); + // every program the film will need is compiled before it starts, so no + // object appearing mid-film can stall a frame + resize(); + world.update(S, 0); + try { + await (renderer.compileAsync ? renderer.compileAsync(W.scene, camera) : renderer.compile(W.scene, camera)); + } catch (e) { /* compiled lazily instead */ } + // and every texture is on the GPU before it is first seen + W.scene.traverse((o) => o.material && o.material.map && renderer.initTexture(o.material.map)); + S.phase = "pre"; + S.T = 0; + new ResizeObserver(() => resize()).observe(stage); + if (reduced) { + root.classList.add("is-still"); + S.started = true; + S.decision = "once"; + S.phase = "end"; + S.u = POST.allow; + stillTelling(() => frame(performance.now())); + frame(performance.now()); + return; + } + frame(performance.now()); + const io = new IntersectionObserver( + (entries) => { + const e = entries[0]; + S.visible = e.isIntersecting; + if (e.intersectionRatio >= 0.55 && !S.started) S.started = true; + if (S.visible) wake(true); else sleep(); + // A scroll that lands while the observer is being set up can leave it + // reporting a stale ratio with no later crossing: confirm by hand. + if (S.visible && !S.started) setTimeout(confirmStart, 250); + }, + { threshold: [0, 0.55] } + ); + function confirmStart() { + if (S.started || !S.visible) return; + const r = stage.getBoundingClientRect(); + const seen = Math.min(r.bottom, innerHeight) - Math.max(r.top, 0); + if (seen >= 0.55 * r.height) { S.started = true; wake(true); } else setTimeout(confirmStart, 250); + } + io.observe(stage); + document.addEventListener("visibilitychange", () => (document.hidden ? sleep() : wake(true))); + }); + + // Debug hook for headless verification only: ?debug exposes a seek. + if (params.has("debug")) { + window.__akhw = { + S, + Q, + gpu, + W, + renderer, + camera, + go(phase, t, decision) { + ui.hideEnd(); + S.started = true; + if (phase === "gate") { S.phase = "pre"; S.T = PRE - 0.01; S.decision = null; wake(true); return; } + if (phase !== "pre" && S.phase === "gate") { ui.hideAlert(true); root.classList.remove("is-gate", "is-later"); } + S.phase = phase; + if (phase === "pre") S.T = t; else S.u = t; + S.decision = decision ?? S.decision; + if (phase === "post" && t >= POST[kindOf(S.decision)]) { S.phase = "end"; S.u = POST[kindOf(S.decision)]; ui.showEnd(); } + wake(true); + }, + gate() { ui.enterGate(); wake(true); }, + freeze(v) { frozen = !!v; if (!v) wake(true); }, + render() { frame(performance.now()); }, + decide: ui.decide, + }; + } + + // Still telling: the prompt sits under the scene; choosing re-renders the + // last frame for that outcome. + function stillTelling(render) { + root.dataset.outcome = "allow"; + const lede = $(".akhw-lede"); + if (lede && lede.dataset.still) lede.textContent = lede.dataset.still; + const alert = $(".akhw-alert"); + const holder = document.createElement("div"); + holder.className = "akhw-still-alert"; + stage.after(holder); + holder.appendChild(alert); + alert.hidden = false; + $(".akhw-hint").hidden = true; + alert.querySelector(".akhw-alert-foot").hidden = true; + alert.addEventListener("click", (e) => { + const b = e.target.closest("[data-decide]"); + if (!b) return; + S.decision = b.dataset.decide; + S.u = POST[kindOf(S.decision)]; + S.phase = "end"; + root.dataset.outcome = outcomeOf(S.decision); + if (render) render(); + }); + if (!render) { + const img = $(".akhw-poster img"); + if (img) img.loading = "eager"; + } + } +} diff --git a/site-src/how/layout.js b/site-src/how/layout.js new file mode 100644 index 0000000..f28d0ad --- /dev/null +++ b/site-src/how/layout.js @@ -0,0 +1,85 @@ +// Where everything stands, for a wide screen or a phone held upright, and +// the paths the cards, the request, the key and the result travel along. +import * as THREE from "three"; + +const V3 = (x, y, z) => new THREE.Vector3(x, y, z); +// contact shadows fall away from the window (back left) +const CAST = V3(0.16, 0, 0.12); + +export function layoutScene(W, kind) { + const L = W.L; + const wide = kind === "wide"; + const A = wide ? V3(-3.05, 1.32, 0.9) : V3(-0.92, 1.0, 1.9); + const V = wide ? V3(0, 1.26, -2.3) : V3(0.02, 1.58, -2.5); + const P = wide ? V3(3.05, 0.62, 0.9) : V3(1.0, 0.48, 2.3); + const sA = wide ? 1 : 0.66, sV = wide ? 1 : 0.8, sP = wide ? 1 : 0.68; + const Wp = P.clone().add((wide ? V3(0, 1.62, -0.32) : V3(0.2, 1.4, -1.5)).multiplyScalar(sP)); + Object.assign(L, { kind, A, V, P, W: Wp, sA, sV, sP }); + + const onDesk = (m, p, s, sx, sz, lift = 0) => { + m.position.set(p.x + CAST.x * p.y, 0.003 + lift, p.z + CAST.z * p.y); + m.scale.set(sx * s, sz * s, 1); + }; + W.agent.position.copy(A); W.agent.scale.setScalar(sA); + onDesk(W.agentShadow, A, sA, 3.2, 0.95); + onDesk(W.agentLight, A, sA, 2.6, 0.7, 0.001); + W.agentLight.position.x += 0.2 * sA; + W.agentLight.position.z += 0.35 * sA; + W.vault.position.copy(V); W.vault.scale.setScalar(sV); + onDesk(W.vaultShadow, V, sV, 2.0, 1.0); + onDesk(W.vaultTint, V, sV, 1.9, 1.1, 0.001); + W.vaultTint.position.z += 0.3 * sV; + W.prog.position.copy(P); W.prog.scale.setScalar(sP); + onDesk(W.progShadow, P, sP, 2.2, 1.6); + W.site.position.copy(Wp); W.site.scale.setScalar(sP); + onDesk(W.siteShadow, Wp, sP, 1.9, 0.5); + [W.card1, W.card2, W.slip].forEach((m) => m.scale.setScalar(wide ? 1 : 0.72)); + L.cardScale = wide ? 1.45 : 0.9; + W.chip.scale.setScalar(wide ? 1 : 0.7); + W.copy.scale.setScalar(wide ? 1.15 : 0.8); + W.dust.material.size = wide ? 0.03 : 0.022; + + const mid = (a, b, t = 0.5) => a.clone().lerp(b, t); + const off = (p, s, x, y, z) => p.clone().add(V3(x, y, z).multiplyScalar(s)); + const kh = W.keyhole; + L.keyholeW = off(P, sP, kh.x, kh.y, kh.z); + L.catPath = new THREE.CatmullRomCurve3([off(V, sV, -0.55, 0.35, 0.45), mid(A, V).add(V3(-0.1, 0.7 * sV, wide ? 1.5 : 0.9)), off(A, sA, 0.55, 0.25, 0.4)], false, "centripetal"); + L.reqPath = new THREE.CatmullRomCurve3([off(A, sA, 1.05, 0.5, 0.05), mid(A, V).add(V3(0.35, 1.2 * sV, 0.2)), off(V, sV, -0.6, 0.62, 0.4)], false, "centripetal"); + L.keyPath = new THREE.CatmullRomCurve3( + [ + off(V, sV, 0.08, 0.0, 1.0), + off(V, sV, 0.75, 0.35, 1.45), + mid(V, P).add(V3(0.1, 0.55 * sV, wide ? 1.55 : 1.2)), + L.keyholeW.clone().add(V3(-0.55, 0.32, 0.7).multiplyScalar(sP)), + L.keyholeW.clone().add(V3(0, 0.05, 0.26).multiplyScalar(sP)), + L.keyholeW.clone().add(V3(0, 0, 0.015).multiplyScalar(sP)), + ], + false, + "centripetal" + ); + L.outPath = new THREE.CatmullRomCurve3([off(P, sP, -0.8, 0.12, 0.45), mid(P, A).add(V3(0, 0.3, wide ? 1.7 : 1.0)), off(A, sA, 1.1, -0.25, 0.3)], false, "centripetal"); + for (const [m, path] of [[W.reqThread, L.reqPath], [W.keyThread, L.keyPath], [W.outThread, L.outPath]]) { + m.geometry.dispose(); + m.geometry = new THREE.TubeGeometry(path, m.userData.segs, m.userData.radius * (wide ? 1 : 0.8), m.userData.radial, false); + m.geometry.setDrawRange(0, 0); + } + + W.copyGlow.scale.setScalar(wide ? 1.1 : 0.75); + L.slipRest = V3(V.x - 0.05 * sV, 0.012, V.z + 1.25 * sV); + L.slipRestQ = new THREE.Quaternion().setFromEuler(new THREE.Euler(-Math.PI / 2, 0, 0.12)); + W.slipShadow.position.set(L.slipRest.x + 0.02, 0.004, L.slipRest.z + 0.03); + W.slipShadow.rotation.z = -0.12; + W.slipShadow.scale.set(0.95 * (wide ? 1 : 0.72) * 1.2, 0.58 * (wide ? 1 : 0.72) * 1.2, 1); + + // framing sphere for the whole cast + const parts = [[A, 1.55 * sA], [V, 1.15 * sV], [P, 0.95 * sP], [Wp, 0.95 * sP]]; + const box3 = new THREE.Box3(); + parts.forEach(([p, r]) => box3.expandByPoint(p.clone().addScalar(r)).expandByPoint(p.clone().subScalar(r))); + L.C = box3.getCenter(new THREE.Vector3()); + L.R = Math.max(...parts.map(([p, r]) => p.distanceTo(L.C) + r)) * (wide ? 0.74 : 0.86); + W.uFloor.uCenter.value.copy(L.C); + W.uFloor.uRad.value.set(wide ? 6.4 : 3.8, wide ? 14 : 9); + // the window patch falls across the AI's side of the desk, from the back left + W.uFloor.uWinO.value.set(wide ? A.x + 1.5 : A.x + 0.5, wide ? A.z - 1.3 : A.z - 1.4); + W.uFloor.uWinS.value.set(wide ? 1.9 : 1.15, wide ? 1.35 : 0.95); +} diff --git a/site-src/how/materials.js b/site-src/how/materials.js new file mode 100644 index 0000000..c241673 --- /dev/null +++ b/site-src/how/materials.js @@ -0,0 +1,192 @@ +// Materials for the morning desk. None of them needs a second render of +// the scene: the glass is a premultiplied layer (a Fresnel-weighted body +// plus the environment's reflections), the desk is lit by a procedural +// window, and the delivered key dissolves in its own shader. +import * as THREE from "three"; + +// Glass without a transmission pass. Light reflected off the surface is +// added on top of whatever is behind it; the body itself is a thin tint +// that thickens toward grazing angles, the way the edges of a real slab of +// glass go dark and green. `edgeColor` pulls that body toward a fixed +// colour so the rim reads on a white page even where the light is flat. +export function glassMaterial({ + color = 0xffffff, + edgeColor = 0x6f8a86, + edgeMix = 0.6, + specEdge = 0, + base = 0.04, + edge = 0.6, + power = 2.4, + roughness = 0.04, + envMapIntensity = 1.4, + clearcoat = 0, + clearcoatRoughness = 0.06, + side = THREE.FrontSide, + key = "glass", +} = {}) { + const Physical = clearcoat > 0 ? THREE.MeshPhysicalMaterial : THREE.MeshStandardMaterial; + const m = new Physical({ color, roughness, metalness: 0, envMapIntensity, transparent: true, premultipliedAlpha: true, depthWrite: false, side }); + if (clearcoat > 0) Object.assign(m, { clearcoat, clearcoatRoughness }); + const u = { + uBase: { value: base }, + uEdge: { value: edge }, + uPow: { value: power }, + uEdgeColor: { value: new THREE.Color(edgeColor) }, + uEdgeMix: { value: edgeMix }, + uSpecEdge: { value: specEdge }, + }; + m.userData.u = u; + m.onBeforeCompile = (sh) => { + Object.assign(sh.uniforms, u); + sh.fragmentShader = sh.fragmentShader + .replace("#include ", "#include \nuniform float uBase, uEdge, uPow, uEdgeMix, uSpecEdge;\nuniform vec3 uEdgeColor;") + .replace( + "#include ", + `float gNV = clamp(abs(dot(normal, normalize(vViewPosition))), 0.0, 1.0); +float gF = pow(1.0 - gNV, uPow); +// what the surface reflects is light the background no longer sends through +float gR = 0.04 + 0.96 * pow(1.0 - gNV, 5.0); +float gA = clamp(uBase + uEdge * gF, 0.0, 1.0); +vec3 gBody = mix(totalDiffuse, uEdgeColor, uEdgeMix); +// thick glass seen edge-on shows its own dark body more than the room +vec3 gSpec = max(outgoingLight - totalDiffuse, vec3(0.0)) * (1.0 - uSpecEdge * gF); +gl_FragColor = vec4(gBody * gA + gSpec, clamp(gA + gR * (1.0 - gA) * (1.0 - uSpecEdge * gF), 0.0, 1.0));` + ) + .replace("#include ", ""); + }; + m.customProgramCacheKey = () => `akhw-${key}`; + return m; +} + +// A decal drawn in the opaque pass with alpha blending: it lands after the +// desk and before every transparent object, so it never needs sorting. +export function decalMaterial(params) { + return new THREE.MeshBasicMaterial({ + transparent: false, + blending: THREE.CustomBlending, + blendSrc: THREE.SrcAlphaFactor, + blendDst: THREE.OneMinusSrcAlphaFactor, + blendSrcAlpha: THREE.OneFactor, + blendDstAlpha: THREE.OneMinusSrcAlphaFactor, + depthWrite: false, + toneMapped: false, + ...params, + }); +} + +// The desk: oiled black walnut in early light. The scan is used in its own +// colour; a soft window falls across it with a satin sheen; and it fades +// into the page's white beyond the cast (all in one cheap unlit shader). +export function deskMaterial() { + const m = new THREE.MeshBasicMaterial({ color: 0xffffff, toneMapped: false }); + const u = { + uCenter: { value: new THREE.Vector3() }, + uRad: { value: new THREE.Vector2(5, 11) }, + uWhite: { value: 0 }, + uAsh: { value: new THREE.Color("#7a5643") }, + uGrain: { value: new THREE.Color("#4a3124") }, + uGain: { value: 1.12 }, + uSheen: { value: 0.07 }, + uShade: { value: 0.86 }, + uSun: { value: 0.5 }, + uWinO: { value: new THREE.Vector2(-1.2, -1.0) }, + uWinS: { value: new THREE.Vector2(3.6, 2.6) }, + uWinA: { value: 0.62 }, + uHasMap: { value: 0 }, + uView: { value: new THREE.Vector2(1, 1) }, + }; + m.userData.u = u; + m.onBeforeCompile = (sh) => { + Object.assign(sh.uniforms, u); + sh.vertexShader = sh.vertexShader + .replace("#include ", "#include \nvarying vec3 vWp;") + .replace("#include ", "#include \nvWp = (modelMatrix * vec4(transformed, 1.0)).xyz;"); + sh.fragmentShader = sh.fragmentShader + .replace( + "#include ", + `#include +varying vec3 vWp; +uniform vec3 uCenter, uAsh, uGrain; +uniform vec2 uRad, uWinO, uWinS, uView; +uniform float uWhite, uShade, uSun, uWinA, uHasMap, uGain, uSheen; +float akBand(float x, float h, float s) { return smoothstep(-h - s, -h + s, x) * (1.0 - smoothstep(h - s, h + s, x)); } +float akBars(float x, float pitch, float bar, float s) { float d = abs(fract(x / pitch + 0.5) - 0.5) * pitch; return smoothstep(bar - s, bar + s, d); }` + ) + .replace( + "#include ", + `#ifdef USE_MAP + vec4 akT = texture2D(map, vMapUv); + diffuseColor.rgb = mix(mix(uGrain, uAsh, 0.5), akT.rgb * uGain, uHasMap); +#else + diffuseColor.rgb = mix(uGrain, uAsh, 0.82); +#endif + // a tall window to the back left: four soft panes, then a broad falloff + float akC = cos(uWinA), akS = sin(uWinA); + vec2 akQ = mat2(akC, -akS, akS, akC) * (vWp.xz - uWinO); + akQ.x += akQ.y * 0.32; + float akWin = akBand(akQ.x, uWinS.x, 0.45) * akBand(akQ.y, uWinS.y, 0.55); + akWin *= akBars(akQ.x, uWinS.x, 0.1, 0.16) * akBars(akQ.y + uWinS.y, uWinS.y, 0.08, 0.16); + float akFall = 1.0 - smoothstep(-6.0, 9.0, dot(vWp.xz - uWinO, vec2(0.55, 0.83))); + // as an ending closes the window light thins out with the room + diffuseColor.rgb *= uShade + (uSun * akWin + 0.06 * akFall) * (1.0 - uWhite); + // hand-rubbed oil: the window reads as a soft satin sheen on the wood + diffuseColor.rgb += vec3(1.0, 0.96, 0.9) * uSheen * akWin * (1.0 - uWhite);` + ) + .replace( + "#include ", + `#include +float akD = length((vWp.xz - uCenter.xz) * vec2(0.8, 1.15)); +float akR0 = mix(uRad.x, uRad.x * 0.2, uWhite), akR1 = mix(uRad.y, uRad.x * 0.85, uWhite); +float akFar = smoothstep(akR0, akR1, akD); +// the desk runs off both sides of the window; only the top and bottom of +// the frame soften into the page +float akY = gl_FragCoord.y / uView.y; +float akEdge = 1.0 - smoothstep(0.0, 0.12, akY) * (1.0 - smoothstep(0.86, 1.0, akY)); +float akW = max(akFar, akEdge); +// a whisper of noise keeps the long fade free of bands +akW = clamp(akW + (fract(sin(dot(gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453) - 0.5) / 255.0, 0.0, 1.0); +gl_FragColor.rgb = mix(gl_FragColor.rgb, vec3(1.0), akW);` + ); + }; + m.customProgramCacheKey = () => "akhw-desk"; + return m; +} + +// The delivered copy of the key burns away from its tip: noise discard plus +// a hot edge. +export function dissolveMaterial(base) { + const uDis = { value: 0 }; + const m = base.clone(); + m.onBeforeCompile = (sh) => { + sh.uniforms.uDis = uDis; + sh.vertexShader = sh.vertexShader + .replace("#include ", "#include \nvarying vec3 vKeyPos;") + .replace("#include ", "#include \nvKeyPos = position;"); + sh.fragmentShader = sh.fragmentShader + .replace( + "#include ", + `#include +varying vec3 vKeyPos; +uniform float uDis; +float kh(vec3 p){ p = fract(p*0.3183099+.1); p*=17.0; return fract(p.x*p.y*p.z*(p.x+p.y+p.z)); } +float kn(vec3 x){ vec3 i=floor(x); vec3 f=fract(x); f=f*f*(3.0-2.0*f); + return mix(mix(mix(kh(i+vec3(0,0,0)),kh(i+vec3(1,0,0)),f.x),mix(kh(i+vec3(0,1,0)),kh(i+vec3(1,1,0)),f.x),f.y), + mix(mix(kh(i+vec3(0,0,1)),kh(i+vec3(1,0,1)),f.x),mix(kh(i+vec3(0,1,1)),kh(i+vec3(1,1,1)),f.x),f.y),f.z); }` + ) + .replace( + "#include ", + `#include +float kN = kn(vKeyPos*26.0)*0.65 + kn(vKeyPos*61.0)*0.35; +float kD = uDis*1.15 - 0.08 + (vKeyPos.x+0.5)*0.25; +if (kN < kD) discard; +float kEdge = 1.0 - smoothstep(kD, kD+0.07, kN);` + ) + .replace( + "#include ", + `#include +totalEmissiveRadiance += vec3(1.0, 0.42, 0.2) * kEdge * step(0.001, uDis) * 2.2;` + ); + }; + m.customProgramCacheKey = () => "akhw-dissolve"; + return { mat: m, uDis }; +} diff --git a/site-src/how/package-lock.json b/site-src/how/package-lock.json new file mode 100644 index 0000000..0401b7a --- /dev/null +++ b/site-src/how/package-lock.json @@ -0,0 +1,92 @@ +{ + "name": "askkey-how-it-works", + "version": "2.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "askkey-how-it-works", + "version": "2.0.0", + "license": "UNLICENSED", + "devDependencies": { + "esbuild": "0.25.10", + "three": "0.186.0" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz", + "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/esbuild": { + "version": "0.25.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz", + "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.10", + "@esbuild/android-arm": "0.25.10", + "@esbuild/android-arm64": "0.25.10", + "@esbuild/android-x64": "0.25.10", + "@esbuild/darwin-arm64": "0.25.10", + "@esbuild/darwin-x64": "0.25.10", + "@esbuild/freebsd-arm64": "0.25.10", + "@esbuild/freebsd-x64": "0.25.10", + "@esbuild/linux-arm": "0.25.10", + "@esbuild/linux-arm64": "0.25.10", + "@esbuild/linux-ia32": "0.25.10", + "@esbuild/linux-loong64": "0.25.10", + "@esbuild/linux-mips64el": "0.25.10", + "@esbuild/linux-ppc64": "0.25.10", + "@esbuild/linux-riscv64": "0.25.10", + "@esbuild/linux-s390x": "0.25.10", + "@esbuild/linux-x64": "0.25.10", + "@esbuild/netbsd-arm64": "0.25.10", + "@esbuild/netbsd-x64": "0.25.10", + "@esbuild/openbsd-arm64": "0.25.10", + "@esbuild/openbsd-x64": "0.25.10", + "@esbuild/openharmony-arm64": "0.25.10", + "@esbuild/sunos-x64": "0.25.10", + "@esbuild/win32-arm64": "0.25.10", + "@esbuild/win32-ia32": "0.25.10", + "@esbuild/win32-x64": "0.25.10" + } + }, + "node_modules/playwright-core": { + "version": "1.56.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz", + "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==", + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/three": { + "version": "0.186.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.186.0.tgz", + "integrity": "sha512-cr/fIM2ddMSVbYVgkfD4jLJv7Fh/8ZTjvo+7gQeSVGUZHxpx9FDwoL5iC7hUz/LiRA8wMbqfnb90xKfm1/HHkQ==", + "license": "MIT" + } + } +} diff --git a/site-src/how/package.json b/site-src/how/package.json new file mode 100644 index 0000000..df412c4 --- /dev/null +++ b/site-src/how/package.json @@ -0,0 +1,17 @@ +{ + "name": "askkey-how-it-works", + "private": true, + "version": "2.0.0", + "description": "Ask Key \"How it works\" film for the website. Source for site/how/how.js.", + "license": "MIT", + "type": "module", + "scripts": { + "build": "esbuild how.src.js --bundle --format=esm --minify --target=es2020,safari15 --legal-comments=none --banner:js=\"/*! Ask Key: How it works. Includes three.js r186, MIT License, Copyright 2010-2026 three.js authors; full text in THREE-LICENSE.txt next to this file. */\" --outfile=../../site/how/how.js && node stamp.mjs", + "license": "cp node_modules/three/LICENSE ../../site/how/THREE-LICENSE.txt", + "stamp": "node stamp.mjs" + }, + "devDependencies": { + "esbuild": "0.25.10", + "three": "0.186.0" + } +} diff --git a/site-src/how/quality.js b/site-src/how/quality.js new file mode 100644 index 0000000..1fcde10 --- /dev/null +++ b/site-src/how/quality.js @@ -0,0 +1,73 @@ +// Resolution is the one knob that matters: every material here is cheap +// per pixel, so frame cost scales with the drawing buffer. The pixel ratio +// starts capped (1.5, or 1 on a software renderer), is set from a short +// timed benchmark of the first real frames, and steps down if the film +// starts dropping frames. It never steps back up above what the benchmark +// allowed, so it cannot oscillate. +export function probeGPU() { + let gl = null; + try { + gl = document.createElement("canvas").getContext("webgl2"); + } catch (e) { + gl = null; + } + if (!gl) return null; + const dbg = gl.getExtension("WEBGL_debug_renderer_info"); + const name = String(dbg ? gl.getParameter(dbg.UNMASKED_RENDERER_WEBGL) : gl.getParameter(gl.RENDERER)); + gl.getExtension("WEBGL_lose_context")?.loseContext(); + return { name, software: /swiftshader|llvmpipe|softpipe|software|basic render/i.test(name) }; +} + +const FLOOR = 0.5; // never render below half the CSS resolution +const BUDGET = 7.5; // ms of synchronous render cost we accept per frame + +export function createQuality(gpu, params) { + const device = Math.max(1, window.devicePixelRatio || 1); + const forced = params.has("dpr") ? Number(params.get("dpr")) : 0; + const cap = forced || Math.min(device, gpu.software ? 1 : 1.5); + const q = { dpr: cap, max: cap, benchmarked: !!forced || params.has("nobench"), changed: false }; + let win = [], hold = 0, smooth = 0; + + // `sample(ms)` is called with the synchronous cost of each of the first + // frames rendered with a forced GPU sync; three samples decide. + const bench = []; + q.sample = (ms) => { + if (q.benchmarked) return false; + bench.push(ms); + // the first frame carries one-off uploads, so the next two decide; a + // hopeless frame on a slow machine is enough on its own + if (bench.length < 3 && ms < 250) return true; + const cost = bench.length >= 3 ? Math.min(bench[1], bench[2]) : ms; + q.benchmarked = true; + if (cost > BUDGET) { + const next = Math.max(FLOOR, Math.round(q.dpr * Math.sqrt(BUDGET / cost) * 20) / 20); + if (next < q.dpr - 0.01) { + q.dpr = q.max = next; + q.changed = true; + } + } + return false; + }; + + // `frame(dt)` is called every played frame with the interval since the + // last one, in seconds. Returns true when the resolution changed. + q.frame = (dt) => { + if (forced || dt <= 0 || dt > 0.25) return false; + smooth = smooth ? smooth * 0.9 + dt * 0.1 : dt; + if (hold > 0) { hold--; return false; } + win.push(dt); + if (win.length < 40) return false; + const sorted = win.slice().sort((a, b) => a - b); + win = []; + const p75 = sorted[Math.floor(sorted.length * 0.75)]; + if (p75 > 0.0205 && q.dpr > FLOOR) { + // a quarter fewer pixels each step + q.dpr = q.max = Math.max(FLOOR, Math.round(q.dpr * 0.87 * 20) / 20); + hold = 30; // let the new size settle before judging again + return true; + } + return false; + }; + q.fps = () => (smooth ? 1 / smooth : 0); + return q; +} diff --git a/site-src/how/rig.js b/site-src/how/rig.js new file mode 100644 index 0000000..79297fb --- /dev/null +++ b/site-src/how/rig.js @@ -0,0 +1,112 @@ +// The camera: one unbroken move. A key frame names what to look at, from +// which direction, and how big a sphere around it must fit in the frame. +// Distance follows from the viewport, so the same move recomposes itself +// for a phone held upright. +import * as THREE from "three"; +import { PRE, POST, clamp, smooth } from "./timing.js"; + +const kf = (t, target, dir, r) => ({ t, target, dir: new THREE.Vector3(...dir).normalize(), r }); +const lerpV = (a, b, t) => a.clone().lerp(b, t); + +export function buildRails(L) { + const { A, V, P, W: Wp, C, R, sA, sV, sP } = L; + const v = (x, y, z) => new THREE.Vector3(x, y, z); + const at = (p, s, x, y, z) => p.clone().add(v(x, y, z).multiplyScalar(s)); + const tall = L.kind === "tall"; + const k = tall ? 1.15 : 1; + const gate = kf(PRE, v(V.x, V.y * 0.55, V.z + 0.55 * sV), [0, 0.3, 1], 1.5 * sV * k); + const pre = [ + kf(0, C.clone().add(v(0, 0.15, 0)), [0.02, tall ? 1.0 : 0.55, 1], R * (tall ? 0.92 : 1.04)), + kf(1.4, C.clone().add(v(-0.2, 0.1, 0)), [0.08, 0.48, 1], R * 0.92), + kf(3.0, at(A, sA, 0.05, 0.08, 0), [0.16, 0.1, 1], 1.18 * sA * k), + kf(4.2, at(A, sA, 0.12, 0.02, 0), [0.24, 0.13, 1], 1.3 * sA * k), + kf(6.0, lerpV(A, V, 0.48).add(v(0, 0.15, 0.2)), [0.22, 0.42, 1], tall ? R * 0.78 : 2.95), + kf(8.0, lerpV(A, V, 0.4).add(v(0, 0.05, 0.3)), [0.05, 0.36, 1], tall ? R * 0.74 : 2.75), + kf(9.8, at(A, sA, 0.55, 0.15, 0), [0.42, 0.22, 1], 1.75 * sA * k), + kf(12.0, lerpV(A, V, 0.7).add(v(0, 0.45 * sV, 0)), [-0.2, 0.22, 1], tall ? R * 0.62 : 1.95), + kf(13.3, v(V.x, V.y * 0.62, V.z + 0.45 * sV), [-0.06, 0.26, 1], 1.55 * sV * k), + gate, + ]; + const allow = [ + { ...gate, t: 0 }, + kf(0.9, v(V.x, V.y * 0.5, V.z + 0.7 * sV), [0.04, 0.42, 1], 1.25 * sV * k), + kf(2.2, at(V, sV, 0.25, 0.1, 0.6), [0.4, 0.14, 1], 1.15 * sV * k), + kf(3.6, lerpV(V, P, 0.55).add(v(0.2, 0.75 * sV, 0.6)), [0.12, 0.38, 1], tall ? R * 0.7 : 2.35), + kf(4.9, at(L.keyholeW, 1, 0.1 * sP, 0.02, 0.3 * sP), [-0.5, 0.16, 1], 0.92 * sP * k), + kf(6.2, at(L.keyholeW, 1, 0.35 * sP, 0.05, 0.15 * sP), [-0.36, 0.12, 1], 1.0 * sP * k), + kf(7.5, lerpV(P, Wp, 0.62), [-0.3, 0.18, 1], 1.55 * sP * k), + kf(9.0, lerpV(P, A, 0.5).add(v(0, 0.35, 0.6)), [0, 0.32, 1], tall ? R * 0.85 : 3.6), + kf(10.4, at(A, sA, 0.15, 0.02, 0), [0.2, 0.12, 1], 1.32 * sA * k), + kf(11.6, at(A, sA, 0.2, 0.05, 0), [0.28, 0.18, 1], 1.45 * sA * k), + kf(14.4, C.clone().add(v(0, 0.12, 0)), [0.0, tall ? 1.15 : 0.6, 1], R * (tall ? 0.94 : 1.0)), + kf(POST.allow, C.clone().add(v(0, 0.12, 0)), [0.03, tall ? 1.12 : 0.58, 1], R * (tall ? 0.95 : 1.01)), + ]; + const deny = [ + { ...gate, t: 0 }, + kf(1.3, at(V, sV, 0, 0.05, 0), [0.12, 0.16, 1], 1.4 * sV * k), + kf(3.0, at(A, sA, 0.15, 0.02, 0), [0.22, 0.13, 1], 1.32 * sA * k), + kf(4.4, at(A, sA, 0.2, 0.05, 0), [0.28, 0.18, 1], 1.45 * sA * k), + kf(7.0, C.clone().add(v(0, 0.12, 0)), [0.0, tall ? 1.15 : 0.6, 1], R * (tall ? 0.94 : 1.0)), + kf(POST.deny, C.clone().add(v(0, 0.12, 0)), [0.03, tall ? 1.12 : 0.58, 1], R * (tall ? 0.95 : 1.01)), + ]; + return { pre: rail(pre), allow: rail(allow), deny: rail(deny) }; +} + +// Catmull-Rom through the key frames, with a monotone time warp so the +// camera never stops between frames: one continuous move. `at` writes into +// a shot object it owns, so a frame allocates nothing. +function rail(keys) { + const n = keys.length; + const tgt = new THREE.CatmullRomCurve3(keys.map((k) => k.target), false, "centripetal"); + const dir = new THREE.CatmullRomCurve3(keys.map((k) => k.dir.clone()), false, "catmullrom", 0.5); + const ts = keys.map((k) => k.t), rs = keys.map((k) => Math.log(k.r)); + // Fritsch–Carlson slopes for index(t) + const d = []; + for (let i = 0; i < n - 1; i++) d.push(1 / (ts[i + 1] - ts[i])); + const m = [d[0]]; + for (let i = 1; i < n - 1; i++) m.push(d[i - 1] * d[i] <= 0 ? 0 : (2 * d[i - 1] * d[i]) / (d[i - 1] + d[i])); + m.push(d[n - 2]); + m[0] *= 0.15; // ease in from rest + const idx = (t) => { + if (t <= ts[0]) return 0; + if (t >= ts[n - 1]) return n - 1; + let i = 0; + while (t > ts[i + 1]) i++; + const h = ts[i + 1] - ts[i], s = (t - ts[i]) / h; + const h00 = 2 * s ** 3 - 3 * s ** 2 + 1, h10 = s ** 3 - 2 * s ** 2 + s, h01 = -2 * s ** 3 + 3 * s ** 2, h11 = s ** 3 - s ** 2; + return h00 * i + h10 * h * m[i] + h01 * (i + 1) + h11 * h * m[i + 1]; + }; + const rAt = (x) => { + const i = Math.min(n - 2, Math.floor(x)), f = x - i; + return Math.exp(rs[i] + (rs[i + 1] - rs[i]) * smooth(f)); + }; + const shot = { target: new THREE.Vector3(), dir: new THREE.Vector3(), r: 1 }; + return { + end: ts[n - 1], + at(t) { + const x = clamp(idx(t), 0, n - 1); + const u = x / (n - 1); + tgt.getPoint(u, shot.target); + dir.getPoint(u, shot.dir).normalize(); + shot.r = rAt(x); + return shot; + }, + }; +} + +const _d = new THREE.Vector3(); +export function placeCamera(camera, shot, clock, pointer, drift) { + const fovV = THREE.MathUtils.degToRad(camera.fov); + // An upright stage wider than a phone's (a tablet held upright) is framed + // as if it were phone-shaped, so the cast keeps clear of every edge. + const aspect = camera.aspect < 1.02 ? Math.min(camera.aspect, 0.75) : camera.aspect; + const fovH = 2 * Math.atan(Math.tan(fovV / 2) * aspect); + const lim = Math.min(fovV, fovH); + const dist = shot.r / Math.sin(lim / 2); + const d = _d.copy(shot.dir); + d.x += drift * (0.025 * Math.sin(clock * 0.23) + pointer.sx * 0.07); + d.y += drift * (0.018 * Math.sin(clock * 0.17 + 1.3) - pointer.sy * 0.045); + d.normalize(); + camera.position.copy(shot.target).addScaledVector(d, dist); + camera.lookAt(shot.target); +} diff --git a/site-src/how/room.js b/site-src/how/room.js new file mode 100644 index 0000000..63fef0b --- /dev/null +++ b/site-src/how/room.js @@ -0,0 +1,66 @@ +// The room the objects reflect: white walls, a pale desk, and a tall window +// to the back left, the same window whose light falls across the desk. It +// is rendered once into a prefiltered environment map at load; nothing in +// it is drawn per frame. +import * as THREE from "three"; + +export function daylightEnvironment(renderer) { + const room = new THREE.Scene(); + const box = new THREE.BoxGeometry(1, 1, 1); + const flat = (color, scale = 1) => { + const m = new THREE.MeshBasicMaterial({ color, side: THREE.BackSide, toneMapped: false }); + m.color.multiplyScalar(scale); + return m; + }; + const shell = new THREE.Mesh(box, [ + flat(0xeceae6, 0.95), // +x wall + flat(0xeceae6, 1.05), // -x wall (the window wall) + flat(0xf6f5f2, 1.1), // ceiling + flat(0xd8cbb9, 0.75), // the desk and floor below + flat(0xeceae6, 0.9), // +z + flat(0xeceae6, 1.0), // -z + ]); + shell.scale.set(22, 9, 22); + shell.position.y = 3; + room.add(shell); + // the window: four tall panes of soft sky, brighter than anything else + const pane = new THREE.MeshBasicMaterial({ color: 0xf4f8ff, side: THREE.DoubleSide, toneMapped: false }); + pane.color.multiplyScalar(4.2); + const pg = new THREE.PlaneGeometry(1, 1); + for (let i = 0; i < 2; i++) for (let j = 0; j < 2; j++) { + const p = new THREE.Mesh(pg, pane); + p.rotation.y = Math.PI / 2; + p.scale.set(2.3, 2.5, 1); + p.position.set(-10.9, 2.6 + j * 2.7, -5.2 + i * 2.5); + room.add(p); + } + // dark things across the room (a shelf, a doorway, the far end of the + // desk): glass and lacquer need something dark to reflect, or their edges + // vanish into a white room + const dark = new THREE.MeshBasicMaterial({ color: 0x2a2b2e, side: THREE.DoubleSide, toneMapped: false }); + [ + [10.9, 2.2, -2.0, -Math.PI / 2, 5.5, 3.2], + [10.9, 2.8, 4.5, -Math.PI / 2, 2.4, 5.0], + [-3.5, 2.4, 10.9, Math.PI, 6.0, 2.6], + [4.5, 1.6, -10.9, 0, 4.0, 2.0], + ].forEach(([x, y, z, ry, w, h]) => { + const f = new THREE.Mesh(pg, dark); + f.position.set(x, y, z); + f.rotation.y = ry; + f.scale.set(w, h, 1); + room.add(f); + }); + // a little light from the ceiling, as in a real room + const lamp = new THREE.Mesh(pg, new THREE.MeshBasicMaterial({ color: 0xffffff, side: THREE.DoubleSide, toneMapped: false })); + lamp.material.color.multiplyScalar(1.6); + lamp.rotation.x = Math.PI / 2; + lamp.scale.set(6, 4, 1); + lamp.position.set(1, 7.4, 2); + room.add(lamp); + + const pmrem = new THREE.PMREMGenerator(renderer); + const env = pmrem.fromScene(room, 0.03, 0.1, 60).texture; + pmrem.dispose(); + room.traverse((o) => o.geometry && o.geometry.dispose()); + return env; +} diff --git a/site-src/how/scene.js b/site-src/how/scene.js new file mode 100644 index 0000000..3383708 --- /dev/null +++ b/site-src/how/scene.js @@ -0,0 +1,309 @@ +// The four things on stage — the AI (a glass block with its transcript +// sealed inside), Ask Key (a frosted vault in the shape of the app icon, with +// the vermilion keys inside), the program ./deploy.sh (a graphite box with a +// keyhole) and the website it publishes — plus the paper slips and the +// threads that connect them, on an oiled walnut desk in morning light. +// Vermilion is reserved for the secret. +import * as THREE from "three"; +import { RoundedBoxGeometry } from "three/examples/jsm/geometries/RoundedBoxGeometry.js"; +import { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js"; +import { canvasTexture, drawCard, drawChip, drawSite, drawProgramFace, shadowTexture, dotTexture, glowTexture, blurredShapesTexture } from "./textures.js"; +import { glassMaterial, decalMaterial, deskMaterial, dissolveMaterial } from "./materials.js"; +import { createTranscript } from "./transcript.js"; +import { layoutScene } from "./layout.js"; +import { daylightEnvironment } from "./room.js"; + +export const ZHU = new THREE.Color("#b8281e"); +export const BG = "#ffffff"; +const V3 = (x, y, z) => new THREE.Vector3(x, y, z); +const V2 = (x, y) => new THREE.Vector2(x, y); + +function roundedPolygon(points, r) { + const s = new THREE.Shape(); + const n = points.length; + for (let i = 0; i < n; i++) { + const p = points[i], a = points[(i - 1 + n) % n], b = points[(i + 1) % n]; + const da = a.clone().sub(p).normalize().multiplyScalar(r); + const db = b.clone().sub(p).normalize().multiplyScalar(r); + const p1 = p.clone().add(da), p2 = p.clone().add(db); + if (i === 0) s.moveTo(p1.x, p1.y); else s.lineTo(p1.x, p1.y); + s.quadraticCurveTo(p.x, p.y, p2.x, p2.y); + } + s.closePath(); + return s; +} + +function capsulePath(cx, cy, w, h) { + const p = new THREE.Path(); + const r = h / 2; + p.moveTo(cx - w / 2 + r, cy - r); + p.lineTo(cx + w / 2 - r, cy - r); + p.absarc(cx + w / 2 - r, cy, r, -Math.PI / 2, Math.PI / 2, false); + p.lineTo(cx - w / 2 + r, cy + r); + p.absarc(cx - w / 2 + r, cy, r, Math.PI / 2, Math.PI * 1.5, false); + return p; +} + +// Key along +x: tip at the origin, bow at x = -0.5 (like the app icon's key). +function keyShapes() { + const s = 0.13; + const bow = roundedPolygon([V2(-0.5 - s, 0), V2(-0.5, -s), V2(-0.5 + s, 0), V2(-0.5, s)], 0.05); + const hole = new THREE.Path(); + hole.absarc(-0.5, 0, 0.043, 0, Math.PI * 2, true); + bow.holes.push(hole); + const shaft = roundedPolygon([V2(-0.42, -0.034), V2(0, -0.034), V2(0, 0.034), V2(-0.42, 0.034)], 0.02); + const t1 = roundedPolygon([V2(-0.11, -0.13), V2(-0.055, -0.13), V2(-0.055, -0.02), V2(-0.11, -0.02)], 0.018); + const t2 = roundedPolygon([V2(-0.035, -0.105), V2(0, -0.105), V2(0, -0.02), V2(-0.035, -0.02)], 0.014); + return [bow, shaft, t1, t2]; +} + +export function keyGeometry() { + const ex = { depth: 0.05, bevelEnabled: true, bevelThickness: 0.014, bevelSize: 0.012, bevelSegments: 3, curveSegments: 20 }; + const g = mergeGeometries(keyShapes().map((sh) => new THREE.ExtrudeGeometry(sh, ex))); + g.translate(0, 0, -0.025); + g.computeVertexNormals(); + return g; +} + +export function buildScene(renderer, I, paper, assets = {}) { + const scene = new THREE.Scene(); + scene.environment = daylightEnvironment(renderer); + scene.environmentIntensity = 1.0; + + // Morning: cool daylight from a window to the back left, a white room + // bouncing light back. No shadow maps; contact shadows are decals. + const sky = new THREE.HemisphereLight(0xf3f7ff, 0xe6dccf, 0.9); + const sun = new THREE.DirectionalLight(0xf2f6ff, 2.2); + sun.position.set(-5, 7, -4); + scene.add(sky, sun); + + // Images arrive after the programs are compiled. Each material starts + // with a 1×1 stand-in so its program already expects a texture, and the + // real one is swapped in without a recompile mid-film. + const standIn = () => { + const t = new THREE.DataTexture(new Uint8Array([255, 255, 255, 0]), 1, 1); + t.colorSpace = THREE.SRGBColorSpace; + t.needsUpdate = true; + return t; + }; + const floorMat = deskMaterial(); + const uFloor = floorMat.userData.u; + floorMat.map = standIn(); + floorMat.map.repeat.set(7, 7); + const floor = new THREE.Mesh(new THREE.PlaneGeometry(60, 60), floorMat); + floor.rotation.x = -Math.PI / 2; + scene.add(floor); + if (assets.wood) new THREE.TextureLoader().load(assets.wood, (tex) => { + tex.wrapS = tex.wrapT = THREE.RepeatWrapping; + // a tile is two planks, 5.5 wide by 4.25 deep: planks about 2 units + tex.repeat.set(60 / 5.5, 60 / 4.25); + tex.colorSpace = THREE.SRGBColorSpace; + tex.anisotropy = 8; + renderer.initTexture(tex); + floorMat.map = tex; + uFloor.uHasMap.value = 1; + if (assets.onTexture) assets.onTexture(); + }); + + const glowTex = glowTexture(); + const glow = (color, size, opacity = 1) => { + const sp = new THREE.Sprite(new THREE.SpriteMaterial({ map: glowTex, color, transparent: true, opacity, depthWrite: false, toneMapped: false })); + sp.scale.setScalar(size); + return sp; + }; + + // Soft contact shadows, cast away from the window and a little blue. + const shadowTex = shadowTexture(); + const shadow = (sx, sz, op = 1, color = 0x5b6475) => { + const m = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), decalMaterial({ map: shadowTex, color, opacity: op })); + m.rotation.x = -Math.PI / 2; + m.scale.set(sx, sz, 1); + m.renderOrder = 1; + return m; + }; + + // --- The AI: clear glass, transcript sealed inside ------------------------- + const agent = new THREE.Group(); + // Back faces and front faces as two meshes (back first, by creation + // order): a double-sided transparent material would make three.js switch + // its side and look its program up twice every frame. + const clearGlass = { edgeColor: 0x3a525a, edgeMix: 1.0, specEdge: 0.7, base: 0.025, edge: 0.9, power: 2.2, roughness: 0.02, envMapIntensity: 1.2, key: "clear" }; + const slab = new RoundedBoxGeometry(2.6, 1.72, 0.3, 8, 0.12); + const glassBack = new THREE.Mesh(slab, glassMaterial({ ...clearGlass, side: THREE.BackSide, key: "clear-back" })); + agent.add(glassBack); + const glass = new THREE.Mesh(slab, glassMaterial({ ...clearGlass, side: THREE.FrontSide })); + agent.add(glass); + const term = createTranscript(I, paper); + // the sheet floats inside with a clear margin, so the glass reads as glass + term.group.scale.setScalar(0.9); + agent.add(term.group); + const agentShadow = shadow(3.2, 0.95, 0.62); + const agentLight = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), decalMaterial({ map: glowTex, color: 0xffffff, opacity: 0.55 })); + agentLight.rotation.x = -Math.PI / 2; + agentLight.renderOrder = 1; + + // --- Ask Key: a frosted vault shaped like the app icon ------------------- + const vault = new THREE.Group(); + const W = 1.5, H = 1.86, c = 0.36; + const tag = roundedPolygon([V2(-W / 2, -H / 2), V2(W / 2, -H / 2), V2(W / 2, H / 2 - c), V2(W / 2 - c, H / 2), V2(-W / 2 + c, H / 2), V2(-W / 2, H / 2 - c)], 0.16); + tag.holes.push(capsulePath(0, H / 2 - 0.25, 0.44, 0.1)); + const vg = new THREE.ExtrudeGeometry(tag, { depth: 0.52, bevelEnabled: true, bevelThickness: 0.07, bevelSize: 0.06, bevelSegments: 6, curveSegments: 24 }); + vg.center(); + const vaultMat = glassMaterial({ color: 0xc7ced5, edgeColor: 0xf1f4f7, edgeMix: 0.3, base: 0.1, edge: 0.6, power: 1.6, roughness: 0.6, envMapIntensity: 0.8, clearcoat: 1, clearcoatRoughness: 0.05, side: THREE.FrontSide, key: "frost" }); + const vaultBody = new THREE.Mesh(vg, vaultMat); + vault.add(vaultBody); + // the frost scatters light inside: a soft milky core behind the keys hides + // the desk the way ground glass would, without blurring anything per frame + const coreTex = blurredShapesTexture([tag], { minX: -1.05, maxX: 1.05, minY: -1.2, maxY: 1.2, ppu: 128, blur: 40, color: "#eef1f4" }); + const core = new THREE.Mesh(new THREE.PlaneGeometry(2.1, 2.4), decalMaterial({ map: coreTex, opacity: 0.82 })); + core.position.z = -0.16; + core.scale.setScalar(0.9); + core.renderOrder = 1; + vault.add(core); + const kg = keyGeometry(); + const lacquer = new THREE.MeshPhysicalMaterial({ color: ZHU, roughness: 0.32, clearcoat: 1, clearcoatRoughness: 0.06, emissive: ZHU, emissiveIntensity: 0, envMapIntensity: 1.1 }); + // Inside the frosted glass the keys are seen softened but still readable + // as keys, drawn once into a lightly blurred texture. The sharp key exists only + // as the copy that is delivered. + const blurKey = blurredShapesTexture(keyShapes(), { minX: -0.78, maxX: 0.15, minY: -0.3, maxY: 0.3, ppu: 256, blur: 7, color: "#c22d1f", passes: 2 }); + const keyPlaneGeo = new THREE.PlaneGeometry(0.93, 0.6).translate(-0.315, 0, 0); + // Drawn just after the frosted shell (they sit a little in front of its + // centre, so depth sorting puts them there): a white veil over vermilion + // would turn it pink, and the blur already says "behind frosted glass". + const keyBlurMat = new THREE.MeshBasicMaterial({ map: blurKey, transparent: true, depthWrite: false, toneMapped: false, opacity: 0.92 }); + const vaultKeys = []; + [0.42, 0.0, -0.42].forEach((y, i) => { + const k = new THREE.Mesh(keyPlaneGeo, keyBlurMat); + k.rotation.z = -0.32 + i * 0.05; + // centre the key (its centre sits ~0.3 behind the tip) + k.position.set(0.3 * Math.cos(k.rotation.z), y + 0.3 * Math.sin(k.rotation.z) - 0.08, 0.05); + vault.add(k); + vaultKeys.push(k); + }); + const vaultShadow = shadow(2.0, 1.0, 0.55); + const vaultGlow = glow(0xd2402a, 3.0, 0.0); + vaultGlow.position.z = -0.4; + vault.add(vaultGlow); + // light through the red keys tints the desk under the vault + const vaultTint = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), decalMaterial({ map: glowTex, color: 0xd8442c, opacity: 0 })); + vaultTint.rotation.x = -Math.PI / 2; + vaultTint.renderOrder = 1; + + // --- The program: a graphite box with a keyhole -------------------------- + const prog = new THREE.Group(); + const graphite = new THREE.MeshPhysicalMaterial({ color: 0x2b2c30, metalness: 0.5, roughness: 0.36, clearcoat: 0.6, clearcoatRoughness: 0.22, envMapIntensity: 0.75 }); + const box = new THREE.Mesh(new RoundedBoxGeometry(1.5, 0.92, 1.0, 6, 0.09), graphite); + prog.add(box); + const faceT = canvasTexture(1024, 614); + drawProgramFace(faceT, I); + const face = new THREE.Mesh(new THREE.PlaneGeometry(1.4, 0.84), new THREE.MeshBasicMaterial({ map: faceT.tex, transparent: true, toneMapped: false })); + face.position.z = 0.501; + prog.add(face); + const keyhole = V3(-0.44, 0.03, 0.5); + const ring = new THREE.Mesh(new THREE.RingGeometry(0.1, 0.118, 64), new THREE.MeshBasicMaterial({ color: 0xff4a32, transparent: true, opacity: 0, toneMapped: false })); + ring.position.copy(keyhole).add(V3(0, 0, 0.003)); + prog.add(ring); + const ringGlow = glow(0xff3b22, 0.9, 0); + ringGlow.position.copy(keyhole).add(V3(0, 0, 0.05)); + prog.add(ringGlow); + const leds = []; + const ledOff = new THREE.MeshBasicMaterial({ color: 0x47474b, toneMapped: false }); + const ledOn = new THREE.MeshBasicMaterial({ color: 0x5fe07f, toneMapped: false }); + const ledGeo = new THREE.CircleGeometry(0.016, 20); + for (let i = 0; i < 6; i++) { + const led = new THREE.Mesh(ledGeo, ledOff); + led.position.set(-0.17 + i * 0.058, -0.3, 0.503); + const lg = glow(0x34c759, 0.14, 0); + lg.position.copy(led.position).add(V3(0, 0, 0.01)); + prog.add(led, lg); + led.userData.glow = lg; + leds.push(led); + } + const progShadow = shadow(2.2, 1.6, 0.78); + + // --- The website it publishes ------------------------------------------- + const site = new THREE.Group(); + const frame = new THREE.Mesh(new RoundedBoxGeometry(1.74, 1.11, 0.03, 4, 0.014), new THREE.MeshStandardMaterial({ color: 0xdfe1e4, roughness: 0.42, metalness: 0.3 })); + site.add(frame); + const siteIdle = canvasTexture(1024, 650), siteLive = canvasTexture(1024, 650); + drawSite(siteIdle, I, false); + drawSite(siteLive, I, true); + const sIdle = new THREE.Mesh(new THREE.PlaneGeometry(1.7, 1.08), new THREE.MeshBasicMaterial({ map: siteIdle.tex, transparent: true, toneMapped: false })); + const sLive = new THREE.Mesh(new THREE.PlaneGeometry(1.7, 1.08), new THREE.MeshBasicMaterial({ map: siteLive.tex, transparent: true, opacity: 0, toneMapped: false })); + sIdle.position.z = 0.017; + sLive.position.z = 0.018; + site.add(sIdle, sLive); + const siteShadow = shadow(1.9, 0.5, 0.18); + + // --- Paper slips -------------------------------------------------------- + const cardMesh = (tex, w, h) => { + const m = new THREE.Mesh(new THREE.PlaneGeometry(w, h), new THREE.MeshBasicMaterial({ map: tex, transparent: true, toneMapped: false, side: THREE.DoubleSide, forceSinglePass: true, depthWrite: false })); + m.visible = false; + return m; + }; + const c1 = canvasTexture(640, 390), c2 = canvasTexture(640, 390), sl = canvasTexture(640, 390), ch = canvasTexture(560, 150); + const redrawCards = () => { + drawCard(c1, [[I.card.name, "name"], [I.card.note, "note"], [I.card.env, "mono"], [I.card.value, "empty"]], paper); + drawCard(c2, [[I.card.name2, "name"], [I.card.note2, "note"], [I.card.env2, "mono"], [I.card.value, "empty"]], paper); + drawCard(sl, [[I.slip.line1, "name"], [I.slip.line2, "mono"]], paper, { head: I.slip.head }); + drawChip(ch, I.chip); + term.redrawBase(); + }; + redrawCards(); + const card1 = cardMesh(c1.tex, 0.82, 0.5), card2 = cardMesh(c2.tex, 0.82, 0.5), slip = cardMesh(sl.tex, 0.82, 0.5), chip = cardMesh(ch.tex, 0.8, 0.214); + const seal = new THREE.Mesh(new THREE.PlaneGeometry(0.3, 0.3), new THREE.MeshBasicMaterial({ map: standIn(), transparent: true, opacity: 0, depthWrite: false, toneMapped: false, side: THREE.DoubleSide, forceSinglePass: true })); + seal.position.set(0.22, -0.03, 0.002); + seal.rotation.z = 0.06; + slip.add(seal); + if (assets.seal) new THREE.TextureLoader().load(assets.seal, (t) => { + t.colorSpace = THREE.SRGBColorSpace; + renderer.initTexture(t); + seal.material.map = t; + if (assets.onTexture) assets.onTexture(); + }); + const slipShadow = shadow(0.9, 0.55, 0); + + // --- The delivered copy of the key, and its dust ------------------------- + const { mat: copyMat, uDis } = dissolveMaterial(lacquer); + copyMat.emissiveIntensity = 0.1; + const copy = new THREE.Mesh(kg, copyMat); + copy.visible = false; + const copyGlow = glow(0xe0452c, 1.1, 0); + scene.add(copyGlow); + const DUST = 240; + const dustGeo = new THREE.BufferGeometry(); + dustGeo.setAttribute("position", new THREE.BufferAttribute(new Float32Array(DUST * 3), 3)); + const dust = new THREE.Points(dustGeo, new THREE.PointsMaterial({ color: 0xd2381f, size: 0.03, map: dotTexture(), transparent: true, depthWrite: false, opacity: 0, toneMapped: false })); + dust.visible = false; + dust.frustumCulled = false; + const seeds = Array.from({ length: DUST }, (_, i) => { + const r = (n) => { const x = Math.sin(i * 127.1 + n * 311.7) * 43758.5453; return x - Math.floor(x); }; + return { a: r(1) * Math.PI * 2, b: r(2) * 2 - 1, s: 0.25 + r(3) * 0.75, along: r(4), lift: 0.3 + r(5) * 0.8 }; + }); + + // --- Threads ------------------------------------------------------------ + const thread = (color, opacity, radius) => { + const m = new THREE.Mesh(new THREE.BufferGeometry(), new THREE.MeshBasicMaterial({ color, transparent: true, opacity, depthWrite: false, toneMapped: false })); + m.userData = { radius, segs: 260, radial: 8, base: opacity }; + m.frustumCulled = false; + return m; + }; + const reqThread = thread(0x3a3d44, 0.5, 0.0065); + const keyThread = thread(0xc42d1d, 1.0, 0.009); + const outThread = thread(0x3a3d44, 0.5, 0.0065); + + scene.add(agent, agentShadow, agentLight, vault, vaultShadow, vaultTint, prog, progShadow, site, siteShadow, card1, card2, slip, slipShadow, chip, copy, dust, reqThread, keyThread, outThread); + + const W_ = { + scene, floor, uFloor, agent, agentShadow, agentLight, vaultGlow, vaultTint, ringGlow, copyGlow, seal, glass, term, vault, vaultBody, vaultKeys, keyBlurMat, lacquer, + prog, progShadow, ring, leds, ledOn, ledOff, site, siteShadow, sLive, sIdle, card1, card2, slip, slipShadow, chip, copy, uDis, dust, seeds, reqThread, keyThread, outThread, + vaultShadow, keyhole, redrawCards, L: {}, + }; + W_.setLayout = (kind) => layoutScene(W_, kind); + W_.reveal = (m, p) => { + const per = m.userData.radial * 6; + m.geometry.setDrawRange(0, Math.floor(THREE.MathUtils.clamp(p, 0, 1) * m.userData.segs) * per); + m.visible = p > 0.001; + }; + return W_; +} diff --git a/site-src/how/stamp.mjs b/site-src/how/stamp.mjs new file mode 100644 index 0000000..f6d444a --- /dev/null +++ b/site-src/how/stamp.mjs @@ -0,0 +1,18 @@ +// Stamp each script and stylesheet URL in the site's pages with a hash of +// its content, so a browser never pairs new pages with an old cached file. +import { createHash } from "node:crypto"; +import { readFileSync, writeFileSync } from "node:fs"; + +const site = new URL("../../site/", import.meta.url); +const files = ["style.css", "motion.js", "how/how.css", "how/how.js"]; +const hash = Object.fromEntries(files.map((f) => [f, createHash("sha256").update(readFileSync(new URL(f, site))).digest("hex").slice(0, 10)])); +for (const page of ["index.html", "zh/index.html"]) { + const url = new URL(page, site); + let html = readFileSync(url, "utf8"); + for (const f of files) { + const re = new RegExp(`(["'])/${f.replace(/[./]/g, "\\$&")}(?:\\?v=[0-9a-f]+)?\\1`, "g"); + html = html.replace(re, (_, q) => `${q}/${f}?v=${hash[f]}${q}`); + } + writeFileSync(url, html); +} +console.log(hash); diff --git a/site-src/how/textures.js b/site-src/how/textures.js new file mode 100644 index 0000000..208e592 --- /dev/null +++ b/site-src/how/textures.js @@ -0,0 +1,315 @@ +// Canvas-drawn textures: every word inside the 3D scene is drawn here (or +// in transcript.js), from the page's own i18n block, so the scene speaks +// the page's language. All of it is drawn once, at load or when fonts arrive. +import * as THREE from "three"; + +export const MONO = '"IBM Plex Mono", "SF Mono", Menlo, "PingFang SC", "Hiragino Sans GB", monospace'; +export const SANS = '"Hanken Grotesk", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", system-ui, sans-serif'; +export const INK = "#1d1d1f"; +export const GRAY = "#8a8a8e"; +export const GREEN = "#2a9d4b"; + +export function canvasTexture(w, h, { transparent = false } = {}) { + const canvas = document.createElement("canvas"); + canvas.width = w; + canvas.height = h; + const ctx = canvas.getContext("2d"); + const tex = new THREE.CanvasTexture(canvas); + tex.colorSpace = THREE.SRGBColorSpace; + tex.anisotropy = 8; + tex.generateMipmaps = true; + tex.minFilter = THREE.LinearMipmapLinearFilter; + return { canvas, ctx, tex, w, h, transparent }; +} + +export function roundRect(ctx, x, y, w, h, r) { + ctx.beginPath(); + ctx.moveTo(x + r, y); + ctx.arcTo(x + w, y, x + w, y + h, r); + ctx.arcTo(x + w, y + h, x, y + h, r); + ctx.arcTo(x, y + h, x, y, r); + ctx.arcTo(x, y, x + w, y, r); + ctx.closePath(); +} + +export function paperFill(ctx, w, h, paper, alpha = 0.22) { + ctx.fillStyle = "#fbfaf7"; + ctx.fillRect(0, 0, w, h); + if (paper && paper.complete && paper.naturalWidth) { + ctx.save(); + ctx.globalAlpha = alpha; + ctx.globalCompositeOperation = "multiply"; + const pat = ctx.createPattern(paper, "repeat"); + ctx.fillStyle = pat; + ctx.fillRect(0, 0, w, h); + ctx.restore(); + } +} + +export function drawCard(t, lines, paper, { head } = {}) { + const { ctx, w, h } = t; + const m = 14; + ctx.clearRect(0, 0, w, h); + // a soft shadow under the slip, so paper reads against a white room + ctx.save(); + ctx.shadowColor = "rgba(40, 50, 70, 0.22)"; + ctx.shadowBlur = 12; + ctx.shadowOffsetY = 4; + roundRect(ctx, m, m, w - 2 * m, h - 2 * m, 24); + ctx.fillStyle = "#fbfaf7"; + ctx.fill(); + ctx.restore(); + ctx.save(); + roundRect(ctx, m, m, w - 2 * m, h - 2 * m, 24); + ctx.clip(); + paperFill(ctx, w, h, paper, 0.25); + ctx.restore(); + roundRect(ctx, m, m, w - 2 * m, h - 2 * m, 24); + ctx.strokeStyle = "rgba(0,0,0,0.1)"; + ctx.lineWidth = 2; + ctx.stroke(); + let y = 80; + if (head) { + ctx.font = `500 30px ${SANS}`; + ctx.fillStyle = GRAY; + ctx.fillText(head, 46, y); + y += 70; + } + for (const [text, style] of lines) { + if (style === "name") { ctx.font = `600 54px ${SANS}`; ctx.fillStyle = INK; } + else if (style === "note") { ctx.font = `400 36px ${SANS}`; ctx.fillStyle = GRAY; } + else if (style === "mono") { ctx.font = `400 38px ${MONO}`; ctx.fillStyle = INK; } + else if (style === "empty") { + ctx.font = `400 32px ${MONO}`; + ctx.fillStyle = "rgba(0,0,0,0.34)"; + ctx.setLineDash([10, 9]); + ctx.strokeStyle = "rgba(0,0,0,0.25)"; + ctx.lineWidth = 3; + const tw = ctx.measureText(text).width; + roundRect(ctx, 42, y - 42, tw + 40, 58, 10); + ctx.stroke(); + ctx.setLineDash([]); + ctx.fillText(text, 62, y - 2); + y += 70; + continue; + } + ctx.fillText(text, 46, y); + y += style === "name" ? 66 : 56; + } + t.tex.needsUpdate = true; +} + +export function drawChip(t, text) { + const { ctx, w, h } = t; + ctx.clearRect(0, 0, w, h); + ctx.save(); + ctx.shadowColor = "rgba(40, 50, 70, 0.2)"; + ctx.shadowBlur = 10; + ctx.shadowOffsetY = 3; + roundRect(ctx, 14, 14, w - 28, h - 28, (h - 28) / 2); + ctx.fillStyle = "#ffffff"; + ctx.fill(); + ctx.restore(); + ctx.strokeStyle = "rgba(0,0,0,0.1)"; + ctx.lineWidth = 3; + ctx.stroke(); + ctx.strokeStyle = GREEN; + ctx.lineWidth = 9; + ctx.lineCap = "round"; + ctx.beginPath(); + ctx.moveTo(62, h / 2); + ctx.lineTo(80, h / 2 + 18); + ctx.lineTo(112, h / 2 - 22); + ctx.stroke(); + ctx.font = `500 58px ${MONO}`; + ctx.fillStyle = INK; + ctx.textBaseline = "middle"; + ctx.fillText(text, 140, h / 2 + 3); + ctx.textBaseline = "alphabetic"; + t.tex.needsUpdate = true; +} + +export function drawSite(t, I, live) { + const { ctx, w, h } = t; + ctx.clearRect(0, 0, w, h); + ctx.save(); + roundRect(ctx, 0, 0, w, h, 34); + ctx.clip(); + ctx.fillStyle = "#ffffff"; + ctx.fillRect(0, 0, w, h); + // chrome + ctx.fillStyle = "#f1f1f2"; + ctx.fillRect(0, 0, w, 92); + ctx.fillStyle = "rgba(0,0,0,0.08)"; + ctx.fillRect(0, 92, w, 2); + [0, 1, 2].forEach((i) => { + ctx.beginPath(); + ctx.arc(52 + i * 36, 46, 11, 0, Math.PI * 2); + ctx.fillStyle = "#d4d4d8"; + ctx.fill(); + }); + roundRect(ctx, w / 2 - 220, 22, 440, 48, 24); + ctx.fillStyle = "#ffffff"; + ctx.fill(); + ctx.font = `400 28px ${SANS}`; + ctx.fillStyle = "#5a5a5e"; + ctx.textAlign = "center"; + ctx.textBaseline = "middle"; + ctx.fillText(I.site.url, w / 2, 47); + ctx.textAlign = "left"; + if (live) { + const g = ctx.createLinearGradient(0, 94, w, h); + g.addColorStop(0, "#f6efe6"); + g.addColorStop(1, "#e9eef4"); + ctx.fillStyle = g; + ctx.fillRect(0, 94, w, 300); + ctx.font = `600 66px ${SANS}`; + ctx.fillStyle = INK; + ctx.textBaseline = "alphabetic"; + ctx.fillText(I.site.title, 64, 250); + ctx.fillStyle = "rgba(0,0,0,0.12)"; + roundRect(ctx, 64, 290, 420, 20, 10); ctx.fill(); + roundRect(ctx, 64, 326, 300, 20, 10); ctx.fill(); + [0, 1, 2].forEach((i) => { + roundRect(ctx, 64 + i * 296, 430, 270, 190, 18); + ctx.fillStyle = ["#eef1f4", "#f3eee8", "#eef3ee"][i]; + ctx.fill(); + }); + // status + ctx.font = `500 28px ${SANS}`; + const s = I.site.live; + const sw = ctx.measureText(s).width; + roundRect(ctx, w - sw - 112, 24, sw + 74, 44, 22); + ctx.fillStyle = "rgba(42,157,75,0.12)"; + ctx.fill(); + ctx.beginPath(); + ctx.arc(w - sw - 84, 46, 9, 0, Math.PI * 2); + ctx.fillStyle = GREEN; + ctx.fill(); + ctx.fillStyle = "#1f7a3a"; + ctx.textBaseline = "middle"; + ctx.fillText(s, w - sw - 64, 47); + } else { + ctx.fillStyle = "#f6f6f7"; + ctx.fillRect(0, 94, w, h - 94); + ctx.fillStyle = "rgba(0,0,0,0.06)"; + roundRect(ctx, 64, 170, 380, 44, 12); ctx.fill(); + roundRect(ctx, 64, 240, 520, 20, 10); ctx.fill(); + roundRect(ctx, 64, 276, 360, 20, 10); ctx.fill(); + ctx.font = `400 34px ${SANS}`; + ctx.fillStyle = "#9a9a9e"; + ctx.textAlign = "center"; + ctx.textBaseline = "middle"; + ctx.fillText(I.site.idle, w / 2, h - 120); + ctx.textAlign = "left"; + } + ctx.restore(); + ctx.textBaseline = "alphabetic"; + t.tex.needsUpdate = true; +} + +export function drawProgramFace(t, I) { + const { ctx, w, h } = t; + ctx.clearRect(0, 0, w, h); + // keyhole well on the left, where the key arrives + const cx = 190, cy = h / 2 - 20; + const g = ctx.createRadialGradient(cx, cy, 10, cx, cy, 130); + g.addColorStop(0, "rgba(0,0,0,0.6)"); + g.addColorStop(1, "rgba(0,0,0,0)"); + ctx.fillStyle = g; + ctx.fillRect(cx - 140, cy - 140, 280, 280); + ctx.beginPath(); + ctx.arc(cx, cy - 16, 26, 0, Math.PI * 2); + ctx.moveTo(cx - 14, cy); + ctx.lineTo(cx + 14, cy); + ctx.lineTo(cx + 22, cy + 52); + ctx.lineTo(cx - 22, cy + 52); + ctx.closePath(); + ctx.fillStyle = "#050505"; + ctx.fill(); + const x = 372; + ctx.font = `500 64px ${MONO}`; + ctx.fillStyle = "#f4f4f5"; + ctx.fillText(I.prog, x, 150); + ctx.font = `400 30px ${MONO}`; + ctx.fillStyle = "rgba(255,255,255,0.42)"; + ctx.fillText("#!/bin/sh", x + 2, 226); + ctx.fillText("rsync ./site server:", x + 2, 272); + ctx.fillText(" uses $DEPLOY_TOKEN", x + 2, 318); + t.tex.needsUpdate = true; +} + +// A soft contact shadow: dense near the centre, long soft falloff. Drawn in +// white; the decal's colour tints it. +export function shadowTexture() { + const c = document.createElement("canvas"); + c.width = c.height = 256; + const ctx = c.getContext("2d"); + const g = ctx.createRadialGradient(128, 128, 0, 128, 128, 128); + g.addColorStop(0, "rgba(255,255,255,0.62)"); + g.addColorStop(0.3, "rgba(255,255,255,0.36)"); + g.addColorStop(0.62, "rgba(255,255,255,0.1)"); + g.addColorStop(1, "rgba(255,255,255,0)"); + ctx.fillStyle = g; + ctx.fillRect(0, 0, 256, 256); + const tex = new THREE.CanvasTexture(c); + tex.colorSpace = THREE.SRGBColorSpace; + return tex; +} + +// Shapes seen through frosted glass: filled once and blurred with a canvas +// shadow (which every browser blurs, unlike ctx.filter). +export function blurredShapesTexture(shapes, { minX, maxX, minY, maxY, ppu, blur, color, passes = 1 }) { + const c = document.createElement("canvas"); + c.width = Math.round((maxX - minX) * ppu); + c.height = Math.round((maxY - minY) * ppu); + const ctx = c.getContext("2d"); + const off = c.width + 200; + ctx.shadowColor = color; + ctx.shadowBlur = blur; + ctx.shadowOffsetX = off; + ctx.fillStyle = "#000"; + const px = (x) => (x - minX) * ppu - off, py = (y) => (maxY - y) * ppu; + ctx.beginPath(); + for (const sh of shapes) { + const { shape, holes } = sh.extractPoints(24); + [shape, ...holes].forEach((pts) => { + pts.forEach((p, i) => (i ? ctx.lineTo(px(p.x), py(p.y)) : ctx.moveTo(px(p.x), py(p.y)))); + ctx.closePath(); + }); + } + // repeated passes build up density in thin parts (a key's shaft) that a + // single blur would leave faint + for (let i = 0; i < passes; i++) ctx.fill("evenodd"); + const tex = new THREE.CanvasTexture(c); + tex.colorSpace = THREE.SRGBColorSpace; + return tex; +} + +export function glowTexture() { + const c = document.createElement("canvas"); + c.width = c.height = 128; + const ctx = c.getContext("2d"); + const g = ctx.createRadialGradient(64, 64, 0, 64, 64, 64); + g.addColorStop(0, "rgba(255,255,255,1)"); + g.addColorStop(0.18, "rgba(255,255,255,0.55)"); + g.addColorStop(0.45, "rgba(255,255,255,0.16)"); + g.addColorStop(1, "rgba(255,255,255,0)"); + ctx.fillStyle = g; + ctx.fillRect(0, 0, 128, 128); + return new THREE.CanvasTexture(c); +} + +export function dotTexture() { + const c = document.createElement("canvas"); + c.width = c.height = 64; + const ctx = c.getContext("2d"); + const g = ctx.createRadialGradient(32, 32, 0, 32, 32, 32); + g.addColorStop(0, "rgba(255,255,255,1)"); + g.addColorStop(0.5, "rgba(255,255,255,0.8)"); + g.addColorStop(1, "rgba(255,255,255,0)"); + ctx.fillStyle = g; + ctx.fillRect(0, 0, 64, 64); + const tex = new THREE.CanvasTexture(c); + return tex; +} diff --git a/site-src/how/timing.js b/site-src/how/timing.js new file mode 100644 index 0000000..1c8390e --- /dev/null +++ b/site-src/how/timing.js @@ -0,0 +1,16 @@ +// The film's clock: when things happen, and the easing they happen with. +export const PRE = 14.4; // the request reaches you +export const POST = { allow: 16.5, deny: 8.5 }; +export const STEP_AT = { pre: [0, 3.4, 8.6], allow: [0, 9.2], deny: [0, 2.6] }; +// the last seconds of each ending, when the room gives way to the page +export const WHITE_OUT = 2.6; + +export const clamp = (v, a = 0, b = 1) => Math.min(b, Math.max(a, v)); +export const seg = (t, a, b) => clamp((t - a) / (b - a)); +export const ease = (t) => (t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2); +export const easeOut = (t) => 1 - Math.pow(1 - t, 3); +export const smooth = (t) => t * t * (3 - 2 * t); +export const fade = (t, a, b, inn = 0.35, out = 0.35) => Math.min(seg(t, a, a + inn), 1 - seg(t, b - out, b)); + +export const kindOf = (d) => (d === "once" || d === "timed" ? "allow" : d ? "deny" : null); +export const outcomeOf = (d) => (d === "once" ? "allow" : d || "allow"); diff --git a/site-src/how/transcript.js b/site-src/how/transcript.js new file mode 100644 index 0000000..c5561ba --- /dev/null +++ b/site-src/how/transcript.js @@ -0,0 +1,197 @@ +// The agent's transcript, a dark terminal window suspended inside the glass. +// The window (background and title bar) is drawn once. Each line of the +// transcript is its own thin strip with its own small texture, so typing a +// character or turning the spinner re-uploads one strip instead of the +// whole page, and fading a line in is a change of opacity, not a redraw. +import * as THREE from "three"; +import { canvasTexture, roundRect, MONO, SANS } from "./textures.js"; + +// Terminal colours, light on dark. +const INK = "#e9e7e3", GRAY = "#9b9ba1", GREEN = "#5fd38a", DIM = "rgba(255,255,255,0.24)"; +const BG = "#1c1d20", BAR = "#2b2c30"; +import { decalMaterial } from "./materials.js"; + +const TW = 2048, TH = 1296; // the page, in canvas pixels +const PW = 2.34, PH = 1.48; // the page, in scene units +const K = 1.28; // drawing scale: layout below is in units of 1/K pixels +const X0 = 92, LH = 66, Y0 = 178; +const BAND_TOP = 58, BAND_H = 104; // a strip, in canvas pixels, around a baseline + +export function createTranscript(I, paper) { + const group = new THREE.Group(); + const base = canvasTexture(TW, TH); + const sheet = new THREE.Mesh(new THREE.PlaneGeometry(PW, PH), new THREE.MeshBasicMaterial({ map: base.tex, color: 0xffffff, toneMapped: false })); + sheet.position.z = -0.01; + const back = new THREE.Mesh(new THREE.PlaneGeometry(PW, PH), new THREE.MeshBasicMaterial({ color: 0x2b2c30, toneMapped: false })); + back.rotation.y = Math.PI; + back.position.z = -0.012; + group.add(sheet, back); + + const stripGeo = new THREE.PlaneGeometry(PW, (BAND_H / TH) * PH); + const rows = []; + function row(i) { + if (rows[i]) return rows[i]; + const t = canvasTexture(TW, BAND_H); + const mesh = new THREE.Mesh(stripGeo, decalMaterial({ map: t.tex, opacity: 1 })); + mesh.position.z = -0.008; + mesh.renderOrder = 1; + mesh.visible = false; + group.add(mesh); + return (rows[i] = { t, mesh, sig: "", y: -1 }); + } + // Pre-create enough strips for the longest telling so no texture or + // program is created mid-film. + for (let i = 0; i < 11; i++) row(i); + + function redrawBase() { + const { ctx } = base; + ctx.setTransform(1, 0, 0, 1, 0, 0); + const g = ctx.createLinearGradient(0, 0, 0, TH); + g.addColorStop(0, BG); + g.addColorStop(1, "#18191b"); + ctx.fillStyle = g; + ctx.fillRect(0, 0, TW, TH); + ctx.setTransform(K, 0, 0, K, 0, 0); + const w = TW / K; + ctx.fillStyle = BAR; + ctx.fillRect(0, 0, w, 96); + ctx.fillStyle = "rgba(0,0,0,0.5)"; + ctx.fillRect(0, 96, w, 2); + ["#ff5f57", "#febc2e", "#28c840"].forEach((c, i) => { + ctx.beginPath(); + ctx.arc(56 + i * 40, 48, 12, 0, Math.PI * 2); + ctx.fillStyle = c; + ctx.fill(); + }); + ctx.font = `400 30px ${SANS}`; + ctx.fillStyle = GRAY; + ctx.textAlign = "center"; + ctx.textBaseline = "middle"; + ctx.fillText(I.term.title, w / 2, 50); + ctx.textAlign = "left"; + ctx.textBaseline = "alphabetic"; + ctx.setTransform(1, 0, 0, 1, 0, 0); + base.tex.needsUpdate = true; + rows.forEach((r) => (r.sig = "")); + } + + // `lines` is a list of { kind, text, chars, caret, alpha, row } computed by + // the timeline; `spin` is the spinner's phase. + function update(lines, spin) { + let y = Y0; + let n = 0; + for (const L of lines) { + if (L.kind === "gap") { y += L.size ?? 20; continue; } + const r = row(n++); + const sig = `${L.kind}|${L.text ?? ""}|${L.row ?? ""}|${L.chars ?? ""}|${L.caret ? 1 : 0}|${L.kind === "wait" ? spin : ""}`; + if (sig !== r.sig) { + drawLine(r.t, L, y, spin); + r.sig = sig; + } + if (r.y !== y) { + r.y = y; + const cy = y * K - BAND_TOP + BAND_H / 2; + r.mesh.position.y = (0.5 - cy / TH) * PH; + } + r.mesh.visible = true; + r.mesh.material.opacity = L.alpha ?? 1; + y += L.kind === "me" ? LH + 10 : LH; + } + for (let i = n; i < rows.length; i++) rows[i].mesh.visible = false; + } + + return { group, sheet, update, redrawBase }; +} + +function drawLine(t, L, y, spin) { + const { ctx } = t; + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.clearRect(0, 0, t.w, t.h); + ctx.setTransform(K, 0, 0, K, 0, BAND_TOP - y * K); + const x0 = X0; + if (L.kind === "me") { + ctx.font = `500 44px ${MONO}`; + ctx.fillStyle = GRAY; + ctx.fillText("›", x0 - 46, y); + ctx.fillStyle = INK; + const s = [...L.text].slice(0, L.chars ?? Infinity).join(""); + ctx.fillText(s, x0, y); + if (L.caret) { + const m = ctx.measureText(s).width; + ctx.fillRect(x0 + m + 6, y - 36, 20, 44); + } + } else if (L.kind === "ai" || L.kind === "ok" || L.kind === "no" || L.kind === "wait") { + ctx.font = `400 38px ${MONO}`; + ctx.lineCap = "round"; + if (L.kind === "ai") { + ctx.beginPath(); + ctx.arc(x0 - 30, y - 13, 9, 0, Math.PI * 2); + ctx.fillStyle = INK; + ctx.fill(); + } else if (L.kind === "ok") { + ctx.strokeStyle = GREEN; + ctx.lineWidth = 6; + ctx.beginPath(); + ctx.moveTo(x0 - 42, y - 14); + ctx.lineTo(x0 - 32, y - 4); + ctx.lineTo(x0 - 14, y - 28); + ctx.stroke(); + } else if (L.kind === "no") { + ctx.strokeStyle = INK; + ctx.lineWidth = 5; + ctx.beginPath(); + ctx.moveTo(x0 - 40, y - 28); ctx.lineTo(x0 - 18, y - 6); + ctx.moveTo(x0 - 18, y - 28); ctx.lineTo(x0 - 40, y - 6); + ctx.stroke(); + } else { + // spinner: eight ticks, one bright + for (let i = 0; i < 8; i++) { + const ang = (i / 8) * Math.PI * 2; + ctx.strokeStyle = Math.floor(spin * 8) % 8 === i ? INK : DIM; + ctx.lineWidth = 5; + ctx.beginPath(); + ctx.moveTo(x0 - 29 + Math.cos(ang) * 6, y - 16 + Math.sin(ang) * 6); + ctx.lineTo(x0 - 29 + Math.cos(ang) * 15, y - 16 + Math.sin(ang) * 15); + ctx.stroke(); + } + } + ctx.fillStyle = L.kind === "ok" ? GREEN : L.kind === "wait" ? GRAY : INK; + ctx.fillText(L.text, x0, y); + } else if (L.kind === "indent") { + ctx.font = `400 38px ${MONO}`; + ctx.fillStyle = INK; + ctx.fillText(L.text, x0, y); + } else if (L.kind === "cat") { + // name · note · ENV [value: —] + const [name, note, env] = L.row; + ctx.font = `600 36px ${SANS}`; + ctx.fillStyle = INK; + ctx.fillText(name, x0 + 28, y); + ctx.font = `400 32px ${SANS}`; + ctx.fillStyle = GRAY; + ctx.fillText(note, x0 + 400, y); + ctx.font = `400 30px ${MONO}`; + const ew = ctx.measureText(env).width; + roundRect(ctx, x0 + 760, y - 38, ew + 36, 52, 10); + ctx.fillStyle = "rgba(255,255,255,0.08)"; + ctx.fill(); + ctx.fillStyle = INK; + ctx.fillText(env, x0 + 778, y - 2); + // the empty value slot + const vx = x0 + 760 + ew + 64; + ctx.setLineDash([10, 9]); + ctx.strokeStyle = "rgba(255,255,255,0.3)"; + ctx.lineWidth = 3; + roundRect(ctx, vx, y - 38, 250, 52, 10); + ctx.stroke(); + ctx.setLineDash([]); + ctx.fillStyle = DIM; + ctx.fillText("— — —", vx + 44, y - 2); + } else if (L.kind === "note") { + ctx.font = `400 30px ${SANS}`; + ctx.fillStyle = GRAY; + ctx.fillText(L.text, x0 + 28, y - 4); + } + ctx.setTransform(1, 0, 0, 1, 0, 0); + t.tex.needsUpdate = true; +} diff --git a/site-src/how/ui.js b/site-src/how/ui.js new file mode 100644 index 0000000..ba10a71 --- /dev/null +++ b/site-src/how/ui.js @@ -0,0 +1,279 @@ +// The DOM around the scene: labels pinned to objects, the caption, the +// chapter rail, Ask Key's approval prompt with its live countdown, and the +// two endings. +import * as THREE from "three"; +import { PRE, POST, STEP_AT, seg, clamp, kindOf, outcomeOf } from "./timing.js"; + +export function createUI({ root, I, S, W, camera, reduced, wake, renderNow }) { + const $ = (s) => root.querySelector(s); + const $$ = (s) => [...root.querySelectorAll(s)]; + const stage = $(".akhw-stage"), say = $(".akhw-say"), tagLayer = $(".akhw-tags"); + const alert = $(".akhw-alert"), hint = $(".akhw-hint"), pending = $(".akhw-pending"), endBar = $(".akhw-end"), playBtn = $(".akhw-play"); + const count = $(".akhw-count"), details = $(".akhw-alert-details"), rows = $(".akhw-alert-rows"); + const steps = $$(".akhw-steps li"); + + // ------------------------------------------------------------ tags + const tags = []; + const v3 = new THREE.Vector3(), o3 = new THREE.Vector3(); + const tag = (cls, html, anchor, show, dy = 0) => { + if (!html || html.includes("undefined")) return; // copy missing for this language + const el = document.createElement("div"); + el.className = `akhw-tag ${cls}`; + el.innerHTML = html; + tagLayer.appendChild(el); + tags.push({ el, anchor, show, dy, on: false, w: 0, x: NaN, y: NaN }); + }; + const T_ = I.tags; + { + const L = W.L; + const add = (p, x, y, z) => v3.copy(p).add(o3.set(x, y, z)); + const below = (key, s, y) => () => add(L[key], 0, -y * L[s], L.kind === "wide" ? 0 : 0.75 * L[s]); + const finalAllow = (s) => s.phase !== "pre" && s.phase !== "gate" && kindOf(s.decision) === "allow" && s.u > 12.6; + const finalDeny = (s) => s.phase !== "pre" && s.phase !== "gate" && kindOf(s.decision) === "deny" && s.u > 5.6; + const finalAny = (s) => finalAllow(s) || finalDeny(s); + const opening = (s) => s.phase === "pre" && s.T < 1.9; + const catalog = (s) => s.phase === "pre" && s.T > 4.9 && s.T < 8.5; + // Names show while the desk around them is wood: light text cannot sit + // on the white the closing shot fades into, so the end uses pills only. + tag("is-id", `${T_.agent[0]}${T_.agent[1]}`, below("A", "sA", 1.08), (s) => opening(s) || catalog(s)); + tag("is-id", `${T_.vault[0]}${T_.vault[1]}`, () => below("V", "sV", L.kind === "wide" ? 1.5 : 1.32)(), (s) => opening(s) || catalog(s)); + tag("is-id", `${T_.prog[0]}${T_.prog[1]}`, () => add(L.P, 0, -0.62 * L.sP, (L.kind === "wide" ? 0.5 : 1.05) * L.sP), (s) => s.phase === "post" && kindOf(s.decision) === "allow" && s.u > 3.2 && s.u < 4.6); + tag("is-pill", T_.noValue, () => add(L.A, 0.2 * L.sA, 0.98 * L.sA, 0), (s) => s.phase === "pre" && s.T > 7.2 && s.T < 8.6); + tag("is-pill is-key", T_.flying, () => add(W.copy.position, 0, 0.3 * L.sP, 0), (s) => s.phase !== "pre" && s.phase !== "gate" && kindOf(s.decision) === "allow" && s.u > 2.2 && s.u < 4.6); + tag("is-pill is-zero", T_.agentEnd.replace(/(\d+)/, "$1"), () => add(L.A, 0, 1.02 * L.sA, 0), (s) => finalAny(s) || (s.phase === "post" && s.u > (kindOf(s.decision) === "allow" ? 10.8 : 3.4))); + tag("is-pill", T_.vaultEnd, () => add(L.V, 0, 1.2 * L.sV, 0), (s) => finalAllow(s) && s.decision === "once"); + tag("is-pill", T_.vaultTimed, () => add(L.V, 0, 1.2 * L.sV, 0), (s) => finalAllow(s) && s.decision === "timed"); + tag("is-pill", T_.vaultDeny, () => add(L.V, 0, 1.2 * L.sV, 0), (s) => finalDeny(s)); + tag("is-pill is-key", T_.progEnd, () => add(L.W, 0, 0.74 * L.sP, 0), (s) => finalAllow(s)); + tag("is-pill", T_.progDeny, () => add(L.W, 0, 0.74 * L.sP, 0), (s) => finalDeny(s)); + } + + // Positions are written in one pass after every width is known, so the + // browser never lays out mid-frame. A label is measured once, when it + // first shows. + let stageW = stage.clientWidth, stageH = stage.clientHeight; + function measure() { + stageW = stage.clientWidth; + stageH = stage.clientHeight; + tags.forEach((t) => (t.w = 0)); + } + function updateTags(s) { + const w = stageW, h = stageH, now = performance.now(); + for (const t of tags) { + const on = s.phase !== "idle" && t.show(s); + if (on !== t.on) { + t.el.classList.toggle("on", on); + t.on = on; + if (!on) t.offAt = now; + } + if (on && !t.w) t.w = t.el.offsetWidth; + } + for (const t of tags) { + // keep following the object while the label fades out + if (!t.on && !(now - (t.offAt || 0) < 600)) continue; + const p = t.anchor().project(camera); + if (p.z > 1) { if (t.on) { t.el.classList.remove("on"); t.on = false; t.offAt = 0; } continue; } + const half = t.w / 2 + 10; + const x = clamp((p.x * 0.5 + 0.5) * w, half, Math.max(half, w - half)), y = (-p.y * 0.5 + 0.5) * h + t.dy; + if (Math.abs(x - t.x) < 0.05 && Math.abs(y - t.y) < 0.05) continue; + t.x = x; t.y = y; + t.el.style.transform = `translate(${x.toFixed(1)}px, ${y.toFixed(1)}px) translate(-50%, -50%)`; + } + } + + // ------------------------------------------------------------- captions + const sayPs = steps.map(() => { + const p = document.createElement("p"); + say.appendChild(p); + return p; + }); + function stepOf(s) { + if (s.phase === "pre" || s.phase === "idle") return s.T < STEP_AT.pre[1] ? 0 : s.T < STEP_AT.pre[2] ? 1 : 2; + if (s.phase === "gate") return 3; + const k = kindOf(s.decision); + return s.u < STEP_AT[k][1] ? 4 : 5; + } + let lastStep = -1, lastOutcome = ""; + const lastFill = steps.map(() => -1); + function updateCaptions(s) { + const st = stepOf(s); + const oc = outcomeOf(s.decision); + if (oc !== lastOutcome) { + root.dataset.outcome = oc; + lastOutcome = oc; + lastStep = -1; + } + if (st !== lastStep) { + const li = steps[st]; + const src = [...li.querySelectorAll("p")].find((p) => getComputedStyle(p).display !== "none"); + sayPs.forEach((p, i) => { + if (i === st && src) p.innerHTML = src.innerHTML; + p.classList.toggle("on", i === st); + }); + steps.forEach((li, i) => li.classList.toggle("on", i === st)); + lastStep = st; + } + const k = kindOf(s.decision); + for (let i = 0; i < steps.length; i++) { + let f; + if (i < st) f = 1; + else if (i > st) f = 0; + else if (st <= 2) f = seg(s.T, STEP_AT.pre[st], st < 2 ? STEP_AT.pre[st + 1] : PRE); + else if (st === 3) f = 1; + else f = seg(s.u, STEP_AT[k][st - 4], st === 4 ? STEP_AT[k][1] : POST[k]); + f = Math.round(f * 400) / 400; + if (f !== lastFill[i]) { + steps[i].style.setProperty("--fill", f.toFixed(3)); + lastFill[i] = f; + } + } + } + + // ------------------------------------------------------------- the gate + let hintTimer = 0; + function showAlert() { + alert.hidden = false; + alert.classList.remove("leave"); + alert.classList.add("enter"); + pending.hidden = true; + root.classList.remove("is-later"); + clearTimeout(hintTimer); + hintTimer = setTimeout(() => { + if (S.phase === "gate" && !S.later) { + hint.hidden = false; + root.classList.add("is-hinting"); + } + }, 6500); + } + function hideAlert(instant) { + clearTimeout(hintTimer); + hint.hidden = true; + root.classList.remove("is-hinting"); + if (instant || reduced) { + alert.hidden = true; + return; + } + alert.classList.remove("enter"); + alert.classList.add("leave"); + setTimeout(() => { + if (alert.classList.contains("leave")) { + alert.hidden = true; + alert.classList.remove("leave"); + } + }, 280); + } + function enterGate() { + S.phase = "gate"; + S.T = PRE; + S.gateAt = performance.now(); + S.later = false; + root.classList.add("is-gate"); + count.textContent = count.dataset.format.replace("{t}", "4:57"); + showAlert(); + } + function decide(d) { + if (S.phase !== "gate") return; + S.decision = d; + S.phase = "post"; + S.u = 0; + S.ended = false; + S.later = false; + root.classList.remove("is-gate", "is-later"); + pending.hidden = true; + hideAlert(); + if (reduced) { + S.u = POST[kindOf(d)]; + S.phase = "end"; + showEnd(); + renderNow(); + } else wake(); + } + function tickCountdown(now) { + if (S.phase !== "gate") return; + const left = Math.max(0, 297 - Math.floor((now - S.gateAt) / 1000)); + const txt = `${Math.floor(left / 60)}:${String(left % 60).padStart(2, "0")}`; + const full = count.dataset.format.replace("{t}", txt); + if (count.textContent !== full) count.textContent = full; + if (S.later) { + const pt = pending.dataset.base.replace("{t}", txt); + if (pending.textContent !== pt) pending.textContent = pt; + } + if (left === 0) { + S.later = false; + decide("expire"); + } + } + pending.dataset.base = pending.textContent.includes("·") ? pending.textContent.split("·")[0].trim() + " · {t}" : pending.textContent; + function later() { + if (S.phase !== "gate" || S.later) return; + S.later = true; + root.classList.add("is-later"); + hideAlert(); + pending.hidden = false; + wake(); + } + alert.addEventListener("click", (e) => { + const b = e.target.closest("[data-decide]"); + if (b && !root.classList.contains("is-still")) decide(b.dataset.decide); + }); + details.addEventListener("click", () => { + const open = details.getAttribute("aria-expanded") !== "true"; + details.setAttribute("aria-expanded", String(open)); + rows.hidden = !open; + }); + $(".akhw-later").addEventListener("click", later); + pending.addEventListener("click", () => { + S.later = false; + showAlert(); + alert.querySelector(".is-primary").focus({ preventScroll: true }); + wake(); + }); + document.addEventListener("keydown", (e) => { + if (e.key === "Escape" && S.phase === "gate" && !S.later && S.visible) later(); + }); + + // ------------------------------------------------------------- endings + const again = $(".akhw-again"), other = $(".akhw-other"); + function showEnd() { + S.ended = true; + endBar.hidden = false; + other.textContent = kindOf(S.decision) === "allow" ? other.dataset.deny : other.dataset.allow; + } + function hideEnd() { + S.ended = false; + endBar.hidden = true; + } + function seek(i) { + hideEnd(); + playBtn.hidden = true; + S.started = true; + if (i <= 2) { + if (S.phase === "gate") hideAlert(true); + root.classList.remove("is-gate", "is-later"); + pending.hidden = true; + S.phase = "pre"; + S.T = STEP_AT.pre[i] + (i === 0 ? 0 : 0.01); + S.decision = null; + } else if (i === 3) { + S.decision = null; + if (S.phase !== "gate") enterGate(); + else if (S.later) { S.later = false; showAlert(); } + } else { + if (S.phase === "gate") { + hideAlert(true); + root.classList.remove("is-gate", "is-later"); + pending.hidden = true; + } + if (!S.decision) S.decision = "once"; + S.phase = "post"; + S.u = STEP_AT[kindOf(S.decision)][i - 4] + 0.01; + } + wake(); + } + again.addEventListener("click", () => seek(0)); + other.addEventListener("click", () => seek(3)); + steps.forEach((li, i) => li.querySelector("button").addEventListener("click", () => seek(i))); + playBtn.addEventListener("click", () => seek(0)); + + return { updateTags, updateCaptions, tickCountdown, enterGate, decide, showEnd, hideEnd, hideAlert, measure, alert, hint, stage }; +} diff --git a/site-src/how/world.js b/site-src/how/world.js new file mode 100644 index 0000000..98b6634 --- /dev/null +++ b/site-src/how/world.js @@ -0,0 +1,222 @@ +// Every visual is a pure function of the film's time and the reader's +// decision, which makes chapter seeking, replays and the alternate endings +// exact. Nothing here allocates per frame. +import * as THREE from "three"; +import { PRE, POST, WHITE_OUT, clamp, seg, ease, easeOut, smooth, fade, kindOf } from "./timing.js"; + +export function createWorld(W, I, camera) { + // ---------------------------------------------------------- transcript + const out = []; + const lines = Array.from({ length: 12 }, () => ({})); + let nLines = 0; + const push = (kind, text, alpha, extra) => { + const L = lines[nLines++]; + L.kind = kind; L.text = text; L.alpha = alpha; L.chars = undefined; L.caret = false; L.row = undefined; + if (extra) Object.assign(L, extra); + return L; + }; + const askChars = [...I.term.ask].length; + function transcriptLines(s) { + nLines = 0; + const T = s.phase === "pre" ? s.T : PRE + 1; + const post = s.phase === "post" || s.phase === "end"; + const u = post ? s.u : -1; + const k = kindOf(s.decision); + const a = (at) => clamp((T - at) / 0.35); + const au = (at) => clamp((u - at) / 0.35); + const me = push("me", I.term.ask, 1); + me.chars = Math.floor(seg(T, 0.7, 2.7) * askChars); + me.caret = T < 3.0 && (T < 2.7 || Math.floor(T * 2.2) % 2 === 0); + if (T >= 3.4) push("ai", I.term.check, a(3.4)); + if (T >= 6.7) push("cat", "", a(6.7), { row: I.term.cat[0] }); + if (T >= 7.0) push("cat", "", a(7.0), { row: I.term.cat[1] }); + if (T >= 7.3) push("note", I.term.noValue, a(7.3)); + if (T >= 8.6) push("ai", I.term.cant, a(8.6)); + if (T >= 8.9) push("indent", I.term.req, a(8.9)); + if (T >= 12.6) { + if (!post || u < 0.5) push("wait", I.term.wait, a(12.6)); + else if (k === "allow") push("ok", s.decision === "timed" ? I.term.okTimed : I.term.ok, au(0.5)); + else push("no", s.decision === "expire" ? I.term.expired : I.term.denied, au(0.5)); + } + if (post && k === "allow") { + if (u >= 10.0) push("ai", I.term.out, au(10.0)); + if (u >= 10.5) push("ok", I.term.live, au(10.5)); + } + if (post && k === "deny" && u >= 1.7) push("ai", s.decision === "expire" ? I.term.expiredNext : I.term.deniedNext, au(1.7)); + out.length = nLines; + for (let i = 0; i < nLines; i++) out[i] = lines[i]; + return out; + } + function updateTranscript(s, clock) { + const ls = transcriptLines(s); + const waiting = ls.some((l) => l.kind === "wait"); + W.term.update(ls, waiting ? Math.floor(clock * 9) / 8 : 0); + } + + // ------------------------------------------------------------ the world + const q = new THREE.Quaternion(), q2 = new THREE.Quaternion(), X = new THREE.Vector3(1, 0, 0), NZ = new THREE.Vector3(0, 0, -1); + const tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(), sp = new THREE.Vector3(), ss = new THREE.Vector3(); + const sq = new THREE.Quaternion(); + function along(m, path, p, wobble = 0) { + path.getPoint(p, tmp); + m.position.copy(tmp); + m.quaternion.copy(camera.quaternion); + m.rotateZ(wobble); + } + + function update(s, clock) { + const T = s.phase === "pre" ? s.T : PRE + 1; + const post = s.phase === "post" || s.phase === "end"; + const u = post ? s.u : 0; + const k = post ? kindOf(s.decision) : null; + const L = W.L; + + // catalog cards: vault → AI + for (let i = 0; i < 2; i++) { + const m = i ? W.card2 : W.card1, t0 = i ? 4.75 : 4.3; + const p = seg(T, t0, t0 + 2.2); + m.visible = p > 0 && p < 1; + if (!m.visible) continue; + const e = ease(p); + along(m, L.catPath, e, Math.sin(clock * 2 + i) * 0.04 + (1 - e) * 0.2); + if (i) m.position.y += 0.12 * L.sA; + const sc = L.cardScale * (0.35 + 0.65 * smooth(seg(p, 0, 0.2))) * (1 - 0.5 * smooth(seg(p, 0.82, 1))); + m.scale.setScalar(sc); + m.material.opacity = Math.min(seg(p, 0, 0.12), 1 - seg(p, 0.86, 1)); + } + + // request slip: AI → vault, then it lands on the desk in front of you + { + const p = seg(T, 9.6, 12.2), l = seg(T, 12.2, 13.3); + const base = L.kind === "wide" ? 1 : 0.72; + W.slip.visible = p > 0; + if (p > 0 && l <= 0) { + along(W.slip, L.reqPath, ease(p), Math.sin(clock * 2.4) * 0.05); + W.slip.material.opacity = seg(p, 0, 0.1); + W.slip.scale.setScalar(base * (1 - 0.2 * smooth(seg(p, 0.8, 1)))); + } else if (l > 0) { + L.reqPath.getPoint(1, tmp); + const e = ease(l); + W.slip.position.lerpVectors(tmp, L.slipRest, e); + W.slip.position.y += Math.sin(e * Math.PI) * 0.25 * L.sV; + W.slip.quaternion.slerpQuaternions(camera.quaternion, L.slipRestQ, smooth(l)); + W.slip.scale.setScalar(base * (0.8 + 0.4 * e)); + W.slip.material.opacity = 1; + } + W.slipShadow.material.opacity = 0.5 * smooth(seg(l, 0.55, 1)) * (post && k === "deny" ? 1 - 0.55 * seg(u, 0.5, 1.6) : 1); + const stamp = k === "allow" ? seg(u, 0.12, 0.5) : 0; + W.seal.material.opacity = Math.min(1, stamp * 3) * 0.92; + W.seal.scale.setScalar(1 + 0.6 * (1 - easeOut(stamp))); + if (post && k === "deny") W.slip.material.opacity = 1 - 0.55 * seg(u, 0.5, 1.6); + W.reveal(W.reqThread, ease(seg(T, 9.6, 12.2))); + } + + // the vault answers: keys warm up while it asks you + const ask = seg(T, 12.3, 13.2) * (post ? 1 - seg(u, 0.2, 1.2) : 1); + const pulse = s.phase === "gate" && !s.later ? 0.5 + 0.5 * Math.sin(clock * 3) : 0; + const warm = ask * (0.5 + pulse * 0.5) + (k === "allow" ? 0.7 * fade(u, 0.4, 2.6, 0.4, 0.8) : 0); + W.lacquer.emissiveIntensity = 0.5 * warm; + // the blurred keys brighten toward a lit vermilion + W.keyBlurMat.color.setScalar(1 + 0.45 * warm); + W.vault.scale.setScalar(L.sV * (1 + 0.025 * ask * smooth(fade(T, 12.3, 13.4, 0.4, 0.6)))); + const lantern = 0.1 + ask * (0.2 + pulse * 0.18) + (k === "allow" ? 0.32 * fade(u, 0.3, 2.8, 0.4, 0.9) : 0); + W.vaultGlow.material.opacity = lantern * 0.85; + W.vaultTint.material.opacity = 0.08 + lantern * 0.42; + + // allow: a copy of the key leaves the vault, goes to the program, is used and destroyed + const allow = k === "allow"; + const copy = W.copy; + copy.visible = allow && u > 0.5 && u < 10.4; + W.dust.visible = false; + if (copy.visible) { + const src = W.vaultKeys[1]; + src.updateWorldMatrix(true, false); + src.matrixWorld.decompose(sp, sq, ss); + const base = L.kind === "wide" ? 1.15 : 0.8; + const e = smooth(seg(u, 0.5, 2.0)); + const f = ease(seg(u, 2.0, 5.2)); + const turn = ease(seg(u, 5.3, 5.85)); + if (u < 2.0) { + L.keyPath.getPoint(0, tmp); + L.keyPath.getTangent(0.001, tmp2); + q.setFromUnitVectors(X, tmp2); + copy.position.lerpVectors(sp, tmp, e); + copy.quaternion.slerpQuaternions(sq, q, e); + copy.scale.setScalar(ss.x + (base - ss.x) * e); + } else { + L.keyPath.getPoint(f, tmp); + L.keyPath.getTangent(Math.min(0.999, Math.max(0.001, f)), tmp2); + tmp2.lerp(NZ, smooth(seg(f, 0.8, 1))).normalize(); + copy.position.copy(tmp); + q.setFromUnitVectors(X, tmp2); + q2.setFromAxisAngle(X, Math.sin(f * Math.PI) * Math.PI - (turn * Math.PI) / 2); + copy.quaternion.copy(q).multiply(q2); + copy.scale.setScalar(base); + } + const dis = seg(u, 8.4, 10.2); + W.uDis.value = dis; + if (dis > 0) { + W.dust.visible = true; + const arr = W.dust.geometry.attributes.position.array; + const tip = copy.position; + const len = 0.62 * base; + const seeds = W.seeds; + for (let i = 0; i < seeds.length; i++) { + const sd = seeds[i]; + const t = clamp((dis - sd.along * 0.6) / 0.6); + const r = easeOut(t) * 0.35 * sd.s * L.sP * 1.6; + arr[i * 3] = tip.x + Math.cos(sd.a) * r * 0.8; + arr[i * 3 + 1] = tip.y + sd.b * 0.06 + t * sd.lift * 0.5 * L.sP + Math.sin(sd.a) * r * 0.25; + arr[i * 3 + 2] = tip.z + len * (1 - sd.along) * (t > 0 ? 1 : 0) + Math.abs(Math.sin(sd.a)) * r * 0.4; + } + W.dust.geometry.attributes.position.needsUpdate = true; + W.dust.material.opacity = 0.95 * (1 - seg(dis, 0.55, 1)); + } + } else { + W.uDis.value = 0; + } + W.copyGlow.visible = copy.visible && W.uDis.value < 0.95; + if (W.copyGlow.visible) { + W.copyGlow.position.copy(copy.position); + W.copyGlow.material.opacity = 0.32 * seg(u, 0.6, 1.6) * (1 - W.uDis.value); + } + W.reveal(W.keyThread, allow ? ease(seg(u, 2.0, 5.2)) : 0); + + // the program runs + W.ring.material.opacity = allow ? seg(u, 4.2, 4.8) * (1 - 0.6 * seg(u, 9.4, 10.4)) : 0; + W.ringGlow.material.opacity = W.ring.material.opacity * (0.4 + 0.2 * fade(u, 5.3, 6.4, 0.2, 0.6)); + for (let i = 0; i < W.leds.length; i++) { + const led = W.leds[i]; + const on = allow && u > 5.95 + i * 0.16; + led.material = on ? W.ledOn : W.ledOff; + led.userData.glow.material.opacity = on ? 0.7 : 0; + } + const live = allow ? smooth(seg(u, 6.9, 7.5)) : 0; + W.sLive.material.opacity = live; + W.sIdle.material.opacity = 1 - live; + W.site.position.y = L.W.y + Math.sin(clock * 0.9) * 0.015 * L.sP + live * 0.04 * (1 - seg(u, 7.5, 8.5)) * L.sP; + + // the result comes back: program → AI + { + const p = allow ? seg(u, 7.7, 9.9) : 0; + W.chip.visible = p > 0 && p < 1; + if (W.chip.visible) { + along(W.chip, L.outPath, ease(p), Math.sin(clock * 2) * 0.03); + W.chip.material.opacity = Math.min(seg(p, 0, 0.1), 1 - seg(p, 0.86, 1)); + } + W.reveal(W.outThread, allow ? ease(seg(u, 7.7, 9.9)) : 0); + } + + // threads settle into a faint diagram for the final frame + const settle = post ? seg(u, k === "allow" ? 11 : 3, k === "allow" ? 13 : 5) : 0; + W.reqThread.material.opacity = k === "deny" ? 0.5 - 0.24 * settle : 0.5; + + // the room gives way to the page as each ending closes + W.uFloor.uWhite.value = post ? smooth(seg(u, POST[k] - WHITE_OUT, POST[k])) : 0; + + // idle life + W.agent.position.y = L.A.y + Math.sin(clock * 0.7) * 0.02 * L.sA; + } + + return { update, updateTranscript }; +} diff --git a/site/assets/apple-touch-icon.png b/site/assets/apple-touch-icon.png new file mode 100644 index 0000000..a73fc1d Binary files /dev/null and b/site/assets/apple-touch-icon.png differ diff --git a/site/assets/favicon-64.png b/site/assets/favicon-64.png new file mode 100644 index 0000000..0410543 Binary files /dev/null and b/site/assets/favicon-64.png differ diff --git a/site/assets/hero-desk.jpg b/site/assets/hero-desk.jpg new file mode 100644 index 0000000..6114aaa Binary files /dev/null and b/site/assets/hero-desk.jpg differ diff --git a/site/assets/icon-256.png b/site/assets/icon-256.png new file mode 100644 index 0000000..cb0e01d Binary files /dev/null and b/site/assets/icon-256.png differ diff --git a/site/assets/og-en.jpg b/site/assets/og-en.jpg new file mode 100644 index 0000000..d7bb20a Binary files /dev/null and b/site/assets/og-en.jpg differ diff --git a/site/assets/og-zh.jpg b/site/assets/og-zh.jpg new file mode 100644 index 0000000..f0a6220 Binary files /dev/null and b/site/assets/og-zh.jpg differ diff --git a/site/assets/paper.jpg b/site/assets/paper.jpg new file mode 100644 index 0000000..5bd8589 Binary files /dev/null and b/site/assets/paper.jpg differ diff --git a/site/assets/pass-key.webp b/site/assets/pass-key.webp new file mode 100644 index 0000000..ae6b910 Binary files /dev/null and b/site/assets/pass-key.webp differ diff --git a/site/assets/pass-shadow.webp b/site/assets/pass-shadow.webp new file mode 100644 index 0000000..3242315 Binary files /dev/null and b/site/assets/pass-shadow.webp differ diff --git a/site/assets/pass.webp b/site/assets/pass.webp new file mode 100644 index 0000000..a8ab251 Binary files /dev/null and b/site/assets/pass.webp differ diff --git a/site/assets/seal-stone.webp b/site/assets/seal-stone.webp new file mode 100644 index 0000000..db35de8 Binary files /dev/null and b/site/assets/seal-stone.webp differ diff --git a/site/assets/seal-wen.webp b/site/assets/seal-wen.webp new file mode 100644 index 0000000..f6e0357 Binary files /dev/null and b/site/assets/seal-wen.webp differ diff --git a/site/assets/seal-yin.webp b/site/assets/seal-yin.webp new file mode 100644 index 0000000..e7b1ab4 Binary files /dev/null and b/site/assets/seal-yin.webp differ diff --git a/site/assets/seal-zhun.webp b/site/assets/seal-zhun.webp new file mode 100644 index 0000000..51e2d2c Binary files /dev/null and b/site/assets/seal-zhun.webp differ diff --git a/site/fonts/HankenGrotesk-Variable.woff2 b/site/fonts/HankenGrotesk-Variable.woff2 new file mode 100644 index 0000000..c2b11a4 Binary files /dev/null and b/site/fonts/HankenGrotesk-Variable.woff2 differ diff --git a/site/fonts/IBMPlexMono-Regular-Latin1.woff2 b/site/fonts/IBMPlexMono-Regular-Latin1.woff2 new file mode 100644 index 0000000..2fdc4b5 Binary files /dev/null and b/site/fonts/IBMPlexMono-Regular-Latin1.woff2 differ diff --git a/site/fonts/OFL-HankenGrotesk.txt b/site/fonts/OFL-HankenGrotesk.txt new file mode 100644 index 0000000..9c8185d --- /dev/null +++ b/site/fonts/OFL-HankenGrotesk.txt @@ -0,0 +1,94 @@ +Copyright 2021 The Hanken Grotesk Project Authors (https://github.com/marcologous/hanken-grotesk) + + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/site/fonts/OFL-IBMPlexMono.txt b/site/fonts/OFL-IBMPlexMono.txt new file mode 100644 index 0000000..c35c4c6 --- /dev/null +++ b/site/fonts/OFL-IBMPlexMono.txt @@ -0,0 +1,93 @@ +Copyright © 2017 IBM Corp. with Reserved Font Name "Plex" + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/site/how/THREE-LICENSE.txt b/site/how/THREE-LICENSE.txt new file mode 100644 index 0000000..8ada2a5 --- /dev/null +++ b/site/how/THREE-LICENSE.txt @@ -0,0 +1,21 @@ +The MIT License + +Copyright © 2010-2026 three.js authors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/site/how/how.css b/site/how/how.css new file mode 100644 index 0000000..81f6489 --- /dev/null +++ b/site/how/how.css @@ -0,0 +1,458 @@ +/* Ask Key — "How it works" section. Everything is scoped under .akhw so it + can sit inside the existing site without touching its styles. */ + +@font-face { + font-family: "Hanken Grotesk"; + src: url("/fonts/HankenGrotesk-Variable.woff2") format("woff2"); + font-weight: 200 600; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: "IBM Plex Mono"; + src: url("/fonts/IBMPlexMono-Regular-Latin1.woff2") format("woff2"); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +/* Standalone page chrome (not needed when embedded in the site). */ +.akhw-page { + margin: 0; + background: #fff; + color: #1a1a1a; + font-family: "Hanken Grotesk", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", system-ui, sans-serif; + font-weight: 300; + -webkit-font-smoothing: antialiased; + overflow-x: hidden; +} +.akhw-bar, .akhw-foot { + display: flex; + align-items: center; + gap: 24px; + padding: 28px clamp(24px, 4.5vw, 64px); + font-size: 13.5px; + color: #6e6e6e; +} +.akhw-bar a, .akhw-foot a { color: inherit; text-decoration: none; } +.akhw-bar a:hover, .akhw-foot a:hover { color: #1a1a1a; } +.akhw-brand { display: flex; align-items: center; gap: 10px; margin-right: auto; color: #1a1a1a !important; font-weight: 400; } +.akhw-foot { justify-content: space-between; margin-top: 120px; border-top: 1px solid #e7e7e7; font-size: 12.5px; color: #9a9a9a; } + +/* Section */ + +.akhw { + --ink: #1a1a1a; + --gray: #6e6e6e; + --soft: #a1a1a6; + --faint: #9a9a9a; + --line: #e7e7e7; + --zhu: #b8281e; + --gutter: clamp(24px, 4.5vw, 64px); + --page: min(1200px, 100% - 2 * var(--gutter)); + --sans: "Hanken Grotesk", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", system-ui, sans-serif; + --song: "Songti SC", "Noto Serif CJK SC", "Source Han Serif SC", serif; + --mono: "IBM Plex Mono", "SF Mono", ui-monospace, Menlo, monospace; + position: relative; + margin-top: clamp(72px, 9vw, 140px); + font-family: var(--sans); + color: var(--ink); +} +.akhw *, .akhw *::before, .akhw *::after { box-sizing: border-box; } + +.akhw-head { width: var(--page); margin: 0 auto; } +.akhw-num { display: block; margin-bottom: 20px; font-family: var(--song); font-size: 15px; color: var(--zhu); } +.akhw-num span { margin-left: 14px; font-family: var(--sans); font-size: 12.5px; letter-spacing: 0.04em; color: var(--faint); } +.akhw-head h2 { + margin: 0; + font-weight: 300; + font-size: clamp(26px, 2.5vw, 34px); + line-height: 1.3; + letter-spacing: -0.01em; + text-wrap: balance; +} +.akhw:lang(zh) .akhw-head h2 { font-family: var(--song); letter-spacing: 0.04em; word-break: keep-all; } +.akhw-lede { margin: 10px 0 0; font-size: 15px; color: var(--gray); } + +/* Stage */ + +.akhw-stage { + position: relative; + width: 100%; + height: clamp(420px, min(56.25vw, 100svh - 260px), 760px); + margin: clamp(16px, 2.4vh, 28px) 0 0; + overflow: hidden; + isolation: isolate; + background: #fff; + color: var(--ink); + user-select: none; + -webkit-user-select: none; +} +.akhw-canvas { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + display: block; + opacity: 0; + transition: filter 0.9s ease, opacity 1.6s ease; +} +/* The room comes up out of the page's white. */ +.akhw.is-ready .akhw-canvas, .akhw.is-still .akhw-canvas { opacity: 1; } +.akhw.is-gate .akhw-canvas { filter: blur(6px) saturate(0.85) brightness(1.04); } +.akhw.is-gate.is-later .akhw-canvas { filter: none; } +/* No hard edge between the page and the room: the top and bottom of the + stage dissolve into white. */ +.akhw-stage::before { + content: ""; + position: absolute; + z-index: 1; + inset: 0; + /* The stage runs the full width of the window; only an object that + crosses its top or bottom edge is softened here. */ + background: + linear-gradient(to bottom, #fff, rgba(255, 255, 255, 0) 2.5%), + linear-gradient(to top, #fff, rgba(255, 255, 255, 0) 2.5%); + pointer-events: none; +} +.akhw-stage::after { + content: ""; + position: absolute; + z-index: 1; + left: 0; + top: 0; + width: min(62%, 860px); + height: 46%; + background: radial-gradient(ellipse 100% 100% at 0 0, rgba(255, 255, 255, 0.9) 0%, rgba(255, 255, 255, 0.62) 45%, rgba(255, 255, 255, 0) 100%); + pointer-events: none; +} +.akhw.is-still .akhw-stage::after, .akhw.no-gl .akhw-stage::after { display: none; } +.akhw-poster { display: none; position: absolute; inset: 0; } +.akhw-poster img { width: 100%; height: 100%; object-fit: cover; } +.akhw.no-gl .akhw-poster { display: block; } +.akhw.no-gl .akhw-canvas, .akhw.no-gl .akhw-tags, .akhw.no-gl .akhw-say { display: none; } + +.akhw-frame { position: relative; } + +/* Captions: one at a time, top-left like a film title card. */ +.akhw-say { + position: absolute; + z-index: 3; + left: calc((100% - var(--page)) / 2); + top: clamp(16px, 4%, 36px); + width: min(26em, 40%); + pointer-events: none; +} +.akhw-say p { + position: absolute; + left: 0; + top: 0; + margin: 0; + font-size: clamp(19px, 1.6vw, 24px); + font-weight: 300; + line-height: 1.25; + letter-spacing: -0.01em; + opacity: 0; + transform: translateY(10px); + transition: opacity 0.22s ease, transform 0.22s ease; +} +.akhw:lang(zh) .akhw-say p { font-family: var(--song); letter-spacing: 0.04em; line-height: 1.35; } +.akhw-say p { color: var(--ink); text-wrap: pretty; } +.akhw-say p span { display: block; margin-top: 0.5em; font-family: var(--sans); font-size: 15px; font-weight: 300; line-height: 1.65; letter-spacing: 0; color: var(--gray); } +.akhw-say p.on { opacity: 1; transform: none; transition: opacity 0.5s ease 0.24s, transform 0.7s cubic-bezier(0.2, 0.8, 0.2, 1) 0.24s; } + +/* Labels pinned to things in the scene. */ +.akhw-tags { position: absolute; inset: 0; z-index: 2; pointer-events: none; } +.akhw-tag { + position: absolute; + left: 0; + top: 0; + white-space: nowrap; + font-size: 13.5px; + line-height: 1.4; + text-align: center; + opacity: 0; + transition: opacity 0.5s ease; + will-change: transform, opacity; +} +.akhw-tag.on { opacity: 1; } +.akhw-tag b { display: block; font-weight: 500; color: var(--ink); font-size: 15px; } +.akhw-tag small { display: block; font-size: 13px; color: var(--gray); } +/* Names lie on the walnut itself, light like a film's lower third. */ +.akhw-tag.is-id { text-shadow: 0 1px 2px rgba(20, 12, 6, 0.55), 0 0 14px rgba(20, 12, 6, 0.35); } +.akhw-tag.is-id b { color: #f6f2ec; } +.akhw-tag.is-id small { color: rgba(246, 242, 236, 0.8); } +/* Paper labels: solid, so nothing has to re-blur the scene behind them. */ +.akhw-tag.is-pill { + padding: 5px 13px; + border-radius: 999px; + background: rgba(255, 255, 255, 0.94); + box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.1), 0 6px 18px -8px rgba(40, 50, 70, 0.35); + font-size: 14px; + font-weight: 500; + color: var(--ink); +} +.akhw-tag.is-pill.is-key { color: var(--zhu); } +.akhw-tag.is-pill.is-zero { font-size: 17px; padding: 8px 20px; } +.akhw-tag.is-pill.is-zero em { font-style: normal; font-variant-numeric: tabular-nums; color: var(--zhu); font-weight: 600; } + +/* The approval prompt: Ask Key's real alert layout, 300 pt wide. */ +.akhw-alert { + --s: 1.14; + position: absolute; + z-index: 5; + left: 50%; + top: 50%; + width: 300px; + padding: 24px 16px 14px; + border-radius: 14px; + background: rgba(236, 236, 236, 0.9); + -webkit-backdrop-filter: blur(30px) saturate(1.6); + backdrop-filter: blur(30px) saturate(1.6); + box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.22), 0 24px 60px -12px rgba(0, 0, 0, 0.35), 0 8px 18px -8px rgba(0, 0, 0, 0.2); + font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC", "Hiragino Sans GB", "Helvetica Neue", sans-serif; + font-size: 13px; + font-weight: 400; + line-height: 1.38; + color: #1d1d1f; + text-align: center; + transform: translate(-50%, -50%) scale(var(--s)); + transform-origin: 50% 50%; + user-select: text; + -webkit-user-select: text; +} +.akhw-alert[hidden] { display: none; } +.akhw-alert.enter { animation: akhw-alert-in 0.42s cubic-bezier(0.2, 0.9, 0.25, 1.15) both; } +.akhw-alert.leave { animation: akhw-alert-out 0.28s ease-in both; } +@keyframes akhw-alert-in { from { opacity: 0; transform: translate(-50%, -46%) scale(calc(var(--s) * 0.92)); } to { opacity: 1; transform: translate(-50%, -50%) scale(var(--s)); } } +@keyframes akhw-alert-out { to { opacity: 0; transform: translate(-50%, -50%) scale(calc(var(--s) * 0.96)); } } +.akhw-alert-icon { display: block; width: 64px; height: 64px; margin: 0 auto 12px; } +.akhw-alert strong { display: block; font-weight: 700; } +.akhw-alert-run { margin-top: 8px; } +.akhw-alert code { font-family: "SF Mono", ui-monospace, Menlo, monospace; font-size: 12px; } +.akhw-alert-details { + display: inline-flex; + align-items: center; + gap: 4px; + margin-top: 12px; + padding: 0; + border: 0; + background: none; + font: inherit; + color: #0a7aff; + cursor: pointer; +} +.akhw-alert-details svg { width: 9px; height: 9px; transition: transform 0.2s ease; } +.akhw-alert-details[aria-expanded="true"] svg { transform: rotate(90deg); } +.akhw-alert-rows { + display: grid; + grid-template-columns: auto minmax(0, 1fr); + gap: 6px 12px; + margin: 12px 0 0; + padding-top: 10px; + border-top: 1px solid rgba(0, 0, 0, 0.12); + text-align: left; +} +.akhw-alert-rows[hidden] { display: none; } +.akhw-alert-rows dt { color: #6e6e73; white-space: nowrap; } +.akhw-alert-rows dd { margin: 0; } +.akhw-alert-actions { display: grid; gap: 8px; margin-top: 16px; } +.akhw-btn { + height: 28px; + border: 0; + border-radius: 7px; + background: #fff; + box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.18), 0 0.5px 1px rgba(0, 0, 0, 0.14); + font: inherit; + color: #1d1d1f; + cursor: pointer; + transition: filter 0.12s ease, transform 0.12s ease; +} +.akhw-btn:hover { filter: brightness(0.97); } +.akhw-btn:active, .akhw-btn.pressed { filter: brightness(0.82); transform: scale(0.985); } +.akhw-btn.is-primary { background: #0a7aff; color: #fff; box-shadow: 0 0.5px 1px rgba(0, 0, 0, 0.2); } +.akhw-btn:focus-visible, .akhw-alert-details:focus-visible, .akhw-later:focus-visible { outline: 3px solid rgba(10, 122, 255, 0.5); outline-offset: 1px; } +.akhw-alert-foot { margin-top: 12px; font-size: 11px; color: #8a8a8e; } +.akhw-count { font-variant-numeric: tabular-nums; } +.akhw-later { padding: 0; border: 0; background: none; font: inherit; color: inherit; cursor: pointer; } +.akhw-later:hover { color: #1d1d1f; } +.akhw.is-hinting .akhw-btn.is-primary { animation: akhw-nudge 2.4s ease-in-out infinite; } +@keyframes akhw-nudge { 0%, 70%, 100% { box-shadow: 0 0.5px 1px rgba(0, 0, 0, 0.2), 0 0 0 0 rgba(10, 122, 255, 0.45); } 85% { box-shadow: 0 0.5px 1px rgba(0, 0, 0, 0.2), 0 0 0 7px rgba(10, 122, 255, 0); } } + +.akhw-hint { + position: absolute; + z-index: 5; + left: 50%; + bottom: clamp(18px, 5%, 48px); + margin: 0; + transform: translateX(-50%); + font-size: 13px; + color: var(--gray); + white-space: nowrap; +} +.akhw-hint[hidden] { display: none; } +.akhw-pending { + position: absolute; + z-index: 5; + right: calc((100% - var(--page)) / 2); + top: clamp(20px, 5%, 44px); + padding: 8px 16px; + border: 0; + border-radius: 999px; + background: rgba(236, 236, 236, 0.92); + box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.12), 0 10px 26px -12px rgba(40, 50, 70, 0.45); + font: inherit; + font-size: 13.5px; + font-weight: 400; + color: var(--ink); + cursor: pointer; +} +.akhw-pending::before { content: ""; display: inline-block; width: 7px; height: 7px; margin-right: 9px; border-radius: 50%; background: var(--zhu); vertical-align: 1px; animation: akhw-blink 1.4s ease-in-out infinite; } +@keyframes akhw-blink { 50% { opacity: 0.25; } } +.akhw-pending[hidden] { display: none; } + +.akhw-end { + position: absolute; + z-index: 4; + left: calc((100% - var(--page)) / 2); + bottom: clamp(18px, 5%, 40px); + display: flex; + flex-wrap: wrap; + gap: 12px; +} +.akhw-end[hidden] { display: none; } +.akhw-end button, .akhw-play { + padding: 8px 18px; + border: 1px solid var(--zhu); + border-radius: 999px; + background: rgba(255, 255, 255, 0.86); + font: inherit; + font-size: 14px; + font-weight: 400; + color: var(--zhu); + cursor: pointer; + transition: background 0.2s ease, color 0.2s ease; +} +.akhw-end button:hover, .akhw-play:hover { background: var(--zhu); color: #fff; } +.akhw-end .akhw-other { border-color: rgba(26, 26, 26, 0.22); color: var(--ink); } +.akhw-end .akhw-other:hover { background: var(--ink); border-color: var(--ink); color: #fff; } +.akhw-play { position: absolute; z-index: 4; left: 50%; bottom: clamp(18px, 5%, 48px); transform: translateX(-50%); } +.akhw-play[hidden] { display: none; } +.akhw button:focus-visible { outline: 1px solid var(--zhu); outline-offset: 4px; } + +/* Chapter rail. Holds the full story as real text; in the animated telling + the text is visually hidden and shown one line at a time as a caption. */ +.akhw-steps { + display: grid; + grid-template-columns: repeat(6, minmax(0, 1fr)); + gap: 0 clamp(10px, 1.6vw, 24px); + width: var(--page); + margin: 10px auto 0; + padding: 0; + list-style: none; +} +.akhw-steps button { + position: relative; + width: 100%; + padding: 6px 0 12px; + border: 0; + background: none; + font: inherit; + font-size: 13.5px; + font-weight: 400; + text-align: left; + color: var(--faint); + cursor: pointer; +} +.akhw-steps button b { font-weight: 400; } +.akhw-steps button:hover, .akhw-steps li.on button { color: var(--ink); } +.akhw-steps button i { position: absolute; left: 0; right: 0; bottom: 0; height: 1px; background: var(--line); } +.akhw-steps button i::after { content: ""; position: absolute; inset: 0; background: var(--zhu); transform-origin: 0 50%; transform: scaleX(var(--fill, 0)); } +.akhw-steps p { + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip-path: inset(50%); + white-space: nowrap; +} +.akhw-steps p span { color: var(--gray); } +.akhw-steps p[data-when] { display: none; } +.akhw[data-outcome="allow"] .akhw-steps p[data-when="allow"], +.akhw[data-outcome="timed"] .akhw-steps p[data-when="timed"], +.akhw[data-outcome="timed"] .akhw-steps li[data-step="5"] p[data-when="allow"], +.akhw[data-outcome="deny"] .akhw-steps p[data-when="deny"], +.akhw[data-outcome="expire"] .akhw-steps p[data-when="expire"] { display: block; } + +.akhw-note { + width: var(--page); + max-width: 760px; + margin: 28px auto 0; + font-size: 13px; + line-height: 1.7; + text-align: center; + color: var(--faint); +} + +/* Still telling: reduced motion, or no WebGL. The stage shows one composed + frame and the rail becomes a readable list of all six steps. */ +.akhw.is-still .akhw-steps { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px clamp(20px, 3vw, 44px); margin-top: 32px; } +.akhw.is-still .akhw-steps button { color: var(--ink); cursor: default; pointer-events: none; } +.akhw.is-still .akhw-steps button i::after { transform: scaleX(1); } +.akhw.is-still .akhw-steps p { + position: static; + width: auto; + height: auto; + overflow: visible; + clip-path: none; + white-space: normal; + margin: 12px 0 0; + font-size: 15px; + line-height: 1.6; +} +.akhw.is-still .akhw-say, .akhw.is-still .akhw-play { display: none; } +.akhw.is-still .akhw-alert { animation: none; } + +.akhw-still-alert { display: flex; justify-content: center; width: var(--page); margin: 32px auto 0; } +.akhw-still-alert .akhw-alert { position: static; transform: none; animation: none; box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.22), 0 12px 30px -12px rgba(0, 0, 0, 0.3); } + +/* On wide, landscape screens the whole chapter, title to rail, fits one + screen. Portrait tablets keep their natural height instead of padding + the scene with empty space. */ +@media (min-width: 701px) and (min-aspect-ratio: 1 / 1) { + .akhw:not(.is-still) { min-height: min(100svh, 980px); display: flex; flex-direction: column; justify-content: center; } +} + +/* Phones and portrait tablets: the scene is recomposed upright by the + script; here the caption moves under the scene so it never covers it. */ +@media (max-width: 700px), (max-aspect-ratio: 1 / 1) { + .akhw-stage { width: 100%; height: clamp(520px, 78svh, 760px); } + .akhw-stage::after { display: none; } + .akhw-say { + position: relative; + left: auto; + top: auto; + width: auto; + height: 7.2em; + margin: 18px var(--gutter) 0; + } + .akhw-say p { font-size: 22px; right: 0; color: var(--ink); } + .akhw-say p span { color: var(--gray); } + .akhw-alert { --s: 1; width: 280px; padding: 20px 14px 12px; } + .akhw-alert-icon { width: 52px; height: 52px; margin-bottom: 10px; } + .akhw-steps { gap: 0 8px; } + .akhw-steps button { font-size: 12.5px; } + .akhw.is-still .akhw-steps { grid-template-columns: minmax(0, 1fr); gap: 18px; } + .akhw-tag { font-size: 11.5px; } + .akhw-tag b { font-size: 12.5px; } + .akhw-tag.is-pill { font-size: 12px; padding: 4px 10px; } + .akhw-tag.is-pill.is-zero { font-size: 13px; padding: 6px 13px; } + .akhw-end { left: 50%; transform: translateX(-50%); flex-wrap: nowrap; } + .akhw-end button { white-space: nowrap; font-size: 13.5px; padding: 8px 14px; } + .akhw-bar, .akhw-foot { padding: 20px var(--gutter, 24px); } + .akhw-foot { flex-direction: column; align-items: flex-start; gap: 8px; } +} +/* Portrait tablets: a square stage, so the upright composition has room. */ +@media (min-width: 701px) and (max-aspect-ratio: 1 / 1) { + .akhw-stage { height: min(100vw, 80svh); } +} diff --git a/site/how/how.js b/site/how/how.js new file mode 100644 index 0000000..ea6c48d --- /dev/null +++ b/site/how/how.js @@ -0,0 +1,4279 @@ +/*! Ask Key: How it works. Includes three.js r186, MIT License, Copyright 2010-2026 three.js authors; full text in THREE-LICENSE.txt next to this file. */ +var Uh=0,Xl=1,Fh=2;var Tr=1,Oh=2,Ts=3,ln=0,It=1,kt=2,Bn=0,ws=1,ql=2,Yl=3,Zl=4,io=5;var Li=100,Bh=101,zh=102,kh=103,Vh=104,Hh=200,so=201,Gh=202,Wh=203,wr=204,As=205,Xh=206,qh=207,Yh=208,Zh=209,Jh=210,$h=211,Kh=212,Qh=213,jh=214,Sa=0,ba=1,Ea=2,rs=3,Ta=4,wa=5,Aa=6,Ra=7,Jl=0,eu=1,tu=2,bn=0,$l=1,Kl=2,Ql=3,jl=4,ec=5,tc=6,Ar=7;var nc=300,xi=301,Di=302,ro=303,ao=304,Rr=306,as=1e3,In=1001,Ca=1002,Ut=1003,nu=1004;var Cr=1005;var zt=1006,oo=1007;var zn=1008;var tn=1009,ic=1010,sc=1011,Rs=1012,lo=1013,En=1014,Tn=1015,wn=1016,co=1017,ho=1018,Cs=1020,rc=35902,ac=35899,oc=1021,lc=1022,fn=1023,Dn=1026,vi=1027,cc=1028,uo=1029,yi=1030,fo=1031;var po=1033,Pr=33776,Ir=33777,Lr=33778,Dr=33779,mo=35840,go=35841,_o=35842,xo=35843,vo=36196,yo=37492,Mo=37496,So=37488,bo=37489,Nr=37490,Eo=37491,To=37808,wo=37809,Ao=37810,Ro=37811,Co=37812,Po=37813,Io=37814,Lo=37815,Do=37816,No=37817,Uo=37818,Fo=37819,Oo=37820,Bo=37821,zo=36492,ko=36494,Vo=36495,Ho=36283,Go=36284,Ur=36285,Wo=36286;var Js=2300,Pa=2301,va=2302,Nl=2303,Ul=2400,Fl=2401,Ol=2402;var iu=3200;var Xo=0,su=1,ti="",St="srgb",$s="srgb-linear",Ks="linear",ht="srgb";var ya=7680;var ru=519,au=512,ou=513,lu=514,qo=515,cu=516,hu=517,Yo=518,uu=519,hc=35044;var uc="300 es",Mn=2e3,os=2001;function Ud(i){for(let e=i.length-1;e>=0;--e)if(i[e]>=65535)return!0;return!1}function Fd(i){return ArrayBuffer.isView(i)&&!(i instanceof DataView)}function ls(i){return document.createElementNS("http://www.w3.org/1999/xhtml",i)}function du(){let i=ls("canvas");return i.style.display="block",i}var nh={},cs=null;function Qs(...i){let e="THREE."+i.shift();cs?cs("log",e,...i):console.log(e,...i)}function fu(i){let e=i[0];if(typeof e=="string"&&e.startsWith("TSL:")){let t=i[1];t&&t.isStackTrace?i[0]+=" "+t.getLocation():i[1]='Stack trace not available. Enable "THREE.Node.captureStackTrace" to capture stack traces.'}return i}function Ge(...i){i=fu(i);let e="THREE."+i.shift();if(cs)cs("warn",e,...i);else{let t=i[0];t&&t.isStackTrace?console.warn(t.getError(e)):console.warn(e,...i)}}function We(...i){i=fu(i);let e="THREE."+i.shift();if(cs)cs("error",e,...i);else{let t=i[0];t&&t.isStackTrace?console.error(t.getError(e)):console.error(e,...i)}}function Ri(...i){let e=i.join(" ");e in nh||(nh[e]=!0,Ge(...i))}function pu(i,e,t){return new Promise(function(n,s){function r(){switch(i.clientWaitSync(e,i.SYNC_FLUSH_COMMANDS_BIT,0)){case i.WAIT_FAILED:s();break;case i.TIMEOUT_EXPIRED:setTimeout(r,t);break;default:n()}}setTimeout(r,t)})}var mu={[Sa]:ba,[Ea]:Aa,[Ta]:Ra,[rs]:wa,[ba]:Sa,[Aa]:Ea,[Ra]:Ta,[wa]:rs},Nn=class{addEventListener(e,t){this._listeners===void 0&&(this._listeners={});let n=this._listeners;n[e]===void 0&&(n[e]=[]),n[e].indexOf(t)===-1&&n[e].push(t)}hasEventListener(e,t){let n=this._listeners;return n===void 0?!1:n[e]!==void 0&&n[e].indexOf(t)!==-1}removeEventListener(e,t){let n=this._listeners;if(n===void 0)return;let s=n[e];if(s!==void 0){let r=s.indexOf(t);r!==-1&&s.splice(r,1)}}dispatchEvent(e){let t=this._listeners;if(t===void 0)return;let n=t[e.type];if(n!==void 0){e.target=this;let s=n.slice(0);for(let r=0,a=s.length;r>8&255]+Gt[i>>16&255]+Gt[i>>24&255]+"-"+Gt[e&255]+Gt[e>>8&255]+"-"+Gt[e>>16&15|64]+Gt[e>>24&255]+"-"+Gt[t&63|128]+Gt[t>>8&255]+"-"+Gt[t>>16&255]+Gt[t>>24&255]+Gt[n&255]+Gt[n>>8&255]+Gt[n>>16&255]+Gt[n>>24&255]).toLowerCase()}function tt(i,e,t){return Math.max(e,Math.min(t,i))}function dc(i,e){return(i%e+e)%e}function Od(i,e,t,n,s){return n+(i-e)*(s-n)/(t-e)}function Bd(i,e,t){return i!==e?(t-i)/(e-i):0}function qs(i,e,t){return(1-t)*i+t*e}function zd(i,e,t,n){return qs(i,e,1-Math.exp(-t*n))}function kd(i,e=1){return e-Math.abs(dc(i,e*2)-e)}function Vd(i,e,t){return i<=e?0:i>=t?1:(i=(i-e)/(t-e),i*i*(3-2*i))}function Hd(i,e,t){return i<=e?0:i>=t?1:(i=(i-e)/(t-e),i*i*i*(i*(i*6-15)+10))}function Gd(i,e){return i+Math.floor(Math.random()*(e-i+1))}function Wd(i,e){return i+Math.random()*(e-i)}function Xd(i){return i*(.5-Math.random())}function qd(i){i!==void 0&&(ih=i);let e=ih+=1831565813;return e=Math.imul(e^e>>>15,e|1),e^=e+Math.imul(e^e>>>7,e|61),((e^e>>>14)>>>0)/4294967296}function Yd(i){return i*Xs}function Zd(i){return i*hs}function Jd(i){return i>0&&Number.isInteger(i)&&2**Math.round(Math.log2(i))===i}function $d(i){return Math.pow(2,Math.ceil(Math.log(i)/Math.LN2))}function Kd(i){return Math.pow(2,Math.floor(Math.log(i)/Math.LN2))}function Qd(i,e,t,n,s){let r=Math.cos,a=Math.sin,o=r(t/2),l=a(t/2),c=r((e+n)/2),h=a((e+n)/2),u=r((e-n)/2),d=a((e-n)/2),f=r((n-e)/2),m=a((n-e)/2);switch(s){case"XYX":i.set(o*h,l*u,l*d,o*c);break;case"YZY":i.set(l*d,o*h,l*u,o*c);break;case"ZXZ":i.set(l*u,l*d,o*h,o*c);break;case"XZX":i.set(o*h,l*m,l*f,o*c);break;case"YXY":i.set(l*f,o*h,l*m,o*c);break;case"ZYZ":i.set(l*m,l*f,o*h,o*c);break;default:Ge("MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+s)}}function yn(i,e){switch(e.constructor){case Float32Array:return i;case Uint32Array:return i/4294967295;case Uint16Array:return i/65535;case Uint8Array:case Uint8ClampedArray:return i/255;case Int32Array:return Math.max(i/2147483647,-1);case Int16Array:return Math.max(i/32767,-1);case Int8Array:return Math.max(i/127,-1);default:throw new Error("THREE.MathUtils: Invalid component type.")}}function ut(i,e){switch(e.constructor){case Float32Array:return i;case Uint32Array:return Math.round(i*4294967295);case Uint16Array:return Math.round(i*65535);case Uint8Array:case Uint8ClampedArray:return Math.round(i*255);case Int32Array:return Math.round(i*2147483647);case Int16Array:return Math.round(i*32767);case Int8Array:return Math.round(i*127);default:throw new Error("THREE.MathUtils: Invalid component type.")}}var Fr={DEG2RAD:Xs,RAD2DEG:hs,generateUUID:Ln,clamp:tt,euclideanModulo:dc,mapLinear:Od,inverseLerp:Bd,lerp:qs,damp:zd,pingpong:kd,smoothstep:Vd,smootherstep:Hd,randInt:Gd,randFloat:Wd,randFloatSpread:Xd,seededRandom:qd,degToRad:Yd,radToDeg:Zd,isPowerOfTwo:Jd,ceilPowerOfTwo:$d,floorPowerOfTwo:Kd,setQuaternionFromProperEuler:Qd,normalize:ut,denormalize:yn},xc=class xc{constructor(e=0,t=0){this.x=e,this.y=t}get width(){return this.x}set width(e){this.x=e}get height(){return this.y}set height(e){this.y=e}set(e,t){return this.x=e,this.y=t,this}setScalar(e){return this.x=e,this.y=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;default:throw new Error("THREE.Vector2: index is out of range: "+e)}return this}getComponent(e){switch(e){case 0:return this.x;case 1:return this.y;default:throw new Error("THREE.Vector2: index is out of range: "+e)}}clone(){return new this.constructor(this.x,this.y)}copy(e){return this.x=e.x,this.y=e.y,this}add(e){return this.x+=e.x,this.y+=e.y,this}addScalar(e){return this.x+=e,this.y+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this}subScalar(e){return this.x-=e,this.y-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this}multiply(e){return this.x*=e.x,this.y*=e.y,this}multiplyScalar(e){return this.x*=e,this.y*=e,this}divide(e){return this.x/=e.x,this.y/=e.y,this}divideScalar(e){return this.multiplyScalar(1/e)}applyMatrix3(e){let t=this.x,n=this.y,s=e.elements;return this.x=s[0]*t+s[3]*n+s[6],this.y=s[1]*t+s[4]*n+s[7],this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this}clamp(e,t){return this.x=tt(this.x,e.x,t.x),this.y=tt(this.y,e.y,t.y),this}clampScalar(e,t){return this.x=tt(this.x,e,t),this.y=tt(this.y,e,t),this}clampLength(e,t){let n=this.length();return this.divideScalar(n||1).multiplyScalar(tt(n,e,t))}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(e){return this.x*e.x+this.y*e.y}cross(e){return this.x*e.y-this.y*e.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(e){let t=Math.sqrt(this.lengthSq()*e.lengthSq());if(t===0)return Math.PI/2;let n=this.dot(e)/t;return Math.acos(tt(n,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){let t=this.x-e.x,n=this.y-e.y;return t*t+n*n}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)}setLength(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this}equals(e){return e.x===this.x&&e.y===this.y}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this}rotateAround(e,t){let n=Math.cos(t),s=Math.sin(t),r=this.x-e.x,a=this.y-e.y;return this.x=r*n-a*s+e.x,this.y=r*s+a*n+e.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}};xc.prototype.isVector2=!0;var ue=xc,qt=class{constructor(e=0,t=0,n=0,s=1){this.isQuaternion=!0,this._x=e,this._y=t,this._z=n,this._w=s}static slerpFlat(e,t,n,s,r,a,o){let l=n[s+0],c=n[s+1],h=n[s+2],u=n[s+3],d=r[a+0],f=r[a+1],m=r[a+2],v=r[a+3];if(u!==v||l!==d||c!==f||h!==m){let g=l*d+c*f+h*m+u*v;g<0&&(d=-d,f=-f,m=-m,v=-v,g=-g);let p=1-o;if(g<.9995){let T=Math.acos(g),w=Math.sin(T);p=Math.sin(p*T)/w,o=Math.sin(o*T)/w,l=l*p+d*o,c=c*p+f*o,h=h*p+m*o,u=u*p+v*o}else{l=l*p+d*o,c=c*p+f*o,h=h*p+m*o,u=u*p+v*o;let T=1/Math.sqrt(l*l+c*c+h*h+u*u);l*=T,c*=T,h*=T,u*=T}}e[t]=l,e[t+1]=c,e[t+2]=h,e[t+3]=u}static multiplyQuaternionsFlat(e,t,n,s,r,a){let o=n[s],l=n[s+1],c=n[s+2],h=n[s+3],u=r[a],d=r[a+1],f=r[a+2],m=r[a+3];return e[t]=o*m+h*u+l*f-c*d,e[t+1]=l*m+h*d+c*u-o*f,e[t+2]=c*m+h*f+o*d-l*u,e[t+3]=h*m-o*u-l*d-c*f,e}get x(){return this._x}set x(e){this._x=e,this._onChangeCallback()}get y(){return this._y}set y(e){this._y=e,this._onChangeCallback()}get z(){return this._z}set z(e){this._z=e,this._onChangeCallback()}get w(){return this._w}set w(e){this._w=e,this._onChangeCallback()}set(e,t,n,s){return this._x=e,this._y=t,this._z=n,this._w=s,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(e){return this._x=e.x,this._y=e.y,this._z=e.z,this._w=e.w,this._onChangeCallback(),this}setFromEuler(e,t=!0){let n=e._x,s=e._y,r=e._z,a=e._order,o=Math.cos,l=Math.sin,c=o(n/2),h=o(s/2),u=o(r/2),d=l(n/2),f=l(s/2),m=l(r/2);switch(a){case"XYZ":this._x=d*h*u+c*f*m,this._y=c*f*u-d*h*m,this._z=c*h*m+d*f*u,this._w=c*h*u-d*f*m;break;case"YXZ":this._x=d*h*u+c*f*m,this._y=c*f*u-d*h*m,this._z=c*h*m-d*f*u,this._w=c*h*u+d*f*m;break;case"ZXY":this._x=d*h*u-c*f*m,this._y=c*f*u+d*h*m,this._z=c*h*m+d*f*u,this._w=c*h*u-d*f*m;break;case"ZYX":this._x=d*h*u-c*f*m,this._y=c*f*u+d*h*m,this._z=c*h*m-d*f*u,this._w=c*h*u+d*f*m;break;case"YZX":this._x=d*h*u+c*f*m,this._y=c*f*u+d*h*m,this._z=c*h*m-d*f*u,this._w=c*h*u-d*f*m;break;case"XZY":this._x=d*h*u-c*f*m,this._y=c*f*u-d*h*m,this._z=c*h*m+d*f*u,this._w=c*h*u+d*f*m;break;default:Ge("Quaternion: .setFromEuler() encountered an unknown order: "+a)}return t===!0&&this._onChangeCallback(),this}setFromAxisAngle(e,t){let n=t/2,s=Math.sin(n);return this._x=e.x*s,this._y=e.y*s,this._z=e.z*s,this._w=Math.cos(n),this._onChangeCallback(),this}setFromRotationMatrix(e){let t=e.elements,n=t[0],s=t[4],r=t[8],a=t[1],o=t[5],l=t[9],c=t[2],h=t[6],u=t[10],d=n+o+u;if(d>0){let f=.5/Math.sqrt(d+1);this._w=.25/f,this._x=(h-l)*f,this._y=(r-c)*f,this._z=(a-s)*f}else if(n>o&&n>u){let f=2*Math.sqrt(1+n-o-u);this._w=(h-l)/f,this._x=.25*f,this._y=(s+a)/f,this._z=(r+c)/f}else if(o>u){let f=2*Math.sqrt(1+o-n-u);this._w=(r-c)/f,this._x=(s+a)/f,this._y=.25*f,this._z=(l+h)/f}else{let f=2*Math.sqrt(1+u-n-o);this._w=(a-s)/f,this._x=(r+c)/f,this._y=(l+h)/f,this._z=.25*f}return this._onChangeCallback(),this}setFromUnitVectors(e,t){let n=e.dot(t)+1;return n<1e-8?(n=0,Math.abs(e.x)>Math.abs(e.z)?(this._x=-e.y,this._y=e.x,this._z=0,this._w=n):(this._x=0,this._y=-e.z,this._z=e.y,this._w=n)):(this._x=e.y*t.z-e.z*t.y,this._y=e.z*t.x-e.x*t.z,this._z=e.x*t.y-e.y*t.x,this._w=n),this.normalize()}angleTo(e){return 2*Math.acos(Math.abs(tt(this.dot(e),-1,1)))}rotateTowards(e,t){let n=this.angleTo(e);if(n===0)return this;let s=Math.min(1,t/n);return this.slerp(e,s),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(e){return this._x*e._x+this._y*e._y+this._z*e._z+this._w*e._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 e=this.length();return e===0?(this._x=0,this._y=0,this._z=0,this._w=1):(e=1/e,this._x=this._x*e,this._y=this._y*e,this._z=this._z*e,this._w=this._w*e),this._onChangeCallback(),this}multiply(e){return this.multiplyQuaternions(this,e)}premultiply(e){return this.multiplyQuaternions(e,this)}multiplyQuaternions(e,t){let n=e._x,s=e._y,r=e._z,a=e._w,o=t._x,l=t._y,c=t._z,h=t._w;return this._x=n*h+a*o+s*c-r*l,this._y=s*h+a*l+r*o-n*c,this._z=r*h+a*c+n*l-s*o,this._w=a*h-n*o-s*l-r*c,this._onChangeCallback(),this}slerp(e,t){let n=e._x,s=e._y,r=e._z,a=e._w,o=this.dot(e);o<0&&(n=-n,s=-s,r=-r,a=-a,o=-o);let l=1-t;if(o<.9995){let c=Math.acos(o),h=Math.sin(c);l=Math.sin(l*c)/h,t=Math.sin(t*c)/h,this._x=this._x*l+n*t,this._y=this._y*l+s*t,this._z=this._z*l+r*t,this._w=this._w*l+a*t,this._onChangeCallback()}else this._x=this._x*l+n*t,this._y=this._y*l+s*t,this._z=this._z*l+r*t,this._w=this._w*l+a*t,this.normalize();return this}slerpQuaternions(e,t,n){return this.copy(e).slerp(t,n)}random(){let e=2*Math.PI*Math.random(),t=2*Math.PI*Math.random(),n=Math.random(),s=Math.sqrt(1-n),r=Math.sqrt(n);return this.set(s*Math.sin(e),s*Math.cos(e),r*Math.sin(t),r*Math.cos(t))}equals(e){return e._x===this._x&&e._y===this._y&&e._z===this._z&&e._w===this._w}fromArray(e,t=0){return this._x=e[t],this._y=e[t+1],this._z=e[t+2],this._w=e[t+3],this._onChangeCallback(),this}toArray(e=[],t=0){return e[t]=this._x,e[t+1]=this._y,e[t+2]=this._z,e[t+3]=this._w,e}fromBufferAttribute(e,t){return this._x=e.getX(t),this._y=e.getY(t),this._z=e.getZ(t),this._w=e.getW(t),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(e){return this._onChangeCallback=e,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}},vc=class vc{constructor(e=0,t=0,n=0){this.x=e,this.y=t,this.z=n}set(e,t,n){return n===void 0&&(n=this.z),this.x=e,this.y=t,this.z=n,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;default:throw new Error("THREE.Vector3: index is out of range: "+e)}return this}getComponent(e){switch(e){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: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this}multiplyVectors(e,t){return this.x=e.x*t.x,this.y=e.y*t.y,this.z=e.z*t.z,this}applyEuler(e){return this.applyQuaternion(sh.setFromEuler(e))}applyAxisAngle(e,t){return this.applyQuaternion(sh.setFromAxisAngle(e,t))}applyMatrix3(e){let t=this.x,n=this.y,s=this.z,r=e.elements;return this.x=r[0]*t+r[3]*n+r[6]*s,this.y=r[1]*t+r[4]*n+r[7]*s,this.z=r[2]*t+r[5]*n+r[8]*s,this}applyNormalMatrix(e){return this.applyMatrix3(e).normalize()}applyMatrix4(e){let t=this.x,n=this.y,s=this.z,r=e.elements,a=1/(r[3]*t+r[7]*n+r[11]*s+r[15]);return this.x=(r[0]*t+r[4]*n+r[8]*s+r[12])*a,this.y=(r[1]*t+r[5]*n+r[9]*s+r[13])*a,this.z=(r[2]*t+r[6]*n+r[10]*s+r[14])*a,this}applyQuaternion(e){let t=this.x,n=this.y,s=this.z,r=e.x,a=e.y,o=e.z,l=e.w,c=2*(a*s-o*n),h=2*(o*t-r*s),u=2*(r*n-a*t);return this.x=t+l*c+a*u-o*h,this.y=n+l*h+o*c-r*u,this.z=s+l*u+r*h-a*c,this}project(e){return this.applyMatrix4(e.matrixWorldInverse).applyMatrix4(e.projectionMatrix)}unproject(e){return this.applyMatrix4(e.projectionMatrixInverse).applyMatrix4(e.matrixWorld)}transformDirection(e){let t=this.x,n=this.y,s=this.z,r=e.elements;return this.x=r[0]*t+r[4]*n+r[8]*s,this.y=r[1]*t+r[5]*n+r[9]*s,this.z=r[2]*t+r[6]*n+r[10]*s,this.normalize()}divide(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this}divideScalar(e){return this.multiplyScalar(1/e)}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this}clamp(e,t){return this.x=tt(this.x,e.x,t.x),this.y=tt(this.y,e.y,t.y),this.z=tt(this.z,e.z,t.z),this}clampScalar(e,t){return this.x=tt(this.x,e,t),this.y=tt(this.y,e,t),this.z=tt(this.z,e,t),this}clampLength(e,t){let n=this.length();return this.divideScalar(n||1).multiplyScalar(tt(n,e,t))}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(e){return this.x*e.x+this.y*e.y+this.z*e.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(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this.z=e.z+(t.z-e.z)*n,this}cross(e){return this.crossVectors(this,e)}crossVectors(e,t){let n=e.x,s=e.y,r=e.z,a=t.x,o=t.y,l=t.z;return this.x=s*l-r*o,this.y=r*a-n*l,this.z=n*o-s*a,this}projectOnVector(e){let t=e.lengthSq();if(t===0)return this.set(0,0,0);let n=e.dot(this)/t;return this.copy(e).multiplyScalar(n)}projectOnPlane(e){return cl.copy(this).projectOnVector(e),this.sub(cl)}reflect(e){return this.sub(cl.copy(e).multiplyScalar(2*this.dot(e)))}angleTo(e){let t=Math.sqrt(this.lengthSq()*e.lengthSq());if(t===0)return Math.PI/2;let n=this.dot(e)/t;return Math.acos(tt(n,-1,1))}distanceTo(e){return Math.sqrt(this.distanceToSquared(e))}distanceToSquared(e){let t=this.x-e.x,n=this.y-e.y,s=this.z-e.z;return t*t+n*n+s*s}manhattanDistanceTo(e){return Math.abs(this.x-e.x)+Math.abs(this.y-e.y)+Math.abs(this.z-e.z)}setFromSpherical(e){return this.setFromSphericalCoords(e.radius,e.phi,e.theta)}setFromSphericalCoords(e,t,n){let s=Math.sin(t)*e;return this.x=s*Math.sin(n),this.y=Math.cos(t)*e,this.z=s*Math.cos(n),this}setFromCylindrical(e){return this.setFromCylindricalCoords(e.radius,e.theta,e.y)}setFromCylindricalCoords(e,t,n){return this.x=e*Math.sin(t),this.y=n,this.z=e*Math.cos(t),this}setFromMatrixPosition(e){let t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this}setFromMatrixScale(e){let t=this.setFromMatrixColumn(e,0).length(),n=this.setFromMatrixColumn(e,1).length(),s=this.setFromMatrixColumn(e,2).length();return this.x=t,this.y=n,this.z=s,this}setFromMatrixColumn(e,t){return this.fromArray(e.elements,t*4)}setFromMatrix3Column(e,t){return this.fromArray(e.elements,t*3)}setFromEuler(e){return this.x=e._x,this.y=e._y,this.z=e._z,this}setFromColor(e){return this.x=e.r,this.y=e.g,this.z=e.b,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){let e=Math.random()*Math.PI*2,t=Math.random()*2-1,n=Math.sqrt(1-t*t);return this.x=n*Math.cos(e),this.y=t,this.z=n*Math.sin(e),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}};vc.prototype.isVector3=!0;var I=vc,cl=new I,sh=new qt,yc=class yc{constructor(e,t,n,s,r,a,o,l,c){this.elements=[1,0,0,0,1,0,0,0,1],e!==void 0&&this.set(e,t,n,s,r,a,o,l,c)}set(e,t,n,s,r,a,o,l,c){let h=this.elements;return h[0]=e,h[1]=s,h[2]=o,h[3]=t,h[4]=r,h[5]=l,h[6]=n,h[7]=a,h[8]=c,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(e){let t=this.elements,n=e.elements;return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],this}extractBasis(e,t,n){return e.setFromMatrix3Column(this,0),t.setFromMatrix3Column(this,1),n.setFromMatrix3Column(this,2),this}setFromMatrix4(e){let t=e.elements;return this.set(t[0],t[4],t[8],t[1],t[5],t[9],t[2],t[6],t[10]),this}multiply(e){return this.multiplyMatrices(this,e)}premultiply(e){return this.multiplyMatrices(e,this)}multiplyMatrices(e,t){let n=e.elements,s=t.elements,r=this.elements,a=n[0],o=n[3],l=n[6],c=n[1],h=n[4],u=n[7],d=n[2],f=n[5],m=n[8],v=s[0],g=s[3],p=s[6],T=s[1],w=s[4],M=s[7],b=s[2],S=s[5],R=s[8];return r[0]=a*v+o*T+l*b,r[3]=a*g+o*w+l*S,r[6]=a*p+o*M+l*R,r[1]=c*v+h*T+u*b,r[4]=c*g+h*w+u*S,r[7]=c*p+h*M+u*R,r[2]=d*v+f*T+m*b,r[5]=d*g+f*w+m*S,r[8]=d*p+f*M+m*R,this}multiplyScalar(e){let t=this.elements;return t[0]*=e,t[3]*=e,t[6]*=e,t[1]*=e,t[4]*=e,t[7]*=e,t[2]*=e,t[5]*=e,t[8]*=e,this}determinant(){let e=this.elements,t=e[0],n=e[1],s=e[2],r=e[3],a=e[4],o=e[5],l=e[6],c=e[7],h=e[8];return t*a*h-t*o*c-n*r*h+n*o*l+s*r*c-s*a*l}invert(){let e=this.elements,t=e[0],n=e[1],s=e[2],r=e[3],a=e[4],o=e[5],l=e[6],c=e[7],h=e[8],u=h*a-o*c,d=o*l-h*r,f=c*r-a*l,m=t*u+n*d+s*f;if(m===0)return this.set(0,0,0,0,0,0,0,0,0);let v=1/m;return e[0]=u*v,e[1]=(s*c-h*n)*v,e[2]=(o*n-s*a)*v,e[3]=d*v,e[4]=(h*t-s*l)*v,e[5]=(s*r-o*t)*v,e[6]=f*v,e[7]=(n*l-c*t)*v,e[8]=(a*t-n*r)*v,this}transpose(){let e,t=this.elements;return e=t[1],t[1]=t[3],t[3]=e,e=t[2],t[2]=t[6],t[6]=e,e=t[5],t[5]=t[7],t[7]=e,this}getNormalMatrix(e){return this.setFromMatrix4(e).invert().transpose()}transposeIntoArray(e){let t=this.elements;return e[0]=t[0],e[1]=t[3],e[2]=t[6],e[3]=t[1],e[4]=t[4],e[5]=t[7],e[6]=t[2],e[7]=t[5],e[8]=t[8],this}setUvTransform(e,t,n,s,r,a,o){let l=Math.cos(r),c=Math.sin(r);return this.set(n*l,n*c,-n*(l*a+c*o)+a+e,-s*c,s*l,-s*(-c*a+l*o)+o+t,0,0,1),this}scale(e,t){return Ri("Matrix3: .scale() is deprecated. Use .makeScale() instead."),this.premultiply(hl.makeScale(e,t)),this}rotate(e){return Ri("Matrix3: .rotate() is deprecated. Use .makeRotation() instead."),this.premultiply(hl.makeRotation(-e)),this}translate(e,t){return Ri("Matrix3: .translate() is deprecated. Use .makeTranslation() instead."),this.premultiply(hl.makeTranslation(e,t)),this}makeTranslation(e,t){return e.isVector2?this.set(1,0,e.x,0,1,e.y,0,0,1):this.set(1,0,e,0,1,t,0,0,1),this}makeRotation(e){let t=Math.cos(e),n=Math.sin(e);return this.set(t,-n,0,n,t,0,0,0,1),this}makeScale(e,t){return this.set(e,0,0,0,t,0,0,0,1),this}equals(e){let t=this.elements,n=e.elements;for(let s=0;s<9;s++)if(t[s]!==n[s])return!1;return!0}fromArray(e,t=0){for(let n=0;n<9;n++)this.elements[n]=e[n+t];return this}toArray(e=[],t=0){let n=this.elements;return e[t]=n[0],e[t+1]=n[1],e[t+2]=n[2],e[t+3]=n[3],e[t+4]=n[4],e[t+5]=n[5],e[t+6]=n[6],e[t+7]=n[7],e[t+8]=n[8],e}clone(){return new this.constructor().fromArray(this.elements)}};yc.prototype.isMatrix3=!0;var Je=yc,hl=new Je,rh=new Je().set(.4123908,.3575843,.1804808,.212639,.7151687,.0721923,.0193308,.1191948,.9505322),ah=new Je().set(3.2409699,-1.5373832,-.4986108,-.9692436,1.8759675,.0415551,.0556301,-.203977,1.0569715);function jd(){let i={enabled:!0,workingColorSpace:$s,spaces:{},convert:function(s,r,a){return this.enabled===!1||r===a||!r||!a||(this.spaces[r].transfer===ht&&(s.r=jn(s.r),s.g=jn(s.g),s.b=jn(s.b)),this.spaces[r].primaries!==this.spaces[a].primaries&&(s.applyMatrix3(this.spaces[r].toXYZ),s.applyMatrix3(this.spaces[a].fromXYZ)),this.spaces[a].transfer===ht&&(s.r=ss(s.r),s.g=ss(s.g),s.b=ss(s.b))),s},workingToColorSpace:function(s,r){return this.convert(s,this.workingColorSpace,r)},colorSpaceToWorking:function(s,r){return this.convert(s,r,this.workingColorSpace)},getPrimaries:function(s){return this.spaces[s].primaries},getTransfer:function(s){return s===ti?Ks:this.spaces[s].transfer},getToneMappingMode:function(s){return this.spaces[s].outputColorSpaceConfig.toneMappingMode||"standard"},getLuminanceCoefficients:function(s,r=this.workingColorSpace){return s.fromArray(this.spaces[r].luminanceCoefficients)},define:function(s){Object.assign(this.spaces,s)},_getMatrix:function(s,r,a){return s.copy(this.spaces[r].toXYZ).multiply(this.spaces[a].fromXYZ)},_getDrawingBufferColorSpace:function(s){return this.spaces[s].outputColorSpaceConfig.drawingBufferColorSpace},_getUnpackColorSpace:function(s=this.workingColorSpace){return this.spaces[s].workingColorSpaceConfig.unpackColorSpace},fromWorkingColorSpace:function(s,r){return Ri("ColorManagement: .fromWorkingColorSpace() has been renamed to .workingToColorSpace()."),i.workingToColorSpace(s,r)},toWorkingColorSpace:function(s,r){return Ri("ColorManagement: .toWorkingColorSpace() has been renamed to .colorSpaceToWorking()."),i.colorSpaceToWorking(s,r)}},e=[.64,.33,.3,.6,.15,.06],t=[.2126,.7152,.0722],n=[.3127,.329];return i.define({[$s]:{primaries:e,whitePoint:n,transfer:Ks,toXYZ:rh,fromXYZ:ah,luminanceCoefficients:t,workingColorSpaceConfig:{unpackColorSpace:St},outputColorSpaceConfig:{drawingBufferColorSpace:St}},[St]:{primaries:e,whitePoint:n,transfer:ht,toXYZ:rh,fromXYZ:ah,luminanceCoefficients:t,outputColorSpaceConfig:{drawingBufferColorSpace:St}}}),i}var rt=jd();function jn(i){return i<.04045?i*.0773993808:Math.pow(i*.9478672986+.0521327014,2.4)}function ss(i){return i<.0031308?i*12.92:1.055*Math.pow(i,.41666)-.055}var ki,Ia=class{static getDataURL(e,t="image/png"){if(/^data:/i.test(e.src)||typeof HTMLCanvasElement>"u")return e.src;let n;if(e instanceof HTMLCanvasElement)n=e;else{ki===void 0&&(ki=ls("canvas")),ki.width=e.width,ki.height=e.height;let s=ki.getContext("2d");e instanceof ImageData?s.putImageData(e,0,0):s.drawImage(e,0,0,e.width,e.height),n=ki}return n.toDataURL(t)}static sRGBToLinear(e){if(typeof HTMLImageElement<"u"&&e instanceof HTMLImageElement||typeof HTMLCanvasElement<"u"&&e instanceof HTMLCanvasElement||typeof ImageBitmap<"u"&&e instanceof ImageBitmap){let t=ls("canvas");t.width=e.width,t.height=e.height;let n=t.getContext("2d");n.drawImage(e,0,0,e.width,e.height);let s=n.getImageData(0,0,e.width,e.height),r=s.data;for(let a=0;a1),this.pmremVersion=0,this.normalized=!1}get width(){return this.source.getSize(dl).x}get height(){return this.source.getSize(dl).y}get depth(){return this.source.getSize(dl).z}get image(){return this.source.data}set image(e){this.source.data=e}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(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}clone(){return new this.constructor().copy(this)}copy(e){return this.name=e.name,this.source=e.source,this.mipmaps=e.mipmaps.slice(0),this.mapping=e.mapping,this.channel=e.channel,this.wrapS=e.wrapS,this.wrapT=e.wrapT,this.magFilter=e.magFilter,this.minFilter=e.minFilter,this.anisotropy=e.anisotropy,this.format=e.format,this.internalFormat=e.internalFormat,this.type=e.type,this.normalized=e.normalized,this.offset.copy(e.offset),this.repeat.copy(e.repeat),this.center.copy(e.center),this.rotation=e.rotation,this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrix.copy(e.matrix),this.generateMipmaps=e.generateMipmaps,this.premultiplyAlpha=e.premultiplyAlpha,this.flipY=e.flipY,this.unpackAlignment=e.unpackAlignment,this.colorSpace=e.colorSpace,this.renderTarget=e.renderTarget,this.isRenderTargetTexture=e.isRenderTargetTexture,this.isArrayTexture=e.isArrayTexture,this.userData=JSON.parse(JSON.stringify(e.userData)),this.needsUpdate=!0,this}setValues(e){for(let t in e){let n=e[t];if(n===void 0){Ge(`Texture.setValues(): parameter '${t}' has value of undefined.`);continue}let s=this[t];if(s===void 0){Ge(`Texture.setValues(): property '${t}' does not exist.`);continue}s&&n&&s.isVector2&&n.isVector2||s&&n&&s.isVector3&&n.isVector3||s&&n&&s.isMatrix3&&n.isMatrix3?s.copy(n):this[t]=n}}toJSON(e){let t=e===void 0||typeof e=="string";if(!t&&e.textures[this.uuid]!==void 0)return e.textures[this.uuid];let n={metadata:{version:4.7,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,image:this.source.toJSON(e).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),t||(e.textures[this.uuid]=n),n}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(e){if(this.mapping!==nc)return e;if(e.applyMatrix3(this.matrix),e.x<0||e.x>1)switch(this.wrapS){case as:e.x=e.x-Math.floor(e.x);break;case In:e.x=e.x<0?0:1;break;case Ca:Math.abs(Math.floor(e.x)%2)===1?e.x=Math.ceil(e.x)-e.x:e.x=e.x-Math.floor(e.x);break}if(e.y<0||e.y>1)switch(this.wrapT){case as:e.y=e.y-Math.floor(e.y);break;case In:e.y=e.y<0?0:1;break;case Ca:Math.abs(Math.floor(e.y)%2)===1?e.y=Math.ceil(e.y)-e.y:e.y=e.y-Math.floor(e.y);break}return this.flipY&&(e.y=1-e.y),e}set needsUpdate(e){e===!0&&(this.version++,this.source.needsUpdate=!0)}set needsPMREMUpdate(e){e===!0&&this.pmremVersion++}};Yt.DEFAULT_IMAGE=null;Yt.DEFAULT_MAPPING=nc;Yt.DEFAULT_ANISOTROPY=1;var Mc=class Mc{constructor(e=0,t=0,n=0,s=1){this.x=e,this.y=t,this.z=n,this.w=s}get width(){return this.z}set width(e){this.z=e}get height(){return this.w}set height(e){this.w=e}set(e,t,n,s){return this.x=e,this.y=t,this.z=n,this.w=s,this}setScalar(e){return this.x=e,this.y=e,this.z=e,this.w=e,this}setX(e){return this.x=e,this}setY(e){return this.y=e,this}setZ(e){return this.z=e,this}setW(e){return this.w=e,this}setComponent(e,t){switch(e){case 0:this.x=t;break;case 1:this.y=t;break;case 2:this.z=t;break;case 3:this.w=t;break;default:throw new Error("THREE.Vector4: index is out of range: "+e)}return this}getComponent(e){switch(e){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: "+e)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this.w=e.w!==void 0?e.w:1,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this.w+=e.w,this}addScalar(e){return this.x+=e,this.y+=e,this.z+=e,this.w+=e,this}addVectors(e,t){return this.x=e.x+t.x,this.y=e.y+t.y,this.z=e.z+t.z,this.w=e.w+t.w,this}addScaledVector(e,t){return this.x+=e.x*t,this.y+=e.y*t,this.z+=e.z*t,this.w+=e.w*t,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this.w-=e.w,this}subScalar(e){return this.x-=e,this.y-=e,this.z-=e,this.w-=e,this}subVectors(e,t){return this.x=e.x-t.x,this.y=e.y-t.y,this.z=e.z-t.z,this.w=e.w-t.w,this}multiply(e){return this.x*=e.x,this.y*=e.y,this.z*=e.z,this.w*=e.w,this}multiplyScalar(e){return this.x*=e,this.y*=e,this.z*=e,this.w*=e,this}applyMatrix4(e){let t=this.x,n=this.y,s=this.z,r=this.w,a=e.elements;return this.x=a[0]*t+a[4]*n+a[8]*s+a[12]*r,this.y=a[1]*t+a[5]*n+a[9]*s+a[13]*r,this.z=a[2]*t+a[6]*n+a[10]*s+a[14]*r,this.w=a[3]*t+a[7]*n+a[11]*s+a[15]*r,this}divide(e){return this.x/=e.x,this.y/=e.y,this.z/=e.z,this.w/=e.w,this}divideScalar(e){return this.multiplyScalar(1/e)}setAxisAngleFromQuaternion(e){this.w=2*Math.acos(e.w);let t=Math.sqrt(1-e.w*e.w);return t<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=e.x/t,this.y=e.y/t,this.z=e.z/t),this}setAxisAngleFromRotationMatrix(e){let t,n,s,r,l=e.elements,c=l[0],h=l[4],u=l[8],d=l[1],f=l[5],m=l[9],v=l[2],g=l[6],p=l[10];if(Math.abs(h-d)<.01&&Math.abs(u-v)<.01&&Math.abs(m-g)<.01){if(Math.abs(h+d)<.1&&Math.abs(u+v)<.1&&Math.abs(m+g)<.1&&Math.abs(c+f+p-3)<.1)return this.set(1,0,0,0),this;t=Math.PI;let w=(c+1)/2,M=(f+1)/2,b=(p+1)/2,S=(h+d)/4,R=(u+v)/4,x=(m+g)/4;return w>M&&w>b?w<.01?(n=0,s=.707106781,r=.707106781):(n=Math.sqrt(w),s=S/n,r=R/n):M>b?M<.01?(n=.707106781,s=0,r=.707106781):(s=Math.sqrt(M),n=S/s,r=x/s):b<.01?(n=.707106781,s=.707106781,r=0):(r=Math.sqrt(b),n=R/r,s=x/r),this.set(n,s,r,t),this}let T=Math.sqrt((g-m)*(g-m)+(u-v)*(u-v)+(d-h)*(d-h));return Math.abs(T)<.001&&(T=1),this.x=(g-m)/T,this.y=(u-v)/T,this.z=(d-h)/T,this.w=Math.acos((c+f+p-1)/2),this}setFromMatrixPosition(e){let t=e.elements;return this.x=t[12],this.y=t[13],this.z=t[14],this.w=t[15],this}min(e){return this.x=Math.min(this.x,e.x),this.y=Math.min(this.y,e.y),this.z=Math.min(this.z,e.z),this.w=Math.min(this.w,e.w),this}max(e){return this.x=Math.max(this.x,e.x),this.y=Math.max(this.y,e.y),this.z=Math.max(this.z,e.z),this.w=Math.max(this.w,e.w),this}clamp(e,t){return this.x=tt(this.x,e.x,t.x),this.y=tt(this.y,e.y,t.y),this.z=tt(this.z,e.z,t.z),this.w=tt(this.w,e.w,t.w),this}clampScalar(e,t){return this.x=tt(this.x,e,t),this.y=tt(this.y,e,t),this.z=tt(this.z,e,t),this.w=tt(this.w,e,t),this}clampLength(e,t){let n=this.length();return this.divideScalar(n||1).multiplyScalar(tt(n,e,t))}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(e){return this.x*e.x+this.y*e.y+this.z*e.z+this.w*e.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(e){return this.normalize().multiplyScalar(e)}lerp(e,t){return this.x+=(e.x-this.x)*t,this.y+=(e.y-this.y)*t,this.z+=(e.z-this.z)*t,this.w+=(e.w-this.w)*t,this}lerpVectors(e,t,n){return this.x=e.x+(t.x-e.x)*n,this.y=e.y+(t.y-e.y)*n,this.z=e.z+(t.z-e.z)*n,this.w=e.w+(t.w-e.w)*n,this}equals(e){return e.x===this.x&&e.y===this.y&&e.z===this.z&&e.w===this.w}fromArray(e,t=0){return this.x=e[t],this.y=e[t+1],this.z=e[t+2],this.w=e[t+3],this}toArray(e=[],t=0){return e[t]=this.x,e[t+1]=this.y,e[t+2]=this.z,e[t+3]=this.w,e}fromBufferAttribute(e,t){return this.x=e.getX(t),this.y=e.getY(t),this.z=e.getZ(t),this.w=e.getW(t),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}};Mc.prototype.isVector4=!0;var Mt=Mc,La=class extends Nn{constructor(e=1,t=1,n={}){super(),n=Object.assign({generateMipmaps:!1,internalFormat:null,minFilter:zt,depthBuffer:!0,stencilBuffer:!1,resolveColorBuffer:!0,resolveDepthBuffer:!0,resolveStencilBuffer:!0,storeMultisampledColorBuffer:!0,storeMultisampledDepthBuffer:!0,storeMultisampledStencilBuffer:!0,depthTexture:null,samples:0,count:1,depth:1,multiview:!1,useArrayDepthTexture:!1},n),this.isRenderTarget=!0,this.width=e,this.height=t,this.depth=n.depth,this.scissor=new Mt(0,0,e,t),this.scissorTest=!1,this.viewport=new Mt(0,0,e,t),this.textures=[];let s={width:e,height:t,depth:n.depth},r=new Yt(s),a=n.count;for(let o=0;o1);this.dispose()}this.viewport.set(0,0,e,t),this.scissor.set(0,0,e,t)}clone(){return new this.constructor().copy(this)}copy(e){this.width=e.width,this.height=e.height,this.depth=e.depth,this.scissor.copy(e.scissor),this.scissorTest=e.scissorTest,this.viewport.copy(e.viewport),this.textures.length=0;for(let t=0,n=e.textures.length;t>>0}enable(e){this.mask|=1<1){for(let t=0;t1){for(let n=0;n0&&(s.userData=this.userData),s.layers=this.layers.mask,s.matrix=this.matrix.toArray(),s.up=this.up.toArray(),this.pivot!==null&&(s.pivot=this.pivot.toArray()),this.morphTargetDictionary!==void 0&&(s.morphTargetDictionary=Object.assign({},this.morphTargetDictionary)),this.morphTargetInfluences!==void 0&&(s.morphTargetInfluences=this.morphTargetInfluences.slice()),this.isInstancedMesh&&(s.type="InstancedMesh",s.count=this.count,s.instanceMatrix=this.instanceMatrix.toJSON(),this.instanceColor!==null&&(s.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(s.type="BatchedMesh",s.perObjectFrustumCulled=this.perObjectFrustumCulled,s.sortObjects=this.sortObjects,s.drawRanges=this._drawRanges,s.reservedRanges=this._reservedRanges,s.geometryInfo=this._geometryInfo.map(o=>({...o,boundingBox:o.boundingBox?o.boundingBox.toJSON():void 0,boundingSphere:o.boundingSphere?o.boundingSphere.toJSON():void 0})),s.instanceInfo=this._instanceInfo.map(o=>({...o})),s.availableInstanceIds=this._availableInstanceIds.slice(),s.availableGeometryIds=this._availableGeometryIds.slice(),s.nextIndexStart=this._nextIndexStart,s.nextVertexStart=this._nextVertexStart,s.geometryCount=this._geometryCount,s.maxInstanceCount=this._maxInstanceCount,s.maxVertexCount=this._maxVertexCount,s.maxIndexCount=this._maxIndexCount,s.geometryInitialized=this._geometryInitialized,s.matricesTexture=this._matricesTexture.toJSON(e),s.indirectTexture=this._indirectTexture.toJSON(e),this._colorsTexture!==null&&(s.colorsTexture=this._colorsTexture.toJSON(e)),this.boundingSphere!==null&&(s.boundingSphere=this.boundingSphere.toJSON()),this.boundingBox!==null&&(s.boundingBox=this.boundingBox.toJSON()));function r(o,l){return o[l.uuid]===void 0&&(o[l.uuid]=l.toJSON(e)),l.uuid}if(this.isScene)this.background&&(this.background.isColor?s.background=this.background.toJSON():this.background.isTexture&&(s.background=this.background.toJSON(e).uuid)),this.environment&&this.environment.isTexture&&this.environment.isRenderTargetTexture!==!0&&(s.environment=this.environment.toJSON(e).uuid);else if(this.isMesh||this.isLine||this.isPoints){s.geometry=r(e.geometries,this.geometry);let o=this.geometry.parameters;if(o!==void 0&&o.shapes!==void 0){let l=o.shapes;if(Array.isArray(l))for(let c=0,h=l.length;c0){s.children=[];for(let o=0;o0){s.animations=[];for(let o=0;o0&&(n.geometries=o),l.length>0&&(n.materials=l),c.length>0&&(n.textures=c),h.length>0&&(n.images=h),u.length>0&&(n.shapes=u),d.length>0&&(n.skeletons=d),f.length>0&&(n.animations=f),m.length>0&&(n.nodes=m)}return n.object=s,n;function a(o){let l=[];for(let c in o){let h=o[c];delete h.metadata,l.push(h)}return l}}clone(e){return new this.constructor().copy(this,e)}copy(e,t=!0){if(this.name=e.name,this.up.copy(e.up),this.position.copy(e.position),this.rotation.order=e.rotation.order,this.quaternion.copy(e.quaternion),this.scale.copy(e.scale),this.pivot=e.pivot!==null?e.pivot.clone():null,this.matrix.copy(e.matrix),this.matrixWorld.copy(e.matrixWorld),this.matrixAutoUpdate=e.matrixAutoUpdate,this.matrixWorldAutoUpdate=e.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=e.matrixWorldNeedsUpdate,this.layers.mask=e.layers.mask,this.visible=e.visible,this.castShadow=e.castShadow,this.receiveShadow=e.receiveShadow,this.frustumCulled=e.frustumCulled,this.renderOrder=e.renderOrder,this.static=e.static,this.animations=e.animations.slice(),this.userData=JSON.parse(JSON.stringify(e.userData)),t===!0)for(let n=0;nf+m?(c.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:e.handedness,target:this})):!c.inputState.pinching&&d<=f-m&&(c.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:e.handedness,target:this}))}else l!==null&&e.gripSpace&&(r=t.getPose(e.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:e,target:this})));o!==null&&(s=t.getPose(e.targetRaySpace,n),s===null&&r!==null&&(s=r),s!==null&&(o.matrix.fromArray(s.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),o.matrixWorldNeedsUpdate=!0,s.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(s.linearVelocity)):o.hasLinearVelocity=!1,s.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(s.angularVelocity)):o.hasAngularVelocity=!1,this.dispatchEvent(cf)))}return o!==null&&(o.visible=s!==null),l!==null&&(l.visible=r!==null),c!==null&&(c.visible=a!==null),this}_getHandJoint(e,t){if(e.joints[t.jointName]===void 0){let n=new jt;n.matrixAutoUpdate=!1,n.visible=!1,e.joints[t.jointName]=n,e.add(n)}return e.joints[t.jointName]}},gu={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},oi={h:0,s:0,l:0},Jr={h:0,s:0,l:0};function pl(i,e,t){return t<0&&(t+=1),t>1&&(t-=1),t<1/6?i+(e-i)*6*t:t<1/2?e:t<2/3?i+(e-i)*6*(2/3-t):i}var Xe=class{constructor(e,t,n){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(e,t,n)}set(e,t,n){if(t===void 0&&n===void 0){let s=e;s&&s.isColor?this.copy(s):typeof s=="number"?this.setHex(s):typeof s=="string"&&this.setStyle(s)}else this.setRGB(e,t,n);return this}setScalar(e){return this.r=e,this.g=e,this.b=e,this}setHex(e,t=St){return e=Math.floor(e),this.r=(e>>16&255)/255,this.g=(e>>8&255)/255,this.b=(e&255)/255,rt.colorSpaceToWorking(this,t),this}setRGB(e,t,n,s=rt.workingColorSpace){return this.r=e,this.g=t,this.b=n,rt.colorSpaceToWorking(this,s),this}setHSL(e,t,n,s=rt.workingColorSpace){if(e=dc(e,1),t=tt(t,0,1),n=tt(n,0,1),t===0)this.r=this.g=this.b=n;else{let r=n<=.5?n*(1+t):n+t-n*t,a=2*n-r;this.r=pl(a,r,e+1/3),this.g=pl(a,r,e),this.b=pl(a,r,e-1/3)}return rt.colorSpaceToWorking(this,s),this}setStyle(e,t=St){function n(r){r!==void 0&&parseFloat(r)<1&&Ge("Color: Alpha component of "+e+" will be ignored.")}let s;if(s=/^(\w+)\(([^\)]*)\)/.exec(e)){let r,a=s[1],o=s[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,t);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,t);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,t);break;default:Ge("Color: Unknown color model "+e)}}else if(s=/^\#([A-Fa-f\d]+)$/.exec(e)){let r=s[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,t);if(a===6)return this.setHex(parseInt(r,16),t);Ge("Color: Invalid hex color "+e)}else if(e&&e.length>0)return this.setColorName(e,t);return this}setColorName(e,t=St){let n=gu[e.toLowerCase()];return n!==void 0?this.setHex(n,t):Ge("Color: Unknown color "+e),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(e){return this.r=e.r,this.g=e.g,this.b=e.b,this}copySRGBToLinear(e){return this.r=jn(e.r),this.g=jn(e.g),this.b=jn(e.b),this}copyLinearToSRGB(e){return this.r=ss(e.r),this.g=ss(e.g),this.b=ss(e.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(e=St){return rt.workingToColorSpace(Wt.copy(this),e),Math.round(tt(Wt.r*255,0,255))*65536+Math.round(tt(Wt.g*255,0,255))*256+Math.round(tt(Wt.b*255,0,255))}getHexString(e=St){return("000000"+this.getHex(e).toString(16)).slice(-6)}getHSL(e,t=rt.workingColorSpace){rt.workingToColorSpace(Wt.copy(this),t);let n=Wt.r,s=Wt.g,r=Wt.b,a=Math.max(n,s,r),o=Math.min(n,s,r),l,c,h=(o+a)/2;if(o===a)l=0,c=0;else{let u=a-o;switch(c=h<=.5?u/(a+o):u/(2-a-o),a){case n:l=(s-r)/u+(s0?s.multiplyScalar(1/Math.sqrt(r)):s.set(0,0,0)}static getBarycoord(e,t,n,s,r){_n.subVectors(s,t),Zn.subVectors(n,t),ml.subVectors(e,t);let a=_n.dot(_n),o=_n.dot(Zn),l=_n.dot(ml),c=Zn.dot(Zn),h=Zn.dot(ml),u=a*c-o*o;if(u===0)return r.set(0,0,0),null;let d=1/u,f=(c*l-o*h)*d,m=(a*h-o*l)*d;return r.set(1-f-m,m,f)}static containsPoint(e,t,n,s){return this.getBarycoord(e,t,n,s,Jn)===null?!1:Jn.x>=0&&Jn.y>=0&&Jn.x+Jn.y<=1}static getInterpolation(e,t,n,s,r,a,o,l){return this.getBarycoord(e,t,n,s,Jn)===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,Jn.x),l.addScaledVector(a,Jn.y),l.addScaledVector(o,Jn.z),l)}static getInterpolatedAttribute(e,t,n,s,r,a){return vl.setScalar(0),yl.setScalar(0),Ml.setScalar(0),vl.fromBufferAttribute(e,t),yl.fromBufferAttribute(e,n),Ml.fromBufferAttribute(e,s),a.setScalar(0),a.addScaledVector(vl,r.x),a.addScaledVector(yl,r.y),a.addScaledVector(Ml,r.z),a}static isFrontFacing(e,t,n,s){return _n.subVectors(n,t),Zn.subVectors(e,t),_n.cross(Zn).dot(s)<0}set(e,t,n){return this.a.copy(e),this.b.copy(t),this.c.copy(n),this}setFromPointsAndIndices(e,t,n,s){return this.a.copy(e[t]),this.b.copy(e[n]),this.c.copy(e[s]),this}setFromAttributeAndIndices(e,t,n,s){return this.a.fromBufferAttribute(e,t),this.b.fromBufferAttribute(e,n),this.c.fromBufferAttribute(e,s),this}clone(){return new this.constructor().copy(this)}copy(e){return this.a.copy(e.a),this.b.copy(e.b),this.c.copy(e.c),this}getArea(){return _n.subVectors(this.c,this.b),Zn.subVectors(this.a,this.b),_n.cross(Zn).length()*.5}getMidpoint(e){return e.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(e){return i.getNormal(this.a,this.b,this.c,e)}getPlane(e){return e.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(e,t){return i.getBarycoord(e,this.a,this.b,this.c,t)}getInterpolation(e,t,n,s,r){return i.getInterpolation(e,this.a,this.b,this.c,t,n,s,r)}containsPoint(e){return i.containsPoint(e,this.a,this.b,this.c)}isFrontFacing(e){return i.isFrontFacing(this.a,this.b,this.c,e)}intersectsBox(e){return e.intersectsTriangle(this)}closestPointToPoint(e,t){let n=this.a,s=this.b,r=this.c,a,o;Wi.subVectors(s,n),Xi.subVectors(r,n),gl.subVectors(e,n);let l=Wi.dot(gl),c=Xi.dot(gl);if(l<=0&&c<=0)return t.copy(n);_l.subVectors(e,s);let h=Wi.dot(_l),u=Xi.dot(_l);if(h>=0&&u<=h)return t.copy(s);let d=l*u-h*c;if(d<=0&&l>=0&&h<=0)return a=l/(l-h),t.copy(n).addScaledVector(Wi,a);xl.subVectors(e,r);let f=Wi.dot(xl),m=Xi.dot(xl);if(m>=0&&f<=m)return t.copy(r);let v=f*c-l*m;if(v<=0&&c>=0&&m<=0)return o=c/(c-m),t.copy(n).addScaledVector(Xi,o);let g=h*m-f*u;if(g<=0&&u-h>=0&&f-m>=0)return ph.subVectors(r,s),o=(u-h)/(u-h+(f-m)),t.copy(s).addScaledVector(ph,o);let p=1/(g+v+d);return a=v*p,o=d*p,t.copy(n).addScaledVector(Wi,a).addScaledVector(Xi,o)}equals(e){return e.a.equals(this.a)&&e.b.equals(this.b)&&e.c.equals(this.c)}},Un=class{constructor(e=new I(1/0,1/0,1/0),t=new I(-1/0,-1/0,-1/0)){this.isBox3=!0,this.min=e,this.max=t}set(e,t){return this.min.copy(e),this.max.copy(t),this}setFromArray(e){this.makeEmpty();for(let t=0,n=e.length;t=this.min.x&&e.x<=this.max.x&&e.y>=this.min.y&&e.y<=this.max.y&&e.z>=this.min.z&&e.z<=this.max.z}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z}getParameter(e,t){return t.set((e.x-this.min.x)/(this.max.x-this.min.x),(e.y-this.min.y)/(this.max.y-this.min.y),(e.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(e){return e.max.x>=this.min.x&&e.min.x<=this.max.x&&e.max.y>=this.min.y&&e.min.y<=this.max.y&&e.max.z>=this.min.z&&e.min.z<=this.max.z}intersectsSphere(e){return this.clampPoint(e.center,xn),xn.distanceToSquared(e.center)<=e.radius*e.radius}intersectsPlane(e){let t,n;return e.normal.x>0?(t=e.normal.x*this.min.x,n=e.normal.x*this.max.x):(t=e.normal.x*this.max.x,n=e.normal.x*this.min.x),e.normal.y>0?(t+=e.normal.y*this.min.y,n+=e.normal.y*this.max.y):(t+=e.normal.y*this.max.y,n+=e.normal.y*this.min.y),e.normal.z>0?(t+=e.normal.z*this.min.z,n+=e.normal.z*this.max.z):(t+=e.normal.z*this.max.z,n+=e.normal.z*this.min.z),t<=-e.constant&&n>=-e.constant}intersectsTriangle(e){if(this.isEmpty())return!1;this.getCenter(Bs),Kr.subVectors(this.max,Bs),qi.subVectors(e.a,Bs),Yi.subVectors(e.b,Bs),Zi.subVectors(e.c,Bs),li.subVectors(Yi,qi),ci.subVectors(Zi,Yi),bi.subVectors(qi,Zi);let t=[0,-li.z,li.y,0,-ci.z,ci.y,0,-bi.z,bi.y,li.z,0,-li.x,ci.z,0,-ci.x,bi.z,0,-bi.x,-li.y,li.x,0,-ci.y,ci.x,0,-bi.y,bi.x,0];return!Sl(t,qi,Yi,Zi,Kr)||(t=[1,0,0,0,1,0,0,0,1],!Sl(t,qi,Yi,Zi,Kr))?!1:(Qr.crossVectors(li,ci),t=[Qr.x,Qr.y,Qr.z],Sl(t,qi,Yi,Zi,Kr))}clampPoint(e,t){return t.copy(e).clamp(this.min,this.max)}distanceToPoint(e){return this.clampPoint(e,xn).distanceTo(e)}getBoundingSphere(e){return this.isEmpty()?e.makeEmpty():(this.getCenter(e.center),e.radius=this.getSize(xn).length()*.5),e}intersect(e){return this.min.max(e.min),this.max.min(e.max),this.isEmpty()&&this.makeEmpty(),this}union(e){return this.min.min(e.min),this.max.max(e.max),this}applyMatrix4(e){return this.isEmpty()?this:($n[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(e),$n[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(e),$n[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(e),$n[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(e),$n[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(e),$n[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(e),$n[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(e),$n[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(e),this.setFromPoints($n),this)}translate(e){return this.min.add(e),this.max.add(e),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}toJSON(){return{min:this.min.toArray(),max:this.max.toArray()}}fromJSON(e){return this.min.fromArray(e.min),this.max.fromArray(e.max),this}},$n=[new I,new I,new I,new I,new I,new I,new I,new I],xn=new I,$r=new Un,qi=new I,Yi=new I,Zi=new I,li=new I,ci=new I,bi=new I,Bs=new I,Kr=new I,Qr=new I,Ei=new I;function Sl(i,e,t,n,s){for(let r=0,a=i.length-3;r<=a;r+=3){Ei.fromArray(i,r);let o=s.x*Math.abs(Ei.x)+s.y*Math.abs(Ei.y)+s.z*Math.abs(Ei.z),l=e.dot(Ei),c=t.dot(Ei),h=n.dot(Ei);if(Math.max(-Math.max(l,c,h),Math.min(l,c,h))>o)return!1}return!0}var Ct=new I,jr=new ue,hf=0,Bt=class extends Nn{constructor(e,t,n=!1){if(super(),Array.isArray(e))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,Object.defineProperty(this,"id",{value:hf++}),this.name="",this.array=e,this.itemSize=t,this.count=e!==void 0?e.length/t:0,this.normalized=n,this.usage=hc,this.updateRanges=[],this.gpuType=Tn,this.version=0}onUploadCallback(){}set needsUpdate(e){e===!0&&this.version++}setUsage(e){return this.usage=e,this}addUpdateRange(e,t){this.updateRanges.push({start:e,count:t})}clearUpdateRanges(){this.updateRanges.length=0}copy(e){return this.name=e.name,this.array=new e.array.constructor(e.array),this.itemSize=e.itemSize,this.count=e.count,this.normalized=e.normalized,this.usage=e.usage,this.gpuType=e.gpuType,this}copyAt(e,t,n){e*=this.itemSize,n*=t.itemSize;for(let s=0,r=this.itemSize;sthis.radius*this.radius&&(t.sub(this.center).normalize(),t.multiplyScalar(this.radius).add(this.center)),t}getBoundingBox(e){return this.isEmpty()?(e.makeEmpty(),e):(e.set(this.center,this.center),e.expandByScalar(this.radius),e)}applyMatrix4(e){return this.center.applyMatrix4(e),this.radius=this.radius*e.getMaxScaleOnAxis(),this}translate(e){return this.center.add(e),this}expandByPoint(e){if(this.isEmpty())return this.center.copy(e),this.radius=0,this;zs.subVectors(e,this.center);let t=zs.lengthSq();if(t>this.radius*this.radius){let n=Math.sqrt(t),s=(n-this.radius)*.5;this.center.addScaledVector(zs,s/n),this.radius+=s}return this}union(e){return e.isEmpty()?this:this.isEmpty()?(this.copy(e),this):(this.center.equals(e.center)===!0?this.radius=Math.max(this.radius,e.radius):(bl.subVectors(e.center,this.center).setLength(e.radius),this.expandByPoint(zs.copy(e.center).add(bl)),this.expandByPoint(zs.copy(e.center).sub(bl))),this)}equals(e){return e.center.equals(this.center)&&e.radius===this.radius}clone(){return new this.constructor().copy(this)}toJSON(){return{radius:this.radius,center:this.center.toArray()}}fromJSON(e){return this.radius=e.radius,this.center.fromArray(e.center),this}},df=0,un=new gt,El=new Ft,Ji=new I,sn=new Un,ks=new Un,Nt=new I,At=class i extends Nn{constructor(){super(),this.isBufferGeometry=!0,Object.defineProperty(this,"id",{value:df++}),this.uuid=Ln(),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(e){return Array.isArray(e)?this.index=new(Ud(e)?nr:tr)(e,1):this.index=e,this}setIndirect(e,t=0){return this.indirect=e,this.indirectOffset=t,this}getIndirect(){return this.indirect}getAttribute(e){return this.attributes[e]}setAttribute(e,t){return this.attributes[e]=t,this}deleteAttribute(e){return delete this.attributes[e],this}hasAttribute(e){return this.attributes[e]!==void 0}addGroup(e,t,n=0){this.groups.push({start:e,count:t,materialIndex:n})}clearGroups(){this.groups=[]}setDrawRange(e,t){this.drawRange.start=e,this.drawRange.count=t}applyMatrix4(e){let t=this.attributes.position;t!==void 0&&(t.applyMatrix4(e),t.needsUpdate=!0);let n=this.attributes.normal;if(n!==void 0){let r=new Je().getNormalMatrix(e);n.applyNormalMatrix(r),n.needsUpdate=!0}let s=this.attributes.tangent;return s!==void 0&&(s.transformDirection(e),s.needsUpdate=!0),this.boundingBox!==null&&this.computeBoundingBox(),this.boundingSphere!==null&&this.computeBoundingSphere(),this._transformed=!0,this}applyQuaternion(e){return un.makeRotationFromQuaternion(e),this.applyMatrix4(un),this}rotateX(e){return un.makeRotationX(e),this.applyMatrix4(un),this}rotateY(e){return un.makeRotationY(e),this.applyMatrix4(un),this}rotateZ(e){return un.makeRotationZ(e),this.applyMatrix4(un),this}translate(e,t,n){return un.makeTranslation(e,t,n),this.applyMatrix4(un),this}scale(e,t,n){return un.makeScale(e,t,n),this.applyMatrix4(un),this}lookAt(e){return El.lookAt(e),El.updateMatrix(),this.applyMatrix4(El.matrix),this}center(){return this.computeBoundingBox(),this.boundingBox.getCenter(Ji).negate(),this.translate(Ji.x,Ji.y,Ji.z),this}setFromPoints(e){let t=this.getAttribute("position");if(t===void 0){let n=[];for(let s=0,r=e.length;st.count&&Ge("BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry."),t.needsUpdate=!0}return this}computeBoundingBox(){this.boundingBox===null&&(this.boundingBox=new Un);let e=this.attributes.position,t=this.morphAttributes.position;if(e&&e.isGLBufferAttribute){We("BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.",this),this.boundingBox.set(new I(-1/0,-1/0,-1/0),new I(1/0,1/0,1/0));return}if(e!==void 0){if(this.boundingBox.setFromBufferAttribute(e),t)for(let n=0,s=t.length;n0&&(e.userData=this.userData),this.parameters!==void 0&&this._transformed!==!0){let l=this.parameters;for(let c in l)l[c]!==void 0&&(e[c]=l[c]);return e}e.data={attributes:{}};let t=this.index;t!==null&&(e.data.index={type:t.array.constructor.name,array:Array.prototype.slice.call(t.array)});let n=this.attributes;for(let l in n){let c=n[l];e.data.attributes[l]=c.toJSON(e.data)}let s={},r=!1;for(let l in this.morphAttributes){let c=this.morphAttributes[l],h=[];for(let u=0,d=c.length;u0&&(s[l]=h,r=!0)}r&&(e.data.morphAttributes=s,e.data.morphTargetsRelative=this.morphTargetsRelative);let a=this.groups;a.length>0&&(e.data.groups=JSON.parse(JSON.stringify(a)));let o=this.boundingSphere;return o!==null&&(e.data.boundingSphere=o.toJSON()),e}clone(){return new this.constructor().copy(this)}copy(e){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;let t={};this.name=e.name;let n=e.index;n!==null&&this.setIndex(n.clone());let s=e.attributes;for(let c in s){let h=s[c];this.setAttribute(c,h.clone(t))}let r=e.morphAttributes;for(let c in r){let h=[],u=r[c];for(let d=0,f=u.length;d1)?null:t.copy(e.start).addScaledVector(s,a)}intersectsLine(e){let t=this.distanceToPoint(e.start),n=this.distanceToPoint(e.end);return t<0&&n>0||n<0&&t>0}intersectsBox(e){return e.intersectsPlane(this)}intersectsSphere(e){return e.intersectsPlane(this)}coplanarPoint(e){return e.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(e,t){let n=t||pf.getNormalMatrix(e),s=this.coplanarPoint(Tl).applyMatrix4(e),r=this.normal.applyMatrix3(n).normalize();return this.constant=-s.dot(r),this}translate(e){return this.constant-=e.dot(this.normal),this}equals(e){return e.normal.equals(this.normal)&&e.constant===this.constant}clone(){return new this.constructor().copy(this)}toJSON(){return{normal:this.normal.toArray(),constant:this.constant}}fromJSON(e){return this.normal.fromArray(e.normal),this.constant=e.constant,this}},mf=0,Fn=class extends Nn{constructor(){super(),this.isMaterial=!0,Object.defineProperty(this,"id",{value:mf++}),this.uuid=Ln(),this.name="",this.type="Material",this.blending=ws,this.side=ln,this.vertexColors=!1,this.opacity=1,this.transparent=!1,this.alphaHash=!1,this.blendSrc=wr,this.blendDst=As,this.blendEquation=Li,this.blendSrcAlpha=null,this.blendDstAlpha=null,this.blendEquationAlpha=null,this.blendColor=new Xe(0,0,0),this.blendAlpha=0,this.depthFunc=rs,this.depthTest=!0,this.depthWrite=!0,this.stencilWriteMask=255,this.stencilFunc=ru,this.stencilRef=0,this.stencilFuncMask=255,this.stencilFail=ya,this.stencilZFail=ya,this.stencilZPass=ya,this.stencilWrite=!1,this.clippingPlanes=null,this.clipIntersection=!1,this.clipShadows=!1,this.shadowSide=null,this.colorWrite=!0,this.precision=null,this.polygonOffset=!1,this.polygonOffsetFactor=0,this.polygonOffsetUnits=0,this.dithering=!1,this.alphaToCoverage=!1,this.premultipliedAlpha=!1,this.forceSinglePass=!1,this.allowOverride=!0,this.visible=!0,this.toneMapped=!0,this.userData={},this.version=0,this._alphaTest=0}get alphaTest(){return this._alphaTest}set alphaTest(e){this._alphaTest>0!=e>0&&this.version++,this._alphaTest=e}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(e){if(e!==void 0)for(let t in e){let n=e[t];if(n===void 0){Ge(`Material: parameter '${t}' has value of undefined.`);continue}let s=this[t];if(s===void 0){Ge(`Material: '${t}' is not a property of THREE.${this.type}.`);continue}s&&s.isColor?s.set(n):s&&s.isVector2&&n&&n.isVector2||s&&s.isEuler&&n&&n.isEuler||s&&s.isVector3&&n&&n.isVector3?s.copy(n):this[t]=n}}toJSON(e){let t=e===void 0||typeof e=="string";t&&(e={textures:{},images:{}});let n={metadata:{version:4.7,type:"Material",generator:"Material.toJSON"}};n.uuid=this.uuid,n.type=this.type,n.blending=this.blending,n.side=this.side,n.shadowSide=this.shadowSide,n.vertexColors=this.vertexColors,n.opacity=this.opacity,n.transparent=this.transparent,n.blendSrc=this.blendSrc,n.blendDst=this.blendDst,n.blendEquation=this.blendEquation,n.blendSrcAlpha=this.blendSrcAlpha,n.blendDstAlpha=this.blendDstAlpha,n.blendEquationAlpha=this.blendEquationAlpha,n.blendColor=this.blendColor.getHex(),n.blendAlpha=this.blendAlpha,n.depthFunc=this.depthFunc,n.depthTest=this.depthTest,n.depthWrite=this.depthWrite,n.colorWrite=this.colorWrite,n.clipIntersection=this.clipIntersection,n.clipShadows=this.clipShadows,n.stencilWriteMask=this.stencilWriteMask,n.stencilFunc=this.stencilFunc,n.stencilRef=this.stencilRef,n.stencilFuncMask=this.stencilFuncMask,n.stencilFail=this.stencilFail,n.stencilZFail=this.stencilZFail,n.stencilZPass=this.stencilZPass,n.stencilWrite=this.stencilWrite,n.polygonOffset=this.polygonOffset,n.polygonOffsetFactor=this.polygonOffsetFactor,n.polygonOffsetUnits=this.polygonOffsetUnits,n.dithering=this.dithering,n.alphaTest=this.alphaTest,n.alphaHash=this.alphaHash,n.alphaToCoverage=this.alphaToCoverage,n.premultipliedAlpha=this.premultipliedAlpha,n.forceSinglePass=this.forceSinglePass,n.allowOverride=this.allowOverride,n.visible=this.visible,n.toneMapped=this.toneMapped,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&&(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(e).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(n.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(e).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(n.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(e).uuid,n.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),this.sheenColorMap&&this.sheenColorMap.isTexture&&(n.sheenColorMap=this.sheenColorMap.toJSON(e).uuid),this.sheenRoughnessMap&&this.sheenRoughnessMap.isTexture&&(n.sheenRoughnessMap=this.sheenRoughnessMap.toJSON(e).uuid),this.dispersion!==void 0&&(n.dispersion=this.dispersion),this.retroreflectivity!==void 0&&(n.retroreflectivity=this.retroreflectivity),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(e).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(n.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(e).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(e).uuid),this.map&&this.map.isTexture&&(n.map=this.map.toJSON(e).uuid),this.matcap&&this.matcap.isTexture&&(n.matcap=this.matcap.toJSON(e).uuid),this.alphaMap&&this.alphaMap.isTexture&&(n.alphaMap=this.alphaMap.toJSON(e).uuid),this.lightMap&&this.lightMap.isTexture&&(n.lightMap=this.lightMap.toJSON(e).uuid,n.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(n.aoMap=this.aoMap.toJSON(e).uuid,n.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(n.bumpMap=this.bumpMap.toJSON(e).uuid,n.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(n.normalMap=this.normalMap.toJSON(e).uuid,n.normalMapType=this.normalMapType,n.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(n.displacementMap=this.displacementMap.toJSON(e).uuid,n.displacementScale=this.displacementScale,n.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(n.roughnessMap=this.roughnessMap.toJSON(e).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(n.metalnessMap=this.metalnessMap.toJSON(e).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(n.emissiveMap=this.emissiveMap.toJSON(e).uuid),this.specularMap&&this.specularMap.isTexture&&(n.specularMap=this.specularMap.toJSON(e).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(n.specularIntensityMap=this.specularIntensityMap.toJSON(e).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(n.specularColorMap=this.specularColorMap.toJSON(e).uuid),this.envMap&&this.envMap.isTexture&&(n.envMap=this.envMap.toJSON(e).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(e).uuid),this.transmission!==void 0&&(n.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(n.transmissionMap=this.transmissionMap.toJSON(e).uuid),this.thickness!==void 0&&(n.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(n.thicknessMap=this.thicknessMap.toJSON(e).uuid),this.attenuationDistance!==void 0&&(n.attenuationDistance=this.attenuationDistance),this.attenuationColor!==void 0&&(n.attenuationColor=this.attenuationColor.getHex()),this.size!==void 0&&(n.size=this.size),this.sizeAttenuation!==void 0&&(n.sizeAttenuation=this.sizeAttenuation),Array.isArray(this.clippingPlanes)&&this.clippingPlanes.length>0&&(n.clippingPlanes=this.clippingPlanes.map(r=>r.toJSON())),this.rotation!==void 0&&(n.rotation=this.rotation),this.depthPacking!==void 0&&(n.depthPacking=this.depthPacking),this.linewidth!==void 0&&(n.linewidth=this.linewidth),this.linecap!==void 0&&(n.linecap=this.linecap),this.linejoin!==void 0&&(n.linejoin=this.linejoin),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.wireframe!==void 0&&(n.wireframe=this.wireframe),this.wireframeLinewidth!==void 0&&(n.wireframeLinewidth=this.wireframeLinewidth),this.wireframeLinecap!==void 0&&(n.wireframeLinecap=this.wireframeLinecap),this.wireframeLinejoin!==void 0&&(n.wireframeLinejoin=this.wireframeLinejoin),this.flatShading!==void 0&&(n.flatShading=this.flatShading),this.fog!==void 0&&(n.fog=this.fog),Object.keys(this.userData).length>0&&(n.userData=this.userData);function s(r){let a=[];for(let o in r){let l=r[o];delete l.metadata,a.push(l)}return a}if(t){let r=s(e.textures),a=s(e.images);r.length>0&&(n.textures=r),a.length>0&&(n.images=a)}return n}fromJSON(e,t){if(e.uuid!==void 0&&(this.uuid=e.uuid),e.name!==void 0&&(this.name=e.name),e.color!==void 0&&this.color!==void 0&&this.color.setHex(e.color),e.roughness!==void 0&&(this.roughness=e.roughness),e.metalness!==void 0&&(this.metalness=e.metalness),e.sheen!==void 0&&(this.sheen=e.sheen),e.sheenColor!==void 0&&(this.sheenColor=new Xe().setHex(e.sheenColor)),e.sheenRoughness!==void 0&&(this.sheenRoughness=e.sheenRoughness),e.emissive!==void 0&&this.emissive!==void 0&&this.emissive.setHex(e.emissive),e.specular!==void 0&&this.specular!==void 0&&this.specular.setHex(e.specular),e.specularIntensity!==void 0&&(this.specularIntensity=e.specularIntensity),e.specularColor!==void 0&&this.specularColor!==void 0&&this.specularColor.setHex(e.specularColor),e.shininess!==void 0&&(this.shininess=e.shininess),e.clearcoat!==void 0&&(this.clearcoat=e.clearcoat),e.clearcoatRoughness!==void 0&&(this.clearcoatRoughness=e.clearcoatRoughness),e.dispersion!==void 0&&(this.dispersion=e.dispersion),e.retroreflectivity!==void 0&&(this.retroreflectivity=e.retroreflectivity),e.iridescence!==void 0&&(this.iridescence=e.iridescence),e.iridescenceIOR!==void 0&&(this.iridescenceIOR=e.iridescenceIOR),e.iridescenceThicknessRange!==void 0&&(this.iridescenceThicknessRange=e.iridescenceThicknessRange),e.transmission!==void 0&&(this.transmission=e.transmission),e.thickness!==void 0&&(this.thickness=e.thickness),e.attenuationDistance!==void 0&&(this.attenuationDistance=e.attenuationDistance),e.attenuationColor!==void 0&&this.attenuationColor!==void 0&&this.attenuationColor.setHex(e.attenuationColor),e.anisotropy!==void 0&&(this.anisotropy=e.anisotropy),e.anisotropyRotation!==void 0&&(this.anisotropyRotation=e.anisotropyRotation),e.fog!==void 0&&(this.fog=e.fog),e.flatShading!==void 0&&(this.flatShading=e.flatShading),e.blending!==void 0&&(this.blending=e.blending),e.combine!==void 0&&(this.combine=e.combine),e.side!==void 0&&(this.side=e.side),e.shadowSide!==void 0&&(this.shadowSide=e.shadowSide),e.opacity!==void 0&&(this.opacity=e.opacity),e.transparent!==void 0&&(this.transparent=e.transparent),e.alphaTest!==void 0&&(this.alphaTest=e.alphaTest),e.alphaHash!==void 0&&(this.alphaHash=e.alphaHash),e.depthFunc!==void 0&&(this.depthFunc=e.depthFunc),e.depthTest!==void 0&&(this.depthTest=e.depthTest),e.depthWrite!==void 0&&(this.depthWrite=e.depthWrite),e.colorWrite!==void 0&&(this.colorWrite=e.colorWrite),e.clippingPlanes!==void 0&&(this.clippingPlanes=e.clippingPlanes.map(n=>new vn().fromJSON(n))),e.clipIntersection!==void 0&&(this.clipIntersection=e.clipIntersection),e.clipShadows!==void 0&&(this.clipShadows=e.clipShadows),e.depthPacking!==void 0&&(this.depthPacking=e.depthPacking),e.blendSrc!==void 0&&(this.blendSrc=e.blendSrc),e.blendDst!==void 0&&(this.blendDst=e.blendDst),e.blendEquation!==void 0&&(this.blendEquation=e.blendEquation),e.blendSrcAlpha!==void 0&&(this.blendSrcAlpha=e.blendSrcAlpha),e.blendDstAlpha!==void 0&&(this.blendDstAlpha=e.blendDstAlpha),e.blendEquationAlpha!==void 0&&(this.blendEquationAlpha=e.blendEquationAlpha),e.blendColor!==void 0&&this.blendColor!==void 0&&this.blendColor.setHex(e.blendColor),e.blendAlpha!==void 0&&(this.blendAlpha=e.blendAlpha),e.stencilWriteMask!==void 0&&(this.stencilWriteMask=e.stencilWriteMask),e.stencilFunc!==void 0&&(this.stencilFunc=e.stencilFunc),e.stencilRef!==void 0&&(this.stencilRef=e.stencilRef),e.stencilFuncMask!==void 0&&(this.stencilFuncMask=e.stencilFuncMask),e.stencilFail!==void 0&&(this.stencilFail=e.stencilFail),e.stencilZFail!==void 0&&(this.stencilZFail=e.stencilZFail),e.stencilZPass!==void 0&&(this.stencilZPass=e.stencilZPass),e.stencilWrite!==void 0&&(this.stencilWrite=e.stencilWrite),e.wireframe!==void 0&&(this.wireframe=e.wireframe),e.wireframeLinewidth!==void 0&&(this.wireframeLinewidth=e.wireframeLinewidth),e.wireframeLinecap!==void 0&&(this.wireframeLinecap=e.wireframeLinecap),e.wireframeLinejoin!==void 0&&(this.wireframeLinejoin=e.wireframeLinejoin),e.rotation!==void 0&&(this.rotation=e.rotation),e.linewidth!==void 0&&(this.linewidth=e.linewidth),e.linecap!==void 0&&(this.linecap=e.linecap),e.linejoin!==void 0&&(this.linejoin=e.linejoin),e.dashSize!==void 0&&(this.dashSize=e.dashSize),e.gapSize!==void 0&&(this.gapSize=e.gapSize),e.scale!==void 0&&(this.scale=e.scale),e.polygonOffset!==void 0&&(this.polygonOffset=e.polygonOffset),e.polygonOffsetFactor!==void 0&&(this.polygonOffsetFactor=e.polygonOffsetFactor),e.polygonOffsetUnits!==void 0&&(this.polygonOffsetUnits=e.polygonOffsetUnits),e.dithering!==void 0&&(this.dithering=e.dithering),e.alphaToCoverage!==void 0&&(this.alphaToCoverage=e.alphaToCoverage),e.premultipliedAlpha!==void 0&&(this.premultipliedAlpha=e.premultipliedAlpha),e.forceSinglePass!==void 0&&(this.forceSinglePass=e.forceSinglePass),e.allowOverride!==void 0&&(this.allowOverride=e.allowOverride),e.visible!==void 0&&(this.visible=e.visible),e.toneMapped!==void 0&&(this.toneMapped=e.toneMapped),e.userData!==void 0&&(this.userData=e.userData),e.vertexColors!==void 0&&(typeof e.vertexColors=="number"?this.vertexColors=e.vertexColors>0:this.vertexColors=e.vertexColors),e.size!==void 0&&(this.size=e.size),e.sizeAttenuation!==void 0&&(this.sizeAttenuation=e.sizeAttenuation),e.map!==void 0&&(this.map=t[e.map]||null),e.matcap!==void 0&&(this.matcap=t[e.matcap]||null),e.alphaMap!==void 0&&(this.alphaMap=t[e.alphaMap]||null),e.bumpMap!==void 0&&(this.bumpMap=t[e.bumpMap]||null),e.bumpScale!==void 0&&(this.bumpScale=e.bumpScale),e.normalMap!==void 0&&(this.normalMap=t[e.normalMap]||null),e.normalMapType!==void 0&&(this.normalMapType=e.normalMapType),e.normalScale!==void 0){let n=e.normalScale;Array.isArray(n)===!1&&(n=[n,n]),this.normalScale=new ue().fromArray(n)}return e.displacementMap!==void 0&&(this.displacementMap=t[e.displacementMap]||null),e.displacementScale!==void 0&&(this.displacementScale=e.displacementScale),e.displacementBias!==void 0&&(this.displacementBias=e.displacementBias),e.roughnessMap!==void 0&&(this.roughnessMap=t[e.roughnessMap]||null),e.metalnessMap!==void 0&&(this.metalnessMap=t[e.metalnessMap]||null),e.emissiveMap!==void 0&&(this.emissiveMap=t[e.emissiveMap]||null),e.emissiveIntensity!==void 0&&(this.emissiveIntensity=e.emissiveIntensity),e.specularMap!==void 0&&(this.specularMap=t[e.specularMap]||null),e.specularIntensityMap!==void 0&&(this.specularIntensityMap=t[e.specularIntensityMap]||null),e.specularColorMap!==void 0&&(this.specularColorMap=t[e.specularColorMap]||null),e.envMap!==void 0&&(this.envMap=t[e.envMap]||null),e.envMapRotation!==void 0&&this.envMapRotation.fromArray(e.envMapRotation),e.envMapIntensity!==void 0&&(this.envMapIntensity=e.envMapIntensity),e.reflectivity!==void 0&&(this.reflectivity=e.reflectivity),e.refractionRatio!==void 0&&(this.refractionRatio=e.refractionRatio),e.lightMap!==void 0&&(this.lightMap=t[e.lightMap]||null),e.lightMapIntensity!==void 0&&(this.lightMapIntensity=e.lightMapIntensity),e.aoMap!==void 0&&(this.aoMap=t[e.aoMap]||null),e.aoMapIntensity!==void 0&&(this.aoMapIntensity=e.aoMapIntensity),e.gradientMap!==void 0&&(this.gradientMap=t[e.gradientMap]||null),e.clearcoatMap!==void 0&&(this.clearcoatMap=t[e.clearcoatMap]||null),e.clearcoatRoughnessMap!==void 0&&(this.clearcoatRoughnessMap=t[e.clearcoatRoughnessMap]||null),e.clearcoatNormalMap!==void 0&&(this.clearcoatNormalMap=t[e.clearcoatNormalMap]||null),e.clearcoatNormalScale!==void 0&&(this.clearcoatNormalScale=new ue().fromArray(e.clearcoatNormalScale)),e.iridescenceMap!==void 0&&(this.iridescenceMap=t[e.iridescenceMap]||null),e.iridescenceThicknessMap!==void 0&&(this.iridescenceThicknessMap=t[e.iridescenceThicknessMap]||null),e.transmissionMap!==void 0&&(this.transmissionMap=t[e.transmissionMap]||null),e.thicknessMap!==void 0&&(this.thicknessMap=t[e.thicknessMap]||null),e.anisotropyMap!==void 0&&(this.anisotropyMap=t[e.anisotropyMap]||null),e.sheenColorMap!==void 0&&(this.sheenColorMap=t[e.sheenColorMap]||null),e.sheenRoughnessMap!==void 0&&(this.sheenRoughnessMap=t[e.sheenRoughnessMap]||null),this}clone(){return new this.constructor().copy(this)}copy(e){this.name=e.name,this.blending=e.blending,this.side=e.side,this.vertexColors=e.vertexColors,this.opacity=e.opacity,this.transparent=e.transparent,this.blendSrc=e.blendSrc,this.blendDst=e.blendDst,this.blendEquation=e.blendEquation,this.blendSrcAlpha=e.blendSrcAlpha,this.blendDstAlpha=e.blendDstAlpha,this.blendEquationAlpha=e.blendEquationAlpha,this.blendColor.copy(e.blendColor),this.blendAlpha=e.blendAlpha,this.depthFunc=e.depthFunc,this.depthTest=e.depthTest,this.depthWrite=e.depthWrite,this.stencilWriteMask=e.stencilWriteMask,this.stencilFunc=e.stencilFunc,this.stencilRef=e.stencilRef,this.stencilFuncMask=e.stencilFuncMask,this.stencilFail=e.stencilFail,this.stencilZFail=e.stencilZFail,this.stencilZPass=e.stencilZPass,this.stencilWrite=e.stencilWrite;let t=e.clippingPlanes,n=null;if(t!==null){let s=t.length;n=new Array(s);for(let r=0;r!==s;++r)n[r]=t[r].clone()}return this.clippingPlanes=n,this.clipIntersection=e.clipIntersection,this.clipShadows=e.clipShadows,this.shadowSide=e.shadowSide,this.colorWrite=e.colorWrite,this.precision=e.precision,this.polygonOffset=e.polygonOffset,this.polygonOffsetFactor=e.polygonOffsetFactor,this.polygonOffsetUnits=e.polygonOffsetUnits,this.dithering=e.dithering,this.alphaTest=e.alphaTest,this.alphaHash=e.alphaHash,this.alphaToCoverage=e.alphaToCoverage,this.premultipliedAlpha=e.premultipliedAlpha,this.forceSinglePass=e.forceSinglePass,this.allowOverride=e.allowOverride,this.visible=e.visible,this.toneMapped=e.toneMapped,this.userData=JSON.parse(JSON.stringify(e.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(e){e===!0&&this.version++}},ps=class extends Fn{constructor(e){super(),this.isSpriteMaterial=!0,this.type="SpriteMaterial",this.color=new Xe(16777215),this.map=null,this.alphaMap=null,this.rotation=0,this.sizeAttenuation=!0,this.transparent=!0,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.alphaMap=e.alphaMap,this.rotation=e.rotation,this.sizeAttenuation=e.sizeAttenuation,this.fog=e.fog,this}},$i,Vs=new I,Ki=new I,Qi=new I,ji=new ue,Hs=new ue,_u=new gt,ea=new I,Gs=new I,ta=new I,mh=new ue,wl=new ue,gh=new ue,sr=class extends Ft{constructor(e=new ps){if(super(),this.isSprite=!0,this.type="Sprite",$i===void 0){$i=new At;let t=new Float32Array([-.5,-.5,0,0,0,.5,-.5,0,1,0,.5,.5,0,1,1,-.5,.5,0,0,1]),n=new ir(t,5);$i.setIndex([0,1,2,0,2,3]),$i.setAttribute("position",new fs(n,3,0,!1)),$i.setAttribute("uv",new fs(n,2,3,!1))}this.geometry=$i,this.material=e,this.center=new ue(.5,.5),this.count=1}intersectsFrustum(e){return e.intersectsSprite(this)}raycast(e,t){e.camera===null&&We('Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.'),Ki.setFromMatrixScale(this.matrixWorld),_u.copy(e.camera.matrixWorld),this.modelViewMatrix.multiplyMatrices(e.camera.matrixWorldInverse,this.matrixWorld),Qi.setFromMatrixPosition(this.modelViewMatrix),e.camera.isPerspectiveCamera&&this.material.sizeAttenuation===!1&&Ki.multiplyScalar(-Qi.z);let n=this.material.rotation,s,r;n!==0&&(r=Math.cos(n),s=Math.sin(n));let a=this.center;na(ea.set(-.5,-.5,0),Qi,a,Ki,s,r),na(Gs.set(.5,-.5,0),Qi,a,Ki,s,r),na(ta.set(.5,.5,0),Qi,a,Ki,s,r),mh.set(0,0),wl.set(1,0),gh.set(1,1);let o=e.ray.intersectTriangle(ea,Gs,ta,!1,Vs);if(o===null&&(na(Gs.set(-.5,.5,0),Qi,a,Ki,s,r),wl.set(0,1),o=e.ray.intersectTriangle(ea,ta,Gs,!1,Vs),o===null))return;let l=e.ray.origin.distanceTo(Vs);le.far||t.push({distance:l,point:Vs.clone(),uv:Qn.getInterpolation(Vs,ea,Gs,ta,mh,wl,gh,new ue),face:null,object:this})}copy(e,t){return super.copy(e,t),e.center!==void 0&&this.center.copy(e.center),this.material=e.material,this}};function na(i,e,t,n,s,r){ji.subVectors(i,t).addScalar(.5).multiply(n),s!==void 0?(Hs.x=r*ji.x-s*ji.y,Hs.y=s*ji.x+r*ji.y):Hs.copy(ji),i.copy(e),i.x+=Hs.x,i.y+=Hs.y,i.applyMatrix4(_u)}var Kn=new I,Al=new I,ia=new I,sa=new I,rr=class{constructor(e=new I,t=new I(0,0,-1)){this.origin=e,this.direction=t}set(e,t){return this.origin.copy(e),this.direction.copy(t),this}copy(e){return this.origin.copy(e.origin),this.direction.copy(e.direction),this}at(e,t){return t.copy(this.origin).addScaledVector(this.direction,e)}lookAt(e){return this.direction.copy(e).sub(this.origin).normalize(),this}recast(e){return this.origin.copy(this.at(e,Kn)),this}closestPointToPoint(e,t){t.subVectors(e,this.origin);let n=t.dot(this.direction);return n<0?t.copy(this.origin):t.copy(this.origin).addScaledVector(this.direction,n)}distanceToPoint(e){return Math.sqrt(this.distanceSqToPoint(e))}distanceSqToPoint(e){let t=Kn.subVectors(e,this.origin).dot(this.direction);return t<0?this.origin.distanceToSquared(e):(Kn.copy(this.origin).addScaledVector(this.direction,t),Kn.distanceToSquared(e))}distanceSqToSegment(e,t,n,s){Al.copy(e).add(t).multiplyScalar(.5),ia.copy(t).sub(e).normalize(),sa.copy(this.origin).sub(Al);let r=e.distanceTo(t)*.5,a=-this.direction.dot(ia),o=sa.dot(this.direction),l=-sa.dot(ia),c=sa.lengthSq(),h=Math.abs(1-a*a),u,d,f,m;if(h>0)if(u=a*l-o,d=a*o-l,m=r*h,u>=0)if(d>=-m)if(d<=m){let v=1/h;u*=v,d*=v,f=u*(u+a*d+2*o)+d*(a*u+d+2*l)+c}else d=r,u=Math.max(0,-(a*d+o)),f=-u*u+d*(d+2*l)+c;else d=-r,u=Math.max(0,-(a*d+o)),f=-u*u+d*(d+2*l)+c;else d<=-m?(u=Math.max(0,-(-a*r+o)),d=u>0?-r:Math.min(Math.max(-r,-l),r),f=-u*u+d*(d+2*l)+c):d<=m?(u=0,d=Math.min(Math.max(-r,-l),r),f=d*(d+2*l)+c):(u=Math.max(0,-(a*r+o)),d=u>0?r:Math.min(Math.max(-r,-l),r),f=-u*u+d*(d+2*l)+c);else d=a>0?-r:r,u=Math.max(0,-(a*d+o)),f=-u*u+d*(d+2*l)+c;return n&&n.copy(this.origin).addScaledVector(this.direction,u),s&&s.copy(Al).addScaledVector(ia,d),f}intersectSphere(e,t){if(e.radius<0)return null;Kn.subVectors(e.center,this.origin);let n=Kn.dot(this.direction),s=Kn.dot(Kn)-n*n,r=e.radius*e.radius;if(s>r)return null;let a=Math.sqrt(r-s),o=n-a,l=n+a;return l<0?null:o<0?this.at(l,t):this.at(o,t)}intersectsSphere(e){return e.radius<0?!1:this.distanceSqToPoint(e.center)<=e.radius*e.radius}distanceToPlane(e){let t=e.normal.dot(this.direction);if(t===0)return e.distanceToPoint(this.origin)===0?0:null;let n=-(this.origin.dot(e.normal)+e.constant)/t;return n>=0?n:null}intersectPlane(e,t){let n=this.distanceToPlane(e);return n===null?null:this.at(n,t)}intersectsPlane(e){let t=e.distanceToPoint(this.origin);return t===0||e.normal.dot(this.direction)*t<0}intersectBox(e,t){let n,s,r,a,o,l,c=1/this.direction.x,h=1/this.direction.y,u=1/this.direction.z,d=this.origin;return c>=0?(n=(e.min.x-d.x)*c,s=(e.max.x-d.x)*c):(n=(e.max.x-d.x)*c,s=(e.min.x-d.x)*c),h>=0?(r=(e.min.y-d.y)*h,a=(e.max.y-d.y)*h):(r=(e.max.y-d.y)*h,a=(e.min.y-d.y)*h),n>a||r>s||((r>n||isNaN(n))&&(n=r),(a=0?(o=(e.min.z-d.z)*u,l=(e.max.z-d.z)*u):(o=(e.max.z-d.z)*u,l=(e.min.z-d.z)*u),n>l||o>s)||((o>n||n!==n)&&(n=o),(l=0?n:s,t)}intersectsBox(e){return this.intersectBox(e,Kn)!==null}intersectTriangle(e,t,n,s,r){let a=this.origin,o=this.direction,l=o.x,c=o.y,h=o.z,u=e.x-a.x,d=e.y-a.y,f=e.z-a.z,m=t.x-a.x,v=t.y-a.y,g=t.z-a.z,p=n.x-a.x,T=n.y-a.y,w=n.z-a.z,M=Math.abs(l),b=Math.abs(c),S=Math.abs(h),R,x,E,C,P,B,V,N,k,$,q,Y;if(M>=b&&M>=S?(E=l,B=u,k=m,Y=p,l>=0?(R=c,x=h,C=d,P=f,V=v,N=g,$=T,q=w):(R=h,x=c,C=f,P=d,V=g,N=v,$=w,q=T)):b>=S?(E=c,B=d,k=v,Y=T,c>=0?(R=h,x=l,C=f,P=u,V=g,N=m,$=w,q=p):(R=l,x=h,C=u,P=f,V=m,N=g,$=p,q=w)):(E=h,B=f,k=g,Y=w,h>=0?(R=l,x=c,C=u,P=d,V=m,N=v,$=p,q=T):(R=c,x=l,C=d,P=u,V=v,N=m,$=T,q=p)),E===0)return null;let F=R/E,z=x/E,Z=1/E,fe=C-F*B,he=P-z*B,qe=V-F*k,Ve=N-z*k,Ye=$-F*Y,K=q-z*Y,ne=Ye*Ve-K*qe,pe=fe*K-he*Ye,De=qe*he-Ve*fe;if(s){if(ne<0||pe<0||De<0)return null}else if((ne<0||pe<0||De<0)&&(ne>0||pe>0||De>0))return null;let me=ne+pe+De;if(me===0)return null;let Fe=Z*(ne*B+pe*k+De*Y);return(me>0?Fe<0:Fe>0)?null:this.at(Fe/me,r)}applyMatrix4(e){return this.origin.applyMatrix4(e),this.direction.transformDirection(e),this}equals(e){return e.origin.equals(this.origin)&&e.direction.equals(this.direction)}clone(){return new this.constructor().copy(this)}},pt=class extends Fn{constructor(e){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new Xe(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 Sn,this.combine=Jl,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.specularMap=e.specularMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.combine=e.combine,this.reflectivity=e.reflectivity,this.refractionRatio=e.refractionRatio,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.fog=e.fog,this}},_h=new gt,Ti=new rr,ra=new Pi,xh=new I,aa=new I,oa=new I,la=new I,Rl=new I,ca=new I,vh=new I,ha=new I,$e=class extends Ft{constructor(e=new At,t=new pt){super(),this.isMesh=!0,this.type="Mesh",this.geometry=e,this.material=t,this.morphTargetDictionary=void 0,this.morphTargetInfluences=void 0,this.count=1,this.updateMorphTargets()}copy(e,t){return super.copy(e,t),e.morphTargetInfluences!==void 0&&(this.morphTargetInfluences=e.morphTargetInfluences.slice()),e.morphTargetDictionary!==void 0&&(this.morphTargetDictionary=Object.assign({},e.morphTargetDictionary)),this.material=Array.isArray(e.material)?e.material.slice():e.material,this.geometry=e.geometry,this}updateMorphTargets(){let t=this.geometry.morphAttributes,n=Object.keys(t);if(n.length>0){let s=t[n[0]];if(s!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,a=s.length;r(e.far-e.near)**2))&&(_h.copy(r).invert(),Ti.copy(e.ray).applyMatrix4(_h),!(n.boundingBox!==null&&Ti.intersectsBox(n.boundingBox)===!1)&&this._computeIntersections(e,t,Ti)))}_computeIntersections(e,t,n){let s,r=this.geometry,a=this.material,o=r.index,l=r.attributes.position,c=r.attributes.uv,h=r.attributes.uv1,u=r.attributes.normal,d=r.groups,f=r.drawRange;if(o!==null)if(Array.isArray(a))for(let m=0,v=d.length;mt.far?null:{distance:c,point:ha.clone(),object:i}}function ua(i,e,t,n,s,r,a,o,l,c){i.getVertexPosition(o,aa),i.getVertexPosition(l,oa),i.getVertexPosition(c,la);let h=gf(i,e,t,n,aa,oa,la,vh);if(h){let u=new I;Qn.getBarycoord(vh,aa,oa,la,u),s&&(h.uv=Qn.getInterpolatedAttribute(s,o,l,c,u,new ue)),r&&(h.uv1=Qn.getInterpolatedAttribute(r,o,l,c,u,new ue)),a&&(h.normal=Qn.getInterpolatedAttribute(a,o,l,c,u,new I),h.normal.dot(n.direction)>0&&h.normal.multiplyScalar(-1));let d={a:o,b:l,c,normal:new I,materialIndex:0};Qn.getNormal(aa,oa,la,d.normal),h.face=d,h.barycoord=u}return h}var ms=class extends Yt{constructor(e=null,t=1,n=1,s,r,a,o,l,c=Ut,h=Ut,u,d){super(null,a,o,l,c,h,s,r,u,d),this.isDataTexture=!0,this.image={data:e,width:t,height:n},this.generateMipmaps=!1,this.flipY=!1,this.unpackAlignment=1}};var wi=new Pi,_f=new ue(.5,.5),da=new I,gs=class{constructor(e=new vn,t=new vn,n=new vn,s=new vn,r=new vn,a=new vn){this.planes=[e,t,n,s,r,a]}set(e,t,n,s,r,a){let o=this.planes;return o[0].copy(e),o[1].copy(t),o[2].copy(n),o[3].copy(s),o[4].copy(r),o[5].copy(a),this}copy(e){let t=this.planes;for(let n=0;n<6;n++)t[n].copy(e.planes[n]);return this}setFromProjectionMatrix(e,t=Mn,n=!1){let s=this.planes,r=e.elements,a=r[0],o=r[1],l=r[2],c=r[3],h=r[4],u=r[5],d=r[6],f=r[7],m=r[8],v=r[9],g=r[10],p=r[11],T=r[12],w=r[13],M=r[14],b=r[15];if(s[0].setComponents(c-a,f-h,p-m,b-T).normalize(),s[1].setComponents(c+a,f+h,p+m,b+T).normalize(),s[2].setComponents(c+o,f+u,p+v,b+w).normalize(),s[3].setComponents(c-o,f-u,p-v,b-w).normalize(),n)s[4].setComponents(l,d,g,M).normalize(),s[5].setComponents(c-l,f-d,p-g,b-M).normalize();else if(s[4].setComponents(c-l,f-d,p-g,b-M).normalize(),t===Mn)s[5].setComponents(c+l,f+d,p+g,b+M).normalize();else if(t===os)s[5].setComponents(l,d,g,M).normalize();else throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+t);return this}intersectsObject(e){if(e.boundingSphere!==void 0)e.boundingSphere===null&&e.computeBoundingSphere(),wi.copy(e.boundingSphere).applyMatrix4(e.matrixWorld);else{let t=e.geometry;t.boundingSphere===null&&t.computeBoundingSphere(),wi.copy(t.boundingSphere).applyMatrix4(e.matrixWorld)}return this.intersectsSphere(wi)}intersectsSprite(e){wi.center.set(0,0,0);let t=_f.distanceTo(e.center);return wi.radius=.7071067811865476+t,wi.applyMatrix4(e.matrixWorld),this.intersectsSphere(wi)}intersectsSphere(e){let t=this.planes,n=e.center,s=-e.radius;for(let r=0;r<6;r++)if(t[r].distanceToPoint(n)0?e.max.x:e.min.x,da.y=s.normal.y>0?e.max.y:e.min.y,da.z=s.normal.z>0?e.max.z:e.min.z,s.distanceToPoint(da)<0)return!1}return!0}containsPoint(e){let t=this.planes;for(let n=0;n<6;n++)if(t[n].distanceToPoint(e)<0)return!1;return!0}clone(){return new this.constructor().copy(this)}};var _s=class extends Fn{constructor(e){super(),this.isPointsMaterial=!0,this.type="PointsMaterial",this.color=new Xe(16777215),this.map=null,this.alphaMap=null,this.size=1,this.sizeAttenuation=!0,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.color.copy(e.color),this.map=e.map,this.alphaMap=e.alphaMap,this.size=e.size,this.sizeAttenuation=e.sizeAttenuation,this.fog=e.fog,this}},yh=new gt,Bl=new rr,fa=new Pi,pa=new I,ar=class extends Ft{constructor(e=new At,t=new _s){super(),this.isPoints=!0,this.type="Points",this.geometry=e,this.material=t,this.morphTargetDictionary=void 0,this.morphTargetInfluences=void 0,this.updateMorphTargets()}copy(e,t){return super.copy(e,t),this.material=Array.isArray(e.material)?e.material.slice():e.material,this.geometry=e.geometry,this}intersectsFrustum(e){return e.intersectsObject(this)}raycast(e,t){let n=this.geometry,s=this.matrixWorld,r=e.params.Points.threshold,a=n.drawRange;if(n.boundingSphere===null&&n.computeBoundingSphere(),fa.copy(n.boundingSphere),fa.applyMatrix4(s),fa.radius+=r,e.ray.intersectsSphere(fa)===!1)return;yh.copy(s).invert(),Bl.copy(e.ray).applyMatrix4(yh);let o=r/((this.scale.x+this.scale.y+this.scale.z)/3),l=o*o,c=n.index,u=n.attributes.position;if(c!==null){let d=Math.max(0,a.start),f=Math.min(c.count,a.start+a.count);for(let m=d,v=f;m0){let s=t[n[0]];if(s!==void 0){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let r=0,a=s.length;rs.far)return;r.push({distance:c,distanceToRay:Math.sqrt(o),point:l,index:e,face:null,faceIndex:null,barycoord:null,object:a})}}var or=class extends Yt{constructor(e=[],t=xi,n,s,r,a,o,l,c,h){super(e,t,n,s,r,a,o,l,c,h),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(e){this.image=e}},ei=class extends Yt{constructor(e,t,n,s,r,a,o,l,c){super(e,t,n,s,r,a,o,l,c),this.isCanvasTexture=!0,this.needsUpdate=!0}};var ui=class extends Yt{constructor(e,t,n=En,s,r,a,o=Ut,l=Ut,c,h=Dn,u=1){if(h!==Dn&&h!==vi)throw new Error("THREE.DepthTexture: format must be either THREE.DepthFormat or THREE.DepthStencilFormat");let d={width:e,height:t,depth:u};super(d,s,r,a,o,l,h,n,c),this.isDepthTexture=!0,this.flipY=!1,this.generateMipmaps=!1,this.compareFunction=null}copy(e){return super.copy(e),this.source=new us(Object.assign({},e.image)),this.compareFunction=e.compareFunction,this}toJSON(e){let t=super.toJSON(e);return t.compareFunction=this.compareFunction,t}},Na=class extends ui{constructor(e,t=En,n=xi,s,r,a=Ut,o=Ut,l,c=Dn){let h={width:e,height:e,depth:1},u=[h,h,h,h,h,h];super(e,e,t,n,s,r,a,o,l,c),this.image=u,this.isCubeDepthTexture=!0,this.isCubeTexture=!0}get images(){return this.image}set images(e){this.image=e}},lr=class extends Yt{constructor(e=null){super(),this.sourceTexture=e,this.isExternalTexture=!0}copy(e){return super.copy(e),this.sourceTexture=e.sourceTexture,this}},On=class i extends At{constructor(e=1,t=1,n=1,s=1,r=1,a=1){super(),this.type="BoxGeometry",this.parameters={width:e,height:t,depth:n,widthSegments:s,heightSegments:r,depthSegments:a};let o=this;s=Math.floor(s),r=Math.floor(r),a=Math.floor(a);let l=[],c=[],h=[],u=[],d=0,f=0;m("z","y","x",-1,-1,n,t,e,a,r,0),m("z","y","x",1,-1,n,t,-e,a,r,1),m("x","z","y",1,1,e,n,t,s,a,2),m("x","z","y",1,-1,e,n,-t,s,a,3),m("x","y","z",1,-1,e,t,n,s,r,4),m("x","y","z",-1,-1,e,t,-n,s,r,5),this.setIndex(l),this.setAttribute("position",new yt(c,3)),this.setAttribute("normal",new yt(h,3)),this.setAttribute("uv",new yt(u,2));function m(v,g,p,T,w,M,b,S,R,x,E){let C=M/R,P=b/x,B=M/2,V=b/2,N=S/2,k=R+1,$=x+1,q=0,Y=0,F=new I;for(let z=0;z<$;z++){let Z=z*P-V;for(let fe=0;fe0?1:-1,h.push(F.x,F.y,F.z),u.push(fe/R),u.push(1-z/x),q+=1}}for(let z=0;z0)l=s-1;else{l=s;break}if(s=l,n[s]===a)return s/(r-1);let h=n[s],d=n[s+1]-h,f=(a-h)/d;return(s+f)/(r-1)}getTangent(e,t){let s=e-1e-4,r=e+1e-4;s<0&&(s=0),r>1&&(r=1);let a=this.getPoint(s),o=this.getPoint(r),l=t||(a.isVector2?new ue:new I);return l.copy(o).sub(a).normalize(),l}getTangentAt(e,t){let n=this.getUtoTmapping(e);return this.getTangent(n,t)}computeFrenetFrames(e,t=!1){let n=new I,s=[],r=[],a=[],o=new I,l=new gt;for(let f=0;f<=e;f++){let m=f/e;s[f]=this.getTangentAt(m,new I)}r[0]=new I,a[0]=new I;let c=Number.MAX_VALUE,h=Math.abs(s[0].x),u=Math.abs(s[0].y),d=Math.abs(s[0].z);h<=c&&(c=h,n.set(1,0,0)),u<=c&&(c=u,n.set(0,1,0)),d<=c&&n.set(0,0,1),o.crossVectors(s[0],n).normalize(),r[0].crossVectors(s[0],o),a[0].crossVectors(s[0],r[0]);for(let f=1;f<=e;f++){if(r[f]=r[f-1].clone(),a[f]=a[f-1].clone(),o.crossVectors(s[f-1],s[f]),o.length()>Number.EPSILON){o.normalize();let m=Math.acos(tt(s[f-1].dot(s[f]),-1,1));r[f].applyMatrix4(l.makeRotationAxis(o,m))}a[f].crossVectors(s[f],r[f])}if(t===!0){let f=Math.acos(tt(r[0].dot(r[e]),-1,1));f/=e,s[0].dot(o.crossVectors(r[0],r[e]))>0&&(f=-f);for(let m=1;m<=e;m++)r[m].applyMatrix4(l.makeRotationAxis(s[m],f*m)),a[m].crossVectors(s[m],r[m])}return{tangents:s,normals:r,binormals:a}}clone(){return new this.constructor().copy(this)}copy(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}toJSON(){let e={metadata:{version:4.7,type:"Curve",generator:"Curve.toJSON"}};return e.arcLengthDivisions=this.arcLengthDivisions,e.type=this.type,e}fromJSON(e){return this.arcLengthDivisions=e.arcLengthDivisions,this}},xs=class extends rn{constructor(e=0,t=0,n=1,s=1,r=0,a=Math.PI*2,o=!1,l=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=e,this.aY=t,this.xRadius=n,this.yRadius=s,this.aStartAngle=r,this.aEndAngle=a,this.aClockwise=o,this.aRotation=l}getPoint(e,t=new ue){let n=t,s=Math.PI*2,r=this.aEndAngle-this.aStartAngle,a=Math.abs(r)s;)r-=s;r0?0:(Math.floor(Math.abs(o)/r)+1)*r:l===0&&o===r-1&&(o=r-2,l=1);let c,h;this.closed||o>0?c=s[(o-1)%r]:(bh.subVectors(s[0],s[1]).add(s[0]),c=bh);let u=s[o%r],d=s[(o+1)%r];if(this.closed||o+2s.length-2?s.length-1:a+1],u=s[a>s.length-3?s.length-1:a+2];return n.set(Eh(o,l.x,c.x,h.x,u.x),Eh(o,l.y,c.y,h.y,u.y)),n}copy(e){super.copy(e),this.points=[];for(let t=0,n=e.points.length;t=n){let a=s[r]-n,o=this.curves[r],l=o.getLength(),c=l===0?0:1-a/l;return o.getPointAt(c,t)}r++}return null}getLength(){let e=this.getCurveLengths();return e[e.length-1]}updateArcLengths(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()}getCurveLengths(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;let e=[],t=0;for(let n=0,s=this.curves.length;n1&&!t[t.length-1].equals(t[0])&&t.push(t[0]),t}copy(e){super.copy(e),this.curves=[];for(let t=0,n=e.curves.length;t0){let u=c.getPoint(0);u.equals(this.currentPoint)||this.lineTo(u.x,u.y)}this.curves.push(c);let h=c.getPoint(1);return this.currentPoint.copy(h),this}copy(e){return super.copy(e),this.currentPoint.copy(e.currentPoint),this}toJSON(){let e=super.toJSON();return e.currentPoint=this.currentPoint.toArray(),e}fromJSON(e){return super.fromJSON(e),this.currentPoint.fromArray(e.currentPoint),this}},vs=class extends di{constructor(e){super(e),this.uuid=Ln(),this.type="Shape",this.holes=[]}getPointsHoles(e){let t=[];for(let n=0,s=this.holes.length;n80*t){o=i[0],l=i[1];let h=o,u=l;for(let d=t;dh&&(h=f),m>u&&(u=m)}c=Math.max(h-o,u-l),c=c!==0?32767/c:0}return mr(r,a,t,o,l,c,0),a}function xu(i,e,t,n,s){let r;if(s===Vf(i,e,t,n)>0)for(let a=e;a=e;a-=n)r=Th(a/n|0,i[a],i[a+1],r);return r&&ys(r,r.next)&&(_r(r),r=r.next),r}function Ii(i,e){if(!i)return i;e||(e=i);let t=i,n;do if(n=!1,!t.steiner&&(ys(t,t.next)||bt(t.prev,t,t.next)===0)){if(_r(t),t=e=t.prev,t===t.next)break;n=!0}else t=t.next;while(n||t!==e);return e}function mr(i,e,t,n,s,r,a){if(!i)return;!a&&r&&Uf(i,n,s,r);let o=i;for(;i.prev!==i.next;){let l=i.prev,c=i.next;if(r?Af(i,n,s,r):wf(i)){e.push(l.i,i.i,c.i),_r(i),i=c.next,o=c.next;continue}if(i=c,i===o){a?a===1?(i=Rf(Ii(i),e),mr(i,e,t,n,s,r,2)):a===2&&Cf(i,e,t,n,s,r):mr(Ii(i),e,t,n,s,r,1);break}}}function wf(i){let e=i.prev,t=i,n=i.next;if(bt(e,t,n)>=0)return!1;let s=e.x,r=t.x,a=n.x,o=e.y,l=t.y,c=n.y,h=Math.min(s,r,a),u=Math.min(o,l,c),d=Math.max(s,r,a),f=Math.max(o,l,c),m=n.next;for(;m!==e;){if(m.x>=h&&m.x<=d&&m.y>=u&&m.y<=f&&Ws(s,o,r,l,a,c,m.x,m.y)&&bt(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function Af(i,e,t,n){let s=i.prev,r=i,a=i.next;if(bt(s,r,a)>=0)return!1;let o=s.x,l=r.x,c=a.x,h=s.y,u=r.y,d=a.y,f=Math.min(o,l,c),m=Math.min(h,u,d),v=Math.max(o,l,c),g=Math.max(h,u,d),p=zl(f,m,e,t,n),T=zl(v,g,e,t,n),w=i.prevZ,M=i.nextZ;for(;w&&w.z>=p&&M&&M.z<=T;){if(w.x>=f&&w.x<=v&&w.y>=m&&w.y<=g&&w!==s&&w!==a&&Ws(o,h,l,u,c,d,w.x,w.y)&&bt(w.prev,w,w.next)>=0||(w=w.prevZ,M.x>=f&&M.x<=v&&M.y>=m&&M.y<=g&&M!==s&&M!==a&&Ws(o,h,l,u,c,d,M.x,M.y)&&bt(M.prev,M,M.next)>=0))return!1;M=M.nextZ}for(;w&&w.z>=p;){if(w.x>=f&&w.x<=v&&w.y>=m&&w.y<=g&&w!==s&&w!==a&&Ws(o,h,l,u,c,d,w.x,w.y)&&bt(w.prev,w,w.next)>=0)return!1;w=w.prevZ}for(;M&&M.z<=T;){if(M.x>=f&&M.x<=v&&M.y>=m&&M.y<=g&&M!==s&&M!==a&&Ws(o,h,l,u,c,d,M.x,M.y)&&bt(M.prev,M,M.next)>=0)return!1;M=M.nextZ}return!0}function Rf(i,e){let t=i;do{let n=t.prev,s=t.next.next;!ys(n,s)&&yu(n,t,t.next,s)&&gr(n,s)&&gr(s,n)&&(e.push(n.i,t.i,s.i),_r(t),_r(t.next),t=i=s),t=t.next}while(t!==i);return Ii(t)}function Cf(i,e,t,n,s,r){let a=i;do{let o=a.next.next;for(;o!==a.prev;){if(a.i!==o.i&&Bf(a,o)){let l=Mu(a,o);a=Ii(a,a.next),l=Ii(l,l.next),mr(a,e,t,n,s,r,0),mr(l,e,t,n,s,r,0);return}o=o.next}a=a.next}while(a!==i)}function Pf(i,e,t,n){let s=[];for(let r=0,a=e.length;r=t.next.y&&t.next.y!==t.y){let u=t.x+(s-t.y)*(t.next.x-t.x)/(t.next.y-t.y);if(u<=n&&u>r&&(r=u,a=t.x=t.x&&t.x>=l&&n!==t.x&&vu(sa.x||t.x===a.x&&Nf(a,t)))&&(a=t,h=u)}t=t.next}while(t!==o);return a}function Nf(i,e){return bt(i.prev,i,e.prev)<0&&bt(e.next,i,i.next)<0}function Uf(i,e,t,n){let s=i;do s.z===0&&(s.z=zl(s.x,s.y,e,t,n)),s.prevZ=s.prev,s.nextZ=s.next,s=s.next;while(s!==i);s.prevZ.nextZ=null,s.prevZ=null,Ff(s)}function Ff(i){let e,t=1;do{let n=i,s;i=null;let r=null;for(e=0;n;){e++;let a=n,o=0;for(let c=0;c0||l>0&&a;)o!==0&&(l===0||!a||n.z<=a.z)?(s=n,n=n.nextZ,o--):(s=a,a=a.nextZ,l--),r?r.nextZ=s:i=s,s.prevZ=r,r=s;n=a}r.nextZ=null,t*=2}while(e>1);return i}function zl(i,e,t,n,s){return i=(i-t)*s|0,e=(e-n)*s|0,i=(i|i<<8)&16711935,i=(i|i<<4)&252645135,i=(i|i<<2)&858993459,i=(i|i<<1)&1431655765,e=(e|e<<8)&16711935,e=(e|e<<4)&252645135,e=(e|e<<2)&858993459,e=(e|e<<1)&1431655765,i|e<<1}function Of(i){let e=i,t=i;do(e.x=(i-a)*(r-o)&&(i-a)*(n-o)>=(t-a)*(e-o)&&(t-a)*(r-o)>=(s-a)*(n-o)}function Ws(i,e,t,n,s,r,a,o){return!(i===a&&e===o)&&vu(i,e,t,n,s,r,a,o)}function Bf(i,e){return i.next.i!==e.i&&i.prev.i!==e.i&&!zf(i,e)&&(gr(i,e)&&gr(e,i)&&kf(i,e)&&(bt(i.prev,i,e.prev)||bt(i,e.prev,e))||ys(i,e)&&bt(i.prev,i,i.next)>0&&bt(e.prev,e,e.next)>0)}function bt(i,e,t){return(e.y-i.y)*(t.x-e.x)-(e.x-i.x)*(t.y-e.y)}function ys(i,e){return i.x===e.x&&i.y===e.y}function yu(i,e,t,n){let s=ga(bt(i,e,t)),r=ga(bt(i,e,n)),a=ga(bt(t,n,i)),o=ga(bt(t,n,e));return!!(s!==r&&a!==o||s===0&&ma(i,t,e)||r===0&&ma(i,n,e)||a===0&&ma(t,i,n)||o===0&&ma(t,e,n))}function ma(i,e,t){return e.x<=Math.max(i.x,t.x)&&e.x>=Math.min(i.x,t.x)&&e.y<=Math.max(i.y,t.y)&&e.y>=Math.min(i.y,t.y)}function ga(i){return i>0?1:i<0?-1:0}function zf(i,e){let t=i;do{if(t.i!==i.i&&t.next.i!==i.i&&t.i!==e.i&&t.next.i!==e.i&&yu(t,t.next,i,e))return!0;t=t.next}while(t!==i);return!1}function gr(i,e){return bt(i.prev,i,i.next)<0?bt(i,e,i.next)>=0&&bt(i,i.prev,e)>=0:bt(i,e,i.prev)<0||bt(i,i.next,e)<0}function kf(i,e){let t=i,n=!1,s=(i.x+e.x)/2,r=(i.y+e.y)/2;do t.y>r!=t.next.y>r&&t.next.y!==t.y&&s<(t.next.x-t.x)*(r-t.y)/(t.next.y-t.y)+t.x&&(n=!n),t=t.next;while(t!==i);return n}function Mu(i,e){let t=kl(i.i,i.x,i.y),n=kl(e.i,e.x,e.y),s=i.next,r=e.prev;return i.next=e,e.prev=i,t.next=s,s.prev=t,n.next=t,t.prev=n,r.next=n,n.prev=r,n}function Th(i,e,t,n){let s=kl(i,e,t);return n?(s.next=n.next,s.prev=n,n.next.prev=s,n.next=s):(s.prev=s,s.next=s),s}function _r(i){i.next.prev=i.prev,i.prev.next=i.next,i.prevZ&&(i.prevZ.nextZ=i.nextZ),i.nextZ&&(i.nextZ.prevZ=i.prevZ)}function kl(i,e,t){return{i,x:e,y:t,prev:null,next:null,z:0,prevZ:null,nextZ:null,steiner:!1}}function Vf(i,e,t,n){let s=0;for(let r=e,a=t-n;r2&&i[e-1].equals(i[0])&&i.pop()}function Ah(i,e){for(let t=0;tNumber.EPSILON){let A=Math.sqrt(st),_=Math.sqrt(He*He+L*L),O=re.x-se/A,X=re.y+Ae/A,Q=le.x-L/_,de=le.y+He/_,ge=((Q-O)*L-(de-X)*He)/(Ae*L-se*He);j=O+Ae*ge-H.x,ae=X+se*ge-H.y;let ee=j*j+ae*ae;if(ee<=2)return new ue(j,ae);we=Math.sqrt(ee/2)}else{let A=!1;Ae>Number.EPSILON?He>Number.EPSILON&&(A=!0):Ae<-Number.EPSILON?He<-Number.EPSILON&&(A=!0):Math.sign(se)===Math.sign(L)&&(A=!0),A?(j=-se,ae=Ae,we=Math.sqrt(st)):(j=Ae,ae=se,we=Math.sqrt(st/2))}return new ue(j/we,ae/we)}let F=[];for(let H=0,re=k.length,le=re-1,j=H+1;H=0;H--){let re=H/g,le=f*Math.cos(re*Math.PI/2),j=m*Math.sin(re*Math.PI/2)+v;for(let ae=0,we=k.length;ae=0;){let j=le,ae=le-1;ae<0&&(ae=H.length-1);for(let we=0,Ae=h+g*2;we0&&(t.defines=this.defines),t.vertexShader=this.vertexShader,t.fragmentShader=this.fragmentShader,t.lights=this.lights,t.clipping=this.clipping;let n={};for(let s in this.extensions)this.extensions[s]===!0&&(n[s]=!0);return Object.keys(n).length>0&&(t.extensions=n),t}fromJSON(e,t){if(super.fromJSON(e,t),e.uniforms!==void 0)for(let n in e.uniforms){let s=e.uniforms[n];switch(this.uniforms[n]={},s.type){case"t":this.uniforms[n].value=t[s.value]||null;break;case"c":this.uniforms[n].value=new Xe().setHex(s.value);break;case"v2":this.uniforms[n].value=new ue().fromArray(s.value);break;case"v3":this.uniforms[n].value=new I().fromArray(s.value);break;case"v4":this.uniforms[n].value=new Mt().fromArray(s.value);break;case"m3":this.uniforms[n].value=new Je().fromArray(s.value);break;case"m4":this.uniforms[n].value=new gt().fromArray(s.value);break;default:this.uniforms[n].value=s.value}}if(e.defines!==void 0&&(this.defines=e.defines),e.vertexShader!==void 0&&(this.vertexShader=e.vertexShader),e.fragmentShader!==void 0&&(this.fragmentShader=e.fragmentShader),e.glslVersion!==void 0&&(this.glslVersion=e.glslVersion),e.extensions!==void 0)for(let n in e.extensions)this.extensions[n]=e.extensions[n];return e.lights!==void 0&&(this.lights=e.lights),e.clipping!==void 0&&(this.clipping=e.clipping),this}},ka=class extends an{constructor(e){super(e),this.isRawShaderMaterial=!0,this.type="RawShaderMaterial"}},fi=class extends Fn{constructor(e){super(),this.isMeshStandardMaterial=!0,this.type="MeshStandardMaterial",this.defines={STANDARD:""},this.color=new Xe(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 Xe(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=Xo,this.normalScale=new ue(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 Sn,this.envMapIntensity=1,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(e)}copy(e){return super.copy(e),this.defines={STANDARD:""},this.color.copy(e.color),this.roughness=e.roughness,this.metalness=e.metalness,this.map=e.map,this.lightMap=e.lightMap,this.lightMapIntensity=e.lightMapIntensity,this.aoMap=e.aoMap,this.aoMapIntensity=e.aoMapIntensity,this.emissive.copy(e.emissive),this.emissiveMap=e.emissiveMap,this.emissiveIntensity=e.emissiveIntensity,this.bumpMap=e.bumpMap,this.bumpScale=e.bumpScale,this.normalMap=e.normalMap,this.normalMapType=e.normalMapType,this.normalScale.copy(e.normalScale),this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.roughnessMap=e.roughnessMap,this.metalnessMap=e.metalnessMap,this.alphaMap=e.alphaMap,this.envMap=e.envMap,this.envMapRotation.copy(e.envMapRotation),this.envMapIntensity=e.envMapIntensity,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this.wireframeLinecap=e.wireframeLinecap,this.wireframeLinejoin=e.wireframeLinejoin,this.flatShading=e.flatShading,this.fog=e.fog,this}},pi=class extends fi{constructor(e){super(),this.isMeshPhysicalMaterial=!0,this.defines={STANDARD:"",PHYSICAL:""},this.type="MeshPhysicalMaterial",this.anisotropyRotation=0,this.anisotropyMap=null,this.clearcoatMap=null,this.clearcoatRoughness=0,this.clearcoatRoughnessMap=null,this.clearcoatNormalScale=new ue(1,1),this.clearcoatNormalMap=null,this.ior=1.5,Object.defineProperty(this,"reflectivity",{get:function(){return tt(2.5*(this.ior-1)/(this.ior+1),0,1)},set:function(t){this.ior=(1+.4*t)/(1-.4*t)}}),this.iridescenceMap=null,this.iridescenceIOR=1.3,this.iridescenceThicknessRange=[100,400],this.iridescenceThicknessMap=null,this.sheenColor=new Xe(0),this.sheenColorMap=null,this.sheenRoughness=1,this.sheenRoughnessMap=null,this.transmissionMap=null,this.thickness=0,this.thicknessMap=null,this.attenuationDistance=1/0,this.attenuationColor=new Xe(1,1,1),this.specularIntensity=1,this.specularIntensityMap=null,this.specularColor=new Xe(1,1,1),this.specularColorMap=null,this._anisotropy=0,this._clearcoat=0,this._dispersion=0,this._iridescence=0,this._retroreflectivity=0,this._sheen=0,this._transmission=0,this.setValues(e)}get anisotropy(){return this._anisotropy}set anisotropy(e){this._anisotropy>0!=e>0&&this.version++,this._anisotropy=e}get clearcoat(){return this._clearcoat}set clearcoat(e){this._clearcoat>0!=e>0&&this.version++,this._clearcoat=e}get iridescence(){return this._iridescence}set iridescence(e){this._iridescence>0!=e>0&&this.version++,this._iridescence=e}get dispersion(){return this._dispersion}set dispersion(e){this._dispersion>0!=e>0&&this.version++,this._dispersion=e}get retroreflectivity(){return this._retroreflectivity}set retroreflectivity(e){this._retroreflectivity>0!=e>0&&this.version++,this._retroreflectivity=e}get sheen(){return this._sheen}set sheen(e){this._sheen>0!=e>0&&this.version++,this._sheen=e}get transmission(){return this._transmission}set transmission(e){this._transmission>0!=e>0&&this.version++,this._transmission=e}copy(e){return super.copy(e),this.defines={STANDARD:"",PHYSICAL:""},this.anisotropy=e.anisotropy,this.anisotropyRotation=e.anisotropyRotation,this.anisotropyMap=e.anisotropyMap,this.clearcoat=e.clearcoat,this.clearcoatMap=e.clearcoatMap,this.clearcoatRoughness=e.clearcoatRoughness,this.clearcoatRoughnessMap=e.clearcoatRoughnessMap,this.clearcoatNormalMap=e.clearcoatNormalMap,this.clearcoatNormalScale.copy(e.clearcoatNormalScale),this.dispersion=e.dispersion,this.ior=e.ior,this.iridescence=e.iridescence,this.iridescenceMap=e.iridescenceMap,this.iridescenceIOR=e.iridescenceIOR,this.iridescenceThicknessRange=[...e.iridescenceThicknessRange],this.iridescenceThicknessMap=e.iridescenceThicknessMap,this.retroreflectivity=e.retroreflectivity,this.sheen=e.sheen,this.sheenColor.copy(e.sheenColor),this.sheenColorMap=e.sheenColorMap,this.sheenRoughness=e.sheenRoughness,this.sheenRoughnessMap=e.sheenRoughnessMap,this.transmission=e.transmission,this.transmissionMap=e.transmissionMap,this.thickness=e.thickness,this.thicknessMap=e.thicknessMap,this.attenuationDistance=e.attenuationDistance,this.attenuationColor.copy(e.attenuationColor),this.specularIntensity=e.specularIntensity,this.specularIntensityMap=e.specularIntensityMap,this.specularColor.copy(e.specularColor),this.specularColorMap=e.specularColorMap,this}};var Va=class extends Fn{constructor(e){super(),this.isMeshDepthMaterial=!0,this.type="MeshDepthMaterial",this.depthPacking=iu,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.setValues(e)}copy(e){return super.copy(e),this.depthPacking=e.depthPacking,this.map=e.map,this.alphaMap=e.alphaMap,this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this.wireframe=e.wireframe,this.wireframeLinewidth=e.wireframeLinewidth,this}},Ha=class extends Fn{constructor(e){super(),this.isMeshDistanceMaterial=!0,this.type="MeshDistanceMaterial",this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.setValues(e)}copy(e){return super.copy(e),this.map=e.map,this.alphaMap=e.alphaMap,this.displacementMap=e.displacementMap,this.displacementScale=e.displacementScale,this.displacementBias=e.displacementBias,this}};function es(i,e){return!i||i.constructor===e?i:typeof e.BYTES_PER_ELEMENT=="number"?new e(i):Array.prototype.slice.call(i)}function Ll(i){return i!==void 0&&i.inTangents!==void 0&&i.outTangents!==void 0}var mi=class{constructor(e,t,n,s){this.parameterPositions=e,this._cachedIndex=0,this.resultBuffer=s!==void 0?s:new t.constructor(n),this.sampleValues=t,this.valueSize=n,this.settings=null,this.DefaultSettings_={}}evaluate(e){let t=this.parameterPositions,n=this._cachedIndex,s=t[n],r=t[n-1];n:{e:{let a;t:{i:if(!(e=r)){let o=t[1];e=r)break e}a=n,n=0;break t}break n}for(;n>>1;et;)--a;if(++a,r!==0||a!==s){r>=a&&(a=Math.max(a,1),r=a-1);let o=this.getValueSize();this.times=n.slice(r,a),this.values=this.values.slice(r*o,a*o)}return this}validate(){let e=!0,t=this.getValueSize();t-Math.floor(t)!==0&&(We("KeyframeTrack: Invalid value size in track.",this),e=!1);let n=this.times,s=this.values,r=n.length;r===0&&(We("KeyframeTrack: Track is empty.",this),e=!1);let a=null;for(let o=0;o!==r;o++){let l=n[o];if(typeof l=="number"&&isNaN(l)){We("KeyframeTrack: Time is not a valid number.",this,o,l),e=!1;break}if(a!==null&&a>l){We("KeyframeTrack: Out of order keys.",this,o,l,a),e=!1;break}a=l}if(s!==void 0&&Fd(s))for(let o=0,l=s.length;o!==l;++o){let c=s[o];if(isNaN(c)){We("KeyframeTrack: Value is not a valid number.",this,o,c),e=!1;break}}return e}optimize(){let e=this.times.slice(),t=this.values.slice(),n=this.getValueSize(),s=this.getInterpolation()===va,r=e.length-1,a=1;for(let o=1;o0){e[a]=e[r];for(let o=r*n,l=a*n,c=0;c!==n;++c)t[l+c]=t[o+c];++a}return a!==e.length?(this.times=e.slice(0,a),this.values=t.slice(0,a*n)):(this.times=e,this.values=t),this}clone(){let e=this.times.slice(),t=this.values.slice(),n=this.constructor,s=new n(this.name,e,t);return s.createInterpolant=this.createInterpolant,Ll(this.settings)&&(s.settings={inTangents:this.settings.inTangents.slice(),outTangents:this.settings.outTangents.slice()}),s}};function Ch(i,e){for(let t=0,n=i.length;t!==n;t+=2)i[t]*=e}on.prototype.ValueTypeName="";on.prototype.TimeBufferType=Float32Array;on.prototype.ValueBufferType=Float32Array;on.prototype.DefaultInterpolation=Pa;var gi=class extends on{constructor(e,t,n){super(e,t,n)}};gi.prototype.ValueTypeName="bool";gi.prototype.ValueBufferType=Array;gi.prototype.DefaultInterpolation=Js;gi.prototype.InterpolantFactoryMethodLinear=void 0;gi.prototype.InterpolantFactoryMethodSmooth=void 0;var Ya=class extends on{constructor(e,t,n,s){super(e,t,n,s)}};Ya.prototype.ValueTypeName="color";var Za=class extends on{constructor(e,t,n,s){super(e,t,n,s)}};Za.prototype.ValueTypeName="number";var Ja=class extends mi{constructor(e,t,n,s){super(e,t,n,s)}interpolate_(e,t,n,s){let r=this.resultBuffer,a=this.sampleValues,o=this.valueSize,l=(n-t)/(s-t),c=e*o;for(let h=c+o;c!==h;c+=4)qt.slerpFlat(r,0,a,c-o,a,c,l);return r}},yr=class extends on{constructor(e,t,n,s){super(e,t,n,s)}InterpolantFactoryMethodLinear(e){return new Ja(this.times,this.values,this.getValueSize(),e)}};yr.prototype.ValueTypeName="quaternion";yr.prototype.InterpolantFactoryMethodSmooth=void 0;var _i=class extends on{constructor(e,t,n){super(e,t,n)}};_i.prototype.ValueTypeName="string";_i.prototype.ValueBufferType=Array;_i.prototype.DefaultInterpolation=Js;_i.prototype.InterpolantFactoryMethodLinear=void 0;_i.prototype.InterpolantFactoryMethodSmooth=void 0;var $a=class extends on{constructor(e,t,n,s){super(e,t,n,s)}};$a.prototype.ValueTypeName="vector";var Ma={enabled:!1,files:{},add:function(i,e){this.enabled!==!1&&(Ph(i)||(this.files[i]=e))},get:function(i){if(this.enabled!==!1&&!Ph(i))return this.files[i]},remove:function(i){delete this.files[i]},clear:function(){this.files={}}};function Ph(i){try{let e=i.slice(i.indexOf(":")+1);return new URL(e).protocol==="blob:"}catch{return!1}}var Ka=class{constructor(e,t,n){let s=this,r=!1,a=0,o=0,l,c=[];this.onStart=void 0,this.onLoad=e,this.onProgress=t,this.onError=n,this._abortController=null,this.itemStart=function(h){o++,r===!1&&s.onStart!==void 0&&s.onStart(h,a,o),r=!0},this.itemEnd=function(h){a++,s.onProgress!==void 0&&s.onProgress(h,a,o),a===o&&(r=!1,s.onLoad!==void 0&&s.onLoad())},this.itemError=function(h){s.onError!==void 0&&s.onError(h)},this.resolveURL=function(h){return h=h.normalize("NFC"),l?l(h):h},this.setURLModifier=function(h){return l=h,this},this.addHandler=function(h,u){return c.push(h,u),this},this.removeHandler=function(h){let u=c.indexOf(h);return u!==-1&&c.splice(u,2),this},this.getHandler=function(h){for(let u=0,d=c.length;uf.start-m.start);let d=0;for(let f=1;f 0 + vec4 plane; + #ifdef ALPHA_TO_COVERAGE + float distanceToPlane, distanceGradient; + float clipOpacity = 1.0; + #pragma unroll_loop_start + for ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) { + plane = clippingPlanes[ i ]; + distanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w; + distanceGradient = fwidth( distanceToPlane ) / 2.0; + clipOpacity *= smoothstep( - distanceGradient, distanceGradient, distanceToPlane ); + if ( clipOpacity == 0.0 ) discard; + } + #pragma unroll_loop_end + #if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES + float unionClipOpacity = 1.0; + #pragma unroll_loop_start + for ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) { + plane = clippingPlanes[ i ]; + distanceToPlane = - dot( vClipPosition, plane.xyz ) + plane.w; + distanceGradient = fwidth( distanceToPlane ) / 2.0; + unionClipOpacity *= 1.0 - smoothstep( - distanceGradient, distanceGradient, distanceToPlane ); + } + #pragma unroll_loop_end + clipOpacity *= 1.0 - unionClipOpacity; + #endif + diffuseColor.a *= clipOpacity; + if ( diffuseColor.a == 0.0 ) discard; + #else + #pragma unroll_loop_start + for ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) { + plane = clippingPlanes[ i ]; + if ( dot( vClipPosition, plane.xyz ) > plane.w ) discard; + } + #pragma unroll_loop_end + #if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES + bool clipped = true; + #pragma unroll_loop_start + for ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) { + plane = clippingPlanes[ i ]; + clipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped; + } + #pragma unroll_loop_end + if ( clipped ) discard; + #endif + #endif +#endif`,wp=`#if NUM_CLIPPING_PLANES > 0 + varying vec3 vClipPosition; + uniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ]; +#endif`,Ap=`#if NUM_CLIPPING_PLANES > 0 + varying vec3 vClipPosition; +#endif`,Rp=`#if NUM_CLIPPING_PLANES > 0 + vClipPosition = - mvPosition.xyz; +#endif`,Cp=`#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) + diffuseColor *= vColor; +#endif`,Pp=`#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) + varying vec4 vColor; +#endif`,Ip=`#if defined( USE_COLOR ) || defined( USE_COLOR_ALPHA ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR ) + varying vec4 vColor; +#endif`,Lp=`#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 + vColor *= color; +#elif defined( USE_COLOR ) + vColor.rgb *= color; +#endif +#ifdef USE_INSTANCING_COLOR + vColor.rgb *= instanceColor.rgb; +#endif +#ifdef USE_BATCHING_COLOR + vColor *= getBatchingColor( getIndirectIndex( gl_DrawID ) ); +#endif`,Dp=`#define PI 3.141592653589793 +#define PI2 6.283185307179586 +#define PI_HALF 1.5707963267948966 +#define RECIPROCAL_PI 0.3183098861837907 +#define RECIPROCAL_PI2 0.15915494309189535 +#define EPSILON 1e-6 +#ifndef saturate +#define saturate( a ) clamp( a, 0.0, 1.0 ) +#endif +#define whiteComplement( a ) ( 1.0 - saturate( a ) ) +float pow2( const in float x ) { return x*x; } +vec3 pow2( const in vec3 x ) { return x*x; } +float pow3( const in float x ) { return x*x*x; } +float pow4( const in float x ) { float x2 = x*x; return x2*x2; } +float max3( const in vec3 v ) { return max( max( v.x, v.y ), v.z ); } +float average( const in vec3 v ) { return dot( v, vec3( 0.3333333 ) ); } +highp float rand( const in vec2 uv ) { + const highp float a = 12.9898, b = 78.233, c = 43758.5453; + highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI ); + return fract( sin( sn ) * c ); +} +#ifdef HIGH_PRECISION + float precisionSafeLength( vec3 v ) { return length( v ); } +#else + float precisionSafeLength( vec3 v ) { + float maxComponent = max3( abs( v ) ); + return length( v / maxComponent ) * maxComponent; + } +#endif +struct IncidentLight { + vec3 color; + vec3 direction; + bool visible; +}; +struct ReflectedLight { + vec3 directDiffuse; + vec3 directSpecular; + vec3 indirectDiffuse; + vec3 indirectSpecular; +}; +#ifdef USE_ALPHAHASH + varying vec3 vPosition; +#endif +vec3 transformDirection( in vec3 dir, in mat4 matrix ) { + return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); +} +#define inverseTransformDirection transformDirectionByInverseViewMatrix +vec3 transformNormalByInverseViewMatrix( in vec3 normal, in mat4 viewMatrix ) { + return normalize( ( vec4( normal, 0.0 ) * viewMatrix ).xyz ); +} +vec3 transformDirectionByInverseViewMatrix( in vec3 dir, in mat4 viewMatrix ) { + return normalize( ( vec4( dir, 0.0 ) * viewMatrix ).xyz ); +} +bool isPerspectiveMatrix( mat4 m ) { + return m[ 2 ][ 3 ] == - 1.0; +} +vec2 equirectUv( in vec3 dir ) { + float u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5; + float v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5; + return vec2( u, v ); +} +vec3 BRDF_Lambert( const in vec3 diffuseColor ) { + return RECIPROCAL_PI * diffuseColor; +} +vec3 F_Schlick( const in vec3 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 ); +} +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`,Np=`#ifdef ENVMAP_TYPE_CUBE_UV + #define cubeUV_minMipLevel 4.0 + #define cubeUV_minTileSize 16.0 + float getFace( vec3 direction ) { + vec3 absDirection = abs( direction ); + float face = - 1.0; + if ( absDirection.x > absDirection.z ) { + if ( absDirection.x > absDirection.y ) + face = direction.x > 0.0 ? 0.0 : 3.0; + else + face = direction.y > 0.0 ? 1.0 : 4.0; + } else { + if ( absDirection.z > absDirection.y ) + face = direction.z > 0.0 ? 2.0 : 5.0; + else + face = direction.y > 0.0 ? 1.0 : 4.0; + } + return face; + } + vec2 getUV( vec3 direction, float face ) { + vec2 uv; + if ( face == 0.0 ) { + uv = vec2( direction.z, direction.y ) / abs( direction.x ); + } else if ( face == 1.0 ) { + uv = vec2( - direction.x, - direction.z ) / abs( direction.y ); + } else if ( face == 2.0 ) { + uv = vec2( - direction.x, direction.y ) / abs( direction.z ); + } else if ( face == 3.0 ) { + uv = vec2( - direction.z, direction.y ) / abs( direction.x ); + } else if ( face == 4.0 ) { + uv = vec2( - direction.x, direction.z ) / abs( direction.y ); + } else { + uv = vec2( direction.x, direction.y ) / abs( direction.z ); + } + return 0.5 * ( uv + 1.0 ); + } + vec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) { + float face = getFace( direction ); + float filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 ); + mipInt = max( mipInt, cubeUV_minMipLevel ); + float faceSize = exp2( mipInt ); + highp vec2 uv = getUV( direction, face ) * ( faceSize - 2.0 ) + 1.0; + if ( face > 2.0 ) { + uv.y += faceSize; + face -= 3.0; + } + uv.x += face * faceSize; + uv.x += filterInt * 3.0 * cubeUV_minTileSize; + uv.y += 4.0 * ( exp2( CUBEUV_MAX_MIP ) - faceSize ); + uv.x *= CUBEUV_TEXEL_WIDTH; + uv.y *= CUBEUV_TEXEL_HEIGHT; + #ifdef texture2DGradEXT + return texture2DGradEXT( envMap, uv, vec2( 0.0 ), vec2( 0.0 ) ).rgb; + #else + return texture2D( envMap, uv ).rgb; + #endif + } + #define cubeUV_r0 1.0 + #define cubeUV_m0 - 2.0 + #define cubeUV_r1 0.8 + #define cubeUV_m1 - 1.0 + #define cubeUV_r4 0.4 + #define cubeUV_m4 2.0 + #define cubeUV_r5 0.305 + #define cubeUV_m5 3.0 + #define cubeUV_r6 0.21 + #define cubeUV_m6 4.0 + float roughnessToMip( float roughness ) { + float mip = 0.0; + if ( roughness >= cubeUV_r1 ) { + mip = ( cubeUV_r0 - roughness ) * ( cubeUV_m1 - cubeUV_m0 ) / ( cubeUV_r0 - cubeUV_r1 ) + cubeUV_m0; + } else if ( roughness >= cubeUV_r4 ) { + mip = ( cubeUV_r1 - roughness ) * ( cubeUV_m4 - cubeUV_m1 ) / ( cubeUV_r1 - cubeUV_r4 ) + cubeUV_m1; + } else if ( roughness >= cubeUV_r5 ) { + mip = ( cubeUV_r4 - roughness ) * ( cubeUV_m5 - cubeUV_m4 ) / ( cubeUV_r4 - cubeUV_r5 ) + cubeUV_m4; + } else if ( roughness >= cubeUV_r6 ) { + mip = ( cubeUV_r5 - roughness ) * ( cubeUV_m6 - cubeUV_m5 ) / ( cubeUV_r5 - cubeUV_r6 ) + cubeUV_m5; + } else { + mip = - 2.0 * log2( 1.16 * roughness ); } + return mip; + } + vec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) { + float mip = clamp( roughnessToMip( roughness ), cubeUV_m0, CUBEUV_MAX_MIP ); + float mipF = fract( mip ); + float mipInt = floor( mip ); + vec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt ); + if ( mipF == 0.0 ) { + return vec4( color0, 1.0 ); + } else { + vec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 ); + return vec4( mix( color0, color1, mipF ), 1.0 ); + } + } +#endif`,Up=`vec3 transformedNormal = objectNormal; +#ifdef USE_TANGENT + vec3 transformedTangent = objectTangent; +#endif +#ifdef USE_BATCHING + mat3 bm = mat3( batchingMatrix ); + transformedNormal /= vec3( dot( bm[ 0 ], bm[ 0 ] ), dot( bm[ 1 ], bm[ 1 ] ), dot( bm[ 2 ], bm[ 2 ] ) ); + transformedNormal = bm * transformedNormal; + #ifdef USE_TANGENT + transformedTangent = bm * transformedTangent; + #endif +#endif +#ifdef USE_INSTANCING + mat3 im = mat3( instanceMatrix ); + transformedNormal /= vec3( dot( im[ 0 ], im[ 0 ] ), dot( im[ 1 ], im[ 1 ] ), dot( im[ 2 ], im[ 2 ] ) ); + transformedNormal = im * transformedNormal; + #ifdef USE_TANGENT + transformedTangent = im * transformedTangent; + #endif +#endif +transformedNormal = normalMatrix * transformedNormal; +#ifdef FLIP_SIDED + transformedNormal = - transformedNormal; +#endif +#ifdef USE_TANGENT + transformedTangent = ( modelViewMatrix * vec4( transformedTangent, 0.0 ) ).xyz; +#endif`,Fp=`#ifdef USE_DISPLACEMENTMAP + uniform sampler2D displacementMap; + uniform float displacementScale; + uniform float displacementBias; +#endif`,Op=`#ifdef USE_DISPLACEMENTMAP + transformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias ); +#endif`,Bp=`#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 + uniform sampler2D emissiveMap; +#endif`,kp="gl_FragColor = linearToOutputTexel( gl_FragColor );",Vp=`vec4 LinearTransferOETF( in vec4 value ) { + return value; +} +vec4 sRGBTransferEOTF( in vec4 value ) { + return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a ); +} +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 ); +}`,Hp=`#ifdef USE_ENVMAP + #ifdef ENV_WORLDPOS + vec3 cameraToFrag; + if ( isOrthographic ) { + cameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) ); + } else { + cameraToFrag = normalize( vWorldPosition - cameraPosition ); + } + vec3 worldNormal = transformNormalByInverseViewMatrix( normal, viewMatrix ); + #ifdef ENVMAP_MODE_REFLECTION + vec3 reflectVec = reflect( cameraToFrag, worldNormal ); + #else + vec3 reflectVec = refract( cameraToFrag, worldNormal, refractionRatio ); + #endif + #else + vec3 reflectVec = vReflect; + #endif + #ifdef ENVMAP_TYPE_CUBE + vec4 envColor = textureCube( envMap, envMapRotation * reflectVec ); + #ifdef ENVMAP_BLENDING_MULTIPLY + outgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity ); + #elif defined( ENVMAP_BLENDING_MIX ) + outgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity ); + #elif defined( ENVMAP_BLENDING_ADD ) + outgoingLight += envColor.xyz * specularStrength * reflectivity; + #endif + #endif +#endif`,Gp=`#ifdef USE_ENVMAP + uniform float envMapIntensity; + uniform mat3 envMapRotation; + #ifdef ENVMAP_TYPE_CUBE + uniform samplerCube envMap; + #else + uniform sampler2D envMap; + #endif +#endif`,Wp=`#ifdef USE_ENVMAP + uniform float reflectivity; + #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) + #define ENV_WORLDPOS + #endif + #ifdef ENV_WORLDPOS + varying vec3 vWorldPosition; + uniform float refractionRatio; + #else + varying vec3 vReflect; + #endif +#endif`,Xp=`#ifdef USE_ENVMAP + #if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( LAMBERT ) + #define ENV_WORLDPOS + #endif + #ifdef ENV_WORLDPOS + + varying vec3 vWorldPosition; + #else + varying vec3 vReflect; + uniform float refractionRatio; + #endif +#endif`,qp=`#ifdef USE_ENVMAP + #ifdef ENV_WORLDPOS + vWorldPosition = worldPosition.xyz; + #else + vec3 cameraToVertex; + if ( isOrthographic ) { + cameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) ); + } else { + cameraToVertex = normalize( worldPosition.xyz - cameraPosition ); + } + vec3 worldNormal = transformNormalByInverseViewMatrix( transformedNormal, viewMatrix ); + #ifdef ENVMAP_MODE_REFLECTION + vReflect = reflect( cameraToVertex, worldNormal ); + #else + vReflect = refract( cameraToVertex, worldNormal, refractionRatio ); + #endif + #endif +#endif`,Yp=`#ifdef USE_FOG + vFogDepth = - mvPosition.z; +#endif`,Zp=`#ifdef USE_FOG + varying float vFogDepth; +#endif`,Jp=`#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`,$p=`#ifdef USE_FOG + uniform vec3 fogColor; + varying float vFogDepth; + #ifdef FOG_EXP2 + uniform float fogDensity; + #else + uniform float fogNear; + uniform float fogFar; + #endif +#endif`,Kp=`#ifdef USE_GRADIENTMAP + uniform sampler2D gradientMap; +#endif +vec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) { + float dotNL = dot( normal, lightDirection ); + vec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 ); + #ifdef USE_GRADIENTMAP + return vec3( texture2D( gradientMap, coord ).r ); + #else + 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 +}`,Qp=`#ifdef USE_LIGHTMAP + uniform sampler2D lightMap; + uniform float lightMapIntensity; +#endif`,jp=`LambertMaterial material; +material.diffuseColor = diffuseColor.rgb; +material.specularStrength = specularStrength;`,em=`varying vec3 vViewPosition; +struct LambertMaterial { + vec3 diffuseColor; + float specularStrength; +}; +void RE_Direct_Lambert( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); + vec3 irradiance = dotNL * directLight.color; + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectDiffuse_Lambert( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in LambertMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +#define RE_Direct RE_Direct_Lambert +#define RE_IndirectDiffuse RE_IndirectDiffuse_Lambert`,tm=`uniform bool receiveShadow; +uniform vec3 ambientLightColor; +#if defined( USE_LIGHT_PROBES ) + uniform vec3 lightProbe[ 9 ]; +#endif +vec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) { + float x = normal.x, y = normal.y, z = normal.z; + vec3 result = shCoefficients[ 0 ] * 0.886227; + result += shCoefficients[ 1 ] * 2.0 * 0.511664 * y; + result += shCoefficients[ 2 ] * 2.0 * 0.511664 * z; + result += shCoefficients[ 3 ] * 2.0 * 0.511664 * x; + result += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y; + result += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z; + result += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 ); + result += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z; + result += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y ); + return result; +} +vec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in vec3 normal ) { + vec3 worldNormal = transformNormalByInverseViewMatrix( normal, viewMatrix ); + vec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe ); + return irradiance; +} +vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) { + vec3 irradiance = ambientLightColor; + return irradiance; +} +float getDistanceAttenuation( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) { + float distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 ); + if ( cutoffDistance > 0.0 ) { + distanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) ); + } + return distanceFalloff; +} +float getSpotAttenuation( const in float coneCosine, const in float penumbraCosine, const in float angleCosine ) { + return smoothstep( coneCosine, penumbraCosine, angleCosine ); +} +#if NUM_SUN_LIGHTS > 0 + struct SunLight { + vec3 direction; + vec3 color; + }; + uniform SunLight sunLights[ NUM_SUN_LIGHTS ]; + void getSunLightInfo( const in SunLight sunLight, out IncidentLight light ) { + light.color = sunLight.color; + light.direction = sunLight.direction; + light.visible = true; + } +#endif +#if NUM_DIR_LIGHTS > 0 + struct DirectionalLight { + vec3 direction; + vec3 color; + }; + uniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ]; + void getDirectionalLightInfo( const in DirectionalLight directionalLight, out IncidentLight light ) { + light.color = directionalLight.color; + light.direction = directionalLight.direction; + light.visible = true; + } +#endif +#if NUM_POINT_LIGHTS > 0 + struct PointLight { + vec3 position; + vec3 color; + float distance; + float decay; + }; + uniform PointLight pointLights[ NUM_POINT_LIGHTS ]; + void getPointLightInfo( const in PointLight pointLight, const in vec3 geometryPosition, out IncidentLight light ) { + vec3 lVector = pointLight.position - geometryPosition; + light.direction = normalize( lVector ); + float lightDistance = length( lVector ); + light.color = pointLight.color; + light.color *= getDistanceAttenuation( lightDistance, pointLight.distance, pointLight.decay ); + light.visible = ( light.color != vec3( 0.0 ) ); + } +#endif +#if NUM_SPOT_LIGHTS > 0 + struct SpotLight { + vec3 position; + vec3 direction; + vec3 color; + float distance; + float decay; + float coneCos; + float penumbraCos; + }; + uniform SpotLight spotLights[ NUM_SPOT_LIGHTS ]; + void getSpotLightInfo( const in SpotLight spotLight, const in vec3 geometryPosition, out IncidentLight light ) { + vec3 lVector = spotLight.position - geometryPosition; + light.direction = normalize( lVector ); + float angleCos = dot( light.direction, spotLight.direction ); + float spotAttenuation = getSpotAttenuation( spotLight.coneCos, spotLight.penumbraCos, angleCos ); + if ( spotAttenuation > 0.0 ) { + float lightDistance = length( lVector ); + light.color = spotLight.color * spotAttenuation; + light.color *= getDistanceAttenuation( lightDistance, spotLight.distance, spotLight.decay ); + light.visible = ( light.color != vec3( 0.0 ) ); + } else { + light.color = vec3( 0.0 ); + light.visible = false; + } + } +#endif +#if NUM_RECT_AREA_LIGHTS > 0 + struct RectAreaLight { + vec3 color; + vec3 position; + vec3 halfWidth; + vec3 halfHeight; + }; + uniform sampler2D ltc_1; uniform sampler2D ltc_2; + uniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ]; +#endif +#if NUM_HEMI_LIGHTS > 0 + struct HemisphereLight { + vec3 direction; + vec3 skyColor; + vec3 groundColor; + }; + uniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ]; + vec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in vec3 normal ) { + float dotNL = dot( normal, hemiLight.direction ); + float hemiDiffuseWeight = 0.5 * dotNL + 0.5; + vec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight ); + return irradiance; + } +#endif +#include `,nm=`#ifdef USE_ENVMAP + vec3 getIBLIrradiance( const in vec3 normal ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 worldNormal = transformNormalByInverseViewMatrix( normal, viewMatrix ); + vec4 envMapColor = textureCubeUV( envMap, envMapRotation * worldNormal, 1.0 ); + return PI * envMapColor.rgb * envMapIntensity; + #else + return vec3( 0.0 ); + #endif + } + vec3 getIBLRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 reflectVec = reflect( - viewDir, normal ); + reflectVec = normalize( mix( reflectVec, normal, pow4( roughness ) ) ); + reflectVec = transformDirectionByInverseViewMatrix( reflectVec, viewMatrix ); + vec4 envMapColor = textureCubeUV( envMap, envMapRotation * reflectVec, roughness ); + return envMapColor.rgb * envMapIntensity; + #else + return vec3( 0.0 ); + #endif + } + #ifdef USE_RETROREFLECTION + vec3 getIBLRetroRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 retroVec = normalize( mix( viewDir, normal, pow4( roughness ) ) ); + retroVec = transformDirectionByInverseViewMatrix( retroVec, viewMatrix ); + vec4 envMapColor = textureCubeUV( envMap, envMapRotation * retroVec, roughness ); + return envMapColor.rgb * envMapIntensity; + #else + return vec3( 0.0 ); + #endif + } + #endif + #ifdef USE_ANISOTROPY + vec3 getIBLAnisotropyRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 bentNormal = cross( bitangent, viewDir ); + bentNormal = normalize( cross( bentNormal, bitangent ) ); + bentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) ); + return getIBLRadiance( viewDir, bentNormal, roughness ); + #else + return vec3( 0.0 ); + #endif + } + #ifdef USE_RETROREFLECTION + vec3 getIBLAnisotropyRetroRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in vec3 bitangent, const in float anisotropy ) { + #ifdef ENVMAP_TYPE_CUBE_UV + vec3 bentNormal = cross( bitangent, viewDir ); + bentNormal = normalize( cross( bentNormal, bitangent ) ); + bentNormal = normalize( mix( bentNormal, normal, pow2( pow2( 1.0 - anisotropy * ( 1.0 - roughness ) ) ) ) ); + return getIBLRetroRadiance( viewDir, bentNormal, roughness ); + #else + return vec3( 0.0 ); + #endif + } + #endif + #endif +#endif`,im=`ToonMaterial material; +material.diffuseColor = diffuseColor.rgb;`,sm=`varying vec3 vViewPosition; +struct ToonMaterial { + vec3 diffuseColor; +}; +void RE_Direct_Toon( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) { + vec3 irradiance = getGradientIrradiance( geometryNormal, directLight.direction ) * directLight.color; + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +void RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in ToonMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +#define RE_Direct RE_Direct_Toon +#define RE_IndirectDiffuse RE_IndirectDiffuse_Toon`,rm=`BlinnPhongMaterial material; +material.diffuseColor = diffuseColor.rgb; +material.specularColor = specular; +material.specularShininess = shininess; +material.specularStrength = specularStrength;`,am=`varying vec3 vViewPosition; +struct BlinnPhongMaterial { + vec3 diffuseColor; + vec3 specularColor; + float specularShininess; + float specularStrength; +}; +void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); + vec3 irradiance = dotNL * directLight.color; + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); + reflectedLight.directSpecular += irradiance * BRDF_BlinnPhong( directLight.direction, geometryViewDir, geometryNormal, material.specularColor, material.specularShininess ) * material.specularStrength; +} +void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { + reflectedLight.indirectDiffuse += irradiance * BRDF_Lambert( material.diffuseColor ); +} +#define RE_Direct RE_Direct_BlinnPhong +#define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong`,om=`PhysicalMaterial material; +material.diffuseColor = diffuseColor.rgb; +material.diffuseContribution = diffuseColor.rgb * ( 1.0 - metalnessFactor ); +material.metalness = metalnessFactor; +vec3 dxy = max( abs( dFdx( nonPerturbedNormal ) ), abs( dFdy( nonPerturbedNormal ) ) ); +float geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z ); +material.roughness = max( roughnessFactor, 0.0525 );material.roughness += geometryRoughness; +material.roughness = min( material.roughness, 1.0 ); +#ifdef IOR + material.ior = ior; + #ifdef USE_SPECULAR + float specularIntensityFactor = specularIntensity; + vec3 specularColorFactor = specularColor; + #ifdef USE_SPECULAR_COLORMAP + specularColorFactor *= texture2D( specularColorMap, vSpecularColorMapUv ).rgb; + #endif + #ifdef USE_SPECULAR_INTENSITYMAP + specularIntensityFactor *= texture2D( specularIntensityMap, vSpecularIntensityMapUv ).a; + #endif + material.specularF90 = mix( specularIntensityFactor, 1.0, metalnessFactor ); + #else + float specularIntensityFactor = 1.0; + vec3 specularColorFactor = vec3( 1.0 ); + material.specularF90 = 1.0; + #endif + material.specularColor = min( pow2( ( material.ior - 1.0 ) / ( material.ior + 1.0 ) ) * specularColorFactor, vec3( 1.0 ) ) * specularIntensityFactor; + material.specularColorBlended = mix( material.specularColor, diffuseColor.rgb, metalnessFactor ); +#else + material.specularColor = vec3( 0.04 ); + material.specularColorBlended = mix( material.specularColor, diffuseColor.rgb, metalnessFactor ); + material.specularF90 = 1.0; +#endif +#ifdef USE_CLEARCOAT + material.clearcoat = clearcoat; + material.clearcoatRoughness = clearcoatRoughness; + material.clearcoatF0 = vec3( 0.04 ); + material.clearcoatF90 = 1.0; + #ifdef USE_CLEARCOATMAP + material.clearcoat *= texture2D( clearcoatMap, vClearcoatMapUv ).x; + #endif + #ifdef USE_CLEARCOAT_ROUGHNESSMAP + material.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vClearcoatRoughnessMapUv ).y; + #endif + material.clearcoat = saturate( material.clearcoat ); material.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 ); + material.clearcoatRoughness += geometryRoughness; + material.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 ); +#endif +#ifdef USE_DISPERSION + material.dispersion = dispersion; +#endif +#ifdef USE_RETROREFLECTION + material.retroreflectivity = retroreflectivity; +#endif +#ifdef USE_IRIDESCENCE + material.iridescence = iridescence; + material.iridescenceIOR = iridescenceIOR; + #ifdef USE_IRIDESCENCEMAP + material.iridescence *= texture2D( iridescenceMap, vIridescenceMapUv ).r; + #endif + #ifdef USE_IRIDESCENCE_THICKNESSMAP + material.iridescenceThickness = (iridescenceThicknessMaximum - iridescenceThicknessMinimum) * texture2D( iridescenceThicknessMap, vIridescenceThicknessMapUv ).g + iridescenceThicknessMinimum; + #else + material.iridescenceThickness = iridescenceThicknessMaximum; + #endif +#endif +#ifdef USE_SHEEN + material.sheenColor = sheenColor; + #ifdef USE_SHEEN_COLORMAP + material.sheenColor *= texture2D( sheenColorMap, vSheenColorMapUv ).rgb; + #endif + material.sheenRoughness = clamp( sheenRoughness, 0.0001, 1.0 ); + #ifdef USE_SHEEN_ROUGHNESSMAP + material.sheenRoughness *= texture2D( sheenRoughnessMap, vSheenRoughnessMapUv ).a; + #endif +#endif +#ifdef USE_ANISOTROPY + #ifdef USE_ANISOTROPYMAP + mat2 anisotropyMat = mat2( anisotropyVector.x, anisotropyVector.y, - anisotropyVector.y, anisotropyVector.x ); + vec3 anisotropyPolar = texture2D( anisotropyMap, vAnisotropyMapUv ).rgb; + vec2 anisotropyV = anisotropyMat * normalize( 2.0 * anisotropyPolar.rg - vec2( 1.0 ) ) * anisotropyPolar.b; + #else + vec2 anisotropyV = anisotropyVector; + #endif + material.anisotropy = length( anisotropyV ); + if( material.anisotropy == 0.0 ) { + anisotropyV = vec2( 1.0, 0.0 ); + } else { + anisotropyV /= material.anisotropy; + material.anisotropy = saturate( material.anisotropy ); + } + 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`,lm=`uniform sampler2D dfgLUT; +struct PhysicalMaterial { + vec3 diffuseColor; + vec3 diffuseContribution; + vec3 specularColor; + vec3 specularColorBlended; + float roughness; + float metalness; + float specularF90; + float dispersion; + vec2 dfg; + vec3 multiScatteringCompensation; + #ifdef USE_RETROREFLECTION + float retroreflectivity; + #endif + #ifdef USE_CLEARCOAT + float clearcoat; + float clearcoatRoughness; + vec3 clearcoatF0; + float clearcoatF90; + #endif + #ifdef USE_IRIDESCENCE + float iridescence; + float iridescenceIOR; + float iridescenceThickness; + vec3 iridescenceFresnel; + vec3 iridescenceF0Dielectric; + vec3 iridescenceF0Metallic; + #endif + #ifdef USE_SHEEN + vec3 sheenColor; + float sheenRoughness; + #endif + #ifdef IOR + float ior; + #endif + #ifdef USE_TRANSMISSION + float transmission; + float transmissionAlpha; + float thickness; + float attenuationDistance; + vec3 attenuationColor; + #endif + #ifdef USE_ANISOTROPY + float anisotropy; + float alphaT; + vec3 anisotropyT; + vec3 anisotropyB; + #endif +}; +vec3 clearcoatSpecularDirect = vec3( 0.0 ); +vec3 clearcoatSpecularIndirect = vec3( 0.0 ); +vec3 sheenSpecularDirect = vec3( 0.0 ); +vec3 sheenSpecularIndirect = vec3(0.0 ); +vec3 Schlick_to_F0( const in vec3 f, const in float f90, const in float dotVH ) { + float x = clamp( 1.0 - dotVH, 0.0, 1.0 ); + float x2 = x * x; + float x5 = clamp( x * x2 * x2, 0.0, 0.9999 ); + return ( f - vec3( f90 ) * x5 ) / ( 1.0 - x5 ); +} +float V_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) { + float a2 = pow2( alpha ); + float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) ); + float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) ); + return 0.5 / max( gv + gl, EPSILON ); +} +float D_GGX( const in float alpha, const in float dotNH ) { + float a2 = pow2( alpha ); + float denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0; + return RECIPROCAL_PI * a2 / pow2( denom ); +} +#ifdef USE_ANISOTROPY + float V_GGX_SmithCorrelated_Anisotropic( const in float alphaT, const in float alphaB, const in float dotTV, const in float dotBV, const in float dotTL, const in float dotBL, const in float dotNV, const in float dotNL ) { + float gv = dotNL * length( vec3( alphaT * dotTV, alphaB * dotBV, dotNV ) ); + float gl = dotNV * length( vec3( alphaT * dotTL, alphaB * dotBL, dotNL ) ); + return 0.5 / max( gv + gl, EPSILON ); + } + float D_GGX_Anisotropic( const in float alphaT, const in float alphaB, const in float dotNH, const in float dotTH, const in float dotBH ) { + float a2 = alphaT * alphaB; + highp vec3 v = vec3( alphaB * dotTH, alphaT * dotBH, a2 * dotNH ); + highp float v2 = dot( v, v ); + float w2 = a2 / v2; + return RECIPROCAL_PI * a2 * pow2 ( w2 ); + } +#endif +#ifdef USE_CLEARCOAT + vec3 BRDF_GGX_Clearcoat( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material) { + vec3 f0 = material.clearcoatF0; + float f90 = material.clearcoatF90; + float roughness = material.clearcoatRoughness; + float alpha = pow2( roughness ); + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float dotVH = saturate( dot( viewDir, halfDir ) ); + vec3 F = F_Schlick( f0, f90, dotVH ); + float V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV ); + float D = D_GGX( alpha, dotNH ); + return F * ( V * D ); + } +#endif +vec3 BRDF_GGX( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, const in PhysicalMaterial material ) { + vec3 f0 = material.specularColorBlended; + float f90 = material.specularF90; + float roughness = material.roughness; + float alpha = pow2( roughness ); + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float dotVH = saturate( dot( viewDir, halfDir ) ); + vec3 F = F_Schlick( f0, f90, dotVH ); + #ifdef USE_IRIDESCENCE + F = mix( F, material.iridescenceFresnel, material.iridescence ); + #endif + #ifdef USE_ANISOTROPY + float dotTL = dot( material.anisotropyT, lightDir ); + float dotTV = dot( material.anisotropyT, viewDir ); + float dotTH = dot( material.anisotropyT, halfDir ); + float dotBL = dot( material.anisotropyB, lightDir ); + float dotBV = dot( material.anisotropyB, viewDir ); + float dotBH = dot( material.anisotropyB, halfDir ); + float V = V_GGX_SmithCorrelated_Anisotropic( material.alphaT, alpha, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL ); + float D = D_GGX_Anisotropic( material.alphaT, alpha, dotNH, dotTH, dotBH ); + #else + float V = V_GGX_SmithCorrelated( alpha, dotNL, dotNV ); + float D = D_GGX( alpha, dotNH ); + #endif + return F * ( V * D ); +} +vec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) { + const float LUT_SIZE = 64.0; + const float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE; + const float LUT_BIAS = 0.5 / LUT_SIZE; + float dotNV = saturate( dot( N, V ) ); + vec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) ); + uv = uv * LUT_SCALE + LUT_BIAS; + return uv; +} +float LTC_ClippedSphereFormFactor( const in vec3 f ) { + float l = length( f ); + return max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 ); +} +vec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) { + float x = dot( v1, v2 ); + float y = abs( x ); + float a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y; + float b = 3.4175940 + ( 4.1616724 + y ) * y; + float v = a / b; + float theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v; + return cross( v1, v2 ) * theta_sintheta; +} +vec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) { + vec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ]; + vec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ]; + vec3 lightNormal = cross( v1, v2 ); + if( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 ); + vec3 T1, T2; + T1 = normalize( V - N * dot( V, N ) ); + T2 = - cross( N, T1 ); + mat3 mat = mInv * transpose( mat3( T1, T2, N ) ); + vec3 coords[ 4 ]; + coords[ 0 ] = mat * ( rectCoords[ 0 ] - P ); + coords[ 1 ] = mat * ( rectCoords[ 1 ] - P ); + coords[ 2 ] = mat * ( rectCoords[ 2 ] - P ); + coords[ 3 ] = mat * ( rectCoords[ 3 ] - P ); + coords[ 0 ] = normalize( coords[ 0 ] ); + coords[ 1 ] = normalize( coords[ 1 ] ); + coords[ 2 ] = normalize( coords[ 2 ] ); + coords[ 3 ] = normalize( coords[ 3 ] ); + vec3 vectorFormFactor = vec3( 0.0 ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] ); + vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] ); + float result = LTC_ClippedSphereFormFactor( vectorFormFactor ); + return vec3( result ); +} +#if defined( USE_SHEEN ) +float D_Charlie( float roughness, float dotNH ) { + float alpha = pow2( roughness ); + float invAlpha = 1.0 / alpha; + float cos2h = dotNH * dotNH; + float sin2h = max( 1.0 - cos2h, 0.0078125 ); + return ( 2.0 + invAlpha ) * pow( sin2h, invAlpha * 0.5 ) / ( 2.0 * PI ); +} +float V_Neubelt( float dotNV, float dotNL ) { + return saturate( 1.0 / ( 4.0 * ( dotNL + dotNV - dotNL * dotNV ) ) ); +} +vec3 BRDF_Sheen( const in vec3 lightDir, const in vec3 viewDir, const in vec3 normal, vec3 sheenColor, const in float sheenRoughness ) { + vec3 halfDir = normalize( lightDir + viewDir ); + float dotNL = saturate( dot( normal, lightDir ) ); + float dotNV = saturate( dot( normal, viewDir ) ); + float dotNH = saturate( dot( normal, halfDir ) ); + float D = D_Charlie( sheenRoughness, dotNH ); + float V = V_Neubelt( dotNV, dotNL ); + return sheenColor * ( D * V ); +} +#endif +float IBLSheenBRDF( const in vec3 normal, const in vec3 viewDir, const in float roughness ) { + float dotNV = saturate( dot( normal, viewDir ) ); + float r2 = roughness * roughness; + float rInv = 1.0 / ( roughness + 0.1 ); + float a = -1.9362 + 1.0678 * roughness + 0.4573 * r2 - 0.8469 * rInv; + float b = -0.6014 + 0.5538 * roughness - 0.4670 * r2 - 0.1255 * rInv; + float DG = exp( a * dotNV + b ); + return saturate( DG ); +} +vec3 EnvironmentBRDF( const in vec3 normal, const in vec3 viewDir, const in vec3 specularColor, const in float specularF90, const in float roughness ) { + float dotNV = saturate( dot( normal, viewDir ) ); + vec2 fab = texture2D( dfgLUT, vec2( roughness, dotNV ) ).rg; + return specularColor * fab.x + specularF90 * fab.y; +} +#ifdef USE_IRIDESCENCE +void computeMultiscatteringIridescence( const in vec2 fab, const in vec3 specularColor, const in float specularF90, const in float iridescence, const in vec3 iridescenceF0, inout vec3 singleScatter, inout vec3 multiScatter ) { +#else +void computeMultiscattering( const in vec2 fab, const in vec3 specularColor, const in float specularF90, inout vec3 singleScatter, inout vec3 multiScatter ) { +#endif + #ifdef USE_IRIDESCENCE + vec3 Fr = mix( specularColor, iridescenceF0, iridescence ); + #else + vec3 Fr = specularColor; + #endif + vec3 FssEss = Fr * fab.x + specularF90 * fab.y; + float Ess = fab.x + fab.y; + float Ems = 1.0 - Ess; + vec3 Favg = Fr + ( 1.0 - Fr ) * 0.047619; vec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg ); + singleScatter += FssEss; + multiScatter += Fms * Ems; +} +#if NUM_RECT_AREA_LIGHTS > 0 + void RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { + vec3 normal = geometryNormal; + vec3 viewDir = geometryViewDir; + vec3 position = geometryPosition; + vec3 lightPos = rectAreaLight.position; + vec3 halfWidth = rectAreaLight.halfWidth; + vec3 halfHeight = rectAreaLight.halfHeight; + vec3 lightColor = rectAreaLight.color; + float roughness = material.roughness; + vec3 rectCoords[ 4 ]; + rectCoords[ 0 ] = lightPos + halfWidth - halfHeight; rectCoords[ 1 ] = lightPos - halfWidth - halfHeight; + rectCoords[ 2 ] = lightPos - halfWidth + halfHeight; + rectCoords[ 3 ] = lightPos + halfWidth + halfHeight; + vec2 uv = LTC_Uv( normal, viewDir, roughness ); + vec4 t1 = texture2D( ltc_1, uv ); + vec4 t2 = texture2D( ltc_2, uv ); + mat3 mInv = mat3( + vec3( t1.x, 0, t1.y ), + vec3( 0, 1, 0 ), + vec3( t1.z, 0, t1.w ) + ); + vec3 fresnel = ( material.specularColorBlended * t2.x + ( material.specularF90 - material.specularColorBlended ) * t2.y ); + reflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords ); + reflectedLight.directDiffuse += lightColor * material.diffuseContribution * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords ); + #ifdef USE_CLEARCOAT + vec3 Ncc = geometryClearcoatNormal; + vec2 uvClearcoat = LTC_Uv( Ncc, viewDir, material.clearcoatRoughness ); + vec4 t1Clearcoat = texture2D( ltc_1, uvClearcoat ); + vec4 t2Clearcoat = texture2D( ltc_2, uvClearcoat ); + mat3 mInvClearcoat = mat3( + vec3( t1Clearcoat.x, 0, t1Clearcoat.y ), + vec3( 0, 1, 0 ), + vec3( t1Clearcoat.z, 0, t1Clearcoat.w ) + ); + vec3 fresnelClearcoat = material.clearcoatF0 * t2Clearcoat.x + ( material.clearcoatF90 - material.clearcoatF0 ) * t2Clearcoat.y; + clearcoatSpecularDirect += lightColor * fresnelClearcoat * LTC_Evaluate( Ncc, viewDir, position, mInvClearcoat, rectCoords ); + #endif + } +#endif +void RE_Direct_Physical( const in IncidentLight directLight, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { + float dotNL = saturate( dot( geometryNormal, directLight.direction ) ); + vec3 irradiance = dotNL * directLight.color; + #ifdef USE_CLEARCOAT + float dotNLcc = saturate( dot( geometryClearcoatNormal, directLight.direction ) ); + vec3 ccIrradiance = dotNLcc * directLight.color; + clearcoatSpecularDirect += ccIrradiance * BRDF_GGX_Clearcoat( directLight.direction, geometryViewDir, geometryClearcoatNormal, material ); + #endif + #ifdef USE_SHEEN + + sheenSpecularDirect += irradiance * BRDF_Sheen( directLight.direction, geometryViewDir, geometryNormal, material.sheenColor, material.sheenRoughness ); + + float sheenAlbedoV = IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness ); + float sheenAlbedoL = IBLSheenBRDF( geometryNormal, directLight.direction, material.sheenRoughness ); + + float sheenEnergyComp = 1.0 - max3( material.sheenColor ) * max( sheenAlbedoV, sheenAlbedoL ); + + irradiance *= sheenEnergyComp; + + #endif + vec3 specularBRDF = BRDF_GGX( directLight.direction, geometryViewDir, geometryNormal, material ); + #ifdef USE_RETROREFLECTION + vec3 retroViewDir = reflect( - geometryViewDir, geometryNormal ); + vec3 retroSpecularBRDF = BRDF_GGX( directLight.direction, retroViewDir, geometryNormal, material ); + specularBRDF = mix( specularBRDF, retroSpecularBRDF, saturate( material.retroreflectivity ) ); + #endif + reflectedLight.directSpecular += irradiance * specularBRDF * material.multiScatteringCompensation; + vec3 halfDir = normalize( directLight.direction + geometryViewDir ); + float dotVH = saturate( dot( geometryViewDir, halfDir ) ); + vec3 F = F_Schlick( material.specularColor, material.specularF90, dotVH ); + #ifdef USE_RETROREFLECTION + vec3 retroHalfDir = normalize( directLight.direction + retroViewDir ); + float dotRetroVH = saturate( dot( retroViewDir, retroHalfDir ) ); + vec3 retroF = F_Schlick( material.specularColor, material.specularF90, dotRetroVH ); + F = mix( F, retroF, saturate( material.retroreflectivity ) ); + #endif + reflectedLight.directDiffuse += irradiance * BRDF_Lambert( material.diffuseContribution ) * ( 1.0 - F ); +} +void RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) { + vec3 singleScattering = vec3( 0.0 ); + vec3 multiScattering = vec3( 0.0 ); + #ifdef USE_IRIDESCENCE + computeMultiscatteringIridescence( material.dfg, material.specularColor, material.specularF90, material.iridescence, material.iridescenceF0Dielectric, singleScattering, multiScattering ); + #else + computeMultiscattering( material.dfg, material.specularColor, material.specularF90, singleScattering, multiScattering ); + #endif + vec3 diffuse = irradiance * BRDF_Lambert( material.diffuseContribution ) * ( 1.0 - singleScattering - multiScattering ); + #ifdef USE_SHEEN + float sheenAlbedo = IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness ); + sheenSpecularIndirect += irradiance * material.sheenColor * sheenAlbedo * RECIPROCAL_PI; + float sheenEnergyComp = 1.0 - max3( material.sheenColor ) * sheenAlbedo; + diffuse *= sheenEnergyComp; + #endif + reflectedLight.indirectDiffuse += diffuse; +} +void RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 irradiance, const in vec3 clearcoatRadiance, const in vec3 geometryPosition, const in vec3 geometryNormal, const in vec3 geometryViewDir, const in vec3 geometryClearcoatNormal, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) { + #ifdef USE_CLEARCOAT + clearcoatSpecularIndirect += clearcoatRadiance * EnvironmentBRDF( geometryClearcoatNormal, geometryViewDir, material.clearcoatF0, material.clearcoatF90, material.clearcoatRoughness ); + #endif + #ifdef USE_SHEEN + sheenSpecularIndirect += irradiance * material.sheenColor * IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness ) * RECIPROCAL_PI; + #endif + vec3 singleScatteringDielectric = vec3( 0.0 ); + vec3 multiScatteringDielectric = vec3( 0.0 ); + vec3 singleScatteringMetallic = vec3( 0.0 ); + vec3 multiScatteringMetallic = vec3( 0.0 ); + #ifdef USE_IRIDESCENCE + computeMultiscatteringIridescence( material.dfg, material.specularColor, material.specularF90, material.iridescence, material.iridescenceF0Dielectric, singleScatteringDielectric, multiScatteringDielectric ); + computeMultiscatteringIridescence( material.dfg, material.diffuseColor, material.specularF90, material.iridescence, material.iridescenceF0Metallic, singleScatteringMetallic, multiScatteringMetallic ); + #else + computeMultiscattering( material.dfg, material.specularColor, material.specularF90, singleScatteringDielectric, multiScatteringDielectric ); + computeMultiscattering( material.dfg, material.diffuseColor, material.specularF90, singleScatteringMetallic, multiScatteringMetallic ); + #endif + vec3 singleScattering = mix( singleScatteringDielectric, singleScatteringMetallic, material.metalness ); + vec3 multiScattering = mix( multiScatteringDielectric, multiScatteringMetallic, material.metalness ); + vec3 totalScatteringDielectric = singleScatteringDielectric + multiScatteringDielectric; + vec3 diffuse = material.diffuseContribution * ( 1.0 - totalScatteringDielectric ); + vec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI; + vec3 indirectSpecular = radiance * singleScattering; + indirectSpecular += multiScattering * cosineWeightedIrradiance; + vec3 indirectDiffuse = diffuse * cosineWeightedIrradiance; + #ifdef USE_SHEEN + float sheenAlbedo = IBLSheenBRDF( geometryNormal, geometryViewDir, material.sheenRoughness ); + float sheenEnergyComp = 1.0 - max3( material.sheenColor ) * sheenAlbedo; + indirectSpecular *= sheenEnergyComp; + indirectDiffuse *= sheenEnergyComp; + #endif + reflectedLight.indirectSpecular += indirectSpecular; + reflectedLight.indirectDiffuse += indirectDiffuse; +} +#define RE_Direct RE_Direct_Physical +#define RE_Direct_RectArea RE_Direct_RectArea_Physical +#define RE_IndirectDiffuse RE_IndirectDiffuse_Physical +#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 ); +}`,cm=` +vec3 geometryPosition = - vViewPosition; +vec3 geometryNormal = normal; +vec3 geometryViewDir = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition ); +vec3 geometryClearcoatNormal = vec3( 0.0 ); +#ifdef USE_CLEARCOAT + geometryClearcoatNormal = clearcoatNormal; +#endif +#ifdef USE_IRIDESCENCE + float dotNVi = saturate( dot( normal, geometryViewDir ) ); + if ( material.iridescenceThickness == 0.0 ) { + material.iridescence = 0.0; + } else { + material.iridescence = saturate( material.iridescence ); + } + if ( material.iridescence > 0.0 ) { + vec3 iridescenceFresnelDielectric = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.specularColor ); + vec3 iridescenceFresnelMetallic = evalIridescence( 1.0, material.iridescenceIOR, dotNVi, material.iridescenceThickness, material.diffuseColor ); + material.iridescenceFresnel = mix( iridescenceFresnelDielectric, iridescenceFresnelMetallic, material.metalness ); + material.iridescenceF0Dielectric = Schlick_to_F0( iridescenceFresnelDielectric, 1.0, dotNVi ); + material.iridescenceF0Metallic = Schlick_to_F0( iridescenceFresnelMetallic, 1.0, dotNVi ); + } +#endif +#ifdef STANDARD + float dotNVms = saturate( dot( geometryNormal, geometryViewDir ) ); + material.dfg = texture2D( dfgLUT, vec2( material.roughness, dotNVms ) ).rg; + #if ( NUM_SUN_LIGHTS > 0 || NUM_DIR_LIGHTS > 0 || NUM_POINT_LIGHTS > 0 || NUM_SPOT_LIGHTS > 0 ) + float EssMs = material.dfg.x + material.dfg.y; + material.multiScatteringCompensation = 1.0 + material.specularColorBlended * ( 1.0 / EssMs - 1.0 ); + #endif +#endif +IncidentLight directLight; +#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct ) + PointLight pointLight; + #if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0 + PointLightShadow pointLightShadow; + #endif + #pragma unroll_loop_start + for ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) { + pointLight = pointLights[ i ]; + getPointLightInfo( pointLight, geometryPosition, directLight ); + #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS ) && ( defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_BASIC ) ) + pointLightShadow = pointLightShadows[ i ]; + directLight.color *= ( directLight.visible && receiveShadow ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowIntensity, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0; + #endif + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct ) + SpotLight spotLight; + vec4 spotColor; + vec3 spotLightCoord; + bool inSpotLightMap; + #if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0 + SpotLightShadow spotLightShadow; + #endif + #pragma unroll_loop_start + for ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) { + spotLight = spotLights[ i ]; + getSpotLightInfo( spotLight, geometryPosition, directLight ); + #if ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS ) + #define SPOT_LIGHT_MAP_INDEX UNROLLED_LOOP_INDEX + #elif ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) + #define SPOT_LIGHT_MAP_INDEX NUM_SPOT_LIGHT_MAPS + #else + #define SPOT_LIGHT_MAP_INDEX ( UNROLLED_LOOP_INDEX - NUM_SPOT_LIGHT_SHADOWS + NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS ) + #endif + #if ( SPOT_LIGHT_MAP_INDEX < NUM_SPOT_LIGHT_MAPS ) + spotLightCoord = vSpotLightCoord[ i ].xyz / vSpotLightCoord[ i ].w; + inSpotLightMap = all( lessThan( abs( spotLightCoord * 2. - 1. ), vec3( 1.0 ) ) ); + spotColor = texture2D( spotLightMap[ SPOT_LIGHT_MAP_INDEX ], spotLightCoord.xy ); + directLight.color = inSpotLightMap ? directLight.color * spotColor.rgb : directLight.color; + #endif + #undef SPOT_LIGHT_MAP_INDEX + #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) + spotLightShadow = spotLightShadows[ i ]; + directLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowIntensity, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotLightCoord[ i ] ) : 1.0; + #endif + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if ( NUM_SUN_LIGHTS > 0 ) && defined( RE_Direct ) + SunLight sunLight; + #if defined( USE_SHADOWMAP ) && NUM_SUN_LIGHT_SHADOWS > 0 + SunLightShadow sunLightShadow; + #endif + #pragma unroll_loop_start + for ( int i = 0; i < NUM_SUN_LIGHTS; i ++ ) { + sunLight = sunLights[ i ]; + getSunLightInfo( sunLight, directLight ); + #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SUN_LIGHT_SHADOWS ) + sunLightShadow = sunLightShadows[ i ]; + directLight.color *= ( directLight.visible && receiveShadow ) ? getSunShadow( sunShadowMap[ i ], sunLightShadow, UNROLLED_LOOP_INDEX ) : 1.0; + #endif + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct ) + DirectionalLight directionalLight; + #if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0 + DirectionalLightShadow directionalLightShadow; + #endif + #pragma unroll_loop_start + for ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) { + directionalLight = directionalLights[ i ]; + getDirectionalLightInfo( directionalLight, directLight ); + #if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS ) + directionalLightShadow = directionalLightShadows[ i ]; + directLight.color *= ( directLight.visible && receiveShadow ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowIntensity, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0; + #endif + RE_Direct( directLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea ) + RectAreaLight rectAreaLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) { + rectAreaLight = rectAreaLights[ i ]; + RE_Direct_RectArea( rectAreaLight, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); + } + #pragma unroll_loop_end +#endif +#if defined( RE_IndirectDiffuse ) + vec3 iblIrradiance = vec3( 0.0 ); + vec3 irradiance = getAmbientLightIrradiance( ambientLightColor ); + #if defined( USE_LIGHT_PROBES ) + irradiance += getLightProbeIrradiance( lightProbe, geometryNormal ); + #endif + #if ( NUM_HEMI_LIGHTS > 0 ) + #pragma unroll_loop_start + for ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) { + irradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometryNormal ); + } + #pragma unroll_loop_end + #endif + #ifdef USE_LIGHT_PROBES_GRID + vec3 probeWorldPos = ( ( vec4( geometryPosition, 1.0 ) - viewMatrix[ 3 ] ) * viewMatrix ).xyz; + vec3 probeWorldNormal = transformNormalByInverseViewMatrix( geometryNormal, viewMatrix ); + irradiance += getLightProbeGridIrradiance( probeWorldPos, probeWorldNormal ); + #endif +#endif +#if defined( RE_IndirectSpecular ) + vec3 radiance = vec3( 0.0 ); + vec3 clearcoatRadiance = vec3( 0.0 ); +#endif`,hm=`#if defined( RE_IndirectDiffuse ) + #ifdef USE_LIGHTMAP + vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); + vec3 lightMapIrradiance = lightMapTexel.rgb * lightMapIntensity; + irradiance += lightMapIrradiance; + #endif + #if defined( USE_ENVMAP ) && defined( ENVMAP_TYPE_CUBE_UV ) + #if defined( STANDARD ) || defined( LAMBERT ) || defined( PHONG ) + iblIrradiance += getIBLIrradiance( geometryNormal ); + #endif + #endif +#endif +#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular ) + #ifdef USE_ANISOTROPY + vec3 iblRadiance = getIBLAnisotropyRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy ); + #else + vec3 iblRadiance = getIBLRadiance( geometryViewDir, geometryNormal, material.roughness ); + #endif + #ifdef USE_RETROREFLECTION + #ifdef USE_ANISOTROPY + vec3 retroIBLRadiance = getIBLAnisotropyRetroRadiance( geometryViewDir, geometryNormal, material.roughness, material.anisotropyB, material.anisotropy ); + #else + vec3 retroIBLRadiance = getIBLRetroRadiance( geometryViewDir, geometryNormal, material.roughness ); + #endif + iblRadiance = mix( iblRadiance, retroIBLRadiance, saturate( material.retroreflectivity ) ); + #endif + radiance += iblRadiance; + #ifdef USE_CLEARCOAT + clearcoatRadiance += getIBLRadiance( geometryViewDir, geometryClearcoatNormal, material.clearcoatRoughness ); + #endif +#endif`,um=`#if defined( RE_IndirectDiffuse ) + #if defined( LAMBERT ) || defined( PHONG ) + irradiance += iblIrradiance; + #endif + RE_IndirectDiffuse( irradiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); +#endif +#if defined( RE_IndirectSpecular ) + RE_IndirectSpecular( radiance, iblIrradiance, clearcoatRadiance, geometryPosition, geometryNormal, geometryViewDir, geometryClearcoatNormal, material, reflectedLight ); +#endif`,dm=`#ifdef USE_LIGHT_PROBES_GRID +uniform highp sampler3D probesSH; +uniform vec3 probesMin; +uniform vec3 probesMax; +uniform vec3 probesResolution; +vec3 getLightProbeGridIrradiance( vec3 worldPos, vec3 worldNormal ) { + vec3 res = probesResolution; + vec3 gridRange = probesMax - probesMin; + vec3 resMinusOne = res - 1.0; + vec3 probeSpacing = gridRange / resMinusOne; + vec3 samplePos = worldPos + worldNormal * probeSpacing * 0.5; + vec3 uvw = clamp( ( samplePos - probesMin ) / gridRange, 0.0, 1.0 ); + uvw = uvw * resMinusOne / res + 0.5 / res; + float nz = res.z; + float paddedSlices = nz + 2.0; + float atlasDepth = 7.0 * paddedSlices; + float uvZBase = uvw.z * nz + 1.0; + vec4 s0 = texture( probesSH, vec3( uvw.xy, ( uvZBase ) / atlasDepth ) ); + vec4 s1 = texture( probesSH, vec3( uvw.xy, ( uvZBase + paddedSlices ) / atlasDepth ) ); + vec4 s2 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 2.0 * paddedSlices ) / atlasDepth ) ); + vec4 s3 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 3.0 * paddedSlices ) / atlasDepth ) ); + vec4 s4 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 4.0 * paddedSlices ) / atlasDepth ) ); + vec4 s5 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 5.0 * paddedSlices ) / atlasDepth ) ); + vec4 s6 = texture( probesSH, vec3( uvw.xy, ( uvZBase + 6.0 * paddedSlices ) / atlasDepth ) ); + vec3 c0 = s0.xyz; + vec3 c1 = vec3( s0.w, s1.xy ); + vec3 c2 = vec3( s1.zw, s2.x ); + vec3 c3 = s2.yzw; + vec3 c4 = s3.xyz; + vec3 c5 = vec3( s3.w, s4.xy ); + vec3 c6 = vec3( s4.zw, s5.x ); + vec3 c7 = s5.yzw; + vec3 c8 = s6.xyz; + float x = worldNormal.x, y = worldNormal.y, z = worldNormal.z; + vec3 result = c0 * 0.886227; + result += c1 * 2.0 * 0.511664 * y; + result += c2 * 2.0 * 0.511664 * z; + result += c3 * 2.0 * 0.511664 * x; + result += c4 * 2.0 * 0.429043 * x * y; + result += c5 * 2.0 * 0.429043 * y * z; + result += c6 * ( 0.743125 * z * z - 0.247708 ); + result += c7 * 2.0 * 0.429043 * x * z; + result += c8 * 0.429043 * ( x * x - y * y ); + return max( result, vec3( 0.0 ) ); +} +#endif`,fm=`#if defined( USE_LOGARITHMIC_DEPTH_BUFFER ) + gl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5; +#endif`,pm=`#if defined( USE_LOGARITHMIC_DEPTH_BUFFER ) + uniform float logDepthBufFC; + varying float vFragDepth; + varying float vIsPerspective; +#endif`,mm=`#ifdef USE_LOGARITHMIC_DEPTH_BUFFER + varying float vFragDepth; + varying float vIsPerspective; +#endif`,gm=`#ifdef USE_LOGARITHMIC_DEPTH_BUFFER + vFragDepth = 1.0 + gl_Position.w; + vIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) ); +#endif`,_m=`#ifdef USE_MAP + vec4 sampledDiffuseColor = texture2D( map, vMapUv ); + #ifdef DECODE_VIDEO_TEXTURE + sampledDiffuseColor = sRGBTransferEOTF( sampledDiffuseColor ); + #endif + diffuseColor *= sampledDiffuseColor; +#endif`,xm=`#ifdef USE_MAP + uniform sampler2D map; +#endif`,vm=`#if defined( USE_MAP ) || defined( USE_ALPHAMAP ) + #if defined( USE_POINTS_UV ) + vec2 uv = vUv; + #else + vec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy; + #endif +#endif +#ifdef USE_MAP + diffuseColor *= texture2D( map, uv ); +#endif +#ifdef USE_ALPHAMAP + diffuseColor.a *= texture2D( alphaMap, uv ).g; +#endif`,ym=`#if defined( USE_POINTS_UV ) + varying vec2 vUv; +#else + #if defined( USE_MAP ) || defined( USE_ALPHAMAP ) + uniform mat3 uvTransform; + #endif +#endif +#ifdef USE_MAP + uniform sampler2D map; +#endif +#ifdef USE_ALPHAMAP + uniform sampler2D alphaMap; +#endif`,Mm=`float metalnessFactor = metalness; +#ifdef USE_METALNESSMAP + vec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv ); + metalnessFactor *= texelMetalness.b; +#endif`,Sm=`#ifdef USE_METALNESSMAP + uniform sampler2D metalnessMap; +#endif`,bm=`#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`,Em=`#if defined( USE_MORPHCOLORS ) + vColor *= morphTargetBaseInfluence; + for ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) { + #if defined( USE_COLOR_ALPHA ) + if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ) * morphTargetInfluences[ i ]; + #elif defined( USE_COLOR ) + if ( morphTargetInfluences[ i ] != 0.0 ) vColor += getMorph( gl_VertexID, i, 2 ).rgb * morphTargetInfluences[ i ]; + #endif + } +#endif`,Tm=`#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`,wm=`#ifdef USE_MORPHTARGETS + #ifndef USE_INSTANCING_MORPH + uniform float morphTargetBaseInfluence; + uniform float morphTargetInfluences[ MORPHTARGETS_COUNT ]; + #endif + uniform sampler2DArray morphTargetsTexture; + uniform ivec2 morphTargetsTextureSize; + vec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) { + int texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset; + int y = texelIndex / morphTargetsTextureSize.x; + int x = texelIndex - y * morphTargetsTextureSize.x; + ivec3 morphUV = ivec3( x, y, morphTargetIndex ); + return texelFetch( morphTargetsTexture, morphUV, 0 ); + } +#endif`,Am=`#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`,Rm=`float faceDirection = gl_FrontFacing ? 1.0 : - 1.0; +#ifdef FLAT_SHADED + vec3 fdx = dFdx( vViewPosition ); + vec3 fdy = dFdy( vViewPosition ); + vec3 normal = normalize( cross( fdx, fdy ) ); +#else + vec3 normal = normalize( vNormal ); + #ifdef DOUBLE_SIDED + normal *= faceDirection; + #endif +#endif +#if defined( USE_NORMALMAP_TANGENTSPACE ) || defined( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) + #ifdef USE_TANGENT + mat3 tbn = mat3( normalize( vTangent ), normalize( vBitangent ), normal ); + #else + mat3 tbn = getTangentFrame( - vViewPosition, normal, + #if defined( USE_NORMALMAP ) + vNormalMapUv + #elif defined( USE_CLEARCOAT_NORMALMAP ) + vClearcoatNormalMapUv + #else + vUv + #endif + ); + #endif + #ifdef DOUBLE_SIDED + tbn[0] *= faceDirection; + tbn[1] *= faceDirection; + #endif +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + #ifdef USE_TANGENT + mat3 tbn2 = mat3( normalize( vTangent ), normalize( vBitangent ), normal ); + #else + mat3 tbn2 = getTangentFrame( - vViewPosition, normal, vClearcoatNormalMapUv ); + #endif + #ifdef DOUBLE_SIDED + tbn2[0] *= faceDirection; + tbn2[1] *= faceDirection; + #endif +#endif +vec3 nonPerturbedNormal = normal;`,Cm=`#ifdef USE_NORMALMAP_OBJECTSPACE + normal = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0; + #ifdef FLIP_SIDED + normal = - normal; + #endif + #ifdef DOUBLE_SIDED + normal = normal * faceDirection; + #endif + normal = normalize( normalMatrix * normal ); +#elif defined( USE_NORMALMAP_TANGENTSPACE ) + vec3 mapN = texture2D( normalMap, vNormalMapUv ).xyz * 2.0 - 1.0; + #if defined( USE_PACKED_NORMALMAP ) + mapN = vec3( mapN.xy, sqrt( saturate( 1.0 - dot( mapN.xy, mapN.xy ) ) ) ); + #endif + mapN.xy *= normalScale; + normal = normalize( tbn * mapN ); +#elif defined( USE_BUMPMAP ) + normal = perturbNormalArb( - vViewPosition, normal, dHdxy_fwd(), faceDirection ); +#endif`,Pm=`#ifndef FLAT_SHADED + varying vec3 vNormal; + #ifdef USE_TANGENT + varying vec3 vTangent; + varying vec3 vBitangent; + #endif +#endif`,Im=`#ifndef FLAT_SHADED + varying vec3 vNormal; + #ifdef USE_TANGENT + varying vec3 vTangent; + varying vec3 vBitangent; + #endif +#endif`,Lm=`#ifndef FLAT_SHADED + vNormal = normalize( transformedNormal ); + #ifdef USE_TANGENT + vTangent = normalize( transformedTangent ); + vBitangent = normalize( cross( vNormal, vTangent ) * tangent.w ); + #ifdef FLIP_SIDED + vBitangent = - vBitangent; + #endif + #endif +#endif`,Dm=`#ifdef USE_NORMALMAP + uniform sampler2D normalMap; + uniform vec2 normalScale; +#endif +#ifdef USE_NORMALMAP_OBJECTSPACE + uniform mat3 normalMatrix; +#endif +#if ! defined ( USE_TANGENT ) && ( defined ( USE_NORMALMAP_TANGENTSPACE ) || defined ( USE_CLEARCOAT_NORMALMAP ) || defined( USE_ANISOTROPY ) ) + mat3 getTangentFrame( vec3 eye_pos, vec3 surf_norm, vec2 uv ) { + vec3 q0 = dFdx( eye_pos.xyz ); + vec3 q1 = dFdy( eye_pos.xyz ); + vec2 st0 = dFdx( uv.st ); + vec2 st1 = dFdy( uv.st ); + vec3 N = surf_norm; + vec3 q1perp = cross( q1, N ); + vec3 q0perp = cross( N, q0 ); + vec3 T = q1perp * st0.x + q0perp * st1.x; + vec3 B = q1perp * st0.y + q0perp * st1.y; + float det = max( dot( T, T ), dot( B, B ) ); + float scale = ( det == 0.0 ) ? 0.0 : inversesqrt( det ); + return mat3( T * scale, B * scale, N ); + } +#endif`,Nm=`#ifdef USE_CLEARCOAT + vec3 clearcoatNormal = nonPerturbedNormal; +#endif`,Um=`#ifdef USE_CLEARCOAT_NORMALMAP + vec3 clearcoatMapN = texture2D( clearcoatNormalMap, vClearcoatNormalMapUv ).xyz * 2.0 - 1.0; + clearcoatMapN.xy *= clearcoatNormalScale; + clearcoatNormal = normalize( tbn2 * clearcoatMapN ); +#endif`,Fm=`#ifdef USE_CLEARCOATMAP + uniform sampler2D clearcoatMap; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + uniform sampler2D clearcoatNormalMap; + uniform vec2 clearcoatNormalScale; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + uniform sampler2D clearcoatRoughnessMap; +#endif`,Om=`#ifdef USE_IRIDESCENCEMAP + uniform sampler2D iridescenceMap; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + uniform sampler2D iridescenceThicknessMap; +#endif`,Bm=`#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 ) { + return normalize( normal ) * 0.5 + 0.5; +} +vec3 unpackRGBToNormal( const in vec3 rgb ) { + return 2.0 * rgb.xyz - 1.0; +} +const float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;const float ShiftRight8 = 1. / 256.; +const float Inv255 = 1. / 255.; +const vec4 PackFactors = vec4( 1.0, 256.0, 256.0 * 256.0, 256.0 * 256.0 * 256.0 ); +const vec2 UnpackFactors2 = vec2( UnpackDownscale, 1.0 / PackFactors.g ); +const vec3 UnpackFactors3 = vec3( UnpackDownscale / PackFactors.rg, 1.0 / PackFactors.b ); +const vec4 UnpackFactors4 = vec4( UnpackDownscale / PackFactors.rgb, 1.0 / PackFactors.a ); +vec4 packDepthToRGBA( const in float v ) { + if( v <= 0.0 ) + return vec4( 0., 0., 0., 0. ); + if( v >= 1.0 ) + return vec4( 1., 1., 1., 1. ); + float vuf; + float af = modf( v * PackFactors.a, vuf ); + float bf = modf( vuf * ShiftRight8, vuf ); + float gf = modf( vuf * ShiftRight8, vuf ); + return vec4( vuf * Inv255, gf * PackUpscale, bf * PackUpscale, af ); +} +vec3 packDepthToRGB( const in float v ) { + if( v <= 0.0 ) + return vec3( 0., 0., 0. ); + if( v >= 1.0 ) + return vec3( 1., 1., 1. ); + float vuf; + float bf = modf( v * PackFactors.b, vuf ); + float gf = modf( vuf * ShiftRight8, vuf ); + return vec3( vuf * Inv255, gf * PackUpscale, bf ); +} +vec2 packDepthToRG( const in float v ) { + if( v <= 0.0 ) + return vec2( 0., 0. ); + if( v >= 1.0 ) + return vec2( 1., 1. ); + float vuf; + float gf = modf( v * 256., vuf ); + return vec2( vuf * Inv255, gf ); +} +float unpackRGBAToDepth( const in vec4 v ) { + return dot( v, UnpackFactors4 ); +} +float unpackRGBToDepth( const in vec3 v ) { + return dot( v, UnpackFactors3 ); +} +float unpackRGToDepth( const in vec2 v ) { + return v.r * UnpackFactors2.r + v.g * UnpackFactors2.g; +} +vec4 pack2HalfToRGBA( const in vec2 v ) { + vec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ) ); + return vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w ); +} +vec2 unpackRGBATo2Half( const in vec4 v ) { + return vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) ); +} +float viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) { + return ( viewZ + near ) / ( near - far ); +} +float orthographicDepthToViewZ( const in float depth, const in float near, const in float far ) { + #ifdef USE_REVERSED_DEPTH_BUFFER + + return depth * ( far - near ) - far; + #else + return depth * ( near - far ) - near; + #endif +} +float viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) { + return ( ( near + viewZ ) * far ) / ( ( far - near ) * viewZ ); +} +float perspectiveDepthToViewZ( const in float depth, const in float near, const in float far ) { + + #ifdef USE_REVERSED_DEPTH_BUFFER + return ( near * far ) / ( ( near - far ) * depth - near ); + #else + return ( near * far ) / ( ( far - near ) * depth - far ); + #endif +}`,km=`#ifdef PREMULTIPLIED_ALPHA + gl_FragColor.rgb *= gl_FragColor.a; +#endif`,Vm=`vec4 mvPosition = vec4( transformed, 1.0 ); +#ifdef USE_BATCHING + mvPosition = batchingMatrix * mvPosition; +#endif +#ifdef USE_INSTANCING + mvPosition = instanceMatrix * mvPosition; +#endif +mvPosition = modelViewMatrix * mvPosition; +gl_Position = projectionMatrix * mvPosition;`,Hm=`#ifdef DITHERING + gl_FragColor.rgb = dithering( gl_FragColor.rgb ); +#endif`,Gm=`#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`,Wm=`float roughnessFactor = roughness; +#ifdef USE_ROUGHNESSMAP + vec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv ); + roughnessFactor *= texelRoughness.g; +#endif`,Xm=`#ifdef USE_ROUGHNESSMAP + uniform sampler2D roughnessMap; +#endif`,qm=`#if NUM_SPOT_LIGHT_COORDS > 0 + varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; +#endif +#if NUM_SPOT_LIGHT_MAPS > 0 + uniform sampler2D spotLightMap[ NUM_SPOT_LIGHT_MAPS ]; +#endif +#ifdef USE_SHADOWMAP + #if NUM_SUN_LIGHT_SHADOWS > 0 + #define SUN_LIGHT_CASCADES 2 + #if defined( SHADOWMAP_TYPE_PCF ) + uniform sampler2DShadow sunShadowMap[ NUM_SUN_LIGHT_SHADOWS ]; + #else + uniform sampler2D sunShadowMap[ NUM_SUN_LIGHT_SHADOWS ]; + #endif + uniform mat4 sunShadowMatrix[ NUM_SUN_LIGHT_SHADOWS * SUN_LIGHT_CASCADES ]; + uniform vec4 sunShadowCascade[ NUM_SUN_LIGHT_SHADOWS * SUN_LIGHT_CASCADES ]; + varying vec4 vSunShadowWorldPosition; + varying vec3 vSunShadowWorldNormal; + struct SunLightShadow { + float shadowIntensity; + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform SunLightShadow sunLightShadows[ NUM_SUN_LIGHT_SHADOWS ]; + #endif + #if NUM_DIR_LIGHT_SHADOWS > 0 + #if defined( SHADOWMAP_TYPE_PCF ) + uniform sampler2DShadow directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ]; + #else + uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ]; + #endif + varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ]; + struct DirectionalLightShadow { + float shadowIntensity; + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ]; + #endif + #if NUM_SPOT_LIGHT_SHADOWS > 0 + #if defined( SHADOWMAP_TYPE_PCF ) + uniform sampler2DShadow spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ]; + #else + uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ]; + #endif + struct SpotLightShadow { + float shadowIntensity; + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ]; + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + #if defined( SHADOWMAP_TYPE_PCF ) + uniform samplerCubeShadow pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ]; + #elif defined( SHADOWMAP_TYPE_BASIC ) + uniform samplerCube pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ]; + #endif + varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ]; + struct PointLightShadow { + float shadowIntensity; + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + float shadowCameraNear; + float shadowCameraFar; + }; + uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ]; + #endif + #if defined( SHADOWMAP_TYPE_PCF ) + float interleavedGradientNoise( vec2 position ) { + return fract( 52.9829189 * fract( dot( position, vec2( 0.06711056, 0.00583715 ) ) ) ); + } + vec2 vogelDiskSample( int sampleIndex, int samplesCount, float phi ) { + const float goldenAngle = 2.399963229728653; + float r = sqrt( ( float( sampleIndex ) + 0.5 ) / float( samplesCount ) ); + float theta = float( sampleIndex ) * goldenAngle + phi; + return vec2( cos( theta ), sin( theta ) ) * r; + } + #endif + #if defined( SHADOWMAP_TYPE_PCF ) + float getShadow( sampler2DShadow shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord ) { + float shadow = 1.0; + shadowCoord.xyz /= shadowCoord.w; + shadowCoord.z += shadowBias; + bool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0; + bool frustumTest = inFrustum && shadowCoord.z <= 1.0; + if ( frustumTest ) { + vec2 texelSize = vec2( 1.0 ) / shadowMapSize; + float radius = shadowRadius * texelSize.x; + float phi = interleavedGradientNoise( gl_FragCoord.xy ) * PI2; + shadow = ( + texture( shadowMap, vec3( shadowCoord.xy + vogelDiskSample( 0, 5, phi ) * radius, shadowCoord.z ) ) + + texture( shadowMap, vec3( shadowCoord.xy + vogelDiskSample( 1, 5, phi ) * radius, shadowCoord.z ) ) + + texture( shadowMap, vec3( shadowCoord.xy + vogelDiskSample( 2, 5, phi ) * radius, shadowCoord.z ) ) + + texture( shadowMap, vec3( shadowCoord.xy + vogelDiskSample( 3, 5, phi ) * radius, shadowCoord.z ) ) + + texture( shadowMap, vec3( shadowCoord.xy + vogelDiskSample( 4, 5, phi ) * radius, shadowCoord.z ) ) + ) * 0.2; + } + return mix( 1.0, shadow, shadowIntensity ); + } + #elif defined( SHADOWMAP_TYPE_VSM ) + float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord ) { + float shadow = 1.0; + shadowCoord.xyz /= shadowCoord.w; + #ifdef USE_REVERSED_DEPTH_BUFFER + shadowCoord.z -= shadowBias; + #else + shadowCoord.z += shadowBias; + #endif + bool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0; + bool frustumTest = inFrustum && shadowCoord.z <= 1.0; + if ( frustumTest ) { + vec2 distribution = texture2D( shadowMap, shadowCoord.xy ).rg; + float mean = distribution.x; + float variance = distribution.y * distribution.y; + #ifdef USE_REVERSED_DEPTH_BUFFER + float hard_shadow = step( mean, shadowCoord.z ); + #else + float hard_shadow = step( shadowCoord.z, mean ); + #endif + + if ( hard_shadow == 1.0 ) { + shadow = 1.0; + } else { + variance = max( variance, 0.0000001 ); + float d = shadowCoord.z - mean; + float p_max = variance / ( variance + d * d ); + p_max = clamp( ( p_max - 0.3 ) / 0.65, 0.0, 1.0 ); + shadow = max( hard_shadow, p_max ); + } + } + return mix( 1.0, shadow, shadowIntensity ); + } + #else + float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord ) { + float shadow = 1.0; + shadowCoord.xyz /= shadowCoord.w; + #ifdef USE_REVERSED_DEPTH_BUFFER + shadowCoord.z -= shadowBias; + #else + shadowCoord.z += shadowBias; + #endif + bool inFrustum = shadowCoord.x >= 0.0 && shadowCoord.x <= 1.0 && shadowCoord.y >= 0.0 && shadowCoord.y <= 1.0; + bool frustumTest = inFrustum && shadowCoord.z <= 1.0; + if ( frustumTest ) { + float depth = texture2D( shadowMap, shadowCoord.xy ).r; + #ifdef USE_REVERSED_DEPTH_BUFFER + shadow = step( depth, shadowCoord.z ); + #else + shadow = step( shadowCoord.z, depth ); + #endif + } + return mix( 1.0, shadow, shadowIntensity ); + } + #endif + #if NUM_SUN_LIGHT_SHADOWS > 0 + float getSunShadow( + #if defined( SHADOWMAP_TYPE_PCF ) + sampler2DShadow shadowMap, + #else + sampler2D shadowMap, + #endif + SunLightShadow sunLightShadow, + int shadowIndex + ) { + vec4 shadowWorldPosition = vec4( vSunShadowWorldPosition.xyz + vSunShadowWorldNormal * sunLightShadow.shadowNormalBias, 1.0 ); + float viewDepth = vSunShadowWorldPosition.w; + int cascadeOffset = shadowIndex * SUN_LIGHT_CASCADES; + float shadow = 1.0; + for ( int i = SUN_LIGHT_CASCADES - 1; i >= 0; i -- ) { + vec4 cascade = sunShadowCascade[ cascadeOffset + i ]; + if ( viewDepth >= cascade.x && viewDepth < cascade.y ) { + float cascadeShadow = getShadow( + shadowMap, + sunLightShadow.shadowMapSize, + sunLightShadow.shadowIntensity, + sunLightShadow.shadowBias, + sunLightShadow.shadowRadius, + sunShadowMatrix[ cascadeOffset + i ] * shadowWorldPosition + ); + shadow = mix( cascadeShadow, shadow, smoothstep( cascade.z, cascade.y, viewDepth ) ); + } + } + return shadow; + } + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + #if defined( SHADOWMAP_TYPE_PCF ) + float getPointShadow( samplerCubeShadow shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) { + float shadow = 1.0; + vec3 lightToPosition = shadowCoord.xyz; + vec3 bd3D = normalize( lightToPosition ); + vec3 absVec = abs( lightToPosition ); + float viewSpaceZ = max( max( absVec.x, absVec.y ), absVec.z ); + if ( viewSpaceZ - shadowCameraFar <= 0.0 && viewSpaceZ - shadowCameraNear >= 0.0 ) { + #ifdef USE_REVERSED_DEPTH_BUFFER + float dp = ( shadowCameraNear * ( shadowCameraFar - viewSpaceZ ) ) / ( viewSpaceZ * ( shadowCameraFar - shadowCameraNear ) ); + dp -= shadowBias; + #else + float dp = ( shadowCameraFar * ( viewSpaceZ - shadowCameraNear ) ) / ( viewSpaceZ * ( shadowCameraFar - shadowCameraNear ) ); + dp += shadowBias; + #endif + float texelSize = shadowRadius / shadowMapSize.x; + vec3 absDir = abs( bd3D ); + vec3 tangent = absDir.x > absDir.z ? vec3( 0.0, 1.0, 0.0 ) : vec3( 1.0, 0.0, 0.0 ); + tangent = normalize( cross( bd3D, tangent ) ); + vec3 bitangent = cross( bd3D, tangent ); + float phi = interleavedGradientNoise( gl_FragCoord.xy ) * PI2; + vec2 sample0 = vogelDiskSample( 0, 5, phi ); + vec2 sample1 = vogelDiskSample( 1, 5, phi ); + vec2 sample2 = vogelDiskSample( 2, 5, phi ); + vec2 sample3 = vogelDiskSample( 3, 5, phi ); + vec2 sample4 = vogelDiskSample( 4, 5, phi ); + shadow = ( + texture( shadowMap, vec4( bd3D + ( tangent * sample0.x + bitangent * sample0.y ) * texelSize, dp ) ) + + texture( shadowMap, vec4( bd3D + ( tangent * sample1.x + bitangent * sample1.y ) * texelSize, dp ) ) + + texture( shadowMap, vec4( bd3D + ( tangent * sample2.x + bitangent * sample2.y ) * texelSize, dp ) ) + + texture( shadowMap, vec4( bd3D + ( tangent * sample3.x + bitangent * sample3.y ) * texelSize, dp ) ) + + texture( shadowMap, vec4( bd3D + ( tangent * sample4.x + bitangent * sample4.y ) * texelSize, dp ) ) + ) * 0.2; + } + return mix( 1.0, shadow, shadowIntensity ); + } + #elif defined( SHADOWMAP_TYPE_BASIC ) + float getPointShadow( samplerCube shadowMap, vec2 shadowMapSize, float shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) { + float shadow = 1.0; + vec3 lightToPosition = shadowCoord.xyz; + vec3 absVec = abs( lightToPosition ); + float viewSpaceZ = max( max( absVec.x, absVec.y ), absVec.z ); + if ( viewSpaceZ - shadowCameraFar <= 0.0 && viewSpaceZ - shadowCameraNear >= 0.0 ) { + float dp = ( shadowCameraFar * ( viewSpaceZ - shadowCameraNear ) ) / ( viewSpaceZ * ( shadowCameraFar - shadowCameraNear ) ); + dp += shadowBias; + vec3 bd3D = normalize( lightToPosition ); + float depth = textureCube( shadowMap, bd3D ).r; + #ifdef USE_REVERSED_DEPTH_BUFFER + depth = 1.0 - depth; + #endif + shadow = step( dp, depth ); + } + return mix( 1.0, shadow, shadowIntensity ); + } + #endif + #endif +#endif`,Ym=`#if NUM_SPOT_LIGHT_COORDS > 0 + uniform mat4 spotLightMatrix[ NUM_SPOT_LIGHT_COORDS ]; + varying vec4 vSpotLightCoord[ NUM_SPOT_LIGHT_COORDS ]; +#endif +#ifdef USE_SHADOWMAP + #if NUM_SUN_LIGHT_SHADOWS > 0 + varying vec4 vSunShadowWorldPosition; + varying vec3 vSunShadowWorldNormal; + #endif + #if NUM_DIR_LIGHT_SHADOWS > 0 + uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ]; + varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ]; + struct DirectionalLightShadow { + float shadowIntensity; + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ]; + #endif + #if NUM_SPOT_LIGHT_SHADOWS > 0 + struct SpotLightShadow { + float shadowIntensity; + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + }; + uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ]; + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ]; + varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ]; + struct PointLightShadow { + float shadowIntensity; + float shadowBias; + float shadowNormalBias; + float shadowRadius; + vec2 shadowMapSize; + float shadowCameraNear; + float shadowCameraFar; + }; + uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ]; + #endif +#endif`,Zm=`#if ( defined( USE_SHADOWMAP ) && ( NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SUN_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0 ) ) || ( NUM_SPOT_LIGHT_COORDS > 0 ) + #ifdef HAS_NORMAL + vec3 shadowWorldNormal = transformNormalByInverseViewMatrix( transformedNormal, viewMatrix ); + #else + vec3 shadowWorldNormal = vec3( 0.0 ); + #endif + vec4 shadowWorldPosition; +#endif +#if defined( USE_SHADOWMAP ) + #if NUM_SUN_LIGHT_SHADOWS > 0 + vSunShadowWorldPosition = vec4( worldPosition.xyz, - mvPosition.z ); + vSunShadowWorldNormal = shadowWorldNormal; + #endif + #if NUM_DIR_LIGHT_SHADOWS > 0 + #pragma unroll_loop_start + for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) { + shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 ); + vDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition; + } + #pragma unroll_loop_end + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 + #pragma unroll_loop_start + for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) { + shadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 ); + vPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition; + } + #pragma unroll_loop_end + #endif +#endif +#if NUM_SPOT_LIGHT_COORDS > 0 + #pragma unroll_loop_start + for ( int i = 0; i < NUM_SPOT_LIGHT_COORDS; i ++ ) { + shadowWorldPosition = worldPosition; + #if ( defined( USE_SHADOWMAP ) && UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS ) + shadowWorldPosition.xyz += shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias; + #endif + vSpotLightCoord[ i ] = spotLightMatrix[ i ] * shadowWorldPosition; + } + #pragma unroll_loop_end +#endif`,Jm=`float getShadowMask() { + float shadow = 1.0; + #ifdef USE_SHADOWMAP + #if NUM_SUN_LIGHT_SHADOWS > 0 + SunLightShadow sunLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_SUN_LIGHT_SHADOWS; i ++ ) { + sunLight = sunLightShadows[ i ]; + shadow *= receiveShadow ? getSunShadow( sunShadowMap[ i ], sunLight, UNROLLED_LOOP_INDEX ) : 1.0; + } + #pragma unroll_loop_end + #endif + #if NUM_DIR_LIGHT_SHADOWS > 0 + DirectionalLightShadow directionalLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) { + directionalLight = directionalLightShadows[ i ]; + shadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowIntensity, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0; + } + #pragma unroll_loop_end + #endif + #if NUM_SPOT_LIGHT_SHADOWS > 0 + SpotLightShadow spotLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) { + spotLight = spotLightShadows[ i ]; + shadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowIntensity, spotLight.shadowBias, spotLight.shadowRadius, vSpotLightCoord[ i ] ) : 1.0; + } + #pragma unroll_loop_end + #endif + #if NUM_POINT_LIGHT_SHADOWS > 0 && ( defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_BASIC ) ) + PointLightShadow pointLight; + #pragma unroll_loop_start + for ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) { + pointLight = pointLightShadows[ i ]; + shadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowIntensity, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0; + } + #pragma unroll_loop_end + #endif + #endif + return shadow; +}`,$m=`#ifdef USE_SKINNING + mat4 boneMatX = getBoneMatrix( skinIndex.x ); + mat4 boneMatY = getBoneMatrix( skinIndex.y ); + mat4 boneMatZ = getBoneMatrix( skinIndex.z ); + mat4 boneMatW = getBoneMatrix( skinIndex.w ); +#endif`,Km=`#ifdef USE_SKINNING + uniform mat4 bindMatrix; + uniform mat4 bindMatrixInverse; + uniform highp sampler2D boneTexture; + mat4 getBoneMatrix( const in float i ) { + int size = textureSize( boneTexture, 0 ).x; + int j = int( i ) * 4; + int x = j % size; + int y = j / size; + vec4 v1 = texelFetch( boneTexture, ivec2( x, y ), 0 ); + vec4 v2 = texelFetch( boneTexture, ivec2( x + 1, y ), 0 ); + vec4 v3 = texelFetch( boneTexture, ivec2( x + 2, y ), 0 ); + vec4 v4 = texelFetch( boneTexture, ivec2( x + 3, y ), 0 ); + return mat4( v1, v2, v3, v4 ); + } +#endif`,Qm=`#ifdef USE_SKINNING + vec4 skinVertex = bindMatrix * vec4( transformed, 1.0 ); + vec4 skinned = vec4( 0.0 ); + skinned += boneMatX * skinVertex * skinWeight.x; + skinned += boneMatY * skinVertex * skinWeight.y; + skinned += boneMatZ * skinVertex * skinWeight.z; + skinned += boneMatW * skinVertex * skinWeight.w; + transformed = ( bindMatrixInverse * skinned ).xyz; +#endif`,jm=`#ifdef USE_SKINNING + mat4 skinMatrix = mat4( 0.0 ); + skinMatrix += skinWeight.x * boneMatX; + skinMatrix += skinWeight.y * boneMatY; + skinMatrix += skinWeight.z * boneMatZ; + skinMatrix += skinWeight.w * boneMatW; + skinMatrix = bindMatrixInverse * skinMatrix * bindMatrix; + objectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz; + #ifdef USE_TANGENT + objectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz; + #endif +#endif`,eg=`float specularStrength; +#ifdef USE_SPECULARMAP + vec4 texelSpecular = texture2D( specularMap, vSpecularMapUv ); + specularStrength = texelSpecular.r; +#else + specularStrength = 1.0; +#endif`,tg=`#ifdef USE_SPECULARMAP + uniform sampler2D specularMap; +#endif`,ng=`#if defined( TONE_MAPPING ) + gl_FragColor.rgb = toneMapping( gl_FragColor.rgb ); +#endif`,ig=`#ifndef saturate +#define saturate( a ) clamp( a, 0.0, 1.0 ) +#endif +uniform float toneMappingExposure; +vec3 LinearToneMapping( vec3 color ) { + return saturate( toneMappingExposure * color ); +} +vec3 ReinhardToneMapping( vec3 color ) { + color *= toneMappingExposure; + return saturate( color / ( vec3( 1.0 ) + color ) ); +} +vec3 CineonToneMapping( vec3 color ) { + color *= toneMappingExposure; + color = max( vec3( 0.0 ), color - 0.004 ); + return pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) ); +} +vec3 RRTAndODTFit( vec3 v ) { + vec3 a = v * ( v + 0.0245786 ) - 0.000090537; + vec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081; + return a / b; +} +vec3 ACESFilmicToneMapping( vec3 color ) { + const mat3 ACESInputMat = mat3( + vec3( 0.59719, 0.07600, 0.02840 ), vec3( 0.35458, 0.90834, 0.13383 ), + vec3( 0.04823, 0.01566, 0.83777 ) + ); + const mat3 ACESOutputMat = mat3( + vec3( 1.60475, -0.10208, -0.00327 ), vec3( -0.53108, 1.10813, -0.07276 ), + vec3( -0.07367, -0.00605, 1.07602 ) + ); + color *= toneMappingExposure / 0.6; + color = ACESInputMat * color; + color = RRTAndODTFit( color ); + color = ACESOutputMat * color; + return saturate( color ); +} +const mat3 LINEAR_REC2020_TO_LINEAR_SRGB = mat3( + vec3( 1.6605, - 0.1246, - 0.0182 ), + vec3( - 0.5876, 1.1329, - 0.1006 ), + vec3( - 0.0728, - 0.0083, 1.1187 ) +); +const mat3 LINEAR_SRGB_TO_LINEAR_REC2020 = mat3( + vec3( 0.6274, 0.0691, 0.0164 ), + vec3( 0.3293, 0.9195, 0.0880 ), + vec3( 0.0433, 0.0113, 0.8956 ) +); +vec3 agxDefaultContrastApprox( vec3 x ) { + vec3 x2 = x * x; + vec3 x4 = x2 * x2; + return + 15.5 * x4 * x2 + - 40.14 * x4 * x + + 31.96 * x4 + - 6.868 * x2 * x + + 0.4298 * x2 + + 0.1191 * x + - 0.00232; +} +vec3 AgXToneMapping( vec3 color ) { + const mat3 AgXInsetMatrix = mat3( + vec3( 0.856627153315983, 0.137318972929847, 0.11189821299995 ), + vec3( 0.0951212405381588, 0.761241990602591, 0.0767994186031903 ), + vec3( 0.0482516061458583, 0.101439036467562, 0.811302368396859 ) + ); + const mat3 AgXOutsetMatrix = mat3( + vec3( 1.1271005818144368, - 0.1413297634984383, - 0.14132976349843826 ), + vec3( - 0.11060664309660323, 1.157823702216272, - 0.11060664309660294 ), + vec3( - 0.016493938717834573, - 0.016493938717834257, 1.2519364065950405 ) + ); + const float AgxMinEv = - 12.47393; const float AgxMaxEv = 4.026069; + color *= toneMappingExposure; + color = LINEAR_SRGB_TO_LINEAR_REC2020 * color; + color = AgXInsetMatrix * color; + color = max( color, 1e-10 ); color = log2( color ); + color = ( color - AgxMinEv ) / ( AgxMaxEv - AgxMinEv ); + color = clamp( color, 0.0, 1.0 ); + color = agxDefaultContrastApprox( color ); + color = AgXOutsetMatrix * color; + color = pow( max( vec3( 0.0 ), color ), vec3( 2.2 ) ); + color = LINEAR_REC2020_TO_LINEAR_SRGB * color; + color = clamp( color, 0.0, 1.0 ); + return color; +} +vec3 NeutralToneMapping( vec3 color ) { + const float StartCompression = 0.8 - 0.04; + const float Desaturation = 0.15; + color *= toneMappingExposure; + float x = min( color.r, min( color.g, color.b ) ); + float offset = x < 0.08 ? x - 6.25 * x * x : 0.04; + color -= offset; + float peak = max( color.r, max( color.g, color.b ) ); + if ( peak < StartCompression ) return color; + float d = 1. - StartCompression; + float newPeak = 1. - d * d / ( peak + d - StartCompression ); + color *= newPeak / peak; + float g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. ); + return mix( color, vec3( newPeak ), g ); +} +vec3 CustomToneMapping( vec3 color ) { return color; }`,sg=`#ifdef USE_TRANSMISSION + material.transmission = transmission; + material.transmissionAlpha = 1.0; + material.thickness = thickness; + material.attenuationDistance = attenuationDistance; + material.attenuationColor = attenuationColor; + #ifdef USE_TRANSMISSIONMAP + material.transmission *= texture2D( transmissionMap, vTransmissionMapUv ).r; + #endif + #ifdef USE_THICKNESSMAP + material.thickness *= texture2D( thicknessMap, vThicknessMapUv ).g; + #endif + vec3 pos = vWorldPosition; + vec3 v = normalize( cameraPosition - pos ); + vec3 n = transformNormalByInverseViewMatrix( normal, viewMatrix ); + vec4 transmitted = getIBLVolumeRefraction( + n, v, material.roughness, material.diffuseContribution, material.specularColorBlended, material.specularF90, + pos, modelMatrix, viewMatrix, projectionMatrix, material.dispersion, material.ior, material.thickness, + material.attenuationColor, material.attenuationDistance ); + material.transmissionAlpha = mix( material.transmissionAlpha, transmitted.a, material.transmission ); + totalDiffuse = mix( totalDiffuse, transmitted.rgb, material.transmission ); +#endif`,rg=`#ifdef USE_TRANSMISSION + uniform float transmission; + uniform float thickness; + uniform float attenuationDistance; + uniform vec3 attenuationColor; + #ifdef USE_TRANSMISSIONMAP + uniform sampler2D transmissionMap; + #endif + #ifdef USE_THICKNESSMAP + uniform sampler2D thicknessMap; + #endif + uniform vec2 transmissionSamplerSize; + uniform sampler2D transmissionSamplerMap; + uniform mat4 modelMatrix; + uniform mat4 projectionMatrix; + varying vec3 vWorldPosition; + float w0( float a ) { + return ( 1.0 / 6.0 ) * ( a * ( a * ( - a + 3.0 ) - 3.0 ) + 1.0 ); + } + float w1( float a ) { + return ( 1.0 / 6.0 ) * ( a * a * ( 3.0 * a - 6.0 ) + 4.0 ); + } + float w2( float a ){ + return ( 1.0 / 6.0 ) * ( a * ( a * ( - 3.0 * a + 3.0 ) + 3.0 ) + 1.0 ); + } + float w3( float a ) { + return ( 1.0 / 6.0 ) * ( a * a * a ); + } + float g0( float a ) { + return w0( a ) + w1( a ); + } + float g1( float a ) { + return w2( a ) + w3( a ); + } + float h0( float a ) { + return - 1.0 + w1( a ) / ( w0( a ) + w1( a ) ); + } + float h1( float a ) { + return 1.0 + w3( a ) / ( w2( a ) + w3( a ) ); + } + vec4 bicubic( sampler2D tex, vec2 uv, vec4 texelSize, float lod ) { + uv = uv * texelSize.zw + 0.5; + vec2 iuv = floor( uv ); + vec2 fuv = fract( uv ); + float g0x = g0( fuv.x ); + float g1x = g1( fuv.x ); + float h0x = h0( fuv.x ); + float h1x = h1( fuv.x ); + float h0y = h0( fuv.y ); + float h1y = h1( fuv.y ); + vec2 p0 = ( vec2( iuv.x + h0x, iuv.y + h0y ) - 0.5 ) * texelSize.xy; + vec2 p1 = ( vec2( iuv.x + h1x, iuv.y + h0y ) - 0.5 ) * texelSize.xy; + vec2 p2 = ( vec2( iuv.x + h0x, iuv.y + h1y ) - 0.5 ) * texelSize.xy; + vec2 p3 = ( vec2( iuv.x + h1x, iuv.y + h1y ) - 0.5 ) * texelSize.xy; + return g0( fuv.y ) * ( g0x * textureLod( tex, p0, lod ) + g1x * textureLod( tex, p1, lod ) ) + + g1( fuv.y ) * ( g0x * textureLod( tex, p2, lod ) + g1x * textureLod( tex, p3, lod ) ); + } + vec4 textureBicubic( sampler2D sampler, vec2 uv, float lod ) { + vec2 fLodSize = vec2( textureSize( sampler, int( lod ) ) ); + vec2 cLodSize = vec2( textureSize( sampler, int( lod + 1.0 ) ) ); + vec2 fLodSizeInv = 1.0 / fLodSize; + vec2 cLodSizeInv = 1.0 / cLodSize; + vec4 fSample = bicubic( sampler, uv, vec4( fLodSizeInv, fLodSize ), floor( lod ) ); + vec4 cSample = bicubic( sampler, uv, vec4( cLodSizeInv, cLodSize ), ceil( lod ) ); + return mix( fSample, cSample, fract( lod ) ); + } + vec3 getVolumeTransmissionRay( const in vec3 n, const in vec3 v, const in float thickness, const in float ior, const in mat4 modelMatrix ) { + vec3 refractionVector = refract( - v, normalize( n ), 1.0 / ior ); + vec3 modelScale; + modelScale.x = length( vec3( modelMatrix[ 0 ].xyz ) ); + modelScale.y = length( vec3( modelMatrix[ 1 ].xyz ) ); + modelScale.z = length( vec3( modelMatrix[ 2 ].xyz ) ); + return normalize( refractionVector ) * thickness * modelScale; + } + float applyIorToRoughness( const in float roughness, const in float ior ) { + return roughness * clamp( ior * 2.0 - 2.0, 0.0, 1.0 ); + } + vec4 getTransmissionSample( const in vec2 fragCoord, const in float roughness, const in float ior ) { + float lod = log2( transmissionSamplerSize.x ) * applyIorToRoughness( roughness, ior ); + return textureBicubic( transmissionSamplerMap, fragCoord.xy, lod ); + } + vec3 volumeAttenuation( const in float transmissionDistance, const in vec3 attenuationColor, const in float attenuationDistance ) { + if ( isinf( attenuationDistance ) ) { + return vec3( 1.0 ); + } else { + vec3 attenuationCoefficient = -log( attenuationColor ) / attenuationDistance; + vec3 transmittance = exp( - attenuationCoefficient * transmissionDistance ); return transmittance; + } + } + vec4 getIBLVolumeRefraction( const in vec3 n, const in vec3 v, const in float roughness, const in vec3 diffuseColor, + const in vec3 specularColor, const in float specularF90, const in vec3 position, const in mat4 modelMatrix, + const in mat4 viewMatrix, const in mat4 projMatrix, const in float dispersion, const in float ior, const in float thickness, + const in vec3 attenuationColor, const in float attenuationDistance ) { + vec4 transmittedLight; + vec3 transmittance; + #ifdef USE_DISPERSION + float halfSpread = ( ior - 1.0 ) * 0.025 * dispersion; + vec3 iors = vec3( ior - halfSpread, ior, ior + halfSpread ); + for ( int i = 0; i < 3; i ++ ) { + vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, iors[ i ], modelMatrix ); + vec3 refractedRayExit = position + transmissionRay; + vec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 ); + vec2 refractionCoords = ndcPos.xy / ndcPos.w; + refractionCoords += 1.0; + refractionCoords /= 2.0; + vec4 transmissionSample = getTransmissionSample( refractionCoords, roughness, iors[ i ] ); + transmittedLight[ i ] = transmissionSample[ i ]; + transmittedLight.a += transmissionSample.a; + transmittance[ i ] = diffuseColor[ i ] * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance )[ i ]; + } + transmittedLight.a /= 3.0; + #else + vec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix ); + vec3 refractedRayExit = position + transmissionRay; + vec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 ); + vec2 refractionCoords = ndcPos.xy / ndcPos.w; + refractionCoords += 1.0; + refractionCoords /= 2.0; + transmittedLight = getTransmissionSample( refractionCoords, roughness, ior ); + transmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance ); + #endif + vec3 attenuatedColor = transmittance * transmittedLight.rgb; + vec3 F = EnvironmentBRDF( n, v, specularColor, specularF90, roughness ); + float transmittanceFactor = ( transmittance.r + transmittance.g + transmittance.b ) / 3.0; + return vec4( ( 1.0 - F ) * attenuatedColor, 1.0 - ( 1.0 - transmittedLight.a ) * transmittanceFactor ); + } +#endif`,ag=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) + varying vec2 vUv; +#endif +#ifdef USE_MAP + varying vec2 vMapUv; +#endif +#ifdef USE_ALPHAMAP + varying vec2 vAlphaMapUv; +#endif +#ifdef USE_LIGHTMAP + varying vec2 vLightMapUv; +#endif +#ifdef USE_AOMAP + varying vec2 vAoMapUv; +#endif +#ifdef USE_BUMPMAP + varying vec2 vBumpMapUv; +#endif +#ifdef USE_NORMALMAP + varying vec2 vNormalMapUv; +#endif +#ifdef USE_EMISSIVEMAP + varying vec2 vEmissiveMapUv; +#endif +#ifdef USE_METALNESSMAP + varying vec2 vMetalnessMapUv; +#endif +#ifdef USE_ROUGHNESSMAP + varying vec2 vRoughnessMapUv; +#endif +#ifdef USE_ANISOTROPYMAP + varying vec2 vAnisotropyMapUv; +#endif +#ifdef USE_CLEARCOATMAP + varying vec2 vClearcoatMapUv; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + varying vec2 vClearcoatNormalMapUv; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + varying vec2 vClearcoatRoughnessMapUv; +#endif +#ifdef USE_IRIDESCENCEMAP + varying vec2 vIridescenceMapUv; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + varying vec2 vIridescenceThicknessMapUv; +#endif +#ifdef USE_SHEEN_COLORMAP + varying vec2 vSheenColorMapUv; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + varying vec2 vSheenRoughnessMapUv; +#endif +#ifdef USE_SPECULARMAP + varying vec2 vSpecularMapUv; +#endif +#ifdef USE_SPECULAR_COLORMAP + varying vec2 vSpecularColorMapUv; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + varying vec2 vSpecularIntensityMapUv; +#endif +#ifdef USE_TRANSMISSIONMAP + uniform mat3 transmissionMapTransform; + varying vec2 vTransmissionMapUv; +#endif +#ifdef USE_THICKNESSMAP + uniform mat3 thicknessMapTransform; + varying vec2 vThicknessMapUv; +#endif`,og=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) + varying vec2 vUv; +#endif +#ifdef USE_MAP + uniform mat3 mapTransform; + varying vec2 vMapUv; +#endif +#ifdef USE_ALPHAMAP + uniform mat3 alphaMapTransform; + varying vec2 vAlphaMapUv; +#endif +#ifdef USE_LIGHTMAP + uniform mat3 lightMapTransform; + varying vec2 vLightMapUv; +#endif +#ifdef USE_AOMAP + uniform mat3 aoMapTransform; + varying vec2 vAoMapUv; +#endif +#ifdef USE_BUMPMAP + uniform mat3 bumpMapTransform; + varying vec2 vBumpMapUv; +#endif +#ifdef USE_NORMALMAP + uniform mat3 normalMapTransform; + varying vec2 vNormalMapUv; +#endif +#ifdef USE_DISPLACEMENTMAP + uniform mat3 displacementMapTransform; + varying vec2 vDisplacementMapUv; +#endif +#ifdef USE_EMISSIVEMAP + uniform mat3 emissiveMapTransform; + varying vec2 vEmissiveMapUv; +#endif +#ifdef USE_METALNESSMAP + uniform mat3 metalnessMapTransform; + varying vec2 vMetalnessMapUv; +#endif +#ifdef USE_ROUGHNESSMAP + uniform mat3 roughnessMapTransform; + varying vec2 vRoughnessMapUv; +#endif +#ifdef USE_ANISOTROPYMAP + uniform mat3 anisotropyMapTransform; + varying vec2 vAnisotropyMapUv; +#endif +#ifdef USE_CLEARCOATMAP + uniform mat3 clearcoatMapTransform; + varying vec2 vClearcoatMapUv; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + uniform mat3 clearcoatNormalMapTransform; + varying vec2 vClearcoatNormalMapUv; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + uniform mat3 clearcoatRoughnessMapTransform; + varying vec2 vClearcoatRoughnessMapUv; +#endif +#ifdef USE_SHEEN_COLORMAP + uniform mat3 sheenColorMapTransform; + varying vec2 vSheenColorMapUv; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + uniform mat3 sheenRoughnessMapTransform; + varying vec2 vSheenRoughnessMapUv; +#endif +#ifdef USE_IRIDESCENCEMAP + uniform mat3 iridescenceMapTransform; + varying vec2 vIridescenceMapUv; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + uniform mat3 iridescenceThicknessMapTransform; + varying vec2 vIridescenceThicknessMapUv; +#endif +#ifdef USE_SPECULARMAP + uniform mat3 specularMapTransform; + varying vec2 vSpecularMapUv; +#endif +#ifdef USE_SPECULAR_COLORMAP + uniform mat3 specularColorMapTransform; + varying vec2 vSpecularColorMapUv; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + uniform mat3 specularIntensityMapTransform; + varying vec2 vSpecularIntensityMapUv; +#endif +#ifdef USE_TRANSMISSIONMAP + uniform mat3 transmissionMapTransform; + varying vec2 vTransmissionMapUv; +#endif +#ifdef USE_THICKNESSMAP + uniform mat3 thicknessMapTransform; + varying vec2 vThicknessMapUv; +#endif`,lg=`#if defined( USE_UV ) || defined( USE_ANISOTROPY ) + vUv = vec3( uv, 1 ).xy; +#endif +#ifdef USE_MAP + vMapUv = ( mapTransform * vec3( MAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ALPHAMAP + vAlphaMapUv = ( alphaMapTransform * vec3( ALPHAMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_LIGHTMAP + vLightMapUv = ( lightMapTransform * vec3( LIGHTMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_AOMAP + vAoMapUv = ( aoMapTransform * vec3( AOMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_BUMPMAP + vBumpMapUv = ( bumpMapTransform * vec3( BUMPMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_NORMALMAP + vNormalMapUv = ( normalMapTransform * vec3( NORMALMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_DISPLACEMENTMAP + vDisplacementMapUv = ( displacementMapTransform * vec3( DISPLACEMENTMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_EMISSIVEMAP + vEmissiveMapUv = ( emissiveMapTransform * vec3( EMISSIVEMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_METALNESSMAP + vMetalnessMapUv = ( metalnessMapTransform * vec3( METALNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ROUGHNESSMAP + vRoughnessMapUv = ( roughnessMapTransform * vec3( ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_ANISOTROPYMAP + vAnisotropyMapUv = ( anisotropyMapTransform * vec3( ANISOTROPYMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOATMAP + vClearcoatMapUv = ( clearcoatMapTransform * vec3( CLEARCOATMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOAT_NORMALMAP + vClearcoatNormalMapUv = ( clearcoatNormalMapTransform * vec3( CLEARCOAT_NORMALMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_CLEARCOAT_ROUGHNESSMAP + vClearcoatRoughnessMapUv = ( clearcoatRoughnessMapTransform * vec3( CLEARCOAT_ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_IRIDESCENCEMAP + vIridescenceMapUv = ( iridescenceMapTransform * vec3( IRIDESCENCEMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_IRIDESCENCE_THICKNESSMAP + vIridescenceThicknessMapUv = ( iridescenceThicknessMapTransform * vec3( IRIDESCENCE_THICKNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SHEEN_COLORMAP + vSheenColorMapUv = ( sheenColorMapTransform * vec3( SHEEN_COLORMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SHEEN_ROUGHNESSMAP + vSheenRoughnessMapUv = ( sheenRoughnessMapTransform * vec3( SHEEN_ROUGHNESSMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULARMAP + vSpecularMapUv = ( specularMapTransform * vec3( SPECULARMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULAR_COLORMAP + vSpecularColorMapUv = ( specularColorMapTransform * vec3( SPECULAR_COLORMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_SPECULAR_INTENSITYMAP + vSpecularIntensityMapUv = ( specularIntensityMapTransform * vec3( SPECULAR_INTENSITYMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_TRANSMISSIONMAP + vTransmissionMapUv = ( transmissionMapTransform * vec3( TRANSMISSIONMAP_UV, 1 ) ).xy; +#endif +#ifdef USE_THICKNESSMAP + vThicknessMapUv = ( thicknessMapTransform * vec3( THICKNESSMAP_UV, 1 ) ).xy; +#endif`,cg=`#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; + #endif + #ifdef USE_INSTANCING + worldPosition = instanceMatrix * worldPosition; + #endif + worldPosition = modelMatrix * worldPosition; +#endif`,hg=`varying vec2 vUv; +uniform mat3 uvTransform; +void main() { + vUv = ( uvTransform * vec3( uv, 1 ) ).xy; + gl_Position = vec4( position.xy, 1.0, 1.0 ); +}`,ug=`uniform sampler2D t2D; +uniform float backgroundIntensity; +varying vec2 vUv; +void main() { + vec4 texColor = texture2D( t2D, vUv ); + #ifdef DECODE_VIDEO_TEXTURE + texColor = vec4( mix( pow( texColor.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), texColor.rgb * 0.0773993808, vec3( lessThanEqual( texColor.rgb, vec3( 0.04045 ) ) ) ), texColor.w ); + #endif + texColor.rgb *= backgroundIntensity; + gl_FragColor = texColor; + #include + #include +}`,dg=`varying vec3 vWorldDirection; +#include +void main() { + vWorldDirection = transformDirection( position, modelMatrix ); + #include + #include + gl_Position.z = gl_Position.w; +}`,fg=`#ifdef ENVMAP_TYPE_CUBE + uniform samplerCube envMap; +#elif defined( ENVMAP_TYPE_CUBE_UV ) + uniform sampler2D envMap; +#endif +uniform float backgroundBlurriness; +uniform float backgroundIntensity; +uniform mat3 backgroundRotation; +varying vec3 vWorldDirection; +#include +void main() { + #ifdef ENVMAP_TYPE_CUBE + vec4 texColor = textureCube( envMap, backgroundRotation * vWorldDirection ); + #elif defined( ENVMAP_TYPE_CUBE_UV ) + vec4 texColor = textureCubeUV( envMap, backgroundRotation * vWorldDirection, backgroundBlurriness ); + #else + vec4 texColor = vec4( 0.0, 0.0, 0.0, 1.0 ); + #endif + texColor.rgb *= backgroundIntensity; + gl_FragColor = texColor; + #include + #include +}`,pg=`varying vec3 vWorldDirection; +#include +void main() { + vWorldDirection = transformDirection( position, modelMatrix ); + #include + #include + gl_Position.z = gl_Position.w; +}`,mg=`uniform samplerCube tCube; +uniform float tFlip; +uniform float opacity; +varying vec3 vWorldDirection; +void main() { + vec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) ); + gl_FragColor = texColor; + gl_FragColor.a *= opacity; + #include + #include +}`,gg=`#include +#include +#include +#include +#include +#include +#include +#include +varying vec2 vHighPrecisionZW; +void main() { + #include + #include + #include + #include + #ifdef USE_DISPLACEMENTMAP + #include + #include + #include + #endif + #include + #include + #include + #include + #include + #include + #include + vHighPrecisionZW = gl_Position.zw; +}`,_g=`#if DEPTH_PACKING == 3200 + uniform float opacity; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +varying vec2 vHighPrecisionZW; +void main() { + vec4 diffuseColor = vec4( 1.0 ); + #include + #if DEPTH_PACKING == 3200 + diffuseColor.a = opacity; + #endif + #include + #include + #include + #include + #include + #ifdef USE_REVERSED_DEPTH_BUFFER + float fragCoordZ = vHighPrecisionZW[ 0 ] / vHighPrecisionZW[ 1 ]; + #else + float fragCoordZ = 0.5 * vHighPrecisionZW[ 0 ] / vHighPrecisionZW[ 1 ] + 0.5; + #endif + #if DEPTH_PACKING == 3200 + gl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity ); + #elif DEPTH_PACKING == 3201 + gl_FragColor = packDepthToRGBA( fragCoordZ ); + #elif DEPTH_PACKING == 3202 + gl_FragColor = vec4( packDepthToRGB( fragCoordZ ), 1.0 ); + #elif DEPTH_PACKING == 3203 + gl_FragColor = vec4( packDepthToRG( fragCoordZ ), 0.0, 1.0 ); + #endif +}`,xg=`#define DISTANCE +varying vec3 vWorldPosition; +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #ifdef USE_DISPLACEMENTMAP + #include + #include + #include + #endif + #include + #include + #include + #include + #include + #include + #include + vWorldPosition = worldPosition.xyz; +}`,vg=`#define DISTANCE +uniform vec3 referencePosition; +uniform float nearDistance; +uniform float farDistance; +varying vec3 vWorldPosition; +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( 1.0 ); + #include + #include + #include + #include + #include + float dist = length( vWorldPosition - referencePosition ); + dist = ( dist - nearDistance ) / ( farDistance - nearDistance ); + dist = saturate( dist ); + gl_FragColor = vec4( dist, 0.0, 0.0, 1.0 ); +}`,yg=`varying vec3 vWorldDirection; +#include +void main() { + vWorldDirection = transformDirection( position, modelMatrix ); + #include + #include +}`,Mg=`uniform sampler2D tEquirect; +varying vec3 vWorldDirection; +#include +void main() { + vec3 direction = normalize( vWorldDirection ); + vec2 sampleUV = equirectUv( direction ); + gl_FragColor = texture2D( tEquirect, sampleUV ); + #include + #include +}`,Sg=`uniform float scale; +attribute float lineDistance; +varying float vLineDistance; +#include +#include +#include +#include +#include +#include +#include +void main() { + vLineDistance = scale * lineDistance; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +}`,bg=`uniform vec3 diffuse; +uniform float opacity; +uniform float dashSize; +uniform float totalSize; +varying float vLineDistance; +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + if ( mod( vLineDistance, totalSize ) > dashSize ) { + discard; + } + vec3 outgoingLight = vec3( 0.0 ); + #include + #include + #include + outgoingLight = diffuseColor.rgb; + #include + #include + #include + #include + #include +}`,Eg=`#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #if defined ( USE_ENVMAP ) || defined ( USE_SKINNING ) + #include + #include + #include + #include + #include + #endif + #include + #include + #include + #include + #include + #include + #include + #include + #include +}`,Tg=`uniform vec3 diffuse; +uniform float opacity; +#ifndef FLAT_SHADED + varying vec3 vNormal; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + #include + #include + #include + #include + #include + #include + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + #ifdef USE_LIGHTMAP + vec4 lightMapTexel = texture2D( lightMap, vLightMapUv ); + reflectedLight.indirectDiffuse += lightMapTexel.rgb * lightMapIntensity * RECIPROCAL_PI; + #else + reflectedLight.indirectDiffuse += vec3( 1.0 ); + #endif + #include + reflectedLight.indirectDiffuse *= diffuseColor.rgb; + vec3 outgoingLight = reflectedLight.indirectDiffuse; + #include + #include + #include + #include + #include + #include + #include +}`,wg=`#define LAMBERT +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include + #include +}`,Ag=`#define LAMBERT +uniform vec3 diffuse; +uniform vec3 emissive; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance; + #include + #include + #include + #include + #include + #include + #include +}`,Rg=`#define MATCAP +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; +}`,Cg=`#define MATCAP +uniform vec3 diffuse; +uniform float opacity; +uniform sampler2D matcap; +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 viewDir = normalize( vViewPosition ); + vec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) ); + vec3 y = cross( viewDir, x ); + vec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5; + #ifdef USE_MATCAP + vec4 matcapColor = texture2D( matcap, uv ); + #else + vec4 matcapColor = vec4( vec3( mix( 0.2, 0.8, uv.y ) ), 1.0 ); + #endif + vec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb; + #include + #include + #include + #include + #include + #include +}`,Pg=`#define NORMAL +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) + varying vec3 vViewPosition; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) + vViewPosition = - mvPosition.xyz; +#endif +}`,Ig=`#define NORMAL +uniform float opacity; +#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE ) + varying vec3 vViewPosition; +#endif +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( 0.0, 0.0, 0.0, opacity ); + #include + #include + #include + #include + gl_FragColor = vec4( normalize( normal ) * 0.5 + 0.5, diffuseColor.a ); + #ifdef OPAQUE + gl_FragColor.a = 1.0; + #endif +}`,Lg=`#define PHONG +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include + #include +}`,Dg=`#define PHONG +uniform vec3 diffuse; +uniform vec3 emissive; +uniform vec3 specular; +uniform float shininess; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance; + #include + #include + #include + #include + #include + #include + #include +}`,Ng=`#define STANDARD +varying vec3 vViewPosition; +#ifdef USE_TRANSMISSION + varying vec3 vWorldPosition; +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include +#ifdef USE_TRANSMISSION + vWorldPosition = worldPosition.xyz; +#endif +}`,Ug=`#define STANDARD +#ifdef PHYSICAL + #define IOR + #define USE_SPECULAR +#endif +uniform vec3 diffuse; +uniform vec3 emissive; +uniform float roughness; +uniform float metalness; +uniform float opacity; +#ifdef IOR + uniform float ior; +#endif +#ifdef USE_SPECULAR + uniform float specularIntensity; + uniform vec3 specularColor; + #ifdef USE_SPECULAR_COLORMAP + uniform sampler2D specularColorMap; + #endif + #ifdef USE_SPECULAR_INTENSITYMAP + uniform sampler2D specularIntensityMap; + #endif +#endif +#ifdef USE_CLEARCOAT + uniform float clearcoat; + uniform float clearcoatRoughness; +#endif +#ifdef USE_DISPERSION + uniform float dispersion; +#endif +#ifdef USE_RETROREFLECTION + uniform float retroreflectivity; +#endif +#ifdef USE_IRIDESCENCE + uniform float iridescence; + uniform float iridescenceIOR; + uniform float iridescenceThicknessMinimum; + uniform float iridescenceThicknessMaximum; +#endif +#ifdef USE_SHEEN + uniform vec3 sheenColor; + uniform float sheenRoughness; + #ifdef USE_SHEEN_COLORMAP + uniform sampler2D sheenColorMap; + #endif + #ifdef USE_SHEEN_ROUGHNESSMAP + uniform sampler2D sheenRoughnessMap; + #endif +#endif +#ifdef USE_ANISOTROPY + uniform vec2 anisotropyVector; + #ifdef USE_ANISOTROPYMAP + uniform sampler2D anisotropyMap; + #endif +#endif +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 totalDiffuse = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse; + vec3 totalSpecular = reflectedLight.directSpecular + reflectedLight.indirectSpecular; + #include + vec3 outgoingLight = totalDiffuse + totalSpecular + totalEmissiveRadiance; + #ifdef USE_SHEEN + + outgoingLight = outgoingLight + sheenSpecularDirect + sheenSpecularIndirect; + + #endif + #ifdef USE_CLEARCOAT + float dotNVcc = saturate( dot( geometryClearcoatNormal, geometryViewDir ) ); + vec3 Fcc = F_Schlick( material.clearcoatF0, material.clearcoatF90, dotNVcc ); + outgoingLight = outgoingLight * ( 1.0 - material.clearcoat * Fcc ) + ( clearcoatSpecularDirect + clearcoatSpecularIndirect ) * material.clearcoat; + #endif + #include + #include + #include + #include + #include + #include +}`,Fg=`#define TOON +varying vec3 vViewPosition; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vViewPosition = - mvPosition.xyz; + #include + #include + #include +}`,Og=`#define TOON +uniform vec3 diffuse; +uniform vec3 emissive; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); + vec3 totalEmissiveRadiance = emissive; + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance; + #include + #include + #include + #include + #include + #include +}`,Bg=`uniform float size; +uniform float scale; +#include +#include +#include +#include +#include +#include +#ifdef USE_POINTS_UV + varying vec2 vUv; + uniform mat3 uvTransform; +#endif +void main() { + #ifdef USE_POINTS_UV + vUv = ( uvTransform * vec3( uv, 1 ) ).xy; + #endif + #include + #include + #include + #include + #include + #include + gl_PointSize = size; + #ifdef USE_SIZEATTENUATION + bool isPerspective = isPerspectiveMatrix( projectionMatrix ); + if ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z ); + #endif + #include + #include + #include + #include +}`,zg=`uniform vec3 diffuse; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + vec3 outgoingLight = vec3( 0.0 ); + #include + #include + #include + #include + #include + outgoingLight = diffuseColor.rgb; + #include + #include + #include + #include + #include +}`,kg=`#include +#include +#include +#include +#include +#include +#include +void main() { + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include + #include +}`,Vg=`uniform vec3 color; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +void main() { + #include + gl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) ); + #include + #include + #include + #include +}`,Hg=`uniform float rotation; +uniform vec2 center; +#include +#include +#include +#include +#include +void main() { + #include + vec4 mvPosition = modelViewMatrix[ 3 ]; + vec2 scale = vec2( length( modelMatrix[ 0 ].xyz ), length( modelMatrix[ 1 ].xyz ) ); + #ifndef USE_SIZEATTENUATION + bool isPerspective = isPerspectiveMatrix( projectionMatrix ); + if ( isPerspective ) scale *= - mvPosition.z; + #endif + vec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale; + vec2 rotatedPosition; + rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y; + rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y; + mvPosition.xy += rotatedPosition; + gl_Position = projectionMatrix * mvPosition; + #include + #include + #include +}`,Gg=`uniform vec3 diffuse; +uniform float opacity; +#include +#include +#include +#include +#include +#include +#include +#include +#include +void main() { + vec4 diffuseColor = vec4( diffuse, opacity ); + #include + vec3 outgoingLight = vec3( 0.0 ); + #include + #include + #include + #include + #include + outgoingLight = diffuseColor.rgb; + #include + #include + #include + #include +}`,et={alphahash_fragment:hp,alphahash_pars_fragment:up,alphamap_fragment:dp,alphamap_pars_fragment:fp,alphatest_fragment:pp,alphatest_pars_fragment:mp,aomap_fragment:gp,aomap_pars_fragment:_p,batching_pars_vertex:xp,batching_vertex:vp,begin_vertex:yp,beginnormal_vertex:Mp,bsdfs:Sp,iridescence_fragment:bp,bumpmap_pars_fragment:Ep,clipping_planes_fragment:Tp,clipping_planes_pars_fragment:wp,clipping_planes_pars_vertex:Ap,clipping_planes_vertex:Rp,color_fragment:Cp,color_pars_fragment:Pp,color_pars_vertex:Ip,color_vertex:Lp,common:Dp,cube_uv_reflection_fragment:Np,defaultnormal_vertex:Up,displacementmap_pars_vertex:Fp,displacementmap_vertex:Op,emissivemap_fragment:Bp,emissivemap_pars_fragment:zp,colorspace_fragment:kp,colorspace_pars_fragment:Vp,envmap_fragment:Hp,envmap_common_pars_fragment:Gp,envmap_pars_fragment:Wp,envmap_pars_vertex:Xp,envmap_physical_pars_fragment:nm,envmap_vertex:qp,fog_vertex:Yp,fog_pars_vertex:Zp,fog_fragment:Jp,fog_pars_fragment:$p,gradientmap_pars_fragment:Kp,lightmap_pars_fragment:Qp,lights_lambert_fragment:jp,lights_lambert_pars_fragment:em,lights_pars_begin:tm,lights_toon_fragment:im,lights_toon_pars_fragment:sm,lights_phong_fragment:rm,lights_phong_pars_fragment:am,lights_physical_fragment:om,lights_physical_pars_fragment:lm,lights_fragment_begin:cm,lights_fragment_maps:hm,lights_fragment_end:um,lightprobes_pars_fragment:dm,logdepthbuf_fragment:fm,logdepthbuf_pars_fragment:pm,logdepthbuf_pars_vertex:mm,logdepthbuf_vertex:gm,map_fragment:_m,map_pars_fragment:xm,map_particle_fragment:vm,map_particle_pars_fragment:ym,metalnessmap_fragment:Mm,metalnessmap_pars_fragment:Sm,morphinstance_vertex:bm,morphcolor_vertex:Em,morphnormal_vertex:Tm,morphtarget_pars_vertex:wm,morphtarget_vertex:Am,normal_fragment_begin:Rm,normal_fragment_maps:Cm,normal_pars_fragment:Pm,normal_pars_vertex:Im,normal_vertex:Lm,normalmap_pars_fragment:Dm,clearcoat_normal_fragment_begin:Nm,clearcoat_normal_fragment_maps:Um,clearcoat_pars_fragment:Fm,iridescence_pars_fragment:Om,opaque_fragment:Bm,packing:zm,premultiplied_alpha_fragment:km,project_vertex:Vm,dithering_fragment:Hm,dithering_pars_fragment:Gm,roughnessmap_fragment:Wm,roughnessmap_pars_fragment:Xm,shadowmap_pars_fragment:qm,shadowmap_pars_vertex:Ym,shadowmap_vertex:Zm,shadowmask_pars_fragment:Jm,skinbase_vertex:$m,skinning_pars_vertex:Km,skinning_vertex:Qm,skinnormal_vertex:jm,specularmap_fragment:eg,specularmap_pars_fragment:tg,tonemapping_fragment:ng,tonemapping_pars_fragment:ig,transmission_fragment:sg,transmission_pars_fragment:rg,uv_pars_fragment:ag,uv_pars_vertex:og,uv_vertex:lg,worldpos_vertex:cg,background_vert:hg,background_frag:ug,backgroundCube_vert:dg,backgroundCube_frag:fg,cube_vert:pg,cube_frag:mg,depth_vert:gg,depth_frag:_g,distance_vert:xg,distance_frag:vg,equirect_vert:yg,equirect_frag:Mg,linedashed_vert:Sg,linedashed_frag:bg,meshbasic_vert:Eg,meshbasic_frag:Tg,meshlambert_vert:wg,meshlambert_frag:Ag,meshmatcap_vert:Rg,meshmatcap_frag:Cg,meshnormal_vert:Pg,meshnormal_frag:Ig,meshphong_vert:Lg,meshphong_frag:Dg,meshphysical_vert:Ng,meshphysical_frag:Ug,meshtoon_vert:Fg,meshtoon_frag:Og,points_vert:Bg,points_frag:zg,shadow_vert:kg,shadow_frag:Vg,sprite_vert:Hg,sprite_frag:Gg},be={common:{diffuse:{value:new Xe(16777215)},opacity:{value:1},map:{value:null},mapTransform:{value:new Je},alphaMap:{value:null},alphaMapTransform:{value:new Je},alphaTest:{value:0}},specularmap:{specularMap:{value:null},specularMapTransform:{value:new Je}},envmap:{envMap:{value:null},envMapRotation:{value:new Je},reflectivity:{value:1},ior:{value:1.5},refractionRatio:{value:.98},dfgLUT:{value:null}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1},aoMapTransform:{value:new Je}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1},lightMapTransform:{value:new Je}},bumpmap:{bumpMap:{value:null},bumpMapTransform:{value:new Je},bumpScale:{value:1}},normalmap:{normalMap:{value:null},normalMapTransform:{value:new Je},normalScale:{value:new ue(1,1)}},displacementmap:{displacementMap:{value:null},displacementMapTransform:{value:new Je},displacementScale:{value:1},displacementBias:{value:0}},emissivemap:{emissiveMap:{value:null},emissiveMapTransform:{value:new Je}},metalnessmap:{metalnessMap:{value:null},metalnessMapTransform:{value:new Je}},roughnessmap:{roughnessMap:{value:null},roughnessMapTransform:{value:new Je}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:25e-5},fogNear:{value:1},fogFar:{value:2e3},fogColor:{value:new Xe(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},sunLights:{value:[],properties:{direction:{},color:{}}},sunLightShadows:{value:[],properties:{shadowIntensity:1,shadowBias:{},shadowNormalBias:{},shadowRadius:{},shadowMapSize:{}}},sunShadowMatrix:{value:[]},sunShadowCascade:{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 I},probesMax:{value:new I},probesResolution:{value:new I}},points:{diffuse:{value:new Xe(16777215)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},alphaMapTransform:{value:new Je},alphaTest:{value:0},uvTransform:{value:new Je}},sprite:{diffuse:{value:new Xe(16777215)},opacity:{value:1},center:{value:new ue(.5,.5)},rotation:{value:0},map:{value:null},mapTransform:{value:new Je},alphaMap:{value:null},alphaMapTransform:{value:new Je},alphaTest:{value:0}}},Vn={basic:{uniforms:Zt([be.common,be.specularmap,be.envmap,be.aomap,be.lightmap,be.fog]),vertexShader:et.meshbasic_vert,fragmentShader:et.meshbasic_frag},lambert:{uniforms:Zt([be.common,be.specularmap,be.envmap,be.aomap,be.lightmap,be.emissivemap,be.bumpmap,be.normalmap,be.displacementmap,be.fog,be.lights,{emissive:{value:new Xe(0)},envMapIntensity:{value:1}}]),vertexShader:et.meshlambert_vert,fragmentShader:et.meshlambert_frag},phong:{uniforms:Zt([be.common,be.specularmap,be.envmap,be.aomap,be.lightmap,be.emissivemap,be.bumpmap,be.normalmap,be.displacementmap,be.fog,be.lights,{emissive:{value:new Xe(0)},specular:{value:new Xe(1118481)},shininess:{value:30},envMapIntensity:{value:1}}]),vertexShader:et.meshphong_vert,fragmentShader:et.meshphong_frag},standard:{uniforms:Zt([be.common,be.envmap,be.aomap,be.lightmap,be.emissivemap,be.bumpmap,be.normalmap,be.displacementmap,be.roughnessmap,be.metalnessmap,be.fog,be.lights,{emissive:{value:new Xe(0)},roughness:{value:1},metalness:{value:0},envMapIntensity:{value:1}}]),vertexShader:et.meshphysical_vert,fragmentShader:et.meshphysical_frag},toon:{uniforms:Zt([be.common,be.aomap,be.lightmap,be.emissivemap,be.bumpmap,be.normalmap,be.displacementmap,be.gradientmap,be.fog,be.lights,{emissive:{value:new Xe(0)}}]),vertexShader:et.meshtoon_vert,fragmentShader:et.meshtoon_frag},matcap:{uniforms:Zt([be.common,be.bumpmap,be.normalmap,be.displacementmap,be.fog,{matcap:{value:null}}]),vertexShader:et.meshmatcap_vert,fragmentShader:et.meshmatcap_frag},points:{uniforms:Zt([be.points,be.fog]),vertexShader:et.points_vert,fragmentShader:et.points_frag},dashed:{uniforms:Zt([be.common,be.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:et.linedashed_vert,fragmentShader:et.linedashed_frag},depth:{uniforms:Zt([be.common,be.displacementmap]),vertexShader:et.depth_vert,fragmentShader:et.depth_frag},normal:{uniforms:Zt([be.common,be.bumpmap,be.normalmap,be.displacementmap,{opacity:{value:1}}]),vertexShader:et.meshnormal_vert,fragmentShader:et.meshnormal_frag},sprite:{uniforms:Zt([be.sprite,be.fog]),vertexShader:et.sprite_vert,fragmentShader:et.sprite_frag},background:{uniforms:{uvTransform:{value:new Je},t2D:{value:null},backgroundIntensity:{value:1}},vertexShader:et.background_vert,fragmentShader:et.background_frag},backgroundCube:{uniforms:{envMap:{value:null},backgroundBlurriness:{value:0},backgroundIntensity:{value:1},backgroundRotation:{value:new Je}},vertexShader:et.backgroundCube_vert,fragmentShader:et.backgroundCube_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:et.cube_vert,fragmentShader:et.cube_frag},equirect:{uniforms:{tEquirect:{value:null}},vertexShader:et.equirect_vert,fragmentShader:et.equirect_frag},distance:{uniforms:Zt([be.common,be.displacementmap,{referencePosition:{value:new I},nearDistance:{value:1},farDistance:{value:1e3}}]),vertexShader:et.distance_vert,fragmentShader:et.distance_frag},shadow:{uniforms:Zt([be.lights,be.fog,{color:{value:new Xe(0)},opacity:{value:1}}]),vertexShader:et.shadow_vert,fragmentShader:et.shadow_frag}};Vn.physical={uniforms:Zt([Vn.standard.uniforms,{clearcoat:{value:0},clearcoatMap:{value:null},clearcoatMapTransform:{value:new Je},clearcoatNormalMap:{value:null},clearcoatNormalMapTransform:{value:new Je},clearcoatNormalScale:{value:new ue(1,1)},clearcoatRoughness:{value:0},clearcoatRoughnessMap:{value:null},clearcoatRoughnessMapTransform:{value:new Je},dispersion:{value:0},retroreflectivity:{value:0},iridescence:{value:0},iridescenceMap:{value:null},iridescenceMapTransform:{value:new Je},iridescenceIOR:{value:1.3},iridescenceThicknessMinimum:{value:100},iridescenceThicknessMaximum:{value:400},iridescenceThicknessMap:{value:null},iridescenceThicknessMapTransform:{value:new Je},sheen:{value:0},sheenColor:{value:new Xe(0)},sheenColorMap:{value:null},sheenColorMapTransform:{value:new Je},sheenRoughness:{value:1},sheenRoughnessMap:{value:null},sheenRoughnessMapTransform:{value:new Je},transmission:{value:0},transmissionMap:{value:null},transmissionMapTransform:{value:new Je},transmissionSamplerSize:{value:new ue},transmissionSamplerMap:{value:null},thickness:{value:0},thicknessMap:{value:null},thicknessMapTransform:{value:new Je},attenuationDistance:{value:0},attenuationColor:{value:new Xe(0)},specularColor:{value:new Xe(1,1,1)},specularColorMap:{value:null},specularColorMapTransform:{value:new Je},specularIntensity:{value:1},specularIntensityMap:{value:null},specularIntensityMapTransform:{value:new Je},anisotropyVector:{value:new ue},anisotropyMap:{value:null},anisotropyMapTransform:{value:new Je}}]),vertexShader:et.meshphysical_vert,fragmentShader:et.meshphysical_frag};var Zo={r:0,b:0,g:0},Wg=new gt,Yu=new Je;Yu.set(-1,0,0,0,1,0,0,0,1);function Xg(i,e,t,n,s,r){let a=new Xe(0),o=s===!0?0:1,l,c,h=null,u=0,d=null;function f(T){let w=T.isScene===!0?T.background:null;if(w&&w.isTexture){let M=T.backgroundBlurriness>0;w=e.get(w,M)}return w}function m(T){let w=!1,M=f(T);M===null?g(a,o):M&&M.isColor&&(g(M,1),w=!0);let b=i.xr.getEnvironmentBlendMode();b==="additive"?t.buffers.color.setClear(0,0,0,1,r):b==="alpha-blend"&&t.buffers.color.setClear(0,0,0,0,r),(i.autoClear||w)&&(t.buffers.depth.setTest(!0),t.buffers.depth.setMask(!0),t.buffers.color.setMask(!0),i.clear(i.autoClearColor,i.autoClearDepth,i.autoClearStencil))}function v(T,w){let M=f(w);M&&(M.isCubeTexture||M.mapping===Rr)?(c===void 0&&(c=new $e(new On(1,1,1),new an({name:"BackgroundCubeMaterial",uniforms:Ni(Vn.backgroundCube.uniforms),vertexShader:Vn.backgroundCube.vertexShader,fragmentShader:Vn.backgroundCube.fragmentShader,side:It,depthTest:!1,depthWrite:!1,fog:!1,allowOverride:!1})),c.geometry.deleteAttribute("normal"),c.geometry.deleteAttribute("uv"),c.onBeforeRender=function(b,S,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=w.backgroundBlurriness,c.material.uniforms.backgroundIntensity.value=w.backgroundIntensity,c.material.uniforms.backgroundRotation.value.setFromMatrix4(Wg.makeRotationFromEuler(w.backgroundRotation)).transpose(),M.isCubeTexture&&M.isRenderTargetTexture===!1&&c.material.uniforms.backgroundRotation.value.premultiply(Yu),c.material.toneMapped=rt.getTransfer(M.colorSpace)!==ht,(h!==M||u!==M.version||d!==i.toneMapping)&&(c.material.needsUpdate=!0,h=M,u=M.version,d=i.toneMapping),c.layers.enableAll(),T.unshift(c,c.geometry,c.material,0,0,null)):M&&M.isTexture&&(l===void 0&&(l=new $e(new Et(2,2),new an({name:"BackgroundMaterial",uniforms:Ni(Vn.background.uniforms),vertexShader:Vn.background.vertexShader,fragmentShader:Vn.background.fragmentShader,side:ln,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=w.backgroundIntensity,l.material.toneMapped=rt.getTransfer(M.colorSpace)!==ht,M.matrixAutoUpdate===!0&&M.updateMatrix(),l.material.uniforms.uvTransform.value.copy(M.matrix),(h!==M||u!==M.version||d!==i.toneMapping)&&(l.material.needsUpdate=!0,h=M,u=M.version,d=i.toneMapping),l.layers.enableAll(),T.unshift(l,l.geometry,l.material,0,0,null))}function g(T,w){T.getRGB(Zo,pc(i)),t.buffers.color.setClear(Zo.r,Zo.g,Zo.b,w,r)}function p(){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(T,w=1){a.set(T),o=w,g(a,o)},getClearAlpha:function(){return o},setClearAlpha:function(T){o=T,g(a,o)},render:m,addToRenderList:v,dispose:p}}function qg(i,e){let t=i.getParameter(i.MAX_VERTEX_ATTRIBS),n={},s=d(null),r=s,a=!1;function o(P,B,V,N,k){let $=!1,q=u(P,N,V,B);r!==q&&(r=q,c(r.object)),$=f(P,N,V,k),$&&m(P,N,V,k),k!==null&&e.update(k,i.ELEMENT_ARRAY_BUFFER),($||a)&&(a=!1,M(P,B,V,N),k!==null&&i.bindBuffer(i.ELEMENT_ARRAY_BUFFER,e.get(k).buffer))}function l(){return i.createVertexArray()}function c(P){return i.bindVertexArray(P)}function h(P){return i.deleteVertexArray(P)}function u(P,B,V,N){let k=N.wireframe===!0,$=n[B.id];$===void 0&&($={},n[B.id]=$);let q=P.isInstancedMesh===!0?P.id:0,Y=$[q];Y===void 0&&(Y={},$[q]=Y);let F=Y[V.id];F===void 0&&(F={},Y[V.id]=F);let z=F[k];return z===void 0&&(z=d(l()),F[k]=z),z}function d(P){let B=[],V=[],N=[];for(let k=0;k=0){let Z=k[F],fe=$[F];if(fe===void 0&&(F==="instanceMatrix"&&P.instanceMatrix&&(fe=P.instanceMatrix),F==="instanceColor"&&P.instanceColor&&(fe=P.instanceColor)),Z===void 0||Z.attribute!==fe||fe&&Z.data!==fe.data)return!0;q++}return r.attributesNum!==q||r.index!==N}function m(P,B,V,N){let k={},$=B.attributes,q=0,Y=V.getAttributes();for(let F in Y)if(Y[F].location>=0){let Z=$[F];Z===void 0&&(F==="instanceMatrix"&&P.instanceMatrix&&(Z=P.instanceMatrix),F==="instanceColor"&&P.instanceColor&&(Z=P.instanceColor));let fe={};fe.attribute=Z,Z&&Z.data&&(fe.data=Z.data),k[F]=fe,q++}r.attributes=k,r.attributesNum=q,r.index=N}function v(){let P=r.newAttributes;for(let B=0,V=P.length;B=0){let z=k[Y];if(z===void 0&&(Y==="instanceMatrix"&&P.instanceMatrix&&(z=P.instanceMatrix),Y==="instanceColor"&&P.instanceColor&&(z=P.instanceColor)),z!==void 0){let Z=z.normalized,fe=z.itemSize,he=e.get(z);if(he===void 0)continue;let qe=he.buffer,Ve=he.type,Ye=he.bytesPerElement,K=Ve===i.INT||Ve===i.UNSIGNED_INT||z.gpuType===lo;if(z.isInterleavedBufferAttribute){let ne=z.data,pe=ne.stride,De=z.offset;if(ne.isInstancedInterleavedBuffer){for(let me=0;me0&&i.getShaderPrecisionFormat(i.FRAGMENT_SHADER,i.HIGH_FLOAT).precision>0)return"highp";R="mediump"}return R==="mediump"&&i.getShaderPrecisionFormat(i.VERTEX_SHADER,i.MEDIUM_FLOAT).precision>0&&i.getShaderPrecisionFormat(i.FRAGMENT_SHADER,i.MEDIUM_FLOAT).precision>0?"mediump":"lowp"}let c=t.precision!==void 0?t.precision:"highp",h=l(c);h!==c&&(Ge("WebGLRenderer:",c,"not supported, using",h,"instead."),c=h);let u=t.logarithmicDepthBuffer===!0,d=t.reversedDepthBuffer===!0&&e.has("EXT_clip_control");t.reversedDepthBuffer===!0&&d===!1&&Ge("WebGLRenderer: Unable to use reversed depth buffer due to missing EXT_clip_control extension. Fallback to default depth buffer.");let f=i.getParameter(i.MAX_TEXTURE_IMAGE_UNITS),m=i.getParameter(i.MAX_VERTEX_TEXTURE_IMAGE_UNITS),v=i.getParameter(i.MAX_TEXTURE_SIZE),g=i.getParameter(i.MAX_CUBE_MAP_TEXTURE_SIZE),p=i.getParameter(i.MAX_VERTEX_ATTRIBS),T=i.getParameter(i.MAX_VERTEX_UNIFORM_VECTORS),w=i.getParameter(i.MAX_VARYING_VECTORS),M=i.getParameter(i.MAX_FRAGMENT_UNIFORM_VECTORS),b=i.getParameter(i.MAX_SAMPLES),S=i.getParameter(i.SAMPLES);return{isWebGL2:!0,getMaxAnisotropy:r,getMaxPrecision:l,textureFormatReadable:a,textureTypeReadable:o,precision:c,logarithmicDepthBuffer:u,reversedDepthBuffer:d,maxTextures:f,maxVertexTextures:m,maxTextureSize:v,maxCubemapSize:g,maxAttributes:p,maxVertexUniforms:T,maxVaryings:w,maxFragmentUniforms:M,maxSamples:b,samples:S}}function Jg(i){let e=this,t=null,n=0,s=!1,r=!1,a=new vn,o=new Je,l={value:null,needsUpdate:!1};this.uniform=l,this.numPlanes=0,this.numIntersection=0,this.init=function(u,d){let f=u.length!==0||d||n!==0||s;return s=d,n=u.length,f},this.beginShadows=function(){r=!0,h(null)},this.endShadows=function(){r=!1},this.setGlobalState=function(u,d){t=h(u,d,0)},this.setState=function(u,d,f){let m=u.clippingPlanes,v=u.clipIntersection,g=u.clipShadows,p=i.get(u);if(!s||m===null||m.length===0||r&&!g)r?h(null):c();else{let T=r?0:n,w=T*4,M=p.clippingState||null;l.value=M,M=h(m,d,w,f);for(let b=0;b!==w;++b)M[b]=t[b];p.clippingState=M,this.numIntersection=v?this.numPlanes:0,this.numPlanes+=T}};function c(){l.value!==t&&(l.value=t,l.needsUpdate=n>0),e.numPlanes=n,e.numIntersection=0}function h(u,d,f,m){let v=u!==null?u.length:0,g=null;if(v!==0){if(g=l.value,m!==!0||g===null){let p=f+v*4,T=d.matrixWorldInverse;o.getNormalMatrix(T),(g===null||g.length0&&this._blur(l,0,0,t),this._applyPMREM(l),this._cleanup(l),l}fromEquirectangular(e,t=null){return this._fromTexture(e,t)}fromCubemap(e,t=null){return this._fromTexture(e,t)}compileCubemapShader(){this._cubemapMaterial===null&&(this._cubemapMaterial=Ru(),this._compileMaterial(this._cubemapMaterial))}compileEquirectangularShader(){this._equirectMaterial===null&&(this._equirectMaterial=Au(),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(e){this._lodMax=Math.floor(Math.log2(e)),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 e=0;e2?b:0,b,b),u.setRenderTarget(s),p&&u.render(v,l),u.render(e,l)}u.toneMapping=f,u.autoClear=d,e.background=T}_textureToCubeUV(e,t){let n=this._renderer,s=e.mapping===xi||e.mapping===Di;s?(this._cubemapMaterial===null&&(this._cubemapMaterial=Ru()),this._cubemapMaterial.uniforms.flipEnvMap.value=e.isRenderTargetTexture===!1?-1:1):this._equirectMaterial===null&&(this._equirectMaterial=Au());let r=s?this._cubemapMaterial:this._equirectMaterial,a=this._lodMeshes[0];a.material=r;let o=r.uniforms;o.envMap.value=e;let l=this._cubeSize;Ps(t,0,0,3*l,2*l),n.setRenderTarget(t),n.render(a,Or)}_applyPMREM(e){let t=this._renderer,n=t.autoClear;t.autoClear=!1;let s=this._lodMeshes.length;for(let r=1;rm-Is?n-m+Is:0),p=4*(this._cubeSize-v);l.envMap.value=e.texture,l.roughness.value=f,l.mipInt.value=m-t,Ps(r,g,p,3*v,2*v),s.setRenderTarget(r),s.render(o,Or),l.envMap.value=r.texture,l.roughness.value=0,l.mipInt.value=m-n,Ps(e,g,p,3*v,2*v),s.setRenderTarget(e),s.render(o,Or)}_blur(e,t,n,s){let r=this._pingPongRenderTarget,a=Math.min(s,Math.PI)/Math.SQRT2;this._blurPass(e,r,t,n,a),this._blurPass(r,e,n,n,a)}_blurPass(e,t,n,s,r){let a=this._renderer,o=this._blurMaterial,l=this._lodMeshes[s];l.material=o;let c=o.uniforms;c.envMap.value=e.texture,c.sigma.value=r,c.mipInt.value=this._lodMax-n;let h=this._sizeLods[s],u=3*h*(s>this._lodMax-Is?s-this._lodMax+Is:0),d=4*(this._cubeSize-h);Ps(t,u,d,3*h,2*h),a.setRenderTarget(t),a.render(l,Or)}};function e0(i){let e=[],t=[],n=i,s=i-Is+1+$g;for(let r=0;r2?0:-1,M=[T,w,0,T+2/3,w,0,T+2/3,w+1,0,T,w,0,T+2/3,w+1,0,T,w+1,0];m.set(M,f*d*p);for(let b=0;bIs&&n--}return{lodMeshes:t,sizeLods:e}}function wu(i,e,t){let n=new en(i,e,t);return n.texture.mapping=Rr,n.texture.name="PMREM.cubeUv",n.scissorTest=!0,n}function Ps(i,e,t,n,s){i.viewport.set(e,t,n,s),i.scissor.set(e,t,n,s)}function t0(i,e,t){return new an({name:"PMREMGGXConvolution",defines:{GGX_SAMPLES:Qg,CUBEUV_TEXEL_WIDTH:1/e,CUBEUV_TEXEL_HEIGHT:1/t,CUBEUV_MAX_MIP:`${i}.0`},uniforms:{envMap:{value:null},roughness:{value:0},mipInt:{value:0}},vertexShader:Qo(),fragmentShader:` + + precision highp float; + precision highp int; + + varying vec3 vOutputDirection; + + uniform sampler2D envMap; + uniform float roughness; + uniform float mipInt; + + #define ENVMAP_TYPE_CUBE_UV + #include + + #define PI 3.14159265359 + + // Van der Corput radical inverse + float radicalInverse_VdC(uint bits) { + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return float(bits) * 2.3283064365386963e-10; // / 0x100000000 + } + + // Hammersley sequence + vec2 hammersley(uint i, uint N) { + return vec2(float(i) / float(N), radicalInverse_VdC(i)); + } + + // GGX VNDF importance sampling (Eric Heitz 2018) + // "Sampling the GGX Distribution of Visible Normals" + // https://jcgt.org/published/0007/04/01/ + vec3 importanceSampleGGX_VNDF(vec2 Xi, vec3 V, float roughness) { + float alpha = roughness * roughness; + + // Section 4.1: Orthonormal basis + vec3 T1 = vec3(1.0, 0.0, 0.0); + vec3 T2 = cross(V, T1); + + // Section 4.2: Parameterization of projected area + float r = sqrt(Xi.x); + float phi = 2.0 * PI * Xi.y; + float t1 = r * cos(phi); + float t2 = r * sin(phi); + float s = 0.5 * (1.0 + V.z); + t2 = (1.0 - s) * sqrt(1.0 - t1 * t1) + s * t2; + + // Section 4.3: Reprojection onto hemisphere + vec3 Nh = t1 * T1 + t2 * T2 + sqrt(max(0.0, 1.0 - t1 * t1 - t2 * t2)) * V; + + // Section 3.4: Transform back to ellipsoid configuration + return normalize(vec3(alpha * Nh.x, alpha * Nh.y, max(0.0, Nh.z))); + } + + void main() { + vec3 N = normalize(vOutputDirection); + vec3 V = N; // Assume view direction equals normal for pre-filtering + + vec3 prefilteredColor = vec3(0.0); + float totalWeight = 0.0; + + // For very low roughness, just sample the environment directly + if (roughness < 0.001) { + gl_FragColor = vec4(bilinearCubeUV(envMap, N, mipInt), 1.0); + return; + } + + // Tangent space basis for VNDF sampling + vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 tangent = normalize(cross(up, N)); + vec3 bitangent = cross(N, tangent); + + for(uint i = 0u; i < uint(GGX_SAMPLES); i++) { + vec2 Xi = hammersley(i, uint(GGX_SAMPLES)); + + // For PMREM, V = N, so in tangent space V is always (0, 0, 1) + vec3 H_tangent = importanceSampleGGX_VNDF(Xi, vec3(0.0, 0.0, 1.0), roughness); + + // Transform H back to world space + vec3 H = normalize(tangent * H_tangent.x + bitangent * H_tangent.y + N * H_tangent.z); + vec3 L = normalize(2.0 * dot(V, H) * H - V); + + float NdotL = max(dot(N, L), 0.0); + + if(NdotL > 0.0) { + // Sample environment at fixed mip level + // VNDF importance sampling handles the distribution filtering + vec3 sampleColor = bilinearCubeUV(envMap, L, mipInt); + + // Weight by NdotL for the split-sum approximation + // VNDF PDF naturally accounts for the visible microfacet distribution + prefilteredColor += sampleColor * NdotL; + totalWeight += NdotL; + } + } + + if (totalWeight > 0.0) { + prefilteredColor = prefilteredColor / totalWeight; + } + + gl_FragColor = vec4(prefilteredColor, 1.0); + } + `,blending:Bn,depthTest:!1,depthWrite:!1})}function n0(i,e,t){return new an({name:"SphericalGaussianBlur",defines:{SAMPLES:Kg,CUBEUV_TEXEL_WIDTH:1/e,CUBEUV_TEXEL_HEIGHT:1/t,CUBEUV_MAX_MIP:`${i}.0`},uniforms:{envMap:{value:null},sigma:{value:0},mipInt:{value:0}},vertexShader:Qo(),fragmentShader:` + + precision highp float; + precision highp int; + + varying vec3 vOutputDirection; + + uniform sampler2D envMap; + uniform float sigma; + uniform float mipInt; + + #define ENVMAP_TYPE_CUBE_UV + #include + + #define PI 3.14159265359 + #define GOLDEN_ANGLE 2.39996322973 + + void main() { + + if ( sigma == 0.0 ) { + + gl_FragColor = vec4( bilinearCubeUV( envMap, vOutputDirection, mipInt ), 1.0 ); + return; + + } + + vec3 outputDirection = normalize( vOutputDirection ); + + vec3 up = abs( outputDirection.z ) < 0.999 ? vec3( 0.0, 0.0, 1.0 ) : vec3( 1.0, 0.0, 0.0 ); + vec3 tangent = normalize( cross( up, outputDirection ) ); + vec3 bitangent = cross( outputDirection, tangent ); + + // Truncate the kernel at three standard deviations or at the antipode. + float thetaMax = min( 3.0 * sigma, PI ); + float truncation = 1.0 - exp( - 0.5 * thetaMax * thetaMax / ( sigma * sigma ) ); + + vec3 accumColor = vec3( 0.0 ); + float accumWeight = 0.0; + + for ( int i = 0; i < SAMPLES; i ++ ) { + + // Stratified inverse-CDF sampling of the Gaussian, placed on a golden-angle spiral. + float stratum = ( float( i ) + 0.5 ) / float( SAMPLES ); + float theta = sigma * sqrt( - 2.0 * log( 1.0 - stratum * truncation ) ); + float phi = float( i ) * GOLDEN_ANGLE; + + vec3 offset = cos( phi ) * tangent + sin( phi ) * bitangent; + vec3 sampleDirection = cos( theta ) * outputDirection + sin( theta ) * offset; + + // Correct the planar sample density to solid angle. + float weight = sin( theta ) / theta; + + accumColor += weight * bilinearCubeUV( envMap, sampleDirection, mipInt ); + accumWeight += weight; + + } + + gl_FragColor = vec4( accumColor / accumWeight, 1.0 ); + + } + `,blending:Bn,depthTest:!1,depthWrite:!1})}function Au(){return new an({name:"EquirectangularToCubeUV",uniforms:{envMap:{value:null}},vertexShader:Qo(),fragmentShader:` + + precision mediump float; + precision mediump int; + + varying vec3 vOutputDirection; + + uniform sampler2D envMap; + + #include + + void main() { + + vec3 outputDirection = normalize( vOutputDirection ); + vec2 uv = equirectUv( outputDirection ); + + gl_FragColor = vec4( texture2D ( envMap, uv ).rgb, 1.0 ); + + } + `,blending:Bn,depthTest:!1,depthWrite:!1})}function Ru(){return new an({name:"CubemapToCubeUV",uniforms:{envMap:{value:null},flipEnvMap:{value:-1}},vertexShader:Qo(),fragmentShader:` + + precision mediump float; + precision mediump int; + + uniform float flipEnvMap; + + varying vec3 vOutputDirection; + + uniform samplerCube envMap; + + void main() { + + gl_FragColor = textureCube( envMap, vec3( flipEnvMap * vOutputDirection.x, vOutputDirection.yz ) ); + + } + `,blending:Bn,depthTest:!1,depthWrite:!1})}function Qo(){return` + + precision mediump float; + precision mediump int; + + attribute vec3 outputDirection; + + varying vec3 vOutputDirection; + + void main() { + + vOutputDirection = outputDirection; + gl_Position = vec4( position, 1.0 ); + + } + `}var $o=class extends en{constructor(e=1,t={}){super(e,e,t),this.isWebGLCubeRenderTarget=!0;let n={width:e,height:e,depth:1},s=[n,n,n,n,n,n];this.texture=new or(s),this._setTextureOptions(t),this.texture.isRenderTargetTexture=!0}fromEquirectangularTexture(e,t){this.texture.type=t.type,this.texture.colorSpace=t.colorSpace,this.texture.generateMipmaps=t.generateMipmaps,this.texture.minFilter=t.minFilter,this.texture.magFilter=t.magFilter;let n={uniforms:{tEquirect:{value:null}},vertexShader:` + + varying vec3 vWorldDirection; + + vec3 transformDirection( in vec3 dir, in mat4 matrix ) { + + return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); + + } + + void main() { + + vWorldDirection = transformDirection( position, modelMatrix ); + + #include + #include + + } + `,fragmentShader:` + + uniform sampler2D tEquirect; + + varying vec3 vWorldDirection; + + #include + + void main() { + + vec3 direction = normalize( vWorldDirection ); + + vec2 sampleUV = equirectUv( direction ); + + gl_FragColor = texture2D( tEquirect, sampleUV ); + + } + `},s=new On(5,5,5),r=new an({name:"CubemapFromEquirect",uniforms:Ni(n.uniforms),vertexShader:n.vertexShader,fragmentShader:n.fragmentShader,side:It,blending:Bn});r.uniforms.tEquirect.value=t;let a=new $e(s,r),o=t.minFilter;return t.minFilter===zn&&(t.minFilter=zt),new eo(1,10,this).update(e,a),t.minFilter=o,a.geometry.dispose(),a.material.dispose(),this}clear(e,t=!0,n=!0,s=!0){let r=e.getRenderTarget();for(let a=0;a<6;a++)e.setRenderTarget(this,a),e.clear(t,n,s);e.setRenderTarget(r)}};function i0(i){let e=new WeakMap,t=new WeakMap,n=null;function s(d,f=!1){return d==null?null:f?a(d):r(d)}function r(d){if(d&&d.isTexture){let f=d.mapping;if(f===ro||f===ao)if(e.has(d)){let m=e.get(d).texture;return o(m,d.mapping)}else{let m=d.image;if(m&&m.height>0){let v=new $o(m.height);return v.fromEquirectangularTexture(i,d),e.set(d,v),d.addEventListener("dispose",c),o(v.texture,d.mapping)}else return null}}return d}function a(d){if(d&&d.isTexture){let f=d.mapping,m=f===ro||f===ao,v=f===xi||f===Di;if(m||v){let g=t.get(d),p=g!==void 0?g.texture.pmremVersion:0;if(d.isRenderTargetTexture&&d.pmremVersion!==p)return n===null&&(n=new Ds(i)),g=m?n.fromEquirectangular(d,g):n.fromCubemap(d,g),g.texture.pmremVersion=d.pmremVersion,t.set(d,g),g.texture;if(g!==void 0)return g.texture;{let T=d.image;return m&&T&&T.height>0||v&&T&&l(T)?(n===null&&(n=new Ds(i)),g=m?n.fromEquirectangular(d):n.fromCubemap(d),g.texture.pmremVersion=d.pmremVersion,t.set(d,g),d.addEventListener("dispose",h),g.texture):null}}}return d}function o(d,f){return f===ro?d.mapping=xi:f===ao&&(d.mapping=Di),d}function l(d){let f=0,m=6;for(let v=0;v=65535?nr:tr)(d,1);g.version=v;let p=r.get(u);p&&e.remove(p),r.set(u,g)}function h(u){let d=r.get(u);if(d){let f=u.index;f!==null&&d.versione.maxTextureSize&&(b=Math.ceil(M/e.maxTextureSize),M=e.maxTextureSize);let S=new Float32Array(M*b*4*u),R=new js(S,M,b,u);R.type=Tn,R.needsUpdate=!0;let x=w*4;for(let C=0;C + #include + + void main() { + gl_FragColor = texture2D( tDiffuse, vUv ); + + #ifdef LINEAR_TONE_MAPPING + gl_FragColor.rgb = LinearToneMapping( gl_FragColor.rgb ); + #elif defined( REINHARD_TONE_MAPPING ) + gl_FragColor.rgb = ReinhardToneMapping( gl_FragColor.rgb ); + #elif defined( CINEON_TONE_MAPPING ) + gl_FragColor.rgb = CineonToneMapping( gl_FragColor.rgb ); + #elif defined( ACES_FILMIC_TONE_MAPPING ) + gl_FragColor.rgb = ACESFilmicToneMapping( gl_FragColor.rgb ); + #elif defined( AGX_TONE_MAPPING ) + gl_FragColor.rgb = AgXToneMapping( gl_FragColor.rgb ); + #elif defined( NEUTRAL_TONE_MAPPING ) + gl_FragColor.rgb = NeutralToneMapping( gl_FragColor.rgb ); + #elif defined( CUSTOM_TONE_MAPPING ) + gl_FragColor.rgb = CustomToneMapping( gl_FragColor.rgb ); + #endif + + #ifdef SRGB_TRANSFER + gl_FragColor = sRGBTransferOETF( gl_FragColor ); + #endif + }`,depthTest:!1,depthWrite:!1}),u=new $e(c,h),d=new Es(-1,1,1,-1,0,1),f=null,m=null,v=!1,g,p=null,T=[],w=!1;this.setSize=function(M,b){a.setSize(M,b),o!==null&&o.setSize(M,b),l!==null&&l.setSize(M,b);for(let S=0;S0&&T[0].isRenderPass===!0;let b=a.width,S=a.height;T.length>0&&o===null&&(o=new en(b,S,{type:wn,depthBuffer:!1,stencilBuffer:!1}),l=new en(b,S,{type:wn,depthBuffer:!1,stencilBuffer:!1}));for(let R=0;R0)return i;let s=e*t,r=Cu[s];if(r===void 0&&(r=new Float32Array(s),Cu[s]=r),e!==0){n.toArray(r,0);for(let a=1,o=0;a!==e;++a)o+=t,i[a].toArray(r,o)}return r}function Lt(i,e){if(i.length!==e.length)return!1;for(let t=0,n=i.length;t0&&(this.seq=s.concat(r))}setValue(e,t,n,s){let r=this.map[t];r!==void 0&&r.setValue(e,n,s)}setOptional(e,t,n){let s=t[n];s!==void 0&&this.setValue(e,n,s)}static upload(e,t,n,s){for(let r=0,a=t.length;r!==a;++r){let o=t[r],l=n[o.id];l.needsUpdate!==!1&&o.setValue(e,l.value,s)}}static seqWithValue(e,t){let n=[];for(let s=0,r=e.length;s!==r;++s){let a=e[s];a.id in t&&n.push(a)}return n}};function Uu(i,e,t){let n=i.createShader(e);return i.shaderSource(n,t),i.compileShader(n),n}var j0=37297,e_=0;function t_(i,e){let t=i.split(` +`),n=[],s=Math.max(e-6,0),r=Math.min(e+6,t.length);for(let a=s;a":" "} ${o}: ${t[a]}`)}return n.join(` +`)}var Fu=new Je;function n_(i){rt._getMatrix(Fu,rt.workingColorSpace,i);let e=`mat3( ${Fu.elements.map(t=>t.toFixed(4))} )`;switch(rt.getTransfer(i)){case Ks:return[e,"LinearTransferOETF"];case ht:return[e,"sRGBTransferOETF"];default:return Ge("WebGLProgram: Unsupported color space: ",i),[e,"LinearTransferOETF"]}}function Ou(i,e,t){let n=i.getShaderParameter(e,i.COMPILE_STATUS),r=(i.getShaderInfoLog(e)||"").trim();if(n&&r==="")return"";let a=/ERROR: 0:(\d+)/.exec(r);if(a){let o=parseInt(a[1]);return t.toUpperCase()+` + +`+r+` + +`+t_(i.getShaderSource(e),o)}else return r}function i_(i,e){let t=n_(e);return[`vec4 ${i}( vec4 value ) {`,` return ${t[1]}( vec4( value.rgb * ${t[0]}, value.a ) );`,"}"].join(` +`)}var s_={[$l]:"Linear",[Kl]:"Reinhard",[Ql]:"Cineon",[jl]:"ACESFilmic",[tc]:"AgX",[Ar]:"Neutral",[ec]:"Custom"};function r_(i,e){let t=s_[e];return t===void 0?(Ge("WebGLProgram: Unsupported toneMapping:",e),"vec3 "+i+"( vec3 color ) { return LinearToneMapping( color ); }"):"vec3 "+i+"( vec3 color ) { return "+t+"ToneMapping( color ); }"}var Jo=new I;function a_(){rt.getLuminanceCoefficients(Jo);let i=Jo.x.toFixed(4),e=Jo.y.toFixed(4),t=Jo.z.toFixed(4);return["float luminance( const in vec3 rgb ) {",` const vec3 weights = vec3( ${i}, ${e}, ${t} );`," return dot( weights, rgb );","}"].join(` +`)}function o_(i){return[i.extensionClipCullDistance?"#extension GL_ANGLE_clip_cull_distance : require":"",i.extensionMultiDraw?"#extension GL_ANGLE_multi_draw : require":""].filter(zr).join(` +`)}function l_(i){let e=[];for(let t in i){let n=i[t];n!==!1&&e.push("#define "+t+" "+n)}return e.join(` +`)}function c_(i,e){let t={},n=i.getProgramParameter(e,i.ACTIVE_ATTRIBUTES);for(let s=0;s/gm;function Dc(i){return i.replace(h_,d_)}var u_=new Map;function d_(i,e){let t=et[e];if(t===void 0){let n=u_.get(e);if(n!==void 0)t=et[n],Ge('WebGLRenderer: Shader chunk "%s" has been deprecated. Use "%s" instead.',e,n);else throw new Error("THREE.WebGLProgram: Can not resolve #include <"+e+">")}return Dc(t)}var f_=/#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 ku(i){return i.replace(f_,p_)}function p_(i,e,t,n){let s="";for(let r=parseInt(e);r0&&(g+=` +`),p=["#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,m].filter(zr).join(` +`),p.length>0&&(p+=` +`)):(g=[Vu(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,m,t.extensionClipCullDistance?"#define USE_CLIP_DISTANCE":"",t.batching?"#define USE_BATCHING":"",t.batchingColor?"#define USE_BATCHING_COLOR":"",t.instancing?"#define USE_INSTANCING":"",t.instancingColor?"#define USE_INSTANCING_COLOR":"",t.instancingMorph?"#define USE_INSTANCING_MORPH":"",t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.map?"#define USE_MAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+h:"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.displacementMap?"#define USE_DISPLACEMENTMAP":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.mapUv?"#define MAP_UV "+t.mapUv:"",t.alphaMapUv?"#define ALPHAMAP_UV "+t.alphaMapUv:"",t.lightMapUv?"#define LIGHTMAP_UV "+t.lightMapUv:"",t.aoMapUv?"#define AOMAP_UV "+t.aoMapUv:"",t.emissiveMapUv?"#define EMISSIVEMAP_UV "+t.emissiveMapUv:"",t.bumpMapUv?"#define BUMPMAP_UV "+t.bumpMapUv:"",t.normalMapUv?"#define NORMALMAP_UV "+t.normalMapUv:"",t.displacementMapUv?"#define DISPLACEMENTMAP_UV "+t.displacementMapUv:"",t.metalnessMapUv?"#define METALNESSMAP_UV "+t.metalnessMapUv:"",t.roughnessMapUv?"#define ROUGHNESSMAP_UV "+t.roughnessMapUv:"",t.anisotropyMapUv?"#define ANISOTROPYMAP_UV "+t.anisotropyMapUv:"",t.clearcoatMapUv?"#define CLEARCOATMAP_UV "+t.clearcoatMapUv:"",t.clearcoatNormalMapUv?"#define CLEARCOAT_NORMALMAP_UV "+t.clearcoatNormalMapUv:"",t.clearcoatRoughnessMapUv?"#define CLEARCOAT_ROUGHNESSMAP_UV "+t.clearcoatRoughnessMapUv:"",t.iridescenceMapUv?"#define IRIDESCENCEMAP_UV "+t.iridescenceMapUv:"",t.iridescenceThicknessMapUv?"#define IRIDESCENCE_THICKNESSMAP_UV "+t.iridescenceThicknessMapUv:"",t.sheenColorMapUv?"#define SHEEN_COLORMAP_UV "+t.sheenColorMapUv:"",t.sheenRoughnessMapUv?"#define SHEEN_ROUGHNESSMAP_UV "+t.sheenRoughnessMapUv:"",t.specularMapUv?"#define SPECULARMAP_UV "+t.specularMapUv:"",t.specularColorMapUv?"#define SPECULAR_COLORMAP_UV "+t.specularColorMapUv:"",t.specularIntensityMapUv?"#define SPECULAR_INTENSITYMAP_UV "+t.specularIntensityMapUv:"",t.transmissionMapUv?"#define TRANSMISSIONMAP_UV "+t.transmissionMapUv:"",t.thicknessMapUv?"#define THICKNESSMAP_UV "+t.thicknessMapUv:"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexNormals?"#define HAS_NORMAL":"",t.vertexColors?"#define USE_COLOR":"",t.vertexAlphas?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.flatShading?"#define FLAT_SHADED":"",t.skinning?"#define USE_SKINNING":"",t.morphTargets?"#define USE_MORPHTARGETS":"",t.morphNormals&&t.flatShading===!1?"#define USE_MORPHNORMALS":"",t.morphColors?"#define USE_MORPHCOLORS":"",t.morphTargetsCount>0?"#define MORPHTARGETS_TEXTURE_STRIDE "+t.morphTextureStride:"",t.morphTargetsCount>0?"#define MORPHTARGETS_COUNT "+t.morphTargetsCount:"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+l:"",t.sizeAttenuation?"#define USE_SIZEATTENUATION":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.logarithmicDepthBuffer?"#define USE_LOGARITHMIC_DEPTH_BUFFER":"",t.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(zr).join(` +`),p=[Vu(t),"#define SHADER_TYPE "+t.shaderType,"#define SHADER_NAME "+t.shaderName,m,t.useFog&&t.fog?"#define USE_FOG":"",t.useFog&&t.fogExp2?"#define FOG_EXP2":"",t.alphaToCoverage?"#define ALPHA_TO_COVERAGE":"",t.map?"#define USE_MAP":"",t.matcap?"#define USE_MATCAP":"",t.envMap?"#define USE_ENVMAP":"",t.envMap?"#define "+c:"",t.envMap?"#define "+h:"",t.envMap?"#define "+u:"",d?"#define CUBEUV_TEXEL_WIDTH "+d.texelWidth:"",d?"#define CUBEUV_TEXEL_HEIGHT "+d.texelHeight:"",d?"#define CUBEUV_MAX_MIP "+d.maxMip+".0":"",t.lightMap?"#define USE_LIGHTMAP":"",t.aoMap?"#define USE_AOMAP":"",t.bumpMap?"#define USE_BUMPMAP":"",t.normalMap?"#define USE_NORMALMAP":"",t.normalMapObjectSpace?"#define USE_NORMALMAP_OBJECTSPACE":"",t.normalMapTangentSpace?"#define USE_NORMALMAP_TANGENTSPACE":"",t.packedNormalMap?"#define USE_PACKED_NORMALMAP":"",t.emissiveMap?"#define USE_EMISSIVEMAP":"",t.anisotropy?"#define USE_ANISOTROPY":"",t.anisotropyMap?"#define USE_ANISOTROPYMAP":"",t.clearcoat?"#define USE_CLEARCOAT":"",t.clearcoatMap?"#define USE_CLEARCOATMAP":"",t.clearcoatRoughnessMap?"#define USE_CLEARCOAT_ROUGHNESSMAP":"",t.clearcoatNormalMap?"#define USE_CLEARCOAT_NORMALMAP":"",t.dispersion?"#define USE_DISPERSION":"",t.retroreflection?"#define USE_RETROREFLECTION":"",t.iridescence?"#define USE_IRIDESCENCE":"",t.iridescenceMap?"#define USE_IRIDESCENCEMAP":"",t.iridescenceThicknessMap?"#define USE_IRIDESCENCE_THICKNESSMAP":"",t.specularMap?"#define USE_SPECULARMAP":"",t.specularColorMap?"#define USE_SPECULAR_COLORMAP":"",t.specularIntensityMap?"#define USE_SPECULAR_INTENSITYMAP":"",t.roughnessMap?"#define USE_ROUGHNESSMAP":"",t.metalnessMap?"#define USE_METALNESSMAP":"",t.alphaMap?"#define USE_ALPHAMAP":"",t.alphaTest?"#define USE_ALPHATEST":"",t.alphaHash?"#define USE_ALPHAHASH":"",t.sheen?"#define USE_SHEEN":"",t.sheenColorMap?"#define USE_SHEEN_COLORMAP":"",t.sheenRoughnessMap?"#define USE_SHEEN_ROUGHNESSMAP":"",t.transmission?"#define USE_TRANSMISSION":"",t.transmissionMap?"#define USE_TRANSMISSIONMAP":"",t.thicknessMap?"#define USE_THICKNESSMAP":"",t.vertexTangents&&t.flatShading===!1?"#define USE_TANGENT":"",t.vertexColors||t.instancingColor?"#define USE_COLOR":"",t.vertexAlphas||t.batchingColor?"#define USE_COLOR_ALPHA":"",t.vertexUv1s?"#define USE_UV1":"",t.vertexUv2s?"#define USE_UV2":"",t.vertexUv3s?"#define USE_UV3":"",t.pointsUvs?"#define USE_POINTS_UV":"",t.gradientMap?"#define USE_GRADIENTMAP":"",t.flatShading?"#define FLAT_SHADED":"",t.doubleSided?"#define DOUBLE_SIDED":"",t.flipSided?"#define FLIP_SIDED":"",t.shadowMapEnabled?"#define USE_SHADOWMAP":"",t.shadowMapEnabled?"#define "+l:"",t.premultipliedAlpha?"#define PREMULTIPLIED_ALPHA":"",t.numLightProbes>0?"#define USE_LIGHT_PROBES":"",t.numLightProbeGrids>0?"#define USE_LIGHT_PROBES_GRID":"",t.decodeVideoTexture?"#define DECODE_VIDEO_TEXTURE":"",t.decodeVideoTextureEmissive?"#define DECODE_VIDEO_TEXTURE_EMISSIVE":"",t.logarithmicDepthBuffer?"#define USE_LOGARITHMIC_DEPTH_BUFFER":"",t.reversedDepthBuffer?"#define USE_REVERSED_DEPTH_BUFFER":"","uniform mat4 viewMatrix;","uniform vec3 cameraPosition;","uniform bool isOrthographic;",t.toneMapping!==bn?"#define TONE_MAPPING":"",t.toneMapping!==bn?et.tonemapping_pars_fragment:"",t.toneMapping!==bn?r_("toneMapping",t.toneMapping):"",t.dithering?"#define DITHERING":"",t.opaque?"#define OPAQUE":"",et.colorspace_pars_fragment,i_("linearToOutputTexel",t.outputColorSpace),a_(),t.useDepthPacking?"#define DEPTH_PACKING "+t.depthPacking:"",` +`].filter(zr).join(` +`)),a=Dc(a),a=Bu(a,t),a=zu(a,t),o=Dc(o),o=Bu(o,t),o=zu(o,t),a=ku(a),o=ku(o),t.isRawShaderMaterial!==!0&&(T=`#version 300 es +`,g=[f,"#define attribute in","#define varying out","#define texture2D texture"].join(` +`)+` +`+g,p=["#define varying in",t.glslVersion===uc?"":"layout(location = 0) out highp vec4 pc_fragColor;",t.glslVersion===uc?"":"#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(` +`)+` +`+p);let w=T+g+a,M=T+p+o,b=Uu(s,s.VERTEX_SHADER,w),S=Uu(s,s.FRAGMENT_SHADER,M);s.attachShader(v,b),s.attachShader(v,S),t.index0AttributeName!==void 0?s.bindAttribLocation(v,0,t.index0AttributeName):t.hasPositionAttribute===!0&&s.bindAttribLocation(v,0,"position"),s.linkProgram(v);function R(P){if(i.debug.checkShaderErrors){let B=s.getProgramInfoLog(v)||"",V=s.getShaderInfoLog(b)||"",N=s.getShaderInfoLog(S)||"",k=B.trim(),$=V.trim(),q=N.trim(),Y=!0,F=!0;if(s.getProgramParameter(v,s.LINK_STATUS)===!1)if(Y=!1,typeof i.debug.onShaderError=="function")i.debug.onShaderError(s,v,b,S);else{let z=Ou(s,b,"vertex"),Z=Ou(s,S,"fragment");We("WebGLProgram: Shader Error "+s.getError()+" - VALIDATE_STATUS "+s.getProgramParameter(v,s.VALIDATE_STATUS)+` + +Material Name: `+P.name+` +Material Type: `+P.type+` + +Program Info Log: `+k+` +`+z+` +`+Z)}else k!==""?Ge("WebGLProgram: Program Info Log:",k):($===""||q==="")&&(F=!1);F&&(P.diagnostics={runnable:Y,programLog:k,vertexShader:{log:$,prefix:g},fragmentShader:{log:q,prefix:p}})}s.deleteShader(b),s.deleteShader(S),x=new Ls(s,v),E=c_(s,v)}let x;this.getUniforms=function(){return x===void 0&&R(this),x};let E;this.getAttributes=function(){return E===void 0&&R(this),E};let C=t.rendererExtensionParallelShaderCompile===!1;return this.isReady=function(){return C===!1&&(C=s.getProgramParameter(v,j0)),C},this.destroy=function(){n.releaseStatesOfProgram(this),s.deleteProgram(v),this.program=void 0},this.type=t.shaderType,this.name=t.shaderName,this.id=e_++,this.cacheKey=e,this.usedTimes=1,this.program=v,this.vertexShader=b,this.fragmentShader=S,this}var T_=0,Nc=class{constructor(){this.shaderCache=new Map,this.materialCache=new Map}update(e,t,n){let s=this._getShaderCacheForMaterial(e);return s.has(t)===!1&&(s.add(t),t.usedTimes++),s.has(n)===!1&&(s.add(n),n.usedTimes++),this}remove(e){let t=this.materialCache.get(e);for(let n of t)n.usedTimes--,n.usedTimes===0&&this.shaderCache.delete(n.code);return this.materialCache.delete(e),this}getVertexShaderStage(e){return this._getShaderStage(e.vertexShader)}getFragmentShaderStage(e){return this._getShaderStage(e.fragmentShader)}dispose(){this.shaderCache.clear(),this.materialCache.clear()}_getShaderCacheForMaterial(e){let t=this.materialCache,n=t.get(e);return n===void 0&&(n=new Set,t.set(e,n)),n}_getShaderStage(e){let t=this.shaderCache,n=t.get(e);return n===void 0&&(n=new Uc(e),t.set(e,n)),n}},Uc=class{constructor(e){this.id=T_++,this.code=e,this.usedTimes=0}};function w_(i){return i===yi||i===Nr||i===Ur}function A_(i,e,t,n,s,r){let a=new er,o=new Nc,l=new Set,c=[],h=new Map,u=n.logarithmicDepthBuffer,d=n.precision,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 m(x){return l.add(x),x===0?"uv":`uv${x}`}function v(x,E,C,P,B,V){let N=P.fog,k=B.geometry,$=x.isMeshStandardMaterial||x.isMeshLambertMaterial||x.isMeshPhongMaterial?P.environment:null,q=x.isMeshStandardMaterial||x.isMeshLambertMaterial&&!x.envMap||x.isMeshPhongMaterial&&!x.envMap,Y=e.get(x.envMap||$,q),F=Y&&Y.mapping===Rr?Y.image.height:null,z=f[x.type];x.precision!==null&&(d=n.getMaxPrecision(x.precision),d!==x.precision&&Ge("WebGLProgram.getParameters:",x.precision,"not supported, using",d,"instead."));let Z=k.morphAttributes.position||k.morphAttributes.normal||k.morphAttributes.color,fe=Z!==void 0?Z.length:0,he=0;k.morphAttributes.position!==void 0&&(he=1),k.morphAttributes.normal!==void 0&&(he=2),k.morphAttributes.color!==void 0&&(he=3);let qe,Ve,Ye,K;if(z){let lt=Vn[z];qe=lt.vertexShader,Ve=lt.fragmentShader}else{qe=x.vertexShader,Ve=x.fragmentShader;let lt=o.getVertexShaderStage(x),Re=o.getFragmentShaderStage(x);o.update(x,lt,Re),Ye=lt.id,K=Re.id}let ne=i.getRenderTarget(),pe=i.state.buffers.depth.getReversed(),De=B.isInstancedMesh===!0,me=B.isBatchedMesh===!0,Fe=!!x.map,oe=!!x.matcap,H=!!Y,re=!!x.aoMap,le=!!x.lightMap,j=!!x.bumpMap&&x.wireframe===!1,ae=!!x.normalMap,we=!!x.displacementMap,Ae=!!x.emissiveMap,se=!!x.metalnessMap,He=!!x.roughnessMap,L=x.anisotropy>0,st=x.clearcoat>0,Qe=x.dispersion>0,A=x.retroreflectivity>0,_=x.iridescence>0,O=x.sheen>0,X=x.transmission>0,Q=L&&!!x.anisotropyMap,de=st&&!!x.clearcoatMap,ge=st&&!!x.clearcoatNormalMap,ee=st&&!!x.clearcoatRoughnessMap,ie=_&&!!x.iridescenceMap,_e=_&&!!x.iridescenceThicknessMap,Ie=O&&!!x.sheenColorMap,Me=O&&!!x.sheenRoughnessMap,xe=!!x.specularMap,Oe=!!x.specularColorMap,ke=!!x.specularIntensityMap,Ze=X&&!!x.transmissionMap,U=X&&!!x.thicknessMap,ve=!!x.gradientMap,te=!!x.alphaMap,ye=x.alphaTest>0,Se=!!x.alphaHash,ce=!!x.extensions,Be=bn;x.toneMapped&&(ne===null||ne.isXRRenderTarget===!0)&&(Be=i.toneMapping);let Le={shaderID:z,shaderType:x.type,shaderName:x.name,vertexShader:qe,fragmentShader:Ve,defines:x.defines,customVertexShaderID:Ye,customFragmentShaderID:K,isRawShaderMaterial:x.isRawShaderMaterial===!0,glslVersion:x.glslVersion,precision:d,batching:me,batchingColor:me&&B._colorsTexture!==null,instancing:De,instancingColor:De&&B.instanceColor!==null,instancingMorph:De&&B.morphTexture!==null,outputColorSpace:ne===null?i.outputColorSpace:ne.isXRRenderTarget===!0?ne.texture.colorSpace:rt.workingColorSpace,alphaToCoverage:!!x.alphaToCoverage,map:Fe,matcap:oe,envMap:H,envMapMode:H&&Y.mapping,envMapCubeUVHeight:F,aoMap:re,lightMap:le,bumpMap:j,normalMap:ae,displacementMap:we,emissiveMap:Ae,normalMapObjectSpace:ae&&x.normalMapType===su,normalMapTangentSpace:ae&&x.normalMapType===Xo,packedNormalMap:ae&&x.normalMapType===Xo&&w_(x.normalMap.format),metalnessMap:se,roughnessMap:He,anisotropy:L,anisotropyMap:Q,clearcoat:st,clearcoatMap:de,clearcoatNormalMap:ge,clearcoatRoughnessMap:ee,dispersion:Qe,retroreflection:A,iridescence:_,iridescenceMap:ie,iridescenceThicknessMap:_e,sheen:O,sheenColorMap:Ie,sheenRoughnessMap:Me,specularMap:xe,specularColorMap:Oe,specularIntensityMap:ke,transmission:X,transmissionMap:Ze,thicknessMap:U,gradientMap:ve,opaque:x.transparent===!1&&x.blending===ws&&x.alphaToCoverage===!1,alphaMap:te,alphaTest:ye,alphaHash:Se,combine:x.combine,mapUv:Fe&&m(x.map.channel),aoMapUv:re&&m(x.aoMap.channel),lightMapUv:le&&m(x.lightMap.channel),bumpMapUv:j&&m(x.bumpMap.channel),normalMapUv:ae&&m(x.normalMap.channel),displacementMapUv:we&&m(x.displacementMap.channel),emissiveMapUv:Ae&&m(x.emissiveMap.channel),metalnessMapUv:se&&m(x.metalnessMap.channel),roughnessMapUv:He&&m(x.roughnessMap.channel),anisotropyMapUv:Q&&m(x.anisotropyMap.channel),clearcoatMapUv:de&&m(x.clearcoatMap.channel),clearcoatNormalMapUv:ge&&m(x.clearcoatNormalMap.channel),clearcoatRoughnessMapUv:ee&&m(x.clearcoatRoughnessMap.channel),iridescenceMapUv:ie&&m(x.iridescenceMap.channel),iridescenceThicknessMapUv:_e&&m(x.iridescenceThicknessMap.channel),sheenColorMapUv:Ie&&m(x.sheenColorMap.channel),sheenRoughnessMapUv:Me&&m(x.sheenRoughnessMap.channel),specularMapUv:xe&&m(x.specularMap.channel),specularColorMapUv:Oe&&m(x.specularColorMap.channel),specularIntensityMapUv:ke&&m(x.specularIntensityMap.channel),transmissionMapUv:Ze&&m(x.transmissionMap.channel),thicknessMapUv:U&&m(x.thicknessMap.channel),alphaMapUv:te&&m(x.alphaMap.channel),vertexTangents:!!k.attributes.tangent&&(ae||L),vertexNormals:!!k.attributes.normal,vertexColors:x.vertexColors,vertexAlphas:x.vertexColors===!0&&!!k.attributes.color&&k.attributes.color.itemSize===4,pointsUvs:B.isPoints===!0&&!!k.attributes.uv&&(Fe||te),fog:!!N,useFog:x.fog===!0,fogExp2:!!N&&N.isFogExp2,flatShading:x.wireframe===!1&&(x.flatShading===!0||k.attributes.normal===void 0&&ae===!1&&(x.isMeshLambertMaterial||x.isMeshPhongMaterial||x.isMeshStandardMaterial||x.isMeshPhysicalMaterial)),sizeAttenuation:x.sizeAttenuation===!0,logarithmicDepthBuffer:u,reversedDepthBuffer:pe,skinning:B.isSkinnedMesh===!0,hasPositionAttribute:k.attributes.position!==void 0,morphTargets:k.morphAttributes.position!==void 0,morphNormals:k.morphAttributes.normal!==void 0,morphColors:k.morphAttributes.color!==void 0,morphTargetsCount:fe,morphTextureStride:he,numSunLights:E.sun.length,numDirLights:E.directional.length,numPointLights:E.point.length,numSpotLights:E.spot.length,numSpotLightMaps:E.spotLightMap.length,numRectAreaLights:E.rectArea.length,numHemiLights:E.hemi.length,numSunLightShadows:E.sunShadowMap.length,numDirLightShadows:E.directionalShadowMap.length,numPointLightShadows:E.pointShadowMap.length,numSpotLightShadows:E.spotShadowMap.length,numSpotLightShadowsWithMaps:E.numSpotLightShadowsWithMaps,numLightProbes:E.numLightProbes,numLightProbeGrids:V.length,numClippingPlanes:r.numPlanes,numClipIntersection:r.numIntersection,dithering:x.dithering,shadowMapEnabled:i.shadowMap.enabled&&C.length>0,shadowMapType:i.shadowMap.type,toneMapping:Be,decodeVideoTexture:Fe&&x.map.isVideoTexture===!0&&rt.getTransfer(x.map.colorSpace)===ht,decodeVideoTextureEmissive:Ae&&x.emissiveMap.isVideoTexture===!0&&rt.getTransfer(x.emissiveMap.colorSpace)===ht,premultipliedAlpha:x.premultipliedAlpha,doubleSided:x.side===kt,flipSided:x.side===It,useDepthPacking:x.depthPacking>=0,depthPacking:x.depthPacking||0,index0AttributeName:x.index0AttributeName,extensionClipCullDistance:ce&&x.extensions.clipCullDistance===!0&&t.has("WEBGL_clip_cull_distance"),extensionMultiDraw:(ce&&x.extensions.multiDraw===!0||me)&&t.has("WEBGL_multi_draw"),rendererExtensionParallelShaderCompile:t.has("KHR_parallel_shader_compile"),customProgramCacheKey:x.customProgramCacheKey()};return Le.vertexUv1s=l.has(1),Le.vertexUv2s=l.has(2),Le.vertexUv3s=l.has(3),l.clear(),Le}function g(x){let E=[];if(x.shaderID?E.push(x.shaderID):(E.push(x.customVertexShaderID),E.push(x.customFragmentShaderID)),x.defines!==void 0)for(let C in x.defines)E.push(C),E.push(x.defines[C]);return x.isRawShaderMaterial===!1&&(p(E,x),T(E,x),E.push(i.outputColorSpace)),E.push(x.customProgramCacheKey),E.join()}function p(x,E){x.push(E.precision),x.push(E.outputColorSpace),x.push(E.envMapMode),x.push(E.envMapCubeUVHeight),x.push(E.mapUv),x.push(E.alphaMapUv),x.push(E.lightMapUv),x.push(E.aoMapUv),x.push(E.bumpMapUv),x.push(E.normalMapUv),x.push(E.displacementMapUv),x.push(E.emissiveMapUv),x.push(E.metalnessMapUv),x.push(E.roughnessMapUv),x.push(E.anisotropyMapUv),x.push(E.clearcoatMapUv),x.push(E.clearcoatNormalMapUv),x.push(E.clearcoatRoughnessMapUv),x.push(E.iridescenceMapUv),x.push(E.iridescenceThicknessMapUv),x.push(E.sheenColorMapUv),x.push(E.sheenRoughnessMapUv),x.push(E.specularMapUv),x.push(E.specularColorMapUv),x.push(E.specularIntensityMapUv),x.push(E.transmissionMapUv),x.push(E.thicknessMapUv),x.push(E.combine),x.push(E.fogExp2),x.push(E.sizeAttenuation),x.push(E.morphTargetsCount),x.push(E.morphAttributeCount),x.push(E.numSunLights),x.push(E.numDirLights),x.push(E.numPointLights),x.push(E.numSpotLights),x.push(E.numSpotLightMaps),x.push(E.numHemiLights),x.push(E.numRectAreaLights),x.push(E.numSunLightShadows),x.push(E.numDirLightShadows),x.push(E.numPointLightShadows),x.push(E.numSpotLightShadows),x.push(E.numSpotLightShadowsWithMaps),x.push(E.numLightProbes),x.push(E.shadowMapType),x.push(E.toneMapping),x.push(E.numClippingPlanes),x.push(E.numClipIntersection),x.push(E.depthPacking)}function T(x,E){a.disableAll(),E.instancing&&a.enable(0),E.instancingColor&&a.enable(1),E.instancingMorph&&a.enable(2),E.matcap&&a.enable(3),E.envMap&&a.enable(4),E.normalMapObjectSpace&&a.enable(5),E.normalMapTangentSpace&&a.enable(6),E.clearcoat&&a.enable(7),E.iridescence&&a.enable(8),E.alphaTest&&a.enable(9),E.vertexColors&&a.enable(10),E.vertexAlphas&&a.enable(11),E.vertexUv1s&&a.enable(12),E.vertexUv2s&&a.enable(13),E.vertexUv3s&&a.enable(14),E.vertexTangents&&a.enable(15),E.anisotropy&&a.enable(16),E.alphaHash&&a.enable(17),E.batching&&a.enable(18),E.dispersion&&a.enable(19),E.retroreflection&&a.enable(24),E.batchingColor&&a.enable(20),E.gradientMap&&a.enable(21),E.packedNormalMap&&a.enable(22),E.vertexNormals&&a.enable(23),x.push(a.mask),a.disableAll(),E.fog&&a.enable(0),E.useFog&&a.enable(1),E.flatShading&&a.enable(2),E.logarithmicDepthBuffer&&a.enable(3),E.reversedDepthBuffer&&a.enable(4),E.skinning&&a.enable(5),E.morphTargets&&a.enable(6),E.morphNormals&&a.enable(7),E.morphColors&&a.enable(8),E.premultipliedAlpha&&a.enable(9),E.shadowMapEnabled&&a.enable(10),E.doubleSided&&a.enable(11),E.flipSided&&a.enable(12),E.useDepthPacking&&a.enable(13),E.dithering&&a.enable(14),E.transmission&&a.enable(15),E.sheen&&a.enable(16),E.opaque&&a.enable(17),E.pointsUvs&&a.enable(18),E.decodeVideoTexture&&a.enable(19),E.decodeVideoTextureEmissive&&a.enable(20),E.alphaToCoverage&&a.enable(21),E.numLightProbeGrids>0&&a.enable(22),E.hasPositionAttribute&&a.enable(23),x.push(a.mask)}function w(x){let E=f[x.type],C;if(E){let P=Vn[E];C=Su.clone(P.uniforms)}else C=x.uniforms;return C}function M(x,E){let C=h.get(E);return C!==void 0?++C.usedTimes:(C=new E_(i,E,x,s),c.push(C),h.set(E,C)),C}function b(x){if(--x.usedTimes===0){let E=c.indexOf(x);c[E]=c[c.length-1],c.pop(),h.delete(x.cacheKey),x.destroy()}}function S(x){o.remove(x)}function R(){o.dispose()}return{getParameters:v,getProgramCacheKey:g,getUniforms:w,acquireProgram:M,releaseProgram:b,releaseShaderCache:S,programs:c,dispose:R}}function R_(){let i=new WeakMap;function e(a){return i.has(a)}function t(a){let o=i.get(a);return o===void 0&&(o={},i.set(a,o)),o}function n(a){i.delete(a)}function s(a,o,l){i.get(a)[o]=l}function r(){i=new WeakMap}return{has:e,get:t,remove:n,update:s,dispose:r}}function C_(i,e){return i.groupOrder!==e.groupOrder?i.groupOrder-e.groupOrder:i.renderOrder!==e.renderOrder?i.renderOrder-e.renderOrder:i.material.id!==e.material.id?i.material.id-e.material.id:i.materialVariant!==e.materialVariant?i.materialVariant-e.materialVariant:i.z!==e.z?i.z-e.z:i.id-e.id}function Hu(i,e){return i.groupOrder!==e.groupOrder?i.groupOrder-e.groupOrder:i.renderOrder!==e.renderOrder?i.renderOrder-e.renderOrder:i.z!==e.z?e.z-i.z:i.id-e.id}function Gu(){let i=[],e=0,t=[],n=[],s=[];function r(){e=0,t.length=0,n.length=0,s.length=0}function a(d){let f=0;return d.isInstancedMesh&&(f+=2),d.isSkinnedMesh&&(f+=1),f}function o(d,f,m,v,g,p){let T=i[e];return T===void 0?(T={id:d.id,object:d,geometry:f,material:m,materialVariant:a(d),groupOrder:v,renderOrder:d.renderOrder,z:g,group:p},i[e]=T):(T.id=d.id,T.object=d,T.geometry=f,T.material=m,T.materialVariant=a(d),T.groupOrder=v,T.renderOrder=d.renderOrder,T.z=g,T.group=p),e++,T}function l(d,f,m,v,g,p,T){T.reversedDepth===!0&&(g=-g);let w=o(d,f,m,v,g,p);m.transmission>0?n.push(w):m.transparent===!0?s.push(w):t.push(w)}function c(d,f,m,v,g,p){let T=o(d,f,m,v,g,p);m.transmission>0?n.unshift(T):m.transparent===!0?s.unshift(T):t.unshift(T)}function h(d,f){t.length>1&&t.sort(d||C_),n.length>1&&n.sort(f||Hu),s.length>1&&s.sort(f||Hu)}function u(){for(let d=e,f=i.length;d=r.length?(a=new Gu,r.push(a)):a=r[s],a}function t(){i=new WeakMap}return{get:e,dispose:t}}function I_(){let i={};return{get:function(e){if(i[e.id]!==void 0)return i[e.id];let t;switch(e.type){case"SunLight":case"DirectionalLight":t={direction:new I,color:new Xe};break;case"SpotLight":t={position:new I,direction:new I,color:new Xe,distance:0,coneCos:0,penumbraCos:0,decay:0};break;case"PointLight":t={position:new I,color:new Xe,distance:0,decay:0};break;case"HemisphereLight":t={direction:new I,skyColor:new Xe,groundColor:new Xe};break;case"RectAreaLight":t={color:new Xe,position:new I,halfWidth:new I,halfHeight:new I};break}return i[e.id]=t,t}}}function L_(){let i={};return{get:function(e){if(i[e.id]!==void 0)return i[e.id];let t;switch(e.type){case"SunLight":case"DirectionalLight":t={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new ue};break;case"SpotLight":t={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new ue};break;case"PointLight":t={shadowIntensity:1,shadowBias:0,shadowNormalBias:0,shadowRadius:1,shadowMapSize:new ue,shadowCameraNear:1,shadowCameraFar:1e3};break}return i[e.id]=t,t}}}var D_=0;function N_(i,e){return(e.castShadow?2:0)-(i.castShadow?2:0)+(e.map?1:0)-(i.map?1:0)}function U_(i){let e=new I_,t=L_(),n={version:0,hash:{sunLength:-1,directionalLength:-1,pointLength:-1,spotLength:-1,rectAreaLength:-1,hemiLength:-1,numSunShadows:-1,numDirectionalShadows:-1,numPointShadows:-1,numSpotShadows:-1,numSpotMaps:-1,numLightProbes:-1},ambient:[0,0,0],probe:[],sun:[],sunShadow:[],sunShadowMap:[],sunShadowMatrix:[],sunShadowCascade:[],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 I);let s=new I,r=new gt,a=new gt;function o(c){let h=0,u=0,d=0;for(let B=0;B<9;B++)n.probe[B].set(0,0,0);let f=0,m=0,v=0,g=0,p=0,T=0,w=0,M=0,b=0,S=0,R=0,x=0,E=0,C=0;c.sort(N_);for(let B=0,V=c.length;B0&&(i.has("OES_texture_float_linear")===!0?(n.rectAreaLTC1=be.LTC_FLOAT_1,n.rectAreaLTC2=be.LTC_FLOAT_2):(n.rectAreaLTC1=be.LTC_HALF_1,n.rectAreaLTC2=be.LTC_HALF_2)),n.ambient[0]=h,n.ambient[1]=u,n.ambient[2]=d;let P=n.hash;(P.sunLength!==f||P.directionalLength!==g||P.pointLength!==p||P.spotLength!==T||P.rectAreaLength!==w||P.hemiLength!==M||P.numSunShadows!==m||P.numDirectionalShadows!==b||P.numPointShadows!==S||P.numSpotShadows!==R||P.numSpotMaps!==x||P.numLightProbes!==C)&&(n.sun.length=f,n.directional.length=g,n.spot.length=T,n.rectArea.length=w,n.point.length=p,n.hemi.length=M,n.sunShadow.length=m,n.sunShadowMap.length=m,n.sunShadowMatrix.length=v,n.sunShadowCascade.length=v,n.directionalShadow.length=b,n.directionalShadowMap.length=b,n.directionalShadowMatrix.length=b,n.pointShadow.length=S,n.pointShadowMap.length=S,n.pointShadowMatrix.length=S,n.spotShadow.length=R,n.spotShadowMap.length=R,n.spotLightMatrix.length=R+x-E,n.spotLightMap.length=x,n.numSpotLightShadowsWithMaps=E,n.numLightProbes=C,P.sunLength=f,P.directionalLength=g,P.pointLength=p,P.spotLength=T,P.rectAreaLength=w,P.hemiLength=M,P.numSunShadows=m,P.numDirectionalShadows=b,P.numPointShadows=S,P.numSpotShadows=R,P.numSpotMaps=x,P.numLightProbes=C,n.version=D_++)}function l(c,h){let u=0,d=0,f=0,m=0,v=0,g=0,p=h.matrixWorldInverse;for(let T=0,w=c.length;T=a.length?(o=new Wu(i),a.push(o)):o=a[r],o}function n(){e=new WeakMap}return{get:t,dispose:n}}var O_=`void main() { + gl_Position = vec4( position, 1.0 ); +}`,B_=`uniform sampler2D shadow_pass; +uniform vec2 resolution; +uniform float radius; +void main() { + const float samples = float( VSM_SAMPLES ); + float mean = 0.0; + float squared_mean = 0.0; + float uvStride = samples <= 1.0 ? 0.0 : 2.0 / ( samples - 1.0 ); + float uvStart = samples <= 1.0 ? 0.0 : - 1.0; + for ( float i = 0.0; i < samples; i ++ ) { + float uvOffset = uvStart + i * uvStride; + #ifdef HORIZONTAL_PASS + vec2 distribution = texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( uvOffset, 0.0 ) * radius ) / resolution ).rg; + mean += distribution.x; + squared_mean += distribution.y * distribution.y + distribution.x * distribution.x; + #else + float depth = texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, uvOffset ) * radius ) / resolution ).r; + mean += depth; + squared_mean += depth * depth; + #endif + } + mean = mean / samples; + 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 ); +}`,z_=[new I(1,0,0),new I(-1,0,0),new I(0,1,0),new I(0,-1,0),new I(0,0,1),new I(0,0,-1)],k_=[new I(0,-1,0),new I(0,-1,0),new I(0,0,1),new I(0,0,-1),new I(0,-1,0),new I(0,-1,0)],Xu=new gt,Br=new I,Rc=new I;function V_(i,e,t){let n=new gs,s=new ue,r=new ue,a=new Mt,o=new Va,l=new Ha,c={},h=t.maxTextureSize,u={[ln]:It,[It]:ln,[kt]:kt},d=new an({defines:{VSM_SAMPLES:8},uniforms:{shadow_pass:{value:null},resolution:{value:new ue},radius:{value:4}},vertexShader:O_,fragmentShader:B_}),f=d.clone();f.defines.HORIZONTAL_PASS=1;let m=new At;m.setAttribute("position",new Bt(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));let v=new $e(m,d),g=this;this.enabled=!1,this.autoUpdate=!0,this.needsUpdate=!1,this.type=Tr;let p=this.type;this.render=function(S,R,x){if(g.enabled===!1||g.autoUpdate===!1&&g.needsUpdate===!1||S.length===0)return;this.type===Oh&&(Ge("WebGLShadowMap: PCFSoftShadowMap has been removed. Using PCFShadowMap instead."),this.type=Tr);let E=i.getRenderTarget(),C=i.getActiveCubeFace(),P=i.getActiveMipmapLevel(),B=i.state;B.setBlending(Bn),B.buffers.depth.getReversed()===!0?B.buffers.color.setClear(0,0,0,0):B.buffers.color.setClear(1,1,1,1),B.buffers.depth.setTest(!0),B.setScissorTest(!1);let V=p!==this.type;V&&R.traverse(function(N){N.material&&(Array.isArray(N.material)?N.material.forEach(k=>k.needsUpdate=!0):N.material.needsUpdate=!0)});for(let N=0,k=S.length;Nh||s.y>h)&&(s.x>h&&(r.x=Math.floor(h/Y.x),s.x=r.x*Y.x,q.mapSize.x=r.x),s.y>h&&(r.y=Math.floor(h/Y.y),s.y=r.y*Y.y,q.mapSize.y=r.y));let F=i.state.buffers.depth.getReversed();if(q.camera._reversedDepth=F,q.map===null||V===!0){if(q.map!==null&&(q.map.depthTexture!==null&&(q.map.depthTexture.dispose(),q.map.depthTexture=null),q.map.dispose()),this.type===Ts){if($.isPointLight){Ge("WebGLShadowMap: VSM shadow maps are not supported for PointLights. Use PCF or BasicShadowMap instead.");continue}q.map=new en(s.x,s.y,{format:yi,type:wn,minFilter:zt,magFilter:zt,generateMipmaps:!1}),q.map.texture.name=$.name+".shadowMap",q.map.depthTexture=new ui(s.x,s.y,Tn),q.map.depthTexture.name=$.name+".shadowMapDepth",q.map.depthTexture.format=Dn,q.map.depthTexture.compareFunction=null,q.map.depthTexture.minFilter=Ut,q.map.depthTexture.magFilter=Ut}else $.isPointLight?(q.map=new $o(s.x),q.map.depthTexture=new Na(s.x,En)):(q.map=new en(s.x,s.y),q.map.depthTexture=new ui(s.x,s.y,En)),q.map.depthTexture.name=$.name+".shadowMap",q.map.depthTexture.format=Dn,this.type===Tr?(q.map.depthTexture.compareFunction=F?Yo:qo,q.map.depthTexture.minFilter=zt,q.map.depthTexture.magFilter=zt):(q.map.depthTexture.compareFunction=null,q.map.depthTexture.minFilter=Ut,q.map.depthTexture.magFilter=Ut);q.camera.updateProjectionMatrix()}q.map.isWebGLCubeRenderTarget!==!0&&(q.map.width!==s.x||q.map.height!==s.y)&&q.map.setSize(s.x,s.y);let z=q.map.isWebGLCubeRenderTarget?6:q.getViewportCount();$.isPointLight!==!0&&q.updateMatrices($,x);for(let Z=0;Z0||R.map&&R.alphaTest>0||R.alphaToCoverage===!0){let B=C.uuid,V=R.uuid,N=c[B];N===void 0&&(N={},c[B]=N);let k=N[V];k===void 0&&(k=C.clone(),N[V]=k,R.addEventListener("dispose",b)),C=k}if(C.visible=R.visible,C.wireframe=R.wireframe,E===Ts?C.side=R.shadowSide!==null?R.shadowSide:R.side:C.side=R.shadowSide!==null?R.shadowSide:u[R.side],C.alphaMap=R.alphaMap,C.alphaTest=R.alphaToCoverage===!0?.5:R.alphaTest,C.map=R.map,C.clipShadows=R.clipShadows,C.clippingPlanes=R.clippingPlanes,C.clipIntersection=R.clipIntersection,C.displacementMap=R.displacementMap,C.displacementScale=R.displacementScale,C.displacementBias=R.displacementBias,C.wireframeLinewidth=R.wireframeLinewidth,C.linewidth=R.linewidth,x.isPointLight===!0&&C.isMeshDistanceMaterial===!0){let B=i.properties.get(C);B.light=x}return C}function M(S,R,x,E,C){if(S.visible===!1)return;if(S.layers.test(R.layers)&&(S.isMesh||S.isLine||S.isPoints)&&(S.castShadow||S.receiveShadow&&C===Ts)&&(!S.frustumCulled||S.intersectsFrustum(n))){S.modelViewMatrix.multiplyMatrices(x.matrixWorldInverse,S.matrixWorld);let V=e.update(S),N=S.material;if(Array.isArray(N)){let k=V.groups;for(let $=0,q=k.length;$=1):F.indexOf("OpenGL ES")!==-1&&(Y=parseFloat(/^OpenGL ES (\d)/.exec(F)[1]),q=Y>=2);let z=null,Z={},fe=i.getParameter(i.SCISSOR_BOX),he=i.getParameter(i.VIEWPORT),qe=new Mt().fromArray(fe),Ve=new Mt().fromArray(he);function Ye(U,ve,te,ye){let Se=new Uint8Array(4),ce=i.createTexture();i.bindTexture(U,ce),i.texParameteri(U,i.TEXTURE_MIN_FILTER,i.NEAREST),i.texParameteri(U,i.TEXTURE_MAG_FILTER,i.NEAREST);for(let Be=0;Be"u"?!1:/OculusBrowser/g.test(navigator.userAgent),c=new ue,h=new WeakMap,u=new Set,d,f=new WeakMap,m=!1;try{m=typeof OffscreenCanvas<"u"&&new OffscreenCanvas(1,1).getContext("2d")!==null}catch{}function v(A,_){return m?new OffscreenCanvas(A,_):ls("canvas")}function g(A,_,O){let X=1,Q=Qe(A);if((Q.width>O||Q.height>O)&&(X=O/Math.max(Q.width,Q.height)),X<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){let de=Math.floor(X*Q.width),ge=Math.floor(X*Q.height);d===void 0&&(d=v(de,ge));let ee=_?v(de,ge):d;return ee.width=de,ee.height=ge,ee.getContext("2d").drawImage(A,0,0,de,ge),Ge("WebGLRenderer: Texture has been resized from ("+Q.width+"x"+Q.height+") to ("+de+"x"+ge+")."),ee}else return"data"in A&&Ge("WebGLRenderer: Image in DataTexture is too big ("+Q.width+"x"+Q.height+")."),A;return A}function p(A){return A.generateMipmaps}function T(A){i.generateMipmap(A)}function w(A){return A.isWebGLCubeRenderTarget?i.TEXTURE_CUBE_MAP:A.isWebGL3DRenderTarget?i.TEXTURE_3D:A.isWebGLArrayRenderTarget||A.isCompressedArrayTexture?i.TEXTURE_2D_ARRAY:i.TEXTURE_2D}function M(A,_,O,X,Q,de=!1){if(A!==null){if(i[A]!==void 0)return i[A];Ge("WebGLRenderer: Attempt to use non-existing WebGL internal format '"+A+"'")}let ge;X&&(ge=e.get("EXT_texture_norm16"),ge||Ge("WebGLRenderer: Unable to use normalized textures without EXT_texture_norm16 extension"));let ee=_;if(_===i.RED&&(O===i.FLOAT&&(ee=i.R32F),O===i.HALF_FLOAT&&(ee=i.R16F),O===i.UNSIGNED_BYTE&&(ee=i.R8),O===i.UNSIGNED_SHORT&&ge&&(ee=ge.R16_EXT),O===i.SHORT&&ge&&(ee=ge.R16_SNORM_EXT)),_===i.RED_INTEGER&&(O===i.UNSIGNED_BYTE&&(ee=i.R8UI),O===i.UNSIGNED_SHORT&&(ee=i.R16UI),O===i.UNSIGNED_INT&&(ee=i.R32UI),O===i.BYTE&&(ee=i.R8I),O===i.SHORT&&(ee=i.R16I),O===i.INT&&(ee=i.R32I)),_===i.RG&&(O===i.FLOAT&&(ee=i.RG32F),O===i.HALF_FLOAT&&(ee=i.RG16F),O===i.UNSIGNED_BYTE&&(ee=i.RG8),O===i.UNSIGNED_SHORT&&ge&&(ee=ge.RG16_EXT),O===i.SHORT&&ge&&(ee=ge.RG16_SNORM_EXT)),_===i.RG_INTEGER&&(O===i.UNSIGNED_BYTE&&(ee=i.RG8UI),O===i.UNSIGNED_SHORT&&(ee=i.RG16UI),O===i.UNSIGNED_INT&&(ee=i.RG32UI),O===i.BYTE&&(ee=i.RG8I),O===i.SHORT&&(ee=i.RG16I),O===i.INT&&(ee=i.RG32I)),_===i.RGB_INTEGER&&(O===i.UNSIGNED_BYTE&&(ee=i.RGB8UI),O===i.UNSIGNED_SHORT&&(ee=i.RGB16UI),O===i.UNSIGNED_INT&&(ee=i.RGB32UI),O===i.BYTE&&(ee=i.RGB8I),O===i.SHORT&&(ee=i.RGB16I),O===i.INT&&(ee=i.RGB32I)),_===i.RGBA_INTEGER&&(O===i.UNSIGNED_BYTE&&(ee=i.RGBA8UI),O===i.UNSIGNED_SHORT&&(ee=i.RGBA16UI),O===i.UNSIGNED_INT&&(ee=i.RGBA32UI),O===i.BYTE&&(ee=i.RGBA8I),O===i.SHORT&&(ee=i.RGBA16I),O===i.INT&&(ee=i.RGBA32I)),_===i.RGB&&(O===i.UNSIGNED_SHORT&&ge&&(ee=ge.RGB16_EXT),O===i.SHORT&&ge&&(ee=ge.RGB16_SNORM_EXT),O===i.UNSIGNED_INT_5_9_9_9_REV&&(ee=i.RGB9_E5),O===i.UNSIGNED_INT_10F_11F_11F_REV&&(ee=i.R11F_G11F_B10F)),_===i.RGBA){let ie=de?Ks:rt.getTransfer(Q);O===i.FLOAT&&(ee=i.RGBA32F),O===i.HALF_FLOAT&&(ee=i.RGBA16F),O===i.UNSIGNED_BYTE&&(ee=ie===ht?i.SRGB8_ALPHA8:i.RGBA8),O===i.UNSIGNED_SHORT&&ge&&(ee=ge.RGBA16_EXT),O===i.SHORT&&ge&&(ee=ge.RGBA16_SNORM_EXT),O===i.UNSIGNED_SHORT_4_4_4_4&&(ee=i.RGBA4),O===i.UNSIGNED_SHORT_5_5_5_1&&(ee=i.RGB5_A1)}return(ee===i.R16F||ee===i.R32F||ee===i.RG16F||ee===i.RG32F||ee===i.RGBA16F||ee===i.RGBA32F)&&e.get("EXT_color_buffer_float"),ee}function b(A,_){let O;return A?_===null||_===En||_===Cs?O=i.DEPTH24_STENCIL8:_===Tn?O=i.DEPTH32F_STENCIL8:_===Rs&&(O=i.DEPTH24_STENCIL8,Ge("DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.")):_===null||_===En||_===Cs?O=i.DEPTH_COMPONENT24:_===Tn?O=i.DEPTH_COMPONENT32F:_===Rs&&(O=i.DEPTH_COMPONENT16),O}function S(A,_){return p(A)===!0||A.isFramebufferTexture&&A.minFilter!==Ut&&A.minFilter!==zt?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){let _=A.target;_.removeEventListener("dispose",R),E(_),_.isVideoTexture&&h.delete(_),_.isHTMLTexture&&u.delete(_)}function x(A){let _=A.target;_.removeEventListener("dispose",x),P(_)}function E(A){let _=n.get(A);if(_.__webglInit===void 0)return;let O=A.source,X=f.get(O);if(X){let Q=X[_.__cacheKey];Q.usedTimes--,Q.usedTimes===0&&C(A),Object.keys(X).length===0&&f.delete(O)}n.remove(A)}function C(A){let _=n.get(A);i.deleteTexture(_.__webglTexture);let O=A.source,X=f.get(O);delete X[_.__cacheKey],a.memory.textures--}function P(A){let _=n.get(A);if(A.depthTexture&&(A.depthTexture.dispose(),n.remove(A.depthTexture)),A.isWebGLCubeRenderTarget)for(let X=0;X<6;X++){if(Array.isArray(_.__webglFramebuffer[X]))for(let Q=0;Q<_.__webglFramebuffer[X].length;Q++)i.deleteFramebuffer(_.__webglFramebuffer[X][Q]);else i.deleteFramebuffer(_.__webglFramebuffer[X]);_.__webglDepthbuffer&&i.deleteRenderbuffer(_.__webglDepthbuffer[X])}else{if(Array.isArray(_.__webglFramebuffer))for(let X=0;X<_.__webglFramebuffer.length;X++)i.deleteFramebuffer(_.__webglFramebuffer[X]);else i.deleteFramebuffer(_.__webglFramebuffer);if(_.__webglDepthbuffer&&i.deleteRenderbuffer(_.__webglDepthbuffer),_.__webglMultisampledFramebuffer&&i.deleteFramebuffer(_.__webglMultisampledFramebuffer),_.__webglColorRenderbuffer)for(let X=0;X<_.__webglColorRenderbuffer.length;X++)_.__webglColorRenderbuffer[X]&&i.deleteRenderbuffer(_.__webglColorRenderbuffer[X]);_.__webglDepthRenderbuffer&&i.deleteRenderbuffer(_.__webglDepthRenderbuffer)}let O=A.textures;for(let X=0,Q=O.length;X=s.maxTextures&&Ge("WebGLTextures: Trying to use "+(A+1)+" texture units while this GPU supports only "+s.maxTextures),B+=1,A}function q(A){let _=[];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 Y(A,_){let O=n.get(A);if(A.isVideoTexture&&L(A),A.isRenderTargetTexture===!1&&A.isExternalTexture!==!0&&A.version>0&&O.__version!==A.version){let X=A.image;if(X===null)Ge("WebGLRenderer: Texture marked for update but no image data found.");else if(X.complete===!1)Ge("WebGLRenderer: Texture marked for update but image is incomplete");else{pe(O,A,_);return}}else A.isExternalTexture&&(O.__webglTexture=A.sourceTexture?A.sourceTexture:null);t.bindTexture(i.TEXTURE_2D,O.__webglTexture,i.TEXTURE0+_)}function F(A,_){let O=n.get(A);if(A.isRenderTargetTexture===!1&&A.version>0&&O.__version!==A.version){pe(O,A,_);return}else A.isExternalTexture&&(O.__webglTexture=A.sourceTexture?A.sourceTexture:null);t.bindTexture(i.TEXTURE_2D_ARRAY,O.__webglTexture,i.TEXTURE0+_)}function z(A,_){let O=n.get(A);if(A.isRenderTargetTexture===!1&&A.version>0&&O.__version!==A.version){pe(O,A,_);return}t.bindTexture(i.TEXTURE_3D,O.__webglTexture,i.TEXTURE0+_)}function Z(A,_){let O=n.get(A);if(A.isCubeDepthTexture!==!0&&A.version>0&&O.__version!==A.version){De(O,A,_);return}t.bindTexture(i.TEXTURE_CUBE_MAP,O.__webglTexture,i.TEXTURE0+_)}let fe={[as]:i.REPEAT,[In]:i.CLAMP_TO_EDGE,[Ca]:i.MIRRORED_REPEAT},he={[Ut]:i.NEAREST,[nu]:i.NEAREST_MIPMAP_NEAREST,[Cr]:i.NEAREST_MIPMAP_LINEAR,[zt]:i.LINEAR,[oo]:i.LINEAR_MIPMAP_NEAREST,[zn]:i.LINEAR_MIPMAP_LINEAR},qe={[au]:i.NEVER,[uu]:i.ALWAYS,[ou]:i.LESS,[qo]:i.LEQUAL,[lu]:i.EQUAL,[Yo]:i.GEQUAL,[cu]:i.GREATER,[hu]:i.NOTEQUAL};function Ve(A,_){if(_.type===Tn&&e.has("OES_texture_float_linear")===!1&&(_.magFilter===zt||_.magFilter===oo||_.magFilter===Cr||_.magFilter===zn||_.minFilter===zt||_.minFilter===oo||_.minFilter===Cr||_.minFilter===zn)&&Ge("WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device."),i.texParameteri(A,i.TEXTURE_WRAP_S,fe[_.wrapS]),i.texParameteri(A,i.TEXTURE_WRAP_T,fe[_.wrapT]),(A===i.TEXTURE_3D||A===i.TEXTURE_2D_ARRAY)&&i.texParameteri(A,i.TEXTURE_WRAP_R,fe[_.wrapR]),i.texParameteri(A,i.TEXTURE_MAG_FILTER,he[_.magFilter]),i.texParameteri(A,i.TEXTURE_MIN_FILTER,he[_.minFilter]),_.compareFunction&&(i.texParameteri(A,i.TEXTURE_COMPARE_MODE,i.COMPARE_REF_TO_TEXTURE),i.texParameteri(A,i.TEXTURE_COMPARE_FUNC,qe[_.compareFunction])),e.has("EXT_texture_filter_anisotropic")===!0){if(_.magFilter===Ut||_.minFilter!==Cr&&_.minFilter!==zn||_.type===Tn&&e.has("OES_texture_float_linear")===!1)return;if(_.anisotropy>1||n.get(_).__currentAnisotropy){let O=e.get("EXT_texture_filter_anisotropic");i.texParameterf(A,O.TEXTURE_MAX_ANISOTROPY_EXT,Math.min(_.anisotropy,s.getMaxAnisotropy())),n.get(_).__currentAnisotropy=_.anisotropy}}}function Ye(A,_){let O=!1;A.__webglInit===void 0&&(A.__webglInit=!0,_.addEventListener("dispose",R));let X=_.source,Q=f.get(X);Q===void 0&&(Q={},f.set(X,Q));let de=q(_);if(de!==A.__cacheKey){Q[de]===void 0&&(Q[de]={texture:i.createTexture(),usedTimes:0},a.memory.textures++,O=!0),Q[de].usedTimes++;let ge=Q[A.__cacheKey];ge!==void 0&&(Q[A.__cacheKey].usedTimes--,ge.usedTimes===0&&C(_)),A.__cacheKey=de,A.__webglTexture=Q[de].texture}return O}function K(A,_,O){return Math.floor(Math.floor(A/O)/_)}function ne(A,_,O,X){let de=A.updateRanges;if(de.length===0)t.texSubImage2D(i.TEXTURE_2D,0,0,0,_.width,_.height,O,X,_.data);else{de.sort((Ie,Me)=>Ie.start-Me.start);let ge=0;for(let Ie=1;Ie0){ke&&Ze&&t.texStorage2D(i.TEXTURE_2D,ve,Me,Oe[0].width,Oe[0].height);for(let te=0,ye=Oe.length;te0){let Se=_c(xe.width,xe.height,_.format,_.type);for(let ce of _.layerUpdates){let Be=xe.data.subarray(ce*Se/xe.data.BYTES_PER_ELEMENT,(ce+1)*Se/xe.data.BYTES_PER_ELEMENT);t.compressedTexSubImage3D(i.TEXTURE_2D_ARRAY,te,0,0,ce,xe.width,xe.height,1,_e,Be)}}else t.compressedTexSubImage3D(i.TEXTURE_2D_ARRAY,te,0,0,0,xe.width,xe.height,ie.depth,_e,xe.data)}else t.compressedTexImage3D(i.TEXTURE_2D_ARRAY,te,Me,xe.width,xe.height,ie.depth,0,xe.data,0,0);else Ge("WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()");else ke?U&&t.texSubImage3D(i.TEXTURE_2D_ARRAY,te,0,0,0,xe.width,xe.height,ie.depth,_e,Ie,xe.data):t.texImage3D(i.TEXTURE_2D_ARRAY,te,Me,xe.width,xe.height,ie.depth,0,_e,Ie,xe.data);_.layerUpdates.size>0&&_.clearLayerUpdates()}else{ke&&Ze&&t.texStorage2D(i.TEXTURE_2D,ve,Me,Oe[0].width,Oe[0].height);for(let te=0,ye=Oe.length;te0){let te=_c(ie.width,ie.height,_.format,_.type);for(let ye of _.layerUpdates){let Se=ie.data.subarray(ye*te/ie.data.BYTES_PER_ELEMENT,(ye+1)*te/ie.data.BYTES_PER_ELEMENT);t.texSubImage3D(i.TEXTURE_2D_ARRAY,0,0,0,ye,ie.width,ie.height,1,_e,Ie,Se)}_.clearLayerUpdates()}else t.texSubImage3D(i.TEXTURE_2D_ARRAY,0,0,0,0,ie.width,ie.height,ie.depth,_e,Ie,ie.data)}else t.texImage3D(i.TEXTURE_2D_ARRAY,0,Me,ie.width,ie.height,ie.depth,0,_e,Ie,ie.data);else if(_.isData3DTexture)ke?(Ze&&t.texStorage3D(i.TEXTURE_3D,ve,Me,ie.width,ie.height,ie.depth),U&&t.texSubImage3D(i.TEXTURE_3D,0,0,0,0,ie.width,ie.height,ie.depth,_e,Ie,ie.data)):t.texImage3D(i.TEXTURE_3D,0,Me,ie.width,ie.height,ie.depth,0,_e,Ie,ie.data);else if(_.isFramebufferTexture){if(Ze)if(ke)t.texStorage2D(i.TEXTURE_2D,ve,Me,ie.width,ie.height);else{let te=ie.width,ye=ie.height;for(let Se=0;Se>=1,ye>>=1}}else if(_.isHTMLTexture){if("texElementImage2D"in i){let te=i.canvas;if(te.hasAttribute("layoutsubtree")||te.setAttribute("layoutsubtree","true"),ie.parentNode!==te){te.appendChild(ie),u.add(_),te.onpaint=ye=>{let Se=ye.changedElements;for(let ce of u)Se.includes(ce.image)&&(ce.needsUpdate=!0)},te.requestPaint();return}if(i.texElementImage2D.length===3)i.texElementImage2D(i.TEXTURE_2D,i.RGBA8,ie);else{let Se=i.RGBA,ce=i.RGBA,Be=i.UNSIGNED_BYTE;i.texElementImage2D(i.TEXTURE_2D,0,Se,ce,Be,ie)}i.texParameteri(i.TEXTURE_2D,i.TEXTURE_MIN_FILTER,i.LINEAR),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_S,i.CLAMP_TO_EDGE),i.texParameteri(i.TEXTURE_2D,i.TEXTURE_WRAP_T,i.CLAMP_TO_EDGE)}}else if(Oe.length>0){if(ke&&Ze){let te=Qe(Oe[0]);t.texStorage2D(i.TEXTURE_2D,ve,Me,te.width,te.height)}for(let te=0,ye=Oe.length;te0&&ye++;let ce=Qe(Me[0]);t.texStorage2D(i.TEXTURE_CUBE_MAP,ye,Ze,ce.width,ce.height)}for(let ce=0;ce<6;ce++)if(Ie){U?te&&t.texSubImage2D(i.TEXTURE_CUBE_MAP_POSITIVE_X+ce,0,0,0,Me[ce].width,Me[ce].height,Oe,ke,Me[ce].data):t.texImage2D(i.TEXTURE_CUBE_MAP_POSITIVE_X+ce,0,Ze,Me[ce].width,Me[ce].height,0,Oe,ke,Me[ce].data);for(let Be=0;Be>de),xe=Math.max(1,_.height>>de);Q===i.TEXTURE_3D||Q===i.TEXTURE_2D_ARRAY?t.texImage3D(Q,de,ie,Me,xe,_.depth,0,ge,ee,null):t.texImage2D(Q,de,ie,Me,xe,0,ge,ee,null)}t.bindFramebuffer(i.FRAMEBUFFER,A),He(_)?o.framebufferTexture2DMultisampleEXT(i.FRAMEBUFFER,X,Q,Ie.__webglTexture,0,se(_)):(Q===i.TEXTURE_2D||Q>=i.TEXTURE_CUBE_MAP_POSITIVE_X&&Q<=i.TEXTURE_CUBE_MAP_NEGATIVE_Z)&&i.framebufferTexture2D(i.FRAMEBUFFER,X,Q,Ie.__webglTexture,de),t.bindFramebuffer(i.FRAMEBUFFER,null)}function Fe(A,_,O){if(i.bindRenderbuffer(i.RENDERBUFFER,A),_.depthBuffer){let X=_.depthTexture,Q=X&&X.isDepthTexture?X.type:null,de=b(_.stencilBuffer,Q),ge=_.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT;He(_)?o.renderbufferStorageMultisampleEXT(i.RENDERBUFFER,se(_),de,_.width,_.height):O?i.renderbufferStorageMultisample(i.RENDERBUFFER,se(_),de,_.width,_.height):i.renderbufferStorage(i.RENDERBUFFER,de,_.width,_.height),i.framebufferRenderbuffer(i.FRAMEBUFFER,ge,i.RENDERBUFFER,A)}else{let X=_.textures;for(let Q=0;Q{delete _.__boundDepthTexture,delete _.__depthDisposeCallback,X.removeEventListener("dispose",Q)};X.addEventListener("dispose",Q),_.__depthDisposeCallback=Q}_.__boundDepthTexture=X}if(A.depthTexture&&!_.__autoAllocateDepthBuffer)if(O)for(let X=0;X<6;X++)oe(_.__webglFramebuffer[X],A,X);else{let X=A.texture.mipmaps;X&&X.length>0?oe(_.__webglFramebuffer[0],A,0):oe(_.__webglFramebuffer,A,0)}else if(O){_.__webglDepthbuffer=[];for(let X=0;X<6;X++)if(t.bindFramebuffer(i.FRAMEBUFFER,_.__webglFramebuffer[X]),_.__webglDepthbuffer[X]===void 0)_.__webglDepthbuffer[X]=i.createRenderbuffer(),Fe(_.__webglDepthbuffer[X],A,!1);else{let Q=A.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,de=_.__webglDepthbuffer[X];i.bindRenderbuffer(i.RENDERBUFFER,de),i.framebufferRenderbuffer(i.FRAMEBUFFER,Q,i.RENDERBUFFER,de)}}else{let X=A.texture.mipmaps;if(X&&X.length>0?t.bindFramebuffer(i.FRAMEBUFFER,_.__webglFramebuffer[0]):t.bindFramebuffer(i.FRAMEBUFFER,_.__webglFramebuffer),_.__webglDepthbuffer===void 0)_.__webglDepthbuffer=i.createRenderbuffer(),Fe(_.__webglDepthbuffer,A,!1);else{let Q=A.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,de=_.__webglDepthbuffer;i.bindRenderbuffer(i.RENDERBUFFER,de),i.framebufferRenderbuffer(i.FRAMEBUFFER,Q,i.RENDERBUFFER,de)}}t.bindFramebuffer(i.FRAMEBUFFER,null)}function re(A,_,O){let X=n.get(A);_!==void 0&&me(X.__webglFramebuffer,A,A.texture,i.COLOR_ATTACHMENT0,i.TEXTURE_2D,0),O!==void 0&&H(A)}function le(A){let _=A.texture,O=n.get(A),X=n.get(_);A.addEventListener("dispose",x);let Q=A.textures,de=A.isWebGLCubeRenderTarget===!0,ge=Q.length>1;if(ge||(X.__webglTexture===void 0&&(X.__webglTexture=i.createTexture()),X.__version=_.version,a.memory.textures++),de){O.__webglFramebuffer=[];for(let ee=0;ee<6;ee++)if(_.mipmaps&&_.mipmaps.length>0){O.__webglFramebuffer[ee]=[];for(let ie=0;ie<_.mipmaps.length;ie++)O.__webglFramebuffer[ee][ie]=i.createFramebuffer()}else O.__webglFramebuffer[ee]=i.createFramebuffer()}else{if(_.mipmaps&&_.mipmaps.length>0){O.__webglFramebuffer=[];for(let ee=0;ee<_.mipmaps.length;ee++)O.__webglFramebuffer[ee]=i.createFramebuffer()}else O.__webglFramebuffer=i.createFramebuffer();if(ge)for(let ee=0,ie=Q.length;ee0&&He(A)===!1){O.__webglMultisampledFramebuffer=i.createFramebuffer(),O.__webglColorRenderbuffer=[],t.bindFramebuffer(i.FRAMEBUFFER,O.__webglMultisampledFramebuffer);for(let ee=0;ee0)for(let ie=0;ie<_.mipmaps.length;ie++)me(O.__webglFramebuffer[ee][ie],A,_,i.COLOR_ATTACHMENT0,i.TEXTURE_CUBE_MAP_POSITIVE_X+ee,ie);else me(O.__webglFramebuffer[ee],A,_,i.COLOR_ATTACHMENT0,i.TEXTURE_CUBE_MAP_POSITIVE_X+ee,0);p(_)&&T(i.TEXTURE_CUBE_MAP),t.unbindTexture()}else if(ge){for(let ee=0,ie=Q.length;ee0)for(let ie=0;ie<_.mipmaps.length;ie++)me(O.__webglFramebuffer[ie],A,_,i.COLOR_ATTACHMENT0,ee,ie);else me(O.__webglFramebuffer,A,_,i.COLOR_ATTACHMENT0,ee,0);p(_)&&T(ee),t.unbindTexture()}A.depthBuffer&&H(A)}function j(A){let _=A.textures;for(let O=0,X=_.length;O0){if(He(A)===!1){let _=A.textures,O=A.width,X=A.height,Q=i.COLOR_BUFFER_BIT,de=A.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT,ge=n.get(A),ee=_.length>1;if(ee)for(let _e=0;_e<_.length;_e++)t.bindFramebuffer(i.FRAMEBUFFER,ge.__webglMultisampledFramebuffer),i.framebufferRenderbuffer(i.FRAMEBUFFER,i.COLOR_ATTACHMENT0+_e,i.RENDERBUFFER,null),t.bindFramebuffer(i.FRAMEBUFFER,ge.__webglFramebuffer),i.framebufferTexture2D(i.DRAW_FRAMEBUFFER,i.COLOR_ATTACHMENT0+_e,i.TEXTURE_2D,null,0);t.bindFramebuffer(i.READ_FRAMEBUFFER,ge.__webglMultisampledFramebuffer);let ie=A.texture.mipmaps;ie&&ie.length>0?t.bindFramebuffer(i.DRAW_FRAMEBUFFER,ge.__webglFramebuffer[0]):t.bindFramebuffer(i.DRAW_FRAMEBUFFER,ge.__webglFramebuffer);for(let _e=0;_e<_.length;_e++){if(A.resolveDepthBuffer&&(A.depthBuffer&&(Q|=i.DEPTH_BUFFER_BIT),A.stencilBuffer&&A.resolveStencilBuffer&&(Q|=i.STENCIL_BUFFER_BIT)),ee){i.framebufferRenderbuffer(i.READ_FRAMEBUFFER,i.COLOR_ATTACHMENT0,i.RENDERBUFFER,ge.__webglColorRenderbuffer[_e]);let Ie=n.get(_[_e]).__webglTexture;i.framebufferTexture2D(i.DRAW_FRAMEBUFFER,i.COLOR_ATTACHMENT0,i.TEXTURE_2D,Ie,0)}i.blitFramebuffer(0,0,O,X,0,0,O,X,Q,i.NEAREST),l===!0&&(ae.length=0,we.length=0,ae.push(i.COLOR_ATTACHMENT0+_e),A.depthBuffer&&A.storeMultisampledDepthBuffer===!1&&(ae.push(de),we.push(de),i.invalidateFramebuffer(i.DRAW_FRAMEBUFFER,we)),i.invalidateFramebuffer(i.READ_FRAMEBUFFER,ae))}if(t.bindFramebuffer(i.READ_FRAMEBUFFER,null),t.bindFramebuffer(i.DRAW_FRAMEBUFFER,null),ee)for(let _e=0;_e<_.length;_e++){t.bindFramebuffer(i.FRAMEBUFFER,ge.__webglMultisampledFramebuffer),i.framebufferRenderbuffer(i.FRAMEBUFFER,i.COLOR_ATTACHMENT0+_e,i.RENDERBUFFER,ge.__webglColorRenderbuffer[_e]);let Ie=n.get(_[_e]).__webglTexture;t.bindFramebuffer(i.FRAMEBUFFER,ge.__webglFramebuffer),i.framebufferTexture2D(i.DRAW_FRAMEBUFFER,i.COLOR_ATTACHMENT0+_e,i.TEXTURE_2D,Ie,0)}t.bindFramebuffer(i.DRAW_FRAMEBUFFER,ge.__webglMultisampledFramebuffer)}else if(A.depthBuffer&&A.storeMultisampledDepthBuffer===!1&&l){let _=A.stencilBuffer?i.DEPTH_STENCIL_ATTACHMENT:i.DEPTH_ATTACHMENT;i.invalidateFramebuffer(i.DRAW_FRAMEBUFFER,[_])}}}function se(A){return Math.min(s.maxSamples,A.samples)}function He(A){let _=n.get(A);return A.samples>0&&e.has("WEBGL_multisampled_render_to_texture")===!0&&_.__useRenderToTexture!==!1}function L(A){let _=a.render.frame;h.get(A)!==_&&(h.set(A,_),A.update())}function st(A,_){let O=A.colorSpace,X=A.format,Q=A.type;return A.isCompressedTexture===!0||A.isVideoTexture===!0||O!==$s&&O!==ti&&(rt.getTransfer(O)===ht?(X!==fn||Q!==tn)&&Ge("WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType."):We("WebGLTextures: Unsupported texture color space:",O)),_}function Qe(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=$,this.resetTextureUnits=V,this.getTextureUnits=N,this.setTextureUnits=k,this.setTexture2D=Y,this.setTexture2DArray=F,this.setTexture3D=z,this.setTextureCube=Z,this.rebindTextures=re,this.setupRenderTarget=le,this.updateRenderTargetMipmap=j,this.updateMultisampleRenderTarget=Ae,this.setupDepthRenderbuffer=H,this.setupFrameBufferTexture=me,this.useMultisampledRTT=He,this.isReversedDepthBuffer=function(){return t.buffers.depth.getReversed()}}function W_(i,e){function t(n,s=ti){let r,a=rt.getTransfer(s);if(n===tn)return i.UNSIGNED_BYTE;if(n===co)return i.UNSIGNED_SHORT_4_4_4_4;if(n===ho)return i.UNSIGNED_SHORT_5_5_5_1;if(n===rc)return i.UNSIGNED_INT_5_9_9_9_REV;if(n===ac)return i.UNSIGNED_INT_10F_11F_11F_REV;if(n===ic)return i.BYTE;if(n===sc)return i.SHORT;if(n===Rs)return i.UNSIGNED_SHORT;if(n===lo)return i.INT;if(n===En)return i.UNSIGNED_INT;if(n===Tn)return i.FLOAT;if(n===wn)return i.HALF_FLOAT;if(n===oc)return i.ALPHA;if(n===lc)return i.RGB;if(n===fn)return i.RGBA;if(n===Dn)return i.DEPTH_COMPONENT;if(n===vi)return i.DEPTH_STENCIL;if(n===cc)return i.RED;if(n===uo)return i.RED_INTEGER;if(n===yi)return i.RG;if(n===fo)return i.RG_INTEGER;if(n===po)return i.RGBA_INTEGER;if(n===Pr||n===Ir||n===Lr||n===Dr)if(a===ht)if(r=e.get("WEBGL_compressed_texture_s3tc_srgb"),r!==null){if(n===Pr)return r.COMPRESSED_SRGB_S3TC_DXT1_EXT;if(n===Ir)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;if(n===Lr)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;if(n===Dr)return r.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT}else return null;else if(r=e.get("WEBGL_compressed_texture_s3tc"),r!==null){if(n===Pr)return r.COMPRESSED_RGB_S3TC_DXT1_EXT;if(n===Ir)return r.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(n===Lr)return r.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(n===Dr)return r.COMPRESSED_RGBA_S3TC_DXT5_EXT}else return null;if(n===mo||n===go||n===_o||n===xo)if(r=e.get("WEBGL_compressed_texture_pvrtc"),r!==null){if(n===mo)return r.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(n===go)return r.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(n===_o)return r.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(n===xo)return r.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}else return null;if(n===vo||n===yo||n===Mo||n===So||n===bo||n===Nr||n===Eo)if(r=e.get("WEBGL_compressed_texture_etc"),r!==null){if(n===vo||n===yo)return a===ht?r.COMPRESSED_SRGB8_ETC2:r.COMPRESSED_RGB8_ETC2;if(n===Mo)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:r.COMPRESSED_RGBA8_ETC2_EAC;if(n===So)return r.COMPRESSED_R11_EAC;if(n===bo)return r.COMPRESSED_SIGNED_R11_EAC;if(n===Nr)return r.COMPRESSED_RG11_EAC;if(n===Eo)return r.COMPRESSED_SIGNED_RG11_EAC}else return null;if(n===To||n===wo||n===Ao||n===Ro||n===Co||n===Po||n===Io||n===Lo||n===Do||n===No||n===Uo||n===Fo||n===Oo||n===Bo)if(r=e.get("WEBGL_compressed_texture_astc"),r!==null){if(n===To)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:r.COMPRESSED_RGBA_ASTC_4x4_KHR;if(n===wo)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:r.COMPRESSED_RGBA_ASTC_5x4_KHR;if(n===Ao)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:r.COMPRESSED_RGBA_ASTC_5x5_KHR;if(n===Ro)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:r.COMPRESSED_RGBA_ASTC_6x5_KHR;if(n===Co)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:r.COMPRESSED_RGBA_ASTC_6x6_KHR;if(n===Po)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:r.COMPRESSED_RGBA_ASTC_8x5_KHR;if(n===Io)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:r.COMPRESSED_RGBA_ASTC_8x6_KHR;if(n===Lo)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:r.COMPRESSED_RGBA_ASTC_8x8_KHR;if(n===Do)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:r.COMPRESSED_RGBA_ASTC_10x5_KHR;if(n===No)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:r.COMPRESSED_RGBA_ASTC_10x6_KHR;if(n===Uo)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:r.COMPRESSED_RGBA_ASTC_10x8_KHR;if(n===Fo)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:r.COMPRESSED_RGBA_ASTC_10x10_KHR;if(n===Oo)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:r.COMPRESSED_RGBA_ASTC_12x10_KHR;if(n===Bo)return a===ht?r.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:r.COMPRESSED_RGBA_ASTC_12x12_KHR}else return null;if(n===zo||n===ko||n===Vo)if(r=e.get("EXT_texture_compression_bptc"),r!==null){if(n===zo)return a===ht?r.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT:r.COMPRESSED_RGBA_BPTC_UNORM_EXT;if(n===ko)return r.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;if(n===Vo)return r.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT}else return null;if(n===Ho||n===Go||n===Ur||n===Wo)if(r=e.get("EXT_texture_compression_rgtc"),r!==null){if(n===Ho)return r.COMPRESSED_RED_RGTC1_EXT;if(n===Go)return r.COMPRESSED_SIGNED_RED_RGTC1_EXT;if(n===Ur)return r.COMPRESSED_RED_GREEN_RGTC2_EXT;if(n===Wo)return r.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT}else return null;return n===Cs?i.UNSIGNED_INT_24_8:i[n]!==void 0?i[n]:null}return{convert:t}}var X_=` +void main() { + + gl_Position = vec4( position, 1.0 ); + +}`,q_=` +uniform sampler2DArray depthColor; +uniform float depthWidth; +uniform float depthHeight; + +void main() { + + vec2 coord = vec2( gl_FragCoord.x / depthWidth, gl_FragCoord.y / depthHeight ); + + if ( coord.x >= 1.0 ) { + + gl_FragDepth = texture( depthColor, vec3( coord.x - 1.0, coord.y, 1 ) ).r; + + } else { + + gl_FragDepth = texture( depthColor, vec3( coord.x, coord.y, 0 ) ).r; + + } + +}`,Fc=class{constructor(){this.texture=null,this.mesh=null,this.depthNear=0,this.depthFar=0}init(e,t){if(this.texture===null){let n=new lr(e.texture);(e.depthNear!==t.depthNear||e.depthFar!==t.depthFar)&&(this.depthNear=e.depthNear,this.depthFar=e.depthFar),this.texture=n}}getMesh(e){if(this.texture!==null&&this.mesh===null){let t=e.cameras[0].viewport,n=new an({vertexShader:X_,fragmentShader:q_,uniforms:{depthColor:{value:this.texture},depthWidth:{value:t.z},depthHeight:{value:t.w}}});this.mesh=new $e(new Et(20,20),n)}return this.mesh}reset(){this.texture=null,this.mesh=null}getDepthTexture(){return this.texture}},Oc=class extends Nn{constructor(e,t){super();let n=this,s=null,r=1,a=null,o="local-floor",l=1,c=null,h=null,u=null,d=null,f=null,m=null,v=typeof XRWebGLBinding<"u",g=new Fc,p={},T=t.getContextAttributes(),w=null,M=null,b=[],S=[],R=new ue,x=null,E=null,C=new Xt;C.viewport=new Mt;let P=new Xt;P.viewport=new Mt;let B=[C,P],V=new to,N=null,k=null;this.cameraAutoUpdate=!0,this.enabled=!1,this.isPresenting=!1,this.getController=function(K){let ne=b[K];return ne===void 0&&(ne=new ds,b[K]=ne),ne.getTargetRaySpace()},this.getControllerGrip=function(K){let ne=b[K];return ne===void 0&&(ne=new ds,b[K]=ne),ne.getGripSpace()},this.getHand=function(K){let ne=b[K];return ne===void 0&&(ne=new ds,b[K]=ne),ne.getHandSpace()};function $(K){let ne=S.indexOf(K.inputSource);if(ne===-1)return;let pe=b[ne];pe!==void 0&&(pe.update(K.inputSource,K.frame,c||a),pe.dispatchEvent({type:K.type,data:K.inputSource}))}function q(){s.removeEventListener("select",$),s.removeEventListener("selectstart",$),s.removeEventListener("selectend",$),s.removeEventListener("squeeze",$),s.removeEventListener("squeezestart",$),s.removeEventListener("squeezeend",$),s.removeEventListener("end",q),s.removeEventListener("inputsourceschange",Y);for(let K=0;K=0&&(S[De]=null,b[De].disconnect(pe))}for(let ne=0;ne=S.length){S.push(pe),De=Fe;break}else if(S[Fe]===null){S[Fe]=pe,De=Fe;break}if(De===-1)break}let me=b[De];me&&me.connect(pe)}}let F=new I,z=new I;function Z(K,ne,pe){F.setFromMatrixPosition(ne.matrixWorld),z.setFromMatrixPosition(pe.matrixWorld);let De=F.distanceTo(z),me=ne.projectionMatrix.elements,Fe=pe.projectionMatrix.elements,oe=me[14]/(me[10]-1),H=me[14]/(me[10]+1),re=(me[9]+1)/me[5],le=(me[9]-1)/me[5],j=(me[8]-1)/me[0],ae=(Fe[8]+1)/Fe[0],we=oe*j,Ae=oe*ae,se=De/(-j+ae),He=se*-j;if(ne.matrixWorld.decompose(K.position,K.quaternion,K.scale),K.translateX(He),K.translateZ(se),K.matrixWorld.compose(K.position,K.quaternion,K.scale),K.matrixWorldInverse.copy(K.matrixWorld).invert(),me[10]===-1)K.projectionMatrix.copy(ne.projectionMatrix),K.projectionMatrixInverse.copy(ne.projectionMatrixInverse);else{let L=oe+se,st=H+se,Qe=we-He,A=Ae+(De-He),_=re*H/st*L,O=le*H/st*L;K.projectionMatrix.makePerspective(Qe,A,_,O,L,st),K.projectionMatrixInverse.copy(K.projectionMatrix).invert()}}function fe(K,ne){ne===null?K.matrixWorld.copy(K.matrix):K.matrixWorld.multiplyMatrices(ne.matrixWorld,K.matrix),K.matrixWorldInverse.copy(K.matrixWorld).invert()}this.updateCamera=function(K){if(s===null)return;let ne=K.near,pe=K.far;g.texture!==null&&(g.depthNear>0&&(ne=g.depthNear),g.depthFar>0&&(pe=g.depthFar)),V.near=P.near=C.near=ne,V.far=P.far=C.far=pe,(N!==V.near||k!==V.far)&&(s.updateRenderState({depthNear:V.near,depthFar:V.far}),N=V.near,k=V.far),V.layers.mask=K.layers.mask|6,C.layers.mask=V.layers.mask&-5,P.layers.mask=V.layers.mask&-3;let De=K.parent,me=V.cameras;fe(V,De);for(let Fe=0;Fe0&&(g.alphaTest.value=p.alphaTest);let T=e.get(p),w=T.envMap,M=T.envMapRotation;w&&(g.envMap.value=w,g.envMapRotation.value.setFromMatrix4(Y_.makeRotationFromEuler(M)).transpose(),w.isCubeTexture&&w.isRenderTargetTexture===!1&&g.envMapRotation.value.premultiply(Qu),g.reflectivity.value=p.reflectivity,g.ior.value=p.ior,g.refractionRatio.value=p.refractionRatio),p.lightMap&&(g.lightMap.value=p.lightMap,g.lightMapIntensity.value=p.lightMapIntensity,t(p.lightMap,g.lightMapTransform)),p.aoMap&&(g.aoMap.value=p.aoMap,g.aoMapIntensity.value=p.aoMapIntensity,t(p.aoMap,g.aoMapTransform))}function a(g,p){g.diffuse.value.copy(p.color),g.opacity.value=p.opacity,p.map&&(g.map.value=p.map,t(p.map,g.mapTransform))}function o(g,p){g.dashSize.value=p.dashSize,g.totalSize.value=p.dashSize+p.gapSize,g.scale.value=p.scale}function l(g,p,T,w){g.diffuse.value.copy(p.color),g.opacity.value=p.opacity,g.size.value=p.size*T,g.scale.value=w*.5,p.map&&(g.map.value=p.map,t(p.map,g.uvTransform)),p.alphaMap&&(g.alphaMap.value=p.alphaMap,t(p.alphaMap,g.alphaMapTransform)),p.alphaTest>0&&(g.alphaTest.value=p.alphaTest)}function c(g,p){g.diffuse.value.copy(p.color),g.opacity.value=p.opacity,g.rotation.value=p.rotation,p.map&&(g.map.value=p.map,t(p.map,g.mapTransform)),p.alphaMap&&(g.alphaMap.value=p.alphaMap,t(p.alphaMap,g.alphaMapTransform)),p.alphaTest>0&&(g.alphaTest.value=p.alphaTest)}function h(g,p){g.specular.value.copy(p.specular),g.shininess.value=Math.max(p.shininess,1e-4)}function u(g,p){p.gradientMap&&(g.gradientMap.value=p.gradientMap)}function d(g,p){g.metalness.value=p.metalness,p.metalnessMap&&(g.metalnessMap.value=p.metalnessMap,t(p.metalnessMap,g.metalnessMapTransform)),g.roughness.value=p.roughness,p.roughnessMap&&(g.roughnessMap.value=p.roughnessMap,t(p.roughnessMap,g.roughnessMapTransform)),p.envMap&&(g.envMapIntensity.value=p.envMapIntensity)}function f(g,p,T){g.ior.value=p.ior,p.sheen>0&&(g.sheenColor.value.copy(p.sheenColor).multiplyScalar(p.sheen),g.sheenRoughness.value=p.sheenRoughness,p.sheenColorMap&&(g.sheenColorMap.value=p.sheenColorMap,t(p.sheenColorMap,g.sheenColorMapTransform)),p.sheenRoughnessMap&&(g.sheenRoughnessMap.value=p.sheenRoughnessMap,t(p.sheenRoughnessMap,g.sheenRoughnessMapTransform))),p.clearcoat>0&&(g.clearcoat.value=p.clearcoat,g.clearcoatRoughness.value=p.clearcoatRoughness,p.clearcoatMap&&(g.clearcoatMap.value=p.clearcoatMap,t(p.clearcoatMap,g.clearcoatMapTransform)),p.clearcoatRoughnessMap&&(g.clearcoatRoughnessMap.value=p.clearcoatRoughnessMap,t(p.clearcoatRoughnessMap,g.clearcoatRoughnessMapTransform)),p.clearcoatNormalMap&&(g.clearcoatNormalMap.value=p.clearcoatNormalMap,t(p.clearcoatNormalMap,g.clearcoatNormalMapTransform),g.clearcoatNormalScale.value.copy(p.clearcoatNormalScale),p.side===It&&g.clearcoatNormalScale.value.negate())),p.dispersion>0&&(g.dispersion.value=p.dispersion),p.retroreflectivity>0&&(g.retroreflectivity.value=p.retroreflectivity),p.iridescence>0&&(g.iridescence.value=p.iridescence,g.iridescenceIOR.value=p.iridescenceIOR,g.iridescenceThicknessMinimum.value=p.iridescenceThicknessRange[0],g.iridescenceThicknessMaximum.value=p.iridescenceThicknessRange[1],p.iridescenceMap&&(g.iridescenceMap.value=p.iridescenceMap,t(p.iridescenceMap,g.iridescenceMapTransform)),p.iridescenceThicknessMap&&(g.iridescenceThicknessMap.value=p.iridescenceThicknessMap,t(p.iridescenceThicknessMap,g.iridescenceThicknessMapTransform))),p.transmission>0&&(g.transmission.value=p.transmission,g.transmissionSamplerMap.value=T.texture,g.transmissionSamplerSize.value.set(T.width,T.height),p.transmissionMap&&(g.transmissionMap.value=p.transmissionMap,t(p.transmissionMap,g.transmissionMapTransform)),g.thickness.value=p.thickness,p.thicknessMap&&(g.thicknessMap.value=p.thicknessMap,t(p.thicknessMap,g.thicknessMapTransform)),g.attenuationDistance.value=p.attenuationDistance,g.attenuationColor.value.copy(p.attenuationColor)),p.anisotropy>0&&(g.anisotropyVector.value.set(p.anisotropy*Math.cos(p.anisotropyRotation),p.anisotropy*Math.sin(p.anisotropyRotation)),p.anisotropyMap&&(g.anisotropyMap.value=p.anisotropyMap,t(p.anisotropyMap,g.anisotropyMapTransform))),g.specularIntensity.value=p.specularIntensity,g.specularColor.value.copy(p.specularColor),p.specularColorMap&&(g.specularColorMap.value=p.specularColorMap,t(p.specularColorMap,g.specularColorMapTransform)),p.specularIntensityMap&&(g.specularIntensityMap.value=p.specularIntensityMap,t(p.specularIntensityMap,g.specularIntensityMapTransform))}function m(g,p){p.matcap&&(g.matcap.value=p.matcap)}function v(g,p){let T=e.get(p).light;g.referencePosition.value.setFromMatrixPosition(T.matrixWorld),g.nearDistance.value=T.shadow.camera.near,g.farDistance.value=T.shadow.camera.far}return{refreshFogUniforms:n,refreshMaterialUniforms:s}}function J_(i,e,t,n){let s={},r={},a=[],o=i.getParameter(i.MAX_UNIFORM_BUFFER_BINDINGS);function l(M,b){let S=b.program;n.uniformBlockBinding(M,S)}function c(M,b){let S=s[M.id];S===void 0&&(g(M),S=h(M),s[M.id]=S,M.addEventListener("dispose",T));let R=b.program;n.updateUBOMapping(M,R);let x=e.render.frame;r[M.id]!==x&&(d(M),r[M.id]=x)}function h(M){let b=u();M.__bindingPointIndex=b;let S=i.createBuffer(),R=M.__size,x=M.usage;return i.bindBuffer(i.UNIFORM_BUFFER,S),i.bufferData(i.UNIFORM_BUFFER,R,x),i.bindBuffer(i.UNIFORM_BUFFER,null),i.bindBufferBase(i.UNIFORM_BUFFER,b,S),S}function u(){for(let M=0;M0&&(S+=R-x),M.__size=S,M.__cache={},this}function p(M){let b={boundary:0,storage:0};return typeof M=="number"||typeof M=="boolean"?(b.boundary=4,b.storage=4):M.isVector2?(b.boundary=8,b.storage=8):M.isVector3||M.isColor?(b.boundary=16,b.storage=12):M.isVector4?(b.boundary=16,b.storage=16):M.isMatrix3?(b.boundary=48,b.storage=48):M.isMatrix4?(b.boundary=64,b.storage=64):M.isTexture?Ge("WebGLRenderer: Texture samplers can not be part of an uniforms group."):ArrayBuffer.isView(M)?(b.boundary=16,b.storage=M.byteLength):Ge("WebGLRenderer: Unsupported uniform value type.",M),b}function T(M){let b=M.target;b.removeEventListener("dispose",T);let S=a.indexOf(b.__bindingPointIndex);a.splice(S,1),i.deleteBuffer(s[b.id]),delete s[b.id],delete r[b.id]}function w(){for(let M in s)i.deleteBuffer(s[M]);a=[],s={},r={}}return{bind:l,update:c,dispose:w}}var $_=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]),kn=null;function K_(){return kn===null&&(kn=new ms($_,16,16,yi,wn),kn.name="DFG_LUT",kn.minFilter=zt,kn.magFilter=zt,kn.wrapS=In,kn.wrapT=In,kn.generateMipmaps=!1,kn.needsUpdate=!0),kn}var Ko=class{constructor(e={}){let{canvas:t=du(),context:n=null,depth:s=!0,stencil:r=!1,alpha:a=!1,antialias:o=!1,premultipliedAlpha:l=!0,preserveDrawingBuffer:c=!1,powerPreference:h="default",failIfMajorPerformanceCaveat:u=!1,reversedDepthBuffer:d=!1,outputBufferType:f=tn}=e;this.isWebGLRenderer=!0;let m;if(n!==null){if(typeof WebGLRenderingContext<"u"&&n instanceof WebGLRenderingContext)throw new Error("THREE.WebGLRenderer: WebGL 1 is not supported since r163.");m=n.getContextAttributes().alpha}else m=a;let v=f,g=new Set([po,fo,uo]),p=new Set([tn,En,Rs,Cs,co,ho]),T=new Uint32Array(4),w=new Int32Array(4),M=new I,b=null,S=null,R=[],x=[],E=null;this.domElement=t,this.debug={checkShaderErrors:!0,diagnostics:{keywords:!1},onShaderError:null},this.autoClear=!0,this.autoClearColor=!0,this.autoClearDepth=!0,this.autoClearStencil=!0,this.sortObjects=!0,this.clippingPlanes=[],this.localClippingEnabled=!1,this.toneMapping=bn,this.toneMappingExposure=1,this.transmissionResolutionScale=1;let C=this,P=!1,B=null,V=null,N=null,k=null;this._outputColorSpace=St;let $=0,q=0,Y=null,F=-1,z=null,Z=new Mt,fe=new Mt,he=null,qe=new Xe(0),Ve=0,Ye=t.width,K=t.height,ne=1,pe=null,De=null,me=new Mt(0,0,Ye,K),Fe=new Mt(0,0,Ye,K),oe=!1,H=new gs,re=!1,le=!1,j=new gt,ae=new I,we=new Mt,Ae={background:null,fog:null,environment:null,overrideMaterial:null,isScene:!0},se=!1;function He(){return Y===null?ne:1}let L=n;function st(y,D){return t.getContext(y,D)}let Qe,A,_,O,X,Q,de,ge,ee,ie,_e,Ie,Me,xe,Oe,ke,Ze,U,ve,te,ye,Se,ce;try{let y={alpha:!0,depth:s,stencil:r,antialias:o,premultipliedAlpha:l,preserveDrawingBuffer:c,powerPreference:h,failIfMajorPerformanceCaveat:u};if("setAttribute"in t&&t.setAttribute("data-engine",`three.js r${"186"}`),t.addEventListener("webglcontextlost",lt,!1),t.addEventListener("webglcontextrestored",Re,!1),t.addEventListener("webglcontextcreationerror",at,!1),L===null){let D="webgl2";if(L=st(D,y),L===null)throw st(D)?new Error("THREE.WebGLRenderer: Error creating WebGL context with your selected attributes."):new Error("THREE.WebGLRenderer: Error creating WebGL context.")}Be()}catch(y){throw t.removeEventListener("webglcontextlost",lt,!1),t.removeEventListener("webglcontextrestored",Re,!1),t.removeEventListener("webglcontextcreationerror",at,!1),We("WebGLRenderer: "+y.message),y}function Be(){Qe=new s0(L),Qe.init(),ye=new W_(L,Qe),A=new Zg(L,Qe,e,ye),_=new H_(L,Qe),A.reversedDepthBuffer&&d&&_.buffers.depth.setReversed(!0),V=L.createFramebuffer(),N=L.createFramebuffer(),k=L.createFramebuffer(),O=new o0(L),X=new R_,Q=new G_(L,Qe,_,X,A,ye,O),de=new i0(C),ge=new cp(L),Se=new qg(L,ge),ee=new r0(L,ge,O,Se),ie=new c0(L,ee,ge,Se,O),U=new l0(L,A,Q),Oe=new Jg(X),_e=new A_(C,de,Qe,A,Se,Oe),Ie=new Z_(C,X),Me=new P_,xe=new F_(Qe),Ze=new Xg(C,de,_,ie,m,l),ke=new V_(C,ie,A),ce=new J_(L,O,A,_),ve=new Yg(L,Qe,O),te=new a0(L,Qe,O),O.programs=_e.programs,C.capabilities=A,C.extensions=Qe,C.properties=X,C.renderLists=Me,C.shadowMap=ke,C.state=_,C.info=O}v!==tn&&(E=new u0(v,t.width,t.height,o,s,r));let Le=new Oc(C,L);this.xr=Le,this.getContext=function(){return L},this.getContextAttributes=function(){return L.getContextAttributes()},this.forceContextLoss=function(){let y=Qe.get("WEBGL_lose_context");y&&y.loseContext()},this.forceContextRestore=function(){let y=Qe.get("WEBGL_lose_context");y&&y.restoreContext()},this.getPixelRatio=function(){return ne},this.setPixelRatio=function(y){y!==void 0&&(ne=y,this.setSize(Ye,K,!1))},this.getSize=function(y){return y.set(Ye,K)},this.setSize=function(y,D,J=!0){if(Le.isPresenting){Ge("WebGLRenderer: Can't change size while VR device is presenting.");return}Ye=y,K=D,t.width=Math.floor(y*ne),t.height=Math.floor(D*ne),J===!0&&(t.style.width=y+"px",t.style.height=D+"px"),E!==null&&E.setSize(t.width,t.height),this.setViewport(0,0,y,D)},this.getDrawingBufferSize=function(y){return y.set(Ye*ne,K*ne).floor()},this.setDrawingBufferSize=function(y,D,J){Ye=y,K=D,ne=J,t.width=Math.floor(y*J),t.height=Math.floor(D*J),this.setViewport(0,0,y,D)},this.setEffects=function(y){if(v===tn){We("WebGLRenderer: setEffects() requires outputBufferType set to HalfFloatType or FloatType.");return}if(y){for(let D=0;D{function Te(){if(G.forEach(function(Pe){let Ne=X.get(Pe).currentProgram;(Ne===void 0||Ne.isReady())&&G.delete(Pe)}),G.size===0){W(y);return}setTimeout(Te,10)}Qe.get("KHR_parallel_shader_compile")!==null?Te():setTimeout(Te,10)})};let ol=null;function Pd(y){ol&&ol(y)}function Yc(){Si.stop()}function Zc(){Si.start()}let Si=new qu;Si.setAnimationLoop(Pd),typeof self<"u"&&Si.setContext(self),this.setAnimationLoop=function(y){ol=y,Le.setAnimationLoop(y),y===null?Si.stop():Si.start()},Le.addEventListener("sessionstart",Yc),Le.addEventListener("sessionend",Zc),this.render=function(y,D){if(D!==void 0&&D.isCamera!==!0){We("WebGLRenderer.render: camera is not an instance of THREE.Camera.");return}if(P===!0)return;B!==null&&B.renderStart(y,D);let J=Le.enabled===!0&&Le.isPresenting===!0,G=E!==null&&(Y===null||J)&&E.begin(C,Y);if(y.matrixWorldAutoUpdate===!0&&y.updateMatrixWorld(),D.parent===null&&D.matrixWorldAutoUpdate===!0&&D.updateMatrixWorld(),Le.enabled===!0&&Le.isPresenting===!0&&(E===null||E.isCompositing()===!1)&&(Le.cameraAutoUpdate===!0&&Le.updateCamera(D),D=Le.getCamera()),y.isScene===!0&&y.onBeforeRender(C,y,D,Y),S=xe.get(y,x.length),S.init(D),S.state.textureUnits=Q.getTextureUnits(),x.push(S),j.multiplyMatrices(D.projectionMatrix,D.matrixWorldInverse),H.setFromProjectionMatrix(j,Mn,D.reversedDepth),le=this.localClippingEnabled,re=Oe.init(this.clippingPlanes,le),b=Me.get(y,R.length),b.init(),R.push(b),Le.enabled===!0&&Le.isPresenting===!0){let Pe=C.xr.getDepthSensingMesh();Pe!==null&&ll(Pe,D,-1/0,C.sortObjects)}ll(y,D,0,C.sortObjects),b.finish(),B!==null&&B.updateLights(S.state.lightsArray),C.sortObjects===!0&&b.sort(pe,De),se=Le.enabled===!1||Le.isPresenting===!1||Le.hasDepthSensing()===!1,se&&Ze.addToRenderList(b,y),this.info.render.frame++,this.info.autoReset===!0&&this.info.reset(),re===!0&&Oe.beginShadows();let W=S.state.shadowsArray;if(ke.render(W,y,D),re===!0&&Oe.endShadows(),(G&&E.hasRenderPass())===!1){let Pe=b.opaque,Ee=b.transmissive;if(S.setupLights(),D.isArrayCamera){let Ne=D.cameras;if(Ee.length>0)for(let ze=0,je=Ne.length;ze0&&$c(Pe,Ee,y,D),se&&Ze.render(y),Jc(b,y,D)}Y!==null&&q===0&&(Q.updateMultisampleRenderTarget(Y),Q.updateRenderTargetMipmap(Y)),G&&E.end(C),y.isScene===!0&&y.onAfterRender(C,y,D),Se.resetDefaultState(),F=-1,z=null,x.pop(),x.length>0?(S=x[x.length-1],Q.setTextureUnits(S.state.textureUnits),re===!0&&Oe.setGlobalState(C.clippingPlanes,S.state.camera)):S=null,R.pop(),R.length>0?b=R[R.length-1]:b=null,B!==null&&B.renderEnd()};function ll(y,D,J,G){if(y.visible===!1)return;if(y.layers.test(D.layers)){if(y.isGroup)J=y.renderOrder;else if(y.isLOD)y.autoUpdate===!0&&y.update(D);else if(y.isLightProbeGrid)S.pushLightProbeGrid(y);else if(y.isLight)S.pushLight(y),y.castShadow&&S.pushShadow(y);else if(y.isSprite){if(!y.frustumCulled||y.intersectsFrustum(H)){G&&we.setFromMatrixPosition(y.matrixWorld).applyMatrix4(j);let Pe=ie.update(y),Ee=y.material;Ee.visible&&b.push(y,Pe,Ee,J,we.z,null,D)}}else if((y.isMesh||y.isLine||y.isPoints)&&(!y.frustumCulled||y.intersectsFrustum(H))){let Pe=ie.update(y),Ee=y.material;if(G&&(y.boundingSphere!==void 0?(y.boundingSphere===null&&y.computeBoundingSphere(),we.copy(y.boundingSphere.center)):(Pe.boundingSphere===null&&Pe.computeBoundingSphere(),we.copy(Pe.boundingSphere.center)),we.applyMatrix4(y.matrixWorld).applyMatrix4(j)),Array.isArray(Ee)){let Ne=Pe.groups;for(let ze=0,je=Ne.length;ze0&&Xr(W,D,J),Te.length>0&&Xr(Te,D,J),Pe.length>0&&Xr(Pe,D,J),_.buffers.depth.setTest(!0),_.buffers.depth.setMask(!0),_.buffers.color.setMask(!0),_.setPolygonOffset(!1)}function $c(y,D,J,G){if((J.isScene===!0?J.overrideMaterial:null)!==null)return;if(S.state.transmissionRenderTarget[G.id]===void 0){let Ue=Qe.has("EXT_color_buffer_half_float")||Qe.has("EXT_color_buffer_float");S.state.transmissionRenderTarget[G.id]=new en(1,1,{generateMipmaps:!0,type:Ue?wn:tn,minFilter:zn,samples:Math.max(4,A.samples),stencilBuffer:r,resolveDepthBuffer:!1,resolveStencilBuffer:!1,storeMultisampledDepthBuffer:!1,storeMultisampledStencilBuffer:!1,colorSpace:rt.workingColorSpace})}let Te=S.state.transmissionRenderTarget[G.id],Pe=G.viewport||Z;Te.setSize(Pe.z*C.transmissionResolutionScale,Pe.w*C.transmissionResolutionScale);let Ee=C.getRenderTarget(),Ne=C.getActiveCubeFace(),ze=C.getActiveMipmapLevel();C.setRenderTarget(Te),C.getClearColor(qe),Ve=C.getClearAlpha(),Ve<1&&C.setClearColor(16777215,.5),C.clear(),se&&Ze.render(J);let je=C.toneMapping;C.toneMapping=bn;let it=G.viewport;if(G.viewport!==void 0&&(G.viewport=void 0),S.setupLightsView(G),re===!0&&Oe.setGlobalState(C.clippingPlanes,G),Xr(y,J,G),Q.updateMultisampleRenderTarget(Te),Q.updateRenderTargetMipmap(Te),Qe.has("WEBGL_multisampled_render_to_texture")===!1){let Ue=!1;for(let ct=0,Rt=D.length;ct0,G.currentProgram=it,G.uniformsList=null,it}function Qc(y){if(y.uniformsList===null){let D=y.currentProgram.getUniforms();y.uniformsList=Ls.seqWithValue(D.seq,y.uniforms)}return y.uniformsList}function jc(y,D){let J=X.get(y);J.outputColorSpace=D.outputColorSpace,J.batching=D.batching,J.batchingColor=D.batchingColor,J.instancing=D.instancing,J.instancingColor=D.instancingColor,J.instancingMorph=D.instancingMorph,J.skinning=D.skinning,J.morphTargets=D.morphTargets,J.morphNormals=D.morphNormals,J.morphColors=D.morphColors,J.morphTargetsCount=D.morphTargetsCount,J.numClippingPlanes=D.numClippingPlanes,J.numIntersection=D.numClipIntersection,J.vertexAlphas=D.vertexAlphas,J.vertexTangents=D.vertexTangents,J.toneMapping=D.toneMapping}function Id(y,D){if(y.length===0)return null;if(y.length===1)return y[0].texture!==null?y[0]:null;M.setFromMatrixPosition(D.matrixWorld);for(let J=0,G=y.length;J0),Ue=!!J.morphAttributes.position,ct=!!J.morphAttributes.normal,Rt=!!J.morphAttributes.color,xt=bn;G.toneMapped&&(Y===null||Y.isXRRenderTarget===!0)&&(xt=C.toneMapping);let ft=J.morphAttributes.position||J.morphAttributes.normal||J.morphAttributes.color,Ht=ft!==void 0?ft.length:0,Ce=X.get(G),Kt=S.state.lights;if(re===!0&&(le===!0||y!==z)){let mt=y===z&&G.id===F;Oe.setState(G,y,mt)}let ot=!1;G.version===Ce.__version?(Ce.needsLights&&Ce.lightsStateVersion!==Kt.state.version||Ce.outputColorSpace!==Ee||W.isBatchedMesh&&Ce.batching===!1||!W.isBatchedMesh&&Ce.batching===!0||W.isBatchedMesh&&Ce.batchingColor===!0&&W._colorsTexture===null||W.isBatchedMesh&&Ce.batchingColor===!1&&W._colorsTexture!==null||W.isInstancedMesh&&Ce.instancing===!1||!W.isInstancedMesh&&Ce.instancing===!0||W.isSkinnedMesh&&Ce.skinning===!1||!W.isSkinnedMesh&&Ce.skinning===!0||W.isInstancedMesh&&Ce.instancingColor===!0&&W.instanceColor===null||W.isInstancedMesh&&Ce.instancingColor===!1&&W.instanceColor!==null||W.isInstancedMesh&&Ce.instancingMorph===!0&&W.morphTexture===null||W.isInstancedMesh&&Ce.instancingMorph===!1&&W.morphTexture!==null||Ce.envMap!==ze||G.fog===!0&&Ce.fog!==Te||Ce.numClippingPlanes!==void 0&&(Ce.numClippingPlanes!==Oe.numPlanes||Ce.numIntersection!==Oe.numIntersection)||Ce.vertexAlphas!==je||Ce.vertexTangents!==it||Ce.morphTargets!==Ue||Ce.morphNormals!==ct||Ce.morphColors!==Rt||Ce.toneMapping!==xt||Ce.morphTargetsCount!==Ht||!!Ce.lightProbeGrid!=S.state.lightProbeGridArray.length>0)&&(ot=!0):(ot=!0,Ce.__version=G.version);let hn=Ce.currentProgram;ot===!0&&(hn=qr(G,D,W),B&&G.isNodeMaterial&&B.onUpdateProgram(G,hn,Ce));let Cn=!1,ii=!1,Bi=!1,dt=hn.getUniforms(),wt=Ce.uniforms;if(_.useProgram(hn.program)&&(Cn=!0,ii=!0,Bi=!0),G.id!==F&&(F=G.id,ii=!0),Ce.needsLights){let mt=Id(S.state.lightProbeGridArray,W);Ce.lightProbeGrid!==mt&&(Ce.lightProbeGrid=mt,ii=!0)}if(Cn||z!==y){_.buffers.depth.getReversed()&&y.reversedDepth!==!0&&(y._reversedDepth=!0,y.updateProjectionMatrix()),dt.setValue(L,"projectionMatrix",y.projectionMatrix),dt.setValue(L,"viewMatrix",y.matrixWorldInverse);let ri=dt.map.cameraPosition;ri!==void 0&&ri.setValue(L,ae.setFromMatrixPosition(y.matrixWorld)),A.logarithmicDepthBuffer&&dt.setValue(L,"logDepthBufFC",2/(Math.log(y.far+1)/Math.LN2)),(G.isMeshPhongMaterial||G.isMeshToonMaterial||G.isMeshLambertMaterial||G.isMeshBasicMaterial||G.isMeshStandardMaterial||G.isShaderMaterial)&&dt.setValue(L,"isOrthographic",y.isOrthographicCamera===!0),z!==y&&(z=y,ii=!0,Bi=!0)}if(Ce.needsLights&&(Kt.state.sunShadowMap.length>0&&dt.setValue(L,"sunShadowMap",Kt.state.sunShadowMap,Q),Kt.state.directionalShadowMap.length>0&&dt.setValue(L,"directionalShadowMap",Kt.state.directionalShadowMap,Q),Kt.state.spotShadowMap.length>0&&dt.setValue(L,"spotShadowMap",Kt.state.spotShadowMap,Q),Kt.state.pointShadowMap.length>0&&dt.setValue(L,"pointShadowMap",Kt.state.pointShadowMap,Q)),W.isSkinnedMesh){dt.setOptional(L,W,"bindMatrix"),dt.setOptional(L,W,"bindMatrixInverse");let mt=W.skeleton;mt&&(mt.boneTexture===null&&mt.computeBoneTexture(),dt.setValue(L,"boneTexture",mt.boneTexture,Q))}W.isBatchedMesh&&(dt.setOptional(L,W,"batchingTexture"),dt.setValue(L,"batchingTexture",W._matricesTexture,Q),dt.setOptional(L,W,"batchingIdTexture"),dt.setValue(L,"batchingIdTexture",W._indirectTexture,Q),dt.setOptional(L,W,"batchingColorTexture"),W._colorsTexture!==null&&dt.setValue(L,"batchingColorTexture",W._colorsTexture,Q));let si=J.morphAttributes;if((si.position!==void 0||si.normal!==void 0||si.color!==void 0)&&U.update(W,J,hn),(ii||Ce.receiveShadow!==W.receiveShadow)&&(Ce.receiveShadow=W.receiveShadow,dt.setValue(L,"receiveShadow",W.receiveShadow)),(G.isMeshStandardMaterial||G.isMeshLambertMaterial||G.isMeshPhongMaterial)&&G.envMap===null&&D.environment!==null&&(wt.envMapIntensity.value=D.environmentIntensity),wt.dfgLUT!==void 0&&(wt.dfgLUT.value=K_()),ii){if(dt.setValue(L,"toneMappingExposure",C.toneMappingExposure),Ce.needsLights&&Dd(wt,Bi),Te&&G.fog===!0&&Ie.refreshFogUniforms(wt,Te),Ie.refreshMaterialUniforms(wt,G,ne,K,S.state.transmissionRenderTarget[y.id]),Ce.needsLights&&Ce.lightProbeGrid){let mt=Ce.lightProbeGrid;wt.probesSH.value=mt.texture,wt.probesMin.value.copy(mt.boundingBox.min),wt.probesMax.value.copy(mt.boundingBox.max),wt.probesResolution.value.copy(mt.resolution)}Ls.upload(L,Qc(Ce),wt,Q)}if(G.isShaderMaterial&&G.uniformsNeedUpdate===!0&&(Ls.upload(L,Qc(Ce),wt,Q),G.uniformsNeedUpdate=!1),G.isSpriteMaterial&&dt.setValue(L,"center",W.center),dt.setValue(L,"modelViewMatrix",W.modelViewMatrix),dt.setValue(L,"normalMatrix",W.normalMatrix),dt.setValue(L,"modelMatrix",W.matrixWorld),G.uniformsGroups!==void 0){let mt=G.uniformsGroups;for(let ri=0,zi=mt.length;ri0&&Q.useMultisampledRTT(y)===!1?G=X.get(y).__webglMultisampledFramebuffer:Array.isArray(ze)?G=ze[J]:G=ze,Z.copy(y.viewport),fe.copy(y.scissor),he=y.scissorTest}else Z.copy(me).multiplyScalar(ne).floor(),fe.copy(Fe).multiplyScalar(ne).floor(),he=oe;if(J!==0&&(G=V),_.bindFramebuffer(L.FRAMEBUFFER,G)&&_.drawBuffers(y,G),_.viewport(Z),_.scissor(fe),_.setScissorTest(he),W){let Ee=X.get(y.texture);L.framebufferTexture2D(L.FRAMEBUFFER,L.COLOR_ATTACHMENT0,L.TEXTURE_CUBE_MAP_POSITIVE_X+D,Ee.__webglTexture,J)}else if(Te){let Ee=D;for(let Ne=0;Ne1&&L.readBuffer(L.COLOR_ATTACHMENT0+Ee);let Ue=eh(ze);if(Ue.__formatReadable===!1){We("WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.");return}if(Ue.__typeReadable===!1){We("WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.");return}D>=0&&D<=y.width-G&&J>=0&&J<=y.height-W&&L.readPixels(D,J,G,W,ye.convert(je),ye.convert(it),Te)}finally{let ze=Y!==null?X.get(Y).__webglFramebuffer:null;_.bindFramebuffer(L.FRAMEBUFFER,ze)}}},this.readRenderTargetPixelsAsync=async function(y,D,J,G,W,Te,Pe,Ee=0){if(!(y&&y.isWebGLRenderTarget))throw new Error("THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.");let Ne=X.get(y).__webglFramebuffer;if(y.isWebGLCubeRenderTarget&&Pe!==void 0&&(Ne=Ne[Pe]),Ne)if(D>=0&&D<=y.width-G&&J>=0&&J<=y.height-W){_.bindFramebuffer(L.FRAMEBUFFER,Ne);let ze=y.textures[Ee],je=ze.format,it=ze.type;y.textures.length>1&&L.readBuffer(L.COLOR_ATTACHMENT0+Ee);let Ue=eh(ze);if(Ue.__formatReadable===!1)throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.");if(Ue.__typeReadable===!1)throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.");let ct=L.createBuffer();L.bindBuffer(L.PIXEL_PACK_BUFFER,ct),L.bufferData(L.PIXEL_PACK_BUFFER,Te.byteLength,L.STREAM_READ),L.readPixels(D,J,G,W,ye.convert(je),ye.convert(it),0),L.bindBuffer(L.PIXEL_PACK_BUFFER,null);let Rt=Y!==null?X.get(Y).__webglFramebuffer:null;_.bindFramebuffer(L.FRAMEBUFFER,Rt);let xt=L.fenceSync(L.SYNC_GPU_COMMANDS_COMPLETE,0);return L.flush(),await pu(L,xt,4),L.bindBuffer(L.PIXEL_PACK_BUFFER,ct),L.getBufferSubData(L.PIXEL_PACK_BUFFER,0,Te),L.bindBuffer(L.PIXEL_PACK_BUFFER,null),L.deleteBuffer(ct),L.deleteSync(xt),Te}else throw new Error("THREE.WebGLRenderer.readRenderTargetPixelsAsync: requested read bounds are out of range.")},this.copyFramebufferToTexture=function(y,D=null,J=0){let G=Math.pow(2,-J),W=Math.floor(y.image.width*G),Te=Math.floor(y.image.height*G),Pe=D!==null?D.x:0,Ee=D!==null?D.y:0;Q.setTexture2D(y,0),L.copyTexSubImage2D(L.TEXTURE_2D,J,0,0,Pe,Ee,W,Te),_.unbindTexture()},this.copyTextureToTexture=function(y,D,J=null,G=null,W=0,Te=0){let Pe,Ee,Ne,ze,je,it,Ue,ct,Rt,xt=y.isCompressedTexture?y.mipmaps[Te]:y.image;if(J!==null)Pe=J.max.x-J.min.x,Ee=J.max.y-J.min.y,Ne=J.isBox3?J.max.z-J.min.z:1,ze=J.min.x,je=J.min.y,it=J.isBox3?J.min.z:0;else{let wt=Math.pow(2,-W);Pe=Math.floor(xt.width*wt),Ee=Math.floor(xt.height*wt),y.isDataArrayTexture?Ne=xt.depth:y.isData3DTexture?Ne=Math.floor(xt.depth*wt):Ne=1,ze=0,je=0,it=0}G!==null?(Ue=G.x,ct=G.y,Rt=G.z):(Ue=0,ct=0,Rt=0);let ft=ye.convert(D.format),Ht=ye.convert(D.type),Ce;D.isData3DTexture?(Q.setTexture3D(D,0),Ce=L.TEXTURE_3D):D.isDataArrayTexture||D.isCompressedArrayTexture?(Q.setTexture2DArray(D,0),Ce=L.TEXTURE_2D_ARRAY):(Q.setTexture2D(D,0),Ce=L.TEXTURE_2D),_.activeTexture(L.TEXTURE0),_.pixelStorei(L.UNPACK_FLIP_Y_WEBGL,D.flipY),_.pixelStorei(L.UNPACK_PREMULTIPLY_ALPHA_WEBGL,D.premultiplyAlpha),_.pixelStorei(L.UNPACK_ALIGNMENT,D.unpackAlignment);let Kt=_.getParameter(L.UNPACK_ROW_LENGTH),ot=_.getParameter(L.UNPACK_IMAGE_HEIGHT),hn=_.getParameter(L.UNPACK_SKIP_PIXELS),Cn=_.getParameter(L.UNPACK_SKIP_ROWS),ii=_.getParameter(L.UNPACK_SKIP_IMAGES);_.pixelStorei(L.UNPACK_ROW_LENGTH,xt.width),_.pixelStorei(L.UNPACK_IMAGE_HEIGHT,xt.height),_.pixelStorei(L.UNPACK_SKIP_PIXELS,ze),_.pixelStorei(L.UNPACK_SKIP_ROWS,je),_.pixelStorei(L.UNPACK_SKIP_IMAGES,it);let Bi=y.isDataArrayTexture||y.isData3DTexture,dt=D.isDataArrayTexture||D.isData3DTexture;if(y.isDepthTexture){let wt=X.get(y),si=X.get(D),mt=X.get(wt.__renderTarget),ri=X.get(si.__renderTarget);_.bindFramebuffer(L.READ_FRAMEBUFFER,mt.__webglFramebuffer),_.bindFramebuffer(L.DRAW_FRAMEBUFFER,ri.__webglFramebuffer);for(let zi=0;zi{n.beginPath(),n.arc(52+a*36,46,11,0,Math.PI*2),n.fillStyle="#d4d4d8",n.fill()}),Vt(n,s/2-220,22,440,48,24),n.fillStyle="#ffffff",n.fill(),n.font=`400 28px ${mn}`,n.fillStyle="#5a5a5e",n.textAlign="center",n.textBaseline="middle",n.fillText(e.site.url,s/2,47),n.textAlign="left",t){let a=n.createLinearGradient(0,94,s,r);a.addColorStop(0,"#f6efe6"),a.addColorStop(1,"#e9eef4"),n.fillStyle=a,n.fillRect(0,94,s,300),n.font=`600 66px ${mn}`,n.fillStyle=el,n.textBaseline="alphabetic",n.fillText(e.site.title,64,250),n.fillStyle="rgba(0,0,0,0.12)",Vt(n,64,290,420,20,10),n.fill(),Vt(n,64,326,300,20,10),n.fill(),[0,1,2].forEach(c=>{Vt(n,64+c*296,430,270,190,18),n.fillStyle=["#eef1f4","#f3eee8","#eef3ee"][c],n.fill()}),n.font=`500 28px ${mn}`;let o=e.site.live,l=n.measureText(o).width;Vt(n,s-l-112,24,l+74,44,22),n.fillStyle="rgba(42,157,75,0.12)",n.fill(),n.beginPath(),n.arc(s-l-84,46,9,0,Math.PI*2),n.fillStyle=nd,n.fill(),n.fillStyle="#1f7a3a",n.textBaseline="middle",n.fillText(o,s-l-64,47)}else n.fillStyle="#f6f6f7",n.fillRect(0,94,s,r-94),n.fillStyle="rgba(0,0,0,0.06)",Vt(n,64,170,380,44,12),n.fill(),Vt(n,64,240,520,20,10),n.fill(),Vt(n,64,276,360,20,10),n.fill(),n.font=`400 34px ${mn}`,n.fillStyle="#9a9a9e",n.textAlign="center",n.textBaseline="middle",n.fillText(e.site.idle,s/2,r-120),n.textAlign="left";n.restore(),n.textBaseline="alphabetic",i.tex.needsUpdate=!0}function sd(i,e){let{ctx:t,w:n,h:s}=i;t.clearRect(0,0,n,s);let r=190,a=s/2-20,o=t.createRadialGradient(r,a,10,r,a,130);o.addColorStop(0,"rgba(0,0,0,0.6)"),o.addColorStop(1,"rgba(0,0,0,0)"),t.fillStyle=o,t.fillRect(r-140,a-140,280,280),t.beginPath(),t.arc(r,a-16,26,0,Math.PI*2),t.moveTo(r-14,a),t.lineTo(r+14,a),t.lineTo(r+22,a+52),t.lineTo(r-22,a+52),t.closePath(),t.fillStyle="#050505",t.fill();let l=372;t.font=`500 64px ${Gn}`,t.fillStyle="#f4f4f5",t.fillText(e.prog,l,150),t.font=`400 30px ${Gn}`,t.fillStyle="rgba(255,255,255,0.42)",t.fillText("#!/bin/sh",l+2,226),t.fillText("rsync ./site server:",l+2,272),t.fillText(" uses $DEPLOY_TOKEN",l+2,318),i.tex.needsUpdate=!0}function rd(){let i=document.createElement("canvas");i.width=i.height=256;let e=i.getContext("2d"),t=e.createRadialGradient(128,128,0,128,128,128);t.addColorStop(0,"rgba(255,255,255,0.62)"),t.addColorStop(.3,"rgba(255,255,255,0.36)"),t.addColorStop(.62,"rgba(255,255,255,0.1)"),t.addColorStop(1,"rgba(255,255,255,0)"),e.fillStyle=t,e.fillRect(0,0,256,256);let n=new ei(i);return n.colorSpace=St,n}function zc(i,{minX:e,maxX:t,minY:n,maxY:s,ppu:r,blur:a,color:o,passes:l=1}){let c=document.createElement("canvas");c.width=Math.round((t-e)*r),c.height=Math.round((s-n)*r);let h=c.getContext("2d"),u=c.width+200;h.shadowColor=o,h.shadowBlur=a,h.shadowOffsetX=u,h.fillStyle="#000";let d=v=>(v-e)*r-u,f=v=>(s-v)*r;h.beginPath();for(let v of i){let{shape:g,holes:p}=v.extractPoints(24);[g,...p].forEach(T=>{T.forEach((w,M)=>M?h.lineTo(d(w.x),f(w.y)):h.moveTo(d(w.x),f(w.y))),h.closePath()})}for(let v=0;v0?pi:fi,m=new f({color:i,roughness:o,metalness:0,envMapIntensity:l,transparent:!0,premultipliedAlpha:!0,depthWrite:!1,side:u});c>0&&Object.assign(m,{clearcoat:c,clearcoatRoughness:h});let v={uBase:{value:s},uEdge:{value:r},uPow:{value:a},uEdgeColor:{value:new Xe(e)},uEdgeMix:{value:t},uSpecEdge:{value:n}};return m.userData.u=v,m.onBeforeCompile=g=>{Object.assign(g.uniforms,v),g.fragmentShader=g.fragmentShader.replace("#include ",`#include +uniform float uBase, uEdge, uPow, uEdgeMix, uSpecEdge; +uniform vec3 uEdgeColor;`).replace("#include ",`float gNV = clamp(abs(dot(normal, normalize(vViewPosition))), 0.0, 1.0); +float gF = pow(1.0 - gNV, uPow); +// what the surface reflects is light the background no longer sends through +float gR = 0.04 + 0.96 * pow(1.0 - gNV, 5.0); +float gA = clamp(uBase + uEdge * gF, 0.0, 1.0); +vec3 gBody = mix(totalDiffuse, uEdgeColor, uEdgeMix); +// thick glass seen edge-on shows its own dark body more than the room +vec3 gSpec = max(outgoingLight - totalDiffuse, vec3(0.0)) * (1.0 - uSpecEdge * gF); +gl_FragColor = vec4(gBody * gA + gSpec, clamp(gA + gR * (1.0 - gA) * (1.0 - uSpecEdge * gF), 0.0, 1.0));`).replace("#include ","")},m.customProgramCacheKey=()=>`akhw-${d}`,m}function Fi(i){return new pt({transparent:!1,blending:io,blendSrc:wr,blendDst:As,blendSrcAlpha:so,blendDstAlpha:As,depthWrite:!1,toneMapped:!1,...i})}function ld(){let i=new pt({color:16777215,toneMapped:!1}),e={uCenter:{value:new I},uRad:{value:new ue(5,11)},uWhite:{value:0},uAsh:{value:new Xe("#7a5643")},uGrain:{value:new Xe("#4a3124")},uGain:{value:1.12},uSheen:{value:.07},uShade:{value:.86},uSun:{value:.5},uWinO:{value:new ue(-1.2,-1)},uWinS:{value:new ue(3.6,2.6)},uWinA:{value:.62},uHasMap:{value:0},uView:{value:new ue(1,1)}};return i.userData.u=e,i.onBeforeCompile=t=>{Object.assign(t.uniforms,e),t.vertexShader=t.vertexShader.replace("#include ",`#include +varying vec3 vWp;`).replace("#include ",`#include +vWp = (modelMatrix * vec4(transformed, 1.0)).xyz;`),t.fragmentShader=t.fragmentShader.replace("#include ",`#include +varying vec3 vWp; +uniform vec3 uCenter, uAsh, uGrain; +uniform vec2 uRad, uWinO, uWinS, uView; +uniform float uWhite, uShade, uSun, uWinA, uHasMap, uGain, uSheen; +float akBand(float x, float h, float s) { return smoothstep(-h - s, -h + s, x) * (1.0 - smoothstep(h - s, h + s, x)); } +float akBars(float x, float pitch, float bar, float s) { float d = abs(fract(x / pitch + 0.5) - 0.5) * pitch; return smoothstep(bar - s, bar + s, d); }`).replace("#include ",`#ifdef USE_MAP + vec4 akT = texture2D(map, vMapUv); + diffuseColor.rgb = mix(mix(uGrain, uAsh, 0.5), akT.rgb * uGain, uHasMap); +#else + diffuseColor.rgb = mix(uGrain, uAsh, 0.82); +#endif + // a tall window to the back left: four soft panes, then a broad falloff + float akC = cos(uWinA), akS = sin(uWinA); + vec2 akQ = mat2(akC, -akS, akS, akC) * (vWp.xz - uWinO); + akQ.x += akQ.y * 0.32; + float akWin = akBand(akQ.x, uWinS.x, 0.45) * akBand(akQ.y, uWinS.y, 0.55); + akWin *= akBars(akQ.x, uWinS.x, 0.1, 0.16) * akBars(akQ.y + uWinS.y, uWinS.y, 0.08, 0.16); + float akFall = 1.0 - smoothstep(-6.0, 9.0, dot(vWp.xz - uWinO, vec2(0.55, 0.83))); + // as an ending closes the window light thins out with the room + diffuseColor.rgb *= uShade + (uSun * akWin + 0.06 * akFall) * (1.0 - uWhite); + // hand-rubbed oil: the window reads as a soft satin sheen on the wood + diffuseColor.rgb += vec3(1.0, 0.96, 0.9) * uSheen * akWin * (1.0 - uWhite);`).replace("#include ",`#include +float akD = length((vWp.xz - uCenter.xz) * vec2(0.8, 1.15)); +float akR0 = mix(uRad.x, uRad.x * 0.2, uWhite), akR1 = mix(uRad.y, uRad.x * 0.85, uWhite); +float akFar = smoothstep(akR0, akR1, akD); +// the desk runs off both sides of the window; only the top and bottom of +// the frame soften into the page +float akY = gl_FragCoord.y / uView.y; +float akEdge = 1.0 - smoothstep(0.0, 0.12, akY) * (1.0 - smoothstep(0.86, 1.0, akY)); +float akW = max(akFar, akEdge); +// a whisper of noise keeps the long fade free of bands +akW = clamp(akW + (fract(sin(dot(gl_FragCoord.xy, vec2(12.9898, 78.233))) * 43758.5453) - 0.5) / 255.0, 0.0, 1.0); +gl_FragColor.rgb = mix(gl_FragColor.rgb, vec3(1.0), akW);`)},i.customProgramCacheKey=()=>"akhw-desk",i}function cd(i){let e={value:0},t=i.clone();return t.onBeforeCompile=n=>{n.uniforms.uDis=e,n.vertexShader=n.vertexShader.replace("#include ",`#include +varying vec3 vKeyPos;`).replace("#include ",`#include +vKeyPos = position;`),n.fragmentShader=n.fragmentShader.replace("#include ",`#include +varying vec3 vKeyPos; +uniform float uDis; +float kh(vec3 p){ p = fract(p*0.3183099+.1); p*=17.0; return fract(p.x*p.y*p.z*(p.x+p.y+p.z)); } +float kn(vec3 x){ vec3 i=floor(x); vec3 f=fract(x); f=f*f*(3.0-2.0*f); + return mix(mix(mix(kh(i+vec3(0,0,0)),kh(i+vec3(1,0,0)),f.x),mix(kh(i+vec3(0,1,0)),kh(i+vec3(1,1,0)),f.x),f.y), + mix(mix(kh(i+vec3(0,0,1)),kh(i+vec3(1,0,1)),f.x),mix(kh(i+vec3(0,1,1)),kh(i+vec3(1,1,1)),f.x),f.y),f.z); }`).replace("#include ",`#include +float kN = kn(vKeyPos*26.0)*0.65 + kn(vKeyPos*61.0)*0.35; +float kD = uDis*1.15 - 0.08 + (vKeyPos.x+0.5)*0.25; +if (kN < kD) discard; +float kEdge = 1.0 - smoothstep(kD, kD+0.07, kN);`).replace("#include ",`#include +totalEmissiveRadiance += vec3(1.0, 0.42, 0.2) * kEdge * step(0.001, uDis) * 2.2;`)},t.customProgramCacheKey=()=>"akhw-dissolve",{mat:t,uDis:e}}var Mi="#e9e7e3",Hr="#9b9ba1",hd="#5fd38a",ud="rgba(255,255,255,0.24)",j_="#1c1d20",ex="#2b2c30",il=2048,Vr=1296,kc=2.34,sl=1.48,Oi=1.28,tx=92,dd=66,nx=178,fd=58,Vc=104;function pd(i,e){let t=new jt,n=An(il,Vr),s=new $e(new Et(kc,sl),new pt({map:n.tex,color:16777215,toneMapped:!1}));s.position.z=-.01;let r=new $e(new Et(kc,sl),new pt({color:2829360,toneMapped:!1}));r.rotation.y=Math.PI,r.position.z=-.012,t.add(s,r);let a=new Et(kc,Vc/Vr*sl),o=[];function l(u){if(o[u])return o[u];let d=An(il,Vc),f=new $e(a,Fi({map:d.tex,opacity:1}));return f.position.z=-.008,f.renderOrder=1,f.visible=!1,t.add(f),o[u]={t:d,mesh:f,sig:"",y:-1}}for(let u=0;u<11;u++)l(u);function c(){let{ctx:u}=n;u.setTransform(1,0,0,1,0,0);let d=u.createLinearGradient(0,0,0,Vr);d.addColorStop(0,j_),d.addColorStop(1,"#18191b"),u.fillStyle=d,u.fillRect(0,0,il,Vr),u.setTransform(Oi,0,0,Oi,0,0);let f=il/Oi;u.fillStyle=ex,u.fillRect(0,0,f,96),u.fillStyle="rgba(0,0,0,0.5)",u.fillRect(0,96,f,2),["#ff5f57","#febc2e","#28c840"].forEach((m,v)=>{u.beginPath(),u.arc(56+v*40,48,12,0,Math.PI*2),u.fillStyle=m,u.fill()}),u.font=`400 30px ${mn}`,u.fillStyle=Hr,u.textAlign="center",u.textBaseline="middle",u.fillText(i.term.title,f/2,50),u.textAlign="left",u.textBaseline="alphabetic",u.setTransform(1,0,0,1,0,0),n.tex.needsUpdate=!0,o.forEach(m=>m.sig="")}function h(u,d){let f=nx,m=0;for(let v of u){if(v.kind==="gap"){f+=v.size??20;continue}let g=l(m++),p=`${v.kind}|${v.text??""}|${v.row??""}|${v.chars??""}|${v.caret?1:0}|${v.kind==="wait"?d:""}`;if(p!==g.sig&&(ix(g.t,v,f,d),g.sig=p),g.y!==f){g.y=f;let T=f*Oi-fd+Vc/2;g.mesh.position.y=(.5-T/Vr)*sl}g.mesh.visible=!0,g.mesh.material.opacity=v.alpha??1,f+=v.kind==="me"?dd+10:dd}for(let v=m;vnew I(i,e,t),md=Ot(.16,0,.12);function gd(i,e){let t=i.L,n=e==="wide",s=n?Ot(-3.05,1.32,.9):Ot(-.92,1,1.9),r=n?Ot(0,1.26,-2.3):Ot(.02,1.58,-2.5),a=n?Ot(3.05,.62,.9):Ot(1,.48,2.3),o=n?1:.66,l=n?1:.8,c=n?1:.68,h=a.clone().add((n?Ot(0,1.62,-.32):Ot(.2,1.4,-1.5)).multiplyScalar(c));Object.assign(t,{kind:e,A:s,V:r,P:a,W:h,sA:o,sV:l,sP:c});let u=(p,T,w,M,b,S=0)=>{p.position.set(T.x+md.x*T.y,.003+S,T.z+md.z*T.y),p.scale.set(M*w,b*w,1)};i.agent.position.copy(s),i.agent.scale.setScalar(o),u(i.agentShadow,s,o,3.2,.95),u(i.agentLight,s,o,2.6,.7,.001),i.agentLight.position.x+=.2*o,i.agentLight.position.z+=.35*o,i.vault.position.copy(r),i.vault.scale.setScalar(l),u(i.vaultShadow,r,l,2,1),u(i.vaultTint,r,l,1.9,1.1,.001),i.vaultTint.position.z+=.3*l,i.prog.position.copy(a),i.prog.scale.setScalar(c),u(i.progShadow,a,c,2.2,1.6),i.site.position.copy(h),i.site.scale.setScalar(c),u(i.siteShadow,h,c,1.9,.5),[i.card1,i.card2,i.slip].forEach(p=>p.scale.setScalar(n?1:.72)),t.cardScale=n?1.45:.9,i.chip.scale.setScalar(n?1:.7),i.copy.scale.setScalar(n?1.15:.8),i.dust.material.size=n?.03:.022;let d=(p,T,w=.5)=>p.clone().lerp(T,w),f=(p,T,w,M,b)=>p.clone().add(Ot(w,M,b).multiplyScalar(T)),m=i.keyhole;t.keyholeW=f(a,c,m.x,m.y,m.z),t.catPath=new dn([f(r,l,-.55,.35,.45),d(s,r).add(Ot(-.1,.7*l,n?1.5:.9)),f(s,o,.55,.25,.4)],!1,"centripetal"),t.reqPath=new dn([f(s,o,1.05,.5,.05),d(s,r).add(Ot(.35,1.2*l,.2)),f(r,l,-.6,.62,.4)],!1,"centripetal"),t.keyPath=new dn([f(r,l,.08,0,1),f(r,l,.75,.35,1.45),d(r,a).add(Ot(.1,.55*l,n?1.55:1.2)),t.keyholeW.clone().add(Ot(-.55,.32,.7).multiplyScalar(c)),t.keyholeW.clone().add(Ot(0,.05,.26).multiplyScalar(c)),t.keyholeW.clone().add(Ot(0,0,.015).multiplyScalar(c))],!1,"centripetal"),t.outPath=new dn([f(a,c,-.8,.12,.45),d(a,s).add(Ot(0,.3,n?1.7:1)),f(s,o,1.1,-.25,.3)],!1,"centripetal");for(let[p,T]of[[i.reqThread,t.reqPath],[i.keyThread,t.keyPath],[i.outThread,t.outPath]])p.geometry.dispose(),p.geometry=new vr(T,p.userData.segs,p.userData.radius*(n?1:.8),p.userData.radial,!1),p.geometry.setDrawRange(0,0);i.copyGlow.scale.setScalar(n?1.1:.75),t.slipRest=Ot(r.x-.05*l,.012,r.z+1.25*l),t.slipRestQ=new qt().setFromEuler(new Sn(-Math.PI/2,0,.12)),i.slipShadow.position.set(t.slipRest.x+.02,.004,t.slipRest.z+.03),i.slipShadow.rotation.z=-.12,i.slipShadow.scale.set(.95*(n?1:.72)*1.2,.58*(n?1:.72)*1.2,1);let v=[[s,1.55*o],[r,1.15*l],[a,.95*c],[h,.95*c]],g=new Un;v.forEach(([p,T])=>g.expandByPoint(p.clone().addScalar(T)).expandByPoint(p.clone().subScalar(T))),t.C=g.getCenter(new I),t.R=Math.max(...v.map(([p,T])=>p.distanceTo(t.C)+T))*(n?.74:.86),i.uFloor.uCenter.value.copy(t.C),i.uFloor.uRad.value.set(n?6.4:3.8,n?14:9),i.uFloor.uWinO.value.set(n?s.x+1.5:s.x+.5,n?s.z-1.3:s.z-1.4),i.uFloor.uWinS.value.set(n?1.9:1.15,n?1.35:.95)}function _d(i){let e=new Ci,t=new On(1,1,1),n=(u,d=1)=>{let f=new pt({color:u,side:It,toneMapped:!1});return f.color.multiplyScalar(d),f},s=new $e(t,[n(15526630,.95),n(15526630,1.05),n(16184818,1.1),n(14207929,.75),n(15526630,.9),n(15526630,1)]);s.scale.set(22,9,22),s.position.y=3,e.add(s);let r=new pt({color:16054527,side:kt,toneMapped:!1});r.color.multiplyScalar(4.2);let a=new Et(1,1);for(let u=0;u<2;u++)for(let d=0;d<2;d++){let f=new $e(a,r);f.rotation.y=Math.PI/2,f.scale.set(2.3,2.5,1),f.position.set(-10.9,2.6+d*2.7,-5.2+u*2.5),e.add(f)}let o=new pt({color:2763566,side:kt,toneMapped:!1});[[10.9,2.2,-2,-Math.PI/2,5.5,3.2],[10.9,2.8,4.5,-Math.PI/2,2.4,5],[-3.5,2.4,10.9,Math.PI,6,2.6],[4.5,1.6,-10.9,0,4,2]].forEach(([u,d,f,m,v,g])=>{let p=new $e(a,o);p.position.set(u,d,f),p.rotation.y=m,p.scale.set(v,g,1),e.add(p)});let l=new $e(a,new pt({color:16777215,side:kt,toneMapped:!1}));l.material.color.multiplyScalar(1.6),l.rotation.x=Math.PI/2,l.scale.set(6,4,1),l.position.set(1,7.4,2),e.add(l);let c=new Ds(i),h=c.fromScene(e,.03,.1,60).texture;return c.dispose(),e.traverse(u=>u.geometry&&u.geometry.dispose()),h}var xd=new Xe("#b8281e"),vd="#ffffff",rl=(i,e,t)=>new I(i,e,t),Tt=(i,e)=>new ue(i,e);function Gr(i,e){let t=new vs,n=i.length;for(let s=0;snew Ms(t,i)));return e.translate(0,0,-.025),e.computeVertexNormals(),e}function Md(i,e,t,n={}){let s=new Ci;s.environment=_d(i),s.environmentIntensity=1;let r=new Sr(15988735,15129807,.9),a=new Er(15922943,2.2);a.position.set(-5,7,-4),s.add(r,a);let o=()=>{let Re=new ms(new Uint8Array([255,255,255,0]),1,1);return Re.colorSpace=St,Re.needsUpdate=!0,Re},l=ld(),c=l.userData.u;l.map=o(),l.map.repeat.set(7,7);let h=new $e(new Et(60,60),l);h.rotation.x=-Math.PI/2,s.add(h),n.wood&&new bs().load(n.wood,Re=>{Re.wrapS=Re.wrapT=as,Re.repeat.set(60/5.5,60/4.25),Re.colorSpace=St,Re.anisotropy=8,i.initTexture(Re),l.map=Re,c.uHasMap.value=1,n.onTexture&&n.onTexture()});let u=ad(),d=(Re,at,nt=1)=>{let $t=new sr(new ps({map:u,color:Re,transparent:!0,opacity:nt,depthWrite:!1,toneMapped:!1}));return $t.scale.setScalar(at),$t},f=rd(),m=(Re,at,nt=1,$t=5989493)=>{let qn=new $e(new Et(1,1),Fi({map:f,color:$t,opacity:nt}));return qn.rotation.x=-Math.PI/2,qn.scale.set(Re,at,1),qn.renderOrder=1,qn},v=new jt,g={edgeColor:3822170,edgeMix:1,specEdge:.7,base:.025,edge:.9,power:2.2,roughness:.02,envMapIntensity:1.2,key:"clear"},p=new Us(2.6,1.72,.3,8,.12),T=new $e(p,nl({...g,side:It,key:"clear-back"}));v.add(T);let w=new $e(p,nl({...g,side:ln}));v.add(w);let M=pd(e,t);M.group.scale.setScalar(.9),v.add(M.group);let b=m(3.2,.95,.62),S=new $e(new Et(1,1),Fi({map:u,color:16777215,opacity:.55}));S.rotation.x=-Math.PI/2,S.renderOrder=1;let R=new jt,x=1.5,E=1.86,C=.36,P=Gr([Tt(-x/2,-E/2),Tt(x/2,-E/2),Tt(x/2,E/2-C),Tt(x/2-C,E/2),Tt(-x/2+C,E/2),Tt(-x/2,E/2-C)],.16);P.holes.push(sx(0,E/2-.25,.44,.1));let B=new Ms(P,{depth:.52,bevelEnabled:!0,bevelThickness:.07,bevelSize:.06,bevelSegments:6,curveSegments:24});B.center();let V=nl({color:13094613,edgeColor:15856887,edgeMix:.3,base:.1,edge:.6,power:1.6,roughness:.6,envMapIntensity:.8,clearcoat:1,clearcoatRoughness:.05,side:ln,key:"frost"}),N=new $e(B,V);R.add(N);let k=zc([P],{minX:-1.05,maxX:1.05,minY:-1.2,maxY:1.2,ppu:128,blur:40,color:"#eef1f4"}),$=new $e(new Et(2.1,2.4),Fi({map:k,opacity:.82}));$.position.z=-.16,$.scale.setScalar(.9),$.renderOrder=1,R.add($);let q=rx(),Y=new pi({color:xd,roughness:.32,clearcoat:1,clearcoatRoughness:.06,emissive:xd,emissiveIntensity:0,envMapIntensity:1.1}),F=zc(yd(),{minX:-.78,maxX:.15,minY:-.3,maxY:.3,ppu:256,blur:7,color:"#c22d1f",passes:2}),z=new Et(.93,.6).translate(-.315,0,0),Z=new pt({map:F,transparent:!0,depthWrite:!1,toneMapped:!1,opacity:.92}),fe=[];[.42,0,-.42].forEach((Re,at)=>{let nt=new $e(z,Z);nt.rotation.z=-.32+at*.05,nt.position.set(.3*Math.cos(nt.rotation.z),Re+.3*Math.sin(nt.rotation.z)-.08,.05),R.add(nt),fe.push(nt)});let he=m(2,1,.55),qe=d(13778986,3,0);qe.position.z=-.4,R.add(qe);let Ve=new $e(new Et(1,1),Fi({map:u,color:14173228,opacity:0}));Ve.rotation.x=-Math.PI/2,Ve.renderOrder=1;let Ye=new jt,K=new pi({color:2829360,metalness:.5,roughness:.36,clearcoat:.6,clearcoatRoughness:.22,envMapIntensity:.75}),ne=new $e(new Us(1.5,.92,1,6,.09),K);Ye.add(ne);let pe=An(1024,614);sd(pe,e);let De=new $e(new Et(1.4,.84),new pt({map:pe.tex,transparent:!0,toneMapped:!1}));De.position.z=.501,Ye.add(De);let me=rl(-.44,.03,.5),Fe=new $e(new xr(.1,.118,64),new pt({color:16730674,transparent:!0,opacity:0,toneMapped:!1}));Fe.position.copy(me).add(rl(0,0,.003)),Ye.add(Fe);let oe=d(16726818,.9,0);oe.position.copy(me).add(rl(0,0,.05)),Ye.add(oe);let H=[],re=new pt({color:4671307,toneMapped:!1}),le=new pt({color:6283391,toneMapped:!1}),j=new cr(.016,20);for(let Re=0;Re<6;Re++){let at=new $e(j,re);at.position.set(-.17+Re*.058,-.3,.503);let nt=d(3458905,.14,0);nt.position.copy(at.position).add(rl(0,0,.01)),Ye.add(at,nt),at.userData.glow=nt,H.push(at)}let ae=m(2.2,1.6,.78),we=new jt,Ae=new $e(new Us(1.74,1.11,.03,4,.014),new fi({color:14672356,roughness:.42,metalness:.3}));we.add(Ae);let se=An(1024,650),He=An(1024,650);Bc(se,e,!1),Bc(He,e,!0);let L=new $e(new Et(1.7,1.08),new pt({map:se.tex,transparent:!0,toneMapped:!1})),st=new $e(new Et(1.7,1.08),new pt({map:He.tex,transparent:!0,opacity:0,toneMapped:!1}));L.position.z=.017,st.position.z=.018,we.add(L,st);let Qe=m(1.9,.5,.18),A=(Re,at,nt)=>{let $t=new $e(new Et(at,nt),new pt({map:Re,transparent:!0,toneMapped:!1,side:kt,forceSinglePass:!0,depthWrite:!1}));return $t.visible=!1,$t},_=An(640,390),O=An(640,390),X=An(640,390),Q=An(560,150),de=()=>{tl(_,[[e.card.name,"name"],[e.card.note,"note"],[e.card.env,"mono"],[e.card.value,"empty"]],t),tl(O,[[e.card.name2,"name"],[e.card.note2,"note"],[e.card.env2,"mono"],[e.card.value,"empty"]],t),tl(X,[[e.slip.line1,"name"],[e.slip.line2,"mono"]],t,{head:e.slip.head}),id(Q,e.chip),M.redrawBase()};de();let ge=A(_.tex,.82,.5),ee=A(O.tex,.82,.5),ie=A(X.tex,.82,.5),_e=A(Q.tex,.8,.214),Ie=new $e(new Et(.3,.3),new pt({map:o(),transparent:!0,opacity:0,depthWrite:!1,toneMapped:!1,side:kt,forceSinglePass:!0}));Ie.position.set(.22,-.03,.002),Ie.rotation.z=.06,ie.add(Ie),n.seal&&new bs().load(n.seal,Re=>{Re.colorSpace=St,i.initTexture(Re),Ie.material.map=Re,n.onTexture&&n.onTexture()});let Me=m(.9,.55,0),{mat:xe,uDis:Oe}=cd(Y);xe.emissiveIntensity=.1;let ke=new $e(q,xe);ke.visible=!1;let Ze=d(14697772,1.1,0);s.add(Ze);let U=240,ve=new At;ve.setAttribute("position",new Bt(new Float32Array(U*3),3));let te=new ar(ve,new _s({color:13776927,size:.03,map:od(),transparent:!0,depthWrite:!1,opacity:0,toneMapped:!1}));te.visible=!1,te.frustumCulled=!1;let ye=Array.from({length:U},(Re,at)=>{let nt=$t=>{let qn=Math.sin(at*127.1+$t*311.7)*43758.5453;return qn-Math.floor(qn)};return{a:nt(1)*Math.PI*2,b:nt(2)*2-1,s:.25+nt(3)*.75,along:nt(4),lift:.3+nt(5)*.8}}),Se=(Re,at,nt)=>{let $t=new $e(new At,new pt({color:Re,transparent:!0,opacity:at,depthWrite:!1,toneMapped:!1}));return $t.userData={radius:nt,segs:260,radial:8,base:at},$t.frustumCulled=!1,$t},ce=Se(3816772,.5,.0065),Be=Se(12856605,1,.009),Le=Se(3816772,.5,.0065);s.add(v,b,S,R,he,Ve,Ye,ae,we,Qe,ge,ee,ie,Me,_e,ke,te,ce,Be,Le);let lt={scene:s,floor:h,uFloor:c,agent:v,agentShadow:b,agentLight:S,vaultGlow:qe,vaultTint:Ve,ringGlow:oe,copyGlow:Ze,seal:Ie,glass:w,term:M,vault:R,vaultBody:N,vaultKeys:fe,keyBlurMat:Z,lacquer:Y,prog:Ye,progShadow:ae,ring:Fe,leds:H,ledOn:le,ledOff:re,site:we,siteShadow:Qe,sLive:st,sIdle:L,card1:ge,card2:ee,slip:ie,slipShadow:Me,chip:_e,copy:ke,uDis:Oe,dust:te,seeds:ye,reqThread:ce,keyThread:Be,outThread:Le,vaultShadow:he,keyhole:me,redrawCards:de,L:{}};return lt.setLayout=Re=>gd(lt,Re),lt.reveal=(Re,at)=>{let nt=Re.userData.radial*6;Re.geometry.setDrawRange(0,Math.floor(Fr.clamp(at,0,1)*Re.userData.segs)*nt),Re.visible=at>.001},lt}var Jt={allow:16.5,deny:8.5},Wn={pre:[0,3.4,8.6],allow:[0,9.2],deny:[0,2.6]},Sd=2.6,ni=(i,e=0,t=1)=>Math.min(t,Math.max(e,i)),Ke=(i,e,t)=>ni((i-e)/(t-e)),Xn=i=>i<.5?4*i*i*i:1-Math.pow(-2*i+2,3)/2,Hc=i=>1-Math.pow(1-i,3),cn=i=>i*i*(3-2*i),Wr=(i,e,t,n=.35,s=.35)=>Math.min(Ke(i,e,e+n),1-Ke(i,t-s,t)),Pt=i=>i==="once"||i==="timed"?"allow":i?"deny":null,al=i=>i==="once"?"allow":i||"allow";var _t=(i,e,t,n)=>({t:i,target:e,dir:new I(...t).normalize(),r:n}),Fs=(i,e,t)=>i.clone().lerp(e,t);function Wc(i){let{A:e,V:t,P:n,W:s,C:r,R:a,sA:o,sV:l,sP:c}=i,h=(T,w,M)=>new I(T,w,M),u=(T,w,M,b,S)=>T.clone().add(h(M,b,S).multiplyScalar(w)),d=i.kind==="tall",f=d?1.15:1,m=_t(14.4,h(t.x,t.y*.55,t.z+.55*l),[0,.3,1],1.5*l*f),v=[_t(0,r.clone().add(h(0,.15,0)),[.02,d?1:.55,1],a*(d?.92:1.04)),_t(1.4,r.clone().add(h(-.2,.1,0)),[.08,.48,1],a*.92),_t(3,u(e,o,.05,.08,0),[.16,.1,1],1.18*o*f),_t(4.2,u(e,o,.12,.02,0),[.24,.13,1],1.3*o*f),_t(6,Fs(e,t,.48).add(h(0,.15,.2)),[.22,.42,1],d?a*.78:2.95),_t(8,Fs(e,t,.4).add(h(0,.05,.3)),[.05,.36,1],d?a*.74:2.75),_t(9.8,u(e,o,.55,.15,0),[.42,.22,1],1.75*o*f),_t(12,Fs(e,t,.7).add(h(0,.45*l,0)),[-.2,.22,1],d?a*.62:1.95),_t(13.3,h(t.x,t.y*.62,t.z+.45*l),[-.06,.26,1],1.55*l*f),m],g=[{...m,t:0},_t(.9,h(t.x,t.y*.5,t.z+.7*l),[.04,.42,1],1.25*l*f),_t(2.2,u(t,l,.25,.1,.6),[.4,.14,1],1.15*l*f),_t(3.6,Fs(t,n,.55).add(h(.2,.75*l,.6)),[.12,.38,1],d?a*.7:2.35),_t(4.9,u(i.keyholeW,1,.1*c,.02,.3*c),[-.5,.16,1],.92*c*f),_t(6.2,u(i.keyholeW,1,.35*c,.05,.15*c),[-.36,.12,1],1*c*f),_t(7.5,Fs(n,s,.62),[-.3,.18,1],1.55*c*f),_t(9,Fs(n,e,.5).add(h(0,.35,.6)),[0,.32,1],d?a*.85:3.6),_t(10.4,u(e,o,.15,.02,0),[.2,.12,1],1.32*o*f),_t(11.6,u(e,o,.2,.05,0),[.28,.18,1],1.45*o*f),_t(14.4,r.clone().add(h(0,.12,0)),[0,d?1.15:.6,1],a*(d?.94:1)),_t(Jt.allow,r.clone().add(h(0,.12,0)),[.03,d?1.12:.58,1],a*(d?.95:1.01))],p=[{...m,t:0},_t(1.3,u(t,l,0,.05,0),[.12,.16,1],1.4*l*f),_t(3,u(e,o,.15,.02,0),[.22,.13,1],1.32*o*f),_t(4.4,u(e,o,.2,.05,0),[.28,.18,1],1.45*o*f),_t(7,r.clone().add(h(0,.12,0)),[0,d?1.15:.6,1],a*(d?.94:1)),_t(Jt.deny,r.clone().add(h(0,.12,0)),[.03,d?1.12:.58,1],a*(d?.95:1.01))];return{pre:Gc(v),allow:Gc(g),deny:Gc(p)}}function Gc(i){let e=i.length,t=new dn(i.map(u=>u.target),!1,"centripetal"),n=new dn(i.map(u=>u.dir.clone()),!1,"catmullrom",.5),s=i.map(u=>u.t),r=i.map(u=>Math.log(u.r)),a=[];for(let u=0;u{if(u<=s[0])return 0;if(u>=s[e-1])return e-1;let d=0;for(;u>s[d+1];)d++;let f=s[d+1]-s[d],m=(u-s[d])/f,v=2*m**3-3*m**2+1,g=m**3-2*m**2+m,p=-2*m**3+3*m**2,T=m**3-m**2;return v*d+g*f*o[d]+p*(d+1)+T*f*o[d+1]},c=u=>{let d=Math.min(e-2,Math.floor(u)),f=u-d;return Math.exp(r[d]+(r[d+1]-r[d])*cn(f))},h={target:new I,dir:new I,r:1};return{end:s[e-1],at(u){let d=ni(l(u),0,e-1),f=d/(e-1);return t.getPoint(f,h.target),n.getPoint(f,h.dir).normalize(),h.r=c(d),h}}}var ax=new I;function bd(i,e,t,n,s){let r=Fr.degToRad(i.fov),a=i.aspect<1.02?Math.min(i.aspect,.75):i.aspect,o=2*Math.atan(Math.tan(r/2)*a),l=Math.min(r,o),c=e.r/Math.sin(l/2),h=ax.copy(e.dir);h.x+=s*(.025*Math.sin(t*.23)+n.sx*.07),h.y+=s*(.018*Math.sin(t*.17+1.3)-n.sy*.045),h.normalize(),i.position.copy(e.target).addScaledVector(h,c),i.lookAt(e.target)}function Ed(i,e,t){let n=[],s=Array.from({length:12},()=>({})),r=0,a=(b,S,R,x)=>{let E=s[r++];return E.kind=b,E.text=S,E.alpha=R,E.chars=void 0,E.caret=!1,E.row=void 0,x&&Object.assign(E,x),E},o=[...e.term.ask].length;function l(b){r=0;let S=b.phase==="pre"?b.T:14.4+1,R=b.phase==="post"||b.phase==="end",x=R?b.u:-1,E=Pt(b.decision),C=V=>ni((S-V)/.35),P=V=>ni((x-V)/.35),B=a("me",e.term.ask,1);B.chars=Math.floor(Ke(S,.7,2.7)*o),B.caret=S<3&&(S<2.7||Math.floor(S*2.2)%2===0),S>=3.4&&a("ai",e.term.check,C(3.4)),S>=6.7&&a("cat","",C(6.7),{row:e.term.cat[0]}),S>=7&&a("cat","",C(7),{row:e.term.cat[1]}),S>=7.3&&a("note",e.term.noValue,C(7.3)),S>=8.6&&a("ai",e.term.cant,C(8.6)),S>=8.9&&a("indent",e.term.req,C(8.9)),S>=12.6&&(!R||x<.5?a("wait",e.term.wait,C(12.6)):E==="allow"?a("ok",b.decision==="timed"?e.term.okTimed:e.term.ok,P(.5)):a("no",b.decision==="expire"?e.term.expired:e.term.denied,P(.5))),R&&E==="allow"&&(x>=10&&a("ai",e.term.out,P(10)),x>=10.5&&a("ok",e.term.live,P(10.5))),R&&E==="deny"&&x>=1.7&&a("ai",b.decision==="expire"?e.term.expiredNext:e.term.deniedNext,P(1.7)),n.length=r;for(let V=0;VE.kind==="wait");i.term.update(R,x?Math.floor(S*9)/8:0)}let h=new qt,u=new qt,d=new I(1,0,0),f=new I(0,0,-1),m=new I,v=new I,g=new I,p=new I,T=new qt;function w(b,S,R,x=0){S.getPoint(R,m),b.position.copy(m),b.quaternion.copy(t.quaternion),b.rotateZ(x)}function M(b,S){let R=b.phase==="pre"?b.T:14.4+1,x=b.phase==="post"||b.phase==="end",E=x?b.u:0,C=x?Pt(b.decision):null,P=i.L;for(let z=0;z<2;z++){let Z=z?i.card2:i.card1,fe=z?4.75:4.3,he=Ke(R,fe,fe+2.2);if(Z.visible=he>0&&he<1,!Z.visible)continue;let qe=Xn(he);w(Z,P.catPath,qe,Math.sin(S*2+z)*.04+(1-qe)*.2),z&&(Z.position.y+=.12*P.sA);let Ve=P.cardScale*(.35+.65*cn(Ke(he,0,.2)))*(1-.5*cn(Ke(he,.82,1)));Z.scale.setScalar(Ve),Z.material.opacity=Math.min(Ke(he,0,.12),1-Ke(he,.86,1))}{let z=Ke(R,9.6,12.2),Z=Ke(R,12.2,13.3),fe=P.kind==="wide"?1:.72;if(i.slip.visible=z>0,z>0&&Z<=0)w(i.slip,P.reqPath,Xn(z),Math.sin(S*2.4)*.05),i.slip.material.opacity=Ke(z,0,.1),i.slip.scale.setScalar(fe*(1-.2*cn(Ke(z,.8,1))));else if(Z>0){P.reqPath.getPoint(1,m);let qe=Xn(Z);i.slip.position.lerpVectors(m,P.slipRest,qe),i.slip.position.y+=Math.sin(qe*Math.PI)*.25*P.sV,i.slip.quaternion.slerpQuaternions(t.quaternion,P.slipRestQ,cn(Z)),i.slip.scale.setScalar(fe*(.8+.4*qe)),i.slip.material.opacity=1}i.slipShadow.material.opacity=.5*cn(Ke(Z,.55,1))*(x&&C==="deny"?1-.55*Ke(E,.5,1.6):1);let he=C==="allow"?Ke(E,.12,.5):0;i.seal.material.opacity=Math.min(1,he*3)*.92,i.seal.scale.setScalar(1+.6*(1-Hc(he))),x&&C==="deny"&&(i.slip.material.opacity=1-.55*Ke(E,.5,1.6)),i.reveal(i.reqThread,Xn(Ke(R,9.6,12.2)))}let B=Ke(R,12.3,13.2)*(x?1-Ke(E,.2,1.2):1),V=b.phase==="gate"&&!b.later?.5+.5*Math.sin(S*3):0,N=B*(.5+V*.5)+(C==="allow"?.7*Wr(E,.4,2.6,.4,.8):0);i.lacquer.emissiveIntensity=.5*N,i.keyBlurMat.color.setScalar(1+.45*N),i.vault.scale.setScalar(P.sV*(1+.025*B*cn(Wr(R,12.3,13.4,.4,.6))));let k=.1+B*(.2+V*.18)+(C==="allow"?.32*Wr(E,.3,2.8,.4,.9):0);i.vaultGlow.material.opacity=k*.85,i.vaultTint.material.opacity=.08+k*.42;let $=C==="allow",q=i.copy;if(q.visible=$&&E>.5&&E<10.4,i.dust.visible=!1,q.visible){let z=i.vaultKeys[1];z.updateWorldMatrix(!0,!1),z.matrixWorld.decompose(g,T,p);let Z=P.kind==="wide"?1.15:.8,fe=cn(Ke(E,.5,2)),he=Xn(Ke(E,2,5.2)),qe=Xn(Ke(E,5.3,5.85));E<2?(P.keyPath.getPoint(0,m),P.keyPath.getTangent(.001,v),h.setFromUnitVectors(d,v),q.position.lerpVectors(g,m,fe),q.quaternion.slerpQuaternions(T,h,fe),q.scale.setScalar(p.x+(Z-p.x)*fe)):(P.keyPath.getPoint(he,m),P.keyPath.getTangent(Math.min(.999,Math.max(.001,he)),v),v.lerp(f,cn(Ke(he,.8,1))).normalize(),q.position.copy(m),h.setFromUnitVectors(d,v),u.setFromAxisAngle(d,Math.sin(he*Math.PI)*Math.PI-qe*Math.PI/2),q.quaternion.copy(h).multiply(u),q.scale.setScalar(Z));let Ve=Ke(E,8.4,10.2);if(i.uDis.value=Ve,Ve>0){i.dust.visible=!0;let Ye=i.dust.geometry.attributes.position.array,K=q.position,ne=.62*Z,pe=i.seeds;for(let De=0;De0?1:0)+Math.abs(Math.sin(me.a))*oe*.4}i.dust.geometry.attributes.position.needsUpdate=!0,i.dust.material.opacity=.95*(1-Ke(Ve,.55,1))}}else i.uDis.value=0;i.copyGlow.visible=q.visible&&i.uDis.value<.95,i.copyGlow.visible&&(i.copyGlow.position.copy(q.position),i.copyGlow.material.opacity=.32*Ke(E,.6,1.6)*(1-i.uDis.value)),i.reveal(i.keyThread,$?Xn(Ke(E,2,5.2)):0),i.ring.material.opacity=$?Ke(E,4.2,4.8)*(1-.6*Ke(E,9.4,10.4)):0,i.ringGlow.material.opacity=i.ring.material.opacity*(.4+.2*Wr(E,5.3,6.4,.2,.6));for(let z=0;z5.95+z*.16;Z.material=fe?i.ledOn:i.ledOff,Z.userData.glow.material.opacity=fe?.7:0}let Y=$?cn(Ke(E,6.9,7.5)):0;i.sLive.material.opacity=Y,i.sIdle.material.opacity=1-Y,i.site.position.y=P.W.y+Math.sin(S*.9)*.015*P.sP+Y*.04*(1-Ke(E,7.5,8.5))*P.sP;{let z=$?Ke(E,7.7,9.9):0;i.chip.visible=z>0&&z<1,i.chip.visible&&(w(i.chip,P.outPath,Xn(z),Math.sin(S*2)*.03),i.chip.material.opacity=Math.min(Ke(z,0,.1),1-Ke(z,.86,1))),i.reveal(i.outThread,$?Xn(Ke(E,7.7,9.9)):0)}let F=x?Ke(E,C==="allow"?11:3,C==="allow"?13:5):0;i.reqThread.material.opacity=C==="deny"?.5-.24*F:.5,i.uFloor.uWhite.value=x?cn(Ke(E,Jt[C]-Sd,Jt[C])):0,i.agent.position.y=P.A.y+Math.sin(S*.7)*.02*P.sA}return{update:M,updateTranscript:c}}function Td({root:i,I:e,S:t,W:n,camera:s,reduced:r,wake:a,renderNow:o}){let l=oe=>i.querySelector(oe),c=oe=>[...i.querySelectorAll(oe)],h=l(".akhw-stage"),u=l(".akhw-say"),d=l(".akhw-tags"),f=l(".akhw-alert"),m=l(".akhw-hint"),v=l(".akhw-pending"),g=l(".akhw-end"),p=l(".akhw-play"),T=l(".akhw-count"),w=l(".akhw-alert-details"),M=l(".akhw-alert-rows"),b=c(".akhw-steps li"),S=[],R=new I,x=new I,E=(oe,H,re,le,j=0)=>{if(!H||H.includes("undefined"))return;let ae=document.createElement("div");ae.className=`akhw-tag ${oe}`,ae.innerHTML=H,d.appendChild(ae),S.push({el:ae,anchor:re,show:le,dy:j,on:!1,w:0,x:NaN,y:NaN})},C=e.tags;{let oe=n.L,H=(se,He,L,st)=>R.copy(se).add(x.set(He,L,st)),re=(se,He,L)=>()=>H(oe[se],0,-L*oe[He],oe.kind==="wide"?0:.75*oe[He]),le=se=>se.phase!=="pre"&&se.phase!=="gate"&&Pt(se.decision)==="allow"&&se.u>12.6,j=se=>se.phase!=="pre"&&se.phase!=="gate"&&Pt(se.decision)==="deny"&&se.u>5.6,ae=se=>le(se)||j(se),we=se=>se.phase==="pre"&&se.T<1.9,Ae=se=>se.phase==="pre"&&se.T>4.9&&se.T<8.5;E("is-id",`${C.agent[0]}${C.agent[1]}`,re("A","sA",1.08),se=>we(se)||Ae(se)),E("is-id",`${C.vault[0]}${C.vault[1]}`,()=>re("V","sV",oe.kind==="wide"?1.5:1.32)(),se=>we(se)||Ae(se)),E("is-id",`${C.prog[0]}${C.prog[1]}`,()=>H(oe.P,0,-.62*oe.sP,(oe.kind==="wide"?.5:1.05)*oe.sP),se=>se.phase==="post"&&Pt(se.decision)==="allow"&&se.u>3.2&&se.u<4.6),E("is-pill",C.noValue,()=>H(oe.A,.2*oe.sA,.98*oe.sA,0),se=>se.phase==="pre"&&se.T>7.2&&se.T<8.6),E("is-pill is-key",C.flying,()=>H(n.copy.position,0,.3*oe.sP,0),se=>se.phase!=="pre"&&se.phase!=="gate"&&Pt(se.decision)==="allow"&&se.u>2.2&&se.u<4.6),E("is-pill is-zero",C.agentEnd.replace(/(\d+)/,"$1"),()=>H(oe.A,0,1.02*oe.sA,0),se=>ae(se)||se.phase==="post"&&se.u>(Pt(se.decision)==="allow"?10.8:3.4)),E("is-pill",C.vaultEnd,()=>H(oe.V,0,1.2*oe.sV,0),se=>le(se)&&se.decision==="once"),E("is-pill",C.vaultTimed,()=>H(oe.V,0,1.2*oe.sV,0),se=>le(se)&&se.decision==="timed"),E("is-pill",C.vaultDeny,()=>H(oe.V,0,1.2*oe.sV,0),se=>j(se)),E("is-pill is-key",C.progEnd,()=>H(oe.W,0,.74*oe.sP,0),se=>le(se)),E("is-pill",C.progDeny,()=>H(oe.W,0,.74*oe.sP,0),se=>j(se))}let P=h.clientWidth,B=h.clientHeight;function V(){P=h.clientWidth,B=h.clientHeight,S.forEach(oe=>oe.w=0)}function N(oe){let H=P,re=B,le=performance.now();for(let j of S){let ae=oe.phase!=="idle"&&j.show(oe);ae!==j.on&&(j.el.classList.toggle("on",ae),j.on=ae,ae||(j.offAt=le)),ae&&!j.w&&(j.w=j.el.offsetWidth)}for(let j of S){if(!j.on&&!(le-(j.offAt||0)<600))continue;let ae=j.anchor().project(s);if(ae.z>1){j.on&&(j.el.classList.remove("on"),j.on=!1,j.offAt=0);continue}let we=j.w/2+10,Ae=ni((ae.x*.5+.5)*H,we,Math.max(we,H-we)),se=(-ae.y*.5+.5)*re+j.dy;Math.abs(Ae-j.x)<.05&&Math.abs(se-j.y)<.05||(j.x=Ae,j.y=se,j.el.style.transform=`translate(${Ae.toFixed(1)}px, ${se.toFixed(1)}px) translate(-50%, -50%)`)}}let k=b.map(()=>{let oe=document.createElement("p");return u.appendChild(oe),oe});function $(oe){if(oe.phase==="pre"||oe.phase==="idle")return oe.T-1);function z(oe){let H=$(oe),re=al(oe.decision);if(re!==Y&&(i.dataset.outcome=re,Y=re,q=-1),H!==q){let ae=[...b[H].querySelectorAll("p")].find(we=>getComputedStyle(we).display!=="none");k.forEach((we,Ae)=>{Ae===H&&ae&&(we.innerHTML=ae.innerHTML),we.classList.toggle("on",Ae===H)}),b.forEach((we,Ae)=>we.classList.toggle("on",Ae===H)),q=H}let le=Pt(oe.decision);for(let j=0;jH?ae=0:H<=2?ae=Ke(oe.T,Wn.pre[H],H<2?Wn.pre[H+1]:14.4):H===3?ae=1:ae=Ke(oe.u,Wn[le][H-4],H===4?Wn[le][1]:Jt[le]),ae=Math.round(ae*400)/400,ae!==F[j]&&(b[j].style.setProperty("--fill",ae.toFixed(3)),F[j]=ae)}}let Z=0;function fe(){f.hidden=!1,f.classList.remove("leave"),f.classList.add("enter"),v.hidden=!0,i.classList.remove("is-later"),clearTimeout(Z),Z=setTimeout(()=>{t.phase==="gate"&&!t.later&&(m.hidden=!1,i.classList.add("is-hinting"))},6500)}function he(oe){if(clearTimeout(Z),m.hidden=!0,i.classList.remove("is-hinting"),oe||r){f.hidden=!0;return}f.classList.remove("enter"),f.classList.add("leave"),setTimeout(()=>{f.classList.contains("leave")&&(f.hidden=!0,f.classList.remove("leave"))},280)}function qe(){t.phase="gate",t.T=14.4,t.gateAt=performance.now(),t.later=!1,i.classList.add("is-gate"),T.textContent=T.dataset.format.replace("{t}","4:57"),fe()}function Ve(oe){t.phase==="gate"&&(t.decision=oe,t.phase="post",t.u=0,t.ended=!1,t.later=!1,i.classList.remove("is-gate","is-later"),v.hidden=!0,he(),r?(t.u=Jt[Pt(oe)],t.phase="end",De(),o()):a())}function Ye(oe){if(t.phase!=="gate")return;let H=Math.max(0,297-Math.floor((oe-t.gateAt)/1e3)),re=`${Math.floor(H/60)}:${String(H%60).padStart(2,"0")}`,le=T.dataset.format.replace("{t}",re);if(T.textContent!==le&&(T.textContent=le),t.later){let j=v.dataset.base.replace("{t}",re);v.textContent!==j&&(v.textContent=j)}H===0&&(t.later=!1,Ve("expire"))}v.dataset.base=v.textContent.includes("\xB7")?v.textContent.split("\xB7")[0].trim()+" \xB7 {t}":v.textContent;function K(){t.phase!=="gate"||t.later||(t.later=!0,i.classList.add("is-later"),he(),v.hidden=!1,a())}f.addEventListener("click",oe=>{let H=oe.target.closest("[data-decide]");H&&!i.classList.contains("is-still")&&Ve(H.dataset.decide)}),w.addEventListener("click",()=>{let oe=w.getAttribute("aria-expanded")!=="true";w.setAttribute("aria-expanded",String(oe)),M.hidden=!oe}),l(".akhw-later").addEventListener("click",K),v.addEventListener("click",()=>{t.later=!1,fe(),f.querySelector(".is-primary").focus({preventScroll:!0}),a()}),document.addEventListener("keydown",oe=>{oe.key==="Escape"&&t.phase==="gate"&&!t.later&&t.visible&&K()});let ne=l(".akhw-again"),pe=l(".akhw-other");function De(){t.ended=!0,g.hidden=!1,pe.textContent=Pt(t.decision)==="allow"?pe.dataset.deny:pe.dataset.allow}function me(){t.ended=!1,g.hidden=!0}function Fe(oe){me(),p.hidden=!0,t.started=!0,oe<=2?(t.phase==="gate"&&he(!0),i.classList.remove("is-gate","is-later"),v.hidden=!0,t.phase="pre",t.T=Wn.pre[oe]+(oe===0?0:.01),t.decision=null):oe===3?(t.decision=null,t.phase!=="gate"?qe():t.later&&(t.later=!1,fe())):(t.phase==="gate"&&(he(!0),i.classList.remove("is-gate","is-later"),v.hidden=!0),t.decision||(t.decision="once"),t.phase="post",t.u=Wn[Pt(t.decision)][oe-4]+.01),a()}return ne.addEventListener("click",()=>Fe(0)),pe.addEventListener("click",()=>Fe(3)),b.forEach((oe,H)=>oe.querySelector("button").addEventListener("click",()=>Fe(H))),p.addEventListener("click",()=>Fe(0)),{updateTags:N,updateCaptions:z,tickCountdown:Ye,enterGate:qe,decide:Ve,showEnd:De,hideEnd:me,hideAlert:he,measure:V,alert:f,hint:m,stage:h}}function Ad(){let i=null;try{i=document.createElement("canvas").getContext("webgl2")}catch{i=null}if(!i)return null;let e=i.getExtension("WEBGL_debug_renderer_info"),t=String(e?i.getParameter(e.UNMASKED_RENDERER_WEBGL):i.getParameter(i.RENDERER));return i.getExtension("WEBGL_lose_context")?.loseContext(),{name:t,software:/swiftshader|llvmpipe|softpipe|software|basic render/i.test(t)}}var Xc=.5,wd=7.5;function Rd(i,e){let t=Math.max(1,window.devicePixelRatio||1),n=e.has("dpr")?Number(e.get("dpr")):0,s=n||Math.min(t,i.software?1:1.5),r={dpr:s,max:s,benchmarked:!!n||e.has("nobench"),changed:!1},a=[],o=0,l=0,c=[];return r.sample=h=>{if(r.benchmarked)return!1;if(c.push(h),c.length<3&&h<250)return!0;let u=c.length>=3?Math.min(c[1],c[2]):h;if(r.benchmarked=!0,u>wd){let d=Math.max(Xc,Math.round(r.dpr*Math.sqrt(wd/u)*20)/20);d{if(n||h<=0||h>.25)return!1;if(l=l?l*.9+h*.1:h,o>0)return o--,!1;if(a.push(h),a.length<40)return!1;let u=a.slice().sort((f,m)=>f-m);return a=[],u[Math.floor(u.length*.75)]>.0205&&r.dpr>Xc?(r.dpr=r.max=Math.max(Xc,Math.round(r.dpr*.87*20)/20),o=30,!0):!1},r.fps=()=>l?1/l:0,r}var Cd=document.querySelector(".akhw");Cd&&ox(Cd);function ox(i){let e=JSON.parse(i.querySelector(".akhw-i18n").textContent),t=Y=>i.querySelector(Y),n=t(".akhw-stage"),s=t(".akhw-canvas"),r=new URLSearchParams(location.search),a=matchMedia("(prefers-reduced-motion: reduce)").matches||r.has("still"),o={phase:"idle",T:0,u:0,decision:null,started:!1,visible:!1,later:!1,gateAt:0,ended:!1},l=Ad(),c=null;if(l)try{c=new Ko({canvas:s,antialias:!l.software,alpha:!1,powerPreference:"high-performance"})}catch{c=null}if(!c||!c.capabilities.isWebGL2){i.classList.add("no-gl","is-still"),q(null);return}c.setClearColor(vd,1),c.outputColorSpace=St,c.toneMapping=Ar,c.toneMappingExposure=1;let h=c.getContext(),u=Rd(l,r),d=Y=>new URL(Y,import.meta.url).href,f=new Image;f.src=d("img/paper.jpg");let m=Md(c,e,f,{wood:d("img/walnut.webp"),seal:d("img/seal-zhun.webp"),onTexture:()=>B(!0)}),v=new Xt(32,1,.1,100),g=null,p=Ed(m,e,v),T=Td({root:i,I:e,S:o,W:m,camera:v,reduced:a,wake:()=>B(!0),renderNow:()=>S(performance.now())}),w={x:0,y:0,sx:0,sy:0},M=0,b=new Uint8Array(4);function S(Y){let F;o.phase==="pre"||o.phase==="idle"?F=g.pre.at(o.T):o.phase==="gate"?F=g.pre.at(14.4):F=g[Pt(o.decision)].at(o.u),bd(v,F,M,w,a?0:1),v.updateMatrixWorld(),p.update(o,M),p.updateTranscript(o,M);let z=performance.now();c.render(m.scene,v),!u.benchmarked&&!a&&(h.readPixels(0,0,1,1,h.RGBA,h.UNSIGNED_BYTE,b),u.sample(performance.now()-z),u.changed&&(u.changed=!1,k())),T.updateTags(o),T.updateCaptions(o),o.visible&&!i.classList.contains("is-ready")&&requestAnimationFrame(()=>i.classList.add("is-ready"))}let R=0,x=0,E=0,C=!0,P=!1;function B(Y){if(Y&&(C=!0),a){g&&S(performance.now());return}!R&&g&&o.visible&&!document.hidden&&(x=0,R=requestAnimationFrame(V))}function V(Y){R=0;let F=x?Math.min(.05,(Y-x)/1e3):0;x=Y;let z=o.started&&!P&&(o.phase==="pre"||o.phase==="post");if(z)if(M+=F,o.phase==="pre")o.T+=F,o.T>=14.4&&T.enterGate();else{o.u+=F;let he=Pt(o.decision);o.u>=Jt[he]&&(o.u=Jt[he],o.phase="end",T.showEnd())}else o.phase==="gate"&&!P&&(M+=F);T.tickCountdown(Y),w.sx+=(w.x-w.sx)*.06,w.sy+=(w.y-w.sy)*.06;let Z=Math.abs(w.x-w.sx)+Math.abs(w.y-w.sy)>.002,fe=o.phase==="gate"&&Y-E>=(o.later?30:46);(z||C||Z||fe||!u.benchmarked)&&(C=!1,E=Y,S(Y),z&&u.frame(F)&&k()),(z||o.phase==="gate"||Z||C||!u.benchmarked)&&o.visible&&!document.hidden&&(R=requestAnimationFrame(V))}function N(){cancelAnimationFrame(R),R=0}n.addEventListener("pointermove",Y=>{if(Y.pointerType!=="mouse"||a)return;let F=n.getBoundingClientRect();w.x=(Y.clientX-F.left)/F.width*2-1,w.y=(Y.clientY-F.top)/F.height*2-1,B()}),n.addEventListener("pointerleave",()=>{w.x=0,w.y=0,B()});function k(){let Y=n.clientWidth,F=n.clientHeight;if(!Y||!F)return;c.setPixelRatio(u.dpr),c.setSize(Y,F,!1),m.uFloor.uView.value.set(Y*u.dpr,F*u.dpr),v.aspect=Y/F;let z=Y/F>=1.02?"wide":"tall";v.fov=z==="wide"?32:46,z!==m.L.kind&&(m.setLayout(z),g=Wc(m.L)),z==="wide"?v.setViewOffset(Y,F,0,-F*.045,Y,F):v.clearViewOffset(),v.updateProjectionMatrix(),T.measure(),g&&o.phase!=="idle"&&S(performance.now())}m.setLayout(n.clientWidth/Math.max(1,n.clientHeight)>=1.02?"wide":"tall"),g=Wc(m.L),Promise.all([document.fonts.load('400 40px "IBM Plex Mono"'),document.fonts.load('500 40px "Hanken Grotesk"'),document.fonts.load('600 40px "Hanken Grotesk"'),new Promise(Y=>f.complete?Y():f.onload=f.onerror=Y)]).catch(()=>{}).then(async()=>{m.redrawCards(),k(),p.update(o,0);try{await(c.compileAsync?c.compileAsync(m.scene,v):c.compile(m.scene,v))}catch{}if(m.scene.traverse(z=>z.material&&z.material.map&&c.initTexture(z.material.map)),o.phase="pre",o.T=0,new ResizeObserver(()=>k()).observe(n),a){i.classList.add("is-still"),o.started=!0,o.decision="once",o.phase="end",o.u=Jt.allow,q(()=>S(performance.now())),S(performance.now());return}S(performance.now());let Y=new IntersectionObserver(z=>{let Z=z[0];o.visible=Z.isIntersecting,Z.intersectionRatio>=.55&&!o.started&&(o.started=!0),o.visible?B(!0):N(),o.visible&&!o.started&&setTimeout(F,250)},{threshold:[0,.55]});function F(){if(o.started||!o.visible)return;let z=n.getBoundingClientRect();Math.min(z.bottom,innerHeight)-Math.max(z.top,0)>=.55*z.height?(o.started=!0,B(!0)):setTimeout(F,250)}Y.observe(n),document.addEventListener("visibilitychange",()=>document.hidden?N():B(!0))}),r.has("debug")&&(window.__akhw={S:o,Q:u,gpu:l,W:m,renderer:c,camera:v,go(Y,F,z){if(T.hideEnd(),o.started=!0,Y==="gate"){o.phase="pre",o.T=14.4-.01,o.decision=null,B(!0);return}Y!=="pre"&&o.phase==="gate"&&(T.hideAlert(!0),i.classList.remove("is-gate","is-later")),o.phase=Y,Y==="pre"?o.T=F:o.u=F,o.decision=z??o.decision,Y==="post"&&F>=Jt[Pt(o.decision)]&&(o.phase="end",o.u=Jt[Pt(o.decision)],T.showEnd()),B(!0)},gate(){T.enterGate(),B(!0)},freeze(Y){P=!!Y,Y||B(!0)},render(){S(performance.now())},decide:T.decide});function q(Y){i.dataset.outcome="allow";let F=t(".akhw-lede");F&&F.dataset.still&&(F.textContent=F.dataset.still);let z=t(".akhw-alert"),Z=document.createElement("div");if(Z.className="akhw-still-alert",n.after(Z),Z.appendChild(z),z.hidden=!1,t(".akhw-hint").hidden=!0,z.querySelector(".akhw-alert-foot").hidden=!0,z.addEventListener("click",fe=>{let he=fe.target.closest("[data-decide]");he&&(o.decision=he.dataset.decide,o.u=Jt[Pt(o.decision)],o.phase="end",i.dataset.outcome=al(o.decision),Y&&Y())}),!Y){let fe=t(".akhw-poster img");fe&&(fe.loading="eager")}}} diff --git a/site/how/img/paper.jpg b/site/how/img/paper.jpg new file mode 100644 index 0000000..5bd8589 Binary files /dev/null and b/site/how/img/paper.jpg differ diff --git a/site/how/img/poster-en-tall.webp b/site/how/img/poster-en-tall.webp new file mode 100644 index 0000000..70e3d4b Binary files /dev/null and b/site/how/img/poster-en-tall.webp differ diff --git a/site/how/img/poster-en-wide.webp b/site/how/img/poster-en-wide.webp new file mode 100644 index 0000000..4a2a2d0 Binary files /dev/null and b/site/how/img/poster-en-wide.webp differ diff --git a/site/how/img/poster-zh-tall.webp b/site/how/img/poster-zh-tall.webp new file mode 100644 index 0000000..4b46def Binary files /dev/null and b/site/how/img/poster-zh-tall.webp differ diff --git a/site/how/img/poster-zh-wide.webp b/site/how/img/poster-zh-wide.webp new file mode 100644 index 0000000..dc02d6d Binary files /dev/null and b/site/how/img/poster-zh-wide.webp differ diff --git a/site/how/img/seal-zhun.webp b/site/how/img/seal-zhun.webp new file mode 100644 index 0000000..51e2d2c Binary files /dev/null and b/site/how/img/seal-zhun.webp differ diff --git a/site/how/img/walnut.webp b/site/how/img/walnut.webp new file mode 100644 index 0000000..cf9d0d8 Binary files /dev/null and b/site/how/img/walnut.webp differ diff --git a/site/index.html b/site/index.html new file mode 100644 index 0000000..b172f46 --- /dev/null +++ b/site/index.html @@ -0,0 +1,334 @@ + + + + + + Ask Key — the Mac key manager for AI + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

No key leaves
without your seal.

+

The Mac key manager for AI.

+
    +
  • Find keys: AI agents look them up, no more pointing the way
  • +
  • Your rules: everyday keys pass, sensitive ones wait for you
  • +
  • Locked down: keys go only to the program, never to the AI
  • +
+
+
+ +

Free and open source · Requires Apple silicon and macOS 14 or later

+
+
+
+
+ A sheet of handmade paper on a wooden desk, beside an open box of cinnabar ink paste and a stone seal. + A vermilion seal impression of the character 准, approved. +
+
+
+ +
+
+
+ 一How it works +

You say one line and click once. That’s it.

+

Watch one request from start to finish. When it needs a key, it stops and waits for you.

+
+ +
+
+ + Ask Key in the middle, the AI on the left and the program ./deploy.sh on the right. The key goes from Ask Key straight to the program; the AI only gets back one line of output. + + + + + + + + +
+ +
+ +
    +
  1. You tell your AI:
    “Publish the website.”

  2. +
  3. It looks through Ask Key’s catalog and finds the key it needs.
    You don’t have to tell it where the key is.

  4. +
  5. To use it, the AI files a request:
    run ./deploy.sh with “Website server”.

  6. +
  7. Ask Key asks you.
    Who wants which key, to run what. It’s all on one prompt.

  8. +
  9. +

    You allowed it.
    Ask Key hands the key straight to ./deploy.sh, not to the AI.

    +

    You allowed it for 30 minutes.
    The key goes straight to ./deploy.sh. For the next 30 minutes it’s used without asking you again.

    +

    You said no.
    ./deploy.sh never runs, and the key stays put.

    +

    Nobody answered.
    The request expired after five minutes.

    +
  10. +
  11. +

    The AI gets back one line: “Deployed”.
    The job is done, and the AI never held the key. Every use is in Access records.

    +

    The AI gets back one line: “Denied”.
    Using a key always goes through you.

    +

    The AI gets back one line: “Expired”.
    Using a key always goes through you.

    +
  12. +
+ + +
+ +
+
+
+ 二Permissions +

Every key follows your rule.

+

Everyday keys pass, important ones ask you every time, and keys your AI should never touch stay hidden.

+

When a key needs asking, Ask Key shows who wants it, which key, and what for. Allow it once, or for 30 minutes; for those 30 minutes, every AI on the same Mac can use it without asking again.

+
+
+

Allow

Your AI uses it without asking, and every use is recorded.

准, approved
+

Ask every timeDefault

Every use waits for your yes.

问, ask
+

Hidden

Your AI can’t see this key, so it never asks for it.

隐, hidden
+ +
+
+
+ +
+
+ 三Clients +

Works with the AI coding tools you already use.

+

Four connect in one click. Any other tool that speaks MCP works with a short config.

+
+ +
Ask Key
+
    +
  • Claude Code
  • +
  • Codex
  • +
  • Cursor
  • +
  • Grok Build
  • +
+
    +
  • Claude Desktop
  • +
  • VS Code
  • +
  • Kiro
  • +
  • Trae
  • +
  • Windsurf
  • +
  • Qwen Code
  • +
  • Zed
  • +
  • Cline
  • +
+
+
    +
  • One clickAsk Key writes the settings for you
  • +
  • By handPaste a short config into any MCP tool
  • +
+
"askkey": {
+  "command": "/Applications/Ask Key.app/Contents/Helpers/askkey",
+  "args": ["mcp"]
+}
+
+
+ +
+
+
+ 四Limits +

What it doesn’t promise.

+

Ask Key decides who gets a key, and when. A few things are outside its reach; know them before you rely on it.

+ The full security model +
+
    +
  1. 01
    Programs can pass keys on

    A program you approve can print, copy or forward the key it receives. You are approving that program, not just the AI that asked.

  2. +
  3. 02
    Names are self-reported

    The requester and purpose in the prompt come from the AI. They help you read the request; they are not a verified identity.

  4. +
  5. 03
    Other programs in your account

    Once a key reaches a program, other programs in the same Mac account may read it. Hidden doesn’t cover that path.

  6. +
  7. 04
    Timed allow covers every AI

    “Allow for 30 minutes” applies to every AI on this Mac, not just the one that asked.

  8. +
  9. 05
    No backup yet

    There is no backup or restore yet. Keep a copy of important keys somewhere else.

  10. +
+
+
+ +
+
+
+
+ +
+ The Ask Key app icon: an orange access card with a white key + + +
+ +
+
+
+

Ask Key

+

The Mac key manager for AI.

+ Download for Mac +

Free · Requires Apple silicon and macOS 14 or later
Drag the app to Applications and keep its name.

+
    +
  • Free and open sourceMIT licensed, every line of code on GitHub. If it helps you, give it a star.
  • +
  • Notarized by AppleThe installer passed Apple’s security check.
  • +
  • Encrypted on your MacYour keys are encrypted and kept on your own Mac.
  • +
+ +
+
+
+
+ + + + diff --git a/site/motion.js b/site/motion.js new file mode 100644 index 0000000..9e0d1a2 --- /dev/null +++ b/site/motion.js @@ -0,0 +1,271 @@ +// A small, self-contained animation. The markup already shows each +// section's final state; these only add motion on wide screens when the +// reader has not asked for reduced motion. +(() => { + const still = matchMedia("(prefers-reduced-motion: reduce)").matches || innerWidth < 900; + const clamp = (v, a = 0, b = 1) => Math.min(b, Math.max(a, v)); + + // The three permissions, stamped in turn. + const desk = document.querySelector(".desk"); + if (desk) { + if (!still) { + desk.classList.add("animated"); + const stone = desk.querySelector(".stone"); + const slips = [...desk.querySelectorAll(".slip")]; + // Settle on the final state: every seal shown, the stone put away. + const finish = () => { + stone.getAnimations().forEach((a) => a.cancel()); + stone.style.opacity = 0; + stone.classList.remove("moving"); + for (const slip of slips) { + slip.querySelector(".imp").style.opacity = "1"; + if (slip.classList.contains("hidden-slip")) slip.classList.add("gone"); + } + }; + const run = async () => { + // If the layout changes while the stone is in the air, stop rather + // than fly to stale coordinates. + const stop = () => stone.getAnimations().forEach((a) => a.cancel()); + addEventListener("resize", stop, { once: true }); + try { await stamp(); } catch { /* cancelled */ } + removeEventListener("resize", stop); + finish(); + }; + const stamp = async () => { + // Positions come from layout offsets inside the desk, not from the + // viewport, so scrolling while the stone is in the air cannot move + // its target. + const box = (el) => { + let x = 0, y = 0; + for (let e = el; e && e !== desk; e = e.offsetParent) { x += e.offsetLeft; y += e.offsetTop; } + return { x, y, w: el.offsetWidth, h: el.offsetHeight }; + }; + const dw = desk.offsetWidth; + // The seal image has a margin of 40/720 around the printed border; + // the stone's face is as wide as the stone, so size the stone to + // the printed border and land its face on it. + const inset = 40 / 720; + const sw = box(slips[0].querySelector(".imp")).w * (1 - 2 * inset); + const sh = sw * 2.16; + stone.style.width = `${sw}px`; + const spot = (slip) => { + const r = box(slip.querySelector(".imp")); + return { x: r.x + r.w / 2 - sw / 2, y: r.y + r.h - r.h * inset - sh }; + }; + const move = (from, to, ms) => stone.animate( + [{ transform: from, opacity: 1 }, { transform: to, opacity: 1 }], + { duration: ms, easing: "cubic-bezier(.45,0,.2,1)", fill: "forwards" }).finished; + let at = `translate(${dw}px, -40px)`; + stone.classList.add("moving"); + stone.style.opacity = 1; + for (const [i, slip] of slips.entries()) { + const s = spot(slip); + const up = `translate(${s.x}px, ${s.y - 22}px)`; + const down = `translate(${s.x}px, ${s.y}px)`; + await move(at, up, i === 0 ? 700 : 520); + await move(up, down, 170); + // Commit the shown state on the element itself, so the seal never + // depends on a finished animation being kept alive. + const imp = slip.querySelector(".imp"); + imp.style.opacity = "1"; + imp.animate( + [{ opacity: 0, transform: "scale(1.08)" }, { opacity: 1, transform: "scale(1)" }], + { duration: 260, easing: "ease-out" }); + await new Promise((r) => setTimeout(r, 120)); + await move(down, up, 260); + at = up; + if (slip.classList.contains("hidden-slip")) slip.classList.add("gone"); + } + await stone.animate( + [{ transform: at, opacity: 1 }, { transform: `translate(${dw * 0.9}px, -80px)`, opacity: 0 }], + { duration: 700, easing: "ease-in", fill: "forwards" }).finished; + }; + const io = new IntersectionObserver((entries) => { + if (entries.some((e) => e.isIntersecting)) { io.disconnect(); run(); } + }, { threshold: 0.55 }); + io.observe(desk); + } + } + + // The clients: Ask Key in the middle, a red line to each tool it sets up + // itself, a dotted one to every other tool that speaks MCP. Wide screens + // put the tools on both sides; narrow ones fan them out to the right. + const hub = document.querySelector(".hub"); + if (hub) { + const NS = "http://www.w3.org/2000/svg"; + const svg = hub.querySelector(".hub-lines"); + const autos = [...hub.querySelectorAll(".hub-names.is-auto li")]; + const mcps = [...hub.querySelectorAll(".hub-names.is-mcp li")]; + const line = (d, kind, delay) => { + const p = document.createElementNS(NS, "path"); + p.setAttribute("d", d); + p.setAttribute("class", kind); + svg.appendChild(p); + p.style.setProperty("--len", p.getTotalLength()); + p.style.setProperty("--d", `${delay}s`); + }; + const place = (li, x, y, left, delay) => { + li.style.left = `${x}px`; + li.style.top = `${y}px`; + li.classList.toggle("is-left", left); + li.style.setProperty("--d", `${delay}s`); + }; + const wide = () => { + hub.style.height = ""; + const W = hub.clientWidth, H = hub.clientHeight, cx = W / 2, cy = H / 2, r = 56; + const rows = [0.08, 0.24, 0.76, 0.92]; + autos.forEach((li, i) => { + const s = i < 2 ? -1 : 1, x = cx + s * W * 0.17, y = H * (i % 2 ? 0.64 : 0.36); + const ex = cx + s * r, ey = cy + (y / H - 0.5) * 24, mx = (x - s * 14 + ex) / 2; + place(li, x, y, s < 0, i * 0.14); + line(`M${x - s * 14},${y} C${mx},${y} ${mx},${ey} ${ex},${ey}`, "is-auto", i * 0.14); + }); + mcps.forEach((li, i) => { + // run level, then turn into the top of the icon or below its name + const s = i < 4 ? -1 : 1, k = i % 4, x = cx + s * W * 0.3, y = H * rows[k]; + const ex = cx + s * (k === 0 || k === 3 ? 44 : 22), ey = k < 2 ? cy - r : cy + r + 58; + place(li, x, y, s < 0, 0.6 + i * 0.08); + line(`M${x - s * 14},${y} C${ex},${y} ${ex},${y} ${ex},${ey}`, "is-mcp", 0.6 + i * 0.08); + }); + }; + const narrow = () => { + const ix = 36, iy = 36, nx = 116, top = 236, step = 32; + hub.style.height = `${top + mcps.length * step}px`; + autos.forEach((li, i) => { + const y = 18 + i * 48; + place(li, nx, y, false, i * 0.14); + line(`M${ix + 36},${iy} C${ix + 66},${iy} ${ix + 50},${y} ${nx - 12},${y}`, "is-auto", i * 0.14); + }); + // the grey branches leave one shared trunk under the icon + line(`M${ix},${iy + 66} L${ix},${top + (mcps.length - 1) * step - 26}`, "is-mcp", 0.6); + mcps.forEach((li, i) => { + const y = top + i * step; + place(li, nx, y, false, 0.6 + i * 0.08); + line(`M${ix},${y - 26} C${ix},${y} ${ix},${y} ${ix + 22},${y} L${nx - 12},${y}`, "is-mcp", 0.6 + i * 0.08); + }); + }; + const layout = () => { + svg.replaceChildren(); + hub.classList.add("is-laid"); + const thin = hub.clientWidth < 620; + hub.classList.toggle("is-narrow", thin); + svg.setAttribute("viewBox", `0 0 ${hub.clientWidth} ${hub.clientHeight}`); + (thin ? narrow : wide)(); + svg.setAttribute("viewBox", `0 0 ${hub.clientWidth} ${hub.clientHeight}`); + }; + if (!matchMedia("(prefers-reduced-motion: reduce)").matches) { + hub.classList.add("is-pending"); + const io = new IntersectionObserver((entries) => { + if (entries.some((e) => e.isIntersecting)) { io.disconnect(); hub.classList.remove("is-pending"); } + }, { threshold: 0.35 }); + io.observe(hub); + } + // Manual setup is one copy away; the config only shows if copying fails. + const copy = document.querySelector(".hub-copy"), conf = document.querySelector(".hub-config"); + if (copy && conf && navigator.clipboard) { + const label = copy.textContent; + copy.hidden = false; + conf.hidden = true; + copy.addEventListener("click", async () => { + try { + await navigator.clipboard.writeText(conf.textContent); + copy.textContent = copy.dataset.done; + setTimeout(() => (copy.textContent = label), 1800); + } catch { + copy.textContent = copy.dataset.fail; + conf.hidden = false; + } + }); + } + document.fonts.ready.then(layout); + let w = innerWidth; + addEventListener("resize", () => { if (innerWidth !== w) { w = innerWidth; layout(); } }); + } + + // The checksum command, one click to copy. + const cmd = document.querySelector(".dl-copycmd"); + if (cmd && navigator.clipboard) { + const label = cmd.textContent; + cmd.addEventListener("click", async () => { + try { await navigator.clipboard.writeText(cmd.dataset.copy); cmd.textContent = cmd.dataset.done; } + catch { cmd.textContent = cmd.dataset.fail; } + setTimeout(() => (cmd.textContent = label), 1800); + }); + } + + // The access card hangs from its cord. It drops in and swings to rest, + // turns toward the pointer like a real card in the hand, catches the light + // as it turns, and swings when brushed. Only transforms change per frame, + // and the loop sleeps whenever the card is off screen. + const pass = document.querySelector(".pass"); + if (pass && !matchMedia("(prefers-reduced-motion: reduce)").matches) { + const swing = pass.querySelector(".pass-swing"); + const tilt = pass.querySelector(".pass-tilt"); + const shadow = pass.querySelector(".pass-shadow"); + const shine = pass.querySelector(".pass-shine"); + let theta = 0, omega = 0, drop = 0, dropV = 0; + let rx = 0, ry = 0, trx = 0, try_ = 0; + let px = null, pt = 0, shineAt = -1; + let visible = false, raf = 0, last = 0, t = 0; + + const frame = (now) => { + const dt = Math.min(0.034, (now - last) / 1000 || 0.016); + last = now; + t += dt; + // a pendulum with a little air: gravity, damping and a faint draught + const draught = 0.1 * Math.sin(t * 0.8) + 0.05 * Math.sin(t * 1.9); + omega += (-14 * Math.sin(theta) - 1.1 * omega + draught) * dt; + theta += omega * dt; + // the drop: a spring that settles the card on its cord + dropV += (-90 * drop - 13 * dropV) * dt; + drop += dropV * dt; + const k = Math.min(1, dt * 7); + rx += (trx - rx) * k; + ry += (try_ - ry) * k; + swing.style.transform = `translateY(${drop.toFixed(2)}%) rotate(${theta.toFixed(4)}rad)`; + tilt.style.transform = `rotateX(${rx.toFixed(2)}deg) rotateY(${ry.toFixed(2)}deg)`; + shadow.style.transform = `translate(${(14 - ry * 0.9).toFixed(1)}px, ${(26 + rx * 0.7).toFixed(1)}px)`; + // light: follows the turn, and now and then sweeps across on its own + // f is where the highlight crosses the card, 0 at its left edge, 1 at its right + let f = 0.15 + ry * 0.04; + if (shineAt < 0 && t > 1.2 && (t % 7) < dt) shineAt = t; + if (shineAt >= 0) { + const p = (t - shineAt) / 1.3; + if (p >= 1) shineAt = -1; + else f = -0.4 + 1.8 * (p * p * (3 - 2 * p)); + } + shine.style.backgroundPosition = `${((1.5 - f) * 50).toFixed(2)}% 0`; + raf = visible ? requestAnimationFrame(frame) : 0; + }; + const wake = () => { if (!raf && visible) { last = performance.now(); raf = requestAnimationFrame(frame); } }; + + // Wait above the cord's rest until the card first comes into view. + drop = -16; + theta = 0.34; + swing.style.transform = `translateY(${drop}%) rotate(${theta}rad)`; + new IntersectionObserver((entries) => { + visible = entries.some((e) => e.isIntersecting); + wake(); + }, { threshold: 0.2 }).observe(pass); + + pass.addEventListener("pointermove", (e) => { + const r = tilt.getBoundingClientRect(); + const nx = (e.clientX - (r.left + r.width / 2)) / (r.width * 0.9); + const ny = (e.clientY - (r.top + r.height / 2)) / (r.height * 0.9); + try_ = Math.max(-1, Math.min(1, nx)) * 18; + trx = Math.max(-1, Math.min(1, -ny)) * 12; + // brushing past the card sets it swinging + if (px !== null && e.pointerType === "mouse") { + const v = (e.clientX - px) / Math.max(1, e.timeStamp - pt); + omega += Math.max(-0.5, Math.min(0.5, v * 0.04)); + } + px = e.clientX; + pt = e.timeStamp; + }); + pass.addEventListener("pointerleave", () => { trx = 0; try_ = 0; px = null; }); + pass.addEventListener("pointerdown", (e) => { + const r = pass.getBoundingClientRect(); + omega += (e.clientX < r.left + r.width / 2 ? 1 : -1) * 0.9; + }); + } +})(); diff --git a/site/style.css b/site/style.css new file mode 100644 index 0000000..a4838fc --- /dev/null +++ b/site/style.css @@ -0,0 +1,387 @@ +@font-face { + font-family: "Hanken Grotesk"; + src: url("/fonts/HankenGrotesk-Variable.woff2") format("woff2"); + font-weight: 200 600; + font-style: normal; + font-display: swap; +} +@font-face { + font-family: "IBM Plex Mono"; + src: url("/fonts/IBMPlexMono-Regular-Latin1.woff2") format("woff2"); + font-weight: 400; + font-style: normal; + font-display: swap; +} + +:root { + --paper: #ffffff; + --ink: #1a1a1a; + --gray: #6e6e6e; + --faint: #858585; + --line: #e7e7e7; + --zhu: #b8281e; + --wood: #1c1511; + + --sans: "Hanken Grotesk", "PingFang SC", "Hiragino Sans GB", "Noto Sans CJK SC", system-ui, sans-serif; + --song: "Songti SC", "Noto Serif CJK SC", "Source Han Serif SC", serif; + --mono: "IBM Plex Mono", "SF Mono", ui-monospace, Menlo, monospace; + + --gutter: clamp(24px, 4.5vw, 64px); + --page: min(1200px, 100% - 2 * var(--gutter)); +} + +*, +*::before, +*::after { box-sizing: border-box; } + +html { -webkit-text-size-adjust: 100%; } + +body { + margin: 0; + background: var(--paper); + color: var(--ink); + font-family: var(--sans); + font-size: 16px; + font-weight: 300; + line-height: 1.75; + -webkit-font-smoothing: antialiased; + font-synthesis-weight: none; +} + +img, video { display: block; max-width: 100%; height: auto; } +a { color: inherit; } +p { text-wrap: pretty; } +code, pre { font-family: var(--mono); } +:focus-visible { outline: 1px solid var(--zhu); outline-offset: 4px; } + +.wrap { width: var(--page); margin-inline: auto; } + +.link { + text-decoration: none; + border-bottom: 1px solid var(--zhu); + padding-bottom: 3px; + font-weight: 400; + color: var(--ink); +} +.link:hover { color: var(--zhu); } + +h1, h2 { text-wrap: balance; font-weight: 300; } +:lang(zh) h1, :lang(zh) h2 { font-family: var(--song); letter-spacing: 0.04em; } +:lang(zh) h2 { word-break: keep-all; } + +.num { + display: block; + margin-bottom: 20px; + font-family: var(--song); + font-size: 15px; + color: var(--zhu); +} +.num span { margin-left: 14px; font-family: var(--sans); font-size: 12.5px; letter-spacing: 0.04em; color: var(--faint); } + +/* Hero */ + +.hero { + position: relative; + display: grid; + /* The text starts on the same left edge as every section below; the + photograph still bleeds to the right edge of the window. */ + grid-template-columns: calc((100% - var(--page)) / 2) calc(var(--page) * 0.5) minmax(0, 1fr); + min-height: 100vh; + min-height: 100svh; +} +.hero-text { + display: flex; + flex-direction: column; + grid-column: 2; + padding: 36px var(--gutter) 56px 0; +} +.nav { + display: flex; + align-items: center; + gap: 26px; + font-size: 14.5px; + color: var(--gray); +} +.nav .brand { + display: flex; + align-items: center; + gap: 10px; + margin-right: auto; + color: var(--ink); + font-weight: 400; + text-decoration: none; +} +.nav .brand img { width: 22px; height: 22px; align-self: center; } +.nav .brand small { margin-left: -2px; font-size: 13px; font-weight: 400; color: var(--faint); } +.nav a { text-decoration: none; } +.nav a:hover { color: var(--ink); } + +.statement { margin: auto 0 0; padding: 56px 0 0; } +.statement h1 { + margin: 0; + font-weight: 200; + font-size: clamp(40px, 4.4vw, 66px); + line-height: 1.14; + letter-spacing: -0.02em; +} +.statement h1 b { font-weight: 400; color: var(--zhu); } +:lang(zh) .statement h1 b { font-weight: inherit; } +:lang(zh) .statement h1 { font-weight: 300; font-size: clamp(36px, 3.8vw, 56px); line-height: 1.35; } +.statement .sub { margin: 26px 0 0; max-width: 26em; font-size: clamp(18px, 1.5vw, 21px); line-height: 1.7; color: #4d4d4d; } +.statement .points { margin: 18px 0 0; padding: 0; list-style: none; font-size: clamp(16px, 1.25vw, 18px); line-height: 1.6; color: #4d4d4d; } +.statement .points li { position: relative; padding-left: 20px; margin-top: 8px; } +.statement .points li b { font-weight: 500; color: var(--ink); } +.statement .points li::before { content: ""; position: absolute; left: 2px; top: 0.72em; width: 8px; height: 2px; background: var(--zhu); } +.statement .sub strong { display: block; margin-bottom: 0; text-wrap: balance; font-size: 1.12em; font-weight: 500; color: var(--ink); } + +.intro { margin: 40px 0 auto; } +.cta { + display: inline-block; + padding: 13px 28px; + border-radius: 999px; + background: var(--ink); + color: #fff; + font-size: 16px; + font-weight: 400; + text-decoration: none; + transition: background 0.2s ease; +} +.cta:hover { background: var(--zhu); } +.ctas { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 28px; } +.cta-alt { font-size: 15px; font-weight: 400; color: var(--gray); text-decoration: none; transition: color 0.2s ease; } +.cta-alt::after { content: " →"; } +.cta-alt:hover { color: var(--zhu); } +.intro .meta { margin: 14px 0 0; font-size: 14px; color: var(--gray); } + +.hero-image { + position: relative; + margin: 0; + overflow: hidden; + grid-column: 3; + background: var(--wood); + container-type: inline-size; +} +.hero-image .plate { + position: absolute; + top: 0; + left: 0; + height: 100%; + aspect-ratio: 1672 / 941; + /* Keep the seal (its centre is 73.6% across the photograph) three quarters + of the way across the column, whatever the window's shape, without ever + uncovering an edge of the column. */ + transform: translateX(clamp(calc(100cqw - 100%), calc(75cqw - 73.6%), 0px)); +} +.hero-image .plate .photo { width: 100%; height: 100%; } +.hero-image .seal { + position: absolute; + left: 67.2%; + top: 37.6%; + width: 12.9%; + height: auto; + mix-blend-mode: multiply; +} + +@media (prefers-reduced-motion: no-preference) { + .hero-image .seal { animation: stamp 0.55s cubic-bezier(0.3, 0.7, 0.2, 1) 0.9s both; } + .fade { animation: fade 1.1s ease 0.15s both; } +} +@keyframes stamp { + 0% { opacity: 0; transform: scale(1.22); filter: blur(3px); } + 55% { opacity: 1; transform: scale(0.97); filter: blur(0); } + 100% { opacity: 1; transform: none; } +} +@keyframes fade { from { opacity: 0; } to { opacity: 1; } } + +/* Seals: three permissions, stamped in turn */ + +.decide { padding: clamp(96px, 12vw, 168px) 0 0; } +.decide-grid { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: clamp(32px, 4vw, 64px); align-items: start; } +.decide h2 { margin: 0 0 20px; font-size: clamp(26px, 2.5vw, 34px); line-height: 1.3; } +.decide p { margin: 0 0 14px; color: var(--gray); font-size: 16px; } + +/* The slips start level with the heading, under the section number. */ +.desk { position: relative; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(12px, 2vw, 28px); margin-top: 46px; } +.slip { + position: relative; + aspect-ratio: 3 / 4; + padding: 22px 20px; + background: #f3eee5 url("/assets/paper.jpg") center / cover; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.06), 0 18px 30px -18px rgba(40, 25, 10, 0.35); + transition: opacity 0.8s ease; +} +.slip h3 { margin: 0 0 6px; font-size: 17px; font-weight: 400; } +:lang(zh) .slip h3 { font-family: var(--song); font-size: 19px; } +/* The short lines on the slips break at punctuation, never inside a word. */ +:lang(zh) .slip p { word-break: keep-all; } +.slip h3 small { display: inline-block; margin-left: 10px; padding: 0 5px; border: 1px solid var(--zhu); border-radius: 2px; font-family: var(--sans); font-size: 11px; line-height: 1.6; letter-spacing: 0.04em; color: var(--zhu); vertical-align: 3px; } +.slip p { margin: 0; font-size: 14.5px; line-height: 1.65; color: #3f3b35; } +.slip .imp { position: absolute; left: 50%; bottom: 9%; width: 32%; margin-left: -16%; opacity: 0; } +.slip.gone { opacity: 0.55; } +.stone { position: absolute; top: 0; left: 0; width: clamp(48px, 4.4vw, 68px); pointer-events: none; opacity: 0; } +.stone.moving { will-change: transform, opacity; } +.stone img { width: 100%; filter: drop-shadow(0 14px 14px rgba(40, 25, 10, 0.25)); } + +.desk:not(.animated) .imp { opacity: 1; } +.desk:not(.animated) .stone { display: none; } +.desk:not(.animated) .hidden-slip { opacity: 0.55; } + +/* Clients, limits, download */ + +.chapter { padding: clamp(96px, 12vw, 168px) 0 0; } +.chapter h2 { margin: 0 0 22px; font-size: clamp(26px, 2.5vw, 34px); line-height: 1.3; } +.chapter p { margin: 0 0 16px; color: var(--gray); font-size: 16px; } + +.chapter .lede { max-width: 40em; margin: 0; font-size: clamp(16px, 1.3vw, 18px); } + +/* Clients: Ask Key in the middle, a red line to each tool it sets up itself and a + dotted one to everything else that speaks MCP. motion.js lays the names out; + without it they read as two plain lists. */ +.hub { position: relative; margin-top: clamp(32px, 4vw, 48px); } +.hub-lines { display: none; } +.hub-core { display: none; } +.hub-names { display: flex; flex-wrap: wrap; gap: 4px 28px; margin: 0 0 16px; padding: 0; list-style: none; } +.hub-names.is-auto { font-size: clamp(22px, 2.3vw, 32px); font-weight: 300; letter-spacing: -0.01em; color: var(--ink); } +.hub-names.is-mcp { font-size: clamp(15px, 1.35vw, 18px); font-weight: 300; color: #8d8d8d; } +.hub.is-laid { height: clamp(440px, 42vw, 560px); } +.hub.is-laid .hub-lines { display: block; position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; } +.hub.is-laid .hub-names { display: contents; } +.hub.is-laid .hub-names li { position: absolute; white-space: nowrap; line-height: 1; transform: translateY(-50%); } +.hub.is-laid .hub-names li.is-left { transform: translate(-100%, -50%); } +.hub.is-laid .hub-core { display: block; position: absolute; left: 50%; top: calc(50% - 56px); transform: translateX(-50%); text-align: center; } +.hub-core img { width: 112px; height: 112px; border-radius: 26px; box-shadow: 0 24px 40px -18px rgba(120, 40, 10, 0.45), 0 2px 6px rgba(0, 0, 0, 0.08); } +.hub-core b { display: block; margin-top: 14px; font-family: var(--song); font-size: 19px; font-weight: 400; letter-spacing: 0.08em; } +:lang(en) .hub-core b { font-family: var(--sans); letter-spacing: 0; } +.hub.is-narrow .hub-core { left: 0; top: 0; transform: none; } +.hub.is-narrow .hub-core img { width: 72px; height: 72px; border-radius: 17px; } +.hub.is-narrow .hub-core b { margin-top: 8px; font-size: 15px; } +.hub.is-narrow .hub-names li.is-left { transform: translateY(-50%); } +.hub.is-narrow .hub-names.is-auto { font-size: 24px; } +.hub.is-narrow .hub-names.is-mcp { font-size: 16px; } +.hub-lines path { fill: none; } +.hub-lines .is-auto { stroke: var(--zhu); stroke-width: 1.4; } +.hub-lines .is-mcp { stroke: #cfcfcf; stroke-width: 1; stroke-dasharray: 2 5; stroke-linecap: round; } +.hub.is-pending .hub-lines .is-auto { stroke-dasharray: var(--len); stroke-dashoffset: var(--len); } +.hub.is-pending .hub-lines .is-mcp, .hub.is-pending .hub-names li { opacity: 0; } +.hub-lines .is-auto { transition: stroke-dashoffset 1.2s cubic-bezier(0.6, 0, 0.2, 1) var(--d); } +.hub-lines .is-mcp, .hub-names li { transition: opacity 0.8s ease var(--d); } +.hub-legend { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 48px; margin: 36px 0 0; padding: 0; list-style: none; font-size: 14.5px; color: var(--gray); } +.hub-legend i { display: inline-block; width: 28px; margin-right: 10px; vertical-align: middle; border-top: 1.4px solid var(--zhu); } +.hub-legend i.is-mcp { border-top: 1.6px dotted #b8b8b8; } +.hub-legend b { margin-right: 6px; font-weight: 500; color: var(--ink); } +.hub.is-narrow + .hub-legend { flex-direction: column; justify-content: flex-start; gap: 8px; } +.hub-copy { margin-left: 14px; padding: 0 0 1px; border: 0; border-bottom: 1px solid var(--zhu); background: none; font: inherit; font-weight: 400; color: var(--ink); cursor: pointer; } +.hub-copy:hover { color: var(--zhu); } +.hub-config { max-width: 560px; margin: 24px auto 0; } +.hub.is-narrow ~ .hub-config { margin-left: 0; } +/* Config is copied as is, so it scrolls rather than wraps inside a path. */ +.code { margin: 0; padding: 16px 20px; border-radius: 10px; background: #f5f5f4; font-size: clamp(11px, 1.1vw, 12.5px); line-height: 1.8; white-space: pre; overflow-x: auto; } + +/* Limits: a pale blue-grey band that fades in and out of the white page, so the + honest part of the page reads as a change of air rather than a new page. */ +.limits-band { position: relative; isolation: isolate; margin-top: clamp(60px, 7vw, 110px); padding: clamp(150px, 15vw, 220px) 0; } +.limits-band::before { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(to bottom, #fff 0, #eef1f1 160px, #eef1f1 calc(100% - 160px), #fff 100%); } +.limits-grid { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); gap: clamp(40px, 5vw, 80px); align-items: start; } +.limits-band h2 { margin: 0; font-size: clamp(28px, 2.8vw, 38px); line-height: 1.3; } +.limits-lead { margin: 20px 0 30px; max-width: 21em; font-size: 16px; line-height: 1.85; color: var(--gray); } +.limits { margin: 0; padding: 0; list-style: none; } +.limits li { display: grid; grid-template-columns: 64px minmax(0, 1fr); padding: 22px 0 24px; border-top: 1px solid rgba(0, 0, 0, 0.08); } +.limits li:last-child { border-bottom: 1px solid rgba(0, 0, 0, 0.08); } +.limits i { padding-top: 4px; font-size: 13px; font-style: normal; letter-spacing: 0.08em; color: var(--zhu); } +.limits b { display: block; font-size: 17px; font-weight: 500; } +.limits p { margin: 6px 0 0; max-width: 36em; font-size: 15px; line-height: 1.75; color: var(--gray); } + +/* Download: the access card on the left, hanging from a vermilion cord; the + brand, the button and three reassurances on the right. motion.js swings + and tilts the card; without it the card simply hangs still. */ +.download { padding: clamp(110px, 13vw, 180px) 0 clamp(96px, 10vw, 140px); overflow-x: clip; } +.dl-grid { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: clamp(40px, 6vw, 96px); align-items: center; } +.pass { position: relative; aspect-ratio: 1; background: radial-gradient(closest-side at 50% 52%, #fbecdf 0%, #fff6ee 55%, rgba(255, 255, 255, 0) 100%); touch-action: pan-y; } +.pass-swing { position: absolute; inset: 0; transform-origin: 50% 0; perspective: 900px; perspective-origin: 50% 45%; } +.pass-cord { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; } +.pass-cord circle { fill: var(--zhu); } +.pass-cord path { fill: none; stroke: url(#pass-cord-fade); stroke-width: 1.8; stroke-linecap: round; vector-effect: non-scaling-stroke; } +.pass-tilt { position: absolute; left: 25%; top: 19%; width: 50%; } +.pass-tilt { aspect-ratio: 641 / 720; transform-origin: 49.5% 13.6%; transform-style: preserve-3d; } +/* The cast shadow is a pre-blurred image with 120 px of margin around the + card, so no browser has to blur anything while the card moves. */ +.pass-shadow { position: absolute; left: 15.64%; top: 9.64%; width: 68.72%; transform: translate(14px, 26px); } +.pass-card, .pass-key { position: absolute; inset: 0; width: 100%; height: 100%; } +.pass-key { transform: translateZ(18px); } +.pass-shine { position: absolute; inset: 0; background: linear-gradient(100deg, rgba(255, 255, 255, 0) 40%, rgba(255, 255, 255, 0.46) 50%, rgba(255, 255, 255, 0) 60%) 100% 0 / 300% 100% no-repeat; transform: translateZ(19px); -webkit-mask: url("/assets/pass.webp") center / 100% 100% no-repeat; mask: url("/assets/pass.webp") center / 100% 100% no-repeat; pointer-events: none; } +.lock { margin: 0; font-weight: 400; } +.lock b { display: block; font-family: var(--song); font-size: clamp(44px, 4.6vw, 64px); font-weight: 400; line-height: 1.1; letter-spacing: 0.1em; } +:lang(en) .lock b { font-family: var(--sans); font-weight: 300; letter-spacing: -0.02em; } +.lock span { display: block; margin-top: 10px; font-family: var(--sans); font-size: 13px; letter-spacing: 0.32em; text-transform: uppercase; color: var(--faint); } +.download .tagline { margin: 22px 0 0; font-size: clamp(17px, 1.4vw, 20px); font-weight: 400; color: #3a3a3a; } +.dl-cta { margin-top: 30px; padding: 15px 34px; font-size: 17px; } +.download .req { margin: 14px 0 0; font-size: 13.5px; line-height: 1.8; color: var(--gray); } +.assure { margin: 44px 0 0; padding: 0; list-style: none; } +.assure li { display: grid; grid-template-columns: 9em minmax(0, 1fr); gap: 16px; padding: 14px 0; border-top: 1px solid var(--line); font-size: 14.5px; color: var(--gray); } +:lang(en) .assure li { grid-template-columns: 12em minmax(0, 1fr); } +.assure b { font-weight: 500; color: var(--ink); } +.assure .star { white-space: nowrap; color: var(--ink); text-decoration: none; border-bottom: 1px solid var(--zhu); } +.assure .star:hover { color: var(--zhu); } +.download .fine { display: flex; flex-wrap: wrap; gap: 6px 28px; margin: 24px 0 0; padding: 0; list-style: none; font-size: 13.5px; } +.download .fine a, .download .fine button { padding: 0; border: 0; background: none; font: inherit; color: var(--gray); text-decoration: none; cursor: pointer; } +.download .fine a:hover, .download .fine button:hover { color: var(--zhu); } + +footer { padding: 28px 0 40px; border-top: 1px solid var(--line); font-size: 13.5px; color: var(--faint); } +footer .wrap { display: flex; flex-wrap: wrap; gap: 10px 26px; } +footer nav { display: flex; flex-wrap: wrap; gap: 8px 22px; margin-left: auto; } +footer a { text-decoration: none; } +footer a:hover { color: var(--ink); } + +/* Responsive */ + +@media (max-width: 900px) { + .dl-grid, .limits-grid { grid-template-columns: minmax(0, 1fr); } + .limits-band { padding: 120px 0; } + .limits-band::before { background: linear-gradient(to bottom, #fff 0, #eef1f1 90px, #eef1f1 calc(100% - 90px), #fff 100%); } + .pass { width: min(100%, 420px); margin: 0 auto; } + .decide-grid { grid-template-columns: minmax(0, 1fr); } + .desk { margin-top: 24px; } +} +/* Narrow windows and portrait tablets keep the two columns; the section + links leave the header, and the seal moves to the middle of the narrower + column. */ +@media (max-width: 1060px) { + .nav .hide-sm { display: none; } +} +@media (max-width: 900px), (max-aspect-ratio: 1 / 1) { + .hero-image .plate { transform: translateX(clamp(calc(100cqw - 100%), calc(50cqw - 73.6%), 0px)); } +} + +/* Phones: the header on white, a shorter band of the photograph, then the + title, the button and only then the three points, so the download is on + the first screen. */ +@media (max-width: 700px) { + .hero { grid-template-columns: minmax(0, 1fr); min-height: 0; } + .hero-image { grid-row: 1; grid-column: 1; height: clamp(240px, 42svh, 420px); } + .hero-text { grid-column: 1; padding: 0 var(--gutter) 56px; } + .statement { display: contents; } + .statement h1 { order: 1; margin-top: 30px; } + .statement .sub { order: 2; margin-top: 16px; } + .intro { order: 3; margin: 24px 0 0; } + .statement .points { order: 4; margin-top: 30px; } + .hero { padding-top: 64px; } + .nav { position: absolute; top: 20px; left: var(--gutter); right: var(--gutter); z-index: 2; } +} +@media (max-width: 560px) { + .ctas { gap: 10px 22px; } + .statement .points li b { display: block; } + .statement .points li b + .sep { display: none; } + .desk { grid-template-columns: minmax(0, 1fr); } + .slip { aspect-ratio: auto; min-height: 168px; } + .slip { padding-right: 124px; } + .limits li { grid-template-columns: 44px minmax(0, 1fr); } + .assure li, :lang(en) .assure li { grid-template-columns: minmax(0, 1fr); gap: 2px; } + .slip .imp { left: auto; right: 18px; bottom: 18px; width: 92px; margin-left: 0; } +} + +/* Touch screens: small links get a finger-sized hit area from an invisible + pseudo-element, so neither the layout nor the underlines move. */ +@media (pointer: coarse) { + .nav a, .cta-alt, .link, .hub-copy, .assure .star, .download .fine a, .download .fine button, footer a { position: relative; } + .nav a::before, .cta-alt::before, .link::before, .hub-copy::before, .assure .star::before, .download .fine a::before, .download .fine button::before, footer a::before { content: ""; position: absolute; inset: -10px -6px; } +} diff --git a/site/zh/index.html b/site/zh/index.html new file mode 100644 index 0000000..843fe78 --- /dev/null +++ b/site/zh/index.html @@ -0,0 +1,333 @@ + + + + + + 请旨 Ask Key:给 AI 用的 Mac 密钥管家 + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+

取用密钥,
先来请旨。

+

给 AI 用的 Mac 密钥管家。

+
    +
  • 密钥在哪,AI 自己就找得到,不用再频繁给它指路
  • +
  • 权限你定,普通密钥直接放行,敏感密钥由你审批
  • +
  • 安全加固,密钥只会交给目标程序,AI 看不到明文
  • +
+
+
+ +

免费开源 · 需 Apple 芯片及 macOS 14 或更高版本

+
+
+
+
+ 木桌上一张宣纸,旁边是打开的印泥盒和一方寿山石印章。 + 纸上盖着朱红的“准”字印 +
+
+
+ +
+
+
+ 一怎么用 +

你说一句话,点一次头,活就干完了。

+

下面是 AI 发布一次网站的全过程。轮到用钥匙时,它会先停下来,等你点头。

+
+ +
+
+ + 请旨在中间,左边是 AI,右边是要用钥匙的程序 ./deploy.sh。钥匙从请旨直接交给程序,AI 只拿回一句结果。 + + + + + + + + +
+ +
+ +
    +
  1. 你跟 AI 说:
    “帮我把网站发布上线。”

  2. +
  3. 它自己去请旨里翻,找到要用的那把钥匙。
    不用你再告诉它钥匙放在哪。

  4. +
  5. 它不能直接拿钥匙,得先向你申请:
    用“网站服务器”运行 ./deploy.sh。

  6. +
  7. 请旨弹个窗,问你批不批。
    谁要、要什么、准备做什么,写得清清楚楚。

  8. +
  9. +

    你点了允许。
    钥匙由请旨直接交给 ./deploy.sh,AI 碰不到。

    +

    你允许了 30 分钟。
    钥匙直接交给 ./deploy.sh。这 30 分钟里再用这把钥匙,就不再问你了。

    +

    你点了拒绝。
    ./deploy.sh 没有运行,钥匙一动没动。

    +

    你一直没理它。
    5 分钟后,这次申请自动作废。

    +
  10. +
  11. +

    AI 只收到一句:“已发布”。
    网站上线了,AI 却从没碰过钥匙。
    每次使用都记在访问记录里。

    +

    AI 只收到一句:“被拒绝”。
    想用钥匙,得先过你这一关。

    +

    AI 只收到一句:“申请已作废”。
    想用钥匙,得先过你这一关。

    +
  12. +
+ + +
+ +
+
+
+ 二权限 +

每把钥匙,规矩你来定。

+

常用的钥匙直接放行,要紧的每次先问你,不想让 AI 碰的,干脆藏起来。

+

需要问你时,请旨会弹窗写明谁要、要什么、准备做什么。可以只允许这一次,也可以允许 30 分钟,这段时间里同一台 Mac 上的所有 AI 都不用再问。

+
+
+

允许

AI 直接用,不用问你,每次使用都有记录。

准
+

每次询问默认

每用一次,都要你点头。

问
+

隐藏

AI 看不到这把钥匙,自然也不会来要。

隐
+ +
+
+
+ +
+
+ 三接入 +

主流 AI 编程工具,都能接上请旨。

+

常用的四款一键自动接入;其他支持 MCP 的工具,粘贴一段配置就能用。

+
+ +
请旨
+
    +
  • Claude Code
  • +
  • Codex
  • +
  • Cursor
  • +
  • Grok Build
  • +
+
    +
  • Claude Desktop
  • +
  • VS Code
  • +
  • Kiro
  • +
  • Trae
  • +
  • Windsurf
  • +
  • Qwen Code
  • +
  • Zed
  • +
  • Cline
  • +
+
+
    +
  • 一键接入在请旨里点一下,自动写好配置
  • +
  • 手动接入粘贴一段配置即可
  • +
+
"askkey": {
+  "command": "/Applications/Ask Key.app/Contents/Helpers/askkey",
+  "args": ["mcp"]
+}
+
+
+ +
+
+
+ 四边界 +

它不承诺的事。

+

请旨管的是钥匙交给谁、什么时候交。下面这几件事,它管不到,用之前心里有数。

+ 完整的安全说明(英文) +
+
    +
  1. 01
    程序能转发出去

    你批准的程序,可以把收到的钥匙打印、复制或转发出去。你批的是这个程序,不只是开口的 AI。

  2. +
  3. 02
    名字是自报的

    弹窗里的请求方和用途由 AI 自己填写,帮你看懂请求,但不是验证过的身份。

  4. +
  5. 03
    同账户的其他程序

    钥匙交给程序后,同一个 Mac 账户里的其他程序也可能读到。“隐藏”管不到这条路。

  6. +
  7. 04
    限时允许不分 AI

    “允许 30 分钟”对这台 Mac 上的所有 AI 都生效,不区分是哪一个。

  8. +
  9. 05
    暂时没有备份

    目前没有备份和恢复。重要的钥匙,请在别处另存一份原件。

  10. +
+
+
+ +
+
+
+
+ +
+ 请旨的应用图标:一张橙色门禁卡,上面是一把白色钥匙 + + +
+ +
+
+
+

请旨Ask Key

+

给 AI 用的 Mac 密钥管家。

+ 下载 macOS 版 +

免费 · 需 Apple 芯片及 macOS 14 或更高版本
下载后把应用拖进“应用程序”,不要改名。

+
    +
  • 免费开源MIT 许可,代码全在 GitHub 上。觉得好用,欢迎点个 Star。
  • +
  • 经过 Apple 公证安装包经过 Apple 的安全检查。
  • +
  • 在本机加密保存密钥加密后存在你自己的 Mac 上。
  • +
+ +
+
+
+
+ + + +