three-text 0.2.2 → 0.2.4
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.
- package/LICENSE_THIRD_PARTY +8 -7
- package/README.md +26 -6
- package/dist/index.cjs +157 -2102
- package/dist/index.js +157 -2102
- package/dist/index.min.cjs +2 -2
- package/dist/index.min.js +2 -2
- package/dist/index.umd.js +157 -2102
- package/dist/index.umd.min.js +2 -2
- package/dist/three/index.cjs +2 -2
- package/dist/three/index.js +3 -3
- package/dist/three/react.cjs +0 -7
- package/dist/three/react.js +0 -7
- package/package.json +2 -2
package/dist/index.umd.min.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* three-text v0.2.
|
|
2
|
+
* three-text v0.2.4
|
|
3
3
|
* Copyright (C) 2025 Countertype LLC
|
|
4
4
|
*
|
|
5
5
|
* This program is free software: you can redistribute it and/or modify
|
|
@@ -11,4 +11,4 @@
|
|
|
11
11
|
*
|
|
12
12
|
* This software includes third-party code - see LICENSE_THIRD_PARTY for details.
|
|
13
13
|
*/
|
|
14
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ThreeText={})}(this,function(e){const t=!("undefined"==typeof window||!window.THREE_TEXT_LOG)||"undefined"!=typeof globalThis&&"true"===globalThis.process?.env?.THREE_TEXT_LOG;const n=new class{warn(e,...t){console.warn(e,...t)}error(e,...t){console.error(e,...t)}log(e,...n){t&&console.log(e,...n)}};const i=new class{constructor(){this.metrics=[],this.activeTimers=new Map}start(e,n){if(!t)return;const i=performance.now();this.activeTimers.set(e,i),this.metrics.push({name:e,startTime:i,metadata:n})}end(e){if(!t)return null;const i=performance.now(),s=this.activeTimers.get(e);if(void 0===s)return n.warn(`Performance timer "${e}" was not started`),null;const r=i-s;this.activeTimers.delete(e);for(let t=this.metrics.length-1;t>=0;t--){const n=this.metrics[t];if(n.name===e&&!n.endTime){n.endTime=i,n.duration=r;break}}return console.log(`${e}: ${r.toFixed(2)}ms`),r}getSummary(){if(!t)return{};const e={};for(const t of this.metrics){if(!t.duration)continue;const n=e[t.name];n?(n.count++,n.totalDuration+=t.duration,n.avgDuration=n.totalDuration/n.count,n.lastDuration=t.duration):e[t.name]={count:1,avgDuration:t.duration,totalDuration:t.duration,lastDuration:t.duration}}return e}printSummary(){if(!t)return;const e=this.getSummary();console.table(e),console.log("Operations:",Object.keys(e).sort().join(", "))}printBaseline(){if(!t)return;const e=this.getSummary();Object.entries(e).forEach(([e,t])=>{console.log(`BASELINE ${e}: ${t.avgDuration.toFixed(2)}ms avg (${t.count} calls)`)})}clear(){t&&(this.metrics.length=0,this.activeTimers.clear())}time(e,n,i){if(!t)return n();this.start(e,i);try{return n()}finally{this.end(e)}}async timeAsync(e,n,i){if(!t)return n();this.start(e,i);try{return await n()}finally{this.end(e)}}},s=200,r=100,o=0,h=1/3;var l,c;!function(e){e[e.BOX=0]="BOX",e[e.GLUE=1]="GLUE",e[e.PENALTY=2]="PENALTY",e[e.DISCRETIONARY=3]="DISCRETIONARY"}(l||(l={})),function(e){e[e.TIGHT=0]="TIGHT",e[e.NORMAL=1]="NORMAL",e[e.LOOSE=2]="LOOSE",e[e.VERY_LOOSE=3]="VERY_LOOSE"}(c||(c={}));class ActiveNodeList{constructor(){this.nodesByKey=new Map,this.activeList=[],this.allNodes=new Set}getKey(e,t){return e<<2|t}insert(e){const t=this.getKey(e.position,e.fitness),n=this.nodesByKey.get(t);n&&e.totalDemerits<n.totalDemerits?(n.totalDemerits=e.totalDemerits,n.previous=e.previous,n.totalWidth=e.totalWidth):n||(this.nodesByKey.set(t,e),this.allNodes.add(e),e.activeListIndex=this.activeList.length,this.activeList.push(e))}findExisting(e,t){return this.nodesByKey.get(this.getKey(e,t))}getAllActive(){return this.activeList}deactivateNode(e){if(e.active&&void 0!==e.activeListIndex){e.active=!1;const t=e.activeListIndex,n=this.activeList.length-1;if(t!==n){const e=this.activeList[n];this.activeList[t]=e,e.activeListIndex=t}this.activeList.pop(),e.activeListIndex=void 0}}size(){return this.allNodes.size}}const d=50,u=50,f=1e4,p=10,g=1e4,m=-1/0,y=2,x=4,_=1e4;class LineBreak{static badness(e,t){if(0===e)return 0;if(t<=0)return _;let n;return n=e<=7230584?Math.floor(297*e/t):t>=1663497?Math.floor(e/Math.floor(t/297)):e,n>1290?_:Math.floor((n*n*n+131072)/262144)}static findHyphenationPoints(e,t="en-us",n,i=y,s=x){let r;if(!n||!n[t])return[];if(r=n[t],!r)return[];const o=`.${e.toLowerCase()}.`,h=new Array(o.length).fill(0);for(let e=0;e<o.length;e++){let t=r;for(let n=e;n<o.length;n++){const i=o[n];if(!t.children||!t.children[i])break;if(t=t.children[i],t.patterns)for(let n=0;n<t.patterns.length;n++){const i=e+n;i<h.length&&(h[i]=Math.max(h[i],t.patterns[n]))}}}const l=[];for(let e=2;e<o.length-2;e++)h[e]%2==1&&l.push(e-1);return l.filter(t=>t>=i&&e.length-t>=s)}static itemizeText(e,t,n=!1,i="en-us",s,r=y,o=x,h){const c=[];return c.push(...this.itemizeParagraph(e,t,n,i,s,r,o,h)),c.push({type:l.GLUE,width:0,stretch:1/0,shrink:0,text:"",originIndex:e.length}),c.push({type:l.PENALTY,width:0,penalty:-1/0,text:"",originIndex:e.length}),c}static itemizeParagraph(e,t,n,i,s,r,o,c){const f=[],p=e.match(/\S+|\s+/g)||[];let g=0;for(let e=0;e<p.length;e++){const m=p[e],y=g;if(/\s+/.test(m)){const e=t(m);f.push({type:l.GLUE,width:e,stretch:.5*e,shrink:e*h,text:m,originIndex:y}),g+=m.length}else{const e=m.split(/(-)/);let h=y;for(let p=0;p<e.length;p++){const g=e[p];if(g)if("-"===g)f.push({type:l.DISCRETIONARY,width:t("-"),preBreak:"-",postBreak:"",noBreak:"-",preBreakWidth:t("-"),penalty:c?.exHyphenPenalty??u,flagged:!0,text:"-",originIndex:h}),h+=1;else{if(g.includes("")){const e=g.split("");let n=0;for(let i=0;i<e.length;i++){const s=e[i];s.length>0&&(f.push({type:l.BOX,width:t(s),text:s,originIndex:h+n}),n+=s.length),i<e.length-1&&(f.push({type:l.DISCRETIONARY,width:0,preBreak:"-",postBreak:"",noBreak:"",preBreakWidth:t("-"),penalty:c?.hyphenPenalty??d,flagged:!0,text:"",originIndex:h+n}),n+=1)}}else if(n&&g.length>=r+o){const e=LineBreak.findHyphenationPoints(g,i,s,r,o);if(e.length>0){let n=0;for(const i of e){const e=g.substring(n,i);f.push({type:l.BOX,width:t(e),text:e,originIndex:h+n}),f.push({type:l.DISCRETIONARY,width:0,preBreak:"-",postBreak:"",noBreak:"",preBreakWidth:t("-"),penalty:c?.hyphenPenalty??d,flagged:!0,text:"",originIndex:h+i}),n=i}const i=g.substring(n);f.push({type:l.BOX,width:t(i),text:i,originIndex:h+n})}else f.push({type:l.BOX,width:t(g),text:g,originIndex:h})}else f.push({type:l.BOX,width:t(g),text:g,originIndex:h});h+=g.length}}g+=m.length}}return f}static hasSingleWordLines(e,t,n){let i=0;for(let s=0;s<t.length-1;s++){const r=t[s];let o=0,h=0;for(let t=i;t<r;t++)e[t].type===l.GLUE&&o++,e[t].type!==l.PENALTY&&(h+=e[t].width);if(0===o&&h>0){if(h/n<.5)return!0}i=r+1}return!1}static breakText(e){i.start("LineBreak.breakText",{textLength:e.text.length,width:e.width,align:e.align||"left",hyphenate:e.hyphenate||!1});const{text:t,width:h,align:c="left",direction:m="ltr",hyphenate:_=!1,language:v="en-us",respectExistingBreaks:w=!0,measureText:b,hyphenationPatterns:S,unitsPerEm:E,tolerance:L=s,pretolerance:O=r,emergencyStretch:T=o,autoEmergencyStretch:P,lefthyphenmin:F=y,righthyphenmin:C=x,linepenalty:B=p,adjdemerits:I=g,hyphenpenalty:A=d,exhyphenpenalty:U=u,doublehyphendemerits:R=f,looseness:D=0,disableSingleWordDetection:z=!1}=e;if(w&&t.includes("\n")){const n=t.split("\n"),s=[];let r=0;for(const t of n){if(0===t.length)s.push({text:"",originalStart:r,originalEnd:r,xOffset:0,isLastLine:!0,naturalWidth:0,endedWithHyphen:!1});else{const n=LineBreak.breakText({...e,text:t,respectExistingBreaks:!1});n.forEach(e=>{e.originalStart+=r,e.originalEnd+=r}),s.push(...n)}r+=t.length+1}return i.end("LineBreak.breakText"),s}let G=_;!G||S&&S[v]||(n.warn(`Hyphenation patterns for ${v} not available`),G=!1);let k=T;void 0!==P&&h?k=h*P:!G&&T===o&&h&&(k=.1*h);const M={linePenalty:B,adjDemerits:I,doubleHyphenDemerits:R,hyphenPenalty:A,exHyphenPenalty:U,currentAlign:c,unitsPerEm:E};if(!h||h===1/0){const e=b(t);return i.end("LineBreak.breakText"),[{text:t,originalStart:0,originalEnd:t.length-1,xOffset:0,isLastLine:!0,naturalWidth:e,endedWithHyphen:!1}]}const N=LineBreak.itemizeText(t,b,G,v,S,F,C,M);if(0===N.length)return[];let H=0,V=k,W=null;const q=!z;for(;H<5;){let e=G?N.filter(e=>e.type!==l.DISCRETIONARY||e.penalty!==(M?.hyphenPenalty??d)):N,n=LineBreak.findBreakpoints(e,h,O,D,!1,0,M);if(0===n.length&&G&&(e=N,n=LineBreak.findBreakpoints(e,h,L,D,!1,0,M)),0===n.length&&(e=N,n=LineBreak.findBreakpoints(e,h,10001,D,!0,V,M)),0===n.length&&(n=LineBreak.findBreakpoints(e,h,1/0,D,!0,V,M)),n.length>0){const i=LineBreak.computeCumulativeWidths(e);if(W=LineBreak.createLines(t,e,n,h,c,m,i,M),q&&n.length>1&&LineBreak.hasSingleWordLines(e,n,h)){V+=.1*h,H++;continue}break}break}if(i.end("LineBreak.breakText"),W&&W.length>0)return W;const j=b(t);return[{text:t,originalStart:0,originalEnd:t.length-1,xOffset:0,adjustmentRatio:0,isLastLine:!0,naturalWidth:j,endedWithHyphen:!1}]}static findBreakpoints(e,t,n=1/0,i=0,s=!1,r=0,o){const h=LineBreak.computeCumulativeWidths(e),d=new ActiveNodeList;d.insert({position:0,line:0,fitness:c.NORMAL,totalDemerits:0,totalWidth:0,previous:null,active:!0});for(let i=0;i<e.length;i++){const s=e[i];s.type===l.PENALTY&&s.penalty<1/0&&LineBreak.considerBreak(e,d,i,t,n,r,h,o),s.type===l.DISCRETIONARY&&s.penalty<1/0&&LineBreak.considerBreak(e,d,i,t,n,r,h,o),s.type===l.GLUE&&i>0&&e[i-1].type===l.BOX&&LineBreak.considerBreak(e,d,i,t,n,r,h,o),LineBreak.deactivateNodes(d,i,t,h.minWidths)}const u=[];let f=null;if(0===i){const e=d.getAllActive();let t=1/0;for(const n of e)n.active&&n.totalDemerits<t&&(t=n.totalDemerits,f=n)}else{const e=d.getAllActive();let t=0,n=1/0;for(const i of e)i.active&&i.totalDemerits<n&&(n=i.totalDemerits,t=i.line);let r=0,o=1/0;for(const n of e){if(!n.active)continue;const e=n.line-t;e<r&&i<=e||e>r&&i>=e?(f=n,r=e,o=n.totalDemerits):e===r&&n.totalDemerits<o&&(f=n,o=n.totalDemerits)}if(!s&&r!==i&&f)return[]}if(!f)return[];for(;f&&f.position>0;)u.unshift(f.position),f=f.previous;return u}static considerBreak(e,t,n,i,s=1/0,r=0,o,h){const c=(e[n].type===l.PENALTY?e[n].penalty:0)<=-1/0,d=t.getAllActive();for(let u=0;u<d.length;u++){const f=d[u];if(!f.active)continue;const p=LineBreak.computeAdjustmentRatio(e,f.position,n,f.line,i,o,h),{ratio:g,adjustment:y,stretch:x,shrink:_,totalWidth:v}=p;let w;if(y>0){const e=x+r;w=e<=0?10001:LineBreak.badness(y,e)}else w=y<0?_<=0||-y>_?10001:LineBreak.badness(-y,_):0;if(!c&&g<-1)continue;const b=LineBreak.computeFitnessClass(w,y>0);if(!c&&w>s)continue;let S=0,E=0;let L=(h?.linePenalty??0)+w,O=Math.abs(L)>=1e4?1e8:L*L;const T=e[n].type===l.PENALTY||e[n].type===l.DISCRETIONARY?e[n].penalty:0;0!==T&&(T>0?O+=T*T:T>m&&(O-=T*T));const P=e[n].type===l.PENALTY&&e[n].flagged||e[n].type===l.DISCRETIONARY&&e[n].flagged,F=f.position>0&&(e[f.position].type===l.PENALTY&&e[f.position].flagged||e[f.position].type===l.DISCRETIONARY&&e[f.position].flagged);P&&F&&(S=h?.doubleHyphenDemerits??0,O+=S),Math.abs(b-f.fitness)>1&&(E=h?.adjDemerits??0,O+=E),c&&(O=0);const C=f.totalDemerits+O;let B=t.findExisting(n,b);B?C<B.totalDemerits&&(B.totalDemerits=C,B.previous=f,B.totalWidth=v):t.insert({position:n,line:f.line+1,fitness:b,totalDemerits:C,totalWidth:v,previous:f,active:!0})}}static computeAdjustmentRatio(e,t,n,i,s,r,o){let h=0,c=0,d=0;if(r){h=r.widths[n]-r.widths[t],c=r.stretches[n]-r.stretches[t],d=r.shrinks[n]-r.shrinks[t];for(let i=t;i<n;i++){const t=e[i];t.type===l.PENALTY&&(h-=t.width)}}else for(let i=t;i<n;i++){const t=e[i];t.type!==l.PENALTY&&(h+=t.width,t.type===l.GLUE&&(c+=t.stretch,d+=t.shrink))}n<e.length&&(e[n].type===l.PENALTY||e[n].type===l.DISCRETIONARY)&&(h+=e[n].type===l.PENALTY?e[n].width:e[n].preBreakWidth);const u=s-h;let f;return f=u>0&&c>0?u/c:u<0&&d>0?u/d:0===u?0:u>0?3:-1,{ratio:f,adjustment:u,stretch:c,shrink:d,totalWidth:h}}static computeFitnessClass(e,t){return t?e<=12?c.NORMAL:e<=99?c.LOOSE:c.VERY_LOOSE:e<=12?c.NORMAL:c.TIGHT}static computeCumulativeWidths(e){const t=e.length+1,n=new Array(t),i=new Array(t),s=new Array(t),r=new Array(t);n[0]=0,i[0]=0,s[0]=0,r[0]=0;for(let t=0;t<e.length;t++){const o=e[t];if(n[t+1]=n[t]+o.width,o.type===l.PENALTY)r[t+1]=r[t];else if(o.type===l.GLUE){const e=o;i[t+1]=i[t]+e.stretch,s[t+1]=s[t]+e.shrink,r[t+1]=r[t]+Math.max(0,e.width-e.shrink)}else i[t+1]=i[t],s[t+1]=s[t],r[t+1]=r[t]+o.width}return{widths:n,stretches:i,shrinks:s,minWidths:r}}static deactivateNodes(e,t,n,i){const s=e.getAllActive();for(let r=s.length-1;r>=0;r--){const o=s[r];if(!o.active)continue;i[t]-i[o.position]>n&&e.deactivateNode(o)}}static createLines(e,t,n,i,s,r,o,h){if(0===n.length)return[{text:e,originalStart:0,originalEnd:e.length-1,xOffset:0}];const c=[];let d=0;for(let e=0;e<n.length;e++){const u=n[e],f=!(n[n.length-1]+1<t.length-1)&&e===n.length-1,p=[];let g=-1,m=-1,y=0;for(let e=d;e<u;e++){const n=t[e];if((n.type!==l.PENALTY||n.text)&&(n.type!==l.DISCRETIONARY||n.noBreak)){if(void 0!==n.originIndex){(-1===g||n.originIndex<g)&&(g=n.originIndex);const e=n.text?n.text.length:0,t=n.originIndex+e-1;t>m&&(m=t)}if(n.text)p.push(n.text);else if(n.type===l.DISCRETIONARY){const e=n;e.noBreak&&p.push(e.noBreak)}y+=n.width}}const x=t[u];let _=!1;if(u<t.length)if(x.type===l.PENALTY&&x.flagged)p.push("-"),y+=x.width,_=!0,void 0!==x.originIndex&&(m=x.originIndex-1);else if(x.type===l.DISCRETIONARY){const e=x;e.preBreak&&(p.push(e.preBreak),y+=e.preBreakWidth,_=e.flagged||!1,void 0!==x.originIndex&&(m=x.originIndex-1))}const v=p.join("");let w=0,b=0,S=s;if("justify"===s&&f&&(S="rtl"===r?"right":"left"),"center"===S)w=(i-y)/2;else if("right"===S)w=i-y;else if("justify"===S&&!f){b=LineBreak.computeAdjustmentRatio(t,d,u,e,i,o,h).ratio}c.push({text:v,originalStart:g,originalEnd:m,xOffset:w,adjustmentRatio:b,isLastLine:!1,naturalWidth:y,endedWithHyphen:_}),d=u+1}if(d<t.length-1){const e=[];let n=-1,o=-1,h=0;for(let i=d;i<t.length-1;i++){const s=t[i];s.type!==l.PENALTY&&(void 0!==s.originIndex&&((-1===n||s.originIndex<n)&&(n=s.originIndex),s.originIndex>o&&(o=s.originIndex)),s.text&&e.push(s.text),h+=s.width)}const u=e.join("");let f=0,p=s;"justify"===s&&(p="rtl"===r?"right":"left"),"center"===p?f=(i-h)/2:"right"===p&&(f=i-h),c.push({text:u,originalStart:n,originalEnd:o,xOffset:f,adjustmentRatio:0,isLastLine:!0,naturalWidth:h,endedWithHyphen:!1}),c.length>1&&(c[c.length-2].isLastLine=!1),c[c.length-1].isLastLine=!0}else c.length>0&&(c[c.length-1].isLastLine=!0);return c}}class TextMeasurer{static measureTextWidth(e,t,n=0){const i=e.hb.createBuffer();i.addText(t),i.guessSegmentProperties(),e.hb.shape(e.font,i);const s=i.json(e.font),r=n*e.upem;let o=0;return s.forEach((e,n)=>{o+=e.ax;const i=n===s.length-1,h=" "===t||" "===t||/^\s+$/.test(t);0===r||i&&!h||(o+=r)}),i.destroy(),o}}class TextLayout{constructor(e){this.loadedFont=e}computeLines(e){const{text:t,width:n,align:i,direction:s,hyphenate:r,language:o,respectExistingBreaks:h,tolerance:l,pretolerance:c,emergencyStretch:d,autoEmergencyStretch:u,hyphenationPatterns:f,lefthyphenmin:p,righthyphenmin:g,linepenalty:m,adjdemerits:y,hyphenpenalty:x,exhyphenpenalty:_,doublehyphendemerits:v,looseness:w,disableSingleWordDetection:b,letterSpacing:S}=e;let E;if(n)E=LineBreak.breakText({text:t,width:n,align:i,direction:s,hyphenate:r,language:o,respectExistingBreaks:h,tolerance:l,pretolerance:c,emergencyStretch:d,autoEmergencyStretch:u,hyphenationPatterns:f,lefthyphenmin:p,righthyphenmin:g,linepenalty:m,adjdemerits:y,hyphenpenalty:x,exhyphenpenalty:_,doublehyphendemerits:v,looseness:w,disableSingleWordDetection:b,unitsPerEm:this.loadedFont.upem,measureText:e=>TextMeasurer.measureTextWidth(this.loadedFont,e,S)});else{const e=t.split("\n");E=[];let n=0;for(const t of e)E.push({text:t,originalStart:n,originalEnd:n+t.length-1,xOffset:0}),n+=t.length+1}return{lines:E}}applyAlignment(e,t){const{width:n,align:i,planeBounds:s}=t;let r=0;const o={min:{...s.min},max:{...s.max}};if(n&&("center"===i||"right"===i)){const t=s.max.x-s.min.x;if("center"===i?r=(n-t)/2-s.min.x:"right"===i&&(r=n-s.max.x),0!==r){for(let t=0;t<e.length;t+=3)e[t]+=r;o.min.x+=r,o.max.x+=r}}return{offset:r,adjustedBounds:o}}}const v=1330926671,w=1953784678,b=2001684038;class FontMetadataExtractor{static extractMetadata(e){if(!e||e.byteLength<12)throw new Error("Invalid font buffer: too small to be a valid font file");const t=new DataView(e),n=t.getUint32(0);if(![65536,v,w].includes(n))throw new Error(`Invalid font format. Expected TrueType or OpenType, got signature: 0x${n.toString(16)}`);const i=new Uint8Array(e),s=t.getUint16(4);let r=!1,o=0,h=0,l=0,c=0,d=0,u=0;for(let e=0;e<s;e++){const n=(new TextDecoder).decode(i.slice(12+16*e,12+16*e+4));("CFF "===n||"CFF2"===n)&&(r=!0),"head"===n&&(o=t.getUint32(12+16*e+8)),"hhea"===n&&(h=t.getUint32(12+16*e+8)),"OS/2"===n&&(l=t.getUint32(12+16*e+8)),"fvar"===n&&(u=t.getUint32(12+16*e+8)),"STAT"===n&&(c=t.getUint32(12+16*e+8)),"name"===n&&(d=t.getUint32(12+16*e+8))}const f=o?t.getUint16(o+18):1e3;let p=null;h&&(p={ascender:t.getInt16(h+4),descender:t.getInt16(h+6),lineGap:t.getInt16(h+8)});let g=null;l&&(g={typoAscender:t.getInt16(l+68),typoDescender:t.getInt16(l+70),typoLineGap:t.getInt16(l+72),winAscent:t.getUint16(l+74),winDescent:t.getUint16(l+76)});let m=null;return u&&c&&d&&(m=this.extractAxisNames(t,c,d)),{isCFF:r,unitsPerEm:f,hheaAscender:p?.ascender||null,hheaDescender:p?.descender||null,hheaLineGap:p?.lineGap||null,typoAscender:g?.typoAscender||null,typoDescender:g?.typoDescender||null,typoLineGap:g?.typoLineGap||null,winAscent:g?.winAscent||null,winDescent:g?.winDescent||null,axisNames:m}}static extractAxisNames(e,t,n){try{if(e.getUint16(t)<1)return null;const i=e.getUint16(t+4),s=e.getUint16(t+6),r=e.getUint32(t+8),o={};for(let h=0;h<s;h++){const s=t+r+h*i,l=String.fromCharCode(e.getUint8(s),e.getUint8(s+1),e.getUint8(s+2),e.getUint8(s+3)),c=e.getUint16(s+4),d=this.getNameFromNameTable(e,n,c);d&&(o[l]=d)}return Object.keys(o).length>0?o:null}catch(e){return null}}static getNameFromNameTable(e,t,n){try{const i=e.getUint16(t+2),s=e.getUint16(t+4);for(let r=0;r<i;r++){const i=t+6+12*r,o=e.getUint16(i),h=e.getUint16(i+2),l=e.getUint16(i+4),c=e.getUint16(i+6),d=e.getUint16(i+8),u=e.getUint16(i+10);if(c===n&&(0===o||3===o&&1033===l)){const n=t+s+u,i=new Uint8Array(e.buffer,n,d);if(0===o||3===o&&1===h){let e="";for(let t=0;t<i.length;t+=2)e+=String.fromCharCode(i[t]<<8|i[t+1]);return e}return new TextDecoder("ascii").decode(i)}}return null}catch(e){return null}}static getVerticalMetrics(e){return null!==e.typoAscender&&null!==e.typoDescender?{ascender:e.typoAscender,descender:e.typoDescender,lineGap:0}:null!==e.hheaAscender&&null!==e.hheaDescender?{ascender:e.hheaAscender,descender:e.hheaDescender,lineGap:0}:null!==e.winAscent&&null!==e.winDescent?{ascender:e.winAscent,descender:-e.winDescent,lineGap:0}:{ascender:Math.round(.8*e.unitsPerEm),descender:-Math.round(.2*e.unitsPerEm),lineGap:0}}static getFontMetrics(e){const t=FontMetadataExtractor.getVerticalMetrics(e);return{ascender:t.ascender,descender:t.descender,lineGap:t.lineGap,unitsPerEm:e.unitsPerEm,naturalLineHeight:t.ascender-t.descender}}}class WoffConverter{static detectFormat(e){if(e.byteLength<4)return"ttf/otf";const t=new DataView(e).getUint32(0);return t===b?"woff":2001684018===t?"woff2":"ttf/otf"}static async decompressWoff(e){const t=new DataView(e),i=new Uint8Array(e);if(t.getUint32(0)!==b)throw new Error("Not a valid WOFF font");const s=t.getUint32(4),r=t.getUint16(12),o=t.getUint32(16);if("undefined"==typeof DecompressionStream)throw new Error("WOFF fonts require DecompressionStream API (Chrome 80+, Firefox 113+, Safari 16.4+). Please use TTF/OTF fonts or upgrade your browser.");const h=new Uint8Array(o),l=new DataView(h.buffer);l.setUint32(0,s),l.setUint16(4,r);const c=2**Math.floor(Math.log2(r))*16;l.setUint16(6,c),l.setUint16(8,Math.floor(Math.log2(r))),l.setUint16(10,16*r-c);let d=12+16*r;const u=[];for(let e=0;e<r;e++){const n=44+20*e;u.push({tag:t.getUint32(n),offset:t.getUint32(n+4),length:t.getUint32(n+8),origLength:t.getUint32(n+12),checksum:t.getUint32(n+16)})}u.sort((e,t)=>e.tag-t.tag);for(let e=0;e<r;e++){const t=u[e],n=12+16*e;if(l.setUint32(n,t.tag),l.setUint32(n+4,t.checksum),l.setUint32(n+8,d),l.setUint32(n+12,t.origLength),t.length===t.origLength)h.set(i.subarray(t.offset,t.offset+t.length),d);else{const e=i.subarray(t.offset,t.offset+t.length),n=await WoffConverter.decompressZlib(e);if(n.byteLength!==t.origLength)throw new Error(`Decompression failed: expected ${t.origLength} bytes, got ${n.byteLength}`);h.set(new Uint8Array(n),d)}d+=t.origLength;d+=(4-t.origLength%4)%4}return n.log("WOFF font decompressed successfully"),h.buffer.slice(0,d)}static async decompressZlib(e){const t=new ReadableStream({start(t){t.enqueue(e),t.close()}}).pipeThrough(new DecompressionStream("deflate"));return new Response(t).arrayBuffer()}}class FontLoader{constructor(e){this.getHarfBuzzInstance=e}async loadFont(e,t){if(i.start("FontLoader.loadFont",{bufferSize:e.byteLength}),!e||e.byteLength<12)throw new Error("Invalid font buffer: too small to be a valid font file");const s=WoffConverter.detectFormat(e);if("woff"===s)n.log("WOFF font detected, decompressing..."),e=await WoffConverter.decompressWoff(e);else if("woff2"===s)throw new Error("WOFF2 fonts are not yet supported. Please use WOFF or TTF/OTF format.");const r=new DataView(e).getUint32(0);if(![65536,v,w].includes(r))throw new Error(`Invalid font format. Expected TrueType or OpenType, got signature: 0x${r.toString(16)}`);const{hb:o,module:h}=await this.getHarfBuzzInstance();try{const n=o.createBlob(new Uint8Array(e)),i=o.createFace(n,0),s=o.createFont(i);t&&s.setVariations(t);const r=i.getAxisInfos(),l=Object.keys(r).length>0,c=FontMetadataExtractor.extractMetadata(e);let d;if(l&&r){d={};for(const[e,t]of Object.entries(r))d[e]={...t,name:c.axisNames?.[e]||null}}return{hb:o,fontBlob:n,face:i,font:s,module:h,upem:c.unitsPerEm,metrics:c,fontVariations:t,isVariable:l,variationAxes:d}}catch(e){throw n.error("Failed to load font:",e),e}finally{i.end("FontLoader.loadFont")}}static destroyFont(e){try{e.font&&"function"==typeof e.font.destroy&&e.font.destroy(),e.face&&"function"==typeof e.face.destroy&&e.face.destroy(),e.fontBlob&&"function"==typeof e.fontBlob.destroy&&e.fontBlob.destroy()}catch(e){n.error("Error destroying font resources:",e)}}}async function loadPattern(e,t){{const n=`ThreeTextPatterns_${e.replace(/-/g,"_")}`;if(window[n])return window[n];const i=t||"/patterns/";return new Promise((t,s)=>{const r=document.createElement("script");r.src=`${i}${e}.umd.js`,r.async=!0,r.onload=()=>{window[n]?t(window[n]):s(new Error(`Pattern script loaded, but global ${n} not found.`))},r.onerror=()=>{s(new Error(`Failed to load hyphenation pattern from ${r.src}. Did you copy the pattern files to your public directory?`))},document.head.appendChild(r)})}}class Vec2{constructor(e=0,t=0){this.x=e,this.y=t}set(e,t){return this.x=e,this.y=t,this}clone(){return new Vec2(this.x,this.y)}copy(e){return this.x=e.x,this.y=e.y,this}add(e){return this.x+=e.x,this.y+=e.y,this}sub(e){return this.x-=e.x,this.y-=e.y,this}multiply(e){return this.x*=e,this.y*=e,this}divide(e){return this.x/=e,this.y/=e,this}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}lengthSq(){return this.x*this.x+this.y*this.y}normalize(){const e=this.length();return e>0&&this.divide(e),this}dot(e){return this.x*e.x+this.y*e.y}distanceTo(e){const t=this.x-e.x,n=this.y-e.y;return Math.sqrt(t*t+n*n)}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y;return t*t+n*n}equals(e){return this.x===e.x&&this.y===e.y}angle(){return Math.atan2(this.y,this.x)}}class Vec3{constructor(e=0,t=0,n=0){this.x=e,this.y=t,this.z=n}set(e,t,n){return this.x=e,this.y=t,this.z=n,this}clone(){return new Vec3(this.x,this.y,this.z)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}multiply(e){return this.x*=e,this.y*=e,this.z*=e,this}divide(e){return this.x/=e,this.y/=e,this.z/=e,this}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}normalize(){const e=this.length();return e>0&&this.divide(e),this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z}cross(e){const t=this.y*e.z-this.z*e.y,n=this.z*e.x-this.x*e.z,i=this.x*e.y-this.y*e.x;return this.x=t,this.y=n,this.z=i,this}distanceTo(e){const t=this.x-e.x,n=this.y-e.y,i=this.z-e.z;return Math.sqrt(t*t+n*n+i*i)}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y,i=this.z-e.z;return t*t+n*n+i*i}equals(e){return this.x===e.x&&this.y===e.y&&this.z===e.z}}class Box3{constructor(e=new Vec3(1/0,1/0,1/0),t=new Vec3(-1/0,-1/0,-1/0)){this.min=e,this.max=t}set(e,t){return this.min.copy(e),this.max.copy(t),this}setFromPoints(e){this.makeEmpty();for(let t=0;t<e.length;t++)this.expandByPoint(e[t]);return this}makeEmpty(){return this.min.x=this.min.y=this.min.z=1/0,this.max.x=this.max.y=this.max.z=-1/0,this}isEmpty(){return this.max.x<this.min.x||this.max.y<this.min.y||this.max.z<this.min.z}expandByPoint(e){return this.min.x=Math.min(this.min.x,e.x),this.min.y=Math.min(this.min.y,e.y),this.min.z=Math.min(this.min.z,e.z),this.max.x=Math.max(this.max.x,e.x),this.max.y=Math.max(this.max.y,e.y),this.max.z=Math.max(this.max.z,e.z),this}expandByScalar(e){return this.min.x-=e,this.min.y-=e,this.min.z-=e,this.max.x+=e,this.max.y+=e,this.max.z+=e,this}containsPoint(e){return e.x>=this.min.x&&e.x<=this.max.x&&e.y>=this.min.y&&e.y<=this.max.y&&e.z>=this.min.z&&e.z<=this.max.z}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z}intersectsBox(e){return e.max.x>=this.min.x&&e.min.x<=this.max.x&&e.max.y>=this.min.y&&e.min.y<=this.max.y&&e.max.z>=this.min.z&&e.min.z<=this.max.z}getCenter(e=new Vec3){return this.isEmpty()?e.set(0,0,0):e.set(.5*(this.min.x+this.max.x),.5*(this.min.y+this.max.y),.5*(this.min.z+this.max.z))}getSize(e=new Vec3){return this.isEmpty()?e.set(0,0,0):e.set(this.max.x-this.min.x,this.max.y-this.min.y,this.max.z-this.min.z)}clone(){return new Box3(this.min.clone(),this.max.clone())}copy(e){return this.min.copy(e.min),this.max.copy(e.max),this}union(e){return this.min.x=Math.min(this.min.x,e.min.x),this.min.y=Math.min(this.min.y,e.min.y),this.min.z=Math.min(this.min.z,e.min.z),this.max.x=Math.max(this.max.x,e.max.x),this.max.y=Math.max(this.max.y,e.max.y),this.max.z=Math.max(this.max.z,e.max.z),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}}var S,E;function assert(e,t){if(!e)throw t||"Assertion Failed!"}!function(e){e[e.ODD=0]="ODD",e[e.NONZERO=1]="NONZERO",e[e.POSITIVE=2]="POSITIVE",e[e.NEGATIVE=3]="NEGATIVE",e[e.ABS_GEQ_TWO=4]="ABS_GEQ_TWO"}(S||(S={})),function(e){e[e.POLYGONS=0]="POLYGONS",e[e.CONNECTED_POLYGONS=1]="CONNECTED_POLYGONS",e[e.BOUNDARY_CONTOURS=2]="BOUNDARY_CONTOURS"}(E||(E={}));var L=function(){function Geom(){}return Geom.vertEq=function(e,t){return e.s===t.s&&e.t===t.t},Geom.vertLeq=function(e,t){return e.s<t.s||e.s===t.s&&e.t<=t.t},Geom.transLeq=function(e,t){return e.t<t.t||e.t===t.t&&e.s<=t.s},Geom.edgeGoesLeft=function(e){return Geom.vertLeq(e.Dst,e.Org)},Geom.edgeGoesRight=function(e){return Geom.vertLeq(e.Org,e.Dst)},Geom.vertL1dist=function(e,t){return Math.abs(e.s-t.s)+Math.abs(e.t-t.t)},Geom.edgeEval=function(e,t,n){assert(Geom.vertLeq(e,t)&&Geom.vertLeq(t,n));var i=t.s-e.s,s=n.s-t.s;return i+s>0?i<s?t.t-e.t+(e.t-n.t)*(i/(i+s)):t.t-n.t+(n.t-e.t)*(s/(i+s)):0},Geom.edgeSign=function(e,t,n){assert(Geom.vertLeq(e,t)&&Geom.vertLeq(t,n));var i=t.s-e.s,s=n.s-t.s;return i+s>0?(t.t-n.t)*i+(t.t-e.t)*s:0},Geom.transEval=function(e,t,n){assert(Geom.transLeq(e,t)&&Geom.transLeq(t,n));var i=t.t-e.t,s=n.t-t.t;return i+s>0?i<s?t.s-e.s+(e.s-n.s)*(i/(i+s)):t.s-n.s+(n.s-e.s)*(s/(i+s)):0},Geom.transSign=function(e,t,n){assert(Geom.transLeq(e,t)&&Geom.transLeq(t,n));var i=t.t-e.t,s=n.t-t.t;return i+s>0?(t.s-n.s)*i+(t.s-e.s)*s:0},Geom.vertCCW=function(e,t,n){return e.s*(t.t-n.t)+t.s*(n.t-e.t)+n.s*(e.t-t.t)>=0},Geom.interpolate=function(e,t,n,i){return(e=e<0?0:e)<=(n=n<0?0:n)?0===n?(t+i)/2:t+e/(e+n)*(i-t):i+n/(e+n)*(t-i)},Geom.intersect=function(e,t,n,i,s){var r,o,h;Geom.vertLeq(e,t)||(h=e,e=t,t=h),Geom.vertLeq(n,i)||(h=n,n=i,i=h),Geom.vertLeq(e,n)||(h=e,e=n,n=h,h=t,t=i,i=h),Geom.vertLeq(n,t)?Geom.vertLeq(t,i)?((r=Geom.edgeEval(e,n,t))+(o=Geom.edgeEval(n,t,i))<0&&(r=-r,o=-o),s.s=Geom.interpolate(r,n.s,o,t.s)):((r=Geom.edgeSign(e,n,t))+(o=-Geom.edgeSign(e,i,t))<0&&(r=-r,o=-o),s.s=Geom.interpolate(r,n.s,o,i.s)):s.s=(n.s+t.s)/2,Geom.transLeq(e,t)||(h=e,e=t,t=h),Geom.transLeq(n,i)||(h=n,n=i,i=h),Geom.transLeq(e,n)||(h=e,e=n,n=h,h=t,t=i,i=h),Geom.transLeq(n,t)?Geom.transLeq(t,i)?((r=Geom.transEval(e,n,t))+(o=Geom.transEval(n,t,i))<0&&(r=-r,o=-o),s.t=Geom.interpolate(r,n.t,o,t.t)):((r=Geom.transSign(e,n,t))+(o=-Geom.transSign(e,i,t))<0&&(r=-r,o=-o),s.t=Geom.interpolate(r,n.t,o,i.t)):s.t=(n.t+t.t)/2},Geom}(),TESSface=function(){this.next=null,this.prev=null,this.anEdge=null,this.trail=null,this.n=0,this.marked=!1,this.inside=!1},O=function(){function TESShalfEdge(e){this.side=e,this.next=null,this.Org=null,this.Sym=null,this.Onext=null,this.Lnext=null,this.Lface=null,this.activeRegion=null,this.winding=0}return Object.defineProperty(TESShalfEdge.prototype,"Rface",{get:function(){return this.Sym.Lface},set:function(e){this.Sym.Lface=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Dst",{get:function(){return this.Sym.Org},set:function(e){this.Sym.Org=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Oprev",{get:function(){return this.Sym.Lnext},set:function(e){this.Sym.Lnext=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Lprev",{get:function(){return this.Onext.Sym},set:function(e){this.Onext.Sym=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Dprev",{get:function(){return this.Lnext.Sym},set:function(e){this.Lnext.Sym=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Rprev",{get:function(){return this.Sym.Onext},set:function(e){this.Sym.Onext=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Dnext",{get:function(){return this.Sym.Onext.Sym},set:function(e){this.Sym.Onext.Sym=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Rnext",{get:function(){return this.Sym.Lnext.Sym},set:function(e){this.Sym.Lnext.Sym=e},enumerable:!0,configurable:!0}),TESShalfEdge}(),TESSvertex=function(){this.next=null,this.prev=null,this.anEdge=null,this.coords=[0,0,0],this.s=0,this.t=0,this.pqHandle=0,this.n=0,this.idx=0},T=function(){function TESSmesh(){var e=new TESSvertex,t=new TESSface,n=new O(0),i=new O(1);e.next=e.prev=e,e.anEdge=null,t.next=t.prev=t,n.next=n,n.Sym=i,i.next=i,i.Sym=n,this.vHead=e,this.fHead=t,this.eHead=n,this.eHeadSym=i}return TESSmesh.prototype.makeEdge_=function(e){var t=new O(0),n=new O(1);e.Sym.side<e.side&&(e=e.Sym);var i=e.Sym.next;return n.next=i,i.Sym.next=t,t.next=e,e.Sym.next=n,t.Sym=n,t.Onext=t,t.Lnext=n,t.Org=null,t.Lface=null,t.winding=0,t.activeRegion=null,n.Sym=t,n.Onext=n,n.Lnext=t,n.Org=null,n.Lface=null,n.winding=0,n.activeRegion=null,t},TESSmesh.prototype.splice_=function(e,t){var n=e.Onext,i=t.Onext;n.Sym.Lnext=t,i.Sym.Lnext=e,e.Onext=i,t.Onext=n},TESSmesh.prototype.makeVertex_=function(e,t,n){var i=e;assert(i,"Vertex can't be null!");var s=n.prev;i.prev=s,s.next=i,i.next=n,n.prev=i,i.anEdge=t;var r=t;do{r.Org=i,r=r.Onext}while(r!==t)},TESSmesh.prototype.makeFace_=function(e,t,n){var i=e;assert(i,"Face can't be null");var s=n.prev;i.prev=s,s.next=i,i.next=n,n.prev=i,i.anEdge=t,i.trail=null,i.marked=!1,i.inside=n.inside;var r=t;do{r.Lface=i,r=r.Lnext}while(r!==t)},TESSmesh.prototype.killEdge_=function(e){e.Sym.side<e.side&&(e=e.Sym);var t=e.next,n=e.Sym.next;t.Sym.next=n,n.Sym.next=t},TESSmesh.prototype.killVertex_=function(e,t){var n=e.anEdge,i=n;do{i.Org=t,i=i.Onext}while(i!==n);var s=e.prev,r=e.next;r.prev=s,s.next=r},TESSmesh.prototype.killFace_=function(e,t){var n=e.anEdge,i=n;do{i.Lface=t,i=i.Lnext}while(i!==n);var s=e.prev,r=e.next;r.prev=s,s.next=r},TESSmesh.prototype.makeEdge=function(){var e=new TESSvertex,t=new TESSvertex,n=new TESSface,i=this.makeEdge_(this.eHead);return this.makeVertex_(e,i,this.vHead),this.makeVertex_(t,i.Sym,this.vHead),this.makeFace_(n,i,this.fHead),i},TESSmesh.prototype.splice=function(e,t){var n=!1,i=!1;if(e!==t){if(t.Org!==e.Org&&(i=!0,this.killVertex_(t.Org,e.Org)),t.Lface!==e.Lface&&(n=!0,this.killFace_(t.Lface,e.Lface)),this.splice_(t,e),!i){var s=new TESSvertex;this.makeVertex_(s,t,e.Org),e.Org.anEdge=e}if(!n){var r=new TESSface;this.makeFace_(r,t,e.Lface),e.Lface.anEdge=e}}},TESSmesh.prototype.delete=function(e){var t=e.Sym,n=!1;if(e.Lface!==e.Rface&&(n=!0,this.killFace_(e.Lface,e.Rface)),e.Onext===e)this.killVertex_(e.Org,null);else if(e.Rface.anEdge=e.Oprev,e.Org.anEdge=e.Onext,this.splice_(e,e.Oprev),!n){var i=new TESSface;this.makeFace_(i,e,e.Lface)}t.Onext===t?(this.killVertex_(t.Org,null),this.killFace_(t.Lface,null)):(e.Lface.anEdge=t.Oprev,t.Org.anEdge=t.Onext,this.splice_(t,t.Oprev)),this.killEdge_(e)},TESSmesh.prototype.addEdgeVertex=function(e){var t=this.makeEdge_(e),n=t.Sym;this.splice_(t,e.Lnext),t.Org=e.Dst;var i=new TESSvertex;return this.makeVertex_(i,n,t.Org),t.Lface=n.Lface=e.Lface,t},TESSmesh.prototype.splitEdge=function(e){var t=this.addEdgeVertex(e).Sym;return this.splice_(e.Sym,e.Sym.Oprev),this.splice_(e.Sym,t),e.Dst=t.Org,t.Dst.anEdge=t.Sym,t.Rface=e.Rface,t.winding=e.winding,t.Sym.winding=e.Sym.winding,t},TESSmesh.prototype.connect=function(e,t){var n=!1,i=this.makeEdge_(e),s=i.Sym;if(t.Lface!==e.Lface&&(n=!0,this.killFace_(t.Lface,e.Lface)),this.splice_(i,e.Lnext),this.splice_(s,t),i.Org=e.Dst,s.Org=t.Org,i.Lface=s.Lface=e.Lface,e.Lface.anEdge=s,!n){var r=new TESSface;this.makeFace_(r,i,e.Lface)}return i},TESSmesh.prototype.zapFace=function(e){var t,n,i,s,r,o=e.anEdge;n=o.Lnext;do{n=(t=n).Lnext,t.Lface=null,null===t.Rface&&(t.Onext===t?this.killVertex_(t.Org,null):(t.Org.anEdge=t.Onext,this.splice_(t,t.Oprev)),(i=t.Sym).Onext===i?this.killVertex_(i.Org,null):(i.Org.anEdge=i.Onext,this.splice_(i,i.Oprev)),this.killEdge_(t))}while(t!=o);s=e.prev,(r=e.next).prev=s,s.next=r},TESSmesh.prototype.countFaceVerts_=function(e){var t=e.anEdge,n=0;do{n++,t=t.Lnext}while(t!==e.anEdge);return n},TESSmesh.prototype.mergeConvexFaces=function(e){var t,n,i,s,r;for(t=this.fHead.next;t!==this.fHead;t=t.next)if(t.inside)for(r=(n=t.anEdge).Org;i=n.Lnext,(s=n.Sym)&&s.Lface&&s.Lface.inside&&this.countFaceVerts_(t)+this.countFaceVerts_(s.Lface)-2<=e&&L.vertCCW(n.Lprev.Org,n.Org,s.Lnext.Lnext.Org)&&L.vertCCW(s.Lprev.Org,s.Org,n.Lnext.Lnext.Org)&&(i=s.Lnext,this.delete(s),n=null,s=null),!n||n.Lnext.Org!==r;)n=i;return!0},TESSmesh.prototype.check=function(){var e,t,n,i,s,r,o=this.fHead,h=this.vHead,l=this.eHead;for(t=o,t=o;(e=t.next)!==o;t=e){assert(e.prev===t),s=e.anEdge;do{assert(s.Sym!==s),assert(s.Sym.Sym===s),assert(s.Lnext.Onext.Sym===s),assert(s.Onext.Sym.Lnext===s),assert(s.Lface===e),s=s.Lnext}while(s!==e.anEdge)}for(assert(e.prev===t&&null===e.anEdge),i=h,i=h;(n=i.next)!==h;i=n){assert(n.prev===i),s=n.anEdge;do{assert(s.Sym!==s),assert(s.Sym.Sym===s),assert(s.Lnext.Onext.Sym===s),assert(s.Onext.Sym.Lnext===s),assert(s.Org===n),s=s.Onext}while(s!==n.anEdge)}for(assert(n.prev===i&&null===n.anEdge),r=l,r=l;(s=r.next)!==l;r=s)assert(s.Sym.next===r.Sym),assert(s.Sym!==s),assert(s.Sym.Sym===s),assert(null!==s.Org),assert(null!==s.Dst),assert(s.Lnext.Onext.Sym===s),assert(s.Onext.Sym.Lnext===s);assert(s.Sym.next===r.Sym&&s.Sym===this.eHeadSym&&s.Sym.Sym===s&&null===s.Org&&null===s.Dst&&null===s.Lface&&null===s.Rface)},TESSmesh}(),PQnode=function(){this.handle=null},PQhandleElem=function(){this.key=null,this.node=0},P=function(){function PriorityQ(e,t){this.leq=t,this.max=0,this.nodes=[],this.handles=[],this.initialized=!1,this.freeList=0,this.size=0,this.max=e,this.nodes=[],this.handles=[];for(var n=0;n<e+1;n++)this.nodes[n]=new PQnode,this.handles[n]=new PQhandleElem;this.initialized=!1,this.nodes[1].handle=1,this.handles[1].key=null}return PriorityQ.prototype.floatDown_=function(e){var t,n,i,s=this.nodes,r=this.handles;for(t=s[e].handle;;){if((i=e<<1)<this.size&&this.leq(r[s[i+1].handle].key,r[s[i].handle].key)&&++i,assert(i<=this.max),n=s[i].handle,i>this.size||this.leq(r[t].key,r[n].key)){s[e].handle=t,r[t].node=e;break}s[e].handle=n,r[n].node=e,e=i}},PriorityQ.prototype.floatUp_=function(e){var t,n,i,s=this.nodes,r=this.handles;for(t=s[e].handle;;){if(n=s[i=e>>1].handle,0===i||this.leq(r[n].key,r[t].key)){s[e].handle=t,r[t].node=e;break}s[e].handle=n,r[n].node=e,e=i}},PriorityQ.prototype.init=function(){for(var e=this.size;e>=1;--e)this.floatDown_(e);this.initialized=!0},PriorityQ.prototype.min=function(){return this.handles[this.nodes[1].handle].key},PriorityQ.prototype.insert=function(e){var t,n;if(2*(t=++this.size)>this.max){var i,s;for(this.max*=2,s=this.nodes.length,this.nodes.length=this.max+1,i=s;i<this.nodes.length;i++)this.nodes[i]=new PQnode;for(s=this.handles.length,this.handles.length=this.max+1,i=s;i<this.handles.length;i++)this.handles[i]=new PQhandleElem}return 0===this.freeList?n=t:(n=this.freeList,this.freeList=this.handles[n].node),this.nodes[t].handle=n,this.handles[n].node=t,this.handles[n].key=e,this.initialized&&this.floatUp_(t),n},PriorityQ.prototype.extractMin=function(){var e=this.nodes,t=this.handles,n=e[1].handle,i=t[n].key;return this.size>0&&(e[1].handle=e[this.size].handle,t[e[1].handle].node=1,t[n].key=null,t[n].node=this.freeList,this.freeList=n,--this.size,this.size>0&&this.floatDown_(1)),i},PriorityQ.prototype.delete=function(e){var t,n=this.nodes,i=this.handles;assert(e>=1&&e<=this.max&&null!==i[e].key),n[t=i[e].node].handle=n[this.size].handle,i[n[t].handle].node=t,--this.size,t<=this.size&&(t<=1||this.leq(i[n[t>>1].handle].key,i[n[t].handle].key)?this.floatDown_(t):this.floatUp_(t)),i[e].key=null,i[e].node=this.freeList,this.freeList=e},PriorityQ}(),ActiveRegion=function(){this.eUp=null,this.nodeUp=null,this.windingNumber=0,this.inside=!1,this.sentinel=!1,this.dirty=!1,this.fixUpperEdge=!1},DictNode=function(){this.key=null,this.next=null,this.prev=null},F=function(){function Dict(e,t){this.frame=e,this.leq=t,this.head=new DictNode,this.head.next=this.head,this.head.prev=this.head}return Dict.prototype.min=function(){return this.head.next},Dict.prototype.max=function(){return this.head.prev},Dict.prototype.insert=function(e){return this.insertBefore(this.head,e)},Dict.prototype.search=function(e){var t=this.head;do{t=t.next}while(null!==t.key&&!this.leq(this.frame,e,t.key));return t},Dict.prototype.insertBefore=function(e,t){do{e=e.prev}while(null!==e.key&&!this.leq(this.frame,e.key,t));var n=new DictNode;return n.key=t,n.next=e.next,e.next.prev=n,n.prev=e,e.next=n,n},Dict.prototype.delete=function(e){e.next.prev=e.prev,e.prev.next=e.next},Dict}(),C=function(){function Sweep(){}return Sweep.regionBelow=function(e){return e.nodeUp.prev.key},Sweep.regionAbove=function(e){return e.nodeUp.next.key},Sweep.debugEvent=function(e){},Sweep.addWinding=function(e,t){e.winding+=t.winding,e.Sym.winding+=t.Sym.winding},Sweep.edgeLeq=function(e,t,n){var i=e.event,s=t.eUp,r=n.eUp;return s.Dst===i?r.Dst===i?L.vertLeq(s.Org,r.Org)?L.edgeSign(r.Dst,s.Org,r.Org)<=0:L.edgeSign(s.Dst,r.Org,s.Org)>=0:L.edgeSign(r.Dst,i,r.Org)<=0:r.Dst===i?L.edgeSign(s.Dst,i,s.Org)>=0:L.edgeEval(s.Dst,i,s.Org)>=L.edgeEval(r.Dst,i,r.Org)},Sweep.deleteRegion=function(e,t){t.fixUpperEdge&&assert(0===t.eUp.winding),t.eUp.activeRegion=null,e.dict.delete(t.nodeUp)},Sweep.fixUpperEdge=function(e,t,n){assert(t.fixUpperEdge),e.mesh.delete(t.eUp),t.fixUpperEdge=!1,t.eUp=n,n.activeRegion=t},Sweep.topLeftRegion=function(e,t){var n,i=t.eUp.Org;do{t=Sweep.regionAbove(t)}while(t.eUp.Org===i);if(t.fixUpperEdge){if(null===(n=e.mesh.connect(Sweep.regionBelow(t).eUp.Sym,t.eUp.Lnext)))return null;Sweep.fixUpperEdge(e,t,n),t=Sweep.regionAbove(t)}return t},Sweep.topRightRegion=function(e){var t=e.eUp.Dst;do{e=Sweep.regionAbove(e)}while(e.eUp.Dst===t);return e},Sweep.addRegionBelow=function(e,t,n){var i=new ActiveRegion;return i.eUp=n,i.nodeUp=e.dict.insertBefore(t.nodeUp,i),i.fixUpperEdge=!1,i.sentinel=!1,i.dirty=!1,n.activeRegion=i,i},Sweep.isWindingInside=function(e,t){switch(e.windingRule){case S.ODD:return!!(1&t);case S.NONZERO:return 0!==t;case S.POSITIVE:return t>0;case S.NEGATIVE:return t<0;case S.ABS_GEQ_TWO:return t>=2||t<=-2}throw new Error("Invalid winding rulle")},Sweep.computeWinding=function(e,t){t.windingNumber=Sweep.regionAbove(t).windingNumber+t.eUp.winding,t.inside=Sweep.isWindingInside(e,t.windingNumber)},Sweep.finishRegion=function(e,t){var n=t.eUp,i=n.Lface;i.inside=t.inside,i.anEdge=n,Sweep.deleteRegion(e,t)},Sweep.finishLeftRegions=function(e,t,n){for(var i,s=null,r=t,o=t.eUp;r!==n;){if(r.fixUpperEdge=!1,(i=(s=Sweep.regionBelow(r)).eUp).Org!=o.Org){if(!s.fixUpperEdge){Sweep.finishRegion(e,r);break}i=e.mesh.connect(o.Lprev,i.Sym),Sweep.fixUpperEdge(e,s,i)}o.Onext!==i&&(e.mesh.splice(i.Oprev,i),e.mesh.splice(o,i)),Sweep.finishRegion(e,r),o=s.eUp,r=s}return o},Sweep.addRightEdges=function(e,t,n,i,s,r){var o,h,l,c,d=!0;l=n;do{assert(L.vertLeq(l.Org,l.Dst)),Sweep.addRegionBelow(e,t,l.Sym),l=l.Onext}while(l!==i);for(null===s&&(s=Sweep.regionBelow(t).eUp.Rprev),h=t,c=s;(l=(o=Sweep.regionBelow(h)).eUp.Sym).Org===c.Org;)l.Onext!==c&&(e.mesh.splice(l.Oprev,l),e.mesh.splice(c.Oprev,l)),o.windingNumber=h.windingNumber-l.winding,o.inside=Sweep.isWindingInside(e,o.windingNumber),h.dirty=!0,!d&&Sweep.checkForRightSplice(e,h)&&(Sweep.addWinding(l,c),Sweep.deleteRegion(e,h),e.mesh.delete(c)),d=!1,h=o,c=l;h.dirty=!0,assert(h.windingNumber-l.winding===o.windingNumber),r&&Sweep.walkDirtyRegions(e,h)},Sweep.spliceMergeVertices=function(e,t,n){e.mesh.splice(t,n)},Sweep.vertexWeights=function(e,t,n){var i=L.vertL1dist(t,e),s=L.vertL1dist(n,e),r=.5*s/(i+s),o=.5*i/(i+s);e.coords[0]+=r*t.coords[0]+o*n.coords[0],e.coords[1]+=r*t.coords[1]+o*n.coords[1],e.coords[2]+=r*t.coords[2]+o*n.coords[2]},Sweep.getIntersectData=function(e,t,n,i,s,r){t.coords[0]=t.coords[1]=t.coords[2]=0,t.idx=-1,Sweep.vertexWeights(t,n,i),Sweep.vertexWeights(t,s,r)},Sweep.checkForRightSplice=function(e,t){var n=Sweep.regionBelow(t),i=t.eUp,s=n.eUp;if(L.vertLeq(i.Org,s.Org)){if(L.edgeSign(s.Dst,i.Org,s.Org)>0)return!1;L.vertEq(i.Org,s.Org)?i.Org!==s.Org&&(e.pq.delete(i.Org.pqHandle),Sweep.spliceMergeVertices(e,s.Oprev,i)):(e.mesh.splitEdge(s.Sym),e.mesh.splice(i,s.Oprev),t.dirty=n.dirty=!0)}else{if(L.edgeSign(i.Dst,s.Org,i.Org)<0)return!1;Sweep.regionAbove(t).dirty=t.dirty=!0,e.mesh.splitEdge(i.Sym),e.mesh.splice(s.Oprev,i)}return!0},Sweep.checkForLeftSplice=function(e,t){var n,i=Sweep.regionBelow(t),s=t.eUp,r=i.eUp;if(assert(!L.vertEq(s.Dst,r.Dst)),L.vertLeq(s.Dst,r.Dst)){if(L.edgeSign(s.Dst,r.Dst,s.Org)<0)return!1;Sweep.regionAbove(t).dirty=t.dirty=!0,n=e.mesh.splitEdge(s),e.mesh.splice(r.Sym,n),n.Lface.inside=t.inside}else{if(L.edgeSign(r.Dst,s.Dst,r.Org)>0)return!1;t.dirty=i.dirty=!0,n=e.mesh.splitEdge(r),e.mesh.splice(s.Lnext,r.Sym),n.Rface.inside=t.inside}return!0},Sweep.checkForIntersect=function(e,t){var n,i,s=Sweep.regionBelow(t),r=t.eUp,o=s.eUp,h=r.Org,l=o.Org,c=r.Dst,d=o.Dst,u=new TESSvertex;if(assert(!L.vertEq(d,c)),assert(L.edgeSign(c,e.event,h)<=0),assert(L.edgeSign(d,e.event,l)>=0),assert(h!==e.event&&l!==e.event),assert(!t.fixUpperEdge&&!s.fixUpperEdge),h===l)return!1;if(Math.min(h.t,c.t)>Math.max(l.t,d.t))return!1;if(L.vertLeq(h,l)){if(L.edgeSign(d,h,l)>0)return!1}else if(L.edgeSign(c,l,h)<0)return!1;return Sweep.debugEvent(e),L.intersect(c,h,d,l,u),assert(Math.min(h.t,c.t)<=u.t),assert(u.t<=Math.max(l.t,d.t)),assert(Math.min(d.s,c.s)<=u.s),assert(u.s<=Math.max(l.s,h.s)),L.vertLeq(u,e.event)&&(u.s=e.event.s,u.t=e.event.t),n=L.vertLeq(h,l)?h:l,L.vertLeq(n,u)&&(u.s=n.s,u.t=n.t),L.vertEq(u,h)||L.vertEq(u,l)?(Sweep.checkForRightSplice(e,t),!1):!L.vertEq(c,e.event)&&L.edgeSign(c,e.event,u)>=0||!L.vertEq(d,e.event)&&L.edgeSign(d,e.event,u)<=0?d===e.event?(e.mesh.splitEdge(r.Sym),e.mesh.splice(o.Sym,r),t=Sweep.topLeftRegion(e,t),r=Sweep.regionBelow(t).eUp,Sweep.finishLeftRegions(e,Sweep.regionBelow(t),s),Sweep.addRightEdges(e,t,r.Oprev,r,r,!0),!0):c===e.event?(e.mesh.splitEdge(o.Sym),e.mesh.splice(r.Lnext,o.Oprev),s=t,t=Sweep.topRightRegion(t),i=Sweep.regionBelow(t).eUp.Rprev,s.eUp=o.Oprev,o=Sweep.finishLeftRegions(e,s,null),Sweep.addRightEdges(e,t,o.Onext,r.Rprev,i,!0),!0):(L.edgeSign(c,e.event,u)>=0&&(Sweep.regionAbove(t).dirty=t.dirty=!0,e.mesh.splitEdge(r.Sym),r.Org.s=e.event.s,r.Org.t=e.event.t),L.edgeSign(d,e.event,u)<=0&&(t.dirty=s.dirty=!0,e.mesh.splitEdge(o.Sym),o.Org.s=e.event.s,o.Org.t=e.event.t),!1):(e.mesh.splitEdge(r.Sym),e.mesh.splitEdge(o.Sym),e.mesh.splice(o.Oprev,r),r.Org.s=u.s,r.Org.t=u.t,r.Org.pqHandle=e.pq.insert(r.Org),Sweep.getIntersectData(e,r.Org,h,c,l,d),Sweep.regionAbove(t).dirty=t.dirty=s.dirty=!0,!1)},Sweep.walkDirtyRegions=function(e,t){for(var n,i,s=Sweep.regionBelow(t);;){for(;s.dirty;)t=s,s=Sweep.regionBelow(s);if(!t.dirty&&(s=t,null===(t=Sweep.regionAbove(t))||!t.dirty))return;if(t.dirty=!1,n=t.eUp,i=s.eUp,n.Dst!==i.Dst&&Sweep.checkForLeftSplice(e,t)&&(s.fixUpperEdge?(Sweep.deleteRegion(e,s),e.mesh.delete(i),i=(s=Sweep.regionBelow(t)).eUp):t.fixUpperEdge&&(Sweep.deleteRegion(e,t),e.mesh.delete(n),n=(t=Sweep.regionAbove(s)).eUp)),n.Org!==i.Org)if(n.Dst===i.Dst||t.fixUpperEdge||s.fixUpperEdge||n.Dst!==e.event&&i.Dst!==e.event)Sweep.checkForRightSplice(e,t);else if(Sweep.checkForIntersect(e,t))return;n.Org===i.Org&&n.Dst===i.Dst&&(Sweep.addWinding(i,n),Sweep.deleteRegion(e,t),e.mesh.delete(n),t=Sweep.regionAbove(s))}},Sweep.connectRightVertex=function(e,t,n){var i,s=n.Onext,r=Sweep.regionBelow(t),o=t.eUp,h=r.eUp,l=!1;o.Dst!==h.Dst&&Sweep.checkForIntersect(e,t),L.vertEq(o.Org,e.event)&&(e.mesh.splice(s.Oprev,o),t=Sweep.topLeftRegion(e,t),s=Sweep.regionBelow(t).eUp,Sweep.finishLeftRegions(e,Sweep.regionBelow(t),r),l=!0),L.vertEq(h.Org,e.event)&&(e.mesh.splice(n,h.Oprev),n=Sweep.finishLeftRegions(e,r,null),l=!0),l?Sweep.addRightEdges(e,t,n.Onext,s,s,!0):(i=L.vertLeq(h.Org,o.Org)?h.Oprev:o,i=e.mesh.connect(n.Lprev,i),Sweep.addRightEdges(e,t,i,i.Onext,i.Onext,!1),i.Sym.activeRegion.fixUpperEdge=!0,Sweep.walkDirtyRegions(e,t))},Sweep.connectLeftDegenerate=function(e,t,n){var i,s,r,o,h;return i=t.eUp,L.vertEq(i.Org,n)?(assert(!1),void Sweep.spliceMergeVertices(e,i,n.anEdge)):L.vertEq(i.Dst,n)?(assert(!1),t=Sweep.topRightRegion(t),s=o=(r=(h=Sweep.regionBelow(t)).eUp.Sym).Onext,h.fixUpperEdge&&(assert(s!==r),Sweep.deleteRegion(e,h),e.mesh.delete(r),r=s.Oprev),e.mesh.splice(n.anEdge,r),L.edgeGoesLeft(s)||(s=null),void Sweep.addRightEdges(e,t,r.Onext,o,s,!0)):(e.mesh.splitEdge(i.Sym),t.fixUpperEdge&&(e.mesh.delete(i.Onext),t.fixUpperEdge=!1),e.mesh.splice(n.anEdge,i),void Sweep.sweepEvent(e,n))},Sweep.connectLeftVertex=function(e,t){var n,i,s,r,o,h,l=new ActiveRegion;if(l.eUp=t.anEdge.Sym,n=e.dict.search(l).key,i=Sweep.regionBelow(n))if(r=n.eUp,o=i.eUp,0!==L.edgeSign(r.Dst,t,r.Org))if(s=L.vertLeq(o.Dst,r.Dst)?n:i,n.inside||s.fixUpperEdge){if(s===n)h=e.mesh.connect(t.anEdge.Sym,r.Lnext);else h=e.mesh.connect(o.Dnext,t.anEdge).Sym;s.fixUpperEdge?Sweep.fixUpperEdge(e,s,h):Sweep.computeWinding(e,Sweep.addRegionBelow(e,n,h)),Sweep.sweepEvent(e,t)}else Sweep.addRightEdges(e,n,t.anEdge,t.anEdge,null,!0);else Sweep.connectLeftDegenerate(e,n,t)},Sweep.sweepEvent=function(e,t){e.event=t,Sweep.debugEvent(e);for(var n=t.anEdge;null===n.activeRegion;)if((n=n.Onext)===t.anEdge)return void Sweep.connectLeftVertex(e,t);var i=Sweep.topLeftRegion(e,n.activeRegion);assert(null!==i);var s=Sweep.regionBelow(i),r=s.eUp,o=Sweep.finishLeftRegions(e,s,null);o.Onext===r?Sweep.connectRightVertex(e,i,o):Sweep.addRightEdges(e,i,o.Onext,r,r,!0)},Sweep.addSentinel=function(e,t,n,i){var s=new ActiveRegion,r=e.mesh.makeEdge();r.Org.s=n,r.Org.t=i,r.Dst.s=t,r.Dst.t=i,e.event=r.Dst,s.eUp=r,s.windingNumber=0,s.inside=!1,s.fixUpperEdge=!1,s.sentinel=!0,s.dirty=!1,s.nodeUp=e.dict.insert(s)},Sweep.initEdgeDict=function(e){e.dict=new F(e,Sweep.edgeLeq);var t=e.bmax[0]-e.bmin[0],n=e.bmax[1]-e.bmin[1],i=e.bmin[0]-t,s=e.bmax[0]+t,r=e.bmin[1]-n,o=e.bmax[1]+n;Sweep.addSentinel(e,i,s,r),Sweep.addSentinel(e,i,s,o)},Sweep.doneEdgeDict=function(e){for(var t,n=0;null!==(t=e.dict.min().key);)t.sentinel||(assert(t.fixUpperEdge),assert(1===++n)),assert(0===t.windingNumber),Sweep.deleteRegion(e,t)},Sweep.removeDegenerateEdges=function(e){var t,n,i,s=e.mesh.eHead;for(t=s.next;t!==s;t=n)n=t.next,i=t.Lnext,L.vertEq(t.Org,t.Dst)&&t.Lnext.Lnext!==t&&(Sweep.spliceMergeVertices(e,i,t),e.mesh.delete(t),i=(t=i).Lnext),i.Lnext===t&&(i!==t&&(i!==n&&i!==n.Sym||(n=n.next),e.mesh.delete(i)),t!==n&&t!==n.Sym||(n=n.next),e.mesh.delete(t))},Sweep.initPriorityQ=function(e){var t,n,i,s=0;for(n=(i=e.mesh.vHead).next;n!==i;n=n.next)s++;for(s+=8,t=e.pq=new P(s,L.vertLeq),n=(i=e.mesh.vHead).next;n!==i;n=n.next)n.pqHandle=t.insert(n);return n===i&&(t.init(),!0)},Sweep.donePriorityQ=function(e){e.pq=null},Sweep.removeDegenerateFaces=function(e,t){var n,i,s;for(n=t.fHead.next;n!==t.fHead;n=i)i=n.next,assert((s=n.anEdge).Lnext!==s),s.Lnext.Lnext===s&&(Sweep.addWinding(s.Onext,s),e.mesh.delete(s));return!0},Sweep.computeInterior=function(e,t){var n,i;if(void 0===t&&(t=!0),Sweep.removeDegenerateEdges(e),!Sweep.initPriorityQ(e))return!1;for(Sweep.initEdgeDict(e);null!==(n=e.pq.extractMin());){for(;null!==(i=e.pq.min())&&L.vertEq(i,n);)i=e.pq.extractMin(),Sweep.spliceMergeVertices(e,n.anEdge,i.anEdge);Sweep.sweepEvent(e,n)}return e.event=e.dict.min().key.eUp.Org,Sweep.debugEvent(e),Sweep.doneEdgeDict(e),Sweep.donePriorityQ(e),!!Sweep.removeDegenerateFaces(e,e.mesh)&&(t&&e.mesh.check(),!0)},Sweep}(),B=function(){function Tesselator(){this.mesh=new T,this.normal=[0,0,0],this.sUnit=[0,0,0],this.tUnit=[0,0,0],this.bmin=[0,0],this.bmax=[0,0],this.windingRule=S.ODD,this.dict=null,this.pq=null,this.event=null,this.vertexIndexCounter=0,this.vertices=[],this.vertexIndices=[],this.vertexCount=0,this.elements=[],this.elementCount=0}return Tesselator.prototype.dot_=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]},Tesselator.prototype.normalize_=function(e){var t=e[0]*e[0]+e[1]*e[1]+e[2]*e[2];if(!t)throw"Zero-size vector!";t=Math.sqrt(t),e[0]/=t,e[1]/=t,e[2]/=t},Tesselator.prototype.longAxis_=function(e){var t=0;return Math.abs(e[1])>Math.abs(e[0])&&(t=1),Math.abs(e[2])>Math.abs(e[t])&&(t=2),t},Tesselator.prototype.computeNormal_=function(e){var t,n,i,s,r,o,h=[0,0,0],l=[0,0,0],c=[0,0,0],d=[0,0,0],u=[0,0,0],f=[null,null,null],p=[null,null,null],g=this.mesh.vHead;t=g.next;for(var m=0;m<3;++m)s=t.coords[m],l[m]=s,p[m]=t,h[m]=s,f[m]=t;for(t=g.next;t!==g;t=t.next)for(var y=0;y<3;++y)(s=t.coords[y])<l[y]&&(l[y]=s,p[y]=t),s>h[y]&&(h[y]=s,f[y]=t);var x=0;if(h[1]-l[1]>h[0]-l[0]&&(x=1),h[2]-l[2]>h[x]-l[x]&&(x=2),l[x]>=h[x])return e[0]=0,e[1]=0,void(e[2]=1);for(o=0,n=p[x],i=f[x],c[0]=n.coords[0]-i.coords[0],c[1]=n.coords[1]-i.coords[1],c[2]=n.coords[2]-i.coords[2],t=g.next;t!==g;t=t.next)d[0]=t.coords[0]-i.coords[0],d[1]=t.coords[1]-i.coords[1],d[2]=t.coords[2]-i.coords[2],u[0]=c[1]*d[2]-c[2]*d[1],u[1]=c[2]*d[0]-c[0]*d[2],u[2]=c[0]*d[1]-c[1]*d[0],(r=u[0]*u[0]+u[1]*u[1]+u[2]*u[2])>o&&(o=r,e[0]=u[0],e[1]=u[1],e[2]=u[2]);o<=0&&(e[0]=e[1]=e[2]=0,e[this.longAxis_(c)]=1)},Tesselator.prototype.checkOrientation_=function(){for(var e,t,n=this.mesh.fHead,i=this.mesh.vHead,s=0,r=n.next;r!==n;r=r.next)if(!((t=r.anEdge).winding<=0))do{s+=(t.Org.s-t.Dst.s)*(t.Org.t+t.Dst.t),t=t.Lnext}while(t!==r.anEdge);if(s<0){for(e=i.next;e!==i;e=e.next)e.t=-e.t;this.tUnit[0]=-this.tUnit[0],this.tUnit[1]=-this.tUnit[1],this.tUnit[2]=-this.tUnit[2]}},Tesselator.prototype.projectPolygon_=function(){var e,t,n=this.mesh.vHead,i=[0,0,0],s=!1;i[0]=this.normal[0],i[1]=this.normal[1],i[2]=this.normal[2],i[0]||i[1]||i[2]||(this.computeNormal_(i),s=!0),e=this.sUnit,t=this.tUnit;var r=this.longAxis_(i);e[r]=0,e[(r+1)%3]=1,e[(r+2)%3]=0,t[r]=0,t[(r+1)%3]=0,t[(r+2)%3]=i[r]>0?1:-1;for(var o=n.next;o!==n;o=o.next)o.s=this.dot_(o.coords,e),o.t=this.dot_(o.coords,t);s&&this.checkOrientation_();for(var h=!0,l=n.next;l!==n;l=l.next)h?(this.bmin[0]=this.bmax[0]=l.s,this.bmin[1]=this.bmax[1]=l.t,h=!1):(l.s<this.bmin[0]&&(this.bmin[0]=l.s),l.s>this.bmax[0]&&(this.bmax[0]=l.s),l.t<this.bmin[1]&&(this.bmin[1]=l.t),l.t>this.bmax[1]&&(this.bmax[1]=l.t))},Tesselator.prototype.addWinding_=function(e,t){e.winding+=t.winding,e.Sym.winding+=t.Sym.winding},Tesselator.prototype.tessellateMonoRegion_=function(e,t){var n,i;if((n=t.anEdge).Lnext===n||n.Lnext.Lnext===n)throw"Mono region invalid";for(;L.vertLeq(n.Dst,n.Org);n=n.Lprev);for(;L.vertLeq(n.Org,n.Dst);n=n.Lnext);i=n.Lprev;for(;n.Lnext!==i;)if(L.vertLeq(n.Dst,i.Org)){for(;i.Lnext!==n&&(L.edgeGoesLeft(i.Lnext)||L.edgeSign(i.Org,i.Dst,i.Lnext.Dst)<=0);)i=e.connect(i.Lnext,i).Sym;i=i.Lprev}else{for(;i.Lnext!==n&&(L.edgeGoesRight(n.Lprev)||L.edgeSign(n.Dst,n.Org,n.Lprev.Org)>=0);)n=e.connect(n,n.Lprev).Sym;n=n.Lnext}if(i.Lnext===n)throw"Mono region invalid";for(;i.Lnext.Lnext!==n;)i=e.connect(i.Lnext,i).Sym;return!0},Tesselator.prototype.tessellateInterior_=function(e){for(var t,n=e.fHead.next;n!==e.fHead;n=t)if(t=n.next,n.inside&&!this.tessellateMonoRegion_(e,n))return!1;return!0},Tesselator.prototype.discardExterior_=function(e){for(var t,n=e.fHead.next;n!==e.fHead;n=t)t=n.next,n.inside||e.zapFace(n)},Tesselator.prototype.setWindingNumber_=function(e,t,n){for(var i,s=e.eHead.next;s!==e.eHead;s=i)i=s.next,s.Rface.inside!==s.Lface.inside?s.winding=s.Lface.inside?t:-t:n?e.delete(s):s.winding=0},Tesselator.prototype.getNeighbourFace_=function(e){return e.Rface&&e.Rface.inside?e.Rface.n:-1},Tesselator.prototype.outputPolymesh_=function(e,t,n,i){var s,r,o=0,h=0;n>3&&e.mergeConvexFaces(n);for(var l=e.vHead.next;l!==e.vHead;l=l.next)l.n=-1;for(var c=e.fHead.next;c!==e.fHead;c=c.next)if(c.n=-1,c.inside){s=c.anEdge,r=0;do{-1===(l=s.Org).n&&(l.n=h,h++),r++,s=s.Lnext}while(s!==c.anEdge);if(r>n)throw"Face vertex greater that support polygon";c.n=o,++o}this.elementCount=o,t===E.CONNECTED_POLYGONS&&(o*=2),this.elements=[],this.elements.length=o*n,this.vertexCount=h,this.vertices=[],this.vertices.length=h*i,this.vertexIndices=[],this.vertexIndices.length=h;for(l=e.vHead.next;l!==e.vHead;l=l.next)if(-1!==l.n){var d=l.n*i;this.vertices[d+0]=l.coords[0],this.vertices[d+1]=l.coords[1],i>2&&(this.vertices[d+2]=l.coords[2]),this.vertexIndices[l.n]=l.idx}var u=0;for(c=e.fHead.next;c!==e.fHead;c=c.next)if(c.inside){s=c.anEdge,r=0;do{l=s.Org;this.elements[u++]=l.n,r++,s=s.Lnext}while(s!==c.anEdge);for(var f=r;f<n;++f)this.elements[u++]=-1;if(t===E.CONNECTED_POLYGONS){s=c.anEdge;do{this.elements[u++]=this.getNeighbourFace_(s),s=s.Lnext}while(s!==c.anEdge);for(var p=r;p<n;++p)this.elements[u++]=-1}}},Tesselator.prototype.outputContours_=function(e,t){var n,i,s=0,r=0;this.vertexCount=0,this.elementCount=0;for(var o=e.fHead.next;o!==e.fHead;o=o.next)if(o.inside){i=n=o.anEdge;do{this.vertexCount++,n=n.Lnext}while(n!==i);this.elementCount++}this.elements=[],this.elements.length=2*this.elementCount,this.vertices=[],this.vertices.length=this.vertexCount*t,this.vertexIndices=[],this.vertexIndices.length=this.vertexCount;var h=0,l=0,c=0;s=0;for(o=e.fHead.next;o!==e.fHead;o=o.next)if(o.inside){r=0,i=n=o.anEdge;do{this.vertices[h++]=n.Org.coords[0],this.vertices[h++]=n.Org.coords[1],t>2&&(this.vertices[h++]=n.Org.coords[2]),this.vertexIndices[l++]=n.Org.idx,r++,n=n.Lnext}while(n!==i);this.elements[c++]=s,this.elements[c++]=r,s+=r}},Tesselator.prototype.addContour=function(e,t){null===this.mesh&&(this.mesh=new T),e<2&&(e=2),e>3&&(e=3);for(var n=null,i=0;i<t.length;i+=e)null===n?(n=this.mesh.makeEdge(),this.mesh.splice(n,n.Sym)):(this.mesh.splitEdge(n),n=n.Lnext),n.Org.coords[0]=t[i+0],n.Org.coords[1]=t[i+1],n.Org.coords[2]=e>2?t[i+2]:0,n.Org.idx=this.vertexIndexCounter++,n.winding=1,n.Sym.winding=-1},Tesselator.prototype.tesselate=function(e,t,n,i,s,r){if(void 0===e&&(e=S.ODD),void 0===t&&(t=E.POLYGONS),void 0===r&&(r=!0),this.vertices=[],this.elements=[],this.vertexIndices=[],this.vertexIndexCounter=0,s&&(this.normal[0]=s[0],this.normal[1]=s[1],this.normal[2]=s[2]),this.windingRule=e,i<2&&(i=2),i>3&&(i=3),!this.mesh)return!1;this.projectPolygon_(),C.computeInterior(this,r);var o=this.mesh;return t===E.BOUNDARY_CONTOURS?this.setWindingNumber_(o,1,!0):this.tessellateInterior_(o),r&&o.check(),t===E.BOUNDARY_CONTOURS?this.outputContours_(o,i):this.outputPolymesh_(o,t,n,i),!0},Tesselator}();S.ODD,S.NONZERO,S.POSITIVE,S.NEGATIVE,S.ABS_GEQ_TWO,E.POLYGONS,E.CONNECTED_POLYGONS,E.BOUNDARY_CONTOURS;class Tessellator{process(e,t=!0,i=!1){if(0===e.length)return{triangles:{vertices:[],indices:[]},contours:[]};const s=e.filter(e=>e.points.length>=3);return 0===s.length?{triangles:{vertices:[],indices:[]},contours:[]}:(n.log(`Tessellator: removeOverlaps=${t}, processing ${s.length} paths`),this.tessellate(s,t,i))}tessellate(e,t,i){const s=i||t?e:e.map(e=>this.reverseWinding(e));let r=this.pathsToContours(s);if(t){n.log("Two-pass: boundary extraction then triangulation");const e=this.performTessellation(r,E.BOUNDARY_CONTOURS);if(!e)return n.warn("Tess2 returned empty result from boundary pass"),{triangles:{vertices:[],indices:[]},contours:[]};r=this.boundaryToContours(e),n.log(`Boundary pass created ${r.length} contours. Starting triangulation pass.`)}else n.log("Single-pass triangulation for "+(i?"CFF":"TTF"));const o=this.performTessellation(r,E.POLYGONS);if(!o){const e=t?"Tess2 returned empty result from triangulation pass":"Tess2 returned empty result from single-pass triangulation";return n.warn(e),{triangles:{vertices:[],indices:[]},contours:r}}return{triangles:{vertices:Array.from(o.vertices),indices:Array.from(o.elements)},contours:r}}pathsToContours(e){return e.map(e=>{const t=[];for(const n of e.points)t.push(n.x,n.y);return t})}performTessellation(e,t){const n=function(e){var t=e.windingRule,n=void 0===t?S.ODD:t,i=e.elementType,s=void 0===i?E.POLYGONS:i,r=e.polySize,o=void 0===r?3:r,h=e.vertexSize,l=void 0===h?2:h,c=e.normal,d=void 0===c?[0,0,1]:c,u=e.contours,f=void 0===u?[]:u,p=e.strict,g=void 0===p||p,m=e.debug,y=void 0!==m&&m;if(!f&&g)throw new Error("Contours can't be empty");if(f){for(var x=new B,_=0;_<f.length;_++)x.addContour(l||2,f[_]);return x.tesselate(n,s,o,l,d,g),{vertices:x.vertices,vertexIndices:x.vertexIndices,vertexCount:x.vertexCount,elements:x.elements,elementCount:x.elementCount,mesh:y?x.mesh:void 0}}}({contours:e,windingRule:S.NONZERO,elementType:t,polySize:3,vertexSize:2,strict:!1});return n?.vertices&&n?.elements?n:null}boundaryToContours(e){const t=[];for(let n=0;n<e.elements.length;n+=2){const i=e.elements[n],s=e.elements[n+1],r=[];for(let t=0;t<s;t++){const n=2*(i+t);r.push(e.vertices[n],e.vertices[n+1])}r.length>2&&(r[0]===r[r.length-2]&&r[1]===r[r.length-1]||r.push(r[0],r[1])),t.push(r)}return t}reverseWinding(e){return{...e,points:[...e.points].reverse()}}}class Extruder{constructor(){}extrude(e,t=0,n){const i=[],s=[],r=[];if(0===t)this.addFlatFaces(e.triangles,i,s,r);else{this.addFrontAndBackFaces(e.triangles,i,s,r,t,n);for(const n of e.contours)this.addSideWalls(n,i,s,r,t)}return{vertices:i,normals:s,indices:r}}addFlatFaces(e,t,n,i){const s=t.length/3,r=e.vertices,o=e.indices;for(let e=0;e<r.length;e+=2)t.push(r[e],r[e+1],0),n.push(0,0,-1);for(let e=0;e<o.length;e++)i.push(s+o[e])}addFrontAndBackFaces(e,t,n,i,s,r){const o=t.length/3,h=e.vertices,l=e.indices;for(let e=0;e<h.length;e+=2)t.push(h[e],h[e+1],0),n.push(0,0,-1);const c=25e-6*r,d=s<=c?c:s;for(let e=0;e<h.length;e+=2)t.push(h[e],h[e+1],d),n.push(0,0,1);const u=h.length/2;for(let e=0;e<l.length;e++)i.push(o+l[e]);for(let e=l.length-1;e>=0;e--)i.push(o+l[e]+u)}addSideWalls(e,t,n,i,s){for(let r=0;r<e.length-2;r+=2){const o=e[r],h=e[r+1],l=e[r+2],c=e[r+3],d=new Vec2(l-o,c-h),u=new Vec2(d.y,-d.x).normalize(),f=t.length/3;t.push(o,h,0,l,c,0,o,h,s,l,c,s),n.push(u.x,u.y,0,u.x,u.y,0,u.x,u.y,0,u.x,u.y,0),i.push(f,f+1,f+2,f+1,f+3,f+2)}}}class BoundaryClusterer{constructor(){}cluster(e,t){return 0===e.length?[]:this.clusterSweepLine(e,t)}clusterSweepLine(e,t){const n=e.length;if(n<=1)return 0===n?[]:[[0]];const i=new Array(n),s=new Array(2*n);let r=0;for(let o=0;o<n;o++)i[o]=this.getWorldBounds(e[o],t[o]),s[r++]=[i[o].minX,0,o],s[r++]=[i[o].maxX,1,o];s.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);const o=Array.from({length:n},(e,t)=>t),h=new Array(n).fill(0);function find(e){return o[e]===e?e:o[e]=find(o[e])}function union(e,t){const n=find(e),i=find(t);n!==i&&(h[n]<h[i]?o[n]=i:h[n]>h[i]?o[i]=n:(o[i]=n,h[n]++))}const l=new Set;for(const[,e,t]of s)if(0===e){const e=i[t];for(const n of l){const s=i[n];e.minY<s.maxY+.001&&e.maxY>s.minY-.001&&union(t,n)}l.add(t)}else l.delete(t);const c=new Map;for(let e=0;e<n;e++){const t=find(e);c.has(t)||c.set(t,[]),c.get(t).push(e)}return Array.from(c.values())}getWorldBounds(e,t){return{minX:e.bounds.min.x+t.x,minY:e.bounds.min.y+t.y,maxX:e.bounds.max.x+t.x,maxY:e.bounds.max.y+t.y}}}class MinHeap{constructor(e){this.heap=[],this.itemIndex=new Map,this.compare=e}insert(e){const t=this.itemIndex.get(e);if(void 0!==t)return this.siftUp(t),void this.siftDown(t);const n=this.heap.length;this.heap.push(e),this.itemIndex.set(e,n),this.siftUp(n)}extractMin(){const e=this.heap.length;if(!e)return;if(1===e){const e=this.heap.pop();return this.itemIndex.clear(),e}const t=this.heap[0],n=this.heap.pop();return this.heap[0]=n,this.itemIndex.delete(t),this.itemIndex.set(n,0),this.siftDown(0),t}update(e){const t=this.itemIndex.get(e);void 0!==t?(this.siftUp(t),this.siftDown(t)):this.insert(e)}isEmpty(){return!this.heap.length}swap(e,t){const n=this.heap[e],i=this.heap[t];this.heap[e]=i,this.heap[t]=n,this.itemIndex.set(n,t),this.itemIndex.set(i,e)}siftUp(e){const t=this.heap[e];for(;e>0;){const n=e-1>>1,i=this.heap[n];if(this.compare(t,i)>=0)break;this.heap[e]=i,this.itemIndex.set(i,e),e=n}this.heap[e]=t,this.itemIndex.set(t,e)}siftDown(e){const t=this.heap[e],n=this.heap.length,i=n>>1;for(;e<i;){const i=1+(e<<1),s=i+1;let r=e,o=t;const h=this.heap[i];if(this.compare(h,o)<0&&(r=i,o=h),s<n){const e=this.heap[s];this.compare(e,o)<0&&(r=s,o=e)}if(r===e)break;this.heap[e]=o,this.itemIndex.set(o,e),e=r}this.heap[e]=t,this.itemIndex.set(t,e)}}const I={enabled:!0,areaThreshold:1,colinearThreshold:.0087,minSegmentLength:10};class PathOptimizer{constructor(e){this.stats={pointsRemovedByVisvalingam:0,pointsRemovedByColinear:0,originalPointCount:0},this.config=e}setConfig(e){this.config=e}optimizePath(e){if(!this.config.enabled||e.points.length<=2)return e;this.stats.originalPointCount+=e.points.length;let t=[...e.points];return t.length<5?e:(t=this.simplifyPathVW(t,this.config.areaThreshold),t.length<3?e:(t=this.removeColinearPoints(t,this.config.colinearThreshold),t.length<3?e:{...e,points:t}))}simplifyPathVW(e,t){if(e.length<=3)return e;const n=e.length,i=e.map((e,t)=>({index:t,area:1/0,prev:null,next:null}));for(let e=0;e<i.length;e++)i[e].prev=i[e-1]||null,i[e].next=i[e+1]||null;const s=new MinHeap((e,t)=>e.area-t.area);for(let t=1;t<i.length-1;t++){const n=i[t];n.area=this.calculateTriangleArea(e[n.prev.index],e[n.index],e[n.next.index]),s.insert(n)}let r=n;for(;!s.isEmpty()&&r>3;){const n=s.extractMin();if(!n||n.area>t)break;if(this.config.minSegmentLength>0&&n.prev&&n.next){const t=e[n.prev.index],i=e[n.index],s=e[n.next.index],r=t.distanceTo(i),o=i.distanceTo(s);if(r<this.config.minSegmentLength||o<this.config.minSegmentLength)continue}n.prev&&(n.prev.next=n.next),n.next&&(n.next.prev=n.prev),r--,n.prev&&n.prev.prev&&(n.prev.area=this.calculateTriangleArea(e[n.prev.prev.index],e[n.prev.index],e[n.next.index]),s.update(n.prev)),n.next&&n.next.next&&(n.next.area=this.calculateTriangleArea(e[n.prev.index],e[n.next.index],e[n.next.next.index]),s.update(n.next))}const o=[];let h=i[0];for(;h;)o.push(e[h.index]),h=h.next;const l=n-o.length;return this.stats.pointsRemovedByVisvalingam+=l,o}removeColinearPoints(e,t){if(e.length<=2)return e;const n=[e[0]];for(let i=1;i<e.length-1;i++){const s=e[i-1],r=e[i],o=e[i+1],h=new Vec2(r.x-s.x,r.y-s.y),l=new Vec2(o.x-r.x,o.y-r.y),c=Math.abs(h.angle()-l.angle());Math.min(c,2*Math.PI-c)>t||h.length()<this.config.minSegmentLength||l.length()<this.config.minSegmentLength?n.push(r):this.stats.pointsRemovedByColinear++}return n.push(e[e.length-1]),n}calculateTriangleArea(e,t,n){return Math.abs((e.x*(t.y-n.y)+t.x*(n.y-e.y)+n.x*(e.y-t.y))/2)}getStats(){return{...this.stats}}resetStats(){this.stats={pointsRemovedByVisvalingam:0,pointsRemovedByColinear:0,originalPointCount:0}}}const A={distanceTolerance:.5,angleTolerance:.2},U=1e-6;class Polygonizer{constructor(e){this.curveFidelityConfig={...A,...e}}setCurveFidelityConfig(e){this.curveFidelityConfig={...A,...e}}polygonizeQuadratic(e,t,n){const i=[];return this.recursiveQuadratic(e.x,e.y,t.x,t.y,n.x,n.y,i),this.addPoint(n.x,n.y,i),i}polygonizeCubic(e,t,n,i){const s=[];return this.recursiveCubic(e.x,e.y,t.x,t.y,n.x,n.y,i.x,i.y,s),this.addPoint(i.x,i.y,s),s}recursiveQuadratic(e,t,n,i,s,r,o,h=0){if(h>16)return;const l=(e+n)/2,c=(t+i)/2,d=(n+s)/2,u=(i+r)/2,f=(l+d)/2,p=(c+u)/2,g=s-e,m=r-t,y=Math.abs((n-s)*m-(i-r)*g),x=this.curveFidelityConfig.distanceTolerance??A.distanceTolerance,_=x*x;if(y>U){if(y*y<=_*(g*g+m*m)){const h=this.curveFidelityConfig.angleTolerance??A.angleTolerance;if(!(h>0))return void this.addPoint(n,i,o);{let l=Math.abs(Math.atan2(r-i,s-n)-Math.atan2(i-t,n-e));if(l>=Math.PI&&(l=2*Math.PI-l),l<h)return void this.addPoint(n,i,o)}}}else{const s=g*g+m*m;if(0===s){if((n-e)*(n-e)+(i-t)*(i-t)<=_)return void this.addPoint(n,i,o)}else{const r=((n-e)*g+(i-t)*m)/s;if(r>0&&r<1&&y*y<=_*s)return void this.addPoint(n,i,o)}}this.recursiveQuadratic(e,t,l,c,f,p,o,h+1),this.recursiveQuadratic(f,p,d,u,s,r,o,h+1)}recursiveCubic(e,t,n,i,s,r,o,h,l,c=0){if(c>16)return;const d=(e+n)/2,u=(t+i)/2,f=(n+s)/2,p=(i+r)/2,g=(s+o)/2,m=(r+h)/2,y=(d+f)/2,x=(u+p)/2,_=(f+g)/2,v=(p+m)/2,w=(y+_)/2,b=(x+v)/2,S=o-e,E=h-t,L=Math.abs((n-o)*E-(i-h)*S),O=Math.abs((s-o)*E-(r-h)*S),T=this.curveFidelityConfig.distanceTolerance??A.distanceTolerance,P=T*T;let F=0;switch(L>U&&(F|=1),O>U&&(F|=2),F){case 0:const c=S*S+E*E;if(0===c){if((n-e)*(n-e)+(i-t)*(i-t)<=P&&(s-e)*(s-e)+(r-t)*(r-t)<=P)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}else{const o=((n-e)*S+(i-t)*E)/c,h=((s-e)*S+(r-t)*E)/c;if(o>0&&o<1&&h>0&&h<1&&(L+O)*(L+O)<=P*c)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}break;case 1:if(O*O<=P*(S*S+E*E)){const e=this.curveFidelityConfig.angleTolerance??A.angleTolerance;if(!(e>0))return this.addPoint(n,i,l),void this.addPoint(s,r,l);{let t=Math.abs(Math.atan2(h-r,o-s)-Math.atan2(r-i,s-n));if(t>=Math.PI&&(t=2*Math.PI-t),t<e)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}}break;case 2:if(L*L<=P*(S*S+E*E)){const o=this.curveFidelityConfig.angleTolerance??A.angleTolerance;if(!(o>0))return this.addPoint(n,i,l),void this.addPoint(s,r,l);{let h=Math.abs(Math.atan2(r-i,s-n)-Math.atan2(i-t,n-e));if(h>=Math.PI&&(h=2*Math.PI-h),h<o)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}}break;case 3:if((L+O)*(L+O)<=P*(S*S+E*E)){const c=this.curveFidelityConfig.angleTolerance??A.angleTolerance;if(!(c>0))return this.addPoint(n,i,l),void this.addPoint(s,r,l);{let d=Math.abs(Math.atan2(r-i,s-n)-Math.atan2(i-t,n-e)),u=Math.abs(Math.atan2(h-r,o-s)-Math.atan2(r-i,s-n));if(d>=Math.PI&&(d=2*Math.PI-d),u>=Math.PI&&(u=2*Math.PI-u),d+u<c)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}}}this.recursiveCubic(e,t,d,u,y,x,w,b,l,c+1),this.recursiveCubic(w,b,_,v,g,m,o,h,l,c+1)}addPoint(e,t,n){const i=new Vec2(e,t);if(0===n.length)return void n.push(i);const s=n[n.length-1],r=i.x-s.x,o=i.y-s.y;r*r+o*o>1e-12&&n.push(i)}}class GlyphContourCollector{constructor(e,t){this.currentGlyphId=0,this.currentTextIndex=0,this.currentGlyphPaths=[],this.currentPath=null,this.currentPoint=null,this.currentGlyphBounds={min:new Vec2(1/0,1/0),max:new Vec2(-1/0,-1/0)},this.collectedGlyphs=[],this.glyphPositions=[],this.glyphTextIndices=[],this.currentPosition=new Vec2(0,0),this.polygonizer=new Polygonizer(e),this.pathOptimizer=new PathOptimizer({...I,...t})}setPosition(e,t){this.currentPosition.set(e,t)}updatePosition(e,t){this.currentPosition.x+=e,this.currentPosition.y+=t}beginGlyph(e,t){this.currentGlyphPaths.length>0&&this.finishGlyph(),this.currentGlyphId=e,this.currentTextIndex=t,this.currentGlyphPaths=[],this.currentGlyphBounds.min.set(1/0,1/0),this.currentGlyphBounds.max.set(-1/0,-1/0),this.glyphPositions.push(this.currentPosition.clone())}finishGlyph(){this.currentPath&&this.finishPath(),this.currentGlyphPaths.length>0&&(this.collectedGlyphs.push({glyphId:this.currentGlyphId,paths:[...this.currentGlyphPaths],bounds:{min:{x:this.currentGlyphBounds.min.x,y:this.currentGlyphBounds.min.y},max:{x:this.currentGlyphBounds.max.x,y:this.currentGlyphBounds.max.y}}}),this.glyphTextIndices.push(this.currentTextIndex)),this.currentGlyphPaths=[]}onMoveTo(e,t){this.currentPath&&this.finishPath(),this.currentPoint=new Vec2(e,t),this.updateBounds(this.currentPoint),this.currentPath={points:[this.currentPoint],glyphIndex:this.currentGlyphId}}onLineTo(e,t){if(!this.currentPath||!this.currentPoint)return;const n=new Vec2(e,t);this.updateBounds(n),this.currentPath.points.push(n),this.currentPoint=n}onQuadTo(e,t,n,i){if(!this.currentPath||!this.currentPoint)return;const s=this.currentPoint,r=new Vec2(e,t),o=new Vec2(n,i),h=o.x-s.x,l=o.y-s.y;if(Math.abs((r.x-o.x)*l-(r.y-o.y)*h)<U)return void this.onLineTo(n,i);const c=this.polygonizer.polygonizeQuadratic(s,r,o);for(const e of c)this.updateBounds(e);for(let e=0;e<c.length;e++)this.currentPath.points.push(c[e]);this.currentPoint=o}onCubicTo(e,t,n,i,s,r){if(!this.currentPath||!this.currentPoint)return;const o=this.currentPoint,h=new Vec2(e,t),l=new Vec2(n,i),c=new Vec2(s,r),d=c.x-o.x,u=c.y-o.y,f=Math.abs((h.x-c.x)*u-(h.y-c.y)*d),p=Math.abs((l.x-c.x)*u-(l.y-c.y)*d);if(f<U&&p<U)return void this.onLineTo(s,r);const g=this.polygonizer.polygonizeCubic(o,h,l,c);for(const e of g)this.updateBounds(e);for(let e=0;e<g.length;e++)this.currentPath.points.push(g[e]);this.currentPoint=c}onClosePath(){if(!this.currentPath||!this.currentPoint)return;const e=this.currentPath.points[0];this.currentPoint.equals(e)||this.currentPath.points.push(e),this.finishPath()}finishPath(){if(this.currentPath){const e=this.pathOptimizer.optimizePath(this.currentPath);this.currentGlyphPaths.push(e),this.currentPath=null,this.currentPoint=null}}updateBounds(e){this.currentGlyphBounds.min.x=Math.min(this.currentGlyphBounds.min.x,e.x),this.currentGlyphBounds.min.y=Math.min(this.currentGlyphBounds.min.y,e.y),this.currentGlyphBounds.max.x=Math.max(this.currentGlyphBounds.max.x,e.x),this.currentGlyphBounds.max.y=Math.max(this.currentGlyphBounds.max.y,e.y)}getCollectedGlyphs(){return this.currentGlyphPaths.length>0&&this.finishGlyph(),this.collectedGlyphs}getGlyphPositions(){return this.glyphPositions}getTextIndices(){return this.glyphTextIndices}reset(){this.collectedGlyphs=[],this.glyphPositions=[],this.glyphTextIndices=[],this.currentGlyphPaths=[],this.currentPath=null,this.currentPoint=null,this.currentGlyphId=0,this.currentTextIndex=0,this.currentPosition.set(0,0),this.currentGlyphBounds={min:new Vec2(1/0,1/0),max:new Vec2(-1/0,-1/0)}}setCurveFidelityConfig(e){this.polygonizer.setCurveFidelityConfig(e)}setGeometryOptimization(e){this.pathOptimizer.setConfig({...I,...e})}getOptimizationStats(){return this.pathOptimizer.getStats()}}class DrawCallbackHandler{constructor(){this.moveTo_func=null,this.lineTo_func=null,this.quadTo_func=null,this.cubicTo_func=null,this.closePath_func=null,this.drawFuncsPtr=0,this.position={x:0,y:0}}setPosition(e,t){this.position.x=e,this.position.y=t,this.collector&&this.collector.setPosition(e,t)}updatePosition(e,t){this.position.x+=e,this.position.y+=t,this.collector&&this.collector.updatePosition(e,t)}createDrawFuncs(e,t){if(!e||!e.module||!e.hb)throw new Error("Invalid font object");if(this.collector=t,this.drawFuncsPtr)return;const n=e.module;this.moveTo_func=n.addFunction((e,t,n,i,s)=>{this.collector?.onMoveTo(i,s)},"viiiffi"),this.lineTo_func=n.addFunction((e,t,n,i,s)=>{this.collector?.onLineTo(i,s)},"viiiffi"),this.quadTo_func=n.addFunction((e,t,n,i,s,r,o)=>{this.collector?.onQuadTo(i,s,r,o)},"viiiffffi"),this.cubicTo_func=n.addFunction((e,t,n,i,s,r,o,h,l)=>{this.collector?.onCubicTo(i,s,r,o,h,l)},"viiiffffffi"),this.closePath_func=n.addFunction((e,t,n)=>{this.collector?.onClosePath()},"viiii"),this.drawFuncsPtr=n.exports.hb_draw_funcs_create(),n.exports.hb_draw_funcs_set_move_to_func(this.drawFuncsPtr,this.moveTo_func,0,0),n.exports.hb_draw_funcs_set_line_to_func(this.drawFuncsPtr,this.lineTo_func,0,0),n.exports.hb_draw_funcs_set_quadratic_to_func(this.drawFuncsPtr,this.quadTo_func,0,0),n.exports.hb_draw_funcs_set_cubic_to_func(this.drawFuncsPtr,this.cubicTo_func,0,0),n.exports.hb_draw_funcs_set_close_path_func(this.drawFuncsPtr,this.closePath_func,0,0)}getDrawFuncsPtr(){if(!this.drawFuncsPtr)throw new Error("Draw functions not initialized");return this.drawFuncsPtr}destroy(e){if(!e||!e.module||!e.hb)return;const t=e.module;try{this.drawFuncsPtr&&(t.exports.hb_draw_funcs_destroy(this.drawFuncsPtr),this.drawFuncsPtr=0),null!==this.moveTo_func&&(t.removeFunction(this.moveTo_func),this.moveTo_func=null),null!==this.lineTo_func&&(t.removeFunction(this.lineTo_func),this.lineTo_func=null),null!==this.quadTo_func&&(t.removeFunction(this.quadTo_func),this.quadTo_func=null),null!==this.cubicTo_func&&(t.removeFunction(this.cubicTo_func),this.cubicTo_func=null),null!==this.closePath_func&&(t.removeFunction(this.closePath_func),this.closePath_func=null)}catch(e){n.warn("Error destroying draw callbacks:",e)}this.collector=void 0}}class GlyphGeometryBuilder{constructor(e,t){this.fontId="default",this.wordCache=new Map,this.cache=e,this.loadedFont=t,this.tessellator=new Tessellator,this.extruder=new Extruder,this.clusterer=new BoundaryClusterer,this.collector=new GlyphContourCollector,this.drawCallbacks=new DrawCallbackHandler,this.drawCallbacks.createDrawFuncs(this.loadedFont,this.collector)}getOptimizationStats(){return this.collector.getOptimizationStats()}setCurveFidelityConfig(e){this.collector.setCurveFidelityConfig(e)}setGeometryOptimization(e){this.collector.setGeometryOptimization(e)}setFontId(e){this.fontId=e}buildInstancedGeometry(e,t,n,s,r=!1){i.start("GlyphGeometryBuilder.buildInstancedGeometry",{lineCount:e.length,wordCount:e.flat().length,depth:t,removeOverlaps:n});const o=[],h=[],l=[],c=[],d={min:{x:1/0,y:1/0,z:0},max:{x:-1/0,y:-1/0,z:t}};for(let i=0;i<e.length;i++){const u=e[i];for(const e of u){const i=[];for(const t of e.glyphs)i.push(this.getContoursForGlyph(t.g));const u=e.glyphs.map(e=>new Vec3(e.x,e.y,0)),f=this.clusterer.cluster(i,u);if(!r&&f.some(e=>e.length>1)){const r=`${this.fontId}_${e.text}_${t}_${n}`;let u=this.wordCache.get(r);if(!u){const n=[];for(let t=0;t<i.length;t++){const s=i[t],r=e.glyphs[t];for(const e of s.paths)n.push({...e,points:e.points.map(e=>new Vec2(e.x+(r.x??0),e.y+(r.y??0)))})}u=this.tessellateGlyphCluster(n,t,s),this.wordCache.set(r,u)}const f=o.length/3;this.appendGeometry(o,h,l,u,e.position,f);const p=u.vertices.length/3;for(let n=0;n<e.glyphs.length;n++){const s=e.glyphs[n],r=i[n],o=new Vec3(e.position.x+(s.x??0),e.position.y+(s.y??0),e.position.z),h=this.createGlyphInfo(s,f,p,o,r,t);c.push(h),this.updatePlaneBounds(h.bounds,d)}}else for(let r=0;r<e.glyphs.length;r++){const u=e.glyphs[r],f=i[r],p=new Vec3(e.position.x+(u.x??0),e.position.y+(u.y??0),e.position.z);if(0===f.paths.length){const e=this.createGlyphInfo(u,0,0,p,f,t);c.push(e);continue}let g=this.cache.get(this.fontId,u.g,t,n);g||(g=this.tessellateGlyph(f,t,n,s),this.cache.set(this.fontId,u.g,t,n,g));const m=o.length/3;this.appendGeometry(o,h,l,g,p,m);const y=this.createGlyphInfo(u,m,g.vertices.length/3,p,f,t);c.push(y),this.updatePlaneBounds(y.bounds,d)}}}const u=new Float32Array(o),f=new Float32Array(h),p=new Uint32Array(l);return i.end("GlyphGeometryBuilder.buildInstancedGeometry"),{vertices:u,normals:f,indices:p,glyphInfos:c,planeBounds:d}}appendGeometry(e,t,n,i,s,r){for(let t=0;t<i.vertices.length;t+=3)e.push(i.vertices[t]+s.x,i.vertices[t+1]+s.y,i.vertices[t+2]+s.z);for(let e=0;e<i.normals.length;e++)t.push(i.normals[e]);for(let e=0;e<i.indices.length;e++)n.push(i.indices[e]+r)}createGlyphInfo(e,t,n,i,s,r){return{textIndex:e.absoluteTextIndex,lineIndex:e.lineIndex,vertexStart:t,vertexCount:n,bounds:{min:{x:s.bounds.min.x+i.x,y:s.bounds.min.y+i.y,z:i.z},max:{x:s.bounds.max.x+i.x,y:s.bounds.max.y+i.y,z:i.z+r}}}}getContoursForGlyph(e){this.collector.reset(),this.collector.beginGlyph(e,0),this.loadedFont.module.exports.hb_font_draw_glyph(this.loadedFont.font.ptr,e,this.drawCallbacks.getDrawFuncsPtr(),0),this.collector.finishGlyph();const t=this.collector.getCollectedGlyphs()[0];return t||{glyphId:e,paths:[],bounds:{min:{x:0,y:0},max:{x:0,y:0}}}}tessellateGlyphCluster(e,t,n){const i=this.tessellator.process(e,!0,n);return this.extrudeAndPackage(i,t)}extrudeAndPackage(e,t){const n=this.extruder.extrude(e,t,this.loadedFont.upem),i=n.vertices;let s=1/0,r=1/0,o=1/0,h=-1/0,l=-1/0,c=-1/0;for(let e=0;e<i.length;e+=3){const t=i[e],n=i[e+1],d=i[e+2];t<s&&(s=t),t>h&&(h=t),n<r&&(r=n),n>l&&(l=n),d<o&&(o=d),d>c&&(c=d)}const d=new Vec3(s,r,o),u=new Vec3(h,l,c),f=n.vertices.length/3<65536?Uint16Array:Uint32Array;return{geometry:e,vertices:new Float32Array(n.vertices),normals:new Float32Array(n.normals),indices:new f(n.indices),bounds:{min:d,max:u},useCount:1}}tessellateGlyph(e,t,n,s){i.start("GlyphGeometryBuilder.tessellateGlyph",{glyphId:e.glyphId,pathCount:e.paths.length});const r=this.tessellator.process(e.paths,n,s);return this.extrudeAndPackage(r,t)}updatePlaneBounds(e,t){const n=new Box3(new Vec3(t.min.x,t.min.y,t.min.z),new Vec3(t.max.x,t.max.y,t.max.z)),i=new Box3(new Vec3(e.min.x,e.min.y,e.min.z),new Vec3(e.max.x,e.max.y,e.max.z));n.union(i),t.min.x=n.min.x,t.min.y=n.min.y,t.min.z=n.min.z,t.max.x=n.max.x,t.max.y=n.max.y,t.max.z=n.max.z}getCacheStats(){return this.cache.getStats()}clearCache(){this.cache.clear(),this.wordCache.clear()}}class TextShaper{constructor(e,t){this.cachedSpaceWidth=new Map,this.loadedFont=e,this.geometryBuilder=t}shapeLines(e,t,n,s,r,o,h){i.start("TextShaper.shapeLines",{lineCount:e.length});const l=new Set;if(o&&"object"==typeof o&&"byText"in o&&o.byText&&h)for(const e of Object.keys(o.byText)){let t=0;for(;-1!==(t=h.indexOf(e,t));)l.add(t),l.add(t+e.length),t+=e.length}const c=[];return e.forEach((e,i)=>{const o=this.shapeLineIntoClusters(e,i,t,n,s,r,l);c.push(o)}),c}shapeLineIntoClusters(e,t,n,i,s,r,o){const h=this.loadedFont.hb.createBuffer();"rtl"===r&&h.setDirection("rtl"),h.addText(e.text),h.guessSegmentProperties(),this.loadedFont.hb.shape(this.loadedFont.font,h);const l=h.json(this.loadedFont.font);h.destroy();const c=[];let d=[],u="",f=new Vec3,p=new Vec3(e.xOffset,-t*n,0);const g=i*this.loadedFont.upem,m=this.calculateSpaceAdjustment(e,s,i);for(let n=0;n<l.length;n++){const i=l[n],s=/\s/.test(e.text[i.cl]);e.endedWithHyphen&&i.cl===e.text.length-1&&"-"===e.text[i.cl]?i.absoluteTextIndex=e.originalEnd:i.absoluteTextIndex=e.originalStart+i.cl,i.lineIndex=t;const r=o.has(i.absoluteTextIndex);(s||r)&&d.length>0&&(c.push({text:u,glyphs:d,position:f.clone()}),d=[],u="");const h=p.clone().add(new Vec3(i.dx,i.dy,0));s||(0===d.length&&f.copy(h),i.x=h.x-f.x,i.y=h.y-f.y,d.push(i),u+=e.text[i.cl]),p.x+=i.ax,p.y+=i.ay,0!==g&&n<l.length-1&&(p.x+=g),s&&(p.x+=m)}return d.length>0&&c.push({text:u,glyphs:d,position:f.clone()}),c}calculateSpaceAdjustment(e,t,n){let i=0;if(void 0!==e.adjustmentRatio&&"justify"===t&&!e.isLastLine){let t=this.cachedSpaceWidth.get(n);void 0===t&&(t=TextMeasurer.measureTextWidth(this.loadedFont," ",n),this.cachedSpaceWidth.set(n,t));const s=.5,r=h;e.adjustmentRatio>0?i=e.adjustmentRatio*t*s:e.adjustmentRatio<0&&(i=e.adjustmentRatio*t*r)}return i}clearCache(){this.geometryBuilder.clearCache()}getCacheStats(){return this.geometryBuilder.getCacheStats()}}class GlyphCache{constructor(e){this.cache=new Map,this.head=null,this.tail=null,this.stats={hits:0,misses:0,totalGlyphs:0,uniqueGlyphs:0,cacheSize:0,saved:0,memoryUsage:0},e&&(this.maxCacheSize=1024*e*1024)}getCacheKey(e,t,n,i){return`${e}_${t}_${Math.round(1e3*n)/1e3}_${i}`}has(e,t,n,i){const s=this.getCacheKey(e,t,n,i);return this.cache.has(s)}get(e,t,n,i){const s=this.getCacheKey(e,t,n,i),r=this.cache.get(s);return r?(this.stats.hits++,this.stats.saved++,r.data.useCount++,this.moveToHead(r),this.stats.totalGlyphs++,r.data):(this.stats.misses++,void this.stats.totalGlyphs++)}set(e,t,n,i,s){const r=this.getCacheKey(e,t,n,i),o=this.calculateMemoryUsage(s);this.maxCacheSize&&this.stats.memoryUsage+o>this.maxCacheSize&&this.evictLRU(o);const h={key:r,data:s,prev:null,next:null};this.cache.set(r,h),this.addToHead(h),this.stats.uniqueGlyphs=this.cache.size,this.stats.cacheSize++,this.stats.memoryUsage+=o}calculateMemoryUsage(e){let t=0;return t+=4*e.vertices.length,t+=4*e.normals.length,t+=e.indices.length*e.indices.BYTES_PER_ELEMENT,t+=24,t+=256,t}evictLRU(e){let t=0;for(;this.tail&&t<e;){const e=this.calculateMemoryUsage(this.tail.data),n=this.tail;this.removeTail(),this.cache.delete(n.key),this.stats.memoryUsage-=e,this.stats.cacheSize--,t+=e}}addToHead(e){this.head?(e.next=this.head,this.head.prev=e,this.head=e):this.head=this.tail=e}removeNode(e){e.prev?e.prev.next=e.next:this.head=e.next,e.next?e.next.prev=e.prev:this.tail=e.prev}removeTail(){this.tail&&this.removeNode(this.tail)}moveToHead(e){e!==this.head&&(this.removeNode(e),this.addToHead(e))}clear(){this.cache.clear(),this.head=null,this.tail=null,this.stats={hits:0,misses:0,totalGlyphs:0,uniqueGlyphs:0,cacheSize:0,saved:0,memoryUsage:0}}getStats(){const e=this.stats.totalGlyphs>0?this.stats.hits/this.stats.totalGlyphs*100:0;return this.stats.uniqueGlyphs=this.cache.size,{...this.stats,hitRate:e,memoryUsageMB:this.stats.memoryUsage/1048576}}}const R=new GlyphCache(250);function getDefaultExportFromCjs(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function getAugmentedNamespace(e){if(e.__esModule)return e;var t=e.default;if("function"==typeof t){var n=function a(){return this instanceof a?Reflect.construct(t,arguments,this.constructor):t.apply(this,arguments)};n.prototype=t.prototype}else n={};return Object.defineProperty(n,"__esModule",{value:!0}),Object.keys(e).forEach(function(t){var i=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(n,t,i.get?i:{enumerable:!0,get:function(){return e[t]}})}),n}var D={exports:{}};var z=getAugmentedNamespace({__proto__:null,default:{},readFileSync:()=>{throw new Error("fs not available in browser")}});!function(e){var t,n=(t="undefined"!=typeof document?document.currentScript?.src:void 0,async function(e={}){var n=e,i="object"==typeof window,s="undefined"!=typeof WorkerGlobalScope,r="object"==typeof process&&process.versions?.node&&"renderer"!=process.type,quit_=(e,t)=>{throw t};"undefined"!=typeof __filename?t=__filename:s&&(t=self.location.href);var o,h,l="";if(r){var c=z;l=__dirname+"/",h=e=>(e=isFileURI(e)?new URL(e):e,c.readFileSync(e)),o=async(e,t=!0)=>(e=isFileURI(e)?new URL(e):e,c.readFileSync(e,t?void 0:"utf8")),process.argv.length>1&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),quit_=(e,t)=>{throw process.exitCode=e,t}}else if(i||s){try{l=new URL(".",t).href}catch{}s&&(h=e=>{var t=new XMLHttpRequest;return t.open("GET",e,!1),t.responseType="arraybuffer",t.send(null),new Uint8Array(t.response)}),o=async e=>{if(isFileURI(e))return new Promise((t,n)=>{var i=new XMLHttpRequest;i.open("GET",e,!0),i.responseType="arraybuffer",i.onload=()=>{200==i.status||0==i.status&&i.response?t(i.response):n(i.status)},i.onerror=n,i.send(null)});var t=await fetch(e,{credentials:"same-origin"});if(t.ok)return t.arrayBuffer();throw new Error(t.status+" : "+t.url)}}console.log.bind(console);var d,u,f,p,g,m,y=console.error.bind(console),x=!1,isFileURI=e=>e.startsWith("file://"),_=!1;function updateMemoryViews(){var e=g.buffer;n.HEAP8=new Int8Array(e),n.HEAPU8=m=new Uint8Array(e),n.HEAP32=new Int32Array(e),n.HEAPU32=new Uint32Array(e),n.HEAPF32=new Float32Array(e),new BigInt64Array(e),new BigUint64Array(e)}var v,w=0,b=null;function abort(e){n.onAbort?.(e),y(e="Aborted("+e+")"),x=!0,e+=". Build with -sASSERTIONS for more info.";var t=new WebAssembly.RuntimeError(e);throw p?.(t),t}function findWasmBinary(){return e="hb.wasm",n.locateFile?n.locateFile(e,l):l+e;var e}async function getWasmBinary(e){if(!d)try{var t=await o(e);return new Uint8Array(t)}catch{}return function(e){if(e==v&&d)return new Uint8Array(d);if(h)return h(e);throw"both async and sync fetching of the wasm failed"}(e)}async function instantiateAsync(e,t,n){if(!e&&!isFileURI(t)&&!r)try{var i=fetch(t,{credentials:"same-origin"});return await WebAssembly.instantiateStreaming(i,n)}catch(e){y(`wasm streaming compile failed: ${e}`),y("falling back to ArrayBuffer instantiation")}return async function(e,t){try{var n=await getWasmBinary(e);return await WebAssembly.instantiate(n,t)}catch(e){y(`failed to asynchronously prepare wasm: ${e}`),abort(e)}}(t,n)}class ExitStatus{name="ExitStatus";constructor(e){this.message=`Program terminated with exit(${e})`,this.status=e}}var S,E,L,callRuntimeCallbacks=e=>{for(;e.length>0;)e.shift()(n)},O=[],addOnPostRun=e=>O.push(e),T=[],addOnPreRun=e=>T.push(e),P=!0,F=0,C={},handleException=e=>{if(e instanceof ExitStatus||"unwind"==e)return u;quit_(1,e)},keepRuntimeAlive=()=>P||F>0,_proc_exit=e=>{u=e,keepRuntimeAlive()||(n.onExit?.(e),x=!0),quit_(e,new ExitStatus(e))},_exit=(e,t)=>{u=e,_proc_exit(e)},callUserCallback=e=>{if(!x)try{e(),(()=>{if(!keepRuntimeAlive())try{_exit(u)}catch(e){handleException(e)}})()}catch(e){handleException(e)}},alignMemory=(e,t)=>Math.ceil(e/t)*t,growMemory=e=>{var t=(e-g.buffer.byteLength+65535)/65536|0;try{return g.grow(t),updateMemoryViews(),1}catch(e){}},uleb128EncodeWithLen=e=>{const t=e.length;return[t%128|128,t>>7,...e]},B={i:127,p:127,j:126,f:125,d:124,e:111},generateTypePack=e=>uleb128EncodeWithLen(Array.from(e,e=>B[e])),getWasmTableEntry=e=>S.get(e),getFunctionAddress=e=>(E||(E=new WeakMap,((e,t)=>{if(E)for(var n=e;n<e+t;n++){var i=getWasmTableEntry(n);i&&E.set(i,n)}})(0,S.length)),E.get(e)||0),I=[],setWasmTableEntry=(e,t)=>S.set(e,t);n.noExitRuntime&&(P=n.noExitRuntime),n.print&&n.print,n.printErr&&(y=n.printErr),n.wasmBinary&&(d=n.wasmBinary),n.arguments&&n.arguments,n.thisProgram&&n.thisProgram,n.wasmMemory=g,n.wasmExports=U,n.addFunction=(e,t)=>{var n=getFunctionAddress(e);if(n)return n;var i=I.length?I.pop():S.grow(1);try{setWasmTableEntry(i,e)}catch(n){if(!(n instanceof TypeError))throw n;var s=((e,t)=>{var n=Uint8Array.of(0,97,115,109,1,0,0,0,1,...uleb128EncodeWithLen([1,96,...generateTypePack(t.slice(1)),...generateTypePack("v"===t[0]?"":t[0])]),2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0),i=new WebAssembly.Module(n);return new WebAssembly.Instance(i,{e:{f:e}}).exports.f})(e,t);setWasmTableEntry(i,s)}return E.set(e,i),i},n.removeFunction=e=>{E.delete(getWasmTableEntry(e)),setWasmTableEntry(e,null),I.push(e)};var A={_abort_js:()=>abort(""),_emscripten_runtime_keepalive_clear:()=>{P=!1,F=0},_setitimer_js:(e,t)=>{if(C[e]&&(clearTimeout(C[e].id),delete C[e]),!t)return 0;var n=setTimeout(()=>{delete C[e],callUserCallback(()=>L(e,performance.now()))},t);return C[e]={id:n,timeout_ms:t},0},emscripten_resize_heap:e=>{var t=m.length,n=2147483648;if((e>>>=0)>n)return!1;for(var i=1;i<=4;i*=2){var s=t*(1+.2/i);s=Math.min(s,e+100663296);var r=Math.min(n,alignMemory(Math.max(e,s),65536));if(growMemory(r))return!0}return!1},proc_exit:_proc_exit},U=await async function(){function receiveInstance(e,t){return U=e.exports,n.wasmExports=U,g=U.memory,n.wasmMemory=g,updateMemoryViews(),S=U.__indirect_function_table,function(e){n._hb_blob_create=e.hb_blob_create,n._hb_blob_destroy=e.hb_blob_destroy,n._hb_blob_get_length=e.hb_blob_get_length,n._hb_blob_get_data=e.hb_blob_get_data,n._hb_buffer_serialize_glyphs=e.hb_buffer_serialize_glyphs,n._hb_buffer_create=e.hb_buffer_create,n._hb_buffer_destroy=e.hb_buffer_destroy,n._hb_buffer_get_content_type=e.hb_buffer_get_content_type,n._hb_buffer_set_direction=e.hb_buffer_set_direction,n._hb_buffer_set_script=e.hb_buffer_set_script,n._hb_buffer_set_language=e.hb_buffer_set_language,n._hb_buffer_set_flags=e.hb_buffer_set_flags,n._hb_buffer_set_cluster_level=e.hb_buffer_set_cluster_level,n._hb_buffer_get_length=e.hb_buffer_get_length,n._hb_buffer_get_glyph_infos=e.hb_buffer_get_glyph_infos,n._hb_buffer_get_glyph_positions=e.hb_buffer_get_glyph_positions,n._hb_glyph_info_get_glyph_flags=e.hb_glyph_info_get_glyph_flags,n._hb_buffer_guess_segment_properties=e.hb_buffer_guess_segment_properties,n._hb_buffer_add_utf8=e.hb_buffer_add_utf8,n._hb_buffer_add_utf16=e.hb_buffer_add_utf16,n._hb_buffer_set_message_func=e.hb_buffer_set_message_func,n._hb_language_from_string=e.hb_language_from_string,n._hb_script_from_string=e.hb_script_from_string,n._hb_version=e.hb_version,n._hb_version_string=e.hb_version_string,n._hb_feature_from_string=e.hb_feature_from_string,n._malloc=e.malloc,n._free=e.free,n._hb_draw_funcs_set_move_to_func=e.hb_draw_funcs_set_move_to_func,n._hb_draw_funcs_set_line_to_func=e.hb_draw_funcs_set_line_to_func,n._hb_draw_funcs_set_quadratic_to_func=e.hb_draw_funcs_set_quadratic_to_func,n._hb_draw_funcs_set_cubic_to_func=e.hb_draw_funcs_set_cubic_to_func,n._hb_draw_funcs_set_close_path_func=e.hb_draw_funcs_set_close_path_func,n._hb_draw_funcs_create=e.hb_draw_funcs_create,n._hb_draw_funcs_destroy=e.hb_draw_funcs_destroy,n._hb_face_create=e.hb_face_create,n._hb_face_destroy=e.hb_face_destroy,n._hb_face_reference_table=e.hb_face_reference_table,n._hb_face_get_upem=e.hb_face_get_upem,n._hb_face_collect_unicodes=e.hb_face_collect_unicodes,n._hb_font_draw_glyph=e.hb_font_draw_glyph,n._hb_font_glyph_to_string=e.hb_font_glyph_to_string,n._hb_font_create=e.hb_font_create,n._hb_font_set_variations=e.hb_font_set_variations,n._hb_font_destroy=e.hb_font_destroy,n._hb_font_set_scale=e.hb_font_set_scale,n._hb_set_create=e.hb_set_create,n._hb_set_destroy=e.hb_set_destroy,n._hb_ot_var_get_axis_infos=e.hb_ot_var_get_axis_infos,n._hb_set_get_population=e.hb_set_get_population,n._hb_set_next_many=e.hb_set_next_many,n._hb_shape=e.hb_shape,L=e._emscripten_timeout}(U),function(){if(w--,n.monitorRunDependencies?.(w),0==w&&b){var e=b;b=null,e()}}(),U}w++,n.monitorRunDependencies?.(w);var e={env:A,wasi_snapshot_preview1:A};if(n.instantiateWasm)return new Promise((t,i)=>{n.instantiateWasm(e,(e,n)=>{t(receiveInstance(e))})});v??=findWasmBinary();var t=function(e){return receiveInstance(e.instance)}(await instantiateAsync(d,v,e));return t}();return function(){if(n.preInit)for("function"==typeof n.preInit&&(n.preInit=[n.preInit]);n.preInit.length>0;)n.preInit.shift()()}(),function run(){function doRun(){n.calledRun=!0,x||(_=!0,U.__wasm_call_ctors(),f?.(n),n.onRuntimeInitialized?.(),function(){if(n.postRun)for("function"==typeof n.postRun&&(n.postRun=[n.postRun]);n.postRun.length;)addOnPostRun(n.postRun.shift());callRuntimeCallbacks(O)}())}w>0?b=run:(function(){if(n.preRun)for("function"==typeof n.preRun&&(n.preRun=[n.preRun]);n.preRun.length;)addOnPreRun(n.preRun.shift());callRuntimeCallbacks(T)}(),w>0?b=run:n.setStatus?(n.setStatus("Running..."),setTimeout(()=>{setTimeout(()=>n.setStatus(""),1),doRun()},1)):doRun())}(),_?n:new Promise((e,t)=>{f=e,p=t})});e.exports=n,e.exports.default=n}(D);var G=getDefaultExportFromCjs(D.exports),k={exports:{}};try{k.exports=function(e){var t=e.wasmExports,n=new TextDecoder("utf8");let i=e.addFunction,s=e.removeFunction;var r=i(function(e){t.free(e)},"vi");function hb_tag(e){return(255&e.charCodeAt(0))<<24|(255&e.charCodeAt(1))<<16|(255&e.charCodeAt(2))<<8|255&e.charCodeAt(3)}var o=hb_tag("JSON"),h="",l=t.malloc(256);function createAsciiString(n){var i=t.malloc(n.length+1);for(let t=0;t<n.length;++t){const s=n.charCodeAt(t);if(s>127)throw new Error("Expected ASCII text");e.HEAPU8[i+t]=s}return e.HEAPU8[i+n.length]=0,{ptr:i,length:n.length,free:function(){t.free(i)}}}function shape(e,n,i){var s=0,r=0;i&&(i=i.split(","),s=t.malloc(16*i.length),i.forEach(function(e,n){var i=createAsciiString(e);t.hb_feature_from_string(i.ptr,-1,s+16*r)&&r++,i.free()})),t.hb_shape(e.ptr,n.ptr,s,r),s&&t.free(s)}return{createBlob:function(n){var i=t.malloc(n.byteLength);e.HEAPU8.set(new Uint8Array(n),i);var s=t.hb_blob_create(i,n.byteLength,2,i,r);return{ptr:s,destroy:function(){t.hb_blob_destroy(s)}}},createFace:function(n,i){var s=t.hb_face_create(n.ptr,i);const r=t.hb_face_get_upem(s);return{ptr:s,upem:r,reference_table:function(n){var i=t.hb_face_reference_table(s,hb_tag(n)),r=t.hb_blob_get_length(i);if(r){var o=t.hb_blob_get_data(i,null);return e.HEAPU8.subarray(o,o+r)}},getAxisInfos:function(){var n=t.malloc(2048),i=t.malloc(4);e.HEAPU32[i/4]=64,t.hb_ot_var_get_axis_infos(s,0,i,n);var r={};return Array.from({length:e.HEAPU32[i/4]}).forEach(function(t,i){var s;r[(s=e.HEAPU32[n/4+8*i+1],[String.fromCharCode(s>>24&255),String.fromCharCode(s>>16&255),String.fromCharCode(s>>8&255),String.fromCharCode(255&s)].join(""))]={min:e.HEAPF32[n/4+8*i+4],default:e.HEAPF32[n/4+8*i+5],max:e.HEAPF32[n/4+8*i+6]}}),t.free(i),t.free(n),r},collectUnicodes:function(){var n=t.hb_set_create();t.hb_face_collect_unicodes(s,n);var i=function(n){const i=t.hb_set_get_population(n),s=t.malloc(i<<2),r=s>>2,o=e.HEAPU32.subarray(r,r+i);return e.HEAPU32.set(o,r),t.hb_set_next_many(n,-1,s,i),o}(n);return t.hb_set_destroy(n),i},destroy:function(){t.hb_face_destroy(s)}}},createFont:function(r){var o=t.hb_font_create(r.ptr),c=null,d=null,u=null,f=null,p=null,g=null;function glyphToPath(e){return c||(d=i(function(e,t,n,i,s,r){h+=`M${i},${s}`},"viiiffi"),u=i(function(e,t,n,i,s,r){h+=`L${i},${s}`},"viiiffi"),f=i(function(e,t,n,i,s,r,o,l,c,d){h+=`C${i},${s} ${r},${o} ${l},${c}`},"viiiffffffi"),p=i(function(e,t,n,i,s,r,o,l){h+=`Q${i},${s} ${r},${o}`},"viiiffffi"),g=i(function(e,t,n,i){h+="Z"},"viiii"),c=t.hb_draw_funcs_create(),t.hb_draw_funcs_set_move_to_func(c,d,0,0),t.hb_draw_funcs_set_line_to_func(c,u,0,0),t.hb_draw_funcs_set_cubic_to_func(c,f,0,0),t.hb_draw_funcs_set_quadratic_to_func(c,p,0,0),t.hb_draw_funcs_set_close_path_func(c,g,0,0)),h="",t.hb_font_draw_glyph(o,e,c,0),h}return{ptr:o,glyphName:function(i){t.hb_font_glyph_to_string(o,i,l,256);var s=e.HEAPU8.subarray(l,l+256);return n.decode(s.slice(0,s.indexOf(0)))},glyphToPath:glyphToPath,glyphToJson:function(e){return glyphToPath(e).replace(/([MLQCZ])/g,"|$1 ").split("|").filter(function(e){return e.length}).map(function(e){var t=e.split(/[ ,]/g);return{type:t[0],values:t.slice(1).filter(function(e){return e.length}).map(function(e){return+e})}})},setScale:function(e,n){t.hb_font_set_scale(o,e,n)},setVariations:function(n){var i=Object.entries(n),s=t.malloc(8*i.length);i.forEach(function(t,n){e.HEAPU32[s/4+2*n+0]=hb_tag(t[0]),e.HEAPF32[s/4+2*n+1]=t[1]}),t.hb_font_set_variations(o,s,i.length),t.free(s)},destroy:function(){t.hb_font_destroy(o),c&&(t.hb_draw_funcs_destroy(c),c=null,s(d),s(u),s(f),s(p),s(g))}}},createBuffer:function(){var n=t.hb_buffer_create();return{ptr:n,addText:function(i){const s=function(n){const i=t.malloc(2*n.length),s=new Uint16Array(e.wasmMemory.buffer,i,n.length);for(let e=0;e<s.length;++e)s[e]=n.charCodeAt(e);return{ptr:i,length:s.length,free:function(){t.free(i)}}}(i);t.hb_buffer_add_utf16(n,s.ptr,s.length,0,s.length),s.free()},guessSegmentProperties:function(){return t.hb_buffer_guess_segment_properties(n)},setDirection:function(e){t.hb_buffer_set_direction(n,{ltr:4,rtl:5,ttb:6,btt:7}[e]||0)},setFlags:function(e){var i=0;e.forEach(function(e){i|=function(e){return"BOT"==e?1:"EOT"==e?2:"PRESERVE_DEFAULT_IGNORABLES"==e?4:"REMOVE_DEFAULT_IGNORABLES"==e?8:"DO_NOT_INSERT_DOTTED_CIRCLE"==e?16:"PRODUCE_UNSAFE_TO_CONCAT"==e?64:0}(e)}),t.hb_buffer_set_flags(n,i)},setLanguage:function(e){var i=createAsciiString(e);t.hb_buffer_set_language(n,t.hb_language_from_string(i.ptr,-1)),i.free()},setScript:function(e){var i=createAsciiString(e);t.hb_buffer_set_script(n,t.hb_script_from_string(i.ptr,-1)),i.free()},setClusterLevel:function(e){t.hb_buffer_set_cluster_level(n,e)},json:function(){for(var i=t.hb_buffer_get_length(n),s=[],r=t.hb_buffer_get_glyph_infos(n,0),o=r/4,h=t.hb_buffer_get_glyph_positions(n,0)/4,l=e.HEAPU32.subarray(o,o+5*i),c=e.HEAP32.subarray(h,h+5*i),d=0;d<i;++d)s.push({g:l[5*d+0],cl:l[5*d+2],ax:c[5*d+0],ay:c[5*d+1],dx:c[5*d+2],dy:c[5*d+3],flags:t.hb_glyph_info_get_glyph_flags(r+20*d)});return s},destroy:function(){t.hb_buffer_destroy(n)}}},shape:shape,shapeWithTrace:function(r,h,l,c,d){var u=[],f=0,p=!1,g=1048576,m=t.malloc(g),y=i(function(i,s,r,h){var l=n.decode(e.HEAPU8.subarray(r,e.HEAPU8.indexOf(0,r)));return l.startsWith("start table GSUB")?f=1:l.startsWith("start table GPOS")&&(f=2),f!=d&&(p=!1),0!=d&&f==d&&l.startsWith("end lookup "+c)&&(p=!0),p?0:(t.hb_buffer_serialize_glyphs(i,0,t.hb_buffer_get_length(i),m,g,0,s,o,4),u.push({m:l,t:JSON.parse(n.decode(e.HEAPU8.subarray(m,e.HEAPU8.indexOf(0,m)))),glyphs:2==t.hb_buffer_get_content_type(i)}),1)},"iiiii");return t.hb_buffer_set_message_func(h.ptr,y,0,0),shape(r,h,l),t.free(m),s(y),u},version:function(){var n=t.malloc(12);t.hb_version(n,n+4,n+8);var i={major:e.HEAPU32[n/4],minor:e.HEAPU32[(n+4)/4],micro:e.HEAPU32[(n+8)/4]};return t.free(n),i},version_string:function(){var i=t.hb_version_string();return n.decode(e.HEAPU8.subarray(i,e.HEAPU8.indexOf(0,i)))}}}}catch(e){}var M=getDefaultExportFromCjs(k.exports);let N=null,H=null,V=null;const W={setWasmPath(e){H=e,V=null,N=null},setWasmBuffer(e){V=e,H=null,N=null},getHarfBuzz:async()=>N||(N=new Promise(async(e,t)=>{try{const t={};if(V)t.wasmBinary=V;else{if(!H)throw new Error("HarfBuzz WASM path or buffer must be set before initialization.");t.locateFile=(e,t)=>e.endsWith(".wasm")?H:t+e}const n=await G(t),i=M(n);e({hb:i,module:{addFunction:n.addFunction,exports:n.wasmExports,removeFunction:n.removeFunction}})}catch(e){t(new Error(`Failed to initialize HarfBuzz: ${e}`))}}),N)};class TextRangeQuery{constructor(e,t){this.text=e,this.glyphsByTextIndex=new Map,t.forEach(e=>{const t=this.glyphsByTextIndex.get(e.textIndex)||[];t.push(e),this.glyphsByTextIndex.set(e.textIndex,t)})}execute(e){const t=[];return e.byText&&t.push(...this.findByText(e.byText)),e.byCharRange&&t.push(...this.findByCharRange(e.byCharRange)),t}findByText(e){const t=[];for(const n of e){let e=0;for(;-1!==(e=this.text.indexOf(n,e));)t.push(this.createTextRange(e,e+n.length,n)),e+=n.length}return t}findByCharRange(e){return e.map(e=>{const t=this.text.slice(e.start,e.end);return this.createTextRange(e.start,e.end,t)})}createTextRange(e,t,n){const i=[],s=new Map;for(let n=e;n<t;n++){const e=this.glyphsByTextIndex.get(n);if(e)for(const t of e){i.push(t);const e=s.get(t.lineIndex)||[];e.push(t),s.set(t.lineIndex,e)}}return{start:e,end:t,originalText:n,bounds:Array.from(s.values()).map(e=>this.calculateBounds(e)),glyphs:i,lineIndices:Array.from(s.keys()).sort((e,t)=>e-t)}}calculateBounds(e){if(0===e.length)return{min:{x:0,y:0,z:0},max:{x:0,y:0,z:0}};const t=new Box3;for(const n of e){const e=new Box3(new Vec3(n.bounds.min.x,n.bounds.min.y,n.bounds.min.z),new Vec3(n.bounds.max.x,n.bounds.max.y,n.bounds.max.z));t.union(e)}return{min:{x:t.min.x,y:t.min.y,z:t.min.z},max:{x:t.max.x,y:t.max.y,z:t.max.z}}}}class Text{static{this.patternCache=new Map}static{this.hbInitPromise=null}static{this.fontCache=new Map}static{this.fontIdCounter=0}constructor(e){this.currentFontId="",Text.hbInitPromise||(Text.hbInitPromise=W.getHarfBuzz()),this.fontLoader=new FontLoader(()=>Text.hbInitPromise)}static setHarfBuzzPath(e){W.setWasmPath(e),Text.hbInitPromise=null}static setHarfBuzzBuffer(e){W.setWasmBuffer(e),Text.hbInitPromise=null}static init(){return Text.hbInitPromise||(Text.hbInitPromise=W.getHarfBuzz()),Text.hbInitPromise}static async create(e){if(!e.font)throw new Error("Font is required. Specify options.font as a URL string or ArrayBuffer.");Text.hbInitPromise||(Text.hbInitPromise=W.getHarfBuzz());const t="string"==typeof e.font?e.font:`buffer-${Text.generateFontContentHash(e.font)}`,n=e.fontVariations?`${t}_${JSON.stringify(e.fontVariations)}`:t;let i=Text.fontCache.get(n);i||(i=await Text.loadAndCacheFont(n,e.font,e.fontVariations));const s=new Text({maxCacheSizeMB:e.maxCacheSizeMB});s.setLoadedFont(i);const{font:r,maxCacheSizeMB:o,...h}=e;return{...await s.createGeometry(h),getLoadedFont:()=>s.getLoadedFont(),getCacheStatistics:()=>s.getCacheStatistics(),clearCache:()=>s.clearCache(),measureTextWidth:(e,t)=>s.measureTextWidth(e,t)}}static async loadAndCacheFont(e,t,n){const i=new Text;await i.loadFont(t,n);const s=i.getLoadedFont();return Text.fontCache.set(e,s),s}static generateFontContentHash(e){if(e){const t=new Uint8Array(e);return`${t[0]}_${t[Math.floor(t.length/2)]}_${t[t.length-1]}_${t.length}`}return""+ ++Text.fontIdCounter}setLoadedFont(e){this.loadedFont=e;const t=Text.generateFontContentHash(e._buffer);this.currentFontId=`font_${t}`,e.fontVariations&&(this.currentFontId+=`_${JSON.stringify(e.fontVariations)}`)}async loadFont(e,t){i.start("Text.loadFont",{fontSrc:"string"==typeof e?e:`buffer(${e.byteLength})`}),Text.hbInitPromise||(Text.hbInitPromise=W.getHarfBuzz()),await Text.hbInitPromise;const s="string"==typeof e?await fetch(e).then(t=>{if(!t.ok)throw new Error(`Failed to load font from ${e}: HTTP ${t.status} ${t.statusText}`);return t.arrayBuffer()}):e;try{this.loadedFont&&this.destroy(),this.loadedFont=await this.fontLoader.loadFont(s,t);const e=Text.generateFontContentHash(s);this.currentFontId=`font_${e}`,t&&(this.currentFontId+=`_${JSON.stringify(t)}`)}catch(e){throw n.error("Failed to load font:",e),e}finally{i.end("Text.loadFont")}}async createGeometry(e){i.start("Text.createGeometry",{textLength:e.text.length,size:e.size||72,hasLayout:!!e.layout,mode:"cached"});try{if(!this.loadedFont)throw new Error("Font not loaded. Use Text.create() with a font option.");const t=await this.prepareHyphenation(e);if(this.validateOptions(t),e=t,this.updateFontVariations(e),!this.geometryBuilder){const t=e.maxCacheSizeMB?new GlyphCache(e.maxCacheSizeMB):R;this.geometryBuilder=new GlyphGeometryBuilder(t,this.loadedFont),this.geometryBuilder.setFontId(this.currentFontId)}this.geometryBuilder.setCurveFidelityConfig(e.curveFidelity),this.geometryBuilder.setGeometryOptimization(e.geometryOptimization),this.loadedFont.font.setScale(this.loadedFont.upem,this.loadedFont.upem),this.textShaper||(this.textShaper=new TextShaper(this.loadedFont,this.geometryBuilder));const n=this.prepareLayout(e),i=e.removeOverlaps??this.loadedFont.isVariable??!1,s=this.textShaper.shapeLines(n.lines,n.scaledLineHeight,n.letterSpacing,n.align,n.direction,e.color,e.text),r=this.geometryBuilder.buildInstancedGeometry(s,n.depth,i,this.loadedFont.metrics.isCFF,e.separateGlyphsWithAttributes||!1),o=this.geometryBuilder.getCacheStats(),h=this.finalizeGeometry(r.vertices,r.normals,r.indices,r.glyphInfos,r.planeBounds,e,o,e.text);if(e.separateGlyphsWithAttributes){const e=this.createGlyphAttributes(h.vertices.length/3,h.glyphs);h.glyphAttributes=e}return h}finally{i.end("Text.createGeometry")}}async prepareHyphenation(e){if(!1!==e.layout?.hyphenate&&e.layout?.width){const t=e.layout?.language||"en-us";if(!e.layout?.hyphenationPatterns?.[t])try{if(!Text.patternCache.has(t)){const n=await loadPattern(t,e.layout?.patternsPath);Text.patternCache.set(t,n)}return{...e,layout:{...e.layout,hyphenationPatterns:{...e.layout?.hyphenationPatterns,[t]:Text.patternCache.get(t)}}}}catch(i){return n.warn(`Failed to load patterns for ${t}: ${i}`),{...e,layout:{...e.layout,hyphenate:!1}}}}return e}validateOptions(e){if(!e.text)throw new Error("Text content is required");const t=e.maxTextLength??1e5;if(e.text.length>t)throw new Error(`Text exceeds ${t} character limit`)}updateFontVariations(e){e.fontVariations&&this.loadedFont&&JSON.stringify(e.fontVariations)!==JSON.stringify(this.loadedFont.fontVariations)&&(this.loadedFont.font.setVariations(e.fontVariations),this.loadedFont.fontVariations=e.fontVariations)}prepareLayout(e){if(!this.loadedFont)throw new Error("Font not loaded. Use Text.create() with a font option");const{text:t,size:n=72,depth:i=0,lineHeight:h=1,letterSpacing:l=0,layout:c={}}=e,{width:d,direction:u="ltr",align:f=("rtl"===u?"right":"left"),respectExistingBreaks:p=!0,hyphenate:g=!0,language:m="en-us",tolerance:y=s,pretolerance:x=r,emergencyStretch:_=o,autoEmergencyStretch:v,hyphenationPatterns:w,lefthyphenmin:b,righthyphenmin:S,linepenalty:E,adjdemerits:L,hyphenpenalty:O,exhyphenpenalty:T,doublehyphendemerits:P,looseness:F,disableSingleWordDetection:C}=c;let B;void 0!==d&&(B=d*(this.loadedFont.upem/n));const I=i*(this.loadedFont.upem/n);this.textLayout||(this.textLayout=new TextLayout(this.loadedFont));const A=this.textLayout.computeLines({text:t,width:B,align:f,direction:u,hyphenate:g,language:m,respectExistingBreaks:p,tolerance:y,pretolerance:x,emergencyStretch:_,autoEmergencyStretch:v,hyphenationPatterns:w,lefthyphenmin:b,righthyphenmin:S,linepenalty:E,adjdemerits:L,hyphenpenalty:O,exhyphenpenalty:T,doublehyphendemerits:P,looseness:F,disableSingleWordDetection:C,letterSpacing:l}),U=FontMetadataExtractor.getVerticalMetrics(this.loadedFont.metrics),R=(U.ascender-U.descender)*h;return{lines:A.lines,scaledLineHeight:R,letterSpacing:l,align:f,direction:u,depth:I,size:n}}applyColorSystem(e,t,n,i){const s=e.length/3,r=new Float32Array(3*s),o=[];if(Array.isArray(n)){for(let e=0;e<s;e++){const t=3*e;r[t]=n[0],r[t+1]=n[1],r[t+2]=n[2]}o.push({start:0,end:i.length,originalText:i,color:n,bounds:[],glyphs:t,lineIndices:[...new Set(t.map(e=>e.lineIndex))]})}else{const e=n.default||[1,1,1];for(let t=0;t<r.length;t+=3)r[t]=e[0],r[t+1]=e[1],r[t+2]=e[2];if(n.byText){new TextRangeQuery(i,t).execute({byText:Object.keys(n.byText)}).forEach(e=>{const t=n.byText[e.originalText];t&&(e.glyphs.forEach(e=>{for(let n=0;n<e.vertexCount;n++){const i=3*(e.vertexStart+n);i>=0&&i<r.length&&(r[i]=t[0],r[i+1]=t[1],r[i+2]=t[2])}}),o.push({start:e.start,end:e.end,originalText:e.originalText,color:t,bounds:e.bounds,glyphs:e.glyphs,lineIndices:e.lineIndices}))})}n.byCharRange&&n.byCharRange.forEach(e=>{const n=[];for(const i of t)if(i.textIndex>=e.start&&i.textIndex<e.end){n.push(i);for(let t=0;t<i.vertexCount;t++){const n=3*(i.vertexStart+t);n>=0&&n<r.length&&(r[n]=e.color[0],r[n+1]=e.color[1],r[n+2]=e.color[2])}}o.push({start:e.start,end:e.end,originalText:i.slice(e.start,e.end),color:e.color,bounds:[],glyphs:n,lineIndices:[...new Set(n.map(e=>e.lineIndex))]})})}return{colors:r,coloredRanges:o}}finalizeGeometry(e,t,n,i,s,r,o,h){const{layout:l={},size:c=72}=r,{width:d,align:u=("rtl"===l.direction?"right":"left")}=l;this.textLayout||(this.textLayout=new TextLayout(this.loadedFont));const f=this.textLayout.applyAlignment(e,{width:d,align:u,planeBounds:s}),p=f.offset;s.min.x=f.adjustedBounds.min.x,s.max.x=f.adjustedBounds.max.x;const g=c/this.loadedFont.upem;for(let t=0;t<e.length;t++)e[t]*=g;s.min.x*=g,s.min.y*=g,s.min.z*=g,s.max.x*=g,s.max.y*=g,s.max.z*=g;for(let e=0;e<i.length;e++){const t=i[e];0!==p&&(t.bounds.min.x+=p,t.bounds.max.x+=p),t.bounds.min.x*=g,t.bounds.min.y*=g,t.bounds.min.z*=g,t.bounds.max.x*=g,t.bounds.max.y*=g,t.bounds.max.z*=g}let m,y;if(r.color){const t=this.applyColorSystem(e,i,r.color,r.text);m=t.colors,y=t.coloredRanges}const x=this.geometryBuilder.getOptimizationStats(),_=n.length/3,v=e.length/3;return{vertices:e,normals:t,indices:n,colors:m,glyphs:i,planeBounds:s,stats:{trianglesGenerated:_,verticesGenerated:v,pointsRemovedByVisvalingam:x.pointsRemovedByVisvalingam,pointsRemovedByColinear:x.pointsRemovedByColinear,originalPointCount:x.originalPointCount,...o||{}},query:e=>{if(!h)throw new Error("Original text not available for querying");return new TextRangeQuery(h,i).execute(e)},coloredRanges:y,glyphAttributes:void 0}}getFontMetrics(){if(!this.loadedFont)throw new Error("Font not loaded. Call loadFont() first");return FontMetadataExtractor.getFontMetrics(this.loadedFont.metrics)}static async preloadPatterns(e,t){await Promise.all(e.map(async e=>{if(!Text.patternCache.has(e))try{const n=await loadPattern(e,t);Text.patternCache.set(e,n)}catch(t){n.warn(`Failed to pre-load patterns for ${e}: ${t}`)}}))}static registerPattern(e,t){Text.patternCache.set(e,t)}getLoadedFont(){return this.loadedFont}measureTextWidth(e,t=0){if(!this.loadedFont)throw new Error("Font not loaded. Call loadFont() first");return TextMeasurer.measureTextWidth(this.loadedFont,e,t)}getCacheStatistics(){return this.geometryBuilder?this.geometryBuilder.getCacheStats():null}clearCache(){this.geometryBuilder&&this.geometryBuilder.clearCache()}createGlyphAttributes(e,t){const n=new Float32Array(3*e),i=new Float32Array(e),s=new Float32Array(e);return t.forEach((t,r)=>{const o=(t.bounds.min.x+t.bounds.max.x)/2,h=(t.bounds.min.y+t.bounds.max.y)/2,l=(t.bounds.min.z+t.bounds.max.z)/2;for(let c=0;c<t.vertexCount;c++){const d=t.vertexStart+c;d<e&&(n[3*d]=o,n[3*d+1]=h,n[3*d+2]=l,i[d]=r,s[d]=t.lineIndex)}}),{glyphCenter:n,glyphIndex:i,glyphLineIndex:s}}destroy(){if(!this.loadedFont)return;const e=this.loadedFont;try{FontLoader.destroyFont(e)}catch(e){n.warn("Error destroying HarfBuzz objects:",e)}finally{this.loadedFont=void 0,this.textLayout=void 0,this.textShaper=void 0}}}e.DEFAULT_CURVE_FIDELITY=A,e.FontMetadataExtractor=FontMetadataExtractor,e.Text=Text,e.globalGlyphCache=R});
|
|
14
|
+
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self).ThreeText={})}(this,function(e){const n=!("undefined"==typeof window||!window.THREE_TEXT_LOG)||"undefined"!=typeof globalThis&&"true"===globalThis.process?.env?.THREE_TEXT_LOG;const i=new class{warn(e,...n){console.warn(e,...n)}error(e,...n){console.error(e,...n)}log(e,...i){n&&console.log(e,...i)}};const s=new class{constructor(){this.metrics=[],this.activeTimers=new Map}start(e,i){if(!n)return;const s=performance.now();this.activeTimers.set(e,s),this.metrics.push({name:e,startTime:s,metadata:i})}end(e){if(!n)return null;const s=performance.now(),r=this.activeTimers.get(e);if(void 0===r)return i.warn(`Performance timer "${e}" was not started`),null;const o=s-r;this.activeTimers.delete(e);for(let n=this.metrics.length-1;n>=0;n--){const i=this.metrics[n];if(i.name===e&&!i.endTime){i.endTime=s,i.duration=o;break}}return console.log(`${e}: ${o.toFixed(2)}ms`),o}getSummary(){if(!n)return{};const e={};for(const n of this.metrics){if(!n.duration)continue;const i=e[n.name];i?(i.count++,i.totalDuration+=n.duration,i.avgDuration=i.totalDuration/i.count,i.lastDuration=n.duration):e[n.name]={count:1,avgDuration:n.duration,totalDuration:n.duration,lastDuration:n.duration}}return e}printSummary(){if(!n)return;const e=this.getSummary();console.table(e),console.log("Operations:",Object.keys(e).sort().join(", "))}printBaseline(){if(!n)return;const e=this.getSummary();Object.entries(e).forEach(([e,n])=>{console.log(`BASELINE ${e}: ${n.avgDuration.toFixed(2)}ms avg (${n.count} calls)`)})}clear(){n&&(this.metrics.length=0,this.activeTimers.clear())}time(e,i,s){if(!n)return i();this.start(e,s);try{return i()}finally{this.end(e)}}async timeAsync(e,i,s){if(!n)return i();this.start(e,s);try{return await i()}finally{this.end(e)}}},r=200,o=100,h=0,c=1/3;var l,d;!function(e){e[e.BOX=0]="BOX",e[e.GLUE=1]="GLUE",e[e.PENALTY=2]="PENALTY",e[e.DISCRETIONARY=3]="DISCRETIONARY"}(l||(l={})),function(e){e[e.TIGHT=0]="TIGHT",e[e.NORMAL=1]="NORMAL",e[e.LOOSE=2]="LOOSE",e[e.VERY_LOOSE=3]="VERY_LOOSE"}(d||(d={}));class ActiveNodeList{constructor(){this.nodesByKey=new Map,this.activeList=[],this.allNodes=new Set}getKey(e,n){return e<<2|n}insert(e){const n=this.getKey(e.position,e.fitness),i=this.nodesByKey.get(n);i&&e.totalDemerits<i.totalDemerits?(i.totalDemerits=e.totalDemerits,i.previous=e.previous,i.totalWidth=e.totalWidth):i||(this.nodesByKey.set(n,e),this.allNodes.add(e),e.activeListIndex=this.activeList.length,this.activeList.push(e))}findExisting(e,n){return this.nodesByKey.get(this.getKey(e,n))}getAllActive(){return this.activeList}deactivateNode(e){if(e.active&&void 0!==e.activeListIndex){e.active=!1;const n=e.activeListIndex,i=this.activeList.length-1;if(n!==i){const e=this.activeList[i];this.activeList[n]=e,e.activeListIndex=n}this.activeList.pop(),e.activeListIndex=void 0}}size(){return this.allNodes.size}}const f=50,p=50,g=1e4,y=10,b=1e4,m=-1/0,_=2,w=4,O=1e4;class LineBreak{static badness(e,n){if(0===e)return 0;if(n<=0)return O;let i;return i=e<=7230584?Math.floor(297*e/n):n>=1663497?Math.floor(e/Math.floor(n/297)):e,i>1290?O:Math.floor((i*i*i+131072)/262144)}static findHyphenationPoints(e,n="en-us",i,s=_,r=w){let o;if(!i||!i[n])return[];if(o=i[n],!o)return[];const h=`.${e.toLowerCase()}.`,c=new Array(h.length).fill(0);for(let e=0;e<h.length;e++){let n=o;for(let i=e;i<h.length;i++){const s=h[i];if(!n.children||!n.children[s])break;if(n=n.children[s],n.patterns)for(let i=0;i<n.patterns.length;i++){const s=e+i;s<c.length&&(c[s]=Math.max(c[s],n.patterns[i]))}}}const l=[];for(let e=2;e<h.length-2;e++)c[e]%2==1&&l.push(e-1);return l.filter(n=>n>=s&&e.length-n>=r)}static itemizeText(e,n,i=!1,s="en-us",r,o=_,h=w,c){const d=[];return d.push(...this.itemizeParagraph(e,n,i,s,r,o,h,c)),d.push({type:l.GLUE,width:0,stretch:1/0,shrink:0,text:"",originIndex:e.length}),d.push({type:l.PENALTY,width:0,penalty:-1/0,text:"",originIndex:e.length}),d}static itemizeParagraph(e,n,i,s,r,o,h,d){const g=[],y=e.match(/\S+|\s+/g)||[];let b=0;for(let e=0;e<y.length;e++){const m=y[e],_=b;if(/\s+/.test(m)){const e=n(m);g.push({type:l.GLUE,width:e,stretch:.5*e,shrink:e*c,text:m,originIndex:_}),b+=m.length}else{const e=m.split(/(-)/);let c=_;for(let y=0;y<e.length;y++){const b=e[y];if(b)if("-"===b)g.push({type:l.DISCRETIONARY,width:n("-"),preBreak:"-",postBreak:"",noBreak:"-",preBreakWidth:n("-"),penalty:d?.exHyphenPenalty??p,flagged:!0,text:"-",originIndex:c}),c+=1;else{if(b.includes("")){const e=b.split("");let i=0;for(let s=0;s<e.length;s++){const r=e[s];r.length>0&&(g.push({type:l.BOX,width:n(r),text:r,originIndex:c+i}),i+=r.length),s<e.length-1&&(g.push({type:l.DISCRETIONARY,width:0,preBreak:"-",postBreak:"",noBreak:"",preBreakWidth:n("-"),penalty:d?.hyphenPenalty??f,flagged:!0,text:"",originIndex:c+i}),i+=1)}}else if(i&&b.length>=o+h){const e=LineBreak.findHyphenationPoints(b,s,r,o,h);if(e.length>0){let i=0;for(const s of e){const e=b.substring(i,s);g.push({type:l.BOX,width:n(e),text:e,originIndex:c+i}),g.push({type:l.DISCRETIONARY,width:0,preBreak:"-",postBreak:"",noBreak:"",preBreakWidth:n("-"),penalty:d?.hyphenPenalty??f,flagged:!0,text:"",originIndex:c+s}),i=s}const s=b.substring(i);g.push({type:l.BOX,width:n(s),text:s,originIndex:c+i})}else g.push({type:l.BOX,width:n(b),text:b,originIndex:c})}else g.push({type:l.BOX,width:n(b),text:b,originIndex:c});c+=b.length}}b+=m.length}}return g}static hasSingleWordLines(e,n,i){let s=0;for(let r=0;r<n.length-1;r++){const o=n[r];let h=0,c=0;for(let n=s;n<o;n++)e[n].type===l.GLUE&&h++,e[n].type!==l.PENALTY&&(c+=e[n].width);if(0===h&&c>0){if(c/i<.5)return!0}s=o+1}return!1}static breakText(e){s.start("LineBreak.breakText",{textLength:e.text.length,width:e.width,align:e.align||"left",hyphenate:e.hyphenate||!1});const{text:n,width:c,align:d="left",direction:m="ltr",hyphenate:O=!1,language:k="en-us",respectExistingBreaks:j=!0,measureText:$,hyphenationPatterns:Y,unitsPerEm:q,tolerance:tt=r,pretolerance:et=o,emergencyStretch:nt=h,autoEmergencyStretch:it,lefthyphenmin:st=_,righthyphenmin:rt=w,linepenalty:at=y,adjdemerits:ot=b,hyphenpenalty:ht=f,exhyphenpenalty:ct=p,doublehyphendemerits:lt=g,looseness:ut=0,disableSingleWordDetection:dt=!1}=e;if(j&&n.includes("\n")){const i=n.split("\n"),r=[];let o=0;for(const n of i){if(0===n.length)r.push({text:"",originalStart:o,originalEnd:o,xOffset:0,isLastLine:!0,naturalWidth:0,endedWithHyphen:!1});else{const i=LineBreak.breakText({...e,text:n,respectExistingBreaks:!1});i.forEach(e=>{e.originalStart+=o,e.originalEnd+=o}),r.push(...i)}o+=n.length+1}return s.end("LineBreak.breakText"),r}let ft=O;!ft||Y&&Y[k]||(i.warn(`Hyphenation patterns for ${k} not available`),ft=!1);let pt=nt;void 0!==it&&c?pt=c*it:!ft&&nt===h&&c&&(pt=.1*c);const gt={linePenalty:at,adjDemerits:ot,doubleHyphenDemerits:lt,hyphenPenalty:ht,exHyphenPenalty:ct,currentAlign:d,unitsPerEm:q};if(!c||c===1/0){const e=$(n);return s.end("LineBreak.breakText"),[{text:n,originalStart:0,originalEnd:n.length-1,xOffset:0,isLastLine:!0,naturalWidth:e,endedWithHyphen:!1}]}const yt=LineBreak.itemizeText(n,$,ft,k,Y,st,rt,gt);if(0===yt.length)return[];let bt=0,mt=pt,_t=null;const xt=!dt;for(;bt<5;){let e=ft?yt.filter(e=>e.type!==l.DISCRETIONARY||e.penalty!==(gt?.hyphenPenalty??f)):yt,i=LineBreak.findBreakpoints(e,c,et,ut,!1,0,gt);if(0===i.length&&ft&&(e=yt,i=LineBreak.findBreakpoints(e,c,tt,ut,!1,0,gt)),0===i.length&&(e=yt,i=LineBreak.findBreakpoints(e,c,10001,ut,!0,mt,gt)),0===i.length&&(i=LineBreak.findBreakpoints(e,c,1/0,ut,!0,mt,gt)),i.length>0){const s=LineBreak.computeCumulativeWidths(e);if(_t=LineBreak.createLines(n,e,i,c,d,m,s,gt),xt&&i.length>1&&LineBreak.hasSingleWordLines(e,i,c)){mt+=.1*c,bt++;continue}break}break}if(s.end("LineBreak.breakText"),_t&&_t.length>0)return _t;const wt=$(n);return[{text:n,originalStart:0,originalEnd:n.length-1,xOffset:0,adjustmentRatio:0,isLastLine:!0,naturalWidth:wt,endedWithHyphen:!1}]}static findBreakpoints(e,n,i=1/0,s=0,r=!1,o=0,h){const c=LineBreak.computeCumulativeWidths(e),f=new ActiveNodeList;f.insert({position:0,line:0,fitness:d.NORMAL,totalDemerits:0,totalWidth:0,previous:null,active:!0});for(let s=0;s<e.length;s++){const r=e[s];r.type===l.PENALTY&&r.penalty<1/0&&LineBreak.considerBreak(e,f,s,n,i,o,c,h),r.type===l.DISCRETIONARY&&r.penalty<1/0&&LineBreak.considerBreak(e,f,s,n,i,o,c,h),r.type===l.GLUE&&s>0&&e[s-1].type===l.BOX&&LineBreak.considerBreak(e,f,s,n,i,o,c,h),LineBreak.deactivateNodes(f,s,n,c.minWidths)}const p=[];let g=null;if(0===s){const e=f.getAllActive();let n=1/0;for(const i of e)i.active&&i.totalDemerits<n&&(n=i.totalDemerits,g=i)}else{const e=f.getAllActive();let n=0,i=1/0;for(const s of e)s.active&&s.totalDemerits<i&&(i=s.totalDemerits,n=s.line);let o=0,h=1/0;for(const i of e){if(!i.active)continue;const e=i.line-n;e<o&&s<=e||e>o&&s>=e?(g=i,o=e,h=i.totalDemerits):e===o&&i.totalDemerits<h&&(g=i,h=i.totalDemerits)}if(!r&&o!==s&&g)return[]}if(!g)return[];for(;g&&g.position>0;)p.unshift(g.position),g=g.previous;return p}static considerBreak(e,n,i,s,r=1/0,o=0,h,c){const d=(e[i].type===l.PENALTY?e[i].penalty:0)<=-1/0,f=n.getAllActive();for(let p=0;p<f.length;p++){const g=f[p];if(!g.active)continue;const y=LineBreak.computeAdjustmentRatio(e,g.position,i,g.line,s,h,c),{ratio:b,adjustment:_,stretch:w,shrink:O,totalWidth:k}=y;let j;if(_>0){const e=w+o;j=e<=0?10001:LineBreak.badness(_,e)}else j=_<0?O<=0||-_>O?10001:LineBreak.badness(-_,O):0;if(!d&&b<-1)continue;const $=LineBreak.computeFitnessClass(j,_>0);if(!d&&j>r)continue;let Y=0,q=0;let tt=(c?.linePenalty??0)+j,et=Math.abs(tt)>=1e4?1e8:tt*tt;const nt=e[i].type===l.PENALTY||e[i].type===l.DISCRETIONARY?e[i].penalty:0;0!==nt&&(nt>0?et+=nt*nt:nt>m&&(et-=nt*nt));const it=e[i].type===l.PENALTY&&e[i].flagged||e[i].type===l.DISCRETIONARY&&e[i].flagged,st=g.position>0&&(e[g.position].type===l.PENALTY&&e[g.position].flagged||e[g.position].type===l.DISCRETIONARY&&e[g.position].flagged);it&&st&&(Y=c?.doubleHyphenDemerits??0,et+=Y),Math.abs($-g.fitness)>1&&(q=c?.adjDemerits??0,et+=q),d&&(et=0);const rt=g.totalDemerits+et;let at=n.findExisting(i,$);at?rt<at.totalDemerits&&(at.totalDemerits=rt,at.previous=g,at.totalWidth=k):n.insert({position:i,line:g.line+1,fitness:$,totalDemerits:rt,totalWidth:k,previous:g,active:!0})}}static computeAdjustmentRatio(e,n,i,s,r,o,h){let c=0,d=0,f=0;if(o){c=o.widths[i]-o.widths[n],d=o.stretches[i]-o.stretches[n],f=o.shrinks[i]-o.shrinks[n];for(let s=n;s<i;s++){const n=e[s];n.type===l.PENALTY&&(c-=n.width)}}else for(let s=n;s<i;s++){const n=e[s];n.type!==l.PENALTY&&(c+=n.width,n.type===l.GLUE&&(d+=n.stretch,f+=n.shrink))}i<e.length&&(e[i].type===l.PENALTY||e[i].type===l.DISCRETIONARY)&&(c+=e[i].type===l.PENALTY?e[i].width:e[i].preBreakWidth);const p=r-c;let g;return g=p>0&&d>0?p/d:p<0&&f>0?p/f:0===p?0:p>0?3:-1,{ratio:g,adjustment:p,stretch:d,shrink:f,totalWidth:c}}static computeFitnessClass(e,n){return n?e<=12?d.NORMAL:e<=99?d.LOOSE:d.VERY_LOOSE:e<=12?d.NORMAL:d.TIGHT}static computeCumulativeWidths(e){const n=e.length+1,i=new Array(n),s=new Array(n),r=new Array(n),o=new Array(n);i[0]=0,s[0]=0,r[0]=0,o[0]=0;for(let n=0;n<e.length;n++){const h=e[n];if(i[n+1]=i[n]+h.width,h.type===l.PENALTY)o[n+1]=o[n];else if(h.type===l.GLUE){const e=h;s[n+1]=s[n]+e.stretch,r[n+1]=r[n]+e.shrink,o[n+1]=o[n]+Math.max(0,e.width-e.shrink)}else s[n+1]=s[n],r[n+1]=r[n],o[n+1]=o[n]+h.width}return{widths:i,stretches:s,shrinks:r,minWidths:o}}static deactivateNodes(e,n,i,s){const r=e.getAllActive();for(let o=r.length-1;o>=0;o--){const h=r[o];if(!h.active)continue;s[n]-s[h.position]>i&&e.deactivateNode(h)}}static createLines(e,n,i,s,r,o,h,c){if(0===i.length)return[{text:e,originalStart:0,originalEnd:e.length-1,xOffset:0}];const d=[];let f=0;for(let e=0;e<i.length;e++){const p=i[e],g=!(i[i.length-1]+1<n.length-1)&&e===i.length-1,y=[];let b=-1,m=-1,_=0;for(let e=f;e<p;e++){const i=n[e];if((i.type!==l.PENALTY||i.text)&&(i.type!==l.DISCRETIONARY||i.noBreak)){if(void 0!==i.originIndex){(-1===b||i.originIndex<b)&&(b=i.originIndex);const e=i.text?i.text.length:0,n=i.originIndex+e-1;n>m&&(m=n)}if(i.text)y.push(i.text);else if(i.type===l.DISCRETIONARY){const e=i;e.noBreak&&y.push(e.noBreak)}_+=i.width}}const w=n[p];let O=!1;if(p<n.length)if(w.type===l.PENALTY&&w.flagged)y.push("-"),_+=w.width,O=!0,void 0!==w.originIndex&&(m=w.originIndex-1);else if(w.type===l.DISCRETIONARY){const e=w;e.preBreak&&(y.push(e.preBreak),_+=e.preBreakWidth,O=e.flagged||!1,void 0!==w.originIndex&&(m=w.originIndex-1))}const k=y.join("");let j=0,$=0,Y=r;if("justify"===r&&g&&(Y="rtl"===o?"right":"left"),"center"===Y)j=(s-_)/2;else if("right"===Y)j=s-_;else if("justify"===Y&&!g){$=LineBreak.computeAdjustmentRatio(n,f,p,e,s,h,c).ratio}d.push({text:k,originalStart:b,originalEnd:m,xOffset:j,adjustmentRatio:$,isLastLine:!1,naturalWidth:_,endedWithHyphen:O}),f=p+1}if(f<n.length-1){const e=[];let i=-1,h=-1,c=0;for(let s=f;s<n.length-1;s++){const r=n[s];r.type!==l.PENALTY&&(void 0!==r.originIndex&&((-1===i||r.originIndex<i)&&(i=r.originIndex),r.originIndex>h&&(h=r.originIndex)),r.text&&e.push(r.text),c+=r.width)}const p=e.join("");let g=0,y=r;"justify"===r&&(y="rtl"===o?"right":"left"),"center"===y?g=(s-c)/2:"right"===y&&(g=s-c),d.push({text:p,originalStart:i,originalEnd:h,xOffset:g,adjustmentRatio:0,isLastLine:!0,naturalWidth:c,endedWithHyphen:!1}),d.length>1&&(d[d.length-2].isLastLine=!1),d[d.length-1].isLastLine=!0}else d.length>0&&(d[d.length-1].isLastLine=!0);return d}}class TextMeasurer{static measureTextWidth(e,n,i=0){const s=e.hb.createBuffer();s.addText(n),s.guessSegmentProperties(),e.hb.shape(e.font,s);const r=s.json(e.font),o=i*e.upem;let h=0;return r.forEach((e,i)=>{h+=e.ax;const s=i===r.length-1,c=" "===n||" "===n||/^\s+$/.test(n);0===o||s&&!c||(h+=o)}),s.destroy(),h}}class TextLayout{constructor(e){this.loadedFont=e}computeLines(e){const{text:n,width:i,align:s,direction:r,hyphenate:o,language:h,respectExistingBreaks:c,tolerance:l,pretolerance:d,emergencyStretch:f,autoEmergencyStretch:p,hyphenationPatterns:g,lefthyphenmin:y,righthyphenmin:b,linepenalty:m,adjdemerits:_,hyphenpenalty:w,exhyphenpenalty:O,doublehyphendemerits:k,looseness:j,disableSingleWordDetection:$,letterSpacing:Y}=e;let q;if(i)q=LineBreak.breakText({text:n,width:i,align:s,direction:r,hyphenate:o,language:h,respectExistingBreaks:c,tolerance:l,pretolerance:d,emergencyStretch:f,autoEmergencyStretch:p,hyphenationPatterns:g,lefthyphenmin:y,righthyphenmin:b,linepenalty:m,adjdemerits:_,hyphenpenalty:w,exhyphenpenalty:O,doublehyphendemerits:k,looseness:j,disableSingleWordDetection:$,unitsPerEm:this.loadedFont.upem,measureText:e=>TextMeasurer.measureTextWidth(this.loadedFont,e,Y)});else{const e=n.split("\n");q=[];let i=0;for(const n of e)q.push({text:n,originalStart:i,originalEnd:i+n.length-1,xOffset:0}),i+=n.length+1}return{lines:q}}applyAlignment(e,n){const{width:i,align:s,planeBounds:r}=n;let o=0;const h={min:{...r.min},max:{...r.max}};if(i&&("center"===s||"right"===s)){const n=r.max.x-r.min.x;if("center"===s?o=(i-n)/2-r.min.x:"right"===s&&(o=i-r.max.x),0!==o){for(let n=0;n<e.length;n+=3)e[n]+=o;h.min.x+=o,h.max.x+=o}}return{offset:o,adjustedBounds:h}}}const k=1330926671,j=1953784678,$=2001684038;class FontMetadataExtractor{static extractMetadata(e){if(!e||e.byteLength<12)throw new Error("Invalid font buffer: too small to be a valid font file");const n=new DataView(e),i=n.getUint32(0);if(![65536,k,j].includes(i))throw new Error(`Invalid font format. Expected TrueType or OpenType, got signature: 0x${i.toString(16)}`);const s=new Uint8Array(e),r=n.getUint16(4);let o=!1,h=0,c=0,l=0,d=0,f=0,p=0;for(let e=0;e<r;e++){const i=(new TextDecoder).decode(s.slice(12+16*e,12+16*e+4));("CFF "===i||"CFF2"===i)&&(o=!0),"head"===i&&(h=n.getUint32(12+16*e+8)),"hhea"===i&&(c=n.getUint32(12+16*e+8)),"OS/2"===i&&(l=n.getUint32(12+16*e+8)),"fvar"===i&&(p=n.getUint32(12+16*e+8)),"STAT"===i&&(d=n.getUint32(12+16*e+8)),"name"===i&&(f=n.getUint32(12+16*e+8))}const g=h?n.getUint16(h+18):1e3;let y=null;c&&(y={ascender:n.getInt16(c+4),descender:n.getInt16(c+6),lineGap:n.getInt16(c+8)});let b=null;l&&(b={typoAscender:n.getInt16(l+68),typoDescender:n.getInt16(l+70),typoLineGap:n.getInt16(l+72),winAscent:n.getUint16(l+74),winDescent:n.getUint16(l+76)});let m=null;return p&&d&&f&&(m=this.extractAxisNames(n,d,f)),{isCFF:o,unitsPerEm:g,hheaAscender:y?.ascender||null,hheaDescender:y?.descender||null,hheaLineGap:y?.lineGap||null,typoAscender:b?.typoAscender||null,typoDescender:b?.typoDescender||null,typoLineGap:b?.typoLineGap||null,winAscent:b?.winAscent||null,winDescent:b?.winDescent||null,axisNames:m}}static extractAxisNames(e,n,i){try{if(e.getUint16(n)<1)return null;const s=e.getUint16(n+4),r=e.getUint16(n+6),o=e.getUint32(n+8),h={};for(let c=0;c<r;c++){const r=n+o+c*s,l=String.fromCharCode(e.getUint8(r),e.getUint8(r+1),e.getUint8(r+2),e.getUint8(r+3)),d=e.getUint16(r+4),f=this.getNameFromNameTable(e,i,d);f&&(h[l]=f)}return Object.keys(h).length>0?h:null}catch(e){return null}}static getNameFromNameTable(e,n,i){try{const s=e.getUint16(n+2),r=e.getUint16(n+4);for(let o=0;o<s;o++){const s=n+6+12*o,h=e.getUint16(s),c=e.getUint16(s+2),l=e.getUint16(s+4),d=e.getUint16(s+6),f=e.getUint16(s+8),p=e.getUint16(s+10);if(d===i&&(0===h||3===h&&1033===l)){const i=n+r+p,s=new Uint8Array(e.buffer,i,f);if(0===h||3===h&&1===c){let e="";for(let n=0;n<s.length;n+=2)e+=String.fromCharCode(s[n]<<8|s[n+1]);return e}return new TextDecoder("ascii").decode(s)}}return null}catch(e){return null}}static getVerticalMetrics(e){return null!==e.typoAscender&&null!==e.typoDescender?{ascender:e.typoAscender,descender:e.typoDescender,lineGap:0}:null!==e.hheaAscender&&null!==e.hheaDescender?{ascender:e.hheaAscender,descender:e.hheaDescender,lineGap:0}:null!==e.winAscent&&null!==e.winDescent?{ascender:e.winAscent,descender:-e.winDescent,lineGap:0}:{ascender:Math.round(.8*e.unitsPerEm),descender:-Math.round(.2*e.unitsPerEm),lineGap:0}}static getFontMetrics(e){const n=FontMetadataExtractor.getVerticalMetrics(e);return{ascender:n.ascender,descender:n.descender,lineGap:n.lineGap,unitsPerEm:e.unitsPerEm,naturalLineHeight:n.ascender-n.descender}}}class WoffConverter{static detectFormat(e){if(e.byteLength<4)return"ttf/otf";const n=new DataView(e).getUint32(0);return n===$?"woff":2001684018===n?"woff2":"ttf/otf"}static async decompressWoff(e){const n=new DataView(e),s=new Uint8Array(e);if(n.getUint32(0)!==$)throw new Error("Not a valid WOFF font");const r=n.getUint32(4),o=n.getUint16(12),h=n.getUint32(16);if("undefined"==typeof DecompressionStream)throw new Error("WOFF fonts require DecompressionStream API (Chrome 80+, Firefox 113+, Safari 16.4+). Please use TTF/OTF fonts or upgrade your browser.");const c=new Uint8Array(h),l=new DataView(c.buffer);l.setUint32(0,r),l.setUint16(4,o);const d=2**Math.floor(Math.log2(o))*16;l.setUint16(6,d),l.setUint16(8,Math.floor(Math.log2(o))),l.setUint16(10,16*o-d);let f=12+16*o;const p=[];for(let e=0;e<o;e++){const i=44+20*e;p.push({tag:n.getUint32(i),offset:n.getUint32(i+4),length:n.getUint32(i+8),origLength:n.getUint32(i+12),checksum:n.getUint32(i+16)})}p.sort((e,n)=>e.tag-n.tag);for(let e=0;e<o;e++){const n=p[e],i=12+16*e;if(l.setUint32(i,n.tag),l.setUint32(i+4,n.checksum),l.setUint32(i+8,f),l.setUint32(i+12,n.origLength),n.length===n.origLength)c.set(s.subarray(n.offset,n.offset+n.length),f);else{const e=s.subarray(n.offset,n.offset+n.length),i=await WoffConverter.decompressZlib(e);if(i.byteLength!==n.origLength)throw new Error(`Decompression failed: expected ${n.origLength} bytes, got ${i.byteLength}`);c.set(new Uint8Array(i),f)}f+=n.origLength;f+=(4-n.origLength%4)%4}return i.log("WOFF font decompressed successfully"),c.buffer.slice(0,f)}static async decompressZlib(e){const n=new ReadableStream({start(n){n.enqueue(e),n.close()}}).pipeThrough(new DecompressionStream("deflate"));return new Response(n).arrayBuffer()}}class FontLoader{constructor(e){this.getHarfBuzzInstance=e}async loadFont(e,n){if(s.start("FontLoader.loadFont",{bufferSize:e.byteLength}),!e||e.byteLength<12)throw new Error("Invalid font buffer: too small to be a valid font file");const r=WoffConverter.detectFormat(e);if("woff"===r)i.log("WOFF font detected, decompressing..."),e=await WoffConverter.decompressWoff(e);else if("woff2"===r)throw new Error("WOFF2 fonts are not yet supported. Please use WOFF or TTF/OTF format.");const o=new DataView(e).getUint32(0);if(![65536,k,j].includes(o))throw new Error(`Invalid font format. Expected TrueType or OpenType, got signature: 0x${o.toString(16)}`);const{hb:h,module:c}=await this.getHarfBuzzInstance();try{const i=h.createBlob(new Uint8Array(e)),s=h.createFace(i,0),r=h.createFont(s);n&&r.setVariations(n);const o=s.getAxisInfos(),l=Object.keys(o).length>0,d=FontMetadataExtractor.extractMetadata(e);let f;if(l&&o){f={};for(const[e,n]of Object.entries(o))f[e]={...n,name:d.axisNames?.[e]||null}}return{hb:h,fontBlob:i,face:s,font:r,module:c,upem:d.unitsPerEm,metrics:d,fontVariations:n,isVariable:l,variationAxes:f}}catch(e){throw i.error("Failed to load font:",e),e}finally{s.end("FontLoader.loadFont")}}static destroyFont(e){try{e.font&&"function"==typeof e.font.destroy&&e.font.destroy(),e.face&&"function"==typeof e.face.destroy&&e.face.destroy(),e.fontBlob&&"function"==typeof e.fontBlob.destroy&&e.fontBlob.destroy()}catch(e){i.error("Error destroying font resources:",e)}}}async function loadPattern(e,n){{const i=`ThreeTextPatterns_${e.replace(/-/g,"_")}`;if(window[i])return window[i];const s=n||"/patterns/";return new Promise((n,r)=>{const o=document.createElement("script");o.src=`${s}${e}.umd.js`,o.async=!0,o.onload=()=>{window[i]?n(window[i]):r(new Error(`Pattern script loaded, but global ${i} not found.`))},o.onerror=()=>{r(new Error(`Failed to load hyphenation pattern from ${o.src}. Did you copy the pattern files to your public directory?`))},document.head.appendChild(o)})}}class Vec2{constructor(e=0,n=0){this.x=e,this.y=n}set(e,n){return this.x=e,this.y=n,this}clone(){return new Vec2(this.x,this.y)}copy(e){return this.x=e.x,this.y=e.y,this}add(e){return this.x+=e.x,this.y+=e.y,this}sub(e){return this.x-=e.x,this.y-=e.y,this}multiply(e){return this.x*=e,this.y*=e,this}divide(e){return this.x/=e,this.y/=e,this}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}lengthSq(){return this.x*this.x+this.y*this.y}normalize(){const e=this.length();return e>0&&this.divide(e),this}dot(e){return this.x*e.x+this.y*e.y}distanceTo(e){const n=this.x-e.x,i=this.y-e.y;return Math.sqrt(n*n+i*i)}distanceToSquared(e){const n=this.x-e.x,i=this.y-e.y;return n*n+i*i}equals(e){return this.x===e.x&&this.y===e.y}angle(){return Math.atan2(this.y,this.x)}}class Vec3{constructor(e=0,n=0,i=0){this.x=e,this.y=n,this.z=i}set(e,n,i){return this.x=e,this.y=n,this.z=i,this}clone(){return new Vec3(this.x,this.y,this.z)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}multiply(e){return this.x*=e,this.y*=e,this.z*=e,this}divide(e){return this.x/=e,this.y/=e,this.z/=e,this}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}normalize(){const e=this.length();return e>0&&this.divide(e),this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z}cross(e){const n=this.y*e.z-this.z*e.y,i=this.z*e.x-this.x*e.z,s=this.x*e.y-this.y*e.x;return this.x=n,this.y=i,this.z=s,this}distanceTo(e){const n=this.x-e.x,i=this.y-e.y,s=this.z-e.z;return Math.sqrt(n*n+i*i+s*s)}distanceToSquared(e){const n=this.x-e.x,i=this.y-e.y,s=this.z-e.z;return n*n+i*i+s*s}equals(e){return this.x===e.x&&this.y===e.y&&this.z===e.z}}class Box3{constructor(e=new Vec3(1/0,1/0,1/0),n=new Vec3(-1/0,-1/0,-1/0)){this.min=e,this.max=n}set(e,n){return this.min.copy(e),this.max.copy(n),this}setFromPoints(e){this.makeEmpty();for(let n=0;n<e.length;n++)this.expandByPoint(e[n]);return this}makeEmpty(){return this.min.x=this.min.y=this.min.z=1/0,this.max.x=this.max.y=this.max.z=-1/0,this}isEmpty(){return this.max.x<this.min.x||this.max.y<this.min.y||this.max.z<this.min.z}expandByPoint(e){return this.min.x=Math.min(this.min.x,e.x),this.min.y=Math.min(this.min.y,e.y),this.min.z=Math.min(this.min.z,e.z),this.max.x=Math.max(this.max.x,e.x),this.max.y=Math.max(this.max.y,e.y),this.max.z=Math.max(this.max.z,e.z),this}expandByScalar(e){return this.min.x-=e,this.min.y-=e,this.min.z-=e,this.max.x+=e,this.max.y+=e,this.max.z+=e,this}containsPoint(e){return e.x>=this.min.x&&e.x<=this.max.x&&e.y>=this.min.y&&e.y<=this.max.y&&e.z>=this.min.z&&e.z<=this.max.z}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z}intersectsBox(e){return e.max.x>=this.min.x&&e.min.x<=this.max.x&&e.max.y>=this.min.y&&e.min.y<=this.max.y&&e.max.z>=this.min.z&&e.min.z<=this.max.z}getCenter(e=new Vec3){return this.isEmpty()?e.set(0,0,0):e.set(.5*(this.min.x+this.max.x),.5*(this.min.y+this.max.y),.5*(this.min.z+this.max.z))}getSize(e=new Vec3){return this.isEmpty()?e.set(0,0,0):e.set(this.max.x-this.min.x,this.max.y-this.min.y,this.max.z-this.min.z)}clone(){return new Box3(this.min.clone(),this.max.clone())}copy(e){return this.min.copy(e.min),this.max.copy(e.max),this}union(e){return this.min.x=Math.min(this.min.x,e.min.x),this.min.y=Math.min(this.min.y,e.min.y),this.min.z=Math.min(this.min.z,e.min.z),this.max.x=Math.max(this.max.x,e.max.x),this.max.y=Math.max(this.max.y,e.max.y),this.max.z=Math.max(this.max.z,e.max.z),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}}var Y="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function getDefaultExportFromCjs(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function getAugmentedNamespace(e){if(e.__esModule)return e;var n=e.default;if("function"==typeof n){var i=function a(){return this instanceof a?Reflect.construct(n,arguments,this.constructor):n.apply(this,arguments)};i.prototype=n.prototype}else i={};return Object.defineProperty(i,"__esModule",{value:!0}),Object.keys(e).forEach(function(n){var s=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(i,n,s.get?s:{enumerable:!0,get:function(){return e[n]}})}),i}var q={exports:{}};!function(e){var n;function t(e,n){return e.b===n.b&&e.a===n.a}function u(e,n){return e.b<n.b||e.b===n.b&&e.a<=n.a}function v(e,n,i){var s=n.b-e.b,r=i.b-n.b;return 0<s+r?s<r?n.a-e.a+s/(s+r)*(e.a-i.a):n.a-i.a+r/(s+r)*(i.a-e.a):0}function x(e,n,i){var s=n.b-e.b,r=i.b-n.b;return 0<s+r?(n.a-i.a)*s+(n.a-e.a)*r:0}function z(e,n){return e.a<n.a||e.a===n.a&&e.b<=n.b}function aa(e,n,i){var s=n.a-e.a,r=i.a-n.a;return 0<s+r?s<r?n.b-e.b+s/(s+r)*(e.b-i.b):n.b-i.b+r/(s+r)*(i.b-e.b):0}function ba(e,n,i){var s=n.a-e.a,r=i.a-n.a;return 0<s+r?(n.b-i.b)*s+(n.b-e.b)*r:0}function ca(e){return u(e.b.a,e.a)}function da(e){return u(e.a,e.b.a)}function A(e,n,i,s){return(e=0>e?0:e)<=(i=0>i?0:i)?0===i?(n+s)/2:n+e/(e+i)*(s-n):s+i/(e+i)*(n-s)}function ea(e){var n=B(e.b);return C(n,e.c),C(n.b,e.c),D(n,e.a),n}function E(e,n){var i=!1,s=!1;e!==n&&(n.a!==e.a&&(s=!0,F(n.a,e.a)),n.d!==e.d&&(i=!0,G(n.d,e.d)),H(n,e),s||(C(n,e.a),e.a.c=e),i||(D(n,e.d),e.d.a=e))}function I(e){var n=e.b,i=!1;e.d!==e.b.d&&(i=!0,G(e.d,e.b.d)),e.c===e?F(e.a,null):(e.b.d.a=J(e),e.a.c=e.c,H(e,J(e)),i||D(e,e.d)),n.c===n?(F(n.a,null),G(n.d,null)):(e.d.a=J(n),n.a.c=n.c,H(n,J(n))),fa(e)}function K(e){var n=B(e),i=n.b;return H(n,e.e),n.a=e.b.a,C(i,n.a),n.d=i.d=e.d,n=n.b,H(e.b,J(e.b)),H(e.b,n),e.b.a=n.a,n.b.a.c=n.b,n.b.d=e.b.d,n.f=e.f,n.b.f=e.b.f,n}function L(e,n){var i=!1,s=B(e),r=s.b;return n.d!==e.d&&(i=!0,G(n.d,e.d)),H(s,e.e),H(r,n),s.a=e.b.a,r.a=n.a,s.d=r.d=e.d,e.d.a=r,i||D(s,e.d),s}function B(e){var n=new M,i=new M,s=e.b.h;return i.h=s,s.b.h=n,n.h=e,e.b.h=i,n.b=i,n.c=n,n.e=i,i.b=n,i.c=i,i.e=n}function H(e,n){var i=e.c,s=n.c;i.b.e=n,s.b.e=e,e.c=s,n.c=i}function C(e,n){var i=n.f,s=new N(n,i);i.e=s,n.f=s,i=s.c=e;do{i.a=s,i=i.c}while(i!==e)}function D(e,n){var i=n.d,s=new ga(n,i);i.b=s,n.d=s,s.a=e,s.c=n.c,i=e;do{i.d=s,i=i.e}while(i!==e)}function fa(e){var n=e.h;e=e.b.h,n.b.h=e,e.b.h=n}function F(e,n){var i=e.c,s=i;do{s.a=n,s=s.c}while(s!==i);i=e.f,(s=e.e).f=i,i.e=s}function G(e,n){var i=e.a,s=i;do{s.d=n,s=s.e}while(s!==i);i=e.d,(s=e.b).d=i,i.b=s}function ha(e){var n=0;return Math.abs(e[1])>Math.abs(e[0])&&(n=1),Math.abs(e[2])>Math.abs(e[n])&&(n=2),n}var i=4e150;function P(e,n){e.f+=n.f,e.b.f+=n.b.f}function ia(e,n,i){return e=e.a,n=n.a,i=i.a,n.b.a===e?i.b.a===e?u(n.a,i.a)?0>=x(i.b.a,n.a,i.a):0<=x(n.b.a,i.a,n.a):0>=x(i.b.a,e,i.a):i.b.a===e?0<=x(n.b.a,e,n.a):(n=v(n.b.a,e,n.a))>=(e=v(i.b.a,e,i.a))}function Q(e){e.a.i=null;var n=e.e;n.a.c=n.c,n.c.a=n.a,e.e=null}function ja(e,n){I(e.a),e.c=!1,e.a=n,n.i=e}function ka(e){var n=e.a.a;do{e=R(e)}while(e.a.a===n);return e.c&&(ja(e,n=L(S(e).a.b,e.a.e)),e=R(e)),e}function la(e,n,i){var s=new ma;return s.a=i,s.e=na(e.f,n.e,s),i.i=s}function oa(e,n){switch(e.s){case 100130:return!!(1&n);case 100131:return 0!==n;case 100132:return 0<n;case 100133:return 0>n;case 100134:return 2<=n||-2>=n}return!1}function pa(e){var n=e.a,i=n.d;i.c=e.d,i.a=n,Q(e)}function T(e,n,i){for(e=n,n=n.a;e!==i;){e.c=!1;var s=S(e),r=s.a;if(r.a!==n.a){if(!s.c){pa(e);break}ja(s,r=L(n.c.b,r.b))}n.c!==r&&(E(J(r),r),E(n,r)),pa(e),n=s.a,e=s}return n}function U(e,n,i,s,r,o){var h=!0;do{la(e,n,i.b),i=i.c}while(i!==s);for(null===r&&(r=S(n).a.b.c);(i=(s=S(n)).a.b).a===r.a;)i.c!==r&&(E(J(i),i),E(J(r),i)),s.f=n.f-i.f,s.d=oa(e,s.f),n.b=!0,!h&&qa(e,n)&&(P(i,r),Q(n),I(r)),h=!1,n=s,r=i;n.b=!0,o&&ra(e,n)}function sa(e,n,i,s,r){var o=[n.g[0],n.g[1],n.g[2]];n.d=null,n.d=e.o&&e.o(o,i,s,e.c)||null,null===n.d&&(r?e.n||(V(e,100156),e.n=!0):n.d=i[0])}function ta(e,n,i){var s=[null,null,null,null];s[0]=n.a.d,s[1]=i.a.d,sa(e,n.a,s,[.5,.5,0,0],!1),E(n,i)}function ua(e,n,i,s,r){var o=Math.abs(n.b-e.b)+Math.abs(n.a-e.a),h=Math.abs(i.b-e.b)+Math.abs(i.a-e.a),c=r+1;s[r]=.5*h/(o+h),s[c]=.5*o/(o+h),e.g[0]+=s[r]*n.g[0]+s[c]*i.g[0],e.g[1]+=s[r]*n.g[1]+s[c]*i.g[1],e.g[2]+=s[r]*n.g[2]+s[c]*i.g[2]}function qa(e,n){var i=S(n),s=n.a,r=i.a;if(u(s.a,r.a)){if(0<x(r.b.a,s.a,r.a))return!1;if(t(s.a,r.a)){if(s.a!==r.a){i=e.e;var o=s.a.h;if(0<=o){var h=(i=i.b).d,c=i.e,l=i.c,d=l[o];h[d]=h[i.a],l[h[d]]=d,d<=--i.a&&(1>=d||u(c[h[d>>1]],c[h[d]])?W(i,d):va(i,d)),c[o]=null,l[o]=i.b,i.b=o}else for(i.c[-(o+1)]=null;0<i.a&&null===i.c[i.d[i.a-1]];)--i.a;ta(e,J(r),s)}}else K(r.b),E(s,J(r)),n.b=i.b=!0}else{if(0>x(s.b.a,r.a,s.a))return!1;R(n).b=n.b=!0,K(s.b),E(J(r),s)}return!0}function wa(e,n){var i=S(n),s=n.a,r=i.a,o=s.a,h=r.a,c=s.b.a,l=r.b.a,d=new N;if(x(c,e.a,o),x(l,e.a,h),o===h||Math.min(o.a,c.a)>Math.max(h.a,l.a))return!1;if(u(o,h)){if(0<x(l,o,h))return!1}else if(0>x(c,h,o))return!1;var f,p,g=c,y=o,b=l,m=h;if(u(g,y)||(f=g,g=y,y=f),u(b,m)||(f=b,b=m,m=f),u(g,b)||(f=g,g=b,b=f,f=y,y=m,m=f),u(b,y)?u(y,m)?(0>(f=v(g,b,y))+(p=v(b,y,m))&&(f=-f,p=-p),d.b=A(f,b.b,p,y.b)):(0>(f=x(g,b,y))+(p=-x(g,m,y))&&(f=-f,p=-p),d.b=A(f,b.b,p,m.b)):d.b=(b.b+y.b)/2,z(g,y)||(f=g,g=y,y=f),z(b,m)||(f=b,b=m,m=f),z(g,b)||(f=g,g=b,b=f,f=y,y=m,m=f),z(b,y)?z(y,m)?(0>(f=aa(g,b,y))+(p=aa(b,y,m))&&(f=-f,p=-p),d.a=A(f,b.a,p,y.a)):(0>(f=ba(g,b,y))+(p=-ba(g,m,y))&&(f=-f,p=-p),d.a=A(f,b.a,p,m.a)):d.a=(b.a+y.a)/2,u(d,e.a)&&(d.b=e.a.b,d.a=e.a.a),g=u(o,h)?o:h,u(g,d)&&(d.b=g.b,d.a=g.a),t(d,o)||t(d,h))return qa(e,n),!1;if(!t(c,e.a)&&0<=x(c,e.a,d)||!t(l,e.a)&&0>=x(l,e.a,d)){if(l===e.a)return K(s.b),E(r.b,s),s=S(n=ka(n)).a,T(e,S(n),i),U(e,n,J(s),s,s,!0),!0;if(c===e.a){K(r.b),E(s.e,J(r)),h=(o=i=n).a.b.a;do{o=R(o)}while(o.a.b.a===h);return o=S(n=o).a.b.c,i.a=J(r),U(e,n,(r=T(e,i,null)).c,s.b.c,o,!0),!0}return 0<=x(c,e.a,d)&&(R(n).b=n.b=!0,K(s.b),s.a.b=e.a.b,s.a.a=e.a.a),0>=x(l,e.a,d)&&(n.b=i.b=!0,K(r.b),r.a.b=e.a.b,r.a.a=e.a.a),!1}return K(s.b),K(r.b),E(J(r),s),s.a.b=d.b,s.a.a=d.a,s.a.h=xa(e.e,s.a),s=s.a,r=[0,0,0,0],d=[o.d,c.d,h.d,l.d],s.g[0]=s.g[1]=s.g[2]=0,ua(s,o,c,r,0),ua(s,h,l,r,2),sa(e,s,d,r,!0),R(n).b=n.b=i.b=!0,!1}function ra(e,n){for(var i=S(n);;){for(;i.b;)n=i,i=S(i);if(!n.b&&(i=n,null===(n=R(n))||!n.b))break;n.b=!1;var s,r=n.a,o=i.a;if(s=r.b.a!==o.b.a)t:{var h=S(s=n),c=s.a,l=h.a,d=void 0;if(u(c.b.a,l.b.a)){if(0>x(c.b.a,l.b.a,c.a)){s=!1;break t}R(s).b=s.b=!0,d=K(c),E(l.b,d),d.d.c=s.d}else{if(0<x(l.b.a,c.b.a,l.a)){s=!1;break t}s.b=h.b=!0,d=K(l),E(c.e,l.b),d.b.d.c=s.d}s=!0}if(s&&(i.c?(Q(i),I(o),o=(i=S(n)).a):n.c&&(Q(n),I(r),r=(n=R(i)).a)),r.a!==o.a)if(r.b.a===o.b.a||n.c||i.c||r.b.a!==e.a&&o.b.a!==e.a)qa(e,n);else if(wa(e,n))break;r.a===o.a&&r.b.a===o.b.a&&(P(o,r),Q(n),I(r),n=R(i))}}function ya(e,n){e.a=n;for(var i=n.c;null===i.i;)if((i=i.c)===n.c){i=e;var s=n;(h=new ma).a=s.c.b;var r=(l=i.f).a;do{r=r.a}while(null!==r.b&&!l.c(l.b,h,r.b));var o=S(l=r.b),h=l.a;r=o.a;if(0===x(h.b.a,s,h.a))t((h=l.a).a,s)||t(h.b.a,s)||(K(h.b),l.c&&(I(h.c),l.c=!1),E(s.c,h),ya(i,s));else{var c=u(r.b.a,h.b.a)?l:o;o=void 0;l.d||c.c?(o=c===l?L(s.c.b,h.e):L(r.b.c.b,s.c).b,c.c?ja(c,o):(h=i,(l=la(i,l,o)).f=R(l).f+l.a.f,l.d=oa(h,l.f)),ya(i,s)):U(i,l,s.c,s.c,null,!0)}return}if(l=(h=S(i=ka(i.i))).a,(h=T(e,h,null)).c===l){h=(l=h).c,r=S(i),o=i.a,c=r.a;var l,d=!1;o.b.a!==c.b.a&&wa(e,i),t(o.a,e.a)&&(E(J(h),o),h=S(i=ka(i)).a,T(e,S(i),r),d=!0),t(c.a,e.a)&&(E(l,J(c)),l=T(e,r,null),d=!0),d?U(e,i,l.c,h,h,!0):(s=u(c.a,o.a)?J(c):o,U(e,i,s=L(l.c.b,s),s.c,s.c,!1),s.b.i.c=!0,ra(e,i))}else U(e,i,h.c,l,l,!0)}function za(e,n){var s=new ma,r=ea(e.b);r.a.b=i,r.a.a=n,r.b.a.b=-i,r.b.a.a=n,e.a=r.b.a,s.a=r,s.f=0,s.d=!1,s.c=!1,s.h=!0,s.b=!1,r=na(r=e.f,r.a,s),s.e=r}function Aa(e){this.a=new Ba,this.b=e,this.c=ia}function na(e,n,i){do{n=n.c}while(null!==n.b&&!e.c(e.b,n.b,i));return e=new Ba(i,n.a,n),n.a.c=e,n.a=e}function Ba(e,n,i){this.b=e||null,this.a=n||this,this.c=i||this}function X(){this.d=s,this.p=this.b=this.q=null,this.j=[0,0,0],this.s=100130,this.n=!1,this.o=this.a=this.e=this.f=null,this.m=!1,this.c=this.r=this.i=this.k=this.l=this.h=null}var s=0;function Z(e,n){if(e.d!==n)for(;e.d!==n;)if(e.d<n)switch(e.d){case s:V(e,100151),e.u(null);break;case 1:V(e,100152),e.t()}else switch(e.d){case 2:V(e,100154),e.v();break;case 1:V(e,100153),e.w()}}function V(e,n){e.p&&e.p(n,e.c)}function ga(e,n){this.b=e||this,this.d=n||this,this.a=null,this.c=!1}function M(){this.h=this,this.i=this.d=this.a=this.e=this.c=this.b=null,this.f=0}function J(e){return e.b.e}function Ca(){this.c=new N,this.a=new ga,this.b=new M,this.d=new M,this.b.b=this.d,this.d.b=this.b}function N(e,n){this.e=e||this,this.f=n||this,this.d=this.c=null,this.g=[0,0,0],this.h=this.a=this.b=0}function Da(){this.c=[],this.d=null,this.a=0,this.e=!1,this.b=new Ha}function xa(e,n){if(e.e){var i,s=e.b,r=++s.a;return 2*r>s.f&&(s.f*=2,s.c=Ja(s.c,s.f+1)),0===s.b?i=r:(i=s.b,s.b=s.c[s.b]),s.e[i]=n,s.c[i]=r,s.d[r]=i,s.h&&va(s,r),i}return s=e.a++,e.c[s]=n,-(s+1)}function Fa(e){if(0===e.a)return Ka(e.b);var n=e.c[e.d[e.a-1]];if(0!==e.b.a&&u(Ga(e.b),n))return Ka(e.b);do{--e.a}while(0<e.a&&null===e.c[e.d[e.a-1]]);return n}function Ha(){this.d=Ja([0],33),this.e=[null,null],this.c=[0,0],this.a=0,this.f=32,this.b=0,this.h=!1,this.d[1]=1}function Ja(e,n){for(var i=Array(n),s=0;s<e.length;s++)i[s]=e[s];for(;s<n;s++)i[s]=0;return i}function Ga(e){return e.e[e.d[1]]}function Ka(e){var n=e.d,i=e.e,s=e.c,r=n[1],o=i[r];return 0<e.a&&(n[1]=n[e.a],s[n[1]]=1,i[r]=null,s[r]=e.b,e.b=r,0<--e.a&&W(e,1)),o}function W(e,n){for(var i=e.d,s=e.e,r=e.c,o=n,h=i[o];;){var c=o<<1;c<e.a&&u(s[i[c+1]],s[i[c]])&&(c+=1);var l=i[c];if(c>e.a||u(s[h],s[l])){i[o]=h,r[h]=o;break}i[o]=l,r[l]=o,o=c}}function va(e,n){for(var i=e.d,s=e.e,r=e.c,o=n,h=i[o];;){var c=o>>1,l=i[c];if(0===c||u(s[l],s[h])){i[o]=h,r[h]=o;break}i[o]=l,r[l]=o,o=c}}function ma(){this.e=this.a=null,this.f=0,this.c=this.b=this.h=this.d=!1}function S(e){return e.e.c.b}function R(e){return e.e.a.b}(n=X.prototype).x=function(){Z(this,s)},n.B=function(e,n){switch(e){case 100142:return;case 100140:switch(n){case 100130:case 100131:case 100132:case 100133:case 100134:return void(this.s=n)}break;case 100141:return void(this.m=!!n);default:return void V(this,100900)}V(this,100901)},n.y=function(e){switch(e){case 100142:return 0;case 100140:return this.s;case 100141:return this.m;default:V(this,100900)}return!1},n.A=function(e,n,i){this.j[0]=e,this.j[1]=n,this.j[2]=i},n.z=function(e,n){var i=n||null;switch(e){case 100100:case 100106:this.h=i;break;case 100104:case 100110:this.l=i;break;case 100101:case 100107:this.k=i;break;case 100102:case 100108:this.i=i;break;case 100103:case 100109:this.p=i;break;case 100105:case 100111:this.o=i;break;case 100112:this.r=i;break;default:V(this,100900)}},n.C=function(e,n){var i=!1,s=[0,0,0];Z(this,2);for(var r=0;3>r;++r){var o=e[r];-1e150>o&&(o=-1e150,i=!0),1e150<o&&(o=1e150,i=!0),s[r]=o}i&&V(this,100155),null===(i=this.q)?E(i=ea(this.b),i.b):(K(i),i=i.e),i.a.d=n,i.a.g[0]=s[0],i.a.g[1]=s[1],i.a.g[2]=s[2],i.f=1,i.b.f=-1,this.q=i},n.u=function(e){Z(this,s),this.d=1,this.b=new Ca,this.c=e},n.t=function(){Z(this,1),this.d=2,this.q=null},n.v=function(){Z(this,2),this.d=1},n.w=function(){Z(this,1),this.d=s;var e=!1,n=[l=this.j[0],r=this.j[1],h=this.j[2]];if(0===l&&0===r&&0===h){for(var r=[-2e150,-2e150,-2e150],o=[2e150,2e150,2e150],h=[],c=[],l=(e=this.b.c).e;l!==e;l=l.e)for(var d=0;3>d;++d){var f=l.g[d];f<o[d]&&(o[d]=f,c[d]=l),f>r[d]&&(r[d]=f,h[d]=l)}if(l=0,r[1]-o[1]>r[0]-o[0]&&(l=1),r[2]-o[2]>r[l]-o[l]&&(l=2),o[l]>=r[l])n[0]=0,n[1]=0,n[2]=1;else{for(r=0,o=c[l],h=h[l],c=[0,0,0],o=[o.g[0]-h.g[0],o.g[1]-h.g[1],o.g[2]-h.g[2]],d=[0,0,0],l=e.e;l!==e;l=l.e)d[0]=l.g[0]-h.g[0],d[1]=l.g[1]-h.g[1],d[2]=l.g[2]-h.g[2],c[0]=o[1]*d[2]-o[2]*d[1],c[1]=o[2]*d[0]-o[0]*d[2],c[2]=o[0]*d[1]-o[1]*d[0],(f=c[0]*c[0]+c[1]*c[1]+c[2]*c[2])>r&&(r=f,n[0]=c[0],n[1]=c[1],n[2]=c[2]);0>=r&&(n[0]=n[1]=n[2]=0,n[ha(o)]=1)}e=!0}for(c=ha(n),l=this.b.c,r=(c+1)%3,h=(c+2)%3,c=0<n[c]?1:-1,n=l.e;n!==l;n=n.e)n.b=n.g[r],n.a=c*n.g[h];if(e){for(n=0,l=(e=this.b.a).b;l!==e;l=l.b)if(!(0>=(r=l.a).f))do{n+=(r.a.b-r.b.a.b)*(r.a.a+r.b.a.a),r=r.e}while(r!==l.a);if(0>n)for(e=(n=this.b.c).e;e!==n;e=e.e)e.a=-e.a}for(this.n=!1,l=(n=this.b.b).h;l!==n;l=e)e=l.h,r=l.e,t(l.a,l.b.a)&&l.e.e!==l&&(ta(this,r,l),I(l),r=(l=r).e),r.e===l&&(r!==l&&(r!==e&&r!==e.b||(e=e.h),I(r)),l!==e&&l!==e.b||(e=e.h),I(l));for(this.e=n=new Da,l=(e=this.b.c).e;l!==e;l=l.e)l.h=xa(n,l);for(function(e){e.d=[];for(var n=0;n<e.a;n++)e.d[n]=n;e.d.sort(function(e){return function(n,i){return u(e[n],e[i])?1:-1}}(e.c)),e.e=!0,function(e){for(var n=e.a;1<=n;--n)W(e,n);e.h=!0}(e.b)}(n),this.f=new Aa(this),za(this,-i),za(this,i);null!==(n=Fa(this.e));){for(;;){t:if(l=this.e,0===l.a)e=Ga(l.b);else if(e=l.c[l.d[l.a-1]],0!==l.b.a&&(l=Ga(l.b),u(l,e))){e=l;break t}if(null===e||!t(e,n))break;e=Fa(this.e),ta(this,n.c,e.c)}ya(this,n)}for(this.a=this.f.a.a.b.a.a,n=0;null!==(e=this.f.a.a.b);)e.h||++n,Q(e);for(this.f=null,(n=this.e).b=null,n.d=null,this.e=n.c=null,l=(n=this.b).a.b;l!==n.a;l=e)e=l.b,(l=l.a).e.e===l&&(P(l.c,l),I(l));if(!this.n){if(n=this.b,this.m)for(l=n.b.h;l!==n.b;l=e)e=l.h,l.b.d.c!==l.d.c?l.f=l.d.c?1:-1:I(l);else for(l=n.a.b;l!==n.a;l=e)if(e=l.b,l.c){for(l=l.a;u(l.b.a,l.a);l=l.c.b);for(;u(l.a,l.b.a);l=l.e);for(r=l.c.b,h=void 0;l.e!==r;)if(u(l.b.a,r.a)){for(;r.e!==l&&(ca(r.e)||0>=x(r.a,r.b.a,r.e.b.a));)r=(h=L(r.e,r)).b;r=r.c.b}else{for(;r.e!==l&&(da(l.c.b)||0<=x(l.b.a,l.a,l.c.b.a));)l=(h=L(l,l.c.b)).b;l=l.e}for(;r.e.e!==l;)r=(h=L(r.e,r)).b}if(this.h||this.i||this.k||this.l)if(this.m){for(e=(n=this.b).a.b;e!==n.a;e=e.b)if(e.c){this.h&&this.h(2,this.c),l=e.a;do{this.k&&this.k(l.a.d,this.c),l=l.e}while(l!==e.a);this.i&&this.i(this.c)}}else{for(n=this.b,e=!!this.l,l=!1,r=-1,h=n.a.d;h!==n.a;h=h.d)if(h.c){l||(this.h&&this.h(4,this.c),l=!0),c=h.a;do{e&&(r!==(o=c.b.d.c?0:1)&&(r=o,this.l&&this.l(!!r,this.c))),this.k&&this.k(c.a.d,this.c),c=c.e}while(c!==h.a)}l&&this.i&&this.i(this.c)}if(this.r){for(l=(n=this.b).a.b;l!==n.a;l=e)if(e=l.b,!l.c){h=(r=l.a).e,c=void 0;do{h=(c=h).e,c.d=null,null===c.b.d&&(c.c===c?F(c.a,null):(c.a.c=c.c,H(c,J(c))),(o=c.b).c===o?F(o.a,null):(o.a.c=o.c,H(o,J(o))),fa(c))}while(c!==r);r=l.d,(l=l.b).d=r,r.b=l}return this.r(this.b),void(this.c=this.b=null)}}this.b=this.c=null},Y.libtess={GluTesselator:X,windingRule:{GLU_TESS_WINDING_ODD:100130,GLU_TESS_WINDING_NONZERO:100131,GLU_TESS_WINDING_POSITIVE:100132,GLU_TESS_WINDING_NEGATIVE:100133,GLU_TESS_WINDING_ABS_GEQ_TWO:100134},primitiveType:{GL_LINE_LOOP:2,GL_TRIANGLES:4,GL_TRIANGLE_STRIP:5,GL_TRIANGLE_FAN:6},errorType:{GLU_TESS_MISSING_BEGIN_POLYGON:100151,GLU_TESS_MISSING_END_POLYGON:100153,GLU_TESS_MISSING_BEGIN_CONTOUR:100152,GLU_TESS_MISSING_END_CONTOUR:100154,GLU_TESS_COORD_TOO_LARGE:100155,GLU_TESS_NEED_COMBINE_CALLBACK:100156},gluEnum:{GLU_TESS_MESH:100112,GLU_TESS_TOLERANCE:100142,GLU_TESS_WINDING_RULE:100140,GLU_TESS_BOUNDARY_ONLY:100141,GLU_INVALID_ENUM:100900,GLU_INVALID_VALUE:100901,GLU_TESS_BEGIN:100100,GLU_TESS_VERTEX:100101,GLU_TESS_END:100102,GLU_TESS_ERROR:100103,GLU_TESS_EDGE_FLAG:100104,GLU_TESS_COMBINE:100105,GLU_TESS_BEGIN_DATA:100106,GLU_TESS_VERTEX_DATA:100107,GLU_TESS_END_DATA:100108,GLU_TESS_ERROR_DATA:100109,GLU_TESS_EDGE_FLAG_DATA:100110,GLU_TESS_COMBINE_DATA:100111}},X.prototype.gluDeleteTess=X.prototype.x,X.prototype.gluTessProperty=X.prototype.B,X.prototype.gluGetTessProperty=X.prototype.y,X.prototype.gluTessNormal=X.prototype.A,X.prototype.gluTessCallback=X.prototype.z,X.prototype.gluTessVertex=X.prototype.C,X.prototype.gluTessBeginPolygon=X.prototype.u,X.prototype.gluTessBeginContour=X.prototype.t,X.prototype.gluTessEndContour=X.prototype.v,X.prototype.gluTessEndPolygon=X.prototype.w,e.exports=Y.libtess}(q);var tt=q.exports;class Tessellator{process(e,n=!0,s=!1){if(0===e.length)return{triangles:{vertices:[],indices:[]},contours:[]};const r=e.filter(e=>e.points.length>=3);return 0===r.length?{triangles:{vertices:[],indices:[]},contours:[]}:(i.log(`Tessellator: removeOverlaps=${n}, processing ${r.length} paths`),this.tessellate(r,n,s))}tessellate(e,n,s){const r=s||n?e:e.map(e=>this.reverseWinding(e));let o=this.pathsToContours(r);if(n){i.log("Two-pass: boundary extraction then triangulation");const e=this.performTessellation(o,"boundary");if(!e)return i.warn("libtess returned empty result from boundary pass"),{triangles:{vertices:[],indices:[]},contours:[]};o=this.boundaryToContours(e),i.log(`Boundary pass created ${o.length} contours. Starting triangulation pass.`)}else i.log("Single-pass triangulation for "+(s?"CFF":"TTF"));const h=this.performTessellation(o,"triangles");if(!h){const e=n?"libtess returned empty result from triangulation pass":"libtess returned empty result from single-pass triangulation";return i.warn(e),{triangles:{vertices:[],indices:[]},contours:o}}return{triangles:{vertices:h.vertices,indices:h.indices||[]},contours:o}}pathsToContours(e){return e.map(e=>{const n=[];for(const i of e.points)n.push(i.x,i.y);return n})}performTessellation(e,n){const s=new tt.GluTesselator;s.gluTessProperty(tt.gluEnum.GLU_TESS_WINDING_RULE,tt.windingRule.GLU_TESS_WINDING_NONZERO);const r=[],o=[],h=[];let c=[];"boundary"===n&&s.gluTessProperty(tt.gluEnum.GLU_TESS_BOUNDARY_ONLY,!0),"triangles"===n?s.gluTessCallback(tt.gluEnum.GLU_TESS_VERTEX_DATA,e=>{o.push(e)}):(s.gluTessCallback(tt.gluEnum.GLU_TESS_BEGIN,()=>{c=[]}),s.gluTessCallback(tt.gluEnum.GLU_TESS_VERTEX_DATA,e=>{c.push(e)}),s.gluTessCallback(tt.gluEnum.GLU_TESS_END,()=>{c.length>0&&h.push([...c])})),s.gluTessCallback(tt.gluEnum.GLU_TESS_COMBINE,e=>{const n=r.length/2;return r.push(e[0],e[1]),n}),s.gluTessCallback(tt.gluEnum.GLU_TESS_ERROR,e=>{i.warn(`libtess error: ${e}`)}),s.gluTessNormal(0,0,1),s.gluTessBeginPolygon(null);for(const n of e){s.gluTessBeginContour();for(let e=0;e<n.length;e+=2){const i=r.length/2;r.push(n[e],n[e+1]),s.gluTessVertex([n[e],n[e+1],0],i)}s.gluTessEndContour()}return s.gluTessEndPolygon(),0===r.length?null:"triangles"===n?{vertices:r,indices:o}:{vertices:r,contourIndices:h}}boundaryToContours(e){if(!e.contourIndices)return[];const n=[];for(const i of e.contourIndices){const s=[];for(const n of i){const i=2*n;s.push(e.vertices[i],e.vertices[i+1])}s.length>2&&(s[0]===s[s.length-2]&&s[1]===s[s.length-1]||s.push(s[0],s[1])),n.push(s)}return n}reverseWinding(e){return{...e,points:[...e.points].reverse()}}}class Extruder{constructor(){}extrude(e,n=0,i){const s=[],r=[],o=[];if(0===n)this.addFlatFaces(e.triangles,s,r,o);else{this.addFrontAndBackFaces(e.triangles,s,r,o,n,i);for(const i of e.contours)this.addSideWalls(i,s,r,o,n)}return{vertices:s,normals:r,indices:o}}addFlatFaces(e,n,i,s){const r=n.length/3,o=e.vertices,h=e.indices;for(let e=0;e<o.length;e+=2)n.push(o[e],o[e+1],0),i.push(0,0,-1);for(let e=0;e<h.length;e++)s.push(r+h[e])}addFrontAndBackFaces(e,n,i,s,r,o){const h=n.length/3,c=e.vertices,l=e.indices;for(let e=0;e<c.length;e+=2)n.push(c[e],c[e+1],0),i.push(0,0,-1);const d=25e-6*o,f=r<=d?d:r;for(let e=0;e<c.length;e+=2)n.push(c[e],c[e+1],f),i.push(0,0,1);const p=c.length/2;for(let e=0;e<l.length;e++)s.push(h+l[e]);for(let e=l.length-1;e>=0;e--)s.push(h+l[e]+p)}addSideWalls(e,n,i,s,r){for(let o=0;o<e.length-2;o+=2){const h=e[o],c=e[o+1],l=e[o+2],d=e[o+3],f=new Vec2(l-h,d-c),p=new Vec2(f.y,-f.x).normalize(),g=n.length/3;n.push(h,c,0,l,d,0,h,c,r,l,d,r),i.push(p.x,p.y,0,p.x,p.y,0,p.x,p.y,0,p.x,p.y,0),s.push(g,g+1,g+2,g+1,g+3,g+2)}}}class BoundaryClusterer{constructor(){}cluster(e,n){return 0===e.length?[]:this.clusterSweepLine(e,n)}clusterSweepLine(e,n){const i=e.length;if(i<=1)return 0===i?[]:[[0]];const s=new Array(i),r=new Array(2*i);let o=0;for(let h=0;h<i;h++)s[h]=this.getWorldBounds(e[h],n[h]),r[o++]=[s[h].minX,0,h],r[o++]=[s[h].maxX,1,h];r.sort((e,n)=>e[0]-n[0]||e[1]-n[1]);const h=Array.from({length:i},(e,n)=>n),c=new Array(i).fill(0);function find(e){return h[e]===e?e:h[e]=find(h[e])}function union(e,n){const i=find(e),s=find(n);i!==s&&(c[i]<c[s]?h[i]=s:c[i]>c[s]?h[s]=i:(h[s]=i,c[i]++))}const l=new Set;for(const[,e,n]of r)if(0===e){const e=s[n];for(const i of l){const r=s[i];e.minY<r.maxY+.001&&e.maxY>r.minY-.001&&union(n,i)}l.add(n)}else l.delete(n);const d=new Map;for(let e=0;e<i;e++){const n=find(e);d.has(n)||d.set(n,[]),d.get(n).push(e)}return Array.from(d.values())}getWorldBounds(e,n){return{minX:e.bounds.min.x+n.x,minY:e.bounds.min.y+n.y,maxX:e.bounds.max.x+n.x,maxY:e.bounds.max.y+n.y}}}class MinHeap{constructor(e){this.heap=[],this.itemIndex=new Map,this.compare=e}insert(e){const n=this.itemIndex.get(e);if(void 0!==n)return this.siftUp(n),void this.siftDown(n);const i=this.heap.length;this.heap.push(e),this.itemIndex.set(e,i),this.siftUp(i)}extractMin(){const e=this.heap.length;if(!e)return;if(1===e){const e=this.heap.pop();return this.itemIndex.clear(),e}const n=this.heap[0],i=this.heap.pop();return this.heap[0]=i,this.itemIndex.delete(n),this.itemIndex.set(i,0),this.siftDown(0),n}update(e){const n=this.itemIndex.get(e);void 0!==n?(this.siftUp(n),this.siftDown(n)):this.insert(e)}isEmpty(){return!this.heap.length}swap(e,n){const i=this.heap[e],s=this.heap[n];this.heap[e]=s,this.heap[n]=i,this.itemIndex.set(i,n),this.itemIndex.set(s,e)}siftUp(e){const n=this.heap[e];for(;e>0;){const i=e-1>>1,s=this.heap[i];if(this.compare(n,s)>=0)break;this.heap[e]=s,this.itemIndex.set(s,e),e=i}this.heap[e]=n,this.itemIndex.set(n,e)}siftDown(e){const n=this.heap[e],i=this.heap.length,s=i>>1;for(;e<s;){const s=1+(e<<1),r=s+1;let o=e,h=n;const c=this.heap[s];if(this.compare(c,h)<0&&(o=s,h=c),r<i){const e=this.heap[r];this.compare(e,h)<0&&(o=r,h=e)}if(o===e)break;this.heap[e]=h,this.itemIndex.set(h,e),e=o}this.heap[e]=n,this.itemIndex.set(n,e)}}const et={enabled:!0,areaThreshold:1,colinearThreshold:.0087,minSegmentLength:10};class PathOptimizer{constructor(e){this.stats={pointsRemovedByVisvalingam:0,pointsRemovedByColinear:0,originalPointCount:0},this.config=e}setConfig(e){this.config=e}optimizePath(e){if(!this.config.enabled||e.points.length<=2)return e;this.stats.originalPointCount+=e.points.length;let n=[...e.points];return n.length<5?e:(n=this.simplifyPathVW(n,this.config.areaThreshold),n.length<3?e:(n=this.removeColinearPoints(n,this.config.colinearThreshold),n.length<3?e:{...e,points:n}))}simplifyPathVW(e,n){if(e.length<=3)return e;const i=e.length,s=e.map((e,n)=>({index:n,area:1/0,prev:null,next:null}));for(let e=0;e<s.length;e++)s[e].prev=s[e-1]||null,s[e].next=s[e+1]||null;const r=new MinHeap((e,n)=>e.area-n.area);for(let n=1;n<s.length-1;n++){const i=s[n];i.area=this.calculateTriangleArea(e[i.prev.index],e[i.index],e[i.next.index]),r.insert(i)}let o=i;for(;!r.isEmpty()&&o>3;){const i=r.extractMin();if(!i||i.area>n)break;if(this.config.minSegmentLength>0&&i.prev&&i.next){const n=e[i.prev.index],s=e[i.index],r=e[i.next.index],o=n.distanceTo(s),h=s.distanceTo(r);if(o<this.config.minSegmentLength||h<this.config.minSegmentLength)continue}i.prev&&(i.prev.next=i.next),i.next&&(i.next.prev=i.prev),o--,i.prev&&i.prev.prev&&(i.prev.area=this.calculateTriangleArea(e[i.prev.prev.index],e[i.prev.index],e[i.next.index]),r.update(i.prev)),i.next&&i.next.next&&(i.next.area=this.calculateTriangleArea(e[i.prev.index],e[i.next.index],e[i.next.next.index]),r.update(i.next))}const h=[];let c=s[0];for(;c;)h.push(e[c.index]),c=c.next;const l=i-h.length;return this.stats.pointsRemovedByVisvalingam+=l,h}removeColinearPoints(e,n){if(e.length<=2)return e;const i=[e[0]];for(let s=1;s<e.length-1;s++){const r=e[s-1],o=e[s],h=e[s+1],c=new Vec2(o.x-r.x,o.y-r.y),l=new Vec2(h.x-o.x,h.y-o.y),d=Math.abs(c.angle()-l.angle());Math.min(d,2*Math.PI-d)>n||c.length()<this.config.minSegmentLength||l.length()<this.config.minSegmentLength?i.push(o):this.stats.pointsRemovedByColinear++}return i.push(e[e.length-1]),i}calculateTriangleArea(e,n,i){return Math.abs((e.x*(n.y-i.y)+n.x*(i.y-e.y)+i.x*(e.y-n.y))/2)}getStats(){return{...this.stats}}resetStats(){this.stats={pointsRemovedByVisvalingam:0,pointsRemovedByColinear:0,originalPointCount:0}}}const nt={distanceTolerance:.5,angleTolerance:.2},it=1e-6;class Polygonizer{constructor(e){this.curveFidelityConfig={...nt,...e}}setCurveFidelityConfig(e){this.curveFidelityConfig={...nt,...e}}polygonizeQuadratic(e,n,i){const s=[];return this.recursiveQuadratic(e.x,e.y,n.x,n.y,i.x,i.y,s),this.addPoint(i.x,i.y,s),s}polygonizeCubic(e,n,i,s){const r=[];return this.recursiveCubic(e.x,e.y,n.x,n.y,i.x,i.y,s.x,s.y,r),this.addPoint(s.x,s.y,r),r}recursiveQuadratic(e,n,i,s,r,o,h,c=0){if(c>16)return;const l=(e+i)/2,d=(n+s)/2,f=(i+r)/2,p=(s+o)/2,g=(l+f)/2,y=(d+p)/2,b=r-e,m=o-n,_=Math.abs((i-r)*m-(s-o)*b),w=this.curveFidelityConfig.distanceTolerance??nt.distanceTolerance,O=w*w;if(_>it){if(_*_<=O*(b*b+m*m)){const c=this.curveFidelityConfig.angleTolerance??nt.angleTolerance;if(!(c>0))return void this.addPoint(i,s,h);{let l=Math.abs(Math.atan2(o-s,r-i)-Math.atan2(s-n,i-e));if(l>=Math.PI&&(l=2*Math.PI-l),l<c)return void this.addPoint(i,s,h)}}}else{const r=b*b+m*m;if(0===r){if((i-e)*(i-e)+(s-n)*(s-n)<=O)return void this.addPoint(i,s,h)}else{const o=((i-e)*b+(s-n)*m)/r;if(o>0&&o<1&&_*_<=O*r)return void this.addPoint(i,s,h)}}this.recursiveQuadratic(e,n,l,d,g,y,h,c+1),this.recursiveQuadratic(g,y,f,p,r,o,h,c+1)}recursiveCubic(e,n,i,s,r,o,h,c,l,d=0){if(d>16)return;const f=(e+i)/2,p=(n+s)/2,g=(i+r)/2,y=(s+o)/2,b=(r+h)/2,m=(o+c)/2,_=(f+g)/2,w=(p+y)/2,O=(g+b)/2,k=(y+m)/2,j=(_+O)/2,$=(w+k)/2,Y=h-e,q=c-n,tt=Math.abs((i-h)*q-(s-c)*Y),et=Math.abs((r-h)*q-(o-c)*Y),st=this.curveFidelityConfig.distanceTolerance??nt.distanceTolerance,rt=st*st;let at=0;switch(tt>it&&(at|=1),et>it&&(at|=2),at){case 0:const d=Y*Y+q*q;if(0===d){if((i-e)*(i-e)+(s-n)*(s-n)<=rt&&(r-e)*(r-e)+(o-n)*(o-n)<=rt)return this.addPoint(i,s,l),void this.addPoint(r,o,l)}else{const h=((i-e)*Y+(s-n)*q)/d,c=((r-e)*Y+(o-n)*q)/d;if(h>0&&h<1&&c>0&&c<1&&(tt+et)*(tt+et)<=rt*d)return this.addPoint(i,s,l),void this.addPoint(r,o,l)}break;case 1:if(et*et<=rt*(Y*Y+q*q)){const e=this.curveFidelityConfig.angleTolerance??nt.angleTolerance;if(!(e>0))return this.addPoint(i,s,l),void this.addPoint(r,o,l);{let n=Math.abs(Math.atan2(c-o,h-r)-Math.atan2(o-s,r-i));if(n>=Math.PI&&(n=2*Math.PI-n),n<e)return this.addPoint(i,s,l),void this.addPoint(r,o,l)}}break;case 2:if(tt*tt<=rt*(Y*Y+q*q)){const h=this.curveFidelityConfig.angleTolerance??nt.angleTolerance;if(!(h>0))return this.addPoint(i,s,l),void this.addPoint(r,o,l);{let c=Math.abs(Math.atan2(o-s,r-i)-Math.atan2(s-n,i-e));if(c>=Math.PI&&(c=2*Math.PI-c),c<h)return this.addPoint(i,s,l),void this.addPoint(r,o,l)}}break;case 3:if((tt+et)*(tt+et)<=rt*(Y*Y+q*q)){const d=this.curveFidelityConfig.angleTolerance??nt.angleTolerance;if(!(d>0))return this.addPoint(i,s,l),void this.addPoint(r,o,l);{let f=Math.abs(Math.atan2(o-s,r-i)-Math.atan2(s-n,i-e)),p=Math.abs(Math.atan2(c-o,h-r)-Math.atan2(o-s,r-i));if(f>=Math.PI&&(f=2*Math.PI-f),p>=Math.PI&&(p=2*Math.PI-p),f+p<d)return this.addPoint(i,s,l),void this.addPoint(r,o,l)}}}this.recursiveCubic(e,n,f,p,_,w,j,$,l,d+1),this.recursiveCubic(j,$,O,k,b,m,h,c,l,d+1)}addPoint(e,n,i){const s=new Vec2(e,n);if(0===i.length)return void i.push(s);const r=i[i.length-1],o=s.x-r.x,h=s.y-r.y;o*o+h*h>1e-12&&i.push(s)}}class GlyphContourCollector{constructor(e,n){this.currentGlyphId=0,this.currentTextIndex=0,this.currentGlyphPaths=[],this.currentPath=null,this.currentPoint=null,this.currentGlyphBounds={min:new Vec2(1/0,1/0),max:new Vec2(-1/0,-1/0)},this.collectedGlyphs=[],this.glyphPositions=[],this.glyphTextIndices=[],this.currentPosition=new Vec2(0,0),this.polygonizer=new Polygonizer(e),this.pathOptimizer=new PathOptimizer({...et,...n})}setPosition(e,n){this.currentPosition.set(e,n)}updatePosition(e,n){this.currentPosition.x+=e,this.currentPosition.y+=n}beginGlyph(e,n){this.currentGlyphPaths.length>0&&this.finishGlyph(),this.currentGlyphId=e,this.currentTextIndex=n,this.currentGlyphPaths=[],this.currentGlyphBounds.min.set(1/0,1/0),this.currentGlyphBounds.max.set(-1/0,-1/0),this.glyphPositions.push(this.currentPosition.clone())}finishGlyph(){this.currentPath&&this.finishPath(),this.currentGlyphPaths.length>0&&(this.collectedGlyphs.push({glyphId:this.currentGlyphId,paths:[...this.currentGlyphPaths],bounds:{min:{x:this.currentGlyphBounds.min.x,y:this.currentGlyphBounds.min.y},max:{x:this.currentGlyphBounds.max.x,y:this.currentGlyphBounds.max.y}}}),this.glyphTextIndices.push(this.currentTextIndex)),this.currentGlyphPaths=[]}onMoveTo(e,n){this.currentPath&&this.finishPath(),this.currentPoint=new Vec2(e,n),this.updateBounds(this.currentPoint),this.currentPath={points:[this.currentPoint],glyphIndex:this.currentGlyphId}}onLineTo(e,n){if(!this.currentPath||!this.currentPoint)return;const i=new Vec2(e,n);this.updateBounds(i),this.currentPath.points.push(i),this.currentPoint=i}onQuadTo(e,n,i,s){if(!this.currentPath||!this.currentPoint)return;const r=this.currentPoint,o=new Vec2(e,n),h=new Vec2(i,s),c=h.x-r.x,l=h.y-r.y;if(Math.abs((o.x-h.x)*l-(o.y-h.y)*c)<it)return void this.onLineTo(i,s);const d=this.polygonizer.polygonizeQuadratic(r,o,h);for(const e of d)this.updateBounds(e);for(let e=0;e<d.length;e++)this.currentPath.points.push(d[e]);this.currentPoint=h}onCubicTo(e,n,i,s,r,o){if(!this.currentPath||!this.currentPoint)return;const h=this.currentPoint,c=new Vec2(e,n),l=new Vec2(i,s),d=new Vec2(r,o),f=d.x-h.x,p=d.y-h.y,g=Math.abs((c.x-d.x)*p-(c.y-d.y)*f),y=Math.abs((l.x-d.x)*p-(l.y-d.y)*f);if(g<it&&y<it)return void this.onLineTo(r,o);const b=this.polygonizer.polygonizeCubic(h,c,l,d);for(const e of b)this.updateBounds(e);for(let e=0;e<b.length;e++)this.currentPath.points.push(b[e]);this.currentPoint=d}onClosePath(){if(!this.currentPath||!this.currentPoint)return;const e=this.currentPath.points[0];this.currentPoint.equals(e)||this.currentPath.points.push(e),this.finishPath()}finishPath(){if(this.currentPath){const e=this.pathOptimizer.optimizePath(this.currentPath);this.currentGlyphPaths.push(e),this.currentPath=null,this.currentPoint=null}}updateBounds(e){this.currentGlyphBounds.min.x=Math.min(this.currentGlyphBounds.min.x,e.x),this.currentGlyphBounds.min.y=Math.min(this.currentGlyphBounds.min.y,e.y),this.currentGlyphBounds.max.x=Math.max(this.currentGlyphBounds.max.x,e.x),this.currentGlyphBounds.max.y=Math.max(this.currentGlyphBounds.max.y,e.y)}getCollectedGlyphs(){return this.currentGlyphPaths.length>0&&this.finishGlyph(),this.collectedGlyphs}getGlyphPositions(){return this.glyphPositions}getTextIndices(){return this.glyphTextIndices}reset(){this.collectedGlyphs=[],this.glyphPositions=[],this.glyphTextIndices=[],this.currentGlyphPaths=[],this.currentPath=null,this.currentPoint=null,this.currentGlyphId=0,this.currentTextIndex=0,this.currentPosition.set(0,0),this.currentGlyphBounds={min:new Vec2(1/0,1/0),max:new Vec2(-1/0,-1/0)}}setCurveFidelityConfig(e){this.polygonizer.setCurveFidelityConfig(e)}setGeometryOptimization(e){this.pathOptimizer.setConfig({...et,...e})}getOptimizationStats(){return this.pathOptimizer.getStats()}}class DrawCallbackHandler{constructor(){this.moveTo_func=null,this.lineTo_func=null,this.quadTo_func=null,this.cubicTo_func=null,this.closePath_func=null,this.drawFuncsPtr=0,this.position={x:0,y:0}}setPosition(e,n){this.position.x=e,this.position.y=n,this.collector&&this.collector.setPosition(e,n)}updatePosition(e,n){this.position.x+=e,this.position.y+=n,this.collector&&this.collector.updatePosition(e,n)}createDrawFuncs(e,n){if(!e||!e.module||!e.hb)throw new Error("Invalid font object");if(this.collector=n,this.drawFuncsPtr)return;const i=e.module;this.moveTo_func=i.addFunction((e,n,i,s,r)=>{this.collector?.onMoveTo(s,r)},"viiiffi"),this.lineTo_func=i.addFunction((e,n,i,s,r)=>{this.collector?.onLineTo(s,r)},"viiiffi"),this.quadTo_func=i.addFunction((e,n,i,s,r,o,h)=>{this.collector?.onQuadTo(s,r,o,h)},"viiiffffi"),this.cubicTo_func=i.addFunction((e,n,i,s,r,o,h,c,l)=>{this.collector?.onCubicTo(s,r,o,h,c,l)},"viiiffffffi"),this.closePath_func=i.addFunction((e,n,i)=>{this.collector?.onClosePath()},"viiii"),this.drawFuncsPtr=i.exports.hb_draw_funcs_create(),i.exports.hb_draw_funcs_set_move_to_func(this.drawFuncsPtr,this.moveTo_func,0,0),i.exports.hb_draw_funcs_set_line_to_func(this.drawFuncsPtr,this.lineTo_func,0,0),i.exports.hb_draw_funcs_set_quadratic_to_func(this.drawFuncsPtr,this.quadTo_func,0,0),i.exports.hb_draw_funcs_set_cubic_to_func(this.drawFuncsPtr,this.cubicTo_func,0,0),i.exports.hb_draw_funcs_set_close_path_func(this.drawFuncsPtr,this.closePath_func,0,0)}getDrawFuncsPtr(){if(!this.drawFuncsPtr)throw new Error("Draw functions not initialized");return this.drawFuncsPtr}destroy(e){if(!e||!e.module||!e.hb)return;const n=e.module;try{this.drawFuncsPtr&&(n.exports.hb_draw_funcs_destroy(this.drawFuncsPtr),this.drawFuncsPtr=0),null!==this.moveTo_func&&(n.removeFunction(this.moveTo_func),this.moveTo_func=null),null!==this.lineTo_func&&(n.removeFunction(this.lineTo_func),this.lineTo_func=null),null!==this.quadTo_func&&(n.removeFunction(this.quadTo_func),this.quadTo_func=null),null!==this.cubicTo_func&&(n.removeFunction(this.cubicTo_func),this.cubicTo_func=null),null!==this.closePath_func&&(n.removeFunction(this.closePath_func),this.closePath_func=null)}catch(e){i.warn("Error destroying draw callbacks:",e)}this.collector=void 0}}class GlyphGeometryBuilder{constructor(e,n){this.fontId="default",this.wordCache=new Map,this.cache=e,this.loadedFont=n,this.tessellator=new Tessellator,this.extruder=new Extruder,this.clusterer=new BoundaryClusterer,this.collector=new GlyphContourCollector,this.drawCallbacks=new DrawCallbackHandler,this.drawCallbacks.createDrawFuncs(this.loadedFont,this.collector)}getOptimizationStats(){return this.collector.getOptimizationStats()}setCurveFidelityConfig(e){this.collector.setCurveFidelityConfig(e)}setGeometryOptimization(e){this.collector.setGeometryOptimization(e)}setFontId(e){this.fontId=e}buildInstancedGeometry(e,n,i,r,o=!1){s.start("GlyphGeometryBuilder.buildInstancedGeometry",{lineCount:e.length,wordCount:e.flat().length,depth:n,removeOverlaps:i});const h=[],c=[],l=[],d=[],f={min:{x:1/0,y:1/0,z:0},max:{x:-1/0,y:-1/0,z:n}};for(let s=0;s<e.length;s++){const p=e[s];for(const e of p){const s=[];for(const n of e.glyphs)s.push(this.getContoursForGlyph(n.g));const p=e.glyphs.map(e=>new Vec3(e.x,e.y,0)),g=this.clusterer.cluster(s,p);if(!o&&g.some(e=>e.length>1)){const o=`${this.fontId}_${e.text}_${n}_${i}`;let p=this.wordCache.get(o);if(!p){const i=[];for(let n=0;n<s.length;n++){const r=s[n],o=e.glyphs[n];for(const e of r.paths)i.push({...e,points:e.points.map(e=>new Vec2(e.x+(o.x??0),e.y+(o.y??0)))})}p=this.tessellateGlyphCluster(i,n,r),this.wordCache.set(o,p)}const g=h.length/3;this.appendGeometry(h,c,l,p,e.position,g);const y=p.vertices.length/3;for(let i=0;i<e.glyphs.length;i++){const r=e.glyphs[i],o=s[i],h=new Vec3(e.position.x+(r.x??0),e.position.y+(r.y??0),e.position.z),c=this.createGlyphInfo(r,g,y,h,o,n);d.push(c),this.updatePlaneBounds(c.bounds,f)}}else for(let o=0;o<e.glyphs.length;o++){const p=e.glyphs[o],g=s[o],y=new Vec3(e.position.x+(p.x??0),e.position.y+(p.y??0),e.position.z);if(0===g.paths.length){const e=this.createGlyphInfo(p,0,0,y,g,n);d.push(e);continue}let b=this.cache.get(this.fontId,p.g,n,i);b||(b=this.tessellateGlyph(g,n,i,r),this.cache.set(this.fontId,p.g,n,i,b));const m=h.length/3;this.appendGeometry(h,c,l,b,y,m);const _=this.createGlyphInfo(p,m,b.vertices.length/3,y,g,n);d.push(_),this.updatePlaneBounds(_.bounds,f)}}}const p=new Float32Array(h),g=new Float32Array(c),y=new Uint32Array(l);return s.end("GlyphGeometryBuilder.buildInstancedGeometry"),{vertices:p,normals:g,indices:y,glyphInfos:d,planeBounds:f}}appendGeometry(e,n,i,s,r,o){for(let n=0;n<s.vertices.length;n+=3)e.push(s.vertices[n]+r.x,s.vertices[n+1]+r.y,s.vertices[n+2]+r.z);for(let e=0;e<s.normals.length;e++)n.push(s.normals[e]);for(let e=0;e<s.indices.length;e++)i.push(s.indices[e]+o)}createGlyphInfo(e,n,i,s,r,o){return{textIndex:e.absoluteTextIndex,lineIndex:e.lineIndex,vertexStart:n,vertexCount:i,bounds:{min:{x:r.bounds.min.x+s.x,y:r.bounds.min.y+s.y,z:s.z},max:{x:r.bounds.max.x+s.x,y:r.bounds.max.y+s.y,z:s.z+o}}}}getContoursForGlyph(e){this.collector.reset(),this.collector.beginGlyph(e,0),this.loadedFont.module.exports.hb_font_draw_glyph(this.loadedFont.font.ptr,e,this.drawCallbacks.getDrawFuncsPtr(),0),this.collector.finishGlyph();const n=this.collector.getCollectedGlyphs()[0];return n||{glyphId:e,paths:[],bounds:{min:{x:0,y:0},max:{x:0,y:0}}}}tessellateGlyphCluster(e,n,i){const s=this.tessellator.process(e,!0,i);return this.extrudeAndPackage(s,n)}extrudeAndPackage(e,n){const i=this.extruder.extrude(e,n,this.loadedFont.upem),s=i.vertices;let r=1/0,o=1/0,h=1/0,c=-1/0,l=-1/0,d=-1/0;for(let e=0;e<s.length;e+=3){const n=s[e],i=s[e+1],f=s[e+2];n<r&&(r=n),n>c&&(c=n),i<o&&(o=i),i>l&&(l=i),f<h&&(h=f),f>d&&(d=f)}const f=new Vec3(r,o,h),p=new Vec3(c,l,d),g=i.vertices.length/3<65536?Uint16Array:Uint32Array;return{geometry:e,vertices:new Float32Array(i.vertices),normals:new Float32Array(i.normals),indices:new g(i.indices),bounds:{min:f,max:p},useCount:1}}tessellateGlyph(e,n,i,r){s.start("GlyphGeometryBuilder.tessellateGlyph",{glyphId:e.glyphId,pathCount:e.paths.length});const o=this.tessellator.process(e.paths,i,r);return this.extrudeAndPackage(o,n)}updatePlaneBounds(e,n){const i=new Box3(new Vec3(n.min.x,n.min.y,n.min.z),new Vec3(n.max.x,n.max.y,n.max.z)),s=new Box3(new Vec3(e.min.x,e.min.y,e.min.z),new Vec3(e.max.x,e.max.y,e.max.z));i.union(s),n.min.x=i.min.x,n.min.y=i.min.y,n.min.z=i.min.z,n.max.x=i.max.x,n.max.y=i.max.y,n.max.z=i.max.z}getCacheStats(){return this.cache.getStats()}clearCache(){this.cache.clear(),this.wordCache.clear()}}class TextShaper{constructor(e,n){this.cachedSpaceWidth=new Map,this.loadedFont=e,this.geometryBuilder=n}shapeLines(e,n,i,r,o,h,c){s.start("TextShaper.shapeLines",{lineCount:e.length});const l=new Set;if(h&&"object"==typeof h&&"byText"in h&&h.byText&&c)for(const e of Object.keys(h.byText)){let n=0;for(;-1!==(n=c.indexOf(e,n));)l.add(n),l.add(n+e.length),n+=e.length}const d=[];return e.forEach((e,s)=>{const h=this.shapeLineIntoClusters(e,s,n,i,r,o,l);d.push(h)}),d}shapeLineIntoClusters(e,n,i,s,r,o,h){const c=this.loadedFont.hb.createBuffer();"rtl"===o&&c.setDirection("rtl"),c.addText(e.text),c.guessSegmentProperties(),this.loadedFont.hb.shape(this.loadedFont.font,c);const l=c.json(this.loadedFont.font);c.destroy();const d=[];let f=[],p="",g=new Vec3,y=new Vec3(e.xOffset,-n*i,0);const b=s*this.loadedFont.upem,m=this.calculateSpaceAdjustment(e,r,s);for(let i=0;i<l.length;i++){const s=l[i],r=/\s/.test(e.text[s.cl]);e.endedWithHyphen&&s.cl===e.text.length-1&&"-"===e.text[s.cl]?s.absoluteTextIndex=e.originalEnd:s.absoluteTextIndex=e.originalStart+s.cl,s.lineIndex=n;const o=h.has(s.absoluteTextIndex);(r||o)&&f.length>0&&(d.push({text:p,glyphs:f,position:g.clone()}),f=[],p="");const c=y.clone().add(new Vec3(s.dx,s.dy,0));r||(0===f.length&&g.copy(c),s.x=c.x-g.x,s.y=c.y-g.y,f.push(s),p+=e.text[s.cl]),y.x+=s.ax,y.y+=s.ay,0!==b&&i<l.length-1&&(y.x+=b),r&&(y.x+=m)}return f.length>0&&d.push({text:p,glyphs:f,position:g.clone()}),d}calculateSpaceAdjustment(e,n,i){let s=0;if(void 0!==e.adjustmentRatio&&"justify"===n&&!e.isLastLine){let n=this.cachedSpaceWidth.get(i);void 0===n&&(n=TextMeasurer.measureTextWidth(this.loadedFont," ",i),this.cachedSpaceWidth.set(i,n));const r=.5,o=c;e.adjustmentRatio>0?s=e.adjustmentRatio*n*r:e.adjustmentRatio<0&&(s=e.adjustmentRatio*n*o)}return s}clearCache(){this.geometryBuilder.clearCache()}getCacheStats(){return this.geometryBuilder.getCacheStats()}}class GlyphCache{constructor(e){this.cache=new Map,this.head=null,this.tail=null,this.stats={hits:0,misses:0,totalGlyphs:0,uniqueGlyphs:0,cacheSize:0,saved:0,memoryUsage:0},e&&(this.maxCacheSize=1024*e*1024)}getCacheKey(e,n,i,s){return`${e}_${n}_${Math.round(1e3*i)/1e3}_${s}`}has(e,n,i,s){const r=this.getCacheKey(e,n,i,s);return this.cache.has(r)}get(e,n,i,s){const r=this.getCacheKey(e,n,i,s),o=this.cache.get(r);return o?(this.stats.hits++,this.stats.saved++,o.data.useCount++,this.moveToHead(o),this.stats.totalGlyphs++,o.data):(this.stats.misses++,void this.stats.totalGlyphs++)}set(e,n,i,s,r){const o=this.getCacheKey(e,n,i,s),h=this.calculateMemoryUsage(r);this.maxCacheSize&&this.stats.memoryUsage+h>this.maxCacheSize&&this.evictLRU(h);const c={key:o,data:r,prev:null,next:null};this.cache.set(o,c),this.addToHead(c),this.stats.uniqueGlyphs=this.cache.size,this.stats.cacheSize++,this.stats.memoryUsage+=h}calculateMemoryUsage(e){let n=0;return n+=4*e.vertices.length,n+=4*e.normals.length,n+=e.indices.length*e.indices.BYTES_PER_ELEMENT,n+=24,n+=256,n}evictLRU(e){let n=0;for(;this.tail&&n<e;){const e=this.calculateMemoryUsage(this.tail.data),i=this.tail;this.removeTail(),this.cache.delete(i.key),this.stats.memoryUsage-=e,this.stats.cacheSize--,n+=e}}addToHead(e){this.head?(e.next=this.head,this.head.prev=e,this.head=e):this.head=this.tail=e}removeNode(e){e.prev?e.prev.next=e.next:this.head=e.next,e.next?e.next.prev=e.prev:this.tail=e.prev}removeTail(){this.tail&&this.removeNode(this.tail)}moveToHead(e){e!==this.head&&(this.removeNode(e),this.addToHead(e))}clear(){this.cache.clear(),this.head=null,this.tail=null,this.stats={hits:0,misses:0,totalGlyphs:0,uniqueGlyphs:0,cacheSize:0,saved:0,memoryUsage:0}}getStats(){const e=this.stats.totalGlyphs>0?this.stats.hits/this.stats.totalGlyphs*100:0;return this.stats.uniqueGlyphs=this.cache.size,{...this.stats,hitRate:e,memoryUsageMB:this.stats.memoryUsage/1048576}}}const st=new GlyphCache(250);var rt={exports:{}};var at=getAugmentedNamespace({__proto__:null,default:{},readFileSync:()=>{throw new Error("fs not available in browser")}});!function(e){var n,i=(n="undefined"!=typeof document?document.currentScript?.src:void 0,async function(e={}){var i=e,s="object"==typeof window,r="undefined"!=typeof WorkerGlobalScope,o="object"==typeof process&&process.versions?.node&&"renderer"!=process.type,quit_=(e,n)=>{throw n};"undefined"!=typeof __filename?n=__filename:r&&(n=self.location.href);var h,c,l="";if(o){var d=at;l=__dirname+"/",c=e=>(e=isFileURI(e)?new URL(e):e,d.readFileSync(e)),h=async(e,n=!0)=>(e=isFileURI(e)?new URL(e):e,d.readFileSync(e,n?void 0:"utf8")),process.argv.length>1&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),quit_=(e,n)=>{throw process.exitCode=e,n}}else if(s||r){try{l=new URL(".",n).href}catch{}r&&(c=e=>{var n=new XMLHttpRequest;return n.open("GET",e,!1),n.responseType="arraybuffer",n.send(null),new Uint8Array(n.response)}),h=async e=>{if(isFileURI(e))return new Promise((n,i)=>{var s=new XMLHttpRequest;s.open("GET",e,!0),s.responseType="arraybuffer",s.onload=()=>{200==s.status||0==s.status&&s.response?n(s.response):i(s.status)},s.onerror=i,s.send(null)});var n=await fetch(e,{credentials:"same-origin"});if(n.ok)return n.arrayBuffer();throw new Error(n.status+" : "+n.url)}}console.log.bind(console);var f,p,g,y,b,m,_=console.error.bind(console),w=!1,isFileURI=e=>e.startsWith("file://"),O=!1;function updateMemoryViews(){var e=b.buffer;i.HEAP8=new Int8Array(e),i.HEAPU8=m=new Uint8Array(e),i.HEAP32=new Int32Array(e),i.HEAPU32=new Uint32Array(e),i.HEAPF32=new Float32Array(e),new BigInt64Array(e),new BigUint64Array(e)}var k,j=0,$=null;function abort(e){i.onAbort?.(e),_(e="Aborted("+e+")"),w=!0,e+=". Build with -sASSERTIONS for more info.";var n=new WebAssembly.RuntimeError(e);throw y?.(n),n}function findWasmBinary(){return e="hb.wasm",i.locateFile?i.locateFile(e,l):l+e;var e}async function getWasmBinary(e){if(!f)try{var n=await h(e);return new Uint8Array(n)}catch{}return function(e){if(e==k&&f)return new Uint8Array(f);if(c)return c(e);throw"both async and sync fetching of the wasm failed"}(e)}async function instantiateAsync(e,n,i){if(!e&&!isFileURI(n)&&!o)try{var s=fetch(n,{credentials:"same-origin"});return await WebAssembly.instantiateStreaming(s,i)}catch(e){_(`wasm streaming compile failed: ${e}`),_("falling back to ArrayBuffer instantiation")}return async function(e,n){try{var i=await getWasmBinary(e);return await WebAssembly.instantiate(i,n)}catch(e){_(`failed to asynchronously prepare wasm: ${e}`),abort(e)}}(n,i)}class ExitStatus{name="ExitStatus";constructor(e){this.message=`Program terminated with exit(${e})`,this.status=e}}var Y,q,tt,callRuntimeCallbacks=e=>{for(;e.length>0;)e.shift()(i)},et=[],addOnPostRun=e=>et.push(e),nt=[],addOnPreRun=e=>nt.push(e),it=!0,st=0,rt={},handleException=e=>{if(e instanceof ExitStatus||"unwind"==e)return p;quit_(1,e)},keepRuntimeAlive=()=>it||st>0,_proc_exit=e=>{p=e,keepRuntimeAlive()||(i.onExit?.(e),w=!0),quit_(e,new ExitStatus(e))},_exit=(e,n)=>{p=e,_proc_exit(e)},callUserCallback=e=>{if(!w)try{e(),(()=>{if(!keepRuntimeAlive())try{_exit(p)}catch(e){handleException(e)}})()}catch(e){handleException(e)}},alignMemory=(e,n)=>Math.ceil(e/n)*n,growMemory=e=>{var n=(e-b.buffer.byteLength+65535)/65536|0;try{return b.grow(n),updateMemoryViews(),1}catch(e){}},uleb128EncodeWithLen=e=>{const n=e.length;return[n%128|128,n>>7,...e]},ot={i:127,p:127,j:126,f:125,d:124,e:111},generateTypePack=e=>uleb128EncodeWithLen(Array.from(e,e=>ot[e])),getWasmTableEntry=e=>Y.get(e),getFunctionAddress=e=>(q||(q=new WeakMap,((e,n)=>{if(q)for(var i=e;i<e+n;i++){var s=getWasmTableEntry(i);s&&q.set(s,i)}})(0,Y.length)),q.get(e)||0),ht=[],setWasmTableEntry=(e,n)=>Y.set(e,n);i.noExitRuntime&&(it=i.noExitRuntime),i.print&&i.print,i.printErr&&(_=i.printErr),i.wasmBinary&&(f=i.wasmBinary),i.arguments&&i.arguments,i.thisProgram&&i.thisProgram,i.wasmMemory=b,i.wasmExports=lt,i.addFunction=(e,n)=>{var i=getFunctionAddress(e);if(i)return i;var s=ht.length?ht.pop():Y.grow(1);try{setWasmTableEntry(s,e)}catch(i){if(!(i instanceof TypeError))throw i;var r=((e,n)=>{var i=Uint8Array.of(0,97,115,109,1,0,0,0,1,...uleb128EncodeWithLen([1,96,...generateTypePack(n.slice(1)),...generateTypePack("v"===n[0]?"":n[0])]),2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0),s=new WebAssembly.Module(i);return new WebAssembly.Instance(s,{e:{f:e}}).exports.f})(e,n);setWasmTableEntry(s,r)}return q.set(e,s),s},i.removeFunction=e=>{q.delete(getWasmTableEntry(e)),setWasmTableEntry(e,null),ht.push(e)};var ct={_abort_js:()=>abort(""),_emscripten_runtime_keepalive_clear:()=>{it=!1,st=0},_setitimer_js:(e,n)=>{if(rt[e]&&(clearTimeout(rt[e].id),delete rt[e]),!n)return 0;var i=setTimeout(()=>{delete rt[e],callUserCallback(()=>tt(e,performance.now()))},n);return rt[e]={id:i,timeout_ms:n},0},emscripten_resize_heap:e=>{var n=m.length,i=2147483648;if((e>>>=0)>i)return!1;for(var s=1;s<=4;s*=2){var r=n*(1+.2/s);r=Math.min(r,e+100663296);var o=Math.min(i,alignMemory(Math.max(e,r),65536));if(growMemory(o))return!0}return!1},proc_exit:_proc_exit},lt=await async function(){function receiveInstance(e,n){return lt=e.exports,i.wasmExports=lt,b=lt.memory,i.wasmMemory=b,updateMemoryViews(),Y=lt.__indirect_function_table,function(e){i._hb_blob_create=e.hb_blob_create,i._hb_blob_destroy=e.hb_blob_destroy,i._hb_blob_get_length=e.hb_blob_get_length,i._hb_blob_get_data=e.hb_blob_get_data,i._hb_buffer_serialize_glyphs=e.hb_buffer_serialize_glyphs,i._hb_buffer_create=e.hb_buffer_create,i._hb_buffer_destroy=e.hb_buffer_destroy,i._hb_buffer_get_content_type=e.hb_buffer_get_content_type,i._hb_buffer_set_direction=e.hb_buffer_set_direction,i._hb_buffer_set_script=e.hb_buffer_set_script,i._hb_buffer_set_language=e.hb_buffer_set_language,i._hb_buffer_set_flags=e.hb_buffer_set_flags,i._hb_buffer_set_cluster_level=e.hb_buffer_set_cluster_level,i._hb_buffer_get_length=e.hb_buffer_get_length,i._hb_buffer_get_glyph_infos=e.hb_buffer_get_glyph_infos,i._hb_buffer_get_glyph_positions=e.hb_buffer_get_glyph_positions,i._hb_glyph_info_get_glyph_flags=e.hb_glyph_info_get_glyph_flags,i._hb_buffer_guess_segment_properties=e.hb_buffer_guess_segment_properties,i._hb_buffer_add_utf8=e.hb_buffer_add_utf8,i._hb_buffer_add_utf16=e.hb_buffer_add_utf16,i._hb_buffer_set_message_func=e.hb_buffer_set_message_func,i._hb_language_from_string=e.hb_language_from_string,i._hb_script_from_string=e.hb_script_from_string,i._hb_version=e.hb_version,i._hb_version_string=e.hb_version_string,i._hb_feature_from_string=e.hb_feature_from_string,i._malloc=e.malloc,i._free=e.free,i._hb_draw_funcs_set_move_to_func=e.hb_draw_funcs_set_move_to_func,i._hb_draw_funcs_set_line_to_func=e.hb_draw_funcs_set_line_to_func,i._hb_draw_funcs_set_quadratic_to_func=e.hb_draw_funcs_set_quadratic_to_func,i._hb_draw_funcs_set_cubic_to_func=e.hb_draw_funcs_set_cubic_to_func,i._hb_draw_funcs_set_close_path_func=e.hb_draw_funcs_set_close_path_func,i._hb_draw_funcs_create=e.hb_draw_funcs_create,i._hb_draw_funcs_destroy=e.hb_draw_funcs_destroy,i._hb_face_create=e.hb_face_create,i._hb_face_destroy=e.hb_face_destroy,i._hb_face_reference_table=e.hb_face_reference_table,i._hb_face_get_upem=e.hb_face_get_upem,i._hb_face_collect_unicodes=e.hb_face_collect_unicodes,i._hb_font_draw_glyph=e.hb_font_draw_glyph,i._hb_font_glyph_to_string=e.hb_font_glyph_to_string,i._hb_font_create=e.hb_font_create,i._hb_font_set_variations=e.hb_font_set_variations,i._hb_font_destroy=e.hb_font_destroy,i._hb_font_set_scale=e.hb_font_set_scale,i._hb_set_create=e.hb_set_create,i._hb_set_destroy=e.hb_set_destroy,i._hb_ot_var_get_axis_infos=e.hb_ot_var_get_axis_infos,i._hb_set_get_population=e.hb_set_get_population,i._hb_set_next_many=e.hb_set_next_many,i._hb_shape=e.hb_shape,tt=e._emscripten_timeout}(lt),function(){if(j--,i.monitorRunDependencies?.(j),0==j&&$){var e=$;$=null,e()}}(),lt}j++,i.monitorRunDependencies?.(j);var e={env:ct,wasi_snapshot_preview1:ct};if(i.instantiateWasm)return new Promise((n,s)=>{i.instantiateWasm(e,(e,i)=>{n(receiveInstance(e))})});k??=findWasmBinary();var n=function(e){return receiveInstance(e.instance)}(await instantiateAsync(f,k,e));return n}();return function(){if(i.preInit)for("function"==typeof i.preInit&&(i.preInit=[i.preInit]);i.preInit.length>0;)i.preInit.shift()()}(),function run(){function doRun(){i.calledRun=!0,w||(O=!0,lt.__wasm_call_ctors(),g?.(i),i.onRuntimeInitialized?.(),function(){if(i.postRun)for("function"==typeof i.postRun&&(i.postRun=[i.postRun]);i.postRun.length;)addOnPostRun(i.postRun.shift());callRuntimeCallbacks(et)}())}j>0?$=run:(function(){if(i.preRun)for("function"==typeof i.preRun&&(i.preRun=[i.preRun]);i.preRun.length;)addOnPreRun(i.preRun.shift());callRuntimeCallbacks(nt)}(),j>0?$=run:i.setStatus?(i.setStatus("Running..."),setTimeout(()=>{setTimeout(()=>i.setStatus(""),1),doRun()},1)):doRun())}(),O?i:new Promise((e,n)=>{g=e,y=n})});e.exports=i,e.exports.default=i}(rt);var ot=getDefaultExportFromCjs(rt.exports),ht={exports:{}};try{ht.exports=function(e){var n=e.wasmExports,i=new TextDecoder("utf8");let s=e.addFunction,r=e.removeFunction;var o=s(function(e){n.free(e)},"vi");function hb_tag(e){return(255&e.charCodeAt(0))<<24|(255&e.charCodeAt(1))<<16|(255&e.charCodeAt(2))<<8|255&e.charCodeAt(3)}var h=hb_tag("JSON"),c="",l=n.malloc(256);function createAsciiString(i){var s=n.malloc(i.length+1);for(let n=0;n<i.length;++n){const r=i.charCodeAt(n);if(r>127)throw new Error("Expected ASCII text");e.HEAPU8[s+n]=r}return e.HEAPU8[s+i.length]=0,{ptr:s,length:i.length,free:function(){n.free(s)}}}function shape(e,i,s){var r=0,o=0;s&&(s=s.split(","),r=n.malloc(16*s.length),s.forEach(function(e,i){var s=createAsciiString(e);n.hb_feature_from_string(s.ptr,-1,r+16*o)&&o++,s.free()})),n.hb_shape(e.ptr,i.ptr,r,o),r&&n.free(r)}return{createBlob:function(i){var s=n.malloc(i.byteLength);e.HEAPU8.set(new Uint8Array(i),s);var r=n.hb_blob_create(s,i.byteLength,2,s,o);return{ptr:r,destroy:function(){n.hb_blob_destroy(r)}}},createFace:function(i,s){var r=n.hb_face_create(i.ptr,s);const o=n.hb_face_get_upem(r);return{ptr:r,upem:o,reference_table:function(i){var s=n.hb_face_reference_table(r,hb_tag(i)),o=n.hb_blob_get_length(s);if(o){var h=n.hb_blob_get_data(s,null);return e.HEAPU8.subarray(h,h+o)}},getAxisInfos:function(){var i=n.malloc(2048),s=n.malloc(4);e.HEAPU32[s/4]=64,n.hb_ot_var_get_axis_infos(r,0,s,i);var o={};return Array.from({length:e.HEAPU32[s/4]}).forEach(function(n,s){var r;o[(r=e.HEAPU32[i/4+8*s+1],[String.fromCharCode(r>>24&255),String.fromCharCode(r>>16&255),String.fromCharCode(r>>8&255),String.fromCharCode(255&r)].join(""))]={min:e.HEAPF32[i/4+8*s+4],default:e.HEAPF32[i/4+8*s+5],max:e.HEAPF32[i/4+8*s+6]}}),n.free(s),n.free(i),o},collectUnicodes:function(){var i=n.hb_set_create();n.hb_face_collect_unicodes(r,i);var s=function(i){const s=n.hb_set_get_population(i),r=n.malloc(s<<2),o=r>>2,h=e.HEAPU32.subarray(o,o+s);return e.HEAPU32.set(h,o),n.hb_set_next_many(i,-1,r,s),h}(i);return n.hb_set_destroy(i),s},destroy:function(){n.hb_face_destroy(r)}}},createFont:function(o){var h=n.hb_font_create(o.ptr),d=null,f=null,p=null,g=null,y=null,b=null;function glyphToPath(e){return d||(f=s(function(e,n,i,s,r,o){c+=`M${s},${r}`},"viiiffi"),p=s(function(e,n,i,s,r,o){c+=`L${s},${r}`},"viiiffi"),g=s(function(e,n,i,s,r,o,h,l,d,f){c+=`C${s},${r} ${o},${h} ${l},${d}`},"viiiffffffi"),y=s(function(e,n,i,s,r,o,h,l){c+=`Q${s},${r} ${o},${h}`},"viiiffffi"),b=s(function(e,n,i,s){c+="Z"},"viiii"),d=n.hb_draw_funcs_create(),n.hb_draw_funcs_set_move_to_func(d,f,0,0),n.hb_draw_funcs_set_line_to_func(d,p,0,0),n.hb_draw_funcs_set_cubic_to_func(d,g,0,0),n.hb_draw_funcs_set_quadratic_to_func(d,y,0,0),n.hb_draw_funcs_set_close_path_func(d,b,0,0)),c="",n.hb_font_draw_glyph(h,e,d,0),c}return{ptr:h,glyphName:function(s){n.hb_font_glyph_to_string(h,s,l,256);var r=e.HEAPU8.subarray(l,l+256);return i.decode(r.slice(0,r.indexOf(0)))},glyphToPath:glyphToPath,glyphToJson:function(e){return glyphToPath(e).replace(/([MLQCZ])/g,"|$1 ").split("|").filter(function(e){return e.length}).map(function(e){var n=e.split(/[ ,]/g);return{type:n[0],values:n.slice(1).filter(function(e){return e.length}).map(function(e){return+e})}})},setScale:function(e,i){n.hb_font_set_scale(h,e,i)},setVariations:function(i){var s=Object.entries(i),r=n.malloc(8*s.length);s.forEach(function(n,i){e.HEAPU32[r/4+2*i+0]=hb_tag(n[0]),e.HEAPF32[r/4+2*i+1]=n[1]}),n.hb_font_set_variations(h,r,s.length),n.free(r)},destroy:function(){n.hb_font_destroy(h),d&&(n.hb_draw_funcs_destroy(d),d=null,r(f),r(p),r(g),r(y),r(b))}}},createBuffer:function(){var i=n.hb_buffer_create();return{ptr:i,addText:function(s){const r=function(i){const s=n.malloc(2*i.length),r=new Uint16Array(e.wasmMemory.buffer,s,i.length);for(let e=0;e<r.length;++e)r[e]=i.charCodeAt(e);return{ptr:s,length:r.length,free:function(){n.free(s)}}}(s);n.hb_buffer_add_utf16(i,r.ptr,r.length,0,r.length),r.free()},guessSegmentProperties:function(){return n.hb_buffer_guess_segment_properties(i)},setDirection:function(e){n.hb_buffer_set_direction(i,{ltr:4,rtl:5,ttb:6,btt:7}[e]||0)},setFlags:function(e){var s=0;e.forEach(function(e){s|=function(e){return"BOT"==e?1:"EOT"==e?2:"PRESERVE_DEFAULT_IGNORABLES"==e?4:"REMOVE_DEFAULT_IGNORABLES"==e?8:"DO_NOT_INSERT_DOTTED_CIRCLE"==e?16:"PRODUCE_UNSAFE_TO_CONCAT"==e?64:0}(e)}),n.hb_buffer_set_flags(i,s)},setLanguage:function(e){var s=createAsciiString(e);n.hb_buffer_set_language(i,n.hb_language_from_string(s.ptr,-1)),s.free()},setScript:function(e){var s=createAsciiString(e);n.hb_buffer_set_script(i,n.hb_script_from_string(s.ptr,-1)),s.free()},setClusterLevel:function(e){n.hb_buffer_set_cluster_level(i,e)},json:function(){for(var s=n.hb_buffer_get_length(i),r=[],o=n.hb_buffer_get_glyph_infos(i,0),h=o/4,c=n.hb_buffer_get_glyph_positions(i,0)/4,l=e.HEAPU32.subarray(h,h+5*s),d=e.HEAP32.subarray(c,c+5*s),f=0;f<s;++f)r.push({g:l[5*f+0],cl:l[5*f+2],ax:d[5*f+0],ay:d[5*f+1],dx:d[5*f+2],dy:d[5*f+3],flags:n.hb_glyph_info_get_glyph_flags(o+20*f)});return r},destroy:function(){n.hb_buffer_destroy(i)}}},shape:shape,shapeWithTrace:function(o,c,l,d,f){var p=[],g=0,y=!1,b=1048576,m=n.malloc(b),_=s(function(s,r,o,c){var l=i.decode(e.HEAPU8.subarray(o,e.HEAPU8.indexOf(0,o)));return l.startsWith("start table GSUB")?g=1:l.startsWith("start table GPOS")&&(g=2),g!=f&&(y=!1),0!=f&&g==f&&l.startsWith("end lookup "+d)&&(y=!0),y?0:(n.hb_buffer_serialize_glyphs(s,0,n.hb_buffer_get_length(s),m,b,0,r,h,4),p.push({m:l,t:JSON.parse(i.decode(e.HEAPU8.subarray(m,e.HEAPU8.indexOf(0,m)))),glyphs:2==n.hb_buffer_get_content_type(s)}),1)},"iiiii");return n.hb_buffer_set_message_func(c.ptr,_,0,0),shape(o,c,l),n.free(m),r(_),p},version:function(){var i=n.malloc(12);n.hb_version(i,i+4,i+8);var s={major:e.HEAPU32[i/4],minor:e.HEAPU32[(i+4)/4],micro:e.HEAPU32[(i+8)/4]};return n.free(i),s},version_string:function(){var s=n.hb_version_string();return i.decode(e.HEAPU8.subarray(s,e.HEAPU8.indexOf(0,s)))}}}}catch(e){}var ct=getDefaultExportFromCjs(ht.exports);let lt=null,ut=null,dt=null;const ft={setWasmPath(e){ut=e,dt=null,lt=null},setWasmBuffer(e){dt=e,ut=null,lt=null},getHarfBuzz:async()=>lt||(lt=new Promise(async(e,n)=>{try{const n={};if(dt)n.wasmBinary=dt;else{if(!ut)throw new Error("HarfBuzz WASM path or buffer must be set before initialization.");n.locateFile=(e,n)=>e.endsWith(".wasm")?ut:n+e}const i=await ot(n),s=ct(i);e({hb:s,module:{addFunction:i.addFunction,exports:i.wasmExports,removeFunction:i.removeFunction}})}catch(e){n(new Error(`Failed to initialize HarfBuzz: ${e}`))}}),lt)};class TextRangeQuery{constructor(e,n){this.text=e,this.glyphsByTextIndex=new Map,n.forEach(e=>{const n=this.glyphsByTextIndex.get(e.textIndex)||[];n.push(e),this.glyphsByTextIndex.set(e.textIndex,n)})}execute(e){const n=[];return e.byText&&n.push(...this.findByText(e.byText)),e.byCharRange&&n.push(...this.findByCharRange(e.byCharRange)),n}findByText(e){const n=[];for(const i of e){let e=0;for(;-1!==(e=this.text.indexOf(i,e));)n.push(this.createTextRange(e,e+i.length,i)),e+=i.length}return n}findByCharRange(e){return e.map(e=>{const n=this.text.slice(e.start,e.end);return this.createTextRange(e.start,e.end,n)})}createTextRange(e,n,i){const s=[],r=new Map;for(let i=e;i<n;i++){const e=this.glyphsByTextIndex.get(i);if(e)for(const n of e){s.push(n);const e=r.get(n.lineIndex)||[];e.push(n),r.set(n.lineIndex,e)}}return{start:e,end:n,originalText:i,bounds:Array.from(r.values()).map(e=>this.calculateBounds(e)),glyphs:s,lineIndices:Array.from(r.keys()).sort((e,n)=>e-n)}}calculateBounds(e){if(0===e.length)return{min:{x:0,y:0,z:0},max:{x:0,y:0,z:0}};const n=new Box3;for(const i of e){const e=new Box3(new Vec3(i.bounds.min.x,i.bounds.min.y,i.bounds.min.z),new Vec3(i.bounds.max.x,i.bounds.max.y,i.bounds.max.z));n.union(e)}return{min:{x:n.min.x,y:n.min.y,z:n.min.z},max:{x:n.max.x,y:n.max.y,z:n.max.z}}}}class Text{static{this.patternCache=new Map}static{this.hbInitPromise=null}static{this.fontCache=new Map}static{this.fontIdCounter=0}constructor(e){this.currentFontId="",Text.hbInitPromise||(Text.hbInitPromise=ft.getHarfBuzz()),this.fontLoader=new FontLoader(()=>Text.hbInitPromise)}static setHarfBuzzPath(e){ft.setWasmPath(e),Text.hbInitPromise=null}static setHarfBuzzBuffer(e){ft.setWasmBuffer(e),Text.hbInitPromise=null}static init(){return Text.hbInitPromise||(Text.hbInitPromise=ft.getHarfBuzz()),Text.hbInitPromise}static async create(e){if(!e.font)throw new Error("Font is required. Specify options.font as a URL string or ArrayBuffer.");Text.hbInitPromise||(Text.hbInitPromise=ft.getHarfBuzz());const n="string"==typeof e.font?e.font:`buffer-${Text.generateFontContentHash(e.font)}`,i=e.fontVariations?`${n}_${JSON.stringify(e.fontVariations)}`:n;let s=Text.fontCache.get(i);s||(s=await Text.loadAndCacheFont(i,e.font,e.fontVariations));const r=new Text({maxCacheSizeMB:e.maxCacheSizeMB});r.setLoadedFont(s);const{font:o,maxCacheSizeMB:h,...c}=e;return{...await r.createGeometry(c),getLoadedFont:()=>r.getLoadedFont(),getCacheStatistics:()=>r.getCacheStatistics(),clearCache:()=>r.clearCache(),measureTextWidth:(e,n)=>r.measureTextWidth(e,n)}}static async loadAndCacheFont(e,n,i){const s=new Text;await s.loadFont(n,i);const r=s.getLoadedFont();return Text.fontCache.set(e,r),r}static generateFontContentHash(e){if(e){const n=new Uint8Array(e);return`${n[0]}_${n[Math.floor(n.length/2)]}_${n[n.length-1]}_${n.length}`}return""+ ++Text.fontIdCounter}setLoadedFont(e){this.loadedFont=e;const n=Text.generateFontContentHash(e._buffer);this.currentFontId=`font_${n}`,e.fontVariations&&(this.currentFontId+=`_${JSON.stringify(e.fontVariations)}`)}async loadFont(e,n){s.start("Text.loadFont",{fontSrc:"string"==typeof e?e:`buffer(${e.byteLength})`}),Text.hbInitPromise||(Text.hbInitPromise=ft.getHarfBuzz()),await Text.hbInitPromise;const r="string"==typeof e?await fetch(e).then(n=>{if(!n.ok)throw new Error(`Failed to load font from ${e}: HTTP ${n.status} ${n.statusText}`);return n.arrayBuffer()}):e;try{this.loadedFont&&this.destroy(),this.loadedFont=await this.fontLoader.loadFont(r,n);const e=Text.generateFontContentHash(r);this.currentFontId=`font_${e}`,n&&(this.currentFontId+=`_${JSON.stringify(n)}`)}catch(e){throw i.error("Failed to load font:",e),e}finally{s.end("Text.loadFont")}}async createGeometry(e){s.start("Text.createGeometry",{textLength:e.text.length,size:e.size||72,hasLayout:!!e.layout,mode:"cached"});try{if(!this.loadedFont)throw new Error("Font not loaded. Use Text.create() with a font option.");const n=await this.prepareHyphenation(e);if(this.validateOptions(n),e=n,this.updateFontVariations(e),!this.geometryBuilder){const n=e.maxCacheSizeMB?new GlyphCache(e.maxCacheSizeMB):st;this.geometryBuilder=new GlyphGeometryBuilder(n,this.loadedFont),this.geometryBuilder.setFontId(this.currentFontId)}this.geometryBuilder.setCurveFidelityConfig(e.curveFidelity),this.geometryBuilder.setGeometryOptimization(e.geometryOptimization),this.loadedFont.font.setScale(this.loadedFont.upem,this.loadedFont.upem),this.textShaper||(this.textShaper=new TextShaper(this.loadedFont,this.geometryBuilder));const i=this.prepareLayout(e),s=e.removeOverlaps??this.loadedFont.isVariable??!1,r=this.textShaper.shapeLines(i.lines,i.scaledLineHeight,i.letterSpacing,i.align,i.direction,e.color,e.text),o=this.geometryBuilder.buildInstancedGeometry(r,i.depth,s,this.loadedFont.metrics.isCFF,e.separateGlyphsWithAttributes||!1),h=this.geometryBuilder.getCacheStats(),c=this.finalizeGeometry(o.vertices,o.normals,o.indices,o.glyphInfos,o.planeBounds,e,h,e.text);if(e.separateGlyphsWithAttributes){const e=this.createGlyphAttributes(c.vertices.length/3,c.glyphs);c.glyphAttributes=e}return c}finally{s.end("Text.createGeometry")}}async prepareHyphenation(e){if(!1!==e.layout?.hyphenate&&e.layout?.width){const n=e.layout?.language||"en-us";if(!e.layout?.hyphenationPatterns?.[n])try{if(!Text.patternCache.has(n)){const i=await loadPattern(n,e.layout?.patternsPath);Text.patternCache.set(n,i)}return{...e,layout:{...e.layout,hyphenationPatterns:{...e.layout?.hyphenationPatterns,[n]:Text.patternCache.get(n)}}}}catch(s){return i.warn(`Failed to load patterns for ${n}: ${s}`),{...e,layout:{...e.layout,hyphenate:!1}}}}return e}validateOptions(e){if(!e.text)throw new Error("Text content is required");const n=e.maxTextLength??1e5;if(e.text.length>n)throw new Error(`Text exceeds ${n} character limit`)}updateFontVariations(e){e.fontVariations&&this.loadedFont&&JSON.stringify(e.fontVariations)!==JSON.stringify(this.loadedFont.fontVariations)&&(this.loadedFont.font.setVariations(e.fontVariations),this.loadedFont.fontVariations=e.fontVariations)}prepareLayout(e){if(!this.loadedFont)throw new Error("Font not loaded. Use Text.create() with a font option");const{text:n,size:i=72,depth:s=0,lineHeight:c=1,letterSpacing:l=0,layout:d={}}=e,{width:f,direction:p="ltr",align:g=("rtl"===p?"right":"left"),respectExistingBreaks:y=!0,hyphenate:b=!0,language:m="en-us",tolerance:_=r,pretolerance:w=o,emergencyStretch:O=h,autoEmergencyStretch:k,hyphenationPatterns:j,lefthyphenmin:$,righthyphenmin:Y,linepenalty:q,adjdemerits:tt,hyphenpenalty:et,exhyphenpenalty:nt,doublehyphendemerits:it,looseness:st,disableSingleWordDetection:rt}=d;let at;void 0!==f&&(at=f*(this.loadedFont.upem/i));const ot=s*(this.loadedFont.upem/i);this.textLayout||(this.textLayout=new TextLayout(this.loadedFont));const ht=this.textLayout.computeLines({text:n,width:at,align:g,direction:p,hyphenate:b,language:m,respectExistingBreaks:y,tolerance:_,pretolerance:w,emergencyStretch:O,autoEmergencyStretch:k,hyphenationPatterns:j,lefthyphenmin:$,righthyphenmin:Y,linepenalty:q,adjdemerits:tt,hyphenpenalty:et,exhyphenpenalty:nt,doublehyphendemerits:it,looseness:st,disableSingleWordDetection:rt,letterSpacing:l}),ct=FontMetadataExtractor.getVerticalMetrics(this.loadedFont.metrics),lt=(ct.ascender-ct.descender)*c;return{lines:ht.lines,scaledLineHeight:lt,letterSpacing:l,align:g,direction:p,depth:ot,size:i}}applyColorSystem(e,n,i,s){const r=e.length/3,o=new Float32Array(3*r),h=[];if(Array.isArray(i)){for(let e=0;e<r;e++){const n=3*e;o[n]=i[0],o[n+1]=i[1],o[n+2]=i[2]}h.push({start:0,end:s.length,originalText:s,color:i,bounds:[],glyphs:n,lineIndices:[...new Set(n.map(e=>e.lineIndex))]})}else{const e=i.default||[1,1,1];for(let n=0;n<o.length;n+=3)o[n]=e[0],o[n+1]=e[1],o[n+2]=e[2];if(i.byText){new TextRangeQuery(s,n).execute({byText:Object.keys(i.byText)}).forEach(e=>{const n=i.byText[e.originalText];n&&(e.glyphs.forEach(e=>{for(let i=0;i<e.vertexCount;i++){const s=3*(e.vertexStart+i);s>=0&&s<o.length&&(o[s]=n[0],o[s+1]=n[1],o[s+2]=n[2])}}),h.push({start:e.start,end:e.end,originalText:e.originalText,color:n,bounds:e.bounds,glyphs:e.glyphs,lineIndices:e.lineIndices}))})}i.byCharRange&&i.byCharRange.forEach(e=>{const i=[];for(const s of n)if(s.textIndex>=e.start&&s.textIndex<e.end){i.push(s);for(let n=0;n<s.vertexCount;n++){const i=3*(s.vertexStart+n);i>=0&&i<o.length&&(o[i]=e.color[0],o[i+1]=e.color[1],o[i+2]=e.color[2])}}h.push({start:e.start,end:e.end,originalText:s.slice(e.start,e.end),color:e.color,bounds:[],glyphs:i,lineIndices:[...new Set(i.map(e=>e.lineIndex))]})})}return{colors:o,coloredRanges:h}}finalizeGeometry(e,n,i,s,r,o,h,c){const{layout:l={},size:d=72}=o,{width:f,align:p=("rtl"===l.direction?"right":"left")}=l;this.textLayout||(this.textLayout=new TextLayout(this.loadedFont));const g=this.textLayout.applyAlignment(e,{width:f,align:p,planeBounds:r}),y=g.offset;r.min.x=g.adjustedBounds.min.x,r.max.x=g.adjustedBounds.max.x;const b=d/this.loadedFont.upem;for(let n=0;n<e.length;n++)e[n]*=b;r.min.x*=b,r.min.y*=b,r.min.z*=b,r.max.x*=b,r.max.y*=b,r.max.z*=b;for(let e=0;e<s.length;e++){const n=s[e];0!==y&&(n.bounds.min.x+=y,n.bounds.max.x+=y),n.bounds.min.x*=b,n.bounds.min.y*=b,n.bounds.min.z*=b,n.bounds.max.x*=b,n.bounds.max.y*=b,n.bounds.max.z*=b}let m,_;if(o.color){const n=this.applyColorSystem(e,s,o.color,o.text);m=n.colors,_=n.coloredRanges}const w=this.geometryBuilder.getOptimizationStats(),O=i.length/3,k=e.length/3;return{vertices:e,normals:n,indices:i,colors:m,glyphs:s,planeBounds:r,stats:{trianglesGenerated:O,verticesGenerated:k,pointsRemovedByVisvalingam:w.pointsRemovedByVisvalingam,pointsRemovedByColinear:w.pointsRemovedByColinear,originalPointCount:w.originalPointCount,...h||{}},query:e=>{if(!c)throw new Error("Original text not available for querying");return new TextRangeQuery(c,s).execute(e)},coloredRanges:_,glyphAttributes:void 0}}getFontMetrics(){if(!this.loadedFont)throw new Error("Font not loaded. Call loadFont() first");return FontMetadataExtractor.getFontMetrics(this.loadedFont.metrics)}static async preloadPatterns(e,n){await Promise.all(e.map(async e=>{if(!Text.patternCache.has(e))try{const i=await loadPattern(e,n);Text.patternCache.set(e,i)}catch(n){i.warn(`Failed to pre-load patterns for ${e}: ${n}`)}}))}static registerPattern(e,n){Text.patternCache.set(e,n)}getLoadedFont(){return this.loadedFont}measureTextWidth(e,n=0){if(!this.loadedFont)throw new Error("Font not loaded. Call loadFont() first");return TextMeasurer.measureTextWidth(this.loadedFont,e,n)}getCacheStatistics(){return this.geometryBuilder?this.geometryBuilder.getCacheStats():null}clearCache(){this.geometryBuilder&&this.geometryBuilder.clearCache()}createGlyphAttributes(e,n){const i=new Float32Array(3*e),s=new Float32Array(e),r=new Float32Array(e);return n.forEach((n,o)=>{const h=(n.bounds.min.x+n.bounds.max.x)/2,c=(n.bounds.min.y+n.bounds.max.y)/2,l=(n.bounds.min.z+n.bounds.max.z)/2;for(let d=0;d<n.vertexCount;d++){const f=n.vertexStart+d;f<e&&(i[3*f]=h,i[3*f+1]=c,i[3*f+2]=l,s[f]=o,r[f]=n.lineIndex)}}),{glyphCenter:i,glyphIndex:s,glyphLineIndex:r}}destroy(){if(!this.loadedFont)return;const e=this.loadedFont;try{FontLoader.destroyFont(e)}catch(e){i.warn("Error destroying HarfBuzz objects:",e)}finally{this.loadedFont=void 0,this.textLayout=void 0,this.textShaper=void 0}}}e.DEFAULT_CURVE_FIDELITY=nt,e.FontMetadataExtractor=FontMetadataExtractor,e.Text=Text,e.globalGlyphCache=st});
|
package/dist/three/index.cjs
CHANGED
|
@@ -19,8 +19,8 @@ class Text {
|
|
|
19
19
|
const geometry = new three.BufferGeometry();
|
|
20
20
|
geometry.setAttribute('position', new three.Float32BufferAttribute(coreResult.vertices, 3));
|
|
21
21
|
geometry.setAttribute('normal', new three.Float32BufferAttribute(coreResult.normals, 3));
|
|
22
|
-
geometry.setIndex(
|
|
23
|
-
// Add optional
|
|
22
|
+
geometry.setIndex(new three.Uint32BufferAttribute(coreResult.indices, 1));
|
|
23
|
+
// Add optional color attribute (only if provided)
|
|
24
24
|
if (coreResult.colors) {
|
|
25
25
|
geometry.setAttribute('color', new three.Float32BufferAttribute(coreResult.colors, 3));
|
|
26
26
|
}
|
package/dist/three/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BufferGeometry, Float32BufferAttribute } from 'three';
|
|
1
|
+
import { BufferGeometry, Float32BufferAttribute, Uint32BufferAttribute } from 'three';
|
|
2
2
|
import { Text as Text$1 } from '../index.js';
|
|
3
3
|
|
|
4
4
|
// Three.js adapter - wraps core text processing and returns BufferGeometry
|
|
@@ -17,8 +17,8 @@ class Text {
|
|
|
17
17
|
const geometry = new BufferGeometry();
|
|
18
18
|
geometry.setAttribute('position', new Float32BufferAttribute(coreResult.vertices, 3));
|
|
19
19
|
geometry.setAttribute('normal', new Float32BufferAttribute(coreResult.normals, 3));
|
|
20
|
-
geometry.setIndex(
|
|
21
|
-
// Add optional
|
|
20
|
+
geometry.setIndex(new Uint32BufferAttribute(coreResult.indices, 1));
|
|
21
|
+
// Add optional color attribute (only if provided)
|
|
22
22
|
if (coreResult.colors) {
|
|
23
23
|
geometry.setAttribute('color', new Float32BufferAttribute(coreResult.colors, 3));
|
|
24
24
|
}
|
package/dist/three/react.cjs
CHANGED
|
@@ -72,13 +72,6 @@ const Text$1 = react.forwardRef(function Text(props, ref) {
|
|
|
72
72
|
font,
|
|
73
73
|
...memoizedTextOptions,
|
|
74
74
|
});
|
|
75
|
-
if (text.geometry &&
|
|
76
|
-
!text.geometry.attributes.color &&
|
|
77
|
-
vertexColors) {
|
|
78
|
-
const vertexCount = text.geometry.attributes.position.count;
|
|
79
|
-
const colors = new Float32Array(vertexCount * 3).fill(1.0);
|
|
80
|
-
text.geometry.setAttribute("color", new THREE__namespace.BufferAttribute(colors, 3));
|
|
81
|
-
}
|
|
82
75
|
if (!cancelled) {
|
|
83
76
|
setGeometry(text.geometry);
|
|
84
77
|
if (onLoad)
|
package/dist/three/react.js
CHANGED
|
@@ -51,13 +51,6 @@ const Text$1 = forwardRef(function Text(props, ref) {
|
|
|
51
51
|
font,
|
|
52
52
|
...memoizedTextOptions,
|
|
53
53
|
});
|
|
54
|
-
if (text.geometry &&
|
|
55
|
-
!text.geometry.attributes.color &&
|
|
56
|
-
vertexColors) {
|
|
57
|
-
const vertexCount = text.geometry.attributes.position.count;
|
|
58
|
-
const colors = new Float32Array(vertexCount * 3).fill(1.0);
|
|
59
|
-
text.geometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));
|
|
60
|
-
}
|
|
61
54
|
if (!cancelled) {
|
|
62
55
|
setGeometry(text.geometry);
|
|
63
56
|
if (onLoad)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "three-text",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "3D font rendering and text layout engine for the web",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
},
|
|
92
92
|
"dependencies": {
|
|
93
93
|
"harfbuzzjs": "^0.4.11",
|
|
94
|
-
"
|
|
94
|
+
"libtess": "^1.2.2"
|
|
95
95
|
},
|
|
96
96
|
"devDependencies": {
|
|
97
97
|
"@react-three/fiber": ">=8.0.0",
|