three-text 0.2.10 → 0.2.12

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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * three-text v0.2.10
2
+ * three-text v0.2.12
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,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=800,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,m=1e4,b=-1/0,_=2,w=4,k=1e4,O=.5;class LineBreak{static badness(e,n){if(0===e)return 0;if(n<=0)return k;let i;return i=e<=7230584?Math.floor(297*e/n):n>=1663497?Math.floor(e/Math.floor(n/297)):e,i>1290?k: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 isCJK(e){const n=e.codePointAt(0);return void 0!==n&&(n>=19968&&n<=40959||n>=13312&&n<=19903||n>=131072&&n<=173791||n>=173824&&n<=177983||n>=177984&&n<=178207||n>=178208&&n<=183983||n>=63744&&n<=64255||n>=12352&&n<=12447||n>=12448&&n<=12543||n>=44032&&n<=55215||n>=4352&&n<=4607||n>=12592&&n<=12687||n>=43360&&n<=43391||n>=55216&&n<=55295||n>=65440&&n<=65500)}static isCJClosingPunctuation(e){const n=e.charCodeAt(0);return 12289===n||12290===n||65292===n||65294===n||65306===n||65307===n||65281===n||65311===n||65289===n||12305===n||65373===n||12301===n||12303===n||12297===n||12299===n||12309===n||12311===n||12313===n||12315===n||12540===n||8212===n||8230===n||8229===n}static isCJOpeningPunctuation(e){const n=e.charCodeAt(0);return 65288===n||12304===n||65371===n||12300===n||12302===n||12296===n||12298===n||12308===n||12310===n||12312===n||12314===n}static isCJPunctuation(e){return this.isCJClosingPunctuation(e)||this.isCJOpeningPunctuation(e)}static itemizeCJKText(e,n,i,s=0,r){const o=[],h=Array.from(e);let d,f,p,g=s;if(r)d=r.width,f=r.stretch,p=r.shrink;else{const e=n("字");d=0,f=.04*e,p=.04*e}for(let e=0;e<h.length;e++){const i=h[e],s=e<h.length-1?h[e+1]:null;if(/\s/.test(i)){const e=n(i);o.push({type:l.GLUE,width:e,stretch:.5*e,shrink:e*c,text:i,originIndex:g}),g+=i.length;continue}if(o.push({type:l.BOX,width:n(i),text:i,originIndex:g}),g+=i.length,s&&!/\s/.test(s)){let e=!0;this.isCJClosingPunctuation(s)&&(e=!1),this.isCJOpeningPunctuation(i)&&(e=!1);const n=this.isCJPunctuation(i)&&this.isCJPunctuation(s);e&&!n&&o.push({type:l.GLUE,width:d,stretch:f,shrink:p,text:"",originIndex:g})}}return o}static itemizeParagraph(e,n,i,s,r,o,h,c){const l=[],d=Array.from(e),f=n("字"),p={width:0,stretch:.04*f,shrink:.04*f};let g="",y=0,m=null,b=0;const flushBuffer=()=>{if(0!==g.length){if("cjk"===m){const e=this.itemizeCJKText(g,n,c,y,p);l.push(...e)}else{const e=this.itemizeWordBased(g,y,n,i,s,r,o,h,c);l.push(...e)}g="",m=null}};for(let e=0;e<d.length;e++){const n=d[e],i=this.isCJK(n)?"cjk":"word";null!==m&&m!==i&&(flushBuffer(),y=b),null===m&&(m=i,y=b),g+=n,b+=n.length}return flushBuffer(),l}static itemizeWordBased(e,n,i,s,r,o,h,d,g){const y=[],m=e.match(/\S+|\s+/g)||[];let b=0;for(let e=0;e<m.length;e++){const _=m[e],w=n+b;if(/\s+/.test(_)){const e=i(_);y.push({type:l.GLUE,width:e,stretch:.5*e,shrink:e*c,text:_,originIndex:w}),b+=_.length}else{const e=_.split(/(-)/);let n=w;for(let c=0;c<e.length;c++){const m=e[c];if(m)if("-"===m)y.push({type:l.DISCRETIONARY,width:i("-"),preBreak:"-",postBreak:"",noBreak:"-",preBreakWidth:i("-"),penalty:g?.exHyphenPenalty??p,flagged:!0,text:"-",originIndex:n}),n+=1;else{if(m.includes("­")){const e=m.split("­");let s=0;for(let r=0;r<e.length;r++){const o=e[r];o.length>0&&(y.push({type:l.BOX,width:i(o),text:o,originIndex:n+s}),s+=o.length),r<e.length-1&&(y.push({type:l.DISCRETIONARY,width:0,preBreak:"-",postBreak:"",noBreak:"",preBreakWidth:i("-"),penalty:g?.hyphenPenalty??f,flagged:!0,text:"",originIndex:n+s}),s+=1)}}else if(s&&m.length>=h+d&&/^\p{L}+$/u.test(m)){const e=LineBreak.findHyphenationPoints(m,r,o,h,d);if(e.length>0){let s=0;for(const r of e){const e=m.substring(s,r);y.push({type:l.BOX,width:i(e),text:e,originIndex:n+s}),y.push({type:l.DISCRETIONARY,width:0,preBreak:"-",postBreak:"",noBreak:"",preBreakWidth:i("-"),penalty:g?.hyphenPenalty??f,flagged:!0,text:"",originIndex:n+r}),s=r}const r=m.substring(s);y.push({type:l.BOX,width:i(r),text:r,originIndex:n+s})}else y.push({type:l.BOX,width:i(m),text:m,originIndex:n})}else y.push({type:l.BOX,width:i(m),text:m,originIndex:n});n+=m.length}}b+=_.length}}return y}static hasShortLines(e,n,i,s){let r=0;for(let o=0;o<n.length-1;o++){const h=n[o];let c=0;for(let n=r;n<h;n++)e[n].type!==l.PENALTY&&(c+=e[n].width);if(c>0){if(c/i<s)return!0}r=h+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:l="left",direction:d="ltr",hyphenate:b=!1,language:j="en-us",respectExistingBreaks:$=!0,measureText:Y,hyphenationPatterns:q,unitsPerEm:tt,tolerance:et=r,pretolerance:nt=o,emergencyStretch:it=h,autoEmergencyStretch:st,lefthyphenmin:rt=_,righthyphenmin:at=w,linepenalty:ot=y,adjdemerits:ht=m,hyphenpenalty:ct=f,exhyphenpenalty:lt=p,doublehyphendemerits:ut=g,looseness:dt=0,disableShortLineDetection:ft=!1,shortLineThreshold:pt=O}=e;if($&&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 gt=b;!gt||q&&q[j]||(i.warn(`Hyphenation patterns for ${j} not available`),gt=!1);let yt=it;void 0!==st&&c?yt=c*st:!gt&&it===h&&c&&(yt=.1*c);const mt={linePenalty:ot,adjDemerits:ht,doubleHyphenDemerits:ut,hyphenPenalty:ct,exHyphenPenalty:lt,currentAlign:l,unitsPerEm:tt};if(!c||c===1/0){const e=Y(n);return s.end("LineBreak.breakText"),[{text:n,originalStart:0,originalEnd:n.length-1,xOffset:0,isLastLine:!0,naturalWidth:e,endedWithHyphen:!1}]}const bt=LineBreak.itemizeText(n,Y,!1,j,q,rt,at,mt);if(0===bt.length)return[];let xt=0,_t=yt,vt=null;const wt=!ft;for(;xt<5;){let e=bt,i=LineBreak.findBreakpoints(e,c,nt,dt,!1,0,mt);if(0===i.length&&gt){e=LineBreak.itemizeText(n,Y,!0,j,q,rt,at,mt),i=LineBreak.findBreakpoints(e,c,et,dt,!1,0,mt)}if(0===i.length&&(_t=yt+xt*c*.1,i=LineBreak.findBreakpoints(e,c,et,dt,!0,_t,mt)),0===i.length&&(i=LineBreak.findBreakpoints(e,c,k,dt,!0,_t,mt)),i.length>0){const s=LineBreak.computeCumulativeWidths(e);if(vt=LineBreak.createLines(n,e,i,c,l,d,s,mt),wt&&i.length>1&&LineBreak.hasShortLines(e,i,c,pt)){xt++;continue}break}break}if(s.end("LineBreak.breakText"),vt&&vt.length>0)return vt;const Tt=Y(n);return[{text:n,originalStart:0,originalEnd:n.length-1,xOffset:0,adjustmentRatio:0,isLastLine:!0,naturalWidth:Tt,endedWithHyphen:!1}]}static findBreakpoints(e,n,i=1/0,s=0,r=!1,o=0,h){const c=LineBreak.computeCumulativeWidths(e),f=new ActiveNodeList,p={value:1/0};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 d=e[s];d.type===l.PENALTY&&d.penalty<1/0&&LineBreak.considerBreak(e,f,s,n,i,o,c,h,r,p),d.type===l.DISCRETIONARY&&d.penalty<1/0&&LineBreak.considerBreak(e,f,s,n,i,o,c,h,r,p),d.type===l.GLUE&&s>0&&e[s-1].type===l.BOX&&LineBreak.considerBreak(e,f,s,n,i,o,c,h,r,p),LineBreak.deactivateNodes(f,s,n,c.minWidths)}const g=[];let y=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,y=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?(y=i,o=e,h=i.totalDemerits):e===o&&i.totalDemerits<h&&(y=i,h=i.totalDemerits)}if(!r&&o!==s&&y)return[]}if(!y)return[];for(;y&&y.position>0;)g.unshift(y.position),y=y.previous;return g}static considerBreak(e,n,i,s,r=1/0,o=0,h,c,d=!1,f={value:1/0}){const p=(e[i].type===l.PENALTY?e[i].penalty:0)<=-1/0,g=n.getAllActive();for(let y=0;y<g.length;y++){const m=g[y];if(!m.active)continue;const _=LineBreak.computeAdjustmentRatio(e,m.position,i,m.line,s,h,c),{ratio:w,adjustment:k,stretch:O,shrink:j,totalWidth:$}=_;let Y;if(k>0){const e=O+o;Y=e<=0?10001:LineBreak.badness(k,e)}else Y=k<0?j<=0||-k>j?10001:LineBreak.badness(-k,j):0;const q=d&&p&&f.value===1/0&&1===g.length&&m.active;if(!p&&!q&&w<-1)continue;const tt=LineBreak.computeFitnessClass(Y,k>0);if(!p&&!q&&Y>r)continue;let et=0,nt=0;let it=(c?.linePenalty??0)+Y,st=Math.abs(it)>=1e4?1e8:it*it;const rt=q,at=e[i].type===l.PENALTY||e[i].type===l.DISCRETIONARY?e[i].penalty:0;0!==at&&(at>0?st+=at*at:at>b&&(st-=at*at));const ot=e[i].type===l.PENALTY&&e[i].flagged||e[i].type===l.DISCRETIONARY&&e[i].flagged,ht=m.position>0&&(e[m.position].type===l.PENALTY&&e[m.position].flagged||e[m.position].type===l.DISCRETIONARY&&e[m.position].flagged);ot&&ht&&(et=c?.doubleHyphenDemerits??0,st+=et),Math.abs(tt-m.fitness)>1&&(nt=c?.adjDemerits??0,st+=nt),(p||rt)&&(st=0);const ct=m.totalDemerits+st;ct<f.value&&(f.value=ct);let lt=n.findExisting(i,tt);lt?ct<lt.totalDemerits&&(lt.totalDemerits=ct,lt.previous=m,lt.totalWidth=$):n.insert({position:i,line:m.line+1,fitness:tt,totalDemerits:ct,totalWidth:$,previous:m,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)s[n+1]=s[n],r[n+1]=r[n],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 m=-1,b=-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===m||i.originIndex<m)&&(m=i.originIndex);const e=i.text?i.text.length:0,n=i.originIndex+e-1;n>b&&(b=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 k=!1;if(p<n.length)if(w.type===l.PENALTY&&w.flagged)y.push("-"),_+=w.width,k=!0,void 0!==w.originIndex&&(b=w.originIndex-1);else if(w.type===l.DISCRETIONARY){const e=w;e.preBreak&&(y.push(e.preBreak),_+=e.preBreakWidth,k=e.flagged||!1,void 0!==w.originIndex&&(b=w.originIndex-1))}const O=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:O,originalStart:m,originalEnd:b,xOffset:j,adjustmentRatio:$,isLastLine:!1,naturalWidth:_,endedWithHyphen:k}),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}}function convertFontFeaturesToString(e){if(!e||0===Object.keys(e).length)return;const n=[];for(const[s,r]of Object.entries(e))/^[a-zA-Z0-9]{4}$/.test(s)?!1===r||0===r?n.push(`${s}=0`):!0===r||1===r?n.push(s):"number"==typeof r&&r>1?n.push(`${s}=${Math.floor(r)}`):i.warn(`Invalid value for feature "${s}": ${r}. Expected boolean or positive number.`):i.warn(`Invalid OpenType feature tag: "${s}". Tags must be exactly 4 alphanumeric characters.`);return n.length>0?n.join(","):void 0}class TextMeasurer{static measureTextWidth(e,n,i=0){const s=e.hb.createBuffer();s.addText(n),s.guessSegmentProperties();const r=convertFontFeaturesToString(e.fontFeatures);e.hb.shape(e.font,s,r);const o=s.json(e.font),h=i*e.upem;let c=0;return o.forEach(e=>{c+=e.ax,0!==h&&(c+=h)}),s.destroy(),c}}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:m,linepenalty:b,adjdemerits:_,hyphenpenalty:w,exhyphenpenalty:k,doublehyphendemerits:O,looseness:j,disableShortLineDetection:$,shortLineThreshold:Y,letterSpacing:q}=e;let tt;if(i)tt=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:m,linepenalty:b,adjdemerits:_,hyphenpenalty:w,exhyphenpenalty:k,doublehyphendemerits:O,looseness:j,disableShortLineDetection:$,shortLineThreshold:Y,unitsPerEm:this.loadedFont.upem,measureText:e=>TextMeasurer.measureTextWidth(this.loadedFont,e,q)});else{const e=n.split("\n");tt=[];let i=0;for(const n of e)tt.push({text:n,originalStart:i,originalEnd:i+n.length-1,xOffset:0}),i+=n.length+1}return{lines:tt}}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 j=1330926671,$=1953784678,Y=2001684038,q=1851878757;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,j,$].includes(i))throw new Error(`Invalid font format. Expected TrueType or OpenType, got signature: 0x${i.toString(16)}`);const s=n.getUint16(4);let r=!1,o=0,h=0,c=0,l=0,d=0,f=0;for(let e=0;e<s;e++){const i=12+16*e,s=n.getUint32(i);1128678944===s||1128678962===s?r=!0:1751474532===s?o=n.getUint32(i+8):1751672161===s?h=n.getUint32(i+8):1330851634===s?c=n.getUint32(i+8):1719034226===s?f=n.getUint32(i+8):1398030676===s?l=n.getUint32(i+8):s===q&&(d=n.getUint32(i+8))}const p=o?n.getUint16(o+18):1e3;let g=null;h&&(g={ascender:n.getInt16(h+4),descender:n.getInt16(h+6),lineGap:n.getInt16(h+8)});let y=null;c&&(y={typoAscender:n.getInt16(c+68),typoDescender:n.getInt16(c+70),typoLineGap:n.getInt16(c+72),winAscent:n.getUint16(c+74),winDescent:n.getUint16(c+76)});let m=null;return f&&l&&d&&(m=this.extractAxisNames(n,l,d)),{isCFF:r,unitsPerEm:p,hheaAscender:g?.ascender||null,hheaDescender:g?.descender||null,hheaLineGap:g?.lineGap||null,typoAscender:y?.typoAscender||null,typoDescender:y?.typoDescender||null,typoLineGap:y?.typoLineGap||null,winAscent:y?.winAscent||null,winDescent:y?.winDescent||null,axisNames:m}}static extractFeatureTags(e){const n=new DataView(e),i=n.getUint16(4);let s=0,r=0,o=0;for(let e=0;e<i;e++){const i=12+16*e,h=n.getUint32(i);1196643650===h?s=n.getUint32(i+8):1196445523===h?r=n.getUint32(i+8):h===q&&(o=n.getUint32(i+8))}const h=new Set,c={};try{if(s){const e=this.extractFeatureDataFromTable(n,s,o);e.features.forEach(e=>h.add(e)),Object.assign(c,e.names)}if(r){const e=this.extractFeatureDataFromTable(n,r,o);e.features.forEach(e=>h.add(e)),Object.assign(c,e.names)}}catch(e){return}const l=Array.from(h).sort();if(0!==l.length)return{tags:l,names:Object.keys(c).length>0?c:{}}}static extractFeatureDataFromTable(e,n,i){const s=n+e.getUint16(n+6),r=e.getUint16(s),o=[],h={};for(let n=0;n<r;n++){const r=s+2+6*n,c=String.fromCharCode(e.getUint8(r),e.getUint8(r+1),e.getUint8(r+2),e.getUint8(r+3));if(o.push(c),/^(ss\d{2}|cv\d{2})$/.test(c)&&i){const n=s+e.getUint16(r+4),o=e.getUint16(n);if(0!==o){const s=n+o;if(0===e.getUint16(s)){const n=e.getUint16(s+2),r=this.getNameFromNameTable(e,i,n);r&&(h[c]=r)}}}}return{features:o,names:h}}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===Y?"woff":2001684018===n?"woff2":"ttf/otf"}static async decompressWoff(e){const n=new DataView(e),s=new Uint8Array(e);if(n.getUint32(0)!==Y)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,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}}const p=FontMetadataExtractor.extractFeatureTags(e);return{hb:h,fontBlob:i,face:s,font:r,module:c,upem:d.unitsPerEm,metrics:d,fontVariations:n,isVariable:l,variationAxes:f,availableFeatures:p?.tags,featureNames:p?.names}}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 tt="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 et={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,m=l,b=h;if(u(g,y)||(f=g,g=y,y=f),u(m,b)||(f=m,m=b,b=f),u(g,m)||(f=g,g=m,m=f,f=y,y=b,b=f),u(m,y)?u(y,b)?(0>(f=v(g,m,y))+(p=v(m,y,b))&&(f=-f,p=-p),d.b=A(f,m.b,p,y.b)):(0>(f=x(g,m,y))+(p=-x(g,b,y))&&(f=-f,p=-p),d.b=A(f,m.b,p,b.b)):d.b=(m.b+y.b)/2,z(g,y)||(f=g,g=y,y=f),z(m,b)||(f=m,m=b,b=f),z(g,m)||(f=g,g=m,m=f,f=y,y=b,b=f),z(m,y)?z(y,b)?(0>(f=aa(g,m,y))+(p=aa(m,y,b))&&(f=-f,p=-p),d.a=A(f,m.a,p,y.a)):(0>(f=ba(g,m,y))+(p=-ba(g,b,y))&&(f=-f,p=-p),d.a=A(f,m.a,p,b.a)):d.a=(m.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},tt.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=tt.libtess}(et);var nt=et.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,r){const o=r||n?e:e.map(e=>this.reverseWinding(e));let h=this.pathsToContours(o);if(n){i.log("Two-pass: boundary extraction then triangulation"),s.start("Tessellator.boundaryPass",{contourCount:h.length});const e=this.performTessellation(h,"boundary");if(s.end("Tessellator.boundaryPass"),!e)return i.warn("libtess returned empty result from boundary pass"),{triangles:{vertices:[],indices:[]},contours:[]};h=this.boundaryToContours(e),i.log(`Boundary pass created ${h.length} contours. Starting triangulation pass.`)}else i.log("Single-pass triangulation for "+(r?"CFF":"TTF"));s.start("Tessellator.triangulationPass",{contourCount:h.length});const c=this.performTessellation(h,"triangles");if(s.end("Tessellator.triangulationPass"),!c){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:h}}return{triangles:{vertices:c.vertices,indices:c.indices||[]},contours:h}}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 nt.GluTesselator;s.gluTessProperty(nt.gluEnum.GLU_TESS_WINDING_RULE,nt.windingRule.GLU_TESS_WINDING_NONZERO);const r=[],o=[],h=[];let c=[];"boundary"===n&&s.gluTessProperty(nt.gluEnum.GLU_TESS_BOUNDARY_ONLY,!0),"triangles"===n?s.gluTessCallback(nt.gluEnum.GLU_TESS_VERTEX_DATA,e=>{o.push(e)}):(s.gluTessCallback(nt.gluEnum.GLU_TESS_BEGIN,()=>{c=[]}),s.gluTessCallback(nt.gluEnum.GLU_TESS_VERTEX_DATA,e=>{c.push(e)}),s.gluTessCallback(nt.gluEnum.GLU_TESS_END,()=>{c.length>0&&h.push([...c])})),s.gluTessCallback(nt.gluEnum.GLU_TESS_COMBINE,e=>{const n=r.length/2;return r.push(e[0],e[1]),n}),s.gluTessCallback(nt.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){if(s.start("BoundaryClusterer.cluster",{glyphCount:e.length}),0===e.length)return s.end("BoundaryClusterer.cluster"),[];const i=this.clusterSweepLine(e,n);return s.end("BoundaryClusterer.cluster"),i}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 it={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 st={distanceTolerance:.5,angleTolerance:.2},rt=1e-6;class Polygonizer{constructor(e){this.curveFidelityConfig={...st,...e}}setCurveFidelityConfig(e){this.curveFidelityConfig={...st,...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,m=r-e,b=o-n,_=Math.abs((i-r)*b-(s-o)*m),w=this.curveFidelityConfig.distanceTolerance??st.distanceTolerance,k=w*w;if(_>rt){if(_*_<=k*(m*m+b*b)){const c=this.curveFidelityConfig.angleTolerance??st.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=m*m+b*b;if(0===r){if((i-e)*(i-e)+(s-n)*(s-n)<=k)return void this.addPoint(i,s,h)}else{const o=((i-e)*m+(s-n)*b)/r;if(o>0&&o<1&&_*_<=k*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,m=(r+h)/2,b=(o+c)/2,_=(f+g)/2,w=(p+y)/2,k=(g+m)/2,O=(y+b)/2,j=(_+k)/2,$=(w+O)/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),nt=this.curveFidelityConfig.distanceTolerance??st.distanceTolerance,it=nt*nt;let at=0;switch(tt>rt&&(at|=1),et>rt&&(at|=2),at){case 0:const d=Y*Y+q*q;if(0===d){if((i-e)*(i-e)+(s-n)*(s-n)<=it&&(r-e)*(r-e)+(o-n)*(o-n)<=it)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)<=it*d)return this.addPoint(i,s,l),void this.addPoint(r,o,l)}break;case 1:if(et*et<=it*(Y*Y+q*q)){const e=this.curveFidelityConfig.angleTolerance??st.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<=it*(Y*Y+q*q)){const h=this.curveFidelityConfig.angleTolerance??st.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)<=it*(Y*Y+q*q)){const d=this.curveFidelityConfig.angleTolerance??st.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,$,k,O,m,b,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({...it,...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()),s.start("Glyph.polygonizeAndOptimize",{glyphId:e,textIndex:n})}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)),s.end("Glyph.polygonizeAndOptimize"),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)<rt)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<rt&&y<rt)return void this.onLineTo(r,o);const m=this.polygonizer.polygonizeCubic(h,c,l,d);for(const e of m)this.updateBounds(e);for(let e=0;e<m.length;e++)this.currentPath.points.push(m[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({...it,...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 LRUCache{constructor(e={}){this.cache=new Map,this.head=null,this.tail=null,this.stats={hits:0,misses:0,evictions:0,size:0,memoryUsage:0},this.options={maxEntries:e.maxEntries??1/0,maxMemoryBytes:e.maxMemoryBytes??1/0,calculateSize:e.calculateSize??(()=>0),onEvict:e.onEvict}}get(e){const n=this.cache.get(e);return n?(this.stats.hits++,this.moveToHead(n),n.value):void this.stats.misses++}has(e){return this.cache.has(e)}set(e,n){const i=this.cache.get(e);if(i){const e=this.options.calculateSize(i.value),s=this.options.calculateSize(n);return this.stats.memoryUsage=this.stats.memoryUsage-e+s,i.value=n,void this.moveToHead(i)}const s=this.options.calculateSize(n);this.evictIfNeeded(s);const r={key:e,value:n,prev:null,next:null};this.cache.set(e,r),this.addToHead(r),this.stats.size=this.cache.size,this.stats.memoryUsage+=s}delete(e){const n=this.cache.get(e);if(!n)return!1;const i=this.options.calculateSize(n.value);return this.removeNode(n),this.cache.delete(e),this.stats.size=this.cache.size,this.stats.memoryUsage-=i,this.options.onEvict&&this.options.onEvict(e,n.value),!0}clear(){if(this.options.onEvict)for(const[e,n]of this.cache)this.options.onEvict(e,n.value);this.cache.clear(),this.head=null,this.tail=null,this.stats={hits:0,misses:0,evictions:0,size:0,memoryUsage:0}}getStats(){const e=this.stats.hits+this.stats.misses,n=e>0?this.stats.hits/e*100:0,i=this.stats.memoryUsage/1048576;return{...this.stats,hitRate:n,memoryUsageMB:i}}keys(){const e=[];let n=this.head;for(;n;)e.push(n.key),n=n.next;return e}get size(){return this.cache.size}evictIfNeeded(e){for(;this.cache.size>=this.options.maxEntries&&this.tail;)this.evictTail();if(this.options.maxMemoryBytes<1/0)for(;this.tail&&this.stats.memoryUsage+e>this.options.maxMemoryBytes;)this.evictTail()}evictTail(){if(!this.tail)return;const e=this.tail,n=this.options.calculateSize(e.value);this.removeTail(),this.cache.delete(e.key),this.stats.size=this.cache.size,this.stats.memoryUsage-=n,this.stats.evictions++,this.options.onEvict&&this.options.onEvict(e.key,e.value)}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))}}class GlyphGeometryBuilder{constructor(e,n){this.fontId="default",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),this.contourCache=new LRUCache({maxEntries:1e3,calculateSize:e=>{let n=0;for(const i of e.paths)n+=16*i.points.length;return n+64}}),this.wordCache=new LRUCache({maxEntries:1e3,calculateSize:e=>{let n=4*e.vertices.length;return n+=4*e.normals.length,n+=e.indices.length*e.indices.BYTES_PER_ELEMENT,n}})}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 m=this.cache.get(this.fontId,p.g,n,i);m||(m=this.tessellateGlyph(g,n,i,r),this.cache.set(this.fontId,p.g,n,i,m));const b=h.length/3;this.appendGeometry(h,c,l,m,y,b);const _=this.createGlyphInfo(p,b,m.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){const n=this.contourCache.get(e);if(n)return n;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 i=this.collector.getCollectedGlyphs()[0]||{glyphId:e,paths:[],bounds:{min:{x:0,y:0},max:{x:0,y:0}}};return this.contourCache.set(e,i),i}tessellateGlyphCluster(e,n,i){const s=this.tessellator.process(e,!0,i);return this.extrudeAndPackage(s,n)}extrudeAndPackage(e,n){s.start("Extruder.extrude",{depth:n,upem:this.loadedFont.upem});const i=this.extruder.extrude(e,n,this.loadedFont.upem);s.end("Extruder.extrude");const r=i.vertices;let o=1/0,h=1/0,c=1/0,l=-1/0,d=-1/0,f=-1/0;for(let e=0;e<r.length;e+=3){const n=r[e],i=r[e+1],s=r[e+2];n<o&&(o=n),n>l&&(l=n),i<h&&(h=i),i>d&&(d=i),s<c&&(c=s),s>f&&(f=s)}const p=new Vec3(o,h,c),g=new Vec3(l,d,f),y=i.vertices.length/3<65536?Uint16Array:Uint32Array;return{geometry:e,vertices:new Float32Array(i.vertices),normals:new Float32Array(i.normals),indices:new y(i.indices),bounds:{min:p,max:g},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 s.end("GlyphGeometryBuilder.tessellateGlyph"),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();const l=convertFontFeaturesToString(this.loadedFont.fontFeatures);this.loadedFont.hb.shape(this.loadedFont.font,c,l);const d=c.json(this.loadedFont.font);c.destroy();const f=[];let p=[],g="",y=new Vec3,m=new Vec3(e.xOffset,-n*i,0);const b=s*this.loadedFont.upem,_=this.calculateSpaceAdjustment(e,r,s),w=this.calculateCJKAdjustment(e,r);for(let i=0;i<d.length;i++){const s=d[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)&&p.length>0&&(f.push({text:g,glyphs:p,position:y.clone()}),p=[],g="");const c=m.clone().add(new Vec3(s.dx,s.dy,0));if(r||(0===p.length&&y.copy(c),s.x=c.x-y.x,s.y=c.y-y.y,p.push(s),g+=e.text[s.cl]),m.x+=s.ax,m.y+=s.ay,0!==b&&i<d.length-1&&(m.x+=b),r&&(m.x+=_),0!==w&&i<d.length-1&&!r){const n=e.text[s.cl],r=d[i+1],o=e.text[r.cl],h=LineBreak.isCJK(n),c=o&&LineBreak.isCJK(o);if(h&&c){let e=!0;LineBreak.isCJClosingPunctuation(o)&&(e=!1),LineBreak.isCJOpeningPunctuation(n)&&(e=!1),LineBreak.isCJPunctuation(n)&&LineBreak.isCJPunctuation(o)&&(e=!1),e&&(m.x+=w)}}}return p.length>0&&f.push({text:g,glyphs:p,position:y.clone()}),f}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=n,o=.5,h=c;e.adjustmentRatio>0?s=e.adjustmentRatio*r*o:e.adjustmentRatio<0&&(s=e.adjustmentRatio*r*h)}return s}calculateCJKAdjustment(e,n){if(void 0===e.adjustmentRatio||"justify"!==n||e.isLastLine)return 0;const i=this.loadedFont.upem,s=.04*i,r=.04*i;return e.adjustmentRatio>0?e.adjustmentRatio*s:e.adjustmentRatio<0?e.adjustmentRatio*r:0}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 at=new GlyphCache(250);var ot={exports:{}};var ht=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=ht;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,m,b,_=console.error.bind(console),w=!1,isFileURI=e=>e.startsWith("file://"),k=!1;function updateMemoryViews(){var e=m.buffer;i.HEAP8=new Int8Array(e),i.HEAPU8=b=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 O,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==O&&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-m.buffer.byteLength+65535)/65536|0;try{return m.grow(n),updateMemoryViews(),1}catch(e){}},uleb128EncodeWithLen=e=>{const n=e.length;return[n%128|128,n>>7,...e]},at={i:127,p:127,j:126,f:125,d:124,e:111},generateTypePack=e=>uleb128EncodeWithLen(Array.from(e,e=>at[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),ot=[],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=m,i.wasmExports=lt,i.addFunction=(e,n)=>{var i=getFunctionAddress(e);if(i)return i;var s=ot.length?ot.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),ot.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=b.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,m=lt.memory,i.wasmMemory=m,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))})});O??=findWasmBinary();var n=function(e){return receiveInstance(e.instance)}(await instantiateAsync(f,O,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||(k=!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())}(),k?i:new Promise((e,n)=>{g=e,y=n})});e.exports=i,e.exports.default=i}(ot);var ct=getDefaultExportFromCjs(ot.exports),lt={exports:{}};try{lt.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,m=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"),m=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,m,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(m))}}},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,m=1048576,b=n.malloc(m),_=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),b,m,0,r,h,4),p.push({m:l,t:JSON.parse(i.decode(e.HEAPU8.subarray(b,e.HEAPU8.indexOf(0,b)))),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(b),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 ut=getDefaultExportFromCjs(lt.exports);let dt=null,ft=null,pt=null;const gt={setWasmPath(e){ft=e,pt=null,dt=null},setWasmBuffer(e){pt=e,ft=null,dt=null},getHarfBuzz:async()=>dt||(dt=new Promise(async(e,n)=>{try{const n={};if(pt)n.wasmBinary=pt;else{if(!ft)throw new Error("HarfBuzz WASM path or buffer must be set before initialization.");n.locateFile=(e,n)=>e.endsWith(".wasm")?ft:n+e}const i=await ct(n),s=ut(i);e({hb:s,module:{addFunction:i.addFunction,exports:i.wasmExports,removeFunction:i.removeFunction}})}catch(e){n(new Error(`Failed to initialize HarfBuzz: ${e}`))}}),dt)};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=gt.getHarfBuzz()),this.fontLoader=new FontLoader(()=>Text.hbInitPromise)}static setHarfBuzzPath(e){gt.setWasmPath(e),Text.hbInitPromise=null}static setHarfBuzzBuffer(e){gt.setWasmBuffer(e),Text.hbInitPromise=null}static init(){return Text.hbInitPromise||(Text.hbInitPromise=gt.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=gt.getHarfBuzz());const n=await Text.resolveFont(e),i=new Text({maxCacheSizeMB:e.maxCacheSizeMB});i.setLoadedFont(n);const{font:s,maxCacheSizeMB:r,...o}=e,h=await i.createGeometry(o),update=async n=>{const s={...e};for(const e in n){const i=n[e];void 0!==i&&(s[e]=i)}if(void 0!==n.font||void 0!==n.fontVariations||void 0!==n.fontFeatures){const e=await Text.resolveFont(s);i.setLoadedFont(e),i.resetHelpers()}e=s;const{font:r,maxCacheSizeMB:o,...h}=e;return{...await i.createGeometry(h),getLoadedFont:()=>i.getLoadedFont(),getCacheStatistics:()=>i.getCacheStatistics(),clearCache:()=>i.clearCache(),measureTextWidth:(e,n)=>i.measureTextWidth(e,n),update:update}};return{...h,getLoadedFont:()=>i.getLoadedFont(),getCacheStatistics:()=>i.getCacheStatistics(),clearCache:()=>i.clearCache(),measureTextWidth:(e,n)=>i.measureTextWidth(e,n),update:update}}static async resolveFont(e){let n="string"==typeof e.font?e.font:`buffer-${Text.generateFontContentHash(e.font)}`;e.fontVariations&&(n+=`_var_${JSON.stringify(e.fontVariations)}`),e.fontFeatures&&(n+=`_feat_${JSON.stringify(e.fontFeatures)}`);let i=Text.fontCache.get(n);return i||(i=await Text.loadAndCacheFont(n,e.font,e.fontVariations,e.fontFeatures)),i}static async loadAndCacheFont(e,n,i,s){const r=new Text;await r.loadFont(n,i,s);const o=r.getLoadedFont();return Text.fontCache.set(e,o),o}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+=`_var_${JSON.stringify(e.fontVariations)}`),e.fontFeatures&&(this.currentFontId+=`_feat_${JSON.stringify(e.fontFeatures)}`)}async loadFont(e,n,r){s.start("Text.loadFont",{fontSrc:"string"==typeof e?e:`buffer(${e.byteLength})`}),Text.hbInitPromise||(Text.hbInitPromise=gt.getHarfBuzz()),await Text.hbInitPromise;const o="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(o,n),r&&(this.loadedFont.fontFeatures=r);const e=Text.generateFontContentHash(o);this.currentFontId=`font_${e}`,n&&(this.currentFontId+=`_var_${JSON.stringify(n)}`),r&&(this.currentFontId+=`_feat_${JSON.stringify(r)}`)}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):at;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:m=!0,language:b="en-us",tolerance:_=r,pretolerance:w=o,emergencyStretch:k=h,autoEmergencyStretch:O,hyphenationPatterns:j,lefthyphenmin:$,righthyphenmin:Y,linepenalty:q,adjdemerits:tt,hyphenpenalty:et,exhyphenpenalty:nt,doublehyphendemerits:it,looseness:st,disableShortLineDetection:rt,shortLineThreshold:at}=d;let ot;void 0!==f&&(ot=f*(this.loadedFont.upem/i));const ht=s*(this.loadedFont.upem/i);this.textLayout||(this.textLayout=new TextLayout(this.loadedFont));const ct=this.textLayout.computeLines({text:n,width:ot,align:g,direction:p,hyphenate:m,language:b,respectExistingBreaks:y,tolerance:_,pretolerance:w,emergencyStretch:k,autoEmergencyStretch:O,hyphenationPatterns:j,lefthyphenmin:$,righthyphenmin:Y,linepenalty:q,adjdemerits:tt,hyphenpenalty:et,exhyphenpenalty:nt,doublehyphendemerits:it,looseness:st,disableShortLineDetection:rt,shortLineThreshold:at,letterSpacing:l}),lt=FontMetadataExtractor.getVerticalMetrics(this.loadedFont.metrics),ut=(lt.ascender-lt.descender)*c;return{lines:ct.lines,scaledLineHeight:ut,letterSpacing:l,align:g,direction:p,depth:ht,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 m=d/this.loadedFont.upem;for(let n=0;n<e.length;n++)e[n]*=m;r.min.x*=m,r.min.y*=m,r.min.z*=m,r.max.x*=m,r.max.y*=m,r.max.z*=m;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*=m,n.bounds.min.y*=m,n.bounds.min.z*=m,n.bounds.max.x*=m,n.bounds.max.y*=m,n.bounds.max.z*=m}let b,_;if(o.color){const n=this.applyColorSystem(e,s,o.color,o.text);b=n.colors,_=n.coloredRanges}const w=this.geometryBuilder.getOptimizationStats(),k=i.length/3,O=e.length/3;return{vertices:e,normals:n,indices:i,colors:b,glyphs:s,planeBounds:r,stats:{trianglesGenerated:k,verticesGenerated:O,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}}resetHelpers(){this.geometryBuilder=void 0,this.textShaper=void 0,this.textLayout=void 0}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=st,e.FontMetadataExtractor=FontMetadataExtractor,e.Text=Text,e.globalGlyphCache=at});
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=800,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,m=1e4,b=-1/0,_=2,w=4,k=1e4,O=.7;class LineBreak{static badness(e,n){if(0===e)return 0;if(n<=0)return k;let i;return i=e<=7230584?Math.floor(297*e/n):n>=1663497?Math.floor(e/Math.floor(n/297)):e,i>1290?k: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 isCJK(e){const n=e.codePointAt(0);return void 0!==n&&(n>=19968&&n<=40959||n>=13312&&n<=19903||n>=131072&&n<=173791||n>=173824&&n<=177983||n>=177984&&n<=178207||n>=178208&&n<=183983||n>=63744&&n<=64255||n>=12352&&n<=12447||n>=12448&&n<=12543||n>=44032&&n<=55215||n>=4352&&n<=4607||n>=12592&&n<=12687||n>=43360&&n<=43391||n>=55216&&n<=55295||n>=65440&&n<=65500)}static isCJClosingPunctuation(e){const n=e.charCodeAt(0);return 12289===n||12290===n||65292===n||65294===n||65306===n||65307===n||65281===n||65311===n||65289===n||12305===n||65373===n||12301===n||12303===n||12297===n||12299===n||12309===n||12311===n||12313===n||12315===n||12540===n||8212===n||8230===n||8229===n}static isCJOpeningPunctuation(e){const n=e.charCodeAt(0);return 65288===n||12304===n||65371===n||12300===n||12302===n||12296===n||12298===n||12308===n||12310===n||12312===n||12314===n}static isCJPunctuation(e){return this.isCJClosingPunctuation(e)||this.isCJOpeningPunctuation(e)}static itemizeCJKText(e,n,i,s=0,r){const o=[],h=Array.from(e);let d,f,p,g=s;if(r)d=r.width,f=r.stretch,p=r.shrink;else{const e=n("字");d=0,f=.04*e,p=.04*e}for(let e=0;e<h.length;e++){const i=h[e],s=e<h.length-1?h[e+1]:null;if(/\s/.test(i)){const e=n(i);o.push({type:l.GLUE,width:e,stretch:.5*e,shrink:e*c,text:i,originIndex:g}),g+=i.length;continue}if(o.push({type:l.BOX,width:n(i),text:i,originIndex:g}),g+=i.length,s&&!/\s/.test(s)){let e=!0;this.isCJClosingPunctuation(s)&&(e=!1),this.isCJOpeningPunctuation(i)&&(e=!1);const n=this.isCJPunctuation(i)&&this.isCJPunctuation(s);e&&!n&&o.push({type:l.GLUE,width:d,stretch:f,shrink:p,text:"",originIndex:g})}}return o}static itemizeParagraph(e,n,i,s,r,o,h,c){const l=[],d=Array.from(e),f=n("字"),p={width:0,stretch:.04*f,shrink:.04*f};let g="",y=0,m=null,b=0;const flushBuffer=()=>{if(0!==g.length){if("cjk"===m){const e=this.itemizeCJKText(g,n,c,y,p);l.push(...e)}else{const e=this.itemizeWordBased(g,y,n,i,s,r,o,h,c);l.push(...e)}g="",m=null}};for(let e=0;e<d.length;e++){const n=d[e],i=this.isCJK(n)?"cjk":"word";null!==m&&m!==i&&(flushBuffer(),y=b),null===m&&(m=i,y=b),g+=n,b+=n.length}return flushBuffer(),l}static itemizeWordBased(e,n,i,s,r,o,h,d,g){const y=[],m=e.match(/\S+|\s+/g)||[];let b=0;for(let e=0;e<m.length;e++){const _=m[e],w=n+b;if(/\s+/.test(_)){const e=i(_);y.push({type:l.GLUE,width:e,stretch:.5*e,shrink:e*c,text:_,originIndex:w}),b+=_.length}else{const e=_.split(/(-)/);let n=w;for(let c=0;c<e.length;c++){const m=e[c];if(m)if("-"===m)y.push({type:l.DISCRETIONARY,width:i("-"),preBreak:"-",postBreak:"",noBreak:"-",preBreakWidth:i("-"),penalty:g?.exHyphenPenalty??p,flagged:!0,text:"-",originIndex:n}),n+=1;else{if(m.includes("­")){const e=m.split("­");let s=0;for(let r=0;r<e.length;r++){const o=e[r];o.length>0&&(y.push({type:l.BOX,width:i(o),text:o,originIndex:n+s}),s+=o.length),r<e.length-1&&(y.push({type:l.DISCRETIONARY,width:0,preBreak:"-",postBreak:"",noBreak:"",preBreakWidth:i("-"),penalty:g?.hyphenPenalty??f,flagged:!0,text:"",originIndex:n+s}),s+=1)}}else if(s&&m.length>=h+d&&/^\p{L}+$/u.test(m)){const e=LineBreak.findHyphenationPoints(m,r,o,h,d);if(e.length>0){let s=0;for(const r of e){const e=m.substring(s,r);y.push({type:l.BOX,width:i(e),text:e,originIndex:n+s}),y.push({type:l.DISCRETIONARY,width:0,preBreak:"-",postBreak:"",noBreak:"",preBreakWidth:i("-"),penalty:g?.hyphenPenalty??f,flagged:!0,text:"",originIndex:n+r}),s=r}const r=m.substring(s);y.push({type:l.BOX,width:i(r),text:r,originIndex:n+s})}else y.push({type:l.BOX,width:i(m),text:m,originIndex:n})}else y.push({type:l.BOX,width:i(m),text:m,originIndex:n});n+=m.length}}b+=_.length}}return y}static hasShortLines(e,n,i,s){let r=0;for(let o=0;o<n.length-1;o++){const h=n[o];let c=0;for(let n=r;n<h;n++)e[n].type!==l.PENALTY&&(c+=e[n].width);if(c>0){if(c/i<s)return!0}r=h+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:l="left",direction:d="ltr",hyphenate:b=!1,language:j="en-us",respectExistingBreaks:$=!0,measureText:Y,hyphenationPatterns:q,unitsPerEm:tt,tolerance:et=r,pretolerance:nt=o,emergencyStretch:it=h,autoEmergencyStretch:st,lefthyphenmin:rt=_,righthyphenmin:at=w,linepenalty:ot=y,adjdemerits:ht=m,hyphenpenalty:ct=f,exhyphenpenalty:lt=p,doublehyphendemerits:ut=g,looseness:dt=0,disableShortLineDetection:ft=!1,shortLineThreshold:pt=O}=e;if($&&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 gt=b;!gt||q&&q[j]||(i.warn(`Hyphenation patterns for ${j} not available`),gt=!1);let yt=it;void 0!==st&&c?yt=c*st:!gt&&it===h&&c&&(yt=.1*c);const mt={linePenalty:ot,adjDemerits:ht,doubleHyphenDemerits:ut,hyphenPenalty:ct,exHyphenPenalty:lt,currentAlign:l,unitsPerEm:tt};if(!c||c===1/0){const e=Y(n);return s.end("LineBreak.breakText"),[{text:n,originalStart:0,originalEnd:n.length-1,xOffset:0,isLastLine:!0,naturalWidth:e,endedWithHyphen:!1}]}const bt=LineBreak.itemizeText(n,Y,!1,j,q,rt,at,mt);if(0===bt.length)return[];let xt=0,_t=yt,vt=null;const wt=!ft;for(;xt<5;){let e=bt,i=LineBreak.findBreakpoints(e,c,nt,dt,!1,0,mt);if(0===i.length&&gt){e=LineBreak.itemizeText(n,Y,!0,j,q,rt,at,mt),i=LineBreak.findBreakpoints(e,c,et,dt,!1,0,mt)}if(0===i.length&&(_t=yt+xt*c*.1,i=LineBreak.findBreakpoints(e,c,et,dt,!0,_t,mt)),0===i.length&&(i=LineBreak.findBreakpoints(e,c,k,dt,!0,_t,mt)),i.length>0){const s=LineBreak.computeCumulativeWidths(e);if(vt=LineBreak.createLines(n,e,i,c,l,d,s,mt),wt&&i.length>1&&LineBreak.hasShortLines(e,i,c,pt)){xt++;continue}break}break}if(s.end("LineBreak.breakText"),vt&&vt.length>0)return vt;const Tt=Y(n);return[{text:n,originalStart:0,originalEnd:n.length-1,xOffset:0,adjustmentRatio:0,isLastLine:!0,naturalWidth:Tt,endedWithHyphen:!1}]}static findBreakpoints(e,n,i=1/0,s=0,r=!1,o=0,h){const c=LineBreak.computeCumulativeWidths(e),f=new ActiveNodeList,p={value:1/0};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 d=e[s];d.type===l.PENALTY&&d.penalty<1/0&&LineBreak.considerBreak(e,f,s,n,i,o,c,h,r,p),d.type===l.DISCRETIONARY&&d.penalty<1/0&&LineBreak.considerBreak(e,f,s,n,i,o,c,h,r,p),d.type===l.GLUE&&s>0&&e[s-1].type===l.BOX&&LineBreak.considerBreak(e,f,s,n,i,o,c,h,r,p),LineBreak.deactivateNodes(f,s,n,c.minWidths)}const g=[];let y=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,y=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?(y=i,o=e,h=i.totalDemerits):e===o&&i.totalDemerits<h&&(y=i,h=i.totalDemerits)}if(!r&&o!==s&&y)return[]}if(!y)return[];for(;y&&y.position>0;)g.unshift(y.position),y=y.previous;return g}static considerBreak(e,n,i,s,r=1/0,o=0,h,c,d=!1,f={value:1/0}){const p=(e[i].type===l.PENALTY?e[i].penalty:0)<=-1/0,g=n.getAllActive();for(let y=0;y<g.length;y++){const m=g[y];if(!m.active)continue;const _=LineBreak.computeAdjustmentRatio(e,m.position,i,m.line,s,h,c),{ratio:w,adjustment:k,stretch:O,shrink:j,totalWidth:$}=_;let Y;if(k>0){const e=O+o;Y=e<=0?10001:LineBreak.badness(k,e)}else Y=k<0?j<=0||-k>j?10001:LineBreak.badness(-k,j):0;const q=d&&p&&f.value===1/0&&1===g.length&&m.active;if(!p&&!q&&w<-1)continue;const tt=LineBreak.computeFitnessClass(Y,k>0);if(!p&&!q&&Y>r)continue;let et=0,nt=0;let it=(c?.linePenalty??0)+Y,st=Math.abs(it)>=1e4?1e8:it*it;const rt=q,at=e[i].type===l.PENALTY||e[i].type===l.DISCRETIONARY?e[i].penalty:0;0!==at&&(at>0?st+=at*at:at>b&&(st-=at*at));const ot=e[i].type===l.PENALTY&&e[i].flagged||e[i].type===l.DISCRETIONARY&&e[i].flagged,ht=m.position>0&&(e[m.position].type===l.PENALTY&&e[m.position].flagged||e[m.position].type===l.DISCRETIONARY&&e[m.position].flagged);ot&&ht&&(et=c?.doubleHyphenDemerits??0,st+=et),Math.abs(tt-m.fitness)>1&&(nt=c?.adjDemerits??0,st+=nt),(p||rt)&&(st=0);const ct=m.totalDemerits+st;ct<f.value&&(f.value=ct);let lt=n.findExisting(i,tt);lt?ct<lt.totalDemerits&&(lt.totalDemerits=ct,lt.previous=m,lt.totalWidth=$):n.insert({position:i,line:m.line+1,fitness:tt,totalDemerits:ct,totalWidth:$,previous:m,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)s[n+1]=s[n],r[n+1]=r[n],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 m=-1,b=-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===m||i.originIndex<m)&&(m=i.originIndex);const e=i.text?i.text.length:0,n=i.originIndex+e-1;n>b&&(b=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 k=!1;if(p<n.length)if(w.type===l.PENALTY&&w.flagged)y.push("-"),_+=w.width,k=!0,void 0!==w.originIndex&&(b=w.originIndex-1);else if(w.type===l.DISCRETIONARY){const e=w;e.preBreak&&(y.push(e.preBreak),_+=e.preBreakWidth,k=e.flagged||!1,void 0!==w.originIndex&&(b=w.originIndex-1))}const O=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:O,originalStart:m,originalEnd:b,xOffset:j,adjustmentRatio:$,isLastLine:!1,naturalWidth:_,endedWithHyphen:k}),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}}function convertFontFeaturesToString(e){if(!e||0===Object.keys(e).length)return;const n=[];for(const[s,r]of Object.entries(e))/^[a-zA-Z0-9]{4}$/.test(s)?!1===r||0===r?n.push(`${s}=0`):!0===r||1===r?n.push(s):"number"==typeof r&&r>1?n.push(`${s}=${Math.floor(r)}`):i.warn(`Invalid value for feature "${s}": ${r}. Expected boolean or positive number.`):i.warn(`Invalid OpenType feature tag: "${s}". Tags must be exactly 4 alphanumeric characters.`);return n.length>0?n.join(","):void 0}class TextMeasurer{static measureTextWidth(e,n,i=0){const s=e.hb.createBuffer();s.addText(n),s.guessSegmentProperties();const r=convertFontFeaturesToString(e.fontFeatures);e.hb.shape(e.font,s,r);const o=s.json(e.font),h=i*e.upem;let c=0;return o.forEach(e=>{c+=e.ax,0!==h&&(c+=h)}),s.destroy(),c}}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:m,linepenalty:b,adjdemerits:_,hyphenpenalty:w,exhyphenpenalty:k,doublehyphendemerits:O,looseness:j,disableShortLineDetection:$,shortLineThreshold:Y,letterSpacing:q}=e;let tt;if(i)tt=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:m,linepenalty:b,adjdemerits:_,hyphenpenalty:w,exhyphenpenalty:k,doublehyphendemerits:O,looseness:j,disableShortLineDetection:$,shortLineThreshold:Y,unitsPerEm:this.loadedFont.upem,measureText:e=>TextMeasurer.measureTextWidth(this.loadedFont,e,q)});else{const e=n.split("\n");tt=[];let i=0;for(const n of e)tt.push({text:n,originalStart:i,originalEnd:i+n.length-1,xOffset:0}),i+=n.length+1}return{lines:tt}}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 j=1330926671,$=1953784678,Y=2001684038,q=1851878757;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,j,$].includes(i))throw new Error(`Invalid font format. Expected TrueType or OpenType, got signature: 0x${i.toString(16)}`);const s=n.getUint16(4);let r=!1,o=0,h=0,c=0,l=0,d=0,f=0;for(let e=0;e<s;e++){const i=12+16*e,s=n.getUint32(i);1128678944===s||1128678962===s?r=!0:1751474532===s?o=n.getUint32(i+8):1751672161===s?h=n.getUint32(i+8):1330851634===s?c=n.getUint32(i+8):1719034226===s?f=n.getUint32(i+8):1398030676===s?l=n.getUint32(i+8):s===q&&(d=n.getUint32(i+8))}const p=o?n.getUint16(o+18):1e3;let g=null;h&&(g={ascender:n.getInt16(h+4),descender:n.getInt16(h+6),lineGap:n.getInt16(h+8)});let y=null;c&&(y={typoAscender:n.getInt16(c+68),typoDescender:n.getInt16(c+70),typoLineGap:n.getInt16(c+72),winAscent:n.getUint16(c+74),winDescent:n.getUint16(c+76)});let m=null;return f&&l&&d&&(m=this.extractAxisNames(n,l,d)),{isCFF:r,unitsPerEm:p,hheaAscender:g?.ascender||null,hheaDescender:g?.descender||null,hheaLineGap:g?.lineGap||null,typoAscender:y?.typoAscender||null,typoDescender:y?.typoDescender||null,typoLineGap:y?.typoLineGap||null,winAscent:y?.winAscent||null,winDescent:y?.winDescent||null,axisNames:m}}static extractFeatureTags(e){const n=new DataView(e),i=n.getUint16(4);let s=0,r=0,o=0;for(let e=0;e<i;e++){const i=12+16*e,h=n.getUint32(i);1196643650===h?s=n.getUint32(i+8):1196445523===h?r=n.getUint32(i+8):h===q&&(o=n.getUint32(i+8))}const h=new Set,c={};try{if(s){const e=this.extractFeatureDataFromTable(n,s,o);e.features.forEach(e=>h.add(e)),Object.assign(c,e.names)}if(r){const e=this.extractFeatureDataFromTable(n,r,o);e.features.forEach(e=>h.add(e)),Object.assign(c,e.names)}}catch(e){return}const l=Array.from(h).sort();if(0!==l.length)return{tags:l,names:Object.keys(c).length>0?c:{}}}static extractFeatureDataFromTable(e,n,i){const s=n+e.getUint16(n+6),r=e.getUint16(s),o=[],h={};for(let n=0;n<r;n++){const r=s+2+6*n,c=String.fromCharCode(e.getUint8(r),e.getUint8(r+1),e.getUint8(r+2),e.getUint8(r+3));if(o.push(c),/^(ss\d{2}|cv\d{2})$/.test(c)&&i){const n=s+e.getUint16(r+4),o=e.getUint16(n);if(0!==o){const s=n+o;if(0===e.getUint16(s)){const n=e.getUint16(s+2),r=this.getNameFromNameTable(e,i,n);r&&(h[c]=r)}}}}return{features:o,names:h}}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===Y?"woff":2001684018===n?"woff2":"ttf/otf"}static async decompressWoff(e){const n=new DataView(e),s=new Uint8Array(e);if(n.getUint32(0)!==Y)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,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}}const p=FontMetadataExtractor.extractFeatureTags(e);return{hb:h,fontBlob:i,face:s,font:r,module:c,upem:d.unitsPerEm,metrics:d,fontVariations:n,isVariable:l,variationAxes:f,availableFeatures:p?.tags,featureNames:p?.names}}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 tt="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 et={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,m=l,b=h;if(u(g,y)||(f=g,g=y,y=f),u(m,b)||(f=m,m=b,b=f),u(g,m)||(f=g,g=m,m=f,f=y,y=b,b=f),u(m,y)?u(y,b)?(0>(f=v(g,m,y))+(p=v(m,y,b))&&(f=-f,p=-p),d.b=A(f,m.b,p,y.b)):(0>(f=x(g,m,y))+(p=-x(g,b,y))&&(f=-f,p=-p),d.b=A(f,m.b,p,b.b)):d.b=(m.b+y.b)/2,z(g,y)||(f=g,g=y,y=f),z(m,b)||(f=m,m=b,b=f),z(g,m)||(f=g,g=m,m=f,f=y,y=b,b=f),z(m,y)?z(y,b)?(0>(f=aa(g,m,y))+(p=aa(m,y,b))&&(f=-f,p=-p),d.a=A(f,m.a,p,y.a)):(0>(f=ba(g,m,y))+(p=-ba(g,b,y))&&(f=-f,p=-p),d.a=A(f,m.a,p,b.a)):d.a=(m.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},tt.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=tt.libtess}(et);var nt=et.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,r){const o=r||n?e:e.map(e=>this.reverseWinding(e));let h=this.pathsToContours(o);if(n){i.log("Two-pass: boundary extraction then triangulation"),s.start("Tessellator.boundaryPass",{contourCount:h.length});const e=this.performTessellation(h,"boundary");if(s.end("Tessellator.boundaryPass"),!e)return i.warn("libtess returned empty result from boundary pass"),{triangles:{vertices:[],indices:[]},contours:[]};h=this.boundaryToContours(e),i.log(`Boundary pass created ${h.length} contours. Starting triangulation pass.`)}else i.log("Single-pass triangulation for "+(r?"CFF":"TTF"));s.start("Tessellator.triangulationPass",{contourCount:h.length});const c=this.performTessellation(h,"triangles");if(s.end("Tessellator.triangulationPass"),!c){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:h}}return{triangles:{vertices:c.vertices,indices:c.indices||[]},contours:h}}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 nt.GluTesselator;s.gluTessProperty(nt.gluEnum.GLU_TESS_WINDING_RULE,nt.windingRule.GLU_TESS_WINDING_NONZERO);const r=[],o=[],h=[];let c=[];"boundary"===n&&s.gluTessProperty(nt.gluEnum.GLU_TESS_BOUNDARY_ONLY,!0),"triangles"===n?s.gluTessCallback(nt.gluEnum.GLU_TESS_VERTEX_DATA,e=>{o.push(e)}):(s.gluTessCallback(nt.gluEnum.GLU_TESS_BEGIN,()=>{c=[]}),s.gluTessCallback(nt.gluEnum.GLU_TESS_VERTEX_DATA,e=>{c.push(e)}),s.gluTessCallback(nt.gluEnum.GLU_TESS_END,()=>{c.length>0&&h.push([...c])})),s.gluTessCallback(nt.gluEnum.GLU_TESS_COMBINE,e=>{const n=r.length/2;return r.push(e[0],e[1]),n}),s.gluTessCallback(nt.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){if(s.start("BoundaryClusterer.cluster",{glyphCount:e.length}),0===e.length)return s.end("BoundaryClusterer.cluster"),[];const i=this.clusterSweepLine(e,n);return s.end("BoundaryClusterer.cluster"),i}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 it={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 st={distanceTolerance:.5,angleTolerance:.2},rt=1e-6;class Polygonizer{constructor(e){this.curveFidelityConfig={...st,...e}}setCurveFidelityConfig(e){this.curveFidelityConfig={...st,...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,m=r-e,b=o-n,_=Math.abs((i-r)*b-(s-o)*m),w=this.curveFidelityConfig.distanceTolerance??st.distanceTolerance,k=w*w;if(_>rt){if(_*_<=k*(m*m+b*b)){const c=this.curveFidelityConfig.angleTolerance??st.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=m*m+b*b;if(0===r){if((i-e)*(i-e)+(s-n)*(s-n)<=k)return void this.addPoint(i,s,h)}else{const o=((i-e)*m+(s-n)*b)/r;if(o>0&&o<1&&_*_<=k*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,m=(r+h)/2,b=(o+c)/2,_=(f+g)/2,w=(p+y)/2,k=(g+m)/2,O=(y+b)/2,j=(_+k)/2,$=(w+O)/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),nt=this.curveFidelityConfig.distanceTolerance??st.distanceTolerance,it=nt*nt;let at=0;switch(tt>rt&&(at|=1),et>rt&&(at|=2),at){case 0:const d=Y*Y+q*q;if(0===d){if((i-e)*(i-e)+(s-n)*(s-n)<=it&&(r-e)*(r-e)+(o-n)*(o-n)<=it)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)<=it*d)return this.addPoint(i,s,l),void this.addPoint(r,o,l)}break;case 1:if(et*et<=it*(Y*Y+q*q)){const e=this.curveFidelityConfig.angleTolerance??st.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<=it*(Y*Y+q*q)){const h=this.curveFidelityConfig.angleTolerance??st.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)<=it*(Y*Y+q*q)){const d=this.curveFidelityConfig.angleTolerance??st.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,$,k,O,m,b,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({...it,...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()),s.start("Glyph.polygonizeAndOptimize",{glyphId:e,textIndex:n})}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)),s.end("Glyph.polygonizeAndOptimize"),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)<rt)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<rt&&y<rt)return void this.onLineTo(r,o);const m=this.polygonizer.polygonizeCubic(h,c,l,d);for(const e of m)this.updateBounds(e);for(let e=0;e<m.length;e++)this.currentPath.points.push(m[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({...it,...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 LRUCache{constructor(e={}){this.cache=new Map,this.head=null,this.tail=null,this.stats={hits:0,misses:0,evictions:0,size:0,memoryUsage:0},this.options={maxEntries:e.maxEntries??1/0,maxMemoryBytes:e.maxMemoryBytes??1/0,calculateSize:e.calculateSize??(()=>0),onEvict:e.onEvict}}get(e){const n=this.cache.get(e);return n?(this.stats.hits++,this.moveToHead(n),n.value):void this.stats.misses++}has(e){return this.cache.has(e)}set(e,n){const i=this.cache.get(e);if(i){const e=this.options.calculateSize(i.value),s=this.options.calculateSize(n);return this.stats.memoryUsage=this.stats.memoryUsage-e+s,i.value=n,void this.moveToHead(i)}const s=this.options.calculateSize(n);this.evictIfNeeded(s);const r={key:e,value:n,prev:null,next:null};this.cache.set(e,r),this.addToHead(r),this.stats.size=this.cache.size,this.stats.memoryUsage+=s}delete(e){const n=this.cache.get(e);if(!n)return!1;const i=this.options.calculateSize(n.value);return this.removeNode(n),this.cache.delete(e),this.stats.size=this.cache.size,this.stats.memoryUsage-=i,this.options.onEvict&&this.options.onEvict(e,n.value),!0}clear(){if(this.options.onEvict)for(const[e,n]of this.cache)this.options.onEvict(e,n.value);this.cache.clear(),this.head=null,this.tail=null,this.stats={hits:0,misses:0,evictions:0,size:0,memoryUsage:0}}getStats(){const e=this.stats.hits+this.stats.misses,n=e>0?this.stats.hits/e*100:0,i=this.stats.memoryUsage/1048576;return{...this.stats,hitRate:n,memoryUsageMB:i}}keys(){const e=[];let n=this.head;for(;n;)e.push(n.key),n=n.next;return e}get size(){return this.cache.size}evictIfNeeded(e){for(;this.cache.size>=this.options.maxEntries&&this.tail;)this.evictTail();if(this.options.maxMemoryBytes<1/0)for(;this.tail&&this.stats.memoryUsage+e>this.options.maxMemoryBytes;)this.evictTail()}evictTail(){if(!this.tail)return;const e=this.tail,n=this.options.calculateSize(e.value);this.removeTail(),this.cache.delete(e.key),this.stats.size=this.cache.size,this.stats.memoryUsage-=n,this.stats.evictions++,this.options.onEvict&&this.options.onEvict(e.key,e.value)}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))}}class GlyphGeometryBuilder{constructor(e,n){this.fontId="default",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),this.contourCache=new LRUCache({maxEntries:1e3,calculateSize:e=>{let n=0;for(const i of e.paths)n+=16*i.points.length;return n+64}}),this.wordCache=new LRUCache({maxEntries:1e3,calculateSize:e=>{let n=4*e.vertices.length;return n+=4*e.normals.length,n+=e.indices.length*e.indices.BYTES_PER_ELEMENT,n}})}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,h){s.start("GlyphGeometryBuilder.buildInstancedGeometry",{lineCount:e.length,wordCount:e.flat().length,depth:n,removeOverlaps:i});const c=[],l=[],d=[],f=[],p={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 g=e[s];for(const e of g){const s=[];for(const n of e.glyphs)s.push(this.getContoursForGlyph(n.g));const g=e.glyphs.map(e=>new Vec3(e.x,e.y,0)),y=this.clusterer.cluster(s,g),m=h&&e.glyphs.some(e=>h.has(e.absoluteTextIndex));if(!(o||m)&&y.some(e=>e.length>1)){const o=`${this.fontId}_${e.text}_${n}_${i}`;let h=this.wordCache.get(o);if(!h){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)))})}h=this.tessellateGlyphCluster(i,n,r),this.wordCache.set(o,h)}const g=c.length/3;this.appendGeometry(c,l,d,h,e.position,g);const y=h.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);f.push(c),this.updatePlaneBounds(c.bounds,p)}}else for(let o=0;o<e.glyphs.length;o++){const h=e.glyphs[o],g=s[o],y=new Vec3(e.position.x+(h.x??0),e.position.y+(h.y??0),e.position.z);if(0===g.paths.length){const e=this.createGlyphInfo(h,0,0,y,g,n);f.push(e);continue}let m=this.cache.get(this.fontId,h.g,n,i);m||(m=this.tessellateGlyph(g,n,i,r),this.cache.set(this.fontId,h.g,n,i,m));const b=c.length/3;this.appendGeometry(c,l,d,m,y,b);const _=this.createGlyphInfo(h,b,m.vertices.length/3,y,g,n);f.push(_),this.updatePlaneBounds(_.bounds,p)}}}const g=new Float32Array(c),y=new Float32Array(l),m=new Uint32Array(d);return s.end("GlyphGeometryBuilder.buildInstancedGeometry"),{vertices:g,normals:y,indices:m,glyphInfos:f,planeBounds:p}}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){const n=this.contourCache.get(e);if(n)return n;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 i=this.collector.getCollectedGlyphs()[0]||{glyphId:e,paths:[],bounds:{min:{x:0,y:0},max:{x:0,y:0}}};return this.contourCache.set(e,i),i}tessellateGlyphCluster(e,n,i){const s=this.tessellator.process(e,!0,i);return this.extrudeAndPackage(s,n)}extrudeAndPackage(e,n){s.start("Extruder.extrude",{depth:n,upem:this.loadedFont.upem});const i=this.extruder.extrude(e,n,this.loadedFont.upem);s.end("Extruder.extrude");const r=i.vertices;let o=1/0,h=1/0,c=1/0,l=-1/0,d=-1/0,f=-1/0;for(let e=0;e<r.length;e+=3){const n=r[e],i=r[e+1],s=r[e+2];n<o&&(o=n),n>l&&(l=n),i<h&&(h=i),i>d&&(d=i),s<c&&(c=s),s>f&&(f=s)}const p=new Vec3(o,h,c),g=new Vec3(l,d,f),y=i.vertices.length/3<65536?Uint16Array:Uint32Array;return{geometry:e,vertices:new Float32Array(i.vertices),normals:new Float32Array(i.normals),indices:new y(i.indices),bounds:{min:p,max:g},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 s.end("GlyphGeometryBuilder.tessellateGlyph"),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=[];return e.forEach((e,s)=>{const h=this.shapeLineIntoClusters(e,s,n,i,r,o);l.push(h)}),l}shapeLineIntoClusters(e,n,i,s,r,o){const h=this.loadedFont.hb.createBuffer();"rtl"===o&&h.setDirection("rtl"),h.addText(e.text),h.guessSegmentProperties();const c=convertFontFeaturesToString(this.loadedFont.fontFeatures);this.loadedFont.hb.shape(this.loadedFont.font,h,c);const l=h.json(this.loadedFont.font);h.destroy();const d=[];let f=[],p="",g=new Vec3,y=new Vec3(e.xOffset,-n*i,0);const m=s*this.loadedFont.upem,b=this.calculateSpaceAdjustment(e,r,s),_=this.calculateCJKAdjustment(e,r);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,r&&f.length>0&&(d.push({text:p,glyphs:f,position:g.clone()}),f=[],p="");const o=y.clone().add(new Vec3(s.dx,s.dy,0));if(r||(0===f.length&&g.copy(o),s.x=o.x-g.x,s.y=o.y-g.y,f.push(s),p+=e.text[s.cl]),y.x+=s.ax,y.y+=s.ay,0!==m&&i<l.length-1&&(y.x+=m),r&&(y.x+=b),0!==_&&i<l.length-1&&!r){const n=e.text[s.cl],r=l[i+1],o=e.text[r.cl],h=LineBreak.isCJK(n),c=o&&LineBreak.isCJK(o);if(h&&c){let e=!0;LineBreak.isCJClosingPunctuation(o)&&(e=!1),LineBreak.isCJOpeningPunctuation(n)&&(e=!1),LineBreak.isCJPunctuation(n)&&LineBreak.isCJPunctuation(o)&&(e=!1),e&&(y.x+=_)}}}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=n,o=.5,h=c;e.adjustmentRatio>0?s=e.adjustmentRatio*r*o:e.adjustmentRatio<0&&(s=e.adjustmentRatio*r*h)}return s}calculateCJKAdjustment(e,n){if(void 0===e.adjustmentRatio||"justify"!==n||e.isLastLine)return 0;const i=this.loadedFont.upem,s=.04*i,r=.04*i;return e.adjustmentRatio>0?e.adjustmentRatio*s:e.adjustmentRatio<0?e.adjustmentRatio*r:0}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 at=new GlyphCache(250);var ot={exports:{}};var ht=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=ht;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,m,b,_=console.error.bind(console),w=!1,isFileURI=e=>e.startsWith("file://"),k=!1;function updateMemoryViews(){var e=m.buffer;i.HEAP8=new Int8Array(e),i.HEAPU8=b=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 O,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==O&&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-m.buffer.byteLength+65535)/65536|0;try{return m.grow(n),updateMemoryViews(),1}catch(e){}},uleb128EncodeWithLen=e=>{const n=e.length;return[n%128|128,n>>7,...e]},at={i:127,p:127,j:126,f:125,d:124,e:111},generateTypePack=e=>uleb128EncodeWithLen(Array.from(e,e=>at[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),ot=[],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=m,i.wasmExports=lt,i.addFunction=(e,n)=>{var i=getFunctionAddress(e);if(i)return i;var s=ot.length?ot.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),ot.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=b.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,m=lt.memory,i.wasmMemory=m,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))})});O??=findWasmBinary();var n=function(e){return receiveInstance(e.instance)}(await instantiateAsync(f,O,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||(k=!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())}(),k?i:new Promise((e,n)=>{g=e,y=n})});e.exports=i,e.exports.default=i}(ot);var ct=getDefaultExportFromCjs(ot.exports),lt={exports:{}};try{lt.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,m=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"),m=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,m,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(m))}}},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,m=1048576,b=n.malloc(m),_=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),b,m,0,r,h,4),p.push({m:l,t:JSON.parse(i.decode(e.HEAPU8.subarray(b,e.HEAPU8.indexOf(0,b)))),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(b),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 ut=getDefaultExportFromCjs(lt.exports);let dt=null,ft=null,pt=null;const gt={setWasmPath(e){ft=e,pt=null,dt=null},setWasmBuffer(e){pt=e,ft=null,dt=null},getHarfBuzz:async()=>dt||(dt=new Promise(async(e,n)=>{try{const n={};if(pt)n.wasmBinary=pt;else{if(!ft)throw new Error("HarfBuzz WASM path or buffer must be set before initialization.");n.locateFile=(e,n)=>e.endsWith(".wasm")?ft:n+e}const i=await ct(n),s=ut(i);e({hb:s,module:{addFunction:i.addFunction,exports:i.wasmExports,removeFunction:i.removeFunction}})}catch(e){n(new Error(`Failed to initialize HarfBuzz: ${e}`))}}),dt)};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=gt.getHarfBuzz()),this.fontLoader=new FontLoader(()=>Text.hbInitPromise)}static setHarfBuzzPath(e){gt.setWasmPath(e),Text.hbInitPromise=null}static setHarfBuzzBuffer(e){gt.setWasmBuffer(e),Text.hbInitPromise=null}static init(){return Text.hbInitPromise||(Text.hbInitPromise=gt.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=gt.getHarfBuzz());const n=await Text.resolveFont(e),i=new Text({maxCacheSizeMB:e.maxCacheSizeMB});i.setLoadedFont(n);const{font:s,maxCacheSizeMB:r,...o}=e,h=await i.createGeometry(o),update=async n=>{const s={...e};for(const e in n){const i=n[e];void 0!==i&&(s[e]=i)}if(void 0!==n.font||void 0!==n.fontVariations||void 0!==n.fontFeatures){const e=await Text.resolveFont(s);i.setLoadedFont(e),i.resetHelpers()}e=s;const{font:r,maxCacheSizeMB:o,...h}=e;return{...await i.createGeometry(h),getLoadedFont:()=>i.getLoadedFont(),getCacheStatistics:()=>i.getCacheStatistics(),clearCache:()=>i.clearCache(),measureTextWidth:(e,n)=>i.measureTextWidth(e,n),update:update}};return{...h,getLoadedFont:()=>i.getLoadedFont(),getCacheStatistics:()=>i.getCacheStatistics(),clearCache:()=>i.clearCache(),measureTextWidth:(e,n)=>i.measureTextWidth(e,n),update:update}}static async resolveFont(e){let n="string"==typeof e.font?e.font:`buffer-${Text.generateFontContentHash(e.font)}`;e.fontVariations&&(n+=`_var_${JSON.stringify(e.fontVariations)}`),e.fontFeatures&&(n+=`_feat_${JSON.stringify(e.fontFeatures)}`);let i=Text.fontCache.get(n);return i||(i=await Text.loadAndCacheFont(n,e.font,e.fontVariations,e.fontFeatures)),i}static async loadAndCacheFont(e,n,i,s){const r=new Text;await r.loadFont(n,i,s);const o=r.getLoadedFont();return Text.fontCache.set(e,o),o}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+=`_var_${JSON.stringify(e.fontVariations)}`),e.fontFeatures&&(this.currentFontId+=`_feat_${JSON.stringify(e.fontFeatures)}`)}async loadFont(e,n,r){s.start("Text.loadFont",{fontSrc:"string"==typeof e?e:`buffer(${e.byteLength})`}),Text.hbInitPromise||(Text.hbInitPromise=gt.getHarfBuzz()),await Text.hbInitPromise;const o="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(o,n),r&&(this.loadedFont.fontFeatures=r);const e=Text.generateFontContentHash(o);this.currentFontId=`font_${e}`,n&&(this.currentFontId+=`_var_${JSON.stringify(n)}`),r&&(this.currentFontId+=`_feat_${JSON.stringify(r)}`)}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):at;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);let o;if(e.color&&"object"==typeof e.color&&!Array.isArray(e.color)&&(e.color.byText||e.color.byCharRange)){if(o=new Set,e.color.byText)for(const n of Object.keys(e.color.byText)){let i=0;for(;-1!==(i=e.text.indexOf(n,i));){for(let e=i;e<i+n.length;e++)o.add(e);i+=n.length}}if(e.color.byCharRange)for(const n of e.color.byCharRange)for(let e=n.start;e<n.end;e++)o.add(e)}const h=this.geometryBuilder.buildInstancedGeometry(r,i.depth,s,this.loadedFont.metrics.isCFF,e.separateGlyphsWithAttributes||!1,o),c=this.geometryBuilder.getCacheStats(),l=this.finalizeGeometry(h.vertices,h.normals,h.indices,h.glyphInfos,h.planeBounds,e,c,e.text);if(e.separateGlyphsWithAttributes){const e=this.createGlyphAttributes(l.vertices.length/3,l.glyphs);l.glyphAttributes=e}return l}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:m=!0,language:b="en-us",tolerance:_=r,pretolerance:w=o,emergencyStretch:k=h,autoEmergencyStretch:O,hyphenationPatterns:j,lefthyphenmin:$,righthyphenmin:Y,linepenalty:q,adjdemerits:tt,hyphenpenalty:et,exhyphenpenalty:nt,doublehyphendemerits:it,looseness:st,disableShortLineDetection:rt,shortLineThreshold:at}=d;let ot;void 0!==f&&(ot=f*(this.loadedFont.upem/i));const ht=s*(this.loadedFont.upem/i);this.textLayout||(this.textLayout=new TextLayout(this.loadedFont));const ct=this.textLayout.computeLines({text:n,width:ot,align:g,direction:p,hyphenate:m,language:b,respectExistingBreaks:y,tolerance:_,pretolerance:w,emergencyStretch:k,autoEmergencyStretch:O,hyphenationPatterns:j,lefthyphenmin:$,righthyphenmin:Y,linepenalty:q,adjdemerits:tt,hyphenpenalty:et,exhyphenpenalty:nt,doublehyphendemerits:it,looseness:st,disableShortLineDetection:rt,shortLineThreshold:at,letterSpacing:l}),lt=FontMetadataExtractor.getVerticalMetrics(this.loadedFont.metrics),ut=(lt.ascender-lt.descender)*c;return{lines:ct.lines,scaledLineHeight:ut,letterSpacing:l,align:g,direction:p,depth:ht,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 m=d/this.loadedFont.upem;for(let n=0;n<e.length;n++)e[n]*=m;r.min.x*=m,r.min.y*=m,r.min.z*=m,r.max.x*=m,r.max.y*=m,r.max.z*=m;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*=m,n.bounds.min.y*=m,n.bounds.min.z*=m,n.bounds.max.x*=m,n.bounds.max.y*=m,n.bounds.max.z*=m}let b,_;if(o.color){const n=this.applyColorSystem(e,s,o.color,o.text);b=n.colors,_=n.coloredRanges}const w=this.geometryBuilder.getOptimizationStats(),k=i.length/3,O=e.length/3;return{vertices:e,normals:n,indices:i,colors:b,glyphs:s,planeBounds:r,stats:{trianglesGenerated:k,verticesGenerated:O,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}}resetHelpers(){this.geometryBuilder=void 0,this.textShaper=void 0,this.textLayout=void 0}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=st,e.FontMetadataExtractor=FontMetadataExtractor,e.Text=Text,e.globalGlyphCache=at});
@@ -35,7 +35,7 @@ export declare class GlyphGeometryBuilder {
35
35
  setCurveFidelityConfig(config?: CurveFidelityConfig): void;
36
36
  setGeometryOptimization(options?: GeometryOptimizationOptions): void;
37
37
  setFontId(fontId: string): void;
38
- buildInstancedGeometry(clustersByLine: GlyphCluster[][], depth: number, removeOverlaps: boolean, isCFF: boolean, separateGlyphs?: boolean): InstancedTextGeometry;
38
+ buildInstancedGeometry(clustersByLine: GlyphCluster[][], depth: number, removeOverlaps: boolean, isCFF: boolean, separateGlyphs?: boolean, coloredTextIndices?: Set<number>): InstancedTextGeometry;
39
39
  private appendGeometry;
40
40
  private createGlyphInfo;
41
41
  private getContoursForGlyph;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-text",
3
- "version": "0.2.10",
3
+ "version": "0.2.12",
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",
@@ -101,6 +101,7 @@
101
101
  "@rollup/plugin-replace": "^6.0.2",
102
102
  "@rollup/plugin-terser": "^0.4.0",
103
103
  "@rollup/plugin-typescript": "^11.0.0",
104
+ "@types/libtess": "^1.2.0",
104
105
  "@types/react": ">=17.0.0",
105
106
  "@types/three": ">=0.175.0",
106
107
  "http-server": "^14.1.1",