textmode.js 0.1.4-beta.1 → 0.1.4-beta.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.
@@ -1,12 +1,12 @@
1
1
  var se = Object.defineProperty;
2
- var ae = (l, e, t) => e in l ? se(l, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : l[e] = t;
3
- var o = (l, e, t) => ae(l, typeof e != "symbol" ? e + "" : e, t);
2
+ var oe = (h, e, t) => e in h ? se(h, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : h[e] = t;
3
+ var a = (h, e, t) => oe(h, typeof e != "symbol" ? e + "" : e, t);
4
4
  class F extends Error {
5
5
  constructor(t, r, i = {}) {
6
6
  const s = F.createFormattedMessage(t, i);
7
7
  super(s);
8
- o(this, "originalError");
9
- o(this, "context");
8
+ a(this, "originalError");
9
+ a(this, "context");
10
10
  this.name = "TextmodeError", this.originalError = r, this.context = i;
11
11
  }
12
12
  /**
@@ -18,8 +18,8 @@ class F extends Error {
18
18
  i += `
19
19
 
20
20
  📋 Context:`;
21
- for (const [s, a] of Object.entries(r)) {
22
- const n = F.formatValue(a);
21
+ for (const [s, o] of Object.entries(r)) {
22
+ const n = F.formatValue(o);
23
23
  i += `
24
24
  - ${s}: ${n}`;
25
25
  }
@@ -41,15 +41,15 @@ class F extends Error {
41
41
  return t.length === 0 ? "[]" : t.length <= 5 ? `[${t.map((r) => F.formatValue(r)).join(", ")}]` : `[${t.slice(0, 3).map((r) => F.formatValue(r)).join(", ")}, ... +${t.length - 3} more]`;
42
42
  if (typeof t == "object") {
43
43
  const r = Object.keys(t);
44
- return r.length === 0 ? "{}" : r.length <= 3 ? `{ ${r.map((a) => `${a}: ${F.formatValue(t[a])}`).join(", ")} }` : `{ ${r.slice(0, 2).map((s) => `${s}: ${F.formatValue(t[s])}`).join(", ")}, ... +${r.length - 2} more }`;
44
+ return r.length === 0 ? "{}" : r.length <= 3 ? `{ ${r.map((o) => `${o}: ${F.formatValue(t[o])}`).join(", ")} }` : `{ ${r.slice(0, 2).map((s) => `${s}: ${F.formatValue(t[s])}`).join(", ")}, ... +${r.length - 2} more }`;
45
45
  }
46
46
  return String(t);
47
47
  }
48
48
  }
49
- var ne = /* @__PURE__ */ ((l) => (l[l.SILENT = 0] = "SILENT", l[l.WARNING = 1] = "WARNING", l[l.ERROR = 2] = "ERROR", l[l.THROW = 3] = "THROW", l))(ne || {});
49
+ var ne = /* @__PURE__ */ ((h) => (h[h.SILENT = 0] = "SILENT", h[h.WARNING = 1] = "WARNING", h[h.ERROR = 2] = "ERROR", h[h.THROW = 3] = "THROW", h))(ne || {});
50
50
  const E = class E {
51
51
  constructor() {
52
- o(this, "_options", {
52
+ a(this, "_options", {
53
53
  globalLevel: 3
54
54
  /* THROW */
55
55
  });
@@ -103,19 +103,19 @@ const E = class E {
103
103
  this._options.globalLevel = e;
104
104
  }
105
105
  };
106
- o(E, "_instance", null);
107
- let z = E;
108
- const x = z.getInstance();
109
- class oe {
106
+ a(E, "_instance", null);
107
+ let $ = E;
108
+ const x = $.getInstance();
109
+ class ae {
110
110
  constructor(e, t, r = t, i = {}) {
111
- o(this, "gl");
112
- o(this, "_framebuffer");
113
- o(this, "_texture");
114
- o(this, "_width");
115
- o(this, "_height");
116
- o(this, "options");
117
- o(this, "previousState", null);
118
- o(this, "_pixels", null);
111
+ a(this, "gl");
112
+ a(this, "_framebuffer");
113
+ a(this, "_texture");
114
+ a(this, "_width");
115
+ a(this, "_height");
116
+ a(this, "options");
117
+ a(this, "previousState", null);
118
+ a(this, "_pixels", null);
119
119
  this.gl = e, this._width = t, this._height = r, this.options = {
120
120
  filter: "nearest",
121
121
  wrap: "clamp",
@@ -189,18 +189,32 @@ class oe {
189
189
  get(e, t, r, i) {
190
190
  const { gl: s } = this;
191
191
  if (e === void 0 && t === void 0) {
192
- const a = new Uint8Array(this._width * this._height * 4), n = s.getParameter(s.FRAMEBUFFER_BINDING);
193
- return s.bindFramebuffer(s.FRAMEBUFFER, this._framebuffer), s.readPixels(0, 0, this._width, this._height, s.RGBA, s.UNSIGNED_BYTE, a), s.bindFramebuffer(s.FRAMEBUFFER, n), a;
192
+ const o = new Uint8Array(this._width * this._height * 4), n = s.getParameter(s.FRAMEBUFFER_BINDING);
193
+ return s.bindFramebuffer(s.FRAMEBUFFER, this._framebuffer), s.readPixels(0, 0, this._width, this._height, s.RGBA, s.UNSIGNED_BYTE, o), s.bindFramebuffer(s.FRAMEBUFFER, n), o;
194
194
  } else if (r === void 0 && i === void 0) {
195
195
  (e < 0 || t < 0 || e >= this._width || t >= this._height) && (console.warn("The x and y values passed to Framebuffer.get are outside of its range and will be clamped."), e = Math.max(0, Math.min(e, this._width - 1)), t = Math.max(0, Math.min(t, this._height - 1)));
196
- const a = new Uint8Array(4), n = s.getParameter(s.FRAMEBUFFER_BINDING);
197
- return s.bindFramebuffer(s.FRAMEBUFFER, this._framebuffer), s.readPixels(e, t, 1, 1, s.RGBA, s.UNSIGNED_BYTE, a), s.bindFramebuffer(s.FRAMEBUFFER, n), [a[0], a[1], a[2], a[3]];
196
+ const o = new Uint8Array(4), n = s.getParameter(s.FRAMEBUFFER_BINDING);
197
+ return s.bindFramebuffer(s.FRAMEBUFFER, this._framebuffer), s.readPixels(e, t, 1, 1, s.RGBA, s.UNSIGNED_BYTE, o), s.bindFramebuffer(s.FRAMEBUFFER, n), [o[0], o[1], o[2], o[3]];
198
198
  } else {
199
199
  e = Math.max(0, Math.min(e, this._width - 1)), t = Math.max(0, Math.min(t, this._height - 1)), r = Math.max(1, Math.min(r, this._width - e)), i = Math.max(1, Math.min(i, this._height - t));
200
- const a = new Uint8Array(r * i * 4), n = s.getParameter(s.FRAMEBUFFER_BINDING);
201
- return s.bindFramebuffer(s.FRAMEBUFFER, this._framebuffer), s.readPixels(e, t, r, i, s.RGBA, s.UNSIGNED_BYTE, a), s.bindFramebuffer(s.FRAMEBUFFER, n), a;
200
+ const o = new Uint8Array(r * i * 4), n = s.getParameter(s.FRAMEBUFFER_BINDING);
201
+ return s.bindFramebuffer(s.FRAMEBUFFER, this._framebuffer), s.readPixels(e, t, r, i, s.RGBA, s.UNSIGNED_BYTE, o), s.bindFramebuffer(s.FRAMEBUFFER, n), o;
202
202
  }
203
203
  }
204
+ /**
205
+ * Dispose of WebGL resources used by this framebuffer.
206
+ * This method is idempotent and safe to call multiple times.
207
+ */
208
+ dispose() {
209
+ const { gl: e } = this;
210
+ this._framebuffer && (e.deleteFramebuffer(this._framebuffer), this._framebuffer = null), this._texture && (e.deleteTexture(this._texture), this._texture = null), this._pixels = null;
211
+ }
212
+ /**
213
+ * Check if this framebuffer has been disposed
214
+ */
215
+ get isDisposed() {
216
+ return this._framebuffer === null || this._texture === null;
217
+ }
204
218
  get framebuffer() {
205
219
  return this._framebuffer;
206
220
  }
@@ -219,29 +233,29 @@ class oe {
219
233
  }
220
234
  class Q {
221
235
  constructor(e, t, r) {
222
- o(this, "gl");
223
- o(this, "x");
224
- o(this, "y");
236
+ a(this, "gl");
237
+ a(this, "x");
238
+ a(this, "y");
225
239
  this.gl = e, this.x = t, this.y = r;
226
240
  }
227
241
  }
228
- class M {
242
+ class A {
229
243
  constructor(e, t, r, i, s) {
230
244
  /** The WebGL rendering context */
231
- o(this, "gl");
245
+ a(this, "gl");
232
246
  /** The vertex buffer containing position and texture coordinates */
233
- o(this, "vertexBuffer");
247
+ a(this, "vertexBuffer");
234
248
  /** The number of vertices in this geometry (always 6 for two triangles) */
235
- o(this, "vertexCount", 6);
249
+ a(this, "vertexCount", 6);
236
250
  /** Bytes per vertex: depends on position format (vec2 vs vec3) */
237
- o(this, "bytesPerVertex");
251
+ a(this, "bytesPerVertex");
238
252
  this.gl = e, this.bytesPerVertex = 16;
239
- const a = e.getParameter(e.VIEWPORT), n = a[2], h = a[3], c = e.getParameter(e.FRAMEBUFFER_BINDING) !== null, u = t / n * 2 - 1, d = (t + i) / n * 2 - 1;
253
+ const o = e.getParameter(e.VIEWPORT), n = o[2], l = o[3], c = e.getParameter(e.FRAMEBUFFER_BINDING) !== null, u = t / n * 2 - 1, d = (t + i) / n * 2 - 1;
240
254
  let f, g;
241
- c ? (f = r / h * 2 - 1, g = (r + s) / h * 2 - 1) : (f = 1 - r / h * 2, g = 1 - (r + s) / h * 2);
242
- let _, p, C, b;
243
- _ = u, C = d, p = f, b = g;
244
- const v = this.generateVertices(_, p, C, b);
255
+ c ? (f = r / l * 2 - 1, g = (r + s) / l * 2 - 1) : (f = 1 - r / l * 2, g = 1 - (r + s) / l * 2);
256
+ let p, _, b, C;
257
+ p = u, b = d, _ = f, C = g;
258
+ const v = this.generateVertices(p, _, b, C);
245
259
  this.vertexBuffer = e.createBuffer(), e.bindBuffer(e.ARRAY_BUFFER, this.vertexBuffer), e.bufferData(e.ARRAY_BUFFER, v, e.STATIC_DRAW);
246
260
  }
247
261
  /**
@@ -292,18 +306,18 @@ class M {
292
306
  this.gl.enableVertexAttribArray(t), this.gl.vertexAttribPointer(t, 2, this.gl.FLOAT, !1, this.bytesPerVertex, 0), this.gl.enableVertexAttribArray(r), this.gl.vertexAttribPointer(r, 2, this.gl.FLOAT, !1, this.bytesPerVertex, 8), this.gl.drawArrays(this.gl.TRIANGLES, 0, this.vertexCount), this.gl.disableVertexAttribArray(t), this.gl.disableVertexAttribArray(r);
293
307
  }
294
308
  }
295
- class le extends Q {
296
- constructor(t, r, i, s, a) {
309
+ class he extends Q {
310
+ constructor(t, r, i, s, o) {
297
311
  super(t, r, i);
298
- o(this, "width");
299
- o(this, "height");
300
- this.width = s, this.height = a;
312
+ a(this, "width");
313
+ a(this, "height");
314
+ this.width = s, this.height = o;
301
315
  }
302
316
  /**
303
317
  * Render the filled rectangle using the existing Rectangle geometry.
304
318
  */
305
319
  renderFill() {
306
- new M(this.gl, this.x, this.y, this.width, this.height).render();
320
+ new A(this.gl, this.x, this.y, this.width, this.height).render();
307
321
  }
308
322
  /**
309
323
  * Render the stroke rectangle as four separate Rectangle instances for each edge.
@@ -312,30 +326,30 @@ class le extends Q {
312
326
  */
313
327
  renderStroke(t) {
314
328
  if (t <= 0) return;
315
- const r = new M(this.gl, this.x, this.y, this.width, t), i = new M(this.gl, this.x + this.width - t, this.y, t, this.height), s = new M(this.gl, this.x, this.y + this.height - t, this.width, t), a = new M(this.gl, this.x, this.y, t, this.height);
316
- r.render(), i.render(), s.render(), a.render();
329
+ const r = new A(this.gl, this.x, this.y, this.width, t), i = new A(this.gl, this.x + this.width - t, this.y, t, this.height), s = new A(this.gl, this.x, this.y + this.height - t, this.width, t), o = new A(this.gl, this.x, this.y, t, this.height);
330
+ r.render(), i.render(), s.render(), o.render();
317
331
  }
318
332
  }
319
- class he {
320
- constructor(e, t, r, i, s, a) {
333
+ class le {
334
+ constructor(e, t, r, i, s, o) {
321
335
  /** The WebGL rendering context */
322
- o(this, "gl");
336
+ a(this, "gl");
323
337
  /** The vertex buffer containing position and texture coordinates */
324
- o(this, "vertexBuffer");
338
+ a(this, "vertexBuffer");
325
339
  /** The number of vertices in this geometry (always 6 for two triangles) */
326
- o(this, "vertexCount", 6);
340
+ a(this, "vertexCount", 6);
327
341
  /** Bytes per vertex: vec2+vec2 = 16 bytes */
328
- o(this, "bytesPerVertex");
342
+ a(this, "bytesPerVertex");
329
343
  this.gl = e, this.bytesPerVertex = 16;
330
- const n = e.getParameter(e.VIEWPORT), h = n[2], c = n[3], u = e.getParameter(e.FRAMEBUFFER_BINDING) !== null, d = i - t, f = s - r, g = Math.sqrt(d * d + f * f);
344
+ const n = e.getParameter(e.VIEWPORT), l = n[2], c = n[3], u = e.getParameter(e.FRAMEBUFFER_BINDING) !== null, d = i - t, f = s - r, g = Math.sqrt(d * d + f * f);
331
345
  if (g === 0) {
332
346
  const ie = this.generateVertices(0, 0, 0, 0);
333
347
  this.vertexBuffer = e.createBuffer(), e.bindBuffer(e.ARRAY_BUFFER, this.vertexBuffer), e.bufferData(e.ARRAY_BUFFER, ie, e.STATIC_DRAW);
334
348
  return;
335
349
  }
336
- const _ = d / g, C = -(f / g), b = _, v = a / 2, w = t + C * v, A = r + b * v, R = t - C * v, y = r - b * v, P = i + C * v, D = s + b * v, Z = i - C * v, W = s - b * v, J = w / h * 2 - 1, K = R / h * 2 - 1, ee = P / h * 2 - 1, te = Z / h * 2 - 1;
350
+ const p = d / g, b = -(f / g), C = p, v = o / 2, w = t + b * v, D = r + C * v, R = t - b * v, y = r - C * v, P = i + b * v, M = s + C * v, Z = i - b * v, W = s - C * v, J = w / l * 2 - 1, K = R / l * 2 - 1, ee = P / l * 2 - 1, te = Z / l * 2 - 1;
337
351
  let B, G, V, k;
338
- u ? (B = A / c * 2 - 1, G = y / c * 2 - 1, V = D / c * 2 - 1, k = W / c * 2 - 1) : (B = 1 - A / c * 2, G = 1 - y / c * 2, V = 1 - D / c * 2, k = 1 - W / c * 2);
352
+ u ? (B = D / c * 2 - 1, G = y / c * 2 - 1, V = M / c * 2 - 1, k = W / c * 2 - 1) : (B = 1 - D / c * 2, G = 1 - y / c * 2, V = 1 - M / c * 2, k = 1 - W / c * 2);
339
353
  const re = this.generateLineVertices(
340
354
  J,
341
355
  B,
@@ -391,7 +405,7 @@ class he {
391
405
  * Uses the four corners calculated based on line direction and thickness
392
406
  * @private
393
407
  */
394
- generateLineVertices(e, t, r, i, s, a, n, h) {
408
+ generateLineVertices(e, t, r, i, s, o, n, l) {
395
409
  return new Float32Array([
396
410
  e,
397
411
  t,
@@ -404,7 +418,7 @@ class he {
404
418
  1,
405
419
  // corner2 (start - perpendicular)
406
420
  s,
407
- a,
421
+ o,
408
422
  1,
409
423
  0,
410
424
  // corner3 (end + perpendicular)
@@ -414,12 +428,12 @@ class he {
414
428
  1,
415
429
  // corner2 (start - perpendicular)
416
430
  n,
417
- h,
431
+ l,
418
432
  1,
419
433
  1,
420
434
  // corner4 (end - perpendicular)
421
435
  s,
422
- a,
436
+ o,
423
437
  1,
424
438
  0
425
439
  // corner3 (end + perpendicular)
@@ -436,11 +450,11 @@ class he {
436
450
  }
437
451
  }
438
452
  class ce extends Q {
439
- constructor(t, r, i, s, a) {
453
+ constructor(t, r, i, s, o) {
440
454
  super(t, r, i);
441
- o(this, "x2");
442
- o(this, "y2");
443
- this.x2 = s, this.y2 = a;
455
+ a(this, "x2");
456
+ a(this, "y2");
457
+ this.x2 = s, this.y2 = o;
444
458
  }
445
459
  /**
446
460
  * Lines don't support fill rendering - this method does nothing.
@@ -454,23 +468,23 @@ class ce extends Q {
454
468
  */
455
469
  renderStroke(t) {
456
470
  if (t <= 0) return;
457
- new he(this.gl, this.x, this.y, this.x2, this.y2, t).render();
471
+ new le(this.gl, this.x, this.y, this.x2, this.y2, t).render();
458
472
  }
459
473
  }
460
474
  class T {
461
475
  constructor(e, t, r) {
462
- o(this, "gl");
463
- o(this, "program");
464
- o(this, "uniformLocations", /* @__PURE__ */ new Map());
465
- o(this, "attributeLocations", /* @__PURE__ */ new Map());
466
- o(this, "textureUnitCounter", 0);
476
+ a(this, "gl");
477
+ a(this, "program");
478
+ a(this, "uniformLocations", /* @__PURE__ */ new Map());
479
+ a(this, "attributeLocations", /* @__PURE__ */ new Map());
480
+ a(this, "textureUnitCounter", 0);
467
481
  this.gl = e, this.program = this.createProgram(t, r), this.cacheLocations();
468
482
  }
469
483
  createProgram(e, t) {
470
484
  const r = this.createShader(this.gl.VERTEX_SHADER, e), i = this.createShader(this.gl.FRAGMENT_SHADER, t), s = this.gl.createProgram();
471
485
  if (this.gl.attachShader(s, r), this.gl.attachShader(s, i), this.gl.linkProgram(s), !this.gl.getProgramParameter(s, this.gl.LINK_STATUS)) {
472
- const a = this.gl.getProgramInfoLog(s);
473
- throw new Error(`Shader program link error: ${a}`);
486
+ const o = this.gl.getProgramInfoLog(s);
487
+ throw new Error(`Shader program link error: ${o}`);
474
488
  }
475
489
  return this.gl.deleteShader(r), this.gl.deleteShader(i), s;
476
490
  }
@@ -520,7 +534,7 @@ class T {
520
534
  this.gl.uniform1i(r, t ? 1 : 0);
521
535
  else if (Array.isArray(t))
522
536
  if (i && (i.type === this.gl.INT_VEC2 || i.type === this.gl.INT_VEC3 || i.type === this.gl.INT_VEC4)) {
523
- const s = t.map((a) => Math.floor(a));
537
+ const s = t.map((o) => Math.floor(o));
524
538
  switch (s.length) {
525
539
  case 2:
526
540
  this.gl.uniform2iv(r, s);
@@ -590,6 +604,19 @@ class T {
590
604
  get glProgram() {
591
605
  return this.program;
592
606
  }
607
+ /**
608
+ * Dispose of WebGL resources used by this shader.
609
+ * This method is idempotent and safe to call multiple times.
610
+ */
611
+ dispose() {
612
+ this.program && (this.gl.deleteProgram(this.program), this.program = null), this.uniformLocations.clear(), this.attributeLocations.clear(), this.textureUnitCounter = 0;
613
+ }
614
+ /**
615
+ * Check if this shader has been disposed
616
+ */
617
+ get isDisposed() {
618
+ return this.program === null;
619
+ }
593
620
  /**
594
621
  * Reset texture unit counter (useful when starting a new frame)
595
622
  */
@@ -600,22 +627,22 @@ class T {
600
627
  var S = "attribute vec2 a_position;attribute vec2 a_texCoord;varying vec2 v_uv;uniform float u_rotation;uniform vec2 u_center;uniform float u_aspectRatio;mat2 rotate2D(float angle){float s=sin(angle);float c=cos(angle);return mat2(c,-s,s,c);}void main(){v_uv=a_texCoord;vec2 pos=a_position;pos-=u_center;pos.x*=u_aspectRatio;pos=rotate2D(-u_rotation)*pos;pos.x/=u_aspectRatio;pos+=u_center;gl_Position=vec4(pos,0.0,1.0);}", ue = "precision lowp float;uniform sampler2D u_texture;varying vec2 v_uv;void main(){gl_FragColor=texture2D(u_texture,v_uv);}", de = "precision lowp float;uniform vec4 u_color;void main(){gl_FragColor=u_color;}";
601
628
  class fe {
602
629
  constructor(e) {
603
- o(this, "gl");
604
- o(this, "imageShader");
605
- o(this, "solidColorShader");
606
- o(this, "currentShader", null);
630
+ a(this, "gl");
631
+ a(this, "imageShader");
632
+ a(this, "solidColorShader");
633
+ a(this, "currentShader", null);
607
634
  // Fill state management - default: white fill enabled
608
- o(this, "currentFillColor", [1, 1, 1, 1]);
609
- o(this, "fillMode", !0);
635
+ a(this, "currentFillColor", [1, 1, 1, 1]);
636
+ a(this, "fillMode", !0);
610
637
  // Stroke state management - default: black stroke enabled, weight 1
611
- o(this, "currentStrokeColor", [0, 0, 0, 1]);
612
- o(this, "currentStrokeWeight", 1);
613
- o(this, "strokeMode", !0);
638
+ a(this, "currentStrokeColor", [0, 0, 0, 1]);
639
+ a(this, "currentStrokeWeight", 1);
640
+ a(this, "strokeMode", !0);
614
641
  // Transformation state management
615
- o(this, "currentRotation", 0);
642
+ a(this, "currentRotation", 0);
616
643
  // in degrees
617
644
  // State stack for push/pop functionality
618
- o(this, "stateStack", []);
645
+ a(this, "stateStack", []);
619
646
  this.gl = e, this.imageShader = new T(this.gl, S, ue), this.solidColorShader = new T(this.gl, S, de), this.gl.enable(this.gl.BLEND), this.gl.blendEquation(this.gl.FUNC_ADD), this.gl.blendFunc(this.gl.ONE, this.gl.ONE_MINUS_SRC_ALPHA);
620
647
  }
621
648
  /**
@@ -729,18 +756,18 @@ class fe {
729
756
  * Draw a rectangle with the current fill and/or stroke settings
730
757
  */
731
758
  rect(e, t, r, i) {
732
- const s = new le(this.gl, e, t, r, i);
759
+ const s = new he(this.gl, e, t, r, i);
733
760
  if (this.currentShader !== null) {
734
761
  if (this.currentRotation !== 0) {
735
- const { centerX: d, centerY: f, radians: g, aspectRatio: _ } = this.calculateRotationParams(e, t, r, i);
736
- this.setUniform("u_rotation", g), this.setUniform("u_center", [d, f]), this.setUniform("u_aspectRatio", _);
762
+ const { centerX: d, centerY: f, radians: g, aspectRatio: p } = this.calculateRotationParams(e, t, r, i);
763
+ this.setUniform("u_rotation", g), this.setUniform("u_center", [d, f]), this.setUniform("u_aspectRatio", p);
737
764
  } else
738
765
  this.setUniform("u_rotation", 0), this.setUniform("u_center", [0, 0]), this.setUniform("u_aspectRatio", 1);
739
766
  s.renderFill(), this.currentShader = null;
740
767
  return;
741
768
  }
742
- const a = this.solidColorShader, { centerX: n, centerY: h, radians: c, aspectRatio: u } = this.calculateRotationParams(e, t, r, i);
743
- this.fillMode && (this.shader(a), this.setUniform("u_color", this.currentFillColor), this.setUniform("u_rotation", c), this.setUniform("u_center", [n, h]), this.setUniform("u_aspectRatio", u), s.renderFill()), this.strokeMode && (this.shader(a), this.setUniform("u_color", this.currentStrokeColor), this.setUniform("u_rotation", c), this.setUniform("u_center", [n, h]), this.setUniform("u_aspectRatio", u), s.renderStroke(this.currentStrokeWeight)), this.currentShader = null;
769
+ const o = this.solidColorShader, { centerX: n, centerY: l, radians: c, aspectRatio: u } = this.calculateRotationParams(e, t, r, i);
770
+ this.fillMode && (this.shader(o), this.setUniform("u_color", this.currentFillColor), this.setUniform("u_rotation", c), this.setUniform("u_center", [n, l]), this.setUniform("u_aspectRatio", u), s.renderFill()), this.strokeMode && (this.shader(o), this.setUniform("u_color", this.currentStrokeColor), this.setUniform("u_rotation", c), this.setUniform("u_center", [n, l]), this.setUniform("u_aspectRatio", u), s.renderStroke(this.currentStrokeWeight)), this.currentShader = null;
744
771
  }
745
772
  /**
746
773
  * Draw a line from (x1, y1) to (x2, y2) with the current stroke settings.
@@ -755,31 +782,31 @@ class fe {
755
782
  const s = new ce(this.gl, e, t, r, i);
756
783
  if (this.currentShader !== null) {
757
784
  if (this.currentRotation !== 0) {
758
- const p = (e + r) / 2, C = (t + i) / 2, b = Math.abs(r - e), v = Math.abs(i - t), { centerX: w, centerY: A, radians: R, aspectRatio: y } = this.calculateRotationParams(p - b / 2, C - v / 2, b, v);
759
- this.setUniform("u_rotation", R), this.setUniform("u_center", [w, A]), this.setUniform("u_aspectRatio", y);
785
+ const _ = (e + r) / 2, b = (t + i) / 2, C = Math.abs(r - e), v = Math.abs(i - t), { centerX: w, centerY: D, radians: R, aspectRatio: y } = this.calculateRotationParams(_ - C / 2, b - v / 2, C, v);
786
+ this.setUniform("u_rotation", R), this.setUniform("u_center", [w, D]), this.setUniform("u_aspectRatio", y);
760
787
  } else
761
788
  this.setUniform("u_rotation", 0), this.setUniform("u_center", [0, 0]), this.setUniform("u_aspectRatio", 1);
762
789
  s.renderStroke(this.currentStrokeWeight), this.currentShader = null;
763
790
  return;
764
791
  }
765
- const a = this.solidColorShader, n = (e + r) / 2, h = (t + i) / 2, c = Math.abs(r - e), u = Math.abs(i - t), { centerX: d, centerY: f, radians: g, aspectRatio: _ } = this.calculateRotationParams(n - c / 2, h - u / 2, c, u);
766
- this.shader(a), this.setUniform("u_color", this.currentStrokeColor), this.setUniform("u_rotation", g), this.setUniform("u_center", [d, f]), this.setUniform("u_aspectRatio", _), s.renderStroke(this.currentStrokeWeight), this.currentShader = null;
792
+ const o = this.solidColorShader, n = (e + r) / 2, l = (t + i) / 2, c = Math.abs(r - e), u = Math.abs(i - t), { centerX: d, centerY: f, radians: g, aspectRatio: p } = this.calculateRotationParams(n - c / 2, l - u / 2, c, u);
793
+ this.shader(o), this.setUniform("u_color", this.currentStrokeColor), this.setUniform("u_rotation", g), this.setUniform("u_center", [d, f]), this.setUniform("u_aspectRatio", p), s.renderStroke(this.currentStrokeWeight), this.currentShader = null;
767
794
  }
768
795
  /**
769
796
  * Calculate rotation parameters for built-in shaders (NDC coordinates)
770
797
  */
771
798
  calculateRotationParams(e, t, r, i) {
772
- const s = this.gl.getParameter(this.gl.VIEWPORT), a = s[2], n = s[3], h = a / n, c = this.gl.getParameter(this.gl.FRAMEBUFFER_BINDING) !== null, u = e + r / 2, d = t + i / 2, f = u / a * 2 - 1;
799
+ const s = this.gl.getParameter(this.gl.VIEWPORT), o = s[2], n = s[3], l = o / n, c = this.gl.getParameter(this.gl.FRAMEBUFFER_BINDING) !== null, u = e + r / 2, d = t + i / 2, f = u / o * 2 - 1;
773
800
  let g;
774
801
  c ? g = d / n * 2 - 1 : g = 1 - d / n * 2;
775
- const _ = this.currentRotation * Math.PI / 180;
776
- return { centerX: f, centerY: g, radians: _, aspectRatio: h };
802
+ const p = this.currentRotation * Math.PI / 180;
803
+ return { centerX: f, centerY: g, radians: p, aspectRatio: l };
777
804
  }
778
805
  /**
779
806
  * Create a new framebuffer
780
807
  */
781
808
  createFramebuffer(e, t, r = {}) {
782
- return new oe(this.gl, e, t, r);
809
+ return new ae(this.gl, e, t, r);
783
810
  }
784
811
  /**
785
812
  * Fill the current framebuffer with a solid color
@@ -805,23 +832,36 @@ class fe {
805
832
  get context() {
806
833
  return this.gl;
807
834
  }
835
+ /**
836
+ * Dispose of all WebGL resources managed by this renderer.
837
+ * This method is idempotent and safe to call multiple times.
838
+ */
839
+ dispose() {
840
+ this.imageShader && !this.imageShader.isDisposed && this.imageShader.dispose(), this.solidColorShader && !this.solidColorShader.isDisposed && this.solidColorShader.dispose(), this.imageShader = null, this.solidColorShader = null, this.currentShader = null, this.stateStack = [];
841
+ }
842
+ /**
843
+ * Check if this renderer has been disposed
844
+ */
845
+ get isDisposed() {
846
+ return this.imageShader === null || this.solidColorShader === null;
847
+ }
808
848
  /**
809
849
  * Render a framebuffer at a specific position with optional scaling
810
850
  */
811
851
  image(e, t, r, i, s) {
812
852
  this.shader(this.imageShader), this.setUniform("u_texture", e.texture);
813
- const { centerX: a, centerY: n, radians: h, aspectRatio: c } = this.calculateRotationParams(
853
+ const { centerX: o, centerY: n, radians: l, aspectRatio: c } = this.calculateRotationParams(
814
854
  t,
815
855
  r,
816
856
  i ?? e.width,
817
857
  s ?? e.height
818
858
  );
819
- this.setUniform("u_rotation", h), this.setUniform("u_center", [a, n]), this.setUniform("u_aspectRatio", c), this.rect(t, r, i ?? e.width, s ?? e.height);
859
+ this.setUniform("u_rotation", l), this.setUniform("u_center", [o, n]), this.setUniform("u_aspectRatio", c), this.rect(t, r, i ?? e.width, s ?? e.height);
820
860
  }
821
861
  }
822
862
  var m = {};
823
- m.parse = function(l) {
824
- var e = function(s, a, n, h) {
863
+ m.parse = function(h) {
864
+ var e = function(s, o, n, l) {
825
865
  var c = m.T, u = {
826
866
  cmap: c.cmap,
827
867
  head: c.head,
@@ -830,119 +870,119 @@ m.parse = function(l) {
830
870
  hmtx: c.hmtx,
831
871
  loca: c.loca,
832
872
  glyf: c.glyf
833
- }, d = { _data: s, _index: a, _offset: n };
873
+ }, d = { _data: s, _index: o, _offset: n };
834
874
  for (var f in u) {
835
875
  var g = m.findTable(s, f, n);
836
876
  if (g) {
837
- var _ = g[0], p = h[_];
838
- p == null && (p = u[f].parseTab(s, _, g[1], d)), d[f] = h[_] = p;
877
+ var p = g[0], _ = l[p];
878
+ _ == null && (_ = u[f].parseTab(s, p, g[1], d)), d[f] = l[p] = _;
839
879
  }
840
880
  }
841
881
  return d;
842
- }, t = new Uint8Array(l), r = {}, i = e(t, 0, 0, r);
882
+ }, t = new Uint8Array(h), r = {}, i = e(t, 0, 0, r);
843
883
  return [i];
844
884
  };
845
- m.findTable = function(l, e, t) {
846
- for (var r = m.B, i = r.readUshort(l, t + 4), s = t + 12, a = 0; a < i; a++) {
847
- var n = r.readASCII(l, s, 4);
848
- r.readUint(l, s + 4);
849
- var h = r.readUint(l, s + 8), c = r.readUint(l, s + 12);
850
- if (n == e) return [h, c];
885
+ m.findTable = function(h, e, t) {
886
+ for (var r = m.B, i = r.readUshort(h, t + 4), s = t + 12, o = 0; o < i; o++) {
887
+ var n = r.readASCII(h, s, 4);
888
+ r.readUint(h, s + 4);
889
+ var l = r.readUint(h, s + 8), c = r.readUint(h, s + 12);
890
+ if (n == e) return [l, c];
851
891
  s += 16;
852
892
  }
853
893
  return null;
854
894
  };
855
895
  m.T = {};
856
896
  m.B = {
857
- readShort: function(l, e) {
897
+ readShort: function(h, e) {
858
898
  var t = m.B.t.uint16;
859
- return t[0] = l[e] << 8 | l[e + 1], m.B.t.int16[0];
899
+ return t[0] = h[e] << 8 | h[e + 1], m.B.t.int16[0];
860
900
  },
861
- readUshort: function(l, e) {
862
- return l[e] << 8 | l[e + 1];
901
+ readUshort: function(h, e) {
902
+ return h[e] << 8 | h[e + 1];
863
903
  },
864
- readUshorts: function(l, e, t) {
904
+ readUshorts: function(h, e, t) {
865
905
  for (var r = [], i = 0; i < t; i++)
866
- r.push(m.B.readUshort(l, e + i * 2));
906
+ r.push(m.B.readUshort(h, e + i * 2));
867
907
  return r;
868
908
  },
869
- readUint: function(l, e) {
909
+ readUint: function(h, e) {
870
910
  var t = m.B.t.uint8;
871
- return t[3] = l[e], t[2] = l[e + 1], t[1] = l[e + 2], t[0] = l[e + 3], m.B.t.uint32[0];
911
+ return t[3] = h[e], t[2] = h[e + 1], t[1] = h[e + 2], t[0] = h[e + 3], m.B.t.uint32[0];
872
912
  },
873
- readASCII: function(l, e, t) {
874
- for (var r = "", i = 0; i < t; i++) r += String.fromCharCode(l[e + i]);
913
+ readASCII: function(h, e, t) {
914
+ for (var r = "", i = 0; i < t; i++) r += String.fromCharCode(h[e + i]);
875
915
  return r;
876
916
  },
877
917
  // Simplified typed array buffer - only what's needed
878
918
  t: function() {
879
- var l = new ArrayBuffer(8);
919
+ var h = new ArrayBuffer(8);
880
920
  return {
881
- uint8: new Uint8Array(l),
882
- int16: new Int16Array(l),
883
- uint16: new Uint16Array(l),
884
- uint32: new Uint32Array(l)
921
+ uint8: new Uint8Array(h),
922
+ int16: new Int16Array(h),
923
+ uint16: new Uint16Array(h),
924
+ uint32: new Uint32Array(h)
885
925
  };
886
926
  }()
887
927
  };
888
928
  m.T.cmap = {
889
- parseTab: function(l, e, t) {
929
+ parseTab: function(h, e, t) {
890
930
  var r = { tables: [], ids: {}, off: e };
891
- l = new Uint8Array(l.buffer, e, t), e = 0;
892
- var i = m.B, s = i.readUshort, a = m.T.cmap;
893
- s(l, e), e += 2;
894
- var n = s(l, e);
931
+ h = new Uint8Array(h.buffer, e, t), e = 0;
932
+ var i = m.B, s = i.readUshort, o = m.T.cmap;
933
+ s(h, e), e += 2;
934
+ var n = s(h, e);
895
935
  e += 2;
896
- for (var h = [], c = 0; c < n; c++) {
897
- var u = s(l, e);
936
+ for (var l = [], c = 0; c < n; c++) {
937
+ var u = s(h, e);
898
938
  e += 2;
899
- var d = s(l, e);
939
+ var d = s(h, e);
900
940
  e += 2;
901
- var f = i.readUint(l, e);
941
+ var f = i.readUint(h, e);
902
942
  e += 4;
903
- var g = "p" + u + "e" + d, _ = h.indexOf(f);
904
- if (_ == -1) {
905
- _ = r.tables.length;
906
- var p = {};
907
- h.push(f);
908
- var C = p.format = s(l, f);
909
- C == 4 ? p = a.parse4(l, f, p) : C == 12 && (p = a.parse12(l, f, p)), r.tables.push(p);
943
+ var g = "p" + u + "e" + d, p = l.indexOf(f);
944
+ if (p == -1) {
945
+ p = r.tables.length;
946
+ var _ = {};
947
+ l.push(f);
948
+ var b = _.format = s(h, f);
949
+ b == 4 ? _ = o.parse4(h, f, _) : b == 12 && (_ = o.parse12(h, f, _)), r.tables.push(_);
910
950
  }
911
- r.ids[g] != null && console.log("multiple tables for one platform+encoding: " + g), r.ids[g] = _;
951
+ r.ids[g] != null && console.log("multiple tables for one platform+encoding: " + g), r.ids[g] = p;
912
952
  }
913
953
  return r;
914
954
  },
915
- parse4: function(l, e, t) {
916
- var r = m.B, i = r.readUshort, s = r.readUshorts, a = e;
955
+ parse4: function(h, e, t) {
956
+ var r = m.B, i = r.readUshort, s = r.readUshorts, o = e;
917
957
  e += 2;
918
- var n = i(l, e);
919
- e += 2, i(l, e), e += 2;
920
- var h = i(l, e);
958
+ var n = i(h, e);
959
+ e += 2, i(h, e), e += 2;
960
+ var l = i(h, e);
921
961
  e += 2;
922
- var c = h >>> 1;
923
- t.searchRange = i(l, e), e += 2, t.entrySelector = i(l, e), e += 2, t.rangeShift = i(l, e), e += 2, t.endCount = s(l, e, c), e += c * 2, e += 2, t.startCount = s(l, e, c), e += c * 2, t.idDelta = [];
962
+ var c = l >>> 1;
963
+ t.searchRange = i(h, e), e += 2, t.entrySelector = i(h, e), e += 2, t.rangeShift = i(h, e), e += 2, t.endCount = s(h, e, c), e += c * 2, e += 2, t.startCount = s(h, e, c), e += c * 2, t.idDelta = [];
924
964
  for (var u = 0; u < c; u++)
925
- t.idDelta.push(r.readShort(l, e)), e += 2;
926
- return t.idRangeOffset = s(l, e, c), e += c * 2, t.glyphIdArray = s(l, e, a + n - e >> 1), t;
965
+ t.idDelta.push(r.readShort(h, e)), e += 2;
966
+ return t.idRangeOffset = s(h, e, c), e += c * 2, t.glyphIdArray = s(h, e, o + n - e >> 1), t;
927
967
  },
928
- parse12: function(l, e, t) {
968
+ parse12: function(h, e, t) {
929
969
  var r = m.B, i = r.readUint;
930
- e += 4, i(l, e), e += 4, i(l, e), e += 4;
931
- var s = i(l, e) * 3;
970
+ e += 4, i(h, e), e += 4, i(h, e), e += 4;
971
+ var s = i(h, e) * 3;
932
972
  e += 4;
933
- for (var a = t.groups = new Uint32Array(s), n = 0; n < s; n += 3)
934
- a[n] = i(l, e + (n << 2)), a[n + 1] = i(l, e + (n << 2) + 4), a[n + 2] = i(l, e + (n << 2) + 8);
973
+ for (var o = t.groups = new Uint32Array(s), n = 0; n < s; n += 3)
974
+ o[n] = i(h, e + (n << 2)), o[n + 1] = i(h, e + (n << 2) + 4), o[n + 2] = i(h, e + (n << 2) + 8);
935
975
  return t;
936
976
  }
937
977
  };
938
978
  m.T.head = {
939
- parseTab: function(l, e, t) {
979
+ parseTab: function(h, e, t) {
940
980
  var r = m.B, i = {};
941
- return e += 18, i.unitsPerEm = r.readUshort(l, e), e += 2, e += 16, i.xMin = r.readShort(l, e), e += 2, i.yMin = r.readShort(l, e), e += 2, i.xMax = r.readShort(l, e), e += 2, i.yMax = r.readShort(l, e), e += 2, e += 6, i.indexToLocFormat = r.readShort(l, e), i;
981
+ return e += 18, i.unitsPerEm = r.readUshort(h, e), e += 2, e += 16, i.xMin = r.readShort(h, e), e += 2, i.yMin = r.readShort(h, e), e += 2, i.xMax = r.readShort(h, e), e += 2, i.yMax = r.readShort(h, e), e += 2, e += 6, i.indexToLocFormat = r.readShort(h, e), i;
942
982
  }
943
983
  };
944
984
  m.T.hhea = {
945
- parseTab: function(l, e, t) {
985
+ parseTab: function(h, e, t) {
946
986
  var r = m.B, i = {};
947
987
  e += 4;
948
988
  for (var s = [
@@ -962,79 +1002,79 @@ m.T.hhea = {
962
1002
  "res3",
963
1003
  "metricDataFormat",
964
1004
  "numberOfHMetrics"
965
- ], a = 0; a < s.length; a++) {
966
- var n = s[a], h = n == "advanceWidthMax" || n == "numberOfHMetrics" ? r.readUshort : r.readShort;
967
- i[n] = h(l, e + a * 2);
1005
+ ], o = 0; o < s.length; o++) {
1006
+ var n = s[o], l = n == "advanceWidthMax" || n == "numberOfHMetrics" ? r.readUshort : r.readShort;
1007
+ i[n] = l(h, e + o * 2);
968
1008
  }
969
1009
  return i;
970
1010
  }
971
1011
  };
972
1012
  m.T.hmtx = {
973
- parseTab: function(l, e, t, r) {
974
- for (var i = m.B, s = [], a = [], n = r.maxp.numGlyphs, h = r.hhea.numberOfHMetrics, c = 0, u = 0, d = 0; d < h; )
975
- c = i.readUshort(l, e + (d << 2)), u = i.readShort(l, e + (d << 2) + 2), s.push(c), a.push(u), d++;
1013
+ parseTab: function(h, e, t, r) {
1014
+ for (var i = m.B, s = [], o = [], n = r.maxp.numGlyphs, l = r.hhea.numberOfHMetrics, c = 0, u = 0, d = 0; d < l; )
1015
+ c = i.readUshort(h, e + (d << 2)), u = i.readShort(h, e + (d << 2) + 2), s.push(c), o.push(u), d++;
976
1016
  for (; d < n; )
977
- s.push(c), a.push(u), d++;
978
- return { aWidth: s, lsBearing: a };
1017
+ s.push(c), o.push(u), d++;
1018
+ return { aWidth: s, lsBearing: o };
979
1019
  }
980
1020
  };
981
1021
  m.T.maxp = {
982
- parseTab: function(l, e, t) {
1022
+ parseTab: function(h, e, t) {
983
1023
  var r = m.B, i = r.readUshort, s = {};
984
- return r.readUint(l, e), e += 4, s.numGlyphs = i(l, e), e += 2, s;
1024
+ return r.readUint(h, e), e += 4, s.numGlyphs = i(h, e), e += 2, s;
985
1025
  }
986
1026
  };
987
1027
  m.T.loca = {
988
- parseTab: function(l, e, t, r) {
989
- var i = m.B, s = [], a = r.head.indexToLocFormat, n = r.maxp.numGlyphs + 1;
990
- if (a == 0) for (var h = 0; h < n; h++) s.push(i.readUshort(l, e + (h << 1)) << 1);
991
- if (a == 1) for (var h = 0; h < n; h++) s.push(i.readUint(l, e + (h << 2)));
1028
+ parseTab: function(h, e, t, r) {
1029
+ var i = m.B, s = [], o = r.head.indexToLocFormat, n = r.maxp.numGlyphs + 1;
1030
+ if (o == 0) for (var l = 0; l < n; l++) s.push(i.readUshort(h, e + (l << 1)) << 1);
1031
+ if (o == 1) for (var l = 0; l < n; l++) s.push(i.readUint(h, e + (l << 2)));
992
1032
  return s;
993
1033
  }
994
1034
  };
995
1035
  m.T.glyf = {
996
- parseTab: function(l, e, t, r) {
997
- for (var i = [], s = r.maxp.numGlyphs, a = 0; a < s; a++) i.push(null);
1036
+ parseTab: function(h, e, t, r) {
1037
+ for (var i = [], s = r.maxp.numGlyphs, o = 0; o < s; o++) i.push(null);
998
1038
  return i;
999
1039
  },
1000
- _parseGlyf: function(l, e) {
1001
- var t = m.B, r = l._data, i = l.loca;
1040
+ _parseGlyf: function(h, e) {
1041
+ var t = m.B, r = h._data, i = h.loca;
1002
1042
  if (i[e] == i[e + 1]) return null;
1003
- var s = m.findTable(r, "glyf", l._offset)[0] + i[e], a = {};
1004
- if (a.noc = t.readShort(r, s), s += 2, a.xMin = t.readShort(r, s), s += 2, a.yMin = t.readShort(r, s), s += 2, a.xMax = t.readShort(r, s), s += 2, a.yMax = t.readShort(r, s), s += 2, a.xMin >= a.xMax || a.yMin >= a.yMax) return null;
1005
- if (a.noc > 0) {
1006
- a.endPts = [];
1007
- for (var n = 0; n < a.noc; n++)
1008
- a.endPts.push(t.readUshort(r, s)), s += 2;
1009
- var h = t.readUshort(r, s);
1010
- if (s += 2, r.length - s < h) return null;
1011
- s += h;
1012
- var c = a.endPts[a.noc - 1] + 1;
1013
- a.flags = [];
1043
+ var s = m.findTable(r, "glyf", h._offset)[0] + i[e], o = {};
1044
+ if (o.noc = t.readShort(r, s), s += 2, o.xMin = t.readShort(r, s), s += 2, o.yMin = t.readShort(r, s), s += 2, o.xMax = t.readShort(r, s), s += 2, o.yMax = t.readShort(r, s), s += 2, o.xMin >= o.xMax || o.yMin >= o.yMax) return null;
1045
+ if (o.noc > 0) {
1046
+ o.endPts = [];
1047
+ for (var n = 0; n < o.noc; n++)
1048
+ o.endPts.push(t.readUshort(r, s)), s += 2;
1049
+ var l = t.readUshort(r, s);
1050
+ if (s += 2, r.length - s < l) return null;
1051
+ s += l;
1052
+ var c = o.endPts[o.noc - 1] + 1;
1053
+ o.flags = [];
1014
1054
  for (var n = 0; n < c; n++) {
1015
1055
  var u = r[s];
1016
- if (s++, a.flags.push(u), u & 8) {
1056
+ if (s++, o.flags.push(u), u & 8) {
1017
1057
  var d = r[s];
1018
1058
  s++;
1019
1059
  for (var f = 0; f < d; f++)
1020
- a.flags.push(u), n++;
1060
+ o.flags.push(u), n++;
1021
1061
  }
1022
1062
  }
1023
- a.xs = [];
1063
+ o.xs = [];
1024
1064
  for (var n = 0; n < c; n++) {
1025
- var g = (a.flags[n] & 2) != 0, _ = (a.flags[n] & 16) != 0;
1026
- g ? (a.xs.push(_ ? r[s] : -r[s]), s++) : _ ? a.xs.push(0) : (a.xs.push(t.readShort(r, s)), s += 2);
1065
+ var g = (o.flags[n] & 2) != 0, p = (o.flags[n] & 16) != 0;
1066
+ g ? (o.xs.push(p ? r[s] : -r[s]), s++) : p ? o.xs.push(0) : (o.xs.push(t.readShort(r, s)), s += 2);
1027
1067
  }
1028
- a.ys = [];
1068
+ o.ys = [];
1029
1069
  for (var n = 0; n < c; n++) {
1030
- var g = (a.flags[n] & 4) != 0, _ = (a.flags[n] & 32) != 0;
1031
- g ? (a.ys.push(_ ? r[s] : -r[s]), s++) : _ ? a.ys.push(0) : (a.ys.push(t.readShort(r, s)), s += 2);
1070
+ var g = (o.flags[n] & 4) != 0, p = (o.flags[n] & 32) != 0;
1071
+ g ? (o.ys.push(p ? r[s] : -r[s]), s++) : p ? o.ys.push(0) : (o.ys.push(t.readShort(r, s)), s += 2);
1032
1072
  }
1033
- for (var p = 0, C = 0, n = 0; n < c; n++)
1034
- p += a.xs[n], C += a.ys[n], a.xs[n] = p, a.ys[n] = C;
1073
+ for (var _ = 0, b = 0, n = 0; n < c; n++)
1074
+ _ += o.xs[n], b += o.ys[n], o.xs[n] = _, o.ys[n] = b;
1035
1075
  } else
1036
- a.parts = [];
1037
- return a;
1076
+ o.parts = [];
1077
+ return o;
1038
1078
  }
1039
1079
  };
1040
1080
  typeof module < "u" && module.exports ? module.exports = m : typeof window < "u" && (window.Typr = m);
@@ -1069,10 +1109,10 @@ class me {
1069
1109
  for (let r = 0; r < e.startCount.length; r++) {
1070
1110
  const i = e.startCount[r], s = e.endCount[r];
1071
1111
  if (!(i === 65535 && s === 65535)) {
1072
- for (let a = i; a <= s; a++)
1073
- if (this._calculateGlyphIndexFormat4(e, a, r) > 0) {
1074
- const h = String.fromCodePoint(a);
1075
- t.push(h);
1112
+ for (let o = i; o <= s; o++)
1113
+ if (this._calculateGlyphIndexFormat4(e, o, r) > 0) {
1114
+ const l = String.fromCodePoint(o);
1115
+ t.push(l);
1076
1116
  }
1077
1117
  }
1078
1118
  }
@@ -1088,9 +1128,9 @@ class me {
1088
1128
  if (!e.groups)
1089
1129
  return t;
1090
1130
  for (let r = 0; r < e.groups.length; r += 3) {
1091
- const i = e.groups[r], s = e.groups[r + 1], a = e.groups[r + 2];
1131
+ const i = e.groups[r], s = e.groups[r + 1], o = e.groups[r + 2];
1092
1132
  for (let n = i; n <= s; n++)
1093
- if (a + (n - i) > 0) {
1133
+ if (o + (n - i) > 0) {
1094
1134
  const c = String.fromCodePoint(n);
1095
1135
  t.push(c);
1096
1136
  }
@@ -1141,9 +1181,9 @@ class ge {
1141
1181
  * @param renderer The WebGL renderer instance
1142
1182
  */
1143
1183
  constructor(e) {
1144
- o(this, "_textureCanvas");
1145
- o(this, "_textureContext");
1146
- o(this, "_renderer");
1184
+ a(this, "_textureCanvas");
1185
+ a(this, "_textureContext");
1186
+ a(this, "_renderer");
1147
1187
  this._renderer = e, this._textureCanvas = document.createElement("canvas"), this._textureContext = this._textureCanvas.getContext("2d", { willReadFrequently: !0, alpha: !1 });
1148
1188
  }
1149
1189
  /**
@@ -1155,12 +1195,12 @@ class ge {
1155
1195
  * @returns Object containing framebuffer, columns, and rows
1156
1196
  */
1157
1197
  createTextureAtlas(e, t, r, i) {
1158
- const s = e.length, a = Math.ceil(Math.sqrt(s)), n = Math.ceil(s / a), h = t.width * a, c = t.height * n;
1159
- this._setupCanvas(h, c, r, i), this._renderCharactersToCanvas(e, t, a, r), this._applyBlackWhiteThreshold();
1160
- const u = this._renderer.createFramebuffer(h, c, { filter: "nearest" });
1198
+ const s = e.length, o = Math.ceil(Math.sqrt(s)), n = Math.ceil(s / o), l = t.width * o, c = t.height * n;
1199
+ this._setupCanvas(l, c, r, i), this._renderCharactersToCanvas(e, t, o, r), this._applyBlackWhiteThreshold();
1200
+ const u = this._renderer.createFramebuffer(l, c, { filter: "nearest" });
1161
1201
  return u.update(this._textureCanvas), {
1162
1202
  framebuffer: u,
1163
- columns: a,
1203
+ columns: o,
1164
1204
  rows: n
1165
1205
  };
1166
1206
  }
@@ -1185,7 +1225,7 @@ class ge {
1185
1225
  */
1186
1226
  _renderCharactersToCanvas(e, t, r, i) {
1187
1227
  for (let s = 0; s < e.length; s++) {
1188
- const a = s % r, n = Math.floor(s / r), h = a * t.width + t.width * 0.5, c = n * t.height + t.height * 0.5, u = Math.round(h - t.width * 0.5), d = Math.round(c - i * 0.5);
1228
+ const o = s % r, n = Math.floor(s / r), l = o * t.width + t.width * 0.5, c = n * t.height + t.height * 0.5, u = Math.round(l - t.width * 0.5), d = Math.round(c - i * 0.5);
1189
1229
  this._textureContext.fillText(e[s].character, u, d);
1190
1230
  }
1191
1231
  }
@@ -1198,19 +1238,19 @@ class ge {
1198
1238
  _applyBlackWhiteThreshold(e = 128) {
1199
1239
  const t = this._textureContext.getImageData(0, 0, this._textureCanvas.width, this._textureCanvas.height), r = t.data;
1200
1240
  for (let i = 0; i < r.length; i += 4) {
1201
- const s = 0.299 * r[i] + 0.587 * r[i + 1] + 0.114 * r[i + 2], a = e + 32, n = s > a ? 255 : 0;
1241
+ const s = 0.299 * r[i] + 0.587 * r[i + 1] + 0.114 * r[i + 2], o = e + 32, n = s > o ? 255 : 0;
1202
1242
  r[i] = n, r[i + 1] = n, r[i + 2] = n;
1203
1243
  }
1204
1244
  this._textureContext.putImageData(t, 0, 0);
1205
1245
  }
1206
1246
  }
1207
- class pe {
1247
+ class _e {
1208
1248
  /**
1209
1249
  * Creates a new MetricsCalculation instance.
1210
1250
  */
1211
1251
  constructor() {
1212
- o(this, "_tempCanvas");
1213
- o(this, "_tempContext");
1252
+ a(this, "_tempCanvas");
1253
+ a(this, "_tempContext");
1214
1254
  this._tempCanvas = document.createElement("canvas"), this._tempContext = this._tempCanvas.getContext("2d");
1215
1255
  }
1216
1256
  /**
@@ -1224,9 +1264,9 @@ class pe {
1224
1264
  calculateMaxGlyphDimensions(e, t, r) {
1225
1265
  this._tempContext.font = `${t}px ${r}`;
1226
1266
  let i = 0, s = 0;
1227
- for (const a of e) {
1228
- const n = this._tempContext.measureText(a), h = n.width, c = n.actualBoundingBoxAscent + n.actualBoundingBoxDescent;
1229
- h > 0 && (i = Math.max(i, h), s = Math.max(s, c));
1267
+ for (const o of e) {
1268
+ const n = this._tempContext.measureText(o), l = n.width, c = n.actualBoundingBoxAscent + n.actualBoundingBoxDescent;
1269
+ l > 0 && (i = Math.max(i, l), s = Math.max(s, c));
1230
1270
  }
1231
1271
  return {
1232
1272
  width: Math.ceil(i),
@@ -1234,7 +1274,7 @@ class pe {
1234
1274
  };
1235
1275
  }
1236
1276
  }
1237
- class _e {
1277
+ class pe {
1238
1278
  /**
1239
1279
  * Creates TextmodeCharacter objects with unique color assignments.
1240
1280
  * @param characters Array of character strings
@@ -1243,16 +1283,16 @@ class _e {
1243
1283
  */
1244
1284
  createCharacterObjects(e, t) {
1245
1285
  return e.map((r, i) => {
1246
- const s = r.codePointAt(0) || 0, a = this._generateCharacterColor(i);
1286
+ const s = r.codePointAt(0) || 0, o = this._generateCharacterColor(i);
1247
1287
  let n = 0;
1248
1288
  if (t.hmtx && t.hmtx.aWidth) {
1249
- const h = this._getGlyphIndex(t, s);
1250
- h > 0 && t.hmtx.aWidth[h] !== void 0 && (n = t.hmtx.aWidth[h]);
1289
+ const l = this._getGlyphIndex(t, s);
1290
+ l > 0 && t.hmtx.aWidth[l] !== void 0 && (n = t.hmtx.aWidth[l]);
1251
1291
  }
1252
1292
  return {
1253
1293
  character: r,
1254
1294
  unicode: s,
1255
- color: a,
1295
+ color: o,
1256
1296
  advanceWidth: n
1257
1297
  };
1258
1298
  });
@@ -1274,9 +1314,9 @@ class _e {
1274
1314
  if (i.idRangeOffset[s] === 0)
1275
1315
  return t + i.idDelta[s] & 65535;
1276
1316
  {
1277
- const a = i.idRangeOffset[s] / 2 + (t - i.startCount[s]) - (i.startCount.length - s);
1278
- if (a >= 0 && a < i.glyphIdArray.length) {
1279
- const n = i.glyphIdArray[a];
1317
+ const o = i.idRangeOffset[s] / 2 + (t - i.startCount[s]) - (i.startCount.length - s);
1318
+ if (o >= 0 && o < i.glyphIdArray.length) {
1319
+ const n = i.glyphIdArray[o];
1280
1320
  if (n !== 0)
1281
1321
  return n + i.idDelta[s] & 65535;
1282
1322
  }
@@ -1332,21 +1372,21 @@ class xe {
1332
1372
  * @ignore
1333
1373
  */
1334
1374
  constructor(e, t = 16) {
1335
- o(this, "_font");
1336
- o(this, "_characters", []);
1337
- o(this, "_fontFramebuffer");
1338
- o(this, "_fontSize", 16);
1339
- o(this, "_textureColumns", 0);
1340
- o(this, "_textureRows", 0);
1341
- o(this, "_maxGlyphDimensions", { width: 0, height: 0 });
1342
- o(this, "_fontFace");
1343
- o(this, "_fontFamilyName", "UrsaFont");
1375
+ a(this, "_font");
1376
+ a(this, "_characters", []);
1377
+ a(this, "_fontFramebuffer");
1378
+ a(this, "_fontSize", 16);
1379
+ a(this, "_textureColumns", 0);
1380
+ a(this, "_textureRows", 0);
1381
+ a(this, "_maxGlyphDimensions", { width: 0, height: 0 });
1382
+ a(this, "_fontFace");
1383
+ a(this, "_fontFamilyName", "UrsaFont");
1344
1384
  // Component classes
1345
- o(this, "_characterExtractor");
1346
- o(this, "_textureAtlas");
1347
- o(this, "_metricsCalculator");
1348
- o(this, "_characterColorMapper");
1349
- this._fontSize = t, this._characterExtractor = new me(), this._textureAtlas = new ge(e), this._metricsCalculator = new pe(), this._characterColorMapper = new _e();
1385
+ a(this, "_characterExtractor");
1386
+ a(this, "_textureAtlas");
1387
+ a(this, "_metricsCalculator");
1388
+ a(this, "_characterColorMapper");
1389
+ this._fontSize = t, this._characterExtractor = new me(), this._textureAtlas = new ge(e), this._metricsCalculator = new _e(), this._characterColorMapper = new pe();
1350
1390
  }
1351
1391
  /**
1352
1392
  * Initializes the font manager by loading the font and creating the texture atlas.
@@ -1484,6 +1524,19 @@ class xe {
1484
1524
  get maxGlyphDimensions() {
1485
1525
  return this._maxGlyphDimensions;
1486
1526
  }
1527
+ /**
1528
+ * Dispose of all resources used by this font manager.
1529
+ * This method is idempotent and safe to call multiple times.
1530
+ */
1531
+ dispose() {
1532
+ this._fontFramebuffer && !this._fontFramebuffer.isDisposed && this._fontFramebuffer.dispose(), this._fontFace && document.fonts.has(this._fontFace) && document.fonts.delete(this._fontFace), this._fontFramebuffer = null, this._fontFace = null, this._font = null, this._characters = [], this._maxGlyphDimensions = { width: 0, height: 0 }, this._textureColumns = 0, this._textureRows = 0;
1533
+ }
1534
+ /**
1535
+ * Check if this font manager has been disposed
1536
+ */
1537
+ get isDisposed() {
1538
+ return this._fontFramebuffer === null || this._font === null;
1539
+ }
1487
1540
  /** Returns the font size used for rendering. */
1488
1541
  get fontSize() {
1489
1542
  return this._fontSize;
@@ -1503,25 +1556,25 @@ class ve {
1503
1556
  */
1504
1557
  constructor(e, t, r) {
1505
1558
  /** The number of columns in the grid. */
1506
- o(this, "_cols");
1559
+ a(this, "_cols");
1507
1560
  /** The number of rows in the grid. */
1508
- o(this, "_rows");
1561
+ a(this, "_rows");
1509
1562
  /** The total width of the grid in pixels. */
1510
- o(this, "_width");
1563
+ a(this, "_width");
1511
1564
  /** The total height of the grid in pixels. */
1512
- o(this, "_height");
1565
+ a(this, "_height");
1513
1566
  /** The offset to the outer canvas on the x-axis when centering the grid. */
1514
- o(this, "_offsetX");
1567
+ a(this, "_offsetX");
1515
1568
  /** The offset to the outer canvas on the y-axis when centering the grid. */
1516
- o(this, "_offsetY");
1569
+ a(this, "_offsetY");
1517
1570
  /** Whether the grid dimensions are fixed, or responsive based on the canvas dimensions. */
1518
- o(this, "_fixedDimensions", !1);
1571
+ a(this, "_fixedDimensions", !1);
1519
1572
  /** The canvas element used to determine the grid dimensions. */
1520
- o(this, "_canvas");
1573
+ a(this, "_canvas");
1521
1574
  /** The width of each cell in the grid. */
1522
- o(this, "_cellWidth");
1575
+ a(this, "_cellWidth");
1523
1576
  /** The height of each cell in the grid. */
1524
- o(this, "_cellHeight");
1577
+ a(this, "_cellHeight");
1525
1578
  this._canvas = e, this._cellWidth = t, this._cellHeight = r, this.reset();
1526
1579
  }
1527
1580
  /**
@@ -1598,6 +1651,19 @@ class ve {
1598
1651
  get cellHeight() {
1599
1652
  return this._cellHeight;
1600
1653
  }
1654
+ /**
1655
+ * Dispose of this TextmodeGrid and clean up references.
1656
+ * This method is idempotent and safe to call multiple times.
1657
+ */
1658
+ dispose() {
1659
+ this._canvas = null, this._cols = 0, this._rows = 0, this._width = 0, this._height = 0, this._offsetX = 0, this._offsetY = 0, this._cellWidth = 0, this._cellHeight = 0;
1660
+ }
1661
+ /**
1662
+ * Check if this TextmodeGrid has been disposed
1663
+ */
1664
+ get isDisposed() {
1665
+ return this._canvas === null;
1666
+ }
1601
1667
  /** Returns the number of columns in the grid. */
1602
1668
  get cols() {
1603
1669
  return this._cols;
@@ -1623,28 +1689,28 @@ class ve {
1623
1689
  return this._offsetY;
1624
1690
  }
1625
1691
  }
1626
- class Ce {
1692
+ class be {
1627
1693
  constructor(e, t = !1, r = {}) {
1628
- o(this, "_canvas");
1629
- o(this, "captureSource");
1630
- o(this, "_isStandalone");
1694
+ a(this, "_canvas");
1695
+ a(this, "captureSource");
1696
+ a(this, "_isStandalone");
1631
1697
  this.captureSource = e, this._isStandalone = t, this._canvas = this.createCanvas(r.width, r.height);
1632
1698
  }
1633
1699
  createCanvas(e, t) {
1634
1700
  var i;
1635
1701
  const r = document.createElement("canvas");
1636
- if (r.className = "textmodeCanvas", this._isStandalone)
1702
+ if (r.className = "textmodeCanvas", r.style.imageRendering = "pixelated", this._isStandalone)
1637
1703
  r.width = e || 800, r.height = t || 600, document.body.appendChild(r);
1638
1704
  else {
1639
1705
  const s = this.captureSource.getBoundingClientRect();
1640
- let a = Math.round(s.width), n = Math.round(s.height);
1706
+ let o = Math.round(s.width), n = Math.round(s.height);
1641
1707
  if (this.captureSource instanceof HTMLVideoElement) {
1642
1708
  const u = this.captureSource;
1643
- (a === 0 || n === 0) && u.videoWidth > 0 && u.videoHeight > 0 && (a = u.videoWidth, n = u.videoHeight);
1709
+ (o === 0 || n === 0) && u.videoWidth > 0 && u.videoHeight > 0 && (o = u.videoWidth, n = u.videoHeight);
1644
1710
  }
1645
- r.width = a, r.height = n, r.style.position = "absolute", r.style.pointerEvents = "none";
1646
- const h = window.getComputedStyle(this.captureSource);
1647
- let c = parseInt(h.zIndex || "0", 10);
1711
+ r.width = o, r.height = n, r.style.position = "absolute", r.style.pointerEvents = "none";
1712
+ const l = window.getComputedStyle(this.captureSource);
1713
+ let c = parseInt(l.zIndex || "0", 10);
1648
1714
  isNaN(c) && (c = 0), r.style.zIndex = (c + 1).toString(), this.positionOverlayCanvas(r), (i = this.captureSource.parentNode) == null || i.insertBefore(r, this.captureSource.nextSibling);
1649
1715
  }
1650
1716
  return r;
@@ -1665,8 +1731,8 @@ class Ce {
1665
1731
  const r = this.captureSource.getBoundingClientRect();
1666
1732
  let i = Math.round(r.width), s = Math.round(r.height);
1667
1733
  if (this.captureSource instanceof HTMLVideoElement) {
1668
- const a = this.captureSource;
1669
- (i === 0 || s === 0) && a.videoWidth > 0 && a.videoHeight > 0 && (i = a.videoWidth, s = a.videoHeight);
1734
+ const o = this.captureSource;
1735
+ (i === 0 || s === 0) && o.videoWidth > 0 && o.videoHeight > 0 && (i = o.videoWidth, s = o.videoHeight);
1670
1736
  }
1671
1737
  this._canvas.width = i, this._canvas.height = s, this.positionOverlayCanvas(this._canvas);
1672
1738
  }
@@ -1688,6 +1754,27 @@ class Ce {
1688
1754
  throw new F("WebGL context could not be created. Ensure your browser supports WebGL.");
1689
1755
  return t;
1690
1756
  }
1757
+ /**
1758
+ * Dispose of this TextmodeCanvas and clean up all resources.
1759
+ * This method is idempotent and safe to call multiple times.
1760
+ */
1761
+ dispose() {
1762
+ if (this._canvas) {
1763
+ const e = this._canvas.getContext("webgl") || this._canvas.getContext("webgl2");
1764
+ if (e) {
1765
+ const t = e.getExtension("WEBGL_lose_context");
1766
+ t && t.loseContext();
1767
+ }
1768
+ this._canvas.parentNode && this._canvas.parentNode.removeChild(this._canvas), this._canvas = null;
1769
+ }
1770
+ this.captureSource = null;
1771
+ }
1772
+ /**
1773
+ * Check if this TextmodeCanvas has been disposed
1774
+ */
1775
+ get isDisposed() {
1776
+ return this._canvas === null;
1777
+ }
1691
1778
  get canvas() {
1692
1779
  return this._canvas;
1693
1780
  }
@@ -1708,15 +1795,15 @@ class U {
1708
1795
  * @ignore
1709
1796
  */
1710
1797
  constructor(e, t, r, i = {}) {
1711
- o(this, "renderer");
1712
- o(this, "fontManager");
1713
- o(this, "grid");
1714
- o(this, "_characterFramebuffer");
1715
- o(this, "_primaryColorFramebuffer");
1716
- o(this, "_secondaryColorFramebuffer");
1717
- o(this, "_rotationFramebuffer");
1718
- o(this, "_transformFramebuffer");
1719
- o(this, "_options");
1798
+ a(this, "renderer");
1799
+ a(this, "fontManager");
1800
+ a(this, "grid");
1801
+ a(this, "_characterFramebuffer");
1802
+ a(this, "_primaryColorFramebuffer");
1803
+ a(this, "_secondaryColorFramebuffer");
1804
+ a(this, "_rotationFramebuffer");
1805
+ a(this, "_transformFramebuffer");
1806
+ a(this, "_options");
1720
1807
  this.renderer = e, this.fontManager = t, this.grid = r, this._options = i, this._characterFramebuffer = this.renderer.createFramebuffer(this.grid.cols, this.grid.rows), this._primaryColorFramebuffer = this.renderer.createFramebuffer(this.grid.cols, this.grid.rows), this._secondaryColorFramebuffer = this.renderer.createFramebuffer(this.grid.cols, this.grid.rows), this._rotationFramebuffer = this.renderer.createFramebuffer(this.grid.cols, this.grid.rows), this._transformFramebuffer = this.renderer.createFramebuffer(this.grid.cols, this.grid.rows);
1721
1808
  }
1722
1809
  /**
@@ -1745,6 +1832,19 @@ class U {
1745
1832
  disable() {
1746
1833
  this.enabled(!1);
1747
1834
  }
1835
+ /**
1836
+ * Dispose of all framebuffers used by this converter.
1837
+ * This method is idempotent and safe to call multiple times.
1838
+ */
1839
+ dispose() {
1840
+ this._characterFramebuffer && !this._characterFramebuffer.isDisposed && this._characterFramebuffer.dispose(), this._primaryColorFramebuffer && !this._primaryColorFramebuffer.isDisposed && this._primaryColorFramebuffer.dispose(), this._secondaryColorFramebuffer && !this._secondaryColorFramebuffer.isDisposed && this._secondaryColorFramebuffer.dispose(), this._rotationFramebuffer && !this._rotationFramebuffer.isDisposed && this._rotationFramebuffer.dispose(), this._transformFramebuffer && !this._transformFramebuffer.isDisposed && this._transformFramebuffer.dispose(), this._characterFramebuffer = null, this._primaryColorFramebuffer = null, this._secondaryColorFramebuffer = null, this._rotationFramebuffer = null, this._transformFramebuffer = null;
1841
+ }
1842
+ /**
1843
+ * Check if this converter has been disposed
1844
+ */
1845
+ get isDisposed() {
1846
+ return this._characterFramebuffer === null;
1847
+ }
1748
1848
  /** Returns the framebuffer containing character data. */
1749
1849
  get characterFramebuffer() {
1750
1850
  return this._characterFramebuffer;
@@ -1770,7 +1870,7 @@ class U {
1770
1870
  return this._options;
1771
1871
  }
1772
1872
  }
1773
- class be {
1873
+ class Ce {
1774
1874
  /**
1775
1875
  * Create a new color palette instance.
1776
1876
  * @param renderer The renderer instance.
@@ -1778,9 +1878,9 @@ class be {
1778
1878
  */
1779
1879
  constructor(e, t) {
1780
1880
  /** The framebuffer used to store the color palette. */
1781
- o(this, "_framebuffer");
1782
- o(this, "_renderer");
1783
- o(this, "_colors");
1881
+ a(this, "_framebuffer");
1882
+ a(this, "_renderer");
1883
+ a(this, "_colors");
1784
1884
  this._renderer = e, this._colors = t;
1785
1885
  const r = Math.max(this._colors.length, 1);
1786
1886
  this._framebuffer = this._renderer.createFramebuffer(r, 1), this._updateFramebuffer();
@@ -1794,8 +1894,8 @@ class be {
1794
1894
  this._framebuffer.width !== e && this._framebuffer.resize(e, t);
1795
1895
  const r = new Uint8Array(e * t * 4);
1796
1896
  for (let i = 0; i < e; i++) {
1797
- const s = i < this._colors.length ? this._colors[i] : [0, 0, 0], a = i * 4;
1798
- r[a] = s[0], r[a + 1] = s[1], r[a + 2] = s[2], r[a + 3] = 255;
1897
+ const s = i < this._colors.length ? this._colors[i] : [0, 0, 0], o = i * 4;
1898
+ r[o] = s[0], r[o + 1] = s[1], r[o + 2] = s[2], r[o + 3] = 255;
1799
1899
  }
1800
1900
  this._framebuffer.updatePixels(r, e, t);
1801
1901
  }
@@ -1828,8 +1928,8 @@ class be {
1828
1928
  class X extends U {
1829
1929
  constructor(t, r, i, s = {}) {
1830
1930
  super(t, r, i, s);
1831
- o(this, "palette");
1832
- this.palette = new be(this.renderer, this.fontManager.getCharacterColors(" .:-=+*%@#"));
1931
+ a(this, "palette");
1932
+ this.palette = new Ce(this.renderer, this.fontManager.getCharacterColors(" .:-=+*%@#"));
1833
1933
  }
1834
1934
  /**
1835
1935
  * Sets the characters used for mapping.
@@ -1852,7 +1952,7 @@ class X extends U {
1852
1952
  */
1853
1953
  characterColor(t, r = t, i = t, s = 255) {
1854
1954
  x.validate(
1855
- [t, r, i, s].every((a) => a >= 0 && a <= 255),
1955
+ [t, r, i, s].every((o) => o >= 0 && o <= 255),
1856
1956
  "Character color values must be between 0 and 255",
1857
1957
  { method: "characterColor", providedValues: { r: t, g: r, b: i, a: s } }
1858
1958
  ) && (this._options.characterColor = [t, r, i, s]);
@@ -1880,7 +1980,7 @@ class X extends U {
1880
1980
  */
1881
1981
  cellColor(t, r = t, i = t, s = 255) {
1882
1982
  x.validate(
1883
- [t, r, i, s].every((a) => a >= 0 && a <= 255),
1983
+ [t, r, i, s].every((o) => o >= 0 && o <= 255),
1884
1984
  "Cell color values must be between 0 and 255",
1885
1985
  { method: "cellColor", providedValues: { r: t, g: r, b: i, a: s } }
1886
1986
  ) && (this._options.cellColor = [t, r, i, s]);
@@ -1982,12 +2082,12 @@ class L extends X {
1982
2082
  */
1983
2083
  constructor(t, r, i) {
1984
2084
  super(t, r, i, { ...Re });
1985
- o(this, "sampleShader");
1986
- o(this, "colorFillShader");
1987
- o(this, "charMappingShader");
1988
- o(this, "transformFillShader");
1989
- o(this, "rotationFillShader");
1990
- o(this, "sampleFramebuffer");
2085
+ a(this, "sampleShader");
2086
+ a(this, "colorFillShader");
2087
+ a(this, "charMappingShader");
2088
+ a(this, "transformFillShader");
2089
+ a(this, "rotationFillShader");
2090
+ a(this, "sampleFramebuffer");
1991
2091
  this.sampleShader = new T(t.context, S, Fe), this.colorFillShader = new T(t.context, S, we), this.transformFillShader = new T(t.context, S, ye), this.rotationFillShader = new T(t.context, S, Te), this.charMappingShader = new T(t.context, S, Se), this.sampleFramebuffer = this.renderer.createFramebuffer(this.grid.cols, this.grid.rows);
1992
2092
  }
1993
2093
  convert(t) {
@@ -2027,17 +2127,17 @@ class Ue {
2027
2127
  * @ignore
2028
2128
  */
2029
2129
  constructor(e, t, r) {
2030
- o(this, "renderer");
2031
- o(this, "font");
2032
- o(this, "grid");
2033
- o(this, "converters");
2034
- o(this, "_resultFramebuffer");
2035
- o(this, "_asciiShader");
2036
- o(this, "_characterFramebuffer");
2037
- o(this, "_primaryColorFramebuffer");
2038
- o(this, "_secondaryColorFramebuffer");
2039
- o(this, "_rotationFramebuffer");
2040
- o(this, "_transformFramebuffer");
2130
+ a(this, "renderer");
2131
+ a(this, "font");
2132
+ a(this, "grid");
2133
+ a(this, "converters");
2134
+ a(this, "_resultFramebuffer");
2135
+ a(this, "_asciiShader");
2136
+ a(this, "_characterFramebuffer");
2137
+ a(this, "_primaryColorFramebuffer");
2138
+ a(this, "_secondaryColorFramebuffer");
2139
+ a(this, "_rotationFramebuffer");
2140
+ a(this, "_transformFramebuffer");
2041
2141
  this.renderer = e, this.font = t, this.grid = r, this._asciiShader = this.renderer.createShader(S, Ee), this.converters = [
2042
2142
  { name: "brightness", converter: new L(e, t, r) },
2043
2143
  { name: "custom", converter: new U(e, t, r) }
@@ -2056,8 +2156,8 @@ class Ue {
2056
2156
  const t = (r, i) => {
2057
2157
  r.begin(), this.renderer.clear();
2058
2158
  for (const s of this.converters) {
2059
- const a = s.converter;
2060
- a.options.enabled && this.renderer.image(i(a), 0, 0);
2159
+ const o = s.converter;
2160
+ o.options.enabled && this.renderer.image(i(o), 0, 0);
2061
2161
  }
2062
2162
  r.end();
2063
2163
  };
@@ -2167,6 +2267,21 @@ class Ue {
2167
2267
  for (const e of this.converters)
2168
2268
  e.converter.enable();
2169
2269
  }
2270
+ /**
2271
+ * Dispose of all resources used by this conversion pipeline.
2272
+ * This method is idempotent and safe to call multiple times.
2273
+ */
2274
+ dispose() {
2275
+ for (const e of this.converters)
2276
+ e.converter && !e.converter.isDisposed && e.converter.dispose();
2277
+ this._characterFramebuffer && !this._characterFramebuffer.isDisposed && this._characterFramebuffer.dispose(), this._primaryColorFramebuffer && !this._primaryColorFramebuffer.isDisposed && this._primaryColorFramebuffer.dispose(), this._secondaryColorFramebuffer && !this._secondaryColorFramebuffer.isDisposed && this._secondaryColorFramebuffer.dispose(), this._rotationFramebuffer && !this._rotationFramebuffer.isDisposed && this._rotationFramebuffer.dispose(), this._transformFramebuffer && !this._transformFramebuffer.isDisposed && this._transformFramebuffer.dispose(), this._resultFramebuffer && !this._resultFramebuffer.isDisposed && this._resultFramebuffer.dispose(), this._asciiShader && !this._asciiShader.isDisposed && this._asciiShader.dispose(), this.converters = [], this._characterFramebuffer = null, this._primaryColorFramebuffer = null, this._secondaryColorFramebuffer = null, this._rotationFramebuffer = null, this._transformFramebuffer = null, this._resultFramebuffer = null, this._asciiShader = null;
2278
+ }
2279
+ /**
2280
+ * Check if this conversion pipeline has been disposed
2281
+ */
2282
+ get isDisposed() {
2283
+ return this._resultFramebuffer === null || this._asciiShader === null;
2284
+ }
2170
2285
  /** Returns the character framebuffer containing the combined result of all converters. */
2171
2286
  get characterFramebuffer() {
2172
2287
  return this._characterFramebuffer;
@@ -2195,12 +2310,12 @@ class H {
2195
2310
  * @returns Object containing all pixel data arrays
2196
2311
  */
2197
2312
  extractFramebufferData(e) {
2198
- const t = e.get("brightness"), r = t == null ? void 0 : t.characterFramebuffer, i = t == null ? void 0 : t.primaryColorFramebuffer, s = t == null ? void 0 : t.secondaryColorFramebuffer, a = t == null ? void 0 : t.transformFramebuffer, n = t == null ? void 0 : t.rotationFramebuffer;
2199
- return r == null || r.loadPixels(), i == null || i.loadPixels(), s == null || s.loadPixels(), a == null || a.loadPixels(), n == null || n.loadPixels(), {
2313
+ const t = e.get("brightness"), r = t == null ? void 0 : t.characterFramebuffer, i = t == null ? void 0 : t.primaryColorFramebuffer, s = t == null ? void 0 : t.secondaryColorFramebuffer, o = t == null ? void 0 : t.transformFramebuffer, n = t == null ? void 0 : t.rotationFramebuffer;
2314
+ return r == null || r.loadPixels(), i == null || i.loadPixels(), s == null || s.loadPixels(), o == null || o.loadPixels(), n == null || n.loadPixels(), {
2200
2315
  characterPixels: (r == null ? void 0 : r.pixels) || new Uint8Array(0),
2201
2316
  primaryColorPixels: (i == null ? void 0 : i.pixels) || new Uint8Array(0),
2202
2317
  secondaryColorPixels: (s == null ? void 0 : s.pixels) || new Uint8Array(0),
2203
- transformPixels: (a == null ? void 0 : a.pixels) || new Uint8Array(0),
2318
+ transformPixels: (o == null ? void 0 : o.pixels) || new Uint8Array(0),
2204
2319
  rotationPixels: (n == null ? void 0 : n.pixels) || new Uint8Array(0)
2205
2320
  };
2206
2321
  }
@@ -2248,8 +2363,8 @@ class N {
2248
2363
  */
2249
2364
  downloadFile(e, t, r) {
2250
2365
  try {
2251
- const i = this.createBlob(e, r), s = URL.createObjectURL(i), a = document.createElement("a");
2252
- a.href = s, a.download = t, a.style.display = "none", a.rel = "noopener", document.body.appendChild(a), a.click(), document.body.removeChild(a), URL.revokeObjectURL(s);
2366
+ const i = this.createBlob(e, r), s = URL.createObjectURL(i), o = document.createElement("a");
2367
+ o.href = s, o.download = t, o.style.display = "none", o.rel = "noopener", document.body.appendChild(o), o.click(), document.body.removeChild(o), URL.revokeObjectURL(s);
2253
2368
  } catch (i) {
2254
2369
  throw console.error("Failed to download file:", i), new Error(`File download failed: ${i instanceof Error ? i.message : "Unknown error"}`);
2255
2370
  }
@@ -2287,7 +2402,7 @@ class N {
2287
2402
  return `'textmode-export'-${this.generateTimestamp()}`;
2288
2403
  }
2289
2404
  }
2290
- class Ae extends H {
2405
+ class De extends H {
2291
2406
  /**
2292
2407
  * Extracts transform data from transform pixels
2293
2408
  * @param transformPixels Transform framebuffer pixels
@@ -2296,10 +2411,10 @@ class Ae extends H {
2296
2411
  * @returns Transform data object
2297
2412
  */
2298
2413
  extractTransformData(e, t, r) {
2299
- const i = e[r], s = e[r + 1], a = e[r + 2], n = i === 255, h = s === 255, c = a === 255, u = t[r], d = t[r + 1], f = u + d / 255, g = Math.round(f * 360 / 255 * 100) / 100;
2414
+ const i = e[r], s = e[r + 1], o = e[r + 2], n = i === 255, l = s === 255, c = o === 255, u = t[r], d = t[r + 1], f = u + d / 255, g = Math.round(f * 360 / 255 * 100) / 100;
2300
2415
  return {
2301
2416
  isInverted: n,
2302
- flipHorizontal: h,
2417
+ flipHorizontal: l,
2303
2418
  flipVertical: c,
2304
2419
  rotation: g
2305
2420
  };
@@ -2330,8 +2445,8 @@ class Ae extends H {
2330
2445
  const r = [];
2331
2446
  let i = 0;
2332
2447
  for (let s = 0; s < t.rows; s++)
2333
- for (let a = 0; a < t.cols; a++) {
2334
- const n = i * 4, h = this.getCharacterIndex(
2448
+ for (let o = 0; o < t.cols; o++) {
2449
+ const n = i * 4, l = this.getCharacterIndex(
2335
2450
  e.characterPixels,
2336
2451
  n
2337
2452
  );
@@ -2345,9 +2460,9 @@ class Ae extends H {
2345
2460
  const g = c;
2346
2461
  c = u, u = g;
2347
2462
  }
2348
- const f = this.calculateCellPosition(a, s, t);
2463
+ const f = this.calculateCellPosition(o, s, t);
2349
2464
  r.push({
2350
- charIndex: h,
2465
+ charIndex: l,
2351
2466
  primaryColor: c,
2352
2467
  secondaryColor: u,
2353
2468
  transform: d,
@@ -2357,7 +2472,7 @@ class Ae extends H {
2357
2472
  return r;
2358
2473
  }
2359
2474
  }
2360
- class Me {
2475
+ class Ae {
2361
2476
  /**
2362
2477
  * Gets the glyph index for a given Unicode code point in a Typr.js font
2363
2478
  * @param fontData The Typr.js font data
@@ -2374,9 +2489,9 @@ class Me {
2374
2489
  if (i.idRangeOffset[s] === 0)
2375
2490
  return t + i.idDelta[s] & 65535;
2376
2491
  {
2377
- const a = i.idRangeOffset[s] / 2 + (t - i.startCount[s]) - (i.startCount.length - s);
2378
- if (a >= 0 && a < i.glyphIdArray.length) {
2379
- const n = i.glyphIdArray[a];
2492
+ const o = i.idRangeOffset[s] / 2 + (t - i.startCount[s]) - (i.startCount.length - s);
2493
+ if (o >= 0 && o < i.glyphIdArray.length) {
2494
+ const n = i.glyphIdArray[o];
2380
2495
  if (n !== 0)
2381
2496
  return n + i.idDelta[s] & 65535;
2382
2497
  }
@@ -2407,15 +2522,15 @@ class Me {
2407
2522
  createGlyphPath(e, t, r, i, s) {
2408
2523
  if (!t || !t.xs || t.xs.length === 0)
2409
2524
  return this.createEmptyPath();
2410
- const a = s / e.head.unitsPerEm;
2525
+ const o = s / e.head.unitsPerEm;
2411
2526
  return {
2412
2527
  getBoundingBox: () => ({
2413
- x1: r + t.xMin * a,
2414
- y1: i + -t.yMax * a,
2415
- x2: r + t.xMax * a,
2416
- y2: i + -t.yMin * a
2528
+ x1: r + t.xMin * o,
2529
+ y1: i + -t.yMax * o,
2530
+ x2: r + t.xMax * o,
2531
+ y2: i + -t.yMin * o
2417
2532
  }),
2418
- toSVG: () => this.glyphToSVGPath(t, r, i, a)
2533
+ toSVG: () => this.glyphToSVGPath(t, r, i, o)
2419
2534
  };
2420
2535
  }
2421
2536
  /**
@@ -2428,29 +2543,29 @@ class Me {
2428
2543
  */
2429
2544
  glyphToSVGPath(e, t, r, i) {
2430
2545
  if (!e || !e.xs) return "";
2431
- const { xs: s, ys: a, endPts: n, flags: h } = e;
2432
- if (!s || !a || !n || !h) return "";
2546
+ const { xs: s, ys: o, endPts: n, flags: l } = e;
2547
+ if (!s || !o || !n || !l) return "";
2433
2548
  let c = "", u = 0;
2434
2549
  for (let d = 0; d < n.length; d++) {
2435
2550
  const f = n[d];
2436
2551
  if (!(f < u)) {
2437
2552
  if (f >= u) {
2438
- const g = t + s[u] * i, _ = r - a[u] * i;
2439
- c += `M${g.toFixed(2)},${_.toFixed(2)}`;
2440
- let p = u + 1;
2441
- for (; p <= f; )
2442
- if ((h[p] & 1) !== 0) {
2443
- const b = t + s[p] * i, v = r - a[p] * i;
2444
- c += `L${b.toFixed(2)},${v.toFixed(2)}`, p++;
2553
+ const g = t + s[u] * i, p = r - o[u] * i;
2554
+ c += `M${g.toFixed(2)},${p.toFixed(2)}`;
2555
+ let _ = u + 1;
2556
+ for (; _ <= f; )
2557
+ if ((l[_] & 1) !== 0) {
2558
+ const C = t + s[_] * i, v = r - o[_] * i;
2559
+ c += `L${C.toFixed(2)},${v.toFixed(2)}`, _++;
2445
2560
  } else {
2446
- const b = t + s[p] * i, v = r - a[p] * i;
2447
- let w = p + 1 > f ? u : p + 1;
2448
- if ((h[w] & 1) !== 0) {
2449
- const R = t + s[w] * i, y = r - a[w] * i;
2450
- c += `Q${b.toFixed(2)},${v.toFixed(2)} ${R.toFixed(2)},${y.toFixed(2)}`, p = w + 1;
2561
+ const C = t + s[_] * i, v = r - o[_] * i;
2562
+ let w = _ + 1 > f ? u : _ + 1;
2563
+ if ((l[w] & 1) !== 0) {
2564
+ const R = t + s[w] * i, y = r - o[w] * i;
2565
+ c += `Q${C.toFixed(2)},${v.toFixed(2)} ${R.toFixed(2)},${y.toFixed(2)}`, _ = w + 1;
2451
2566
  } else {
2452
- const R = t + s[w] * i, y = r - a[w] * i, P = (b + R) / 2, D = (v + y) / 2;
2453
- c += `Q${b.toFixed(2)},${v.toFixed(2)} ${P.toFixed(2)},${D.toFixed(2)}`, p = w;
2567
+ const R = t + s[w] * i, y = r - o[w] * i, P = (C + R) / 2, M = (v + y) / 2;
2568
+ c += `Q${C.toFixed(2)},${v.toFixed(2)} ${P.toFixed(2)},${M.toFixed(2)}`, _ = w;
2454
2569
  }
2455
2570
  }
2456
2571
  c += "Z";
@@ -2471,18 +2586,18 @@ class Me {
2471
2586
  */
2472
2587
  generateCharacterPath(e, t, r, i, s) {
2473
2588
  try {
2474
- const a = e.codePointAt(0) || 0, n = this.getGlyphIndex(t, a);
2589
+ const o = e.codePointAt(0) || 0, n = this.getGlyphIndex(t, o);
2475
2590
  if (n === 0)
2476
2591
  return this.createEmptyPath();
2477
- let h = null;
2592
+ let l = null;
2478
2593
  try {
2479
- t.glyf && t.glyf[n] !== null ? h = t.glyf[n] : m && m.T && m.T.glyf && m.T.glyf._parseGlyf && (h = m.T.glyf._parseGlyf(t, n), t.glyf && h && (t.glyf[n] = h));
2594
+ t.glyf && t.glyf[n] !== null ? l = t.glyf[n] : m && m.T && m.T.glyf && m.T.glyf._parseGlyf && (l = m.T.glyf._parseGlyf(t, n), t.glyf && l && (t.glyf[n] = l));
2480
2595
  } catch (c) {
2481
2596
  console.warn(`Failed to parse glyph ${n}:`, c);
2482
2597
  }
2483
- return h ? this.createGlyphPath(t, h, r, i, s) : this.createEmptyPath();
2484
- } catch (a) {
2485
- return console.warn(`Failed to generate path for character "${e}":`, a), this.createEmptyPath();
2598
+ return l ? this.createGlyphPath(t, l, r, i, s) : this.createEmptyPath();
2599
+ } catch (o) {
2600
+ return console.warn(`Failed to generate path for character "${e}":`, o), this.createEmptyPath();
2486
2601
  }
2487
2602
  }
2488
2603
  /**
@@ -2497,19 +2612,19 @@ class Me {
2497
2612
  * @param advanceWidth Character advance width
2498
2613
  * @returns SVG path data string or null if generation fails
2499
2614
  */
2500
- generatePositionedCharacterPath(e, t, r, i, s, a, n, h) {
2615
+ generatePositionedCharacterPath(e, t, r, i, s, o, n, l) {
2501
2616
  try {
2502
- const c = n / t.head.unitsPerEm, u = h * c, d = r + (s - u) / 2, f = i + (a + n * 0.7) / 2;
2617
+ const c = n / t.head.unitsPerEm, u = l * c, d = r + (s - u) / 2, f = i + (o + n * 0.7) / 2;
2503
2618
  return this.generateCharacterPath(e, t, d, f, n).toSVG() || null;
2504
2619
  } catch (c) {
2505
2620
  return console.warn(`Failed to generate positioned character path for "${e}":`, c), null;
2506
2621
  }
2507
2622
  }
2508
2623
  }
2509
- class De {
2624
+ class Me {
2510
2625
  constructor() {
2511
- o(this, "pathGenerator");
2512
- this.pathGenerator = new Me();
2626
+ a(this, "pathGenerator");
2627
+ this.pathGenerator = new Ae();
2513
2628
  }
2514
2629
  /**
2515
2630
  * Generates the SVG header with metadata
@@ -2561,12 +2676,12 @@ class De {
2561
2676
  * @returns Transform attribute string or empty string
2562
2677
  */
2563
2678
  generateTransformAttribute(e, t) {
2564
- const { transform: r, position: i } = e, s = i.cellX + t.cellWidth / 2, a = i.cellY + t.cellHeight / 2, n = [];
2679
+ const { transform: r, position: i } = e, s = i.cellX + t.cellWidth / 2, o = i.cellY + t.cellHeight / 2, n = [];
2565
2680
  if (r.flipHorizontal || r.flipVertical) {
2566
- const h = r.flipHorizontal ? -1 : 1, c = r.flipVertical ? -1 : 1;
2567
- n.push(`translate(${s} ${a})`), n.push(`scale(${h} ${c})`), n.push(`translate(${-s} ${-a})`);
2681
+ const l = r.flipHorizontal ? -1 : 1, c = r.flipVertical ? -1 : 1;
2682
+ n.push(`translate(${s} ${o})`), n.push(`scale(${l} ${c})`), n.push(`translate(${-s} ${-o})`);
2568
2683
  }
2569
- return r.rotation && n.push(`rotate(${r.rotation} ${s} ${a})`), n.length ? ` transform="${n.join(" ")}"` : "";
2684
+ return r.rotation && n.push(`rotate(${r.rotation} ${s} ${o})`), n.length ? ` transform="${n.join(" ")}"` : "";
2570
2685
  }
2571
2686
  /**
2572
2687
  * Generates background rectangle for a cell
@@ -2595,7 +2710,7 @@ class De {
2595
2710
  const s = r.characters[e.charIndex];
2596
2711
  if (!s)
2597
2712
  return "";
2598
- const a = this.pathGenerator.generatePositionedCharacterPath(
2713
+ const o = this.pathGenerator.generatePositionedCharacterPath(
2599
2714
  s.character,
2600
2715
  r.font,
2601
2716
  e.position.cellX,
@@ -2605,12 +2720,12 @@ class De {
2605
2720
  r.fontSize,
2606
2721
  s.advanceWidth
2607
2722
  );
2608
- if (!a)
2723
+ if (!o)
2609
2724
  return "";
2610
2725
  const n = this.rgbaToColorString(e.primaryColor);
2611
2726
  return i.drawMode === "stroke" ? `
2612
- <path id="${`path-${e.charIndex}-${e.position.cellX}-${e.position.cellY}`.replace(/\./g, "-")}" d="${a}" stroke="${n}" stroke-width="${i.strokeWidth}" fill="none" />` : `
2613
- <path d="${a}" fill="${n}" />`;
2727
+ <path id="${`path-${e.charIndex}-${e.position.cellX}-${e.position.cellY}`.replace(/\./g, "-")}" d="${o}" stroke="${n}" stroke-width="${i.strokeWidth}" fill="none" />` : `
2728
+ <path d="${o}" fill="${n}" />`;
2614
2729
  }
2615
2730
  /**
2616
2731
  * Generates complete SVG content for a single cell
@@ -2623,9 +2738,9 @@ class De {
2623
2738
  generateCellContent(e, t, r, i) {
2624
2739
  let s = "";
2625
2740
  s += this.generateCellBackground(e, t, i);
2626
- const a = this.generateTransformAttribute(e, t), n = this.generateCharacterPath(e, t, r, i);
2627
- return n && (a ? (s += `
2628
- <g${a}>`, s += n, s += `
2741
+ const o = this.generateTransformAttribute(e, t), n = this.generateCharacterPath(e, t, r, i);
2742
+ return n && (o ? (s += `
2743
+ <g${o}>`, s += n, s += `
2629
2744
  </g>`) : s += n), s;
2630
2745
  }
2631
2746
  /**
@@ -2640,8 +2755,8 @@ class De {
2640
2755
  let s = this.generateSVGHeader(t);
2641
2756
  s += this.generateBackground(t, i), s += `
2642
2757
  <g id="ascii-cells">`;
2643
- for (const a of e)
2644
- s += this.generateCellContent(a, t, r, i);
2758
+ for (const o of e)
2759
+ s += this.generateCellContent(o, t, r, i);
2645
2760
  return s += this.generateSVGFooter(), s;
2646
2761
  }
2647
2762
  /**
@@ -2686,10 +2801,10 @@ class Ie extends N {
2686
2801
  }
2687
2802
  class Y {
2688
2803
  constructor() {
2689
- o(this, "dataExtractor");
2690
- o(this, "contentGenerator");
2691
- o(this, "fileHandler");
2692
- this.dataExtractor = new Ae(), this.contentGenerator = new De(), this.fileHandler = new Ie();
2804
+ a(this, "dataExtractor");
2805
+ a(this, "contentGenerator");
2806
+ a(this, "fileHandler");
2807
+ this.dataExtractor = new De(), this.contentGenerator = new Me(), this.fileHandler = new Ie();
2693
2808
  }
2694
2809
  /**
2695
2810
  * Applies default values to SVG export options
@@ -2714,13 +2829,13 @@ class Y {
2714
2829
  const r = this.applyDefaultOptions(t), i = this.dataExtractor.extractFramebufferData(e.pipeline), s = this.dataExtractor.extractSVGCellData(
2715
2830
  i,
2716
2831
  e.grid
2717
- ), a = this.contentGenerator.generateSVGContent(
2832
+ ), o = this.contentGenerator.generateSVGContent(
2718
2833
  s,
2719
2834
  e.grid,
2720
2835
  e.font,
2721
2836
  r
2722
2837
  );
2723
- return this.contentGenerator.optimizeSVGContent(a);
2838
+ return this.contentGenerator.optimizeSVGContent(o);
2724
2839
  }
2725
2840
  /**
2726
2841
  * Exports SVG content to a downloadable file
@@ -2748,15 +2863,15 @@ class Pe extends H {
2748
2863
  extractCharacterGrid(e, t, r, i = " ") {
2749
2864
  var n;
2750
2865
  const s = [];
2751
- let a = 0;
2752
- for (let h = 0; h < t.rows; h++) {
2866
+ let o = 0;
2867
+ for (let l = 0; l < t.rows; l++) {
2753
2868
  const c = [];
2754
2869
  for (let u = 0; u < t.cols; u++) {
2755
- const d = a * 4, f = this.getCharacterIndex(
2870
+ const d = o * 4, f = this.getCharacterIndex(
2756
2871
  e.characterPixels,
2757
2872
  d
2758
2873
  ), g = ((n = r.characters[f]) == null ? void 0 : n.character) || i;
2759
- c.push(g), a++;
2874
+ c.push(g), o++;
2760
2875
  }
2761
2876
  s.push(c);
2762
2877
  }
@@ -2773,8 +2888,8 @@ class Be {
2773
2888
  generateTXTContent(e, t) {
2774
2889
  const r = [];
2775
2890
  for (const s of e) {
2776
- let a = s.join("");
2777
- t.preserveTrailingSpaces || (a = a.replace(/\s+$/, "")), r.push(a);
2891
+ let o = s.join("");
2892
+ t.preserveTrailingSpaces || (o = o.replace(/\s+$/, "")), r.push(o);
2778
2893
  }
2779
2894
  const i = t.lineEnding === "crlf" ? `\r
2780
2895
  ` : `
@@ -2808,9 +2923,9 @@ class Ge extends N {
2808
2923
  }
2809
2924
  class j {
2810
2925
  constructor() {
2811
- o(this, "dataExtractor");
2812
- o(this, "contentGenerator");
2813
- o(this, "fileHandler");
2926
+ a(this, "dataExtractor");
2927
+ a(this, "contentGenerator");
2928
+ a(this, "fileHandler");
2814
2929
  this.dataExtractor = new Pe(), this.contentGenerator = new Be(), this.fileHandler = new Ge();
2815
2930
  }
2816
2931
  /**
@@ -2869,8 +2984,8 @@ class Ve extends H {
2869
2984
  const i = e.canvas;
2870
2985
  if (t === 1 && r === "transparent")
2871
2986
  return i;
2872
- const s = document.createElement("canvas"), a = s.getContext("2d"), n = Math.round(i.width * t), h = Math.round(i.height * t);
2873
- return s.width = n, s.height = h, r !== "transparent" && (a.fillStyle = r, a.fillRect(0, 0, n, h)), a.imageSmoothingEnabled = !1, a.drawImage(
2987
+ const s = document.createElement("canvas"), o = s.getContext("2d"), n = Math.round(i.width * t), l = Math.round(i.height * t);
2988
+ return s.width = n, s.height = l, r !== "transparent" && (o.fillStyle = r, o.fillRect(0, 0, n, l)), o.imageSmoothingEnabled = !1, o.drawImage(
2874
2989
  i,
2875
2990
  0,
2876
2991
  0,
@@ -2879,7 +2994,7 @@ class Ve extends H {
2879
2994
  0,
2880
2995
  0,
2881
2996
  n,
2882
- h
2997
+ l
2883
2998
  ), s;
2884
2999
  }
2885
3000
  }
@@ -2902,10 +3017,10 @@ class ke {
2902
3017
  */
2903
3018
  async generateImageBlob(e, t) {
2904
3019
  return new Promise((r, i) => {
2905
- const s = this.getMimeType(t.format), a = (n) => {
3020
+ const s = this.getMimeType(t.format), o = (n) => {
2906
3021
  n ? r(n) : i(new Error(`Failed to generate ${t.format.toUpperCase()} blob`));
2907
3022
  };
2908
- t.format === "png" ? e.toBlob(a, s) : e.toBlob(a, s, t.quality);
3023
+ t.format === "png" ? e.toBlob(o, s) : e.toBlob(o, s, t.quality);
2909
3024
  });
2910
3025
  }
2911
3026
  /**
@@ -2930,12 +3045,12 @@ const q = {
2930
3045
  png: "image/png",
2931
3046
  jpg: "image/jpeg",
2932
3047
  webp: "image/webp"
2933
- }, $ = {
3048
+ }, z = {
2934
3049
  png: ".png",
2935
3050
  jpg: ".jpg",
2936
3051
  webp: ".webp"
2937
3052
  };
2938
- class $e extends N {
3053
+ class ze extends N {
2939
3054
  /**
2940
3055
  * Saves image content as a downloadable file
2941
3056
  * @param content The image content (data URL or blob)
@@ -2944,7 +3059,7 @@ class $e extends N {
2944
3059
  */
2945
3060
  saveImage(e, t, r) {
2946
3061
  try {
2947
- const i = $[r];
3062
+ const i = z[r];
2948
3063
  typeof e == "string" ? this.saveImageFromDataURL(e, this.sanitizeFilename(t) + i) : this.saveImageFromBlob(e, this.sanitizeFilename(t) + i);
2949
3064
  } catch (i) {
2950
3065
  throw console.error(`Failed to save ${r.toUpperCase()} image:`, i), new Error(`Image save failed: ${i instanceof Error ? i.message : "Unknown error"}`);
@@ -2979,7 +3094,7 @@ class $e extends N {
2979
3094
  * @returns True if the format is supported for saving
2980
3095
  */
2981
3096
  validateSaveSupport(e) {
2982
- return e in q && e in $;
3097
+ return e in q && e in z;
2983
3098
  }
2984
3099
  /**
2985
3100
  * Gets the MIME type for the specified image format
@@ -2995,15 +3110,15 @@ class $e extends N {
2995
3110
  * @returns The file extension (including the dot)
2996
3111
  */
2997
3112
  getFileExtension(e) {
2998
- return $[e];
3113
+ return z[e];
2999
3114
  }
3000
3115
  }
3001
- class ze {
3116
+ class $e {
3002
3117
  constructor() {
3003
- o(this, "dataExtractor");
3004
- o(this, "contentGenerator");
3005
- o(this, "fileHandler");
3006
- this.dataExtractor = new Ve(), this.contentGenerator = new ke(), this.fileHandler = new $e();
3118
+ a(this, "dataExtractor");
3119
+ a(this, "contentGenerator");
3120
+ a(this, "fileHandler");
3121
+ this.dataExtractor = new Ve(), this.contentGenerator = new ke(), this.fileHandler = new ze();
3007
3122
  }
3008
3123
  /**
3009
3124
  * Applies default values to image export options
@@ -3089,34 +3204,38 @@ class ze {
3089
3204
  class I {
3090
3205
  constructor(e = null, t = {}) {
3091
3206
  /** The element to capture content from (optional for standalone mode) */
3092
- o(this, "captureSource");
3207
+ a(this, "captureSource");
3093
3208
  /** Our WebGL overlay canvas manager */
3094
- o(this, "textmodeCanvas");
3209
+ a(this, "textmodeCanvas");
3095
3210
  /** Core WebGL renderer */
3096
- o(this, "_renderer");
3097
- o(this, "_canvasFramebuffer");
3098
- o(this, "_font");
3099
- o(this, "_grid");
3100
- o(this, "resizeObserver");
3211
+ a(this, "_renderer");
3212
+ a(this, "_canvasFramebuffer");
3213
+ a(this, "_font");
3214
+ a(this, "_grid");
3215
+ a(this, "resizeObserver");
3101
3216
  // Auto-rendering properties
3102
- o(this, "_mode");
3103
- o(this, "_frameRateLimit");
3104
- o(this, "animationFrameId", null);
3105
- o(this, "lastFrameTime", 0);
3106
- o(this, "frameInterval");
3107
- o(this, "_frameRate", 0);
3108
- o(this, "lastRenderTime", 0);
3109
- o(this, "_frameCount", 0);
3217
+ a(this, "_mode");
3218
+ a(this, "_frameRateLimit");
3219
+ a(this, "animationFrameId", null);
3220
+ a(this, "lastFrameTime", 0);
3221
+ a(this, "frameInterval");
3222
+ a(this, "_isLooping", !0);
3223
+ a(this, "_frameRate", 0);
3224
+ a(this, "lastRenderTime", 0);
3225
+ a(this, "_frameCount", 0);
3110
3226
  // Frame rate measurement smoothing
3111
- o(this, "frameTimeHistory", []);
3112
- o(this, "frameTimeHistorySize", 10);
3113
- o(this, "_pipeline");
3227
+ a(this, "frameTimeHistory", []);
3228
+ a(this, "frameTimeHistorySize", 10);
3229
+ a(this, "_pipeline");
3114
3230
  // Standalone canvas properties
3115
- o(this, "_standalone", !1);
3116
- o(this, "_drawCallback", () => {
3231
+ a(this, "_standalone", !1);
3232
+ a(this, "_drawCallback", () => {
3117
3233
  });
3118
- o(this, "_resizedCallback", () => {
3234
+ a(this, "_resizedCallback", () => {
3119
3235
  });
3236
+ // Destroy state
3237
+ a(this, "_isDestroyed", !1);
3238
+ a(this, "_windowResizeListener", null);
3120
3239
  this.captureSource = e, this._standalone = e === null, this._mode = t.renderMode ?? "auto", this._frameRateLimit = t.frameRate ?? 60, this.frameInterval = 1e3 / this._frameRateLimit;
3121
3240
  }
3122
3241
  /**
@@ -3127,16 +3246,16 @@ class I {
3127
3246
  */
3128
3247
  static async create(e = null, t = {}) {
3129
3248
  const r = new I(e, t), i = r._standalone ? t : void 0;
3130
- r.textmodeCanvas = new Ce(r.captureSource, r._standalone, i), r._renderer = new fe(r.textmodeCanvas.getWebGLContext());
3131
- let s, a;
3132
- r._standalone ? (s = t.width || 800, a = t.height || 600) : (s = r.textmodeCanvas.width || 800, a = r.textmodeCanvas.height || 600), r._canvasFramebuffer = r._renderer.createFramebuffer(s, a), r._font = new xe(r._renderer, t.fontSize ?? 16), await r._font.initialize(t.fontSource);
3249
+ r.textmodeCanvas = new be(r.captureSource, r._standalone, i), r._renderer = new fe(r.textmodeCanvas.getWebGLContext());
3250
+ let s, o;
3251
+ r._standalone ? (s = t.width || 800, o = t.height || 600) : (s = r.textmodeCanvas.width || 800, o = r.textmodeCanvas.height || 600), r._canvasFramebuffer = r._renderer.createFramebuffer(s, o), r._font = new xe(r._renderer, t.fontSize ?? 16), await r._font.initialize(t.fontSource);
3133
3252
  const n = r._font.maxGlyphDimensions;
3134
3253
  return r._grid = new ve(r.textmodeCanvas.canvas, n.width, n.height), r._pipeline = new Ue(r._renderer, r._font, r._grid), r.setupEventListeners(), r.startAutoRendering(), r;
3135
3254
  }
3136
3255
  setupEventListeners() {
3137
- window.addEventListener("resize", () => {
3256
+ this._windowResizeListener = () => {
3138
3257
  this._standalone ? this._resizedCallback() : this.resize();
3139
- }), window.ResizeObserver && this.captureSource && !this._standalone && (this.resizeObserver = new ResizeObserver(() => {
3258
+ }, window.addEventListener("resize", this._windowResizeListener), window.ResizeObserver && this.captureSource && !this._standalone && (this.resizeObserver = new ResizeObserver(() => {
3140
3259
  this.resize();
3141
3260
  }), this.resizeObserver.observe(this.captureSource));
3142
3261
  }
@@ -3288,7 +3407,7 @@ class I {
3288
3407
  * ```
3289
3408
  */
3290
3409
  async saveCanvas(e, t = "png", r = {}) {
3291
- await new ze().saveImage(this.textmodeCanvas, {
3410
+ await new $e().saveImage(this.textmodeCanvas, {
3292
3411
  ...r,
3293
3412
  filename: e,
3294
3413
  format: t
@@ -3358,7 +3477,19 @@ class I {
3358
3477
  * ```
3359
3478
  */
3360
3479
  render() {
3361
- this.measureFrameRate(), this._frameCount++, this._standalone || this._canvasFramebuffer.update(this.captureSource), this._canvasFramebuffer.begin(), this._drawCallback(), this._renderer.reset(), this._canvasFramebuffer.end(), this._pipeline.render(this._canvasFramebuffer), this._pipeline.hasEnabledConverters() ? (this._renderer.background(0), this._renderer.image(this._pipeline.texture, this._grid.offsetX, this._grid.offsetY, this._pipeline.texture.width, this._pipeline.texture.height)) : (this._renderer.clear(), this._renderer.image(this._canvasFramebuffer, this._grid.offsetX, this._grid.offsetY, this._canvasFramebuffer.width, this._canvasFramebuffer.height));
3480
+ if (this._isDestroyed) {
3481
+ console.warn("Cannot render: Textmodifier instance has been destroyed");
3482
+ return;
3483
+ }
3484
+ if (this.measureFrameRate(), this._frameCount++, !this._canvasFramebuffer || !this._renderer || !this._pipeline) {
3485
+ console.warn("Cannot render: Required resources have been disposed");
3486
+ return;
3487
+ }
3488
+ if (this._standalone ? this._canvasFramebuffer && (this._canvasFramebuffer.begin(), this._drawCallback(), this._renderer && this._renderer.reset(), this._canvasFramebuffer && this._canvasFramebuffer.end()) : this.captureSource && this._canvasFramebuffer && this._canvasFramebuffer.update(this.captureSource), !this._pipeline || !this._renderer) {
3489
+ console.warn("Cannot complete render: Pipeline or renderer has been disposed");
3490
+ return;
3491
+ }
3492
+ this._pipeline.render(this._canvasFramebuffer), this._pipeline.hasEnabledConverters() ? this._renderer && this._pipeline.texture && this._grid && (this._renderer.background(0), this._renderer.image(this._pipeline.texture, this._grid.offsetX, this._grid.offsetY, this._pipeline.texture.width, this._pipeline.texture.height)) : this._renderer && this._canvasFramebuffer && this._grid && (this._renderer.clear(), this._renderer.image(this._canvasFramebuffer, this._grid.offsetX, this._grid.offsetY, this._canvasFramebuffer.width, this._canvasFramebuffer.height));
3362
3493
  }
3363
3494
  resize() {
3364
3495
  this.textmodeCanvas.resize(), this._canvasFramebuffer.resize(this.textmodeCanvas.width, this.textmodeCanvas.height), this._grid.resize(), this._pipeline.resize(), this._renderer.resetViewport(), this._mode !== "manual" && this.render();
@@ -3367,11 +3498,17 @@ class I {
3367
3498
  * Start automatic rendering
3368
3499
  */
3369
3500
  startAutoRendering() {
3370
- if (this._mode !== "auto") return;
3501
+ if (this._mode !== "auto" || this._isDestroyed || !this._isLooping) return;
3371
3502
  this.lastFrameTime = performance.now();
3372
3503
  const e = (t) => {
3504
+ if (this._isDestroyed)
3505
+ return;
3506
+ if (!this._isLooping) {
3507
+ this.animationFrameId = null;
3508
+ return;
3509
+ }
3373
3510
  const r = t - this.lastFrameTime;
3374
- r >= this.frameInterval && (this.render(), this.lastFrameTime = t - r % this.frameInterval), this.animationFrameId = requestAnimationFrame(e);
3511
+ r >= this.frameInterval && (this.render(), this.lastFrameTime = t - r % this.frameInterval), !this._isDestroyed && this._isLooping && (this.animationFrameId = requestAnimationFrame(e));
3375
3512
  };
3376
3513
  this.animationFrameId = requestAnimationFrame(e);
3377
3514
  }
@@ -3380,6 +3517,7 @@ class I {
3380
3517
  * Uses a rolling average for smoother frame rate reporting
3381
3518
  */
3382
3519
  measureFrameRate() {
3520
+ if (this._isDestroyed) return;
3383
3521
  const e = performance.now();
3384
3522
  if (this.lastRenderTime > 0) {
3385
3523
  const t = e - this.lastRenderTime;
@@ -3420,7 +3558,11 @@ class I {
3420
3558
  * ```
3421
3559
  */
3422
3560
  renderMode(e) {
3423
- this._mode !== e && (this.stopAutoRendering(), this._mode = e, e === "auto" && this.startAutoRendering());
3561
+ if (this._isDestroyed) {
3562
+ console.warn("Cannot change render mode: Textmodifier instance has been destroyed");
3563
+ return;
3564
+ }
3565
+ this._mode !== e && (this.stopAutoRendering(), this._mode = e, e === "auto" && this._isLooping && this.startAutoRendering());
3424
3566
  }
3425
3567
  /**
3426
3568
  * Set the maximum frame rate for auto rendering. If called without arguments, returns the current measured frame rate.
@@ -3441,7 +3583,105 @@ class I {
3441
3583
  frameRate(e) {
3442
3584
  if (e === void 0)
3443
3585
  return this._frameRate;
3444
- this._frameRateLimit = e, this.frameInterval = 1e3 / e, this._mode === "auto" && (this.stopAutoRendering(), this.startAutoRendering());
3586
+ this._frameRateLimit = e, this.frameInterval = 1e3 / e, this._mode === "auto" && this._isLooping && (this.stopAutoRendering(), this.startAutoRendering());
3587
+ }
3588
+ /**
3589
+ * Stop the automatic rendering loop while keeping the render mode as 'auto'.
3590
+ *
3591
+ * This method pauses the render loop without changing the render mode, allowing
3592
+ * it to be resumed later with {@link loop}. This is useful for temporarily pausing
3593
+ * animation while maintaining the ability to restart it.
3594
+ *
3595
+ * **Note:** This only affects rendering when in `'auto'` mode. In `'manual'` mode,
3596
+ * this method has no effect since rendering is already controlled manually.
3597
+ *
3598
+ * @example
3599
+ * ```javascript
3600
+ * // Create a textmodifier instance in auto mode
3601
+ * const textmodifier = await textmode.create(canvas);
3602
+ *
3603
+ * // The render loop is running automatically
3604
+ * console.log(textmodifier.isLooping()); // true
3605
+ *
3606
+ * // Stop the automatic rendering loop
3607
+ * textmodifier.noLoop();
3608
+ * console.log(textmodifier.isLooping()); // false
3609
+ *
3610
+ * // Resume the automatic rendering loop
3611
+ * textmodifier.loop();
3612
+ * console.log(textmodifier.isLooping()); // true
3613
+ * ```
3614
+ */
3615
+ noLoop() {
3616
+ if (this._isDestroyed) {
3617
+ console.warn("Cannot stop loop: Textmodifier instance has been destroyed");
3618
+ return;
3619
+ }
3620
+ this._isLooping && (this._isLooping = !1, this.animationFrameId && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null));
3621
+ }
3622
+ /**
3623
+ * Resume the automatic rendering loop if it was stopped by {@link noLoop}.
3624
+ *
3625
+ * This method restarts the render loop when in `'auto'` mode. If the render mode
3626
+ * is `'manual'`, the loop state will be set but automatic rendering will not start
3627
+ * until the mode is changed back to `'auto'`.
3628
+ *
3629
+ * @example
3630
+ * ```javascript
3631
+ * // Create a textmodifier instance
3632
+ * const textmodifier = await textmode.create(canvas);
3633
+ *
3634
+ * // Stop the loop
3635
+ * textmodifier.noLoop();
3636
+ *
3637
+ * // Resume the loop
3638
+ * textmodifier.loop();
3639
+ *
3640
+ * // You can also use this pattern for conditional animation
3641
+ * if (someCondition) {
3642
+ * textmodifier.loop();
3643
+ * } else {
3644
+ * textmodifier.noLoop();
3645
+ * }
3646
+ * ```
3647
+ */
3648
+ loop() {
3649
+ if (this._isDestroyed) {
3650
+ console.warn("Cannot start loop: Textmodifier instance has been destroyed");
3651
+ return;
3652
+ }
3653
+ this._isLooping || (this._isLooping = !0, this._mode === "auto" && this.startAutoRendering());
3654
+ }
3655
+ /**
3656
+ * Check whether the textmodifier is currently running the automatic render loop.
3657
+ *
3658
+ * Returns `true` when both the render mode is `'auto'` AND the loop is active.
3659
+ * Returns `false` when in `'manual'` mode or when {@link noLoop} has been called.
3660
+ *
3661
+ * @returns True if the automatic render loop is currently active, false otherwise.
3662
+ *
3663
+ * @example
3664
+ * ```javascript
3665
+ * const textmodifier = await textmode.create(canvas);
3666
+ *
3667
+ * // Check loop status in different states
3668
+ * console.log(textmodifier.isLooping()); // true (auto mode, looping)
3669
+ *
3670
+ * textmodifier.noLoop();
3671
+ * console.log(textmodifier.isLooping()); // false (auto mode, not looping)
3672
+ *
3673
+ * textmodifier.renderMode('manual');
3674
+ * console.log(textmodifier.isLooping()); // false (manual mode)
3675
+ *
3676
+ * textmodifier.renderMode('auto');
3677
+ * console.log(textmodifier.isLooping()); // false (auto mode, but loop was stopped)
3678
+ *
3679
+ * textmodifier.loop();
3680
+ * console.log(textmodifier.isLooping()); // true (auto mode, looping)
3681
+ * ```
3682
+ */
3683
+ isLooping() {
3684
+ return this._isDestroyed ? !1 : this._mode === "auto" && this._isLooping;
3445
3685
  }
3446
3686
  /**
3447
3687
  * Set the font size used for rendering.
@@ -3973,33 +4213,77 @@ class I {
3973
4213
  setUniform(e, t) {
3974
4214
  this._renderer.setUniform(e, t);
3975
4215
  }
4216
+ /**
4217
+ * Completely destroy this Textmodifier instance and free all associated resources.
4218
+ *
4219
+ * This method performs comprehensive cleanup of:
4220
+ * - WebGL resources (framebuffers, textures, shaders)
4221
+ * - Animation frames and timers
4222
+ * - Event listeners
4223
+ * - DOM elements
4224
+ * - Font resources
4225
+ *
4226
+ * After calling this method, the instance should not be used and will be eligible for garbage collection.
4227
+ * This method is idempotent and safe to call multiple times.
4228
+ *
4229
+ * @example
4230
+ * ```javascript
4231
+ * // Create a textmodifier instance
4232
+ * const textmodifier = await textmode.create(canvas);
4233
+ *
4234
+ * // Use it for rendering
4235
+ * textmodifier.render();
4236
+ *
4237
+ * // When done, completely clean up
4238
+ * textmodifier.destroy();
4239
+ *
4240
+ * // Instance is now safely disposed and ready for garbage collection
4241
+ * ```
4242
+ */
4243
+ destroy() {
4244
+ this._isDestroyed || (this._isDestroyed = !0, this.stopAutoRendering(), this._windowResizeListener && (window.removeEventListener("resize", this._windowResizeListener), this._windowResizeListener = null), this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = null), this._pipeline && !this._pipeline.isDisposed && this._pipeline.dispose(), this._font && !this._font.isDisposed && this._font.dispose(), this._grid && !this._grid.isDisposed && this._grid.dispose(), this._canvasFramebuffer && !this._canvasFramebuffer.isDisposed && this._canvasFramebuffer.dispose(), this._renderer && !this._renderer.isDisposed && this._renderer.dispose(), this.textmodeCanvas && !this.textmodeCanvas.isDisposed && this.textmodeCanvas.dispose(), this.captureSource = null, this.textmodeCanvas = null, this._renderer = null, this._canvasFramebuffer = null, this._font = null, this._grid = null, this._pipeline = null, this.resizeObserver = null, this._drawCallback = () => {
4245
+ }, this._resizedCallback = () => {
4246
+ }, this.animationFrameId = null, this.lastFrameTime = 0, this.lastRenderTime = 0, this._frameCount = 0, this._frameRate = 0, this.frameTimeHistory = [], this._isLooping = !1);
4247
+ }
3976
4248
  /** Get the current grid object used for rendering. */
3977
4249
  get grid() {
4250
+ if (this._isDestroyed)
4251
+ throw new Error("Cannot access grid: Textmodifier instance has been destroyed");
3978
4252
  return this._grid;
3979
4253
  }
3980
4254
  /** Get the current font object used for rendering. */
3981
4255
  get font() {
4256
+ if (this._isDestroyed)
4257
+ throw new Error("Cannot access font: Textmodifier instance has been destroyed");
3982
4258
  return this._font;
3983
4259
  }
3984
4260
  /** Get the current rendering mode.*/
3985
4261
  get mode() {
4262
+ if (this._isDestroyed)
4263
+ throw new Error("Cannot access mode: Textmodifier instance has been destroyed");
3986
4264
  return this._mode;
3987
4265
  }
3988
4266
  /** Get the current textmode conversion pipeline. */
3989
4267
  get pipeline() {
4268
+ if (this._isDestroyed)
4269
+ throw new Error("Cannot access pipeline: Textmodifier instance has been destroyed");
3990
4270
  return this._pipeline;
3991
4271
  }
3992
4272
  /** Get the current frame count. */
3993
4273
  get frameCount() {
3994
- return this._frameCount;
4274
+ return this._isDestroyed ? 0 : this._frameCount;
3995
4275
  }
3996
4276
  /** Get the width of the canvas. */
3997
4277
  get width() {
3998
- return this.textmodeCanvas.width;
4278
+ return this._isDestroyed ? 0 : this.textmodeCanvas.width;
3999
4279
  }
4000
4280
  /** Get the height of the canvas. */
4001
4281
  get height() {
4002
- return this.textmodeCanvas.height;
4282
+ return this._isDestroyed ? 0 : this.textmodeCanvas.height;
4283
+ }
4284
+ /** Check if this Textmodifier instance has been destroyed. */
4285
+ get isDestroyed() {
4286
+ return this._isDestroyed;
4003
4287
  }
4004
4288
  }
4005
4289
  class O {
@@ -4046,6 +4330,20 @@ class O {
4046
4330
  * // Draw a rectangle with the fill color
4047
4331
  * t.rect(x, y, 200, 150);
4048
4332
  * });
4333
+ *
4334
+ * ////////
4335
+ *
4336
+ * // Resource management example
4337
+ * const textmodifier = await textmode.create(canvas);
4338
+ *
4339
+ * // Use the textmodifier...
4340
+ * textmodifier.render();
4341
+ *
4342
+ * // When done, completely clean up all resources
4343
+ * textmodifier.destroy();
4344
+ *
4345
+ * // The instance is now safely disposed and ready for garbage collection
4346
+ * console.log(textmodifier.isDestroyed); // true
4049
4347
  * ```
4050
4348
  */
4051
4349
  static async create(e, t = {}) {
@@ -4078,7 +4376,7 @@ class O {
4078
4376
  * ```
4079
4377
  */
4080
4378
  static get version() {
4081
- return "0.1.4-beta.1";
4379
+ return "0.1.4-beta.2";
4082
4380
  }
4083
4381
  constructor() {
4084
4382
  throw new Error("Textmode is a static class and cannot be instantiated.");
@@ -4088,7 +4386,7 @@ const He = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
4088
4386
  __proto__: null
4089
4387
  }, Symbol.toStringTag, { value: "Module" })), Ne = O.create, Oe = O.setErrorLevel, We = O.version;
4090
4388
  export {
4091
- Ce as TextmodeCanvas,
4389
+ be as TextmodeCanvas,
4092
4390
  Ue as TextmodeConversionPipeline,
4093
4391
  ne as TextmodeErrorLevel,
4094
4392
  xe as TextmodeFont,