badgecraft 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/LICENSE +21 -0
  3. package/README.md +406 -0
  4. package/cli/index.mjs +143 -0
  5. package/cli/render.d.ts +20 -0
  6. package/cli/render.mjs +87 -0
  7. package/cli/studio.mjs +98 -0
  8. package/dist/badge-B-g_9WFj.d.ts +79 -0
  9. package/dist/badge-CCjUxNIG.d.cts +79 -0
  10. package/dist/chunk-3OMN635U.js +44 -0
  11. package/dist/chunk-3OMN635U.js.map +1 -0
  12. package/dist/chunk-BRT5S5PF.cjs +3418 -0
  13. package/dist/chunk-BRT5S5PF.cjs.map +1 -0
  14. package/dist/chunk-EBDSIGZR.cjs +48 -0
  15. package/dist/chunk-EBDSIGZR.cjs.map +1 -0
  16. package/dist/chunk-RRYBMB25.js +3410 -0
  17. package/dist/chunk-RRYBMB25.js.map +1 -0
  18. package/dist/cli-browser.js +526 -0
  19. package/dist/element.cjs +176 -0
  20. package/dist/element.cjs.map +1 -0
  21. package/dist/element.d.cts +31 -0
  22. package/dist/element.d.ts +31 -0
  23. package/dist/element.js +174 -0
  24. package/dist/element.js.map +1 -0
  25. package/dist/index.cjs +47 -0
  26. package/dist/index.cjs.map +1 -0
  27. package/dist/index.d.cts +58 -0
  28. package/dist/index.d.ts +58 -0
  29. package/dist/index.js +17 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/react.cjs +60 -0
  32. package/dist/react.cjs.map +1 -0
  33. package/dist/react.d.cts +29 -0
  34. package/dist/react.d.ts +29 -0
  35. package/dist/react.js +55 -0
  36. package/dist/react.js.map +1 -0
  37. package/dist/studio/assets/badge-9Zq6e9Ht.js +524 -0
  38. package/dist/studio/assets/base-ItCYnbux.css +1 -0
  39. package/dist/studio/assets/base-LFa9cTPp.js +1 -0
  40. package/dist/studio/assets/element-CCTxyf61.js +1 -0
  41. package/dist/studio/assets/index-BVuSTaz-.css +1 -0
  42. package/dist/studio/assets/index-CTTcx2pV.js +28 -0
  43. package/dist/studio/assets/option-keys-CKi71y0n.js +1 -0
  44. package/dist/studio/assets/react-Cq5Erey2.js +9 -0
  45. package/dist/studio/assets/react-DyJFYpWJ.js +1 -0
  46. package/dist/studio/assets/studio-C6plMNOe.css +1 -0
  47. package/dist/studio/assets/studio-DBcSY6tV.js +1 -0
  48. package/dist/studio/assets/style-C2sJ2Xy3.css +1 -0
  49. package/dist/studio/assets/vue-BpGwr3iF.js +1 -0
  50. package/dist/studio/element.html +31 -0
  51. package/dist/studio/env/studio.hdr +5 -0
  52. package/dist/studio/index.html +24 -0
  53. package/dist/studio/logos/apple.svg +1 -0
  54. package/dist/studio/logos/atlassian.svg +1 -0
  55. package/dist/studio/logos/google.svg +1 -0
  56. package/dist/studio/logos/meta.svg +1 -0
  57. package/dist/studio/react.html +16 -0
  58. package/dist/studio/studio.html +27 -0
  59. package/dist/studio/vue.html +15 -0
  60. package/dist/types-CHM3-ZZV.d.cts +204 -0
  61. package/dist/types-CHM3-ZZV.d.ts +204 -0
  62. package/dist/vue.cjs +93 -0
  63. package/dist/vue.cjs.map +1 -0
  64. package/dist/vue.d.cts +115 -0
  65. package/dist/vue.d.ts +115 -0
  66. package/dist/vue.js +87 -0
  67. package/dist/vue.js.map +1 -0
  68. package/docs/cli.md +146 -0
  69. package/docs/gallery.jpg +0 -0
  70. package/docs/performance.md +151 -0
  71. package/docs/render-quality.md +220 -0
  72. package/docs/studio.jpg +0 -0
  73. package/package.json +163 -0
@@ -0,0 +1,526 @@
1
+ "use strict";var BadgecraftLibrary=(()=>{var We=Object.defineProperty;var jt=Object.getOwnPropertyDescriptor;var Kt=Object.getOwnPropertyNames;var Yt=Object.prototype.hasOwnProperty;var Qt=(n,e)=>{for(var r in e)We(n,r,{get:e[r],enumerable:!0})},Zt=(n,e,r,t)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of Kt(e))!Yt.call(n,o)&&o!==r&&We(n,o,{get:()=>e[o],enumerable:!(t=jt(e,o))||t.enumerable});return n};var Jt=n=>Zt(We({},"__esModule",{value:!0}),n);var Lr={};Qt(Lr,{Badgecraft:()=>Ae,createBadge:()=>Xt,defaults:()=>k,environments:()=>Ee,framePaths:()=>ve,isSupported:()=>Pr,materials:()=>he,resolveMaterial:()=>J});var z;function er(n){if(z===void 0&&(z=typeof document<"u"?document.createElement("canvas").getContext("2d"):null),!z)return null;z.fillStyle="#000000",z.fillStyle=n;let e=String(z.fillStyle);z.fillStyle="#ffffff",z.fillStyle=n;let r=String(z.fillStyle);if(e!==r)return null;if(!/^#|^rgba?\(/i.test(e)){z.clearRect(0,0,1,1),z.fillRect(0,0,1,1);let t=z.getImageData(0,0,1,1).data;return`rgb(${t[0]},${t[1]},${t[2]})`}return e}function tr(n,e=[1,1,1]){if(!n)return e;let r=n.trim(),t=/^#|^rgba?\(/i.test(r)?r:er(r);if(!t)return e;if(r=t,r[0]==="#"){let a=r.slice(1);if(!/^(?:[\da-f]{3,4}|[\da-f]{6}|[\da-f]{8})$/i.test(a))return e;if((a.length===3||a.length===4)&&(a=[...a.slice(0,3)].map(i=>i+i).join("")),a.length>=6){let i=parseInt(a.slice(0,6),16);if(!Number.isNaN(i))return[(i>>16&255)/255,(i>>8&255)/255,(i&255)/255]}return e}let o=r.match(/rgba?\(([^)]+)\)/i);if(o){let i=o[1].split(/[\s,/]+/).filter(Boolean).slice(0,3).map(s=>s.endsWith("%")?parseFloat(s)/100:parseFloat(s)/255);if(i.length===3&&i.every(s=>Number.isFinite(s)))return i.map(s=>Math.max(0,Math.min(1,s)))}return e}function Ge(n){return n<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function j(n,e){let[r,t,o]=tr(n,e);return[Ge(r),Ge(t),Ge(o)]}function Z(n){if(n===null||typeof n!="object")return JSON.stringify(n)??"undefined";if(Array.isArray(n))return`[${n.map(Z).join(",")}]`;let e=n;return`{${Object.keys(e).filter(t=>e[t]!==void 0&&typeof e[t]!="function").sort().map(t=>`${JSON.stringify(t)}:${Z(e[t])}`).join(",")}}`}function He(n,e=0){let r=3735928559^e,t=1103547991^e;for(let o=0;o<n.length;o++){let a=n.charCodeAt(o);r=Math.imul(r^a,2654435761),t=Math.imul(t^a,1597334677)}return r=Math.imul(r^r>>>16,2246822507)^Math.imul(t^t>>>13,3266489909),t=Math.imul(t^t>>>16,2246822507)^Math.imul(r^r>>>13,3266489909),(4294967296*(2097151&t)+(r>>>0)).toString(36)}var O=(n,e,r)=>n<e?e:n>r?r:n;var Ee={studio:{top:"#727984",horizon:"#20232a",bottom:"#101116",intensity:1,lights:[{azimuth:-12,elevation:8,size:[90,65],intensity:.22,color:"#ffffff",softness:1},{azimuth:-36,elevation:38,size:[58,65],intensity:4.5,color:"#fff8ef",softness:.45},{azimuth:48,elevation:12,size:[16,85],intensity:3.2,color:"#e9f1ff",softness:.35},{azimuth:0,elevation:72,size:[135,24],intensity:3.8,color:"#ffffff",softness:.5},{azimuth:-120,elevation:20,size:[24,65],intensity:1.8,color:"#ffffff",softness:.4},{azimuth:135,elevation:30,size:34,shape:"circle",intensity:2,color:"#fff2dd",softness:.6}]},soft:{top:"#c9ccd2",horizon:"#8a8c91",bottom:"#3a3a3d",intensity:1,lights:[{azimuth:0,elevation:25,size:[160,70],intensity:1.2,color:"#ffffff",softness:1},{azimuth:-60,elevation:45,size:[80,60],intensity:2,color:"#fffaf0",softness:1}]},sunset:{top:"#3b3f7a",horizon:"#e0806a",bottom:"#1a1012",intensity:1,lights:[{azimuth:-55,elevation:12,size:26,shape:"circle",intensity:14,color:"#ffb46b",softness:.6},{azimuth:0,elevation:15,size:[120,40],intensity:.9,color:"#ffc7a8",softness:1},{azimuth:70,elevation:40,size:[60,40],intensity:1.6,color:"#8fa6ff",softness:.8}]},night:{top:"#101218",horizon:"#07080b",bottom:"#020203",intensity:1,lights:[{azimuth:-30,elevation:40,size:[30,22],intensity:9,color:"#ffffff",softness:.35},{azimuth:115,elevation:25,size:[16,60],intensity:5,color:"#dfe8ff",softness:.3},{azimuth:-135,elevation:15,size:[14,50],intensity:4,color:"#ffffff",softness:.3},{azimuth:0,elevation:10,size:[90,30],intensity:.45,color:"#ffffff",softness:1}]},neon:{top:"#1a1030",horizon:"#101018",bottom:"#050508",intensity:1,lights:[{azimuth:-45,elevation:25,size:[20,80],intensity:6,color:"#ff3fa4",softness:.4},{azimuth:45,elevation:25,size:[20,80],intensity:6,color:"#2fd8ff",softness:.4},{azimuth:0,elevation:60,size:[120,18],intensity:3,color:"#b98cff",softness:.6},{azimuth:0,elevation:10,size:[100,40],intensity:.8,color:"#ffffff",softness:1}]}};function ot(n){if(n||(n="studio"),typeof n=="string"){let o=Object.prototype.hasOwnProperty.call(Ee,n)?Ee[n]:void 0;return o?{kind:"procedural",spec:o,key:`preset:${n}`}:{kind:"image",spec:{url:n},key:`url:${n}|1`}}let e=(o,a,i,s)=>typeof o=="number"&&Number.isFinite(o)?O(o,i,s):a,r=e(n.intensity,1,0,1e4);if("url"in n){let o={url:n.url,intensity:r};return{kind:"image",spec:o,key:`url:${o.url}|${r}`}}let t={...n,intensity:r,lights:n.lights?.map(o=>{let a=o.size??30,i=Array.isArray(a)?a:[a,a];return{...o,azimuth:e(o.azimuth,0,-1/0,1/0)%360,elevation:e(o.elevation,0,-90,90),intensity:e(o.intensity,1,0,1e4),softness:e(o.softness,.5,0,1),size:i.map(s=>e(s,30,.001,170))}})};return{kind:"procedural",spec:t,key:`proc:${Z(t)}`}}var at={color:"#ffffff",useSvgColor:!1,metalness:0,roughness:.4,clearcoat:0,clearcoatRoughness:.05,ior:1.5,iridescence:0,iridescenceThickness:450,flakes:0,flakeScale:220,brushed:0,brushDirection:"circular",emissive:0},U=(n,e,r={})=>({color:n,metalness:1,roughness:e,...r}),he={gold:U("#f7dc8f",.24),"rose-gold":U("#f6b99c",.22),"white-gold":U("#efe7d2",.2),"matte-gold":U("#f0d284",.48),"brushed-gold":U("#f7dc8f",.34,{brushed:.7,brushDirection:"circular"}),silver:U("#f1f0ee",.24),"brushed-silver":U("#e9e9ea",.3,{brushed:.7,brushDirection:"circular"}),platinum:U("#d8d3cb",.22),chrome:U("#e6e9ec",.04),copper:U("#f2a27c",.24),bronze:U("#d69a5c",.32),brass:U("#e9c46f",.26),titanium:U("#b9b2a9",.3),gunmetal:U("#6b6d73",.28),"black-chrome":U("#3c3d42",.1),enamel:{useSvgColor:!0,metalness:0,roughness:.28,clearcoat:1,clearcoatRoughness:.09},"matte-enamel":{useSvgColor:!0,metalness:0,roughness:.62,clearcoat:.15,clearcoatRoughness:.4},candy:{useSvgColor:!0,metalness:.85,roughness:.3,clearcoat:1,clearcoatRoughness:.04},glitter:{useSvgColor:!0,metalness:.2,roughness:.35,clearcoat:1,clearcoatRoughness:.04,flakes:.9,flakeScale:260},pearl:{color:"#f4eee6",metalness:.15,roughness:.28,clearcoat:1,clearcoatRoughness:.05,iridescence:.7,iridescenceThickness:560},holographic:U("#f2f2f4",.18,{iridescence:1,iridescenceThickness:420,flakes:.4}),onyx:{color:"#191b20",metalness:0,roughness:.28,clearcoat:1,clearcoatRoughness:.1},obsidian:{color:"#0e0e10",metalness:0,roughness:.2,clearcoat:1,clearcoatRoughness:.03}},it={metal:"gold",enamel:"enamel",base:"onyx",accent:"silver"};function J(n,e){let r=n??it[e],t;if(typeof r=="string")t=he[r]??he[it[e]];else{let{preset:i,...s}=r;t={...i?he[i]:{},...st(s)}}let o={...at,...st(t)},a={metalness:[0,1],roughness:[0,1],clearcoat:[0,1],clearcoatRoughness:[0,1],ior:[1,3],iridescence:[0,1],iridescenceThickness:[100,1200],flakes:[0,1],flakeScale:[1,1e4],brushed:[0,1],emissive:[0,1]};for(let i of Object.keys(a)){let[s,l]=a[i];o[i]=Number.isFinite(o[i])?O(o[i],s,l):at[i]}return t.useSvgColor===void 0&&e==="enamel"&&!t.color&&(o.useSvgColor=!0),o}function st(n){let e={};for(let r of Object.keys(n))n[r]!==void 0&&(e[r]=n[r]);return e}var k={mode:"auto",color:"#ffffff",rim:.03,outline:"auto",autoOutline:.012,fillHoles:!0,relief:{depth:.05,thickness:.03,floor:.3,profile:"round",bevel:.02,edge:.014,enamelLevel:.16,enamelDome:.12,domeWidth:.05,smoothing:.9,ao:.45},exposure:1,toneMapping:"neutral",interaction:"tilt",tiltMax:18,pose:{pitch:-5,yaw:-8,roll:0},idle:"none",lockedColor:"#3a3a3c",shadow:.35,padding:.06},rr={round:0,soft:1,chamfer:2},nr={neutral:0,aces:1,agx:2,none:3},P=(n,e,r=-1/0,t=1/0)=>typeof n=="number"&&Number.isFinite(n)?O(n,r,t):e;function Xe(n){let e={...k.relief,...or(n.relief??{})},r=n.frame==null?null:typeof n.frame=="string"?{shape:n.frame}:{shape:"circle",...n.frame};r&&(r.padding=P(r.padding,.22,0,.45),r.innerRing=P(r.innerRing,0,0,.3));let t={depth:P(e.depth,k.relief.depth,.001,.5),mode:n.mode??k.mode,color:n.color??k.color,frame:r,rim:P(n.rim,k.rim,0,.3),outline:n.outline===void 0||n.outline==="auto"?"auto":P(n.outline,0,0,.3),autoOutline:k.autoOutline,fillHoles:n.fillHoles??k.fillHoles,floor:P(e.floor,k.relief.floor,0,.95),profile:rr[e.profile]??0,bevel:P(e.bevel,k.relief.bevel,.001,.5),edge:P(e.edge,k.relief.edge,.001,.2),enamelLevel:P(e.enamelLevel,k.relief.enamelLevel,0,1),enamelDome:P(e.enamelDome,k.relief.enamelDome,-1,1),domeWidth:P(e.domeWidth,k.relief.domeWidth,.001,.5),smoothing:P(e.smoothing,k.relief.smoothing,0,8)},o={materials:[J(n.metal,"metal"),J(n.enamel,"enamel"),J(n.base,"base"),J(n.accent,"accent")],environment:ot(n.environment),envRotation:P(n.environmentRotation,0)%360*Math.PI/180,thickness:P(e.thickness,k.relief.thickness,0,.5),edge:t.edge,ao:P(e.ao,k.relief.ao,0,1),exposure:P(n.exposure,k.exposure,0,16),toneMapping:nr[n.toneMapping??k.toneMapping]??0,interaction:n.interaction??k.interaction,tiltMax:P(n.tiltMax,k.tiltMax,0,80),pose:{pitch:P(n.pose?.pitch,k.pose.pitch,-89,89),yaw:P(n.pose?.yaw,k.pose.yaw,-180,180),roll:P(n.pose?.roll,k.pose.roll,-180,180)},idle:n.idle??k.idle,locked:!!n.locked,lockedColor:n.lockedColor??k.lockedColor,shadow:P(n.shadow,k.shadow,0,1),padding:P(n.padding,k.padding,0,.4)},a=typeof n.quality!="number"||!Number.isFinite(n.quality)?"auto":O(Math.round(n.quality),64,2048);return{bake:t,bakeKey:Z(t),render:o,renderKey:Z(o),quality:a}}function or(n){let e={};for(let r of Object.keys(n))n[r]!==void 0&&(e[r]=n[r]);return e}function ar(n){return{f:new Float64Array(n),z:new Float64Array(n+1),v:new Int32Array(n)}}function lt(n,e,r,t,o,a){let{f:i,z:s,v:l}=o;l[0]=0,s[0]=-1e20,s[1]=1e20,i[0]=n[e];for(let m=1,c=0;m<t;m++){i[m]=n[e+m*r];let f=m*m,u;do{let h=l[c];u=(i[m]-i[h]+f-h*h)/(m-h)/2}while(u<=s[c]&&--c>-1);c++,l[c]=m,s[c]=u,s[c+1]=1e20}for(let m=0,c=0;m<t;m++){for(;s[c+1]<m;)c++;let f=l[c],u=m-f;n[e+m*r]=i[f]+u*u,a&&(a[e+m*r]=f)}}function qe(n,e,r){let t=ar(Math.max(e,r)),o=new Int32Array(e*r),a=new Int32Array(e*r);for(let s=0;s<e;s++)lt(n,s,e,r,t,o);for(let s=0;s<r;s++)lt(n,s*e,1,e,t,a);let i=new Int32Array(e*r);for(let s=0;s<r;s++){let l=s*e;for(let m=0;m<e;m++){let c=a[l+m],f=o[l+c];i[l+m]=f*e+c}}return i}function ir(n,e,r){let t=Math.abs(n),o=Math.abs(e);if(t<o){let i=t;t=o,o=i}if(o<1e-6)return .5-r;let a=.5*o/t;return r<a?.5*(t+o)-Math.sqrt(2*t*o*r):r<1-a?(.5-r)*t:-.5*(t+o)+Math.sqrt(2*t*o*(1-r))}function $e(n,e,r,t={}){let o=t.insideOnly??!1,a=(t.refineWithin??1/0)**2,i=Math.min(a,2304),s=e*r,l=new Float32Array(s),m=new Float32Array(s),c=new Float32Array(s),f=new Float32Array(s),u=new Float32Array(s),h=0,b=(v,x)=>n[(x<0?0:x>=r?r-1:x)*e+(v<0?0:v>=e?e-1:v)];for(let v=0;v<r;v++){let x=v>0&&v<r-1;for(let y=0;y<e;y++){let E=v*e+y,R=n[E],L;if(R>0&&R<1)L=!0;else if(x&&y>0&&y<e-1){let S=n[E-1],B=n[E+1],_=n[E-e],X=n[E+e];L=R<=0?S>=1||B>=1||_>=1||X>=1:S<=0||B<=0||_<=0||X<=0}else L=R<=0?Math.max(b(y-1,v),b(y+1,v),b(y,v-1),b(y,v+1))>=1:Math.min(b(y-1,v),b(y+1,v),b(y,v-1),b(y,v+1))<=0;if(!L){l[E]=1e20;continue}l[E]=0,h++;let I=b(y+1,v-1)+2*b(y+1,v)+b(y+1,v+1)-b(y-1,v-1)-2*b(y-1,v)-b(y-1,v+1),p=b(y-1,v+1)+2*b(y,v+1)+b(y+1,v+1)-b(y-1,v-1)-2*b(y,v-1)-b(y+1,v-1),T=Math.hypot(I,p);if(T>1e-4){let S=I/T,B=p/T;f[E]=S,u[E]=B;let _=ir(S,B,R);m[E]=y+S*_,c[E]=v+B*_}else m[E]=y,c[E]=v}}let M=new Float32Array(s);if(h===0){let v=n[0]>=.5?e+r:-(e+r);return M.fill(v),M}let g=new Uint8Array(s);for(let v=0;v<s;v++)g[v]=l[v]===0?1:0;let A=qe(l,e,r);for(let v=0;v<r;v++)for(let x=0;x<e;x++){let y=v*e+x;if(o&&n[y]<=0)continue;let E=A[y];if(l[y]>a){let N=Math.sqrt(l[y]);M[y]=n[y]>=.5?N:-N;continue}let R=l[y]<i?2:1,L=E%e,I=(E-L)/e,p=E,T=1/0;for(let N=-R;N<=R;N++){let se=I+N;if(!(se<0||se>=r))for(let le=-R;le<=R;le++){let ce=L+le;if(ce<0||ce>=e)continue;let H=se*e+ce;if(!g[H])continue;let ue=x-m[H],W=v-c[H],fe=ue*ue+W*W;fe<T&&(T=fe,p=H)}}let S=x-m[p],B=v-c[p],_=Math.sqrt(T),X=S*f[p]+B*u[p],C=_<1.5&&(f[p]!==0||u[p]!==0)?X>=0:n[y]>=.5;M[y]=C?_:-_}return M}function Ve(n,e,r,t){let o=$e(n,e,r,{insideOnly:!0,refineWithin:t});for(let a=0;a<o.length;a++)o[a]=n[a]>0?Math.max(0,o[a]):0;return o}function je(n,e,r,t){if(t<=.01)return n.slice();let o=Math.max(1,Math.ceil(t*3)),a=new Float32Array(o*2+1),i=0;for(let c=-o;c<=o;c++){let f=Math.exp(-c*c/(2*t*t));a[c+o]=f,i+=f}for(let c=0;c<a.length;c++)a[c]/=i;let s=new Float32Array(e*r),l=new Float32Array(e*r),m=a.length;for(let c=0;c<r;c++){let f=c*e;for(let u=0;u<e;u++){let h=0;if(u>=o&&u<e-o){let b=f+u-o;for(let M=0;M<m;M++)h+=n[b+M]*a[M]}else for(let b=-o;b<=o;b++){let M=u+b<0?0:u+b>=e?e-1:u+b;h+=n[f+M]*a[b+o]}s[f+u]=h}}for(let c=-o;c<=o;c++){let f=a[c+o];for(let u=0;u<r;u++){let b=(u+c<0?0:u+c>=r?r-1:u+c)*e,M=u*e;for(let g=0;g<e;g++)l[M+g]+=s[b+g]*f}}return l}function sr(n,e,r,t,o){let a=new Float32Array(r*t),i=1/(2*o+1);for(let s=0;s<t;s++){let l=s*r,m=n[l]*(o+1);for(let c=1;c<=o;c++)m+=n[l+Math.min(c,r-1)];for(let c=0;c<r;c++){a[l+c]=m*i;let f=n[l+Math.min(c+o+1,r-1)],u=n[l+Math.max(c-o,0)];m+=f-u}}for(let s=0;s<r;s++){let l=a[s]*(o+1);for(let m=1;m<=o;m++)l+=a[Math.min(m,t-1)*r+s];for(let m=0;m<t;m++){e[m*r+s]=l*i;let c=a[Math.min(m+o+1,t-1)*r+s],f=a[Math.max(m-o,0)*r+s];l+=c-f}}}function pe(n,e,r,t){if(t<2)return je(n,e,r,t);let o=3,a=Math.sqrt(12*t*t/o+1),i=Math.floor(a);i%2===0&&i--;let s=i+2,l=Math.round((12*t*t-o*i*i-4*o*i-3*o)/(-4*i-4)),m=n.slice(),c=new Float32Array(e*r);for(let f=0;f<o;f++){let u=f<l?i:s;sr(m,c,e,r,u-1>>1);let h=m;m=c,c=h}return m}function Ke(n,e,r,t,o){let a=r*t,i=new Float32Array(a);for(let c=0;c<a;c++)i[c]=n[c]*e[c];let s=pe(i,r,t,o),l=pe(e,r,t,o),m=new Float32Array(a);for(let c=0;c<a;c++)m[c]=l[c]>1e-4?s[c]/l[c]:n[c];return m}function ct(n,e,r,t,o){t=t<0?0:t>e-1?e-1:t,o=o<0?0:o>r-1?r-1:o;let a=Math.floor(t),i=Math.floor(o),s=a+1<e?a+1:a,l=i+1<r?i+1:i,m=t-a,c=o-i,f=n[i*e+a],u=n[i*e+s],h=n[l*e+a],b=n[l*e+s];return(f+(u-f)*m)*(1-c)+(h+(b-h)*m)*c}var ut=.6;function ft(n,e){if(n<=0)return 0;if(n>=1)return 1;if(e===0){let r=1-n;return Math.sqrt(1-r*r)}return e===1?Math.sin(n*Math.PI/2):n}function K(n,e,r){let t=new Float32Array(r);for(let o=0;o<r;o++)t[o]=n[o*4+e]/255;return t}function cr(n,e){let r=e*e,t=new Uint8Array(r),o=new Int32Array(r),a=0,i=l=>{!t[l]&&n[l]<.5&&(t[l]=1,o[a++]=l)};for(let l=0;l<e;l++)i(l),i((e-1)*e+l);for(let l=0;l<e;l++)i(l*e),i(l*e+e-1);for(;a>0;){let l=o[--a],m=l%e;m>0&&i(l-1),m<e-1&&i(l+1),l>=e&&i(l-e),l<r-e&&i(l+e)}let s=new Float32Array(r);for(let l=0;l<r;l++){if(t[l]){s[l]=n[l];continue}let m=l%e,c=m>0&&t[l-1]||m<e-1&&t[l+1]||l>=e&&t[l-e]||l<r-e&&t[l+e];s[l]=c?n[l]:1}return s}function ur(n,e,r,t,o){let a=t*t,i=new Float32Array(a),s=t*.15,l=.75;for(let m=0;m<t;m++)for(let c=0;c<t;c++){let f=m*t+c;if(e[f]<=.01)continue;let u=n[f],h=r[f]>=e[f]*.5?s:o*1.05,b=(n[c<t-1?f+1:f]-n[c>0?f-1:f])*.5,M=(n[m<t-1?f+t:f]-n[m>0?f-t:f])*.5,g=Math.hypot(b,M);if(g<.2){i[f]=u;continue}let A=b/g*l,v=M/g*l,x=c,y=m,E=u,R=u,L=Math.ceil(h/l)+2;for(let I=0;I<L&&R<h;I++){x+=A,y+=v;let p=ct(n,t,t,x,y);if(p<=E+.001)break;E=p,R=p}i[f]=R}return i}function mt(n){let{size:e,params:r}=n,t=e*e,o=r.profile,a=r.rim*e,i=Math.max(1,r.bevel*e),s=Math.max(1,r.edge*e),l=Math.max(1,r.domeWidth*e),m=r.floor,c=K(n.roles,0,t),f=K(n.roles,1,t),u=K(n.roles,2,t),h=K(n.slotsA,0,t),b=K(n.slotsA,1,t),M=K(n.slotsA,2,t),g=K(n.slotsB,0,t),A=K(n.slotsB,1,t),v=new Float32Array(t);for(let d=0;d<t;d++)v[d]=Math.min(1,c[d]+f[d]+u[d]+h[d]);let x=r.fillHoles?cr(v,e):v,y=new Float32Array(t);for(let d=0;d<t;d++)y[d]=Math.max(0,x[d]-v[d]);let E=$e(x,e,e,{refineWithin:Math.max(s,a)*2+8});if(a>.5)for(let d=0;d<t;d++){if(x[d]<=0)continue;let F=Math.min(x[d],Math.max(0,Math.min(1,a+.5-E[d])));if(F<=0)continue;let w=1-F;c[d]=Math.max(c[d],F),f[d]*=w,u[d]*=w,h[d]*=w,y[d]*=w,g[d]=Math.max(g[d],F),A[d]*=w,M[d]*=w,b[d]*=w}let R=new Float32Array(t);for(let d=0;d<t;d++)R[d]=Math.min(1,c[d]+f[d]);let L=Ve(R,e,e,e*.16),I=Ke(Ve(u,e,e,l*1.5),u,e,e,Math.max(1,l*.3)),p=Ke(ur(L,R,c,e,i),R,e,e,3*e/512),T=[];for(let d=0;d<t;d++)c[d]>.5&&L[d]>.75*p[d]&&p[d]>.5&&T.push(p[d]);T.sort((d,F)=>d-F);let S=T.length>8?T[T.length>>1]:0,B=S>0?ut*S/e/Math.max(.05,1-m):1/0,_=Math.max(r.depth*.2,Math.min(r.depth,B)),X=S>0?_*e*Math.max(.05,1-m)/ut:1/0,C=new Float32Array(t),N=0;for(let d=0;d<t;d++){if(x[d]<=0)continue;N+=x[d];let F=E[d]<=0?0:ft(E[d]/s,0),w=m*F,q=R[d],V=u[d],me=h[d]+y[d],Y=q+V+me;if(Y<1e-4){C[d]=w;continue}let ze=me*w;if(q>0){let Q=Math.min(1,c[d]/Math.max(q,1e-4)),de=Math.max(.75,p[d]),qt=Math.max(.75,Q*de+(1-Q)*Math.min(i,de)),$t=L[d]/qt,Vt=Q*Math.min(1,de/X)+(1-Q);ze+=q*(w+(1-w)*Vt*ft($t,o))}if(V>0){let Q=Math.min(1,I[d]/l),de=1-(1-Q)*(1-Q);ze+=V*(w+F*(r.enamelLevel+r.enamelDome*de))}C[d]=ze/Y}let se=e/512;C=je(C,e,e,r.smoothing*se);let le=pe(C,e,e,Math.max(1,e*.008)),ce=pe(C,e,e,Math.max(2,e*.03)),H=new Float32Array(t*4),ue=new Float32Array(t);for(let d=0;d<e;d++)for(let F=0;F<e;F++){let w=d*e+F,q=(C[F<e-1?w+1:w]-C[F>0?w-1:w])*.5,V=(C[d<e-1?w+e:w]-C[d>0?w-e:w])*.5;H[w*4]=C[w],H[w*4+1]=q,H[w*4+2]=V,H[w*4+3]=E[w],ue[w]=Math.min(1,Math.max(0,le[w]-C[w])*2.2+Math.max(0,ce[w]-C[w])*1.1)}let W=new Uint8Array(t*4),fe=new Float32Array(t),nt=0;for(let d=0;d<t;d++){let F=n.albedo[d*4+3]>=128;fe[d]=F?0:1e20,F&&nt++}let Oe=nt>0?qe(fe,e,e):null;for(let d=0;d<t;d++){let F=n.albedo[d*4+3]>=128||!Oe?d:Oe[d];Oe||n.albedo[d*4+3]>0?(W[d*4]=n.albedo[F*4],W[d*4+1]=n.albedo[F*4+1],W[d*4+2]=n.albedo[F*4+2]):W[d*4]=W[d*4+1]=W[d*4+2]=255,W[d*4+3]=Math.round(ue[d]*255)}let te=new Uint8Array(t*4);for(let d=0;d<t;d++){let F=g[d],w=A[d],q=M[d]+y[d],V=b[d],me=F+w+q+V;if(me>.001){let Y=255/me;te[d*4]=Math.round(F*Y),te[d*4+1]=Math.round(w*Y),te[d*4+2]=Math.round(q*Y),te[d*4+3]=Math.round(V*Y)}else x[d]>0&&(te[d*4+2]=255)}return{size:e,surface:H,albedo:W,weights:te,heightScale:_,coverage:N/t}}var dt=`"use strict";(()=>{function An(a){return{f:new Float64Array(a),z:new Float64Array(a+1),v:new Int32Array(a)}}function cn(a,n,e,t,c,u){let{f:m,z:f,v:s}=c;s[0]=0,f[0]=-1e20,f[1]=1e20,m[0]=a[n];for(let l=1,r=0;l<t;l++){m[l]=a[n+l*e];let b=l*l,x;do{let d=s[r];x=(m[l]-m[d]+b-d*d)/(l-d)/2}while(x<=f[r]&&--r>-1);r++,s[r]=l,f[r]=x,f[r+1]=1e20}for(let l=0,r=0;l<t;l++){for(;f[r+1]<l;)r++;let b=s[r],x=l-b;a[n+l*e]=m[b]+x*x,u&&(u[n+l*e]=b)}}function nn(a,n,e){let t=An(Math.max(n,e)),c=new Int32Array(n*e),u=new Int32Array(n*e);for(let f=0;f<n;f++)cn(a,f,n,e,t,c);for(let f=0;f<e;f++)cn(a,f*n,1,n,t,u);let m=new Int32Array(n*e);for(let f=0;f<e;f++){let s=f*n;for(let l=0;l<n;l++){let r=u[s+l],b=c[s+r];m[s+l]=b*n+r}}return m}function Mn(a,n,e){let t=Math.abs(a),c=Math.abs(n);if(t<c){let m=t;t=c,c=m}if(c<1e-6)return .5-e;let u=.5*c/t;return e<u?.5*(t+c)-Math.sqrt(2*t*c*e):e<1-u?(.5-e)*t:-.5*(t+c)+Math.sqrt(2*t*c*(1-e))}function tn(a,n,e,t={}){let c=t.insideOnly??!1,u=(t.refineWithin??1/0)**2,m=Math.min(u,2304),f=n*e,s=new Float32Array(f),l=new Float32Array(f),r=new Float32Array(f),b=new Float32Array(f),x=new Float32Array(f),d=0,A=(y,I)=>a[(I<0?0:I>=e?e-1:I)*n+(y<0?0:y>=n?n-1:y)];for(let y=0;y<e;y++){let I=y>0&&y<e-1;for(let i=0;i<n;i++){let F=y*n+i,B=a[F],O;if(B>0&&B<1)O=!0;else if(I&&i>0&&i<n-1){let U=a[F-1],W=a[F+1],D=a[F-n],j=a[F+n];O=B<=0?U>=1||W>=1||D>=1||j>=1:U<=0||W<=0||D<=0||j<=0}else O=B<=0?Math.max(A(i-1,y),A(i+1,y),A(i,y-1),A(i,y+1))>=1:Math.min(A(i-1,y),A(i+1,y),A(i,y-1),A(i,y+1))<=0;if(!O){s[F]=1e20;continue}s[F]=0,d++;let E=A(i+1,y-1)+2*A(i+1,y)+A(i+1,y+1)-A(i-1,y-1)-2*A(i-1,y)-A(i-1,y+1),q=A(i-1,y+1)+2*A(i,y+1)+A(i+1,y+1)-A(i-1,y-1)-2*A(i,y-1)-A(i+1,y-1),v=Math.hypot(E,q);if(v>1e-4){let U=E/v,W=q/v;b[F]=U,x[F]=W;let D=Mn(U,W,B);l[F]=i+U*D,r[F]=y+W*D}else l[F]=i,r[F]=y}}let k=new Float32Array(f);if(d===0){let y=a[0]>=.5?n+e:-(n+e);return k.fill(y),k}let P=new Uint8Array(f);for(let y=0;y<f;y++)P[y]=s[y]===0?1:0;let _=nn(s,n,e);for(let y=0;y<e;y++)for(let I=0;I<n;I++){let i=y*n+I;if(c&&a[i]<=0)continue;let F=_[i];if(s[i]>u){let R=Math.sqrt(s[i]);k[i]=a[i]>=.5?R:-R;continue}let B=s[i]<m?2:1,O=F%n,E=(F-O)/n,q=F,v=1/0;for(let R=-B;R<=B;R++){let K=E+R;if(!(K<0||K>=e))for(let Q=-B;Q<=B;Q++){let V=O+Q;if(V<0||V>=n)continue;let C=K*n+V;if(!P[C])continue;let X=I-l[C],N=y-r[C],Y=X*X+N*N;Y<v&&(v=Y,q=C)}}let U=I-l[q],W=y-r[q],D=Math.sqrt(v),j=U*b[q]+W*x[q],S=D<1.5&&(b[q]!==0||x[q]!==0)?j>=0:a[i]>=.5;k[i]=S?D:-D}return k}function on(a,n,e,t){let c=tn(a,n,e,{insideOnly:!0,refineWithin:t});for(let u=0;u<c.length;u++)c[u]=a[u]>0?Math.max(0,c[u]):0;return c}function en(a,n,e,t){if(t<=.01)return a.slice();let c=Math.max(1,Math.ceil(t*3)),u=new Float32Array(c*2+1),m=0;for(let r=-c;r<=c;r++){let b=Math.exp(-r*r/(2*t*t));u[r+c]=b,m+=b}for(let r=0;r<u.length;r++)u[r]/=m;let f=new Float32Array(n*e),s=new Float32Array(n*e),l=u.length;for(let r=0;r<e;r++){let b=r*n;for(let x=0;x<n;x++){let d=0;if(x>=c&&x<n-c){let A=b+x-c;for(let k=0;k<l;k++)d+=a[A+k]*u[k]}else for(let A=-c;A<=c;A++){let k=x+A<0?0:x+A>=n?n-1:x+A;d+=a[b+k]*u[A+c]}f[b+x]=d}}for(let r=-c;r<=c;r++){let b=u[r+c];for(let x=0;x<e;x++){let A=(x+r<0?0:x+r>=e?e-1:x+r)*n,k=x*n;for(let P=0;P<n;P++)s[k+P]+=f[A+P]*b}}return s}function Fn(a,n,e,t,c){let u=new Float32Array(e*t),m=1/(2*c+1);for(let f=0;f<t;f++){let s=f*e,l=a[s]*(c+1);for(let r=1;r<=c;r++)l+=a[s+Math.min(r,e-1)];for(let r=0;r<e;r++){u[s+r]=l*m;let b=a[s+Math.min(r+c+1,e-1)],x=a[s+Math.max(r-c,0)];l+=b-x}}for(let f=0;f<e;f++){let s=u[f]*(c+1);for(let l=1;l<=c;l++)s+=u[Math.min(l,t-1)*e+f];for(let l=0;l<t;l++){n[l*e+f]=s*m;let r=u[Math.min(l+c+1,t-1)*e+f],b=u[Math.max(l-c,0)*e+f];s+=r-b}}}function g(a,n,e,t){if(t<2)return en(a,n,e,t);let c=3,u=Math.sqrt(12*t*t/c+1),m=Math.floor(u);m%2===0&&m--;let f=m+2,s=Math.round((12*t*t-c*m*m-4*c*m-3*c)/(-4*m-4)),l=a.slice(),r=new Float32Array(n*e);for(let b=0;b<c;b++){let x=b<s?m:f;Fn(l,r,n,e,x-1>>1);let d=l;l=r,r=d}return l}function rn(a,n,e,t,c){let u=e*t,m=new Float32Array(u);for(let r=0;r<u;r++)m[r]=a[r]*n[r];let f=g(m,e,t,c),s=g(n,e,t,c),l=new Float32Array(u);for(let r=0;r<u;r++)l[r]=s[r]>1e-4?f[r]/s[r]:a[r];return l}function ln(a,n,e,t,c){t=t<0?0:t>n-1?n-1:t,c=c<0?0:c>e-1?e-1:c;let u=Math.floor(t),m=Math.floor(c),f=u+1<n?u+1:u,s=m+1<e?m+1:m,l=t-u,r=c-m,b=a[m*n+u],x=a[m*n+f],d=a[s*n+u],A=a[s*n+f];return(b+(x-b)*l)*(1-r)+(d+(A-d)*l)*r}var fn=.6;function un(a,n){if(a<=0)return 0;if(a>=1)return 1;if(n===0){let e=1-a;return Math.sqrt(1-e*e)}return n===1?Math.sin(a*Math.PI/2):a}function L(a,n,e){let t=new Float32Array(e);for(let c=0;c<e;c++)t[c]=a[c*4+n]/255;return t}function dn(a,n){let e=n*n,t=new Uint8Array(e),c=new Int32Array(e),u=0,m=s=>{!t[s]&&a[s]<.5&&(t[s]=1,c[u++]=s)};for(let s=0;s<n;s++)m(s),m((n-1)*n+s);for(let s=0;s<n;s++)m(s*n),m(s*n+n-1);for(;u>0;){let s=c[--u],l=s%n;l>0&&m(s-1),l<n-1&&m(s+1),s>=n&&m(s-n),s<e-n&&m(s+n)}let f=new Float32Array(e);for(let s=0;s<e;s++){if(t[s]){f[s]=a[s];continue}let l=s%n,r=l>0&&t[s-1]||l<n-1&&t[s+1]||s>=n&&t[s-n]||s<e-n&&t[s+n];f[s]=r?a[s]:1}return f}function In(a,n,e,t,c){let u=t*t,m=new Float32Array(u),f=t*.15,s=.75;for(let l=0;l<t;l++)for(let r=0;r<t;r++){let b=l*t+r;if(n[b]<=.01)continue;let x=a[b],d=e[b]>=n[b]*.5?f:c*1.05,A=(a[r<t-1?b+1:b]-a[r>0?b-1:b])*.5,k=(a[l<t-1?b+t:b]-a[l>0?b-t:b])*.5,P=Math.hypot(A,k);if(P<.2){m[b]=x;continue}let _=A/P*s,y=k/P*s,I=r,i=l,F=x,B=x,O=Math.ceil(d/s)+2;for(let E=0;E<O&&B<d;E++){I+=_,i+=y;let q=ln(a,t,t,I,i);if(q<=F+.001)break;F=q,B=q}m[b]=B}return m}function mn(a){let{size:n,params:e}=a,t=n*n,c=e.profile,u=e.rim*n,m=Math.max(1,e.bevel*n),f=Math.max(1,e.edge*n),s=Math.max(1,e.domeWidth*n),l=e.floor,r=L(a.roles,0,t),b=L(a.roles,1,t),x=L(a.roles,2,t),d=L(a.slotsA,0,t),A=L(a.slotsA,1,t),k=L(a.slotsA,2,t),P=L(a.slotsB,0,t),_=L(a.slotsB,1,t),y=new Float32Array(t);for(let o=0;o<t;o++)y[o]=Math.min(1,r[o]+b[o]+x[o]+d[o]);let I=e.fillHoles?dn(y,n):y,i=new Float32Array(t);for(let o=0;o<t;o++)i[o]=Math.max(0,I[o]-y[o]);let F=tn(I,n,n,{refineWithin:Math.max(f,u)*2+8});if(u>.5)for(let o=0;o<t;o++){if(I[o]<=0)continue;let p=Math.min(I[o],Math.max(0,Math.min(1,u+.5-F[o])));if(p<=0)continue;let M=1-p;r[o]=Math.max(r[o],p),b[o]*=M,x[o]*=M,d[o]*=M,i[o]*=M,P[o]=Math.max(P[o],p),_[o]*=M,k[o]*=M,A[o]*=M}let B=new Float32Array(t);for(let o=0;o<t;o++)B[o]=Math.min(1,r[o]+b[o]);let O=on(B,n,n,n*.16),E=rn(on(x,n,n,s*1.5),x,n,n,Math.max(1,s*.3)),q=rn(In(O,B,r,n,m),B,n,n,3*n/512),v=[];for(let o=0;o<t;o++)r[o]>.5&&O[o]>.75*q[o]&&q[o]>.5&&v.push(q[o]);v.sort((o,p)=>o-p);let U=v.length>8?v[v.length>>1]:0,W=U>0?fn*U/n/Math.max(.05,1-l):1/0,D=Math.max(e.depth*.2,Math.min(e.depth,W)),j=U>0?D*n*Math.max(.05,1-l)/fn:1/0,S=new Float32Array(t),R=0;for(let o=0;o<t;o++){if(I[o]<=0)continue;R+=I[o];let p=F[o]<=0?0:un(F[o]/f,0),M=l*p,H=B[o],w=x[o],Z=d[o]+i[o],T=H+w+Z;if(T<1e-4){S[o]=M;continue}let z=Z*M;if(H>0){let G=Math.min(1,r[o]/Math.max(H,1e-4)),$=Math.max(.75,q[o]),yn=Math.max(.75,G*$+(1-G)*Math.min(m,$)),bn=O[o]/yn,xn=G*Math.min(1,$/j)+(1-G);z+=H*(M+(1-M)*xn*un(bn,c))}if(w>0){let G=Math.min(1,E[o]/s),$=1-(1-G)*(1-G);z+=w*(M+p*(e.enamelLevel+e.enamelDome*$))}S[o]=z/T}let K=n/512;S=en(S,n,n,e.smoothing*K);let Q=g(S,n,n,Math.max(1,n*.008)),V=g(S,n,n,Math.max(2,n*.03)),C=new Float32Array(t*4),X=new Float32Array(t);for(let o=0;o<n;o++)for(let p=0;p<n;p++){let M=o*n+p,H=(S[p<n-1?M+1:M]-S[p>0?M-1:M])*.5,w=(S[o<n-1?M+n:M]-S[o>0?M-n:M])*.5;C[M*4]=S[M],C[M*4+1]=H,C[M*4+2]=w,C[M*4+3]=F[M],X[M]=Math.min(1,Math.max(0,Q[M]-S[M])*2.2+Math.max(0,V[M]-S[M])*1.1)}let N=new Uint8Array(t*4),Y=new Float32Array(t),sn=0;for(let o=0;o<t;o++){let p=a.albedo[o*4+3]>=128;Y[o]=p?0:1e20,p&&sn++}let h=sn>0?nn(Y,n,n):null;for(let o=0;o<t;o++){let p=a.albedo[o*4+3]>=128||!h?o:h[o];h||a.albedo[o*4+3]>0?(N[o*4]=a.albedo[p*4],N[o*4+1]=a.albedo[p*4+1],N[o*4+2]=a.albedo[p*4+2]):N[o*4]=N[o*4+1]=N[o*4+2]=255,N[o*4+3]=Math.round(X[o]*255)}let J=new Uint8Array(t*4);for(let o=0;o<t;o++){let p=P[o],M=_[o],H=k[o]+i[o],w=A[o],Z=p+M+H+w;if(Z>.001){let T=255/Z;J[o*4]=Math.round(p*T),J[o*4+1]=Math.round(M*T),J[o*4+2]=Math.round(H*T),J[o*4+3]=Math.round(w*T)}else I[o]>0&&(J[o*4+2]=255)}return{size:n,surface:C,albedo:N,weights:J,heightScale:D,coverage:R/t}}var an=self;an.onmessage=a=>{let{id:n,input:e}=a.data;try{let t=mn(e);an.postMessage({id:n,out:t},[t.surface.buffer,t.albedo.buffer,t.weights.buffer])}catch(t){an.postMessage({id:n,error:t instanceof Error?t.message:String(t)})}};})();
2
+ `;var fr=3,ee=[],re=null,ht=!1,mr=1;function pt(n){try{n.resolve(mt(n.input))}catch(e){n.reject(e instanceof Error?e:new Error(String(e)))}}function Ye(){ht=!0;let n=ee.flatMap(e=>[...e.jobs.values()]);for(let e of ee)e.worker.terminate();ee=[],re&&URL.revokeObjectURL(re),re=null,n.forEach(pt)}function dr(){try{re||(re=URL.createObjectURL(new Blob([dt],{type:"text/javascript"})));let n={worker:new Worker(re),jobs:new Map};return n.worker.onmessage=e=>{let{id:r,out:t,error:o}=e.data,a=n.jobs.get(r);a&&(n.jobs.delete(r),t?a.resolve(t):a.reject(new Error(o??"bake failed")))},n.worker.onerror=e=>{e.preventDefault(),Ye()},n}catch{return Ye(),null}}function hr(){if(ht||typeof Worker>"u"||typeof Blob>"u")return null;let n=Math.min(fr,Math.max(1,(navigator.hardwareConcurrency||2)-1)),e=ee.find(r=>r.jobs.size===0);if(e)return e;if(ee.length<n){let r=dr();if(r)return ee.push(r),r}return ee.reduce((r,t)=>!r||t.jobs.size<r.jobs.size?t:r,null)}function vt(n){return new Promise((e,r)=>{let t={input:n,resolve:e,reject:r},o=hr();if(!o){setTimeout(()=>pt(t),0);return}let a=mr++;o.jobs.set(a,t);let i={...n,roles:n.roles.slice(),slotsA:n.slotsA.slice(),slotsB:n.slotsB.slice(),albedo:n.albedo.slice()};try{o.worker.postMessage({id:a,input:i},[i.roles.buffer,i.slotsA.buffer,i.slotsB.buffer,i.albedo.buffer])}catch{Ye()}})}var ne=n=>Math.round(n*1e3)/1e3;function Ze(n,e){let r=n.length,t="";for(let o=0;o<r;o++){let a=n[o],i=n[(o-1+r)%r],s=n[(o+1)%r],l=Math.hypot(i[0]-a[0],i[1]-a[1]),m=Math.hypot(s[0]-a[0],s[1]-a[1]),c=Math.min(e,l/2,m/2),f=[a[0]+(i[0]-a[0])/l*c,a[1]+(i[1]-a[1])/l*c],u=[a[0]+(s[0]-a[0])/m*c,a[1]+(s[1]-a[1])/m*c];t+=`${o===0?"M":"L"}${ne(f[0])} ${ne(f[1])}Q${ne(a[0])} ${ne(a[1])} ${ne(u[0])} ${ne(u[1])}`}return`${t}Z`}function Qe(n,e,r,t,o=50,a=50){let i=[];for(let s=0;s<n;s++){let l=(r+360/n*s)*Math.PI/180;i.push([o+Math.cos(l)*e,a+Math.sin(l)*e])}return Ze(i,t)}function pr(n,e,r,t){let o=[];for(let a=0;a<n*2;a++){let i=a%2===0?e:r,s=(-90+180/n*a)*Math.PI/180;o.push([50+Math.cos(s)*i,50+Math.sin(s)*i])}return Ze(o,t)}var ve={circle:"M50 3A47 47 0 1 1 50 97A47 47 0 1 1 50 3Z",hexagon:Qe(6,48,-90,9),octagon:Qe(8,48,-67.5,6),shield:"M14 13Q50 1 86 13L86 47C86 72 70 88 50 97C30 88 14 72 14 47Z",square:Ze([[5,5],[95,5],[95,95],[5,95]],16),diamond:Qe(4,48,-90,8),star:pr(5,49,27,5)};var D="http://www.w3.org/2000/svg",gt="http://www.w3.org/1999/xlink",vr=new Set(["path","rect","circle","ellipse","line","polyline","polygon","text","tspan","textPath","image"]),xt="defs,clipPath,mask,pattern,marker,symbol,linearGradient,radialGradient,filter,foreignObject,style,title,desc,metadata,script";function br(n){return n.replace(/<svg\b[^>]*>/i,e=>{let r=e;return/\sxmlns\s*=/.test(r)||(r=r.replace(/<svg/i,`<svg xmlns="${D}"`)),/xlink:/.test(n)&&!/xmlns:xlink\s*=/.test(r)&&(r=r.replace(/<svg/i,`<svg xmlns:xlink="${gt}"`)),r})}function et(n){let e=new DOMParser().parseFromString(br(n),"image/svg+xml"),r=e.documentElement;if(!r||r.localName!=="svg"||r.namespaceURI!==D||e.getElementsByTagName("parsererror").length>0)throw new Error("badgecraft: the input is not a valid SVG document");for(let t of[r,...r.querySelectorAll("*")]){if(t.namespaceURI!==D||["script","foreignObject","animate","animateMotion","animateTransform","set","discard"].includes(t.localName)){t.remove();continue}for(let o of[...t.attributes])if(/^on/i.test(o.localName))t.removeAttributeNode(o);else if(o.localName==="href"){let a=o.value.trim(),i=t.localName==="image"&&/^data:image\//i.test(a);!a.startsWith("#")&&!i&&t.removeAttributeNode(o)}}return r}function gr(n){let e=n.getAttribute("viewBox");if(e){let o=e.trim().split(/[\s,]+/).map(Number);if(o.length===4&&o.every(Number.isFinite)&&o[2]>0&&o[3]>0)return o}let r=n.getAttribute("width"),t=n.getAttribute("height");if(r&&t&&!r.includes("%")&&!t.includes("%")){let o=parseFloat(r),a=parseFloat(t);if(o>0&&a>0)return[0,0,o,a]}return null}function xr(n){return n.getAttribute("href")??n.getAttributeNS(gt,"href")}function yr(n){for(let e=0;e<4;e++){let r=[...n.getElementsByTagNameNS(D,"use")].filter(t=>!t.closest(xt));if(r.length===0)return;for(let t of r){let o=xr(t),a=o?.startsWith("#")?[...n.querySelectorAll("[id]")].find(f=>f.id===o.slice(1)):null;if(!a||a.contains(t)){t.remove();continue}let i=t.ownerDocument,s=t.getAttribute("x")??"0",l=t.getAttribute("y")??"0",m=i.createElementNS(D,"g");for(let f of[...t.attributes])["href","xlink:href","x","y","width","height","transform"].includes(f.name)||m.setAttribute(f.name,f.value);let c=`${t.getAttribute("transform")??""} translate(${s} ${l})`.trim();if(m.setAttribute("transform",c),a.localName==="symbol"){let f=i.createElementNS(D,"svg");f.setAttribute("width",t.getAttribute("width")??a.getAttribute("width")??"100%"),f.setAttribute("height",t.getAttribute("height")??a.getAttribute("height")??"100%");for(let u of["viewBox","preserveAspectRatio"]){let h=a.getAttribute(u);h&&f.setAttribute(u,h)}f.setAttribute("overflow","visible");for(let u of[...a.childNodes])f.appendChild(u.cloneNode(!0));m.appendChild(f)}else{let f=a.cloneNode(!0);f.removeAttribute("id"),m.appendChild(f)}t.replaceWith(m)}}}function Mr(n,e,r){let t=n.ownerDocument,o=t.createElementNS(D,"svg");o.setAttribute("viewBox","0 0 100 100");let a=r.path??ve[r.shape??"circle"]??ve.circle,i=t.createElementNS(D,"path");if(i.setAttribute("d",a),i.setAttribute("fill","#000"),i.setAttribute("data-relief","flat"),i.setAttribute("data-material",r.material??"base"),i.setAttribute("data-mb-frame",""),o.appendChild(i),r.innerRing&&r.innerRing>0){let m=r.innerRing*100,c=.84,f=t.createElementNS(D,"path");f.setAttribute("d",a),f.setAttribute("fill","none"),f.setAttribute("stroke","#fff"),f.setAttribute("stroke-width",String(m/c)),f.setAttribute("stroke-linejoin","round"),f.setAttribute("transform",`translate(50 50) scale(${c}) translate(-50 -50)`),f.setAttribute("data-material","metal"),f.setAttribute("data-mb-frame",""),o.appendChild(f)}let s=Math.min(.45,Math.max(0,r.padding??.22))*100,l=t.createElementNS(D,"svg");for(let m of[...n.attributes])/^(xmlns(:.*)?|width|height|x|y|viewBox|preserveAspectRatio|version|baseProfile)$/.test(m.name)||l.setAttribute(m.name,m.value);for(l.setAttribute("x",String(s)),l.setAttribute("y",String(s)),l.setAttribute("width",String(100-2*s)),l.setAttribute("height",String(100-2*s)),l.setAttribute("viewBox",e.join(" ")),l.setAttribute("preserveAspectRatio","xMidYMid meet"),l.setAttribute("overflow","visible");n.firstChild;)l.appendChild(n.firstChild);return o.appendChild(l),o}function be(n,e){return n.closest(`[${e}]`)?.getAttribute(e)??null}var Ar={wire:"metal",raised:"metal",inset:"enamel",flat:"base"},Er=new Set(["metal","enamel","base","accent"]);function Je(n,e,r){let t=n.getAttribute(e)??be(n,e)??be(n,"data-material");return t&&Er.has(t)?t:Ar[r]}function bt(n,e){return!n||n==="none"||/^rgba\(.*,\s*0\)$/.test(n)||n==="transparent"?!1:parseFloat(e||"1")>.004}function we(n,e){let r=t=>t?"ff":"00";return n==="roles"?`#${r(e.role==="wire")}${r(e.role==="raised")}${r(e.role==="inset")}`:n==="slotsA"?`#${r(e.role==="flat")}${r(e.slot==="accent")}${r(e.slot==="base")}`:`#${r(e.slot==="metal")}${r(e.slot==="enamel")}00`}function Te(n,e,r,t){let o=n.cloneNode(!0),a=o.ownerDocument,i=o.querySelectorAll("[data-mb-i]"),s=new Map,l=c=>{let f=s.get(c);return f||(f=`mb-solid-${c.slice(1)}`,s.set(c,f)),`url(#${f})`};for(let c of i){let f=e[Number(c.getAttribute("data-mb-i"))];c.removeAttribute("data-mb-i");let u=c.getAttribute("style")??"";if(u&&!u.trim().endsWith(";")&&(u+=";"),f.hidden){c.setAttribute("style",`${u}display:none !important;`);continue}if(r==="albedo"){u+="filter:none !important;mix-blend-mode:normal !important;",f.shape&&(!f.fill&&!f.image&&(u+="fill:none !important;"),(!f.stroke||f.stroke.slot==="metal")&&(u+="stroke:none !important;"),f.image&&!f.fill&&(u+="display:none !important;")),c.setAttribute("style",u);continue}u+="opacity:1 !important;filter:none !important;mix-blend-mode:normal !important;",f.shape&&(u+="fill-opacity:1 !important;stroke-opacity:1 !important;marker:none !important;",f.image?u+=f.fill?`filter:${l(we(r,f.fill))} !important;`:"display:none !important;":(u+=f.fill?`fill:${we(r,f.fill)} !important;`:"fill:none !important;",f.stroke?u+=`stroke:${we(r,f.stroke)} !important;`:f.outline?u+=`stroke:${we(r,f.outline)} !important;stroke-width:${t}px !important;vector-effect:non-scaling-stroke !important;stroke-linejoin:round !important;stroke-linecap:round !important;stroke-dasharray:none !important;`:u+="stroke:none !important;")),c.setAttribute("style",u)}let m=o.getAttribute("style")??"";if(o.setAttribute("style",`${m}${m&&!m.trim().endsWith(";")?";":""}background:none !important;`),s.size>0){let c=a.createElementNS(D,"defs");for(let[f,u]of s){let h=a.createElementNS(D,"filter");h.setAttribute("id",u),h.setAttribute("color-interpolation-filters","sRGB");let b=a.createElementNS(D,"feFlood");b.setAttribute("flood-color",f);let M=a.createElementNS(D,"feComposite");M.setAttribute("in2","SourceAlpha"),M.setAttribute("operator","in"),h.append(b,M),c.appendChild(h)}o.insertBefore(c,o.firstChild)}return new XMLSerializer().serializeToString(o)}function yt(n,e,r){if(typeof document>"u")throw new Error("badgecraft: SVG preparation needs a browser DOM");let t=document.importNode(et(n),!0),o=document.createElement("div");o.setAttribute("aria-hidden","true"),o.style.cssText="position:fixed;left:-10000px;top:-10000px;width:64px;height:64px;overflow:hidden;opacity:0;pointer-events:none;contain:strict;",o.style.color=e.color;let a=o.attachShadow({mode:"open"});(document.body??document.documentElement).appendChild(o);try{yr(t),a.appendChild(t);let i=gr(t);if(!i){let p=t.getBBox?.();i=p&&p.width>0&&p.height>0?[p.x,p.y,p.width,p.height]:[0,0,100,100]}if(e.frame){let p=Mr(t,i,e.frame);t.replaceWith(p),t=p,i=[0,0,100,100]}let s=[...t.querySelectorAll("*")].filter(p=>!p.closest(xt)),l=new Map,m=p=>{if(!p||p===t.parentNode)return!1;let T=l.get(p);if(T!==void 0)return T;let S=getComputedStyle(p),B=S.display==="none"||parseFloat(S.opacity||"1")<=.004||p!==t&&m(p.parentElement);return l.set(p,B),B},c=s.map(p=>{let T=vr.has(p.localName),S=p.localName==="image",B=m(p)||T&&getComputedStyle(p).visibility==="hidden",_=!1,X=!1,C="";if(T&&!B){let N=getComputedStyle(p);_=S||p.localName!=="line"&&bt(N.fill,N.fillOpacity),X=!S&&bt(N.stroke,N.strokeOpacity)&&parseFloat(N.strokeWidth)>0,C=N.fill}return{el:p,hidden:B,shape:T,image:S,hasFill:_,hasStroke:X,fillPaint:C,frame:!!p.closest("[data-mb-frame]")}}),f=c.filter(p=>p.shape&&!p.hidden&&!p.frame),u=f.some(p=>p.hasStroke&&be(p.el,"data-stroke-relief")!=="none"),h=new Set(f.filter(p=>p.hasFill&&!p.image).map(p=>p.fillPaint)),b=f.some(p=>p.image),M=e.mode!=="auto"?e.mode:u||b||h.size>1||[...h].some(p=>p.startsWith("url("))?"cloisonne":"embossed",g=e.outline==="auto"?M==="cloisonne"&&!u&&h.size>1?e.autoOutline:0:Math.max(0,e.outline),A=c.map(p=>{let T={hidden:p.hidden,shape:p.shape,image:p.image,fill:null,stroke:null,outline:null};if(p.hidden||!p.shape)return T;if(p.hasFill){let S=be(p.el,"data-relief")??(M==="embossed"?"raised":"inset");(S==="raised"||S==="inset"||S==="flat")&&(T.fill={role:S,slot:Je(p.el,"data-fill-material",S)})}if(p.hasStroke){let S=be(p.el,"data-stroke-relief")??"raised",B=S==="raised"?"wire":S==="inset"||S==="flat"?S:null;B&&(T.stroke={role:B,slot:Je(p.el,"data-stroke-material",B)})}else g>0&&T.fill&&T.fill.role==="inset"&&!p.image&&!p.frame&&(T.outline={role:"wire",slot:Je(p.el,"data-stroke-material","wire")});return T});s.forEach((p,T)=>p.setAttribute("data-mb-i",String(T)));let v=.03+g*.6,[x,y,E,R]=i,L=Math.max(E,R)*(1+2*v);t.setAttribute("viewBox",`${x+E/2-L/2} ${y+R/2-L/2} ${L} ${L}`),t.setAttribute("width",String(r)),t.setAttribute("height",String(r)),t.setAttribute("preserveAspectRatio","xMidYMid meet"),t.removeAttribute("x"),t.removeAttribute("y"),t.getAttribute("color")||t.setAttribute("color",e.color);let I=g*r;return{roles:Te(t,A,"roles",I),slotsA:Te(t,A,"slotsA",I),slotsB:Te(t,A,"slotsB",I),albedo:Te(t,A,"albedo",I),mode:M,outline:g}}finally{o.remove()}}function wr(n){return new Promise((e,r)=>{let t=new Image;t.decoding="async",t.onload=()=>e(t),t.onerror=()=>r(new Error("badgecraft: the browser could not render the SVG")),t.src=n})}async function ge(n,e,r){let t=URL.createObjectURL(new Blob([n],{type:"image/svg+xml;charset=utf-8"}));try{let o=await wr(t),a=document.createElement("canvas");a.width=e,a.height=e;let i=a.getContext("2d",{willReadFrequently:!0});if(!i)throw new Error("badgecraft: 2D canvas unavailable");return r&&(i.fillStyle=r,i.fillRect(0,0,e,e)),i.drawImage(o,0,0,e,e),i.getImageData(0,0,e,e).data}finally{URL.revokeObjectURL(t)}}function At(n,e,r){return`${He(n)}:${He(e)}:${r}`}async function Et(n,e,r){let t=yt(n,{mode:e.mode,color:e.color,frame:e.frame,outline:e.outline,autoOutline:e.autoOutline},r),[o,a,i,s]=await Promise.all([ge(t.roles,r,"#000"),ge(t.slotsA,r,"#000"),ge(t.slotsB,r,"#000"),ge(t.albedo,r)]);return vt({size:r,roles:o,slotsA:a,slotsB:i,albedo:s,params:{depth:e.depth,rim:e.rim,fillHoles:e.fillHoles,floor:e.floor,profile:e.profile,bevel:e.bevel,edge:e.edge,enamelLevel:e.enamelLevel,enamelDome:e.enamelDome,domeWidth:e.domeWidth,smoothing:e.smoothing}})}var G=new Map,Se=new Map,Tr=8,Sr=48*1024*1024;function Rr(n,e){let r=G.get(n);if(r)return G.delete(n),G.set(n,r),r;let t=e();return t.then(o=>{G.get(n)===t&&(Se.set(n,o.surface.byteLength+o.albedo.byteLength+o.weights.byteLength),Mt())},()=>G.get(n)===t&&G.delete(n)),r=t,G.set(n,r),Mt(),r}function Mt(){let n=0;for(let e of Se.values())n+=e;for(;G.size>1&&(G.size>Tr||n>Sr);){let e=G.keys().next().value;n-=Se.get(e)??0,G.delete(e),Se.delete(e)}}var oe=new Map;async function wt(n,e,r){let t=oe.get(e);if(t?.textures&&t.generation!==n.generation&&(t=void 0),!t){let o={refs:0,generation:n.generation,promise:Rr(e,r).then(a=>(o.textures=n.createBadgeTextures(a),o.generation=n.generation,o.textures))};o.promise.catch(()=>oe.get(e)===o&&oe.delete(e)),oe.set(e,o),t=o}t.refs++,t.disposeTimer&&(clearTimeout(t.disposeTimer),t.disposeTimer=void 0);try{return{key:e,textures:await t.promise,entry:t}}catch(o){throw t.refs--,o}}function Re(n,e){let r=e.entry;r.refs--,!(r.refs>0)&&(r.disposeTimer=setTimeout(()=>{r.refs>0||(oe.get(e.key)===r&&oe.delete(e.key),r.textures&&r.generation===n.generation&&n.deleteBadgeTextures(r.textures))},4e3))}function Tt(n){let e=new Uint8Array(n),r=0,t=()=>{let h="";for(;r<e.length&&e[r]!==10;)h+=String.fromCharCode(e[r++]);if(r>=e.length)throw new Error("badgecraft: truncated HDR header");return r++,h.replace(/\r$/,"")};if(!t().startsWith("#?"))throw new Error("badgecraft: not a Radiance HDR file");let a=t();for(;a.length>0;)a=t();let i=t().match(/-Y\s+(\d+)\s+\+X\s+(\d+)/);if(!i)throw new Error("badgecraft: unsupported HDR orientation");let s=Number(i[1]),l=Number(i[2]);if(l<1||s<1||l*s>16777216)throw new Error("badgecraft: invalid or oversized HDR dimensions");let m=h=>{if(r+h>e.length)throw new Error("badgecraft: truncated HDR pixels")},c=new Uint8Array(l*s*4),f=new Uint8Array(l*4);for(let h=0;h<s;h++){if(m(4),!(l>=8&&l<32768&&e[r]===2&&e[r+1]===2&&!(e[r+2]&128))){m(l*4),c.set(e.subarray(r,r+l*4),h*l*4),r+=l*4;continue}if((e[r+2]<<8|e[r+3])!==l)throw new Error("badgecraft: HDR scanline width mismatch");r+=4;for(let M=0;M<4;M++){let g=0;for(;g<l;){m(1);let A=e[r++],v=A>128?A-128:A;if(v===0||g+v>l)throw new Error("badgecraft: invalid HDR run length");if(m(A>128?1:v),A>128){A-=128;let x=e[r++];for(let y=0;y<A;y++)f[g++*4+M]=x}else for(let x=0;x<A;x++)f[g++*4+M]=e[r++]}}c.set(f,h*l*4)}let u=new Float32Array(l*s*4);for(let h=0;h<l*s;h++){let b=c[h*4+3],M=b?Math.pow(2,b-136):0;u[h*4]=c[h*4]*M,u[h*4+1]=c[h*4+1]*M,u[h*4+2]=c[h*4+2]*M,u[h*4+3]=1}return{width:l,height:s,data:u}}function St(n,e){let r=Math.min(e,384),t=[],o=[],a=[],i=new Map,s=[],l=(u,h)=>{let b=Math.max(0,Math.min(e-1,u*e-.5)),M=Math.max(0,Math.min(e-1,h*e-.5)),g=Math.floor(b),A=Math.floor(M),v=Math.min(g+1,e-1),x=Math.min(A+1,e-1),y=n[(A*e+g)*4+3]*(1-b+g)+n[(A*e+v)*4+3]*(b-g),E=n[(x*e+g)*4+3]*(1-b+g)+n[(x*e+v)*4+3]*(b-g);return y*(1-M+A)+E*(M-A)};for(let u=0;u<=r;u++)for(let h=0;h<=r;h++)t.push(h/r,u/r,0),a.push(l(h/r,u/r));let m=(u,h)=>{if(a[u]===0)return u;if(a[h]===0)return h;let b=u<h?`${u}:${h}`:`${h}:${u}`,M=i.get(b);if(M!==void 0)return M;let g=0,A=1;for(let y=0;y<12;y++){let E=(g+A)/2;l(t[u*3]*(1-E)+t[h*3]*E,t[u*3+1]*(1-E)+t[h*3+1]*E)>=0==a[u]>=0?g=E:A=E}let v=(g+A)/2,x=t.length/3;return t.push(t[u*3]*(1-v)+t[h*3]*v,t[u*3+1]*(1-v)+t[h*3+1]*v,0),a.push(0),i.set(b,x),x},c=(u,h,b)=>{let M=[u,h,b],g=[];for(let A=0;A<3;A++){let v=M[A],x=M[(A+1)%3];a[v]>=0&&g.push(v),a[v]>=0!=a[x]>=0&&g.push(m(v,x))}for(let A=g.length-1;A>=0;A--)g[A]===g[(A+1)%g.length]&&g.splice(A,1);if(!(g.length<3)){for(let A=1;A+1<g.length;A++)o.push(g[0],g[A],g[A+1]);for(let A=0;A<g.length;A++){let v=g[A],x=g[(A+1)%g.length],y=[0,1].some(E=>t[v*3+E]===t[x*3+E]&&(t[v*3+E]===0||t[v*3+E]===1));(a[v]===0&&a[x]===0||y)&&s.push([v,x])}}};for(let u=0;u<r;u++)for(let h=0;h<r;h++){let b=u*(r+1)+h,M=b+1,g=b+r+1,A=g+1,v=a[b],x=a[M],y=a[g],E=a[A];if(!(v<0&&x<0&&y<0&&E<0)){if(v>0&&x>0&&y>0&&E>0&&h>0&&u>0&&h<r-1&&u<r-1){o.push(b,g,M,M,g,A);continue}c(b,g,M),c(M,g,A)}}let f=o.length;for(let[u,h]of s){let b=t.length/3;for(let[M,g]of[[u,1],[u,-1],[h,1],[h,-1]])t.push(t[M*3],t[M*3+1],g);o.push(b,b+1,b+2,b+2,b+1,b+3)}return{vertices:new Float32Array(t),indices:new Uint32Array(o),faceCount:f}}function Rt(n,e,r,t){let o=1/Math.tan(n/2),a=1/(r-t),i=new Float32Array(16);return i[0]=o/e,i[5]=o,i[10]=(t+r)*a,i[11]=-1,i[14]=2*t*r*a,i}function Fe(n,e){let r=new Float32Array(16);for(let t=0;t<4;t++)for(let o=0;o<4;o++)r[t*4+o]=n[o]*e[t*4]+n[4+o]*e[t*4+1]+n[8+o]*e[t*4+2]+n[12+o]*e[t*4+3];return r}function kt(n,e,r){let t=ke();return t[12]=n,t[13]=e,t[14]=r,t}function ke(){let n=new Float32Array(16);return n[0]=n[5]=n[10]=n[15]=1,n}function Ft(n,e,r=0){let t=Math.cos(n),o=Math.sin(n),a=Math.cos(e),i=Math.sin(e),s=ke();s[5]=t,s[6]=o,s[9]=-o,s[10]=t;let l=ke();l[0]=a,l[2]=-i,l[8]=i,l[10]=a;let m=Fe(l,s);if(r){let c=Math.cos(r),f=Math.sin(r),u=ke();u[0]=c,u[1]=f,u[4]=-f,u[5]=c,m=Fe(m,u)}return m}function Pt(n){return new Float32Array([n[0],n[1],n[2],n[4],n[5],n[6],n[8],n[9],n[10]])}var Pe=`
3
+ const float PI = 3.14159265359;
4
+
5
+ // Equirectangular mapping. u = 0.5 looks along +z (towards the viewer), v = 0 is straight up.
6
+ vec2 dirToUv(vec3 d, float rotation) {
7
+ float u = atan(d.x, d.z) * (0.5 / PI) + 0.5 + rotation;
8
+ float v = acos(clamp(d.y, -1.0, 1.0)) / PI;
9
+ return vec2(u, v);
10
+ }
11
+
12
+ vec3 uvToDir(vec2 uv) {
13
+ float phi = (uv.x - 0.5) * 2.0 * PI;
14
+ float theta = uv.y * PI;
15
+ return vec3(sin(theta) * sin(phi), cos(theta), sin(theta) * cos(phi));
16
+ }
17
+ `,Le=`#version 300 es
18
+ void main() {
19
+ vec2 p = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
20
+ gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);
21
+ }
22
+ `;var Lt=`#version 300 es
23
+ precision highp float;
24
+ ${Pe}
25
+ uniform vec2 uSize;
26
+ uniform vec3 uTop;
27
+ uniform vec3 uHorizon;
28
+ uniform vec3 uBottom;
29
+ uniform int uLightCount;
30
+ uniform vec3 uLightDir[8];
31
+ uniform vec3 uLightColor[8];
32
+ uniform vec4 uLightShape[8]; // tan(half width), tan(half height), softness, circle?
33
+ uniform float uScale;
34
+ out vec4 outColor;
35
+
36
+ void main() {
37
+ vec2 uv = gl_FragCoord.xy / uSize;
38
+ vec3 d = uvToDir(uv);
39
+ vec3 col = d.y > 0.0
40
+ ? mix(uHorizon, uTop, pow(d.y, 0.55))
41
+ : mix(uHorizon, uBottom, pow(-d.y, 0.4));
42
+ for (int i = 0; i < 8; i++) {
43
+ if (i >= uLightCount) break;
44
+ vec3 c = uLightDir[i];
45
+ float cd = dot(d, c);
46
+ if (cd <= 0.02) continue;
47
+ vec3 up = abs(c.y) > 0.99 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
48
+ vec3 right = normalize(cross(up, c));
49
+ vec3 upv = cross(c, right);
50
+ vec2 p = vec2(dot(d, right), dot(d, upv)) / cd;
51
+ vec4 s = uLightShape[i];
52
+ float soft = clamp(s.z, 0.02, 1.0);
53
+ float e;
54
+ if (s.w > 0.5) {
55
+ e = length(p) / s.x;
56
+ } else {
57
+ vec2 q = abs(p) / s.xy;
58
+ e = pow(pow(q.x, 8.0) + pow(q.y, 8.0), 0.125);
59
+ }
60
+ float m = 1.0 - smoothstep(1.0 - soft, 1.0, e);
61
+ col += uLightColor[i] * m;
62
+ }
63
+ outColor = vec4(col * uScale, 1.0);
64
+ }
65
+ `,Bt=`
66
+ vec2 hammersley(int i, int n) {
67
+ uint b = uint(i);
68
+ b = (b << 16u) | (b >> 16u);
69
+ b = ((b & 0x55555555u) << 1u) | ((b & 0xAAAAAAAAu) >> 1u);
70
+ b = ((b & 0x33333333u) << 2u) | ((b & 0xCCCCCCCCu) >> 2u);
71
+ b = ((b & 0x0F0F0F0Fu) << 4u) | ((b & 0xF0F0F0F0u) >> 4u);
72
+ b = ((b & 0x00FF00FFu) << 8u) | ((b & 0xFF00FF00u) >> 8u);
73
+ return vec2(float(i) / float(n), float(b) * 2.3283064365386963e-10);
74
+ }
75
+
76
+ mat3 tangentFrame(vec3 n) {
77
+ vec3 up = abs(n.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
78
+ vec3 t = normalize(cross(up, n));
79
+ return mat3(t, cross(n, t), n);
80
+ }
81
+ `,Ct=`#version 300 es
82
+ precision highp float;
83
+ ${Pe}
84
+ ${Bt}
85
+ uniform sampler2D uSrc;
86
+ uniform vec2 uSize;
87
+ uniform float uRoughness;
88
+ uniform float uTexelSolidAngle;
89
+ out vec4 outColor;
90
+ const int SAMPLES = 256;
91
+
92
+ void main() {
93
+ vec2 uv = gl_FragCoord.xy / uSize;
94
+ // The mirror level is a resample, not a convolution. Preserve crisp studio
95
+ // cards and skip 256 identical GGX samples over the largest mip level.
96
+ if (uRoughness <= 0.001) {
97
+ outColor = vec4(textureLod(uSrc, uv, 0.0).rgb, 1.0);
98
+ return;
99
+ }
100
+ vec3 N = uvToDir(uv);
101
+ float a = max(uRoughness * uRoughness, 1e-4);
102
+ float a2 = a * a;
103
+ mat3 tbn = tangentFrame(N);
104
+ vec3 sum = vec3(0.0);
105
+ float wsum = 0.0;
106
+ for (int i = 0; i < SAMPLES; i++) {
107
+ vec2 xi = hammersley(i, SAMPLES);
108
+ float phi = 2.0 * PI * xi.x;
109
+ float cosT = sqrt((1.0 - xi.y) / (1.0 + (a2 - 1.0) * xi.y));
110
+ float sinT = sqrt(1.0 - cosT * cosT);
111
+ vec3 H = tbn * vec3(cos(phi) * sinT, sin(phi) * sinT, cosT);
112
+ float NdH = dot(N, H);
113
+ vec3 L = 2.0 * NdH * H - N;
114
+ float NdL = dot(N, L);
115
+ if (NdL > 0.0) {
116
+ float d = NdH * NdH * (a2 - 1.0) + 1.0;
117
+ float D = a2 / (PI * d * d);
118
+ float pdf = D * 0.25;
119
+ float saSample = 1.0 / (float(SAMPLES) * pdf + 1e-5);
120
+ float lod = max(0.5 * log2(saSample / uTexelSolidAngle) + 1.0, 0.0);
121
+ sum += textureLod(uSrc, dirToUv(L, 0.0), lod).rgb * NdL;
122
+ wsum += NdL;
123
+ }
124
+ }
125
+ outColor = vec4(sum / max(wsum, 1e-4), 1.0);
126
+ }
127
+ `,It=`#version 300 es
128
+ precision highp float;
129
+ ${Pe}
130
+ ${Bt}
131
+ uniform sampler2D uSrc;
132
+ uniform vec2 uSize;
133
+ uniform float uTexelSolidAngle;
134
+ out vec4 outColor;
135
+ const int SAMPLES = 512;
136
+
137
+ void main() {
138
+ vec2 uv = gl_FragCoord.xy / uSize;
139
+ vec3 N = uvToDir(uv);
140
+ mat3 tbn = tangentFrame(N);
141
+ vec3 sum = vec3(0.0);
142
+ for (int i = 0; i < SAMPLES; i++) {
143
+ vec2 xi = hammersley(i, SAMPLES);
144
+ float phi = 2.0 * PI * xi.x;
145
+ float cosT = sqrt(1.0 - xi.y);
146
+ float sinT = sqrt(xi.y);
147
+ vec3 L = tbn * vec3(cos(phi) * sinT, sin(phi) * sinT, cosT);
148
+ float pdf = cosT / PI;
149
+ float saSample = 1.0 / (float(SAMPLES) * pdf + 1e-5);
150
+ float lod = max(0.5 * log2(saSample / uTexelSolidAngle) + 1.0, 0.0);
151
+ sum += textureLod(uSrc, dirToUv(L, 0.0), lod).rgb;
152
+ }
153
+ outColor = vec4(sum / float(SAMPLES), 1.0);
154
+ }
155
+ `,Nt=`#version 300 es
156
+ precision highp float;
157
+ layout(location = 0) in vec2 aUv;
158
+ layout(location = 1) in float aLip;
159
+ uniform sampler2D uSurface;
160
+ uniform mat4 uModel;
161
+ uniform mat4 uViewProj;
162
+ uniform float uDepth;
163
+ uniform float uThickness;
164
+ uniform float uEdgeTexels;
165
+ uniform float uSide;
166
+ out vec2 vUv;
167
+ out vec3 vWorld;
168
+ out vec3 vLocal;
169
+
170
+ float roundProfile(float t) {
171
+ float u = 1.0 - clamp(t, 0.0, 1.0);
172
+ return sqrt(max(0.0, 1.0 - u * u));
173
+ }
174
+
175
+ void main() {
176
+ vec4 s = textureLod(uSurface, aUv, 0.0);
177
+ float side = uSide == 0.0 ? aLip : uSide;
178
+ float z = side > 0.0 ? s.r * uDepth : -uThickness * roundProfile(max(s.a, 0.0) / uEdgeTexels);
179
+ vec3 p = vec3(aUv.x - 0.5, 0.5 - aUv.y, z);
180
+ vec4 w = uModel * vec4(p, 1.0);
181
+ vUv = aUv;
182
+ vWorld = w.xyz;
183
+ vLocal = p;
184
+ gl_Position = uViewProj * w;
185
+ }
186
+ `,Ut=`#version 300 es
187
+ precision highp float;
188
+ ${Pe}
189
+ in vec2 vUv;
190
+ in vec3 vWorld;
191
+ in vec3 vLocal;
192
+
193
+ uniform sampler2D uSurface;
194
+ uniform sampler2D uAlbedo;
195
+ uniform sampler2D uWeights;
196
+ uniform sampler2D uEnvSpec;
197
+ uniform sampler2D uEnvIrr;
198
+ uniform float uEnvMaxLod;
199
+ uniform float uEnvRotation;
200
+ uniform float uEnvScale;
201
+
202
+ uniform vec4 uMatColor[4]; // linear rgb, useSvgColor
203
+ uniform vec4 uMatA[4]; // metalness, roughness, clearcoat, clearcoat roughness
204
+ uniform vec4 uMatB[4]; // dielectric f0, iridescence, film thickness (nm), flakes
205
+ uniform vec4 uMatC[4]; // brushed, brush direction, flake scale, emissive
206
+
207
+ uniform mat3 uNormalMatrix;
208
+ uniform vec3 uCamPos;
209
+ uniform float uMapSize;
210
+ uniform float uPixelScale;
211
+ uniform float uDepth;
212
+ uniform float uThickness;
213
+ uniform float uEdgeTexels;
214
+ uniform float uAo;
215
+ uniform float uExposure;
216
+ uniform float uSide;
217
+ uniform int uToneMap;
218
+ uniform float uLocked;
219
+ uniform vec3 uLockedColor;
220
+ uniform float uShine;
221
+
222
+ out vec4 outColor;
223
+
224
+ vec3 envSpec(vec3 dir, float roughness) {
225
+ return textureLod(uEnvSpec, dirToUv(dir, uEnvRotation), roughness * uEnvMaxLod).rgb * uEnvScale;
226
+ }
227
+
228
+ vec3 envIrr(vec3 dir) {
229
+ return textureLod(uEnvIrr, dirToUv(dir, uEnvRotation), 0.0).rgb * uEnvScale;
230
+ }
231
+
232
+ // Karis' analytic approximation of the split-sum BRDF integral.
233
+ vec2 envBRDF(float roughness, float NdV) {
234
+ const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
235
+ const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
236
+ vec4 r = roughness * c0 + c1;
237
+ float a004 = min(r.x * r.x, exp2(-9.28 * NdV)) * r.x + r.y;
238
+ return vec2(-1.04, 1.04) * a004 + r.zw;
239
+ }
240
+
241
+ float hash12(vec2 p) {
242
+ vec3 p3 = fract(vec3(p.xyx) * 0.1031);
243
+ p3 += dot(p3, p3.yzx + 33.33);
244
+ return fract((p3.x + p3.y) * p3.z);
245
+ }
246
+
247
+ vec3 hash32(vec2 p) {
248
+ vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973));
249
+ p3 += dot(p3, p3.yxz + 33.33);
250
+ return fract((p3.xxy + p3.yzz) * p3.zyx);
251
+ }
252
+
253
+ float noise1(float x) {
254
+ float i = floor(x);
255
+ float f = fract(x);
256
+ float a = hash12(vec2(i, 17.0));
257
+ float b = hash12(vec2(i + 1.0, 17.0));
258
+ return mix(a, b, f * f * (3.0 - 2.0 * f));
259
+ }
260
+
261
+ // Thin-film interference tint (cheap spectral approximation).
262
+ vec3 thinFilm(float cosTheta, float thicknessNm) {
263
+ float n = 1.4;
264
+ float cosT = sqrt(max(0.0, 1.0 - (1.0 - cosTheta * cosTheta) / (n * n)));
265
+ float opd = 2.0 * n * thicknessNm * cosT;
266
+ vec3 phase = 2.0 * PI * opd / vec3(650.0, 532.0, 450.0);
267
+ return 0.5 + 0.5 * cos(phase);
268
+ }
269
+
270
+ vec3 srgbToLinear(vec3 c) {
271
+ return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(0.04045, c));
272
+ }
273
+
274
+ vec3 linearToSrgb(vec3 c) {
275
+ c = clamp(c, 0.0, 1.0);
276
+ return mix(c * 12.92, 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, c));
277
+ }
278
+
279
+ // Khronos PBR Neutral: keeps base colours faithful, rolls off highlights.
280
+ vec3 toneNeutral(vec3 color) {
281
+ const float startCompression = 0.8 - 0.04;
282
+ const float desaturation = 0.15;
283
+ float x = min(color.r, min(color.g, color.b));
284
+ float offset = x < 0.08 ? x - 6.25 * x * x : 0.04;
285
+ color -= offset;
286
+ float peak = max(color.r, max(color.g, color.b));
287
+ if (peak < startCompression) return color;
288
+ const float d = 1.0 - startCompression;
289
+ float newPeak = 1.0 - d * d / (peak + d - startCompression);
290
+ color *= newPeak / peak;
291
+ float g = 1.0 - 1.0 / (desaturation * (peak - newPeak) + 1.0);
292
+ return mix(color, vec3(newPeak), g);
293
+ }
294
+
295
+ vec3 toneAces(vec3 x) {
296
+ x *= 0.6;
297
+ return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0);
298
+ }
299
+
300
+ vec3 toneAgx(vec3 v) {
301
+ const mat3 m = mat3(0.842479062253094, 0.0423282422610123, 0.0423756549057051,
302
+ 0.0784335999999992, 0.878468636469772, 0.0784336,
303
+ 0.0792237451477643, 0.0791661274605434, 0.879142973793104);
304
+ const mat3 mi = mat3(1.19687900512017, -0.0528968517574562, -0.0529716355144438,
305
+ -0.0980208811401368, 1.15190312990417, -0.0980434501171241,
306
+ -0.0990297440797205, -0.0989611768448433, 1.15107367264116);
307
+ const float minEv = -12.47393;
308
+ const float maxEv = 4.026069;
309
+ v = m * v;
310
+ v = clamp(log2(max(v, 1e-10)), minEv, maxEv);
311
+ v = (v - minEv) / (maxEv - minEv);
312
+ vec3 v2 = v * v;
313
+ vec3 v4 = v2 * v2;
314
+ v = 15.5 * v4 * v2 - 40.14 * v4 * v + 31.96 * v4 - 6.868 * v2 * v + 0.4298 * v2 + 0.1191 * v - 0.00232;
315
+ v = mi * v;
316
+ return pow(max(v, 0.0), vec3(2.2));
317
+ }
318
+
319
+ vec3 toneMap(vec3 c) {
320
+ if (uToneMap == 0) return toneNeutral(c);
321
+ if (uToneMap == 1) return toneAces(c);
322
+ if (uToneMap == 2) return toneAgx(c);
323
+ return c;
324
+ }
325
+
326
+ void main() {
327
+ vec4 s = texture(uSurface, vUv);
328
+ float sd = s.a;
329
+ // The contour mesh supplies silhouette coverage through MSAA. A second
330
+ // distance-field alpha cut would expose cracks at the front/back seam.
331
+ float alpha = 1.0;
332
+
333
+ vec4 w = texture(uWeights, vUv);
334
+ w /= max(w.r + w.g + w.b + w.a, 1e-4);
335
+
336
+ if (uLocked > 0.5) {
337
+ float line = alpha * clamp(w.r + w.a, 0.0, 1.0);
338
+ if (line <= 0.001) discard;
339
+ outColor = vec4(linearToSrgb(uLockedColor) * line, line);
340
+ return;
341
+ }
342
+
343
+ vec3 nLocal;
344
+ if (uSide > 0.0) {
345
+ float k = uDepth * uMapSize;
346
+ nLocal = normalize(vec3(-s.g * k, s.b * k, 1.0));
347
+ } else {
348
+ // Flat back with the same rounded edge as the front.
349
+ float texel = 1.0 / uMapSize;
350
+ float sx = texture(uSurface, vUv + vec2(texel, 0.0)).a - texture(uSurface, vUv - vec2(texel, 0.0)).a;
351
+ float sy = texture(uSurface, vUv + vec2(0.0, texel)).a - texture(uSurface, vUv - vec2(0.0, texel)).a;
352
+ float t = clamp(sd / uEdgeTexels, 0.0, 1.0);
353
+ float u = 1.0 - t;
354
+ float dp = t < 1.0 ? u / max(sqrt(max(1.0 - u * u, 1e-4)), 0.05) : 0.0;
355
+ float k = uThickness * dp / uEdgeTexels * uMapSize * 0.5;
356
+ nLocal = uSide == 0.0 ? normalize(vec3(-sx, sy, 0.0)) : normalize(vec3(-k * sx, k * sy, -1.0));
357
+ w = vec4(1.0, 0.0, 0.0, 0.0);
358
+ }
359
+ vec3 N = normalize(uNormalMatrix * nLocal);
360
+ vec3 V = normalize(uCamPos - vWorld);
361
+
362
+ vec4 albedo = texture(uAlbedo, vUv);
363
+ vec3 svg = albedo.rgb; // sRGB texture: already linear
364
+ float cavity = uSide > 0.0 ? albedo.a : 0.0;
365
+
366
+ vec3 baseColor = vec3(0.0);
367
+ vec4 A = vec4(0.0);
368
+ vec4 B = vec4(0.0);
369
+ vec4 C = vec4(0.0);
370
+ float brushDir = 0.0;
371
+ float brushBest = -1.0;
372
+ for (int i = 0; i < 4; i++) {
373
+ float wi = w[i];
374
+ baseColor += wi * mix(uMatColor[i].rgb, svg, uMatColor[i].a);
375
+ A += wi * uMatA[i];
376
+ B += wi * uMatB[i];
377
+ C += wi * uMatC[i];
378
+ float bw = wi * uMatC[i].x;
379
+ if (bw > brushBest) {
380
+ brushBest = bw;
381
+ brushDir = uMatC[i].y;
382
+ }
383
+ }
384
+ float metalness = clamp(A.x, 0.0, 1.0);
385
+ float roughness = clamp(A.y, 0.02, 1.0);
386
+ float clearcoat = clamp(A.z, 0.0, 1.0);
387
+ float ccRoughness = clamp(A.w, 0.02, 1.0);
388
+ float f0d = B.x;
389
+ float irid = B.y;
390
+ float filmNm = B.z;
391
+ float flakes = B.w;
392
+ float brushed = C.x;
393
+ if (uSide < 0.0) {
394
+ // The back plate gets a lathe-turned finish.
395
+ brushed = max(brushed, 0.55);
396
+ brushDir = 0.0;
397
+ }
398
+ float flakeScale = max(C.z, 1.0);
399
+ float emissive = C.w;
400
+
401
+ // Brushed metal: streaky normal perturbation along the brushing direction.
402
+ vec3 Nb = N;
403
+ if (brushed > 0.001) {
404
+ vec2 p = vLocal.xy;
405
+ float coord;
406
+ vec2 across;
407
+ if (brushDir < 0.5) { coord = length(p) * 700.0; across = normalize(p + 1e-5); }
408
+ else if (brushDir < 1.5) { coord = atan(p.y, p.x) * 160.0; across = normalize(vec2(-p.y, p.x) + 1e-5); }
409
+ else if (brushDir < 2.5) { coord = p.y * 700.0; across = vec2(0.0, 1.0); }
410
+ else { coord = p.x * 700.0; across = vec2(1.0, 0.0); }
411
+ // Streaks finer than a pixel would alias into moir\xE9; fade them and let roughness carry the look.
412
+ float footprint = fwidth(coord) * uPixelScale;
413
+ float n = (noise1(coord) - 0.5) * clamp(1.4 - footprint * 0.9, 0.0, 1.0)
414
+ + 0.5 * (noise1(coord * 3.7 + 11.0) - 0.5) * clamp(1.4 - footprint * 3.3, 0.0, 1.0);
415
+ Nb = normalize(N + uNormalMatrix * vec3(across * n * 0.22 * brushed, 0.0));
416
+ roughness = mix(roughness, min(1.0, roughness + 0.12), brushed);
417
+ }
418
+
419
+ float NdV = clamp(dot(Nb, V), 1e-4, 1.0);
420
+ // Resolve normal detail below a pixel into roughness instead of sparkling
421
+ // pinprick highlights. This uses derivatives, with no additional map reads.
422
+ vec3 dx = dFdx(N) * uPixelScale;
423
+ vec3 dy = dFdy(N) * uPixelScale;
424
+ float variance = min(0.15 * (dot(dx, dx) + dot(dy, dy)), 0.025);
425
+ roughness = sqrt(clamp(roughness * roughness + variance, 0.0004, 1.0));
426
+ ccRoughness = sqrt(clamp(ccRoughness * ccRoughness + variance, 0.0004, 1.0));
427
+
428
+ vec3 F0 = mix(vec3(f0d), baseColor, metalness);
429
+ if (irid > 0.001) {
430
+ vec3 film = thinFilm(NdV, filmNm);
431
+ F0 = mix(F0, mix(film, film * baseColor * 1.6, metalness * 0.5), irid);
432
+ }
433
+ vec2 ab = envBRDF(roughness, NdV);
434
+ vec3 FssEss = F0 * ab.x + ab.y;
435
+ float Ems = 1.0 - (ab.x + ab.y);
436
+ vec3 Favg = F0 + (1.0 - F0) / 21.0;
437
+ vec3 Fms = FssEss * Favg / (1.0 - Ems * Favg);
438
+ vec3 specWeight = FssEss + Fms * Ems;
439
+
440
+ float ao = 1.0 - uAo * cavity;
441
+ float specAo = mix(1.0, ao, 0.65);
442
+ vec3 R = reflect(-V, Nb);
443
+ vec3 irradiance = envIrr(Nb);
444
+ vec3 diffuse = baseColor * (1.0 - metalness) * (1.0 - specWeight) * irradiance * ao;
445
+ // Multiple scattering is broad, so it follows irradiance rather than the
446
+ // sharp reflected softbox. Reuse the diffuse lookup already in this pass.
447
+ vec3 color = diffuse + envSpec(R, roughness) * FssEss * specAo
448
+ + irradiance * Fms * Ems * ao;
449
+
450
+ // Metallic flakes: each cell reflects the environment at its own random angle.
451
+ if (flakes > 0.001) {
452
+ vec2 cuv = vUv * flakeScale;
453
+ vec2 cell = floor(cuv);
454
+ vec3 rnd = hash32(cell);
455
+ vec2 f = fract(cuv) - 0.5 - (rnd.xy - 0.5) * 0.4;
456
+ float footprint = max(fwidth(cuv.x), fwidth(cuv.y)) * uPixelScale;
457
+ float edge = max(0.025, footprint * 0.35);
458
+ float mask = (1.0 - smoothstep(0.23 - edge, 0.23 + edge, length(f))) * step(0.3, rnd.z);
459
+ // Unresolved flakes become the average coverage, avoiding crawling pixels.
460
+ float resolved = 1.0 - smoothstep(0.6, 1.8, footprint);
461
+ mask = mix(0.116, mask, resolved);
462
+ vec3 fn = normalize(Nb + uNormalMatrix * vec3((rnd.xy - 0.5) * 1.3 * resolved, 0.0));
463
+ vec3 fr = reflect(-V, fn);
464
+ vec3 flakeColor = envSpec(fr, mix(max(roughness, 0.25), 0.06, resolved)) * mix(vec3(0.85), baseColor, 0.55) * specAo;
465
+ color = mix(color, flakeColor, mask * clamp(flakes, 0.0, 1.0));
466
+ }
467
+
468
+ // Clear-coat layer (uses the unperturbed normal).
469
+ if (clearcoat > 0.001) {
470
+ float NdVc = clamp(dot(N, V), 1e-4, 1.0);
471
+ float Fc = 0.04 + 0.96 * pow(1.0 - NdVc, 5.0);
472
+ vec2 abc = envBRDF(ccRoughness, NdVc);
473
+ vec3 cc = envSpec(reflect(-V, N), ccRoughness) * (0.04 * abc.x + abc.y);
474
+ float transmission = 1.0 - clearcoat * Fc;
475
+ color = color * transmission * transmission + clearcoat * cc * specAo;
476
+ }
477
+
478
+ color += baseColor * emissive;
479
+
480
+ // Optional travelling glint across the face.
481
+ if (uShine > 0.0) {
482
+ float band = dot(vLocal.xy, normalize(vec2(1.0, 0.6))) - (uShine * 2.6 - 1.3);
483
+ color += exp(-band * band * 90.0) * 0.9 * specWeight;
484
+ }
485
+
486
+ color = toneMap(color * uExposure);
487
+ color = linearToSrgb(color);
488
+ color += (hash12(gl_FragCoord.xy) - 0.5) / 255.0;
489
+ outColor = vec4(color * alpha, alpha);
490
+ }
491
+ `,_t=`#version 300 es
492
+ precision highp float;
493
+ layout(location = 0) in vec2 aUv;
494
+ uniform mat4 uModel;
495
+ uniform mat4 uViewProj;
496
+ uniform float uZ;
497
+ uniform float uOffset;
498
+ uniform float uSpread;
499
+ out vec2 vUv;
500
+
501
+ void main() {
502
+ vec2 uv = (aUv - 0.5) * uSpread + 0.5;
503
+ vec3 p = vec3(uv.x - 0.5, 0.5 - uv.y, uZ);
504
+ vec4 w = uModel * vec4(p, 1.0);
505
+ w.y -= uOffset;
506
+ vUv = uv;
507
+ gl_Position = uViewProj * w;
508
+ }
509
+ `,Dt=`#version 300 es
510
+ precision highp float;
511
+ in vec2 vUv;
512
+ uniform sampler2D uSurface;
513
+ uniform float uOpacity;
514
+ uniform float uBlur;
515
+ out vec4 outColor;
516
+
517
+ void main() {
518
+ float sd = texture(uSurface, clamp(vUv, 0.0, 1.0)).a;
519
+ float a = smoothstep(-uBlur, uBlur * 0.5, sd);
520
+ a = a * a * uOpacity;
521
+ if (a <= 0.002) discard;
522
+ outColor = vec4(0.0, 0.0, 0.0, a);
523
+ }
524
+ `;var ae=512,Ce=6,ie=64,kr={circular:0,radial:1,horizontal:2,vertical:3};function Ot(n,e,r){let t=n.createShader(e);if(n.shaderSource(t,r),n.compileShader(t),!n.getShaderParameter(t,n.COMPILE_STATUS)&&!n.isContextLost()){let o=n.getShaderInfoLog(t);throw n.deleteShader(t),new Error(`badgecraft: shader compile failed
525
+ ${o}`)}return t}function xe(n,e,r){let t=n.createProgram(),o=Ot(n,n.VERTEX_SHADER,e),a=Ot(n,n.FRAGMENT_SHADER,r);if(n.attachShader(t,o),n.attachShader(t,a),n.linkProgram(t),n.deleteShader(o),n.deleteShader(a),!n.getProgramParameter(t,n.LINK_STATUS)&&!n.isContextLost())throw new Error(`badgecraft: program link failed
526
+ ${n.getProgramInfoLog(t)}`);let i={},s=n.getProgramParameter(t,n.ACTIVE_UNIFORMS);for(let l=0;l<s;l++){let m=n.getActiveUniform(t,l);if(!m)continue;let c=m.name.replace(/\[0\]$/,"");i[c]=n.getUniformLocation(t,m.name)}return{program:t,u:i}}var Ie,Ne=class n{constructor(){this.generation=0;this.floatTargets=!1;this.anisotropy=null;this.maxAnisotropy=1;this.renderLimit=2048;this.envCache=new Map;this.listeners=new Set;this.canvas=document.createElement("canvas"),this.canvas.width=256,this.canvas.height=256;let e=this.canvas.getContext("webgl2",{alpha:!0,premultipliedAlpha:!0,antialias:!0,depth:!0,stencil:!1,preserveDrawingBuffer:!1});if(!e)throw new Error("badgecraft: WebGL2 is not available");this.gl=e,this.canvas.addEventListener("webglcontextlost",r=>r.preventDefault()),this.canvas.addEventListener("webglcontextrestored",()=>{this.envCache.clear(),this.init(),this.generation++,this.listeners.forEach(r=>r())}),this.init()}static shared(){if(Ie===void 0)try{Ie=new n}catch(e){console.warn(e),Ie=null}return Ie}onRestore(e){return this.listeners.add(e),()=>this.listeners.delete(e)}init(){let e=this.gl;this.renderLimit=Math.min(2048,e.getParameter(e.MAX_RENDERBUFFER_SIZE)),this.floatTargets=!!e.getExtension("EXT_color_buffer_float"),this.anisotropy=e.getExtension("EXT_texture_filter_anisotropic"),this.maxAnisotropy=this.anisotropy?Math.min(2,e.getParameter(this.anisotropy.MAX_TEXTURE_MAX_ANISOTROPY_EXT)):1,e.getExtension("OES_texture_float_linear"),this.badgeProgram=xe(e,Nt,Ut),this.shadowProgram=xe(e,_t,Dt),this.envProgram=xe(e,Le,Lt),this.prefilterProgram=xe(e,Le,Ct),this.irrProgram=xe(e,Le,It),this.fbo=e.createFramebuffer(),this.emptyVao=e.createVertexArray();let r=new Float32Array([0,0,1,0,0,1,1,1]),t=new Uint16Array([0,2,1,1,2,3]);this.shadowQuad=e.createVertexArray(),e.bindVertexArray(this.shadowQuad);let o=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,o),e.bufferData(e.ARRAY_BUFFER,r,e.STATIC_DRAW),e.enableVertexAttribArray(0),e.vertexAttribPointer(0,2,e.FLOAT,!1,0,0);let a=e.createBuffer();e.bindBuffer(e.ELEMENT_ARRAY_BUFFER,a),e.bufferData(e.ELEMENT_ARRAY_BUFFER,t,e.STATIC_DRAW),e.bindVertexArray(null)}get contextLost(){return this.gl.isContextLost()}texture(e,r,t,o,a,i){let s=this.gl,l=s.createTexture();return s.bindTexture(s.TEXTURE_2D,l),s.pixelStorei(s.UNPACK_ALIGNMENT,1),s.texImage2D(s.TEXTURE_2D,0,e,o,o,0,r,t,a),s.texParameteri(s.TEXTURE_2D,s.TEXTURE_WRAP_S,s.CLAMP_TO_EDGE),s.texParameteri(s.TEXTURE_2D,s.TEXTURE_WRAP_T,s.CLAMP_TO_EDGE),s.texParameteri(s.TEXTURE_2D,s.TEXTURE_MAG_FILTER,s.LINEAR),i?(s.generateMipmap(s.TEXTURE_2D),s.texParameteri(s.TEXTURE_2D,s.TEXTURE_MIN_FILTER,s.LINEAR_MIPMAP_LINEAR),this.anisotropy&&s.texParameterf(s.TEXTURE_2D,this.anisotropy.TEXTURE_MAX_ANISOTROPY_EXT,this.maxAnisotropy)):s.texParameteri(s.TEXTURE_2D,s.TEXTURE_MIN_FILTER,s.LINEAR),l}createBadgeTextures(e){let r=this.gl,t=St(e.surface,e.size),o=r.createVertexArray(),a=r.createBuffer(),i=r.createBuffer();return r.bindVertexArray(o),r.bindBuffer(r.ARRAY_BUFFER,a),r.bufferData(r.ARRAY_BUFFER,t.vertices,r.STATIC_DRAW),r.enableVertexAttribArray(0),r.vertexAttribPointer(0,2,r.FLOAT,!1,12,0),r.enableVertexAttribArray(1),r.vertexAttribPointer(1,1,r.FLOAT,!1,12,8),r.bindBuffer(r.ELEMENT_ARRAY_BUFFER,i),r.bufferData(r.ELEMENT_ARRAY_BUFFER,t.indices,r.STATIC_DRAW),r.bindVertexArray(null),{mesh:o,vertexBuffer:a,indexBuffer:i,faceCount:t.faceCount,sideCount:t.indices.length-t.faceCount,surface:this.texture(r.RGBA16F,r.RGBA,r.FLOAT,e.size,e.surface,this.floatTargets),albedo:this.texture(r.SRGB8_ALPHA8,r.RGBA,r.UNSIGNED_BYTE,e.size,e.albedo,!0),weights:this.texture(r.RGBA8,r.RGBA,r.UNSIGNED_BYTE,e.size,e.weights,!0),size:e.size,heightScale:e.heightScale}}deleteBadgeTextures(e){let r=this.gl;r.deleteVertexArray(e.mesh),r.deleteBuffer(e.vertexBuffer),r.deleteBuffer(e.indexBuffer),r.deleteTexture(e.surface),r.deleteTexture(e.albedo),r.deleteTexture(e.weights)}async acquireEnvironment(e){let r=e.key,t=this.envCache.get(r);if(!t){let o={refs:0,promise:this.buildEnvironment(e)};o.promise.then(a=>o.textures=a,()=>this.envCache.get(r)===o&&this.envCache.delete(r)),this.envCache.set(r,o),t=o}t.refs++,t.disposeTimer&&(clearTimeout(t.disposeTimer),t.disposeTimer=void 0);try{return{key:r,textures:await t.promise}}catch(o){throw t.refs--,o}}releaseEnvironment(e){let r=this.envCache.get(e.key);!r||r.textures!==e.textures||(r.refs--,!(r.refs>0)&&(r.disposeTimer=setTimeout(()=>{r.refs>0||this.envCache.get(e.key)!==r||(this.envCache.delete(e.key),r.textures&&!this.gl.isContextLost()&&(this.gl.deleteTexture(r.textures.spec),this.gl.deleteTexture(r.textures.irr)))},5e3)))}envFormat(){let e=this.gl;return this.floatTargets?{internal:e.RGBA16F,type:e.HALF_FLOAT,scale:1}:{internal:e.RGBA8,type:e.UNSIGNED_BYTE,scale:8}}allocEnvTexture(e,r,t){let o=this.gl,{internal:a}=this.envFormat(),i=o.createTexture();return o.bindTexture(o.TEXTURE_2D,i),o.texStorage2D(o.TEXTURE_2D,t,a,e,r),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_WRAP_S,o.REPEAT),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_WRAP_T,o.CLAMP_TO_EDGE),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_MAG_FILTER,o.LINEAR),o.texParameteri(o.TEXTURE_2D,o.TEXTURE_MIN_FILTER,t>1?o.LINEAR_MIPMAP_LINEAR:o.LINEAR),i}async buildEnvironment(e){let r=this.gl,{scale:t}=this.envFormat(),o=this.generation,a=e.kind==="image"?await this.loadImageEnvironment(e.spec.url,(e.spec.intensity??1)/t):null;if(r.isContextLost()||o!==this.generation)throw new Error("badgecraft: environment invalidated by context loss");let i=ae*2,s=ae,l=Math.floor(Math.log2(i))+1,m=this.allocEnvTexture(i,s,l);try{e.kind==="procedural"?this.renderProcedural(m,i,s,e.spec,t):a&&this.uploadImageEnvironment(m,i,s,a)}catch(M){throw r.deleteTexture(m),M}r.bindTexture(r.TEXTURE_2D,m),r.generateMipmap(r.TEXTURE_2D);let c=this.allocEnvTexture(ae,ae/2,Ce),f=4*Math.PI/(i*s),u=this.prefilterProgram;r.useProgram(u.program),r.activeTexture(r.TEXTURE0),r.bindTexture(r.TEXTURE_2D,m),r.uniform1i(u.u.uSrc,0),r.uniform1f(u.u.uTexelSolidAngle,f);for(let M=0;M<Ce;M++){let g=ae>>M,A=Math.max(1,ae/2>>M);this.bindTarget(c,M,g,A),r.uniform2f(u.u.uSize,g,A),r.uniform1f(u.u.uRoughness,M/(Ce-1)),this.fullscreen()}let h=this.allocEnvTexture(ie,ie/2,1),b=this.irrProgram;return r.useProgram(b.program),r.bindTexture(r.TEXTURE_2D,m),r.uniform1i(b.u.uSrc,0),r.uniform1f(b.u.uTexelSolidAngle,f),this.bindTarget(h,0,ie,ie/2),r.uniform2f(b.u.uSize,ie,ie/2),this.fullscreen(),r.bindFramebuffer(r.FRAMEBUFFER,null),r.deleteTexture(m),{spec:c,irr:h,maxLod:Ce-1,scale:t}}bindTarget(e,r,t,o){let a=this.gl;a.bindFramebuffer(a.FRAMEBUFFER,this.fbo),a.framebufferTexture2D(a.FRAMEBUFFER,a.COLOR_ATTACHMENT0,a.TEXTURE_2D,e,r),a.viewport(0,0,t,o),a.disable(a.BLEND),a.disable(a.DEPTH_TEST),a.disable(a.CULL_FACE),a.disable(a.SCISSOR_TEST)}fullscreen(){let e=this.gl;e.bindVertexArray(this.emptyVao),e.drawArrays(e.TRIANGLES,0,3),e.bindVertexArray(null)}renderProcedural(e,r,t,o,a){let i=this.gl,s=this.envProgram,l=o.intensity??1,m=(o.lights??[]).slice(0,8),c=new Float32Array(24),f=new Float32Array(24),u=new Float32Array(32);m.forEach((g,A)=>{let v=g.azimuth*Math.PI/180,x=g.elevation*Math.PI/180;c.set([Math.sin(v)*Math.cos(x),Math.sin(x),Math.cos(v)*Math.cos(x)],A*3);let y=j(g.color??"#ffffff"),E=(g.intensity??1)*l;f.set([y[0]*E,y[1]*E,y[2]*E],A*3);let R=g.size??30,[L,I]=Array.isArray(R)?R:[R,R],p=T=>Math.tan(Math.min(T,170)*Math.PI/360);u.set([p(L),p(I),g.softness??.5,g.shape==="circle"?1:0],A*4)});let h=j(o.top??"#555555").map(g=>g*l),b=j(o.horizon??"#222222").map(g=>g*l),M=j(o.bottom??"#080808").map(g=>g*l);i.useProgram(s.program),this.bindTarget(e,0,r,t),i.uniform2f(s.u.uSize,r,t),i.uniform3fv(s.u.uTop,h),i.uniform3fv(s.u.uHorizon,b),i.uniform3fv(s.u.uBottom,M),i.uniform1i(s.u.uLightCount,m.length),i.uniform3fv(s.u.uLightDir,c),i.uniform3fv(s.u.uLightColor,f),i.uniform4fv(s.u.uLightShape,u),i.uniform1f(s.u.uScale,1/a),this.fullscreen()}async loadImageEnvironment(e,r){let t,o,a;if(/\.hdr(\?|#|$)/i.test(e)){let i=await fetch(e);if(!i.ok)throw new Error(`badgecraft: failed to load environment ${e}`);({width:t,height:o,data:a}=Tt(await i.arrayBuffer()))}else{let i=new Image;i.crossOrigin="anonymous",i.src=e,await i.decode();let s=Math.min(1,2048/Math.max(i.naturalWidth,i.naturalHeight));t=Math.max(1,Math.round(i.naturalWidth*s)),o=Math.max(1,Math.round(i.naturalHeight*s));let l=document.createElement("canvas");l.width=t,l.height=o;let m=l.getContext("2d");m.drawImage(i,0,0,t,o);let c=m.getImageData(0,0,t,o).data;a=new Float32Array(t*o*4);let f=new Float32Array(256);for(let u=0;u<256;u++){let h=u/255;f[u]=h<=.04045?h/12.92:Math.pow((h+.055)/1.055,2.4)}for(let u=0;u<t*o;u++)a[u*4]=f[c[u*4]],a[u*4+1]=f[c[u*4+1]],a[u*4+2]=f[c[u*4+2]],a[u*4+3]=1}for(let i=0;i<a.length;i++)(i&3)!==3&&(a[i]*=r);return{width:t,height:o,data:a}}uploadImageEnvironment(e,r,t,o){let a=this.gl,{width:i,height:s,data:l}=o,m=a.getParameter(a.MAX_TEXTURE_SIZE);if(i>m||s>m)throw new Error(`badgecraft: environment dimensions exceed the GPU texture limit (${m}px)`);let c=a.createTexture();a.bindTexture(a.TEXTURE_2D,c),a.pixelStorei(a.UNPACK_ALIGNMENT,1);let f=!!a.getExtension("OES_texture_float_linear");a.texImage2D(a.TEXTURE_2D,0,f?a.RGBA32F:a.RGBA16F,i,s,0,a.RGBA,a.FLOAT,l),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MIN_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_MAG_FILTER,a.LINEAR),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_S,a.REPEAT),a.texParameteri(a.TEXTURE_2D,a.TEXTURE_WRAP_T,a.CLAMP_TO_EDGE);let u=this.prefilterProgram;a.useProgram(u.program),a.activeTexture(a.TEXTURE0),a.uniform1i(u.u.uSrc,0),a.uniform1f(u.u.uRoughness,0),a.uniform1f(u.u.uTexelSolidAngle,4*Math.PI/(i*s)),this.bindTarget(e,0,r,t),a.bindTexture(a.TEXTURE_2D,c),a.uniform2f(u.u.uSize,r,t),this.fullscreen(),a.deleteTexture(c)}ensureSize(e,r){let t=this.canvas;t.width>=e&&t.height>=r||(t.width=Math.max(t.width,Math.ceil(e/128)*128),t.height=Math.max(t.height,Math.ceil(r/128)*128))}draw(e,r){let t=this.gl;if(t.isContextLost())return;let o=Math.max(1,Math.min(2,this.renderLimit/Math.max(e.width,e.height))),a=Math.round(e.width*o),i=Math.round(e.height*o);this.ensureSize(a,i),t.bindFramebuffer(t.FRAMEBUFFER,null),t.viewport(0,0,a,i),t.enable(t.SCISSOR_TEST),t.scissor(0,0,a,i),t.clearColor(0,0,0,0),t.clearDepth(1),t.depthMask(!0),t.clear(t.COLOR_BUFFER_BIT|t.DEPTH_BUFFER_BIT),t.enable(t.BLEND),t.blendFunc(t.ONE,t.ONE_MINUS_SRC_ALPHA),t.enable(t.DEPTH_TEST),t.depthFunc(t.LEQUAL);let s=22*Math.PI/180,l=a/i,m=.5/(1-2*Math.min(.4,Math.max(0,e.padding))),f=(l>=1?m:m/l)/Math.tan(s/2),u=Rt(s,l,Math.max(.05,f-2),f+2),h=Fe(u,kt(0,0,-f)),b=Ft(e.pitch,e.yaw,e.roll),M=Pt(b),g=e.locked?0:e.maps.heightScale,A=e.locked?0:e.thickness,v=Math.max(1,e.edge*e.maps.size);if(t.activeTexture(t.TEXTURE0),t.bindTexture(t.TEXTURE_2D,e.maps.surface),e.shadow>0&&!e.locked){let y=this.shadowProgram;t.useProgram(y.program),t.depthMask(!1),t.disable(t.CULL_FACE),t.uniformMatrix4fv(y.u.uModel,!1,b),t.uniformMatrix4fv(y.u.uViewProj,!1,h),t.uniform1i(y.u.uSurface,0),t.uniform1f(y.u.uZ,-A-.01),t.uniform1f(y.u.uOffset,.018),t.uniform1f(y.u.uSpread,1),t.uniform1f(y.u.uOpacity,e.shadow),t.uniform1f(y.u.uBlur,e.shadowBlur*e.maps.size),t.bindVertexArray(this.shadowQuad),t.drawElements(t.TRIANGLES,6,t.UNSIGNED_SHORT,0),t.depthMask(!0)}let x=this.badgeProgram;t.useProgram(x.program),t.activeTexture(t.TEXTURE1),t.bindTexture(t.TEXTURE_2D,e.maps.albedo),t.activeTexture(t.TEXTURE2),t.bindTexture(t.TEXTURE_2D,e.maps.weights),t.activeTexture(t.TEXTURE3),t.bindTexture(t.TEXTURE_2D,e.env.spec),t.activeTexture(t.TEXTURE4),t.bindTexture(t.TEXTURE_2D,e.env.irr),t.uniform1i(x.u.uSurface,0),t.uniform1i(x.u.uAlbedo,1),t.uniform1i(x.u.uWeights,2),t.uniform1i(x.u.uEnvSpec,3),t.uniform1i(x.u.uEnvIrr,4),t.uniform1f(x.u.uEnvMaxLod,e.env.maxLod),t.uniform1f(x.u.uEnvScale,e.env.scale),t.uniform1f(x.u.uEnvRotation,e.envRotation/(2*Math.PI)),t.uniformMatrix4fv(x.u.uModel,!1,b),t.uniformMatrix4fv(x.u.uViewProj,!1,h),t.uniformMatrix3fv(x.u.uNormalMatrix,!1,M),t.uniform3f(x.u.uCamPos,0,0,f),t.uniform1f(x.u.uMapSize,e.maps.size),t.uniform1f(x.u.uPixelScale,o),t.uniform1f(x.u.uDepth,g),t.uniform1f(x.u.uThickness,A),t.uniform1f(x.u.uEdgeTexels,v),t.uniform1f(x.u.uAo,e.ao),t.uniform1f(x.u.uExposure,e.exposure),t.uniform1i(x.u.uToneMap,e.toneMapping),t.uniform1f(x.u.uLocked,e.locked?1:0),t.uniform3fv(x.u.uLockedColor,e.lockedColor),t.uniform1f(x.u.uShine,e.shine),this.setMaterials(x.u,e.materials),t.enable(t.CULL_FACE),t.cullFace(t.BACK),t.bindVertexArray(e.maps.mesh),e.locked||(t.frontFace(t.CW),t.uniform1f(x.u.uSide,-1),t.drawElements(t.TRIANGLES,e.maps.faceCount,t.UNSIGNED_INT,0)),t.frontFace(t.CCW),t.uniform1f(x.u.uSide,1),t.drawElements(t.TRIANGLES,e.maps.faceCount,t.UNSIGNED_INT,0),!e.locked&&e.maps.sideCount>0&&(t.uniform1f(x.u.uSide,0),t.drawElements(t.TRIANGLES,e.maps.sideCount,t.UNSIGNED_INT,e.maps.faceCount*4)),t.bindVertexArray(null),t.disable(t.SCISSOR_TEST),r.clearRect(0,0,r.canvas.width,r.canvas.height),r.imageSmoothingEnabled=!0,r.imageSmoothingQuality="high",r.drawImage(this.canvas,0,this.canvas.height-i,a,i,0,0,r.canvas.width,r.canvas.height)}setMaterials(e,r){let t=this.gl,o=new Float32Array(16),a=new Float32Array(16),i=new Float32Array(16),s=new Float32Array(16);r.forEach((l,m)=>{let c=j(l.color);o.set([c[0],c[1],c[2],l.useSvgColor?1:0],m*4),a.set([l.metalness,l.roughness,l.clearcoat,l.clearcoatRoughness],m*4);let f=((l.ior-1)/(l.ior+1))**2,u=((l.ior-1.5)/(l.ior+1.5))**2,h=Math.min(1,Math.max(0,l.clearcoat));i.set([f+(u-f)*h,l.iridescence,l.iridescenceThickness,l.flakes],m*4),s.set([l.brushed,kr[l.brushDirection]??0,l.flakeScale,l.emissive],m*4)}),t.uniform4fv(e.uMatColor,o),t.uniform4fv(e.uMatA,a),t.uniform4fv(e.uMatB,i),t.uniform4fv(e.uMatC,s)}};var ye=new Set,Me=new Set,_e=0,Ue=0,tt=!1;function zt(n){_e=0,tt=!0;let e=Ue?Math.min(.05,(n-Ue)/1e3):1/60;Ue=n,Me.clear();for(let r of[...ye]){let t=!1;try{t=r.frame(e,n)}catch(o){console.error(o)}!t&&!Me.has(r)&&ye.delete(r)}Me.clear(),tt=!1,ye.size>0?_e=requestAnimationFrame(zt):Ue=0}function Wt(n){if(ye.add(n),tt){Me.add(n);return}!_e&&typeof requestAnimationFrame<"u"&&(_e=requestAnimationFrame(zt))}function Gt(n){ye.delete(n),Me.delete(n)}var $=new Map;async function Ht(n){if(typeof n!="string")return Promise.resolve(new XMLSerializer().serializeToString(n));let e=n.trim();if(!e)throw new Error("badgecraft: SVG source is empty");if(e.startsWith("<"))return Promise.resolve(e);if(e.startsWith("data:")){let a=e.indexOf(",");if(a<0)throw new Error("badgecraft: invalid SVG data URL");let i=e.slice(0,a),s=e.slice(a+1);return Promise.resolve(i.includes(";base64")?decodeURIComponent(escape(atob(s))):decodeURIComponent(s))}let r=new URL(e,document.baseURI).href,t=$.get(r);if(t)return $.delete(r),$.set(r,t),t;let o=fetch(r).then(a=>{if(!a.ok)throw new Error(`badgecraft: failed to load SVG from ${e} (${a.status})`);return a.text()});for(o.catch(()=>$.get(r)===o&&$.delete(r)),$.set(r,o);$.size>32;)$.delete($.keys().next().value);return o}var Fr=2048;function rt(n,e,r,t){let o=Math.ceil(e/.004166666666666667),a=e/o;for(let i=0;i<o;i++){let s=r*(n.target-n.x)-t*n.v;n.v+=s*a,n.x+=n.v*a}return Math.abs(n.target-n.x)<.02&&Math.abs(n.v)<.2?(n.x=n.target,n.v=0,!1):!0}var De=()=>typeof matchMedia<"u"&&matchMedia("(prefers-reduced-motion: reduce)").matches,Ae=class{constructor(e,r){this.maps=null;this.mapSize=0;this.pendingSize=0;this.env=null;this.fallbackImage=null;this.bakeToken=0;this.envToken=0;this.visible=!0;this.destroyed=!1;this.dirty=!0;this.isReady=!1;this.cleanups=[];this.pitch={x:0,v:0,target:0};this.yaw={x:0,v:0,target:0};this.hover=null;this.drag=null;this.coasting=!1;this.spinning=!1;this.time=0;this.shine=0;this.shineStart=-1;this.host=e,this.options={...r},this.resolved=Xe(this.options),this.ready=new Promise((o,a)=>{this.resolveReady=o,this.rejectReady=a}),this.ready.catch(()=>{}),this.canvas=document.createElement("canvas"),this.canvas.setAttribute("aria-hidden","true"),this.canvas.style.cssText="display:block;width:100%;height:100%;",this.canvas.width=0,this.canvas.height=0,e.appendChild(this.canvas),e.hasAttribute("role")||e.setAttribute("role","img"),this.ensureHostSize();let t=this.canvas.getContext("2d");if(!t)throw this.canvas.remove(),new Error("badgecraft: 2D canvas unavailable");this.ctx=t,this.renderer=Ne.shared(),this.renderer&&this.cleanups.push(this.renderer.onRestore(()=>this.handleContextRestore())),this.observe(),this.bindPointer(),this.applyInteractionStyle(),this.loadEnvironment()}ensureHostSize(){let e=this.host;if(e.getClientRects().length>0){let r=getComputedStyle(e);e.clientHeight===0&&!r.aspectRatio.includes("/")&&(e.style.aspectRatio="1 / 1"),e.clientWidth===0&&r.display==="inline"&&(e.style.display="inline-block"),e.clientWidth===0&&!e.style.width&&(e.style.width="160px")}}update(e){this.setOptions({...this.options,...e})}setOptions(e){if(this.destroyed)return;let r=this.resolved,t=this.options.svg;this.options={...e},this.resolved=Xe(this.options);let o=this.resolved,a=o.quality==="auto"&&o.render.padding!==r.render.padding&&this.targetMapSize()>this.mapSize*1.25;(o.bakeKey!==r.bakeKey||this.options.svg!==t||o.quality!==r.quality||a)&&this.rebuild(),o.render.environment.key!==r.render.environment.key&&this.loadEnvironment(),(o.render.interaction!==r.render.interaction||o.render.locked!==r.render.locked)&&(this.stopMotion(),this.applyInteractionStyle()),o.renderKey!==r.renderKey&&this.invalidate()}spin(e=1){this.destroyed||this.resolved.render.locked||!Number.isFinite(e*360)||De()||(this.spinning=!0,this.coasting=!1,this.yaw.target=Math.round(this.yaw.x/360)*360+360*e,this.pitch.target=0,this.invalidate())}glint(){this.destroyed||this.resolved.render.locked||De()||(this.shineStart=this.time,this.invalidate())}toDataURL(e="image/png",r){return this.renderNow(),this.canvas.toDataURL(e,r)}toBlob(e="image/png",r){return this.renderNow(),new Promise(t=>this.canvas.toBlob(t,e,r))}destroy(){this.destroyed||(this.destroyed=!0,this.bakeToken++,this.envToken++,this.isReady||this.rejectReady(new DOMException("badgecraft: destroyed before ready","AbortError")),Gt(this),this.cleanups.forEach(e=>e()),this.maps&&this.renderer&&Re(this.renderer,this.maps),this.env&&this.renderer&&this.renderer.releaseEnvironment(this.env),this.maps=null,this.env=null,this.fallbackImage=null,this.canvas.remove())}observe(){let e=new ResizeObserver(r=>{let t=r[r.length-1],o=t.devicePixelContentBoxSize?.[0],a=window.devicePixelRatio||1,i=o?o.inlineSize:Math.round(t.contentRect.width*a),s=o?o.blockSize:Math.round(t.contentRect.height*a);this.resize(i,s)});try{e.observe(this.canvas,{box:"device-pixel-content-box"})}catch{e.observe(this.canvas)}if(this.cleanups.push(()=>e.disconnect()),typeof IntersectionObserver<"u"){let r=new IntersectionObserver(t=>{this.visible=t[t.length-1].isIntersecting,this.visible&&this.invalidate()},{rootMargin:"200px"});r.observe(this.canvas),this.cleanups.push(()=>r.disconnect())}}resize(e,r){if(e<=0||r<=0){this.host.getClientRects().length>0&&requestAnimationFrame(()=>{this.destroyed||this.ensureHostSize()});return}let t=Math.min(1,Fr/Math.max(e,r));e=Math.max(1,Math.round(e*t)),r=Math.max(1,Math.round(r*t)),(this.canvas.width!==e||this.canvas.height!==r)&&(this.canvas.width=e,this.canvas.height=r,this.dirty=!0);let o=this.targetMapSize();(!this.maps||o>this.mapSize*1.25)&&o!==this.pendingSize&&this.renderer?this.rebuild():!this.renderer&&!this.fallbackImage&&this.rebuild(),this.renderer?this.renderNow():this.paintFallback()}targetMapSize(){let e=this.resolved.quality;if(e!=="auto")return e;let r=Math.max(this.canvas.width,this.canvas.height)*(1-2*this.resolved.render.padding);return O(Math.ceil(r*1.2/64)*64,256,1024)}async rebuild(){let e=++this.bakeToken;if(this.canvas.width<=0&&this.resolved.quality==="auto")return;let r=this.targetMapSize();this.pendingSize=r;try{let t=await Ht(this.options.svg);if(e!==this.bakeToken||this.destroyed)return;if(!this.renderer){let l=await this.loadFallback(t);if(e!==this.bakeToken||this.destroyed)return;this.fallbackImage=l,this.paintFallback(),this.markReady();return}let{bake:o,bakeKey:a}=this.resolved,i=At(t,a,r);if(this.maps?.key===i)return;let s=await wt(this.renderer,i,()=>Et(t,o,r));if(e!==this.bakeToken||this.destroyed){Re(this.renderer,s);return}this.maps&&Re(this.renderer,this.maps),this.maps=s,this.mapSize=r,this.invalidate()}catch(t){e===this.bakeToken&&this.fail(t)}finally{e===this.bakeToken&&(this.pendingSize=0)}}async loadEnvironment(){if(!this.renderer)return;let e=++this.envToken,r=this.resolved.render.environment;try{let t=await this.renderer.acquireEnvironment(r);if(e!==this.envToken||this.destroyed){this.renderer.releaseEnvironment(t);return}this.env&&this.renderer.releaseEnvironment(this.env),this.env=t,this.invalidate()}catch(t){e===this.envToken&&!this.renderer.contextLost&&this.fail(t)}}handleContextRestore(){this.destroyed||(this.maps=null,this.env=null,this.mapSize=0,this.loadEnvironment(),this.rebuild())}fail(e){if(this.destroyed)return;let r=e instanceof Error?e:new Error(String(e));this.isReady||this.rejectReady(r),this.options.onError?this.options.onError(r):console.error(r)}markReady(){this.isReady||(this.isReady=!0,this.resolveReady(),this.options.onReady?.())}async loadFallback(e){let r=et(e);r.hasAttribute("color")||r.setAttribute("color",this.resolved.bake.color),e=new XMLSerializer().serializeToString(r);let t=URL.createObjectURL(new Blob([e],{type:"image/svg+xml"}));try{let o=new Image;return o.src=t,await o.decode(),o}finally{URL.revokeObjectURL(t)}}paintFallback(){let e=this.fallbackImage;if(!e)return;let{width:r,height:t}=this.canvas;this.ctx.clearRect(0,0,r,t);let a=Math.min(r,t)*(1-2*this.resolved.render.padding)/Math.max(e.naturalWidth,e.naturalHeight),i=e.naturalWidth*a,s=e.naturalHeight*a;this.ctx.drawImage(e,(r-i)/2,(t-s)/2,i,s)}invalidate(){this.dirty=!0,this.destroyed||Wt(this)}renderNow(){let e=this.renderer;if(!e||!this.maps||!this.env||this.destroyed||e.contextLost||this.canvas.width<=0)return;let r=this.resolved.render,t=Math.PI/180;e.draw({width:this.canvas.width,height:this.canvas.height,maps:this.maps.textures,env:this.env.textures,materials:r.materials,pitch:(this.pitch.x+(r.locked?0:r.pose.pitch))*t,yaw:(this.yaw.x+(r.locked?0:r.pose.yaw))*t,roll:(r.locked?0:r.pose.roll)*t,thickness:r.thickness,edge:r.edge,ao:r.ao,exposure:r.exposure,toneMapping:r.toneMapping,envRotation:r.envRotation,locked:r.locked,lockedColor:j(r.lockedColor),shadow:r.shadow,shadowBlur:.022,padding:r.padding,shine:this.shine},this.ctx),this.dirty=!1,this.markReady()}frame(e){if(this.destroyed)return!1;this.time+=e;let r=this.resolved.render,t=De(),o=!1,a=this.pitch.x+this.yaw.x*1e3+this.shine*1e7;if(!this.drag&&!this.spinning&&!this.coasting){let i=0,s=0;if(this.hover&&r.interaction==="tilt"&&!r.locked){let l=t?r.tiltMax*.4:r.tiltMax;i=this.hover.y*l,s=this.hover.x*l}else r.idle==="float"&&!t&&!r.locked&&(i=Math.sin(this.time*.9)*4,s=Math.sin(this.time*.6+1.3)*7,o=!0);this.pitch.target=i,this.yaw.target=Math.round(this.yaw.x/360)*360+s}if(this.drag)o=!0;else if(this.coasting)this.yaw.x+=this.yaw.v*e,this.yaw.v*=Math.exp(-e*1.6),rt(this.pitch,e,120,18),Math.abs(this.yaw.v)<120&&(this.coasting=!1,this.spinning=!0,this.yaw.target=Math.round(this.yaw.x/360)*360),o=!0;else{let i=this.spinning?26:140,s=this.spinning?2*Math.sqrt(i)*.82:2*Math.sqrt(i)*.72,l=rt(this.pitch,e,i,s),m=rt(this.yaw,e,i,s);!l&&!m&&this.spinning&&(this.spinning=!1,this.yaw.x=this.yaw.target=(this.yaw.x%360+360)%360),o=o||l||m}if(r.idle==="shine"&&!t&&!r.locked&&this.shineStart<0&&(this.time%5<e&&(this.shineStart=this.time),o=!0),this.shineStart>=0){let i=(this.time-this.shineStart)/1.3;this.shine=i>=1?0:Math.max(1e-4,i),i>=1&&(this.shineStart=-1),o=!0}return this.pitch.x+this.yaw.x*1e3+this.shine*1e7!==a&&(this.dirty=!0),this.dirty&&(this.renderer?this.renderNow():(this.paintFallback(),this.dirty=!1)),o&&this.visible}stopMotion(){let e=this.drag?.id;this.drag=null,e!==void 0&&this.canvas.hasPointerCapture(e)&&this.canvas.releasePointerCapture(e),this.hover=null,this.coasting=!1,this.spinning=!1,this.pitch.v=this.yaw.v=0,this.pitch.target=0,this.yaw.target=Math.round(this.yaw.x/360)*360}applyInteractionStyle(){let e=this.resolved.render.locked?"none":this.resolved.render.interaction;this.canvas.style.touchAction=e==="drag"?"none":"pan-y",this.canvas.style.cursor=e==="drag"?"grab":""}bindPointer(){let e=this.canvas,r=s=>{let l=e.getBoundingClientRect();return{x:O((s.clientX-l.left)/l.width*2-1,-1,1),y:O((s.clientY-l.top)/l.height*2-1,-1,1)}},t=s=>{if(this.resolved.render.interaction==="tilt"&&s.pointerType!=="touch"&&(this.hover=r(s),this.invalidate()),this.drag&&s.pointerId===this.drag.id){let m=s.clientX-this.drag.x,c=s.clientY-this.drag.y,f=performance.now(),u=this.yaw.x;this.yaw.x=this.drag.yaw+m*.7,this.pitch.x=O(this.drag.pitch+c*.35,-30,30);let h=Math.max(1,f-this.drag.t)/1e3;this.drag.vx=this.drag.vx*.6+(this.yaw.x-u)/h*.4,this.drag.t=f,this.yaw.v=0,this.pitch.v=0,this.invalidate()}},o=()=>{this.hover=null,this.invalidate()},a=s=>{this.drag||s.button!==0||this.resolved.render.interaction!=="drag"||this.resolved.render.locked||(e.setPointerCapture(s.pointerId),this.spinning=!1,this.coasting=!1,this.drag={id:s.pointerId,x:s.clientX,y:s.clientY,yaw:this.yaw.x,pitch:this.pitch.x,t:performance.now(),vx:0},e.style.cursor="grabbing",this.invalidate())},i=s=>{if(!this.drag||s.pointerId!==this.drag.id)return;let l=performance.now()-this.drag.t>80;this.yaw.v=l||s.type!=="pointerup"||De()?0:O(this.drag.vx,-2400,2400),this.drag=null,e.style.cursor="grab",this.pitch.target=0,Math.abs(this.yaw.v)>120?this.coasting=!0:(this.spinning=!0,this.yaw.target=Math.round(this.yaw.x/360)*360),this.invalidate()};e.addEventListener("pointermove",t),e.addEventListener("pointerleave",o),e.addEventListener("pointerdown",a),e.addEventListener("pointerup",i),e.addEventListener("pointercancel",i),e.addEventListener("lostpointercapture",i),this.cleanups.push(()=>{e.removeEventListener("pointermove",t),e.removeEventListener("pointerleave",o),e.removeEventListener("pointerdown",a),e.removeEventListener("pointerup",i),e.removeEventListener("pointercancel",i),e.removeEventListener("lostpointercapture",i)})}};function Xt(n,e){return new Ae(n,e)}function Pr(){if(typeof document>"u")return!1;try{let n=document.createElement("canvas").getContext("webgl2");return n?.getExtension("WEBGL_lose_context")?.loseContext(),!!n}catch{return!1}}return Jt(Lr);})();