three-text 0.2.0 → 0.2.1

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.0
2
+ * three-text v0.2.1
3
3
  * Copyright (C) 2025 Countertype LLC
4
4
  *
5
5
  * This program is free software: you can redistribute it and/or modify
@@ -11,4 +11,4 @@
11
11
  *
12
12
  * This software includes third-party code - see LICENSE_THIRD_PARTY for details.
13
13
  */
14
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ThreeText={})}(this,function(e){const t=!("undefined"==typeof window||!window.THREE_TEXT_LOG)||"undefined"!=typeof globalThis&&"true"===globalThis.process?.env?.THREE_TEXT_LOG;const n=new class{warn(e,...t){console.warn(e,...t)}error(e,...t){console.error(e,...t)}log(e,...n){t&&console.log(e,...n)}};const i=new class{constructor(){this.metrics=[],this.activeTimers=new Map}start(e,n){if(!t)return;const i=performance.now();this.activeTimers.set(e,i),this.metrics.push({name:e,startTime:i,metadata:n})}end(e){if(!t)return null;const i=performance.now(),s=this.activeTimers.get(e);if(void 0===s)return n.warn(`Performance timer "${e}" was not started`),null;const r=i-s;this.activeTimers.delete(e);for(let t=this.metrics.length-1;t>=0;t--){const n=this.metrics[t];if(n.name===e&&!n.endTime){n.endTime=i,n.duration=r;break}}return console.log(`${e}: ${r.toFixed(2)}ms`),r}getSummary(){if(!t)return{};const e={};for(const t of this.metrics){if(!t.duration)continue;const n=e[t.name];n?(n.count++,n.totalDuration+=t.duration,n.avgDuration=n.totalDuration/n.count,n.lastDuration=t.duration):e[t.name]={count:1,avgDuration:t.duration,totalDuration:t.duration,lastDuration:t.duration}}return e}printSummary(){if(!t)return;const e=this.getSummary();console.table(e),console.log("Operations:",Object.keys(e).sort().join(", "))}printBaseline(){if(!t)return;const e=this.getSummary();Object.entries(e).forEach(([e,t])=>{console.log(`BASELINE ${e}: ${t.avgDuration.toFixed(2)}ms avg (${t.count} calls)`)})}clear(){t&&(this.metrics.length=0,this.activeTimers.clear())}time(e,n,i){if(!t)return n();this.start(e,i);try{return n()}finally{this.end(e)}}async timeAsync(e,n,i){if(!t)return n();this.start(e,i);try{return await n()}finally{this.end(e)}}},s=200,r=100,o=0,h=1/3;var l,c;!function(e){e[e.BOX=0]="BOX",e[e.GLUE=1]="GLUE",e[e.PENALTY=2]="PENALTY",e[e.DISCRETIONARY=3]="DISCRETIONARY"}(l||(l={})),function(e){e[e.TIGHT=0]="TIGHT",e[e.NORMAL=1]="NORMAL",e[e.LOOSE=2]="LOOSE",e[e.VERY_LOOSE=3]="VERY_LOOSE"}(c||(c={}));class ActiveNodeList{constructor(){this.nodesByKey=new Map,this.activeList=[],this.allNodes=new Set}getKey(e,t){return e<<2|t}insert(e){const t=this.getKey(e.position,e.fitness),n=this.nodesByKey.get(t);n&&e.totalDemerits<n.totalDemerits?(n.totalDemerits=e.totalDemerits,n.previous=e.previous,n.totalWidth=e.totalWidth):n||(this.nodesByKey.set(t,e),this.allNodes.add(e),e.activeListIndex=this.activeList.length,this.activeList.push(e))}findExisting(e,t){return this.nodesByKey.get(this.getKey(e,t))}getAllActive(){return this.activeList}deactivateNode(e){if(e.active&&void 0!==e.activeListIndex){e.active=!1;const t=e.activeListIndex,n=this.activeList.length-1;if(t!==n){const e=this.activeList[n];this.activeList[t]=e,e.activeListIndex=t}this.activeList.pop(),e.activeListIndex=void 0}}size(){return this.allNodes.size}}const d=50,u=50,f=1e4,p=10,g=1e4,m=-1/0,y=2,x=4,_=1e4;class LineBreak{static badness(e,t){if(0===e)return 0;if(t<=0)return _;let n;return n=e<=7230584?Math.floor(297*e/t):t>=1663497?Math.floor(e/Math.floor(t/297)):e,n>1290?_:Math.floor((n*n*n+131072)/262144)}static findHyphenationPoints(e,t="en-us",n,i=y,s=x){let r;if(!n||!n[t])return[];if(r=n[t],!r)return[];const o=`.${e.toLowerCase()}.`,h=new Array(o.length).fill(0);for(let e=0;e<o.length;e++){let t=r;for(let n=e;n<o.length;n++){const i=o[n];if(!t.children||!t.children[i])break;if(t=t.children[i],t.patterns)for(let n=0;n<t.patterns.length;n++){const i=e+n;i<h.length&&(h[i]=Math.max(h[i],t.patterns[n]))}}}const l=[];for(let e=2;e<o.length-2;e++)h[e]%2==1&&l.push(e-1);return l.filter(t=>t>=i&&e.length-t>=s)}static itemizeText(e,t,n=!1,i="en-us",s,r=y,o=x,h){const c=[];return c.push(...this.itemizeParagraph(e,t,n,i,s,r,o,h)),c.push({type:l.GLUE,width:0,stretch:1/0,shrink:0,text:"",originIndex:e.length}),c.push({type:l.PENALTY,width:0,penalty:-1/0,text:"",originIndex:e.length}),c}static itemizeParagraph(e,t,n,i,s,r,o,c){const f=[],p=e.match(/\S+|\s+/g)||[];let g=0;for(let e=0;e<p.length;e++){const m=p[e],y=g;if(/\s+/.test(m)){const e=t(m);f.push({type:l.GLUE,width:e,stretch:.5*e,shrink:e*h,text:m,originIndex:y}),g+=m.length}else{const e=m.split(/(-)/);let h=y;for(let p=0;p<e.length;p++){const g=e[p];if(g)if("-"===g)f.push({type:l.DISCRETIONARY,width:t("-"),preBreak:"-",postBreak:"",noBreak:"-",preBreakWidth:t("-"),penalty:c?.exHyphenPenalty??u,flagged:!0,text:"-",originIndex:h}),h+=1;else{if(g.includes("­")){const e=g.split("­");let n=0;for(let i=0;i<e.length;i++){const s=e[i];s.length>0&&(f.push({type:l.BOX,width:t(s),text:s,originIndex:h+n}),n+=s.length),i<e.length-1&&(f.push({type:l.DISCRETIONARY,width:0,preBreak:"-",postBreak:"",noBreak:"",preBreakWidth:t("-"),penalty:c?.hyphenPenalty??d,flagged:!0,text:"",originIndex:h+n}),n+=1)}}else if(n&&g.length>=r+o){const e=LineBreak.findHyphenationPoints(g,i,s,r,o);if(e.length>0){let n=0;for(const i of e){const e=g.substring(n,i);f.push({type:l.BOX,width:t(e),text:e,originIndex:h+n}),f.push({type:l.DISCRETIONARY,width:0,preBreak:"-",postBreak:"",noBreak:"",preBreakWidth:t("-"),penalty:c?.hyphenPenalty??d,flagged:!0,text:"",originIndex:h+i}),n=i}const i=g.substring(n);f.push({type:l.BOX,width:t(i),text:i,originIndex:h+n})}else f.push({type:l.BOX,width:t(g),text:g,originIndex:h})}else f.push({type:l.BOX,width:t(g),text:g,originIndex:h});h+=g.length}}g+=m.length}}return f}static hasSingleWordLines(e,t,n){let i=0;for(let s=0;s<t.length-1;s++){const r=t[s];let o=0,h=0;for(let t=i;t<r;t++)e[t].type===l.GLUE&&o++,e[t].type!==l.PENALTY&&(h+=e[t].width);if(0===o&&h>0){if(h/n<.5)return!0}i=r+1}return!1}static breakText(e){i.start("LineBreak.breakText",{textLength:e.text.length,width:e.width,align:e.align||"left",hyphenate:e.hyphenate||!1});const{text:t,width:h,align:c="left",direction:m="ltr",hyphenate:_=!1,language:v="en-us",respectExistingBreaks:w=!0,measureText:b,hyphenationPatterns:S,unitsPerEm:E,tolerance:L=s,pretolerance:O=r,emergencyStretch:T=o,autoEmergencyStretch:P,lefthyphenmin:F=y,righthyphenmin:C=x,linepenalty:B=p,adjdemerits:I=g,hyphenpenalty:A=d,exhyphenpenalty:U=u,doublehyphendemerits:R=f,looseness:D=0,disableSingleWordDetection:z=!1}=e;if(w&&t.includes("\n")){const n=t.split("\n"),s=[];let r=0;for(const t of n){if(0===t.length)s.push({text:"",originalStart:r,originalEnd:r,xOffset:0,isLastLine:!0,naturalWidth:0,endedWithHyphen:!1});else{const n=LineBreak.breakText({...e,text:t,respectExistingBreaks:!1});n.forEach(e=>{e.originalStart+=r,e.originalEnd+=r}),s.push(...n)}r+=t.length+1}return i.end("LineBreak.breakText"),s}let G=_;!G||S&&S[v]||(n.warn(`Hyphenation patterns for ${v} not available`),G=!1);let k=T;void 0!==P&&h?k=h*P:!G&&T===o&&h&&(k=.1*h);const M={linePenalty:B,adjDemerits:I,doubleHyphenDemerits:R,hyphenPenalty:A,exHyphenPenalty:U,currentAlign:c,unitsPerEm:E};if(!h||h===1/0){const e=b(t);return i.end("LineBreak.breakText"),[{text:t,originalStart:0,originalEnd:t.length-1,xOffset:0,isLastLine:!0,naturalWidth:e,endedWithHyphen:!1}]}const N=LineBreak.itemizeText(t,b,G,v,S,F,C,M);if(0===N.length)return[];let H=0,V=k,W=null;const q=!z;for(;H<5;){let e=G?N.filter(e=>e.type!==l.DISCRETIONARY||e.penalty!==(M?.hyphenPenalty??d)):N,n=LineBreak.findBreakpoints(e,h,O,D,!1,0,M);if(0===n.length&&G&&(e=N,n=LineBreak.findBreakpoints(e,h,L,D,!1,0,M)),0===n.length&&(e=N,n=LineBreak.findBreakpoints(e,h,10001,D,!0,V,M)),0===n.length&&(n=LineBreak.findBreakpoints(e,h,1/0,D,!0,V,M)),n.length>0){const i=LineBreak.computeCumulativeWidths(e);if(W=LineBreak.createLines(t,e,n,h,c,m,i,M),q&&n.length>1&&LineBreak.hasSingleWordLines(e,n,h)){V+=.1*h,H++;continue}break}break}if(i.end("LineBreak.breakText"),W&&W.length>0)return W;const j=b(t);return[{text:t,originalStart:0,originalEnd:t.length-1,xOffset:0,adjustmentRatio:0,isLastLine:!0,naturalWidth:j,endedWithHyphen:!1}]}static findBreakpoints(e,t,n=1/0,i=0,s=!1,r=0,o){const h=LineBreak.computeCumulativeWidths(e),d=new ActiveNodeList;d.insert({position:0,line:0,fitness:c.NORMAL,totalDemerits:0,totalWidth:0,previous:null,active:!0});for(let i=0;i<e.length;i++){const s=e[i];s.type===l.PENALTY&&s.penalty<1/0&&LineBreak.considerBreak(e,d,i,t,n,r,h,o),s.type===l.DISCRETIONARY&&s.penalty<1/0&&LineBreak.considerBreak(e,d,i,t,n,r,h,o),s.type===l.GLUE&&i>0&&e[i-1].type===l.BOX&&LineBreak.considerBreak(e,d,i,t,n,r,h,o),LineBreak.deactivateNodes(d,i,t,h.minWidths)}const u=[];let f=null;if(0===i){const e=d.getAllActive();let t=1/0;for(const n of e)n.active&&n.totalDemerits<t&&(t=n.totalDemerits,f=n)}else{const e=d.getAllActive();let t=0,n=1/0;for(const i of e)i.active&&i.totalDemerits<n&&(n=i.totalDemerits,t=i.line);let r=0,o=1/0;for(const n of e){if(!n.active)continue;const e=n.line-t;e<r&&i<=e||e>r&&i>=e?(f=n,r=e,o=n.totalDemerits):e===r&&n.totalDemerits<o&&(f=n,o=n.totalDemerits)}if(!s&&r!==i&&f)return[]}if(!f)return[];for(;f&&f.position>0;)u.unshift(f.position),f=f.previous;return u}static considerBreak(e,t,n,i,s=1/0,r=0,o,h){const c=(e[n].type===l.PENALTY?e[n].penalty:0)<=-1/0,d=t.getAllActive();for(let u=0;u<d.length;u++){const f=d[u];if(!f.active)continue;const p=LineBreak.computeAdjustmentRatio(e,f.position,n,f.line,i,o,h),{ratio:g,adjustment:y,stretch:x,shrink:_,totalWidth:v}=p;let w;if(y>0){const e=x+r;w=e<=0?10001:LineBreak.badness(y,e)}else w=y<0?_<=0||-y>_?10001:LineBreak.badness(-y,_):0;if(!c&&g<-1)continue;const b=LineBreak.computeFitnessClass(w,y>0);if(!c&&w>s)continue;let S=0,E=0;let L=(h?.linePenalty??0)+w,O=Math.abs(L)>=1e4?1e8:L*L;const T=e[n].type===l.PENALTY||e[n].type===l.DISCRETIONARY?e[n].penalty:0;0!==T&&(T>0?O+=T*T:T>m&&(O-=T*T));const P=e[n].type===l.PENALTY&&e[n].flagged||e[n].type===l.DISCRETIONARY&&e[n].flagged,F=f.position>0&&(e[f.position].type===l.PENALTY&&e[f.position].flagged||e[f.position].type===l.DISCRETIONARY&&e[f.position].flagged);P&&F&&(S=h?.doubleHyphenDemerits??0,O+=S),Math.abs(b-f.fitness)>1&&(E=h?.adjDemerits??0,O+=E),c&&(O=0);const C=f.totalDemerits+O;let B=t.findExisting(n,b);B?C<B.totalDemerits&&(B.totalDemerits=C,B.previous=f,B.totalWidth=v):t.insert({position:n,line:f.line+1,fitness:b,totalDemerits:C,totalWidth:v,previous:f,active:!0})}}static computeAdjustmentRatio(e,t,n,i,s,r,o){let h=0,c=0,d=0;if(r){h=r.widths[n]-r.widths[t],c=r.stretches[n]-r.stretches[t],d=r.shrinks[n]-r.shrinks[t];for(let i=t;i<n;i++){const t=e[i];t.type===l.PENALTY&&(h-=t.width)}}else for(let i=t;i<n;i++){const t=e[i];t.type!==l.PENALTY&&(h+=t.width,t.type===l.GLUE&&(c+=t.stretch,d+=t.shrink))}n<e.length&&(e[n].type===l.PENALTY||e[n].type===l.DISCRETIONARY)&&(h+=e[n].type===l.PENALTY?e[n].width:e[n].preBreakWidth);const u=s-h;let f;return f=u>0&&c>0?u/c:u<0&&d>0?u/d:0===u?0:u>0?3:-1,{ratio:f,adjustment:u,stretch:c,shrink:d,totalWidth:h}}static computeFitnessClass(e,t){return t?e<=12?c.NORMAL:e<=99?c.LOOSE:c.VERY_LOOSE:e<=12?c.NORMAL:c.TIGHT}static computeCumulativeWidths(e){const t=e.length+1,n=new Array(t),i=new Array(t),s=new Array(t),r=new Array(t);n[0]=0,i[0]=0,s[0]=0,r[0]=0;for(let t=0;t<e.length;t++){const o=e[t];if(n[t+1]=n[t]+o.width,o.type===l.PENALTY)r[t+1]=r[t];else if(o.type===l.GLUE){const e=o;i[t+1]=i[t]+e.stretch,s[t+1]=s[t]+e.shrink,r[t+1]=r[t]+Math.max(0,e.width-e.shrink)}else i[t+1]=i[t],s[t+1]=s[t],r[t+1]=r[t]+o.width}return{widths:n,stretches:i,shrinks:s,minWidths:r}}static deactivateNodes(e,t,n,i){const s=e.getAllActive();for(let r=s.length-1;r>=0;r--){const o=s[r];if(!o.active)continue;i[t]-i[o.position]>n&&e.deactivateNode(o)}}static createLines(e,t,n,i,s,r,o,h){if(0===n.length)return[{text:e,originalStart:0,originalEnd:e.length-1,xOffset:0}];const c=[];let d=0;for(let e=0;e<n.length;e++){const u=n[e],f=!(n[n.length-1]+1<t.length-1)&&e===n.length-1,p=[];let g=-1,m=-1,y=0;for(let e=d;e<u;e++){const n=t[e];if((n.type!==l.PENALTY||n.text)&&(n.type!==l.DISCRETIONARY||n.noBreak)){if(void 0!==n.originIndex){(-1===g||n.originIndex<g)&&(g=n.originIndex);const e=n.text?n.text.length:0,t=n.originIndex+e-1;t>m&&(m=t)}if(n.text)p.push(n.text);else if(n.type===l.DISCRETIONARY){const e=n;e.noBreak&&p.push(e.noBreak)}y+=n.width}}const x=t[u];let _=!1;if(u<t.length)if(x.type===l.PENALTY&&x.flagged)p.push("-"),y+=x.width,_=!0,void 0!==x.originIndex&&(m=x.originIndex-1);else if(x.type===l.DISCRETIONARY){const e=x;e.preBreak&&(p.push(e.preBreak),y+=e.preBreakWidth,_=e.flagged||!1,void 0!==x.originIndex&&(m=x.originIndex-1))}const v=p.join("");let w=0,b=0,S=s;if("justify"===s&&f&&(S="rtl"===r?"right":"left"),"center"===S)w=(i-y)/2;else if("right"===S)w=i-y;else if("justify"===S&&!f){b=LineBreak.computeAdjustmentRatio(t,d,u,e,i,o,h).ratio}c.push({text:v,originalStart:g,originalEnd:m,xOffset:w,adjustmentRatio:b,isLastLine:!1,naturalWidth:y,endedWithHyphen:_}),d=u+1}if(d<t.length-1){const e=[];let n=-1,o=-1,h=0;for(let i=d;i<t.length-1;i++){const s=t[i];s.type!==l.PENALTY&&(void 0!==s.originIndex&&((-1===n||s.originIndex<n)&&(n=s.originIndex),s.originIndex>o&&(o=s.originIndex)),s.text&&e.push(s.text),h+=s.width)}const u=e.join("");let f=0,p=s;"justify"===s&&(p="rtl"===r?"right":"left"),"center"===p?f=(i-h)/2:"right"===p&&(f=i-h),c.push({text:u,originalStart:n,originalEnd:o,xOffset:f,adjustmentRatio:0,isLastLine:!0,naturalWidth:h,endedWithHyphen:!1}),c.length>1&&(c[c.length-2].isLastLine=!1),c[c.length-1].isLastLine=!0}else c.length>0&&(c[c.length-1].isLastLine=!0);return c}}class TextMeasurer{static measureTextWidth(e,t,n=0){const i=e.hb.createBuffer();i.addText(t),i.guessSegmentProperties(),e.hb.shape(e.font,i);const s=i.json(e.font),r=n*e.upem;let o=0;return s.forEach((e,n)=>{o+=e.ax;const i=n===s.length-1,h=" "===t||" "===t||/^\s+$/.test(t);0===r||i&&!h||(o+=r)}),i.destroy(),o}}class TextLayout{constructor(e){this.loadedFont=e}computeLines(e){const{text:t,width:n,align:i,direction:s,hyphenate:r,language:o,respectExistingBreaks:h,tolerance:l,pretolerance:c,emergencyStretch:d,autoEmergencyStretch:u,hyphenationPatterns:f,lefthyphenmin:p,righthyphenmin:g,linepenalty:m,adjdemerits:y,hyphenpenalty:x,exhyphenpenalty:_,doublehyphendemerits:v,looseness:w,disableSingleWordDetection:b,letterSpacing:S}=e;let E;if(n)E=LineBreak.breakText({text:t,width:n,align:i,direction:s,hyphenate:r,language:o,respectExistingBreaks:h,tolerance:l,pretolerance:c,emergencyStretch:d,autoEmergencyStretch:u,hyphenationPatterns:f,lefthyphenmin:p,righthyphenmin:g,linepenalty:m,adjdemerits:y,hyphenpenalty:x,exhyphenpenalty:_,doublehyphendemerits:v,looseness:w,disableSingleWordDetection:b,unitsPerEm:this.loadedFont.upem,measureText:e=>TextMeasurer.measureTextWidth(this.loadedFont,e,S)});else{const e=t.split("\n");E=[];let n=0;for(const t of e)E.push({text:t,originalStart:n,originalEnd:n+t.length-1,xOffset:0}),n+=t.length+1}return{lines:E}}applyAlignment(e,t){const{width:n,align:i,planeBounds:s}=t;let r=0;const o={min:{...s.min},max:{...s.max}};if(n&&("center"===i||"right"===i)){const t=s.max.x-s.min.x;if("center"===i?r=(n-t)/2-s.min.x:"right"===i&&(r=n-s.max.x),0!==r){for(let t=0;t<e.length;t+=3)e[t]+=r;o.min.x+=r,o.max.x+=r}}return{offset:r,adjustedBounds:o}}}const v=1330926671,w=1953784678,b=2001684038;class FontMetadataExtractor{static extractMetadata(e){if(!e||e.byteLength<12)throw new Error("Invalid font buffer: too small to be a valid font file");const t=new DataView(e),n=t.getUint32(0);if(![65536,v,w].includes(n))throw new Error(`Invalid font format. Expected TrueType or OpenType, got signature: 0x${n.toString(16)}`);const i=new Uint8Array(e),s=t.getUint16(4);let r=!1,o=0,h=0,l=0,c=0,d=0,u=0;for(let e=0;e<s;e++){const n=(new TextDecoder).decode(i.slice(12+16*e,12+16*e+4));("CFF "===n||"CFF2"===n)&&(r=!0),"head"===n&&(o=t.getUint32(12+16*e+8)),"hhea"===n&&(h=t.getUint32(12+16*e+8)),"OS/2"===n&&(l=t.getUint32(12+16*e+8)),"fvar"===n&&(u=t.getUint32(12+16*e+8)),"STAT"===n&&(c=t.getUint32(12+16*e+8)),"name"===n&&(d=t.getUint32(12+16*e+8))}const f=o?t.getUint16(o+18):1e3;let p=null;h&&(p={ascender:t.getInt16(h+4),descender:t.getInt16(h+6),lineGap:t.getInt16(h+8)});let g=null;l&&(g={typoAscender:t.getInt16(l+68),typoDescender:t.getInt16(l+70),typoLineGap:t.getInt16(l+72),winAscent:t.getUint16(l+74),winDescent:t.getUint16(l+76)});let m=null;return u&&c&&d&&(m=this.extractAxisNames(t,c,d)),{isCFF:r,unitsPerEm:f,hheaAscender:p?.ascender||null,hheaDescender:p?.descender||null,hheaLineGap:p?.lineGap||null,typoAscender:g?.typoAscender||null,typoDescender:g?.typoDescender||null,typoLineGap:g?.typoLineGap||null,winAscent:g?.winAscent||null,winDescent:g?.winDescent||null,axisNames:m}}static extractAxisNames(e,t,n){try{if(e.getUint16(t)<1)return null;const i=e.getUint16(t+4),s=e.getUint16(t+6),r=e.getUint32(t+8),o={};for(let h=0;h<s;h++){const s=t+r+h*i,l=String.fromCharCode(e.getUint8(s),e.getUint8(s+1),e.getUint8(s+2),e.getUint8(s+3)),c=e.getUint16(s+4),d=this.getNameFromNameTable(e,n,c);d&&(o[l]=d)}return Object.keys(o).length>0?o:null}catch(e){return null}}static getNameFromNameTable(e,t,n){try{const i=e.getUint16(t+2),s=e.getUint16(t+4);for(let r=0;r<i;r++){const i=t+6+12*r,o=e.getUint16(i),h=e.getUint16(i+2),l=e.getUint16(i+4),c=e.getUint16(i+6),d=e.getUint16(i+8),u=e.getUint16(i+10);if(c===n&&(0===o||3===o&&1033===l)){const n=t+s+u,i=new Uint8Array(e.buffer,n,d);if(0===o||3===o&&1===h){let e="";for(let t=0;t<i.length;t+=2)e+=String.fromCharCode(i[t]<<8|i[t+1]);return e}return new TextDecoder("ascii").decode(i)}}return null}catch(e){return null}}static getVerticalMetrics(e){return null!==e.typoAscender&&null!==e.typoDescender?{ascender:e.typoAscender,descender:e.typoDescender,lineGap:0}:null!==e.hheaAscender&&null!==e.hheaDescender?{ascender:e.hheaAscender,descender:e.hheaDescender,lineGap:0}:null!==e.winAscent&&null!==e.winDescent?{ascender:e.winAscent,descender:-e.winDescent,lineGap:0}:{ascender:Math.round(.8*e.unitsPerEm),descender:-Math.round(.2*e.unitsPerEm),lineGap:0}}static getFontMetrics(e){const t=FontMetadataExtractor.getVerticalMetrics(e);return{ascender:t.ascender,descender:t.descender,lineGap:t.lineGap,unitsPerEm:e.unitsPerEm,naturalLineHeight:t.ascender-t.descender}}}class WoffConverter{static detectFormat(e){if(e.byteLength<4)return"ttf/otf";const t=new DataView(e).getUint32(0);return t===b?"woff":2001684018===t?"woff2":"ttf/otf"}static async decompressWoff(e){const t=new DataView(e),i=new Uint8Array(e);if(t.getUint32(0)!==b)throw new Error("Not a valid WOFF font");const s=t.getUint32(4),r=t.getUint16(12),o=t.getUint32(16);if("undefined"==typeof DecompressionStream)throw new Error("WOFF fonts require DecompressionStream API (Chrome 80+, Firefox 113+, Safari 16.4+). Please use TTF/OTF fonts or upgrade your browser.");const h=new Uint8Array(o),l=new DataView(h.buffer);l.setUint32(0,s),l.setUint16(4,r);const c=2**Math.floor(Math.log2(r))*16;l.setUint16(6,c),l.setUint16(8,Math.floor(Math.log2(r))),l.setUint16(10,16*r-c);let d=12+16*r;const u=[];for(let e=0;e<r;e++){const n=44+20*e;u.push({tag:t.getUint32(n),offset:t.getUint32(n+4),length:t.getUint32(n+8),origLength:t.getUint32(n+12),checksum:t.getUint32(n+16)})}u.sort((e,t)=>e.tag-t.tag);for(let e=0;e<r;e++){const t=u[e],n=12+16*e;if(l.setUint32(n,t.tag),l.setUint32(n+4,t.checksum),l.setUint32(n+8,d),l.setUint32(n+12,t.origLength),t.length===t.origLength)h.set(i.subarray(t.offset,t.offset+t.length),d);else{const e=i.subarray(t.offset,t.offset+t.length),n=await WoffConverter.decompressZlib(e);if(n.byteLength!==t.origLength)throw new Error(`Decompression failed: expected ${t.origLength} bytes, got ${n.byteLength}`);h.set(new Uint8Array(n),d)}d+=t.origLength;d+=(4-t.origLength%4)%4}return n.log("WOFF font decompressed successfully"),h.buffer.slice(0,d)}static async decompressZlib(e){const t=new ReadableStream({start(t){t.enqueue(e),t.close()}}).pipeThrough(new DecompressionStream("deflate"));return new Response(t).arrayBuffer()}}class FontLoader{constructor(e){this.getHarfBuzzInstance=e}async loadFont(e,t){if(i.start("FontLoader.loadFont",{bufferSize:e.byteLength}),!e||e.byteLength<12)throw new Error("Invalid font buffer: too small to be a valid font file");const s=WoffConverter.detectFormat(e);if("woff"===s)n.log("WOFF font detected, decompressing..."),e=await WoffConverter.decompressWoff(e);else if("woff2"===s)throw new Error("WOFF2 fonts are not yet supported. Please use WOFF or TTF/OTF format.");const r=new DataView(e).getUint32(0);if(![65536,v,w].includes(r))throw new Error(`Invalid font format. Expected TrueType or OpenType, got signature: 0x${r.toString(16)}`);const{hb:o,module:h}=await this.getHarfBuzzInstance();try{const n=o.createBlob(new Uint8Array(e)),i=o.createFace(n,0),s=o.createFont(i);t&&s.setVariations(t);const r=i.getAxisInfos(),l=Object.keys(r).length>0,c=FontMetadataExtractor.extractMetadata(e);let d;if(l&&r){d={};for(const[e,t]of Object.entries(r))d[e]={...t,name:c.axisNames?.[e]||null}}return{hb:o,fontBlob:n,face:i,font:s,module:h,upem:c.unitsPerEm,metrics:c,fontVariations:t,isVariable:l,variationAxes:d}}catch(e){throw n.error("Failed to load font:",e),e}finally{i.end("FontLoader.loadFont")}}static destroyFont(e){try{e.font&&"function"==typeof e.font.destroy&&e.font.destroy(),e.face&&"function"==typeof e.face.destroy&&e.face.destroy(),e.fontBlob&&"function"==typeof e.fontBlob.destroy&&e.fontBlob.destroy()}catch(e){n.error("Error destroying font resources:",e)}}}async function loadPattern(e,t){{const n=`ThreeTextPatterns_${e.replace(/-/g,"_")}`;if(window[n])return window[n];const i=t||"/patterns/";return new Promise((t,s)=>{const r=document.createElement("script");r.src=`${i}${e}.umd.js`,r.async=!0,r.onload=()=>{window[n]?t(window[n]):s(new Error(`Pattern script loaded, but global ${n} not found.`))},r.onerror=()=>{s(new Error(`Failed to load hyphenation pattern from ${r.src}. Did you copy the pattern files to your public directory?`))},document.head.appendChild(r)})}}class Vec2{constructor(e=0,t=0){this.x=e,this.y=t}set(e,t){return this.x=e,this.y=t,this}clone(){return new Vec2(this.x,this.y)}copy(e){return this.x=e.x,this.y=e.y,this}add(e){return this.x+=e.x,this.y+=e.y,this}sub(e){return this.x-=e.x,this.y-=e.y,this}multiply(e){return this.x*=e,this.y*=e,this}divide(e){return this.x/=e,this.y/=e,this}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}lengthSq(){return this.x*this.x+this.y*this.y}normalize(){const e=this.length();return e>0&&this.divide(e),this}dot(e){return this.x*e.x+this.y*e.y}distanceTo(e){const t=this.x-e.x,n=this.y-e.y;return Math.sqrt(t*t+n*n)}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y;return t*t+n*n}equals(e){return this.x===e.x&&this.y===e.y}angle(){return Math.atan2(this.y,this.x)}}class Vec3{constructor(e=0,t=0,n=0){this.x=e,this.y=t,this.z=n}set(e,t,n){return this.x=e,this.y=t,this.z=n,this}clone(){return new Vec3(this.x,this.y,this.z)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}multiply(e){return this.x*=e,this.y*=e,this.z*=e,this}divide(e){return this.x/=e,this.y/=e,this.z/=e,this}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}normalize(){const e=this.length();return e>0&&this.divide(e),this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z}cross(e){const t=this.y*e.z-this.z*e.y,n=this.z*e.x-this.x*e.z,i=this.x*e.y-this.y*e.x;return this.x=t,this.y=n,this.z=i,this}distanceTo(e){const t=this.x-e.x,n=this.y-e.y,i=this.z-e.z;return Math.sqrt(t*t+n*n+i*i)}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y,i=this.z-e.z;return t*t+n*n+i*i}equals(e){return this.x===e.x&&this.y===e.y&&this.z===e.z}}class Box3{constructor(e=new Vec3(1/0,1/0,1/0),t=new Vec3(-1/0,-1/0,-1/0)){this.min=e,this.max=t}set(e,t){return this.min.copy(e),this.max.copy(t),this}setFromPoints(e){this.makeEmpty();for(let t=0;t<e.length;t++)this.expandByPoint(e[t]);return this}makeEmpty(){return this.min.x=this.min.y=this.min.z=1/0,this.max.x=this.max.y=this.max.z=-1/0,this}isEmpty(){return this.max.x<this.min.x||this.max.y<this.min.y||this.max.z<this.min.z}expandByPoint(e){return this.min.x=Math.min(this.min.x,e.x),this.min.y=Math.min(this.min.y,e.y),this.min.z=Math.min(this.min.z,e.z),this.max.x=Math.max(this.max.x,e.x),this.max.y=Math.max(this.max.y,e.y),this.max.z=Math.max(this.max.z,e.z),this}expandByScalar(e){return this.min.x-=e,this.min.y-=e,this.min.z-=e,this.max.x+=e,this.max.y+=e,this.max.z+=e,this}containsPoint(e){return e.x>=this.min.x&&e.x<=this.max.x&&e.y>=this.min.y&&e.y<=this.max.y&&e.z>=this.min.z&&e.z<=this.max.z}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z}intersectsBox(e){return e.max.x>=this.min.x&&e.min.x<=this.max.x&&e.max.y>=this.min.y&&e.min.y<=this.max.y&&e.max.z>=this.min.z&&e.min.z<=this.max.z}getCenter(e=new Vec3){return this.isEmpty()?e.set(0,0,0):e.set(.5*(this.min.x+this.max.x),.5*(this.min.y+this.max.y),.5*(this.min.z+this.max.z))}getSize(e=new Vec3){return this.isEmpty()?e.set(0,0,0):e.set(this.max.x-this.min.x,this.max.y-this.min.y,this.max.z-this.min.z)}clone(){return new Box3(this.min.clone(),this.max.clone())}copy(e){return this.min.copy(e.min),this.max.copy(e.max),this}union(e){return this.min.x=Math.min(this.min.x,e.min.x),this.min.y=Math.min(this.min.y,e.min.y),this.min.z=Math.min(this.min.z,e.min.z),this.max.x=Math.max(this.max.x,e.max.x),this.max.y=Math.max(this.max.y,e.max.y),this.max.z=Math.max(this.max.z,e.max.z),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}}var S,E;function assert(e,t){if(!e)throw t||"Assertion Failed!"}!function(e){e[e.ODD=0]="ODD",e[e.NONZERO=1]="NONZERO",e[e.POSITIVE=2]="POSITIVE",e[e.NEGATIVE=3]="NEGATIVE",e[e.ABS_GEQ_TWO=4]="ABS_GEQ_TWO"}(S||(S={})),function(e){e[e.POLYGONS=0]="POLYGONS",e[e.CONNECTED_POLYGONS=1]="CONNECTED_POLYGONS",e[e.BOUNDARY_CONTOURS=2]="BOUNDARY_CONTOURS"}(E||(E={}));var L=function(){function Geom(){}return Geom.vertEq=function(e,t){return e.s===t.s&&e.t===t.t},Geom.vertLeq=function(e,t){return e.s<t.s||e.s===t.s&&e.t<=t.t},Geom.transLeq=function(e,t){return e.t<t.t||e.t===t.t&&e.s<=t.s},Geom.edgeGoesLeft=function(e){return Geom.vertLeq(e.Dst,e.Org)},Geom.edgeGoesRight=function(e){return Geom.vertLeq(e.Org,e.Dst)},Geom.vertL1dist=function(e,t){return Math.abs(e.s-t.s)+Math.abs(e.t-t.t)},Geom.edgeEval=function(e,t,n){assert(Geom.vertLeq(e,t)&&Geom.vertLeq(t,n));var i=t.s-e.s,s=n.s-t.s;return i+s>0?i<s?t.t-e.t+(e.t-n.t)*(i/(i+s)):t.t-n.t+(n.t-e.t)*(s/(i+s)):0},Geom.edgeSign=function(e,t,n){assert(Geom.vertLeq(e,t)&&Geom.vertLeq(t,n));var i=t.s-e.s,s=n.s-t.s;return i+s>0?(t.t-n.t)*i+(t.t-e.t)*s:0},Geom.transEval=function(e,t,n){assert(Geom.transLeq(e,t)&&Geom.transLeq(t,n));var i=t.t-e.t,s=n.t-t.t;return i+s>0?i<s?t.s-e.s+(e.s-n.s)*(i/(i+s)):t.s-n.s+(n.s-e.s)*(s/(i+s)):0},Geom.transSign=function(e,t,n){assert(Geom.transLeq(e,t)&&Geom.transLeq(t,n));var i=t.t-e.t,s=n.t-t.t;return i+s>0?(t.s-n.s)*i+(t.s-e.s)*s:0},Geom.vertCCW=function(e,t,n){return e.s*(t.t-n.t)+t.s*(n.t-e.t)+n.s*(e.t-t.t)>=0},Geom.interpolate=function(e,t,n,i){return(e=e<0?0:e)<=(n=n<0?0:n)?0===n?(t+i)/2:t+e/(e+n)*(i-t):i+n/(e+n)*(t-i)},Geom.intersect=function(e,t,n,i,s){var r,o,h;Geom.vertLeq(e,t)||(h=e,e=t,t=h),Geom.vertLeq(n,i)||(h=n,n=i,i=h),Geom.vertLeq(e,n)||(h=e,e=n,n=h,h=t,t=i,i=h),Geom.vertLeq(n,t)?Geom.vertLeq(t,i)?((r=Geom.edgeEval(e,n,t))+(o=Geom.edgeEval(n,t,i))<0&&(r=-r,o=-o),s.s=Geom.interpolate(r,n.s,o,t.s)):((r=Geom.edgeSign(e,n,t))+(o=-Geom.edgeSign(e,i,t))<0&&(r=-r,o=-o),s.s=Geom.interpolate(r,n.s,o,i.s)):s.s=(n.s+t.s)/2,Geom.transLeq(e,t)||(h=e,e=t,t=h),Geom.transLeq(n,i)||(h=n,n=i,i=h),Geom.transLeq(e,n)||(h=e,e=n,n=h,h=t,t=i,i=h),Geom.transLeq(n,t)?Geom.transLeq(t,i)?((r=Geom.transEval(e,n,t))+(o=Geom.transEval(n,t,i))<0&&(r=-r,o=-o),s.t=Geom.interpolate(r,n.t,o,t.t)):((r=Geom.transSign(e,n,t))+(o=-Geom.transSign(e,i,t))<0&&(r=-r,o=-o),s.t=Geom.interpolate(r,n.t,o,i.t)):s.t=(n.t+t.t)/2},Geom}(),TESSface=function(){this.next=null,this.prev=null,this.anEdge=null,this.trail=null,this.n=0,this.marked=!1,this.inside=!1},O=function(){function TESShalfEdge(e){this.side=e,this.next=null,this.Org=null,this.Sym=null,this.Onext=null,this.Lnext=null,this.Lface=null,this.activeRegion=null,this.winding=0}return Object.defineProperty(TESShalfEdge.prototype,"Rface",{get:function(){return this.Sym.Lface},set:function(e){this.Sym.Lface=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Dst",{get:function(){return this.Sym.Org},set:function(e){this.Sym.Org=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Oprev",{get:function(){return this.Sym.Lnext},set:function(e){this.Sym.Lnext=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Lprev",{get:function(){return this.Onext.Sym},set:function(e){this.Onext.Sym=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Dprev",{get:function(){return this.Lnext.Sym},set:function(e){this.Lnext.Sym=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Rprev",{get:function(){return this.Sym.Onext},set:function(e){this.Sym.Onext=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Dnext",{get:function(){return this.Sym.Onext.Sym},set:function(e){this.Sym.Onext.Sym=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Rnext",{get:function(){return this.Sym.Lnext.Sym},set:function(e){this.Sym.Lnext.Sym=e},enumerable:!0,configurable:!0}),TESShalfEdge}(),TESSvertex=function(){this.next=null,this.prev=null,this.anEdge=null,this.coords=[0,0,0],this.s=0,this.t=0,this.pqHandle=0,this.n=0,this.idx=0},T=function(){function TESSmesh(){var e=new TESSvertex,t=new TESSface,n=new O(0),i=new O(1);e.next=e.prev=e,e.anEdge=null,t.next=t.prev=t,n.next=n,n.Sym=i,i.next=i,i.Sym=n,this.vHead=e,this.fHead=t,this.eHead=n,this.eHeadSym=i}return TESSmesh.prototype.makeEdge_=function(e){var t=new O(0),n=new O(1);e.Sym.side<e.side&&(e=e.Sym);var i=e.Sym.next;return n.next=i,i.Sym.next=t,t.next=e,e.Sym.next=n,t.Sym=n,t.Onext=t,t.Lnext=n,t.Org=null,t.Lface=null,t.winding=0,t.activeRegion=null,n.Sym=t,n.Onext=n,n.Lnext=t,n.Org=null,n.Lface=null,n.winding=0,n.activeRegion=null,t},TESSmesh.prototype.splice_=function(e,t){var n=e.Onext,i=t.Onext;n.Sym.Lnext=t,i.Sym.Lnext=e,e.Onext=i,t.Onext=n},TESSmesh.prototype.makeVertex_=function(e,t,n){var i=e;assert(i,"Vertex can't be null!");var s=n.prev;i.prev=s,s.next=i,i.next=n,n.prev=i,i.anEdge=t;var r=t;do{r.Org=i,r=r.Onext}while(r!==t)},TESSmesh.prototype.makeFace_=function(e,t,n){var i=e;assert(i,"Face can't be null");var s=n.prev;i.prev=s,s.next=i,i.next=n,n.prev=i,i.anEdge=t,i.trail=null,i.marked=!1,i.inside=n.inside;var r=t;do{r.Lface=i,r=r.Lnext}while(r!==t)},TESSmesh.prototype.killEdge_=function(e){e.Sym.side<e.side&&(e=e.Sym);var t=e.next,n=e.Sym.next;t.Sym.next=n,n.Sym.next=t},TESSmesh.prototype.killVertex_=function(e,t){var n=e.anEdge,i=n;do{i.Org=t,i=i.Onext}while(i!==n);var s=e.prev,r=e.next;r.prev=s,s.next=r},TESSmesh.prototype.killFace_=function(e,t){var n=e.anEdge,i=n;do{i.Lface=t,i=i.Lnext}while(i!==n);var s=e.prev,r=e.next;r.prev=s,s.next=r},TESSmesh.prototype.makeEdge=function(){var e=new TESSvertex,t=new TESSvertex,n=new TESSface,i=this.makeEdge_(this.eHead);return this.makeVertex_(e,i,this.vHead),this.makeVertex_(t,i.Sym,this.vHead),this.makeFace_(n,i,this.fHead),i},TESSmesh.prototype.splice=function(e,t){var n=!1,i=!1;if(e!==t){if(t.Org!==e.Org&&(i=!0,this.killVertex_(t.Org,e.Org)),t.Lface!==e.Lface&&(n=!0,this.killFace_(t.Lface,e.Lface)),this.splice_(t,e),!i){var s=new TESSvertex;this.makeVertex_(s,t,e.Org),e.Org.anEdge=e}if(!n){var r=new TESSface;this.makeFace_(r,t,e.Lface),e.Lface.anEdge=e}}},TESSmesh.prototype.delete=function(e){var t=e.Sym,n=!1;if(e.Lface!==e.Rface&&(n=!0,this.killFace_(e.Lface,e.Rface)),e.Onext===e)this.killVertex_(e.Org,null);else if(e.Rface.anEdge=e.Oprev,e.Org.anEdge=e.Onext,this.splice_(e,e.Oprev),!n){var i=new TESSface;this.makeFace_(i,e,e.Lface)}t.Onext===t?(this.killVertex_(t.Org,null),this.killFace_(t.Lface,null)):(e.Lface.anEdge=t.Oprev,t.Org.anEdge=t.Onext,this.splice_(t,t.Oprev)),this.killEdge_(e)},TESSmesh.prototype.addEdgeVertex=function(e){var t=this.makeEdge_(e),n=t.Sym;this.splice_(t,e.Lnext),t.Org=e.Dst;var i=new TESSvertex;return this.makeVertex_(i,n,t.Org),t.Lface=n.Lface=e.Lface,t},TESSmesh.prototype.splitEdge=function(e){var t=this.addEdgeVertex(e).Sym;return this.splice_(e.Sym,e.Sym.Oprev),this.splice_(e.Sym,t),e.Dst=t.Org,t.Dst.anEdge=t.Sym,t.Rface=e.Rface,t.winding=e.winding,t.Sym.winding=e.Sym.winding,t},TESSmesh.prototype.connect=function(e,t){var n=!1,i=this.makeEdge_(e),s=i.Sym;if(t.Lface!==e.Lface&&(n=!0,this.killFace_(t.Lface,e.Lface)),this.splice_(i,e.Lnext),this.splice_(s,t),i.Org=e.Dst,s.Org=t.Org,i.Lface=s.Lface=e.Lface,e.Lface.anEdge=s,!n){var r=new TESSface;this.makeFace_(r,i,e.Lface)}return i},TESSmesh.prototype.zapFace=function(e){var t,n,i,s,r,o=e.anEdge;n=o.Lnext;do{n=(t=n).Lnext,t.Lface=null,null===t.Rface&&(t.Onext===t?this.killVertex_(t.Org,null):(t.Org.anEdge=t.Onext,this.splice_(t,t.Oprev)),(i=t.Sym).Onext===i?this.killVertex_(i.Org,null):(i.Org.anEdge=i.Onext,this.splice_(i,i.Oprev)),this.killEdge_(t))}while(t!=o);s=e.prev,(r=e.next).prev=s,s.next=r},TESSmesh.prototype.countFaceVerts_=function(e){var t=e.anEdge,n=0;do{n++,t=t.Lnext}while(t!==e.anEdge);return n},TESSmesh.prototype.mergeConvexFaces=function(e){var t,n,i,s,r;for(t=this.fHead.next;t!==this.fHead;t=t.next)if(t.inside)for(r=(n=t.anEdge).Org;i=n.Lnext,(s=n.Sym)&&s.Lface&&s.Lface.inside&&this.countFaceVerts_(t)+this.countFaceVerts_(s.Lface)-2<=e&&L.vertCCW(n.Lprev.Org,n.Org,s.Lnext.Lnext.Org)&&L.vertCCW(s.Lprev.Org,s.Org,n.Lnext.Lnext.Org)&&(i=s.Lnext,this.delete(s),n=null,s=null),!n||n.Lnext.Org!==r;)n=i;return!0},TESSmesh.prototype.check=function(){var e,t,n,i,s,r,o=this.fHead,h=this.vHead,l=this.eHead;for(t=o,t=o;(e=t.next)!==o;t=e){assert(e.prev===t),s=e.anEdge;do{assert(s.Sym!==s),assert(s.Sym.Sym===s),assert(s.Lnext.Onext.Sym===s),assert(s.Onext.Sym.Lnext===s),assert(s.Lface===e),s=s.Lnext}while(s!==e.anEdge)}for(assert(e.prev===t&&null===e.anEdge),i=h,i=h;(n=i.next)!==h;i=n){assert(n.prev===i),s=n.anEdge;do{assert(s.Sym!==s),assert(s.Sym.Sym===s),assert(s.Lnext.Onext.Sym===s),assert(s.Onext.Sym.Lnext===s),assert(s.Org===n),s=s.Onext}while(s!==n.anEdge)}for(assert(n.prev===i&&null===n.anEdge),r=l,r=l;(s=r.next)!==l;r=s)assert(s.Sym.next===r.Sym),assert(s.Sym!==s),assert(s.Sym.Sym===s),assert(null!==s.Org),assert(null!==s.Dst),assert(s.Lnext.Onext.Sym===s),assert(s.Onext.Sym.Lnext===s);assert(s.Sym.next===r.Sym&&s.Sym===this.eHeadSym&&s.Sym.Sym===s&&null===s.Org&&null===s.Dst&&null===s.Lface&&null===s.Rface)},TESSmesh}(),PQnode=function(){this.handle=null},PQhandleElem=function(){this.key=null,this.node=0},P=function(){function PriorityQ(e,t){this.leq=t,this.max=0,this.nodes=[],this.handles=[],this.initialized=!1,this.freeList=0,this.size=0,this.max=e,this.nodes=[],this.handles=[];for(var n=0;n<e+1;n++)this.nodes[n]=new PQnode,this.handles[n]=new PQhandleElem;this.initialized=!1,this.nodes[1].handle=1,this.handles[1].key=null}return PriorityQ.prototype.floatDown_=function(e){var t,n,i,s=this.nodes,r=this.handles;for(t=s[e].handle;;){if((i=e<<1)<this.size&&this.leq(r[s[i+1].handle].key,r[s[i].handle].key)&&++i,assert(i<=this.max),n=s[i].handle,i>this.size||this.leq(r[t].key,r[n].key)){s[e].handle=t,r[t].node=e;break}s[e].handle=n,r[n].node=e,e=i}},PriorityQ.prototype.floatUp_=function(e){var t,n,i,s=this.nodes,r=this.handles;for(t=s[e].handle;;){if(n=s[i=e>>1].handle,0===i||this.leq(r[n].key,r[t].key)){s[e].handle=t,r[t].node=e;break}s[e].handle=n,r[n].node=e,e=i}},PriorityQ.prototype.init=function(){for(var e=this.size;e>=1;--e)this.floatDown_(e);this.initialized=!0},PriorityQ.prototype.min=function(){return this.handles[this.nodes[1].handle].key},PriorityQ.prototype.insert=function(e){var t,n;if(2*(t=++this.size)>this.max){var i,s;for(this.max*=2,s=this.nodes.length,this.nodes.length=this.max+1,i=s;i<this.nodes.length;i++)this.nodes[i]=new PQnode;for(s=this.handles.length,this.handles.length=this.max+1,i=s;i<this.handles.length;i++)this.handles[i]=new PQhandleElem}return 0===this.freeList?n=t:(n=this.freeList,this.freeList=this.handles[n].node),this.nodes[t].handle=n,this.handles[n].node=t,this.handles[n].key=e,this.initialized&&this.floatUp_(t),n},PriorityQ.prototype.extractMin=function(){var e=this.nodes,t=this.handles,n=e[1].handle,i=t[n].key;return this.size>0&&(e[1].handle=e[this.size].handle,t[e[1].handle].node=1,t[n].key=null,t[n].node=this.freeList,this.freeList=n,--this.size,this.size>0&&this.floatDown_(1)),i},PriorityQ.prototype.delete=function(e){var t,n=this.nodes,i=this.handles;assert(e>=1&&e<=this.max&&null!==i[e].key),n[t=i[e].node].handle=n[this.size].handle,i[n[t].handle].node=t,--this.size,t<=this.size&&(t<=1||this.leq(i[n[t>>1].handle].key,i[n[t].handle].key)?this.floatDown_(t):this.floatUp_(t)),i[e].key=null,i[e].node=this.freeList,this.freeList=e},PriorityQ}(),ActiveRegion=function(){this.eUp=null,this.nodeUp=null,this.windingNumber=0,this.inside=!1,this.sentinel=!1,this.dirty=!1,this.fixUpperEdge=!1},DictNode=function(){this.key=null,this.next=null,this.prev=null},F=function(){function Dict(e,t){this.frame=e,this.leq=t,this.head=new DictNode,this.head.next=this.head,this.head.prev=this.head}return Dict.prototype.min=function(){return this.head.next},Dict.prototype.max=function(){return this.head.prev},Dict.prototype.insert=function(e){return this.insertBefore(this.head,e)},Dict.prototype.search=function(e){var t=this.head;do{t=t.next}while(null!==t.key&&!this.leq(this.frame,e,t.key));return t},Dict.prototype.insertBefore=function(e,t){do{e=e.prev}while(null!==e.key&&!this.leq(this.frame,e.key,t));var n=new DictNode;return n.key=t,n.next=e.next,e.next.prev=n,n.prev=e,e.next=n,n},Dict.prototype.delete=function(e){e.next.prev=e.prev,e.prev.next=e.next},Dict}(),C=function(){function Sweep(){}return Sweep.regionBelow=function(e){return e.nodeUp.prev.key},Sweep.regionAbove=function(e){return e.nodeUp.next.key},Sweep.debugEvent=function(e){},Sweep.addWinding=function(e,t){e.winding+=t.winding,e.Sym.winding+=t.Sym.winding},Sweep.edgeLeq=function(e,t,n){var i=e.event,s=t.eUp,r=n.eUp;return s.Dst===i?r.Dst===i?L.vertLeq(s.Org,r.Org)?L.edgeSign(r.Dst,s.Org,r.Org)<=0:L.edgeSign(s.Dst,r.Org,s.Org)>=0:L.edgeSign(r.Dst,i,r.Org)<=0:r.Dst===i?L.edgeSign(s.Dst,i,s.Org)>=0:L.edgeEval(s.Dst,i,s.Org)>=L.edgeEval(r.Dst,i,r.Org)},Sweep.deleteRegion=function(e,t){t.fixUpperEdge&&assert(0===t.eUp.winding),t.eUp.activeRegion=null,e.dict.delete(t.nodeUp)},Sweep.fixUpperEdge=function(e,t,n){assert(t.fixUpperEdge),e.mesh.delete(t.eUp),t.fixUpperEdge=!1,t.eUp=n,n.activeRegion=t},Sweep.topLeftRegion=function(e,t){var n,i=t.eUp.Org;do{t=Sweep.regionAbove(t)}while(t.eUp.Org===i);if(t.fixUpperEdge){if(null===(n=e.mesh.connect(Sweep.regionBelow(t).eUp.Sym,t.eUp.Lnext)))return null;Sweep.fixUpperEdge(e,t,n),t=Sweep.regionAbove(t)}return t},Sweep.topRightRegion=function(e){var t=e.eUp.Dst;do{e=Sweep.regionAbove(e)}while(e.eUp.Dst===t);return e},Sweep.addRegionBelow=function(e,t,n){var i=new ActiveRegion;return i.eUp=n,i.nodeUp=e.dict.insertBefore(t.nodeUp,i),i.fixUpperEdge=!1,i.sentinel=!1,i.dirty=!1,n.activeRegion=i,i},Sweep.isWindingInside=function(e,t){switch(e.windingRule){case S.ODD:return!!(1&t);case S.NONZERO:return 0!==t;case S.POSITIVE:return t>0;case S.NEGATIVE:return t<0;case S.ABS_GEQ_TWO:return t>=2||t<=-2}throw new Error("Invalid winding rulle")},Sweep.computeWinding=function(e,t){t.windingNumber=Sweep.regionAbove(t).windingNumber+t.eUp.winding,t.inside=Sweep.isWindingInside(e,t.windingNumber)},Sweep.finishRegion=function(e,t){var n=t.eUp,i=n.Lface;i.inside=t.inside,i.anEdge=n,Sweep.deleteRegion(e,t)},Sweep.finishLeftRegions=function(e,t,n){for(var i,s=null,r=t,o=t.eUp;r!==n;){if(r.fixUpperEdge=!1,(i=(s=Sweep.regionBelow(r)).eUp).Org!=o.Org){if(!s.fixUpperEdge){Sweep.finishRegion(e,r);break}i=e.mesh.connect(o.Lprev,i.Sym),Sweep.fixUpperEdge(e,s,i)}o.Onext!==i&&(e.mesh.splice(i.Oprev,i),e.mesh.splice(o,i)),Sweep.finishRegion(e,r),o=s.eUp,r=s}return o},Sweep.addRightEdges=function(e,t,n,i,s,r){var o,h,l,c,d=!0;l=n;do{assert(L.vertLeq(l.Org,l.Dst)),Sweep.addRegionBelow(e,t,l.Sym),l=l.Onext}while(l!==i);for(null===s&&(s=Sweep.regionBelow(t).eUp.Rprev),h=t,c=s;(l=(o=Sweep.regionBelow(h)).eUp.Sym).Org===c.Org;)l.Onext!==c&&(e.mesh.splice(l.Oprev,l),e.mesh.splice(c.Oprev,l)),o.windingNumber=h.windingNumber-l.winding,o.inside=Sweep.isWindingInside(e,o.windingNumber),h.dirty=!0,!d&&Sweep.checkForRightSplice(e,h)&&(Sweep.addWinding(l,c),Sweep.deleteRegion(e,h),e.mesh.delete(c)),d=!1,h=o,c=l;h.dirty=!0,assert(h.windingNumber-l.winding===o.windingNumber),r&&Sweep.walkDirtyRegions(e,h)},Sweep.spliceMergeVertices=function(e,t,n){e.mesh.splice(t,n)},Sweep.vertexWeights=function(e,t,n){var i=L.vertL1dist(t,e),s=L.vertL1dist(n,e),r=.5*s/(i+s),o=.5*i/(i+s);e.coords[0]+=r*t.coords[0]+o*n.coords[0],e.coords[1]+=r*t.coords[1]+o*n.coords[1],e.coords[2]+=r*t.coords[2]+o*n.coords[2]},Sweep.getIntersectData=function(e,t,n,i,s,r){t.coords[0]=t.coords[1]=t.coords[2]=0,t.idx=-1,Sweep.vertexWeights(t,n,i),Sweep.vertexWeights(t,s,r)},Sweep.checkForRightSplice=function(e,t){var n=Sweep.regionBelow(t),i=t.eUp,s=n.eUp;if(L.vertLeq(i.Org,s.Org)){if(L.edgeSign(s.Dst,i.Org,s.Org)>0)return!1;L.vertEq(i.Org,s.Org)?i.Org!==s.Org&&(e.pq.delete(i.Org.pqHandle),Sweep.spliceMergeVertices(e,s.Oprev,i)):(e.mesh.splitEdge(s.Sym),e.mesh.splice(i,s.Oprev),t.dirty=n.dirty=!0)}else{if(L.edgeSign(i.Dst,s.Org,i.Org)<0)return!1;Sweep.regionAbove(t).dirty=t.dirty=!0,e.mesh.splitEdge(i.Sym),e.mesh.splice(s.Oprev,i)}return!0},Sweep.checkForLeftSplice=function(e,t){var n,i=Sweep.regionBelow(t),s=t.eUp,r=i.eUp;if(assert(!L.vertEq(s.Dst,r.Dst)),L.vertLeq(s.Dst,r.Dst)){if(L.edgeSign(s.Dst,r.Dst,s.Org)<0)return!1;Sweep.regionAbove(t).dirty=t.dirty=!0,n=e.mesh.splitEdge(s),e.mesh.splice(r.Sym,n),n.Lface.inside=t.inside}else{if(L.edgeSign(r.Dst,s.Dst,r.Org)>0)return!1;t.dirty=i.dirty=!0,n=e.mesh.splitEdge(r),e.mesh.splice(s.Lnext,r.Sym),n.Rface.inside=t.inside}return!0},Sweep.checkForIntersect=function(e,t){var n,i,s=Sweep.regionBelow(t),r=t.eUp,o=s.eUp,h=r.Org,l=o.Org,c=r.Dst,d=o.Dst,u=new TESSvertex;if(assert(!L.vertEq(d,c)),assert(L.edgeSign(c,e.event,h)<=0),assert(L.edgeSign(d,e.event,l)>=0),assert(h!==e.event&&l!==e.event),assert(!t.fixUpperEdge&&!s.fixUpperEdge),h===l)return!1;if(Math.min(h.t,c.t)>Math.max(l.t,d.t))return!1;if(L.vertLeq(h,l)){if(L.edgeSign(d,h,l)>0)return!1}else if(L.edgeSign(c,l,h)<0)return!1;return Sweep.debugEvent(e),L.intersect(c,h,d,l,u),assert(Math.min(h.t,c.t)<=u.t),assert(u.t<=Math.max(l.t,d.t)),assert(Math.min(d.s,c.s)<=u.s),assert(u.s<=Math.max(l.s,h.s)),L.vertLeq(u,e.event)&&(u.s=e.event.s,u.t=e.event.t),n=L.vertLeq(h,l)?h:l,L.vertLeq(n,u)&&(u.s=n.s,u.t=n.t),L.vertEq(u,h)||L.vertEq(u,l)?(Sweep.checkForRightSplice(e,t),!1):!L.vertEq(c,e.event)&&L.edgeSign(c,e.event,u)>=0||!L.vertEq(d,e.event)&&L.edgeSign(d,e.event,u)<=0?d===e.event?(e.mesh.splitEdge(r.Sym),e.mesh.splice(o.Sym,r),t=Sweep.topLeftRegion(e,t),r=Sweep.regionBelow(t).eUp,Sweep.finishLeftRegions(e,Sweep.regionBelow(t),s),Sweep.addRightEdges(e,t,r.Oprev,r,r,!0),!0):c===e.event?(e.mesh.splitEdge(o.Sym),e.mesh.splice(r.Lnext,o.Oprev),s=t,t=Sweep.topRightRegion(t),i=Sweep.regionBelow(t).eUp.Rprev,s.eUp=o.Oprev,o=Sweep.finishLeftRegions(e,s,null),Sweep.addRightEdges(e,t,o.Onext,r.Rprev,i,!0),!0):(L.edgeSign(c,e.event,u)>=0&&(Sweep.regionAbove(t).dirty=t.dirty=!0,e.mesh.splitEdge(r.Sym),r.Org.s=e.event.s,r.Org.t=e.event.t),L.edgeSign(d,e.event,u)<=0&&(t.dirty=s.dirty=!0,e.mesh.splitEdge(o.Sym),o.Org.s=e.event.s,o.Org.t=e.event.t),!1):(e.mesh.splitEdge(r.Sym),e.mesh.splitEdge(o.Sym),e.mesh.splice(o.Oprev,r),r.Org.s=u.s,r.Org.t=u.t,r.Org.pqHandle=e.pq.insert(r.Org),Sweep.getIntersectData(e,r.Org,h,c,l,d),Sweep.regionAbove(t).dirty=t.dirty=s.dirty=!0,!1)},Sweep.walkDirtyRegions=function(e,t){for(var n,i,s=Sweep.regionBelow(t);;){for(;s.dirty;)t=s,s=Sweep.regionBelow(s);if(!t.dirty&&(s=t,null===(t=Sweep.regionAbove(t))||!t.dirty))return;if(t.dirty=!1,n=t.eUp,i=s.eUp,n.Dst!==i.Dst&&Sweep.checkForLeftSplice(e,t)&&(s.fixUpperEdge?(Sweep.deleteRegion(e,s),e.mesh.delete(i),i=(s=Sweep.regionBelow(t)).eUp):t.fixUpperEdge&&(Sweep.deleteRegion(e,t),e.mesh.delete(n),n=(t=Sweep.regionAbove(s)).eUp)),n.Org!==i.Org)if(n.Dst===i.Dst||t.fixUpperEdge||s.fixUpperEdge||n.Dst!==e.event&&i.Dst!==e.event)Sweep.checkForRightSplice(e,t);else if(Sweep.checkForIntersect(e,t))return;n.Org===i.Org&&n.Dst===i.Dst&&(Sweep.addWinding(i,n),Sweep.deleteRegion(e,t),e.mesh.delete(n),t=Sweep.regionAbove(s))}},Sweep.connectRightVertex=function(e,t,n){var i,s=n.Onext,r=Sweep.regionBelow(t),o=t.eUp,h=r.eUp,l=!1;o.Dst!==h.Dst&&Sweep.checkForIntersect(e,t),L.vertEq(o.Org,e.event)&&(e.mesh.splice(s.Oprev,o),t=Sweep.topLeftRegion(e,t),s=Sweep.regionBelow(t).eUp,Sweep.finishLeftRegions(e,Sweep.regionBelow(t),r),l=!0),L.vertEq(h.Org,e.event)&&(e.mesh.splice(n,h.Oprev),n=Sweep.finishLeftRegions(e,r,null),l=!0),l?Sweep.addRightEdges(e,t,n.Onext,s,s,!0):(i=L.vertLeq(h.Org,o.Org)?h.Oprev:o,i=e.mesh.connect(n.Lprev,i),Sweep.addRightEdges(e,t,i,i.Onext,i.Onext,!1),i.Sym.activeRegion.fixUpperEdge=!0,Sweep.walkDirtyRegions(e,t))},Sweep.connectLeftDegenerate=function(e,t,n){var i,s,r,o,h;return i=t.eUp,L.vertEq(i.Org,n)?(assert(!1),void Sweep.spliceMergeVertices(e,i,n.anEdge)):L.vertEq(i.Dst,n)?(assert(!1),t=Sweep.topRightRegion(t),s=o=(r=(h=Sweep.regionBelow(t)).eUp.Sym).Onext,h.fixUpperEdge&&(assert(s!==r),Sweep.deleteRegion(e,h),e.mesh.delete(r),r=s.Oprev),e.mesh.splice(n.anEdge,r),L.edgeGoesLeft(s)||(s=null),void Sweep.addRightEdges(e,t,r.Onext,o,s,!0)):(e.mesh.splitEdge(i.Sym),t.fixUpperEdge&&(e.mesh.delete(i.Onext),t.fixUpperEdge=!1),e.mesh.splice(n.anEdge,i),void Sweep.sweepEvent(e,n))},Sweep.connectLeftVertex=function(e,t){var n,i,s,r,o,h,l=new ActiveRegion;if(l.eUp=t.anEdge.Sym,n=e.dict.search(l).key,i=Sweep.regionBelow(n))if(r=n.eUp,o=i.eUp,0!==L.edgeSign(r.Dst,t,r.Org))if(s=L.vertLeq(o.Dst,r.Dst)?n:i,n.inside||s.fixUpperEdge){if(s===n)h=e.mesh.connect(t.anEdge.Sym,r.Lnext);else h=e.mesh.connect(o.Dnext,t.anEdge).Sym;s.fixUpperEdge?Sweep.fixUpperEdge(e,s,h):Sweep.computeWinding(e,Sweep.addRegionBelow(e,n,h)),Sweep.sweepEvent(e,t)}else Sweep.addRightEdges(e,n,t.anEdge,t.anEdge,null,!0);else Sweep.connectLeftDegenerate(e,n,t)},Sweep.sweepEvent=function(e,t){e.event=t,Sweep.debugEvent(e);for(var n=t.anEdge;null===n.activeRegion;)if((n=n.Onext)===t.anEdge)return void Sweep.connectLeftVertex(e,t);var i=Sweep.topLeftRegion(e,n.activeRegion);assert(null!==i);var s=Sweep.regionBelow(i),r=s.eUp,o=Sweep.finishLeftRegions(e,s,null);o.Onext===r?Sweep.connectRightVertex(e,i,o):Sweep.addRightEdges(e,i,o.Onext,r,r,!0)},Sweep.addSentinel=function(e,t,n,i){var s=new ActiveRegion,r=e.mesh.makeEdge();r.Org.s=n,r.Org.t=i,r.Dst.s=t,r.Dst.t=i,e.event=r.Dst,s.eUp=r,s.windingNumber=0,s.inside=!1,s.fixUpperEdge=!1,s.sentinel=!0,s.dirty=!1,s.nodeUp=e.dict.insert(s)},Sweep.initEdgeDict=function(e){e.dict=new F(e,Sweep.edgeLeq);var t=e.bmax[0]-e.bmin[0],n=e.bmax[1]-e.bmin[1],i=e.bmin[0]-t,s=e.bmax[0]+t,r=e.bmin[1]-n,o=e.bmax[1]+n;Sweep.addSentinel(e,i,s,r),Sweep.addSentinel(e,i,s,o)},Sweep.doneEdgeDict=function(e){for(var t,n=0;null!==(t=e.dict.min().key);)t.sentinel||(assert(t.fixUpperEdge),assert(1===++n)),assert(0===t.windingNumber),Sweep.deleteRegion(e,t)},Sweep.removeDegenerateEdges=function(e){var t,n,i,s=e.mesh.eHead;for(t=s.next;t!==s;t=n)n=t.next,i=t.Lnext,L.vertEq(t.Org,t.Dst)&&t.Lnext.Lnext!==t&&(Sweep.spliceMergeVertices(e,i,t),e.mesh.delete(t),i=(t=i).Lnext),i.Lnext===t&&(i!==t&&(i!==n&&i!==n.Sym||(n=n.next),e.mesh.delete(i)),t!==n&&t!==n.Sym||(n=n.next),e.mesh.delete(t))},Sweep.initPriorityQ=function(e){var t,n,i,s=0;for(n=(i=e.mesh.vHead).next;n!==i;n=n.next)s++;for(s+=8,t=e.pq=new P(s,L.vertLeq),n=(i=e.mesh.vHead).next;n!==i;n=n.next)n.pqHandle=t.insert(n);return n===i&&(t.init(),!0)},Sweep.donePriorityQ=function(e){e.pq=null},Sweep.removeDegenerateFaces=function(e,t){var n,i,s;for(n=t.fHead.next;n!==t.fHead;n=i)i=n.next,assert((s=n.anEdge).Lnext!==s),s.Lnext.Lnext===s&&(Sweep.addWinding(s.Onext,s),e.mesh.delete(s));return!0},Sweep.computeInterior=function(e,t){var n,i;if(void 0===t&&(t=!0),Sweep.removeDegenerateEdges(e),!Sweep.initPriorityQ(e))return!1;for(Sweep.initEdgeDict(e);null!==(n=e.pq.extractMin());){for(;null!==(i=e.pq.min())&&L.vertEq(i,n);)i=e.pq.extractMin(),Sweep.spliceMergeVertices(e,n.anEdge,i.anEdge);Sweep.sweepEvent(e,n)}return e.event=e.dict.min().key.eUp.Org,Sweep.debugEvent(e),Sweep.doneEdgeDict(e),Sweep.donePriorityQ(e),!!Sweep.removeDegenerateFaces(e,e.mesh)&&(t&&e.mesh.check(),!0)},Sweep}(),B=function(){function Tesselator(){this.mesh=new T,this.normal=[0,0,0],this.sUnit=[0,0,0],this.tUnit=[0,0,0],this.bmin=[0,0],this.bmax=[0,0],this.windingRule=S.ODD,this.dict=null,this.pq=null,this.event=null,this.vertexIndexCounter=0,this.vertices=[],this.vertexIndices=[],this.vertexCount=0,this.elements=[],this.elementCount=0}return Tesselator.prototype.dot_=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]},Tesselator.prototype.normalize_=function(e){var t=e[0]*e[0]+e[1]*e[1]+e[2]*e[2];if(!t)throw"Zero-size vector!";t=Math.sqrt(t),e[0]/=t,e[1]/=t,e[2]/=t},Tesselator.prototype.longAxis_=function(e){var t=0;return Math.abs(e[1])>Math.abs(e[0])&&(t=1),Math.abs(e[2])>Math.abs(e[t])&&(t=2),t},Tesselator.prototype.computeNormal_=function(e){var t,n,i,s,r,o,h=[0,0,0],l=[0,0,0],c=[0,0,0],d=[0,0,0],u=[0,0,0],f=[null,null,null],p=[null,null,null],g=this.mesh.vHead;t=g.next;for(var m=0;m<3;++m)s=t.coords[m],l[m]=s,p[m]=t,h[m]=s,f[m]=t;for(t=g.next;t!==g;t=t.next)for(var y=0;y<3;++y)(s=t.coords[y])<l[y]&&(l[y]=s,p[y]=t),s>h[y]&&(h[y]=s,f[y]=t);var x=0;if(h[1]-l[1]>h[0]-l[0]&&(x=1),h[2]-l[2]>h[x]-l[x]&&(x=2),l[x]>=h[x])return e[0]=0,e[1]=0,void(e[2]=1);for(o=0,n=p[x],i=f[x],c[0]=n.coords[0]-i.coords[0],c[1]=n.coords[1]-i.coords[1],c[2]=n.coords[2]-i.coords[2],t=g.next;t!==g;t=t.next)d[0]=t.coords[0]-i.coords[0],d[1]=t.coords[1]-i.coords[1],d[2]=t.coords[2]-i.coords[2],u[0]=c[1]*d[2]-c[2]*d[1],u[1]=c[2]*d[0]-c[0]*d[2],u[2]=c[0]*d[1]-c[1]*d[0],(r=u[0]*u[0]+u[1]*u[1]+u[2]*u[2])>o&&(o=r,e[0]=u[0],e[1]=u[1],e[2]=u[2]);o<=0&&(e[0]=e[1]=e[2]=0,e[this.longAxis_(c)]=1)},Tesselator.prototype.checkOrientation_=function(){for(var e,t,n=this.mesh.fHead,i=this.mesh.vHead,s=0,r=n.next;r!==n;r=r.next)if(!((t=r.anEdge).winding<=0))do{s+=(t.Org.s-t.Dst.s)*(t.Org.t+t.Dst.t),t=t.Lnext}while(t!==r.anEdge);if(s<0){for(e=i.next;e!==i;e=e.next)e.t=-e.t;this.tUnit[0]=-this.tUnit[0],this.tUnit[1]=-this.tUnit[1],this.tUnit[2]=-this.tUnit[2]}},Tesselator.prototype.projectPolygon_=function(){var e,t,n=this.mesh.vHead,i=[0,0,0],s=!1;i[0]=this.normal[0],i[1]=this.normal[1],i[2]=this.normal[2],i[0]||i[1]||i[2]||(this.computeNormal_(i),s=!0),e=this.sUnit,t=this.tUnit;var r=this.longAxis_(i);e[r]=0,e[(r+1)%3]=1,e[(r+2)%3]=0,t[r]=0,t[(r+1)%3]=0,t[(r+2)%3]=i[r]>0?1:-1;for(var o=n.next;o!==n;o=o.next)o.s=this.dot_(o.coords,e),o.t=this.dot_(o.coords,t);s&&this.checkOrientation_();for(var h=!0,l=n.next;l!==n;l=l.next)h?(this.bmin[0]=this.bmax[0]=l.s,this.bmin[1]=this.bmax[1]=l.t,h=!1):(l.s<this.bmin[0]&&(this.bmin[0]=l.s),l.s>this.bmax[0]&&(this.bmax[0]=l.s),l.t<this.bmin[1]&&(this.bmin[1]=l.t),l.t>this.bmax[1]&&(this.bmax[1]=l.t))},Tesselator.prototype.addWinding_=function(e,t){e.winding+=t.winding,e.Sym.winding+=t.Sym.winding},Tesselator.prototype.tessellateMonoRegion_=function(e,t){var n,i;if((n=t.anEdge).Lnext===n||n.Lnext.Lnext===n)throw"Mono region invalid";for(;L.vertLeq(n.Dst,n.Org);n=n.Lprev);for(;L.vertLeq(n.Org,n.Dst);n=n.Lnext);i=n.Lprev;for(;n.Lnext!==i;)if(L.vertLeq(n.Dst,i.Org)){for(;i.Lnext!==n&&(L.edgeGoesLeft(i.Lnext)||L.edgeSign(i.Org,i.Dst,i.Lnext.Dst)<=0);)i=e.connect(i.Lnext,i).Sym;i=i.Lprev}else{for(;i.Lnext!==n&&(L.edgeGoesRight(n.Lprev)||L.edgeSign(n.Dst,n.Org,n.Lprev.Org)>=0);)n=e.connect(n,n.Lprev).Sym;n=n.Lnext}if(i.Lnext===n)throw"Mono region invalid";for(;i.Lnext.Lnext!==n;)i=e.connect(i.Lnext,i).Sym;return!0},Tesselator.prototype.tessellateInterior_=function(e){for(var t,n=e.fHead.next;n!==e.fHead;n=t)if(t=n.next,n.inside&&!this.tessellateMonoRegion_(e,n))return!1;return!0},Tesselator.prototype.discardExterior_=function(e){for(var t,n=e.fHead.next;n!==e.fHead;n=t)t=n.next,n.inside||e.zapFace(n)},Tesselator.prototype.setWindingNumber_=function(e,t,n){for(var i,s=e.eHead.next;s!==e.eHead;s=i)i=s.next,s.Rface.inside!==s.Lface.inside?s.winding=s.Lface.inside?t:-t:n?e.delete(s):s.winding=0},Tesselator.prototype.getNeighbourFace_=function(e){return e.Rface&&e.Rface.inside?e.Rface.n:-1},Tesselator.prototype.outputPolymesh_=function(e,t,n,i){var s,r,o=0,h=0;n>3&&e.mergeConvexFaces(n);for(var l=e.vHead.next;l!==e.vHead;l=l.next)l.n=-1;for(var c=e.fHead.next;c!==e.fHead;c=c.next)if(c.n=-1,c.inside){s=c.anEdge,r=0;do{-1===(l=s.Org).n&&(l.n=h,h++),r++,s=s.Lnext}while(s!==c.anEdge);if(r>n)throw"Face vertex greater that support polygon";c.n=o,++o}this.elementCount=o,t===E.CONNECTED_POLYGONS&&(o*=2),this.elements=[],this.elements.length=o*n,this.vertexCount=h,this.vertices=[],this.vertices.length=h*i,this.vertexIndices=[],this.vertexIndices.length=h;for(l=e.vHead.next;l!==e.vHead;l=l.next)if(-1!==l.n){var d=l.n*i;this.vertices[d+0]=l.coords[0],this.vertices[d+1]=l.coords[1],i>2&&(this.vertices[d+2]=l.coords[2]),this.vertexIndices[l.n]=l.idx}var u=0;for(c=e.fHead.next;c!==e.fHead;c=c.next)if(c.inside){s=c.anEdge,r=0;do{l=s.Org;this.elements[u++]=l.n,r++,s=s.Lnext}while(s!==c.anEdge);for(var f=r;f<n;++f)this.elements[u++]=-1;if(t===E.CONNECTED_POLYGONS){s=c.anEdge;do{this.elements[u++]=this.getNeighbourFace_(s),s=s.Lnext}while(s!==c.anEdge);for(var p=r;p<n;++p)this.elements[u++]=-1}}},Tesselator.prototype.outputContours_=function(e,t){var n,i,s=0,r=0;this.vertexCount=0,this.elementCount=0;for(var o=e.fHead.next;o!==e.fHead;o=o.next)if(o.inside){i=n=o.anEdge;do{this.vertexCount++,n=n.Lnext}while(n!==i);this.elementCount++}this.elements=[],this.elements.length=2*this.elementCount,this.vertices=[],this.vertices.length=this.vertexCount*t,this.vertexIndices=[],this.vertexIndices.length=this.vertexCount;var h=0,l=0,c=0;s=0;for(o=e.fHead.next;o!==e.fHead;o=o.next)if(o.inside){r=0,i=n=o.anEdge;do{this.vertices[h++]=n.Org.coords[0],this.vertices[h++]=n.Org.coords[1],t>2&&(this.vertices[h++]=n.Org.coords[2]),this.vertexIndices[l++]=n.Org.idx,r++,n=n.Lnext}while(n!==i);this.elements[c++]=s,this.elements[c++]=r,s+=r}},Tesselator.prototype.addContour=function(e,t){null===this.mesh&&(this.mesh=new T),e<2&&(e=2),e>3&&(e=3);for(var n=null,i=0;i<t.length;i+=e)null===n?(n=this.mesh.makeEdge(),this.mesh.splice(n,n.Sym)):(this.mesh.splitEdge(n),n=n.Lnext),n.Org.coords[0]=t[i+0],n.Org.coords[1]=t[i+1],n.Org.coords[2]=e>2?t[i+2]:0,n.Org.idx=this.vertexIndexCounter++,n.winding=1,n.Sym.winding=-1},Tesselator.prototype.tesselate=function(e,t,n,i,s,r){if(void 0===e&&(e=S.ODD),void 0===t&&(t=E.POLYGONS),void 0===r&&(r=!0),this.vertices=[],this.elements=[],this.vertexIndices=[],this.vertexIndexCounter=0,s&&(this.normal[0]=s[0],this.normal[1]=s[1],this.normal[2]=s[2]),this.windingRule=e,i<2&&(i=2),i>3&&(i=3),!this.mesh)return!1;this.projectPolygon_(),C.computeInterior(this,r);var o=this.mesh;return t===E.BOUNDARY_CONTOURS?this.setWindingNumber_(o,1,!0):this.tessellateInterior_(o),r&&o.check(),t===E.BOUNDARY_CONTOURS?this.outputContours_(o,i):this.outputPolymesh_(o,t,n,i),!0},Tesselator}();S.ODD,S.NONZERO,S.POSITIVE,S.NEGATIVE,S.ABS_GEQ_TWO,E.POLYGONS,E.CONNECTED_POLYGONS,E.BOUNDARY_CONTOURS;class Tessellator{process(e,t=!0,i=!1){if(0===e.length)return{triangles:{vertices:[],indices:[]},contours:[]};const s=e.filter(e=>e.points.length>=3);return 0===s.length?{triangles:{vertices:[],indices:[]},contours:[]}:(n.log(`Tessellator: removeOverlaps=${t}, processing ${s.length} paths`),this.tessellate(s,t,i))}tessellate(e,t,i){const s=i||t?e:e.map(e=>this.reverseWinding(e));let r=this.pathsToContours(s);if(t){n.log("Two-pass: boundary extraction then triangulation");const e=this.performTessellation(r,E.BOUNDARY_CONTOURS);if(!e)return n.warn("Tess2 returned empty result from boundary pass"),{triangles:{vertices:[],indices:[]},contours:[]};r=this.boundaryToContours(e),n.log(`Boundary pass created ${r.length} contours. Starting triangulation pass.`)}else n.log("Single-pass triangulation for "+(i?"CFF":"TTF"));const o=this.performTessellation(r,E.POLYGONS);if(!o){const e=t?"Tess2 returned empty result from triangulation pass":"Tess2 returned empty result from single-pass triangulation";return n.warn(e),{triangles:{vertices:[],indices:[]},contours:r}}return{triangles:{vertices:Array.from(o.vertices),indices:Array.from(o.elements)},contours:r}}pathsToContours(e){return e.map(e=>{const t=[];for(const n of e.points)t.push(n.x,n.y);return t})}performTessellation(e,t){const n=function(e){var t=e.windingRule,n=void 0===t?S.ODD:t,i=e.elementType,s=void 0===i?E.POLYGONS:i,r=e.polySize,o=void 0===r?3:r,h=e.vertexSize,l=void 0===h?2:h,c=e.normal,d=void 0===c?[0,0,1]:c,u=e.contours,f=void 0===u?[]:u,p=e.strict,g=void 0===p||p,m=e.debug,y=void 0!==m&&m;if(!f&&g)throw new Error("Contours can't be empty");if(f){for(var x=new B,_=0;_<f.length;_++)x.addContour(l||2,f[_]);return x.tesselate(n,s,o,l,d,g),{vertices:x.vertices,vertexIndices:x.vertexIndices,vertexCount:x.vertexCount,elements:x.elements,elementCount:x.elementCount,mesh:y?x.mesh:void 0}}}({contours:e,windingRule:S.NONZERO,elementType:t,polySize:3,vertexSize:2,strict:!1});return n?.vertices&&n?.elements?n:null}boundaryToContours(e){const t=[];for(let n=0;n<e.elements.length;n+=2){const i=e.elements[n],s=e.elements[n+1],r=[];for(let t=0;t<s;t++){const n=2*(i+t);r.push(e.vertices[n],e.vertices[n+1])}r.length>2&&(r[0]===r[r.length-2]&&r[1]===r[r.length-1]||r.push(r[0],r[1])),t.push(r)}return t}reverseWinding(e){return{...e,points:[...e.points].reverse()}}}class Extruder{constructor(){}extrude(e,t=0,n){const i=[],s=[],r=[];if(0===t)this.addFlatFaces(e.triangles,i,s,r);else{this.addFrontAndBackFaces(e.triangles,i,s,r,t,n);for(const n of e.contours)this.addSideWalls(n,i,s,r,t)}return{vertices:i,normals:s,indices:r}}addFlatFaces(e,t,n,i){const s=t.length/3,r=e.vertices,o=e.indices;for(let e=0;e<r.length;e+=2)t.push(r[e],r[e+1],0),n.push(0,0,1);for(let e=0;e<o.length;e++)i.push(s+o[e])}addFrontAndBackFaces(e,t,n,i,s,r){const o=t.length/3,h=e.vertices,l=e.indices;for(let e=0;e<h.length;e+=2)t.push(h[e],h[e+1],0),n.push(0,0,-1);const c=25e-6*r,d=s<=c?c:s;for(let e=0;e<h.length;e+=2)t.push(h[e],h[e+1],d),n.push(0,0,1);const u=h.length/2;for(let e=0;e<l.length;e++)i.push(o+l[e]);for(let e=l.length-1;e>=0;e--)i.push(o+l[e]+u)}addSideWalls(e,t,n,i,s){for(let r=0;r<e.length-2;r+=2){const o=e[r],h=e[r+1],l=e[r+2],c=e[r+3],d=new Vec2(l-o,c-h),u=new Vec2(d.y,-d.x).normalize(),f=t.length/3;t.push(o,h,0,l,c,0,o,h,s,l,c,s),n.push(u.x,u.y,0,u.x,u.y,0,u.x,u.y,0,u.x,u.y,0),i.push(f,f+1,f+2,f+1,f+3,f+2)}}}class BoundaryClusterer{constructor(){}cluster(e,t){return 0===e.length?[]:this.clusterSweepLine(e,t)}clusterSweepLine(e,t){const n=e.length;if(n<=1)return 0===n?[]:[[0]];const i=new Array(n),s=new Array(2*n);let r=0;for(let o=0;o<n;o++)i[o]=this.getWorldBounds(e[o],t[o]),s[r++]=[i[o].minX,0,o],s[r++]=[i[o].maxX,1,o];s.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);const o=Array.from({length:n},(e,t)=>t),h=new Array(n).fill(0);function find(e){return o[e]===e?e:o[e]=find(o[e])}function union(e,t){const n=find(e),i=find(t);n!==i&&(h[n]<h[i]?o[n]=i:h[n]>h[i]?o[i]=n:(o[i]=n,h[n]++))}const l=new Set;for(const[,e,t]of s)if(0===e){const e=i[t];for(const n of l){const s=i[n];e.minY<s.maxY+.001&&e.maxY>s.minY-.001&&union(t,n)}l.add(t)}else l.delete(t);const c=new Map;for(let e=0;e<n;e++){const t=find(e);c.has(t)||c.set(t,[]),c.get(t).push(e)}return Array.from(c.values())}getWorldBounds(e,t){return{minX:e.bounds.min.x+t.x,minY:e.bounds.min.y+t.y,maxX:e.bounds.max.x+t.x,maxY:e.bounds.max.y+t.y}}}class MinHeap{constructor(e){this.heap=[],this.itemIndex=new Map,this.compare=e}insert(e){const t=this.itemIndex.get(e);if(void 0!==t)return this.siftUp(t),void this.siftDown(t);const n=this.heap.length;this.heap.push(e),this.itemIndex.set(e,n),this.siftUp(n)}extractMin(){const e=this.heap.length;if(!e)return;if(1===e){const e=this.heap.pop();return this.itemIndex.clear(),e}const t=this.heap[0],n=this.heap.pop();return this.heap[0]=n,this.itemIndex.delete(t),this.itemIndex.set(n,0),this.siftDown(0),t}update(e){const t=this.itemIndex.get(e);void 0!==t?(this.siftUp(t),this.siftDown(t)):this.insert(e)}isEmpty(){return!this.heap.length}swap(e,t){const n=this.heap[e],i=this.heap[t];this.heap[e]=i,this.heap[t]=n,this.itemIndex.set(n,t),this.itemIndex.set(i,e)}siftUp(e){const t=this.heap[e];for(;e>0;){const n=e-1>>1,i=this.heap[n];if(this.compare(t,i)>=0)break;this.heap[e]=i,this.itemIndex.set(i,e),e=n}this.heap[e]=t,this.itemIndex.set(t,e)}siftDown(e){const t=this.heap[e],n=this.heap.length,i=n>>1;for(;e<i;){const i=1+(e<<1),s=i+1;let r=e,o=t;const h=this.heap[i];if(this.compare(h,o)<0&&(r=i,o=h),s<n){const e=this.heap[s];this.compare(e,o)<0&&(r=s,o=e)}if(r===e)break;this.heap[e]=o,this.itemIndex.set(o,e),e=r}this.heap[e]=t,this.itemIndex.set(t,e)}}const I={enabled:!0,areaThreshold:1,colinearThreshold:.0087,minSegmentLength:10};class PathOptimizer{constructor(e){this.stats={pointsRemovedByVisvalingam:0,pointsRemovedByColinear:0,originalPointCount:0},this.config=e}setConfig(e){this.config=e}optimizePath(e){if(!this.config.enabled||e.points.length<=2)return e;this.stats.originalPointCount+=e.points.length;let t=[...e.points];return t.length<5?e:(t=this.simplifyPathVW(t,this.config.areaThreshold),t.length<3?e:(t=this.removeColinearPoints(t,this.config.colinearThreshold),t.length<3?e:{...e,points:t}))}simplifyPathVW(e,t){if(e.length<=3)return e;const n=e.length,i=e.map((e,t)=>({index:t,area:1/0,prev:null,next:null}));for(let e=0;e<i.length;e++)i[e].prev=i[e-1]||null,i[e].next=i[e+1]||null;const s=new MinHeap((e,t)=>e.area-t.area);for(let t=1;t<i.length-1;t++){const n=i[t];n.area=this.calculateTriangleArea(e[n.prev.index],e[n.index],e[n.next.index]),s.insert(n)}let r=n;for(;!s.isEmpty()&&r>3;){const n=s.extractMin();if(!n||n.area>t)break;if(this.config.minSegmentLength>0&&n.prev&&n.next){const t=e[n.prev.index],i=e[n.index],s=e[n.next.index],r=t.distanceTo(i),o=i.distanceTo(s);if(r<this.config.minSegmentLength||o<this.config.minSegmentLength)continue}n.prev&&(n.prev.next=n.next),n.next&&(n.next.prev=n.prev),r--,n.prev&&n.prev.prev&&(n.prev.area=this.calculateTriangleArea(e[n.prev.prev.index],e[n.prev.index],e[n.next.index]),s.update(n.prev)),n.next&&n.next.next&&(n.next.area=this.calculateTriangleArea(e[n.prev.index],e[n.next.index],e[n.next.next.index]),s.update(n.next))}const o=[];let h=i[0];for(;h;)o.push(e[h.index]),h=h.next;const l=n-o.length;return this.stats.pointsRemovedByVisvalingam+=l,o}removeColinearPoints(e,t){if(e.length<=2)return e;const n=[e[0]];for(let i=1;i<e.length-1;i++){const s=e[i-1],r=e[i],o=e[i+1],h=new Vec2(r.x-s.x,r.y-s.y),l=new Vec2(o.x-r.x,o.y-r.y),c=Math.abs(h.angle()-l.angle());Math.min(c,2*Math.PI-c)>t||h.length()<this.config.minSegmentLength||l.length()<this.config.minSegmentLength?n.push(r):this.stats.pointsRemovedByColinear++}return n.push(e[e.length-1]),n}calculateTriangleArea(e,t,n){return Math.abs((e.x*(t.y-n.y)+t.x*(n.y-e.y)+n.x*(e.y-t.y))/2)}getStats(){return{...this.stats}}resetStats(){this.stats={pointsRemovedByVisvalingam:0,pointsRemovedByColinear:0,originalPointCount:0}}}const A={distanceTolerance:.5,angleTolerance:.2},U=1e-6;class Polygonizer{constructor(e){this.curveFidelityConfig={...A,...e}}setCurveFidelityConfig(e){this.curveFidelityConfig={...A,...e}}polygonizeQuadratic(e,t,n){const i=[];return this.recursiveQuadratic(e.x,e.y,t.x,t.y,n.x,n.y,i),this.addPoint(n.x,n.y,i),i}polygonizeCubic(e,t,n,i){const s=[];return this.recursiveCubic(e.x,e.y,t.x,t.y,n.x,n.y,i.x,i.y,s),this.addPoint(i.x,i.y,s),s}recursiveQuadratic(e,t,n,i,s,r,o,h=0){if(h>16)return;const l=(e+n)/2,c=(t+i)/2,d=(n+s)/2,u=(i+r)/2,f=(l+d)/2,p=(c+u)/2,g=s-e,m=r-t,y=Math.abs((n-s)*m-(i-r)*g),x=this.curveFidelityConfig.distanceTolerance??A.distanceTolerance,_=x*x;if(y>U){if(y*y<=_*(g*g+m*m)){const h=this.curveFidelityConfig.angleTolerance??A.angleTolerance;if(!(h>0))return void this.addPoint(n,i,o);{let l=Math.abs(Math.atan2(r-i,s-n)-Math.atan2(i-t,n-e));if(l>=Math.PI&&(l=2*Math.PI-l),l<h)return void this.addPoint(n,i,o)}}}else{const s=g*g+m*m;if(0===s){if((n-e)*(n-e)+(i-t)*(i-t)<=_)return void this.addPoint(n,i,o)}else{const r=((n-e)*g+(i-t)*m)/s;if(r>0&&r<1&&y*y<=_*s)return void this.addPoint(n,i,o)}}this.recursiveQuadratic(e,t,l,c,f,p,o,h+1),this.recursiveQuadratic(f,p,d,u,s,r,o,h+1)}recursiveCubic(e,t,n,i,s,r,o,h,l,c=0){if(c>16)return;const d=(e+n)/2,u=(t+i)/2,f=(n+s)/2,p=(i+r)/2,g=(s+o)/2,m=(r+h)/2,y=(d+f)/2,x=(u+p)/2,_=(f+g)/2,v=(p+m)/2,w=(y+_)/2,b=(x+v)/2,S=o-e,E=h-t,L=Math.abs((n-o)*E-(i-h)*S),O=Math.abs((s-o)*E-(r-h)*S),T=this.curveFidelityConfig.distanceTolerance??A.distanceTolerance,P=T*T;let F=0;switch(L>U&&(F|=1),O>U&&(F|=2),F){case 0:const c=S*S+E*E;if(0===c){if((n-e)*(n-e)+(i-t)*(i-t)<=P&&(s-e)*(s-e)+(r-t)*(r-t)<=P)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}else{const o=((n-e)*S+(i-t)*E)/c,h=((s-e)*S+(r-t)*E)/c;if(o>0&&o<1&&h>0&&h<1&&(L+O)*(L+O)<=P*c)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}break;case 1:if(O*O<=P*(S*S+E*E)){const e=this.curveFidelityConfig.angleTolerance??A.angleTolerance;if(!(e>0))return this.addPoint(n,i,l),void this.addPoint(s,r,l);{let t=Math.abs(Math.atan2(h-r,o-s)-Math.atan2(r-i,s-n));if(t>=Math.PI&&(t=2*Math.PI-t),t<e)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}}break;case 2:if(L*L<=P*(S*S+E*E)){const o=this.curveFidelityConfig.angleTolerance??A.angleTolerance;if(!(o>0))return this.addPoint(n,i,l),void this.addPoint(s,r,l);{let h=Math.abs(Math.atan2(r-i,s-n)-Math.atan2(i-t,n-e));if(h>=Math.PI&&(h=2*Math.PI-h),h<o)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}}break;case 3:if((L+O)*(L+O)<=P*(S*S+E*E)){const c=this.curveFidelityConfig.angleTolerance??A.angleTolerance;if(!(c>0))return this.addPoint(n,i,l),void this.addPoint(s,r,l);{let d=Math.abs(Math.atan2(r-i,s-n)-Math.atan2(i-t,n-e)),u=Math.abs(Math.atan2(h-r,o-s)-Math.atan2(r-i,s-n));if(d>=Math.PI&&(d=2*Math.PI-d),u>=Math.PI&&(u=2*Math.PI-u),d+u<c)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}}}this.recursiveCubic(e,t,d,u,y,x,w,b,l,c+1),this.recursiveCubic(w,b,_,v,g,m,o,h,l,c+1)}addPoint(e,t,n){const i=new Vec2(e,t);if(0===n.length)return void n.push(i);const s=n[n.length-1],r=i.x-s.x,o=i.y-s.y;r*r+o*o>1e-12&&n.push(i)}}class GlyphContourCollector{constructor(e,t){this.currentGlyphId=0,this.currentTextIndex=0,this.currentGlyphPaths=[],this.currentPath=null,this.currentPoint=null,this.currentGlyphBounds={min:new Vec2(1/0,1/0),max:new Vec2(-1/0,-1/0)},this.collectedGlyphs=[],this.glyphPositions=[],this.glyphTextIndices=[],this.currentPosition=new Vec2(0,0),this.polygonizer=new Polygonizer(e),this.pathOptimizer=new PathOptimizer({...I,...t})}setPosition(e,t){this.currentPosition.set(e,t)}updatePosition(e,t){this.currentPosition.x+=e,this.currentPosition.y+=t}beginGlyph(e,t){this.currentGlyphPaths.length>0&&this.finishGlyph(),this.currentGlyphId=e,this.currentTextIndex=t,this.currentGlyphPaths=[],this.currentGlyphBounds.min.set(1/0,1/0),this.currentGlyphBounds.max.set(-1/0,-1/0),this.glyphPositions.push(this.currentPosition.clone())}finishGlyph(){this.currentPath&&this.finishPath(),this.currentGlyphPaths.length>0&&(this.collectedGlyphs.push({glyphId:this.currentGlyphId,paths:[...this.currentGlyphPaths],bounds:{min:{x:this.currentGlyphBounds.min.x,y:this.currentGlyphBounds.min.y},max:{x:this.currentGlyphBounds.max.x,y:this.currentGlyphBounds.max.y}}}),this.glyphTextIndices.push(this.currentTextIndex)),this.currentGlyphPaths=[]}onMoveTo(e,t){this.currentPath&&this.finishPath(),this.currentPoint=new Vec2(e,t),this.updateBounds(this.currentPoint),this.currentPath={points:[this.currentPoint],glyphIndex:this.currentGlyphId}}onLineTo(e,t){if(!this.currentPath||!this.currentPoint)return;const n=new Vec2(e,t);this.updateBounds(n),this.currentPath.points.push(n),this.currentPoint=n}onQuadTo(e,t,n,i){if(!this.currentPath||!this.currentPoint)return;const s=this.currentPoint,r=new Vec2(e,t),o=new Vec2(n,i),h=o.x-s.x,l=o.y-s.y;if(Math.abs((r.x-o.x)*l-(r.y-o.y)*h)<U)return void this.onLineTo(n,i);const c=this.polygonizer.polygonizeQuadratic(s,r,o);for(const e of c)this.updateBounds(e);for(let e=0;e<c.length;e++)this.currentPath.points.push(c[e]);this.currentPoint=o}onCubicTo(e,t,n,i,s,r){if(!this.currentPath||!this.currentPoint)return;const o=this.currentPoint,h=new Vec2(e,t),l=new Vec2(n,i),c=new Vec2(s,r),d=c.x-o.x,u=c.y-o.y,f=Math.abs((h.x-c.x)*u-(h.y-c.y)*d),p=Math.abs((l.x-c.x)*u-(l.y-c.y)*d);if(f<U&&p<U)return void this.onLineTo(s,r);const g=this.polygonizer.polygonizeCubic(o,h,l,c);for(const e of g)this.updateBounds(e);for(let e=0;e<g.length;e++)this.currentPath.points.push(g[e]);this.currentPoint=c}onClosePath(){if(!this.currentPath||!this.currentPoint)return;const e=this.currentPath.points[0];this.currentPoint.equals(e)||this.currentPath.points.push(e),this.finishPath()}finishPath(){if(this.currentPath){const e=this.pathOptimizer.optimizePath(this.currentPath);this.currentGlyphPaths.push(e),this.currentPath=null,this.currentPoint=null}}updateBounds(e){this.currentGlyphBounds.min.x=Math.min(this.currentGlyphBounds.min.x,e.x),this.currentGlyphBounds.min.y=Math.min(this.currentGlyphBounds.min.y,e.y),this.currentGlyphBounds.max.x=Math.max(this.currentGlyphBounds.max.x,e.x),this.currentGlyphBounds.max.y=Math.max(this.currentGlyphBounds.max.y,e.y)}getCollectedGlyphs(){return this.currentGlyphPaths.length>0&&this.finishGlyph(),this.collectedGlyphs}getGlyphPositions(){return this.glyphPositions}getTextIndices(){return this.glyphTextIndices}reset(){this.collectedGlyphs=[],this.glyphPositions=[],this.glyphTextIndices=[],this.currentGlyphPaths=[],this.currentPath=null,this.currentPoint=null,this.currentGlyphId=0,this.currentTextIndex=0,this.currentPosition.set(0,0),this.currentGlyphBounds={min:new Vec2(1/0,1/0),max:new Vec2(-1/0,-1/0)}}setCurveFidelityConfig(e){this.polygonizer.setCurveFidelityConfig(e)}setGeometryOptimization(e){this.pathOptimizer.setConfig({...I,...e})}getOptimizationStats(){return this.pathOptimizer.getStats()}}class DrawCallbackHandler{constructor(){this.moveTo_func=null,this.lineTo_func=null,this.quadTo_func=null,this.cubicTo_func=null,this.closePath_func=null,this.drawFuncsPtr=0,this.position={x:0,y:0}}setPosition(e,t){this.position.x=e,this.position.y=t,this.collector&&this.collector.setPosition(e,t)}updatePosition(e,t){this.position.x+=e,this.position.y+=t,this.collector&&this.collector.updatePosition(e,t)}createDrawFuncs(e,t){if(!e||!e.module||!e.hb)throw new Error("Invalid font object");if(this.collector=t,this.drawFuncsPtr)return;const n=e.module;this.moveTo_func=n.addFunction((e,t,n,i,s)=>{this.collector?.onMoveTo(i,s)},"viiiffi"),this.lineTo_func=n.addFunction((e,t,n,i,s)=>{this.collector?.onLineTo(i,s)},"viiiffi"),this.quadTo_func=n.addFunction((e,t,n,i,s,r,o)=>{this.collector?.onQuadTo(i,s,r,o)},"viiiffffi"),this.cubicTo_func=n.addFunction((e,t,n,i,s,r,o,h,l)=>{this.collector?.onCubicTo(i,s,r,o,h,l)},"viiiffffffi"),this.closePath_func=n.addFunction((e,t,n)=>{this.collector?.onClosePath()},"viiii"),this.drawFuncsPtr=n.exports.hb_draw_funcs_create(),n.exports.hb_draw_funcs_set_move_to_func(this.drawFuncsPtr,this.moveTo_func,0,0),n.exports.hb_draw_funcs_set_line_to_func(this.drawFuncsPtr,this.lineTo_func,0,0),n.exports.hb_draw_funcs_set_quadratic_to_func(this.drawFuncsPtr,this.quadTo_func,0,0),n.exports.hb_draw_funcs_set_cubic_to_func(this.drawFuncsPtr,this.cubicTo_func,0,0),n.exports.hb_draw_funcs_set_close_path_func(this.drawFuncsPtr,this.closePath_func,0,0)}getDrawFuncsPtr(){if(!this.drawFuncsPtr)throw new Error("Draw functions not initialized");return this.drawFuncsPtr}destroy(e){if(!e||!e.module||!e.hb)return;const t=e.module;try{this.drawFuncsPtr&&(t.exports.hb_draw_funcs_destroy(this.drawFuncsPtr),this.drawFuncsPtr=0),null!==this.moveTo_func&&(t.removeFunction(this.moveTo_func),this.moveTo_func=null),null!==this.lineTo_func&&(t.removeFunction(this.lineTo_func),this.lineTo_func=null),null!==this.quadTo_func&&(t.removeFunction(this.quadTo_func),this.quadTo_func=null),null!==this.cubicTo_func&&(t.removeFunction(this.cubicTo_func),this.cubicTo_func=null),null!==this.closePath_func&&(t.removeFunction(this.closePath_func),this.closePath_func=null)}catch(e){n.warn("Error destroying draw callbacks:",e)}this.collector=void 0}}class GlyphGeometryBuilder{constructor(e,t){this.fontId="default",this.wordCache=new Map,this.cache=e,this.loadedFont=t,this.tessellator=new Tessellator,this.extruder=new Extruder,this.clusterer=new BoundaryClusterer,this.collector=new GlyphContourCollector,this.drawCallbacks=new DrawCallbackHandler,this.drawCallbacks.createDrawFuncs(this.loadedFont,this.collector)}getOptimizationStats(){return this.collector.getOptimizationStats()}setCurveFidelityConfig(e){this.collector.setCurveFidelityConfig(e)}setGeometryOptimization(e){this.collector.setGeometryOptimization(e)}setFontId(e){this.fontId=e}buildInstancedGeometry(e,t,n,s,r=!1){i.start("GlyphGeometryBuilder.buildInstancedGeometry",{lineCount:e.length,wordCount:e.flat().length,depth:t,removeOverlaps:n});const o=[],h=[],l=[],c=[],d={min:{x:1/0,y:1/0,z:0},max:{x:-1/0,y:-1/0,z:t}};for(let i=0;i<e.length;i++){const u=e[i];for(const e of u){const i=[];for(const t of e.glyphs)i.push(this.getContoursForGlyph(t.g));const u=e.glyphs.map(e=>new Vec3(e.x,e.y,0)),f=this.clusterer.cluster(i,u);if(!r&&f.some(e=>e.length>1)){const r=`${this.fontId}_${e.text}_${t}_${n}`;let u=this.wordCache.get(r);if(!u){const n=[];for(let t=0;t<i.length;t++){const s=i[t],r=e.glyphs[t];for(const e of s.paths)n.push({...e,points:e.points.map(e=>new Vec2(e.x+(r.x??0),e.y+(r.y??0)))})}u=this.tessellateGlyphCluster(n,t,s),this.wordCache.set(r,u)}const f=o.length/3;this.appendGeometry(o,h,l,u,e.position,f);const p=u.vertices.length/3;for(let n=0;n<e.glyphs.length;n++){const s=e.glyphs[n],r=i[n],o=new Vec3(e.position.x+(s.x??0),e.position.y+(s.y??0),e.position.z),h=this.createGlyphInfo(s,f,p,o,r,t);c.push(h),this.updatePlaneBounds(h.bounds,d)}}else for(let r=0;r<e.glyphs.length;r++){const u=e.glyphs[r],f=i[r],p=new Vec3(e.position.x+(u.x??0),e.position.y+(u.y??0),e.position.z);if(0===f.paths.length){const e=this.createGlyphInfo(u,0,0,p,f,t);c.push(e);continue}let g=this.cache.get(this.fontId,u.g,t,n);g||(g=this.tessellateGlyph(f,t,n,s),this.cache.set(this.fontId,u.g,t,n,g));const m=o.length/3;this.appendGeometry(o,h,l,g,p,m);const y=this.createGlyphInfo(u,m,g.vertices.length/3,p,f,t);c.push(y),this.updatePlaneBounds(y.bounds,d)}}}const u=new Float32Array(o),f=new Float32Array(h),p=new Uint32Array(l);return i.end("GlyphGeometryBuilder.buildInstancedGeometry"),{vertices:u,normals:f,indices:p,glyphInfos:c,planeBounds:d}}appendGeometry(e,t,n,i,s,r){for(let t=0;t<i.vertices.length;t+=3)e.push(i.vertices[t]+s.x,i.vertices[t+1]+s.y,i.vertices[t+2]+s.z);for(let e=0;e<i.normals.length;e++)t.push(i.normals[e]);for(let e=0;e<i.indices.length;e++)n.push(i.indices[e]+r)}createGlyphInfo(e,t,n,i,s,r){return{textIndex:e.absoluteTextIndex,lineIndex:e.lineIndex,vertexStart:t,vertexCount:n,bounds:{min:{x:s.bounds.min.x+i.x,y:s.bounds.min.y+i.y,z:i.z},max:{x:s.bounds.max.x+i.x,y:s.bounds.max.y+i.y,z:i.z+r}}}}getContoursForGlyph(e){this.collector.reset(),this.collector.beginGlyph(e,0),this.loadedFont.module.exports.hb_font_draw_glyph(this.loadedFont.font.ptr,e,this.drawCallbacks.getDrawFuncsPtr(),0),this.collector.finishGlyph();const t=this.collector.getCollectedGlyphs()[0];return t||{glyphId:e,paths:[],bounds:{min:{x:0,y:0},max:{x:0,y:0}}}}tessellateGlyphCluster(e,t,n){const i=this.tessellator.process(e,!0,n);return this.extrudeAndPackage(i,t)}extrudeAndPackage(e,t){const n=this.extruder.extrude(e,t,this.loadedFont.upem),i=n.vertices;let s=1/0,r=1/0,o=1/0,h=-1/0,l=-1/0,c=-1/0;for(let e=0;e<i.length;e+=3){const t=i[e],n=i[e+1],d=i[e+2];t<s&&(s=t),t>h&&(h=t),n<r&&(r=n),n>l&&(l=n),d<o&&(o=d),d>c&&(c=d)}const d=new Vec3(s,r,o),u=new Vec3(h,l,c),f=n.vertices.length/3<65536?Uint16Array:Uint32Array;return{geometry:e,vertices:new Float32Array(n.vertices),normals:new Float32Array(n.normals),indices:new f(n.indices),bounds:{min:d,max:u},useCount:1}}tessellateGlyph(e,t,n,s){i.start("GlyphGeometryBuilder.tessellateGlyph",{glyphId:e.glyphId,pathCount:e.paths.length});const r=this.tessellator.process(e.paths,n,s);return this.extrudeAndPackage(r,t)}updatePlaneBounds(e,t){const n=new Box3(new Vec3(t.min.x,t.min.y,t.min.z),new Vec3(t.max.x,t.max.y,t.max.z)),i=new Box3(new Vec3(e.min.x,e.min.y,e.min.z),new Vec3(e.max.x,e.max.y,e.max.z));n.union(i),t.min.x=n.min.x,t.min.y=n.min.y,t.min.z=n.min.z,t.max.x=n.max.x,t.max.y=n.max.y,t.max.z=n.max.z}getCacheStats(){return this.cache.getStats()}clearCache(){this.cache.clear(),this.wordCache.clear()}}class TextShaper{constructor(e,t){this.cachedSpaceWidth=new Map,this.loadedFont=e,this.geometryBuilder=t}shapeLines(e,t,n,s,r,o,h){i.start("TextShaper.shapeLines",{lineCount:e.length});const l=new Set;if(o&&"object"==typeof o&&"byText"in o&&o.byText&&h)for(const e of Object.keys(o.byText)){let t=0;for(;-1!==(t=h.indexOf(e,t));)l.add(t),l.add(t+e.length),t+=e.length}const c=[];return e.forEach((e,i)=>{const o=this.shapeLineIntoClusters(e,i,t,n,s,r,l);c.push(o)}),c}shapeLineIntoClusters(e,t,n,i,s,r,o){const h=this.loadedFont.hb.createBuffer();"rtl"===r&&h.setDirection("rtl"),h.addText(e.text),h.guessSegmentProperties(),this.loadedFont.hb.shape(this.loadedFont.font,h);const l=h.json(this.loadedFont.font);h.destroy();const c=[];let d=[],u="",f=new Vec3,p=new Vec3(e.xOffset,-t*n,0);const g=i*this.loadedFont.upem,m=this.calculateSpaceAdjustment(e,s,i);for(let n=0;n<l.length;n++){const i=l[n],s=/\s/.test(e.text[i.cl]);e.endedWithHyphen&&i.cl===e.text.length-1&&"-"===e.text[i.cl]?i.absoluteTextIndex=e.originalEnd:i.absoluteTextIndex=e.originalStart+i.cl,i.lineIndex=t;const r=o.has(i.absoluteTextIndex);(s||r)&&d.length>0&&(c.push({text:u,glyphs:d,position:f.clone()}),d=[],u="");const h=p.clone().add(new Vec3(i.dx,i.dy,0));s||(0===d.length&&f.copy(h),i.x=h.x-f.x,i.y=h.y-f.y,d.push(i),u+=e.text[i.cl]),p.x+=i.ax,p.y+=i.ay,0!==g&&n<l.length-1&&(p.x+=g),s&&(p.x+=m)}return d.length>0&&c.push({text:u,glyphs:d,position:f.clone()}),c}calculateSpaceAdjustment(e,t,n){let i=0;if(void 0!==e.adjustmentRatio&&"justify"===t&&!e.isLastLine){let t=this.cachedSpaceWidth.get(n);void 0===t&&(t=TextMeasurer.measureTextWidth(this.loadedFont," ",n),this.cachedSpaceWidth.set(n,t));const s=.5,r=h;e.adjustmentRatio>0?i=e.adjustmentRatio*t*s:e.adjustmentRatio<0&&(i=e.adjustmentRatio*t*r)}return i}clearCache(){this.geometryBuilder.clearCache()}getCacheStats(){return this.geometryBuilder.getCacheStats()}}class GlyphCache{constructor(e){this.cache=new Map,this.head=null,this.tail=null,this.stats={hits:0,misses:0,totalGlyphs:0,uniqueGlyphs:0,cacheSize:0,saved:0,memoryUsage:0},e&&(this.maxCacheSize=1024*e*1024)}getCacheKey(e,t,n,i){return`${e}_${t}_${Math.round(1e3*n)/1e3}_${i}`}has(e,t,n,i){const s=this.getCacheKey(e,t,n,i);return this.cache.has(s)}get(e,t,n,i){const s=this.getCacheKey(e,t,n,i),r=this.cache.get(s);return r?(this.stats.hits++,this.stats.saved++,r.data.useCount++,this.moveToHead(r),this.stats.totalGlyphs++,r.data):(this.stats.misses++,void this.stats.totalGlyphs++)}set(e,t,n,i,s){const r=this.getCacheKey(e,t,n,i),o=this.calculateMemoryUsage(s);this.maxCacheSize&&this.stats.memoryUsage+o>this.maxCacheSize&&this.evictLRU(o);const h={key:r,data:s,prev:null,next:null};this.cache.set(r,h),this.addToHead(h),this.stats.uniqueGlyphs=this.cache.size,this.stats.cacheSize++,this.stats.memoryUsage+=o}calculateMemoryUsage(e){let t=0;return t+=4*e.vertices.length,t+=4*e.normals.length,t+=e.indices.length*e.indices.BYTES_PER_ELEMENT,t+=24,t+=256,t}evictLRU(e){let t=0;for(;this.tail&&t<e;){const e=this.calculateMemoryUsage(this.tail.data),n=this.tail;this.removeTail(),this.cache.delete(n.key),this.stats.memoryUsage-=e,this.stats.cacheSize--,t+=e}}addToHead(e){this.head?(e.next=this.head,this.head.prev=e,this.head=e):this.head=this.tail=e}removeNode(e){e.prev?e.prev.next=e.next:this.head=e.next,e.next?e.next.prev=e.prev:this.tail=e.prev}removeTail(){this.tail&&this.removeNode(this.tail)}moveToHead(e){e!==this.head&&(this.removeNode(e),this.addToHead(e))}clear(){this.cache.clear(),this.head=null,this.tail=null,this.stats={hits:0,misses:0,totalGlyphs:0,uniqueGlyphs:0,cacheSize:0,saved:0,memoryUsage:0}}getStats(){const e=this.stats.totalGlyphs>0?this.stats.hits/this.stats.totalGlyphs*100:0;return this.stats.uniqueGlyphs=this.cache.size,{...this.stats,hitRate:e,memoryUsageMB:this.stats.memoryUsage/1048576}}}const R=new GlyphCache(250);function getDefaultExportFromCjs(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function getAugmentedNamespace(e){if(e.__esModule)return e;var t=e.default;if("function"==typeof t){var n=function a(){return this instanceof a?Reflect.construct(t,arguments,this.constructor):t.apply(this,arguments)};n.prototype=t.prototype}else n={};return Object.defineProperty(n,"__esModule",{value:!0}),Object.keys(e).forEach(function(t){var i=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(n,t,i.get?i:{enumerable:!0,get:function(){return e[t]}})}),n}var D={exports:{}};var z=getAugmentedNamespace({__proto__:null,default:{},readFileSync:()=>{throw new Error("fs not available in browser")}});!function(e){var t,n=(t="undefined"!=typeof document?document.currentScript?.src:void 0,async function(e={}){var n=e,i="object"==typeof window,s="undefined"!=typeof WorkerGlobalScope,r="object"==typeof process&&process.versions?.node&&"renderer"!=process.type,quit_=(e,t)=>{throw t};"undefined"!=typeof __filename?t=__filename:s&&(t=self.location.href);var o,h,l="";if(r){var c=z;l=__dirname+"/",h=e=>(e=isFileURI(e)?new URL(e):e,c.readFileSync(e)),o=async(e,t=!0)=>(e=isFileURI(e)?new URL(e):e,c.readFileSync(e,t?void 0:"utf8")),process.argv.length>1&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),quit_=(e,t)=>{throw process.exitCode=e,t}}else if(i||s){try{l=new URL(".",t).href}catch{}s&&(h=e=>{var t=new XMLHttpRequest;return t.open("GET",e,!1),t.responseType="arraybuffer",t.send(null),new Uint8Array(t.response)}),o=async e=>{if(isFileURI(e))return new Promise((t,n)=>{var i=new XMLHttpRequest;i.open("GET",e,!0),i.responseType="arraybuffer",i.onload=()=>{200==i.status||0==i.status&&i.response?t(i.response):n(i.status)},i.onerror=n,i.send(null)});var t=await fetch(e,{credentials:"same-origin"});if(t.ok)return t.arrayBuffer();throw new Error(t.status+" : "+t.url)}}console.log.bind(console);var d,u,f,p,g,m,y=console.error.bind(console),x=!1,isFileURI=e=>e.startsWith("file://"),_=!1;function updateMemoryViews(){var e=g.buffer;n.HEAP8=new Int8Array(e),n.HEAPU8=m=new Uint8Array(e),n.HEAP32=new Int32Array(e),n.HEAPU32=new Uint32Array(e),n.HEAPF32=new Float32Array(e),new BigInt64Array(e),new BigUint64Array(e)}var v,w=0,b=null;function abort(e){n.onAbort?.(e),y(e="Aborted("+e+")"),x=!0,e+=". Build with -sASSERTIONS for more info.";var t=new WebAssembly.RuntimeError(e);throw p?.(t),t}function findWasmBinary(){return e="hb.wasm",n.locateFile?n.locateFile(e,l):l+e;var e}async function getWasmBinary(e){if(!d)try{var t=await o(e);return new Uint8Array(t)}catch{}return function(e){if(e==v&&d)return new Uint8Array(d);if(h)return h(e);throw"both async and sync fetching of the wasm failed"}(e)}async function instantiateAsync(e,t,n){if(!e&&!isFileURI(t)&&!r)try{var i=fetch(t,{credentials:"same-origin"});return await WebAssembly.instantiateStreaming(i,n)}catch(e){y(`wasm streaming compile failed: ${e}`),y("falling back to ArrayBuffer instantiation")}return async function(e,t){try{var n=await getWasmBinary(e);return await WebAssembly.instantiate(n,t)}catch(e){y(`failed to asynchronously prepare wasm: ${e}`),abort(e)}}(t,n)}class ExitStatus{name="ExitStatus";constructor(e){this.message=`Program terminated with exit(${e})`,this.status=e}}var S,E,L,callRuntimeCallbacks=e=>{for(;e.length>0;)e.shift()(n)},O=[],addOnPostRun=e=>O.push(e),T=[],addOnPreRun=e=>T.push(e),P=!0,F=0,C={},handleException=e=>{if(e instanceof ExitStatus||"unwind"==e)return u;quit_(1,e)},keepRuntimeAlive=()=>P||F>0,_proc_exit=e=>{u=e,keepRuntimeAlive()||(n.onExit?.(e),x=!0),quit_(e,new ExitStatus(e))},_exit=(e,t)=>{u=e,_proc_exit(e)},callUserCallback=e=>{if(!x)try{e(),(()=>{if(!keepRuntimeAlive())try{_exit(u)}catch(e){handleException(e)}})()}catch(e){handleException(e)}},alignMemory=(e,t)=>Math.ceil(e/t)*t,growMemory=e=>{var t=(e-g.buffer.byteLength+65535)/65536|0;try{return g.grow(t),updateMemoryViews(),1}catch(e){}},uleb128EncodeWithLen=e=>{const t=e.length;return[t%128|128,t>>7,...e]},B={i:127,p:127,j:126,f:125,d:124,e:111},generateTypePack=e=>uleb128EncodeWithLen(Array.from(e,e=>B[e])),getWasmTableEntry=e=>S.get(e),getFunctionAddress=e=>(E||(E=new WeakMap,((e,t)=>{if(E)for(var n=e;n<e+t;n++){var i=getWasmTableEntry(n);i&&E.set(i,n)}})(0,S.length)),E.get(e)||0),I=[],setWasmTableEntry=(e,t)=>S.set(e,t);n.noExitRuntime&&(P=n.noExitRuntime),n.print&&n.print,n.printErr&&(y=n.printErr),n.wasmBinary&&(d=n.wasmBinary),n.arguments&&n.arguments,n.thisProgram&&n.thisProgram,n.wasmMemory=g,n.wasmExports=U,n.addFunction=(e,t)=>{var n=getFunctionAddress(e);if(n)return n;var i=I.length?I.pop():S.grow(1);try{setWasmTableEntry(i,e)}catch(n){if(!(n instanceof TypeError))throw n;var s=((e,t)=>{var n=Uint8Array.of(0,97,115,109,1,0,0,0,1,...uleb128EncodeWithLen([1,96,...generateTypePack(t.slice(1)),...generateTypePack("v"===t[0]?"":t[0])]),2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0),i=new WebAssembly.Module(n);return new WebAssembly.Instance(i,{e:{f:e}}).exports.f})(e,t);setWasmTableEntry(i,s)}return E.set(e,i),i},n.removeFunction=e=>{E.delete(getWasmTableEntry(e)),setWasmTableEntry(e,null),I.push(e)};var A={_abort_js:()=>abort(""),_emscripten_runtime_keepalive_clear:()=>{P=!1,F=0},_setitimer_js:(e,t)=>{if(C[e]&&(clearTimeout(C[e].id),delete C[e]),!t)return 0;var n=setTimeout(()=>{delete C[e],callUserCallback(()=>L(e,performance.now()))},t);return C[e]={id:n,timeout_ms:t},0},emscripten_resize_heap:e=>{var t=m.length,n=2147483648;if((e>>>=0)>n)return!1;for(var i=1;i<=4;i*=2){var s=t*(1+.2/i);s=Math.min(s,e+100663296);var r=Math.min(n,alignMemory(Math.max(e,s),65536));if(growMemory(r))return!0}return!1},proc_exit:_proc_exit},U=await async function(){function receiveInstance(e,t){return U=e.exports,n.wasmExports=U,g=U.memory,n.wasmMemory=g,updateMemoryViews(),S=U.__indirect_function_table,function(e){n._hb_blob_create=e.hb_blob_create,n._hb_blob_destroy=e.hb_blob_destroy,n._hb_blob_get_length=e.hb_blob_get_length,n._hb_blob_get_data=e.hb_blob_get_data,n._hb_buffer_serialize_glyphs=e.hb_buffer_serialize_glyphs,n._hb_buffer_create=e.hb_buffer_create,n._hb_buffer_destroy=e.hb_buffer_destroy,n._hb_buffer_get_content_type=e.hb_buffer_get_content_type,n._hb_buffer_set_direction=e.hb_buffer_set_direction,n._hb_buffer_set_script=e.hb_buffer_set_script,n._hb_buffer_set_language=e.hb_buffer_set_language,n._hb_buffer_set_flags=e.hb_buffer_set_flags,n._hb_buffer_set_cluster_level=e.hb_buffer_set_cluster_level,n._hb_buffer_get_length=e.hb_buffer_get_length,n._hb_buffer_get_glyph_infos=e.hb_buffer_get_glyph_infos,n._hb_buffer_get_glyph_positions=e.hb_buffer_get_glyph_positions,n._hb_glyph_info_get_glyph_flags=e.hb_glyph_info_get_glyph_flags,n._hb_buffer_guess_segment_properties=e.hb_buffer_guess_segment_properties,n._hb_buffer_add_utf8=e.hb_buffer_add_utf8,n._hb_buffer_add_utf16=e.hb_buffer_add_utf16,n._hb_buffer_set_message_func=e.hb_buffer_set_message_func,n._hb_language_from_string=e.hb_language_from_string,n._hb_script_from_string=e.hb_script_from_string,n._hb_version=e.hb_version,n._hb_version_string=e.hb_version_string,n._hb_feature_from_string=e.hb_feature_from_string,n._malloc=e.malloc,n._free=e.free,n._hb_draw_funcs_set_move_to_func=e.hb_draw_funcs_set_move_to_func,n._hb_draw_funcs_set_line_to_func=e.hb_draw_funcs_set_line_to_func,n._hb_draw_funcs_set_quadratic_to_func=e.hb_draw_funcs_set_quadratic_to_func,n._hb_draw_funcs_set_cubic_to_func=e.hb_draw_funcs_set_cubic_to_func,n._hb_draw_funcs_set_close_path_func=e.hb_draw_funcs_set_close_path_func,n._hb_draw_funcs_create=e.hb_draw_funcs_create,n._hb_draw_funcs_destroy=e.hb_draw_funcs_destroy,n._hb_face_create=e.hb_face_create,n._hb_face_destroy=e.hb_face_destroy,n._hb_face_reference_table=e.hb_face_reference_table,n._hb_face_get_upem=e.hb_face_get_upem,n._hb_face_collect_unicodes=e.hb_face_collect_unicodes,n._hb_font_draw_glyph=e.hb_font_draw_glyph,n._hb_font_glyph_to_string=e.hb_font_glyph_to_string,n._hb_font_create=e.hb_font_create,n._hb_font_set_variations=e.hb_font_set_variations,n._hb_font_destroy=e.hb_font_destroy,n._hb_font_set_scale=e.hb_font_set_scale,n._hb_set_create=e.hb_set_create,n._hb_set_destroy=e.hb_set_destroy,n._hb_ot_var_get_axis_infos=e.hb_ot_var_get_axis_infos,n._hb_set_get_population=e.hb_set_get_population,n._hb_set_next_many=e.hb_set_next_many,n._hb_shape=e.hb_shape,L=e._emscripten_timeout}(U),function(){if(w--,n.monitorRunDependencies?.(w),0==w&&b){var e=b;b=null,e()}}(),U}w++,n.monitorRunDependencies?.(w);var e={env:A,wasi_snapshot_preview1:A};if(n.instantiateWasm)return new Promise((t,i)=>{n.instantiateWasm(e,(e,n)=>{t(receiveInstance(e))})});v??=findWasmBinary();var t=function(e){return receiveInstance(e.instance)}(await instantiateAsync(d,v,e));return t}();return function(){if(n.preInit)for("function"==typeof n.preInit&&(n.preInit=[n.preInit]);n.preInit.length>0;)n.preInit.shift()()}(),function run(){function doRun(){n.calledRun=!0,x||(_=!0,U.__wasm_call_ctors(),f?.(n),n.onRuntimeInitialized?.(),function(){if(n.postRun)for("function"==typeof n.postRun&&(n.postRun=[n.postRun]);n.postRun.length;)addOnPostRun(n.postRun.shift());callRuntimeCallbacks(O)}())}w>0?b=run:(function(){if(n.preRun)for("function"==typeof n.preRun&&(n.preRun=[n.preRun]);n.preRun.length;)addOnPreRun(n.preRun.shift());callRuntimeCallbacks(T)}(),w>0?b=run:n.setStatus?(n.setStatus("Running..."),setTimeout(()=>{setTimeout(()=>n.setStatus(""),1),doRun()},1)):doRun())}(),_?n:new Promise((e,t)=>{f=e,p=t})});e.exports=n,e.exports.default=n}(D);var G=getDefaultExportFromCjs(D.exports),k={exports:{}};try{k.exports=function(e){var t=e.wasmExports,n=new TextDecoder("utf8");let i=e.addFunction,s=e.removeFunction;var r=i(function(e){t.free(e)},"vi");function hb_tag(e){return(255&e.charCodeAt(0))<<24|(255&e.charCodeAt(1))<<16|(255&e.charCodeAt(2))<<8|255&e.charCodeAt(3)}var o=hb_tag("JSON"),h="",l=t.malloc(256);function createAsciiString(n){var i=t.malloc(n.length+1);for(let t=0;t<n.length;++t){const s=n.charCodeAt(t);if(s>127)throw new Error("Expected ASCII text");e.HEAPU8[i+t]=s}return e.HEAPU8[i+n.length]=0,{ptr:i,length:n.length,free:function(){t.free(i)}}}function shape(e,n,i){var s=0,r=0;i&&(i=i.split(","),s=t.malloc(16*i.length),i.forEach(function(e,n){var i=createAsciiString(e);t.hb_feature_from_string(i.ptr,-1,s+16*r)&&r++,i.free()})),t.hb_shape(e.ptr,n.ptr,s,r),s&&t.free(s)}return{createBlob:function(n){var i=t.malloc(n.byteLength);e.HEAPU8.set(new Uint8Array(n),i);var s=t.hb_blob_create(i,n.byteLength,2,i,r);return{ptr:s,destroy:function(){t.hb_blob_destroy(s)}}},createFace:function(n,i){var s=t.hb_face_create(n.ptr,i);const r=t.hb_face_get_upem(s);return{ptr:s,upem:r,reference_table:function(n){var i=t.hb_face_reference_table(s,hb_tag(n)),r=t.hb_blob_get_length(i);if(r){var o=t.hb_blob_get_data(i,null);return e.HEAPU8.subarray(o,o+r)}},getAxisInfos:function(){var n=t.malloc(2048),i=t.malloc(4);e.HEAPU32[i/4]=64,t.hb_ot_var_get_axis_infos(s,0,i,n);var r={};return Array.from({length:e.HEAPU32[i/4]}).forEach(function(t,i){var s;r[(s=e.HEAPU32[n/4+8*i+1],[String.fromCharCode(s>>24&255),String.fromCharCode(s>>16&255),String.fromCharCode(s>>8&255),String.fromCharCode(255&s)].join(""))]={min:e.HEAPF32[n/4+8*i+4],default:e.HEAPF32[n/4+8*i+5],max:e.HEAPF32[n/4+8*i+6]}}),t.free(i),t.free(n),r},collectUnicodes:function(){var n=t.hb_set_create();t.hb_face_collect_unicodes(s,n);var i=function(n){const i=t.hb_set_get_population(n),s=t.malloc(i<<2),r=s>>2,o=e.HEAPU32.subarray(r,r+i);return e.HEAPU32.set(o,r),t.hb_set_next_many(n,-1,s,i),o}(n);return t.hb_set_destroy(n),i},destroy:function(){t.hb_face_destroy(s)}}},createFont:function(r){var o=t.hb_font_create(r.ptr),c=null,d=null,u=null,f=null,p=null,g=null;function glyphToPath(e){return c||(d=i(function(e,t,n,i,s,r){h+=`M${i},${s}`},"viiiffi"),u=i(function(e,t,n,i,s,r){h+=`L${i},${s}`},"viiiffi"),f=i(function(e,t,n,i,s,r,o,l,c,d){h+=`C${i},${s} ${r},${o} ${l},${c}`},"viiiffffffi"),p=i(function(e,t,n,i,s,r,o,l){h+=`Q${i},${s} ${r},${o}`},"viiiffffi"),g=i(function(e,t,n,i){h+="Z"},"viiii"),c=t.hb_draw_funcs_create(),t.hb_draw_funcs_set_move_to_func(c,d,0,0),t.hb_draw_funcs_set_line_to_func(c,u,0,0),t.hb_draw_funcs_set_cubic_to_func(c,f,0,0),t.hb_draw_funcs_set_quadratic_to_func(c,p,0,0),t.hb_draw_funcs_set_close_path_func(c,g,0,0)),h="",t.hb_font_draw_glyph(o,e,c,0),h}return{ptr:o,glyphName:function(i){t.hb_font_glyph_to_string(o,i,l,256);var s=e.HEAPU8.subarray(l,l+256);return n.decode(s.slice(0,s.indexOf(0)))},glyphToPath:glyphToPath,glyphToJson:function(e){return glyphToPath(e).replace(/([MLQCZ])/g,"|$1 ").split("|").filter(function(e){return e.length}).map(function(e){var t=e.split(/[ ,]/g);return{type:t[0],values:t.slice(1).filter(function(e){return e.length}).map(function(e){return+e})}})},setScale:function(e,n){t.hb_font_set_scale(o,e,n)},setVariations:function(n){var i=Object.entries(n),s=t.malloc(8*i.length);i.forEach(function(t,n){e.HEAPU32[s/4+2*n+0]=hb_tag(t[0]),e.HEAPF32[s/4+2*n+1]=t[1]}),t.hb_font_set_variations(o,s,i.length),t.free(s)},destroy:function(){t.hb_font_destroy(o),c&&(t.hb_draw_funcs_destroy(c),c=null,s(d),s(u),s(f),s(p),s(g))}}},createBuffer:function(){var n=t.hb_buffer_create();return{ptr:n,addText:function(i){const s=function(n){const i=t.malloc(2*n.length),s=new Uint16Array(e.wasmMemory.buffer,i,n.length);for(let e=0;e<s.length;++e)s[e]=n.charCodeAt(e);return{ptr:i,length:s.length,free:function(){t.free(i)}}}(i);t.hb_buffer_add_utf16(n,s.ptr,s.length,0,s.length),s.free()},guessSegmentProperties:function(){return t.hb_buffer_guess_segment_properties(n)},setDirection:function(e){t.hb_buffer_set_direction(n,{ltr:4,rtl:5,ttb:6,btt:7}[e]||0)},setFlags:function(e){var i=0;e.forEach(function(e){i|=function(e){return"BOT"==e?1:"EOT"==e?2:"PRESERVE_DEFAULT_IGNORABLES"==e?4:"REMOVE_DEFAULT_IGNORABLES"==e?8:"DO_NOT_INSERT_DOTTED_CIRCLE"==e?16:"PRODUCE_UNSAFE_TO_CONCAT"==e?64:0}(e)}),t.hb_buffer_set_flags(n,i)},setLanguage:function(e){var i=createAsciiString(e);t.hb_buffer_set_language(n,t.hb_language_from_string(i.ptr,-1)),i.free()},setScript:function(e){var i=createAsciiString(e);t.hb_buffer_set_script(n,t.hb_script_from_string(i.ptr,-1)),i.free()},setClusterLevel:function(e){t.hb_buffer_set_cluster_level(n,e)},json:function(){for(var i=t.hb_buffer_get_length(n),s=[],r=t.hb_buffer_get_glyph_infos(n,0),o=r/4,h=t.hb_buffer_get_glyph_positions(n,0)/4,l=e.HEAPU32.subarray(o,o+5*i),c=e.HEAP32.subarray(h,h+5*i),d=0;d<i;++d)s.push({g:l[5*d+0],cl:l[5*d+2],ax:c[5*d+0],ay:c[5*d+1],dx:c[5*d+2],dy:c[5*d+3],flags:t.hb_glyph_info_get_glyph_flags(r+20*d)});return s},destroy:function(){t.hb_buffer_destroy(n)}}},shape:shape,shapeWithTrace:function(r,h,l,c,d){var u=[],f=0,p=!1,g=1048576,m=t.malloc(g),y=i(function(i,s,r,h){var l=n.decode(e.HEAPU8.subarray(r,e.HEAPU8.indexOf(0,r)));return l.startsWith("start table GSUB")?f=1:l.startsWith("start table GPOS")&&(f=2),f!=d&&(p=!1),0!=d&&f==d&&l.startsWith("end lookup "+c)&&(p=!0),p?0:(t.hb_buffer_serialize_glyphs(i,0,t.hb_buffer_get_length(i),m,g,0,s,o,4),u.push({m:l,t:JSON.parse(n.decode(e.HEAPU8.subarray(m,e.HEAPU8.indexOf(0,m)))),glyphs:2==t.hb_buffer_get_content_type(i)}),1)},"iiiii");return t.hb_buffer_set_message_func(h.ptr,y,0,0),shape(r,h,l),t.free(m),s(y),u},version:function(){var n=t.malloc(12);t.hb_version(n,n+4,n+8);var i={major:e.HEAPU32[n/4],minor:e.HEAPU32[(n+4)/4],micro:e.HEAPU32[(n+8)/4]};return t.free(n),i},version_string:function(){var i=t.hb_version_string();return n.decode(e.HEAPU8.subarray(i,e.HEAPU8.indexOf(0,i)))}}}}catch(e){}var M=getDefaultExportFromCjs(k.exports);let N=null,H=null,V=null;const W={setWasmPath(e){H=e,V=null,N=null},setWasmBuffer(e){V=e,H=null,N=null},getHarfBuzz:async()=>N||(N=new Promise(async(e,t)=>{try{const t={};if(V)t.wasmBinary=V;else{if(!H)throw new Error("HarfBuzz WASM path or buffer must be set before initialization.");t.locateFile=(e,t)=>e.endsWith(".wasm")?H:t+e}const n=await G(t),i=M(n);e({hb:i,module:{addFunction:n.addFunction,exports:n.wasmExports,removeFunction:n.removeFunction}})}catch(e){t(new Error(`Failed to initialize HarfBuzz: ${e}`))}}),N)};class TextRangeQuery{constructor(e,t){this.text=e,this.glyphsByTextIndex=new Map,t.forEach(e=>{const t=this.glyphsByTextIndex.get(e.textIndex)||[];t.push(e),this.glyphsByTextIndex.set(e.textIndex,t)})}execute(e){const t=[];return e.byText&&t.push(...this.findByText(e.byText)),e.byCharRange&&t.push(...this.findByCharRange(e.byCharRange)),t}findByText(e){const t=[];for(const n of e){let e=0;for(;-1!==(e=this.text.indexOf(n,e));)t.push(this.createTextRange(e,e+n.length,n)),e+=n.length}return t}findByCharRange(e){return e.map(e=>{const t=this.text.slice(e.start,e.end);return this.createTextRange(e.start,e.end,t)})}createTextRange(e,t,n){const i=[],s=new Map;for(let n=e;n<t;n++){const e=this.glyphsByTextIndex.get(n);if(e)for(const t of e){i.push(t);const e=s.get(t.lineIndex)||[];e.push(t),s.set(t.lineIndex,e)}}return{start:e,end:t,originalText:n,bounds:Array.from(s.values()).map(e=>this.calculateBounds(e)),glyphs:i,lineIndices:Array.from(s.keys()).sort((e,t)=>e-t)}}calculateBounds(e){if(0===e.length)return{min:{x:0,y:0,z:0},max:{x:0,y:0,z:0}};const t=new Box3;for(const n of e){const e=new Box3(new Vec3(n.bounds.min.x,n.bounds.min.y,n.bounds.min.z),new Vec3(n.bounds.max.x,n.bounds.max.y,n.bounds.max.z));t.union(e)}return{min:{x:t.min.x,y:t.min.y,z:t.min.z},max:{x:t.max.x,y:t.max.y,z:t.max.z}}}}class Text{static{this.patternCache=new Map}static{this.hbInitPromise=null}static{this.fontCache=new Map}static{this.fontIdCounter=0}constructor(e){this.currentFontId="",Text.hbInitPromise||(Text.hbInitPromise=W.getHarfBuzz()),this.fontLoader=new FontLoader(()=>Text.hbInitPromise)}static setHarfBuzzPath(e){W.setWasmPath(e),Text.hbInitPromise=null}static setHarfBuzzBuffer(e){W.setWasmBuffer(e),Text.hbInitPromise=null}static init(){return Text.hbInitPromise||(Text.hbInitPromise=W.getHarfBuzz()),Text.hbInitPromise}static async create(e){if(!e.font)throw new Error("Font is required. Specify options.font as a URL string or ArrayBuffer.");Text.hbInitPromise||(Text.hbInitPromise=W.getHarfBuzz());const t="string"==typeof e.font?e.font:`buffer-${Text.generateFontContentHash(e.font)}`,n=e.fontVariations?`${t}_${JSON.stringify(e.fontVariations)}`:t;let i=Text.fontCache.get(n);i||(i=await Text.loadAndCacheFont(n,e.font,e.fontVariations));const s=new Text({maxCacheSizeMB:e.maxCacheSizeMB});s.setLoadedFont(i);const{font:r,maxCacheSizeMB:o,...h}=e;return{...await s.createGeometry(h),getLoadedFont:()=>s.getLoadedFont(),getCacheStatistics:()=>s.getCacheStatistics(),clearCache:()=>s.clearCache(),measureTextWidth:(e,t)=>s.measureTextWidth(e,t)}}static async loadAndCacheFont(e,t,n){const i=new Text;await i.loadFont(t,n);const s=i.getLoadedFont();return Text.fontCache.set(e,s),s}static generateFontContentHash(e){if(e){const t=new Uint8Array(e);return`${t[0]}_${t[Math.floor(t.length/2)]}_${t[t.length-1]}_${t.length}`}return""+ ++Text.fontIdCounter}setLoadedFont(e){this.loadedFont=e;const t=Text.generateFontContentHash(e._buffer);this.currentFontId=`font_${t}`,e.fontVariations&&(this.currentFontId+=`_${JSON.stringify(e.fontVariations)}`)}async loadFont(e,t){i.start("Text.loadFont",{fontSrc:"string"==typeof e?e:`buffer(${e.byteLength})`}),Text.hbInitPromise||(Text.hbInitPromise=W.getHarfBuzz()),await Text.hbInitPromise;const s="string"==typeof e?await fetch(e).then(t=>{if(!t.ok)throw new Error(`Failed to load font from ${e}: HTTP ${t.status} ${t.statusText}`);return t.arrayBuffer()}):e;try{this.loadedFont&&this.destroy(),this.loadedFont=await this.fontLoader.loadFont(s,t);const e=Text.generateFontContentHash(s);this.currentFontId=`font_${e}`,t&&(this.currentFontId+=`_${JSON.stringify(t)}`)}catch(e){throw n.error("Failed to load font:",e),e}finally{i.end("Text.loadFont")}}async createGeometry(e){i.start("Text.createGeometry",{textLength:e.text.length,size:e.size||72,hasLayout:!!e.layout,mode:"cached"});try{if(!this.loadedFont)throw new Error("Font not loaded. Use Text.create() with a font option.");const t=await this.prepareHyphenation(e);if(this.validateOptions(t),e=t,this.updateFontVariations(e),!this.geometryBuilder){const t=e.maxCacheSizeMB?new GlyphCache(e.maxCacheSizeMB):R;this.geometryBuilder=new GlyphGeometryBuilder(t,this.loadedFont),this.geometryBuilder.setFontId(this.currentFontId)}this.geometryBuilder.setCurveFidelityConfig(e.curveFidelity),this.geometryBuilder.setGeometryOptimization(e.geometryOptimization),this.loadedFont.font.setScale(this.loadedFont.upem,this.loadedFont.upem),this.textShaper||(this.textShaper=new TextShaper(this.loadedFont,this.geometryBuilder));const n=this.prepareLayout(e),i=e.removeOverlaps??this.loadedFont.isVariable??!1,s=this.textShaper.shapeLines(n.lines,n.scaledLineHeight,n.letterSpacing,n.align,n.direction,e.color,e.text),r=this.geometryBuilder.buildInstancedGeometry(s,n.depth,i,this.loadedFont.metrics.isCFF,e.separateGlyphsWithAttributes||!1),o=this.geometryBuilder.getCacheStats(),h=this.finalizeGeometry(r.vertices,r.normals,r.indices,r.glyphInfos,r.planeBounds,e,o,e.text);if(e.separateGlyphsWithAttributes){const e=this.createGlyphAttributes(h.vertices.length/3,h.glyphs);h.glyphAttributes=e}return h}finally{i.end("Text.createGeometry")}}async prepareHyphenation(e){if(!1!==e.layout?.hyphenate&&e.layout?.width){const t=e.layout?.language||"en-us";if(!e.layout?.hyphenationPatterns?.[t])try{if(!Text.patternCache.has(t)){const n=await loadPattern(t,e.layout?.patternsPath);Text.patternCache.set(t,n)}return{...e,layout:{...e.layout,hyphenationPatterns:{...e.layout?.hyphenationPatterns,[t]:Text.patternCache.get(t)}}}}catch(i){return n.warn(`Failed to load patterns for ${t}: ${i}`),{...e,layout:{...e.layout,hyphenate:!1}}}}return e}validateOptions(e){if(!e.text)throw new Error("Text content is required");const t=e.maxTextLength??1e5;if(e.text.length>t)throw new Error(`Text exceeds ${t} character limit`)}updateFontVariations(e){e.fontVariations&&this.loadedFont&&JSON.stringify(e.fontVariations)!==JSON.stringify(this.loadedFont.fontVariations)&&(this.loadedFont.font.setVariations(e.fontVariations),this.loadedFont.fontVariations=e.fontVariations)}prepareLayout(e){if(!this.loadedFont)throw new Error("Font not loaded. Use Text.create() with a font option");const{text:t,size:n=72,depth:i=0,lineHeight:h=1,letterSpacing:l=0,layout:c={}}=e,{width:d,direction:u="ltr",align:f=("rtl"===u?"right":"left"),respectExistingBreaks:p=!0,hyphenate:g=!0,language:m="en-us",tolerance:y=s,pretolerance:x=r,emergencyStretch:_=o,autoEmergencyStretch:v,hyphenationPatterns:w,lefthyphenmin:b,righthyphenmin:S,linepenalty:E,adjdemerits:L,hyphenpenalty:O,exhyphenpenalty:T,doublehyphendemerits:P,looseness:F,disableSingleWordDetection:C}=c;let B;void 0!==d&&(B=d*(this.loadedFont.upem/n));const I=i*(this.loadedFont.upem/n);this.textLayout||(this.textLayout=new TextLayout(this.loadedFont));const A=this.textLayout.computeLines({text:t,width:B,align:f,direction:u,hyphenate:g,language:m,respectExistingBreaks:p,tolerance:y,pretolerance:x,emergencyStretch:_,autoEmergencyStretch:v,hyphenationPatterns:w,lefthyphenmin:b,righthyphenmin:S,linepenalty:E,adjdemerits:L,hyphenpenalty:O,exhyphenpenalty:T,doublehyphendemerits:P,looseness:F,disableSingleWordDetection:C,letterSpacing:l}),U=FontMetadataExtractor.getVerticalMetrics(this.loadedFont.metrics),R=(U.ascender-U.descender)*h;return{lines:A.lines,scaledLineHeight:R,letterSpacing:l,align:f,direction:u,depth:I,size:n}}applyColorSystem(e,t,n,i){const s=e.length/3,r=new Float32Array(3*s),o=[];if(Array.isArray(n)){for(let e=0;e<s;e++){const t=3*e;r[t]=n[0],r[t+1]=n[1],r[t+2]=n[2]}o.push({start:0,end:i.length,originalText:i,color:n,bounds:[],glyphs:t,lineIndices:[...new Set(t.map(e=>e.lineIndex))]})}else{const e=n.default||[1,1,1];for(let t=0;t<r.length;t+=3)r[t]=e[0],r[t+1]=e[1],r[t+2]=e[2];if(n.byText){new TextRangeQuery(i,t).execute({byText:Object.keys(n.byText)}).forEach(e=>{const t=n.byText[e.originalText];t&&(e.glyphs.forEach(e=>{for(let n=0;n<e.vertexCount;n++){const i=3*(e.vertexStart+n);i>=0&&i<r.length&&(r[i]=t[0],r[i+1]=t[1],r[i+2]=t[2])}}),o.push({start:e.start,end:e.end,originalText:e.originalText,color:t,bounds:e.bounds,glyphs:e.glyphs,lineIndices:e.lineIndices}))})}n.byCharRange&&n.byCharRange.forEach(e=>{const n=[];for(const i of t)if(i.textIndex>=e.start&&i.textIndex<e.end){n.push(i);for(let t=0;t<i.vertexCount;t++){const n=3*(i.vertexStart+t);n>=0&&n<r.length&&(r[n]=e.color[0],r[n+1]=e.color[1],r[n+2]=e.color[2])}}o.push({start:e.start,end:e.end,originalText:i.slice(e.start,e.end),color:e.color,bounds:[],glyphs:n,lineIndices:[...new Set(n.map(e=>e.lineIndex))]})})}return{colors:r,coloredRanges:o}}finalizeGeometry(e,t,n,i,s,r,o,h){const{layout:l={},size:c=72}=r,{width:d,align:u=("rtl"===l.direction?"right":"left")}=l;this.textLayout||(this.textLayout=new TextLayout(this.loadedFont));const f=this.textLayout.applyAlignment(e,{width:d,align:u,planeBounds:s}),p=f.offset;s.min.x=f.adjustedBounds.min.x,s.max.x=f.adjustedBounds.max.x;const g=c/this.loadedFont.upem;for(let t=0;t<e.length;t++)e[t]*=g;for(let e=0;e<t.length;e++)t[e]*=g;s.min.x*=g,s.min.y*=g,s.min.z*=g,s.max.x*=g,s.max.y*=g,s.max.z*=g;for(let e=0;e<i.length;e++){const t=i[e];0!==p&&(t.bounds.min.x+=p,t.bounds.max.x+=p),t.bounds.min.x*=g,t.bounds.min.y*=g,t.bounds.min.z*=g,t.bounds.max.x*=g,t.bounds.max.y*=g,t.bounds.max.z*=g}let m,y;if(r.color){const t=this.applyColorSystem(e,i,r.color,r.text);m=t.colors,y=t.coloredRanges}const x=this.geometryBuilder.getOptimizationStats(),_=n.length/3,v=e.length/3;return{vertices:e,normals:t,indices:n,colors:m,glyphs:i,planeBounds:s,stats:{trianglesGenerated:_,verticesGenerated:v,pointsRemovedByVisvalingam:x.pointsRemovedByVisvalingam,pointsRemovedByColinear:x.pointsRemovedByColinear,originalPointCount:x.originalPointCount,...o||{}},query:e=>{if(!h)throw new Error("Original text not available for querying");return new TextRangeQuery(h,i).execute(e)},coloredRanges:y,glyphAttributes:void 0}}getFontMetrics(){if(!this.loadedFont)throw new Error("Font not loaded. Call loadFont() first");return FontMetadataExtractor.getFontMetrics(this.loadedFont.metrics)}static async preloadPatterns(e,t){await Promise.all(e.map(async e=>{if(!Text.patternCache.has(e))try{const n=await loadPattern(e,t);Text.patternCache.set(e,n)}catch(t){n.warn(`Failed to pre-load patterns for ${e}: ${t}`)}}))}static registerPattern(e,t){Text.patternCache.set(e,t)}getLoadedFont(){return this.loadedFont}measureTextWidth(e,t=0){if(!this.loadedFont)throw new Error("Font not loaded. Call loadFont() first");return TextMeasurer.measureTextWidth(this.loadedFont,e,t)}getCacheStatistics(){return this.geometryBuilder?this.geometryBuilder.getCacheStats():null}clearCache(){this.geometryBuilder&&this.geometryBuilder.clearCache()}createGlyphAttributes(e,t){const n=new Float32Array(3*e),i=new Float32Array(e),s=new Float32Array(e);return t.forEach((t,r)=>{const o=(t.bounds.min.x+t.bounds.max.x)/2,h=(t.bounds.min.y+t.bounds.max.y)/2,l=(t.bounds.min.z+t.bounds.max.z)/2;for(let c=0;c<t.vertexCount;c++){const d=t.vertexStart+c;d<e&&(n[3*d]=o,n[3*d+1]=h,n[3*d+2]=l,i[d]=r,s[d]=t.lineIndex)}}),{glyphCenter:n,glyphIndex:i,glyphLineIndex:s}}destroy(){if(!this.loadedFont)return;const e=this.loadedFont;try{FontLoader.destroyFont(e)}catch(e){n.warn("Error destroying HarfBuzz objects:",e)}finally{this.loadedFont=void 0,this.textLayout=void 0,this.textShaper=void 0}}}e.DEFAULT_CURVE_FIDELITY=A,e.FontMetadataExtractor=FontMetadataExtractor,e.Text=Text,e.globalGlyphCache=R});
14
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ThreeText={})}(this,function(e){const t=!("undefined"==typeof window||!window.THREE_TEXT_LOG)||"undefined"!=typeof globalThis&&"true"===globalThis.process?.env?.THREE_TEXT_LOG;const n=new class{warn(e,...t){console.warn(e,...t)}error(e,...t){console.error(e,...t)}log(e,...n){t&&console.log(e,...n)}};const i=new class{constructor(){this.metrics=[],this.activeTimers=new Map}start(e,n){if(!t)return;const i=performance.now();this.activeTimers.set(e,i),this.metrics.push({name:e,startTime:i,metadata:n})}end(e){if(!t)return null;const i=performance.now(),s=this.activeTimers.get(e);if(void 0===s)return n.warn(`Performance timer "${e}" was not started`),null;const r=i-s;this.activeTimers.delete(e);for(let t=this.metrics.length-1;t>=0;t--){const n=this.metrics[t];if(n.name===e&&!n.endTime){n.endTime=i,n.duration=r;break}}return console.log(`${e}: ${r.toFixed(2)}ms`),r}getSummary(){if(!t)return{};const e={};for(const t of this.metrics){if(!t.duration)continue;const n=e[t.name];n?(n.count++,n.totalDuration+=t.duration,n.avgDuration=n.totalDuration/n.count,n.lastDuration=t.duration):e[t.name]={count:1,avgDuration:t.duration,totalDuration:t.duration,lastDuration:t.duration}}return e}printSummary(){if(!t)return;const e=this.getSummary();console.table(e),console.log("Operations:",Object.keys(e).sort().join(", "))}printBaseline(){if(!t)return;const e=this.getSummary();Object.entries(e).forEach(([e,t])=>{console.log(`BASELINE ${e}: ${t.avgDuration.toFixed(2)}ms avg (${t.count} calls)`)})}clear(){t&&(this.metrics.length=0,this.activeTimers.clear())}time(e,n,i){if(!t)return n();this.start(e,i);try{return n()}finally{this.end(e)}}async timeAsync(e,n,i){if(!t)return n();this.start(e,i);try{return await n()}finally{this.end(e)}}},s=200,r=100,o=0,h=1/3;var l,c;!function(e){e[e.BOX=0]="BOX",e[e.GLUE=1]="GLUE",e[e.PENALTY=2]="PENALTY",e[e.DISCRETIONARY=3]="DISCRETIONARY"}(l||(l={})),function(e){e[e.TIGHT=0]="TIGHT",e[e.NORMAL=1]="NORMAL",e[e.LOOSE=2]="LOOSE",e[e.VERY_LOOSE=3]="VERY_LOOSE"}(c||(c={}));class ActiveNodeList{constructor(){this.nodesByKey=new Map,this.activeList=[],this.allNodes=new Set}getKey(e,t){return e<<2|t}insert(e){const t=this.getKey(e.position,e.fitness),n=this.nodesByKey.get(t);n&&e.totalDemerits<n.totalDemerits?(n.totalDemerits=e.totalDemerits,n.previous=e.previous,n.totalWidth=e.totalWidth):n||(this.nodesByKey.set(t,e),this.allNodes.add(e),e.activeListIndex=this.activeList.length,this.activeList.push(e))}findExisting(e,t){return this.nodesByKey.get(this.getKey(e,t))}getAllActive(){return this.activeList}deactivateNode(e){if(e.active&&void 0!==e.activeListIndex){e.active=!1;const t=e.activeListIndex,n=this.activeList.length-1;if(t!==n){const e=this.activeList[n];this.activeList[t]=e,e.activeListIndex=t}this.activeList.pop(),e.activeListIndex=void 0}}size(){return this.allNodes.size}}const d=50,u=50,f=1e4,p=10,g=1e4,m=-1/0,y=2,x=4,_=1e4;class LineBreak{static badness(e,t){if(0===e)return 0;if(t<=0)return _;let n;return n=e<=7230584?Math.floor(297*e/t):t>=1663497?Math.floor(e/Math.floor(t/297)):e,n>1290?_:Math.floor((n*n*n+131072)/262144)}static findHyphenationPoints(e,t="en-us",n,i=y,s=x){let r;if(!n||!n[t])return[];if(r=n[t],!r)return[];const o=`.${e.toLowerCase()}.`,h=new Array(o.length).fill(0);for(let e=0;e<o.length;e++){let t=r;for(let n=e;n<o.length;n++){const i=o[n];if(!t.children||!t.children[i])break;if(t=t.children[i],t.patterns)for(let n=0;n<t.patterns.length;n++){const i=e+n;i<h.length&&(h[i]=Math.max(h[i],t.patterns[n]))}}}const l=[];for(let e=2;e<o.length-2;e++)h[e]%2==1&&l.push(e-1);return l.filter(t=>t>=i&&e.length-t>=s)}static itemizeText(e,t,n=!1,i="en-us",s,r=y,o=x,h){const c=[];return c.push(...this.itemizeParagraph(e,t,n,i,s,r,o,h)),c.push({type:l.GLUE,width:0,stretch:1/0,shrink:0,text:"",originIndex:e.length}),c.push({type:l.PENALTY,width:0,penalty:-1/0,text:"",originIndex:e.length}),c}static itemizeParagraph(e,t,n,i,s,r,o,c){const f=[],p=e.match(/\S+|\s+/g)||[];let g=0;for(let e=0;e<p.length;e++){const m=p[e],y=g;if(/\s+/.test(m)){const e=t(m);f.push({type:l.GLUE,width:e,stretch:.5*e,shrink:e*h,text:m,originIndex:y}),g+=m.length}else{const e=m.split(/(-)/);let h=y;for(let p=0;p<e.length;p++){const g=e[p];if(g)if("-"===g)f.push({type:l.DISCRETIONARY,width:t("-"),preBreak:"-",postBreak:"",noBreak:"-",preBreakWidth:t("-"),penalty:c?.exHyphenPenalty??u,flagged:!0,text:"-",originIndex:h}),h+=1;else{if(g.includes("­")){const e=g.split("­");let n=0;for(let i=0;i<e.length;i++){const s=e[i];s.length>0&&(f.push({type:l.BOX,width:t(s),text:s,originIndex:h+n}),n+=s.length),i<e.length-1&&(f.push({type:l.DISCRETIONARY,width:0,preBreak:"-",postBreak:"",noBreak:"",preBreakWidth:t("-"),penalty:c?.hyphenPenalty??d,flagged:!0,text:"",originIndex:h+n}),n+=1)}}else if(n&&g.length>=r+o){const e=LineBreak.findHyphenationPoints(g,i,s,r,o);if(e.length>0){let n=0;for(const i of e){const e=g.substring(n,i);f.push({type:l.BOX,width:t(e),text:e,originIndex:h+n}),f.push({type:l.DISCRETIONARY,width:0,preBreak:"-",postBreak:"",noBreak:"",preBreakWidth:t("-"),penalty:c?.hyphenPenalty??d,flagged:!0,text:"",originIndex:h+i}),n=i}const i=g.substring(n);f.push({type:l.BOX,width:t(i),text:i,originIndex:h+n})}else f.push({type:l.BOX,width:t(g),text:g,originIndex:h})}else f.push({type:l.BOX,width:t(g),text:g,originIndex:h});h+=g.length}}g+=m.length}}return f}static hasSingleWordLines(e,t,n){let i=0;for(let s=0;s<t.length-1;s++){const r=t[s];let o=0,h=0;for(let t=i;t<r;t++)e[t].type===l.GLUE&&o++,e[t].type!==l.PENALTY&&(h+=e[t].width);if(0===o&&h>0){if(h/n<.5)return!0}i=r+1}return!1}static breakText(e){i.start("LineBreak.breakText",{textLength:e.text.length,width:e.width,align:e.align||"left",hyphenate:e.hyphenate||!1});const{text:t,width:h,align:c="left",direction:m="ltr",hyphenate:_=!1,language:v="en-us",respectExistingBreaks:w=!0,measureText:b,hyphenationPatterns:S,unitsPerEm:E,tolerance:L=s,pretolerance:O=r,emergencyStretch:T=o,autoEmergencyStretch:P,lefthyphenmin:F=y,righthyphenmin:C=x,linepenalty:B=p,adjdemerits:I=g,hyphenpenalty:A=d,exhyphenpenalty:U=u,doublehyphendemerits:R=f,looseness:D=0,disableSingleWordDetection:z=!1}=e;if(w&&t.includes("\n")){const n=t.split("\n"),s=[];let r=0;for(const t of n){if(0===t.length)s.push({text:"",originalStart:r,originalEnd:r,xOffset:0,isLastLine:!0,naturalWidth:0,endedWithHyphen:!1});else{const n=LineBreak.breakText({...e,text:t,respectExistingBreaks:!1});n.forEach(e=>{e.originalStart+=r,e.originalEnd+=r}),s.push(...n)}r+=t.length+1}return i.end("LineBreak.breakText"),s}let G=_;!G||S&&S[v]||(n.warn(`Hyphenation patterns for ${v} not available`),G=!1);let k=T;void 0!==P&&h?k=h*P:!G&&T===o&&h&&(k=.1*h);const M={linePenalty:B,adjDemerits:I,doubleHyphenDemerits:R,hyphenPenalty:A,exHyphenPenalty:U,currentAlign:c,unitsPerEm:E};if(!h||h===1/0){const e=b(t);return i.end("LineBreak.breakText"),[{text:t,originalStart:0,originalEnd:t.length-1,xOffset:0,isLastLine:!0,naturalWidth:e,endedWithHyphen:!1}]}const N=LineBreak.itemizeText(t,b,G,v,S,F,C,M);if(0===N.length)return[];let H=0,V=k,W=null;const q=!z;for(;H<5;){let e=G?N.filter(e=>e.type!==l.DISCRETIONARY||e.penalty!==(M?.hyphenPenalty??d)):N,n=LineBreak.findBreakpoints(e,h,O,D,!1,0,M);if(0===n.length&&G&&(e=N,n=LineBreak.findBreakpoints(e,h,L,D,!1,0,M)),0===n.length&&(e=N,n=LineBreak.findBreakpoints(e,h,10001,D,!0,V,M)),0===n.length&&(n=LineBreak.findBreakpoints(e,h,1/0,D,!0,V,M)),n.length>0){const i=LineBreak.computeCumulativeWidths(e);if(W=LineBreak.createLines(t,e,n,h,c,m,i,M),q&&n.length>1&&LineBreak.hasSingleWordLines(e,n,h)){V+=.1*h,H++;continue}break}break}if(i.end("LineBreak.breakText"),W&&W.length>0)return W;const j=b(t);return[{text:t,originalStart:0,originalEnd:t.length-1,xOffset:0,adjustmentRatio:0,isLastLine:!0,naturalWidth:j,endedWithHyphen:!1}]}static findBreakpoints(e,t,n=1/0,i=0,s=!1,r=0,o){const h=LineBreak.computeCumulativeWidths(e),d=new ActiveNodeList;d.insert({position:0,line:0,fitness:c.NORMAL,totalDemerits:0,totalWidth:0,previous:null,active:!0});for(let i=0;i<e.length;i++){const s=e[i];s.type===l.PENALTY&&s.penalty<1/0&&LineBreak.considerBreak(e,d,i,t,n,r,h,o),s.type===l.DISCRETIONARY&&s.penalty<1/0&&LineBreak.considerBreak(e,d,i,t,n,r,h,o),s.type===l.GLUE&&i>0&&e[i-1].type===l.BOX&&LineBreak.considerBreak(e,d,i,t,n,r,h,o),LineBreak.deactivateNodes(d,i,t,h.minWidths)}const u=[];let f=null;if(0===i){const e=d.getAllActive();let t=1/0;for(const n of e)n.active&&n.totalDemerits<t&&(t=n.totalDemerits,f=n)}else{const e=d.getAllActive();let t=0,n=1/0;for(const i of e)i.active&&i.totalDemerits<n&&(n=i.totalDemerits,t=i.line);let r=0,o=1/0;for(const n of e){if(!n.active)continue;const e=n.line-t;e<r&&i<=e||e>r&&i>=e?(f=n,r=e,o=n.totalDemerits):e===r&&n.totalDemerits<o&&(f=n,o=n.totalDemerits)}if(!s&&r!==i&&f)return[]}if(!f)return[];for(;f&&f.position>0;)u.unshift(f.position),f=f.previous;return u}static considerBreak(e,t,n,i,s=1/0,r=0,o,h){const c=(e[n].type===l.PENALTY?e[n].penalty:0)<=-1/0,d=t.getAllActive();for(let u=0;u<d.length;u++){const f=d[u];if(!f.active)continue;const p=LineBreak.computeAdjustmentRatio(e,f.position,n,f.line,i,o,h),{ratio:g,adjustment:y,stretch:x,shrink:_,totalWidth:v}=p;let w;if(y>0){const e=x+r;w=e<=0?10001:LineBreak.badness(y,e)}else w=y<0?_<=0||-y>_?10001:LineBreak.badness(-y,_):0;if(!c&&g<-1)continue;const b=LineBreak.computeFitnessClass(w,y>0);if(!c&&w>s)continue;let S=0,E=0;let L=(h?.linePenalty??0)+w,O=Math.abs(L)>=1e4?1e8:L*L;const T=e[n].type===l.PENALTY||e[n].type===l.DISCRETIONARY?e[n].penalty:0;0!==T&&(T>0?O+=T*T:T>m&&(O-=T*T));const P=e[n].type===l.PENALTY&&e[n].flagged||e[n].type===l.DISCRETIONARY&&e[n].flagged,F=f.position>0&&(e[f.position].type===l.PENALTY&&e[f.position].flagged||e[f.position].type===l.DISCRETIONARY&&e[f.position].flagged);P&&F&&(S=h?.doubleHyphenDemerits??0,O+=S),Math.abs(b-f.fitness)>1&&(E=h?.adjDemerits??0,O+=E),c&&(O=0);const C=f.totalDemerits+O;let B=t.findExisting(n,b);B?C<B.totalDemerits&&(B.totalDemerits=C,B.previous=f,B.totalWidth=v):t.insert({position:n,line:f.line+1,fitness:b,totalDemerits:C,totalWidth:v,previous:f,active:!0})}}static computeAdjustmentRatio(e,t,n,i,s,r,o){let h=0,c=0,d=0;if(r){h=r.widths[n]-r.widths[t],c=r.stretches[n]-r.stretches[t],d=r.shrinks[n]-r.shrinks[t];for(let i=t;i<n;i++){const t=e[i];t.type===l.PENALTY&&(h-=t.width)}}else for(let i=t;i<n;i++){const t=e[i];t.type!==l.PENALTY&&(h+=t.width,t.type===l.GLUE&&(c+=t.stretch,d+=t.shrink))}n<e.length&&(e[n].type===l.PENALTY||e[n].type===l.DISCRETIONARY)&&(h+=e[n].type===l.PENALTY?e[n].width:e[n].preBreakWidth);const u=s-h;let f;return f=u>0&&c>0?u/c:u<0&&d>0?u/d:0===u?0:u>0?3:-1,{ratio:f,adjustment:u,stretch:c,shrink:d,totalWidth:h}}static computeFitnessClass(e,t){return t?e<=12?c.NORMAL:e<=99?c.LOOSE:c.VERY_LOOSE:e<=12?c.NORMAL:c.TIGHT}static computeCumulativeWidths(e){const t=e.length+1,n=new Array(t),i=new Array(t),s=new Array(t),r=new Array(t);n[0]=0,i[0]=0,s[0]=0,r[0]=0;for(let t=0;t<e.length;t++){const o=e[t];if(n[t+1]=n[t]+o.width,o.type===l.PENALTY)r[t+1]=r[t];else if(o.type===l.GLUE){const e=o;i[t+1]=i[t]+e.stretch,s[t+1]=s[t]+e.shrink,r[t+1]=r[t]+Math.max(0,e.width-e.shrink)}else i[t+1]=i[t],s[t+1]=s[t],r[t+1]=r[t]+o.width}return{widths:n,stretches:i,shrinks:s,minWidths:r}}static deactivateNodes(e,t,n,i){const s=e.getAllActive();for(let r=s.length-1;r>=0;r--){const o=s[r];if(!o.active)continue;i[t]-i[o.position]>n&&e.deactivateNode(o)}}static createLines(e,t,n,i,s,r,o,h){if(0===n.length)return[{text:e,originalStart:0,originalEnd:e.length-1,xOffset:0}];const c=[];let d=0;for(let e=0;e<n.length;e++){const u=n[e],f=!(n[n.length-1]+1<t.length-1)&&e===n.length-1,p=[];let g=-1,m=-1,y=0;for(let e=d;e<u;e++){const n=t[e];if((n.type!==l.PENALTY||n.text)&&(n.type!==l.DISCRETIONARY||n.noBreak)){if(void 0!==n.originIndex){(-1===g||n.originIndex<g)&&(g=n.originIndex);const e=n.text?n.text.length:0,t=n.originIndex+e-1;t>m&&(m=t)}if(n.text)p.push(n.text);else if(n.type===l.DISCRETIONARY){const e=n;e.noBreak&&p.push(e.noBreak)}y+=n.width}}const x=t[u];let _=!1;if(u<t.length)if(x.type===l.PENALTY&&x.flagged)p.push("-"),y+=x.width,_=!0,void 0!==x.originIndex&&(m=x.originIndex-1);else if(x.type===l.DISCRETIONARY){const e=x;e.preBreak&&(p.push(e.preBreak),y+=e.preBreakWidth,_=e.flagged||!1,void 0!==x.originIndex&&(m=x.originIndex-1))}const v=p.join("");let w=0,b=0,S=s;if("justify"===s&&f&&(S="rtl"===r?"right":"left"),"center"===S)w=(i-y)/2;else if("right"===S)w=i-y;else if("justify"===S&&!f){b=LineBreak.computeAdjustmentRatio(t,d,u,e,i,o,h).ratio}c.push({text:v,originalStart:g,originalEnd:m,xOffset:w,adjustmentRatio:b,isLastLine:!1,naturalWidth:y,endedWithHyphen:_}),d=u+1}if(d<t.length-1){const e=[];let n=-1,o=-1,h=0;for(let i=d;i<t.length-1;i++){const s=t[i];s.type!==l.PENALTY&&(void 0!==s.originIndex&&((-1===n||s.originIndex<n)&&(n=s.originIndex),s.originIndex>o&&(o=s.originIndex)),s.text&&e.push(s.text),h+=s.width)}const u=e.join("");let f=0,p=s;"justify"===s&&(p="rtl"===r?"right":"left"),"center"===p?f=(i-h)/2:"right"===p&&(f=i-h),c.push({text:u,originalStart:n,originalEnd:o,xOffset:f,adjustmentRatio:0,isLastLine:!0,naturalWidth:h,endedWithHyphen:!1}),c.length>1&&(c[c.length-2].isLastLine=!1),c[c.length-1].isLastLine=!0}else c.length>0&&(c[c.length-1].isLastLine=!0);return c}}class TextMeasurer{static measureTextWidth(e,t,n=0){const i=e.hb.createBuffer();i.addText(t),i.guessSegmentProperties(),e.hb.shape(e.font,i);const s=i.json(e.font),r=n*e.upem;let o=0;return s.forEach((e,n)=>{o+=e.ax;const i=n===s.length-1,h=" "===t||" "===t||/^\s+$/.test(t);0===r||i&&!h||(o+=r)}),i.destroy(),o}}class TextLayout{constructor(e){this.loadedFont=e}computeLines(e){const{text:t,width:n,align:i,direction:s,hyphenate:r,language:o,respectExistingBreaks:h,tolerance:l,pretolerance:c,emergencyStretch:d,autoEmergencyStretch:u,hyphenationPatterns:f,lefthyphenmin:p,righthyphenmin:g,linepenalty:m,adjdemerits:y,hyphenpenalty:x,exhyphenpenalty:_,doublehyphendemerits:v,looseness:w,disableSingleWordDetection:b,letterSpacing:S}=e;let E;if(n)E=LineBreak.breakText({text:t,width:n,align:i,direction:s,hyphenate:r,language:o,respectExistingBreaks:h,tolerance:l,pretolerance:c,emergencyStretch:d,autoEmergencyStretch:u,hyphenationPatterns:f,lefthyphenmin:p,righthyphenmin:g,linepenalty:m,adjdemerits:y,hyphenpenalty:x,exhyphenpenalty:_,doublehyphendemerits:v,looseness:w,disableSingleWordDetection:b,unitsPerEm:this.loadedFont.upem,measureText:e=>TextMeasurer.measureTextWidth(this.loadedFont,e,S)});else{const e=t.split("\n");E=[];let n=0;for(const t of e)E.push({text:t,originalStart:n,originalEnd:n+t.length-1,xOffset:0}),n+=t.length+1}return{lines:E}}applyAlignment(e,t){const{width:n,align:i,planeBounds:s}=t;let r=0;const o={min:{...s.min},max:{...s.max}};if(n&&("center"===i||"right"===i)){const t=s.max.x-s.min.x;if("center"===i?r=(n-t)/2-s.min.x:"right"===i&&(r=n-s.max.x),0!==r){for(let t=0;t<e.length;t+=3)e[t]+=r;o.min.x+=r,o.max.x+=r}}return{offset:r,adjustedBounds:o}}}const v=1330926671,w=1953784678,b=2001684038;class FontMetadataExtractor{static extractMetadata(e){if(!e||e.byteLength<12)throw new Error("Invalid font buffer: too small to be a valid font file");const t=new DataView(e),n=t.getUint32(0);if(![65536,v,w].includes(n))throw new Error(`Invalid font format. Expected TrueType or OpenType, got signature: 0x${n.toString(16)}`);const i=new Uint8Array(e),s=t.getUint16(4);let r=!1,o=0,h=0,l=0,c=0,d=0,u=0;for(let e=0;e<s;e++){const n=(new TextDecoder).decode(i.slice(12+16*e,12+16*e+4));("CFF "===n||"CFF2"===n)&&(r=!0),"head"===n&&(o=t.getUint32(12+16*e+8)),"hhea"===n&&(h=t.getUint32(12+16*e+8)),"OS/2"===n&&(l=t.getUint32(12+16*e+8)),"fvar"===n&&(u=t.getUint32(12+16*e+8)),"STAT"===n&&(c=t.getUint32(12+16*e+8)),"name"===n&&(d=t.getUint32(12+16*e+8))}const f=o?t.getUint16(o+18):1e3;let p=null;h&&(p={ascender:t.getInt16(h+4),descender:t.getInt16(h+6),lineGap:t.getInt16(h+8)});let g=null;l&&(g={typoAscender:t.getInt16(l+68),typoDescender:t.getInt16(l+70),typoLineGap:t.getInt16(l+72),winAscent:t.getUint16(l+74),winDescent:t.getUint16(l+76)});let m=null;return u&&c&&d&&(m=this.extractAxisNames(t,c,d)),{isCFF:r,unitsPerEm:f,hheaAscender:p?.ascender||null,hheaDescender:p?.descender||null,hheaLineGap:p?.lineGap||null,typoAscender:g?.typoAscender||null,typoDescender:g?.typoDescender||null,typoLineGap:g?.typoLineGap||null,winAscent:g?.winAscent||null,winDescent:g?.winDescent||null,axisNames:m}}static extractAxisNames(e,t,n){try{if(e.getUint16(t)<1)return null;const i=e.getUint16(t+4),s=e.getUint16(t+6),r=e.getUint32(t+8),o={};for(let h=0;h<s;h++){const s=t+r+h*i,l=String.fromCharCode(e.getUint8(s),e.getUint8(s+1),e.getUint8(s+2),e.getUint8(s+3)),c=e.getUint16(s+4),d=this.getNameFromNameTable(e,n,c);d&&(o[l]=d)}return Object.keys(o).length>0?o:null}catch(e){return null}}static getNameFromNameTable(e,t,n){try{const i=e.getUint16(t+2),s=e.getUint16(t+4);for(let r=0;r<i;r++){const i=t+6+12*r,o=e.getUint16(i),h=e.getUint16(i+2),l=e.getUint16(i+4),c=e.getUint16(i+6),d=e.getUint16(i+8),u=e.getUint16(i+10);if(c===n&&(0===o||3===o&&1033===l)){const n=t+s+u,i=new Uint8Array(e.buffer,n,d);if(0===o||3===o&&1===h){let e="";for(let t=0;t<i.length;t+=2)e+=String.fromCharCode(i[t]<<8|i[t+1]);return e}return new TextDecoder("ascii").decode(i)}}return null}catch(e){return null}}static getVerticalMetrics(e){return null!==e.typoAscender&&null!==e.typoDescender?{ascender:e.typoAscender,descender:e.typoDescender,lineGap:0}:null!==e.hheaAscender&&null!==e.hheaDescender?{ascender:e.hheaAscender,descender:e.hheaDescender,lineGap:0}:null!==e.winAscent&&null!==e.winDescent?{ascender:e.winAscent,descender:-e.winDescent,lineGap:0}:{ascender:Math.round(.8*e.unitsPerEm),descender:-Math.round(.2*e.unitsPerEm),lineGap:0}}static getFontMetrics(e){const t=FontMetadataExtractor.getVerticalMetrics(e);return{ascender:t.ascender,descender:t.descender,lineGap:t.lineGap,unitsPerEm:e.unitsPerEm,naturalLineHeight:t.ascender-t.descender}}}class WoffConverter{static detectFormat(e){if(e.byteLength<4)return"ttf/otf";const t=new DataView(e).getUint32(0);return t===b?"woff":2001684018===t?"woff2":"ttf/otf"}static async decompressWoff(e){const t=new DataView(e),i=new Uint8Array(e);if(t.getUint32(0)!==b)throw new Error("Not a valid WOFF font");const s=t.getUint32(4),r=t.getUint16(12),o=t.getUint32(16);if("undefined"==typeof DecompressionStream)throw new Error("WOFF fonts require DecompressionStream API (Chrome 80+, Firefox 113+, Safari 16.4+). Please use TTF/OTF fonts or upgrade your browser.");const h=new Uint8Array(o),l=new DataView(h.buffer);l.setUint32(0,s),l.setUint16(4,r);const c=2**Math.floor(Math.log2(r))*16;l.setUint16(6,c),l.setUint16(8,Math.floor(Math.log2(r))),l.setUint16(10,16*r-c);let d=12+16*r;const u=[];for(let e=0;e<r;e++){const n=44+20*e;u.push({tag:t.getUint32(n),offset:t.getUint32(n+4),length:t.getUint32(n+8),origLength:t.getUint32(n+12),checksum:t.getUint32(n+16)})}u.sort((e,t)=>e.tag-t.tag);for(let e=0;e<r;e++){const t=u[e],n=12+16*e;if(l.setUint32(n,t.tag),l.setUint32(n+4,t.checksum),l.setUint32(n+8,d),l.setUint32(n+12,t.origLength),t.length===t.origLength)h.set(i.subarray(t.offset,t.offset+t.length),d);else{const e=i.subarray(t.offset,t.offset+t.length),n=await WoffConverter.decompressZlib(e);if(n.byteLength!==t.origLength)throw new Error(`Decompression failed: expected ${t.origLength} bytes, got ${n.byteLength}`);h.set(new Uint8Array(n),d)}d+=t.origLength;d+=(4-t.origLength%4)%4}return n.log("WOFF font decompressed successfully"),h.buffer.slice(0,d)}static async decompressZlib(e){const t=new ReadableStream({start(t){t.enqueue(e),t.close()}}).pipeThrough(new DecompressionStream("deflate"));return new Response(t).arrayBuffer()}}class FontLoader{constructor(e){this.getHarfBuzzInstance=e}async loadFont(e,t){if(i.start("FontLoader.loadFont",{bufferSize:e.byteLength}),!e||e.byteLength<12)throw new Error("Invalid font buffer: too small to be a valid font file");const s=WoffConverter.detectFormat(e);if("woff"===s)n.log("WOFF font detected, decompressing..."),e=await WoffConverter.decompressWoff(e);else if("woff2"===s)throw new Error("WOFF2 fonts are not yet supported. Please use WOFF or TTF/OTF format.");const r=new DataView(e).getUint32(0);if(![65536,v,w].includes(r))throw new Error(`Invalid font format. Expected TrueType or OpenType, got signature: 0x${r.toString(16)}`);const{hb:o,module:h}=await this.getHarfBuzzInstance();try{const n=o.createBlob(new Uint8Array(e)),i=o.createFace(n,0),s=o.createFont(i);t&&s.setVariations(t);const r=i.getAxisInfos(),l=Object.keys(r).length>0,c=FontMetadataExtractor.extractMetadata(e);let d;if(l&&r){d={};for(const[e,t]of Object.entries(r))d[e]={...t,name:c.axisNames?.[e]||null}}return{hb:o,fontBlob:n,face:i,font:s,module:h,upem:c.unitsPerEm,metrics:c,fontVariations:t,isVariable:l,variationAxes:d}}catch(e){throw n.error("Failed to load font:",e),e}finally{i.end("FontLoader.loadFont")}}static destroyFont(e){try{e.font&&"function"==typeof e.font.destroy&&e.font.destroy(),e.face&&"function"==typeof e.face.destroy&&e.face.destroy(),e.fontBlob&&"function"==typeof e.fontBlob.destroy&&e.fontBlob.destroy()}catch(e){n.error("Error destroying font resources:",e)}}}async function loadPattern(e,t){{const n=`ThreeTextPatterns_${e.replace(/-/g,"_")}`;if(window[n])return window[n];const i=t||"/patterns/";return new Promise((t,s)=>{const r=document.createElement("script");r.src=`${i}${e}.umd.js`,r.async=!0,r.onload=()=>{window[n]?t(window[n]):s(new Error(`Pattern script loaded, but global ${n} not found.`))},r.onerror=()=>{s(new Error(`Failed to load hyphenation pattern from ${r.src}. Did you copy the pattern files to your public directory?`))},document.head.appendChild(r)})}}class Vec2{constructor(e=0,t=0){this.x=e,this.y=t}set(e,t){return this.x=e,this.y=t,this}clone(){return new Vec2(this.x,this.y)}copy(e){return this.x=e.x,this.y=e.y,this}add(e){return this.x+=e.x,this.y+=e.y,this}sub(e){return this.x-=e.x,this.y-=e.y,this}multiply(e){return this.x*=e,this.y*=e,this}divide(e){return this.x/=e,this.y/=e,this}length(){return Math.sqrt(this.x*this.x+this.y*this.y)}lengthSq(){return this.x*this.x+this.y*this.y}normalize(){const e=this.length();return e>0&&this.divide(e),this}dot(e){return this.x*e.x+this.y*e.y}distanceTo(e){const t=this.x-e.x,n=this.y-e.y;return Math.sqrt(t*t+n*n)}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y;return t*t+n*n}equals(e){return this.x===e.x&&this.y===e.y}angle(){return Math.atan2(this.y,this.x)}}class Vec3{constructor(e=0,t=0,n=0){this.x=e,this.y=t,this.z=n}set(e,t,n){return this.x=e,this.y=t,this.z=n,this}clone(){return new Vec3(this.x,this.y,this.z)}copy(e){return this.x=e.x,this.y=e.y,this.z=e.z,this}add(e){return this.x+=e.x,this.y+=e.y,this.z+=e.z,this}sub(e){return this.x-=e.x,this.y-=e.y,this.z-=e.z,this}multiply(e){return this.x*=e,this.y*=e,this.z*=e,this}divide(e){return this.x/=e,this.y/=e,this.z/=e,this}length(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)}lengthSq(){return this.x*this.x+this.y*this.y+this.z*this.z}normalize(){const e=this.length();return e>0&&this.divide(e),this}dot(e){return this.x*e.x+this.y*e.y+this.z*e.z}cross(e){const t=this.y*e.z-this.z*e.y,n=this.z*e.x-this.x*e.z,i=this.x*e.y-this.y*e.x;return this.x=t,this.y=n,this.z=i,this}distanceTo(e){const t=this.x-e.x,n=this.y-e.y,i=this.z-e.z;return Math.sqrt(t*t+n*n+i*i)}distanceToSquared(e){const t=this.x-e.x,n=this.y-e.y,i=this.z-e.z;return t*t+n*n+i*i}equals(e){return this.x===e.x&&this.y===e.y&&this.z===e.z}}class Box3{constructor(e=new Vec3(1/0,1/0,1/0),t=new Vec3(-1/0,-1/0,-1/0)){this.min=e,this.max=t}set(e,t){return this.min.copy(e),this.max.copy(t),this}setFromPoints(e){this.makeEmpty();for(let t=0;t<e.length;t++)this.expandByPoint(e[t]);return this}makeEmpty(){return this.min.x=this.min.y=this.min.z=1/0,this.max.x=this.max.y=this.max.z=-1/0,this}isEmpty(){return this.max.x<this.min.x||this.max.y<this.min.y||this.max.z<this.min.z}expandByPoint(e){return this.min.x=Math.min(this.min.x,e.x),this.min.y=Math.min(this.min.y,e.y),this.min.z=Math.min(this.min.z,e.z),this.max.x=Math.max(this.max.x,e.x),this.max.y=Math.max(this.max.y,e.y),this.max.z=Math.max(this.max.z,e.z),this}expandByScalar(e){return this.min.x-=e,this.min.y-=e,this.min.z-=e,this.max.x+=e,this.max.y+=e,this.max.z+=e,this}containsPoint(e){return e.x>=this.min.x&&e.x<=this.max.x&&e.y>=this.min.y&&e.y<=this.max.y&&e.z>=this.min.z&&e.z<=this.max.z}containsBox(e){return this.min.x<=e.min.x&&e.max.x<=this.max.x&&this.min.y<=e.min.y&&e.max.y<=this.max.y&&this.min.z<=e.min.z&&e.max.z<=this.max.z}intersectsBox(e){return e.max.x>=this.min.x&&e.min.x<=this.max.x&&e.max.y>=this.min.y&&e.min.y<=this.max.y&&e.max.z>=this.min.z&&e.min.z<=this.max.z}getCenter(e=new Vec3){return this.isEmpty()?e.set(0,0,0):e.set(.5*(this.min.x+this.max.x),.5*(this.min.y+this.max.y),.5*(this.min.z+this.max.z))}getSize(e=new Vec3){return this.isEmpty()?e.set(0,0,0):e.set(this.max.x-this.min.x,this.max.y-this.min.y,this.max.z-this.min.z)}clone(){return new Box3(this.min.clone(),this.max.clone())}copy(e){return this.min.copy(e.min),this.max.copy(e.max),this}union(e){return this.min.x=Math.min(this.min.x,e.min.x),this.min.y=Math.min(this.min.y,e.min.y),this.min.z=Math.min(this.min.z,e.min.z),this.max.x=Math.max(this.max.x,e.max.x),this.max.y=Math.max(this.max.y,e.max.y),this.max.z=Math.max(this.max.z,e.max.z),this}equals(e){return e.min.equals(this.min)&&e.max.equals(this.max)}}var S,E;function assert(e,t){if(!e)throw t||"Assertion Failed!"}!function(e){e[e.ODD=0]="ODD",e[e.NONZERO=1]="NONZERO",e[e.POSITIVE=2]="POSITIVE",e[e.NEGATIVE=3]="NEGATIVE",e[e.ABS_GEQ_TWO=4]="ABS_GEQ_TWO"}(S||(S={})),function(e){e[e.POLYGONS=0]="POLYGONS",e[e.CONNECTED_POLYGONS=1]="CONNECTED_POLYGONS",e[e.BOUNDARY_CONTOURS=2]="BOUNDARY_CONTOURS"}(E||(E={}));var L=function(){function Geom(){}return Geom.vertEq=function(e,t){return e.s===t.s&&e.t===t.t},Geom.vertLeq=function(e,t){return e.s<t.s||e.s===t.s&&e.t<=t.t},Geom.transLeq=function(e,t){return e.t<t.t||e.t===t.t&&e.s<=t.s},Geom.edgeGoesLeft=function(e){return Geom.vertLeq(e.Dst,e.Org)},Geom.edgeGoesRight=function(e){return Geom.vertLeq(e.Org,e.Dst)},Geom.vertL1dist=function(e,t){return Math.abs(e.s-t.s)+Math.abs(e.t-t.t)},Geom.edgeEval=function(e,t,n){assert(Geom.vertLeq(e,t)&&Geom.vertLeq(t,n));var i=t.s-e.s,s=n.s-t.s;return i+s>0?i<s?t.t-e.t+(e.t-n.t)*(i/(i+s)):t.t-n.t+(n.t-e.t)*(s/(i+s)):0},Geom.edgeSign=function(e,t,n){assert(Geom.vertLeq(e,t)&&Geom.vertLeq(t,n));var i=t.s-e.s,s=n.s-t.s;return i+s>0?(t.t-n.t)*i+(t.t-e.t)*s:0},Geom.transEval=function(e,t,n){assert(Geom.transLeq(e,t)&&Geom.transLeq(t,n));var i=t.t-e.t,s=n.t-t.t;return i+s>0?i<s?t.s-e.s+(e.s-n.s)*(i/(i+s)):t.s-n.s+(n.s-e.s)*(s/(i+s)):0},Geom.transSign=function(e,t,n){assert(Geom.transLeq(e,t)&&Geom.transLeq(t,n));var i=t.t-e.t,s=n.t-t.t;return i+s>0?(t.s-n.s)*i+(t.s-e.s)*s:0},Geom.vertCCW=function(e,t,n){return e.s*(t.t-n.t)+t.s*(n.t-e.t)+n.s*(e.t-t.t)>=0},Geom.interpolate=function(e,t,n,i){return(e=e<0?0:e)<=(n=n<0?0:n)?0===n?(t+i)/2:t+e/(e+n)*(i-t):i+n/(e+n)*(t-i)},Geom.intersect=function(e,t,n,i,s){var r,o,h;Geom.vertLeq(e,t)||(h=e,e=t,t=h),Geom.vertLeq(n,i)||(h=n,n=i,i=h),Geom.vertLeq(e,n)||(h=e,e=n,n=h,h=t,t=i,i=h),Geom.vertLeq(n,t)?Geom.vertLeq(t,i)?((r=Geom.edgeEval(e,n,t))+(o=Geom.edgeEval(n,t,i))<0&&(r=-r,o=-o),s.s=Geom.interpolate(r,n.s,o,t.s)):((r=Geom.edgeSign(e,n,t))+(o=-Geom.edgeSign(e,i,t))<0&&(r=-r,o=-o),s.s=Geom.interpolate(r,n.s,o,i.s)):s.s=(n.s+t.s)/2,Geom.transLeq(e,t)||(h=e,e=t,t=h),Geom.transLeq(n,i)||(h=n,n=i,i=h),Geom.transLeq(e,n)||(h=e,e=n,n=h,h=t,t=i,i=h),Geom.transLeq(n,t)?Geom.transLeq(t,i)?((r=Geom.transEval(e,n,t))+(o=Geom.transEval(n,t,i))<0&&(r=-r,o=-o),s.t=Geom.interpolate(r,n.t,o,t.t)):((r=Geom.transSign(e,n,t))+(o=-Geom.transSign(e,i,t))<0&&(r=-r,o=-o),s.t=Geom.interpolate(r,n.t,o,i.t)):s.t=(n.t+t.t)/2},Geom}(),TESSface=function(){this.next=null,this.prev=null,this.anEdge=null,this.trail=null,this.n=0,this.marked=!1,this.inside=!1},O=function(){function TESShalfEdge(e){this.side=e,this.next=null,this.Org=null,this.Sym=null,this.Onext=null,this.Lnext=null,this.Lface=null,this.activeRegion=null,this.winding=0}return Object.defineProperty(TESShalfEdge.prototype,"Rface",{get:function(){return this.Sym.Lface},set:function(e){this.Sym.Lface=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Dst",{get:function(){return this.Sym.Org},set:function(e){this.Sym.Org=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Oprev",{get:function(){return this.Sym.Lnext},set:function(e){this.Sym.Lnext=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Lprev",{get:function(){return this.Onext.Sym},set:function(e){this.Onext.Sym=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Dprev",{get:function(){return this.Lnext.Sym},set:function(e){this.Lnext.Sym=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Rprev",{get:function(){return this.Sym.Onext},set:function(e){this.Sym.Onext=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Dnext",{get:function(){return this.Sym.Onext.Sym},set:function(e){this.Sym.Onext.Sym=e},enumerable:!0,configurable:!0}),Object.defineProperty(TESShalfEdge.prototype,"Rnext",{get:function(){return this.Sym.Lnext.Sym},set:function(e){this.Sym.Lnext.Sym=e},enumerable:!0,configurable:!0}),TESShalfEdge}(),TESSvertex=function(){this.next=null,this.prev=null,this.anEdge=null,this.coords=[0,0,0],this.s=0,this.t=0,this.pqHandle=0,this.n=0,this.idx=0},T=function(){function TESSmesh(){var e=new TESSvertex,t=new TESSface,n=new O(0),i=new O(1);e.next=e.prev=e,e.anEdge=null,t.next=t.prev=t,n.next=n,n.Sym=i,i.next=i,i.Sym=n,this.vHead=e,this.fHead=t,this.eHead=n,this.eHeadSym=i}return TESSmesh.prototype.makeEdge_=function(e){var t=new O(0),n=new O(1);e.Sym.side<e.side&&(e=e.Sym);var i=e.Sym.next;return n.next=i,i.Sym.next=t,t.next=e,e.Sym.next=n,t.Sym=n,t.Onext=t,t.Lnext=n,t.Org=null,t.Lface=null,t.winding=0,t.activeRegion=null,n.Sym=t,n.Onext=n,n.Lnext=t,n.Org=null,n.Lface=null,n.winding=0,n.activeRegion=null,t},TESSmesh.prototype.splice_=function(e,t){var n=e.Onext,i=t.Onext;n.Sym.Lnext=t,i.Sym.Lnext=e,e.Onext=i,t.Onext=n},TESSmesh.prototype.makeVertex_=function(e,t,n){var i=e;assert(i,"Vertex can't be null!");var s=n.prev;i.prev=s,s.next=i,i.next=n,n.prev=i,i.anEdge=t;var r=t;do{r.Org=i,r=r.Onext}while(r!==t)},TESSmesh.prototype.makeFace_=function(e,t,n){var i=e;assert(i,"Face can't be null");var s=n.prev;i.prev=s,s.next=i,i.next=n,n.prev=i,i.anEdge=t,i.trail=null,i.marked=!1,i.inside=n.inside;var r=t;do{r.Lface=i,r=r.Lnext}while(r!==t)},TESSmesh.prototype.killEdge_=function(e){e.Sym.side<e.side&&(e=e.Sym);var t=e.next,n=e.Sym.next;t.Sym.next=n,n.Sym.next=t},TESSmesh.prototype.killVertex_=function(e,t){var n=e.anEdge,i=n;do{i.Org=t,i=i.Onext}while(i!==n);var s=e.prev,r=e.next;r.prev=s,s.next=r},TESSmesh.prototype.killFace_=function(e,t){var n=e.anEdge,i=n;do{i.Lface=t,i=i.Lnext}while(i!==n);var s=e.prev,r=e.next;r.prev=s,s.next=r},TESSmesh.prototype.makeEdge=function(){var e=new TESSvertex,t=new TESSvertex,n=new TESSface,i=this.makeEdge_(this.eHead);return this.makeVertex_(e,i,this.vHead),this.makeVertex_(t,i.Sym,this.vHead),this.makeFace_(n,i,this.fHead),i},TESSmesh.prototype.splice=function(e,t){var n=!1,i=!1;if(e!==t){if(t.Org!==e.Org&&(i=!0,this.killVertex_(t.Org,e.Org)),t.Lface!==e.Lface&&(n=!0,this.killFace_(t.Lface,e.Lface)),this.splice_(t,e),!i){var s=new TESSvertex;this.makeVertex_(s,t,e.Org),e.Org.anEdge=e}if(!n){var r=new TESSface;this.makeFace_(r,t,e.Lface),e.Lface.anEdge=e}}},TESSmesh.prototype.delete=function(e){var t=e.Sym,n=!1;if(e.Lface!==e.Rface&&(n=!0,this.killFace_(e.Lface,e.Rface)),e.Onext===e)this.killVertex_(e.Org,null);else if(e.Rface.anEdge=e.Oprev,e.Org.anEdge=e.Onext,this.splice_(e,e.Oprev),!n){var i=new TESSface;this.makeFace_(i,e,e.Lface)}t.Onext===t?(this.killVertex_(t.Org,null),this.killFace_(t.Lface,null)):(e.Lface.anEdge=t.Oprev,t.Org.anEdge=t.Onext,this.splice_(t,t.Oprev)),this.killEdge_(e)},TESSmesh.prototype.addEdgeVertex=function(e){var t=this.makeEdge_(e),n=t.Sym;this.splice_(t,e.Lnext),t.Org=e.Dst;var i=new TESSvertex;return this.makeVertex_(i,n,t.Org),t.Lface=n.Lface=e.Lface,t},TESSmesh.prototype.splitEdge=function(e){var t=this.addEdgeVertex(e).Sym;return this.splice_(e.Sym,e.Sym.Oprev),this.splice_(e.Sym,t),e.Dst=t.Org,t.Dst.anEdge=t.Sym,t.Rface=e.Rface,t.winding=e.winding,t.Sym.winding=e.Sym.winding,t},TESSmesh.prototype.connect=function(e,t){var n=!1,i=this.makeEdge_(e),s=i.Sym;if(t.Lface!==e.Lface&&(n=!0,this.killFace_(t.Lface,e.Lface)),this.splice_(i,e.Lnext),this.splice_(s,t),i.Org=e.Dst,s.Org=t.Org,i.Lface=s.Lface=e.Lface,e.Lface.anEdge=s,!n){var r=new TESSface;this.makeFace_(r,i,e.Lface)}return i},TESSmesh.prototype.zapFace=function(e){var t,n,i,s,r,o=e.anEdge;n=o.Lnext;do{n=(t=n).Lnext,t.Lface=null,null===t.Rface&&(t.Onext===t?this.killVertex_(t.Org,null):(t.Org.anEdge=t.Onext,this.splice_(t,t.Oprev)),(i=t.Sym).Onext===i?this.killVertex_(i.Org,null):(i.Org.anEdge=i.Onext,this.splice_(i,i.Oprev)),this.killEdge_(t))}while(t!=o);s=e.prev,(r=e.next).prev=s,s.next=r},TESSmesh.prototype.countFaceVerts_=function(e){var t=e.anEdge,n=0;do{n++,t=t.Lnext}while(t!==e.anEdge);return n},TESSmesh.prototype.mergeConvexFaces=function(e){var t,n,i,s,r;for(t=this.fHead.next;t!==this.fHead;t=t.next)if(t.inside)for(r=(n=t.anEdge).Org;i=n.Lnext,(s=n.Sym)&&s.Lface&&s.Lface.inside&&this.countFaceVerts_(t)+this.countFaceVerts_(s.Lface)-2<=e&&L.vertCCW(n.Lprev.Org,n.Org,s.Lnext.Lnext.Org)&&L.vertCCW(s.Lprev.Org,s.Org,n.Lnext.Lnext.Org)&&(i=s.Lnext,this.delete(s),n=null,s=null),!n||n.Lnext.Org!==r;)n=i;return!0},TESSmesh.prototype.check=function(){var e,t,n,i,s,r,o=this.fHead,h=this.vHead,l=this.eHead;for(t=o,t=o;(e=t.next)!==o;t=e){assert(e.prev===t),s=e.anEdge;do{assert(s.Sym!==s),assert(s.Sym.Sym===s),assert(s.Lnext.Onext.Sym===s),assert(s.Onext.Sym.Lnext===s),assert(s.Lface===e),s=s.Lnext}while(s!==e.anEdge)}for(assert(e.prev===t&&null===e.anEdge),i=h,i=h;(n=i.next)!==h;i=n){assert(n.prev===i),s=n.anEdge;do{assert(s.Sym!==s),assert(s.Sym.Sym===s),assert(s.Lnext.Onext.Sym===s),assert(s.Onext.Sym.Lnext===s),assert(s.Org===n),s=s.Onext}while(s!==n.anEdge)}for(assert(n.prev===i&&null===n.anEdge),r=l,r=l;(s=r.next)!==l;r=s)assert(s.Sym.next===r.Sym),assert(s.Sym!==s),assert(s.Sym.Sym===s),assert(null!==s.Org),assert(null!==s.Dst),assert(s.Lnext.Onext.Sym===s),assert(s.Onext.Sym.Lnext===s);assert(s.Sym.next===r.Sym&&s.Sym===this.eHeadSym&&s.Sym.Sym===s&&null===s.Org&&null===s.Dst&&null===s.Lface&&null===s.Rface)},TESSmesh}(),PQnode=function(){this.handle=null},PQhandleElem=function(){this.key=null,this.node=0},P=function(){function PriorityQ(e,t){this.leq=t,this.max=0,this.nodes=[],this.handles=[],this.initialized=!1,this.freeList=0,this.size=0,this.max=e,this.nodes=[],this.handles=[];for(var n=0;n<e+1;n++)this.nodes[n]=new PQnode,this.handles[n]=new PQhandleElem;this.initialized=!1,this.nodes[1].handle=1,this.handles[1].key=null}return PriorityQ.prototype.floatDown_=function(e){var t,n,i,s=this.nodes,r=this.handles;for(t=s[e].handle;;){if((i=e<<1)<this.size&&this.leq(r[s[i+1].handle].key,r[s[i].handle].key)&&++i,assert(i<=this.max),n=s[i].handle,i>this.size||this.leq(r[t].key,r[n].key)){s[e].handle=t,r[t].node=e;break}s[e].handle=n,r[n].node=e,e=i}},PriorityQ.prototype.floatUp_=function(e){var t,n,i,s=this.nodes,r=this.handles;for(t=s[e].handle;;){if(n=s[i=e>>1].handle,0===i||this.leq(r[n].key,r[t].key)){s[e].handle=t,r[t].node=e;break}s[e].handle=n,r[n].node=e,e=i}},PriorityQ.prototype.init=function(){for(var e=this.size;e>=1;--e)this.floatDown_(e);this.initialized=!0},PriorityQ.prototype.min=function(){return this.handles[this.nodes[1].handle].key},PriorityQ.prototype.insert=function(e){var t,n;if(2*(t=++this.size)>this.max){var i,s;for(this.max*=2,s=this.nodes.length,this.nodes.length=this.max+1,i=s;i<this.nodes.length;i++)this.nodes[i]=new PQnode;for(s=this.handles.length,this.handles.length=this.max+1,i=s;i<this.handles.length;i++)this.handles[i]=new PQhandleElem}return 0===this.freeList?n=t:(n=this.freeList,this.freeList=this.handles[n].node),this.nodes[t].handle=n,this.handles[n].node=t,this.handles[n].key=e,this.initialized&&this.floatUp_(t),n},PriorityQ.prototype.extractMin=function(){var e=this.nodes,t=this.handles,n=e[1].handle,i=t[n].key;return this.size>0&&(e[1].handle=e[this.size].handle,t[e[1].handle].node=1,t[n].key=null,t[n].node=this.freeList,this.freeList=n,--this.size,this.size>0&&this.floatDown_(1)),i},PriorityQ.prototype.delete=function(e){var t,n=this.nodes,i=this.handles;assert(e>=1&&e<=this.max&&null!==i[e].key),n[t=i[e].node].handle=n[this.size].handle,i[n[t].handle].node=t,--this.size,t<=this.size&&(t<=1||this.leq(i[n[t>>1].handle].key,i[n[t].handle].key)?this.floatDown_(t):this.floatUp_(t)),i[e].key=null,i[e].node=this.freeList,this.freeList=e},PriorityQ}(),ActiveRegion=function(){this.eUp=null,this.nodeUp=null,this.windingNumber=0,this.inside=!1,this.sentinel=!1,this.dirty=!1,this.fixUpperEdge=!1},DictNode=function(){this.key=null,this.next=null,this.prev=null},F=function(){function Dict(e,t){this.frame=e,this.leq=t,this.head=new DictNode,this.head.next=this.head,this.head.prev=this.head}return Dict.prototype.min=function(){return this.head.next},Dict.prototype.max=function(){return this.head.prev},Dict.prototype.insert=function(e){return this.insertBefore(this.head,e)},Dict.prototype.search=function(e){var t=this.head;do{t=t.next}while(null!==t.key&&!this.leq(this.frame,e,t.key));return t},Dict.prototype.insertBefore=function(e,t){do{e=e.prev}while(null!==e.key&&!this.leq(this.frame,e.key,t));var n=new DictNode;return n.key=t,n.next=e.next,e.next.prev=n,n.prev=e,e.next=n,n},Dict.prototype.delete=function(e){e.next.prev=e.prev,e.prev.next=e.next},Dict}(),C=function(){function Sweep(){}return Sweep.regionBelow=function(e){return e.nodeUp.prev.key},Sweep.regionAbove=function(e){return e.nodeUp.next.key},Sweep.debugEvent=function(e){},Sweep.addWinding=function(e,t){e.winding+=t.winding,e.Sym.winding+=t.Sym.winding},Sweep.edgeLeq=function(e,t,n){var i=e.event,s=t.eUp,r=n.eUp;return s.Dst===i?r.Dst===i?L.vertLeq(s.Org,r.Org)?L.edgeSign(r.Dst,s.Org,r.Org)<=0:L.edgeSign(s.Dst,r.Org,s.Org)>=0:L.edgeSign(r.Dst,i,r.Org)<=0:r.Dst===i?L.edgeSign(s.Dst,i,s.Org)>=0:L.edgeEval(s.Dst,i,s.Org)>=L.edgeEval(r.Dst,i,r.Org)},Sweep.deleteRegion=function(e,t){t.fixUpperEdge&&assert(0===t.eUp.winding),t.eUp.activeRegion=null,e.dict.delete(t.nodeUp)},Sweep.fixUpperEdge=function(e,t,n){assert(t.fixUpperEdge),e.mesh.delete(t.eUp),t.fixUpperEdge=!1,t.eUp=n,n.activeRegion=t},Sweep.topLeftRegion=function(e,t){var n,i=t.eUp.Org;do{t=Sweep.regionAbove(t)}while(t.eUp.Org===i);if(t.fixUpperEdge){if(null===(n=e.mesh.connect(Sweep.regionBelow(t).eUp.Sym,t.eUp.Lnext)))return null;Sweep.fixUpperEdge(e,t,n),t=Sweep.regionAbove(t)}return t},Sweep.topRightRegion=function(e){var t=e.eUp.Dst;do{e=Sweep.regionAbove(e)}while(e.eUp.Dst===t);return e},Sweep.addRegionBelow=function(e,t,n){var i=new ActiveRegion;return i.eUp=n,i.nodeUp=e.dict.insertBefore(t.nodeUp,i),i.fixUpperEdge=!1,i.sentinel=!1,i.dirty=!1,n.activeRegion=i,i},Sweep.isWindingInside=function(e,t){switch(e.windingRule){case S.ODD:return!!(1&t);case S.NONZERO:return 0!==t;case S.POSITIVE:return t>0;case S.NEGATIVE:return t<0;case S.ABS_GEQ_TWO:return t>=2||t<=-2}throw new Error("Invalid winding rulle")},Sweep.computeWinding=function(e,t){t.windingNumber=Sweep.regionAbove(t).windingNumber+t.eUp.winding,t.inside=Sweep.isWindingInside(e,t.windingNumber)},Sweep.finishRegion=function(e,t){var n=t.eUp,i=n.Lface;i.inside=t.inside,i.anEdge=n,Sweep.deleteRegion(e,t)},Sweep.finishLeftRegions=function(e,t,n){for(var i,s=null,r=t,o=t.eUp;r!==n;){if(r.fixUpperEdge=!1,(i=(s=Sweep.regionBelow(r)).eUp).Org!=o.Org){if(!s.fixUpperEdge){Sweep.finishRegion(e,r);break}i=e.mesh.connect(o.Lprev,i.Sym),Sweep.fixUpperEdge(e,s,i)}o.Onext!==i&&(e.mesh.splice(i.Oprev,i),e.mesh.splice(o,i)),Sweep.finishRegion(e,r),o=s.eUp,r=s}return o},Sweep.addRightEdges=function(e,t,n,i,s,r){var o,h,l,c,d=!0;l=n;do{assert(L.vertLeq(l.Org,l.Dst)),Sweep.addRegionBelow(e,t,l.Sym),l=l.Onext}while(l!==i);for(null===s&&(s=Sweep.regionBelow(t).eUp.Rprev),h=t,c=s;(l=(o=Sweep.regionBelow(h)).eUp.Sym).Org===c.Org;)l.Onext!==c&&(e.mesh.splice(l.Oprev,l),e.mesh.splice(c.Oprev,l)),o.windingNumber=h.windingNumber-l.winding,o.inside=Sweep.isWindingInside(e,o.windingNumber),h.dirty=!0,!d&&Sweep.checkForRightSplice(e,h)&&(Sweep.addWinding(l,c),Sweep.deleteRegion(e,h),e.mesh.delete(c)),d=!1,h=o,c=l;h.dirty=!0,assert(h.windingNumber-l.winding===o.windingNumber),r&&Sweep.walkDirtyRegions(e,h)},Sweep.spliceMergeVertices=function(e,t,n){e.mesh.splice(t,n)},Sweep.vertexWeights=function(e,t,n){var i=L.vertL1dist(t,e),s=L.vertL1dist(n,e),r=.5*s/(i+s),o=.5*i/(i+s);e.coords[0]+=r*t.coords[0]+o*n.coords[0],e.coords[1]+=r*t.coords[1]+o*n.coords[1],e.coords[2]+=r*t.coords[2]+o*n.coords[2]},Sweep.getIntersectData=function(e,t,n,i,s,r){t.coords[0]=t.coords[1]=t.coords[2]=0,t.idx=-1,Sweep.vertexWeights(t,n,i),Sweep.vertexWeights(t,s,r)},Sweep.checkForRightSplice=function(e,t){var n=Sweep.regionBelow(t),i=t.eUp,s=n.eUp;if(L.vertLeq(i.Org,s.Org)){if(L.edgeSign(s.Dst,i.Org,s.Org)>0)return!1;L.vertEq(i.Org,s.Org)?i.Org!==s.Org&&(e.pq.delete(i.Org.pqHandle),Sweep.spliceMergeVertices(e,s.Oprev,i)):(e.mesh.splitEdge(s.Sym),e.mesh.splice(i,s.Oprev),t.dirty=n.dirty=!0)}else{if(L.edgeSign(i.Dst,s.Org,i.Org)<0)return!1;Sweep.regionAbove(t).dirty=t.dirty=!0,e.mesh.splitEdge(i.Sym),e.mesh.splice(s.Oprev,i)}return!0},Sweep.checkForLeftSplice=function(e,t){var n,i=Sweep.regionBelow(t),s=t.eUp,r=i.eUp;if(assert(!L.vertEq(s.Dst,r.Dst)),L.vertLeq(s.Dst,r.Dst)){if(L.edgeSign(s.Dst,r.Dst,s.Org)<0)return!1;Sweep.regionAbove(t).dirty=t.dirty=!0,n=e.mesh.splitEdge(s),e.mesh.splice(r.Sym,n),n.Lface.inside=t.inside}else{if(L.edgeSign(r.Dst,s.Dst,r.Org)>0)return!1;t.dirty=i.dirty=!0,n=e.mesh.splitEdge(r),e.mesh.splice(s.Lnext,r.Sym),n.Rface.inside=t.inside}return!0},Sweep.checkForIntersect=function(e,t){var n,i,s=Sweep.regionBelow(t),r=t.eUp,o=s.eUp,h=r.Org,l=o.Org,c=r.Dst,d=o.Dst,u=new TESSvertex;if(assert(!L.vertEq(d,c)),assert(L.edgeSign(c,e.event,h)<=0),assert(L.edgeSign(d,e.event,l)>=0),assert(h!==e.event&&l!==e.event),assert(!t.fixUpperEdge&&!s.fixUpperEdge),h===l)return!1;if(Math.min(h.t,c.t)>Math.max(l.t,d.t))return!1;if(L.vertLeq(h,l)){if(L.edgeSign(d,h,l)>0)return!1}else if(L.edgeSign(c,l,h)<0)return!1;return Sweep.debugEvent(e),L.intersect(c,h,d,l,u),assert(Math.min(h.t,c.t)<=u.t),assert(u.t<=Math.max(l.t,d.t)),assert(Math.min(d.s,c.s)<=u.s),assert(u.s<=Math.max(l.s,h.s)),L.vertLeq(u,e.event)&&(u.s=e.event.s,u.t=e.event.t),n=L.vertLeq(h,l)?h:l,L.vertLeq(n,u)&&(u.s=n.s,u.t=n.t),L.vertEq(u,h)||L.vertEq(u,l)?(Sweep.checkForRightSplice(e,t),!1):!L.vertEq(c,e.event)&&L.edgeSign(c,e.event,u)>=0||!L.vertEq(d,e.event)&&L.edgeSign(d,e.event,u)<=0?d===e.event?(e.mesh.splitEdge(r.Sym),e.mesh.splice(o.Sym,r),t=Sweep.topLeftRegion(e,t),r=Sweep.regionBelow(t).eUp,Sweep.finishLeftRegions(e,Sweep.regionBelow(t),s),Sweep.addRightEdges(e,t,r.Oprev,r,r,!0),!0):c===e.event?(e.mesh.splitEdge(o.Sym),e.mesh.splice(r.Lnext,o.Oprev),s=t,t=Sweep.topRightRegion(t),i=Sweep.regionBelow(t).eUp.Rprev,s.eUp=o.Oprev,o=Sweep.finishLeftRegions(e,s,null),Sweep.addRightEdges(e,t,o.Onext,r.Rprev,i,!0),!0):(L.edgeSign(c,e.event,u)>=0&&(Sweep.regionAbove(t).dirty=t.dirty=!0,e.mesh.splitEdge(r.Sym),r.Org.s=e.event.s,r.Org.t=e.event.t),L.edgeSign(d,e.event,u)<=0&&(t.dirty=s.dirty=!0,e.mesh.splitEdge(o.Sym),o.Org.s=e.event.s,o.Org.t=e.event.t),!1):(e.mesh.splitEdge(r.Sym),e.mesh.splitEdge(o.Sym),e.mesh.splice(o.Oprev,r),r.Org.s=u.s,r.Org.t=u.t,r.Org.pqHandle=e.pq.insert(r.Org),Sweep.getIntersectData(e,r.Org,h,c,l,d),Sweep.regionAbove(t).dirty=t.dirty=s.dirty=!0,!1)},Sweep.walkDirtyRegions=function(e,t){for(var n,i,s=Sweep.regionBelow(t);;){for(;s.dirty;)t=s,s=Sweep.regionBelow(s);if(!t.dirty&&(s=t,null===(t=Sweep.regionAbove(t))||!t.dirty))return;if(t.dirty=!1,n=t.eUp,i=s.eUp,n.Dst!==i.Dst&&Sweep.checkForLeftSplice(e,t)&&(s.fixUpperEdge?(Sweep.deleteRegion(e,s),e.mesh.delete(i),i=(s=Sweep.regionBelow(t)).eUp):t.fixUpperEdge&&(Sweep.deleteRegion(e,t),e.mesh.delete(n),n=(t=Sweep.regionAbove(s)).eUp)),n.Org!==i.Org)if(n.Dst===i.Dst||t.fixUpperEdge||s.fixUpperEdge||n.Dst!==e.event&&i.Dst!==e.event)Sweep.checkForRightSplice(e,t);else if(Sweep.checkForIntersect(e,t))return;n.Org===i.Org&&n.Dst===i.Dst&&(Sweep.addWinding(i,n),Sweep.deleteRegion(e,t),e.mesh.delete(n),t=Sweep.regionAbove(s))}},Sweep.connectRightVertex=function(e,t,n){var i,s=n.Onext,r=Sweep.regionBelow(t),o=t.eUp,h=r.eUp,l=!1;o.Dst!==h.Dst&&Sweep.checkForIntersect(e,t),L.vertEq(o.Org,e.event)&&(e.mesh.splice(s.Oprev,o),t=Sweep.topLeftRegion(e,t),s=Sweep.regionBelow(t).eUp,Sweep.finishLeftRegions(e,Sweep.regionBelow(t),r),l=!0),L.vertEq(h.Org,e.event)&&(e.mesh.splice(n,h.Oprev),n=Sweep.finishLeftRegions(e,r,null),l=!0),l?Sweep.addRightEdges(e,t,n.Onext,s,s,!0):(i=L.vertLeq(h.Org,o.Org)?h.Oprev:o,i=e.mesh.connect(n.Lprev,i),Sweep.addRightEdges(e,t,i,i.Onext,i.Onext,!1),i.Sym.activeRegion.fixUpperEdge=!0,Sweep.walkDirtyRegions(e,t))},Sweep.connectLeftDegenerate=function(e,t,n){var i,s,r,o,h;return i=t.eUp,L.vertEq(i.Org,n)?(assert(!1),void Sweep.spliceMergeVertices(e,i,n.anEdge)):L.vertEq(i.Dst,n)?(assert(!1),t=Sweep.topRightRegion(t),s=o=(r=(h=Sweep.regionBelow(t)).eUp.Sym).Onext,h.fixUpperEdge&&(assert(s!==r),Sweep.deleteRegion(e,h),e.mesh.delete(r),r=s.Oprev),e.mesh.splice(n.anEdge,r),L.edgeGoesLeft(s)||(s=null),void Sweep.addRightEdges(e,t,r.Onext,o,s,!0)):(e.mesh.splitEdge(i.Sym),t.fixUpperEdge&&(e.mesh.delete(i.Onext),t.fixUpperEdge=!1),e.mesh.splice(n.anEdge,i),void Sweep.sweepEvent(e,n))},Sweep.connectLeftVertex=function(e,t){var n,i,s,r,o,h,l=new ActiveRegion;if(l.eUp=t.anEdge.Sym,n=e.dict.search(l).key,i=Sweep.regionBelow(n))if(r=n.eUp,o=i.eUp,0!==L.edgeSign(r.Dst,t,r.Org))if(s=L.vertLeq(o.Dst,r.Dst)?n:i,n.inside||s.fixUpperEdge){if(s===n)h=e.mesh.connect(t.anEdge.Sym,r.Lnext);else h=e.mesh.connect(o.Dnext,t.anEdge).Sym;s.fixUpperEdge?Sweep.fixUpperEdge(e,s,h):Sweep.computeWinding(e,Sweep.addRegionBelow(e,n,h)),Sweep.sweepEvent(e,t)}else Sweep.addRightEdges(e,n,t.anEdge,t.anEdge,null,!0);else Sweep.connectLeftDegenerate(e,n,t)},Sweep.sweepEvent=function(e,t){e.event=t,Sweep.debugEvent(e);for(var n=t.anEdge;null===n.activeRegion;)if((n=n.Onext)===t.anEdge)return void Sweep.connectLeftVertex(e,t);var i=Sweep.topLeftRegion(e,n.activeRegion);assert(null!==i);var s=Sweep.regionBelow(i),r=s.eUp,o=Sweep.finishLeftRegions(e,s,null);o.Onext===r?Sweep.connectRightVertex(e,i,o):Sweep.addRightEdges(e,i,o.Onext,r,r,!0)},Sweep.addSentinel=function(e,t,n,i){var s=new ActiveRegion,r=e.mesh.makeEdge();r.Org.s=n,r.Org.t=i,r.Dst.s=t,r.Dst.t=i,e.event=r.Dst,s.eUp=r,s.windingNumber=0,s.inside=!1,s.fixUpperEdge=!1,s.sentinel=!0,s.dirty=!1,s.nodeUp=e.dict.insert(s)},Sweep.initEdgeDict=function(e){e.dict=new F(e,Sweep.edgeLeq);var t=e.bmax[0]-e.bmin[0],n=e.bmax[1]-e.bmin[1],i=e.bmin[0]-t,s=e.bmax[0]+t,r=e.bmin[1]-n,o=e.bmax[1]+n;Sweep.addSentinel(e,i,s,r),Sweep.addSentinel(e,i,s,o)},Sweep.doneEdgeDict=function(e){for(var t,n=0;null!==(t=e.dict.min().key);)t.sentinel||(assert(t.fixUpperEdge),assert(1===++n)),assert(0===t.windingNumber),Sweep.deleteRegion(e,t)},Sweep.removeDegenerateEdges=function(e){var t,n,i,s=e.mesh.eHead;for(t=s.next;t!==s;t=n)n=t.next,i=t.Lnext,L.vertEq(t.Org,t.Dst)&&t.Lnext.Lnext!==t&&(Sweep.spliceMergeVertices(e,i,t),e.mesh.delete(t),i=(t=i).Lnext),i.Lnext===t&&(i!==t&&(i!==n&&i!==n.Sym||(n=n.next),e.mesh.delete(i)),t!==n&&t!==n.Sym||(n=n.next),e.mesh.delete(t))},Sweep.initPriorityQ=function(e){var t,n,i,s=0;for(n=(i=e.mesh.vHead).next;n!==i;n=n.next)s++;for(s+=8,t=e.pq=new P(s,L.vertLeq),n=(i=e.mesh.vHead).next;n!==i;n=n.next)n.pqHandle=t.insert(n);return n===i&&(t.init(),!0)},Sweep.donePriorityQ=function(e){e.pq=null},Sweep.removeDegenerateFaces=function(e,t){var n,i,s;for(n=t.fHead.next;n!==t.fHead;n=i)i=n.next,assert((s=n.anEdge).Lnext!==s),s.Lnext.Lnext===s&&(Sweep.addWinding(s.Onext,s),e.mesh.delete(s));return!0},Sweep.computeInterior=function(e,t){var n,i;if(void 0===t&&(t=!0),Sweep.removeDegenerateEdges(e),!Sweep.initPriorityQ(e))return!1;for(Sweep.initEdgeDict(e);null!==(n=e.pq.extractMin());){for(;null!==(i=e.pq.min())&&L.vertEq(i,n);)i=e.pq.extractMin(),Sweep.spliceMergeVertices(e,n.anEdge,i.anEdge);Sweep.sweepEvent(e,n)}return e.event=e.dict.min().key.eUp.Org,Sweep.debugEvent(e),Sweep.doneEdgeDict(e),Sweep.donePriorityQ(e),!!Sweep.removeDegenerateFaces(e,e.mesh)&&(t&&e.mesh.check(),!0)},Sweep}(),B=function(){function Tesselator(){this.mesh=new T,this.normal=[0,0,0],this.sUnit=[0,0,0],this.tUnit=[0,0,0],this.bmin=[0,0],this.bmax=[0,0],this.windingRule=S.ODD,this.dict=null,this.pq=null,this.event=null,this.vertexIndexCounter=0,this.vertices=[],this.vertexIndices=[],this.vertexCount=0,this.elements=[],this.elementCount=0}return Tesselator.prototype.dot_=function(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]},Tesselator.prototype.normalize_=function(e){var t=e[0]*e[0]+e[1]*e[1]+e[2]*e[2];if(!t)throw"Zero-size vector!";t=Math.sqrt(t),e[0]/=t,e[1]/=t,e[2]/=t},Tesselator.prototype.longAxis_=function(e){var t=0;return Math.abs(e[1])>Math.abs(e[0])&&(t=1),Math.abs(e[2])>Math.abs(e[t])&&(t=2),t},Tesselator.prototype.computeNormal_=function(e){var t,n,i,s,r,o,h=[0,0,0],l=[0,0,0],c=[0,0,0],d=[0,0,0],u=[0,0,0],f=[null,null,null],p=[null,null,null],g=this.mesh.vHead;t=g.next;for(var m=0;m<3;++m)s=t.coords[m],l[m]=s,p[m]=t,h[m]=s,f[m]=t;for(t=g.next;t!==g;t=t.next)for(var y=0;y<3;++y)(s=t.coords[y])<l[y]&&(l[y]=s,p[y]=t),s>h[y]&&(h[y]=s,f[y]=t);var x=0;if(h[1]-l[1]>h[0]-l[0]&&(x=1),h[2]-l[2]>h[x]-l[x]&&(x=2),l[x]>=h[x])return e[0]=0,e[1]=0,void(e[2]=1);for(o=0,n=p[x],i=f[x],c[0]=n.coords[0]-i.coords[0],c[1]=n.coords[1]-i.coords[1],c[2]=n.coords[2]-i.coords[2],t=g.next;t!==g;t=t.next)d[0]=t.coords[0]-i.coords[0],d[1]=t.coords[1]-i.coords[1],d[2]=t.coords[2]-i.coords[2],u[0]=c[1]*d[2]-c[2]*d[1],u[1]=c[2]*d[0]-c[0]*d[2],u[2]=c[0]*d[1]-c[1]*d[0],(r=u[0]*u[0]+u[1]*u[1]+u[2]*u[2])>o&&(o=r,e[0]=u[0],e[1]=u[1],e[2]=u[2]);o<=0&&(e[0]=e[1]=e[2]=0,e[this.longAxis_(c)]=1)},Tesselator.prototype.checkOrientation_=function(){for(var e,t,n=this.mesh.fHead,i=this.mesh.vHead,s=0,r=n.next;r!==n;r=r.next)if(!((t=r.anEdge).winding<=0))do{s+=(t.Org.s-t.Dst.s)*(t.Org.t+t.Dst.t),t=t.Lnext}while(t!==r.anEdge);if(s<0){for(e=i.next;e!==i;e=e.next)e.t=-e.t;this.tUnit[0]=-this.tUnit[0],this.tUnit[1]=-this.tUnit[1],this.tUnit[2]=-this.tUnit[2]}},Tesselator.prototype.projectPolygon_=function(){var e,t,n=this.mesh.vHead,i=[0,0,0],s=!1;i[0]=this.normal[0],i[1]=this.normal[1],i[2]=this.normal[2],i[0]||i[1]||i[2]||(this.computeNormal_(i),s=!0),e=this.sUnit,t=this.tUnit;var r=this.longAxis_(i);e[r]=0,e[(r+1)%3]=1,e[(r+2)%3]=0,t[r]=0,t[(r+1)%3]=0,t[(r+2)%3]=i[r]>0?1:-1;for(var o=n.next;o!==n;o=o.next)o.s=this.dot_(o.coords,e),o.t=this.dot_(o.coords,t);s&&this.checkOrientation_();for(var h=!0,l=n.next;l!==n;l=l.next)h?(this.bmin[0]=this.bmax[0]=l.s,this.bmin[1]=this.bmax[1]=l.t,h=!1):(l.s<this.bmin[0]&&(this.bmin[0]=l.s),l.s>this.bmax[0]&&(this.bmax[0]=l.s),l.t<this.bmin[1]&&(this.bmin[1]=l.t),l.t>this.bmax[1]&&(this.bmax[1]=l.t))},Tesselator.prototype.addWinding_=function(e,t){e.winding+=t.winding,e.Sym.winding+=t.Sym.winding},Tesselator.prototype.tessellateMonoRegion_=function(e,t){var n,i;if((n=t.anEdge).Lnext===n||n.Lnext.Lnext===n)throw"Mono region invalid";for(;L.vertLeq(n.Dst,n.Org);n=n.Lprev);for(;L.vertLeq(n.Org,n.Dst);n=n.Lnext);i=n.Lprev;for(;n.Lnext!==i;)if(L.vertLeq(n.Dst,i.Org)){for(;i.Lnext!==n&&(L.edgeGoesLeft(i.Lnext)||L.edgeSign(i.Org,i.Dst,i.Lnext.Dst)<=0);)i=e.connect(i.Lnext,i).Sym;i=i.Lprev}else{for(;i.Lnext!==n&&(L.edgeGoesRight(n.Lprev)||L.edgeSign(n.Dst,n.Org,n.Lprev.Org)>=0);)n=e.connect(n,n.Lprev).Sym;n=n.Lnext}if(i.Lnext===n)throw"Mono region invalid";for(;i.Lnext.Lnext!==n;)i=e.connect(i.Lnext,i).Sym;return!0},Tesselator.prototype.tessellateInterior_=function(e){for(var t,n=e.fHead.next;n!==e.fHead;n=t)if(t=n.next,n.inside&&!this.tessellateMonoRegion_(e,n))return!1;return!0},Tesselator.prototype.discardExterior_=function(e){for(var t,n=e.fHead.next;n!==e.fHead;n=t)t=n.next,n.inside||e.zapFace(n)},Tesselator.prototype.setWindingNumber_=function(e,t,n){for(var i,s=e.eHead.next;s!==e.eHead;s=i)i=s.next,s.Rface.inside!==s.Lface.inside?s.winding=s.Lface.inside?t:-t:n?e.delete(s):s.winding=0},Tesselator.prototype.getNeighbourFace_=function(e){return e.Rface&&e.Rface.inside?e.Rface.n:-1},Tesselator.prototype.outputPolymesh_=function(e,t,n,i){var s,r,o=0,h=0;n>3&&e.mergeConvexFaces(n);for(var l=e.vHead.next;l!==e.vHead;l=l.next)l.n=-1;for(var c=e.fHead.next;c!==e.fHead;c=c.next)if(c.n=-1,c.inside){s=c.anEdge,r=0;do{-1===(l=s.Org).n&&(l.n=h,h++),r++,s=s.Lnext}while(s!==c.anEdge);if(r>n)throw"Face vertex greater that support polygon";c.n=o,++o}this.elementCount=o,t===E.CONNECTED_POLYGONS&&(o*=2),this.elements=[],this.elements.length=o*n,this.vertexCount=h,this.vertices=[],this.vertices.length=h*i,this.vertexIndices=[],this.vertexIndices.length=h;for(l=e.vHead.next;l!==e.vHead;l=l.next)if(-1!==l.n){var d=l.n*i;this.vertices[d+0]=l.coords[0],this.vertices[d+1]=l.coords[1],i>2&&(this.vertices[d+2]=l.coords[2]),this.vertexIndices[l.n]=l.idx}var u=0;for(c=e.fHead.next;c!==e.fHead;c=c.next)if(c.inside){s=c.anEdge,r=0;do{l=s.Org;this.elements[u++]=l.n,r++,s=s.Lnext}while(s!==c.anEdge);for(var f=r;f<n;++f)this.elements[u++]=-1;if(t===E.CONNECTED_POLYGONS){s=c.anEdge;do{this.elements[u++]=this.getNeighbourFace_(s),s=s.Lnext}while(s!==c.anEdge);for(var p=r;p<n;++p)this.elements[u++]=-1}}},Tesselator.prototype.outputContours_=function(e,t){var n,i,s=0,r=0;this.vertexCount=0,this.elementCount=0;for(var o=e.fHead.next;o!==e.fHead;o=o.next)if(o.inside){i=n=o.anEdge;do{this.vertexCount++,n=n.Lnext}while(n!==i);this.elementCount++}this.elements=[],this.elements.length=2*this.elementCount,this.vertices=[],this.vertices.length=this.vertexCount*t,this.vertexIndices=[],this.vertexIndices.length=this.vertexCount;var h=0,l=0,c=0;s=0;for(o=e.fHead.next;o!==e.fHead;o=o.next)if(o.inside){r=0,i=n=o.anEdge;do{this.vertices[h++]=n.Org.coords[0],this.vertices[h++]=n.Org.coords[1],t>2&&(this.vertices[h++]=n.Org.coords[2]),this.vertexIndices[l++]=n.Org.idx,r++,n=n.Lnext}while(n!==i);this.elements[c++]=s,this.elements[c++]=r,s+=r}},Tesselator.prototype.addContour=function(e,t){null===this.mesh&&(this.mesh=new T),e<2&&(e=2),e>3&&(e=3);for(var n=null,i=0;i<t.length;i+=e)null===n?(n=this.mesh.makeEdge(),this.mesh.splice(n,n.Sym)):(this.mesh.splitEdge(n),n=n.Lnext),n.Org.coords[0]=t[i+0],n.Org.coords[1]=t[i+1],n.Org.coords[2]=e>2?t[i+2]:0,n.Org.idx=this.vertexIndexCounter++,n.winding=1,n.Sym.winding=-1},Tesselator.prototype.tesselate=function(e,t,n,i,s,r){if(void 0===e&&(e=S.ODD),void 0===t&&(t=E.POLYGONS),void 0===r&&(r=!0),this.vertices=[],this.elements=[],this.vertexIndices=[],this.vertexIndexCounter=0,s&&(this.normal[0]=s[0],this.normal[1]=s[1],this.normal[2]=s[2]),this.windingRule=e,i<2&&(i=2),i>3&&(i=3),!this.mesh)return!1;this.projectPolygon_(),C.computeInterior(this,r);var o=this.mesh;return t===E.BOUNDARY_CONTOURS?this.setWindingNumber_(o,1,!0):this.tessellateInterior_(o),r&&o.check(),t===E.BOUNDARY_CONTOURS?this.outputContours_(o,i):this.outputPolymesh_(o,t,n,i),!0},Tesselator}();S.ODD,S.NONZERO,S.POSITIVE,S.NEGATIVE,S.ABS_GEQ_TWO,E.POLYGONS,E.CONNECTED_POLYGONS,E.BOUNDARY_CONTOURS;class Tessellator{process(e,t=!0,i=!1){if(0===e.length)return{triangles:{vertices:[],indices:[]},contours:[]};const s=e.filter(e=>e.points.length>=3);return 0===s.length?{triangles:{vertices:[],indices:[]},contours:[]}:(n.log(`Tessellator: removeOverlaps=${t}, processing ${s.length} paths`),this.tessellate(s,t,i))}tessellate(e,t,i){const s=i||t?e:e.map(e=>this.reverseWinding(e));let r=this.pathsToContours(s);if(t){n.log("Two-pass: boundary extraction then triangulation");const e=this.performTessellation(r,E.BOUNDARY_CONTOURS);if(!e)return n.warn("Tess2 returned empty result from boundary pass"),{triangles:{vertices:[],indices:[]},contours:[]};r=this.boundaryToContours(e),n.log(`Boundary pass created ${r.length} contours. Starting triangulation pass.`)}else n.log("Single-pass triangulation for "+(i?"CFF":"TTF"));const o=this.performTessellation(r,E.POLYGONS);if(!o){const e=t?"Tess2 returned empty result from triangulation pass":"Tess2 returned empty result from single-pass triangulation";return n.warn(e),{triangles:{vertices:[],indices:[]},contours:r}}return{triangles:{vertices:Array.from(o.vertices),indices:Array.from(o.elements)},contours:r}}pathsToContours(e){return e.map(e=>{const t=[];for(const n of e.points)t.push(n.x,n.y);return t})}performTessellation(e,t){const n=function(e){var t=e.windingRule,n=void 0===t?S.ODD:t,i=e.elementType,s=void 0===i?E.POLYGONS:i,r=e.polySize,o=void 0===r?3:r,h=e.vertexSize,l=void 0===h?2:h,c=e.normal,d=void 0===c?[0,0,1]:c,u=e.contours,f=void 0===u?[]:u,p=e.strict,g=void 0===p||p,m=e.debug,y=void 0!==m&&m;if(!f&&g)throw new Error("Contours can't be empty");if(f){for(var x=new B,_=0;_<f.length;_++)x.addContour(l||2,f[_]);return x.tesselate(n,s,o,l,d,g),{vertices:x.vertices,vertexIndices:x.vertexIndices,vertexCount:x.vertexCount,elements:x.elements,elementCount:x.elementCount,mesh:y?x.mesh:void 0}}}({contours:e,windingRule:S.NONZERO,elementType:t,polySize:3,vertexSize:2,strict:!1});return n?.vertices&&n?.elements?n:null}boundaryToContours(e){const t=[];for(let n=0;n<e.elements.length;n+=2){const i=e.elements[n],s=e.elements[n+1],r=[];for(let t=0;t<s;t++){const n=2*(i+t);r.push(e.vertices[n],e.vertices[n+1])}r.length>2&&(r[0]===r[r.length-2]&&r[1]===r[r.length-1]||r.push(r[0],r[1])),t.push(r)}return t}reverseWinding(e){return{...e,points:[...e.points].reverse()}}}class Extruder{constructor(){}extrude(e,t=0,n){const i=[],s=[],r=[];if(0===t)this.addFlatFaces(e.triangles,i,s,r);else{this.addFrontAndBackFaces(e.triangles,i,s,r,t,n);for(const n of e.contours)this.addSideWalls(n,i,s,r,t)}return{vertices:i,normals:s,indices:r}}addFlatFaces(e,t,n,i){const s=t.length/3,r=e.vertices,o=e.indices;for(let e=0;e<r.length;e+=2)t.push(r[e],r[e+1],0),n.push(0,0,-1);for(let e=0;e<o.length;e++)i.push(s+o[e])}addFrontAndBackFaces(e,t,n,i,s,r){const o=t.length/3,h=e.vertices,l=e.indices;for(let e=0;e<h.length;e+=2)t.push(h[e],h[e+1],0),n.push(0,0,-1);const c=25e-6*r,d=s<=c?c:s;for(let e=0;e<h.length;e+=2)t.push(h[e],h[e+1],d),n.push(0,0,1);const u=h.length/2;for(let e=0;e<l.length;e++)i.push(o+l[e]);for(let e=l.length-1;e>=0;e--)i.push(o+l[e]+u)}addSideWalls(e,t,n,i,s){for(let r=0;r<e.length-2;r+=2){const o=e[r],h=e[r+1],l=e[r+2],c=e[r+3],d=new Vec2(l-o,c-h),u=new Vec2(d.y,-d.x).normalize(),f=t.length/3;t.push(o,h,0,l,c,0,o,h,s,l,c,s),n.push(u.x,u.y,0,u.x,u.y,0,u.x,u.y,0,u.x,u.y,0),i.push(f,f+1,f+2,f+1,f+3,f+2)}}}class BoundaryClusterer{constructor(){}cluster(e,t){return 0===e.length?[]:this.clusterSweepLine(e,t)}clusterSweepLine(e,t){const n=e.length;if(n<=1)return 0===n?[]:[[0]];const i=new Array(n),s=new Array(2*n);let r=0;for(let o=0;o<n;o++)i[o]=this.getWorldBounds(e[o],t[o]),s[r++]=[i[o].minX,0,o],s[r++]=[i[o].maxX,1,o];s.sort((e,t)=>e[0]-t[0]||e[1]-t[1]);const o=Array.from({length:n},(e,t)=>t),h=new Array(n).fill(0);function find(e){return o[e]===e?e:o[e]=find(o[e])}function union(e,t){const n=find(e),i=find(t);n!==i&&(h[n]<h[i]?o[n]=i:h[n]>h[i]?o[i]=n:(o[i]=n,h[n]++))}const l=new Set;for(const[,e,t]of s)if(0===e){const e=i[t];for(const n of l){const s=i[n];e.minY<s.maxY+.001&&e.maxY>s.minY-.001&&union(t,n)}l.add(t)}else l.delete(t);const c=new Map;for(let e=0;e<n;e++){const t=find(e);c.has(t)||c.set(t,[]),c.get(t).push(e)}return Array.from(c.values())}getWorldBounds(e,t){return{minX:e.bounds.min.x+t.x,minY:e.bounds.min.y+t.y,maxX:e.bounds.max.x+t.x,maxY:e.bounds.max.y+t.y}}}class MinHeap{constructor(e){this.heap=[],this.itemIndex=new Map,this.compare=e}insert(e){const t=this.itemIndex.get(e);if(void 0!==t)return this.siftUp(t),void this.siftDown(t);const n=this.heap.length;this.heap.push(e),this.itemIndex.set(e,n),this.siftUp(n)}extractMin(){const e=this.heap.length;if(!e)return;if(1===e){const e=this.heap.pop();return this.itemIndex.clear(),e}const t=this.heap[0],n=this.heap.pop();return this.heap[0]=n,this.itemIndex.delete(t),this.itemIndex.set(n,0),this.siftDown(0),t}update(e){const t=this.itemIndex.get(e);void 0!==t?(this.siftUp(t),this.siftDown(t)):this.insert(e)}isEmpty(){return!this.heap.length}swap(e,t){const n=this.heap[e],i=this.heap[t];this.heap[e]=i,this.heap[t]=n,this.itemIndex.set(n,t),this.itemIndex.set(i,e)}siftUp(e){const t=this.heap[e];for(;e>0;){const n=e-1>>1,i=this.heap[n];if(this.compare(t,i)>=0)break;this.heap[e]=i,this.itemIndex.set(i,e),e=n}this.heap[e]=t,this.itemIndex.set(t,e)}siftDown(e){const t=this.heap[e],n=this.heap.length,i=n>>1;for(;e<i;){const i=1+(e<<1),s=i+1;let r=e,o=t;const h=this.heap[i];if(this.compare(h,o)<0&&(r=i,o=h),s<n){const e=this.heap[s];this.compare(e,o)<0&&(r=s,o=e)}if(r===e)break;this.heap[e]=o,this.itemIndex.set(o,e),e=r}this.heap[e]=t,this.itemIndex.set(t,e)}}const I={enabled:!0,areaThreshold:1,colinearThreshold:.0087,minSegmentLength:10};class PathOptimizer{constructor(e){this.stats={pointsRemovedByVisvalingam:0,pointsRemovedByColinear:0,originalPointCount:0},this.config=e}setConfig(e){this.config=e}optimizePath(e){if(!this.config.enabled||e.points.length<=2)return e;this.stats.originalPointCount+=e.points.length;let t=[...e.points];return t.length<5?e:(t=this.simplifyPathVW(t,this.config.areaThreshold),t.length<3?e:(t=this.removeColinearPoints(t,this.config.colinearThreshold),t.length<3?e:{...e,points:t}))}simplifyPathVW(e,t){if(e.length<=3)return e;const n=e.length,i=e.map((e,t)=>({index:t,area:1/0,prev:null,next:null}));for(let e=0;e<i.length;e++)i[e].prev=i[e-1]||null,i[e].next=i[e+1]||null;const s=new MinHeap((e,t)=>e.area-t.area);for(let t=1;t<i.length-1;t++){const n=i[t];n.area=this.calculateTriangleArea(e[n.prev.index],e[n.index],e[n.next.index]),s.insert(n)}let r=n;for(;!s.isEmpty()&&r>3;){const n=s.extractMin();if(!n||n.area>t)break;if(this.config.minSegmentLength>0&&n.prev&&n.next){const t=e[n.prev.index],i=e[n.index],s=e[n.next.index],r=t.distanceTo(i),o=i.distanceTo(s);if(r<this.config.minSegmentLength||o<this.config.minSegmentLength)continue}n.prev&&(n.prev.next=n.next),n.next&&(n.next.prev=n.prev),r--,n.prev&&n.prev.prev&&(n.prev.area=this.calculateTriangleArea(e[n.prev.prev.index],e[n.prev.index],e[n.next.index]),s.update(n.prev)),n.next&&n.next.next&&(n.next.area=this.calculateTriangleArea(e[n.prev.index],e[n.next.index],e[n.next.next.index]),s.update(n.next))}const o=[];let h=i[0];for(;h;)o.push(e[h.index]),h=h.next;const l=n-o.length;return this.stats.pointsRemovedByVisvalingam+=l,o}removeColinearPoints(e,t){if(e.length<=2)return e;const n=[e[0]];for(let i=1;i<e.length-1;i++){const s=e[i-1],r=e[i],o=e[i+1],h=new Vec2(r.x-s.x,r.y-s.y),l=new Vec2(o.x-r.x,o.y-r.y),c=Math.abs(h.angle()-l.angle());Math.min(c,2*Math.PI-c)>t||h.length()<this.config.minSegmentLength||l.length()<this.config.minSegmentLength?n.push(r):this.stats.pointsRemovedByColinear++}return n.push(e[e.length-1]),n}calculateTriangleArea(e,t,n){return Math.abs((e.x*(t.y-n.y)+t.x*(n.y-e.y)+n.x*(e.y-t.y))/2)}getStats(){return{...this.stats}}resetStats(){this.stats={pointsRemovedByVisvalingam:0,pointsRemovedByColinear:0,originalPointCount:0}}}const A={distanceTolerance:.5,angleTolerance:.2},U=1e-6;class Polygonizer{constructor(e){this.curveFidelityConfig={...A,...e}}setCurveFidelityConfig(e){this.curveFidelityConfig={...A,...e}}polygonizeQuadratic(e,t,n){const i=[];return this.recursiveQuadratic(e.x,e.y,t.x,t.y,n.x,n.y,i),this.addPoint(n.x,n.y,i),i}polygonizeCubic(e,t,n,i){const s=[];return this.recursiveCubic(e.x,e.y,t.x,t.y,n.x,n.y,i.x,i.y,s),this.addPoint(i.x,i.y,s),s}recursiveQuadratic(e,t,n,i,s,r,o,h=0){if(h>16)return;const l=(e+n)/2,c=(t+i)/2,d=(n+s)/2,u=(i+r)/2,f=(l+d)/2,p=(c+u)/2,g=s-e,m=r-t,y=Math.abs((n-s)*m-(i-r)*g),x=this.curveFidelityConfig.distanceTolerance??A.distanceTolerance,_=x*x;if(y>U){if(y*y<=_*(g*g+m*m)){const h=this.curveFidelityConfig.angleTolerance??A.angleTolerance;if(!(h>0))return void this.addPoint(n,i,o);{let l=Math.abs(Math.atan2(r-i,s-n)-Math.atan2(i-t,n-e));if(l>=Math.PI&&(l=2*Math.PI-l),l<h)return void this.addPoint(n,i,o)}}}else{const s=g*g+m*m;if(0===s){if((n-e)*(n-e)+(i-t)*(i-t)<=_)return void this.addPoint(n,i,o)}else{const r=((n-e)*g+(i-t)*m)/s;if(r>0&&r<1&&y*y<=_*s)return void this.addPoint(n,i,o)}}this.recursiveQuadratic(e,t,l,c,f,p,o,h+1),this.recursiveQuadratic(f,p,d,u,s,r,o,h+1)}recursiveCubic(e,t,n,i,s,r,o,h,l,c=0){if(c>16)return;const d=(e+n)/2,u=(t+i)/2,f=(n+s)/2,p=(i+r)/2,g=(s+o)/2,m=(r+h)/2,y=(d+f)/2,x=(u+p)/2,_=(f+g)/2,v=(p+m)/2,w=(y+_)/2,b=(x+v)/2,S=o-e,E=h-t,L=Math.abs((n-o)*E-(i-h)*S),O=Math.abs((s-o)*E-(r-h)*S),T=this.curveFidelityConfig.distanceTolerance??A.distanceTolerance,P=T*T;let F=0;switch(L>U&&(F|=1),O>U&&(F|=2),F){case 0:const c=S*S+E*E;if(0===c){if((n-e)*(n-e)+(i-t)*(i-t)<=P&&(s-e)*(s-e)+(r-t)*(r-t)<=P)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}else{const o=((n-e)*S+(i-t)*E)/c,h=((s-e)*S+(r-t)*E)/c;if(o>0&&o<1&&h>0&&h<1&&(L+O)*(L+O)<=P*c)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}break;case 1:if(O*O<=P*(S*S+E*E)){const e=this.curveFidelityConfig.angleTolerance??A.angleTolerance;if(!(e>0))return this.addPoint(n,i,l),void this.addPoint(s,r,l);{let t=Math.abs(Math.atan2(h-r,o-s)-Math.atan2(r-i,s-n));if(t>=Math.PI&&(t=2*Math.PI-t),t<e)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}}break;case 2:if(L*L<=P*(S*S+E*E)){const o=this.curveFidelityConfig.angleTolerance??A.angleTolerance;if(!(o>0))return this.addPoint(n,i,l),void this.addPoint(s,r,l);{let h=Math.abs(Math.atan2(r-i,s-n)-Math.atan2(i-t,n-e));if(h>=Math.PI&&(h=2*Math.PI-h),h<o)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}}break;case 3:if((L+O)*(L+O)<=P*(S*S+E*E)){const c=this.curveFidelityConfig.angleTolerance??A.angleTolerance;if(!(c>0))return this.addPoint(n,i,l),void this.addPoint(s,r,l);{let d=Math.abs(Math.atan2(r-i,s-n)-Math.atan2(i-t,n-e)),u=Math.abs(Math.atan2(h-r,o-s)-Math.atan2(r-i,s-n));if(d>=Math.PI&&(d=2*Math.PI-d),u>=Math.PI&&(u=2*Math.PI-u),d+u<c)return this.addPoint(n,i,l),void this.addPoint(s,r,l)}}}this.recursiveCubic(e,t,d,u,y,x,w,b,l,c+1),this.recursiveCubic(w,b,_,v,g,m,o,h,l,c+1)}addPoint(e,t,n){const i=new Vec2(e,t);if(0===n.length)return void n.push(i);const s=n[n.length-1],r=i.x-s.x,o=i.y-s.y;r*r+o*o>1e-12&&n.push(i)}}class GlyphContourCollector{constructor(e,t){this.currentGlyphId=0,this.currentTextIndex=0,this.currentGlyphPaths=[],this.currentPath=null,this.currentPoint=null,this.currentGlyphBounds={min:new Vec2(1/0,1/0),max:new Vec2(-1/0,-1/0)},this.collectedGlyphs=[],this.glyphPositions=[],this.glyphTextIndices=[],this.currentPosition=new Vec2(0,0),this.polygonizer=new Polygonizer(e),this.pathOptimizer=new PathOptimizer({...I,...t})}setPosition(e,t){this.currentPosition.set(e,t)}updatePosition(e,t){this.currentPosition.x+=e,this.currentPosition.y+=t}beginGlyph(e,t){this.currentGlyphPaths.length>0&&this.finishGlyph(),this.currentGlyphId=e,this.currentTextIndex=t,this.currentGlyphPaths=[],this.currentGlyphBounds.min.set(1/0,1/0),this.currentGlyphBounds.max.set(-1/0,-1/0),this.glyphPositions.push(this.currentPosition.clone())}finishGlyph(){this.currentPath&&this.finishPath(),this.currentGlyphPaths.length>0&&(this.collectedGlyphs.push({glyphId:this.currentGlyphId,paths:[...this.currentGlyphPaths],bounds:{min:{x:this.currentGlyphBounds.min.x,y:this.currentGlyphBounds.min.y},max:{x:this.currentGlyphBounds.max.x,y:this.currentGlyphBounds.max.y}}}),this.glyphTextIndices.push(this.currentTextIndex)),this.currentGlyphPaths=[]}onMoveTo(e,t){this.currentPath&&this.finishPath(),this.currentPoint=new Vec2(e,t),this.updateBounds(this.currentPoint),this.currentPath={points:[this.currentPoint],glyphIndex:this.currentGlyphId}}onLineTo(e,t){if(!this.currentPath||!this.currentPoint)return;const n=new Vec2(e,t);this.updateBounds(n),this.currentPath.points.push(n),this.currentPoint=n}onQuadTo(e,t,n,i){if(!this.currentPath||!this.currentPoint)return;const s=this.currentPoint,r=new Vec2(e,t),o=new Vec2(n,i),h=o.x-s.x,l=o.y-s.y;if(Math.abs((r.x-o.x)*l-(r.y-o.y)*h)<U)return void this.onLineTo(n,i);const c=this.polygonizer.polygonizeQuadratic(s,r,o);for(const e of c)this.updateBounds(e);for(let e=0;e<c.length;e++)this.currentPath.points.push(c[e]);this.currentPoint=o}onCubicTo(e,t,n,i,s,r){if(!this.currentPath||!this.currentPoint)return;const o=this.currentPoint,h=new Vec2(e,t),l=new Vec2(n,i),c=new Vec2(s,r),d=c.x-o.x,u=c.y-o.y,f=Math.abs((h.x-c.x)*u-(h.y-c.y)*d),p=Math.abs((l.x-c.x)*u-(l.y-c.y)*d);if(f<U&&p<U)return void this.onLineTo(s,r);const g=this.polygonizer.polygonizeCubic(o,h,l,c);for(const e of g)this.updateBounds(e);for(let e=0;e<g.length;e++)this.currentPath.points.push(g[e]);this.currentPoint=c}onClosePath(){if(!this.currentPath||!this.currentPoint)return;const e=this.currentPath.points[0];this.currentPoint.equals(e)||this.currentPath.points.push(e),this.finishPath()}finishPath(){if(this.currentPath){const e=this.pathOptimizer.optimizePath(this.currentPath);this.currentGlyphPaths.push(e),this.currentPath=null,this.currentPoint=null}}updateBounds(e){this.currentGlyphBounds.min.x=Math.min(this.currentGlyphBounds.min.x,e.x),this.currentGlyphBounds.min.y=Math.min(this.currentGlyphBounds.min.y,e.y),this.currentGlyphBounds.max.x=Math.max(this.currentGlyphBounds.max.x,e.x),this.currentGlyphBounds.max.y=Math.max(this.currentGlyphBounds.max.y,e.y)}getCollectedGlyphs(){return this.currentGlyphPaths.length>0&&this.finishGlyph(),this.collectedGlyphs}getGlyphPositions(){return this.glyphPositions}getTextIndices(){return this.glyphTextIndices}reset(){this.collectedGlyphs=[],this.glyphPositions=[],this.glyphTextIndices=[],this.currentGlyphPaths=[],this.currentPath=null,this.currentPoint=null,this.currentGlyphId=0,this.currentTextIndex=0,this.currentPosition.set(0,0),this.currentGlyphBounds={min:new Vec2(1/0,1/0),max:new Vec2(-1/0,-1/0)}}setCurveFidelityConfig(e){this.polygonizer.setCurveFidelityConfig(e)}setGeometryOptimization(e){this.pathOptimizer.setConfig({...I,...e})}getOptimizationStats(){return this.pathOptimizer.getStats()}}class DrawCallbackHandler{constructor(){this.moveTo_func=null,this.lineTo_func=null,this.quadTo_func=null,this.cubicTo_func=null,this.closePath_func=null,this.drawFuncsPtr=0,this.position={x:0,y:0}}setPosition(e,t){this.position.x=e,this.position.y=t,this.collector&&this.collector.setPosition(e,t)}updatePosition(e,t){this.position.x+=e,this.position.y+=t,this.collector&&this.collector.updatePosition(e,t)}createDrawFuncs(e,t){if(!e||!e.module||!e.hb)throw new Error("Invalid font object");if(this.collector=t,this.drawFuncsPtr)return;const n=e.module;this.moveTo_func=n.addFunction((e,t,n,i,s)=>{this.collector?.onMoveTo(i,s)},"viiiffi"),this.lineTo_func=n.addFunction((e,t,n,i,s)=>{this.collector?.onLineTo(i,s)},"viiiffi"),this.quadTo_func=n.addFunction((e,t,n,i,s,r,o)=>{this.collector?.onQuadTo(i,s,r,o)},"viiiffffi"),this.cubicTo_func=n.addFunction((e,t,n,i,s,r,o,h,l)=>{this.collector?.onCubicTo(i,s,r,o,h,l)},"viiiffffffi"),this.closePath_func=n.addFunction((e,t,n)=>{this.collector?.onClosePath()},"viiii"),this.drawFuncsPtr=n.exports.hb_draw_funcs_create(),n.exports.hb_draw_funcs_set_move_to_func(this.drawFuncsPtr,this.moveTo_func,0,0),n.exports.hb_draw_funcs_set_line_to_func(this.drawFuncsPtr,this.lineTo_func,0,0),n.exports.hb_draw_funcs_set_quadratic_to_func(this.drawFuncsPtr,this.quadTo_func,0,0),n.exports.hb_draw_funcs_set_cubic_to_func(this.drawFuncsPtr,this.cubicTo_func,0,0),n.exports.hb_draw_funcs_set_close_path_func(this.drawFuncsPtr,this.closePath_func,0,0)}getDrawFuncsPtr(){if(!this.drawFuncsPtr)throw new Error("Draw functions not initialized");return this.drawFuncsPtr}destroy(e){if(!e||!e.module||!e.hb)return;const t=e.module;try{this.drawFuncsPtr&&(t.exports.hb_draw_funcs_destroy(this.drawFuncsPtr),this.drawFuncsPtr=0),null!==this.moveTo_func&&(t.removeFunction(this.moveTo_func),this.moveTo_func=null),null!==this.lineTo_func&&(t.removeFunction(this.lineTo_func),this.lineTo_func=null),null!==this.quadTo_func&&(t.removeFunction(this.quadTo_func),this.quadTo_func=null),null!==this.cubicTo_func&&(t.removeFunction(this.cubicTo_func),this.cubicTo_func=null),null!==this.closePath_func&&(t.removeFunction(this.closePath_func),this.closePath_func=null)}catch(e){n.warn("Error destroying draw callbacks:",e)}this.collector=void 0}}class GlyphGeometryBuilder{constructor(e,t){this.fontId="default",this.wordCache=new Map,this.cache=e,this.loadedFont=t,this.tessellator=new Tessellator,this.extruder=new Extruder,this.clusterer=new BoundaryClusterer,this.collector=new GlyphContourCollector,this.drawCallbacks=new DrawCallbackHandler,this.drawCallbacks.createDrawFuncs(this.loadedFont,this.collector)}getOptimizationStats(){return this.collector.getOptimizationStats()}setCurveFidelityConfig(e){this.collector.setCurveFidelityConfig(e)}setGeometryOptimization(e){this.collector.setGeometryOptimization(e)}setFontId(e){this.fontId=e}buildInstancedGeometry(e,t,n,s,r=!1){i.start("GlyphGeometryBuilder.buildInstancedGeometry",{lineCount:e.length,wordCount:e.flat().length,depth:t,removeOverlaps:n});const o=[],h=[],l=[],c=[],d={min:{x:1/0,y:1/0,z:0},max:{x:-1/0,y:-1/0,z:t}};for(let i=0;i<e.length;i++){const u=e[i];for(const e of u){const i=[];for(const t of e.glyphs)i.push(this.getContoursForGlyph(t.g));const u=e.glyphs.map(e=>new Vec3(e.x,e.y,0)),f=this.clusterer.cluster(i,u);if(!r&&f.some(e=>e.length>1)){const r=`${this.fontId}_${e.text}_${t}_${n}`;let u=this.wordCache.get(r);if(!u){const n=[];for(let t=0;t<i.length;t++){const s=i[t],r=e.glyphs[t];for(const e of s.paths)n.push({...e,points:e.points.map(e=>new Vec2(e.x+(r.x??0),e.y+(r.y??0)))})}u=this.tessellateGlyphCluster(n,t,s),this.wordCache.set(r,u)}const f=o.length/3;this.appendGeometry(o,h,l,u,e.position,f);const p=u.vertices.length/3;for(let n=0;n<e.glyphs.length;n++){const s=e.glyphs[n],r=i[n],o=new Vec3(e.position.x+(s.x??0),e.position.y+(s.y??0),e.position.z),h=this.createGlyphInfo(s,f,p,o,r,t);c.push(h),this.updatePlaneBounds(h.bounds,d)}}else for(let r=0;r<e.glyphs.length;r++){const u=e.glyphs[r],f=i[r],p=new Vec3(e.position.x+(u.x??0),e.position.y+(u.y??0),e.position.z);if(0===f.paths.length){const e=this.createGlyphInfo(u,0,0,p,f,t);c.push(e);continue}let g=this.cache.get(this.fontId,u.g,t,n);g||(g=this.tessellateGlyph(f,t,n,s),this.cache.set(this.fontId,u.g,t,n,g));const m=o.length/3;this.appendGeometry(o,h,l,g,p,m);const y=this.createGlyphInfo(u,m,g.vertices.length/3,p,f,t);c.push(y),this.updatePlaneBounds(y.bounds,d)}}}const u=new Float32Array(o),f=new Float32Array(h),p=new Uint32Array(l);return i.end("GlyphGeometryBuilder.buildInstancedGeometry"),{vertices:u,normals:f,indices:p,glyphInfos:c,planeBounds:d}}appendGeometry(e,t,n,i,s,r){for(let t=0;t<i.vertices.length;t+=3)e.push(i.vertices[t]+s.x,i.vertices[t+1]+s.y,i.vertices[t+2]+s.z);for(let e=0;e<i.normals.length;e++)t.push(i.normals[e]);for(let e=0;e<i.indices.length;e++)n.push(i.indices[e]+r)}createGlyphInfo(e,t,n,i,s,r){return{textIndex:e.absoluteTextIndex,lineIndex:e.lineIndex,vertexStart:t,vertexCount:n,bounds:{min:{x:s.bounds.min.x+i.x,y:s.bounds.min.y+i.y,z:i.z},max:{x:s.bounds.max.x+i.x,y:s.bounds.max.y+i.y,z:i.z+r}}}}getContoursForGlyph(e){this.collector.reset(),this.collector.beginGlyph(e,0),this.loadedFont.module.exports.hb_font_draw_glyph(this.loadedFont.font.ptr,e,this.drawCallbacks.getDrawFuncsPtr(),0),this.collector.finishGlyph();const t=this.collector.getCollectedGlyphs()[0];return t||{glyphId:e,paths:[],bounds:{min:{x:0,y:0},max:{x:0,y:0}}}}tessellateGlyphCluster(e,t,n){const i=this.tessellator.process(e,!0,n);return this.extrudeAndPackage(i,t)}extrudeAndPackage(e,t){const n=this.extruder.extrude(e,t,this.loadedFont.upem),i=n.vertices;let s=1/0,r=1/0,o=1/0,h=-1/0,l=-1/0,c=-1/0;for(let e=0;e<i.length;e+=3){const t=i[e],n=i[e+1],d=i[e+2];t<s&&(s=t),t>h&&(h=t),n<r&&(r=n),n>l&&(l=n),d<o&&(o=d),d>c&&(c=d)}const d=new Vec3(s,r,o),u=new Vec3(h,l,c),f=n.vertices.length/3<65536?Uint16Array:Uint32Array;return{geometry:e,vertices:new Float32Array(n.vertices),normals:new Float32Array(n.normals),indices:new f(n.indices),bounds:{min:d,max:u},useCount:1}}tessellateGlyph(e,t,n,s){i.start("GlyphGeometryBuilder.tessellateGlyph",{glyphId:e.glyphId,pathCount:e.paths.length});const r=this.tessellator.process(e.paths,n,s);return this.extrudeAndPackage(r,t)}updatePlaneBounds(e,t){const n=new Box3(new Vec3(t.min.x,t.min.y,t.min.z),new Vec3(t.max.x,t.max.y,t.max.z)),i=new Box3(new Vec3(e.min.x,e.min.y,e.min.z),new Vec3(e.max.x,e.max.y,e.max.z));n.union(i),t.min.x=n.min.x,t.min.y=n.min.y,t.min.z=n.min.z,t.max.x=n.max.x,t.max.y=n.max.y,t.max.z=n.max.z}getCacheStats(){return this.cache.getStats()}clearCache(){this.cache.clear(),this.wordCache.clear()}}class TextShaper{constructor(e,t){this.cachedSpaceWidth=new Map,this.loadedFont=e,this.geometryBuilder=t}shapeLines(e,t,n,s,r,o,h){i.start("TextShaper.shapeLines",{lineCount:e.length});const l=new Set;if(o&&"object"==typeof o&&"byText"in o&&o.byText&&h)for(const e of Object.keys(o.byText)){let t=0;for(;-1!==(t=h.indexOf(e,t));)l.add(t),l.add(t+e.length),t+=e.length}const c=[];return e.forEach((e,i)=>{const o=this.shapeLineIntoClusters(e,i,t,n,s,r,l);c.push(o)}),c}shapeLineIntoClusters(e,t,n,i,s,r,o){const h=this.loadedFont.hb.createBuffer();"rtl"===r&&h.setDirection("rtl"),h.addText(e.text),h.guessSegmentProperties(),this.loadedFont.hb.shape(this.loadedFont.font,h);const l=h.json(this.loadedFont.font);h.destroy();const c=[];let d=[],u="",f=new Vec3,p=new Vec3(e.xOffset,-t*n,0);const g=i*this.loadedFont.upem,m=this.calculateSpaceAdjustment(e,s,i);for(let n=0;n<l.length;n++){const i=l[n],s=/\s/.test(e.text[i.cl]);e.endedWithHyphen&&i.cl===e.text.length-1&&"-"===e.text[i.cl]?i.absoluteTextIndex=e.originalEnd:i.absoluteTextIndex=e.originalStart+i.cl,i.lineIndex=t;const r=o.has(i.absoluteTextIndex);(s||r)&&d.length>0&&(c.push({text:u,glyphs:d,position:f.clone()}),d=[],u="");const h=p.clone().add(new Vec3(i.dx,i.dy,0));s||(0===d.length&&f.copy(h),i.x=h.x-f.x,i.y=h.y-f.y,d.push(i),u+=e.text[i.cl]),p.x+=i.ax,p.y+=i.ay,0!==g&&n<l.length-1&&(p.x+=g),s&&(p.x+=m)}return d.length>0&&c.push({text:u,glyphs:d,position:f.clone()}),c}calculateSpaceAdjustment(e,t,n){let i=0;if(void 0!==e.adjustmentRatio&&"justify"===t&&!e.isLastLine){let t=this.cachedSpaceWidth.get(n);void 0===t&&(t=TextMeasurer.measureTextWidth(this.loadedFont," ",n),this.cachedSpaceWidth.set(n,t));const s=.5,r=h;e.adjustmentRatio>0?i=e.adjustmentRatio*t*s:e.adjustmentRatio<0&&(i=e.adjustmentRatio*t*r)}return i}clearCache(){this.geometryBuilder.clearCache()}getCacheStats(){return this.geometryBuilder.getCacheStats()}}class GlyphCache{constructor(e){this.cache=new Map,this.head=null,this.tail=null,this.stats={hits:0,misses:0,totalGlyphs:0,uniqueGlyphs:0,cacheSize:0,saved:0,memoryUsage:0},e&&(this.maxCacheSize=1024*e*1024)}getCacheKey(e,t,n,i){return`${e}_${t}_${Math.round(1e3*n)/1e3}_${i}`}has(e,t,n,i){const s=this.getCacheKey(e,t,n,i);return this.cache.has(s)}get(e,t,n,i){const s=this.getCacheKey(e,t,n,i),r=this.cache.get(s);return r?(this.stats.hits++,this.stats.saved++,r.data.useCount++,this.moveToHead(r),this.stats.totalGlyphs++,r.data):(this.stats.misses++,void this.stats.totalGlyphs++)}set(e,t,n,i,s){const r=this.getCacheKey(e,t,n,i),o=this.calculateMemoryUsage(s);this.maxCacheSize&&this.stats.memoryUsage+o>this.maxCacheSize&&this.evictLRU(o);const h={key:r,data:s,prev:null,next:null};this.cache.set(r,h),this.addToHead(h),this.stats.uniqueGlyphs=this.cache.size,this.stats.cacheSize++,this.stats.memoryUsage+=o}calculateMemoryUsage(e){let t=0;return t+=4*e.vertices.length,t+=4*e.normals.length,t+=e.indices.length*e.indices.BYTES_PER_ELEMENT,t+=24,t+=256,t}evictLRU(e){let t=0;for(;this.tail&&t<e;){const e=this.calculateMemoryUsage(this.tail.data),n=this.tail;this.removeTail(),this.cache.delete(n.key),this.stats.memoryUsage-=e,this.stats.cacheSize--,t+=e}}addToHead(e){this.head?(e.next=this.head,this.head.prev=e,this.head=e):this.head=this.tail=e}removeNode(e){e.prev?e.prev.next=e.next:this.head=e.next,e.next?e.next.prev=e.prev:this.tail=e.prev}removeTail(){this.tail&&this.removeNode(this.tail)}moveToHead(e){e!==this.head&&(this.removeNode(e),this.addToHead(e))}clear(){this.cache.clear(),this.head=null,this.tail=null,this.stats={hits:0,misses:0,totalGlyphs:0,uniqueGlyphs:0,cacheSize:0,saved:0,memoryUsage:0}}getStats(){const e=this.stats.totalGlyphs>0?this.stats.hits/this.stats.totalGlyphs*100:0;return this.stats.uniqueGlyphs=this.cache.size,{...this.stats,hitRate:e,memoryUsageMB:this.stats.memoryUsage/1048576}}}const R=new GlyphCache(250);function getDefaultExportFromCjs(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function getAugmentedNamespace(e){if(e.__esModule)return e;var t=e.default;if("function"==typeof t){var n=function a(){return this instanceof a?Reflect.construct(t,arguments,this.constructor):t.apply(this,arguments)};n.prototype=t.prototype}else n={};return Object.defineProperty(n,"__esModule",{value:!0}),Object.keys(e).forEach(function(t){var i=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(n,t,i.get?i:{enumerable:!0,get:function(){return e[t]}})}),n}var D={exports:{}};var z=getAugmentedNamespace({__proto__:null,default:{},readFileSync:()=>{throw new Error("fs not available in browser")}});!function(e){var t,n=(t="undefined"!=typeof document?document.currentScript?.src:void 0,async function(e={}){var n=e,i="object"==typeof window,s="undefined"!=typeof WorkerGlobalScope,r="object"==typeof process&&process.versions?.node&&"renderer"!=process.type,quit_=(e,t)=>{throw t};"undefined"!=typeof __filename?t=__filename:s&&(t=self.location.href);var o,h,l="";if(r){var c=z;l=__dirname+"/",h=e=>(e=isFileURI(e)?new URL(e):e,c.readFileSync(e)),o=async(e,t=!0)=>(e=isFileURI(e)?new URL(e):e,c.readFileSync(e,t?void 0:"utf8")),process.argv.length>1&&process.argv[1].replace(/\\/g,"/"),process.argv.slice(2),quit_=(e,t)=>{throw process.exitCode=e,t}}else if(i||s){try{l=new URL(".",t).href}catch{}s&&(h=e=>{var t=new XMLHttpRequest;return t.open("GET",e,!1),t.responseType="arraybuffer",t.send(null),new Uint8Array(t.response)}),o=async e=>{if(isFileURI(e))return new Promise((t,n)=>{var i=new XMLHttpRequest;i.open("GET",e,!0),i.responseType="arraybuffer",i.onload=()=>{200==i.status||0==i.status&&i.response?t(i.response):n(i.status)},i.onerror=n,i.send(null)});var t=await fetch(e,{credentials:"same-origin"});if(t.ok)return t.arrayBuffer();throw new Error(t.status+" : "+t.url)}}console.log.bind(console);var d,u,f,p,g,m,y=console.error.bind(console),x=!1,isFileURI=e=>e.startsWith("file://"),_=!1;function updateMemoryViews(){var e=g.buffer;n.HEAP8=new Int8Array(e),n.HEAPU8=m=new Uint8Array(e),n.HEAP32=new Int32Array(e),n.HEAPU32=new Uint32Array(e),n.HEAPF32=new Float32Array(e),new BigInt64Array(e),new BigUint64Array(e)}var v,w=0,b=null;function abort(e){n.onAbort?.(e),y(e="Aborted("+e+")"),x=!0,e+=". Build with -sASSERTIONS for more info.";var t=new WebAssembly.RuntimeError(e);throw p?.(t),t}function findWasmBinary(){return e="hb.wasm",n.locateFile?n.locateFile(e,l):l+e;var e}async function getWasmBinary(e){if(!d)try{var t=await o(e);return new Uint8Array(t)}catch{}return function(e){if(e==v&&d)return new Uint8Array(d);if(h)return h(e);throw"both async and sync fetching of the wasm failed"}(e)}async function instantiateAsync(e,t,n){if(!e&&!isFileURI(t)&&!r)try{var i=fetch(t,{credentials:"same-origin"});return await WebAssembly.instantiateStreaming(i,n)}catch(e){y(`wasm streaming compile failed: ${e}`),y("falling back to ArrayBuffer instantiation")}return async function(e,t){try{var n=await getWasmBinary(e);return await WebAssembly.instantiate(n,t)}catch(e){y(`failed to asynchronously prepare wasm: ${e}`),abort(e)}}(t,n)}class ExitStatus{name="ExitStatus";constructor(e){this.message=`Program terminated with exit(${e})`,this.status=e}}var S,E,L,callRuntimeCallbacks=e=>{for(;e.length>0;)e.shift()(n)},O=[],addOnPostRun=e=>O.push(e),T=[],addOnPreRun=e=>T.push(e),P=!0,F=0,C={},handleException=e=>{if(e instanceof ExitStatus||"unwind"==e)return u;quit_(1,e)},keepRuntimeAlive=()=>P||F>0,_proc_exit=e=>{u=e,keepRuntimeAlive()||(n.onExit?.(e),x=!0),quit_(e,new ExitStatus(e))},_exit=(e,t)=>{u=e,_proc_exit(e)},callUserCallback=e=>{if(!x)try{e(),(()=>{if(!keepRuntimeAlive())try{_exit(u)}catch(e){handleException(e)}})()}catch(e){handleException(e)}},alignMemory=(e,t)=>Math.ceil(e/t)*t,growMemory=e=>{var t=(e-g.buffer.byteLength+65535)/65536|0;try{return g.grow(t),updateMemoryViews(),1}catch(e){}},uleb128EncodeWithLen=e=>{const t=e.length;return[t%128|128,t>>7,...e]},B={i:127,p:127,j:126,f:125,d:124,e:111},generateTypePack=e=>uleb128EncodeWithLen(Array.from(e,e=>B[e])),getWasmTableEntry=e=>S.get(e),getFunctionAddress=e=>(E||(E=new WeakMap,((e,t)=>{if(E)for(var n=e;n<e+t;n++){var i=getWasmTableEntry(n);i&&E.set(i,n)}})(0,S.length)),E.get(e)||0),I=[],setWasmTableEntry=(e,t)=>S.set(e,t);n.noExitRuntime&&(P=n.noExitRuntime),n.print&&n.print,n.printErr&&(y=n.printErr),n.wasmBinary&&(d=n.wasmBinary),n.arguments&&n.arguments,n.thisProgram&&n.thisProgram,n.wasmMemory=g,n.wasmExports=U,n.addFunction=(e,t)=>{var n=getFunctionAddress(e);if(n)return n;var i=I.length?I.pop():S.grow(1);try{setWasmTableEntry(i,e)}catch(n){if(!(n instanceof TypeError))throw n;var s=((e,t)=>{var n=Uint8Array.of(0,97,115,109,1,0,0,0,1,...uleb128EncodeWithLen([1,96,...generateTypePack(t.slice(1)),...generateTypePack("v"===t[0]?"":t[0])]),2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0),i=new WebAssembly.Module(n);return new WebAssembly.Instance(i,{e:{f:e}}).exports.f})(e,t);setWasmTableEntry(i,s)}return E.set(e,i),i},n.removeFunction=e=>{E.delete(getWasmTableEntry(e)),setWasmTableEntry(e,null),I.push(e)};var A={_abort_js:()=>abort(""),_emscripten_runtime_keepalive_clear:()=>{P=!1,F=0},_setitimer_js:(e,t)=>{if(C[e]&&(clearTimeout(C[e].id),delete C[e]),!t)return 0;var n=setTimeout(()=>{delete C[e],callUserCallback(()=>L(e,performance.now()))},t);return C[e]={id:n,timeout_ms:t},0},emscripten_resize_heap:e=>{var t=m.length,n=2147483648;if((e>>>=0)>n)return!1;for(var i=1;i<=4;i*=2){var s=t*(1+.2/i);s=Math.min(s,e+100663296);var r=Math.min(n,alignMemory(Math.max(e,s),65536));if(growMemory(r))return!0}return!1},proc_exit:_proc_exit},U=await async function(){function receiveInstance(e,t){return U=e.exports,n.wasmExports=U,g=U.memory,n.wasmMemory=g,updateMemoryViews(),S=U.__indirect_function_table,function(e){n._hb_blob_create=e.hb_blob_create,n._hb_blob_destroy=e.hb_blob_destroy,n._hb_blob_get_length=e.hb_blob_get_length,n._hb_blob_get_data=e.hb_blob_get_data,n._hb_buffer_serialize_glyphs=e.hb_buffer_serialize_glyphs,n._hb_buffer_create=e.hb_buffer_create,n._hb_buffer_destroy=e.hb_buffer_destroy,n._hb_buffer_get_content_type=e.hb_buffer_get_content_type,n._hb_buffer_set_direction=e.hb_buffer_set_direction,n._hb_buffer_set_script=e.hb_buffer_set_script,n._hb_buffer_set_language=e.hb_buffer_set_language,n._hb_buffer_set_flags=e.hb_buffer_set_flags,n._hb_buffer_set_cluster_level=e.hb_buffer_set_cluster_level,n._hb_buffer_get_length=e.hb_buffer_get_length,n._hb_buffer_get_glyph_infos=e.hb_buffer_get_glyph_infos,n._hb_buffer_get_glyph_positions=e.hb_buffer_get_glyph_positions,n._hb_glyph_info_get_glyph_flags=e.hb_glyph_info_get_glyph_flags,n._hb_buffer_guess_segment_properties=e.hb_buffer_guess_segment_properties,n._hb_buffer_add_utf8=e.hb_buffer_add_utf8,n._hb_buffer_add_utf16=e.hb_buffer_add_utf16,n._hb_buffer_set_message_func=e.hb_buffer_set_message_func,n._hb_language_from_string=e.hb_language_from_string,n._hb_script_from_string=e.hb_script_from_string,n._hb_version=e.hb_version,n._hb_version_string=e.hb_version_string,n._hb_feature_from_string=e.hb_feature_from_string,n._malloc=e.malloc,n._free=e.free,n._hb_draw_funcs_set_move_to_func=e.hb_draw_funcs_set_move_to_func,n._hb_draw_funcs_set_line_to_func=e.hb_draw_funcs_set_line_to_func,n._hb_draw_funcs_set_quadratic_to_func=e.hb_draw_funcs_set_quadratic_to_func,n._hb_draw_funcs_set_cubic_to_func=e.hb_draw_funcs_set_cubic_to_func,n._hb_draw_funcs_set_close_path_func=e.hb_draw_funcs_set_close_path_func,n._hb_draw_funcs_create=e.hb_draw_funcs_create,n._hb_draw_funcs_destroy=e.hb_draw_funcs_destroy,n._hb_face_create=e.hb_face_create,n._hb_face_destroy=e.hb_face_destroy,n._hb_face_reference_table=e.hb_face_reference_table,n._hb_face_get_upem=e.hb_face_get_upem,n._hb_face_collect_unicodes=e.hb_face_collect_unicodes,n._hb_font_draw_glyph=e.hb_font_draw_glyph,n._hb_font_glyph_to_string=e.hb_font_glyph_to_string,n._hb_font_create=e.hb_font_create,n._hb_font_set_variations=e.hb_font_set_variations,n._hb_font_destroy=e.hb_font_destroy,n._hb_font_set_scale=e.hb_font_set_scale,n._hb_set_create=e.hb_set_create,n._hb_set_destroy=e.hb_set_destroy,n._hb_ot_var_get_axis_infos=e.hb_ot_var_get_axis_infos,n._hb_set_get_population=e.hb_set_get_population,n._hb_set_next_many=e.hb_set_next_many,n._hb_shape=e.hb_shape,L=e._emscripten_timeout}(U),function(){if(w--,n.monitorRunDependencies?.(w),0==w&&b){var e=b;b=null,e()}}(),U}w++,n.monitorRunDependencies?.(w);var e={env:A,wasi_snapshot_preview1:A};if(n.instantiateWasm)return new Promise((t,i)=>{n.instantiateWasm(e,(e,n)=>{t(receiveInstance(e))})});v??=findWasmBinary();var t=function(e){return receiveInstance(e.instance)}(await instantiateAsync(d,v,e));return t}();return function(){if(n.preInit)for("function"==typeof n.preInit&&(n.preInit=[n.preInit]);n.preInit.length>0;)n.preInit.shift()()}(),function run(){function doRun(){n.calledRun=!0,x||(_=!0,U.__wasm_call_ctors(),f?.(n),n.onRuntimeInitialized?.(),function(){if(n.postRun)for("function"==typeof n.postRun&&(n.postRun=[n.postRun]);n.postRun.length;)addOnPostRun(n.postRun.shift());callRuntimeCallbacks(O)}())}w>0?b=run:(function(){if(n.preRun)for("function"==typeof n.preRun&&(n.preRun=[n.preRun]);n.preRun.length;)addOnPreRun(n.preRun.shift());callRuntimeCallbacks(T)}(),w>0?b=run:n.setStatus?(n.setStatus("Running..."),setTimeout(()=>{setTimeout(()=>n.setStatus(""),1),doRun()},1)):doRun())}(),_?n:new Promise((e,t)=>{f=e,p=t})});e.exports=n,e.exports.default=n}(D);var G=getDefaultExportFromCjs(D.exports),k={exports:{}};try{k.exports=function(e){var t=e.wasmExports,n=new TextDecoder("utf8");let i=e.addFunction,s=e.removeFunction;var r=i(function(e){t.free(e)},"vi");function hb_tag(e){return(255&e.charCodeAt(0))<<24|(255&e.charCodeAt(1))<<16|(255&e.charCodeAt(2))<<8|255&e.charCodeAt(3)}var o=hb_tag("JSON"),h="",l=t.malloc(256);function createAsciiString(n){var i=t.malloc(n.length+1);for(let t=0;t<n.length;++t){const s=n.charCodeAt(t);if(s>127)throw new Error("Expected ASCII text");e.HEAPU8[i+t]=s}return e.HEAPU8[i+n.length]=0,{ptr:i,length:n.length,free:function(){t.free(i)}}}function shape(e,n,i){var s=0,r=0;i&&(i=i.split(","),s=t.malloc(16*i.length),i.forEach(function(e,n){var i=createAsciiString(e);t.hb_feature_from_string(i.ptr,-1,s+16*r)&&r++,i.free()})),t.hb_shape(e.ptr,n.ptr,s,r),s&&t.free(s)}return{createBlob:function(n){var i=t.malloc(n.byteLength);e.HEAPU8.set(new Uint8Array(n),i);var s=t.hb_blob_create(i,n.byteLength,2,i,r);return{ptr:s,destroy:function(){t.hb_blob_destroy(s)}}},createFace:function(n,i){var s=t.hb_face_create(n.ptr,i);const r=t.hb_face_get_upem(s);return{ptr:s,upem:r,reference_table:function(n){var i=t.hb_face_reference_table(s,hb_tag(n)),r=t.hb_blob_get_length(i);if(r){var o=t.hb_blob_get_data(i,null);return e.HEAPU8.subarray(o,o+r)}},getAxisInfos:function(){var n=t.malloc(2048),i=t.malloc(4);e.HEAPU32[i/4]=64,t.hb_ot_var_get_axis_infos(s,0,i,n);var r={};return Array.from({length:e.HEAPU32[i/4]}).forEach(function(t,i){var s;r[(s=e.HEAPU32[n/4+8*i+1],[String.fromCharCode(s>>24&255),String.fromCharCode(s>>16&255),String.fromCharCode(s>>8&255),String.fromCharCode(255&s)].join(""))]={min:e.HEAPF32[n/4+8*i+4],default:e.HEAPF32[n/4+8*i+5],max:e.HEAPF32[n/4+8*i+6]}}),t.free(i),t.free(n),r},collectUnicodes:function(){var n=t.hb_set_create();t.hb_face_collect_unicodes(s,n);var i=function(n){const i=t.hb_set_get_population(n),s=t.malloc(i<<2),r=s>>2,o=e.HEAPU32.subarray(r,r+i);return e.HEAPU32.set(o,r),t.hb_set_next_many(n,-1,s,i),o}(n);return t.hb_set_destroy(n),i},destroy:function(){t.hb_face_destroy(s)}}},createFont:function(r){var o=t.hb_font_create(r.ptr),c=null,d=null,u=null,f=null,p=null,g=null;function glyphToPath(e){return c||(d=i(function(e,t,n,i,s,r){h+=`M${i},${s}`},"viiiffi"),u=i(function(e,t,n,i,s,r){h+=`L${i},${s}`},"viiiffi"),f=i(function(e,t,n,i,s,r,o,l,c,d){h+=`C${i},${s} ${r},${o} ${l},${c}`},"viiiffffffi"),p=i(function(e,t,n,i,s,r,o,l){h+=`Q${i},${s} ${r},${o}`},"viiiffffi"),g=i(function(e,t,n,i){h+="Z"},"viiii"),c=t.hb_draw_funcs_create(),t.hb_draw_funcs_set_move_to_func(c,d,0,0),t.hb_draw_funcs_set_line_to_func(c,u,0,0),t.hb_draw_funcs_set_cubic_to_func(c,f,0,0),t.hb_draw_funcs_set_quadratic_to_func(c,p,0,0),t.hb_draw_funcs_set_close_path_func(c,g,0,0)),h="",t.hb_font_draw_glyph(o,e,c,0),h}return{ptr:o,glyphName:function(i){t.hb_font_glyph_to_string(o,i,l,256);var s=e.HEAPU8.subarray(l,l+256);return n.decode(s.slice(0,s.indexOf(0)))},glyphToPath:glyphToPath,glyphToJson:function(e){return glyphToPath(e).replace(/([MLQCZ])/g,"|$1 ").split("|").filter(function(e){return e.length}).map(function(e){var t=e.split(/[ ,]/g);return{type:t[0],values:t.slice(1).filter(function(e){return e.length}).map(function(e){return+e})}})},setScale:function(e,n){t.hb_font_set_scale(o,e,n)},setVariations:function(n){var i=Object.entries(n),s=t.malloc(8*i.length);i.forEach(function(t,n){e.HEAPU32[s/4+2*n+0]=hb_tag(t[0]),e.HEAPF32[s/4+2*n+1]=t[1]}),t.hb_font_set_variations(o,s,i.length),t.free(s)},destroy:function(){t.hb_font_destroy(o),c&&(t.hb_draw_funcs_destroy(c),c=null,s(d),s(u),s(f),s(p),s(g))}}},createBuffer:function(){var n=t.hb_buffer_create();return{ptr:n,addText:function(i){const s=function(n){const i=t.malloc(2*n.length),s=new Uint16Array(e.wasmMemory.buffer,i,n.length);for(let e=0;e<s.length;++e)s[e]=n.charCodeAt(e);return{ptr:i,length:s.length,free:function(){t.free(i)}}}(i);t.hb_buffer_add_utf16(n,s.ptr,s.length,0,s.length),s.free()},guessSegmentProperties:function(){return t.hb_buffer_guess_segment_properties(n)},setDirection:function(e){t.hb_buffer_set_direction(n,{ltr:4,rtl:5,ttb:6,btt:7}[e]||0)},setFlags:function(e){var i=0;e.forEach(function(e){i|=function(e){return"BOT"==e?1:"EOT"==e?2:"PRESERVE_DEFAULT_IGNORABLES"==e?4:"REMOVE_DEFAULT_IGNORABLES"==e?8:"DO_NOT_INSERT_DOTTED_CIRCLE"==e?16:"PRODUCE_UNSAFE_TO_CONCAT"==e?64:0}(e)}),t.hb_buffer_set_flags(n,i)},setLanguage:function(e){var i=createAsciiString(e);t.hb_buffer_set_language(n,t.hb_language_from_string(i.ptr,-1)),i.free()},setScript:function(e){var i=createAsciiString(e);t.hb_buffer_set_script(n,t.hb_script_from_string(i.ptr,-1)),i.free()},setClusterLevel:function(e){t.hb_buffer_set_cluster_level(n,e)},json:function(){for(var i=t.hb_buffer_get_length(n),s=[],r=t.hb_buffer_get_glyph_infos(n,0),o=r/4,h=t.hb_buffer_get_glyph_positions(n,0)/4,l=e.HEAPU32.subarray(o,o+5*i),c=e.HEAP32.subarray(h,h+5*i),d=0;d<i;++d)s.push({g:l[5*d+0],cl:l[5*d+2],ax:c[5*d+0],ay:c[5*d+1],dx:c[5*d+2],dy:c[5*d+3],flags:t.hb_glyph_info_get_glyph_flags(r+20*d)});return s},destroy:function(){t.hb_buffer_destroy(n)}}},shape:shape,shapeWithTrace:function(r,h,l,c,d){var u=[],f=0,p=!1,g=1048576,m=t.malloc(g),y=i(function(i,s,r,h){var l=n.decode(e.HEAPU8.subarray(r,e.HEAPU8.indexOf(0,r)));return l.startsWith("start table GSUB")?f=1:l.startsWith("start table GPOS")&&(f=2),f!=d&&(p=!1),0!=d&&f==d&&l.startsWith("end lookup "+c)&&(p=!0),p?0:(t.hb_buffer_serialize_glyphs(i,0,t.hb_buffer_get_length(i),m,g,0,s,o,4),u.push({m:l,t:JSON.parse(n.decode(e.HEAPU8.subarray(m,e.HEAPU8.indexOf(0,m)))),glyphs:2==t.hb_buffer_get_content_type(i)}),1)},"iiiii");return t.hb_buffer_set_message_func(h.ptr,y,0,0),shape(r,h,l),t.free(m),s(y),u},version:function(){var n=t.malloc(12);t.hb_version(n,n+4,n+8);var i={major:e.HEAPU32[n/4],minor:e.HEAPU32[(n+4)/4],micro:e.HEAPU32[(n+8)/4]};return t.free(n),i},version_string:function(){var i=t.hb_version_string();return n.decode(e.HEAPU8.subarray(i,e.HEAPU8.indexOf(0,i)))}}}}catch(e){}var M=getDefaultExportFromCjs(k.exports);let N=null,H=null,V=null;const W={setWasmPath(e){H=e,V=null,N=null},setWasmBuffer(e){V=e,H=null,N=null},getHarfBuzz:async()=>N||(N=new Promise(async(e,t)=>{try{const t={};if(V)t.wasmBinary=V;else{if(!H)throw new Error("HarfBuzz WASM path or buffer must be set before initialization.");t.locateFile=(e,t)=>e.endsWith(".wasm")?H:t+e}const n=await G(t),i=M(n);e({hb:i,module:{addFunction:n.addFunction,exports:n.wasmExports,removeFunction:n.removeFunction}})}catch(e){t(new Error(`Failed to initialize HarfBuzz: ${e}`))}}),N)};class TextRangeQuery{constructor(e,t){this.text=e,this.glyphsByTextIndex=new Map,t.forEach(e=>{const t=this.glyphsByTextIndex.get(e.textIndex)||[];t.push(e),this.glyphsByTextIndex.set(e.textIndex,t)})}execute(e){const t=[];return e.byText&&t.push(...this.findByText(e.byText)),e.byCharRange&&t.push(...this.findByCharRange(e.byCharRange)),t}findByText(e){const t=[];for(const n of e){let e=0;for(;-1!==(e=this.text.indexOf(n,e));)t.push(this.createTextRange(e,e+n.length,n)),e+=n.length}return t}findByCharRange(e){return e.map(e=>{const t=this.text.slice(e.start,e.end);return this.createTextRange(e.start,e.end,t)})}createTextRange(e,t,n){const i=[],s=new Map;for(let n=e;n<t;n++){const e=this.glyphsByTextIndex.get(n);if(e)for(const t of e){i.push(t);const e=s.get(t.lineIndex)||[];e.push(t),s.set(t.lineIndex,e)}}return{start:e,end:t,originalText:n,bounds:Array.from(s.values()).map(e=>this.calculateBounds(e)),glyphs:i,lineIndices:Array.from(s.keys()).sort((e,t)=>e-t)}}calculateBounds(e){if(0===e.length)return{min:{x:0,y:0,z:0},max:{x:0,y:0,z:0}};const t=new Box3;for(const n of e){const e=new Box3(new Vec3(n.bounds.min.x,n.bounds.min.y,n.bounds.min.z),new Vec3(n.bounds.max.x,n.bounds.max.y,n.bounds.max.z));t.union(e)}return{min:{x:t.min.x,y:t.min.y,z:t.min.z},max:{x:t.max.x,y:t.max.y,z:t.max.z}}}}class Text{static{this.patternCache=new Map}static{this.hbInitPromise=null}static{this.fontCache=new Map}static{this.fontIdCounter=0}constructor(e){this.currentFontId="",Text.hbInitPromise||(Text.hbInitPromise=W.getHarfBuzz()),this.fontLoader=new FontLoader(()=>Text.hbInitPromise)}static setHarfBuzzPath(e){W.setWasmPath(e),Text.hbInitPromise=null}static setHarfBuzzBuffer(e){W.setWasmBuffer(e),Text.hbInitPromise=null}static init(){return Text.hbInitPromise||(Text.hbInitPromise=W.getHarfBuzz()),Text.hbInitPromise}static async create(e){if(!e.font)throw new Error("Font is required. Specify options.font as a URL string or ArrayBuffer.");Text.hbInitPromise||(Text.hbInitPromise=W.getHarfBuzz());const t="string"==typeof e.font?e.font:`buffer-${Text.generateFontContentHash(e.font)}`,n=e.fontVariations?`${t}_${JSON.stringify(e.fontVariations)}`:t;let i=Text.fontCache.get(n);i||(i=await Text.loadAndCacheFont(n,e.font,e.fontVariations));const s=new Text({maxCacheSizeMB:e.maxCacheSizeMB});s.setLoadedFont(i);const{font:r,maxCacheSizeMB:o,...h}=e;return{...await s.createGeometry(h),getLoadedFont:()=>s.getLoadedFont(),getCacheStatistics:()=>s.getCacheStatistics(),clearCache:()=>s.clearCache(),measureTextWidth:(e,t)=>s.measureTextWidth(e,t)}}static async loadAndCacheFont(e,t,n){const i=new Text;await i.loadFont(t,n);const s=i.getLoadedFont();return Text.fontCache.set(e,s),s}static generateFontContentHash(e){if(e){const t=new Uint8Array(e);return`${t[0]}_${t[Math.floor(t.length/2)]}_${t[t.length-1]}_${t.length}`}return""+ ++Text.fontIdCounter}setLoadedFont(e){this.loadedFont=e;const t=Text.generateFontContentHash(e._buffer);this.currentFontId=`font_${t}`,e.fontVariations&&(this.currentFontId+=`_${JSON.stringify(e.fontVariations)}`)}async loadFont(e,t){i.start("Text.loadFont",{fontSrc:"string"==typeof e?e:`buffer(${e.byteLength})`}),Text.hbInitPromise||(Text.hbInitPromise=W.getHarfBuzz()),await Text.hbInitPromise;const s="string"==typeof e?await fetch(e).then(t=>{if(!t.ok)throw new Error(`Failed to load font from ${e}: HTTP ${t.status} ${t.statusText}`);return t.arrayBuffer()}):e;try{this.loadedFont&&this.destroy(),this.loadedFont=await this.fontLoader.loadFont(s,t);const e=Text.generateFontContentHash(s);this.currentFontId=`font_${e}`,t&&(this.currentFontId+=`_${JSON.stringify(t)}`)}catch(e){throw n.error("Failed to load font:",e),e}finally{i.end("Text.loadFont")}}async createGeometry(e){i.start("Text.createGeometry",{textLength:e.text.length,size:e.size||72,hasLayout:!!e.layout,mode:"cached"});try{if(!this.loadedFont)throw new Error("Font not loaded. Use Text.create() with a font option.");const t=await this.prepareHyphenation(e);if(this.validateOptions(t),e=t,this.updateFontVariations(e),!this.geometryBuilder){const t=e.maxCacheSizeMB?new GlyphCache(e.maxCacheSizeMB):R;this.geometryBuilder=new GlyphGeometryBuilder(t,this.loadedFont),this.geometryBuilder.setFontId(this.currentFontId)}this.geometryBuilder.setCurveFidelityConfig(e.curveFidelity),this.geometryBuilder.setGeometryOptimization(e.geometryOptimization),this.loadedFont.font.setScale(this.loadedFont.upem,this.loadedFont.upem),this.textShaper||(this.textShaper=new TextShaper(this.loadedFont,this.geometryBuilder));const n=this.prepareLayout(e),i=e.removeOverlaps??this.loadedFont.isVariable??!1,s=this.textShaper.shapeLines(n.lines,n.scaledLineHeight,n.letterSpacing,n.align,n.direction,e.color,e.text),r=this.geometryBuilder.buildInstancedGeometry(s,n.depth,i,this.loadedFont.metrics.isCFF,e.separateGlyphsWithAttributes||!1),o=this.geometryBuilder.getCacheStats(),h=this.finalizeGeometry(r.vertices,r.normals,r.indices,r.glyphInfos,r.planeBounds,e,o,e.text);if(e.separateGlyphsWithAttributes){const e=this.createGlyphAttributes(h.vertices.length/3,h.glyphs);h.glyphAttributes=e}return h}finally{i.end("Text.createGeometry")}}async prepareHyphenation(e){if(!1!==e.layout?.hyphenate&&e.layout?.width){const t=e.layout?.language||"en-us";if(!e.layout?.hyphenationPatterns?.[t])try{if(!Text.patternCache.has(t)){const n=await loadPattern(t,e.layout?.patternsPath);Text.patternCache.set(t,n)}return{...e,layout:{...e.layout,hyphenationPatterns:{...e.layout?.hyphenationPatterns,[t]:Text.patternCache.get(t)}}}}catch(i){return n.warn(`Failed to load patterns for ${t}: ${i}`),{...e,layout:{...e.layout,hyphenate:!1}}}}return e}validateOptions(e){if(!e.text)throw new Error("Text content is required");const t=e.maxTextLength??1e5;if(e.text.length>t)throw new Error(`Text exceeds ${t} character limit`)}updateFontVariations(e){e.fontVariations&&this.loadedFont&&JSON.stringify(e.fontVariations)!==JSON.stringify(this.loadedFont.fontVariations)&&(this.loadedFont.font.setVariations(e.fontVariations),this.loadedFont.fontVariations=e.fontVariations)}prepareLayout(e){if(!this.loadedFont)throw new Error("Font not loaded. Use Text.create() with a font option");const{text:t,size:n=72,depth:i=0,lineHeight:h=1,letterSpacing:l=0,layout:c={}}=e,{width:d,direction:u="ltr",align:f=("rtl"===u?"right":"left"),respectExistingBreaks:p=!0,hyphenate:g=!0,language:m="en-us",tolerance:y=s,pretolerance:x=r,emergencyStretch:_=o,autoEmergencyStretch:v,hyphenationPatterns:w,lefthyphenmin:b,righthyphenmin:S,linepenalty:E,adjdemerits:L,hyphenpenalty:O,exhyphenpenalty:T,doublehyphendemerits:P,looseness:F,disableSingleWordDetection:C}=c;let B;void 0!==d&&(B=d*(this.loadedFont.upem/n));const I=i*(this.loadedFont.upem/n);this.textLayout||(this.textLayout=new TextLayout(this.loadedFont));const A=this.textLayout.computeLines({text:t,width:B,align:f,direction:u,hyphenate:g,language:m,respectExistingBreaks:p,tolerance:y,pretolerance:x,emergencyStretch:_,autoEmergencyStretch:v,hyphenationPatterns:w,lefthyphenmin:b,righthyphenmin:S,linepenalty:E,adjdemerits:L,hyphenpenalty:O,exhyphenpenalty:T,doublehyphendemerits:P,looseness:F,disableSingleWordDetection:C,letterSpacing:l}),U=FontMetadataExtractor.getVerticalMetrics(this.loadedFont.metrics),R=(U.ascender-U.descender)*h;return{lines:A.lines,scaledLineHeight:R,letterSpacing:l,align:f,direction:u,depth:I,size:n}}applyColorSystem(e,t,n,i){const s=e.length/3,r=new Float32Array(3*s),o=[];if(Array.isArray(n)){for(let e=0;e<s;e++){const t=3*e;r[t]=n[0],r[t+1]=n[1],r[t+2]=n[2]}o.push({start:0,end:i.length,originalText:i,color:n,bounds:[],glyphs:t,lineIndices:[...new Set(t.map(e=>e.lineIndex))]})}else{const e=n.default||[1,1,1];for(let t=0;t<r.length;t+=3)r[t]=e[0],r[t+1]=e[1],r[t+2]=e[2];if(n.byText){new TextRangeQuery(i,t).execute({byText:Object.keys(n.byText)}).forEach(e=>{const t=n.byText[e.originalText];t&&(e.glyphs.forEach(e=>{for(let n=0;n<e.vertexCount;n++){const i=3*(e.vertexStart+n);i>=0&&i<r.length&&(r[i]=t[0],r[i+1]=t[1],r[i+2]=t[2])}}),o.push({start:e.start,end:e.end,originalText:e.originalText,color:t,bounds:e.bounds,glyphs:e.glyphs,lineIndices:e.lineIndices}))})}n.byCharRange&&n.byCharRange.forEach(e=>{const n=[];for(const i of t)if(i.textIndex>=e.start&&i.textIndex<e.end){n.push(i);for(let t=0;t<i.vertexCount;t++){const n=3*(i.vertexStart+t);n>=0&&n<r.length&&(r[n]=e.color[0],r[n+1]=e.color[1],r[n+2]=e.color[2])}}o.push({start:e.start,end:e.end,originalText:i.slice(e.start,e.end),color:e.color,bounds:[],glyphs:n,lineIndices:[...new Set(n.map(e=>e.lineIndex))]})})}return{colors:r,coloredRanges:o}}finalizeGeometry(e,t,n,i,s,r,o,h){const{layout:l={},size:c=72}=r,{width:d,align:u=("rtl"===l.direction?"right":"left")}=l;this.textLayout||(this.textLayout=new TextLayout(this.loadedFont));const f=this.textLayout.applyAlignment(e,{width:d,align:u,planeBounds:s}),p=f.offset;s.min.x=f.adjustedBounds.min.x,s.max.x=f.adjustedBounds.max.x;const g=c/this.loadedFont.upem;for(let t=0;t<e.length;t++)e[t]*=g;s.min.x*=g,s.min.y*=g,s.min.z*=g,s.max.x*=g,s.max.y*=g,s.max.z*=g;for(let e=0;e<i.length;e++){const t=i[e];0!==p&&(t.bounds.min.x+=p,t.bounds.max.x+=p),t.bounds.min.x*=g,t.bounds.min.y*=g,t.bounds.min.z*=g,t.bounds.max.x*=g,t.bounds.max.y*=g,t.bounds.max.z*=g}let m,y;if(r.color){const t=this.applyColorSystem(e,i,r.color,r.text);m=t.colors,y=t.coloredRanges}const x=this.geometryBuilder.getOptimizationStats(),_=n.length/3,v=e.length/3;return{vertices:e,normals:t,indices:n,colors:m,glyphs:i,planeBounds:s,stats:{trianglesGenerated:_,verticesGenerated:v,pointsRemovedByVisvalingam:x.pointsRemovedByVisvalingam,pointsRemovedByColinear:x.pointsRemovedByColinear,originalPointCount:x.originalPointCount,...o||{}},query:e=>{if(!h)throw new Error("Original text not available for querying");return new TextRangeQuery(h,i).execute(e)},coloredRanges:y,glyphAttributes:void 0}}getFontMetrics(){if(!this.loadedFont)throw new Error("Font not loaded. Call loadFont() first");return FontMetadataExtractor.getFontMetrics(this.loadedFont.metrics)}static async preloadPatterns(e,t){await Promise.all(e.map(async e=>{if(!Text.patternCache.has(e))try{const n=await loadPattern(e,t);Text.patternCache.set(e,n)}catch(t){n.warn(`Failed to pre-load patterns for ${e}: ${t}`)}}))}static registerPattern(e,t){Text.patternCache.set(e,t)}getLoadedFont(){return this.loadedFont}measureTextWidth(e,t=0){if(!this.loadedFont)throw new Error("Font not loaded. Call loadFont() first");return TextMeasurer.measureTextWidth(this.loadedFont,e,t)}getCacheStatistics(){return this.geometryBuilder?this.geometryBuilder.getCacheStats():null}clearCache(){this.geometryBuilder&&this.geometryBuilder.clearCache()}createGlyphAttributes(e,t){const n=new Float32Array(3*e),i=new Float32Array(e),s=new Float32Array(e);return t.forEach((t,r)=>{const o=(t.bounds.min.x+t.bounds.max.x)/2,h=(t.bounds.min.y+t.bounds.max.y)/2,l=(t.bounds.min.z+t.bounds.max.z)/2;for(let c=0;c<t.vertexCount;c++){const d=t.vertexStart+c;d<e&&(n[3*d]=o,n[3*d+1]=h,n[3*d+2]=l,i[d]=r,s[d]=t.lineIndex)}}),{glyphCenter:n,glyphIndex:i,glyphLineIndex:s}}destroy(){if(!this.loadedFont)return;const e=this.loadedFont;try{FontLoader.destroyFont(e)}catch(e){n.warn("Error destroying HarfBuzz objects:",e)}finally{this.loadedFont=void 0,this.textLayout=void 0,this.textShaper=void 0}}}e.DEFAULT_CURVE_FIDELITY=A,e.FontMetadataExtractor=FontMetadataExtractor,e.Text=Text,e.globalGlyphCache=R});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-text",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
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",