(function(){const P=document.createElement("link").relList;if(P&&P.supports&&P.supports("modulepreload"))return;for(const W of document.querySelectorAll('link[rel="modulepreload"]'))Z(W);new MutationObserver(W=>{for(const V of W)if(V.type==="childList")for(const fn of V.addedNodes)fn.tagName==="LINK"&&fn.rel==="modulepreload"&&Z(fn)}).observe(document,{childList:!0,subtree:!0});function E(W){const V={};return W.integrity&&(V.integrity=W.integrity),W.referrerPolicy&&(V.referrerPolicy=W.referrerPolicy),W.crossOrigin==="use-credentials"?V.credentials="include":W.crossOrigin==="anonymous"?V.credentials="omit":V.credentials="same-origin",V}function Z(W){if(W.ep)return;W.ep=!0;const V=E(W);fetch(W.href,V)}})();function It(a,P){return class extends a{constructor(...E){super(...E),P(this)}}}const Et=It(Array,a=>a.fill(0));let b=1e-6;function Ft(a){function P(n=0,s=0){const t=new a(2);return n!==void 0&&(t[0]=n,s!==void 0&&(t[1]=s)),t}const E=P;function Z(n,s,t){const e=t??new a(2);return e[0]=n,e[1]=s,e}function W(n,s){const t=s??new a(2);return t[0]=Math.ceil(n[0]),t[1]=Math.ceil(n[1]),t}function V(n,s){const t=s??new a(2);return t[0]=Math.floor(n[0]),t[1]=Math.floor(n[1]),t}function fn(n,s){const t=s??new a(2);return t[0]=Math.round(n[0]),t[1]=Math.round(n[1]),t}function ln(n,s=0,t=1,e){const u=e??new a(2);return u[0]=Math.min(t,Math.max(s,n[0])),u[1]=Math.min(t,Math.max(s,n[1])),u}function qn(n,s,t){const e=t??new a(2);return e[0]=n[0]+s[0],e[1]=n[1]+s[1],e}function Gn(n,s,t,e){const u=e??new a(2);return u[0]=n[0]+s[0]*t,u[1]=n[1]+s[1]*t,u}function Bn(n,s){const t=n[0],e=n[1],u=s[0],h=s[1],y=Math.sqrt(t*t+e*e),o=Math.sqrt(u*u+h*h),i=y*o,d=i&&vn(n,s)/i;return Math.acos(d)}function dn(n,s,t){const e=t??new a(2);return e[0]=n[0]-s[0],e[1]=n[1]-s[1],e}const In=dn;function en(n,s){return Math.abs(n[0]-s[0])1e-5?(t[0]=e/h,t[1]=u/h):(t[0]=0,t[1]=0),t}function T(n,s){const t=s??new a(2);return t[0]=-n[0],t[1]=-n[1],t}function S(n,s){const t=s??new a(2);return t[0]=n[0],t[1]=n[1],t}const F=S;function L(n,s,t){const e=t??new a(2);return e[0]=n[0]*s[0],e[1]=n[1]*s[1],e}const N=L;function O(n,s,t){const e=t??new a(2);return e[0]=n[0]/s[0],e[1]=n[1]/s[1],e}const G=O;function Y(n=1,s){const t=s??new a(2),e=Math.random()*2*Math.PI;return t[0]=Math.cos(e)*n,t[1]=Math.sin(e)*n,t}function M(n){const s=n??new a(2);return s[0]=0,s[1]=0,s}function A(n,s,t){const e=t??new a(2),u=n[0],h=n[1];return e[0]=u*s[0]+h*s[4]+s[12],e[1]=u*s[1]+h*s[5]+s[13],e}function c(n,s,t){const e=t??new a(2),u=n[0],h=n[1];return e[0]=s[0]*u+s[4]*h+s[8],e[1]=s[1]*u+s[5]*h+s[9],e}function r(n,s,t,e){const u=e??new a(2),h=n[0]-s[0],y=n[1]-s[1],o=Math.sin(t),i=Math.cos(t);return u[0]=h*i-y*o+s[0],u[1]=h*o+y*i+s[1],u}function f(n,s,t){const e=t??new a(2);return z(n,e),wn(e,s,e)}function p(n,s,t){const e=t??new a(2);return C(n)>s?f(n,s,e):S(n,e)}function m(n,s,t){const e=t??new a(2);return Dn(n,s,.5,e)}return{create:P,fromValues:E,set:Z,ceil:W,floor:V,round:fn,clamp:ln,add:qn,addScaled:Gn,angle:Bn,subtract:dn,sub:In,equalsApproximately:en,equals:Tn,lerp:Dn,lerpV:yn,max:En,min:xn,mulScalar:wn,scale:Fn,divScalar:_n,inverse:zn,invert:Un,cross:An,dot:vn,length:C,len:Ln,lengthSq:X,lenSq:Q,distance:$,dist:l,distanceSq:v,distSq:g,normalize:z,negate:T,copy:S,clone:F,multiply:L,mul:N,divide:O,div:G,random:Y,zero:M,transformMat4:A,transformMat3:c,rotate:r,setLength:f,truncate:p,midpoint:m}}const lt=new Map;function _t(a){let P=lt.get(a);return P||(P=Ft(a),lt.set(a,P)),P}function Lt(a){const P=_t(a);function E(l,v,g,z,T,S,F,L,N){const O=new a(12);return O[3]=0,O[7]=0,O[11]=0,l!==void 0&&(O[0]=l,v!==void 0&&(O[1]=v,g!==void 0&&(O[2]=g,z!==void 0&&(O[4]=z,T!==void 0&&(O[5]=T,S!==void 0&&(O[6]=S,F!==void 0&&(O[8]=F,L!==void 0&&(O[9]=L,N!==void 0&&(O[10]=N))))))))),O}function Z(l,v,g,z,T,S,F,L,N,O){const G=O??new a(12);return G[0]=l,G[1]=v,G[2]=g,G[3]=0,G[4]=z,G[5]=T,G[6]=S,G[7]=0,G[8]=F,G[9]=L,G[10]=N,G[11]=0,G}function W(l,v){const g=v??new a(12);return g[0]=l[0],g[1]=l[1],g[2]=l[2],g[3]=0,g[4]=l[4],g[5]=l[5],g[6]=l[6],g[7]=0,g[8]=l[8],g[9]=l[9],g[10]=l[10],g[11]=0,g}function V(l,v){const g=v??new a(12),z=l[0],T=l[1],S=l[2],F=l[3],L=z+z,N=T+T,O=S+S,G=z*L,Y=T*L,M=T*N,A=S*L,c=S*N,r=S*O,f=F*L,p=F*N,m=F*O;return g[0]=1-M-r,g[1]=Y+m,g[2]=A-p,g[3]=0,g[4]=Y-m,g[5]=1-G-r,g[6]=c+f,g[7]=0,g[8]=A+p,g[9]=c-f,g[10]=1-G-M,g[11]=0,g}function fn(l,v){const g=v??new a(12);return g[0]=-l[0],g[1]=-l[1],g[2]=-l[2],g[4]=-l[4],g[5]=-l[5],g[6]=-l[6],g[8]=-l[8],g[9]=-l[9],g[10]=-l[10],g}function ln(l,v){const g=v??new a(12);return g[0]=l[0],g[1]=l[1],g[2]=l[2],g[4]=l[4],g[5]=l[5],g[6]=l[6],g[8]=l[8],g[9]=l[9],g[10]=l[10],g}const qn=ln;function Gn(l,v){return Math.abs(l[0]-v[0])1e-5?(d[0]=w/_,d[1]=x/_,d[2]=D/_):(d[0]=0,d[1]=0,d[2]=0),d}function T(o,i){const d=i??new a(3);return d[0]=-o[0],d[1]=-o[1],d[2]=-o[2],d}function S(o,i){const d=i??new a(3);return d[0]=o[0],d[1]=o[1],d[2]=o[2],d}const F=S;function L(o,i,d){const w=d??new a(3);return w[0]=o[0]*i[0],w[1]=o[1]*i[1],w[2]=o[2]*i[2],w}const N=L;function O(o,i,d){const w=d??new a(3);return w[0]=o[0]/i[0],w[1]=o[1]/i[1],w[2]=o[2]/i[2],w}const G=O;function Y(o=1,i){const d=i??new a(3),w=Math.random()*2*Math.PI,x=Math.random()*2-1,D=Math.sqrt(1-x*x)*o;return d[0]=Math.cos(w)*D,d[1]=Math.sin(w)*D,d[2]=x*o,d}function M(o){const i=o??new a(3);return i[0]=0,i[1]=0,i[2]=0,i}function A(o,i,d){const w=d??new a(3),x=o[0],D=o[1],_=o[2],U=i[3]*x+i[7]*D+i[11]*_+i[15]||1;return w[0]=(i[0]*x+i[4]*D+i[8]*_+i[12])/U,w[1]=(i[1]*x+i[5]*D+i[9]*_+i[13])/U,w[2]=(i[2]*x+i[6]*D+i[10]*_+i[14])/U,w}function c(o,i,d){const w=d??new a(3),x=o[0],D=o[1],_=o[2];return w[0]=x*i[0*4+0]+D*i[1*4+0]+_*i[2*4+0],w[1]=x*i[0*4+1]+D*i[1*4+1]+_*i[2*4+1],w[2]=x*i[0*4+2]+D*i[1*4+2]+_*i[2*4+2],w}function r(o,i,d){const w=d??new a(3),x=o[0],D=o[1],_=o[2];return w[0]=x*i[0]+D*i[4]+_*i[8],w[1]=x*i[1]+D*i[5]+_*i[9],w[2]=x*i[2]+D*i[6]+_*i[10],w}function f(o,i,d){const w=d??new a(3),x=i[0],D=i[1],_=i[2],U=i[3]*2,I=o[0],q=o[1],B=o[2],R=D*B-_*q,H=_*I-x*B,K=x*q-D*I;return w[0]=I+R*U+(D*K-_*H)*2,w[1]=q+H*U+(_*R-x*K)*2,w[2]=B+K*U+(x*H-D*R)*2,w}function p(o,i){const d=i??new a(3);return d[0]=o[12],d[1]=o[13],d[2]=o[14],d}function m(o,i,d){const w=d??new a(3),x=i*4;return w[0]=o[x+0],w[1]=o[x+1],w[2]=o[x+2],w}function n(o,i){const d=i??new a(3),w=o[0],x=o[1],D=o[2],_=o[4],U=o[5],I=o[6],q=o[8],B=o[9],R=o[10];return d[0]=Math.sqrt(w*w+x*x+D*D),d[1]=Math.sqrt(_*_+U*U+I*I),d[2]=Math.sqrt(q*q+B*B+R*R),d}function s(o,i,d,w){const x=w??new a(3),D=[],_=[];return D[0]=o[0]-i[0],D[1]=o[1]-i[1],D[2]=o[2]-i[2],_[0]=D[0],_[1]=D[1]*Math.cos(d)-D[2]*Math.sin(d),_[2]=D[1]*Math.sin(d)+D[2]*Math.cos(d),x[0]=_[0]+i[0],x[1]=_[1]+i[1],x[2]=_[2]+i[2],x}function t(o,i,d,w){const x=w??new a(3),D=[],_=[];return D[0]=o[0]-i[0],D[1]=o[1]-i[1],D[2]=o[2]-i[2],_[0]=D[2]*Math.sin(d)+D[0]*Math.cos(d),_[1]=D[1],_[2]=D[2]*Math.cos(d)-D[0]*Math.sin(d),x[0]=_[0]+i[0],x[1]=_[1]+i[1],x[2]=_[2]+i[2],x}function e(o,i,d,w){const x=w??new a(3),D=[],_=[];return D[0]=o[0]-i[0],D[1]=o[1]-i[1],D[2]=o[2]-i[2],_[0]=D[0]*Math.cos(d)-D[1]*Math.sin(d),_[1]=D[0]*Math.sin(d)+D[1]*Math.cos(d),_[2]=D[2],x[0]=_[0]+i[0],x[1]=_[1]+i[1],x[2]=_[2]+i[2],x}function u(o,i,d){const w=d??new a(3);return z(o,w),wn(w,i,w)}function h(o,i,d){const w=d??new a(3);return C(o)>i?u(o,i,w):S(o,w)}function y(o,i,d){const w=d??new a(3);return Dn(o,i,.5,w)}return{create:P,fromValues:E,set:Z,ceil:W,floor:V,round:fn,clamp:ln,add:qn,addScaled:Gn,angle:Bn,subtract:dn,sub:In,equalsApproximately:en,equals:Tn,lerp:Dn,lerpV:yn,max:En,min:xn,mulScalar:wn,scale:Fn,divScalar:_n,inverse:zn,invert:Un,cross:An,dot:vn,length:C,len:Ln,lengthSq:X,lenSq:Q,distance:$,dist:l,distanceSq:v,distSq:g,normalize:z,negate:T,copy:S,clone:F,multiply:L,mul:N,divide:O,div:G,random:Y,zero:M,transformMat4:A,transformMat4Upper3x3:c,transformMat3:r,transformQuat:f,getTranslation:p,getAxis:m,getScaling:n,rotateX:s,rotateY:t,rotateZ:e,setLength:u,truncate:h,midpoint:y}}const wt=new Map;function ot(a){let P=wt.get(a);return P||(P=bt(a),wt.set(a,P)),P}function Rt(a){const P=ot(a);function E(n,s,t,e,u,h,y,o,i,d,w,x,D,_,U,I){const q=new a(16);return n!==void 0&&(q[0]=n,s!==void 0&&(q[1]=s,t!==void 0&&(q[2]=t,e!==void 0&&(q[3]=e,u!==void 0&&(q[4]=u,h!==void 0&&(q[5]=h,y!==void 0&&(q[6]=y,o!==void 0&&(q[7]=o,i!==void 0&&(q[8]=i,d!==void 0&&(q[9]=d,w!==void 0&&(q[10]=w,x!==void 0&&(q[11]=x,D!==void 0&&(q[12]=D,_!==void 0&&(q[13]=_,U!==void 0&&(q[14]=U,I!==void 0&&(q[15]=I)))))))))))))))),q}function Z(n,s,t,e,u,h,y,o,i,d,w,x,D,_,U,I,q){const B=q??new a(16);return B[0]=n,B[1]=s,B[2]=t,B[3]=e,B[4]=u,B[5]=h,B[6]=y,B[7]=o,B[8]=i,B[9]=d,B[10]=w,B[11]=x,B[12]=D,B[13]=_,B[14]=U,B[15]=I,B}function W(n,s){const t=s??new a(16);return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=0,t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=0,t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function V(n,s){const t=s??new a(16),e=n[0],u=n[1],h=n[2],y=n[3],o=e+e,i=u+u,d=h+h,w=e*o,x=u*o,D=u*i,_=h*o,U=h*i,I=h*d,q=y*o,B=y*i,R=y*d;return t[0]=1-D-I,t[1]=x+R,t[2]=_-B,t[3]=0,t[4]=x-R,t[5]=1-w-I,t[6]=U+q,t[7]=0,t[8]=_+B,t[9]=U-q,t[10]=1-w-D,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t}function fn(n,s){const t=s??new a(16);return t[0]=-n[0],t[1]=-n[1],t[2]=-n[2],t[3]=-n[3],t[4]=-n[4],t[5]=-n[5],t[6]=-n[6],t[7]=-n[7],t[8]=-n[8],t[9]=-n[9],t[10]=-n[10],t[11]=-n[11],t[12]=-n[12],t[13]=-n[13],t[14]=-n[14],t[15]=-n[15],t}function ln(n,s){const t=s??new a(16);return t[0]=n[0],t[1]=n[1],t[2]=n[2],t[3]=n[3],t[4]=n[4],t[5]=n[5],t[6]=n[6],t[7]=n[7],t[8]=n[8],t[9]=n[9],t[10]=n[10],t[11]=n[11],t[12]=n[12],t[13]=n[13],t[14]=n[14],t[15]=n[15],t}const qn=ln;function Gn(n,s){return Math.abs(n[0]-s[0])b?(c[0]=M[0]/f,c[1]=M[1]/f,c[2]=M[2]/f):(c[0]=1,c[1]=0,c[2]=0),{angle:r,axis:c}}function ln(M,A){const c=C(M,A);return Math.acos(2*c*c-1)}function qn(M,A,c){const r=c??new a(4),f=M[0],p=M[1],m=M[2],n=M[3],s=A[0],t=A[1],e=A[2],u=A[3];return r[0]=f*u+n*s+p*e-m*t,r[1]=p*u+n*t+m*s-f*e,r[2]=m*u+n*e+f*t-p*s,r[3]=n*u-f*s-p*t-m*e,r}const Gn=qn;function Bn(M,A,c){const r=c??new a(4),f=A*.5,p=M[0],m=M[1],n=M[2],s=M[3],t=Math.sin(f),e=Math.cos(f);return r[0]=p*e+s*t,r[1]=m*e+n*t,r[2]=n*e-m*t,r[3]=s*e-p*t,r}function dn(M,A,c){const r=c??new a(4),f=A*.5,p=M[0],m=M[1],n=M[2],s=M[3],t=Math.sin(f),e=Math.cos(f);return r[0]=p*e-n*t,r[1]=m*e+s*t,r[2]=n*e+p*t,r[3]=s*e-m*t,r}function In(M,A,c){const r=c??new a(4),f=A*.5,p=M[0],m=M[1],n=M[2],s=M[3],t=Math.sin(f),e=Math.cos(f);return r[0]=p*e+m*t,r[1]=m*e-p*t,r[2]=n*e+s*t,r[3]=s*e-n*t,r}function en(M,A,c,r){const f=r??new a(4),p=M[0],m=M[1],n=M[2],s=M[3];let t=A[0],e=A[1],u=A[2],h=A[3],y=p*t+m*e+n*u+s*h;y<0&&(y=-y,t=-t,e=-e,u=-u,h=-h);let o,i;if(1-y>b){const d=Math.acos(y),w=Math.sin(d);o=Math.sin((1-c)*d)/w,i=Math.sin(c*d)/w}else o=1-c,i=c;return f[0]=o*p+i*t,f[1]=o*m+i*e,f[2]=o*n+i*u,f[3]=o*s+i*h,f}function Tn(M,A){const c=A??new a(4),r=M[0],f=M[1],p=M[2],m=M[3],n=r*r+f*f+p*p+m*m,s=n?1/n:0;return c[0]=-r*s,c[1]=-f*s,c[2]=-p*s,c[3]=m*s,c}function Dn(M,A){const c=A??new a(4);return c[0]=-M[0],c[1]=-M[1],c[2]=-M[2],c[3]=M[3],c}function yn(M,A){const c=A??new a(4),r=M[0]+M[5]+M[10];if(r>0){const f=Math.sqrt(r+1);c[3]=.5*f;const p=.5/f;c[0]=(M[6]-M[9])*p,c[1]=(M[8]-M[2])*p,c[2]=(M[1]-M[4])*p}else{let f=0;M[5]>M[0]&&(f=1),M[10]>M[f*4+f]&&(f=2);const p=(f+1)%3,m=(f+2)%3,n=Math.sqrt(M[f*4+f]-M[p*4+p]-M[m*4+m]+1);c[f]=.5*n;const s=.5/n;c[3]=(M[p*4+m]-M[m*4+p])*s,c[p]=(M[p*4+f]+M[f*4+p])*s,c[m]=(M[m*4+f]+M[f*4+m])*s}return c}function En(M,A,c,r,f){const p=f??new a(4),m=M*.5,n=A*.5,s=c*.5,t=Math.sin(m),e=Math.cos(m),u=Math.sin(n),h=Math.cos(n),y=Math.sin(s),o=Math.cos(s);switch(r){case"xyz":p[0]=t*h*o+e*u*y,p[1]=e*u*o-t*h*y,p[2]=e*h*y+t*u*o,p[3]=e*h*o-t*u*y;break;case"xzy":p[0]=t*h*o-e*u*y,p[1]=e*u*o-t*h*y,p[2]=e*h*y+t*u*o,p[3]=e*h*o+t*u*y;break;case"yxz":p[0]=t*h*o+e*u*y,p[1]=e*u*o-t*h*y,p[2]=e*h*y-t*u*o,p[3]=e*h*o+t*u*y;break;case"yzx":p[0]=t*h*o+e*u*y,p[1]=e*u*o+t*h*y,p[2]=e*h*y-t*u*o,p[3]=e*h*o-t*u*y;break;case"zxy":p[0]=t*h*o-e*u*y,p[1]=e*u*o+t*h*y,p[2]=e*h*y+t*u*o,p[3]=e*h*o-t*u*y;break;case"zyx":p[0]=t*h*o-e*u*y,p[1]=e*u*o+t*h*y,p[2]=e*h*y-t*u*o,p[3]=e*h*o+t*u*y;break;default:throw new Error(`Unknown rotation order: ${r}`)}return p}function xn(M,A){const c=A??new a(4);return c[0]=M[0],c[1]=M[1],c[2]=M[2],c[3]=M[3],c}const wn=xn;function Fn(M,A,c){const r=c??new a(4);return r[0]=M[0]+A[0],r[1]=M[1]+A[1],r[2]=M[2]+A[2],r[3]=M[3]+A[3],r}function _n(M,A,c){const r=c??new a(4);return r[0]=M[0]-A[0],r[1]=M[1]-A[1],r[2]=M[2]-A[2],r[3]=M[3]-A[3],r}const zn=_n;function Un(M,A,c){const r=c??new a(4);return r[0]=M[0]*A,r[1]=M[1]*A,r[2]=M[2]*A,r[3]=M[3]*A,r}const An=Un;function vn(M,A,c){const r=c??new a(4);return r[0]=M[0]/A,r[1]=M[1]/A,r[2]=M[2]/A,r[3]=M[3]/A,r}function C(M,A){return M[0]*A[0]+M[1]*A[1]+M[2]*A[2]+M[3]*A[3]}function Ln(M,A,c,r){const f=r??new a(4);return f[0]=M[0]+c*(A[0]-M[0]),f[1]=M[1]+c*(A[1]-M[1]),f[2]=M[2]+c*(A[2]-M[2]),f[3]=M[3]+c*(A[3]-M[3]),f}function X(M){const A=M[0],c=M[1],r=M[2],f=M[3];return Math.sqrt(A*A+c*c+r*r+f*f)}const Q=X;function $(M){const A=M[0],c=M[1],r=M[2],f=M[3];return A*A+c*c+r*r+f*f}const l=$;function v(M,A){const c=A??new a(4),r=M[0],f=M[1],p=M[2],m=M[3],n=Math.sqrt(r*r+f*f+p*p+m*m);return n>1e-5?(c[0]=r/n,c[1]=f/n,c[2]=p/n,c[3]=m/n):(c[0]=0,c[1]=0,c[2]=0,c[3]=1),c}function g(M,A){return Math.abs(M[0]-A[0]).999999?(r[0]=0,r[1]=0,r[2]=0,r[3]=1,r):(P.cross(M,A,S),r[0]=S[0],r[1]=S[1],r[2]=S[2],r[3]=1+f,v(r,r))}const O=new a(4),G=new a(4);function Y(M,A,c,r,f,p){const m=p??new a(4);return en(M,r,f,O),en(A,c,f,G),en(O,G,2*f*(1-f),m),m}return{create:E,fromValues:Z,set:W,fromAxisAngle:V,toAxisAngle:fn,angle:ln,multiply:qn,mul:Gn,rotateX:Bn,rotateY:dn,rotateZ:In,slerp:en,inverse:Tn,conjugate:Dn,fromMat:yn,fromEuler:En,copy:xn,clone:wn,add:Fn,subtract:_n,sub:zn,mulScalar:Un,scale:An,divScalar:vn,dot:C,lerp:Ln,length:X,len:Q,lengthSq:$,lenSq:l,normalize:v,equalsApproximately:g,equals:z,identity:T,rotationTo:N,sqlerp:Y}}const ht=new Map;function Wt(a){let P=ht.get(a);return P||(P=Nt(a),ht.set(a,P)),P}function Ht(a){function P(c,r,f,p){const m=new a(4);return c!==void 0&&(m[0]=c,r!==void 0&&(m[1]=r,f!==void 0&&(m[2]=f,p!==void 0&&(m[3]=p)))),m}const E=P;function Z(c,r,f,p,m){const n=m??new a(4);return n[0]=c,n[1]=r,n[2]=f,n[3]=p,n}function W(c,r){const f=r??new a(4);return f[0]=Math.ceil(c[0]),f[1]=Math.ceil(c[1]),f[2]=Math.ceil(c[2]),f[3]=Math.ceil(c[3]),f}function V(c,r){const f=r??new a(4);return f[0]=Math.floor(c[0]),f[1]=Math.floor(c[1]),f[2]=Math.floor(c[2]),f[3]=Math.floor(c[3]),f}function fn(c,r){const f=r??new a(4);return f[0]=Math.round(c[0]),f[1]=Math.round(c[1]),f[2]=Math.round(c[2]),f[3]=Math.round(c[3]),f}function ln(c,r=0,f=1,p){const m=p??new a(4);return m[0]=Math.min(f,Math.max(r,c[0])),m[1]=Math.min(f,Math.max(r,c[1])),m[2]=Math.min(f,Math.max(r,c[2])),m[3]=Math.min(f,Math.max(r,c[3])),m}function qn(c,r,f){const p=f??new a(4);return p[0]=c[0]+r[0],p[1]=c[1]+r[1],p[2]=c[2]+r[2],p[3]=c[3]+r[3],p}function Gn(c,r,f,p){const m=p??new a(4);return m[0]=c[0]+r[0]*f,m[1]=c[1]+r[1]*f,m[2]=c[2]+r[2]*f,m[3]=c[3]+r[3]*f,m}function Bn(c,r,f){const p=f??new a(4);return p[0]=c[0]-r[0],p[1]=c[1]-r[1],p[2]=c[2]-r[2],p[3]=c[3]-r[3],p}const dn=Bn;function In(c,r){return Math.abs(c[0]-r[0])1e-5?(f[0]=p/t,f[1]=m/t,f[2]=n/t,f[3]=s/t):(f[0]=0,f[1]=0,f[2]=0,f[3]=0),f}function g(c,r){const f=r??new a(4);return f[0]=-c[0],f[1]=-c[1],f[2]=-c[2],f[3]=-c[3],f}function z(c,r){const f=r??new a(4);return f[0]=c[0],f[1]=c[1],f[2]=c[2],f[3]=c[3],f}const T=z;function S(c,r,f){const p=f??new a(4);return p[0]=c[0]*r[0],p[1]=c[1]*r[1],p[2]=c[2]*r[2],p[3]=c[3]*r[3],p}const F=S;function L(c,r,f){const p=f??new a(4);return p[0]=c[0]/r[0],p[1]=c[1]/r[1],p[2]=c[2]/r[2],p[3]=c[3]/r[3],p}const N=L;function O(c){const r=c??new a(4);return r[0]=0,r[1]=0,r[2]=0,r[3]=0,r}function G(c,r,f){const p=f??new a(4),m=c[0],n=c[1],s=c[2],t=c[3];return p[0]=r[0]*m+r[4]*n+r[8]*s+r[12]*t,p[1]=r[1]*m+r[5]*n+r[9]*s+r[13]*t,p[2]=r[2]*m+r[6]*n+r[10]*s+r[14]*t,p[3]=r[3]*m+r[7]*n+r[11]*s+r[15]*t,p}function Y(c,r,f){const p=f??new a(4);return v(c,p),xn(p,r,p)}function M(c,r,f){const p=f??new a(4);return An(c)>r?Y(c,r,p):z(c,p)}function A(c,r,f){const p=f??new a(4);return Tn(c,r,.5,p)}return{create:P,fromValues:E,set:Z,ceil:W,floor:V,round:fn,clamp:ln,add:qn,addScaled:Gn,subtract:Bn,sub:dn,equalsApproximately:In,equals:en,lerp:Tn,lerpV:Dn,max:yn,min:En,mulScalar:xn,scale:wn,divScalar:Fn,inverse:_n,invert:zn,dot:Un,length:An,len:vn,lengthSq:C,lenSq:Ln,distance:X,dist:Q,distanceSq:$,distSq:l,normalize:v,negate:g,copy:z,clone:T,multiply:S,mul:F,divide:L,div:N,zero:O,transformMat4:G,setLength:Y,truncate:M,midpoint:A}}const Mt=new Map;function Xt(a){let P=Mt.get(a);return P||(P=Ht(a),Mt.set(a,P)),P}function st(a,P,E,Z,W,V){return{mat4:$t(a),mat3:Vt(P),quat:Wt(E),vec2:_t(Z),vec3:ot(W),vec4:Xt(V)}}const{mat4:bn,mat3:ie,quat:ue,vec2:ae,vec3:Yt,vec4:fe}=st(Float32Array,Float32Array,Float32Array,Float32Array,Float32Array,Float32Array);st(Float64Array,Float64Array,Float64Array,Float64Array,Float64Array,Float64Array);st(Et,Array,Array,Array,Array,Array);const Cn=`//////////////////////////////////////////////////////////////////////////////// // Utilities //////////////////////////////////////////////////////////////////////////////// var rand_seed : vec2f; fn init_rand(invocation_id : u32, seed : vec4f) { rand_seed = seed.xz; rand_seed = fract(rand_seed * cos(35.456+f32(invocation_id) * seed.yw)); rand_seed = fract(rand_seed * cos(41.235+f32(invocation_id) * seed.xw)); } fn rand() -> f32 { rand_seed.x = fract(cos(dot(rand_seed, vec2f(23.14077926, 232.61690225))) * 136.8168); rand_seed.y = fract(cos(dot(rand_seed, vec2f(54.47856553, 345.84153136))) * 534.7645); return rand_seed.y; } //////////////////////////////////////////////////////////////////////////////// // Vertex shader //////////////////////////////////////////////////////////////////////////////// struct RenderParams { modelViewProjectionMatrix : mat4x4f, right : vec3f, up : vec3f } @binding(0) @group(0) var render_params : RenderParams; struct VertexInput { @location(0) position : vec3f, @location(1) color : vec4f, @location(2) quad_pos : vec2f, // -1..+1 } struct VertexOutput { @builtin(position) position : vec4f, @location(0) color : vec4f, @location(1) quad_pos : vec2f, // -1..+1 } @vertex fn vs_main(in : VertexInput) -> VertexOutput { var quad_pos = mat2x3f(render_params.right, render_params.up) * in.quad_pos; var position = in.position + quad_pos * 0.005; var out : VertexOutput; out.position = render_params.modelViewProjectionMatrix * vec4f(position, 1.0); out.color = in.color; out.quad_pos = in.quad_pos; return out; } //////////////////////////////////////////////////////////////////////////////// // Fragment shader //////////////////////////////////////////////////////////////////////////////// @fragment fn fs_main(in : VertexOutput) -> @location(0) vec4f { var color = in.color; // Apply a circular particle alpha mask color.a = color.a * max(1.0 - length(in.quad_pos), 0.0); return color; } //////////////////////////////////////////////////////////////////////////////// // Simulation Compute shader //////////////////////////////////////////////////////////////////////////////// struct SimulationParams { deltaTime : f32, brightnessFactor : f32, seed : vec4f, } struct Particle { position : vec3f, lifetime : f32, color : vec4f, velocity : vec3f, } struct Particles { particles : array, } @binding(0) @group(0) var sim_params : SimulationParams; @binding(1) @group(0) var data : Particles; @binding(2) @group(0) var texture : texture_2d; @compute @workgroup_size(64) fn simulate(@builtin(global_invocation_id) global_invocation_id : vec3u) { let idx = global_invocation_id.x; init_rand(idx, sim_params.seed); var particle = data.particles[idx]; // Apply gravity particle.velocity.z = particle.velocity.z - sim_params.deltaTime * 0.5; // Basic velocity integration particle.position = particle.position + sim_params.deltaTime * particle.velocity; // Age each particle. Fade out before vanishing. particle.lifetime = particle.lifetime - sim_params.deltaTime; particle.color.a = smoothstep(0.0, 0.5, particle.lifetime); // If the lifetime has gone negative, then the particle is dead and should be // respawned. if (particle.lifetime < 0.0) { // Use the probability map to find where the particle should be spawned. // Starting with the 1x1 mip level. var coord : vec2i; for (var level = u32(textureNumLevels(texture) - 1); level > 0; level--) { // Load the probability value from the mip-level // Generate a random number and using the probabilty values, pick the // next texel in the next largest mip level: // // 0.0 probabilites.r probabilites.g probabilites.b 1.0 // | | | | | // | TOP-LEFT | TOP-RIGHT | BOTTOM-LEFT | BOTTOM_RIGHT | // let probabilites = textureLoad(texture, coord, level); let value = vec4f(rand()); let mask = (value >= vec4f(0.0, probabilites.xyz)) & (value < probabilites); coord = coord * 2; coord.x = coord.x + select(0, 1, any(mask.yw)); // x y coord.y = coord.y + select(0, 1, any(mask.zw)); // z w } let uv = vec2f(coord) / vec2f(textureDimensions(texture)); particle.position = vec3f((uv - 0.5) * 3.0 * vec2f(1.0, -1.0), 0.0); particle.color = textureLoad(texture, coord, 0); particle.color.r *= sim_params.brightnessFactor; particle.color.g *= sim_params.brightnessFactor; particle.color.b *= sim_params.brightnessFactor; particle.velocity.x = (rand() - 0.5) * 0.1; particle.velocity.y = (rand() - 0.5) * 0.1; particle.velocity.z = rand() * 0.3; particle.lifetime = 0.5 + rand() * 3.0; } // Store the new particle value data.particles[idx] = particle; } `,zt=`struct UBO { width : u32, } struct Buffer { weights : array, } @binding(0) @group(0) var ubo : UBO; @binding(1) @group(0) var buf_in : Buffer; @binding(2) @group(0) var buf_out : Buffer; @binding(3) @group(0) var tex_in : texture_2d; @binding(3) @group(0) var tex_out : texture_storage_2d; //////////////////////////////////////////////////////////////////////////////// // import_level // // Loads the alpha channel from a texel of the source image, and writes it to // the buf_out.weights. //////////////////////////////////////////////////////////////////////////////// @compute @workgroup_size(64) fn import_level(@builtin(global_invocation_id) coord : vec3u) { _ = &buf_in; let offset = coord.x + coord.y * ubo.width; buf_out.weights[offset] = textureLoad(tex_in, vec2i(coord.xy), 0).w; } //////////////////////////////////////////////////////////////////////////////// // export_level // // Loads 4 f32 weight values from buf_in.weights, and stores summed value into // buf_out.weights, along with the calculated 'probabilty' vec4 values into the // mip level of tex_out. See simulate() in particle.wgsl to understand the // probability logic. //////////////////////////////////////////////////////////////////////////////// @compute @workgroup_size(64) fn export_level(@builtin(global_invocation_id) coord : vec3u) { if (all(coord.xy < vec2u(textureDimensions(tex_out)))) { let dst_offset = coord.x + coord.y * ubo.width; let src_offset = coord.x*2u + coord.y*2u * ubo.width; let a = buf_in.weights[src_offset + 0u]; let b = buf_in.weights[src_offset + 1u]; let c = buf_in.weights[src_offset + 0u + ubo.width]; let d = buf_in.weights[src_offset + 1u + ubo.width]; let sum = dot(vec4f(a, b, c, d), vec4f(1.0)); buf_out.weights[dst_offset] = sum / 4.0; let probabilities = vec4f(a, a+b, a+b+c, sum) / max(sum, 0.0001); textureStore(tex_out, vec2i(coord.xy), probabilities); } } `;function Zt(a){"gpu"in navigator||$n("navigator.gpu is not defined - WebGPU not available in this browser"),a||$n("requestAdapter returned null - this sample can't run on this system")}function jt(a,P){if(!P){Zt(a),$n("Unable to get a device for an unknown reason");return}P.lost.then(E=>{$n(`Device lost ("${E.reason}"): ${E.message}`)}),P.onuncapturederror=E=>{$n(`Uncaptured error: ${E.error.message}`)}}const $n=(()=>{function a(){if(typeof document>"u")return{show(V){console.error(V)}};const E=document.createElement("dialog");E.close(),document.body.append(E);const Z=document.createElement("pre");Z.style.whiteSpace="pre-wrap",E.append(Z);const W=document.createElement("button");return W.textContent="OK",W.onclick=()=>E.close(),E.append(W),{show(V){E.open||(Z.textContent=V,E.showModal())}}}let P;return E=>{throw P||(P=a()),P.show(E),new Error(E)}})(),Kn=5e4,Qt=0,Kt=4*4,ct=3*4+1*4+4*4+3*4+1*4+0,Vn=document.querySelector("canvas"),At=await navigator.gpu?.requestAdapter(),j=await At?.requestDevice();jt(At,j);const vt=Vn.getContext("webgpu"),Pt=window.devicePixelRatio;Vn.width=Vn.clientWidth*Pt;Vn.height=Vn.clientHeight*Pt;const mt="rgba16float";function Jt(){vt.configure({device:j,format:mt,toneMapping:{mode:et.toneMappingMode},alphaMode:"premultiplied"})}const St=j.createBuffer({size:Kn*ct,usage:GPUBufferUsage.VERTEX|GPUBufferUsage.STORAGE}),qt=j.createRenderPipeline({layout:"auto",vertex:{module:j.createShaderModule({code:Cn}),buffers:[{arrayStride:ct,stepMode:"instance",attributes:[{shaderLocation:0,offset:Qt,format:"float32x3"},{shaderLocation:1,offset:Kt,format:"float32x4"}]},{arrayStride:2*4,stepMode:"vertex",attributes:[{shaderLocation:2,offset:0,format:"float32x2"}]}]},fragment:{module:j.createShaderModule({code:Cn}),targets:[{format:mt,blend:{color:{srcFactor:"src-alpha",dstFactor:"one",operation:"add"},alpha:{srcFactor:"zero",dstFactor:"one",operation:"add"}}}]},primitive:{topology:"triangle-list"},depthStencil:{depthWriteEnabled:!1,depthCompare:"less",format:"depth24plus"}}),kt=j.createTexture({size:[Vn.width,Vn.height],format:"depth24plus",usage:GPUTextureUsage.RENDER_ATTACHMENT}),Ct=4*4*4+3*4+4+3*4+4+0,Bt=j.createBuffer({size:Ct,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),ne=j.createBindGroup({layout:qt.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:Bt}}]}),kn={colorAttachments:[{view:void 0,clearValue:[0,0,0,1],loadOp:"clear",storeOp:"store"}],depthStencilAttachment:{view:kt.createView(),depthClearValue:1,depthLoadOp:"clear",depthStoreOp:"store"}},rt=j.createBuffer({size:6*2*4,usage:GPUBufferUsage.VERTEX,mappedAtCreation:!0}),te=[-1,-1,1,-1,-1,1,-1,1,1,-1,1,1];new Float32Array(rt.getMappedRange()).set(te);rt.unmap();let Jn,Rn=1,Nn=1,nt=1;{const a=await fetch("./5m.png"),P=await createImageBitmap(await a.blob());for(;Rn>a,E=Nn>>a,Z=a==0?gt.getBindGroupLayout(0):xt.getBindGroupLayout(0),W=j.createBindGroup({layout:Z,entries:[{binding:0,resource:{buffer:Tt}},{binding:1,resource:{buffer:a&1?Dt:yt}},{binding:2,resource:{buffer:a&1?yt:Dt}},{binding:3,resource:Jn.createView({format:"rgba8unorm",dimension:"2d",baseMipLevel:a,mipLevelCount:1})}]});if(a==0){const V=tt.beginComputePass();V.setPipeline(gt),V.setBindGroup(0,W),V.dispatchWorkgroups(Math.ceil(P/64),E),V.end()}else{const V=tt.beginComputePass();V.setPipeline(xt),V.setBindGroup(0,W),V.dispatchWorkgroups(Math.ceil(P/64),E),V.end()}}j.queue.submit([tt.finish()]);const et={simulate:!0,deltaTime:.04,toneMappingMode:"standard",brightnessFactor:1},oe=1*4+1*4+3*4+4*4+0,Ut=j.createBuffer({size:oe,usage:GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST}),Ot=j.createComputePipeline({layout:"auto",compute:{module:j.createShaderModule({code:Cn}),entryPoint:"simulate"}}),se=j.createBindGroup({layout:Ot.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:Ut}},{binding:1,resource:{buffer:St,offset:0,size:Kn*ct}},{binding:2,resource:Jn.createView()}]}),ce=Vn.width/Vn.height,re=bn.perspective(2*Math.PI/5,ce,1,100),On=bn.create(),tn=bn.create();function Gt(){j.queue.writeBuffer(Ut,0,new Float32Array([et.deltaTime,et.brightnessFactor,0,0,0,Math.random()*100,Math.random()*100,1+Math.random(),1+Math.random()])),bn.identity(On),bn.translate(On,Yt.fromValues(0,0,-3),On),bn.rotateX(On,Math.PI*-.2,On),bn.multiply(re,On,tn),j.queue.writeBuffer(Bt,0,new Float32Array([tn[0],tn[1],tn[2],tn[3],tn[4],tn[5],tn[6],tn[7],tn[8],tn[9],tn[10],tn[11],tn[12],tn[13],tn[14],tn[15],On[0],On[4],On[8],0,On[1],On[5],On[9],0]));const a=vt.getCurrentTexture(),P=Array.from(kn.colorAttachments);P[0].view=a.createView(),kn.colorAttachments=P;const E=j.createCommandEncoder();{const Z=E.beginComputePass();Z.setPipeline(Ot),Z.setBindGroup(0,se),Z.dispatchWorkgroups(Math.ceil(Kn/64)),Z.end()}{const Z=E.beginRenderPass(kn);Z.setPipeline(qt),Z.setBindGroup(0,ne),Z.setVertexBuffer(0,St),Z.setVertexBuffer(1,rt),Z.draw(6,Kn,0,0),Z.end()}j.queue.submit([E.finish()]),requestAnimationFrame(Gt)}Jt();requestAnimationFrame(Gt);