three-text 0.3.2 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.umd.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * three-text v0.3.2
2
+ * three-text v0.3.3
3
3
  * Copyright (C) 2025 Countertype LLC
4
4
  *
5
5
  * This program is free software: you can redistribute it and/or modify
@@ -5871,8 +5871,10 @@
5871
5871
  colors[i + 1] = defaultColor[1];
5872
5872
  colors[i + 2] = defaultColor[2];
5873
5873
  }
5874
- if (color.byText && byTextMatches) {
5875
- const glyphsByTextIndex = new Map();
5874
+ // Build glyph index once for both byText and byCharRange
5875
+ let glyphsByTextIndex;
5876
+ if ((color.byText && byTextMatches) || color.byCharRange) {
5877
+ glyphsByTextIndex = new Map();
5876
5878
  for (const glyph of glyphInfoArray) {
5877
5879
  const existing = glyphsByTextIndex.get(glyph.textIndex);
5878
5880
  if (existing) {
@@ -5882,18 +5884,26 @@
5882
5884
  glyphsByTextIndex.set(glyph.textIndex, [glyph]);
5883
5885
  }
5884
5886
  }
5887
+ }
5888
+ if (color.byText && byTextMatches && glyphsByTextIndex) {
5885
5889
  for (const match of byTextMatches) {
5886
5890
  const targetColor = color.byText[match.pattern];
5887
5891
  if (!targetColor)
5888
5892
  continue;
5889
5893
  const matchGlyphs = [];
5890
- const lineIndicesSet = new Set();
5894
+ const lineGroups = new Map();
5891
5895
  for (let i = match.start; i < match.end; i++) {
5892
5896
  const glyphs = glyphsByTextIndex.get(i);
5893
5897
  if (glyphs) {
5894
5898
  for (const glyph of glyphs) {
5895
5899
  matchGlyphs.push(glyph);
5896
- lineIndicesSet.add(glyph.lineIndex);
5900
+ const lineGlyphs = lineGroups.get(glyph.lineIndex);
5901
+ if (lineGlyphs) {
5902
+ lineGlyphs.push(glyph);
5903
+ }
5904
+ else {
5905
+ lineGroups.set(glyph.lineIndex, [glyph]);
5906
+ }
5897
5907
  for (let v = 0; v < glyph.vertexCount; v++) {
5898
5908
  const vertexIndex = (glyph.vertexStart + v) * 3;
5899
5909
  if (vertexIndex >= 0 && vertexIndex < colors.length) {
@@ -5905,48 +5915,91 @@
5905
5915
  }
5906
5916
  }
5907
5917
  }
5918
+ // Calculate bounds per line for collision detection
5919
+ const bounds = Array.from(lineGroups.values()).map((lineGlyphs) => this.calculateGlyphBounds(lineGlyphs));
5908
5920
  coloredRanges.push({
5909
5921
  start: match.start,
5910
5922
  end: match.end,
5911
5923
  originalText: match.pattern,
5912
5924
  color: targetColor,
5913
- bounds: [],
5925
+ bounds,
5914
5926
  glyphs: matchGlyphs,
5915
- lineIndices: Array.from(lineIndicesSet).sort((a, b) => a - b)
5927
+ lineIndices: Array.from(lineGroups.keys()).sort((a, b) => a - b)
5916
5928
  });
5917
5929
  }
5918
5930
  }
5919
5931
  // Apply range coloring
5920
- if (color.byCharRange) {
5921
- color.byCharRange.forEach((range) => {
5932
+ if (color.byCharRange && glyphsByTextIndex) {
5933
+ for (const range of color.byCharRange) {
5922
5934
  const rangeGlyphs = [];
5923
- for (const glyph of glyphInfoArray) {
5924
- if (glyph.textIndex >= range.start && glyph.textIndex < range.end) {
5925
- rangeGlyphs.push(glyph);
5926
- for (let i = 0; i < glyph.vertexCount; i++) {
5927
- const vertexIndex = (glyph.vertexStart + i) * 3;
5928
- if (vertexIndex >= 0 && vertexIndex < colors.length) {
5929
- colors[vertexIndex] = range.color[0];
5930
- colors[vertexIndex + 1] = range.color[1];
5931
- colors[vertexIndex + 2] = range.color[2];
5935
+ const lineGroups = new Map();
5936
+ for (let i = range.start; i < range.end; i++) {
5937
+ const glyphs = glyphsByTextIndex.get(i);
5938
+ if (glyphs) {
5939
+ for (const glyph of glyphs) {
5940
+ rangeGlyphs.push(glyph);
5941
+ const lineGlyphs = lineGroups.get(glyph.lineIndex);
5942
+ if (lineGlyphs) {
5943
+ lineGlyphs.push(glyph);
5944
+ }
5945
+ else {
5946
+ lineGroups.set(glyph.lineIndex, [glyph]);
5947
+ }
5948
+ for (let v = 0; v < glyph.vertexCount; v++) {
5949
+ const vertexIndex = (glyph.vertexStart + v) * 3;
5950
+ if (vertexIndex >= 0 && vertexIndex < colors.length) {
5951
+ colors[vertexIndex] = range.color[0];
5952
+ colors[vertexIndex + 1] = range.color[1];
5953
+ colors[vertexIndex + 2] = range.color[2];
5954
+ }
5932
5955
  }
5933
5956
  }
5934
5957
  }
5935
5958
  }
5959
+ // Calculate bounds per line for collision detection
5960
+ const bounds = Array.from(lineGroups.values()).map((lineGlyphs) => this.calculateGlyphBounds(lineGlyphs));
5936
5961
  coloredRanges.push({
5937
5962
  start: range.start,
5938
5963
  end: range.end,
5939
5964
  originalText: originalText.slice(range.start, range.end),
5940
5965
  color: range.color,
5941
- bounds: [], // Would calculate from glyphs if needed
5966
+ bounds,
5942
5967
  glyphs: rangeGlyphs,
5943
- lineIndices: [...new Set(rangeGlyphs.map((g) => g.lineIndex))]
5968
+ lineIndices: Array.from(lineGroups.keys()).sort((a, b) => a - b)
5944
5969
  });
5945
- });
5970
+ }
5946
5971
  }
5947
5972
  }
5948
5973
  return { colors, coloredRanges };
5949
5974
  }
5975
+ calculateGlyphBounds(glyphs) {
5976
+ if (glyphs.length === 0) {
5977
+ return {
5978
+ min: { x: 0, y: 0, z: 0 },
5979
+ max: { x: 0, y: 0, z: 0 }
5980
+ };
5981
+ }
5982
+ let minX = Infinity, minY = Infinity, minZ = Infinity;
5983
+ let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;
5984
+ for (const glyph of glyphs) {
5985
+ if (glyph.bounds.min.x < minX)
5986
+ minX = glyph.bounds.min.x;
5987
+ if (glyph.bounds.min.y < minY)
5988
+ minY = glyph.bounds.min.y;
5989
+ if (glyph.bounds.min.z < minZ)
5990
+ minZ = glyph.bounds.min.z;
5991
+ if (glyph.bounds.max.x > maxX)
5992
+ maxX = glyph.bounds.max.x;
5993
+ if (glyph.bounds.max.y > maxY)
5994
+ maxY = glyph.bounds.max.y;
5995
+ if (glyph.bounds.max.z > maxZ)
5996
+ maxZ = glyph.bounds.max.z;
5997
+ }
5998
+ return {
5999
+ min: { x: minX, y: minY, z: minZ },
6000
+ max: { x: maxX, y: maxY, z: maxZ }
6001
+ };
6002
+ }
5950
6003
  finalizeGeometry(vertices, normals, indices, glyphInfoArray, planeBounds, options, originalText, byTextMatches) {
5951
6004
  const { layout = {} } = options;
5952
6005
  const { width, align = layout.direction === 'rtl' ? 'right' : 'left' } = layout;
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * three-text v0.3.2
2
+ * three-text v0.3.3
3
3
  * Copyright (C) 2025 Countertype LLC
4
4
  *
5
5
  * This program is free software: you can redistribute it and/or modify
@@ -128,18 +128,18 @@ i.forEach(t=>{t.Ct+=s,t.Dt+=s}),n.push(...i)}s+=e.length+1}return n}let W=r
128
128
  !W||y&&y[o]||(h.warn(`Hyphenation patterns for ${o} not available`),W=!1)
129
129
  let R=I
130
130
  void 0!==F&&i?R=i*F:!W&&I===u&&i&&(R=.1*i)
131
- const j={Ut:k,$t:C,Wt:N,lt:D,ht:B,Rt:n,vt:p,jt:p?b*p:0}
131
+ const z={Ut:k,$t:C,Wt:N,lt:D,ht:B,Rt:n,vt:p,zt:p?b*p:0}
132
132
  if(!i||i===1/0){const t=f(e)
133
- return[{text:e,Ct:0,Dt:e.length-1,Bt:0,Nt:!0,naturalWidth:t,Pt:!1}]}const z=A.H(e,f,d,!1,o,y,G,O,j)
134
- if(0===z.length)return[]
133
+ return[{text:e,Ct:0,Dt:e.length-1,Bt:0,Nt:!0,naturalWidth:t,Pt:!1}]}const j=A.H(e,f,d,!1,o,y,G,O,z)
134
+ if(0===j.length)return[]
135
135
  let H=0,V=R,q=null
136
136
  const Y=!U
137
- for(;5>H;){let t=z,r=A.zt(t,i,M,P,!1,0,j)
138
- if(0===r.length&&W&&(t=A.H(e,f,d,!0,o,y,G,O,j),r=A.zt(t,i,L,P,!1,0,j)),0===r.length&&(V=R+H*i*.1,r=A.zt(t,i,L,P,!0,V,j)),0===r.length&&(r=A.zt(t,i,E,P,!0,V,j)),r.length>0){const o=A.Ht(t)
139
- if(q=A.Vt(e,t,r,i,n,s,o,j),Y&&r.length>1&&A.ut(t,r,i,$)){H++
137
+ for(;5>H;){let t=j,r=A.jt(t,i,M,P,!1,0,z)
138
+ if(0===r.length&&W&&(t=A.H(e,f,d,!0,o,y,G,O,z),r=A.jt(t,i,L,P,!1,0,z)),0===r.length&&(V=R+H*i*.1,r=A.jt(t,i,L,P,!0,V,z)),0===r.length&&(r=A.jt(t,i,E,P,!0,V,z)),r.length>0){const o=A.Ht(t)
139
+ if(q=A.Vt(e,t,r,i,n,s,o,z),Y&&r.length>1&&A.ut(t,r,i,$)){H++
140
140
  continue}break}break}if(q&&q.length>0)return q
141
141
  const J=f(e)
142
- return[{text:e,Ct:0,Dt:e.length-1,Bt:0,qt:0,Nt:!0,naturalWidth:J,Pt:!1}]}static zt(t,e,i=1/0,n=0,s=!1,r=0,o){const a=A.Ht(t),h=new p,c={value:1/0}
142
+ return[{text:e,Ct:0,Dt:e.length-1,Bt:0,qt:0,Nt:!0,naturalWidth:J,Pt:!1}]}static jt(t,e,i=1/0,n=0,s=!1,r=0,o){const a=A.Ht(t),h=new p,c={value:1/0}
143
143
  h.F({position:0,line:0,G:y.NORMAL,O:0,D:0,k:null,active:!0})
144
144
  for(let n=0;t.length>n;n++){const l=t[n]
145
145
  l.type===d.PENALTY&&1/0>l.J&&A.Yt(t,h,n,e,i,r,a,o,s,c),l.type===d.DISCRETIONARY&&1/0>l.J&&A.Yt(t,h,n,e,i,r,a,o,s,c),l.type===d.GLUE&&n>0&&t[n-1].type===d.BOX&&A.Yt(t,h,n,e,i,r,a,o,s,c),A.Jt(h,n,e,a.Kt)}const l=[]
@@ -175,7 +175,7 @@ k?k.O>O&&(k.O=O,k.k=y,k.D=x):e.F({position:i,line:y.line+1,G:E,O,D:x,k:y,active:
175
175
  if(r){a=r.te[i]-r.te[e],h=r.ee[i]-r.ee[e],c=r.ie[i]-r.ie[e]
176
176
  for(let n=e;i>n;n++){const e=t[n]
177
177
  e.type===d.PENALTY&&(a-=e.width)}}else for(let n=e;i>n;n++){const e=t[n]
178
- e.type!==d.PENALTY&&(a+=e.width,e.type===d.GLUE&&(h+=e.stretch,c+=e.q))}i>=t.length||t[i].type!==d.PENALTY&&t[i].type!==d.DISCRETIONARY||(a+=t[i].type===d.PENALTY?t[i].width:t[i].ot),o?.jt&&0!==a&&(a-=o.jt)
178
+ e.type!==d.PENALTY&&(a+=e.width,e.type===d.GLUE&&(h+=e.stretch,c+=e.q))}i>=t.length||t[i].type!==d.PENALTY&&t[i].type!==d.DISCRETIONARY||(a+=t[i].type===d.PENALTY?t[i].width:t[i].ot),o?.zt&&0!==a&&(a-=o.zt)
179
179
  const l=s-a
180
180
  let u
181
181
  return u=l>0&&h>0?l/h:0>l&&c>0?l/c:0===l?0:l>0?3:-1,{ratio:u,Qt:l,stretch:h,q:c,D:a}}static Zt(t,e){return e?t>12?t>99?y.VERY_LOOSE:y.LOOSE:y.NORMAL:t>12?y.TIGHT:y.NORMAL}static Ht(t){const e=t.length+1,i=Array(e),n=Array(e),s=Array(e),r=Array(e)
@@ -198,13 +198,13 @@ let v=!1
198
198
  if(e.length>l)if(g.type===d.PENALTY&&g.ct)f.push("-"),w+=g.width,v=!0,void 0!==g.Y&&(p=g.Y-1)
199
199
  else if(g.type===d.DISCRETIONARY){const t=g
200
200
  t.nt&&(f.push(t.nt),w+=t.ot,v=t.ct||!1,void 0!==g.Y&&(p=g.Y-1))}const m=f.join("")
201
- a?.jt&&0!==w&&(w-=a.jt)
201
+ a?.zt&&0!==w&&(w-=a.zt)
202
202
  let x=0,b=0,S=s
203
203
  "justify"===s&&u&&(S="rtl"===r?"right":"left"),"center"===S?x=(n-w)/2:"right"===S?x=n-w:"justify"!==S||u||(b=A.Xt(e,c,l,t,n,o,a).ratio),h.push({text:m,Ct:y,Dt:p,Bt:x,qt:b,Nt:!1,naturalWidth:w,Pt:v}),c=l+1}if(e.length-1>c){const t=[]
204
204
  let i=-1,o=-1,l=0
205
205
  for(let n=c;e.length-1>n;n++){const s=e[n]
206
206
  s.type!==d.PENALTY&&(void 0!==s.Y&&((-1===i||i>s.Y)&&(i=s.Y),s.Y>o&&(o=s.Y)),s.text&&t.push(s.text),l+=s.width)}const u=t.join("")
207
- a?.jt&&0!==l&&(l-=a.jt)
207
+ a?.zt&&0!==l&&(l-=a.zt)
208
208
  let f=0,y=s
209
209
  "justify"===s&&(y="rtl"===r?"right":"left"),"center"===y?f=(n-l)/2:"right"===y&&(f=n-l),h.push({text:u,Ct:i,Dt:o,Bt:f,qt:0,Nt:!0,naturalWidth:l,Pt:!1}),h.length>1&&(h[h.length-2].Nt=!1),h[h.length-1].Nt=!0}else h.length>0&&(h[h.length-1].Nt=!0)
210
210
  return h}}const L=new WeakMap
@@ -239,8 +239,8 @@ if(0!==i)for(let e=0;t.length>e;e+=3)t[e]+=i
239
239
  return{offset:i,le:n}}ue(t){const{width:e,align:i,planeBounds:n}=t
240
240
  let s=0
241
241
  const r={min:{...n.min},max:{...n.max}}
242
- return!e||"center"!==i&&"right"!==i||(s="center"===i?(e-(n.max.x-n.min.x))/2-n.min.x:e-n.max.x),0!==s&&(r.min.x+=s,r.max.x+=s),{offset:s,le:r}}}const F=65536,G=1330926671,O=2001684038,k=1751474532,C=1751672161,D=1330851634,B=1719034226,N=1398030676,P=1851878757,U=1128678944,$=1128678962,W=1196643650,R=1196445523,j=new TextDecoder("utf-16be")
243
- class z{static fe(t){if(!t||12>t.byteLength)throw Error("Invalid font buffer: too small to be a valid font file")
242
+ return!e||"center"!==i&&"right"!==i||(s="center"===i?(e-(n.max.x-n.min.x))/2-n.min.x:e-n.max.x),0!==s&&(r.min.x+=s,r.max.x+=s),{offset:s,le:r}}}const F=65536,G=1330926671,O=2001684038,k=1751474532,C=1751672161,D=1330851634,B=1719034226,N=1398030676,P=1851878757,U=1128678944,$=1128678962,W=1196643650,R=1196445523,z=new TextDecoder("utf-16be")
243
+ class j{static fe(t){if(!t||12>t.byteLength)throw Error("Invalid font buffer: too small to be a valid font file")
244
244
  const e=new DataView(t),n=e.getUint32(0)
245
245
  if(![F,G].includes(n))throw Error("Invalid font format. Expected TTF/OTF (or WOFF), got signature: 0x"+n.toString(16))
246
246
  const s=i(e),r=s.has(U)||s.has($),o=s.get(k)?.offset??0,a=s.get(C)?.offset??0,h=s.get(D)?.offset??0,c=s.get(B)?.offset??0,l=s.get(N)?.offset??0,u=s.get(P)?.offset??0,f=o?e.getUint16(o+18):1e3
@@ -277,7 +277,7 @@ for(let r=0;n>r;r++){const n=e+6+12*r,o=t.getUint16(n),a=t.getUint16(n+2),h=t.ge
277
277
  const n=e.get(i)
278
278
  if(!n)return null
279
279
  try{const e=new Uint8Array(t.buffer,n.offset,n.length)
280
- return 0===n.Ce||3===n.Ce&&1===n.De?j.decode(e):new TextDecoder("ascii").decode(e)}catch{return null}}static Oe(t,e,i){const n=e.has(U)||e.has($),s=e.get(k)?.offset??0,r=e.get(C)?.offset??0,o=e.get(D)?.offset??0,a=e.get(B)?.offset??0,h=e.get(N)?.offset??0,c=s?t.getUint16(s+18):1e3
280
+ return 0===n.Ce||3===n.Ce&&1===n.De?z.decode(e):new TextDecoder("ascii").decode(e)}catch{return null}}static Oe(t,e,i){const n=e.has(U)||e.has($),s=e.get(k)?.offset??0,r=e.get(C)?.offset??0,o=e.get(D)?.offset??0,a=e.get(B)?.offset??0,h=e.get(N)?.offset??0,c=s?t.getUint16(s+18):1e3
281
281
  let l=null
282
282
  r&&(l={de:t.getInt16(r+4),ye:t.getInt16(r+6),pe:t.getInt16(r+8)})
283
283
  let u=null
@@ -300,10 +300,10 @@ if(0===f)continue
300
300
  const d=u+f
301
301
  if(0!==t.getUint16(d))continue
302
302
  const y=t.getUint16(d+2),p=this.Be(t,i,y)
303
- p&&(s[String.fromCharCode(a>>24&255,a>>16&255,a>>8&255,255&a)]=p)}}static Ue(t){return String.fromCharCode(t>>24&255,t>>16&255,t>>8&255,255&t)}static $e(t){return null!==t.we&&null!==t.ge?{de:t.we,ye:t.ge,pe:0}:null!==t._e&&null!==t.Ee?{de:t._e,ye:t.Ee,pe:0}:null!==t.me&&null!==t.xe?{de:t.me,ye:-t.xe,pe:0}:{de:Math.round(.8*t.vt),ye:-Math.round(.2*t.vt),pe:0}}static We(t){const e=z.$e(t)
304
- return{de:e.de,ye:e.ye,pe:e.pe,vt:t.vt,Re:e.de-e.ye}}}class H{static je(t){if(4>t.byteLength)return"ttf/otf"
303
+ p&&(s[String.fromCharCode(a>>24&255,a>>16&255,a>>8&255,255&a)]=p)}}static Ue(t){return String.fromCharCode(t>>24&255,t>>16&255,t>>8&255,255&t)}static $e(t){return null!==t.we&&null!==t.ge?{de:t.we,ye:t.ge,pe:0}:null!==t._e&&null!==t.Ee?{de:t._e,ye:t.Ee,pe:0}:null!==t.me&&null!==t.xe?{de:t.me,ye:-t.xe,pe:0}:{de:Math.round(.8*t.vt),ye:-Math.round(.2*t.vt),pe:0}}static We(t){const e=j.$e(t)
304
+ return{de:e.de,ye:e.ye,pe:e.pe,vt:t.vt,Re:e.de-e.ye}}}class H{static ze(t){if(4>t.byteLength)return"ttf/otf"
305
305
  const e=new DataView(t).getUint32(0)
306
- return e===O?"woff":2001684018===e?"woff2":"ttf/otf"}static async ze(t){const e=new DataView(t),i=new Uint8Array(t)
306
+ return e===O?"woff":2001684018===e?"woff2":"ttf/otf"}static async je(t){const e=new DataView(t),i=new Uint8Array(t)
307
307
  if(e.getUint32(0)!==O)throw Error("Not a valid WOFF font")
308
308
  const n=e.getUint32(4),s=e.getUint16(12),r=e.getUint32(16)
309
309
  if("undefined"==typeof DecompressionStream)throw Error("WOFF fonts require DecompressionStream API (Chrome 80+, Firefox 113+, Safari 16.4+). Please use TTF/OTF fonts or upgrade your browser.")
@@ -322,15 +322,15 @@ return new Uint8Array(n)}))
322
322
  for(let t=0;s>t;t++){const e=l[t],i=12+16*t
323
323
  a.setUint32(i,e.tag),a.setUint32(i+4,e.t),a.setUint32(i+8,c),a.setUint32(i+12,e.He),o.set(u[t],c),c+=e.He,c+=(4-e.He%4)%4}return o.buffer.slice(0,c)}static async Ve(t){const e=new ReadableStream({start(e){e.enqueue(t),e.close()}}).pipeThrough(new DecompressionStream("deflate"))
324
324
  return new Response(e).arrayBuffer()}}class V{constructor(t){this.qe=t}async Ye(t,e){if(!t||12>t.byteLength)throw Error("Invalid font buffer: too small to be a valid font file")
325
- const i=H.je(t)
326
- if("woff"===i)t=await H.ze(t)
325
+ const i=H.ze(t)
326
+ if("woff"===i)t=await H.je(t)
327
327
  else if("woff2"===i)throw Error("WOFF2 fonts are not yet supported. Please use WOFF or TTF/OTF format.")
328
328
  const n=new DataView(t).getUint32(0)
329
329
  if(![F,G].includes(n))throw Error("Invalid font format. Expected TTF/OTF (or WOFF), got signature: 0x"+n.toString(16))
330
330
  const{hb:s,module:r}=await this.qe()
331
331
  try{const i=s.Je(new Uint8Array(t)),n=s.Ke(i,0),o=s.Xe(n)
332
332
  e&&o.Qe(e)
333
- const a=n.Ze(),h=Object.keys(a).length>0,{h:c,features:l}=z.Fe(t)
333
+ const a=n.Ze(),h=Object.keys(a).length>0,{h:c,features:l}=j.Fe(t)
334
334
  let u
335
335
  if(h&&a){u={}
336
336
  for(const[t,e]of Object.entries(a))u[t]={...e,name:c.Ae?.[t]||null}}return{hb:s,fontBlob:i,face:n,font:o,module:r,upem:c.vt,h:c,ti:e,ei:h,ii:u,ni:l?.tags,si:l?.names,ri:t}}catch(t){throw h.error("Failed to load font:",t),t}}static oi(t){try{t.font&&"function"==typeof t.font.destroy&&t.font.destroy(),t.face&&"function"==typeof t.face.destroy&&t.face.destroy(),t.fontBlob&&"function"==typeof t.fontBlob.destroy&&t.fontBlob.destroy()}catch(t){h.error("Error destroying font resources:",t)}}}const q=/^[a-z]{2,3}(?:-[a-z0-9]{2,16})*$/i,Y=new Set(["af","as","be","bg","bn","ca","cs","cy","da","de-1996","el-monoton","el-polyton","en-gb","en-us","eo","es","et","eu","fi","fr","fur","ga","gl","gu","hi","hr","hsb","hu","hy","ia","id","is","it","ka","kmr","kn","la","lt","lv","mk","ml","mn-cyrl","mr","mul-ethi","nb","nl","nn","oc","or","pa","pl","pms","pt","rm","ro","ru","sa","sh-cyrl","sh-latn","sk","sl","sq","sr-cyrl","sv","ta","te","th","tk","tr","uk","zh-latn-pinyin"])
@@ -367,7 +367,7 @@ var e=t.e
367
367
  e.a.c=e.c,e.c.a=e.a,t.e=null}function L(t,e){d(t.a),t.c=!1,t.a=e,e.pi=t}function M(t){var e=t.a.a
368
368
  do{t=ut(t)}while(t.a.a===e)
369
369
  return t.c&&(L(t,e=p(lt(t).a.b,t.a.e)),t=ut(t)),t}function I(t,e,i){var n=new ct
370
- return n.a=i,n.e=j(t.f,e.e,n),i.pi=n}function F(t,e){switch(t.s){case 100130:return!!(1&e)
370
+ return n.a=i,n.e=z(t.f,e.e,n),i.pi=n}function F(t,e){switch(t.s){case 100130:return!!(1&e)
371
371
  case 100131:return 0!==e
372
372
  case 100132:return e>0
373
373
  case 100133:return 0>e
@@ -413,8 +413,8 @@ do{a=a.a}while(null!==a.b&&!l.c(l.b,u,a.b))
413
413
  if(a=(c=lt(l=a.b)).a,0===s((u=l.a).b.a,o,u.a))e((u=l.a).a,o)||e(u.b.a,o)||(y(u.b),l.c&&(d(u.c),l.c=!1),f(o.c,u),$(r,o))
414
414
  else{var h=i(a.b.a,u.b.a)?l:c,c=void 0
415
415
  l.d||h.c?(c=h===l?p(o.c.b,u.e):p(a.b.c.b,o.c).b,h.c?L(h,c):(u=r,(l=I(r,l,c)).f=ut(l).f+l.a.f,l.d=F(u,l.f)),$(r,o)):k(r,l,o.c,o.c,null,!0)}return}if(l=(u=lt(r=M(r.pi))).a,(u=O(t,u,null)).c===l){var l,u=(l=u).c,w=(a=lt(r),!1);(c=r.a).b.a!==(h=a.a).b.a&&P(t,r),e(c.a,t.a)&&(f(K(u),c),u=lt(r=M(r)).a,O(t,lt(r),a),w=!0),e(h.a,t.a)&&(f(l,K(h)),l=O(t,a,null),w=!0),w?k(t,r,l.c,u,u,!0):(o=i(h.a,c.a)?K(h):c,k(t,r,o=p(l.c.b,o),o.c,o.c,!1),o.b.pi.c=!0,U(t,r))}else k(t,r,u.c,l,l,!0)}function W(t,e){var i=new ct,n=u(t.b)
416
- n.a.b=dt,n.a.a=e,n.b.a.b=-dt,n.b.a.a=e,t.a=n.b.a,i.a=n,i.f=0,i.d=!1,i.c=!1,i.yi=!0,i.b=!1,n=j(n=t.f,n.a,i),i.e=n}function R(t){this.a=new z,this.b=t,this.c=T}function j(t,e,i){do{e=e.c}while(null!==e.b&&!t.c(t.b,e.b,i))
417
- return t=new z(i,e.a,e),e.a.c=t,e.a=t}function z(t,e,i){this.b=t||null,this.a=e||this,this.c=i||this}function H(){this.d=yt,this.gi=this.b=this.mi=null,this.xi=[0,0,0],this.s=100130,this.n=!1,this.wi=this.a=this.e=this.f=null,this.bi=!1,this.c=this.r=this.pi=this.Si=this._i=this.yi=null}function V(t,e){if(t.d!==e)for(;t.d!==e;)if(e>t.d)switch(t.d){case yt:q(t,100151),t.Ei(null)
416
+ n.a.b=dt,n.a.a=e,n.b.a.b=-dt,n.b.a.a=e,t.a=n.b.a,i.a=n,i.f=0,i.d=!1,i.c=!1,i.yi=!0,i.b=!1,n=z(n=t.f,n.a,i),i.e=n}function R(t){this.a=new j,this.b=t,this.c=T}function z(t,e,i){do{e=e.c}while(null!==e.b&&!t.c(t.b,e.b,i))
417
+ return t=new j(i,e.a,e),e.a.c=t,e.a=t}function j(t,e,i){this.b=t||null,this.a=e||this,this.c=i||this}function H(){this.d=yt,this.gi=this.b=this.mi=null,this.xi=[0,0,0],this.s=100130,this.n=!1,this.wi=this.a=this.e=this.f=null,this.bi=!1,this.c=this.r=this.pi=this.Si=this._i=this.yi=null}function V(t,e){if(t.d!==e)for(;t.d!==e;)if(e>t.d)switch(t.d){case yt:q(t,100151),t.Ei(null)
418
418
  break
419
419
  case 1:q(t,100152),t.Ti()}else switch(t.d){case 2:q(t,100154),t.Ai()
420
420
  break
@@ -484,14 +484,14 @@ r=u.d,(u=u.b).d=r,r.b=u}return this.r(this.b),void(this.c=this.b=null)}}this.b=t
484
484
  var st=nt.exports
485
485
  class rt{process(t,e=!0,i=!1,n=!0){if(0===t.length)return{Wi:{vertices:[],indices:[]},Ri:[]}
486
486
  const s=t.filter(t=>t.points.length>=3)
487
- return 0===s.length?{Wi:{vertices:[],indices:[]},Ri:[]}:this.ji(s,e,i,n)}ji(t,e,i,n){const s=!i&&!e
487
+ return 0===s.length?{Wi:{vertices:[],indices:[]},Ri:[]}:this.zi(s,e,i,n)}zi(t,e,i,n){const s=!i&&!e
488
488
  let r,o
489
- s?(o=this.zi(t,!0),(e||n)&&(r=this.zi(t))):(r=this.zi(t),o=r)
490
- let a=n?s?o:r??this.zi(t):[]
489
+ s?(o=this.ji(t,!0),(e||n)&&(r=this.ji(t))):(r=this.ji(t),o=r)
490
+ let a=n?s?o:r??this.ji(t):[]
491
491
  if(e){const t=this.Hi(r,"boundary")
492
492
  if(!t)return h.warn("libtess returned empty result from boundary pass"),{Wi:{vertices:[],indices:[]},Ri:[]}
493
493
  o=this.Vi(t),n&&(a=o)}const c=this.Hi(o,"triangles")
494
- return c?{Wi:{vertices:c.vertices,indices:c.indices||[]},Ri:a}:(h.warn(e?"libtess returned empty result from triangulation pass":"libtess returned empty result from single-pass triangulation"),{Wi:{vertices:[],indices:[]},Ri:a})}zi(t,e=!1){const i=Array(t.length)
494
+ return c?{Wi:{vertices:c.vertices,indices:c.indices||[]},Ri:a}:(h.warn(e?"libtess returned empty result from triangulation pass":"libtess returned empty result from single-pass triangulation"),{Wi:{vertices:[],indices:[]},Ri:a})}ji(t,e=!1){const i=Array(t.length)
495
495
  for(let n=0;t.length>n;n++){const s=t[n].points,r=s.length,o=r>1&&s[0].x===s[r-1].x&&s[0].y===s[r-1].y?r-1:r,a=Array(2*(o+1))
496
496
  let h=0
497
497
  if(e)for(let t=o-1;t>=0;t--){const e=s[t]
@@ -625,7 +625,7 @@ if(0>=c)return this.kn(i,n,h),void this.kn(s,r,h)
625
625
  if(c>Math.abs(Math.atan2(l*d-u*f,l*f+u*d))+Math.abs(Math.atan2(f*p-d*y,f*y+d*p)))return this.kn(i,n,h),void this.kn(s,r,h)}}}this.Dn(t,e,l,u,w,g,x,b,h,c+1),this.Dn(x,b,v,m,y,p,o,a,h,c+1)}kn(t,e,i){const n=new J(t,e)
626
626
  if(0===i.length)return void i.push(n)
627
627
  const s=i[i.length-1],r=n.x-s.x,o=n.y-s.y
628
- r*r+o*o>1e-12&&i.push(n)}}class yt{constructor(t,e){this.Bn=0,this.Nn=0,this.Pn=[],this.Un=null,this.$n=null,this.Wn={min:new J(1/0,1/0),max:new J(-1/0,-1/0)},this.Rn=[],this.jn=[],this.zn=[],this.Hn=new J(0,0),this.Vn=new dt(t),this.qn=new lt({...ct,...e})}setPosition(t,e){this.Hn.set(t,e)}Yn(t,e){this.Hn.x+=t,this.Hn.y+=e}Jn(t,e){this.Pn.length>0&&this.Kn(),this.Bn=t,this.Nn=e,this.Pn=[],this.Wn.min.set(1/0,1/0),this.Wn.max.set(-1/0,-1/0),this.jn.push(this.Hn.clone())}Kn(){this.Un&&this.Xn(),this.Pn.length>0&&(this.Rn.push({Qn:this.Bn,Zn:this.Pn,bounds:{min:{x:this.Wn.min.x,y:this.Wn.min.y},max:{x:this.Wn.max.x,y:this.Wn.max.y}}}),this.zn.push(this.Nn)),this.Pn=[]}ts(t,e){this.Un&&this.Xn(),this.$n=new J(t,e),this.es(this.$n),this.Un={points:[this.$n],glyphIndex:this.Bn}}ns(t,e){if(!this.Un||!this.$n)return
628
+ r*r+o*o>1e-12&&i.push(n)}}class yt{constructor(t,e){this.Bn=0,this.Nn=0,this.Pn=[],this.Un=null,this.$n=null,this.Wn={min:new J(1/0,1/0),max:new J(-1/0,-1/0)},this.Rn=[],this.zn=[],this.jn=[],this.Hn=new J(0,0),this.Vn=new dt(t),this.qn=new lt({...ct,...e})}setPosition(t,e){this.Hn.set(t,e)}Yn(t,e){this.Hn.x+=t,this.Hn.y+=e}Jn(t,e){this.Pn.length>0&&this.Kn(),this.Bn=t,this.Nn=e,this.Pn=[],this.Wn.min.set(1/0,1/0),this.Wn.max.set(-1/0,-1/0),this.zn.push(this.Hn.clone())}Kn(){this.Un&&this.Xn(),this.Pn.length>0&&(this.Rn.push({Qn:this.Bn,Zn:this.Pn,bounds:{min:{x:this.Wn.min.x,y:this.Wn.min.y},max:{x:this.Wn.max.x,y:this.Wn.max.y}}}),this.jn.push(this.Nn)),this.Pn=[]}ts(t,e){this.Un&&this.Xn(),this.$n=new J(t,e),this.es(this.$n),this.Un={points:[this.$n],glyphIndex:this.Bn}}ns(t,e){if(!this.Un||!this.$n)return
629
629
  const i=new J(t,e)
630
630
  this.es(i),this.Un.points.push(i),this.$n=i}ss(t,e,i,n){if(!this.Un||!this.$n)return
631
631
  const s=this.$n,r=new J(t,e),o=new J(i,n)
@@ -640,7 +640,7 @@ for(let t=0;f.length>t;t++){const e=f[t]
640
640
  this.es(e),this.Un.points.push(e)}this.$n=c}hs(){if(!this.Un||!this.$n)return
641
641
  const t=this.Un.points[0]
642
642
  this.$n.equals(t)||this.Un.points.push(t),this.Xn()}Xn(){if(this.Un){const t=this.qn.xn(this.Un)
643
- this.Pn.push(t),this.Un=null,this.$n=null}}es(t){this.Wn.min.x=Math.min(this.Wn.min.x,t.x),this.Wn.min.y=Math.min(this.Wn.min.y,t.y),this.Wn.max.x=Math.max(this.Wn.max.x,t.x),this.Wn.max.y=Math.max(this.Wn.max.y,t.y)}cs(){return this.Pn.length>0&&this.Kn(),this.Rn}ls(){return this.jn}us(){return this.zn}reset(){this.Rn=[],this.jn=[],this.zn=[],this.Pn=[],this.Un=null,this.$n=null,this.Bn=0,this.Nn=0,this.Hn.set(0,0),this.Wn={min:new J(1/0,1/0),max:new J(-1/0,-1/0)}}Fn(t){this.Vn.Fn(t)}fs(t){this.qn.mn({...ct,...t})}ds(){return this.qn.getStats()}}class pt{constructor(){this.ys=null,this.ps=null,this.ws=null,this.gs=null,this.vs=null,this.xs=0,this.position={x:0,y:0}}setPosition(t,e){this.position.x=t,this.position.y=e,this.bs&&this.bs.setPosition(t,e)}Yn(t,e){this.position.x+=t,this.position.y+=e,this.bs&&this.bs.Yn(t,e)}Ss(t){this.bs=t}_s(t,e){if(!t||!t.module||!t.hb)throw Error("Invalid font object")
643
+ this.Pn.push(t),this.Un=null,this.$n=null}}es(t){this.Wn.min.x=Math.min(this.Wn.min.x,t.x),this.Wn.min.y=Math.min(this.Wn.min.y,t.y),this.Wn.max.x=Math.max(this.Wn.max.x,t.x),this.Wn.max.y=Math.max(this.Wn.max.y,t.y)}cs(){return this.Pn.length>0&&this.Kn(),this.Rn}ls(){return this.zn}us(){return this.jn}reset(){this.Rn=[],this.zn=[],this.jn=[],this.Pn=[],this.Un=null,this.$n=null,this.Bn=0,this.Nn=0,this.Hn.set(0,0),this.Wn={min:new J(1/0,1/0),max:new J(-1/0,-1/0)}}Fn(t){this.Vn.Fn(t)}fs(t){this.qn.mn({...ct,...t})}ds(){return this.qn.getStats()}}class pt{constructor(){this.ys=null,this.ps=null,this.ws=null,this.gs=null,this.vs=null,this.xs=0,this.position={x:0,y:0}}setPosition(t,e){this.position.x=t,this.position.y=e,this.bs&&this.bs.setPosition(t,e)}Yn(t,e){this.position.x+=t,this.position.y+=e,this.bs&&this.bs.Yn(t,e)}Ss(t){this.bs=t}_s(t,e){if(!t||!t.module||!t.hb)throw Error("Invalid font object")
644
644
  if(this.bs=e,this.xs)return
645
645
  const i=t.module
646
646
  this.ys=i.Es((t,e,i,n,s)=>{this.bs?.ts(n,s)},"viiiffi"),this.ps=i.Es((t,e,i,n,s)=>{this.bs?.ns(n,s)},"viiiffi"),this.ws=i.Es((t,e,i,n,s,r,o)=>{this.bs?.ss(n,s,r,o)},"viiiffffi"),this.gs=i.Es((t,e,i,n,s,r,o,a,h)=>{this.bs?.rs(n,s,r,o,a,h)},"viiiffffffi"),this.vs=i.Es(()=>{this.bs?.hs()},"viiii"),this.xs=i.exports.Ts(),i.exports.As(this.xs,this.ys,0,0),i.exports.Ls(this.xs,this.ps,0,0),i.exports.Ms(this.xs,this.ws,0,0),i.exports.Is(this.xs,this.gs,0,0),i.exports.Fs(this.xs,this.vs,0,0)}Gs(){if(!this.xs)throw Error("Draw functions not initialized")
@@ -650,7 +650,7 @@ try{this.xs&&(e.exports.Os(this.xs),this.xs=0),null!==this.ys&&(e.ks(this.ys),th
650
650
  class gt{constructor(t,e){this.Cs="default",this.Ds="default",this.Bs=new Set,this.cache=t,this.ae=e,this.tessellator=new rt,this.Ns=new ot,this.Ps=new at,this.bs=new yt,this.Us=(()=>{const t=this.ae.module,e=wt.get(t)
651
651
  if(e)return e
652
652
  const i=new pt
653
- return wt.set(t,i),i})(),this.Us._s(this.ae,this.bs),this.$s=Z,this.Ws=tt,this.Rs=et}ds(){return this.bs.ds()}Fn(t){this.In=t,this.bs.Fn(t),this.js()}fs(t){this.zs=t,this.bs.fs(t),this.js()}Hs(t){this.Cs=t,this.js()}js(){this.Ds=`${this.Cs}__${this.Vs()}`}Vs(){const t=this.In?.Ln??ut.Ln,e=this.In?.Mn??ut.Mn,i=this.zs?.enabled??!0,n=this.zs?.dn??1,s=this.zs?.yn??.0087,r=this.zs?.pn??10
653
+ return wt.set(t,i),i})(),this.Us._s(this.ae,this.bs),this.$s=Z,this.Ws=tt,this.Rs=et}ds(){return this.bs.ds()}Fn(t){this.In=t,this.bs.Fn(t),this.zs()}fs(t){this.js=t,this.bs.fs(t),this.zs()}Hs(t){this.Cs=t,this.zs()}zs(){this.Ds=`${this.Cs}__${this.Vs()}`}Vs(){const t=this.In?.Ln??ut.Ln,e=this.In?.Mn??ut.Mn,i=this.js?.enabled??!0,n=this.js?.dn??1,s=this.js?.yn??.0087,r=this.js?.pn??10
654
654
  return[`cf:${t.toFixed(4)},${e.toFixed(4)}`,`opt:${i?1:0},${n.toFixed(4)},${s.toFixed(6)},${r.toFixed(4)}`].join("|")}qs(t,e,i,n,r,o=!1,h){if(a){let e=0
655
655
  for(let i=0;t.length>i;i++)e+=t[i].length}const c=[]
656
656
  let l=0,u=0,f=0,d=0
@@ -741,14 +741,14 @@ var d,y,p,w,g,v,m,x=console.error.bind(console),b=!1,S=t=>t.startsWith("file://"
741
741
  class A{name="ExitStatus"
742
742
  constructor(t){this.message=`Program terminated with exit(${t})`,this.status=t}}var L,M,I,F=t=>{for(;t.length>0;)t.shift()(s)},G=[],O=t=>G.push(t),k=[],C=t=>k.push(t),D=!0,B=0,N={},P=t=>{if(t instanceof A||"unwind"==t)return y
743
743
  h(1,t)},U=()=>D||B>0,$=t=>{y=t,U()||(s.Ar?.(t),b=!0),h(t,new A(t))},W=(t,e)=>Math.ceil(t/e)*e,R=t=>{var e=(t-g.buffer.byteLength+65535)/65536|0
744
- try{return g.grow(e),i(),1}catch(t){}},j=t=>{const e=t.length
745
- return[e%128|128,e>>7,...t]},z={pi:127,gi:127,xi:126,f:125,d:124,e:111},H=t=>j(Array.from(t,t=>z[t])),V=t=>L.get(t),q=[],Y=(t,e)=>L.set(t,e)
744
+ try{return g.grow(e),i(),1}catch(t){}},z=t=>{const e=t.length
745
+ return[e%128|128,e>>7,...t]},j={pi:127,gi:127,xi:126,f:125,d:124,e:111},H=t=>z(Array.from(t,t=>j[t])),V=t=>L.get(t),q=[],Y=(t,e)=>L.set(t,e)
746
746
  s.Lr&&(D=s.Lr),s.Mr&&(x=s.Mr),s.Ir&&(d=s.Ir),s.Fr=g,s.Gr=K,s.Es=(t,e)=>{var i=(t=>(M||(M=new WeakMap,((t,e)=>{if(M)for(var i=0;0+e>i;i++){var n=V(i)
747
747
  n&&M.set(n,i)}})(0,L.length)),M.get(t)||0))(t)
748
748
  if(i)return i
749
749
  var n=q.length?q.pop():L.grow(1)
750
750
  try{Y(n,t)}catch(i){if(!(i instanceof TypeError))throw i
751
- var s=((t,e)=>{var i=Uint8Array.of(0,97,115,109,1,0,0,0,1,...j([1,96,...H(e.slice(1)),...H("v"===e[0]?"":e[0])]),2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0),n=new WebAssembly.Module(i)
751
+ var s=((t,e)=>{var i=Uint8Array.of(0,97,115,109,1,0,0,0,1,...z([1,96,...H(e.slice(1)),...H("v"===e[0]?"":e[0])]),2,7,1,1,101,1,102,0,0,7,5,1,1,102,0,0),n=new WebAssembly.Module(i)
752
752
  return new WebAssembly.Instance(n,{e:{f:t}}).exports.f})(t,e)
753
753
  Y(n,s)}return M.set(t,n),n},s.ks=t=>{M.delete(V(t)),Y(t,null),q.push(t)}
754
754
  var J={Or:()=>n(""),kr(){D=!1,B=0},Cr(t,e){if(N[t]&&(clearTimeout(N[t].id),delete N[t]),!e)return 0
@@ -756,7 +756,7 @@ var i=setTimeout(()=>{delete N[t],(t=>{if(!b)try{t(),(()=>{if(!U())try{y=t=y,$(t
756
756
  return N[t]={id:i,Dr:e},0},Br(t){var e=v.length,i=2147483648
757
757
  if((t>>>=0)>i)return!1
758
758
  for(var n=1;4>=n;n*=2){var s=e*(1+.2/n),r=Math.min(i,W(Math.max(t,s=Math.min(s,t+100663296)),65536))
759
- if(R(r))return!0}return!1},Nr:$},K=await(async()=>{function t(t){return s.Gr=K=t.exports,s.Fr=g=K.memory,i(),L=K.Pr,(t=>{s.Ur=t.$r,s.Wr=t.Rr,s.jr=t.zr,s.Hr=t.Vr,s.qr=t.Yr,s.Jr=t.Kr,s.Xr=t.Qr,s.Zr=t.eo,s.io=t.no,s.so=t.ro,s.oo=t.ao,s.ho=t.co,s.lo=t.uo,s.fo=t.do,s.yo=t.po,s.wo=t.vo,s.mo=t.xo,s.bo=t.So,s._o=t.Eo,s.To=t.Ao,s.Lo=t.Mo,s.Io=t.Fo,s.Go=t.Oo,s.ko=t.Co,s.Do=t.Bo,s.No=t.Po,s.Uo=t.$o,s.Wo=t.Ro,s.jo=t.As,s.zo=t.Ls,s.Ho=t.Ms,s.Vo=t.Is,s.qo=t.Fs,s.Yo=t.Ts,s.Jo=t.Os,s.Ko=t.Xo,s.Qo=t.Zo,s.ta=t.ea,s.ia=t.na,s.sa=t.ra,s.oa=t.ur,s.aa=t.ha,s.ca=t.la,s.ua=t.fa,s.da=t.ya,s.pa=t.wa,s.ga=t.va,s.ma=t.xa,s.ba=t.Sa,s._a=t.Ea,s.Ta=t.Aa,s.La=t.Ma,I=t.Ia})(K),(()=>{if(E--,s.Fa?.(E),0==E&&T){var t=T
759
+ if(R(r))return!0}return!1},Nr:$},K=await(async()=>{function t(t){return s.Gr=K=t.exports,s.Fr=g=K.memory,i(),L=K.Pr,(t=>{s.Ur=t.$r,s.Wr=t.Rr,s.zr=t.jr,s.Hr=t.Vr,s.qr=t.Yr,s.Jr=t.Kr,s.Xr=t.Qr,s.Zr=t.eo,s.io=t.no,s.so=t.ro,s.oo=t.ao,s.ho=t.co,s.lo=t.uo,s.fo=t.do,s.yo=t.po,s.wo=t.vo,s.mo=t.xo,s.bo=t.So,s._o=t.Eo,s.To=t.Ao,s.Lo=t.Mo,s.Io=t.Fo,s.Go=t.Oo,s.ko=t.Co,s.Do=t.Bo,s.No=t.Po,s.Uo=t.$o,s.Wo=t.Ro,s.zo=t.As,s.jo=t.Ls,s.Ho=t.Ms,s.Vo=t.Is,s.qo=t.Fs,s.Yo=t.Ts,s.Jo=t.Os,s.Ko=t.Xo,s.Qo=t.Zo,s.ta=t.ea,s.ia=t.na,s.sa=t.ra,s.oa=t.ur,s.aa=t.ha,s.ca=t.la,s.ua=t.fa,s.da=t.ya,s.pa=t.wa,s.ga=t.va,s.ma=t.xa,s.ba=t.Sa,s._a=t.Ea,s.Ta=t.Aa,s.La=t.Ma,I=t.Ia})(K),(()=>{if(E--,s.Fa?.(E),0==E&&T){var t=T
760
760
  T=null,t()}})(),K}E++,s.Fa?.(E)
761
761
  var e,r={o:J,Ga:J}
762
762
  return s.Oa?new Promise(e=>{s.Oa(r,i=>{e(t(i))})}):(m??=(e="hb.wasm",s.ka?s.ka(e,u):u+e),t((await(async function(t,e,i){if(!t&&!S(e)&&!a)try{var s=fetch(e,{credentials:"same-origin"})
@@ -783,7 +783,7 @@ t.HEAPU8.set(new Uint8Array(e),i)
783
783
  var n=s.$r(i,e.byteLength,2,i,h)
784
784
  return{dr:n,destroy(){s.Rr(n)}}},Ke(i,n){var r=s.Xo(i.dr,n)
785
785
  const o=s.na(r)
786
- return{dr:r,upem:o,Wa(i){var n=s.ea(r,e(i)),o=s.zr(n)
786
+ return{dr:r,upem:o,Wa(i){var n=s.ea(r,e(i)),o=s.jr(n)
787
787
  if(o){var a=s.Vr(n,null)
788
788
  return t.HEAPU8.subarray(a,a+o)}},Ze(){var e=s.$o(2048),i=s.$o(4)
789
789
  t.HEAPU32[i/4]=64,s.Sa(r,0,i,e)
@@ -794,9 +794,9 @@ s.ra(r,e)
794
794
  var i=(e=>{const i=s.Ea(e),n=s.$o(i<<2),r=n>>2,o=t.HEAPU32.subarray(r,r+i)
795
795
  return t.HEAPU32.set(o,r),s.Aa(e,-1,n,i),o})(e)
796
796
  return s.xa(e),i},destroy(){s.Zo(r)}}},Xe(i){function n(t){return c||(f=o((t,e,i,n,s)=>{l+=`M${n},${s}`},"viiiffi"),d=o((t,e,i,n,s)=>{l+=`L${n},${s}`},"viiiffi"),y=o((t,e,i,n,s,r,o,a,h)=>{l+=`C${n},${s} ${r},${o} ${a},${h}`},"viiiffffffi"),p=o((t,e,i,n,s,r,o)=>{l+=`Q${n},${s} ${r},${o}`},"viiiffffi"),w=o(()=>{l+="Z"},"viiii"),c=s.Ts(),s.As(c,f,0,0),s.Ls(c,d,0,0),s.Is(c,y,0,0),s.Ms(c,p,0,0),s.Fs(c,w,0,0)),l="",s.ur(h,t,c,0),l}var h=s.la(i.dr),c=null,f=null,d=null,y=null,p=null,w=null
797
- return{dr:h,ja(e){s.ha(h,e,u,256)
797
+ return{dr:h,za(e){s.ha(h,e,u,256)
798
798
  var i=t.HEAPU8.subarray(u,u+256)
799
- return r.decode(i.slice(0,i.indexOf(0)))},za:n,Ha:t=>n(t).replace(/([MLQCZ])/g,"|$1 ").split("|").filter(t=>t.length).map(t=>{var e=t.split(/[ ,]/g)
799
+ return r.decode(i.slice(0,i.indexOf(0)))},ja:n,Ha:t=>n(t).replace(/([MLQCZ])/g,"|$1 ").split("|").filter(t=>t.length).map(t=>{var e=t.split(/[ ,]/g)
800
800
  return{type:e[0],values:e.slice(1).filter(t=>t.length).map(t=>+t)}}),setScale(t,e){s.wa(h,t,e)},Qe(i){var n=Object.entries(i),r=s.$o(8*n.length)
801
801
  n.forEach((i,n)=>{t.HEAPU32[r/4+2*n+0]=e(i[0]),t.HEAPF32[r/4+2*n+1]=i[1]}),s.fa(h,r,n.length),s.Ro(r)},destroy(){s.ya(h),c&&(s.Os(c),c=null,a(f),a(d),a(y),a(p),a(w))}}},createBuffer(){var e=s.Kr()
802
802
  return{dr:e,ne(i){const n=(e=>{const i=s.$o(2*e.length),n=new Uint16Array(t.Fr.buffer,i,e.length)
@@ -865,7 +865,7 @@ try{this.ae&&this.destroy(),this.ae=await this.Mh.Ye(n,e),i&&(this.ae.re=i)
865
865
  const t=Ft.Dh(n)
866
866
  this.Lh="font_"+t,e&&(this.Lh+="_var_"+Ft.Ah(e)),i&&(this.Lh+="_feat_"+Ft.Ah(i))}catch(t){throw h.error("Failed to load font:",t),t}}async kh(t){try{if(!this.ae)throw Error("Font not loaded. Use Text.create() with a font option.")
867
867
  const e=await this.$h(t)
868
- this.Wh(e),this.Rh(t=e),this.gr||(this.gr=new gt(Q,this.ae),this.gr.Hs(this.Lh)),this.gr.Fn(t.jh),this.gr.fs(t.zh),this.ae.font.setScale(this.ae.upem,this.ae.upem),this.Hh||(this.Hh=new vt(this.ae,this.gr))
868
+ this.Wh(e),this.Rh(t=e),this.gr||(this.gr=new gt(Q,this.ae),this.gr.Hs(this.Lh)),this.gr.Fn(t.zh),this.gr.fs(t.jh),this.ae.font.setScale(this.ae.upem,this.ae.upem),this.Hh||(this.Hh=new vt(this.ae,this.gr))
869
869
  const i=this.Vh(t),n=t.qh??this.ae.ei??!1,s=this.Hh.vr(i.lines,i.Yh,i.letterSpacing,i.align,i.direction,t.color,t.text)
870
870
  let r,o
871
871
  if(t.color&&"object"==typeof t.color&&!Array.isArray(t.color)&&(t.color.fh||t.color.yh)){if(r=new Set,t.color.fh){o=[]
@@ -884,34 +884,45 @@ let k
884
884
  void 0!==a&&(k=a*O)
885
885
  const C=n*O,D=C>0?Math.max(C,25e-6*this.ae.upem):0
886
886
  this.tc||(this.tc=new I(this.ae))
887
- const B=this.tc.he({text:e,width:k,align:f,direction:h,dt:y,language:p,yt:d,xt:w,bt:g,St:v,_t:m,gt:x,Et:b,Tt:S,At:_,Lt:E,Mt:T,It:A,Ft:L,Gt:M,Ot:F,kt:G,letterSpacing:r}),N=z.$e(this.ae.h)
887
+ const B=this.tc.he({text:e,width:k,align:f,direction:h,dt:y,language:p,yt:d,xt:w,bt:g,St:v,_t:m,gt:x,Et:b,Tt:S,At:_,Lt:E,Mt:T,It:A,Ft:L,Gt:M,Ot:F,kt:G,letterSpacing:r}),N=j.$e(this.ae.h)
888
888
  return{lines:B.lines,Yh:(N.de-N.ye)*s,letterSpacing:r,align:f,direction:h,depth:D,size:i,Jh:1/O}}ec(t,e,i,n,s){const r=t.length/3,o=new Float32Array(3*r),a=[]
889
889
  if(Array.isArray(i)){for(let t=0;r>t;t++){const e=3*t
890
890
  o[e]=i[0],o[e+1]=i[1],o[e+2]=i[2]}a.push({start:0,end:n.length,wh:n,color:i,bounds:[],glyphs:e,mh:[...new Set(e.map(t=>t.cr))]})}else{const t=i.default||[1,1,1]
891
891
  for(let e=0;o.length>e;e+=3)o[e]=t[0],o[e+1]=t[1],o[e+2]=t[2]
892
- if(i.fh&&s){const t=new Map
893
- for(const i of e){const e=t.get(i.hr)
894
- e?e.push(i):t.set(i.hr,[i])}for(const e of s){const n=i.fh[e.pattern]
895
- if(!n)continue
896
- const s=[],r=new Set
897
- for(let i=e.start;e.end>i;i++){const e=t.get(i)
898
- if(e)for(const t of e){s.push(t),r.add(t.cr)
899
- for(let e=0;t.lr>e;e++){const i=3*(t.Ks+e)
900
- i>=0&&o.length>i&&(o[i]=n[0],o[i+1]=n[1],o[i+2]=n[2])}}}a.push({start:e.start,end:e.end,wh:e.pattern,color:n,bounds:[],glyphs:s,mh:Array.from(r).sort((t,e)=>t-e)})}}i.yh&&i.yh.forEach(t=>{const i=[]
901
- for(const n of e)if(n.hr>=t.start&&t.end>n.hr){i.push(n)
892
+ let r
893
+ if(i.fh&&s||i.yh){r=new Map
894
+ for(const t of e){const e=r.get(t.hr)
895
+ e?e.push(t):r.set(t.hr,[t])}}if(i.fh&&s&&r)for(const t of s){const e=i.fh[t.pattern]
896
+ if(!e)continue
897
+ const n=[],s=new Map
898
+ for(let i=t.start;t.end>i;i++){const t=r.get(i)
899
+ if(t)for(const i of t){n.push(i)
900
+ const t=s.get(i.cr)
901
+ t?t.push(i):s.set(i.cr,[i])
902
+ for(let t=0;i.lr>t;t++){const n=3*(i.Ks+t)
903
+ n>=0&&o.length>n&&(o[n]=e[0],o[n+1]=e[1],o[n+2]=e[2])}}}const h=Array.from(s.values()).map(t=>this.nc(t))
904
+ a.push({start:t.start,end:t.end,wh:t.pattern,color:e,bounds:h,glyphs:n,mh:Array.from(s.keys()).sort((t,e)=>t-e)})}if(i.yh&&r)for(const t of i.yh){const e=[],i=new Map
905
+ for(let n=t.start;t.end>n;n++){const s=r.get(n)
906
+ if(s)for(const n of s){e.push(n)
907
+ const s=i.get(n.cr)
908
+ s?s.push(n):i.set(n.cr,[n])
902
909
  for(let e=0;n.lr>e;e++){const i=3*(n.Ks+e)
903
- i>=0&&o.length>i&&(o[i]=t.color[0],o[i+1]=t.color[1],o[i+2]=t.color[2])}}a.push({start:t.start,end:t.end,wh:n.slice(t.start,t.end),color:t.color,bounds:[],glyphs:i,mh:[...new Set(i.map(t=>t.cr))]})})}return{colors:o,nc:a}}Kh(t,e,i,n,s,r,o,a){const{layout:h={}}=r,{width:c,align:l=("rtl"===h.direction?"right":"left")}=h
910
+ i>=0&&o.length>i&&(o[i]=t.color[0],o[i+1]=t.color[1],o[i+2]=t.color[2])}}}const s=Array.from(i.values()).map(t=>this.nc(t))
911
+ a.push({start:t.start,end:t.end,wh:n.slice(t.start,t.end),color:t.color,bounds:s,glyphs:e,mh:Array.from(i.keys()).sort((t,e)=>t-e)})}}return{colors:o,sc:a}}nc(t){if(0===t.length)return{min:{x:0,y:0,z:0},max:{x:0,y:0,z:0}}
912
+ let e=1/0,i=1/0,n=1/0,s=-1/0,r=-1/0,o=-1/0
913
+ for(const a of t)e>a.bounds.min.x&&(e=a.bounds.min.x),i>a.bounds.min.y&&(i=a.bounds.min.y),n>a.bounds.min.z&&(n=a.bounds.min.z),a.bounds.max.x>s&&(s=a.bounds.max.x),a.bounds.max.y>r&&(r=a.bounds.max.y),a.bounds.max.z>o&&(o=a.bounds.max.z)
914
+ return{min:{x:e,y:i,z:n},max:{x:s,y:r,z:o}}}Kh(t,e,i,n,s,r,o,a){const{layout:h={}}=r,{width:c,align:l=("rtl"===h.direction?"right":"left")}=h
904
915
  this.tc||(this.tc=new I(this.ae))
905
916
  const u=this.tc.ue({width:c,align:l,planeBounds:s}),f=u.offset
906
917
  if(s.min.x=u.le.min.x,s.max.x=u.le.max.x,0!==f){for(let e=0;t.length>e;e+=3)t[e]+=f
907
918
  for(let t=0;n.length>t;t++)n[t].bounds.min.x+=f,n[t].bounds.max.x+=f}let d,y
908
919
  if(r.color){const e=this.ec(t,n,r.color,r.text,a)
909
- d=e.colors,y=e.nc}const p=this.gr.ds()
910
- return{vertices:t,normals:e,indices:i,colors:d,glyphs:n,planeBounds:s,stats:{sc:i.length/3,rc:t.length/3,wn:p.wn,gn:p.gn,vn:p.vn},query:(()=>{let t=null
920
+ d=e.colors,y=e.sc}const p=this.gr.ds()
921
+ return{vertices:t,normals:e,indices:i,colors:d,glyphs:n,planeBounds:s,stats:{rc:i.length/3,oc:t.length/3,wn:p.wn,gn:p.gn,vn:p.vn},query:(()=>{let t=null
911
922
  return e=>{if(!o)throw Error("Original text not available for querying")
912
- return t||(t=new Mt(o,n)),t.uh(e)}})(),nc:y,glyphAttributes:void 0}}We(){if(!this.ae)throw Error("Font not loaded. Call loadFont() first")
913
- return z.We(this.ae.h)}static async oc(t,e){await Promise.all(t.map(async t=>{if(!Ft.xh.has(t))try{const i=await n(t,e)
914
- Ft.xh.set(t,i)}catch(e){h.warn(`Failed to pre-load patterns for ${t}: ${e}`)}}))}static ac(t,e){Ft.xh.set(t,e)}static hc(t){Ft.Eh=t===1/0?1/0:1048576*Math.max(1,Math.floor(t)),Ft.Ph()}getLoadedFont(){return this.ae}measureTextWidth(t,e=0){if(!this.ae)throw Error("Font not loaded. Call loadFont() first")
923
+ return t||(t=new Mt(o,n)),t.uh(e)}})(),sc:y,glyphAttributes:void 0}}We(){if(!this.ae)throw Error("Font not loaded. Call loadFont() first")
924
+ return j.We(this.ae.h)}static async ac(t,e){await Promise.all(t.map(async t=>{if(!Ft.xh.has(t))try{const i=await n(t,e)
925
+ Ft.xh.set(t,i)}catch(e){h.warn(`Failed to pre-load patterns for ${t}: ${e}`)}}))}static hc(t,e){Ft.xh.set(t,e)}static cc(t){Ft.Eh=t===1/0?1/0:1048576*Math.max(1,Math.floor(t)),Ft.Ph()}getLoadedFont(){return this.ae}measureTextWidth(t,e=0){if(!this.ae)throw Error("Font not loaded. Call loadFont() first")
915
926
  return M.measureTextWidth(this.ae,t,e)}getCacheSize(){return this.gr?this.gr.pr().size:0}clearCache(){this.gr&&this.gr.clearCache()}Xh(t,e){const i=new Float32Array(3*t),n=new Float32Array(t),s=new Float32Array(t),r=new Float32Array(t),o=new Float32Array(t)
916
927
  let a=1/0,h=-1/0
917
928
  for(let t=0;e.length>t;t++){const i=(e[t].bounds.min.x+e[t].bounds.max.x)/2
@@ -920,4 +931,4 @@ for(let h=0;e.length>h;h++){const l=e[h],u=(l.bounds.min.x+l.bounds.max.x)/2,f=(
920
931
  if(g>w){n.fill(h,w,g),s.fill(l.cr,w,g),r.fill(p,w,g),o.fill(y,w,g)
921
932
  for(let t=3*w;3*g>t;t+=3)i[t]=u,i[t+1]=f,i[t+2]=d}}return{glyphCenter:i,glyphIndex:n,glyphLineIndex:s,glyphProgress:r,glyphBaselineY:o}}Ch(){this.gr=void 0,this.Hh=void 0,this.tc=void 0}destroy(){if(!this.ae)return
922
933
  const t=this.ae
923
- try{V.oi(t)}catch(t){h.warn("Error destroying HarfBuzz objects:",t)}finally{this.ae=void 0,this.tc=void 0,this.Hh=void 0}}}t.DEFAULT_CURVE_FIDELITY=ut,t.FontMetadataExtractor=z,t.Text=Ft,t.cc=()=>new X,t.lc=Q})
934
+ try{V.oi(t)}catch(t){h.warn("Error destroying HarfBuzz objects:",t)}finally{this.ae=void 0,this.tc=void 0,this.Hh=void 0}}}t.DEFAULT_CURVE_FIDELITY=ut,t.FontMetadataExtractor=j,t.Text=Ft,t.lc=()=>new X,t.uc=Q})
@@ -333,6 +333,7 @@ declare class Text$1 {
333
333
  private updateFontVariations;
334
334
  private prepareLayout;
335
335
  private applyColorSystem;
336
+ private calculateGlyphBounds;
336
337
  private finalizeGeometry;
337
338
  getFontMetrics(): FontMetrics;
338
339
  static preloadPatterns(languages: string[], patternsPath?: string): Promise<void>;
@@ -39,6 +39,7 @@ export declare class Text {
39
39
  private updateFontVariations;
40
40
  private prepareLayout;
41
41
  private applyColorSystem;
42
+ private calculateGlyphBounds;
42
43
  private finalizeGeometry;
43
44
  getFontMetrics(): FontMetrics;
44
45
  static preloadPatterns(languages: string[], patternsPath?: string): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-text",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "3D mesh font geometry and text layout engine for the web",
5
5
  "main": "dist/three/index.cjs",
6
6
  "module": "dist/three/index.js",