From e6e2795cfdcb69fd1289f2378100f451029f341b Mon Sep 17 00:00:00 2001 From: bowen Date: Sun, 26 Jul 2026 13:12:48 +0000 Subject: [PATCH 1/6] fix(site): vendor the missing three.core.min.js and follow JS imports in check_site MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit three.js r185 is not self-contained: three.module.min.js's first statement imports ./three.core.min.js, which was never vendored. The 404 failed the module graph before scene.js ran a line, so the page reserved a large empty rectangle under "The stack, twelve blocks deep" and scene.js's own no-WebGL fallback — which lives inside the module that failed to load — could never run either. Nothing caught it: check_site.py scanned src/href attributes, the importmap, and import() calls in demo.js, but never followed imports *inside* a vendored JS file. It now resolves every static and dynamic specifier in every shipped .js against that file's own directory (bare names through the importmap), so this class of break fails the build instead of production. The specifier charset is deliberately narrow — minified three.js contains English strings like "...resized from ("+w+")" that a permissive pattern reads as imports. Co-Authored-By: Claude Opus 5 Signed-off-by: bowen --- docs/vendor/three.core.min.js | 6 ++++ scripts/check_site.py | 60 +++++++++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 docs/vendor/three.core.min.js diff --git a/docs/vendor/three.core.min.js b/docs/vendor/three.core.min.js new file mode 100644 index 0000000..bf26ba3 --- /dev/null +++ b/docs/vendor/three.core.min.js @@ -0,0 +1,6 @@ +/** + * @license + * Copyright 2010-2026 Three.js Authors + * SPDX-License-Identifier: MIT + */ +const t="185",e={LEFT:0,MIDDLE:1,RIGHT:2,ROTATE:0,DOLLY:1,PAN:2},s={ROTATE:0,PAN:1,DOLLY_PAN:2,DOLLY_ROTATE:3},i=0,r=1,n=2,a=3,o=0,h=1,l=2,c=3,u=0,d=1,p=2,m=0,y=1,g=2,f=3,x=4,b=5,v=6,w=100,M=101,S=102,_=103,A=104,T=200,z=201,C=202,I=203,B=204,k=205,O=206,P=207,R=208,E=209,N=210,V=211,L=212,F=213,D=214,U=0,j=1,W=2,J=3,q=4,H=5,X=6,Y=7,Z=0,G=1,$=2,Q=0,K=1,tt=2,et=3,st=4,it=5,rt=6,nt=7,at="attached",ot="detached",ht=300,lt=301,ct=302,ut=303,dt=304,pt=306,mt=1e3,yt=1001,gt=1002,ft=1003,xt=1004,bt=1004,vt=1005,wt=1005,Mt=1006,St=1007,_t=1007,At=1008,Tt=1008,zt=1009,Ct=1010,It=1011,Bt=1012,kt=1013,Ot=1014,Pt=1015,Rt=1016,Et=1017,Nt=1018,Vt=1020,Lt=35902,Ft=35899,Dt=1021,Ut=1022,jt=1023,Wt=1026,Jt=1027,qt=1028,Ht=1029,Xt=1030,Yt=1031,Zt=1032,Gt=1033,$t=33776,Qt=33777,Kt=33778,te=33779,ee=35840,se=35841,ie=35842,re=35843,ne=36196,ae=37492,oe=37496,he=37488,le=37489,ce=37490,ue=37491,de=37808,pe=37809,me=37810,ye=37811,ge=37812,fe=37813,xe=37814,be=37815,ve=37816,we=37817,Me=37818,Se=37819,_e=37820,Ae=37821,Te=36492,ze=36494,Ce=36495,Ie=36283,Be=36284,ke=36285,Oe=36286,Pe=2200,Re=2201,Ee=2202,Ne=2300,Ve=2301,Le=2302,Fe=2303,De=2400,Ue=2401,je=2402,We=2500,Je=2501,qe=0,He=1,Xe=2,Ye=3200,Ze=3201,Ge=3202,$e=3203,Qe=0,Ke=1,ts="",es="srgb",ss="srgb-linear",is="linear",rs="srgb",ns="",as="rg",os="ga",hs=0,ls=7680,cs=7681,us=7682,ds=7683,ps=34055,ms=34056,ys=5386,gs=512,fs=513,xs=514,bs=515,vs=516,ws=517,Ms=518,Ss=519,_s=512,As=513,Ts=514,zs=515,Cs=516,Is=517,Bs=518,ks=519,Os=35044,Ps=35048,Rs=35040,Es=35045,Ns=35049,Vs=35041,Ls=35046,Fs=35050,Ds=35042,Us="100",js="300 es",Ws=2e3,Js=2001,qs={COMPUTE:"compute",RENDER:"render"},Hs={PERSPECTIVE:"perspective",LINEAR:"linear",FLAT:"flat"},Xs={NORMAL:"normal",CENTROID:"centroid",SAMPLE:"sample",FIRST:"first",EITHER:"either"},Ys={TEXTURE_COMPARE:"depthTextureCompare"};const Zs={Int8Array:Int8Array,Uint8Array:Uint8Array,Uint8ClampedArray:Uint8ClampedArray,Int16Array:Int16Array,Uint16Array:Uint16Array,Int32Array:Int32Array,Uint32Array:Uint32Array,Float32Array:Float32Array,Float64Array:Float64Array};function Gs(t,e){return new Zs[t](e)}function $s(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)}function Qs(t){return document.createElementNS("http://www.w3.org/1999/xhtml",t)}function Ks(){const t=Qs("canvas");return t.style.display="block",t}const ti={};let ei=null;function si(t){ei=t}function ii(){return ei}function ri(...t){const e="THREE."+t.shift();ei?ei("log",e,...t):console.log(e,...t)}function ni(t){const e=t[0];if("string"==typeof e&&e.startsWith("TSL:")){const e=t[1];e&&e.isStackTrace?t[0]+=" "+e.getLocation():t[1]='Stack trace not available. Enable "THREE.Node.captureStackTrace" to capture stack traces.'}return t}function ai(...t){const e="THREE."+(t=ni(t)).shift();if(ei)ei("warn",e,...t);else{const s=t[0];s&&s.isStackTrace?console.warn(s.getError(e)):console.warn(e,...t)}}function oi(...t){const e="THREE."+(t=ni(t)).shift();if(ei)ei("error",e,...t);else{const s=t[0];s&&s.isStackTrace?console.error(s.getError(e)):console.error(e,...t)}}function hi(...t){const e=t.join(" ");e in ti||(ti[e]=!0,ai(...t))}function li(){return"undefined"!=typeof self&&void 0!==self.scheduler&&void 0!==self.scheduler.yield?self.scheduler.yield():new Promise(t=>{requestAnimationFrame(t)})}function ci(t,e,s){return new Promise(function(i,r){setTimeout(function n(){switch(t.clientWaitSync(e,t.SYNC_FLUSH_COMMANDS_BIT,0)){case t.WAIT_FAILED:r();break;case t.TIMEOUT_EXPIRED:setTimeout(n,s);break;default:i()}},s)})}const ui={[U]:1,[W]:6,[q]:7,[J]:5,[j]:0,[X]:2,[Y]:4,[H]:3};class di{addEventListener(t,e){void 0===this._listeners&&(this._listeners={});const s=this._listeners;void 0===s[t]&&(s[t]=[]),-1===s[t].indexOf(e)&&s[t].push(e)}hasEventListener(t,e){const s=this._listeners;return void 0!==s&&(void 0!==s[t]&&-1!==s[t].indexOf(e))}removeEventListener(t,e){const s=this._listeners;if(void 0===s)return;const i=s[t];if(void 0!==i){const t=i.indexOf(e);-1!==t&&i.splice(t,1)}}dispatchEvent(t){const e=this._listeners;if(void 0===e)return;const s=e[t.type];if(void 0!==s){t.target=this;const e=s.slice(0);for(let s=0,i=e.length;s>8&255]+pi[t>>16&255]+pi[t>>24&255]+"-"+pi[255&e]+pi[e>>8&255]+"-"+pi[e>>16&15|64]+pi[e>>24&255]+"-"+pi[63&s|128]+pi[s>>8&255]+"-"+pi[s>>16&255]+pi[s>>24&255]+pi[255&i]+pi[i>>8&255]+pi[i>>16&255]+pi[i>>24&255]).toLowerCase()}function xi(t,e,s){return Math.max(e,Math.min(s,t))}function bi(t,e){return(t%e+e)%e}function vi(t,e,s){return(1-s)*t+s*e}function wi(t,e){switch(e.constructor){case Float32Array:return t;case Uint32Array:return t/4294967295;case Uint16Array:return t/65535;case Uint8Array:return t/255;case Int32Array:return Math.max(t/2147483647,-1);case Int16Array:return Math.max(t/32767,-1);case Int8Array:return Math.max(t/127,-1);default:throw new Error("THREE.MathUtils: Invalid component type.")}}function Mi(t,e){switch(e.constructor){case Float32Array:return t;case Uint32Array:return Math.round(4294967295*t);case Uint16Array:return Math.round(65535*t);case Uint8Array:return Math.round(255*t);case Int32Array:return Math.round(2147483647*t);case Int16Array:return Math.round(32767*t);case Int8Array:return Math.round(127*t);default:throw new Error("THREE.MathUtils: Invalid component type.")}}const Si={DEG2RAD:yi,RAD2DEG:gi,generateUUID:fi,clamp:xi,euclideanModulo:bi,mapLinear:function(t,e,s,i,r){return i+(t-e)*(r-i)/(s-e)},inverseLerp:function(t,e,s){return t!==e?(s-t)/(e-t):0},lerp:vi,damp:function(t,e,s,i){return vi(t,e,1-Math.exp(-s*i))},pingpong:function(t,e=1){return e-Math.abs(bi(t,2*e)-e)},smoothstep:function(t,e,s){return t<=e?0:t>=s?1:(t=(t-e)/(s-e))*t*(3-2*t)},smootherstep:function(t,e,s){return t<=e?0:t>=s?1:(t=(t-e)/(s-e))*t*t*(t*(6*t-15)+10)},randInt:function(t,e){return t+Math.floor(Math.random()*(e-t+1))},randFloat:function(t,e){return t+Math.random()*(e-t)},randFloatSpread:function(t){return t*(.5-Math.random())},seededRandom:function(t){void 0!==t&&(mi=t);let e=mi+=1831565813;return e=Math.imul(e^e>>>15,1|e),e^=e+Math.imul(e^e>>>7,61|e),((e^e>>>14)>>>0)/4294967296},degToRad:function(t){return t*yi},radToDeg:function(t){return t*gi},isPowerOfTwo:function(t){return!(t&t-1)&&0!==t},ceilPowerOfTwo:function(t){return Math.pow(2,Math.ceil(Math.log(t)/Math.LN2))},floorPowerOfTwo:function(t){return Math.pow(2,Math.floor(Math.log(t)/Math.LN2))},setQuaternionFromProperEuler:function(t,e,s,i,r){const n=Math.cos,a=Math.sin,o=n(s/2),h=a(s/2),l=n((e+i)/2),c=a((e+i)/2),u=n((e-i)/2),d=a((e-i)/2),p=n((i-e)/2),m=a((i-e)/2);switch(r){case"XYX":t.set(o*c,h*u,h*d,o*l);break;case"YZY":t.set(h*d,o*c,h*u,o*l);break;case"ZXZ":t.set(h*u,h*d,o*c,o*l);break;case"XZX":t.set(o*c,h*m,h*p,o*l);break;case"YXY":t.set(h*p,o*c,h*m,o*l);break;case"ZYZ":t.set(h*m,h*p,o*c,o*l);break;default:ai("MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: "+r)}},normalize:Mi,denormalize:wi};class _i{static{_i.prototype.isVector2=!0}constructor(t=0,e=0){this.x=t,this.y=e}get width(){return this.x}set width(t){this.x=t}get height(){return this.y}set height(t){this.y=t}set(t,e){return this.x=t,this.y=e,this}setScalar(t){return this.x=t,this.y=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;default:throw new Error("THREE.Vector2: index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;default:throw new Error("THREE.Vector2: index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y)}copy(t){return this.x=t.x,this.y=t.y,this}add(t){return this.x+=t.x,this.y+=t.y,this}addScalar(t){return this.x+=t,this.y+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this}subScalar(t){return this.x-=t,this.y-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this}multiply(t){return this.x*=t.x,this.y*=t.y,this}multiplyScalar(t){return this.x*=t,this.y*=t,this}divide(t){return this.x/=t.x,this.y/=t.y,this}divideScalar(t){return this.multiplyScalar(1/t)}applyMatrix3(t){const e=this.x,s=this.y,i=t.elements;return this.x=i[0]*e+i[3]*s+i[6],this.y=i[1]*e+i[4]*s+i[7],this}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this}clamp(t,e){return this.x=xi(this.x,t.x,e.x),this.y=xi(this.y,t.y,e.y),this}clampScalar(t,e){return this.x=xi(this.x,t,e),this.y=xi(this.y,t,e),this}clampLength(t,e){const s=this.length();return this.divideScalar(s||1).multiplyScalar(xi(s,t,e))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this}negate(){return this.x=-this.x,this.y=-this.y,this}dot(t){return this.x*t.x+this.y*t.y}cross(t){return this.x*t.y-this.y*t.x}lengthSq(){return this.x*this.x+this.y*this.y}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)}normalize(){return this.divideScalar(this.length()||1)}angle(){return Math.atan2(-this.y,-this.x)+Math.PI}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(0===e)return Math.PI/2;const s=this.dot(t)/e;return Math.acos(xi(s,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,s=this.y-t.y;return e*e+s*s}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this}lerpVectors(t,e,s){return this.x=t.x+(e.x-t.x)*s,this.y=t.y+(e.y-t.y)*s,this}equals(t){return t.x===this.x&&t.y===this.y}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this}rotateAround(t,e){const s=Math.cos(e),i=Math.sin(e),r=this.x-t.x,n=this.y-t.y;return this.x=r*s-n*i+t.x,this.y=r*i+n*s+t.y,this}random(){return this.x=Math.random(),this.y=Math.random(),this}*[Symbol.iterator](){yield this.x,yield this.y}}class Ai{constructor(t=0,e=0,s=0,i=1){this.isQuaternion=!0,this._x=t,this._y=e,this._z=s,this._w=i}static slerpFlat(t,e,s,i,r,n,a){let o=s[i+0],h=s[i+1],l=s[i+2],c=s[i+3],u=r[n+0],d=r[n+1],p=r[n+2],m=r[n+3];if(c!==m||o!==u||h!==d||l!==p){let t=o*u+h*d+l*p+c*m;t<0&&(u=-u,d=-d,p=-p,m=-m,t=-t);let e=1-a;if(t<.9995){const s=Math.acos(t),i=Math.sin(s);e=Math.sin(e*s)/i,o=o*e+u*(a=Math.sin(a*s)/i),h=h*e+d*a,l=l*e+p*a,c=c*e+m*a}else{o=o*e+u*a,h=h*e+d*a,l=l*e+p*a,c=c*e+m*a;const t=1/Math.sqrt(o*o+h*h+l*l+c*c);o*=t,h*=t,l*=t,c*=t}}t[e]=o,t[e+1]=h,t[e+2]=l,t[e+3]=c}static multiplyQuaternionsFlat(t,e,s,i,r,n){const a=s[i],o=s[i+1],h=s[i+2],l=s[i+3],c=r[n],u=r[n+1],d=r[n+2],p=r[n+3];return t[e]=a*p+l*c+o*d-h*u,t[e+1]=o*p+l*u+h*c-a*d,t[e+2]=h*p+l*d+a*u-o*c,t[e+3]=l*p-a*c-o*u-h*d,t}get x(){return this._x}set x(t){this._x=t,this._onChangeCallback()}get y(){return this._y}set y(t){this._y=t,this._onChangeCallback()}get z(){return this._z}set z(t){this._z=t,this._onChangeCallback()}get w(){return this._w}set w(t){this._w=t,this._onChangeCallback()}set(t,e,s,i){return this._x=t,this._y=e,this._z=s,this._w=i,this._onChangeCallback(),this}clone(){return new this.constructor(this._x,this._y,this._z,this._w)}copy(t){return this._x=t.x,this._y=t.y,this._z=t.z,this._w=t.w,this._onChangeCallback(),this}setFromEuler(t,e=!0){const s=t._x,i=t._y,r=t._z,n=t._order,a=Math.cos,o=Math.sin,h=a(s/2),l=a(i/2),c=a(r/2),u=o(s/2),d=o(i/2),p=o(r/2);switch(n){case"XYZ":this._x=u*l*c+h*d*p,this._y=h*d*c-u*l*p,this._z=h*l*p+u*d*c,this._w=h*l*c-u*d*p;break;case"YXZ":this._x=u*l*c+h*d*p,this._y=h*d*c-u*l*p,this._z=h*l*p-u*d*c,this._w=h*l*c+u*d*p;break;case"ZXY":this._x=u*l*c-h*d*p,this._y=h*d*c+u*l*p,this._z=h*l*p+u*d*c,this._w=h*l*c-u*d*p;break;case"ZYX":this._x=u*l*c-h*d*p,this._y=h*d*c+u*l*p,this._z=h*l*p-u*d*c,this._w=h*l*c+u*d*p;break;case"YZX":this._x=u*l*c+h*d*p,this._y=h*d*c+u*l*p,this._z=h*l*p-u*d*c,this._w=h*l*c-u*d*p;break;case"XZY":this._x=u*l*c-h*d*p,this._y=h*d*c-u*l*p,this._z=h*l*p+u*d*c,this._w=h*l*c+u*d*p;break;default:ai("Quaternion: .setFromEuler() encountered an unknown order: "+n)}return!0===e&&this._onChangeCallback(),this}setFromAxisAngle(t,e){const s=e/2,i=Math.sin(s);return this._x=t.x*i,this._y=t.y*i,this._z=t.z*i,this._w=Math.cos(s),this._onChangeCallback(),this}setFromRotationMatrix(t){const e=t.elements,s=e[0],i=e[4],r=e[8],n=e[1],a=e[5],o=e[9],h=e[2],l=e[6],c=e[10],u=s+a+c;if(u>0){const t=.5/Math.sqrt(u+1);this._w=.25/t,this._x=(l-o)*t,this._y=(r-h)*t,this._z=(n-i)*t}else if(s>a&&s>c){const t=2*Math.sqrt(1+s-a-c);this._w=(l-o)/t,this._x=.25*t,this._y=(i+n)/t,this._z=(r+h)/t}else if(a>c){const t=2*Math.sqrt(1+a-s-c);this._w=(r-h)/t,this._x=(i+n)/t,this._y=.25*t,this._z=(o+l)/t}else{const t=2*Math.sqrt(1+c-s-a);this._w=(n-i)/t,this._x=(r+h)/t,this._y=(o+l)/t,this._z=.25*t}return this._onChangeCallback(),this}setFromUnitVectors(t,e){let s=t.dot(e)+1;return s<1e-8?(s=0,Math.abs(t.x)>Math.abs(t.z)?(this._x=-t.y,this._y=t.x,this._z=0,this._w=s):(this._x=0,this._y=-t.z,this._z=t.y,this._w=s)):(this._x=t.y*e.z-t.z*e.y,this._y=t.z*e.x-t.x*e.z,this._z=t.x*e.y-t.y*e.x,this._w=s),this.normalize()}angleTo(t){return 2*Math.acos(Math.abs(xi(this.dot(t),-1,1)))}rotateTowards(t,e){const s=this.angleTo(t);if(0===s)return this;const i=Math.min(1,e/s);return this.slerp(t,i),this}identity(){return this.set(0,0,0,1)}invert(){return this.conjugate()}conjugate(){return this._x*=-1,this._y*=-1,this._z*=-1,this._onChangeCallback(),this}dot(t){return this._x*t._x+this._y*t._y+this._z*t._z+this._w*t._w}lengthSq(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w}length(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)}normalize(){let t=this.length();return 0===t?(this._x=0,this._y=0,this._z=0,this._w=1):(t=1/t,this._x=this._x*t,this._y=this._y*t,this._z=this._z*t,this._w=this._w*t),this._onChangeCallback(),this}multiply(t){return this.multiplyQuaternions(this,t)}premultiply(t){return this.multiplyQuaternions(t,this)}multiplyQuaternions(t,e){const s=t._x,i=t._y,r=t._z,n=t._w,a=e._x,o=e._y,h=e._z,l=e._w;return this._x=s*l+n*a+i*h-r*o,this._y=i*l+n*o+r*a-s*h,this._z=r*l+n*h+s*o-i*a,this._w=n*l-s*a-i*o-r*h,this._onChangeCallback(),this}slerp(t,e){let s=t._x,i=t._y,r=t._z,n=t._w,a=this.dot(t);a<0&&(s=-s,i=-i,r=-r,n=-n,a=-a);let o=1-e;if(a<.9995){const t=Math.acos(a),h=Math.sin(t);o=Math.sin(o*t)/h,e=Math.sin(e*t)/h,this._x=this._x*o+s*e,this._y=this._y*o+i*e,this._z=this._z*o+r*e,this._w=this._w*o+n*e,this._onChangeCallback()}else this._x=this._x*o+s*e,this._y=this._y*o+i*e,this._z=this._z*o+r*e,this._w=this._w*o+n*e,this.normalize();return this}slerpQuaternions(t,e,s){return this.copy(t).slerp(e,s)}random(){const t=2*Math.PI*Math.random(),e=2*Math.PI*Math.random(),s=Math.random(),i=Math.sqrt(1-s),r=Math.sqrt(s);return this.set(i*Math.sin(t),i*Math.cos(t),r*Math.sin(e),r*Math.cos(e))}equals(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._w===this._w}fromArray(t,e=0){return this._x=t[e],this._y=t[e+1],this._z=t[e+2],this._w=t[e+3],this._onChangeCallback(),this}toArray(t=[],e=0){return t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._w,t}fromBufferAttribute(t,e){return this._x=t.getX(e),this._y=t.getY(e),this._z=t.getZ(e),this._w=t.getW(e),this._onChangeCallback(),this}toJSON(){return this.toArray()}_onChange(t){return this._onChangeCallback=t,this}_onChangeCallback(){}*[Symbol.iterator](){yield this._x,yield this._y,yield this._z,yield this._w}}class Ti{static{Ti.prototype.isVector3=!0}constructor(t=0,e=0,s=0){this.x=t,this.y=e,this.z=s}set(t,e,s){return void 0===s&&(s=this.z),this.x=t,this.y=e,this.z=s,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;default:throw new Error("THREE.Vector3: index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("THREE.Vector3: index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this}multiplyVectors(t,e){return this.x=t.x*e.x,this.y=t.y*e.y,this.z=t.z*e.z,this}applyEuler(t){return this.applyQuaternion(Ci.setFromEuler(t))}applyAxisAngle(t,e){return this.applyQuaternion(Ci.setFromAxisAngle(t,e))}applyMatrix3(t){const e=this.x,s=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[3]*s+r[6]*i,this.y=r[1]*e+r[4]*s+r[7]*i,this.z=r[2]*e+r[5]*s+r[8]*i,this}applyNormalMatrix(t){return this.applyMatrix3(t).normalize()}applyMatrix4(t){const e=this.x,s=this.y,i=this.z,r=t.elements,n=1/(r[3]*e+r[7]*s+r[11]*i+r[15]);return this.x=(r[0]*e+r[4]*s+r[8]*i+r[12])*n,this.y=(r[1]*e+r[5]*s+r[9]*i+r[13])*n,this.z=(r[2]*e+r[6]*s+r[10]*i+r[14])*n,this}applyQuaternion(t){const e=this.x,s=this.y,i=this.z,r=t.x,n=t.y,a=t.z,o=t.w,h=2*(n*i-a*s),l=2*(a*e-r*i),c=2*(r*s-n*e);return this.x=e+o*h+n*c-a*l,this.y=s+o*l+a*h-r*c,this.z=i+o*c+r*l-n*h,this}project(t){return this.applyMatrix4(t.matrixWorldInverse).applyMatrix4(t.projectionMatrix)}unproject(t){return this.applyMatrix4(t.projectionMatrixInverse).applyMatrix4(t.matrixWorld)}transformDirection(t){const e=this.x,s=this.y,i=this.z,r=t.elements;return this.x=r[0]*e+r[4]*s+r[8]*i,this.y=r[1]*e+r[5]*s+r[9]*i,this.z=r[2]*e+r[6]*s+r[10]*i,this.normalize()}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this}divideScalar(t){return this.multiplyScalar(1/t)}min(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this.z=Math.min(this.z,t.z),this}max(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this.z=Math.max(this.z,t.z),this}clamp(t,e){return this.x=xi(this.x,t.x,e.x),this.y=xi(this.y,t.y,e.y),this.z=xi(this.z,t.z,e.z),this}clampScalar(t,e){return this.x=xi(this.x,t,e),this.y=xi(this.y,t,e),this.z=xi(this.z,t,e),this}clampLength(t,e){const s=this.length();return this.divideScalar(s||1).multiplyScalar(xi(s,t,e))}floor(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this}ceil(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this}round(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this}roundToZero(){return this.x=Math.trunc(this.x),this.y=Math.trunc(this.y),this.z=Math.trunc(this.z),this}negate(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this}dot(t){return this.x*t.x+this.y*t.y+this.z*t.z}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}manhattanLength(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)}normalize(){return this.divideScalar(this.length()||1)}setLength(t){return this.normalize().multiplyScalar(t)}lerp(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this.z+=(t.z-this.z)*e,this}lerpVectors(t,e,s){return this.x=t.x+(e.x-t.x)*s,this.y=t.y+(e.y-t.y)*s,this.z=t.z+(e.z-t.z)*s,this}cross(t){return this.crossVectors(this,t)}crossVectors(t,e){const s=t.x,i=t.y,r=t.z,n=e.x,a=e.y,o=e.z;return this.x=i*o-r*a,this.y=r*n-s*o,this.z=s*a-i*n,this}projectOnVector(t){const e=t.lengthSq();if(0===e)return this.set(0,0,0);const s=t.dot(this)/e;return this.copy(t).multiplyScalar(s)}projectOnPlane(t){return zi.copy(this).projectOnVector(t),this.sub(zi)}reflect(t){return this.sub(zi.copy(t).multiplyScalar(2*this.dot(t)))}angleTo(t){const e=Math.sqrt(this.lengthSq()*t.lengthSq());if(0===e)return Math.PI/2;const s=this.dot(t)/e;return Math.acos(xi(s,-1,1))}distanceTo(t){return Math.sqrt(this.distanceToSquared(t))}distanceToSquared(t){const e=this.x-t.x,s=this.y-t.y,i=this.z-t.z;return e*e+s*s+i*i}manhattanDistanceTo(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)+Math.abs(this.z-t.z)}setFromSpherical(t){return this.setFromSphericalCoords(t.radius,t.phi,t.theta)}setFromSphericalCoords(t,e,s){const i=Math.sin(e)*t;return this.x=i*Math.sin(s),this.y=Math.cos(e)*t,this.z=i*Math.cos(s),this}setFromCylindrical(t){return this.setFromCylindricalCoords(t.radius,t.theta,t.y)}setFromCylindricalCoords(t,e,s){return this.x=t*Math.sin(e),this.y=s,this.z=t*Math.cos(e),this}setFromMatrixPosition(t){const e=t.elements;return this.x=e[12],this.y=e[13],this.z=e[14],this}setFromMatrixScale(t){const e=this.setFromMatrixColumn(t,0).length(),s=this.setFromMatrixColumn(t,1).length(),i=this.setFromMatrixColumn(t,2).length();return this.x=e,this.y=s,this.z=i,this}setFromMatrixColumn(t,e){return this.fromArray(t.elements,4*e)}setFromMatrix3Column(t,e){return this.fromArray(t.elements,3*e)}setFromEuler(t){return this.x=t._x,this.y=t._y,this.z=t._z,this}setFromColor(t){return this.x=t.r,this.y=t.g,this.z=t.b,this}equals(t){return t.x===this.x&&t.y===this.y&&t.z===this.z}fromArray(t,e=0){return this.x=t[e],this.y=t[e+1],this.z=t[e+2],this}toArray(t=[],e=0){return t[e]=this.x,t[e+1]=this.y,t[e+2]=this.z,t}fromBufferAttribute(t,e){return this.x=t.getX(e),this.y=t.getY(e),this.z=t.getZ(e),this}random(){return this.x=Math.random(),this.y=Math.random(),this.z=Math.random(),this}randomDirection(){const t=Math.random()*Math.PI*2,e=2*Math.random()-1,s=Math.sqrt(1-e*e);return this.x=s*Math.cos(t),this.y=e,this.z=s*Math.sin(t),this}*[Symbol.iterator](){yield this.x,yield this.y,yield this.z}}const zi=new Ti,Ci=new Ai;class Ii{static{Ii.prototype.isMatrix3=!0}constructor(t,e,s,i,r,n,a,o,h){this.elements=[1,0,0,0,1,0,0,0,1],void 0!==t&&this.set(t,e,s,i,r,n,a,o,h)}set(t,e,s,i,r,n,a,o,h){const l=this.elements;return l[0]=t,l[1]=i,l[2]=a,l[3]=e,l[4]=r,l[5]=o,l[6]=s,l[7]=n,l[8]=h,this}identity(){return this.set(1,0,0,0,1,0,0,0,1),this}copy(t){const e=this.elements,s=t.elements;return e[0]=s[0],e[1]=s[1],e[2]=s[2],e[3]=s[3],e[4]=s[4],e[5]=s[5],e[6]=s[6],e[7]=s[7],e[8]=s[8],this}extractBasis(t,e,s){return t.setFromMatrix3Column(this,0),e.setFromMatrix3Column(this,1),s.setFromMatrix3Column(this,2),this}setFromMatrix4(t){const e=t.elements;return this.set(e[0],e[4],e[8],e[1],e[5],e[9],e[2],e[6],e[10]),this}multiply(t){return this.multiplyMatrices(this,t)}premultiply(t){return this.multiplyMatrices(t,this)}multiplyMatrices(t,e){const s=t.elements,i=e.elements,r=this.elements,n=s[0],a=s[3],o=s[6],h=s[1],l=s[4],c=s[7],u=s[2],d=s[5],p=s[8],m=i[0],y=i[3],g=i[6],f=i[1],x=i[4],b=i[7],v=i[2],w=i[5],M=i[8];return r[0]=n*m+a*f+o*v,r[3]=n*y+a*x+o*w,r[6]=n*g+a*b+o*M,r[1]=h*m+l*f+c*v,r[4]=h*y+l*x+c*w,r[7]=h*g+l*b+c*M,r[2]=u*m+d*f+p*v,r[5]=u*y+d*x+p*w,r[8]=u*g+d*b+p*M,this}multiplyScalar(t){const e=this.elements;return e[0]*=t,e[3]*=t,e[6]*=t,e[1]*=t,e[4]*=t,e[7]*=t,e[2]*=t,e[5]*=t,e[8]*=t,this}determinant(){const t=this.elements,e=t[0],s=t[1],i=t[2],r=t[3],n=t[4],a=t[5],o=t[6],h=t[7],l=t[8];return e*n*l-e*a*h-s*r*l+s*a*o+i*r*h-i*n*o}invert(){const t=this.elements,e=t[0],s=t[1],i=t[2],r=t[3],n=t[4],a=t[5],o=t[6],h=t[7],l=t[8],c=l*n-a*h,u=a*o-l*r,d=h*r-n*o,p=e*c+s*u+i*d;if(0===p)return this.set(0,0,0,0,0,0,0,0,0);const m=1/p;return t[0]=c*m,t[1]=(i*h-l*s)*m,t[2]=(a*s-i*n)*m,t[3]=u*m,t[4]=(l*e-i*o)*m,t[5]=(i*r-a*e)*m,t[6]=d*m,t[7]=(s*o-h*e)*m,t[8]=(n*e-s*r)*m,this}transpose(){let t;const e=this.elements;return t=e[1],e[1]=e[3],e[3]=t,t=e[2],e[2]=e[6],e[6]=t,t=e[5],e[5]=e[7],e[7]=t,this}getNormalMatrix(t){return this.setFromMatrix4(t).invert().transpose()}transposeIntoArray(t){const e=this.elements;return t[0]=e[0],t[1]=e[3],t[2]=e[6],t[3]=e[1],t[4]=e[4],t[5]=e[7],t[6]=e[2],t[7]=e[5],t[8]=e[8],this}setUvTransform(t,e,s,i,r,n,a){const o=Math.cos(r),h=Math.sin(r);return this.set(s*o,s*h,-s*(o*n+h*a)+n+t,-i*h,i*o,-i*(-h*n+o*a)+a+e,0,0,1),this}scale(t,e){return hi("Matrix3: .scale() is deprecated. Use .makeScale() instead."),this.premultiply(Bi.makeScale(t,e)),this}rotate(t){return hi("Matrix3: .rotate() is deprecated. Use .makeRotation() instead."),this.premultiply(Bi.makeRotation(-t)),this}translate(t,e){return hi("Matrix3: .translate() is deprecated. Use .makeTranslation() instead."),this.premultiply(Bi.makeTranslation(t,e)),this}makeTranslation(t,e){return t.isVector2?this.set(1,0,t.x,0,1,t.y,0,0,1):this.set(1,0,t,0,1,e,0,0,1),this}makeRotation(t){const e=Math.cos(t),s=Math.sin(t);return this.set(e,-s,0,s,e,0,0,0,1),this}makeScale(t,e){return this.set(t,0,0,0,e,0,0,0,1),this}equals(t){const e=this.elements,s=t.elements;for(let t=0;t<9;t++)if(e[t]!==s[t])return!1;return!0}fromArray(t,e=0){for(let s=0;s<9;s++)this.elements[s]=t[s+e];return this}toArray(t=[],e=0){const s=this.elements;return t[e]=s[0],t[e+1]=s[1],t[e+2]=s[2],t[e+3]=s[3],t[e+4]=s[4],t[e+5]=s[5],t[e+6]=s[6],t[e+7]=s[7],t[e+8]=s[8],t}clone(){return(new this.constructor).fromArray(this.elements)}}const Bi=new Ii,ki=(new Ii).set(.4123908,.3575843,.1804808,.212639,.7151687,.0721923,.0193308,.1191948,.9505322),Oi=(new Ii).set(3.2409699,-1.5373832,-.4986108,-.9692436,1.8759675,.0415551,.0556301,-.203977,1.0569715);function Pi(){const t={enabled:!0,workingColorSpace:ss,spaces:{},convert:function(t,e,s){return!1!==this.enabled&&e!==s&&e&&s?(this.spaces[e].transfer===rs&&(t.r=Ei(t.r),t.g=Ei(t.g),t.b=Ei(t.b)),this.spaces[e].primaries!==this.spaces[s].primaries&&(t.applyMatrix3(this.spaces[e].toXYZ),t.applyMatrix3(this.spaces[s].fromXYZ)),this.spaces[s].transfer===rs&&(t.r=Ni(t.r),t.g=Ni(t.g),t.b=Ni(t.b)),t):t},workingToColorSpace:function(t,e){return this.convert(t,this.workingColorSpace,e)},colorSpaceToWorking:function(t,e){return this.convert(t,e,this.workingColorSpace)},getPrimaries:function(t){return this.spaces[t].primaries},getTransfer:function(t){return""===t?is:this.spaces[t].transfer},getToneMappingMode:function(t){return this.spaces[t].outputColorSpaceConfig.toneMappingMode||"standard"},getLuminanceCoefficients:function(t,e=this.workingColorSpace){return t.fromArray(this.spaces[e].luminanceCoefficients)},define:function(t){Object.assign(this.spaces,t)},_getMatrix:function(t,e,s){return t.copy(this.spaces[e].toXYZ).multiply(this.spaces[s].fromXYZ)},_getDrawingBufferColorSpace:function(t){return this.spaces[t].outputColorSpaceConfig.drawingBufferColorSpace},_getUnpackColorSpace:function(t=this.workingColorSpace){return this.spaces[t].workingColorSpaceConfig.unpackColorSpace},fromWorkingColorSpace:function(e,s){return hi("ColorManagement: .fromWorkingColorSpace() has been renamed to .workingToColorSpace()."),t.workingToColorSpace(e,s)},toWorkingColorSpace:function(e,s){return hi("ColorManagement: .toWorkingColorSpace() has been renamed to .colorSpaceToWorking()."),t.colorSpaceToWorking(e,s)}},e=[.64,.33,.3,.6,.15,.06],s=[.2126,.7152,.0722],i=[.3127,.329];return t.define({[ss]:{primaries:e,whitePoint:i,transfer:is,toXYZ:ki,fromXYZ:Oi,luminanceCoefficients:s,workingColorSpaceConfig:{unpackColorSpace:es},outputColorSpaceConfig:{drawingBufferColorSpace:es}},[es]:{primaries:e,whitePoint:i,transfer:rs,toXYZ:ki,fromXYZ:Oi,luminanceCoefficients:s,outputColorSpaceConfig:{drawingBufferColorSpace:es}}}),t}const Ri=Pi();function Ei(t){return t<.04045?.0773993808*t:Math.pow(.9478672986*t+.0521327014,2.4)}function Ni(t){return t<.0031308?12.92*t:1.055*Math.pow(t,.41666)-.055}let Vi;class Li{static getDataURL(t,e="image/png"){if(/^data:/i.test(t.src))return t.src;if("undefined"==typeof HTMLCanvasElement)return t.src;let s;if(t instanceof HTMLCanvasElement)s=t;else{void 0===Vi&&(Vi=Qs("canvas")),Vi.width=t.width,Vi.height=t.height;const e=Vi.getContext("2d");t instanceof ImageData?e.putImageData(t,0,0):e.drawImage(t,0,0,t.width,t.height),s=Vi}return s.toDataURL(e)}static sRGBToLinear(t){if("undefined"!=typeof HTMLImageElement&&t instanceof HTMLImageElement||"undefined"!=typeof HTMLCanvasElement&&t instanceof HTMLCanvasElement||"undefined"!=typeof ImageBitmap&&t instanceof ImageBitmap){const e=Qs("canvas");e.width=t.width,e.height=t.height;const s=e.getContext("2d");s.drawImage(t,0,0,t.width,t.height);const i=s.getImageData(0,0,t.width,t.height),r=i.data;for(let t=0;t1),this.pmremVersion=0,this.normalized=!1}get width(){return this.source.getSize(Wi).x}get height(){return this.source.getSize(Wi).y}get depth(){return this.source.getSize(Wi).z}get image(){return this.source.data}set image(t){this.source.data=t}updateMatrix(){this.matrix.setUvTransform(this.offset.x,this.offset.y,this.repeat.x,this.repeat.y,this.rotation,this.center.x,this.center.y)}addUpdateRange(t,e){this.updateRanges.push({start:t,count:e})}clearUpdateRanges(){this.updateRanges.length=0}clone(){return(new this.constructor).copy(this)}copy(t){return this.name=t.name,this.source=t.source,this.mipmaps=t.mipmaps.slice(0),this.mapping=t.mapping,this.channel=t.channel,this.wrapS=t.wrapS,this.wrapT=t.wrapT,this.magFilter=t.magFilter,this.minFilter=t.minFilter,this.anisotropy=t.anisotropy,this.format=t.format,this.internalFormat=t.internalFormat,this.type=t.type,this.normalized=t.normalized,this.offset.copy(t.offset),this.repeat.copy(t.repeat),this.center.copy(t.center),this.rotation=t.rotation,this.matrixAutoUpdate=t.matrixAutoUpdate,this.matrix.copy(t.matrix),this.generateMipmaps=t.generateMipmaps,this.premultiplyAlpha=t.premultiplyAlpha,this.flipY=t.flipY,this.unpackAlignment=t.unpackAlignment,this.colorSpace=t.colorSpace,this.renderTarget=t.renderTarget,this.isRenderTargetTexture=t.isRenderTargetTexture,this.isArrayTexture=t.isArrayTexture,this.userData=JSON.parse(JSON.stringify(t.userData)),this.needsUpdate=!0,this}setValues(t){for(const e in t){const s=t[e];if(void 0===s){ai(`Texture.setValues(): parameter '${e}' has value of undefined.`);continue}const i=this[e];void 0!==i?i&&s&&i.isVector2&&s.isVector2||i&&s&&i.isVector3&&s.isVector3||i&&s&&i.isMatrix3&&s.isMatrix3?i.copy(s):this[e]=s:ai(`Texture.setValues(): property '${e}' does not exist.`)}}toJSON(t){const e=void 0===t||"string"==typeof t;if(!e&&void 0!==t.textures[this.uuid])return t.textures[this.uuid];const s={metadata:{version:4.7,type:"Texture",generator:"Texture.toJSON"},uuid:this.uuid,name:this.name,image:this.source.toJSON(t).uuid,mapping:this.mapping,channel:this.channel,repeat:[this.repeat.x,this.repeat.y],offset:[this.offset.x,this.offset.y],center:[this.center.x,this.center.y],rotation:this.rotation,wrap:[this.wrapS,this.wrapT],format:this.format,internalFormat:this.internalFormat,type:this.type,normalized:this.normalized,colorSpace:this.colorSpace,minFilter:this.minFilter,magFilter:this.magFilter,anisotropy:this.anisotropy,flipY:this.flipY,generateMipmaps:this.generateMipmaps,premultiplyAlpha:this.premultiplyAlpha,unpackAlignment:this.unpackAlignment};return Object.keys(this.userData).length>0&&(s.userData=this.userData),e||(t.textures[this.uuid]=s),s}dispose(){this.dispatchEvent({type:"dispose"})}transformUv(t){if(this.mapping!==ht)return t;if(t.applyMatrix3(this.matrix),t.x<0||t.x>1)switch(this.wrapS){case mt:t.x=t.x-Math.floor(t.x);break;case yt:t.x=t.x<0?0:1;break;case gt:1===Math.abs(Math.floor(t.x)%2)?t.x=Math.ceil(t.x)-t.x:t.x=t.x-Math.floor(t.x)}if(t.y<0||t.y>1)switch(this.wrapT){case mt:t.y=t.y-Math.floor(t.y);break;case yt:t.y=t.y<0?0:1;break;case gt:1===Math.abs(Math.floor(t.y)%2)?t.y=Math.ceil(t.y)-t.y:t.y=t.y-Math.floor(t.y)}return this.flipY&&(t.y=1-t.y),t}set needsUpdate(t){!0===t&&(this.version++,this.source.needsUpdate=!0)}set needsPMREMUpdate(t){!0===t&&this.pmremVersion++}}Ji.DEFAULT_IMAGE=null,Ji.DEFAULT_MAPPING=ht,Ji.DEFAULT_ANISOTROPY=1;class qi{static{qi.prototype.isVector4=!0}constructor(t=0,e=0,s=0,i=1){this.x=t,this.y=e,this.z=s,this.w=i}get width(){return this.z}set width(t){this.z=t}get height(){return this.w}set height(t){this.w=t}set(t,e,s,i){return this.x=t,this.y=e,this.z=s,this.w=i,this}setScalar(t){return this.x=t,this.y=t,this.z=t,this.w=t,this}setX(t){return this.x=t,this}setY(t){return this.y=t,this}setZ(t){return this.z=t,this}setW(t){return this.w=t,this}setComponent(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;case 3:this.w=e;break;default:throw new Error("THREE.Vector4: index is out of range: "+t)}return this}getComponent(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw new Error("THREE.Vector4: index is out of range: "+t)}}clone(){return new this.constructor(this.x,this.y,this.z,this.w)}copy(t){return this.x=t.x,this.y=t.y,this.z=t.z,this.w=void 0!==t.w?t.w:1,this}add(t){return this.x+=t.x,this.y+=t.y,this.z+=t.z,this.w+=t.w,this}addScalar(t){return this.x+=t,this.y+=t,this.z+=t,this.w+=t,this}addVectors(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this.w=t.w+e.w,this}addScaledVector(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this.w+=t.w*e,this}sub(t){return this.x-=t.x,this.y-=t.y,this.z-=t.z,this.w-=t.w,this}subScalar(t){return this.x-=t,this.y-=t,this.z-=t,this.w-=t,this}subVectors(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this.w=t.w-e.w,this}multiply(t){return this.x*=t.x,this.y*=t.y,this.z*=t.z,this.w*=t.w,this}multiplyScalar(t){return this.x*=t,this.y*=t,this.z*=t,this.w*=t,this}applyMatrix4(t){const e=this.x,s=this.y,i=this.z,r=this.w,n=t.elements;return this.x=n[0]*e+n[4]*s+n[8]*i+n[12]*r,this.y=n[1]*e+n[5]*s+n[9]*i+n[13]*r,this.z=n[2]*e+n[6]*s+n[10]*i+n[14]*r,this.w=n[3]*e+n[7]*s+n[11]*i+n[15]*r,this}divide(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this.w/=t.w,this}divideScalar(t){return this.multiplyScalar(1/t)}setAxisAngleFromQuaternion(t){this.w=2*Math.acos(t.w);const e=Math.sqrt(1-t.w*t.w);return e<1e-4?(this.x=1,this.y=0,this.z=0):(this.x=t.x/e,this.y=t.y/e,this.z=t.z/e),this}setAxisAngleFromRotationMatrix(t){let e,s,i,r;const n=.01,a=.1,o=t.elements,h=o[0],l=o[4],c=o[8],u=o[1],d=o[5],p=o[9],m=o[2],y=o[6],g=o[10];if(Math.abs(l-u)o&&t>f?tf?o1);this.dispose()}this.viewport.set(0,0,t,e),this.scissor.set(0,0,t,e)}clone(){return(new this.constructor).copy(this)}copy(t){this.width=t.width,this.height=t.height,this.depth=t.depth,this.scissor.copy(t.scissor),this.scissorTest=t.scissorTest,this.viewport.copy(t.viewport),this.textures.length=0;for(let e=0,s=t.textures.length;e>>0}enable(t){this.mask|=1<1){for(let t=0;t1){for(let t=0;t0&&(i.userData=this.userData),i.layers=this.layers.mask,i.matrix=this.matrix.toArray(),i.up=this.up.toArray(),null!==this.pivot&&(i.pivot=this.pivot.toArray()),!1===this.matrixAutoUpdate&&(i.matrixAutoUpdate=!1),void 0!==this.morphTargetDictionary&&(i.morphTargetDictionary=Object.assign({},this.morphTargetDictionary)),void 0!==this.morphTargetInfluences&&(i.morphTargetInfluences=this.morphTargetInfluences.slice()),this.isInstancedMesh&&(i.type="InstancedMesh",i.count=this.count,i.instanceMatrix=this.instanceMatrix.toJSON(),null!==this.instanceColor&&(i.instanceColor=this.instanceColor.toJSON())),this.isBatchedMesh&&(i.type="BatchedMesh",i.perObjectFrustumCulled=this.perObjectFrustumCulled,i.sortObjects=this.sortObjects,i.drawRanges=this._drawRanges,i.reservedRanges=this._reservedRanges,i.geometryInfo=this._geometryInfo.map(t=>({...t,boundingBox:t.boundingBox?t.boundingBox.toJSON():void 0,boundingSphere:t.boundingSphere?t.boundingSphere.toJSON():void 0})),i.instanceInfo=this._instanceInfo.map(t=>({...t})),i.availableInstanceIds=this._availableInstanceIds.slice(),i.availableGeometryIds=this._availableGeometryIds.slice(),i.nextIndexStart=this._nextIndexStart,i.nextVertexStart=this._nextVertexStart,i.geometryCount=this._geometryCount,i.maxInstanceCount=this._maxInstanceCount,i.maxVertexCount=this._maxVertexCount,i.maxIndexCount=this._maxIndexCount,i.geometryInitialized=this._geometryInitialized,i.matricesTexture=this._matricesTexture.toJSON(t),i.indirectTexture=this._indirectTexture.toJSON(t),null!==this._colorsTexture&&(i.colorsTexture=this._colorsTexture.toJSON(t)),null!==this.boundingSphere&&(i.boundingSphere=this.boundingSphere.toJSON()),null!==this.boundingBox&&(i.boundingBox=this.boundingBox.toJSON())),this.isScene)this.background&&(this.background.isColor?i.background=this.background.toJSON():this.background.isTexture&&(i.background=this.background.toJSON(t).uuid)),this.environment&&this.environment.isTexture&&!0!==this.environment.isRenderTargetTexture&&(i.environment=this.environment.toJSON(t).uuid);else if(this.isMesh||this.isLine||this.isPoints){i.geometry=r(t.geometries,this.geometry);const e=this.geometry.parameters;if(void 0!==e&&void 0!==e.shapes){const s=e.shapes;if(Array.isArray(s))for(let e=0,i=s.length;e0){i.children=[];for(let e=0;e0){i.animations=[];for(let e=0;e0&&(s.geometries=e),i.length>0&&(s.materials=i),r.length>0&&(s.textures=r),a.length>0&&(s.images=a),o.length>0&&(s.shapes=o),h.length>0&&(s.skeletons=h),l.length>0&&(s.animations=l),c.length>0&&(s.nodes=c)}return s.object=i,s;function n(t){const e=[];for(const s in t){const i=t[s];delete i.metadata,e.push(i)}return e}}clone(t){return(new this.constructor).copy(this,t)}copy(t,e=!0){if(this.name=t.name,this.up.copy(t.up),this.position.copy(t.position),this.rotation.order=t.rotation.order,this.quaternion.copy(t.quaternion),this.scale.copy(t.scale),this.pivot=null!==t.pivot?t.pivot.clone():null,this.matrix.copy(t.matrix),this.matrixWorld.copy(t.matrixWorld),this.matrixAutoUpdate=t.matrixAutoUpdate,this.matrixWorldAutoUpdate=t.matrixWorldAutoUpdate,this.matrixWorldNeedsUpdate=t.matrixWorldNeedsUpdate,this.layers.mask=t.layers.mask,this.visible=t.visible,this.castShadow=t.castShadow,this.receiveShadow=t.receiveShadow,this.frustumCulled=t.frustumCulled,this.renderOrder=t.renderOrder,this.static=t.static,this.animations=t.animations.slice(),this.userData=JSON.parse(JSON.stringify(t.userData)),!0===e)for(let e=0;eo+l?(h.inputState.pinching=!1,this.dispatchEvent({type:"pinchend",handedness:t.handedness,target:this})):!h.inputState.pinching&&a<=o-l&&(h.inputState.pinching=!0,this.dispatchEvent({type:"pinchstart",handedness:t.handedness,target:this}))}else null!==o&&t.gripSpace&&(r=e.getPose(t.gripSpace,s),null!==r&&(o.matrix.fromArray(r.transform.matrix),o.matrix.decompose(o.position,o.rotation,o.scale),o.matrixWorldNeedsUpdate=!0,r.linearVelocity?(o.hasLinearVelocity=!0,o.linearVelocity.copy(r.linearVelocity)):o.hasLinearVelocity=!1,r.angularVelocity?(o.hasAngularVelocity=!0,o.angularVelocity.copy(r.angularVelocity)):o.hasAngularVelocity=!1,o.eventsEnabled&&o.dispatchEvent({type:"gripUpdated",data:t,target:this})));null!==a&&(i=e.getPose(t.targetRaySpace,s),null===i&&null!==r&&(i=r),null!==i&&(a.matrix.fromArray(i.transform.matrix),a.matrix.decompose(a.position,a.rotation,a.scale),a.matrixWorldNeedsUpdate=!0,i.linearVelocity?(a.hasLinearVelocity=!0,a.linearVelocity.copy(i.linearVelocity)):a.hasLinearVelocity=!1,i.angularVelocity?(a.hasAngularVelocity=!0,a.angularVelocity.copy(i.angularVelocity)):a.hasAngularVelocity=!1,this.dispatchEvent(zr)))}return null!==a&&(a.visible=null!==i),null!==o&&(o.visible=null!==r),null!==h&&(h.visible=null!==n),this}_getHandJoint(t,e){if(void 0===t.joints[e.jointName]){const s=new Tr;s.matrixAutoUpdate=!1,s.visible=!1,t.joints[e.jointName]=s,t.add(s)}return t.joints[e.jointName]}}const Ir={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},Br={h:0,s:0,l:0},kr={h:0,s:0,l:0};function Or(t,e,s){return s<0&&(s+=1),s>1&&(s-=1),s<1/6?t+6*(e-t)*s:s<.5?e:s<2/3?t+6*(e-t)*(2/3-s):t}class Pr{constructor(t,e,s){return this.isColor=!0,this.r=1,this.g=1,this.b=1,this.set(t,e,s)}set(t,e,s){if(void 0===e&&void 0===s){const e=t;e&&e.isColor?this.copy(e):"number"==typeof e?this.setHex(e):"string"==typeof e&&this.setStyle(e)}else this.setRGB(t,e,s);return this}setScalar(t){return this.r=t,this.g=t,this.b=t,this}setHex(t,e=es){return t=Math.floor(t),this.r=(t>>16&255)/255,this.g=(t>>8&255)/255,this.b=(255&t)/255,Ri.colorSpaceToWorking(this,e),this}setRGB(t,e,s,i=Ri.workingColorSpace){return this.r=t,this.g=e,this.b=s,Ri.colorSpaceToWorking(this,i),this}setHSL(t,e,s,i=Ri.workingColorSpace){if(t=bi(t,1),e=xi(e,0,1),s=xi(s,0,1),0===e)this.r=this.g=this.b=s;else{const i=s<=.5?s*(1+e):s+e-s*e,r=2*s-i;this.r=Or(r,i,t+1/3),this.g=Or(r,i,t),this.b=Or(r,i,t-1/3)}return Ri.colorSpaceToWorking(this,i),this}setStyle(t,e=es){function s(e){void 0!==e&&parseFloat(e)<1&&ai("Color: Alpha component of "+t+" will be ignored.")}let i;if(i=/^(\w+)\(([^\)]*)\)/.exec(t)){let r;const n=i[1],a=i[2];switch(n){case"rgb":case"rgba":if(r=/^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return s(r[4]),this.setRGB(Math.min(255,parseInt(r[1],10))/255,Math.min(255,parseInt(r[2],10))/255,Math.min(255,parseInt(r[3],10))/255,e);if(r=/^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return s(r[4]),this.setRGB(Math.min(100,parseInt(r[1],10))/100,Math.min(100,parseInt(r[2],10))/100,Math.min(100,parseInt(r[3],10))/100,e);break;case"hsl":case"hsla":if(r=/^\s*(\d*\.?\d+)\s*,\s*(\d*\.?\d+)\%\s*,\s*(\d*\.?\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(a))return s(r[4]),this.setHSL(parseFloat(r[1])/360,parseFloat(r[2])/100,parseFloat(r[3])/100,e);break;default:ai("Color: Unknown color model "+t)}}else if(i=/^\#([A-Fa-f\d]+)$/.exec(t)){const s=i[1],r=s.length;if(3===r)return this.setRGB(parseInt(s.charAt(0),16)/15,parseInt(s.charAt(1),16)/15,parseInt(s.charAt(2),16)/15,e);if(6===r)return this.setHex(parseInt(s,16),e);ai("Color: Invalid hex color "+t)}else if(t&&t.length>0)return this.setColorName(t,e);return this}setColorName(t,e=es){const s=Ir[t.toLowerCase()];return void 0!==s?this.setHex(s,e):ai("Color: Unknown color "+t),this}clone(){return new this.constructor(this.r,this.g,this.b)}copy(t){return this.r=t.r,this.g=t.g,this.b=t.b,this}copySRGBToLinear(t){return this.r=Ei(t.r),this.g=Ei(t.g),this.b=Ei(t.b),this}copyLinearToSRGB(t){return this.r=Ni(t.r),this.g=Ni(t.g),this.b=Ni(t.b),this}convertSRGBToLinear(){return this.copySRGBToLinear(this),this}convertLinearToSRGB(){return this.copyLinearToSRGB(this),this}getHex(t=es){return Ri.workingToColorSpace(Rr.copy(this),t),65536*Math.round(xi(255*Rr.r,0,255))+256*Math.round(xi(255*Rr.g,0,255))+Math.round(xi(255*Rr.b,0,255))}getHexString(t=es){return("000000"+this.getHex(t).toString(16)).slice(-6)}getHSL(t,e=Ri.workingColorSpace){Ri.workingToColorSpace(Rr.copy(this),e);const s=Rr.r,i=Rr.g,r=Rr.b,n=Math.max(s,i,r),a=Math.min(s,i,r);let o,h;const l=(a+n)/2;if(a===n)o=0,h=0;else{const t=n-a;switch(h=l<=.5?t/(n+a):t/(2-n-a),n){case s:o=(i-r)/t+(i0&&(e.object.backgroundBlurriness=this.backgroundBlurriness),1!==this.backgroundIntensity&&(e.object.backgroundIntensity=this.backgroundIntensity),e.object.backgroundRotation=this.backgroundRotation.toArray(),1!==this.environmentIntensity&&(e.object.environmentIntensity=this.environmentIntensity),e.object.environmentRotation=this.environmentRotation.toArray(),e}}const Lr=new Ti,Fr=new Ti,Dr=new Ti,Ur=new Ti,jr=new Ti,Wr=new Ti,Jr=new Ti,qr=new Ti,Hr=new Ti,Xr=new Ti,Yr=new qi,Zr=new qi,Gr=new qi;class $r{constructor(t=new Ti,e=new Ti,s=new Ti){this.a=t,this.b=e,this.c=s}static getNormal(t,e,s,i){i.subVectors(s,e),Lr.subVectors(t,e),i.cross(Lr);const r=i.lengthSq();return r>0?i.multiplyScalar(1/Math.sqrt(r)):i.set(0,0,0)}static getBarycoord(t,e,s,i,r){Lr.subVectors(i,e),Fr.subVectors(s,e),Dr.subVectors(t,e);const n=Lr.dot(Lr),a=Lr.dot(Fr),o=Lr.dot(Dr),h=Fr.dot(Fr),l=Fr.dot(Dr),c=n*h-a*a;if(0===c)return r.set(0,0,0),null;const u=1/c,d=(h*o-a*l)*u,p=(n*l-a*o)*u;return r.set(1-d-p,p,d)}static containsPoint(t,e,s,i){return null!==this.getBarycoord(t,e,s,i,Ur)&&(Ur.x>=0&&Ur.y>=0&&Ur.x+Ur.y<=1)}static getInterpolation(t,e,s,i,r,n,a,o){return null===this.getBarycoord(t,e,s,i,Ur)?(o.x=0,o.y=0,"z"in o&&(o.z=0),"w"in o&&(o.w=0),null):(o.setScalar(0),o.addScaledVector(r,Ur.x),o.addScaledVector(n,Ur.y),o.addScaledVector(a,Ur.z),o)}static getInterpolatedAttribute(t,e,s,i,r,n){return Yr.setScalar(0),Zr.setScalar(0),Gr.setScalar(0),Yr.fromBufferAttribute(t,e),Zr.fromBufferAttribute(t,s),Gr.fromBufferAttribute(t,i),n.setScalar(0),n.addScaledVector(Yr,r.x),n.addScaledVector(Zr,r.y),n.addScaledVector(Gr,r.z),n}static isFrontFacing(t,e,s,i){return Lr.subVectors(s,e),Fr.subVectors(t,e),Lr.cross(Fr).dot(i)<0}set(t,e,s){return this.a.copy(t),this.b.copy(e),this.c.copy(s),this}setFromPointsAndIndices(t,e,s,i){return this.a.copy(t[e]),this.b.copy(t[s]),this.c.copy(t[i]),this}setFromAttributeAndIndices(t,e,s,i){return this.a.fromBufferAttribute(t,e),this.b.fromBufferAttribute(t,s),this.c.fromBufferAttribute(t,i),this}clone(){return(new this.constructor).copy(this)}copy(t){return this.a.copy(t.a),this.b.copy(t.b),this.c.copy(t.c),this}getArea(){return Lr.subVectors(this.c,this.b),Fr.subVectors(this.a,this.b),.5*Lr.cross(Fr).length()}getMidpoint(t){return t.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)}getNormal(t){return $r.getNormal(this.a,this.b,this.c,t)}getPlane(t){return t.setFromCoplanarPoints(this.a,this.b,this.c)}getBarycoord(t,e){return $r.getBarycoord(t,this.a,this.b,this.c,e)}getInterpolation(t,e,s,i,r){return $r.getInterpolation(t,this.a,this.b,this.c,e,s,i,r)}containsPoint(t){return $r.containsPoint(t,this.a,this.b,this.c)}isFrontFacing(t){return $r.isFrontFacing(this.a,this.b,this.c,t)}intersectsBox(t){return t.intersectsTriangle(this)}closestPointToPoint(t,e){const s=this.a,i=this.b,r=this.c;let n,a;jr.subVectors(i,s),Wr.subVectors(r,s),qr.subVectors(t,s);const o=jr.dot(qr),h=Wr.dot(qr);if(o<=0&&h<=0)return e.copy(s);Hr.subVectors(t,i);const l=jr.dot(Hr),c=Wr.dot(Hr);if(l>=0&&c<=l)return e.copy(i);const u=o*c-l*h;if(u<=0&&o>=0&&l<=0)return n=o/(o-l),e.copy(s).addScaledVector(jr,n);Xr.subVectors(t,r);const d=jr.dot(Xr),p=Wr.dot(Xr);if(p>=0&&d<=p)return e.copy(r);const m=d*h-o*p;if(m<=0&&h>=0&&p<=0)return a=h/(h-p),e.copy(s).addScaledVector(Wr,a);const y=l*p-d*c;if(y<=0&&c-l>=0&&d-p>=0)return Jr.subVectors(r,i),a=(c-l)/(c-l+(d-p)),e.copy(i).addScaledVector(Jr,a);const g=1/(y+m+u);return n=m*g,a=u*g,e.copy(s).addScaledVector(jr,n).addScaledVector(Wr,a)}equals(t){return t.a.equals(this.a)&&t.b.equals(this.b)&&t.c.equals(this.c)}}class Qr{constructor(t=new Ti(1/0,1/0,1/0),e=new Ti(-1/0,-1/0,-1/0)){this.isBox3=!0,this.min=t,this.max=e}set(t,e){return this.min.copy(t),this.max.copy(e),this}setFromArray(t){this.makeEmpty();for(let e=0,s=t.length;e=this.min.x&&t.x<=this.max.x&&t.y>=this.min.y&&t.y<=this.max.y&&t.z>=this.min.z&&t.z<=this.max.z}containsBox(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y&&this.min.z<=t.min.z&&t.max.z<=this.max.z}getParameter(t,e){return e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y),(t.z-this.min.z)/(this.max.z-this.min.z))}intersectsBox(t){return t.max.x>=this.min.x&&t.min.x<=this.max.x&&t.max.y>=this.min.y&&t.min.y<=this.max.y&&t.max.z>=this.min.z&&t.min.z<=this.max.z}intersectsSphere(t){return this.clampPoint(t.center,tn),tn.distanceToSquared(t.center)<=t.radius*t.radius}intersectsPlane(t){let e,s;return t.normal.x>0?(e=t.normal.x*this.min.x,s=t.normal.x*this.max.x):(e=t.normal.x*this.max.x,s=t.normal.x*this.min.x),t.normal.y>0?(e+=t.normal.y*this.min.y,s+=t.normal.y*this.max.y):(e+=t.normal.y*this.max.y,s+=t.normal.y*this.min.y),t.normal.z>0?(e+=t.normal.z*this.min.z,s+=t.normal.z*this.max.z):(e+=t.normal.z*this.max.z,s+=t.normal.z*this.min.z),e<=-t.constant&&s>=-t.constant}intersectsTriangle(t){if(this.isEmpty())return!1;this.getCenter(ln),cn.subVectors(this.max,ln),sn.subVectors(t.a,ln),rn.subVectors(t.b,ln),nn.subVectors(t.c,ln),an.subVectors(rn,sn),on.subVectors(nn,rn),hn.subVectors(sn,nn);let e=[0,-an.z,an.y,0,-on.z,on.y,0,-hn.z,hn.y,an.z,0,-an.x,on.z,0,-on.x,hn.z,0,-hn.x,-an.y,an.x,0,-on.y,on.x,0,-hn.y,hn.x,0];return!!pn(e,sn,rn,nn,cn)&&(e=[1,0,0,0,1,0,0,0,1],!!pn(e,sn,rn,nn,cn)&&(un.crossVectors(an,on),e=[un.x,un.y,un.z],pn(e,sn,rn,nn,cn)))}clampPoint(t,e){return e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return this.clampPoint(t,tn).distanceTo(t)}getBoundingSphere(t){return this.isEmpty()?t.makeEmpty():(this.getCenter(t.center),t.radius=.5*this.getSize(tn).length()),t}intersect(t){return this.min.max(t.min),this.max.min(t.max),this.isEmpty()&&this.makeEmpty(),this}union(t){return this.min.min(t.min),this.max.max(t.max),this}applyMatrix4(t){return this.isEmpty()||(Kr[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(t),Kr[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(t),Kr[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(t),Kr[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(t),Kr[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(t),Kr[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(t),Kr[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(t),Kr[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(t),this.setFromPoints(Kr)),this}translate(t){return this.min.add(t),this.max.add(t),this}equals(t){return t.min.equals(this.min)&&t.max.equals(this.max)}toJSON(){return{min:this.min.toArray(),max:this.max.toArray()}}fromJSON(t){return this.min.fromArray(t.min),this.max.fromArray(t.max),this}}const Kr=[new Ti,new Ti,new Ti,new Ti,new Ti,new Ti,new Ti,new Ti],tn=new Ti,en=new Qr,sn=new Ti,rn=new Ti,nn=new Ti,an=new Ti,on=new Ti,hn=new Ti,ln=new Ti,cn=new Ti,un=new Ti,dn=new Ti;function pn(t,e,s,i,r){for(let n=0,a=t.length-3;n<=a;n+=3){dn.fromArray(t,n);const a=r.x*Math.abs(dn.x)+r.y*Math.abs(dn.y)+r.z*Math.abs(dn.z),o=e.dot(dn),h=s.dot(dn),l=i.dot(dn);if(Math.max(-Math.max(o,h,l),Math.min(o,h,l))>a)return!1}return!0}const mn=yn();function yn(){const t=new ArrayBuffer(4),e=new Float32Array(t),s=new Uint32Array(t),i=new Uint32Array(512),r=new Uint32Array(512);for(let t=0;t<256;++t){const e=t-127;e<-27?(i[t]=0,i[256|t]=32768,r[t]=24,r[256|t]=24):e<-14?(i[t]=1024>>-e-14,i[256|t]=1024>>-e-14|32768,r[t]=-e-1,r[256|t]=-e-1):e<=15?(i[t]=e+15<<10,i[256|t]=e+15<<10|32768,r[t]=13,r[256|t]=13):e<128?(i[t]=31744,i[256|t]=64512,r[t]=24,r[256|t]=24):(i[t]=31744,i[256|t]=64512,r[t]=13,r[256|t]=13)}const n=new Uint32Array(2048),a=new Uint32Array(64),o=new Uint32Array(64);for(let t=1;t<1024;++t){let e=t<<13,s=0;for(;!(8388608&e);)e<<=1,s-=8388608;e&=-8388609,s+=947912704,n[t]=e|s}for(let t=1024;t<2048;++t)n[t]=939524096+(t-1024<<13);for(let t=1;t<31;++t)a[t]=t<<23;a[31]=1199570944,a[32]=2147483648;for(let t=33;t<63;++t)a[t]=2147483648+(t-32<<23);a[63]=3347054592;for(let t=1;t<64;++t)32!==t&&(o[t]=1024);return{floatView:e,uint32View:s,baseTable:i,shiftTable:r,mantissaTable:n,exponentTable:a,offsetTable:o}}function gn(t){Math.abs(t)>65504&&ai("DataUtils.toHalfFloat(): Value out of range."),t=xi(t,-65504,65504),mn.floatView[0]=t;const e=mn.uint32View[0],s=e>>23&511;return mn.baseTable[s]+((8388607&e)>>mn.shiftTable[s])}function fn(t){const e=t>>10;return mn.uint32View[0]=mn.mantissaTable[mn.offsetTable[e]+(1023&t)]+mn.exponentTable[e],mn.floatView[0]}class xn{static toHalfFloat(t){return gn(t)}static fromHalfFloat(t){return fn(t)}}const bn=new Ti,vn=new _i;let wn=0;class Mn extends di{constructor(t,e,s=!1){if(super(),Array.isArray(t))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.isBufferAttribute=!0,Object.defineProperty(this,"id",{value:wn++}),this.name="",this.array=t,this.itemSize=e,this.count=void 0!==t?t.length/e:0,this.normalized=s,this.usage=Os,this.updateRanges=[],this.gpuType=Pt,this.version=0}onUploadCallback(){}set needsUpdate(t){!0===t&&this.version++}setUsage(t){return this.usage=t,this}addUpdateRange(t,e){this.updateRanges.push({start:t,count:e})}clearUpdateRanges(){this.updateRanges.length=0}copy(t){return this.name=t.name,this.array=new t.array.constructor(t.array),this.itemSize=t.itemSize,this.count=t.count,this.normalized=t.normalized,this.usage=t.usage,this.gpuType=t.gpuType,this}copyAt(t,e,s){t*=this.itemSize,s*=e.itemSize;for(let i=0,r=this.itemSize;ithis.radius*this.radius&&(e.sub(this.center).normalize(),e.multiplyScalar(this.radius).add(this.center)),e}getBoundingBox(t){return this.isEmpty()?(t.makeEmpty(),t):(t.set(this.center,this.center),t.expandByScalar(this.radius),t)}applyMatrix4(t){return this.center.applyMatrix4(t),this.radius=this.radius*t.getMaxScaleOnAxis(),this}translate(t){return this.center.add(t),this}expandByPoint(t){if(this.isEmpty())return this.center.copy(t),this.radius=0,this;Pn.subVectors(t,this.center);const e=Pn.lengthSq();if(e>this.radius*this.radius){const t=Math.sqrt(e),s=.5*(t-this.radius);this.center.addScaledVector(Pn,s/t),this.radius+=s}return this}union(t){return t.isEmpty()?this:this.isEmpty()?(this.copy(t),this):(!0===this.center.equals(t.center)?this.radius=Math.max(this.radius,t.radius):(Rn.subVectors(t.center,this.center).setLength(t.radius),this.expandByPoint(Pn.copy(t.center).add(Rn)),this.expandByPoint(Pn.copy(t.center).sub(Rn))),this)}equals(t){return t.center.equals(this.center)&&t.radius===this.radius}clone(){return(new this.constructor).copy(this)}toJSON(){return{radius:this.radius,center:this.center.toArray()}}fromJSON(t){return this.radius=t.radius,this.center.fromArray(t.center),this}}let Nn=0;const Vn=new Qi,Ln=new Ar,Fn=new Ti,Dn=new Qr,Un=new Qr,jn=new Ti;class Wn extends di{constructor(){super(),this.isBufferGeometry=!0,Object.defineProperty(this,"id",{value:Nn++}),this.uuid=fi(),this.name="",this.type="BufferGeometry",this.index=null,this.indirect=null,this.indirectOffset=0,this.attributes={},this.morphAttributes={},this.morphTargetsRelative=!1,this.groups=[],this.boundingBox=null,this.boundingSphere=null,this.drawRange={start:0,count:1/0},this.userData={},this._transformed=!1}getIndex(){return this.index}setIndex(t){return Array.isArray(t)?this.index=new(function(t){for(let e=t.length-1;e>=0;--e)if(t[e]>=65535)return!0;return!1}(t)?In:zn)(t,1):this.index=t,this}setIndirect(t,e=0){return this.indirect=t,this.indirectOffset=e,this}getIndirect(){return this.indirect}getAttribute(t){return this.attributes[t]}setAttribute(t,e){return this.attributes[t]=e,this}deleteAttribute(t){return delete this.attributes[t],this}hasAttribute(t){return void 0!==this.attributes[t]}addGroup(t,e,s=0){this.groups.push({start:t,count:e,materialIndex:s})}clearGroups(){this.groups=[]}setDrawRange(t,e){this.drawRange.start=t,this.drawRange.count=e}applyMatrix4(t){const e=this.attributes.position;void 0!==e&&(e.applyMatrix4(t),e.needsUpdate=!0);const s=this.attributes.normal;if(void 0!==s){const e=(new Ii).getNormalMatrix(t);s.applyNormalMatrix(e),s.needsUpdate=!0}const i=this.attributes.tangent;return void 0!==i&&(i.transformDirection(t),i.needsUpdate=!0),null!==this.boundingBox&&this.computeBoundingBox(),null!==this.boundingSphere&&this.computeBoundingSphere(),this._transformed=!0,this}applyQuaternion(t){return Vn.makeRotationFromQuaternion(t),this.applyMatrix4(Vn),this}rotateX(t){return Vn.makeRotationX(t),this.applyMatrix4(Vn),this}rotateY(t){return Vn.makeRotationY(t),this.applyMatrix4(Vn),this}rotateZ(t){return Vn.makeRotationZ(t),this.applyMatrix4(Vn),this}translate(t,e,s){return Vn.makeTranslation(t,e,s),this.applyMatrix4(Vn),this}scale(t,e,s){return Vn.makeScale(t,e,s),this.applyMatrix4(Vn),this}lookAt(t){return Ln.lookAt(t),Ln.updateMatrix(),this.applyMatrix4(Ln.matrix),this}center(){return this.computeBoundingBox(),this.boundingBox.getCenter(Fn).negate(),this.translate(Fn.x,Fn.y,Fn.z),this}setFromPoints(t){const e=this.getAttribute("position");if(void 0===e){const e=[];for(let s=0,i=t.length;se.count&&ai("BufferGeometry: Buffer size too small for points data. Use .dispose() and create a new geometry."),e.needsUpdate=!0}return this}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new Qr);const t=this.attributes.position,e=this.morphAttributes.position;if(t&&t.isGLBufferAttribute)return oi("BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.",this),void this.boundingBox.set(new Ti(-1/0,-1/0,-1/0),new Ti(1/0,1/0,1/0));if(void 0!==t){if(this.boundingBox.setFromBufferAttribute(t),e)for(let t=0,s=e.length;t0&&(t.userData=this.userData),void 0!==this.parameters&&!0!==this._transformed){const e=this.parameters;for(const s in e)void 0!==e[s]&&(t[s]=e[s]);return t}t.data={attributes:{}};const e=this.index;null!==e&&(t.data.index={type:e.array.constructor.name,array:Array.prototype.slice.call(e.array)});const s=this.attributes;for(const e in s){const i=s[e];t.data.attributes[e]=i.toJSON(t.data)}const i={};let r=!1;for(const e in this.morphAttributes){const s=this.morphAttributes[e],n=[];for(let e=0,i=s.length;e0&&(i[e]=n,r=!0)}r&&(t.data.morphAttributes=i,t.data.morphTargetsRelative=this.morphTargetsRelative);const n=this.groups;n.length>0&&(t.data.groups=JSON.parse(JSON.stringify(n)));const a=this.boundingSphere;return null!==a&&(t.data.boundingSphere=a.toJSON()),t}clone(){return(new this.constructor).copy(this)}copy(t){this.index=null,this.attributes={},this.morphAttributes={},this.groups=[],this.boundingBox=null,this.boundingSphere=null;const e={};this.name=t.name;const s=t.index;null!==s&&this.setIndex(s.clone());const i=t.attributes;for(const t in i){const s=i[t];this.setAttribute(t,s.clone(e))}const r=t.morphAttributes;for(const t in r){const s=[],i=r[t];for(let t=0,r=i.length;t0!=t>0&&this.version++,this._alphaTest=t}onBeforeRender(){}onBeforeCompile(){}customProgramCacheKey(){return this.onBeforeCompile.toString()}setValues(t){if(void 0!==t)for(const e in t){const s=t[e];if(void 0===s){ai(`Material: parameter '${e}' has value of undefined.`);continue}const i=this[e];void 0!==i?i&&i.isColor?i.set(s):i&&i.isVector2&&s&&s.isVector2||i&&i.isEuler&&s&&s.isEuler||i&&i.isVector3&&s&&s.isVector3?i.copy(s):this[e]=s:ai(`Material: '${e}' is not a property of THREE.${this.type}.`)}}toJSON(t){const e=void 0===t||"string"==typeof t;e&&(t={textures:{},images:{}});const s={metadata:{version:4.7,type:"Material",generator:"Material.toJSON"}};function i(t){const e=[];for(const s in t){const i=t[s];delete i.metadata,e.push(i)}return e}if(s.uuid=this.uuid,s.type=this.type,""!==this.name&&(s.name=this.name),this.color&&this.color.isColor&&(s.color=this.color.getHex()),void 0!==this.roughness&&(s.roughness=this.roughness),void 0!==this.metalness&&(s.metalness=this.metalness),void 0!==this.sheen&&(s.sheen=this.sheen),this.sheenColor&&this.sheenColor.isColor&&(s.sheenColor=this.sheenColor.getHex()),void 0!==this.sheenRoughness&&(s.sheenRoughness=this.sheenRoughness),this.emissive&&this.emissive.isColor&&(s.emissive=this.emissive.getHex()),void 0!==this.emissiveIntensity&&1!==this.emissiveIntensity&&(s.emissiveIntensity=this.emissiveIntensity),this.specular&&this.specular.isColor&&(s.specular=this.specular.getHex()),void 0!==this.specularIntensity&&(s.specularIntensity=this.specularIntensity),this.specularColor&&this.specularColor.isColor&&(s.specularColor=this.specularColor.getHex()),void 0!==this.shininess&&(s.shininess=this.shininess),void 0!==this.clearcoat&&(s.clearcoat=this.clearcoat),void 0!==this.clearcoatRoughness&&(s.clearcoatRoughness=this.clearcoatRoughness),this.clearcoatMap&&this.clearcoatMap.isTexture&&(s.clearcoatMap=this.clearcoatMap.toJSON(t).uuid),this.clearcoatRoughnessMap&&this.clearcoatRoughnessMap.isTexture&&(s.clearcoatRoughnessMap=this.clearcoatRoughnessMap.toJSON(t).uuid),this.clearcoatNormalMap&&this.clearcoatNormalMap.isTexture&&(s.clearcoatNormalMap=this.clearcoatNormalMap.toJSON(t).uuid,s.clearcoatNormalScale=this.clearcoatNormalScale.toArray()),this.sheenColorMap&&this.sheenColorMap.isTexture&&(s.sheenColorMap=this.sheenColorMap.toJSON(t).uuid),this.sheenRoughnessMap&&this.sheenRoughnessMap.isTexture&&(s.sheenRoughnessMap=this.sheenRoughnessMap.toJSON(t).uuid),void 0!==this.dispersion&&(s.dispersion=this.dispersion),void 0!==this.iridescence&&(s.iridescence=this.iridescence),void 0!==this.iridescenceIOR&&(s.iridescenceIOR=this.iridescenceIOR),void 0!==this.iridescenceThicknessRange&&(s.iridescenceThicknessRange=this.iridescenceThicknessRange),this.iridescenceMap&&this.iridescenceMap.isTexture&&(s.iridescenceMap=this.iridescenceMap.toJSON(t).uuid),this.iridescenceThicknessMap&&this.iridescenceThicknessMap.isTexture&&(s.iridescenceThicknessMap=this.iridescenceThicknessMap.toJSON(t).uuid),void 0!==this.anisotropy&&(s.anisotropy=this.anisotropy),void 0!==this.anisotropyRotation&&(s.anisotropyRotation=this.anisotropyRotation),this.anisotropyMap&&this.anisotropyMap.isTexture&&(s.anisotropyMap=this.anisotropyMap.toJSON(t).uuid),this.map&&this.map.isTexture&&(s.map=this.map.toJSON(t).uuid),this.matcap&&this.matcap.isTexture&&(s.matcap=this.matcap.toJSON(t).uuid),this.alphaMap&&this.alphaMap.isTexture&&(s.alphaMap=this.alphaMap.toJSON(t).uuid),this.lightMap&&this.lightMap.isTexture&&(s.lightMap=this.lightMap.toJSON(t).uuid,s.lightMapIntensity=this.lightMapIntensity),this.aoMap&&this.aoMap.isTexture&&(s.aoMap=this.aoMap.toJSON(t).uuid,s.aoMapIntensity=this.aoMapIntensity),this.bumpMap&&this.bumpMap.isTexture&&(s.bumpMap=this.bumpMap.toJSON(t).uuid,s.bumpScale=this.bumpScale),this.normalMap&&this.normalMap.isTexture&&(s.normalMap=this.normalMap.toJSON(t).uuid,s.normalMapType=this.normalMapType,s.normalScale=this.normalScale.toArray()),this.displacementMap&&this.displacementMap.isTexture&&(s.displacementMap=this.displacementMap.toJSON(t).uuid,s.displacementScale=this.displacementScale,s.displacementBias=this.displacementBias),this.roughnessMap&&this.roughnessMap.isTexture&&(s.roughnessMap=this.roughnessMap.toJSON(t).uuid),this.metalnessMap&&this.metalnessMap.isTexture&&(s.metalnessMap=this.metalnessMap.toJSON(t).uuid),this.emissiveMap&&this.emissiveMap.isTexture&&(s.emissiveMap=this.emissiveMap.toJSON(t).uuid),this.specularMap&&this.specularMap.isTexture&&(s.specularMap=this.specularMap.toJSON(t).uuid),this.specularIntensityMap&&this.specularIntensityMap.isTexture&&(s.specularIntensityMap=this.specularIntensityMap.toJSON(t).uuid),this.specularColorMap&&this.specularColorMap.isTexture&&(s.specularColorMap=this.specularColorMap.toJSON(t).uuid),this.envMap&&this.envMap.isTexture&&(s.envMap=this.envMap.toJSON(t).uuid,void 0!==this.combine&&(s.combine=this.combine)),void 0!==this.envMapRotation&&(s.envMapRotation=this.envMapRotation.toArray()),void 0!==this.envMapIntensity&&(s.envMapIntensity=this.envMapIntensity),void 0!==this.reflectivity&&(s.reflectivity=this.reflectivity),void 0!==this.refractionRatio&&(s.refractionRatio=this.refractionRatio),this.gradientMap&&this.gradientMap.isTexture&&(s.gradientMap=this.gradientMap.toJSON(t).uuid),void 0!==this.transmission&&(s.transmission=this.transmission),this.transmissionMap&&this.transmissionMap.isTexture&&(s.transmissionMap=this.transmissionMap.toJSON(t).uuid),void 0!==this.thickness&&(s.thickness=this.thickness),this.thicknessMap&&this.thicknessMap.isTexture&&(s.thicknessMap=this.thicknessMap.toJSON(t).uuid),void 0!==this.attenuationDistance&&this.attenuationDistance!==1/0&&(s.attenuationDistance=this.attenuationDistance),void 0!==this.attenuationColor&&(s.attenuationColor=this.attenuationColor.getHex()),void 0!==this.size&&(s.size=this.size),null!==this.shadowSide&&(s.shadowSide=this.shadowSide),void 0!==this.sizeAttenuation&&(s.sizeAttenuation=this.sizeAttenuation),1!==this.blending&&(s.blending=this.blending),0!==this.side&&(s.side=this.side),!0===this.vertexColors&&(s.vertexColors=!0),this.opacity<1&&(s.opacity=this.opacity),!0===this.transparent&&(s.transparent=!0),204!==this.blendSrc&&(s.blendSrc=this.blendSrc),205!==this.blendDst&&(s.blendDst=this.blendDst),100!==this.blendEquation&&(s.blendEquation=this.blendEquation),null!==this.blendSrcAlpha&&(s.blendSrcAlpha=this.blendSrcAlpha),null!==this.blendDstAlpha&&(s.blendDstAlpha=this.blendDstAlpha),null!==this.blendEquationAlpha&&(s.blendEquationAlpha=this.blendEquationAlpha),this.blendColor&&this.blendColor.isColor&&(s.blendColor=this.blendColor.getHex()),0!==this.blendAlpha&&(s.blendAlpha=this.blendAlpha),3!==this.depthFunc&&(s.depthFunc=this.depthFunc),!1===this.depthTest&&(s.depthTest=this.depthTest),!1===this.depthWrite&&(s.depthWrite=this.depthWrite),!1===this.colorWrite&&(s.colorWrite=this.colorWrite),255!==this.stencilWriteMask&&(s.stencilWriteMask=this.stencilWriteMask),519!==this.stencilFunc&&(s.stencilFunc=this.stencilFunc),0!==this.stencilRef&&(s.stencilRef=this.stencilRef),255!==this.stencilFuncMask&&(s.stencilFuncMask=this.stencilFuncMask),this.stencilFail!==ls&&(s.stencilFail=this.stencilFail),this.stencilZFail!==ls&&(s.stencilZFail=this.stencilZFail),this.stencilZPass!==ls&&(s.stencilZPass=this.stencilZPass),!0===this.stencilWrite&&(s.stencilWrite=this.stencilWrite),void 0!==this.rotation&&0!==this.rotation&&(s.rotation=this.rotation),!0===this.polygonOffset&&(s.polygonOffset=!0),0!==this.polygonOffsetFactor&&(s.polygonOffsetFactor=this.polygonOffsetFactor),0!==this.polygonOffsetUnits&&(s.polygonOffsetUnits=this.polygonOffsetUnits),void 0!==this.linewidth&&1!==this.linewidth&&(s.linewidth=this.linewidth),void 0!==this.dashSize&&(s.dashSize=this.dashSize),void 0!==this.gapSize&&(s.gapSize=this.gapSize),void 0!==this.scale&&(s.scale=this.scale),!0===this.dithering&&(s.dithering=!0),this.alphaTest>0&&(s.alphaTest=this.alphaTest),!0===this.alphaHash&&(s.alphaHash=!0),!0===this.alphaToCoverage&&(s.alphaToCoverage=!0),!0===this.premultipliedAlpha&&(s.premultipliedAlpha=!0),!0===this.forceSinglePass&&(s.forceSinglePass=!0),!1===this.allowOverride&&(s.allowOverride=!1),!0===this.wireframe&&(s.wireframe=!0),this.wireframeLinewidth>1&&(s.wireframeLinewidth=this.wireframeLinewidth),"round"!==this.wireframeLinecap&&(s.wireframeLinecap=this.wireframeLinecap),"round"!==this.wireframeLinejoin&&(s.wireframeLinejoin=this.wireframeLinejoin),!0===this.flatShading&&(s.flatShading=!0),!1===this.visible&&(s.visible=!1),!1===this.toneMapped&&(s.toneMapped=!1),!1===this.fog&&(s.fog=!1),Object.keys(this.userData).length>0&&(s.userData=this.userData),e){const e=i(t.textures),r=i(t.images);e.length>0&&(s.textures=e),r.length>0&&(s.images=r)}return s}fromJSON(t,e){if(void 0!==t.uuid&&(this.uuid=t.uuid),void 0!==t.name&&(this.name=t.name),void 0!==t.color&&void 0!==this.color&&this.color.setHex(t.color),void 0!==t.roughness&&(this.roughness=t.roughness),void 0!==t.metalness&&(this.metalness=t.metalness),void 0!==t.sheen&&(this.sheen=t.sheen),void 0!==t.sheenColor&&(this.sheenColor=(new Pr).setHex(t.sheenColor)),void 0!==t.sheenRoughness&&(this.sheenRoughness=t.sheenRoughness),void 0!==t.emissive&&void 0!==this.emissive&&this.emissive.setHex(t.emissive),void 0!==t.specular&&void 0!==this.specular&&this.specular.setHex(t.specular),void 0!==t.specularIntensity&&(this.specularIntensity=t.specularIntensity),void 0!==t.specularColor&&void 0!==this.specularColor&&this.specularColor.setHex(t.specularColor),void 0!==t.shininess&&(this.shininess=t.shininess),void 0!==t.clearcoat&&(this.clearcoat=t.clearcoat),void 0!==t.clearcoatRoughness&&(this.clearcoatRoughness=t.clearcoatRoughness),void 0!==t.dispersion&&(this.dispersion=t.dispersion),void 0!==t.iridescence&&(this.iridescence=t.iridescence),void 0!==t.iridescenceIOR&&(this.iridescenceIOR=t.iridescenceIOR),void 0!==t.iridescenceThicknessRange&&(this.iridescenceThicknessRange=t.iridescenceThicknessRange),void 0!==t.transmission&&(this.transmission=t.transmission),void 0!==t.thickness&&(this.thickness=t.thickness),void 0!==t.attenuationDistance&&(this.attenuationDistance=t.attenuationDistance),void 0!==t.attenuationColor&&void 0!==this.attenuationColor&&this.attenuationColor.setHex(t.attenuationColor),void 0!==t.anisotropy&&(this.anisotropy=t.anisotropy),void 0!==t.anisotropyRotation&&(this.anisotropyRotation=t.anisotropyRotation),void 0!==t.fog&&(this.fog=t.fog),void 0!==t.flatShading&&(this.flatShading=t.flatShading),void 0!==t.blending&&(this.blending=t.blending),void 0!==t.combine&&(this.combine=t.combine),void 0!==t.side&&(this.side=t.side),void 0!==t.shadowSide&&(this.shadowSide=t.shadowSide),void 0!==t.opacity&&(this.opacity=t.opacity),void 0!==t.transparent&&(this.transparent=t.transparent),void 0!==t.alphaTest&&(this.alphaTest=t.alphaTest),void 0!==t.alphaHash&&(this.alphaHash=t.alphaHash),void 0!==t.depthFunc&&(this.depthFunc=t.depthFunc),void 0!==t.depthTest&&(this.depthTest=t.depthTest),void 0!==t.depthWrite&&(this.depthWrite=t.depthWrite),void 0!==t.colorWrite&&(this.colorWrite=t.colorWrite),void 0!==t.blendSrc&&(this.blendSrc=t.blendSrc),void 0!==t.blendDst&&(this.blendDst=t.blendDst),void 0!==t.blendEquation&&(this.blendEquation=t.blendEquation),void 0!==t.blendSrcAlpha&&(this.blendSrcAlpha=t.blendSrcAlpha),void 0!==t.blendDstAlpha&&(this.blendDstAlpha=t.blendDstAlpha),void 0!==t.blendEquationAlpha&&(this.blendEquationAlpha=t.blendEquationAlpha),void 0!==t.blendColor&&void 0!==this.blendColor&&this.blendColor.setHex(t.blendColor),void 0!==t.blendAlpha&&(this.blendAlpha=t.blendAlpha),void 0!==t.stencilWriteMask&&(this.stencilWriteMask=t.stencilWriteMask),void 0!==t.stencilFunc&&(this.stencilFunc=t.stencilFunc),void 0!==t.stencilRef&&(this.stencilRef=t.stencilRef),void 0!==t.stencilFuncMask&&(this.stencilFuncMask=t.stencilFuncMask),void 0!==t.stencilFail&&(this.stencilFail=t.stencilFail),void 0!==t.stencilZFail&&(this.stencilZFail=t.stencilZFail),void 0!==t.stencilZPass&&(this.stencilZPass=t.stencilZPass),void 0!==t.stencilWrite&&(this.stencilWrite=t.stencilWrite),void 0!==t.wireframe&&(this.wireframe=t.wireframe),void 0!==t.wireframeLinewidth&&(this.wireframeLinewidth=t.wireframeLinewidth),void 0!==t.wireframeLinecap&&(this.wireframeLinecap=t.wireframeLinecap),void 0!==t.wireframeLinejoin&&(this.wireframeLinejoin=t.wireframeLinejoin),void 0!==t.rotation&&(this.rotation=t.rotation),void 0!==t.linewidth&&(this.linewidth=t.linewidth),void 0!==t.dashSize&&(this.dashSize=t.dashSize),void 0!==t.gapSize&&(this.gapSize=t.gapSize),void 0!==t.scale&&(this.scale=t.scale),void 0!==t.polygonOffset&&(this.polygonOffset=t.polygonOffset),void 0!==t.polygonOffsetFactor&&(this.polygonOffsetFactor=t.polygonOffsetFactor),void 0!==t.polygonOffsetUnits&&(this.polygonOffsetUnits=t.polygonOffsetUnits),void 0!==t.dithering&&(this.dithering=t.dithering),void 0!==t.alphaToCoverage&&(this.alphaToCoverage=t.alphaToCoverage),void 0!==t.premultipliedAlpha&&(this.premultipliedAlpha=t.premultipliedAlpha),void 0!==t.forceSinglePass&&(this.forceSinglePass=t.forceSinglePass),void 0!==t.allowOverride&&(this.allowOverride=t.allowOverride),void 0!==t.visible&&(this.visible=t.visible),void 0!==t.toneMapped&&(this.toneMapped=t.toneMapped),void 0!==t.userData&&(this.userData=t.userData),void 0!==t.vertexColors&&("number"==typeof t.vertexColors?this.vertexColors=t.vertexColors>0:this.vertexColors=t.vertexColors),void 0!==t.size&&(this.size=t.size),void 0!==t.sizeAttenuation&&(this.sizeAttenuation=t.sizeAttenuation),void 0!==t.map&&(this.map=e[t.map]||null),void 0!==t.matcap&&(this.matcap=e[t.matcap]||null),void 0!==t.alphaMap&&(this.alphaMap=e[t.alphaMap]||null),void 0!==t.bumpMap&&(this.bumpMap=e[t.bumpMap]||null),void 0!==t.bumpScale&&(this.bumpScale=t.bumpScale),void 0!==t.normalMap&&(this.normalMap=e[t.normalMap]||null),void 0!==t.normalMapType&&(this.normalMapType=t.normalMapType),void 0!==t.normalScale){let e=t.normalScale;!1===Array.isArray(e)&&(e=[e,e]),this.normalScale=(new _i).fromArray(e)}return void 0!==t.displacementMap&&(this.displacementMap=e[t.displacementMap]||null),void 0!==t.displacementScale&&(this.displacementScale=t.displacementScale),void 0!==t.displacementBias&&(this.displacementBias=t.displacementBias),void 0!==t.roughnessMap&&(this.roughnessMap=e[t.roughnessMap]||null),void 0!==t.metalnessMap&&(this.metalnessMap=e[t.metalnessMap]||null),void 0!==t.emissiveMap&&(this.emissiveMap=e[t.emissiveMap]||null),void 0!==t.emissiveIntensity&&(this.emissiveIntensity=t.emissiveIntensity),void 0!==t.specularMap&&(this.specularMap=e[t.specularMap]||null),void 0!==t.specularIntensityMap&&(this.specularIntensityMap=e[t.specularIntensityMap]||null),void 0!==t.specularColorMap&&(this.specularColorMap=e[t.specularColorMap]||null),void 0!==t.envMap&&(this.envMap=e[t.envMap]||null),void 0!==t.envMapRotation&&this.envMapRotation.fromArray(t.envMapRotation),void 0!==t.envMapIntensity&&(this.envMapIntensity=t.envMapIntensity),void 0!==t.reflectivity&&(this.reflectivity=t.reflectivity),void 0!==t.refractionRatio&&(this.refractionRatio=t.refractionRatio),void 0!==t.lightMap&&(this.lightMap=e[t.lightMap]||null),void 0!==t.lightMapIntensity&&(this.lightMapIntensity=t.lightMapIntensity),void 0!==t.aoMap&&(this.aoMap=e[t.aoMap]||null),void 0!==t.aoMapIntensity&&(this.aoMapIntensity=t.aoMapIntensity),void 0!==t.gradientMap&&(this.gradientMap=e[t.gradientMap]||null),void 0!==t.clearcoatMap&&(this.clearcoatMap=e[t.clearcoatMap]||null),void 0!==t.clearcoatRoughnessMap&&(this.clearcoatRoughnessMap=e[t.clearcoatRoughnessMap]||null),void 0!==t.clearcoatNormalMap&&(this.clearcoatNormalMap=e[t.clearcoatNormalMap]||null),void 0!==t.clearcoatNormalScale&&(this.clearcoatNormalScale=(new _i).fromArray(t.clearcoatNormalScale)),void 0!==t.iridescenceMap&&(this.iridescenceMap=e[t.iridescenceMap]||null),void 0!==t.iridescenceThicknessMap&&(this.iridescenceThicknessMap=e[t.iridescenceThicknessMap]||null),void 0!==t.transmissionMap&&(this.transmissionMap=e[t.transmissionMap]||null),void 0!==t.thicknessMap&&(this.thicknessMap=e[t.thicknessMap]||null),void 0!==t.anisotropyMap&&(this.anisotropyMap=e[t.anisotropyMap]||null),void 0!==t.sheenColorMap&&(this.sheenColorMap=e[t.sheenColorMap]||null),void 0!==t.sheenRoughnessMap&&(this.sheenRoughnessMap=e[t.sheenRoughnessMap]||null),this}clone(){return(new this.constructor).copy(this)}copy(t){this.name=t.name,this.blending=t.blending,this.side=t.side,this.vertexColors=t.vertexColors,this.opacity=t.opacity,this.transparent=t.transparent,this.blendSrc=t.blendSrc,this.blendDst=t.blendDst,this.blendEquation=t.blendEquation,this.blendSrcAlpha=t.blendSrcAlpha,this.blendDstAlpha=t.blendDstAlpha,this.blendEquationAlpha=t.blendEquationAlpha,this.blendColor.copy(t.blendColor),this.blendAlpha=t.blendAlpha,this.depthFunc=t.depthFunc,this.depthTest=t.depthTest,this.depthWrite=t.depthWrite,this.stencilWriteMask=t.stencilWriteMask,this.stencilFunc=t.stencilFunc,this.stencilRef=t.stencilRef,this.stencilFuncMask=t.stencilFuncMask,this.stencilFail=t.stencilFail,this.stencilZFail=t.stencilZFail,this.stencilZPass=t.stencilZPass,this.stencilWrite=t.stencilWrite;const e=t.clippingPlanes;let s=null;if(null!==e){const t=e.length;s=new Array(t);for(let i=0;i!==t;++i)s[i]=e[i].clone()}return this.clippingPlanes=s,this.clipIntersection=t.clipIntersection,this.clipShadows=t.clipShadows,this.shadowSide=t.shadowSide,this.colorWrite=t.colorWrite,this.precision=t.precision,this.polygonOffset=t.polygonOffset,this.polygonOffsetFactor=t.polygonOffsetFactor,this.polygonOffsetUnits=t.polygonOffsetUnits,this.dithering=t.dithering,this.alphaTest=t.alphaTest,this.alphaHash=t.alphaHash,this.alphaToCoverage=t.alphaToCoverage,this.premultipliedAlpha=t.premultipliedAlpha,this.forceSinglePass=t.forceSinglePass,this.allowOverride=t.allowOverride,this.visible=t.visible,this.toneMapped=t.toneMapped,this.userData=JSON.parse(JSON.stringify(t.userData)),this}dispose(){this.dispatchEvent({type:"dispose"})}set needsUpdate(t){!0===t&&this.version++}}class Gn extends Zn{constructor(t){super(),this.isSpriteMaterial=!0,this.type="SpriteMaterial",this.color=new Pr(16777215),this.map=null,this.alphaMap=null,this.rotation=0,this.sizeAttenuation=!0,this.transparent=!0,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.alphaMap=t.alphaMap,this.rotation=t.rotation,this.sizeAttenuation=t.sizeAttenuation,this.fog=t.fog,this}}const $n=new Ti,Qn=new Ti,Kn=new Ti,ta=new _i,ea=new _i,sa=new Qi,ia=new Ti,ra=new Ti,na=new Ti,aa=new _i,oa=new _i,ha=new _i;class la extends Ar{constructor(t=new Gn){if(super(),this.isSprite=!0,this.type="Sprite",void 0===Xn){Xn=new Wn;const t=new Float32Array([-.5,-.5,0,0,0,.5,-.5,0,1,0,.5,.5,0,1,1,-.5,.5,0,0,1]),e=new Jn(t,5);Xn.setIndex([0,1,2,0,2,3]),Xn.setAttribute("position",new Hn(e,3,0,!1)),Xn.setAttribute("uv",new Hn(e,2,3,!1))}this.geometry=Xn,this.material=t,this.center=new _i(.5,.5),this.count=1}raycast(t,e){null===t.camera&&oi('Sprite: "Raycaster.camera" needs to be set in order to raycast against sprites.'),Qn.setFromMatrixScale(this.matrixWorld),sa.copy(t.camera.matrixWorld),this.modelViewMatrix.multiplyMatrices(t.camera.matrixWorldInverse,this.matrixWorld),Kn.setFromMatrixPosition(this.modelViewMatrix),t.camera.isPerspectiveCamera&&!1===this.material.sizeAttenuation&&Qn.multiplyScalar(-Kn.z);const s=this.material.rotation;let i,r;0!==s&&(r=Math.cos(s),i=Math.sin(s));const n=this.center;ca(ia.set(-.5,-.5,0),Kn,n,Qn,i,r),ca(ra.set(.5,-.5,0),Kn,n,Qn,i,r),ca(na.set(.5,.5,0),Kn,n,Qn,i,r),aa.set(0,0),oa.set(1,0),ha.set(1,1);let a=t.ray.intersectTriangle(ia,ra,na,!1,$n);if(null===a&&(ca(ra.set(-.5,.5,0),Kn,n,Qn,i,r),oa.set(0,1),a=t.ray.intersectTriangle(ia,na,ra,!1,$n),null===a))return;const o=t.ray.origin.distanceTo($n);ot.far||e.push({distance:o,point:$n.clone(),uv:$r.getInterpolation($n,ia,ra,na,aa,oa,ha,new _i),face:null,object:this})}copy(t,e){return super.copy(t,e),void 0!==t.center&&this.center.copy(t.center),this.material=t.material,this}}function ca(t,e,s,i,r,n){ta.subVectors(t,s).addScalar(.5).multiply(i),void 0!==r?(ea.x=n*ta.x-r*ta.y,ea.y=r*ta.x+n*ta.y):ea.copy(ta),t.copy(e),t.x+=ea.x,t.y+=ea.y,t.applyMatrix4(sa)}const ua=new Ti,da=new Ti;class pa extends Ar{constructor(){super(),this.isLOD=!0,this._currentLevel=0,this.type="LOD",Object.defineProperties(this,{levels:{enumerable:!0,value:[]}}),this.autoUpdate=!0}copy(t){super.copy(t,!1);const e=t.levels;for(let t=0,s=e.length;t0){let s,i;for(s=1,i=e.length;s0){ua.setFromMatrixPosition(this.matrixWorld);const s=t.ray.origin.distanceTo(ua);this.getObjectForDistance(s).raycast(t,e)}}update(t){const e=this.levels;if(e.length>1){ua.setFromMatrixPosition(t.matrixWorld),da.setFromMatrixPosition(this.matrixWorld);const s=ua.distanceTo(da)/t.zoom;let i,r;for(e[0].object.visible=!0,i=1,r=e.length;i=t))break;e[i-1].object.visible=!1,e[i].object.visible=!0}for(this._currentLevel=i-1;i0)if(c=n*o-a,u=n*a-o,p=r*l,c>=0)if(u>=-p)if(u<=p){const t=1/l;c*=t,u*=t,d=c*(c+n*u+2*a)+u*(n*c+u+2*o)+h}else u=r,c=Math.max(0,-(n*u+a)),d=-c*c+u*(u+2*o)+h;else u=-r,c=Math.max(0,-(n*u+a)),d=-c*c+u*(u+2*o)+h;else u<=-p?(c=Math.max(0,-(-n*r+a)),u=c>0?-r:Math.min(Math.max(-r,-o),r),d=-c*c+u*(u+2*o)+h):u<=p?(c=0,u=Math.min(Math.max(-r,-o),r),d=u*(u+2*o)+h):(c=Math.max(0,-(n*r+a)),u=c>0?r:Math.min(Math.max(-r,-o),r),d=-c*c+u*(u+2*o)+h);else u=n>0?-r:r,c=Math.max(0,-(n*u+a)),d=-c*c+u*(u+2*o)+h;return s&&s.copy(this.origin).addScaledVector(this.direction,c),i&&i.copy(ya).addScaledVector(ga,u),d}intersectSphere(t,e){ma.subVectors(t.center,this.origin);const s=ma.dot(this.direction),i=ma.dot(ma)-s*s,r=t.radius*t.radius;if(i>r)return null;const n=Math.sqrt(r-i),a=s-n,o=s+n;return o<0?null:a<0?this.at(o,e):this.at(a,e)}intersectsSphere(t){return!(t.radius<0)&&this.distanceSqToPoint(t.center)<=t.radius*t.radius}distanceToPlane(t){const e=t.normal.dot(this.direction);if(0===e)return 0===t.distanceToPoint(this.origin)?0:null;const s=-(this.origin.dot(t.normal)+t.constant)/e;return s>=0?s:null}intersectPlane(t,e){const s=this.distanceToPlane(t);return null===s?null:this.at(s,e)}intersectsPlane(t){const e=t.distanceToPoint(this.origin);if(0===e)return!0;return t.normal.dot(this.direction)*e<0}intersectBox(t,e){let s,i,r,n,a,o;const h=1/this.direction.x,l=1/this.direction.y,c=1/this.direction.z,u=this.origin;return h>=0?(s=(t.min.x-u.x)*h,i=(t.max.x-u.x)*h):(s=(t.max.x-u.x)*h,i=(t.min.x-u.x)*h),l>=0?(r=(t.min.y-u.y)*l,n=(t.max.y-u.y)*l):(r=(t.max.y-u.y)*l,n=(t.min.y-u.y)*l),s>n||r>i?null:((r>s||isNaN(s))&&(s=r),(n=0?(a=(t.min.z-u.z)*c,o=(t.max.z-u.z)*c):(a=(t.max.z-u.z)*c,o=(t.min.z-u.z)*c),s>o||a>i?null:((a>s||s!=s)&&(s=a),(o=0?s:i,e)))}intersectsBox(t){return null!==this.intersectBox(t,ma)}intersectTriangle(t,e,s,i,r){xa.subVectors(e,t),ba.subVectors(s,t),va.crossVectors(xa,ba);let n,a=this.direction.dot(va);if(a>0){if(i)return null;n=1}else{if(!(a<0))return null;n=-1,a=-a}fa.subVectors(this.origin,t);const o=n*this.direction.dot(ba.crossVectors(fa,ba));if(o<0)return null;const h=n*this.direction.dot(xa.cross(fa));if(h<0)return null;if(o+h>a)return null;const l=-n*fa.dot(va);return l<0?null:this.at(l/a,r)}applyMatrix4(t){return this.origin.applyMatrix4(t),this.direction.transformDirection(t),this}equals(t){return t.origin.equals(this.origin)&&t.direction.equals(this.direction)}clone(){return(new this.constructor).copy(this)}}class Ma extends Zn{constructor(t){super(),this.isMeshBasicMaterial=!0,this.type="MeshBasicMaterial",this.color=new Pr(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 hr,this.combine=0,this.reflectivity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.envMapRotation.copy(t.envMapRotation),this.combine=t.combine,this.reflectivity=t.reflectivity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.fog=t.fog,this}}const Sa=new Qi,_a=new wa,Aa=new En,Ta=new Ti,za=new Ti,Ca=new Ti,Ia=new Ti,Ba=new Ti,ka=new Ti,Oa=new Ti,Pa=new Ti;class Ra extends Ar{constructor(t=new Wn,e=new Ma){super(),this.isMesh=!0,this.type="Mesh",this.geometry=t,this.material=e,this.morphTargetDictionary=void 0,this.morphTargetInfluences=void 0,this.count=1,this.updateMorphTargets()}copy(t,e){return super.copy(t,e),void 0!==t.morphTargetInfluences&&(this.morphTargetInfluences=t.morphTargetInfluences.slice()),void 0!==t.morphTargetDictionary&&(this.morphTargetDictionary=Object.assign({},t.morphTargetDictionary)),this.material=Array.isArray(t.material)?t.material.slice():t.material,this.geometry=t.geometry,this}updateMorphTargets(){const t=this.geometry.morphAttributes,e=Object.keys(t);if(e.length>0){const s=t[e[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=s.length;t(t.far-t.near)**2)return}Sa.copy(r).invert(),_a.copy(t.ray).applyMatrix4(Sa),null!==s.boundingBox&&!1===_a.intersectsBox(s.boundingBox)||this._computeIntersections(t,e,_a)}}_computeIntersections(t,e,s){let i;const r=this.geometry,n=this.material,a=r.index,o=r.attributes.position,h=r.attributes.uv,l=r.attributes.uv1,c=r.attributes.normal,u=r.groups,d=r.drawRange;if(null!==a)if(Array.isArray(n))for(let r=0,o=u.length;rs.far?null:{distance:l,point:Pa.clone(),object:t}}(t,e,s,i,za,Ca,Ia,Oa);if(c){const t=new Ti;$r.getBarycoord(Oa,za,Ca,Ia,t),r&&(c.uv=$r.getInterpolatedAttribute(r,o,h,l,t,new _i)),n&&(c.uv1=$r.getInterpolatedAttribute(n,o,h,l,t,new _i)),a&&(c.normal=$r.getInterpolatedAttribute(a,o,h,l,t,new Ti),c.normal.dot(i.direction)>0&&c.normal.multiplyScalar(-1));const e={a:o,b:h,c:l,normal:new Ti,materialIndex:0};$r.getNormal(za,Ca,Ia,e.normal),c.face=e,c.barycoord=t}return c}const Na=new qi,Va=new qi,La=new qi,Fa=new qi,Da=new Qi,Ua=new Ti,ja=new En,Wa=new Qi,Ja=new wa;class qa extends Ra{constructor(t,e){super(t,e),this.isSkinnedMesh=!0,this.type="SkinnedMesh",this.bindMode=at,this.bindMatrix=new Qi,this.bindMatrixInverse=new Qi,this.boundingBox=null,this.boundingSphere=null}computeBoundingBox(){const t=this.geometry;null===this.boundingBox&&(this.boundingBox=new Qr),this.boundingBox.makeEmpty();const e=t.getAttribute("position");for(let t=0;t1)?null:e.copy(t.start).addScaledVector(i,n)}intersectsLine(t){const e=this.distanceToPoint(t.start),s=this.distanceToPoint(t.end);return e<0&&s>0||s<0&&e>0}intersectsBox(t){return t.intersectsPlane(this)}intersectsSphere(t){return t.intersectsPlane(this)}coplanarPoint(t){return t.copy(this.normal).multiplyScalar(-this.constant)}applyMatrix4(t,e){const s=e||ho.getNormalMatrix(t),i=this.coplanarPoint(ao).applyMatrix4(t),r=this.normal.applyMatrix3(s).normalize();return this.constant=-i.dot(r),this}translate(t){return this.constant-=t.dot(this.normal),this}equals(t){return t.normal.equals(this.normal)&&t.constant===this.constant}clone(){return(new this.constructor).copy(this)}}const co=new En,uo=new _i(.5,.5),po=new Ti;class mo{constructor(t=new lo,e=new lo,s=new lo,i=new lo,r=new lo,n=new lo){this.planes=[t,e,s,i,r,n]}set(t,e,s,i,r,n){const a=this.planes;return a[0].copy(t),a[1].copy(e),a[2].copy(s),a[3].copy(i),a[4].copy(r),a[5].copy(n),this}copy(t){const e=this.planes;for(let s=0;s<6;s++)e[s].copy(t.planes[s]);return this}setFromProjectionMatrix(t,e=2e3,s=!1){const i=this.planes,r=t.elements,n=r[0],a=r[1],o=r[2],h=r[3],l=r[4],c=r[5],u=r[6],d=r[7],p=r[8],m=r[9],y=r[10],g=r[11],f=r[12],x=r[13],b=r[14],v=r[15];if(i[0].setComponents(h-n,d-l,g-p,v-f).normalize(),i[1].setComponents(h+n,d+l,g+p,v+f).normalize(),i[2].setComponents(h+a,d+c,g+m,v+x).normalize(),i[3].setComponents(h-a,d-c,g-m,v-x).normalize(),s)i[4].setComponents(o,u,y,b).normalize(),i[5].setComponents(h-o,d-u,g-y,v-b).normalize();else if(i[4].setComponents(h-o,d-u,g-y,v-b).normalize(),e===Ws)i[5].setComponents(h+o,d+u,g+y,v+b).normalize();else{if(e!==Js)throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: "+e);i[5].setComponents(o,u,y,b).normalize()}return this}intersectsObject(t){if(void 0!==t.boundingSphere)null===t.boundingSphere&&t.computeBoundingSphere(),co.copy(t.boundingSphere).applyMatrix4(t.matrixWorld);else{const e=t.geometry;null===e.boundingSphere&&e.computeBoundingSphere(),co.copy(e.boundingSphere).applyMatrix4(t.matrixWorld)}return this.intersectsSphere(co)}intersectsSprite(t){co.center.set(0,0,0);const e=uo.distanceTo(t.center);return co.radius=.7071067811865476+e,co.applyMatrix4(t.matrixWorld),this.intersectsSphere(co)}intersectsSphere(t){const e=this.planes,s=t.center,i=-t.radius;for(let t=0;t<6;t++){if(e[t].distanceToPoint(s)0?t.max.x:t.min.x,po.y=i.normal.y>0?t.max.y:t.min.y,po.z=i.normal.z>0?t.max.z:t.min.z,i.distanceToPoint(po)<0)return!1}return!0}containsPoint(t){const e=this.planes;for(let s=0;s<6;s++)if(e[s].distanceToPoint(t)<0)return!1;return!0}clone(){return(new this.constructor).copy(this)}}const yo=new Qi;class go{constructor(){this.coordinateSystem=Ws,this._frustums=[],this._count=0}setFromArrayCamera(t){const e=t.cameras,s=this._frustums;for(let t=0;t=r.length&&r.push({start:-1,count:-1,z:-1,index:-1});const a=r[this.index];n.push(a),this.index++,a.start=t,a.count=e,a.z=s,a.index=i}reset(){this.list.length=0,this.index=0}}const wo=new Qi,Mo=new Pr(1,1,1),So=new mo,_o=new go,Ao=new Qr,To=new En,zo=new Ti,Co=new Ti,Io=new Ti,Bo=new vo,ko=new Ra,Oo=[];function Po(t,e,s=0){const i=e.itemSize;if(t.isInterleavedBufferAttribute||t.array.constructor!==e.array.constructor){const r=t.count;for(let n=0;n65535?new Uint32Array(i):new Uint16Array(i);e.setIndex(new Mn(t,1))}this._geometryInitialized=!0}}_validateGeometry(t){const e=this.geometry;if(Boolean(t.getIndex())!==Boolean(e.getIndex()))throw new Error('THREE.BatchedMesh: All geometries must consistently have "index".');for(const s in e.attributes){if(!t.hasAttribute(s))throw new Error(`THREE.BatchedMesh: Added geometry missing "${s}". All geometries must have consistent attributes.`);const i=t.getAttribute(s),r=e.getAttribute(s);if(i.itemSize!==r.itemSize||i.normalized!==r.normalized)throw new Error("THREE.BatchedMesh: All attributes must have a consistent itemSize and normalized value.")}}validateInstanceId(t){const e=this._instanceInfo;if(t<0||t>=e.length||!1===e[t].active)throw new Error(`THREE.BatchedMesh: Invalid instanceId ${t}. Instance is either out of range or has been deleted.`)}validateGeometryId(t){const e=this._geometryInfo;if(t<0||t>=e.length||!1===e[t].active)throw new Error(`THREE.BatchedMesh: Invalid geometryId ${t}. Geometry is either out of range or has been deleted.`)}setCustomSort(t){return this.customSort=t,this}computeBoundingBox(){null===this.boundingBox&&(this.boundingBox=new Qr);const t=this.boundingBox,e=this._instanceInfo;t.makeEmpty();for(let s=0,i=e.length;s=this.maxInstanceCount&&0===this._availableInstanceIds.length)throw new Error("THREE.BatchedMesh: Maximum item count reached.");const e={visible:!0,active:!0,geometryIndex:t};let s=null;this._availableInstanceIds.length>0?(this._availableInstanceIds.sort(fo),s=this._availableInstanceIds.shift(),this._instanceInfo[s]=e):(s=this._instanceInfo.length,this._instanceInfo.push(e));const i=this._matricesTexture;wo.identity().toArray(i.image.data,16*s),i.needsUpdate=!0;const r=this._colorsTexture;return r&&(Mo.toArray(r.image.data,4*s),r.needsUpdate=!0),this._visibilityChanged=!0,s}addGeometry(t,e=-1,s=-1){this._initializeGeometry(t),this._validateGeometry(t);const i={vertexStart:-1,vertexCount:-1,reservedVertexCount:-1,indexStart:-1,indexCount:-1,reservedIndexCount:-1,start:-1,count:-1,boundingBox:null,boundingSphere:null,active:!0},r=this._geometryInfo;i.vertexStart=this._nextVertexStart,i.reservedVertexCount=-1===e?t.getAttribute("position").count:e;const n=t.getIndex();if(null!==n&&(i.indexStart=this._nextIndexStart,i.reservedIndexCount=-1===s?n.count:s),-1!==i.indexStart&&i.indexStart+i.reservedIndexCount>this._maxIndexCount||i.vertexStart+i.reservedVertexCount>this._maxVertexCount)throw new Error("THREE.BatchedMesh: Reserved space request exceeds the maximum buffer size.");let a;return this._availableGeometryIds.length>0?(this._availableGeometryIds.sort(fo),a=this._availableGeometryIds.shift(),r[a]=i):(a=this._geometryCount,this._geometryCount++,r.push(i)),this.setGeometryAt(a,t),this._nextIndexStart=i.indexStart+i.reservedIndexCount,this._nextVertexStart=i.vertexStart+i.reservedVertexCount,a}setGeometryAt(t,e){if(t>=this._geometryCount)throw new Error("THREE.BatchedMesh: Maximum geometry count reached.");this._validateGeometry(e);const s=this.geometry,i=null!==s.getIndex(),r=s.getIndex(),n=e.getIndex(),a=this._geometryInfo[t];if(i&&n.count>a.reservedIndexCount||e.attributes.position.count>a.reservedVertexCount)throw new Error("THREE.BatchedMesh: Reserved space not large enough for provided geometry.");const o=a.vertexStart,h=a.reservedVertexCount;a.vertexCount=e.getAttribute("position").count;for(const t in s.attributes){const i=e.getAttribute(t),r=s.getAttribute(t);Po(i,r,o);const n=i.itemSize;for(let t=i.count,e=h;t=e.length||!1===e[t].active)return this;const s=this._instanceInfo;for(let e=0,i=s.length;ee).sort((t,e)=>s[t].vertexStart-s[e].vertexStart),r=this.geometry;for(let n=0,a=s.length;n=this._geometryCount)return null;const s=this.geometry,i=this._geometryInfo[t];if(null===i.boundingBox){const t=new Qr,e=s.index,r=s.attributes.position;for(let s=i.start,n=i.start+i.count;s=this._geometryCount)return null;const s=this.geometry,i=this._geometryInfo[t];if(null===i.boundingSphere){const e=new En;this.getBoundingBoxAt(t,Ao),Ao.getCenter(e.center);const r=s.index,n=s.attributes.position;let a=0;for(let t=i.start,s=i.start+i.count;tt.active);if(Math.max(...s.map(t=>t.vertexStart+t.reservedVertexCount))>t)throw new Error(`THREE.BatchedMesh: Geometry vertex values are being used outside the range ${e}. Cannot shrink further.`);if(this.geometry.index){if(Math.max(...s.map(t=>t.indexStart+t.reservedIndexCount))>e)throw new Error(`THREE.BatchedMesh: Geometry index values are being used outside the range ${e}. Cannot shrink further.`)}const i=this.geometry;i.dispose(),this._maxVertexCount=t,this._maxIndexCount=e,this._geometryInitialized&&(this._geometryInitialized=!1,this.geometry=new Wn,this._initializeGeometry(i));const r=this.geometry;i.index&&Ro(i.index.array,r.index.array);for(const t in i.attributes)Ro(i.attributes[t].array,r.attributes[t].array)}raycast(t,e){const s=this._instanceInfo,i=this._geometryInfo,r=this.matrixWorld,n=this.geometry;ko.material=this.material,ko.geometry.index=n.index,ko.geometry.attributes=n.attributes,null===ko.geometry.boundingBox&&(ko.geometry.boundingBox=new Qr),null===ko.geometry.boundingSphere&&(ko.geometry.boundingSphere=new En);for(let n=0,a=s.length;n({...t,boundingBox:null!==t.boundingBox?t.boundingBox.clone():null,boundingSphere:null!==t.boundingSphere?t.boundingSphere.clone():null})),this._instanceInfo=t._instanceInfo.map(t=>({...t})),this._availableInstanceIds=t._availableInstanceIds.slice(),this._availableGeometryIds=t._availableGeometryIds.slice(),this._nextIndexStart=t._nextIndexStart,this._nextVertexStart=t._nextVertexStart,this._geometryCount=t._geometryCount,this._maxInstanceCount=t._maxInstanceCount,this._maxVertexCount=t._maxVertexCount,this._maxIndexCount=t._maxIndexCount,this._geometryInitialized=t._geometryInitialized,this._multiDrawCounts=t._multiDrawCounts.slice(),this._multiDrawStarts=t._multiDrawStarts.slice(),this._indirectTexture=t._indirectTexture.clone(),this._indirectTexture.image.data=this._indirectTexture.image.data.slice(),this._matricesTexture=t._matricesTexture.clone(),this._matricesTexture.image.data=this._matricesTexture.image.data.slice(),null!==this._colorsTexture&&(this._colorsTexture=t._colorsTexture.clone(),this._colorsTexture.image.data=this._colorsTexture.image.data.slice()),this}dispose(){this.geometry.dispose(),this._matricesTexture.dispose(),this._matricesTexture=null,this._indirectTexture.dispose(),this._indirectTexture=null,null!==this._colorsTexture&&(this._colorsTexture.dispose(),this._colorsTexture=null)}onBeforeRender(t,e,s,i,r){if(!this._visibilityChanged&&!this.perObjectFrustumCulled&&!this.sortObjects)return;const n=i.getIndex();let a=null===n?1:n.array.BYTES_PER_ELEMENT,o=1;r.wireframe&&(o=2,a=i.attributes.position.count>65535?4:2);const h=this._instanceInfo,l=this._multiDrawStarts,c=this._multiDrawCounts,u=this._geometryInfo,d=this.perObjectFrustumCulled,p=this._indirectTexture,m=p.image.data,y=s.isArrayCamera?_o:So;d&&(s.isArrayCamera?y.setFromArrayCamera(s):(wo.multiplyMatrices(s.projectionMatrix,s.matrixWorldInverse).multiply(this.matrixWorld),y.setFromProjectionMatrix(wo,s.coordinateSystem,s.reversedDepth)));let g=0;if(this.sortObjects){wo.copy(this.matrixWorld).invert(),zo.setFromMatrixPosition(s.matrixWorld).applyMatrix4(wo),Co.set(0,0,-1).transformDirection(s.matrixWorld).transformDirection(wo);for(let t=0,e=h.length;t0){const s=t[e[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=s.length;ti)return;jo.applyMatrix4(t.matrixWorld);const h=e.ray.origin.distanceTo(jo);return he.far?void 0:{distance:h,point:Wo.clone().applyMatrix4(t.matrixWorld),index:a,face:null,faceIndex:null,barycoord:null,object:t}}const Ho=new Ti,Xo=new Ti;class Yo extends Jo{constructor(t,e){super(t,e),this.isLineSegments=!0,this.type="LineSegments"}computeLineDistances(){const t=this.geometry;if(null===t.index){const e=t.attributes.position,s=[];for(let t=0,i=e.count;t0){const s=t[e[0]];if(void 0!==s){this.morphTargetInfluences=[],this.morphTargetDictionary={};for(let t=0,e=s.length;tr.far)return;n.push({distance:h,distanceToRay:Math.sqrt(o),point:s,index:e,face:null,faceIndex:null,barycoord:null,object:a})}}class ih extends Ji{constructor(t,e,s,i,r=1006,n=1006,a,o,h){super(t,e,s,i,r,n,a,o,h),this.isVideoTexture=!0,this.generateMipmaps=!1,this._requestVideoFrameCallbackId=0;const l=this;"requestVideoFrameCallback"in t&&(this._requestVideoFrameCallbackId=t.requestVideoFrameCallback(function e(){l.needsUpdate=!0,l._requestVideoFrameCallbackId=t.requestVideoFrameCallback(e)}))}clone(){return new this.constructor(this.image).copy(this)}update(){const t=this.image;!1==="requestVideoFrameCallback"in t&&t.readyState>=t.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}dispose(){0!==this._requestVideoFrameCallbackId&&(this.source.data.cancelVideoFrameCallback(this._requestVideoFrameCallbackId),this._requestVideoFrameCallbackId=0),super.dispose()}}class rh extends ih{constructor(t,e,s,i,r,n,a,o){super({},t,e,s,i,r,n,a,o),this.isVideoFrameTexture=!0}update(){}clone(){return(new this.constructor).copy(this)}setFrame(t){this.image=t,this.needsUpdate=!0}}class nh extends Ji{constructor(t,e){super({width:t,height:e}),this.isFramebufferTexture=!0,this.magFilter=ft,this.minFilter=ft,this.generateMipmaps=!1,this.needsUpdate=!0}}class ah extends Ji{constructor(t,e,s,i,r,n,a,o,h,l,c,u){super(null,n,a,o,h,l,i,r,c,u),this.isCompressedTexture=!0,this.image={width:e,height:s},this.mipmaps=t,this.flipY=!1,this.generateMipmaps=!1}}class oh extends ah{constructor(t,e,s,i,r,n){super(t,e,s,r,n),this.isCompressedArrayTexture=!0,this.image.depth=i,this.wrapR=yt,this.layerUpdates=new Set}addLayerUpdate(t){this.layerUpdates.add(t)}clearLayerUpdates(){this.layerUpdates.clear()}}class hh extends ah{constructor(t,e,s){super(void 0,t[0].width,t[0].height,e,s,lt),this.isCompressedCubeTexture=!0,this.isCubeTexture=!0,this.image=t}}class lh extends Ji{constructor(t=[],e=301,s,i,r,n,a,o,h,l){super(t,e,s,i,r,n,a,o,h,l),this.isCubeTexture=!0,this.flipY=!1}get images(){return this.image}set images(t){this.image=t}}class ch extends Ji{constructor(t,e,s,i,r,n,a,o,h){super(t,e,s,i,r,n,a,o,h),this.isCanvasTexture=!0,this.needsUpdate=!0}}class uh extends Ji{constructor(t,e,s,i,r,n,a,o,h){super(t,e,s,i,r,n,a,o,h),this.isHTMLTexture=!0,this.generateMipmaps=!1,this.needsUpdate=!0;const l=t?t.parentNode:null;null!==l&&"requestPaint"in l&&(l.onpaint=()=>{this.needsUpdate=!0},l.requestPaint())}dispose(){const t=this.image?this.image.parentNode:null;null!==t&&"onpaint"in t&&(t.onpaint=null),super.dispose()}}class dh extends Ji{constructor(t,e,s=1014,i,r,n,a=1003,o=1003,h,l=1026,c=1){if(l!==Wt&&1027!==l)throw new Error("THREE.DepthTexture: format must be either THREE.DepthFormat or THREE.DepthStencilFormat");super({width:t,height:e,depth:c},i,r,n,a,o,l,s,h),this.isDepthTexture=!0,this.flipY=!1,this.generateMipmaps=!1,this.compareFunction=null}copy(t){return super.copy(t),this.source=new Di(Object.assign({},t.image)),this.compareFunction=t.compareFunction,this}toJSON(t){const e=super.toJSON(t);return null!==this.compareFunction&&(e.compareFunction=this.compareFunction),e}}class ph extends dh{constructor(t,e=1014,s=301,i,r,n=1003,a=1003,o,h=1026){const l={width:t,height:t,depth:1},c=[l,l,l,l,l,l];super(t,t,e,s,i,r,n,a,o,h),this.image=c,this.isCubeDepthTexture=!0,this.isCubeTexture=!0}get images(){return this.image}set images(t){this.image=t}}class mh extends Ji{constructor(t=null){super(),this.sourceTexture=t,this.isExternalTexture=!0}copy(t){return super.copy(t),this.sourceTexture=t.sourceTexture,this}}class yh extends Wn{constructor(t=1,e=1,s=1,i=1,r=1,n=1){super(),this.type="BoxGeometry",this.parameters={width:t,height:e,depth:s,widthSegments:i,heightSegments:r,depthSegments:n};const a=this;i=Math.floor(i),r=Math.floor(r),n=Math.floor(n);const o=[],h=[],l=[],c=[];let u=0,d=0;function p(t,e,s,i,r,n,p,m,y,g,f){const x=n/y,b=p/g,v=n/2,w=p/2,M=m/2,S=y+1,_=g+1;let A=0,T=0;const z=new Ti;for(let n=0;n<_;n++){const a=n*b-w;for(let o=0;o0?1:-1,l.push(z.x,z.y,z.z),c.push(o/y),c.push(1-n/g),A+=1}}for(let t=0;t0){const t=(f-1)*m;for(let e=0;e0||0!==i)&&(l.push(n,a,h),x+=3),(e>0||i!==r-1)&&(l.push(a,o,h),x+=3)}h.addGroup(g,x,0),g+=x}(),!1===n&&(t>0&&f(!0),e>0&&f(!1)),this.setIndex(l),this.setAttribute("position",new kn(c,3)),this.setAttribute("normal",new kn(u,3)),this.setAttribute("uv",new kn(d,2))}copy(t){return super.copy(t),this.parameters=Object.assign({},t.parameters),this}static fromJSON(t){return new xh(t.radiusTop,t.radiusBottom,t.height,t.radialSegments,t.heightSegments,t.openEnded,t.thetaStart,t.thetaLength)}}class bh extends xh{constructor(t=1,e=1,s=32,i=1,r=!1,n=0,a=2*Math.PI){super(0,t,e,s,i,r,n,a),this.type="ConeGeometry",this.parameters={radius:t,height:e,radialSegments:s,heightSegments:i,openEnded:r,thetaStart:n,thetaLength:a}}static fromJSON(t){return new bh(t.radius,t.height,t.radialSegments,t.heightSegments,t.openEnded,t.thetaStart,t.thetaLength)}}class vh extends Wn{constructor(t=[],e=[],s=1,i=0){super(),this.type="PolyhedronGeometry",this.parameters={vertices:t,indices:e,radius:s,detail:i};const r=[],n=[];function a(t,e,s,i){const r=i+1,n=[];for(let i=0;i<=r;i++){n[i]=[];const a=t.clone().lerp(s,i/r),o=e.clone().lerp(s,i/r),h=r-i;for(let t=0;t<=h;t++)n[i][t]=0===t&&i===r?a:a.clone().lerp(o,t/h)}for(let t=0;t.9&&a<.1&&(e<.2&&(n[t+0]+=1),s<.2&&(n[t+2]+=1),i<.2&&(n[t+4]+=1))}}()}(),this.setAttribute("position",new kn(r,3)),this.setAttribute("normal",new kn(r.slice(),3)),this.setAttribute("uv",new kn(n,2)),0===i?this.computeVertexNormals():this.normalizeNormals()}copy(t){return super.copy(t),this.parameters=Object.assign({},t.parameters),this}static fromJSON(t){return new vh(t.vertices,t.indices,t.radius,t.detail)}}class wh extends vh{constructor(t=1,e=0){const s=(1+Math.sqrt(5))/2,i=1/s;super([-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-i,-s,0,-i,s,0,i,-s,0,i,s,-i,-s,0,-i,s,0,i,-s,0,i,s,0,-s,0,-i,s,0,-i,-s,0,i,s,0,i],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],t,e),this.type="DodecahedronGeometry",this.parameters={radius:t,detail:e}}static fromJSON(t){return new wh(t.radius,t.detail)}}const Mh=new Ti,Sh=new Ti,_h=new Ti,Ah=new $r;class Th extends Wn{constructor(t=null,e=1){if(super(),this.type="EdgesGeometry",this.parameters={geometry:t,thresholdAngle:e},null!==t){const s=4,i=Math.pow(10,s),r=Math.cos(yi*e),n=t.getIndex(),a=t.getAttribute("position"),o=n?n.count:a.count,h=[0,0,0],l=["a","b","c"],c=new Array(3),u={},d=[];for(let t=0;t0)){h=i;break}h=i-1}if(i=h,s[i]===n)return i/(r-1);const l=s[i];return(i+(n-l)/(s[i+1]-l))/(r-1)}getTangent(t,e){const s=1e-4;let i=t-s,r=t+s;i<0&&(i=0),r>1&&(r=1);const n=this.getPoint(i),a=this.getPoint(r),o=e||(n.isVector2?new _i:new Ti);return o.copy(a).sub(n).normalize(),o}getTangentAt(t,e){const s=this.getUtoTmapping(t);return this.getTangent(s,e)}computeFrenetFrames(t,e=!1){const s=new Ti,i=[],r=[],n=[],a=new Ti,o=new Qi;for(let e=0;e<=t;e++){const s=e/t;i[e]=this.getTangentAt(s,new Ti)}r[0]=new Ti,n[0]=new Ti;let h=Number.MAX_VALUE;const l=Math.abs(i[0].x),c=Math.abs(i[0].y),u=Math.abs(i[0].z);l<=h&&(h=l,s.set(1,0,0)),c<=h&&(h=c,s.set(0,1,0)),u<=h&&s.set(0,0,1),a.crossVectors(i[0],s).normalize(),r[0].crossVectors(i[0],a),n[0].crossVectors(i[0],r[0]);for(let e=1;e<=t;e++){if(r[e]=r[e-1].clone(),n[e]=n[e-1].clone(),a.crossVectors(i[e-1],i[e]),a.length()>Number.EPSILON){a.normalize();const t=Math.acos(xi(i[e-1].dot(i[e]),-1,1));r[e].applyMatrix4(o.makeRotationAxis(a,t))}n[e].crossVectors(i[e],r[e])}if(!0===e){let e=Math.acos(xi(r[0].dot(r[t]),-1,1));e/=t,i[0].dot(a.crossVectors(r[0],r[t]))>0&&(e=-e);for(let s=1;s<=t;s++)r[s].applyMatrix4(o.makeRotationAxis(i[s],e*s)),n[s].crossVectors(i[s],r[s])}return{tangents:i,normals:r,binormals:n}}clone(){return(new this.constructor).copy(this)}copy(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}toJSON(){const t={metadata:{version:4.7,type:"Curve",generator:"Curve.toJSON"}};return t.arcLengthDivisions=this.arcLengthDivisions,t.type=this.type,t}fromJSON(t){return this.arcLengthDivisions=t.arcLengthDivisions,this}}class Ch extends zh{constructor(t=0,e=0,s=1,i=1,r=0,n=2*Math.PI,a=!1,o=0){super(),this.isEllipseCurve=!0,this.type="EllipseCurve",this.aX=t,this.aY=e,this.xRadius=s,this.yRadius=i,this.aStartAngle=r,this.aEndAngle=n,this.aClockwise=a,this.aRotation=o}getPoint(t,e=new _i){const s=e,i=2*Math.PI;let r=this.aEndAngle-this.aStartAngle;const n=Math.abs(r)i;)r-=i;r0?0:(Math.floor(Math.abs(h)/r)+1)*r:0===l&&h===r-1&&(h=r-2,l=1),this.closed||h>0?a=i[(h-1)%r]:(Oh.subVectors(i[0],i[1]).add(i[0]),a=Oh);const c=i[h%r],u=i[(h+1)%r];if(this.closed||h+2i.length-2?i.length-1:n+1],c=i[n>i.length-3?i.length-1:n+2];return s.set(Vh(a,o.x,h.x,l.x,c.x),Vh(a,o.y,h.y,l.y,c.y)),s}copy(t){super.copy(t),this.points=[];for(let e=0,s=t.points.length;e=s){const t=i[r]-s,n=this.curves[r],a=n.getLength(),o=0===a?0:1-t/a;return n.getPointAt(o,e)}r++}return null}getLength(){const t=this.getCurveLengths();return t[t.length-1]}updateArcLengths(){this.needsUpdate=!0,this.cacheLengths=null,this.getCurveLengths()}getCurveLengths(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;const t=[];let e=0;for(let s=0,i=this.curves.length;s1&&!e[e.length-1].equals(e[0])&&e.push(e[0]),e}copy(t){super.copy(t),this.curves=[];for(let e=0,s=t.curves.length;e0){const t=h.getPoint(0);t.equals(this.currentPoint)||this.lineTo(t.x,t.y)}this.curves.push(h);const l=h.getPoint(1);return this.currentPoint.copy(l),this}copy(t){return super.copy(t),this.currentPoint.copy(t.currentPoint),this}toJSON(){const t=super.toJSON();return t.currentPoint=this.currentPoint.toArray(),t}fromJSON(t){return super.fromJSON(t),this.currentPoint.fromArray(t.currentPoint),this}}class Gh extends Zh{constructor(t){super(t),this.uuid=fi(),this.type="Shape",this.holes=[]}getPointsHoles(t){const e=[];for(let s=0,i=this.holes.length;s80*s){o=t[0],h=t[1];let e=o,i=h;for(let n=s;ne&&(e=s),r>i&&(i=r)}l=Math.max(e-o,i-h),l=0!==l?32767/l:0}return tl(n,a,s,o,h,l,0),a}function Qh(t,e,s,i,r){let n;if(r===function(t,e,s,i){let r=0;for(let n=e,a=s-i;n0)for(let r=e;r=e;r-=i)n=vl(r/i|0,t[r],t[r+1],n);return n&&ml(n,n.next)&&(wl(n),n=n.next),n}function Kh(t,e){if(!t)return t;e||(e=t);let s,i=t;do{if(s=!1,i.steiner||!ml(i,i.next)&&0!==pl(i.prev,i,i.next))i=i.next;else{if(wl(i),i=e=i.prev,i===i.next)break;s=!0}}while(s||i!==e);return e}function tl(t,e,s,i,r,n,a){if(!t)return;!a&&n&&function(t,e,s,i){let r=t;do{0===r.z&&(r.z=hl(r.x,r.y,e,s,i)),r.prevZ=r.prev,r.nextZ=r.next,r=r.next}while(r!==t);r.prevZ.nextZ=null,r.prevZ=null,function(t){let e,s=1;do{let i,r=t;t=null;let n=null;for(e=0;r;){e++;let a=r,o=0;for(let t=0;t0||h>0&&a;)0!==o&&(0===h||!a||r.z<=a.z)?(i=r,r=r.nextZ,o--):(i=a,a=a.nextZ,h--),n?n.nextZ=i:t=i,i.prevZ=n,n=i;r=a}n.nextZ=null,s*=2}while(e>1)}(r)}(t,i,r,n);let o=t;for(;t.prev!==t.next;){const h=t.prev,l=t.next;if(n?sl(t,i,r,n):el(t))e.push(h.i,t.i,l.i),wl(t),t=l.next,o=l.next;else if((t=l)===o){a?1===a?tl(t=il(Kh(t),e),e,s,i,r,n,2):2===a&&rl(t,e,s,i,r,n):tl(Kh(t),e,s,i,r,n,1);break}}}function el(t){const e=t.prev,s=t,i=t.next;if(pl(e,s,i)>=0)return!1;const r=e.x,n=s.x,a=i.x,o=e.y,h=s.y,l=i.y,c=Math.min(r,n,a),u=Math.min(o,h,l),d=Math.max(r,n,a),p=Math.max(o,h,l);let m=i.next;for(;m!==e;){if(m.x>=c&&m.x<=d&&m.y>=u&&m.y<=p&&ul(r,o,n,h,a,l,m.x,m.y)&&pl(m.prev,m,m.next)>=0)return!1;m=m.next}return!0}function sl(t,e,s,i){const r=t.prev,n=t,a=t.next;if(pl(r,n,a)>=0)return!1;const o=r.x,h=n.x,l=a.x,c=r.y,u=n.y,d=a.y,p=Math.min(o,h,l),m=Math.min(c,u,d),y=Math.max(o,h,l),g=Math.max(c,u,d),f=hl(p,m,e,s,i),x=hl(y,g,e,s,i);let b=t.prevZ,v=t.nextZ;for(;b&&b.z>=f&&v&&v.z<=x;){if(b.x>=p&&b.x<=y&&b.y>=m&&b.y<=g&&b!==r&&b!==a&&ul(o,c,h,u,l,d,b.x,b.y)&&pl(b.prev,b,b.next)>=0)return!1;if(b=b.prevZ,v.x>=p&&v.x<=y&&v.y>=m&&v.y<=g&&v!==r&&v!==a&&ul(o,c,h,u,l,d,v.x,v.y)&&pl(v.prev,v,v.next)>=0)return!1;v=v.nextZ}for(;b&&b.z>=f;){if(b.x>=p&&b.x<=y&&b.y>=m&&b.y<=g&&b!==r&&b!==a&&ul(o,c,h,u,l,d,b.x,b.y)&&pl(b.prev,b,b.next)>=0)return!1;b=b.prevZ}for(;v&&v.z<=x;){if(v.x>=p&&v.x<=y&&v.y>=m&&v.y<=g&&v!==r&&v!==a&&ul(o,c,h,u,l,d,v.x,v.y)&&pl(v.prev,v,v.next)>=0)return!1;v=v.nextZ}return!0}function il(t,e){let s=t;do{const i=s.prev,r=s.next.next;!ml(i,r)&&yl(i,s,s.next,r)&&xl(i,r)&&xl(r,i)&&(e.push(i.i,s.i,r.i),wl(s),wl(s.next),s=t=r),s=s.next}while(s!==t);return Kh(s)}function rl(t,e,s,i,r,n){let a=t;do{let t=a.next.next;for(;t!==a.prev;){if(a.i!==t.i&&dl(a,t)){let o=bl(a,t);return a=Kh(a,a.next),o=Kh(o,o.next),tl(a,e,s,i,r,n,0),void tl(o,e,s,i,r,n,0)}t=t.next}a=a.next}while(a!==t)}function nl(t,e){let s=t.x-e.x;if(0===s&&(s=t.y-e.y,0===s)){s=(t.next.y-t.y)/(t.next.x-t.x)-(e.next.y-e.y)/(e.next.x-e.x)}return s}function al(t,e){const s=function(t,e){let s=e;const i=t.x,r=t.y;let n,a=-1/0;if(ml(t,s))return s;do{if(ml(t,s.next))return s.next;if(r<=s.y&&r>=s.next.y&&s.next.y!==s.y){const t=s.x+(r-s.y)*(s.next.x-s.x)/(s.next.y-s.y);if(t<=i&&t>a&&(a=t,n=s.x=s.x&&s.x>=h&&i!==s.x&&cl(rn.x||s.x===n.x&&ol(n,s)))&&(n=s,c=e)}s=s.next}while(s!==o);return n}(t,e);if(!s)return e;const i=bl(s,t);return Kh(i,i.next),Kh(s,s.next)}function ol(t,e){return pl(t.prev,t,e.prev)<0&&pl(e.next,t,t.next)<0}function hl(t,e,s,i,r){return(t=1431655765&((t=858993459&((t=252645135&((t=16711935&((t=(t-s)*r|0)|t<<8))|t<<4))|t<<2))|t<<1))|(e=1431655765&((e=858993459&((e=252645135&((e=16711935&((e=(e-i)*r|0)|e<<8))|e<<4))|e<<2))|e<<1))<<1}function ll(t){let e=t,s=t;do{(e.x=(t-a)*(n-o)&&(t-a)*(i-o)>=(s-a)*(e-o)&&(s-a)*(n-o)>=(r-a)*(i-o)}function ul(t,e,s,i,r,n,a,o){return!(t===a&&e===o)&&cl(t,e,s,i,r,n,a,o)}function dl(t,e){return t.next.i!==e.i&&t.prev.i!==e.i&&!function(t,e){let s=t;do{if(s.i!==t.i&&s.next.i!==t.i&&s.i!==e.i&&s.next.i!==e.i&&yl(s,s.next,t,e))return!0;s=s.next}while(s!==t);return!1}(t,e)&&(xl(t,e)&&xl(e,t)&&function(t,e){let s=t,i=!1;const r=(t.x+e.x)/2,n=(t.y+e.y)/2;do{s.y>n!=s.next.y>n&&s.next.y!==s.y&&r<(s.next.x-s.x)*(n-s.y)/(s.next.y-s.y)+s.x&&(i=!i),s=s.next}while(s!==t);return i}(t,e)&&(pl(t.prev,t,e.prev)||pl(t,e.prev,e))||ml(t,e)&&pl(t.prev,t,t.next)>0&&pl(e.prev,e,e.next)>0)}function pl(t,e,s){return(e.y-t.y)*(s.x-e.x)-(e.x-t.x)*(s.y-e.y)}function ml(t,e){return t.x===e.x&&t.y===e.y}function yl(t,e,s,i){const r=fl(pl(t,e,s)),n=fl(pl(t,e,i)),a=fl(pl(s,i,t)),o=fl(pl(s,i,e));return r!==n&&a!==o||(!(0!==r||!gl(t,s,e))||(!(0!==n||!gl(t,i,e))||(!(0!==a||!gl(s,t,i))||!(0!==o||!gl(s,e,i)))))}function gl(t,e,s){return e.x<=Math.max(t.x,s.x)&&e.x>=Math.min(t.x,s.x)&&e.y<=Math.max(t.y,s.y)&&e.y>=Math.min(t.y,s.y)}function fl(t){return t>0?1:t<0?-1:0}function xl(t,e){return pl(t.prev,t,t.next)<0?pl(t,e,t.next)>=0&&pl(t,t.prev,e)>=0:pl(t,e,t.prev)<0||pl(t,t.next,e)<0}function bl(t,e){const s=Ml(t.i,t.x,t.y),i=Ml(e.i,e.x,e.y),r=t.next,n=e.prev;return t.next=e,e.prev=t,s.next=r,r.prev=s,i.next=s,s.prev=i,n.next=i,i.prev=n,i}function vl(t,e,s,i){const r=Ml(t,e,s);return i?(r.next=i.next,r.prev=i,i.next.prev=r,i.next=r):(r.prev=r,r.next=r),r}function wl(t){t.next.prev=t.prev,t.prev.next=t.next,t.prevZ&&(t.prevZ.nextZ=t.nextZ),t.nextZ&&(t.nextZ.prevZ=t.prevZ)}function Ml(t,e,s){return{i:t,x:e,y:s,prev:null,next:null,z:0,prevZ:null,nextZ:null,steiner:!1}}class Sl{static triangulate(t,e,s=2){return $h(t,e,s)}}class _l{static area(t){const e=t.length;let s=0;for(let i=e-1,r=0;r2&&t[e-1].equals(t[0])&&t.pop()}function Tl(t,e){for(let s=0;sNumber.EPSILON){const u=Math.sqrt(c),d=Math.sqrt(h*h+l*l),p=e.x-o/u,m=e.y+a/u,y=((s.x-l/d-p)*l-(s.y+h/d-m)*h)/(a*l-o*h);i=p+a*y-t.x,r=m+o*y-t.y;const g=i*i+r*r;if(g<=2)return new _i(i,r);n=Math.sqrt(g/2)}else{let t=!1;a>Number.EPSILON?h>Number.EPSILON&&(t=!0):a<-Number.EPSILON?h<-Number.EPSILON&&(t=!0):Math.sign(o)===Math.sign(l)&&(t=!0),t?(i=-o,r=a,n=Math.sqrt(c)):(i=a,r=o,n=Math.sqrt(c/2))}return new _i(i/n,r/n)}const k=[];for(let t=0,e=z.length,s=e-1,i=t+1;t=0;t--){const e=t/p,s=c*Math.cos(e*Math.PI/2),i=u*Math.sin(e*Math.PI/2)+d;for(let t=0,e=z.length;t=0;){const i=s;let r=s-1;r<0&&(r=t.length-1);for(let t=0,s=o+2*p;t0)&&d.push(e,r,h),(t!==s-1||o0&&(e.defines=this.defines),e.vertexShader=this.vertexShader,e.fragmentShader=this.fragmentShader,e.lights=this.lights,e.clipping=this.clipping;const s={};for(const t in this.extensions)!0===this.extensions[t]&&(s[t]=!0);return Object.keys(s).length>0&&(e.extensions=s),e}fromJSON(t,e){if(super.fromJSON(t,e),void 0!==t.uniforms)for(const s in t.uniforms){const i=t.uniforms[s];switch(this.uniforms[s]={},i.type){case"t":this.uniforms[s].value=e[i.value]||null;break;case"c":this.uniforms[s].value=(new Pr).setHex(i.value);break;case"v2":this.uniforms[s].value=(new _i).fromArray(i.value);break;case"v3":this.uniforms[s].value=(new Ti).fromArray(i.value);break;case"v4":this.uniforms[s].value=(new qi).fromArray(i.value);break;case"m3":this.uniforms[s].value=(new Ii).fromArray(i.value);break;case"m4":this.uniforms[s].value=(new Qi).fromArray(i.value);break;default:this.uniforms[s].value=i.value}}if(void 0!==t.defines&&(this.defines=t.defines),void 0!==t.vertexShader&&(this.vertexShader=t.vertexShader),void 0!==t.fragmentShader&&(this.fragmentShader=t.fragmentShader),void 0!==t.glslVersion&&(this.glslVersion=t.glslVersion),void 0!==t.extensions)for(const e in t.extensions)this.extensions[e]=t.extensions[e];return void 0!==t.lights&&(this.lights=t.lights),void 0!==t.clipping&&(this.clipping=t.clipping),this}}class Gl extends Zl{constructor(t){super(t),this.isRawShaderMaterial=!0,this.type="RawShaderMaterial"}}class $l extends Zn{constructor(t){super(),this.isMeshStandardMaterial=!0,this.type="MeshStandardMaterial",this.defines={STANDARD:""},this.color=new Pr(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 Pr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new _i(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 hr,this.envMapIntensity=1,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.defines={STANDARD:""},this.color.copy(t.color),this.roughness=t.roughness,this.metalness=t.metalness,this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.roughnessMap=t.roughnessMap,this.metalnessMap=t.metalnessMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.envMapRotation.copy(t.envMapRotation),this.envMapIntensity=t.envMapIntensity,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.flatShading=t.flatShading,this.fog=t.fog,this}}class Ql extends $l{constructor(t){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 _i(1,1),this.clearcoatNormalMap=null,this.ior=1.5,Object.defineProperty(this,"reflectivity",{get:function(){return xi(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 Pr(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 Pr(1,1,1),this.specularIntensity=1,this.specularIntensityMap=null,this.specularColor=new Pr(1,1,1),this.specularColorMap=null,this._anisotropy=0,this._clearcoat=0,this._dispersion=0,this._iridescence=0,this._sheen=0,this._transmission=0,this.setValues(t)}get anisotropy(){return this._anisotropy}set anisotropy(t){this._anisotropy>0!=t>0&&this.version++,this._anisotropy=t}get clearcoat(){return this._clearcoat}set clearcoat(t){this._clearcoat>0!=t>0&&this.version++,this._clearcoat=t}get iridescence(){return this._iridescence}set iridescence(t){this._iridescence>0!=t>0&&this.version++,this._iridescence=t}get dispersion(){return this._dispersion}set dispersion(t){this._dispersion>0!=t>0&&this.version++,this._dispersion=t}get sheen(){return this._sheen}set sheen(t){this._sheen>0!=t>0&&this.version++,this._sheen=t}get transmission(){return this._transmission}set transmission(t){this._transmission>0!=t>0&&this.version++,this._transmission=t}copy(t){return super.copy(t),this.defines={STANDARD:"",PHYSICAL:""},this.anisotropy=t.anisotropy,this.anisotropyRotation=t.anisotropyRotation,this.anisotropyMap=t.anisotropyMap,this.clearcoat=t.clearcoat,this.clearcoatMap=t.clearcoatMap,this.clearcoatRoughness=t.clearcoatRoughness,this.clearcoatRoughnessMap=t.clearcoatRoughnessMap,this.clearcoatNormalMap=t.clearcoatNormalMap,this.clearcoatNormalScale.copy(t.clearcoatNormalScale),this.dispersion=t.dispersion,this.ior=t.ior,this.iridescence=t.iridescence,this.iridescenceMap=t.iridescenceMap,this.iridescenceIOR=t.iridescenceIOR,this.iridescenceThicknessRange=[...t.iridescenceThicknessRange],this.iridescenceThicknessMap=t.iridescenceThicknessMap,this.sheen=t.sheen,this.sheenColor.copy(t.sheenColor),this.sheenColorMap=t.sheenColorMap,this.sheenRoughness=t.sheenRoughness,this.sheenRoughnessMap=t.sheenRoughnessMap,this.transmission=t.transmission,this.transmissionMap=t.transmissionMap,this.thickness=t.thickness,this.thicknessMap=t.thicknessMap,this.attenuationDistance=t.attenuationDistance,this.attenuationColor.copy(t.attenuationColor),this.specularIntensity=t.specularIntensity,this.specularIntensityMap=t.specularIntensityMap,this.specularColor.copy(t.specularColor),this.specularColorMap=t.specularColorMap,this}}class Kl extends Zn{constructor(t){super(),this.isMeshPhongMaterial=!0,this.type="MeshPhongMaterial",this.color=new Pr(16777215),this.specular=new Pr(1118481),this.shininess=30,this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Pr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new _i(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new hr,this.combine=0,this.reflectivity=1,this.envMapIntensity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.specular.copy(t.specular),this.shininess=t.shininess,this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.envMapRotation.copy(t.envMapRotation),this.combine=t.combine,this.reflectivity=t.reflectivity,this.envMapIntensity=t.envMapIntensity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.flatShading=t.flatShading,this.fog=t.fog,this}}class tc extends Zn{constructor(t){super(),this.isMeshToonMaterial=!0,this.defines={TOON:""},this.type="MeshToonMaterial",this.color=new Pr(16777215),this.map=null,this.gradientMap=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Pr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new _i(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.gradientMap=t.gradientMap,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.alphaMap=t.alphaMap,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.fog=t.fog,this}}class ec extends Zn{constructor(t){super(),this.isMeshNormalMaterial=!0,this.type="MeshNormalMaterial",this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new _i(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.flatShading=!1,this.setValues(t)}copy(t){return super.copy(t),this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.flatShading=t.flatShading,this}}class sc extends Zn{constructor(t){super(),this.isMeshLambertMaterial=!0,this.type="MeshLambertMaterial",this.color=new Pr(16777215),this.map=null,this.lightMap=null,this.lightMapIntensity=1,this.aoMap=null,this.aoMapIntensity=1,this.emissive=new Pr(0),this.emissiveIntensity=1,this.emissiveMap=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new _i(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.specularMap=null,this.alphaMap=null,this.envMap=null,this.envMapRotation=new hr,this.combine=0,this.reflectivity=1,this.envMapIntensity=1,this.refractionRatio=.98,this.wireframe=!1,this.wireframeLinewidth=1,this.wireframeLinecap="round",this.wireframeLinejoin="round",this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.color.copy(t.color),this.map=t.map,this.lightMap=t.lightMap,this.lightMapIntensity=t.lightMapIntensity,this.aoMap=t.aoMap,this.aoMapIntensity=t.aoMapIntensity,this.emissive.copy(t.emissive),this.emissiveMap=t.emissiveMap,this.emissiveIntensity=t.emissiveIntensity,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.specularMap=t.specularMap,this.alphaMap=t.alphaMap,this.envMap=t.envMap,this.envMapRotation.copy(t.envMapRotation),this.combine=t.combine,this.reflectivity=t.reflectivity,this.envMapIntensity=t.envMapIntensity,this.refractionRatio=t.refractionRatio,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.wireframeLinecap=t.wireframeLinecap,this.wireframeLinejoin=t.wireframeLinejoin,this.flatShading=t.flatShading,this.fog=t.fog,this}}class ic extends Zn{constructor(t){super(),this.isMeshDepthMaterial=!0,this.type="MeshDepthMaterial",this.depthPacking=3200,this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.wireframe=!1,this.wireframeLinewidth=1,this.setValues(t)}copy(t){return super.copy(t),this.depthPacking=t.depthPacking,this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this}}class rc extends Zn{constructor(t){super(),this.isMeshDistanceMaterial=!0,this.type="MeshDistanceMaterial",this.map=null,this.alphaMap=null,this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.setValues(t)}copy(t){return super.copy(t),this.map=t.map,this.alphaMap=t.alphaMap,this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this}}class nc extends Zn{constructor(t){super(),this.isMeshMatcapMaterial=!0,this.defines={MATCAP:""},this.type="MeshMatcapMaterial",this.color=new Pr(16777215),this.matcap=null,this.map=null,this.bumpMap=null,this.bumpScale=1,this.normalMap=null,this.normalMapType=0,this.normalScale=new _i(1,1),this.displacementMap=null,this.displacementScale=1,this.displacementBias=0,this.alphaMap=null,this.wireframe=!1,this.wireframeLinewidth=1,this.flatShading=!1,this.fog=!0,this.setValues(t)}copy(t){return super.copy(t),this.defines={MATCAP:""},this.color.copy(t.color),this.matcap=t.matcap,this.map=t.map,this.bumpMap=t.bumpMap,this.bumpScale=t.bumpScale,this.normalMap=t.normalMap,this.normalMapType=t.normalMapType,this.normalScale.copy(t.normalScale),this.displacementMap=t.displacementMap,this.displacementScale=t.displacementScale,this.displacementBias=t.displacementBias,this.alphaMap=t.alphaMap,this.wireframe=t.wireframe,this.wireframeLinewidth=t.wireframeLinewidth,this.flatShading=t.flatShading,this.fog=t.fog,this}}class ac extends No{constructor(t){super(),this.isLineDashedMaterial=!0,this.type="LineDashedMaterial",this.scale=1,this.dashSize=3,this.gapSize=1,this.setValues(t)}copy(t){return super.copy(t),this.scale=t.scale,this.dashSize=t.dashSize,this.gapSize=t.gapSize,this}}function oc(t,e){return t&&t.constructor!==e?"number"==typeof e.BYTES_PER_ELEMENT?new e(t):Array.prototype.slice.call(t):t}function hc(t){const e=t.length,s=new Array(e);for(let t=0;t!==e;++t)s[t]=t;return s.sort(function(e,s){return t[e]-t[s]}),s}function lc(t,e,s){const i=t.length,r=new t.constructor(i);for(let n=0,a=0;a!==i;++n){const i=s[n]*e;for(let s=0;s!==e;++s)r[a++]=t[i+s]}return r}function cc(t,e,s,i){let r=1,n=t[0];for(;void 0!==n&&void 0===n[i];)n=t[r++];if(void 0===n)return;let a=n[i];if(void 0!==a)if(Array.isArray(a))do{a=n[i],void 0!==a&&(e.push(n.time),s.push(...a)),n=t[r++]}while(void 0!==n);else if(void 0!==a.toArray)do{a=n[i],void 0!==a&&(e.push(n.time),a.toArray(s,s.length)),n=t[r++]}while(void 0!==n);else do{a=n[i],void 0!==a&&(e.push(n.time),s.push(a)),n=t[r++]}while(void 0!==n)}class uc{static convertArray(t,e){return oc(t,e)}static isTypedArray(t){return $s(t)}static getKeyframeOrder(t){return hc(t)}static sortedArray(t,e,s){return lc(t,e,s)}static flattenJSON(t,e,s,i){cc(t,e,s,i)}static subclip(t,e,s,i,r=30){return function(t,e,s,i,r=30){const n=t.clone();n.name=e;const a=[];for(let t=0;t=i)){h.push(e.times[t]);for(let s=0;sn.tracks[t].times[0]&&(o=n.tracks[t].times[0]);for(let t=0;t=i.times[u]){const t=u*h+o,e=t+h-o;d=i.values.slice(t,e)}else{const t=i.createInterpolant(),e=o,s=h-o;t.evaluate(n),d=t.resultBuffer.slice(e,s)}"quaternion"===r&&(new Ai).fromArray(d).normalize().conjugate().toArray(d);const p=a.times.length;for(let t=0;t=r)){const a=e[1];t=r)break e}n=s,s=0;break s}break t}for(;s>>1;te;)--n;if(++n,0!==r||n!==i){r>=n&&(n=Math.max(n,1),r=n-1);const t=this.getValueSize();this.times=s.slice(r,n),this.values=this.values.slice(r*t,n*t)}return this}validate(){let t=!0;const e=this.getValueSize();e-Math.floor(e)!==0&&(oi("KeyframeTrack: Invalid value size in track.",this),t=!1);const s=this.times,i=this.values,r=s.length;0===r&&(oi("KeyframeTrack: Track is empty.",this),t=!1);let n=null;for(let e=0;e!==r;e++){const i=s[e];if("number"==typeof i&&isNaN(i)){oi("KeyframeTrack: Time is not a valid number.",this,e,i),t=!1;break}if(null!==n&&n>i){oi("KeyframeTrack: Out of order keys.",this,e,i,n),t=!1;break}n=i}if(void 0!==i&&$s(i))for(let e=0,s=i.length;e!==s;++e){const s=i[e];if(isNaN(s)){oi("KeyframeTrack: Value is not a valid number.",this,e,s),t=!1;break}}return t}optimize(){const t=this.times.slice(),e=this.values.slice(),s=this.getValueSize(),i=this.getInterpolation()===Le,r=t.length-1;let n=1;for(let a=1;a0){t[n]=t[r];for(let t=r*s,i=n*s,a=0;a!==s;++a)e[i+a]=e[t+a];++n}return n!==t.length?(this.times=t.slice(0,n),this.values=e.slice(0,n*s)):(this.times=t,this.values=e),this}clone(){const t=this.times.slice(),e=this.values.slice(),s=new(0,this.constructor)(this.name,t,e);return s.createInterpolant=this.createInterpolant,s}}fc.prototype.ValueTypeName="",fc.prototype.TimeBufferType=Float32Array,fc.prototype.ValueBufferType=Float32Array,fc.prototype.DefaultInterpolation=Ve;class xc extends fc{constructor(t,e,s){super(t,e,s)}}xc.prototype.ValueTypeName="bool",xc.prototype.ValueBufferType=Array,xc.prototype.DefaultInterpolation=Ne,xc.prototype.InterpolantFactoryMethodLinear=void 0,xc.prototype.InterpolantFactoryMethodSmooth=void 0;class bc extends fc{constructor(t,e,s,i){super(t,e,s,i)}}bc.prototype.ValueTypeName="color";class vc extends fc{constructor(t,e,s,i){super(t,e,s,i)}}vc.prototype.ValueTypeName="number";class wc extends dc{constructor(t,e,s,i){super(t,e,s,i)}interpolate_(t,e,s,i){const r=this.resultBuffer,n=this.sampleValues,a=this.valueSize,o=(s-e)/(i-e);let h=t*a;for(let t=h+a;h!==t;h+=4)Ai.slerpFlat(r,0,n,h-a,n,h,o);return r}}class Mc extends fc{constructor(t,e,s,i){super(t,e,s,i)}InterpolantFactoryMethodLinear(t){return new wc(this.times,this.values,this.getValueSize(),t)}}Mc.prototype.ValueTypeName="quaternion",Mc.prototype.InterpolantFactoryMethodSmooth=void 0;class Sc extends fc{constructor(t,e,s){super(t,e,s)}}Sc.prototype.ValueTypeName="string",Sc.prototype.ValueBufferType=Array,Sc.prototype.DefaultInterpolation=Ne,Sc.prototype.InterpolantFactoryMethodLinear=void 0,Sc.prototype.InterpolantFactoryMethodSmooth=void 0;class _c extends fc{constructor(t,e,s,i){super(t,e,s,i)}}_c.prototype.ValueTypeName="vector";class Ac{constructor(t="",e=-1,s=[],i=2500){this.name=t,this.tracks=s,this.duration=e,this.blendMode=i,this.uuid=fi(),this.userData={},this.duration<0&&this.resetDuration()}static parse(t){const e=[],s=t.tracks,i=1/(t.fps||1);for(let t=0,r=s.length;t!==r;++t)e.push(Tc(s[t]).scale(i));const r=new this(t.name,t.duration,e,t.blendMode);return r.uuid=t.uuid,r.userData=JSON.parse(t.userData||"{}"),r}static toJSON(t){const e=[],s=t.tracks,i={name:t.name,duration:t.duration,tracks:e,uuid:t.uuid,blendMode:t.blendMode,userData:JSON.stringify(t.userData)};for(let t=0,i=s.length;t!==i;++t)e.push(fc.toJSON(s[t]));return i}static CreateFromMorphTargetSequence(t,e,s,i){const r=e.length,n=[];for(let t=0;t1){const t=n[1];let e=i[t];e||(i[t]=e=[]),e.push(s)}}const n=[];for(const t in i)n.push(this.CreateFromMorphTargetSequence(t,i[t],e,s));return n}resetDuration(){let t=0;for(let e=0,s=this.tracks.length;e!==s;++e){const s=this.tracks[e];t=Math.max(t,s.times[s.times.length-1])}return this.duration=t,this}trim(){for(let t=0;t{e&&e(r),this.manager.itemEnd(t)},0);if(void 0!==Oc[t])return void Oc[t].push({onLoad:e,onProgress:s,onError:i});Oc[t]=[],Oc[t].push({onLoad:e,onProgress:s,onError:i});const n=new Request(t,{headers:new Headers(this.requestHeader),credentials:this.withCredentials?"include":"same-origin",signal:"function"==typeof AbortSignal.any?AbortSignal.any([this._abortController.signal,this.manager.abortController.signal]):this._abortController.signal}),a=this.mimeType,o=this.responseType;fetch(n).then(e=>{if(200===e.status||0===e.status){if(0===e.status&&ai("FileLoader: HTTP Status 0 received."),"undefined"==typeof ReadableStream||void 0===e.body||void 0===e.body.getReader)return e;const s=Oc[t],i=e.body.getReader(),r=e.headers.get("X-File-Size")||e.headers.get("Content-Length"),n=r?parseInt(r):0,a=0!==n;let o=0;const h=new ReadableStream({start(t){!function e(){i.read().then(({done:i,value:r})=>{if(i)t.close();else{o+=r.byteLength;const i=new ProgressEvent("progress",{lengthComputable:a,loaded:o,total:n});for(let t=0,e=s.length;t{t.error(e)})}()}});return new Response(h)}throw new Pc(`fetch for "${e.url}" responded with ${e.status}: ${e.statusText}`,e)}).then(t=>{switch(o){case"arraybuffer":return t.arrayBuffer();case"blob":return t.blob();case"document":return t.text().then(t=>(new DOMParser).parseFromString(t,a));case"json":return t.json();default:if(""===a)return t.text();{const e=/charset="?([^;"\s]*)"?/i.exec(a),s=e&&e[1]?e[1].toLowerCase():void 0,i=new TextDecoder(s);return t.arrayBuffer().then(t=>i.decode(t))}}}).then(e=>{zc.add(`file:${t}`,e);const s=Oc[t];delete Oc[t];for(let t=0,i=s.length;t{const s=Oc[t];if(void 0===s)throw this.manager.itemError(t),e;delete Oc[t];for(let t=0,i=s.length;t{this.manager.itemEnd(t)}),this.manager.itemStart(t)}setResponseType(t){return this.responseType=t,this}setMimeType(t){return this.mimeType=t,this}abort(){return this._abortController.abort(),this._abortController=new AbortController,this}}class Ec extends kc{constructor(t){super(t)}load(t,e,s,i){const r=this,n=new Rc(this.manager);n.setPath(this.path),n.setRequestHeader(this.requestHeader),n.setWithCredentials(this.withCredentials),n.load(t,function(s){try{e(r.parse(JSON.parse(s)))}catch(e){i?i(e):oi(e),r.manager.itemError(t)}},s,i)}parse(t){const e=[];for(let s=0;s0){const s=new Ic(e);r=new Lc(s),r.setCrossOrigin(this.crossOrigin);for(let e=0,s=t.length;e0){i=new Lc(this.manager),i.setCrossOrigin(this.crossOrigin);for(let e=0,i=t.length;e{let e=null,s=null;return void 0!==t.boundingBox&&(e=(new Qr).fromJSON(t.boundingBox)),void 0!==t.boundingSphere&&(s=(new En).fromJSON(t.boundingSphere)),{...t,boundingBox:e,boundingSphere:s}}),n._instanceInfo=t.instanceInfo,n._availableInstanceIds=t._availableInstanceIds,n._availableGeometryIds=t._availableGeometryIds,n._nextIndexStart=t.nextIndexStart,n._nextVertexStart=t.nextVertexStart,n._geometryCount=t.geometryCount,n._maxInstanceCount=t.maxInstanceCount,n._maxVertexCount=t.maxVertexCount,n._maxIndexCount=t.maxIndexCount,n._geometryInitialized=t.geometryInitialized,n._matricesTexture=c(t.matricesTexture.uuid),n._indirectTexture=c(t.indirectTexture.uuid),void 0!==t.colorsTexture&&(n._colorsTexture=c(t.colorsTexture.uuid)),void 0!==t.boundingSphere&&(n.boundingSphere=(new En).fromJSON(t.boundingSphere)),void 0!==t.boundingBox&&(n.boundingBox=(new Qr).fromJSON(t.boundingBox));break;case"LOD":n=new pa;break;case"Line":n=new Jo(h(t.geometry),l(t.material));break;case"LineLoop":n=new Zo(h(t.geometry),l(t.material));break;case"LineSegments":n=new Yo(h(t.geometry),l(t.material));break;case"PointCloud":case"Points":n=new eh(h(t.geometry),l(t.material));break;case"Sprite":n=new la(l(t.material));break;case"Group":n=new Tr;break;case"Bone":n=new Ha;break;default:n=new Ar}if(n.uuid=t.uuid,void 0!==t.name&&(n.name=t.name),void 0!==t.matrix?(n.matrix.fromArray(t.matrix),void 0!==t.matrixAutoUpdate&&(n.matrixAutoUpdate=t.matrixAutoUpdate),n.matrixAutoUpdate&&n.matrix.decompose(n.position,n.quaternion,n.scale)):(void 0!==t.position&&n.position.fromArray(t.position),void 0!==t.rotation&&n.rotation.fromArray(t.rotation),void 0!==t.quaternion&&n.quaternion.fromArray(t.quaternion),void 0!==t.scale&&n.scale.fromArray(t.scale)),void 0!==t.up&&n.up.fromArray(t.up),void 0!==t.pivot&&(n.pivot=(new Ti).fromArray(t.pivot)),void 0!==t.morphTargetDictionary&&(n.morphTargetDictionary=Object.assign({},t.morphTargetDictionary)),void 0!==t.morphTargetInfluences&&(n.morphTargetInfluences=t.morphTargetInfluences.slice()),void 0!==t.castShadow&&(n.castShadow=t.castShadow),void 0!==t.receiveShadow&&(n.receiveShadow=t.receiveShadow),t.shadow&&(void 0!==t.shadow.intensity&&(n.shadow.intensity=t.shadow.intensity),void 0!==t.shadow.bias&&(n.shadow.bias=t.shadow.bias),void 0!==t.shadow.normalBias&&(n.shadow.normalBias=t.shadow.normalBias),void 0!==t.shadow.radius&&(n.shadow.radius=t.shadow.radius),void 0!==t.shadow.mapSize&&n.shadow.mapSize.fromArray(t.shadow.mapSize),void 0!==t.shadow.camera&&(n.shadow.camera=this.parseObject(t.shadow.camera))),void 0!==t.visible&&(n.visible=t.visible),void 0!==t.frustumCulled&&(n.frustumCulled=t.frustumCulled),void 0!==t.renderOrder&&(n.renderOrder=t.renderOrder),void 0!==t.static&&(n.static=t.static),void 0!==t.userData&&(n.userData=t.userData),void 0!==t.layers&&(n.layers.mask=t.layers),void 0!==t.children){const a=t.children;for(let t=0;t{!0===Su.has(n)?(i&&i(Su.get(n)),r.manager.itemError(t),r.manager.itemEnd(t)):(e&&e(s),r.manager.itemEnd(t))}):void setTimeout(function(){e&&e(n),r.manager.itemEnd(t)},0);const a={};a.credentials="anonymous"===this.crossOrigin?"same-origin":"include",a.headers=this.requestHeader,a.signal="function"==typeof AbortSignal.any?AbortSignal.any([this._abortController.signal,this.manager.abortController.signal]):this._abortController.signal;const o=fetch(t,a).then(function(t){return t.blob()}).then(function(t){return createImageBitmap(t,Object.assign(r.options,{colorSpaceConversion:"none"}))}).then(function(s){zc.add(`image-bitmap:${t}`,s),e&&e(s),r.manager.itemEnd(t)}).catch(function(e){i&&i(e),Su.set(o,e),zc.remove(`image-bitmap:${t}`),r.manager.itemError(t),r.manager.itemEnd(t)});zc.add(`image-bitmap:${t}`,o),r.manager.itemStart(t)}abort(){return this._abortController.abort(),this._abortController=new AbortController,this}}let Au;class Tu{static getContext(){return void 0===Au&&(Au=new(window.AudioContext||window.webkitAudioContext)),Au}static setContext(t){Au=t}}class zu extends kc{constructor(t){super(t)}load(t,e,s,i){const r=this,n=new Rc(this.manager);function a(e){i?i(e):oi(e),r.manager.itemError(t)}n.setResponseType("arraybuffer"),n.setPath(this.path),n.setRequestHeader(this.requestHeader),n.setWithCredentials(this.withCredentials),n.load(t,function(s){try{const i=s.slice(0),n=Tu.getContext(),o=t+"#decode";r.manager.itemStart(o),n.decodeAudioData(i,function(t){e(t),r.manager.itemEnd(o)}).catch(function(t){a(t),r.manager.itemEnd(o)})}catch(t){a(t)}},s,i)}}const Cu=new Qi,Iu=new Qi,Bu=new Qi;class ku{constructor(){this.type="StereoCamera",this.aspect=1,this.eyeSep=.064,this.cameraL=new eu,this.cameraL.layers.enable(1),this.cameraL.matrixAutoUpdate=!1,this.cameraR=new eu,this.cameraR.layers.enable(2),this.cameraR.matrixAutoUpdate=!1,this._cache={focus:null,fov:null,aspect:null,near:null,far:null,zoom:null,eyeSep:null}}update(t){const e=this._cache;if(e.focus!==t.focus||e.fov!==t.fov||e.aspect!==t.aspect*this.aspect||e.near!==t.near||e.far!==t.far||e.zoom!==t.zoom||e.eyeSep!==this.eyeSep){e.focus=t.focus,e.fov=t.fov,e.aspect=t.aspect*this.aspect,e.near=t.near,e.far=t.far,e.zoom=t.zoom,e.eyeSep=this.eyeSep,Bu.copy(t.projectionMatrix);const s=e.eyeSep/2,i=s*e.near/e.focus,r=e.near*Math.tan(yi*e.fov*.5)/e.zoom;let n,a;Iu.elements[12]=-s,Cu.elements[12]=s,n=-r*e.aspect+i,a=r*e.aspect+i,Bu.elements[0]=2*e.near/(a-n),Bu.elements[8]=(a+n)/(a-n),this.cameraL.projectionMatrix.copy(Bu),n=-r*e.aspect-i,a=r*e.aspect-i,Bu.elements[0]=2*e.near/(a-n),Bu.elements[8]=(a+n)/(a-n),this.cameraR.projectionMatrix.copy(Bu)}this.cameraL.matrix.copy(t.matrixWorld).multiply(Iu),this.cameraL.matrixWorldNeedsUpdate=!0,this.cameraR.matrix.copy(t.matrixWorld).multiply(Cu),this.cameraR.matrixWorldNeedsUpdate=!0}}const Ou=-90;class Pu extends Ar{constructor(t,e,s){super(),this.type="CubeCamera",this.renderTarget=s,this.coordinateSystem=null,this.activeMipmapLevel=0;const i=new eu(Ou,1,t,e);i.layers=this.layers,this.add(i);const r=new eu(Ou,1,t,e);r.layers=this.layers,this.add(r);const n=new eu(Ou,1,t,e);n.layers=this.layers,this.add(n);const a=new eu(Ou,1,t,e);a.layers=this.layers,this.add(a);const o=new eu(Ou,1,t,e);o.layers=this.layers,this.add(o);const h=new eu(Ou,1,t,e);h.layers=this.layers,this.add(h)}updateCoordinateSystem(){const t=this.coordinateSystem,e=this.children.concat(),[s,i,r,n,a,o]=e;for(const t of e)this.remove(t);if(t===Ws)s.up.set(0,1,0),s.lookAt(1,0,0),i.up.set(0,1,0),i.lookAt(-1,0,0),r.up.set(0,0,-1),r.lookAt(0,1,0),n.up.set(0,0,1),n.lookAt(0,-1,0),a.up.set(0,1,0),a.lookAt(0,0,1),o.up.set(0,1,0),o.lookAt(0,0,-1);else{if(t!==Js)throw new Error("THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: "+t);s.up.set(0,-1,0),s.lookAt(-1,0,0),i.up.set(0,-1,0),i.lookAt(1,0,0),r.up.set(0,0,1),r.lookAt(0,1,0),n.up.set(0,0,-1),n.lookAt(0,-1,0),a.up.set(0,-1,0),a.lookAt(0,0,1),o.up.set(0,-1,0),o.lookAt(0,0,-1)}for(const t of e)this.add(t),t.updateMatrixWorld()}update(t,e){null===this.parent&&this.updateMatrixWorld();const{renderTarget:s,activeMipmapLevel:i}=this;this.coordinateSystem!==t.coordinateSystem&&(this.coordinateSystem=t.coordinateSystem,this.updateCoordinateSystem());const[r,n,a,o,h,l]=this.children,c=t.getRenderTarget(),u=t.getActiveCubeFace(),d=t.getActiveMipmapLevel(),p=t.xr.enabled;t.xr.enabled=!1;const m=s.texture.generateMipmaps;s.texture.generateMipmaps=!1;let y=!1;y=!0===t.isWebGLRenderer?t.state.buffers.depth.getReversed():t.reversedDepthBuffer,t.setRenderTarget(s,0,i),y&&!1===t.autoClear&&t.clearDepth(),t.render(e,r),t.setRenderTarget(s,1,i),y&&!1===t.autoClear&&t.clearDepth(),t.render(e,n),t.setRenderTarget(s,2,i),y&&!1===t.autoClear&&t.clearDepth(),t.render(e,a),t.setRenderTarget(s,3,i),y&&!1===t.autoClear&&t.clearDepth(),t.render(e,o),t.setRenderTarget(s,4,i),y&&!1===t.autoClear&&t.clearDepth(),t.render(e,h),s.texture.generateMipmaps=m,t.setRenderTarget(s,5,i),y&&!1===t.autoClear&&t.clearDepth(),t.render(e,l),t.setRenderTarget(c,u,d),t.xr.enabled=p,s.texture.needsPMREMUpdate=!0}}class Ru extends eu{constructor(t=[]){super(),this.isArrayCamera=!0,this.isMultiViewCamera=!1,this.cameras=t}}class Eu{constructor(){this._previousTime=0,this._currentTime=0,this._startTime=performance.now(),this._delta=0,this._elapsed=0,this._timescale=1,this._document=null,this._pageVisibilityHandler=null}connect(t){this._document=t,void 0!==t.hidden&&(this._pageVisibilityHandler=Nu.bind(this),t.addEventListener("visibilitychange",this._pageVisibilityHandler,!1))}disconnect(){null!==this._pageVisibilityHandler&&(this._document.removeEventListener("visibilitychange",this._pageVisibilityHandler),this._pageVisibilityHandler=null),this._document=null}getDelta(){return this._delta/1e3}getElapsed(){return this._elapsed/1e3}getTimescale(){return this._timescale}setTimescale(t){return this._timescale=t,this}reset(){return this._currentTime=performance.now()-this._startTime,this}dispose(){this.disconnect()}update(t){return null!==this._pageVisibilityHandler&&!0===this._document.hidden?this._delta=0:(this._previousTime=this._currentTime,this._currentTime=(void 0!==t?t:performance.now())-this._startTime,this._delta=(this._currentTime-this._previousTime)*this._timescale,this._elapsed+=this._delta),this}}function Nu(){!1===this._document.hidden&&this.reset()}const Vu=new Ti,Lu=new Ai,Fu=new Ti,Du=new Ti,Uu=new Ti;class ju extends Ar{constructor(){super(),this.type="AudioListener",this.context=Tu.getContext(),this.gain=this.context.createGain(),this.gain.connect(this.context.destination),this.filter=null,this.timeDelta=0,this._timer=new Eu}getInput(){return this.gain}removeFilter(){return null!==this.filter&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null),this}getFilter(){return this.filter}setFilter(t){return null!==this.filter?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)):this.gain.disconnect(this.context.destination),this.filter=t,this.gain.connect(this.filter),this.filter.connect(this.context.destination),this}getMasterVolume(){return this.gain.gain.value}setMasterVolume(t){return this.gain.gain.setTargetAtTime(t,this.context.currentTime,.01),this}updateMatrixWorld(t){super.updateMatrixWorld(t),this._timer.update();const e=this.context.listener;if(this.timeDelta=this._timer.getDelta(),this.matrixWorld.decompose(Vu,Lu,Fu),Du.set(0,0,-1).applyQuaternion(Lu),Uu.set(0,1,0).applyQuaternion(Lu),e.positionX){const t=this.context.currentTime+this.timeDelta;e.positionX.linearRampToValueAtTime(Vu.x,t),e.positionY.linearRampToValueAtTime(Vu.y,t),e.positionZ.linearRampToValueAtTime(Vu.z,t),e.forwardX.linearRampToValueAtTime(Du.x,t),e.forwardY.linearRampToValueAtTime(Du.y,t),e.forwardZ.linearRampToValueAtTime(Du.z,t),e.upX.linearRampToValueAtTime(Uu.x,t),e.upY.linearRampToValueAtTime(Uu.y,t),e.upZ.linearRampToValueAtTime(Uu.z,t)}else e.setPosition(Vu.x,Vu.y,Vu.z),e.setOrientation(Du.x,Du.y,Du.z,Uu.x,Uu.y,Uu.z)}}class Wu extends Ar{constructor(t){super(),this.type="Audio",this.listener=t,this.context=t.context,this.gain=this.context.createGain(),this.gain.connect(t.getInput()),this.autoplay=!1,this.buffer=null,this.detune=0,this.loop=!1,this.loopStart=0,this.loopEnd=0,this.offset=0,this.duration=void 0,this.playbackRate=1,this.isPlaying=!1,this.hasPlaybackControl=!0,this.source=null,this.sourceType="empty",this._startedAt=0,this._progress=0,this._connected=!1,this.filters=[]}getOutput(){return this.gain}setNodeSource(t){return this.hasPlaybackControl=!1,this.sourceType="audioNode",this.source=t,this.connect(),this}setMediaElementSource(t){return this.hasPlaybackControl=!1,this.sourceType="mediaNode",this.source=this.context.createMediaElementSource(t),this.connect(),this}setMediaStreamSource(t){return this.hasPlaybackControl=!1,this.sourceType="mediaStreamNode",this.source=this.context.createMediaStreamSource(t),this.connect(),this}setBuffer(t){return this.buffer=t,this.sourceType="buffer",this.autoplay&&this.play(),this}play(t=0){if(!0===this.isPlaying)return void ai("Audio: Audio is already playing.");if(!1===this.hasPlaybackControl)return void ai("Audio: this Audio has no playback control.");this._startedAt=this.context.currentTime+t;const e=this.context.createBufferSource();return e.buffer=this.buffer,e.loop=this.loop,e.loopStart=this.loopStart,e.loopEnd=this.loopEnd,e.onended=this.onEnded.bind(this),e.start(this._startedAt,this._progress+this.offset,this.duration),this.isPlaying=!0,this.source=e,this.setDetune(this.detune),this.setPlaybackRate(this.playbackRate),this.connect()}pause(){if(!1!==this.hasPlaybackControl)return!0===this.isPlaying&&(this._progress+=Math.max(this.context.currentTime-this._startedAt,0)*this.playbackRate,!0===this.loop&&(this._progress=this._progress%(this.duration||this.buffer.duration)),this.source.stop(),this.source.onended=null,this.isPlaying=!1),this;ai("Audio: this Audio has no playback control.")}stop(t=0){if(!1!==this.hasPlaybackControl)return this._progress=0,null!==this.source&&(this.source.stop(this.context.currentTime+t),this.source.onended=null),this.isPlaying=!1,this;ai("Audio: this Audio has no playback control.")}connect(){if(this.filters.length>0){this.source.connect(this.filters[0]);for(let t=1,e=this.filters.length;t0){this.source.disconnect(this.filters[0]);for(let t=1,e=this.filters.length;t0&&this._mixBufferRegionAdditive(s,i,this._addIndex*e,1,e);for(let t=e,r=e+e;t!==r;++t)if(s[t]!==s[t+e]){a.setValue(s,i);break}}saveOriginalState(){const t=this.binding,e=this.buffer,s=this.valueSize,i=s*this._origIndex;t.getValue(e,i);for(let t=s,r=i;t!==r;++t)e[t]=e[i+t%s];this._setIdentity(),this.cumulativeWeight=0,this.cumulativeWeightAdditive=0}restoreOriginalState(){const t=3*this.valueSize;this.binding.setValue(this.buffer,t)}_setAdditiveIdentityNumeric(){const t=this._addIndex*this.valueSize,e=t+this.valueSize;for(let s=t;s=.5)for(let i=0;i!==r;++i)t[e+i]=t[s+i]}_slerp(t,e,s,i){Ai.slerpFlat(t,e,t,e,t,s,i)}_slerpAdditive(t,e,s,i,r){const n=this._workIndex*r;Ai.multiplyQuaternionsFlat(t,n,t,e,t,s),Ai.slerpFlat(t,e,t,e,t,n,i)}_lerp(t,e,s,i,r){const n=1-i;for(let a=0;a!==r;++a){const r=e+a;t[r]=t[r]*n+t[s+a]*i}}_lerpAdditive(t,e,s,i,r){for(let n=0;n!==r;++n){const r=e+n;t[r]=t[r]+t[s+n]*i}}}const $u="\\[\\]\\.:\\/",Qu=new RegExp("["+$u+"]","g"),Ku="[^"+$u+"]",td="[^"+$u.replace("\\.","")+"]",ed=new RegExp("^"+/((?:WC+[\/:])*)/.source.replace("WC",Ku)+/(WCOD+)?/.source.replace("WCOD",td)+/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC",Ku)+/\.(WC+)(?:\[(.+)\])?/.source.replace("WC",Ku)+"$"),sd=["material","materials","bones","map"];class id{constructor(t,e,s){this.path=e,this.parsedPath=s||id.parseTrackName(e),this.node=id.findNode(t,this.parsedPath.nodeName),this.rootNode=t,this.getValue=this._getValue_unbound,this.setValue=this._setValue_unbound}static create(t,e,s){return t&&t.isAnimationObjectGroup?new id.Composite(t,e,s):new id(t,e,s)}static sanitizeNodeName(t){return t.replace(/\s/g,"_").replace(Qu,"")}static parseTrackName(t){const e=ed.exec(t);if(null===e)throw new Error("THREE.PropertyBinding: Cannot parse trackName: "+t);const s={nodeName:e[2],objectName:e[3],objectIndex:e[4],propertyName:e[5],propertyIndex:e[6]},i=s.nodeName&&s.nodeName.lastIndexOf(".");if(void 0!==i&&-1!==i){const t=s.nodeName.substring(i+1);-1!==sd.indexOf(t)&&(s.nodeName=s.nodeName.substring(0,i),s.objectName=t)}if(null===s.propertyName||0===s.propertyName.length)throw new Error("THREE.PropertyBinding: can not parse propertyName from trackName: "+t);return s}static findNode(t,e){if(void 0===e||""===e||"."===e||-1===e||e===t.name||e===t.uuid)return t;if(t.skeleton){const s=t.skeleton.getBoneByName(e);if(void 0!==s)return s}if(t.children){const s=function(t){for(let i=0;i=r){const n=r++,l=t[n];e[l.uuid]=h,t[h]=l,e[o]=n,t[n]=a;for(let t=0,e=i;t!==e;++t){const e=s[t],i=e[n],r=e[h];e[h]=i,e[n]=r}}}this.nCachedObjects_=r}uncache(){const t=this._objects,e=this._indicesByUUID,s=this._bindings,i=s.length;let r=this.nCachedObjects_,n=t.length;for(let a=0,o=arguments.length;a!==o;++a){const o=arguments[a].uuid,h=e[o];if(void 0!==h)if(delete e[o],h0&&(e[a.uuid]=h),t[h]=a,t.pop();for(let t=0,e=i;t!==e;++t){const e=s[t];e[h]=e[r],e.pop()}}}this.nCachedObjects_=r}subscribe_(t,e){const s=this._bindingsIndicesByPath;let i=s[t];const r=this._bindings;if(void 0!==i)return r[i];const n=this._paths,a=this._parsedPaths,o=this._objects,h=o.length,l=this.nCachedObjects_,c=new Array(h);i=r.length,s[t]=i,n.push(t),a.push(e),r.push(c);for(let s=l,i=o.length;s!==i;++s){const i=o[s];c[s]=new id(i,t,e)}return c}unsubscribe_(t){const e=this._bindingsIndicesByPath,s=e[t];if(void 0!==s){const i=this._paths,r=this._parsedPaths,n=this._bindings,a=n.length-1,o=n[a];e[t[a]]=s,n[s]=o,n.pop(),r[s]=r[a],r.pop(),i[s]=i[a],i.pop()}}}class nd{constructor(t,e,s=null,i=e.blendMode){this._mixer=t,this._clip=e,this._localRoot=s,this.blendMode=i;const r=e.tracks,n=r.length,a=new Array(n),o={endingStart:De,endingEnd:De};for(let t=0;t!==n;++t){const e=r[t].createInterpolant(null);a[t]=e,e.settings=o}this._interpolantSettings=o,this._interpolants=a,this._propertyBindings=new Array(n),this._cacheIndex=null,this._byClipCacheIndex=null,this._timeScaleInterpolant=null,this._restoreTimeScale=null,this._weightInterpolant=null,this.loop=2201,this._loopCount=-1,this._startTime=null,this.time=0,this.timeScale=1,this._effectiveTimeScale=1,this.weight=1,this._effectiveWeight=1,this.repetitions=1/0,this.paused=!1,this.enabled=!0,this.clampWhenFinished=!1,this.zeroSlopeAtStart=!0,this.zeroSlopeAtEnd=!0}play(){return this._mixer._activateAction(this),this}stop(){return this._mixer._deactivateAction(this),this.reset()}reset(){return this.paused=!1,this.enabled=!0,this.time=0,this._loopCount=-1,this._startTime=null,this.stopFading().stopWarping()}isRunning(){return this.enabled&&!this.paused&&0!==this.timeScale&&null===this._startTime&&this._mixer._isActiveAction(this)}isScheduled(){return this._mixer._isActiveAction(this)}startAt(t){return this._startTime=t,this}setLoop(t,e){return this.loop=t,this.repetitions=e,this}setEffectiveWeight(t){return this.weight=t,this._effectiveWeight=this.enabled?t:0,this.stopFading()}getEffectiveWeight(){return this._effectiveWeight}fadeIn(t){return this._scheduleFading(t,0,1)}fadeOut(t){return this._scheduleFading(t,1,0)}crossFadeFrom(t,e,s=!1){if(t.fadeOut(e),this.fadeIn(e),!0===s){const s=this._clip.duration,i=t._clip.duration,r=i/s,n=s/i;t._restoreTimeScale=t.timeScale,this._restoreTimeScale=this.timeScale,t.warp(1,r,e),this.warp(n,1,e)}return this}crossFadeTo(t,e,s=!1){return t.crossFadeFrom(this,e,s)}stopFading(){const t=this._weightInterpolant;return null!==t&&(this._weightInterpolant=null,this._mixer._takeBackControlInterpolant(t)),this}setEffectiveTimeScale(t){return this.timeScale=t,this._effectiveTimeScale=this.paused?0:t,this.stopWarping()}getEffectiveTimeScale(){return this._effectiveTimeScale}setDuration(t){return this.timeScale=this._clip.duration/t,this.stopWarping()}syncWith(t){return this.time=t.time,this.timeScale=t.timeScale,this.stopWarping()}halt(t){return this.warp(this._effectiveTimeScale,0,t)}warp(t,e,s){const i=this._mixer,r=i.time,n=this.timeScale;let a=this._timeScaleInterpolant;null===a&&(a=i._lendControlInterpolant(),this._timeScaleInterpolant=a);const o=a.parameterPositions,h=a.sampleValues;return o[0]=r,o[1]=r+s,h[0]=t/n,h[1]=e/n,this}stopWarping(){const t=this._timeScaleInterpolant;return null!==t&&(this._timeScaleInterpolant=null,this._mixer._takeBackControlInterpolant(t)),this._restoreTimeScale=null,this}getMixer(){return this._mixer}getClip(){return this._clip}getRoot(){return this._localRoot||this._mixer._root}_update(t,e,s,i){if(!this.enabled)return void this._updateWeight(t);const r=this._startTime;if(null!==r){const i=(t-r)*s;i<0||0===s?e=0:(this._startTime=null,e=s*i)}e*=this._updateTimeScale(t);const n=this._updateTime(e),a=this._updateWeight(t);if(a>0){const t=this._interpolants,e=this._propertyBindings;if(this.blendMode===Je)for(let s=0,i=t.length;s!==i;++s)t[s].evaluate(n),e[s].accumulateAdditive(a);else for(let s=0,r=t.length;s!==r;++s)t[s].evaluate(n),e[s].accumulate(i,a)}}_updateWeight(t){let e=0;if(this.enabled){e=this.weight;const s=this._weightInterpolant;if(null!==s){const i=s.evaluate(t)[0];e*=i,t>s.parameterPositions[1]&&(this.stopFading(),0===i&&(this.enabled=!1))}}return this._effectiveWeight=e,e}_updateTimeScale(t){let e=0;if(!this.paused){e=this.timeScale;const s=this._timeScaleInterpolant;if(null!==s){e*=s.evaluate(t)[0],t>s.parameterPositions[1]&&(0===e?this.paused=!0:(null!==this._restoreTimeScale&&(e=this._restoreTimeScale),this.timeScale=e),this.stopWarping())}}return this._effectiveTimeScale=e,e}_updateTime(t){const e=this._clip.duration,s=this.loop;let i=this.time+t,r=this._loopCount;const n=2202===s;if(0===t)return-1===r||!n||1&~r?i:e-i;if(2200===s){-1===r&&(this._loopCount=0,this._setEndings(!0,!0,!1));t:{if(i>=e)i=e;else{if(!(i<0)){this.time=i;break t}i=0}this.clampWhenFinished?this.paused=!0:this.enabled=!1,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:t<0?-1:1})}}else{if(-1===r&&(t>=0?(r=0,this._setEndings(!0,0===this.repetitions,n)):this._setEndings(0===this.repetitions,!0,n)),i>=e||i<0){const s=Math.floor(i/e);i-=e*s,r+=Math.abs(s);const a=this.repetitions-r;if(a<=0)this.clampWhenFinished?this.paused=!0:this.enabled=!1,i=t>0?e:0,this.time=i,this._mixer.dispatchEvent({type:"finished",action:this,direction:t>0?1:-1});else{if(1===a){const e=t<0;this._setEndings(e,!e,n)}else this._setEndings(!1,!1,n);this._loopCount=r,this.time=i,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:s})}}else this._loopCount=r,this.time=i;if(n&&!(1&~r))return e-i}return i}_setEndings(t,e,s){const i=this._interpolantSettings;s?(i.endingStart=Ue,i.endingEnd=Ue):(i.endingStart=t?this.zeroSlopeAtStart?Ue:De:je,i.endingEnd=e?this.zeroSlopeAtEnd?Ue:De:je)}_scheduleFading(t,e,s){const i=this._mixer,r=i.time;let n=this._weightInterpolant;null===n&&(n=i._lendControlInterpolant(),this._weightInterpolant=n);const a=n.parameterPositions,o=n.sampleValues;return a[0]=r,o[0]=e,a[1]=r+t,o[1]=s,this}}const ad=new Float32Array(1);class od extends di{constructor(t){super(),this._root=t,this._initMemoryManager(),this._accuIndex=0,this.time=0,this.timeScale=1,"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("observe",{detail:this}))}_bindAction(t,e){const s=t._localRoot||this._root,i=t._clip.tracks,r=i.length,n=t._propertyBindings,a=t._interpolants,o=s.uuid,h=this._bindingsByRootAndName;let l=h[o];void 0===l&&(l={},h[o]=l);for(let t=0;t!==r;++t){const r=i[t],h=r.name;let c=l[h];if(void 0!==c)++c.referenceCount,n[t]=c;else{if(c=n[t],void 0!==c){null===c._cacheIndex&&(++c.referenceCount,this._addInactiveBinding(c,o,h));continue}const i=e&&e._propertyBindings[t].binding.parsedPath;c=new Gu(id.create(s,h,i),r.ValueTypeName,r.getValueSize()),++c.referenceCount,this._addInactiveBinding(c,o,h),n[t]=c}a[t].resultBuffer=c.buffer}}_activateAction(t){if(!this._isActiveAction(t)){if(null===t._cacheIndex){const e=(t._localRoot||this._root).uuid,s=t._clip.uuid,i=this._actionsByClip[s];this._bindAction(t,i&&i.knownActions[0]),this._addInactiveAction(t,s,e)}const e=t._propertyBindings;for(let t=0,s=e.length;t!==s;++t){const s=e[t];0===s.useCount++&&(this._lendBinding(s),s.saveOriginalState())}this._lendAction(t)}}_deactivateAction(t){if(this._isActiveAction(t)){const e=t._propertyBindings;for(let t=0,s=e.length;t!==s;++t){const s=e[t];0===--s.useCount&&(s.restoreOriginalState(),this._takeBackBinding(s))}this._takeBackAction(t)}}_initMemoryManager(){this._actions=[],this._nActiveActions=0,this._actionsByClip={},this._bindings=[],this._nActiveBindings=0,this._bindingsByRootAndName={},this._controlInterpolants=[],this._nActiveControlInterpolants=0;const t=this;this.stats={actions:{get total(){return t._actions.length},get inUse(){return t._nActiveActions}},bindings:{get total(){return t._bindings.length},get inUse(){return t._nActiveBindings}},controlInterpolants:{get total(){return t._controlInterpolants.length},get inUse(){return t._nActiveControlInterpolants}}}}_isActiveAction(t){const e=t._cacheIndex;return null!==e&&e=0;--e)t[e].stop();return this}update(t){t*=this.timeScale;const e=this._actions,s=this._nActiveActions,i=this.time+=t,r=Math.sign(t),n=this._accuIndex^=1;for(let a=0;a!==s;++a){e[a]._update(i,t,r,n)}const a=this._bindings,o=this._nActiveBindings;for(let t=0;t!==o;++t)a[t].apply(n);return this}setTime(t){this.time=0;for(let t=0;t=this.min.x&&t.x<=this.max.x&&t.y>=this.min.y&&t.y<=this.max.y}containsBox(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y}getParameter(t,e){return e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y))}intersectsBox(t){return t.max.x>=this.min.x&&t.min.x<=this.max.x&&t.max.y>=this.min.y&&t.min.y<=this.max.y}clampPoint(t,e){return e.copy(t).clamp(this.min,this.max)}distanceToPoint(t){return this.clampPoint(t,Md).distanceTo(t)}intersect(t){return this.min.max(t.min),this.max.min(t.max),this.isEmpty()&&this.makeEmpty(),this}union(t){return this.min.min(t.min),this.max.max(t.max),this}translate(t){return this.min.add(t),this.max.add(t),this}equals(t){return t.min.equals(this.min)&&t.max.equals(this.max)}}const _d=new Ti,Ad=new Ti,Td=new Ti,zd=new Ti,Cd=new Ti,Id=new Ti,Bd=new Ti;class kd{constructor(t=new Ti,e=new Ti){this.start=t,this.end=e}set(t,e){return this.start.copy(t),this.end.copy(e),this}copy(t){return this.start.copy(t.start),this.end.copy(t.end),this}getCenter(t){return t.addVectors(this.start,this.end).multiplyScalar(.5)}delta(t){return t.subVectors(this.end,this.start)}distanceSq(){return this.start.distanceToSquared(this.end)}distance(){return this.start.distanceTo(this.end)}at(t,e){return this.delta(e).multiplyScalar(t).add(this.start)}closestPointToPointParameter(t,e){_d.subVectors(t,this.start),Ad.subVectors(this.end,this.start);const s=Ad.dot(Ad);if(0===s)return 0;let i=Ad.dot(_d)/s;return e&&(i=xi(i,0,1)),i}closestPointToPoint(t,e,s){const i=this.closestPointToPointParameter(t,e);return this.delta(s).multiplyScalar(i).add(this.start)}distanceSqToLine3(t,e=Id,s=Bd){const i=1e-8*1e-8;let r,n;const a=this.start,o=t.start,h=this.end,l=t.end;Td.subVectors(h,a),zd.subVectors(l,o),Cd.subVectors(a,o);const c=Td.dot(Td),u=zd.dot(zd),d=zd.dot(Cd);if(c<=i&&u<=i)return e.copy(a),s.copy(o),e.sub(s),e.dot(e);if(c<=i)r=0,n=d/u,n=xi(n,0,1);else{const t=Td.dot(Cd);if(u<=i)n=0,r=xi(-t/c,0,1);else{const e=Td.dot(zd),s=c*u-e*e;r=0!==s?xi((e*d-t*u)/s,0,1):0,n=(e*r+d)/u,n<0?(n=0,r=xi(-t/c,0,1)):n>1&&(n=1,r=xi((e-t)/c,0,1))}}return e.copy(a).addScaledVector(Td,r),s.copy(o).addScaledVector(zd,n),e.distanceToSquared(s)}applyMatrix4(t){return this.start.applyMatrix4(t),this.end.applyMatrix4(t),this}equals(t){return t.start.equals(this.start)&&t.end.equals(this.end)}clone(){return(new this.constructor).copy(this)}}const Od=new Ti;class Pd extends Ar{constructor(t,e){super(),this.light=t,this.matrixAutoUpdate=!1,this.color=e,this.type="SpotLightHelper";const s=new Wn,i=[0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,-1,0,1,0,0,0,0,1,1,0,0,0,0,-1,1];for(let t=0,e=1,s=32;t1)for(let s=0;s.99999)this.quaternion.set(0,0,0,1);else if(t.y<-.99999)this.quaternion.set(1,0,0,0);else{rp.set(t.z,0,-t.x).normalize();const e=Math.acos(t.y);this.quaternion.setFromAxisAngle(rp,e)}}setLength(t,e=.2*t,s=.2*e){this.line.scale.set(1,Math.max(1e-4,t-e),1),this.line.updateMatrix(),this.cone.scale.set(s,e,s),this.cone.position.y=t,this.cone.updateMatrix()}setColor(t){this.line.material.color.set(t),this.cone.material.color.set(t)}copy(t){return super.copy(t,!1),this.line.copy(t.line),this.cone.copy(t.cone),this}dispose(){this.line.geometry.dispose(),this.line.material.dispose(),this.cone.geometry.dispose(),this.cone.material.dispose()}}class hp extends Yo{constructor(t=1){const e=[0,0,0,t,0,0,0,0,0,0,t,0,0,0,0,0,0,t],s=new Wn;s.setAttribute("position",new kn(e,3)),s.setAttribute("color",new kn([1,0,0,1,.6,0,0,1,0,.6,1,0,0,0,1,0,.6,1],3));super(s,new No({vertexColors:!0,toneMapped:!1})),this.type="AxesHelper"}setColors(t,e,s){const i=new Pr,r=this.geometry.attributes.color.array;return i.set(t),i.toArray(r,0),i.toArray(r,3),i.set(e),i.toArray(r,6),i.toArray(r,9),i.set(s),i.toArray(r,12),i.toArray(r,15),this.geometry.attributes.color.needsUpdate=!0,this}dispose(){this.geometry.dispose(),this.material.dispose()}}class lp{constructor(){this.type="ShapePath",this.color=new Pr,this.subPaths=[],this.currentPath=null,this.userData={}}moveTo(t,e){return this.currentPath=new Zh,this.subPaths.push(this.currentPath),this.currentPath.moveTo(t,e),this}lineTo(t,e){return this.currentPath.lineTo(t,e),this}quadraticCurveTo(t,e,s,i){return this.currentPath.quadraticCurveTo(t,e,s,i),this}bezierCurveTo(t,e,s,i,r,n){return this.currentPath.bezierCurveTo(t,e,s,i,r,n),this}splineThru(t){return this.currentPath.splineThru(t),this}toShapes(){function t(t,e){let s=!1;const i=e.length;for(let r=0,n=i-1;rt.y!=a.y>t.y&&t.x<(a.x-i.x)*(t.y-i.y)/(a.y-i.y)+i.x&&(s=!s)}return s}function e(e,s){const i=s.getCenter(new _i);if(t(i,e))return i;const r=i.y,n=[],a=e.length;for(let t=0;tr!=i.y>r){const t=s.x+(r-s.y)*(i.x-s.x)/(i.y-s.y);n.push(t)}}return n.length>1&&(n.sort((t,e)=>t-e),i.x=(n[0]+n[1])/2),i}let s=this.userData.style&&this.userData.style.fillRule||"nonzero";"nonzero"!==s&&"evenodd"!==s&&(ai('Fill-rule "'+s+'" is not supported, falling back to "nonzero".'),s="nonzero");const i="nonzero"===s?t=>0!==t:t=>!!(1&t),r=[];for(const t of this.subPaths){const s=t.getPoints();if(s.length<3)continue;const i=_l.area(s);if(0===i)continue;const n=new Sd;for(let t=0;te.absArea-t.absArea);for(let e=0;e=0;i--){const e=r[i];if(e.boundingBox.containsPoint(s.interiorPoint)&&t(s.interiorPoint,e.points)){s.container=e.exclude?e.container:e,n=e.winding,s.winding+=n;break}}i(s.winding)===i(n)&&(s.exclude=!0)}for(const t of r)t.exclude||(t.role=null===t.container||"hole"===t.container.role?"outer":"hole");const n=[],a=new Map;for(const t of r){if(t.exclude||"outer"!==t.role)continue;const e=new Gh;e.curves=t.subPath.curves,n.push(e),a.set(t,e)}for(const t of r){if(t.exclude||"hole"!==t.role)continue;const e=a.get(t.container);if(!e)continue;const s=new Zh;s.curves=t.subPath.curves,e.holes.push(s)}return n}}class cp extends di{constructor(t,e=null){super(),this.object=t,this.domElement=e,this.enabled=!0,this.state=-1,this.keys={},this.mouseButtons={LEFT:null,MIDDLE:null,RIGHT:null},this.touches={ONE:null,TWO:null}}connect(t){void 0!==t?(null!==this.domElement&&this.disconnect(),this.domElement=t):ai("Controls: connect() now requires an element.")}disconnect(){}dispose(){}update(){}}function up(t,e,s,i){const r=function(t){switch(t){case zt:case Ct:return{byteLength:1,components:1};case Bt:case It:case Rt:return{byteLength:2,components:1};case Et:case Nt:return{byteLength:2,components:4};case Ot:case kt:case Pt:return{byteLength:4,components:1};case Lt:case Ft:return{byteLength:4,components:3}}throw new Error(`THREE.TextureUtils: Unknown texture type ${t}.`)}(i);switch(s){case 1021:return t*e;case qt:case Ht:return t*e/r.components*r.byteLength;case 1030:case 1031:return t*e*2/r.components*r.byteLength;case 1022:return t*e*3/r.components*r.byteLength;case jt:case 1033:return t*e*4/r.components*r.byteLength;case 33776:case 33777:return Math.floor((t+3)/4)*Math.floor((e+3)/4)*8;case 33778:case 33779:return Math.floor((t+3)/4)*Math.floor((e+3)/4)*16;case 35841:case 35843:return Math.max(t,16)*Math.max(e,8)/4;case 35840:case 35842:return Math.max(t,8)*Math.max(e,8)/2;case 36196:case 37492:case 37488:case 37489:return Math.floor((t+3)/4)*Math.floor((e+3)/4)*8;case 37496:case 37490:case 37491:case 37808:return Math.floor((t+3)/4)*Math.floor((e+3)/4)*16;case 37809:return Math.floor((t+4)/5)*Math.floor((e+3)/4)*16;case 37810:return Math.floor((t+4)/5)*Math.floor((e+4)/5)*16;case 37811:return Math.floor((t+5)/6)*Math.floor((e+4)/5)*16;case 37812:return Math.floor((t+5)/6)*Math.floor((e+5)/6)*16;case 37813:return Math.floor((t+7)/8)*Math.floor((e+4)/5)*16;case 37814:return Math.floor((t+7)/8)*Math.floor((e+5)/6)*16;case 37815:return Math.floor((t+7)/8)*Math.floor((e+7)/8)*16;case 37816:return Math.floor((t+9)/10)*Math.floor((e+4)/5)*16;case 37817:return Math.floor((t+9)/10)*Math.floor((e+5)/6)*16;case 37818:return Math.floor((t+9)/10)*Math.floor((e+7)/8)*16;case 37819:return Math.floor((t+9)/10)*Math.floor((e+9)/10)*16;case 37820:return Math.floor((t+11)/12)*Math.floor((e+9)/10)*16;case 37821:return Math.floor((t+11)/12)*Math.floor((e+11)/12)*16;case 36492:case 36494:case 36495:return Math.ceil(t/4)*Math.ceil(e/4)*16;case 36283:case 36284:return Math.ceil(t/4)*Math.ceil(e/4)*8;case 36285:case 36286:return Math.ceil(t/4)*Math.ceil(e/4)*16}throw new Error(`Unable to determine texture byte length for ${s} format.`)}class dp{static contain(t,e){return function(t,e){const s=t.image&&t.image.width?t.image.width/t.image.height:1;return s>e?(t.repeat.x=1,t.repeat.y=s/e,t.offset.x=0,t.offset.y=(1-t.repeat.y)/2):(t.repeat.x=e/s,t.repeat.y=1,t.offset.x=(1-t.repeat.x)/2,t.offset.y=0),t}(t,e)}static cover(t,e){return function(t,e){const s=t.image&&t.image.width?t.image.width/t.image.height:1;return s>e?(t.repeat.x=e/s,t.repeat.y=1,t.offset.x=(1-t.repeat.x)/2,t.offset.y=0):(t.repeat.x=1,t.repeat.y=s/e,t.offset.x=0,t.offset.y=(1-t.repeat.y)/2),t}(t,e)}static fill(t){return function(t){return t.repeat.x=1,t.repeat.y=1,t.offset.x=0,t.offset.y=0,t}(t)}static getByteLength(t,e,s,i){return up(t,e,s,i)}}"undefined"!=typeof __THREE_DEVTOOLS__&&__THREE_DEVTOOLS__.dispatchEvent(new CustomEvent("register",{detail:{revision:t}})),"undefined"!=typeof window&&(window.__THREE__?ai("WARNING: Multiple instances of Three.js being imported."):window.__THREE__=t);export{st as ACESFilmicToneMapping,w as AddEquation,$ as AddOperation,Je as AdditiveAnimationBlendMode,g as AdditiveBlending,rt as AgXToneMapping,Dt as AlphaFormat,ks as AlwaysCompare,j as AlwaysDepth,Ss as AlwaysStencilFunc,lu as AmbientLight,nd as AnimationAction,Ac as AnimationClip,Ec as AnimationLoader,od as AnimationMixer,rd as AnimationObjectGroup,uc as AnimationUtils,Ih as ArcCurve,Ru as ArrayCamera,op as ArrowHelper,at as AttachedBindMode,Wu as Audio,Zu as AudioAnalyser,Tu as AudioContext,ju as AudioListener,zu as AudioLoader,hp as AxesHelper,d as BackSide,Ye as BasicDepthPacking,o as BasicShadowMap,Eo as BatchedMesh,gc as BezierInterpolant,Ha as Bone,xc as BooleanKeyframeTrack,Sd as Box2,Qr as Box3,sp as Box3Helper,yh as BoxGeometry,ep as BoxHelper,Mn as BufferAttribute,Wn as BufferGeometry,fu as BufferGeometryLoader,Ct as ByteType,zc as Cache,$c as Camera,Qd as CameraHelper,ch as CanvasTexture,gh as CapsuleGeometry,Nh as CatmullRomCurve3,et as CineonToneMapping,fh as CircleGeometry,yt as ClampToEdgeWrapping,xd as Clock,Pr as Color,bc as ColorKeyframeTrack,Ri as ColorManagement,Ys as Compatibility,oh as CompressedArrayTexture,hh as CompressedCubeTexture,ah as CompressedTexture,Nc as CompressedTextureLoader,bh as ConeGeometry,F as ConstantAlphaFactor,V as ConstantColorFactor,cp as Controls,Pu as CubeCamera,ph as CubeDepthTexture,lt as CubeReflectionMapping,ct as CubeRefractionMapping,lh as CubeTexture,Fc as CubeTextureLoader,pt as CubeUVReflectionMapping,Dh as CubicBezierCurve,Uh as CubicBezierCurve3,pc as CubicInterpolant,r as CullFaceBack,n as CullFaceFront,a as CullFaceFrontBack,i as CullFaceNone,zh as Curve,Yh as CurvePath,b as CustomBlending,it as CustomToneMapping,xh as CylinderGeometry,vd as Cylindrical,Gi as Data3DTexture,Yi as DataArrayTexture,Xa as DataTexture,Dc as DataTextureLoader,xn as DataUtils,ds as DecrementStencilOp,ms as DecrementWrapStencilOp,Bc as DefaultLoadingManager,Wt as DepthFormat,Jt as DepthStencilFormat,dh as DepthTexture,ot as DetachedBindMode,hu as DirectionalLight,Zd as DirectionalLightHelper,yc as DiscreteInterpolant,wh as DodecahedronGeometry,p as DoubleSide,O as DstAlphaFactor,R as DstColorFactor,Fs as DynamicCopyUsage,Ps as DynamicDrawUsage,Ns as DynamicReadUsage,Th as EdgesGeometry,Ch as EllipseCurve,Ts as EqualCompare,q as EqualDepth,xs as EqualStencilFunc,ut as EquirectangularReflectionMapping,dt as EquirectangularRefractionMapping,hr as Euler,di as EventDispatcher,mh as ExternalTexture,zl as ExtrudeGeometry,Rc as FileLoader,Bn as Float16BufferAttribute,kn as Float32BufferAttribute,Pt as FloatType,Nr as Fog,Er as FogExp2,nh as FramebufferTexture,u as FrontSide,mo as Frustum,go as FrustumArray,pd as GLBufferAttribute,Us as GLSL1,js as GLSL3,Cs as GreaterCompare,X as GreaterDepth,Bs as GreaterEqualCompare,H as GreaterEqualDepth,Ms as GreaterEqualStencilFunc,vs as GreaterStencilFunc,Jd as GridHelper,Tr as Group,uh as HTMLTexture,Rt as HalfFloatType,Wc as HemisphereLight,Wd as HemisphereLightHelper,Il as IcosahedronGeometry,_u as ImageBitmapLoader,Lc as ImageLoader,Li as ImageUtils,us as IncrementStencilOp,ps as IncrementWrapStencilOp,$a as InstancedBufferAttribute,gu as InstancedBufferGeometry,dd as InstancedInterleavedBuffer,no as InstancedMesh,Tn as Int16BufferAttribute,Cn as Int32BufferAttribute,Sn as Int8BufferAttribute,kt as IntType,Jn as InterleavedBuffer,Hn as InterleavedBufferAttribute,dc as Interpolant,Fe as InterpolateBezier,Ne as InterpolateDiscrete,Ve as InterpolateLinear,Le as InterpolateSmooth,Xs as InterpolationSamplingMode,Hs as InterpolationSamplingType,ys as InvertStencilOp,ls as KeepStencilOp,fc as KeyframeTrack,pa as LOD,Bl as LatheGeometry,lr as Layers,As as LessCompare,W as LessDepth,zs as LessEqualCompare,J as LessEqualDepth,bs as LessEqualStencilFunc,fs as LessStencilFunc,jc as Light,du as LightProbe,Jo as Line,kd as Line3,No as LineBasicMaterial,jh as LineCurve,Wh as LineCurve3,ac as LineDashedMaterial,Zo as LineLoop,Yo as LineSegments,Mt as LinearFilter,mc as LinearInterpolant,Tt as LinearMipMapLinearFilter,_t as LinearMipMapNearestFilter,At as LinearMipmapLinearFilter,St as LinearMipmapNearestFilter,ss as LinearSRGBColorSpace,K as LinearToneMapping,is as LinearTransfer,kc as Loader,yu as LoaderUtils,Ic as LoadingManager,Pe as LoopOnce,Ee as LoopPingPong,Re as LoopRepeat,e as MOUSE,Zn as Material,v as MaterialBlending,mu as MaterialLoader,Si as MathUtils,wd as Matrix2,Ii as Matrix3,Qi as Matrix4,A as MaxEquation,Ra as Mesh,Ma as MeshBasicMaterial,ic as MeshDepthMaterial,rc as MeshDistanceMaterial,sc as MeshLambertMaterial,nc as MeshMatcapMaterial,ec as MeshNormalMaterial,Kl as MeshPhongMaterial,Ql as MeshPhysicalMaterial,$l as MeshStandardMaterial,tc as MeshToonMaterial,_ as MinEquation,gt as MirroredRepeatWrapping,G as MixOperation,x as MultiplyBlending,Z as MultiplyOperation,ft as NearestFilter,wt as NearestMipMapLinearFilter,bt as NearestMipMapNearestFilter,vt as NearestMipmapLinearFilter,xt as NearestMipmapNearestFilter,nt as NeutralToneMapping,_s as NeverCompare,U as NeverDepth,gs as NeverStencilFunc,m as NoBlending,ts as NoColorSpace,ns as NoNormalPacking,Q as NoToneMapping,We as NormalAnimationBlendMode,y as NormalBlending,os as NormalGAPacking,as as NormalRGPacking,Is as NotEqualCompare,Y as NotEqualDepth,ws as NotEqualStencilFunc,vc as NumberKeyframeTrack,Ar as Object3D,bu as ObjectLoader,Ke as ObjectSpaceNormalMap,kl as OctahedronGeometry,z as OneFactor,D as OneMinusConstantAlphaFactor,L as OneMinusConstantColorFactor,P as OneMinusDstAlphaFactor,E as OneMinusDstColorFactor,k as OneMinusSrcAlphaFactor,I as OneMinusSrcColorFactor,au as OrthographicCamera,h as PCFShadowMap,l as PCFSoftShadowMap,Zh as Path,eu as PerspectiveCamera,lo as Plane,Ol as PlaneGeometry,ip as PlaneHelper,nu as PointLight,Fd as PointLightHelper,eh as Points,Go as PointsMaterial,qd as PolarGridHelper,vh as PolyhedronGeometry,Yu as PositionalAudio,id as PropertyBinding,Gu as PropertyMixer,Jh as QuadraticBezierCurve,qh as QuadraticBezierCurve3,Ai as Quaternion,Mc as QuaternionKeyframeTrack,wc as QuaternionLinearInterpolant,he as R11_EAC_Format,gi as RAD2DEG,ke as RED_GREEN_RGTC2_Format,Ie as RED_RGTC1_Format,t as REVISION,ce as RG11_EAC_Format,Ze as RGBADepthPacking,jt as RGBAFormat,Gt as RGBAIntegerFormat,Se as RGBA_ASTC_10x10_Format,ve as RGBA_ASTC_10x5_Format,we as RGBA_ASTC_10x6_Format,Me as RGBA_ASTC_10x8_Format,_e as RGBA_ASTC_12x10_Format,Ae as RGBA_ASTC_12x12_Format,de as RGBA_ASTC_4x4_Format,pe as RGBA_ASTC_5x4_Format,me as RGBA_ASTC_5x5_Format,ye as RGBA_ASTC_6x5_Format,ge as RGBA_ASTC_6x6_Format,fe as RGBA_ASTC_8x5_Format,xe as RGBA_ASTC_8x6_Format,be as RGBA_ASTC_8x8_Format,Te as RGBA_BPTC_Format,oe as RGBA_ETC2_EAC_Format,re as RGBA_PVRTC_2BPPV1_Format,ie as RGBA_PVRTC_4BPPV1_Format,Qt as RGBA_S3TC_DXT1_Format,Kt as RGBA_S3TC_DXT3_Format,te as RGBA_S3TC_DXT5_Format,Ge as RGBDepthPacking,Ut as RGBFormat,Zt as RGBIntegerFormat,ze as RGB_BPTC_SIGNED_Format,Ce as RGB_BPTC_UNSIGNED_Format,ne as RGB_ETC1_Format,ae as RGB_ETC2_Format,se as RGB_PVRTC_2BPPV1_Format,ee as RGB_PVRTC_4BPPV1_Format,$t as RGB_S3TC_DXT1_Format,$e as RGDepthPacking,Xt as RGFormat,Yt as RGIntegerFormat,Gl as RawShaderMaterial,wa as Ray,yd as Raycaster,cu as RectAreaLight,qt as RedFormat,Ht as RedIntegerFormat,tt as ReinhardToneMapping,Hi as RenderTarget,hd as RenderTarget3D,mt as RepeatWrapping,cs as ReplaceStencilOp,S as ReverseSubtractEquation,ui as ReversedDepthFuncs,Pl as RingGeometry,le as SIGNED_R11_EAC_Format,Oe as SIGNED_RED_GREEN_RGTC2_Format,Be as SIGNED_RED_RGTC1_Format,ue as SIGNED_RG11_EAC_Format,es as SRGBColorSpace,rs as SRGBTransfer,Vr as Scene,Zl as ShaderMaterial,Wl as ShadowMaterial,Gh as Shape,Rl as ShapeGeometry,lp as ShapePath,_l as ShapeUtils,It as ShortType,Ga as Skeleton,Vd as SkeletonHelper,qa as SkinnedMesh,Di as Source,En as Sphere,El as SphereGeometry,bd as Spherical,uu as SphericalHarmonics3,Hh as SplineCurve,iu as SpotLight,Pd as SpotLightHelper,la as Sprite,Gn as SpriteMaterial,B as SrcAlphaFactor,N as SrcAlphaSaturateFactor,C as SrcColorFactor,Ls as StaticCopyUsage,Os as StaticDrawUsage,Es as StaticReadUsage,ku as StereoCamera,Ds as StreamCopyUsage,Rs as StreamDrawUsage,Vs as StreamReadUsage,Sc as StringKeyframeTrack,M as SubtractEquation,f as SubtractiveBlending,s as TOUCH,Qe as TangentSpaceNormalMap,Nl as TetrahedronGeometry,Ji as Texture,Uc as TextureLoader,dp as TextureUtils,Eu as Timer,qs as TimestampQuery,Vl as TorusGeometry,Ll as TorusKnotGeometry,$r as Triangle,Xe as TriangleFanDrawMode,He as TriangleStripDrawMode,qe as TrianglesDrawMode,Fl as TubeGeometry,ht as UVMapping,zn as Uint16BufferAttribute,In as Uint32BufferAttribute,_n as Uint8BufferAttribute,An as Uint8ClampedBufferAttribute,ld as Uniform,ud as UniformsGroup,Yl as UniformsUtils,zt as UnsignedByteType,Ft as UnsignedInt101111Type,Vt as UnsignedInt248Type,Lt as UnsignedInt5999Type,Ot as UnsignedIntType,Et as UnsignedShort4444Type,Nt as UnsignedShort5551Type,Bt as UnsignedShortType,c as VSMShadowMap,_i as Vector2,Ti as Vector3,qi as Vector4,_c as VectorKeyframeTrack,rh as VideoFrameTexture,ih as VideoTexture,$i as WebGL3DRenderTarget,Zi as WebGLArrayRenderTarget,Ws as WebGLCoordinateSystem,Xi as WebGLRenderTarget,Js as WebGPUCoordinateSystem,Cr as WebXRController,Dl as WireframeGeometry,je as WrapAroundEnding,De as ZeroCurvatureEnding,T as ZeroFactor,Ue as ZeroSlopeEnding,hs as ZeroStencilOp,Jl as cloneUniforms,Ks as createCanvasElement,Qs as createElementNS,oi as error,up as getByteLength,ii as getConsoleFunction,Xl as getUnlitUniformColorSpace,$s as isTypedArray,ri as log,ql as mergeUniforms,ci as probeAsync,si as setConsoleFunction,ai as warn,hi as warnOnce,li as yieldToMain}; diff --git a/scripts/check_site.py b/scripts/check_site.py index 2703958..5be82d2 100755 --- a/scripts/check_site.py +++ b/scripts/check_site.py @@ -3,10 +3,14 @@ 1. Every referenced asset exists — a 404 in production that works in local preview is the classic Pages failure. -2. No root-absolute paths: the site is served from /forge/, not /. -3. No cross-origin runtime references: no CDN, no HuggingFace fetch. (Links a +2. Every module specifier inside every shipped .js resolves. three.js r185 is + *two* files (three.module.min.js imports ./three.core.min.js), and a missing + sibling breaks the module graph before a single line of scene.js runs — with + no console error a build step would notice. +3. No root-absolute paths: the site is served from /forge/, not /. +4. No cross-origin runtime references: no CDN, no HuggingFace fetch. (Links a visitor clicks are fine; a resource the page *loads* is not.) -4. `.nojekyll` is present, or Jekyll drops every _-prefixed path. +5. `.nojekyll` is present, or Jekyll drops every _-prefixed path. Usage: check_site.py [docs/dist] """ @@ -28,11 +32,9 @@ refs = set(re.findall(r'(?:src|href)="([^"]+)"', html)) imap = re.search(r'', html, re.S) -if imap: - refs |= set(json.loads(imap.group(1))["imports"].values()) +importmap = json.loads(imap.group(1))["imports"] if imap else {} +refs |= set(importmap.values()) -demo = (dist / "demo.js").read_text() if (dist / "demo.js").exists() else "" -refs |= set(re.findall(r'import\("([^"]+)"\)', demo)) # Fetched at runtime, so they must ship even though no tag names them. refs |= {"./model/model.safetensors", "./model/config.json", "./model/vocab.json"} @@ -54,6 +56,50 @@ if not (dist / r.lstrip("./")).exists(): problems.append(f"missing asset (would 404): {r}") +# ── Module graph ────────────────────────────────────────────────────────── +# Static (`from "x"`, `import "x"`, `export … from "x"`) and dynamic +# (`import("x")`) specifiers, in every shipped module including the vendored +# and wasm-bindgen-generated ones. Resolving these is what would have caught +# the missing three.core.min.js at build time instead of in production. +# +# The specifier charset is deliberately narrow: minified three.js contains +# English strings like "…resized from ("+w+")", and a permissive pattern reads +# those as imports. +SPEC = r"""["']([A-Za-z0-9_@~./-]+)["']""" +SPECIFIERS = re.compile( + rf"""\bfrom\s*{SPEC}|\bimport\s*{SPEC}|\bimport\s*\(\s*{SPEC}""" +) + + +def specifiers(text): + """Every module specifier in `text`, from whichever alternative matched.""" + return {next(g for g in m if g) for m in SPECIFIERS.findall(text)} + +for js in sorted(dist.rglob("*.js")): + text = js.read_text(errors="replace") + for spec in sorted(specifiers(text)): + if spec.startswith(("http://", "https://", "//", "data:")): + problems.append(f"{js.relative_to(dist)}: cross-origin import: {spec}") + continue + if spec.startswith("/"): + problems.append( + f"{js.relative_to(dist)}: root-absolute import (404 under /forge/): {spec}" + ) + continue + if spec.startswith("."): + target = (js.parent / spec).resolve() + elif spec in importmap: + # Bare specifier, resolved by the page's importmap relative to the + # document, not to the importing file. + target = (dist / importmap[spec].lstrip("./")).resolve() + else: + problems.append( + f"{js.relative_to(dist)}: bare import with no importmap entry: {spec}" + ) + continue + if not target.exists(): + problems.append(f"{js.relative_to(dist)}: import would 404: {spec}") + if problems: for p in problems: print(f"error: {p}", file=sys.stderr) From e8fc55acc24ca72b8c5ca6f6b288d492a548d5aa Mon Sep 17 00:00:00 2001 From: bowen Date: Sun, 26 Jul 2026 13:13:03 +0000 Subject: [PATCH 2/6] feat(gpt2): opt-in attention probe for decode steps MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit logits_step_attn_async returns each block's post-softmax attention alongside the logits, so a caller can show what the model attended to while producing a token. ops::softmax is out-of-place, so the probe only clones Arc handles to tensors the step computes anyway — the arithmetic, and therefore the output, is unchanged. generate_async_probe threads it through the decode loop; generate_async_ctl is now a wrapper passing None and keeps its signature. Reading the n_layer+1 tensors one at a time cost a submit and a fence wait each: 111 -> 41 tok/s on an RTX A5000, 2.7x slower than the decode it was observing. WgpuContext::readback_many_async stages them into one encoder and issues every map request before awaiting any, so one poll services all of them; Tensor::to_vec_f32_batch is the facade. Same run, batched: 117 -> 120 tok/s, i.e. free. Tests cover both backends: one capture per block, rows summing to 1, no query attending forward, and — the one that matters — greedy output identical with and without the probe. Co-Authored-By: Claude Opus 5 Signed-off-by: bowen --- Cargo.toml | 5 ++ src/backend/wgpu/mod.rs | 60 +++++++++++++++++ src/lib.rs | 2 +- src/models/gpt2/mod.rs | 145 ++++++++++++++++++++++++++++++++++++++-- src/tensor.rs | 45 +++++++++++++ tests/char_model.rs | 99 ++++++++++++++++++++++++++- 6 files changed, 347 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3ea0395..cf07ecd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,11 @@ sysinfo = { version = "0.39", optional = true } nvml-wrapper = { version = "0.12", optional = true } memmap2 = { version = "0.9", optional = true } +# Native only: the integration tests exercise the async inference API — the +# path the browser actually takes — so they need a blocking executor. +[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] +pollster = "0.4" + # Browser (wasm32): async-only device APIs + JS bindings. [target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2" diff --git a/src/backend/wgpu/mod.rs b/src/backend/wgpu/mod.rs index 0241ca7..6c2ed9e 100644 --- a/src/backend/wgpu/mod.rs +++ b/src/backend/wgpu/mod.rs @@ -235,6 +235,66 @@ impl WgpuContext { Ok(out) } + /// Read several regions back in one submit and one fence wait. + /// + /// [`WgpuContext::readback_async`] costs a submit and a wait *each*, which + /// dominates when a single logical step wants several small tensors: the + /// attention probe reads `n_layer + 1` per generated token, and one at a + /// time that cost more than the decode itself. Staged into one encoder + /// they cost one round trip regardless of how many there are. + /// + /// Regions are returned in the order given. + pub async fn readback_many_async( + &self, + regions: &[(&wgpu::Buffer, usize, usize)], + ) -> Result>> { + if regions.is_empty() { + return Ok(Vec::new()); + } + let mut encoder = self.device.create_command_encoder(&Default::default()); + let staging: Vec = regions + .iter() + .map(|(buf, offset_bytes, size_bytes)| { + let s = self.device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: *size_bytes as u64, + usage: wgpu::BufferUsages::MAP_READ | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + encoder.copy_buffer_to_buffer(buf, *offset_bytes as u64, &s, 0, *size_bytes as u64); + s + }) + .collect(); + self.queue.submit([encoder.finish()]); + + // Every map request is issued before anything is awaited, so one poll + // services all of them. + let waits: Vec<_> = staging + .iter() + .map(|s| { + let (tx, rx) = oneshot::channel(); + s.slice(..) + .map_async(wgpu::MapMode::Read, move |r| tx.send(r)); + rx + }) + .collect(); + #[cfg(not(target_arch = "wasm32"))] + self.device + .poll(wgpu::PollType::Wait) + .map_err(|e| ForgeError::Wgpu(format!("poll: {e:?}")))?; + #[cfg(target_arch = "wasm32")] + let _ = self.device.poll(wgpu::PollType::Poll); + + let mut out = Vec::with_capacity(regions.len()); + for (rx, s) in waits.into_iter().zip(&staging) { + rx.await + .map_err(|e| ForgeError::Wgpu(format!("map_async: {e:?}")))?; + out.push(s.slice(..).get_mapped_range().to_vec()); + s.unmap(); + } + Ok(out) + } + /// Dispatch `name` with binding 0 = `params` (uniform, raw words) and /// bindings 1.. = `buffers` (storage). Each buffer entry is /// (buffer, offset_bytes, size_bytes). diff --git a/src/lib.rs b/src/lib.rs index da4f423..84a3a9e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,7 @@ pub mod wasm; pub use device::Device; pub use dtype::DType; pub use error::{ForgeError, Result}; -pub use models::gpt2::{Gpt2, Gpt2Config, KvCache, Sampling}; +pub use models::gpt2::{AttnStep, Gpt2, Gpt2Config, KvCache, Sampling}; pub use shape::Shape; pub use tensor::Tensor; pub use tokenizer::{AnyTokenizer, CharTokenizer, Gpt2Tokenizer, Tokenizer}; diff --git a/src/models/gpt2/mod.rs b/src/models/gpt2/mod.rs index b9719ae..e4cdfa0 100644 --- a/src/models/gpt2/mod.rs +++ b/src/models/gpt2/mod.rs @@ -111,6 +111,24 @@ pub enum Sampling { }, } +/// One block's attention probabilities for one decode step, read back from +/// the device. +/// +/// `probs` is the row-major `[n_head, q_len, kv_len]` tensor the model +/// actually attended with — captured after the softmax, not recomputed — so a +/// visualization built from it shows the same arithmetic that produced the +/// text. `ops::softmax` is out-of-place, so capturing it perturbs nothing. +#[derive(Debug, Clone)] +pub struct AttnStep { + pub layer: usize, + pub n_head: usize, + /// Query positions in this step: the whole prompt on prefill, 1 per decode. + pub q_len: usize, + /// Past positions attended to, including the queries themselves. + pub kv_len: usize, + pub probs: Vec, +} + /// Preallocated per-layer K/V tensors (`[n_head, n_ctx, head_dim]`) for /// incremental decode. `len` positions are filled; new tokens append. pub struct KvCache { @@ -251,6 +269,10 @@ impl Gpt2 { /// Attention over new tokens only, appending their K/V to the cache and /// attending to all `len + t` cached positions. + /// + /// `probe`, when present, collects the post-softmax probabilities — an + /// `Arc` handle to a tensor that is computed regardless, so the probing + /// and non-probing paths run identical arithmetic. fn attention_cached( &self, block: &Block, @@ -258,6 +280,7 @@ impl Gpt2 { k_cache: &mut Tensor, v_cache: &mut Tensor, len: usize, + probe: Option<&mut Vec>, ) -> Result { let n_head = self.config.n_head; let hd = self.config.n_embd / n_head; @@ -279,6 +302,9 @@ impl Gpt2 { }, )?; // [h, t, kv_len] let att = ops::softmax(&att, true, len)?; // off = kv_len - t + if let Some(probe) = probe { + probe.push(att.clone()); + } let y = ops::matmul( &att, v_cache, @@ -320,8 +346,14 @@ impl Gpt2 { } /// Hidden states for `ids` (new tokens) continuing from `cache`; - /// appends their K/V and advances `cache.len`. - fn hidden_cached(&self, ids: &[u32], cache: &mut KvCache) -> Result { + /// appends their K/V and advances `cache.len`. `probe` is threaded through + /// to [`Gpt2::attention_cached`] and collects one tensor per block. + fn hidden_cached( + &self, + ids: &[u32], + cache: &mut KvCache, + mut probe: Option<&mut Vec>, + ) -> Result { if ids.is_empty() { return Err(ForgeError::Shape("empty token sequence".into())); } @@ -342,7 +374,14 @@ impl Gpt2 { .iter() .zip(cache.k.iter_mut().zip(cache.v.iter_mut())) { - let attn_out = self.attention_cached(block, &block.ln_1.forward(&x)?, kc, vc, pos)?; + let attn_out = self.attention_cached( + block, + &block.ln_1.forward(&x)?, + kc, + vc, + pos, + probe.as_deref_mut(), + )?; x = ops::add(&x, &attn_out)?; let mlp_in = block.ln_2.forward(&x)?; let mlp_out = block @@ -386,7 +425,7 @@ impl Gpt2 { /// Last-position logits for `ids` continuing from `cache` (incremental /// decode: pass the full prompt once, then one token at a time). pub fn logits_step(&self, ids: &[u32], cache: &mut KvCache) -> Result> { - let h = self.hidden_cached(ids, cache)?; + let h = self.hidden_cached(ids, cache, None)?; let last = h.narrow_rows(ids.len() - 1, 1)?; ops::matmul_chunked_transb(&last, &self.emb.wte_chunks, 1.0)?.to_vec_f32() } @@ -394,13 +433,58 @@ impl Gpt2 { /// Async form of [`Gpt2::logits_step`] — identical math; the readback is /// awaited so it works on wasm32 (roadmap v4, pitfall 14). pub async fn logits_step_async(&self, ids: &[u32], cache: &mut KvCache) -> Result> { - let h = self.hidden_cached(ids, cache)?; + let h = self.hidden_cached(ids, cache, None)?; let last = h.narrow_rows(ids.len() - 1, 1)?; ops::matmul_chunked_transb(&last, &self.emb.wte_chunks, 1.0)? .to_vec_f32_async() .await } + /// [`Gpt2::logits_step_async`] plus every block's attention probabilities + /// for this step, in layer order. + /// + /// The logits are identical to `logits_step_async` — the probe only reads + /// tensors the step computes anyway. The whole step is enqueued first, and + /// the logits and every block's attention come back in a *single* batched + /// readback: one at a time they cost ~2.7x the decode itself, since the + /// price is the round trip rather than the ~36 KB. + pub async fn logits_step_attn_async( + &self, + ids: &[u32], + cache: &mut KvCache, + ) -> Result<(Vec, Vec)> { + let mut probe = Vec::with_capacity(self.config.n_layer + 1); + let h = self.hidden_cached(ids, cache, Some(&mut probe))?; + let last = h.narrow_rows(ids.len() - 1, 1)?; + // Logits last, so `probe` stays in layer order and the shapes below + // line up with the tensors that produced them. + let shapes: Vec> = probe.iter().map(|t| t.shape().dims().to_vec()).collect(); + probe.push(ops::matmul_chunked_transb( + &last, + &self.emb.wte_chunks, + 1.0, + )?); + + let mut read = Tensor::to_vec_f32_batch(&probe).await?; + let logits = read.pop().expect("logits were pushed last"); + let mut steps = Vec::with_capacity(read.len()); + for (layer, (probs, dims)) in read.into_iter().zip(shapes).enumerate() { + let [n_head, q_len, kv_len] = dims[..] else { + return Err(ForgeError::Shape(format!( + "attention probe expected rank 3, got {dims:?}" + ))); + }; + steps.push(AttnStep { + layer, + n_head, + q_len, + kv_len, + probs, + }); + } + Ok((logits, steps)) + } + // ---- training (roadmap v4, Stages 8-10) ---- /// Random initialization for training from scratch: N(0, 0.02) weights, @@ -844,12 +928,42 @@ impl Gpt2 { /// [`ControlFlow::Break`] stops after the current token, which is how a /// page offers a working "stop" button. pub async fn generate_async_ctl( + &self, + tokenizer: &impl Tokenizer, + prompt: &str, + max_new_tokens: usize, + sampling: Sampling, + on_text: impl FnMut(&str) -> ControlFlow<()>, + ) -> Result { + // `None` turns off the probe entirely: no capture, no readback, and + // the same `logits_step_async` this method has always called. + self.generate_async_probe( + tokenizer, + prompt, + max_new_tokens, + sampling, + on_text, + None::, + ) + .await + } + + /// [`Gpt2::generate_async_ctl`] with an optional attention probe: + /// `on_attn`, when present, fires once per decode step with every block's + /// attention probabilities — including the prompt prefill, whose `q_len` + /// is the prompt length rather than 1. + /// + /// Opt-in because it costs one readback per block per token. Passing + /// `None` is exactly the non-probing path; the generated text is identical + /// either way, since the probe reads tensors the step already computed. + pub async fn generate_async_probe( &self, tokenizer: &impl Tokenizer, prompt: &str, max_new_tokens: usize, sampling: Sampling, mut on_text: impl FnMut(&str) -> ControlFlow<()>, + mut on_attn: Option, ) -> Result { // The streaming helper takes a plain sink, so the break request is // captured here and checked once the delta has been forwarded. A Cell @@ -869,7 +983,7 @@ impl Gpt2 { Sampling::Greedy => None, }; let mut cache = self.new_cache()?; - let mut logits = self.logits_step_async(&ids, &mut cache).await?; // prompt prefill + let mut logits = self.step_async(&ids, &mut cache, &mut on_attn).await?; // prompt prefill // Stream over the raw byte-level decode (append-only per token), // emitting only its valid-UTF-8 prefix: a multi-byte character split // across BPE tokens is held back until its trailing bytes arrive. @@ -889,10 +1003,27 @@ impl Gpt2 { if ids.len() >= self.config.n_ctx { break; } - logits = self.logits_step_async(&[next], &mut cache).await?; // single-token decode + logits = self.step_async(&[next], &mut cache, &mut on_attn).await?; // single-token decode } Ok(tokenizer.decode(&ids)) } + + /// One decode step, forwarding attention to `on_attn` when probing. + async fn step_async( + &self, + ids: &[u32], + cache: &mut KvCache, + on_attn: &mut Option, + ) -> Result> { + match on_attn { + Some(f) => { + let (logits, steps) = self.logits_step_attn_async(ids, cache).await?; + f(&steps); + Ok(logits) + } + None => self.logits_step_async(ids, cache).await, + } + } } /// Send `bytes[sent..]` to `on_text` up to the longest decodable prefix; diff --git a/src/tensor.rs b/src/tensor.rs index 6d3d966..0bd6487 100644 --- a/src/tensor.rs +++ b/src/tensor.rs @@ -175,6 +175,51 @@ impl Tensor { } } + /// Read several f32 tensors back in one GPU round trip, in the order + /// given. + /// + /// [`Tensor::to_vec_f32_async`] is a submit and a fence wait per call, so + /// a step that wants several small tensors — the attention probe reads + /// `n_layer + 1` per generated token — pays for the round trips, not the + /// bytes. Every tensor must be on the same device. + pub async fn to_vec_f32_batch(tensors: &[Tensor]) -> Result>> { + let mixed = || ForgeError::Shape("to_vec_f32_batch needs one device".into()); + let mut ctx: Option<&Arc> = None; + for t in tensors { + if t.dtype != DType::F32 { + return Err(ForgeError::Shape("to_vec_f32 on non-f32 tensor".into())); + } + if let Storage::Wgpu(s) = &t.storage { + match ctx { + None => ctx = Some(&s.ctx), + Some(c) if Arc::ptr_eq(c, &s.ctx) => {} + Some(_) => return Err(mixed()), + } + } + } + let Some(ctx) = ctx else { + // All host-side: nothing to stage, and no round trip to save. + return tensors.iter().map(Tensor::to_vec_f32).collect(); + }; + let mut regions = Vec::with_capacity(tensors.len()); + for t in tensors { + match &t.storage { + Storage::Wgpu(s) => { + regions.push((s.buf.as_ref(), s.offset * 4, t.shape.numel() * 4)) + } + // A host tensor has nothing to stage, so a mixed batch would + // misalign the results with their inputs. + Storage::Cpu(_) => return Err(mixed()), + } + } + Ok(ctx + .readback_many_async(®ions) + .await? + .iter() + .map(|b| bytemuck::pod_collect_to_vec(b)) + .collect()) + } + pub async fn to_vec_u32_async(&self) -> Result> { if self.dtype != DType::U32 { return Err(ForgeError::Shape("to_vec_u32 on non-u32 tensor".into())); diff --git a/tests/char_model.rs b/tests/char_model.rs index cd5b2f9..69da13f 100644 --- a/tests/char_model.rs +++ b/tests/char_model.rs @@ -5,7 +5,9 @@ //! run on a fresh clone. They still self-skip, because the artifact is only //! present once someone has trained and shipped it. -use forge::{AnyTokenizer, Device, Gpt2, Gpt2Config, Sampling, Tokenizer as _}; +use std::ops::ControlFlow; + +use forge::{AnyTokenizer, AttnStep, Device, Gpt2, Gpt2Config, Sampling, Tokenizer as _}; const DIR: &str = "assets/shakespeare_char"; const PROMPT: &str = "ROMEO:"; @@ -83,3 +85,98 @@ fn generation_stays_inside_the_vocabulary() { "output is not mostly letters: {text:?}" ); } + +// ── Attention probe ─────────────────────────────────────────────────────── +// The website renders these numbers as a live 3D view while it generates, so +// what matters is that they are the model's own softmax output and that +// capturing them changes nothing. + +fn model_on(config: Gpt2Config, device: &Device) -> Gpt2 { + Gpt2::from_safetensors(format!("{DIR}/model.safetensors"), config, device).unwrap() +} + +#[test] +fn attention_probe_captures_the_real_softmax() { + let Some((config, tok)) = assets() else { + return; + }; + // Both backends: WGPU reads every block back in one batched round trip, + // which is a different path from the CPU backend's plain clone. + for device in [Device::Cpu, Device::wgpu().unwrap()] { + let model = model_on(config.clone(), &device); + let ids = tok.encode(PROMPT).unwrap(); + let mut cache = model.new_cache().unwrap(); + let (_, steps) = + pollster::block_on(model.logits_step_attn_async(&ids, &mut cache)).unwrap(); + + assert_eq!(steps.len(), config.n_layer, "one capture per block"); + for (layer, s) in steps.iter().enumerate() { + assert_eq!(s.layer, layer); + assert_eq!(s.n_head, config.n_head); + // Prefill attends with every prompt position at once. + assert_eq!((s.q_len, s.kv_len), (ids.len(), ids.len())); + assert_eq!(s.probs.len(), s.n_head * s.q_len * s.kv_len); + + for head in 0..s.n_head { + for q in 0..s.q_len { + let row = &s.probs[(head * s.q_len + q) * s.kv_len..][..s.kv_len]; + let sum: f32 = row.iter().sum(); + assert!( + (sum - 1.0).abs() < 1e-5, + "{}: layer {layer} head {head} row {q} sums to {sum}, not 1", + device.describe() + ); + // Causal mask: a query never attends to a later position. + for (k, &w) in row.iter().enumerate().skip(q + 1) { + assert_eq!( + w, + 0.0, + "{}: layer {layer} head {head} row {q} sees future {k}", + device.describe() + ); + } + } + } + } + + // One decode step: a single query against one more cached position. + let (_, steps) = + pollster::block_on(model.logits_step_attn_async(&[ids[0]], &mut cache)).unwrap(); + for s in &steps { + assert_eq!((s.q_len, s.kv_len), (1, ids.len() + 1)); + } + } +} + +#[test] +fn attention_probe_does_not_change_the_output() { + let Some((config, tok)) = assets() else { + return; + }; + let model = model_on(config.clone(), &Device::Cpu); + const N: usize = 24; + + let plain = pollster::block_on(model.generate_async(&tok, PROMPT, N, Sampling::Greedy, |_| {})) + .unwrap(); + + let mut seen = 0usize; + let probed = pollster::block_on(model.generate_async_probe( + &tok, + PROMPT, + N, + Sampling::Greedy, + |_| ControlFlow::Continue(()), + Some(|steps: &[AttnStep]| { + assert_eq!(steps.len(), config.n_layer); + seen += 1; + }), + )) + .unwrap(); + + assert_eq!( + plain, probed, + "the probe perturbed the computation it is meant to observe" + ); + // Prefill plus one capture per generated token. + assert_eq!(seen, N + 1, "the probe skipped or duplicated a decode step"); +} From c7e645153a13232e7685d519db6a2a26e5e8cc3c Mon Sep 17 00:00:00 2001 From: bowen Date: Sun, 26 Jul 2026 13:13:03 +0000 Subject: [PATCH 3/6] feat(wasm): generate_with_attention and config accessors generate_with_attention mirrors generate but also calls on_attn(layer, n_head, weights) per block after every token, sending only the newest query row so the payload is n_head * kv_len. generate and the Stage 11 gate path (greedy_ids) are untouched and do no attention readback. n_layer/n_head/n_embd/n_ctx let the page size its architecture view from the model it is running instead of hardcoding GPT-2 124M's 12/12/768/1024. Co-Authored-By: Claude Opus 5 Signed-off-by: bowen --- src/wasm.rs | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/src/wasm.rs b/src/wasm.rs index cc3931a..58e5a27 100644 --- a/src/wasm.rs +++ b/src/wasm.rs @@ -5,7 +5,7 @@ use wasm_bindgen::prelude::*; use crate::Device; -use crate::models::gpt2::{Gpt2, Gpt2Config, Sampling}; +use crate::models::gpt2::{AttnStep, Gpt2, Gpt2Config, Sampling}; use crate::tokenizer::{AnyTokenizer, CharTokenizer, Gpt2Tokenizer, Tokenizer as _}; #[wasm_bindgen(start)] @@ -80,6 +80,24 @@ impl WasmGpt2 { self.tokenizer.vocab_size() } + // The page's architecture view is sized from the model it is actually + // running, not from GPT-2 124M constants baked into JavaScript. + pub fn n_layer(&self) -> usize { + self.model.config.n_layer + } + + pub fn n_head(&self) -> usize { + self.model.config.n_head + } + + pub fn n_embd(&self) -> usize { + self.model.config.n_embd + } + + pub fn n_ctx(&self) -> usize { + self.model.config.n_ctx + } + /// Characters of `prompt` this model's vocabulary cannot represent, /// deduplicated. Empty when the prompt is fine. The char model knows only /// 65 characters, so the page checks before generating rather than @@ -132,6 +150,73 @@ impl WasmGpt2 { .map_err(js_err) } + /// [`WasmGpt2::generate`] plus a live attention feed: after every token, + /// `on_attn(layer, n_head, weights)` fires once per block with that + /// block's attention probabilities as a `Float32Array` of + /// `n_head * kv_len` — head-major, so `kv_len` is `weights.length / + /// n_head`, and `weights[h * kv_len + p]` is how much head `h` weighted + /// position `p` when producing this token. + /// + /// Only the newest query row is sent: on the prompt prefill the model + /// attends with every prompt position at once, but the row that produced + /// the next token is the last one. + /// + /// Opt-in — `generate` does no attention readback at all. + pub async fn generate_with_attention( + &self, + prompt: &str, + max_new_tokens: usize, + top_k: usize, + temperature: f32, + seed: u64, + on_text: &js_sys::Function, + on_attn: &js_sys::Function, + ) -> Result { + let sampling = if top_k == 0 { + Sampling::Greedy + } else { + Sampling::TopK { + k: top_k, + temperature, + seed, + } + }; + let this = JsValue::NULL; + self.model + .generate_async_probe( + &self.tokenizer, + prompt, + max_new_tokens, + sampling, + |s| match on_text.call1(&this, &JsValue::from_str(s)) { + Ok(v) if v.is_falsy() && !v.is_undefined() && !v.is_null() => { + std::ops::ControlFlow::Break(()) + } + _ => std::ops::ControlFlow::Continue(()), + }, + Some(|steps: &[AttnStep]| { + for s in steps { + let last = (s.q_len - 1) * s.kv_len; + let mut row = Vec::with_capacity(s.n_head * s.kv_len); + for head in 0..s.n_head { + let base = head * s.q_len * s.kv_len + last; + row.extend_from_slice(&s.probs[base..base + s.kv_len]); + } + // A failing visualization callback must not abort + // generation; the text is the point. + let _ = on_attn.call3( + &this, + &JsValue::from_f64(s.layer as f64), + &JsValue::from_f64(s.n_head as f64), + &js_sys::Float32Array::from(&row[..]), + ); + } + }), + ) + .await + .map_err(js_err) + } + /// Greedy continuation as raw token ids — used by the Stage 11 gate to /// compare browser output against native WGPU token-for-token. pub async fn greedy_ids( From b9d33a4e2b9bacfa8c7a34eaa46ad01970a0c2ec Mon Sep 17 00:00:00 2001 From: bowen Date: Sun, 26 Jul 2026 13:13:16 +0000 Subject: [PATCH 4/6] feat(site): live 3D attention driven by the running model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit scene.js becomes a createStack({canvas, label}) factory returning {setConfig, pushAttention, reset, dispose} instead of a top-level side-effect script. It no longer hardcodes 12/12/768/1024; demo.js feeds it the real config from the wasm module, defaulting to the shipped char model's 6/6/384/256 until then. While generating, each block slab carries an n_head x kv_len attention strip — heads down, past positions across — as one DataTexture allocated at full context width and written in place per token, with the UV repeat narrowed to the filled part. No geometry is rebuilt per token. Per-head rows are scaled by their own maximum before colouring, which is a display transform on real numbers, not a substitute for them. three.js is now imported only from scene.js, and demo.js await-imports that module when #demo first intersects, so 751 KB is off the first-paint path entirely. If WebGL or the import fails, the canvas card is removed rather than left blank and the text architecture opens in its place — text generation still runs, through the plain generate path with no probe. Co-Authored-By: Claude Opus 5 Signed-off-by: bowen --- docs/src/demo.js | 97 +++++++++-- docs/src/scene.js | 426 +++++++++++++++++++++++++++++++++------------- 2 files changed, 396 insertions(+), 127 deletions(-) diff --git a/docs/src/demo.js b/docs/src/demo.js index 0bec517..0988603 100644 --- a/docs/src/demo.js +++ b/docs/src/demo.js @@ -29,6 +29,57 @@ function explain(title, body, retry) { } } +// ── The 3D stack ────────────────────────────────────────────────────────── +// Separate from the WebGPU check on purpose: WebGL and WebGPU fail +// independently, and either one missing must still leave a complete page. + +let scenePromise = null; + +/** Start the scene at most once; resolves to the controller or null. */ +function ensureScene() { + scenePromise = scenePromise || startScene(); + return scenePromise; +} + +async function startScene() { + const canvas = $("scene"); + if (!canvas) return null; + try { + // three.js is 751 KB and lives behind this call, so it is fetched when + // the section is reached rather than on first paint. + const { createStack } = await import("./scene.js"); + return createStack({ canvas, label: $("scene-label") }); + } catch (e) { + // No WebGL, or the module itself failed to load. Drop the canvas + // entirely — an empty rectangle is worse than no rectangle — and open + // the text architecture, which says the same thing in words. + console.warn("3D stack unavailable:", e); + $("scene-card")?.remove(); + $("demo-grid")?.classList.remove("md:grid-cols-2"); + const text = $("stack-text"); + if (text) text.open = true; + return null; + } +} + +const section = $("demo"); +if (section && "IntersectionObserver" in window) { + const io = new IntersectionObserver( + (entries, obs) => { + if (entries.some((e) => e.isIntersecting)) { + obs.disconnect(); + ensureScene(); + } + }, + { rootMargin: "200px" }, + ); + io.observe(section); +} else { + ensureScene(); +} + +// ── The demo itself ─────────────────────────────────────────────────────── + if (!("gpu" in navigator)) { explain( "WebGPU is not available in this browser", @@ -139,6 +190,17 @@ function wire() { } if (!checkCharset()) return; + // The visualization must describe the model that is running, not the + // defaults it was built with. + const scene = await ensureScene(); + scene?.setConfig({ + nLayer: model.n_layer(), + nHead: model.n_head(), + nEmbd: model.n_embd(), + nCtx: model.n_ctx(), + }); + scene?.reset(); + $("demo-output").textContent = ""; $("demo-stop").hidden = false; stop = false; @@ -150,24 +212,33 @@ function wire() { let count = 0; let first = null; - await model.generate( + const onText = (s) => { + // Returning false stops generation after the current token. + if (stop) return false; + if (first === null) first = performance.now(); + count += 1; + $("demo-output").textContent += s; + const dt = (performance.now() - first) / 1000; + if (dt > 0) { + status(`generating — ${(count / dt).toFixed(1)} tok/s`); + } + }; + const args = [ $("demo-prompt").value, n, topk, 0.8, BigInt(Date.now() % 100000), - (s) => { - // Returning false stops generation after the current token. - if (stop) return false; - if (first === null) first = performance.now(); - count += 1; - $("demo-output").textContent += s; - const dt = (performance.now() - first) / 1000; - if (dt > 0) { - status(`generating — ${(count / dt).toFixed(1)} tok/s`); - } - }, - ); + onText, + ]; + + // Text generation never depends on the 3D view: without it the plain + // path runs, and it does no attention readback at all. + await (scene + ? model.generate_with_attention(...args, (layer, nHead, weights) => + scene.pushAttention(layer, nHead, weights), + ) + : model.generate(...args)); const dt = (performance.now() - t0) / 1000; const decode = first === null ? dt : (performance.now() - first) / 1000; diff --git a/docs/src/scene.js b/docs/src/scene.js index d3e9e48..0c86431 100644 --- a/docs/src/scene.js +++ b/docs/src/scene.js @@ -1,63 +1,91 @@ -// Twelve translucent slabs — GPT-2 124M's twelve transformer blocks. -// Hover highlights a block; click expands it into its sub-layers with the -// real shapes from Gpt2Config::gpt2(). +// A live view of the model the page is actually running: one translucent slab +// per transformer block, each carrying a heads × positions attention strip +// that updates once per generated token from probabilities read back off the +// GPU. Idle, it is just the stack; generating, it shows which earlier +// characters every head is looking at. // -// Only what is used is imported, three.js is vendored (no CDN), the loop stops -// when the canvas scrolls off-screen, and reduced-motion renders one static -// frame. If WebGL is unavailable the static architecture diagram takes the -// canvas's place — the page must be fully informative without it. +// three.js is imported here and nowhere else, so demo.js can `await import()` +// this module only when the section scrolls into view — 751 KB a visitor who +// never scrolls never pays for. +// +// Nothing here is required for the page to work: if WebGL is missing, +// createStack throws and the caller shows the text architecture instead. import { AmbientLight, BoxGeometry, + ClampToEdgeWrapping, Color, + DataTexture, DirectionalLight, Group, + LinearFilter, Mesh, MeshStandardMaterial, PerspectiveCamera, + RGBAFormat, Raycaster, + SRGBColorSpace, Scene, + UnsignedByteType, Vector2, WebGLRenderer, } from "three"; -const N_LAYER = 12; -const N_HEAD = 12; -const N_EMBD = 768; -const N_CTX = 1024; -const HEAD_DIM = N_EMBD / N_HEAD; - -const SUB_LAYERS = [ - ["ln_1", `LayerNorm [${N_EMBD}]`], - ["attn", `causal self-attention ${N_HEAD} heads × ${HEAD_DIM}`], - ["ln_2", `LayerNorm [${N_EMBD}]`], - ["mlp", `MLP ${N_EMBD} → ${4 * N_EMBD} → ${N_EMBD}, GELU`], +// The config of the shipped char model, used until the wasm module reports +// the real one. Never GPT-2 124M's — the page must describe what it runs. +export const DEFAULT_CONFIG = { + name: "Shakespeare char GPT", + nLayer: 6, + nHead: 6, + nEmbd: 384, + nCtx: 256, +}; + +const BASE = new Color(0x9aa0ad); +const HOVER = new Color(0xff8a4c); +const OPEN = new Color(0xea6a24); + +const SLAB_H = 0.26; +const GAP = 0.14; + +// Attention ramp on the forge palette: cold ink → forge orange → hot ember. +const RAMP = [ + [0x1c, 0x1c, 0x24], + [0xea, 0x6a, 0x24], + [0xff, 0xe6, 0xd5], ]; -const canvas = document.getElementById("scene"); -const holder = document.getElementById("scene-holder"); -const label = document.getElementById("scene-label"); -const reduced = window.matchMedia("(prefers-reduced-motion: reduce)"); - -function fallback() { - // Move the static diagram into the canvas's place rather than leaving a - // blank rectangle. - const stat = document.getElementById("stack-static"); - if (holder && stat) { - holder.replaceWith(stat); +function ramp(t, out, o) { + const i = t < 0.5 ? 0 : 1; + const f = t < 0.5 ? t * 2 : (t - 0.5) * 2; + for (let c = 0; c < 3; c++) { + out[o + c] = RAMP[i][c] + (RAMP[i + 1][c] - RAMP[i][c]) * f; } + out[o + 3] = 255; } -let renderer; -try { - if (!canvas) throw new Error("no canvas"); - renderer = new WebGLRenderer({ canvas, antialias: true, alpha: true }); -} catch { - fallback(); +function subLayers({ nHead, nEmbd }) { + const hd = Math.round(nEmbd / nHead); + return [ + `LayerNorm [${nEmbd}]`, + `causal self-attention ${nHead} heads × ${hd}`, + `LayerNorm [${nEmbd}]`, + `MLP ${nEmbd} → ${4 * nEmbd} → ${nEmbd}, GELU`, + ]; } -if (renderer) { +/** + * Build the stack in `canvas`, labelling it into `label`. + * + * Throws if a WebGL context cannot be created — the caller's cue to show the + * text architecture instead of leaving an empty rectangle. + * + * @returns {{setConfig: Function, pushAttention: Function, reset: Function, + * dispose: Function}} + */ +export function createStack({ canvas, label, config }) { + const renderer = new WebGLRenderer({ canvas, antialias: true, alpha: true }); // Uncapped DPR on a 4K screen tanks the framerate for no visible gain. renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); @@ -77,94 +105,151 @@ if (renderer) { const stack = new Group(); scene.add(stack); - const BASE = new Color(0x9aa0ad); - const HOVER = new Color(0xff8a4c); - const OPEN = new Color(0xea6a24); - - const SLAB_H = 0.26; - const GAP = 0.14; - const geometry = new BoxGeometry(3.4, SLAB_H, 2.2); - const blocks = []; - - for (let i = 0; i < N_LAYER; i++) { - const material = new MeshStandardMaterial({ - color: BASE, - transparent: true, - opacity: 0.62, - roughness: 0.35, - metalness: 0.1, + const reduced = window.matchMedia("(prefers-reduced-motion: reduce)"); + let still = reduced.matches; + let cfg = { ...DEFAULT_CONFIG, ...config }; + let blocks = []; + let strips = []; + let subs = []; + let geometry; + let subGeometry; + let hovered = -1; + let opened = -1; + // Positions in context on the most recent token; 0 while idle. + let live = 0; + let spin = 0; + let manual = 0; + let frame = 0; + + // ── build / teardown ──────────────────────────────────────────────────── + + function build() { + geometry = new BoxGeometry(3.4, SLAB_H, 2.2); + subGeometry = new BoxGeometry(3.0, 0.05, 1.9); + + for (let i = 0; i < cfg.nLayer; i++) { + // One texture per block, allocated at full context width so a token + // never rebuilds geometry or reallocates: the strip is written in + // place and revealed by narrowing the UV repeat. + const data = new Uint8Array(cfg.nCtx * cfg.nHead * 4); + const texture = new DataTexture( + data, + cfg.nCtx, + cfg.nHead, + RGBAFormat, + UnsignedByteType, + ); + texture.colorSpace = SRGBColorSpace; + texture.minFilter = LinearFilter; + texture.magFilter = LinearFilter; + texture.wrapS = ClampToEdgeWrapping; + texture.wrapT = ClampToEdgeWrapping; + + const material = new MeshStandardMaterial({ + color: BASE, + transparent: true, + opacity: 0.62, + roughness: 0.35, + metalness: 0.1, + emissive: new Color(0xffffff), + emissiveIntensity: 0, + }); + const mesh = new Mesh(geometry, material); + mesh.position.y = (i - (cfg.nLayer - 1) / 2) * (SLAB_H + GAP); + mesh.userData.index = i; + stack.add(mesh); + blocks.push(mesh); + strips.push({ data, texture }); + } + + // Sub-layer slabs, hidden until a block is opened. + subs = subLayers(cfg).map(() => { + const mesh = new Mesh( + subGeometry, + new MeshStandardMaterial({ + color: OPEN, + transparent: true, + opacity: 0.9, + roughness: 0.3, + }), + ); + mesh.visible = false; + stack.add(mesh); + return mesh; }); - const mesh = new Mesh(geometry, material); - mesh.position.y = (i - (N_LAYER - 1) / 2) * (SLAB_H + GAP); - mesh.userData.index = i; - stack.add(mesh); - blocks.push(mesh); + paint(); } - // Sub-layer slabs, hidden until a block is opened. - const subGeometry = new BoxGeometry(3.0, 0.05, 1.9); - const subs = SUB_LAYERS.map(() => { - const mesh = new Mesh( - subGeometry, - new MeshStandardMaterial({ - color: OPEN, - transparent: true, - opacity: 0.9, - roughness: 0.3, - }), - ); - mesh.visible = false; - stack.add(mesh); - return mesh; - }); + function teardown() { + for (const m of [...blocks, ...subs]) { + stack.remove(m); + m.material.dispose(); + } + for (const s of strips) s.texture.dispose(); + geometry?.dispose(); + subGeometry?.dispose(); + blocks = []; + strips = []; + subs = []; + } - let hovered = -1; - let opened = -1; + // ── painting ──────────────────────────────────────────────────────────── function paint() { for (const b of blocks) { const i = b.userData.index; const on = i === hovered || i === opened; - b.material.color.copy(i === opened ? OPEN : on ? HOVER : BASE); - b.material.opacity = opened >= 0 && i !== opened ? 0.22 : on ? 0.95 : 0.62; + const dimmed = opened >= 0 && i !== opened; + if (live) { + // The strip carries the colour, so the slab tint must not fight it. + b.material.color.setHex(on ? 0xffffff : 0xd8d8dd); + b.material.opacity = dimmed ? 0.3 : 0.95; + } else { + b.material.color.copy(i === opened ? OPEN : on ? HOVER : BASE); + b.material.opacity = dimmed ? 0.22 : on ? 0.95 : 0.62; + } } subs.forEach((s, k) => { s.visible = opened >= 0; if (opened >= 0) { - const base = blocks[opened].position.y; - s.position.set(0, base + (k - 1.5) * 0.085, 0); + s.position.set(0, blocks[opened].position.y + (k - 1.5) * 0.085, 0); } }); - if (label) { - if (opened >= 0) { - label.textContent = `block ${opened} — ${SUB_LAYERS.map((s) => s[1]).join(" · ")}`; - } else if (hovered >= 0) { - label.textContent = `block ${hovered} of ${N_LAYER} · click to expand · n_ctx ${N_CTX}`; - } else { - label.textContent = `GPT-2 124M — ${N_LAYER} blocks, ${N_HEAD} heads, n_embd ${N_EMBD}`; - } + if (!label) return; + if (opened >= 0) { + label.textContent = `block ${opened} — ${subLayers(cfg).join(" · ")}`; + } else if (hovered >= 0) { + label.textContent = live + ? `block ${hovered} — ${cfg.nHead} heads × ${live} positions` + : `block ${hovered} of ${cfg.nLayer} · click to expand`; + } else if (live) { + label.textContent = + `live attention — ${cfg.nLayer} blocks × ${cfg.nHead} heads over ` + + `${live} of ${cfg.nCtx} positions`; + } else { + label.textContent = + `${cfg.name} — ${cfg.nLayer} blocks, ${cfg.nHead} heads, ` + + `n_embd ${cfg.nEmbd}`; } } - paint(); - // ── pointer: hand-rolled drag rotation, ~15 lines, no OrbitControls addon + // ── pointer: hand-rolled drag rotation, no OrbitControls addon ────────── + const pointer = new Vector2(); const raycaster = new Raycaster(); let dragging = false; let last = 0; - let spin = 0; - let manual = 0; - canvas.addEventListener("pointerdown", (e) => { + const onDown = (e) => { dragging = true; last = e.clientX; canvas.setPointerCapture(e.pointerId); - }); - canvas.addEventListener("pointerup", (e) => { + }; + const onUp = (e) => { dragging = false; canvas.releasePointerCapture(e.pointerId); - }); - canvas.addEventListener("pointermove", (e) => { + }; + const onMove = (e) => { const rect = canvas.getBoundingClientRect(); pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1; pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1; @@ -181,20 +266,28 @@ if (renderer) { paint(); if (still) render(); } - }); - canvas.addEventListener("pointerleave", () => { + }; + const onLeave = () => { dragging = false; if (hovered !== -1) { hovered = -1; paint(); if (still) render(); } - }); - canvas.addEventListener("click", () => { + }; + const onClick = () => { opened = hovered >= 0 && hovered !== opened ? hovered : -1; paint(); if (still) render(); - }); + }; + + canvas.addEventListener("pointerdown", onDown); + canvas.addEventListener("pointerup", onUp); + canvas.addEventListener("pointermove", onMove); + canvas.addEventListener("pointerleave", onLeave); + canvas.addEventListener("click", onClick); + + // ── loop ──────────────────────────────────────────────────────────────── function resize() { const w = canvas.clientWidth; @@ -210,9 +303,6 @@ if (renderer) { renderer.render(scene, camera); } - let still = reduced.matches; - let frame = 0; - function loop() { frame = requestAnimationFrame(loop); spin += 0.0022; @@ -236,18 +326,19 @@ if (renderer) { } } - reduced.addEventListener("change", () => { + const onReduced = () => { still = reduced.matches; stop(); start(); - }); - - window.addEventListener("resize", () => { + }; + const onResize = () => { if (still) render(); - }); + }; + reduced.addEventListener("change", onReduced); + window.addEventListener("resize", onResize); // Only run while visible: a permanently spinning scene drains laptop - // batteries, and initializing on first scroll keeps it off the critical path. + // batteries, and starting on first scroll keeps it off the critical path. const io = new IntersectionObserver( (entries) => { for (const e of entries) { @@ -259,8 +350,115 @@ if (renderer) { ); io.observe(canvas); - // The static diagram is a duplicate of what the scene shows; keep it for - // no-WebGL visitors, but collapse it to a summary when the scene works. - const stat = document.getElementById("stack-static"); - if (stat) stat.dataset.sceneOk = "1"; + build(); + start(); + + // ── public surface ────────────────────────────────────────────────────── + + return { + /** Resize the stack to the model that is actually loaded. */ + setConfig(next) { + const merged = { ...cfg, ...next }; + const rebuild = + merged.nLayer !== cfg.nLayer || + merged.nHead !== cfg.nHead || + merged.nCtx !== cfg.nCtx; + cfg = merged; + if (rebuild) { + teardown(); + hovered = -1; + opened = -1; + // New strips are empty, so the stack is idle again whatever it was. + live = 0; + build(); + } else { + paint(); + } + if (still) render(); + }, + + /** + * One block's attention for the token just produced: `weights` is + * head-major `nHead × kvLen`, exactly what the model attended with. + * + * Each head's row is scaled by its own maximum before colouring — + * otherwise a head spread over 200 positions is uniformly black next to + * one focused on three. The gamma is display only; the numbers are the + * model's. + */ + pushAttention(layer, nHead, weights) { + const strip = strips[layer]; + if (!strip || !nHead) return; + // `stride` is the model's kv_len; `kv` is what fits the texture. They + // differ only if the config went stale, and conflating them would shear + // every row. + const stride = Math.floor(weights.length / nHead); + const kv = Math.min(stride, cfg.nCtx); + const rows = Math.min(nHead, cfg.nHead); + if (kv < 1) return; + for (let h = 0; h < rows; h++) { + let max = 0; + for (let p = 0; p < kv; p++) { + const w = weights[h * stride + p]; + if (w > max) max = w; + } + const inv = max > 0 ? 1 / max : 0; + for (let p = 0; p < kv; p++) { + ramp( + Math.pow(weights[h * stride + p] * inv, 0.6), + strip.data, + (h * cfg.nCtx + p) * 4, + ); + } + } + strip.texture.needsUpdate = true; + // Show only the filled part of the texture, stretched across the slab. + strip.texture.repeat.set(kv / cfg.nCtx, 1); + + const mat = blocks[layer].material; + if (mat.map !== strip.texture) { + mat.map = strip.texture; + mat.emissiveMap = strip.texture; + mat.emissiveIntensity = 0.55; + mat.needsUpdate = true; + } + if (live !== kv) { + live = kv; + paint(); + } + // Reduced motion means no render loop, but a strip update is data, not + // decoration, so it still gets drawn. + if (still) render(); + }, + + /** Back to the idle stack — called at the start of every run. */ + reset() { + live = 0; + for (let i = 0; i < blocks.length; i++) { + strips[i].data.fill(0); + strips[i].texture.needsUpdate = true; + const mat = blocks[i].material; + mat.map = null; + mat.emissiveMap = null; + mat.emissiveIntensity = 0; + mat.needsUpdate = true; + } + paint(); + if (still) render(); + }, + + dispose() { + stop(); + io.disconnect(); + reduced.removeEventListener("change", onReduced); + window.removeEventListener("resize", onResize); + canvas.removeEventListener("pointerdown", onDown); + canvas.removeEventListener("pointerup", onUp); + canvas.removeEventListener("pointermove", onMove); + canvas.removeEventListener("pointerleave", onLeave); + canvas.removeEventListener("click", onClick); + teardown(); + renderer.dispose(); + }, + }; } From f4a69954a3e0025dc1848a24659db0f96e3796df Mon Sep 17 00:00:00 2001 From: bowen Date: Sun, 26 Jul 2026 13:13:30 +0000 Subject: [PATCH 5/6] refactor(site): merge demo and architecture, drop verification and roadmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nine sections become five, and every one now answers what Forge is, why it exists, or shows it working. - #stack is absorbed into #demo ("Watch it think"): the 3D view and the demo controls are two columns of one section, canvas first so the visual leads on mobile. Merging them forces a correctness fix — the old section described GPT-2 124M (12 blocks, 12 heads, n_ctx 1024) while the demo has always run the char model's 6/6/384/256. - The ASCII architecture
 becomes a semantic 
    inside
    . Fixed width could not reflow, so it was the one element needing horizontal scrolling on a phone to read a diagram whose point is a vertical flow. It doubles as the no-WebGL fallback target. - #verification and #roadmap are gone; one parity line survives in the hero, and the footer already links Forge_Roadmap_V4.md. The dead stat.dataset.sceneOk hook (no CSS rule ever matched it) went with them. - #what and the "not a rebrand" card merge into #why: three cards for Rust, WebGPU, and the CPU reference backend, at roughly half the words. - The kernels lede drops "because GPT-2 inference or training needs it". Two fixes found on the way. gen_kernels.py emitted one more than its regex consumed, so every build shipped an unbalanced tag. And #demo-charset and #demo-progress-wrap carried Tailwind's `hidden` class while demo.js toggled the `hidden` property — display:none from a class survives hidden = false, so the charset warning and the 43 MB progress bar could never appear. plan/03-website.md is updated to match: the new section list, three.js shipping as two files, the attention view, and the measured probe cost. Co-Authored-By: Claude Opus 5 Signed-off-by: bowen --- docs/src/index.html | 586 +++++++++++++++-------------------------- plan/03-website.md | 181 +++++++++---- scripts/gen_kernels.py | 5 +- 3 files changed, 344 insertions(+), 428 deletions(-) diff --git a/docs/src/index.html b/docs/src/index.html index 254364a..7cbf3f2 100644 --- a/docs/src/index.html +++ b/docs/src/index.html @@ -13,6 +13,9 @@ + @@ -33,10 +36,9 @@ WebGPU-native.

    - Train a small Shakespeare model from scratch, then load real OpenAI - GPT-2 124M weights with the same code. Every operator, WGSL kernel, - and module exists because GPT-2 needs it. + Forge trains a small Shakespeare model from scratch and runs real + OpenAI GPT-2 124M weights with the same code — in Rust, on WebGPU. + It is built to be read as much as run: every operator, WGSL kernel, + and module exists because GPT-2 needs it, and each one is checked + against a plain-Rust CPU implementation.

    Run it in your browser @@ -68,314 +72,242 @@

    >

    -
    -
    -
    Model on this page
    -
    43 MB
    -
    -
    -
    WGSL kernels
    -
    23
    -
    -
    -
    CPU ↔ WGPU logits
    -
    8.4e-5
    -
    -
    -
    Forge ↔ HF
    -
    1.75e-4
    -
    -
    + +

    + verified — CPU and WGPU + logits agree to 8.4e-5, and GPT-2's + output matches HuggingFace + transformers token for token + (tests/gpt2_e2e.rs, on an RTX A5000). +

    - +
    -

    Live demo — Shakespeare, on your GPU

    +

    Watch it think

    - A 10.77M-parameter character-level GPT (6 layers, 6 heads, 384 - dimensions, 65-token vocabulary), trained from scratch by Forge on - Tiny Shakespeare and running here through WebGPU in your browser. - No server does the work — your GPU does. + A 10.77M-parameter character-level GPT — 6 blocks, 6 heads, 384 + dimensions, a 65-character vocabulary — trained from scratch by + Forge on Tiny Shakespeare and running here on your own GPU. The + attention beside it is read back off that GPU as each character is + produced, not an animation of one.

    -
    - -
    - - -
    - - -
    -
    -

    Two backends, one model

    -

    - Model code is backend-agnostic: the same - Gpt2 runs on either device. -

    -
    -
    -

    WGPU backend

    -

    - The production path, via - wgpu - — Vulkan, Metal, D3D12, and browser WebGPU from one set of WGSL - kernels. Reaching an NVIDIA GPU and reaching WebGPU are the same - code path; there is no separate CUDA backend to build. -

    -
    -
    -

    CPU backend

    -

    - A mathematically identical reference implementation, used for - testing and verification. Every kernel is checked against it, - which is what makes the parity numbers below meaningful. -

    -
    -
    - -
    -

    Why “nanoGPT-class” is not a rebrand

    -

    - nanoGPT is the GPT-2 architecture — pre-LN blocks, causal - self-attention, a 4× GELU MLP, learned positional embeddings, and - weight tying — and its own headline feature is loading OpenAI - GPT-2 weights. This is one framework, not two modes. -

    -

    - One honest caveat. - Forge stores Linear weights as - [in, out] (the HF Conv1D - convention), whereas upstream nanoGPT uses - nn.Linear's - [out, in]. Checkpoints are - not - binary-interchangeable with nanoGPT - .pt files: four keys per block would - need transposing, and Forge reads safetensors rather than PyTorch - pickles. + +

    + + The same stack, in text + +
      +
    1. + models/gpt2/ + — config, the 6 transformer blocks above, KV-cache decode, and + generation. Each block is LayerNorm → causal self-attention + (6 heads × 64) → LayerNorm → MLP (384 → 1536 → 384, GELU). +
    2. +
    3. + nn/, autograd/, optim/ + — Linear, LayerNorm, Embedding with a row-chunked token table; + a tape-based reverse mode; AdamW. +
    4. +
    5. + ops.rs + — shape-checked dispatch, one API over both backends. +
    6. +
    7. + backend/ + — WGPU (23 WGSL kernels) and CPU (a plain Rust reference). +
    8. +
    +

    + Context 256 characters, 65-token vocabulary, LM head weight-tied + to the token embedding. GPT-2 124M is the same code with + 12 blocks, 12 heads and n_embd 768 — 548 MB of weights, so it + stays a local artifact: + ./scripts/build_site.sh && ./scripts/serve_web.sh.

    -
    -
    -
    +
    - -
    -
    -

    The stack, twelve blocks deep

    -

    - GPT-2 124M is twelve identical transformer blocks. Hover one to - highlight it; click to expand its sub-layers with real tensor - shapes. +

    + No server does the work — your GPU does. Forge needs no + SharedArrayBuffer, because + rayon is native-only, so this page is + plain static files.

    - -
    -
    - -

    -
    -
    - - -
    -

    Architecture

    -
    -
    -GPT-2 model            models/gpt2/  config, blocks, KV-cache, generation
    -  ↓
    -nn modules + autograd  nn/  Linear, LayerNorm, Embedding (row-chunked wte)
    -                       autograd/  tape, backward ops     optim/  AdamW
    -  ↓
    -tensor ops             ops.rs  shape-checked dispatch, both backends
    -  ↓
    -backend abstraction    backend/
    -  ↓
    -WGPU  ·············  CPU
    -23 WGSL kernels      plain Rust reference
    -
    -

    - Per block: LayerNorm → causal self-attention (12 heads of 64 - dimensions) → LayerNorm → MLP (768 → 3072 → 768, GELU). Context - 1024 tokens, vocabulary 50257, LM head weight-tied to the token - embedding. -

    -
    - -
    + +
    -

    Verification

    -

    - Measured on this repository, not estimated. The CPU backend is the - correctness reference; HF transformers - is the external one. -

    - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - Maximum absolute logit differences -
    ComparisonMax differenceSuite
    CPU ↔ WGPU logits8.4e-5tests/gpt2_e2e.rs
    Forge ↔ HF transformers1.75e-4tests/gpt2_e2e.rs
    Every WGSL kernel ↔ CPU≤ 1e-4tests/op_parity.rs
    -
    +

    Why Forge is built this way

    +

    Three decisions, and what each one buys.

    -
    +
    -

    Identical greedy output

    +

    Rust, not Python

    - Greedy continuations match token-for-token across CPU, WGPU, and - HF transformers. + Explicit memory and dispatch, no interpreter in the loop, and + one binary to run. Training and inference are the same code on + the same tensors, so there is no second implementation to keep + honest.

    -

    Gradients too

    +

    WebGPU, not CUDA

    - Analytic gradients are checked against central differences, and - CPU ↔ WGPU gradient parity is a gate — not just the forward pass. + One set of WGSL kernels reaches Vulkan, Metal, D3D12, and the + browser through + wgpu. + Reaching an NVIDIA GPU and reaching this page are the same code + path; there is no CUDA toolchain to install.

    -

    41 tests, 9 suites

    +

    A CPU reference backend

    - Kernels, tokenizers, autograd, training ops, optimizer - convergence, KV-cache decode, streaming, and end-to-end GPT-2. + Every kernel has a mathematically identical plain-Rust twin to + check against. That is what makes the parity numbers mean + something — and what makes the thing teachable, since the + reference and the kernel can be read side by side.

    + +

    + “nanoGPT-class” is not a rebrand. + nanoGPT is the GPT-2 architecture — pre-LN blocks, causal + self-attention, a 4× GELU MLP, learned positional embeddings, weight + tying — and loading OpenAI's weights is its own headline feature. + One caveat: Forge stores Linear + weights as [in, out] (the HF Conv1D + convention) rather than nanoGPT's + [out, in], and reads safetensors + rather than PyTorch pickles, so checkpoints are not binary- + interchangeable with nanoGPT .pt + files. +

    @@ -384,8 +316,9 @@

    41 tests, 9 suites

    23 WGSL kernels

    - The complete compute surface. Nothing here is generic — each kernel - exists because GPT-2 inference or training needs it. + The complete compute surface, generated from + shaders/ at build time so this list + cannot drift from the code.

    @@ -506,105 +439,6 @@

    Run this demo locally

    - - -
    -
    -

    Roadmap

    -

    - Stages 1–11 are implemented and gated by tests. Stage 12 is - explicitly not a 1.0 requirement. -

    - -
      -
    1. - 1 ✓ - Core types - Shape, DType, Device, Error, Arc'd contiguous Tensor. -
    2. -
    3. - 2 ✓ - CPU reference ops - Plain Rust, unit-tested against hand-computed values. -
    4. -
    5. - 3 ✓ - WebGPU runtime - Adapter, device, queue, shader loader, pipeline cache. -
    6. -
    7. - 4 ✓ - WGSL kernels - Every kernel within 1e-4 of the CPU reference. -
    8. -
    9. - 5 ✓ - Tokenizer & serialization - Byte-level BPE, character-level vocab, safetensors. -
    10. -
    11. - 6 ✓ - GPT-2 inference - Greedy and top-k sampling, weight-tied chunked LM head. -
    12. -
    13. - 7 ✓ - KV-cache decode - Token-identical to full recompute over ≥ 64 tokens. -
    14. -
    15. - 8 ✓ - Autograd - Tape-based reverse mode over the existing ops layer. -
    16. -
    17. - 9 ✓ - Training modules - Deterministic dropout, fused cross-entropy, AdamW. -
    18. -
    19. - 10 ✓ - GPT-2 training - Tiny Shakespeare from scratch, gradient accumulation, - checkpoints. -
    20. -
    21. - 11 ✓ - Browser deployment - wasm32 + WebGPU — the demo at the top of this page. -
    22. -
    23. - 12 - Optimization - Kernel fusion, buffer pooling, matmul tiling. Post-1.0. -
    24. -
    -
    -
    @@ -632,8 +466,8 @@

    Roadmap

    - - +